xrpld
Toggle main menu visibility
Loading...
Searching...
No Matches
xrpld
rpc
detail
PathRequestManager.cpp
1
#include <xrpld/rpc/detail/PathRequestManager.h>
2
3
#include <xrpld/app/ledger/LedgerMaster.h>
4
#include <xrpld/app/main/Application.h>
5
#include <xrpld/rpc/detail/AssetCache.h>
6
#include <xrpld/rpc/detail/PathRequest.h>
7
8
#include <xrpl/basics/Log.h>
9
#include <xrpl/core/Job.h>
10
#include <xrpl/core/JobQueue.h>
11
#include <xrpl/json/json_value.h>
12
#include <xrpl/ledger/ReadView.h>
13
#include <xrpl/protocol/ErrorCodes.h>
14
#include <xrpl/protocol/RPCErr.h>
15
#include <xrpl/protocol/jss.h>
16
#include <xrpl/resource/Consumer.h>
17
#include <xrpl/server/InfoSub.h>
18
19
#include <
algorithm
>
20
#include <
cstdint
>
21
#include <
functional
>
22
#include <
memory
>
23
#include <
mutex
>
24
#include <
utility
>
25
#include <
vector
>
26
27
namespace
xrpl
{
28
33
std::shared_ptr<AssetCache>
34
PathRequestManager::getAssetCache
(
std::shared_ptr<ReadView const>
const
& ledger,
bool
authoritative)
35
{
36
std::scoped_lock
const
sl(
lock_
);
37
38
auto
assetCache =
assetCache_
.lock();
39
40
std::uint32_t
const
lineSeq = assetCache ? assetCache->getLedger()->seq() : 0;
41
std::uint32_t
const
lgrSeq = ledger->seq();
42
JLOG(
journal_
.debug()) <<
"getLineCache has cache for "
<< lineSeq <<
", considering "
43
<< lgrSeq;
44
45
if
((lineSeq == 0) ||
// no ledger
46
(authoritative && (lgrSeq > lineSeq)) ||
// newer authoritative ledger
47
(authoritative && ((lgrSeq + 8) < lineSeq)) ||
// we jumped way back for some reason
48
(lgrSeq > (lineSeq + 8)))
// we jumped way forward for some reason
49
{
50
JLOG(
journal_
.debug()) <<
"getLineCache creating new cache for "
<< lgrSeq;
51
// Assign to the local before the member, because the member is a
52
// weak_ptr, and will immediately discard it if there are no other
53
// references.
54
assetCache_
= assetCache =
55
std::make_shared<AssetCache>
(ledger,
app_
.getJournal(
"AssetCache"
));
56
}
57
return
assetCache;
58
}
59
60
void
61
PathRequestManager::updateAll
(
std::shared_ptr<ReadView const>
const
& inLedger)
62
{
63
auto
event
=
app_
.getJobQueue().makeLoadEvent(
JtPathFind
,
"PathRequest::updateAll"
);
64
65
std::vector<PathRequest::Wptr>
requests;
66
std::shared_ptr<AssetCache>
cache;
67
68
// Get the ledger and cache we should be using
69
{
70
std::scoped_lock
const
sl(
lock_
);
71
requests =
requests_
;
72
cache =
getAssetCache
(inLedger,
true
);
73
}
74
75
bool
newRequests =
app_
.getLedgerMaster().isNewPathRequest();
76
bool
mustBreak =
false
;
77
78
JLOG(
journal_
.trace()) <<
"updateAll seq="
<< cache->getLedger()->seq() <<
", "
79
<< requests.
size
() <<
" requests"
;
80
81
int
processed = 0, removed = 0;
82
83
auto
getSubscriber = [](
PathRequest::pointer
const
& request) ->
InfoSub::pointer
{
84
if
(
auto
ipSub = request->getSubscriber(); ipSub && ipSub->getRequest() == request)
85
{
86
return
ipSub;
87
}
88
request->doAborting();
89
return
nullptr
;
90
};
91
92
do
93
{
94
JLOG(
journal_
.trace()) <<
"updateAll looping"
;
95
for
(
auto
const
& wr : requests)
96
{
97
if
(
app_
.getJobQueue().isStopping())
98
break
;
99
100
auto
request = wr.lock();
101
bool
remove =
true
;
102
JLOG(
journal_
.trace()) <<
"updateAll request "
<< (request ?
""
:
"not "
) <<
"found"
;
103
104
if
(request)
105
{
106
auto
continueCallback = [&getSubscriber, &request]() {
107
// This callback is used by doUpdate to determine whether to
108
// continue working. If getSubscriber returns null, that
109
// indicates that this request is no longer relevant.
110
return
(
bool
)getSubscriber(request);
111
};
112
if
(!request->needsUpdate(newRequests, cache->getLedger()->seq()))
113
{
114
remove =
false
;
115
}
116
else
117
{
118
if
(
auto
ipSub = getSubscriber(request))
119
{
120
if
(!ipSub->getConsumer().warn())
121
{
122
// Release the shared ptr to the subscriber so that
123
// it can be freed if the client disconnects, and
124
// thus fail to lock later.
125
ipSub.reset();
126
json::Value
update = request->doUpdate(cache,
false
, continueCallback);
127
request->updateComplete();
128
update[jss::type] =
"path_find"
;
129
ipSub = getSubscriber(request);
130
if
(ipSub)
131
{
132
ipSub->send(update,
false
);
133
remove =
false
;
134
++processed;
135
}
136
}
137
}
138
else
if
(request->hasCompletion())
139
{
140
// One-shot request with completion function
141
request->doUpdate(cache,
false
);
142
request->updateComplete();
143
++processed;
144
}
145
}
146
}
147
148
if
(remove)
149
{
150
std::scoped_lock
const
sl(
lock_
);
151
152
// Remove any dangling weak pointers or weak
153
// pointers that refer to this path request.
154
auto
ret =
std::ranges::remove_if
(
requests_
, [&removed, &request](
auto
const
& wl) {
155
auto
r = wl.lock();
156
157
if
(r && r != request)
158
return
false
;
159
++removed;
160
return
true
;
161
});
162
163
requests_
.erase(ret.begin(), ret.end());
164
}
165
166
mustBreak = !newRequests &&
app_
.getLedgerMaster().isNewPathRequest();
167
168
// We weren't handling new requests and then
169
// there was a new request
170
if
(mustBreak)
171
break
;
172
}
173
174
if
(mustBreak)
175
{
// a new request came in while we were working
176
newRequests =
true
;
177
}
178
else
if
(newRequests)
179
{
// we only did new requests, so we always need a last pass
180
newRequests =
app_
.getLedgerMaster().isNewPathRequest();
181
}
182
else
183
{
// if there are no new requests, we are done
184
newRequests =
app_
.getLedgerMaster().isNewPathRequest();
185
if
(!newRequests)
186
break
;
187
}
188
189
// Hold on to the line cache until after the lock is released, so it can
190
// be destroyed outside of the lock
191
std::shared_ptr<AssetCache>
lastCache;
192
{
193
// Get the latest requests, cache, and ledger for next pass
194
std::scoped_lock
const
sl(
lock_
);
195
196
if
(
requests_
.empty())
197
break
;
198
requests =
requests_
;
199
lastCache = cache;
200
cache =
getAssetCache
(cache->getLedger(),
false
);
201
}
202
}
while
(!
app_
.getJobQueue().isStopping());
203
204
JLOG(
journal_
.debug()) <<
"updateAll complete: "
<< processed <<
" processed and "
<< removed
205
<<
" removed"
;
206
}
207
208
bool
209
PathRequestManager::requestsPending
()
const
210
{
211
std::scoped_lock
const
sl(
lock_
);
212
return
!
requests_
.empty();
213
}
214
215
void
216
PathRequestManager::insertPathRequest
(
PathRequest::pointer
const
& req)
217
{
218
std::scoped_lock
const
sl(
lock_
);
219
220
// Insert after any older unserviced requests but before
221
// any serviced requests
222
auto
ret =
std::ranges::find_if
(
requests_
, [](
auto
const
& wl) {
223
auto
r = wl.lock();
224
225
// We come before handled requests
226
return
r && !r->isNew();
227
});
228
229
requests_
.emplace(ret, req);
230
}
231
232
// Make a new-style path_find request
233
json::Value
234
PathRequestManager::makePathRequest
(
235
std::shared_ptr<InfoSub>
const
& subscriber,
236
std::shared_ptr<ReadView const>
const
& inLedger,
237
json::Value
const
& requestJson)
238
{
239
auto
req =
std::make_shared<PathRequest>
(
app_
, subscriber, ++
lastIdentifier_
, *
this
,
journal_
);
240
241
auto
[
valid
, jvRes] = req->doCreate(
getAssetCache
(inLedger,
false
), requestJson);
242
243
if
(
valid
)
244
{
245
subscriber->setRequest(req);
246
insertPathRequest
(req);
247
app_
.getLedgerMaster().newPathRequest();
248
}
249
return
std::move(jvRes);
250
}
251
252
// Make an old-style ripple_path_find request
253
json::Value
254
PathRequestManager::makeLegacyPathRequest
(
255
PathRequest::pointer
& req,
256
std::function
<
void
(
void
)> completion,
257
resource::Consumer
& consumer,
258
std::shared_ptr<ReadView const>
const
& inLedger,
259
json::Value
const
& request)
260
{
261
// This assignment must take place before the
262
// completion function is called
263
req =
std::make_shared<PathRequest>
(
264
app_
, completion, consumer, ++
lastIdentifier_
, *
this
,
journal_
);
265
266
auto
[
valid
, jvRes] = req->doCreate(
getAssetCache
(inLedger,
false
), request);
267
268
if
(!
valid
)
269
{
270
req.
reset
();
271
}
272
else
273
{
274
insertPathRequest
(req);
275
if
(!
app_
.getLedgerMaster().newPathRequest())
276
{
277
// The newPathRequest failed. Tell the caller.
278
jvRes =
rpcError
(
RpcTooBusy
);
279
req.
reset
();
280
}
281
}
282
283
return
std::move(jvRes);
284
}
285
286
json::Value
287
PathRequestManager::doLegacyPathRequest
(
288
resource::Consumer
& consumer,
289
std::shared_ptr<ReadView const>
const
& inLedger,
290
json::Value
const
& request)
291
{
292
auto
cache =
std::make_shared<AssetCache>
(inLedger,
app_
.getJournal(
"AssetCache"
));
293
294
auto
req =
295
std::make_shared<PathRequest>
(
app_
, [] {}, consumer, ++
lastIdentifier_
, *
this
,
journal_
);
296
297
auto
[
valid
, jvRes] = req->doCreate(cache, request);
298
if
(
valid
)
299
jvRes = req->doUpdate(cache,
false
);
300
return
std::move(jvRes);
301
}
302
303
}
// namespace xrpl
algorithm
json::Value
Represents a JSON value.
Definition
json_value.h:117
xrpl::InfoSub::pointer
std::shared_ptr< InfoSub > pointer
Definition
InfoSub.h:92
xrpl::PathRequestManager::app_
Application & app_
Definition
PathRequestManager.h:96
xrpl::PathRequestManager::lastIdentifier_
std::atomic< int > lastIdentifier_
Definition
PathRequestManager.h:108
xrpl::PathRequestManager::requestsPending
bool requestsPending() const
Definition
PathRequestManager.cpp:209
xrpl::PathRequestManager::getAssetCache
std::shared_ptr< AssetCache > getAssetCache(std::shared_ptr< ReadView const > const &ledger, bool authoritative)
Get the current AssetCache, updating it if necessary.
Definition
PathRequestManager.cpp:34
xrpl::PathRequestManager::assetCache_
std::weak_ptr< AssetCache > assetCache_
Definition
PathRequestManager.h:106
xrpl::PathRequestManager::makePathRequest
json::Value makePathRequest(std::shared_ptr< InfoSub > const &subscriber, std::shared_ptr< ReadView const > const &ledger, json::Value const &request)
Definition
PathRequestManager.cpp:234
xrpl::PathRequestManager::makeLegacyPathRequest
json::Value makeLegacyPathRequest(PathRequest::pointer &req, std::function< void(void)> completion, resource::Consumer &consumer, std::shared_ptr< ReadView const > const &inLedger, json::Value const &request)
Definition
PathRequestManager.cpp:254
xrpl::PathRequestManager::updateAll
void updateAll(std::shared_ptr< ReadView const > const &ledger)
Update all of the contained PathRequest instances.
Definition
PathRequestManager.cpp:61
xrpl::PathRequestManager::insertPathRequest
void insertPathRequest(PathRequest::pointer const &)
Definition
PathRequestManager.cpp:216
xrpl::PathRequestManager::lock_
std::recursive_mutex lock_
Definition
PathRequestManager.h:110
xrpl::PathRequestManager::doLegacyPathRequest
json::Value doLegacyPathRequest(resource::Consumer &consumer, std::shared_ptr< ReadView const > const &inLedger, json::Value const &request)
Definition
PathRequestManager.cpp:287
xrpl::PathRequestManager::journal_
beast::Journal journal_
Definition
PathRequestManager.h:97
xrpl::PathRequestManager::requests_
std::vector< PathRequest::Wptr > requests_
Definition
PathRequestManager.h:103
xrpl::PathRequest::pointer
std::shared_ptr< PathRequest > pointer
Definition
PathRequest.h:48
xrpl::resource::Consumer
An endpoint that consumes resources.
Definition
Consumer.h:20
cstdint
std::ranges::find_if
T find_if(T... args)
std::function
functional
std::uint32_t
std::make_shared
T make_shared(T... args)
memory
mutex
xrpl::credentials::valid
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
Definition
CredentialHelpers.cpp:166
xrpl
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition
algorithm.h:5
xrpl::RpcTooBusy
@ RpcTooBusy
Definition
ErrorCodes.h:39
xrpl::rpcError
json::Value rpcError(ErrorCodeI iError)
Definition
RPCErr.cpp:13
xrpl::JtPathFind
@ JtPathFind
Definition
Job.h:70
std::ranges::remove_if
T remove_if(T... args)
std::shared_ptr::reset
T reset(T... args)
std::scoped_lock
std::shared_ptr
std::vector::size
T size(T... args)
utility
vector
Generated by
1.17.0