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