rippled
Loading...
Searching...
No Matches
PathRequests.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012, 2013 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <xrpld/app/ledger/LedgerMaster.h>
21#include <xrpld/app/main/Application.h>
22#include <xrpld/app/paths/PathRequests.h>
23#include <xrpld/core/JobQueue.h>
24
25#include <xrpl/basics/Log.h>
26#include <xrpl/protocol/ErrorCodes.h>
27#include <xrpl/protocol/RPCErr.h>
28#include <xrpl/protocol/jss.h>
29
30#include <algorithm>
31
32namespace ripple {
33
40 bool authoritative)
41{
43
44 auto lineCache = lineCache_.lock();
45
46 std::uint32_t const lineSeq = lineCache ? lineCache->getLedger()->seq() : 0;
47 std::uint32_t const lgrSeq = ledger->seq();
48 JLOG(mJournal.debug()) << "getLineCache has cache for " << lineSeq
49 << ", considering " << lgrSeq;
50
51 if ((lineSeq == 0) || // no ledger
52 (authoritative && (lgrSeq > lineSeq)) || // newer authoritative ledger
53 (authoritative &&
54 ((lgrSeq + 8) < lineSeq)) || // we jumped way back for some reason
55 (lgrSeq > (lineSeq + 8))) // we jumped way forward for some reason
56 {
57 JLOG(mJournal.debug())
58 << "getLineCache creating new cache for " << lgrSeq;
59 // Assign to the local before the member, because the member is a
60 // weak_ptr, and will immediately discard it if there are no other
61 // references.
62 lineCache_ = lineCache = std::make_shared<RippleLineCache>(
63 ledger, app_.journal("RippleLineCache"));
64 }
65 return lineCache;
66}
67
68void
70{
71 auto event =
72 app_.getJobQueue().makeLoadEvent(jtPATH_FIND, "PathRequest::updateAll");
73
76
77 // Get the ledger and cache we should be using
78 {
80 requests = requests_;
81 cache = getLineCache(inLedger, true);
82 }
83
84 bool newRequests = app_.getLedgerMaster().isNewPathRequest();
85 bool mustBreak = false;
86
87 JLOG(mJournal.trace()) << "updateAll seq=" << cache->getLedger()->seq()
88 << ", " << requests.size() << " requests";
89
90 int processed = 0, removed = 0;
91
92 auto getSubscriber =
93 [](PathRequest::pointer const& request) -> InfoSub::pointer {
94 if (auto ipSub = request->getSubscriber();
95 ipSub && ipSub->getRequest() == request)
96 {
97 return ipSub;
98 }
99 request->doAborting();
100 return nullptr;
101 };
102
103 do
104 {
105 JLOG(mJournal.trace()) << "updateAll looping";
106 for (auto const& wr : requests)
107 {
109 break;
110
111 auto request = wr.lock();
112 bool remove = true;
113 JLOG(mJournal.trace())
114 << "updateAll request " << (request ? "" : "not ") << "found";
115
116 if (request)
117 {
118 auto continueCallback = [&getSubscriber, &request]() {
119 // This callback is used by doUpdate to determine whether to
120 // continue working. If getSubscriber returns null, that
121 // indicates that this request is no longer relevant.
122 return (bool)getSubscriber(request);
123 };
124 if (!request->needsUpdate(
125 newRequests, cache->getLedger()->seq()))
126 remove = false;
127 else
128 {
129 if (auto ipSub = getSubscriber(request))
130 {
131 if (!ipSub->getConsumer().warn())
132 {
133 // Release the shared ptr to the subscriber so that
134 // it can be freed if the client disconnects, and
135 // thus fail to lock later.
136 ipSub.reset();
137 Json::Value update = request->doUpdate(
138 cache, false, continueCallback);
139 request->updateComplete();
140 update[jss::type] = "path_find";
141 if ((ipSub = getSubscriber(request)))
142 {
143 ipSub->send(update, false);
144 remove = false;
145 ++processed;
146 }
147 }
148 }
149 else if (request->hasCompletion())
150 {
151 // One-shot request with completion function
152 request->doUpdate(cache, false);
153 request->updateComplete();
154 ++processed;
155 }
156 }
157 }
158
159 if (remove)
160 {
162
163 // Remove any dangling weak pointers or weak
164 // pointers that refer to this path request.
165 auto ret = std::remove_if(
166 requests_.begin(),
167 requests_.end(),
168 [&removed, &request](auto const& wl) {
169 auto r = wl.lock();
170
171 if (r && r != request)
172 return false;
173 ++removed;
174 return true;
175 });
176
177 requests_.erase(ret, requests_.end());
178 }
179
180 mustBreak =
181 !newRequests && app_.getLedgerMaster().isNewPathRequest();
182
183 // We weren't handling new requests and then
184 // there was a new request
185 if (mustBreak)
186 break;
187 }
188
189 if (mustBreak)
190 { // a new request came in while we were working
191 newRequests = true;
192 }
193 else if (newRequests)
194 { // we only did new requests, so we always need a last pass
195 newRequests = app_.getLedgerMaster().isNewPathRequest();
196 }
197 else
198 { // if there are no new requests, we are done
199 newRequests = app_.getLedgerMaster().isNewPathRequest();
200 if (!newRequests)
201 break;
202 }
203
204 // Hold on to the line cache until after the lock is released, so it can
205 // be destroyed outside of the lock
207 {
208 // Get the latest requests, cache, and ledger for next pass
210
211 if (requests_.empty())
212 break;
213 requests = requests_;
214 lastCache = cache;
215 cache = getLineCache(cache->getLedger(), false);
216 }
217 } while (!app_.getJobQueue().isStopping());
218
219 JLOG(mJournal.debug()) << "updateAll complete: " << processed
220 << " processed and " << removed << " removed";
221}
222
223bool
225{
227 return !requests_.empty();
228}
229
230void
232{
234
235 // Insert after any older unserviced requests but before
236 // any serviced requests
237 auto ret =
238 std::find_if(requests_.begin(), requests_.end(), [](auto const& wl) {
239 auto r = wl.lock();
240
241 // We come before handled requests
242 return r && !r->isNew();
243 });
244
245 requests_.emplace(ret, req);
246}
247
248// Make a new-style path_find request
251 std::shared_ptr<InfoSub> const& subscriber,
252 std::shared_ptr<ReadView const> const& inLedger,
253 Json::Value const& requestJson)
254{
255 auto req = std::make_shared<PathRequest>(
256 app_, subscriber, ++mLastIdentifier, *this, mJournal);
257
258 auto [valid, jvRes] =
259 req->doCreate(getLineCache(inLedger, false), requestJson);
260
261 if (valid)
262 {
263 subscriber->setRequest(req);
266 }
267 return std::move(jvRes);
268}
269
270// Make an old-style ripple_path_find request
274 std::function<void(void)> completion,
275 Resource::Consumer& consumer,
276 std::shared_ptr<ReadView const> const& inLedger,
277 Json::Value const& request)
278{
279 // This assignment must take place before the
280 // completion function is called
281 req = std::make_shared<PathRequest>(
282 app_, completion, consumer, ++mLastIdentifier, *this, mJournal);
283
284 auto [valid, jvRes] = req->doCreate(getLineCache(inLedger, false), request);
285
286 if (!valid)
287 {
288 req.reset();
289 }
290 else
291 {
294 {
295 // The newPathRequest failed. Tell the caller.
296 jvRes = rpcError(rpcTOO_BUSY);
297 req.reset();
298 }
299 }
300
301 return std::move(jvRes);
302}
303
306 Resource::Consumer& consumer,
307 std::shared_ptr<ReadView const> const& inLedger,
308 Json::Value const& request)
309{
310 auto cache = std::make_shared<RippleLineCache>(
311 inLedger, app_.journal("RippleLineCache"));
312
313 auto req = std::make_shared<PathRequest>(
314 app_, [] {}, consumer, ++mLastIdentifier, *this, mJournal);
315
316 auto [valid, jvRes] = req->doCreate(cache, request);
317 if (valid)
318 jvRes = req->doUpdate(cache, false);
319 return std::move(jvRes);
320}
321
322} // namespace ripple
Represents a JSON value.
Definition: json_value.h:148
Stream debug() const
Definition: Journal.h:328
Stream trace() const
Severity stream access functions.
Definition: Journal.h:322
virtual beast::Journal journal(std::string const &name)=0
virtual JobQueue & getJobQueue()=0
virtual LedgerMaster & getLedgerMaster()=0
bool isStopping() const
Definition: JobQueue.h:230
std::unique_ptr< LoadEvent > makeLoadEvent(JobType t, std::string const &name)
Return a scoped LoadEvent.
Definition: JobQueue.cpp:179
beast::Journal mJournal
Definition: PathRequests.h:106
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_
Definition: PathRequests.h:115
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
Definition: PathRequests.h:119
bool requestsPending() const
std::atomic< int > mLastIdentifier
Definition: PathRequests.h:117
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_
Definition: PathRequests.h:112
Application & app_
Definition: PathRequests.h:105
An endpoint that consumes resources.
Definition: Consumer.h:35
T find_if(T... args)
TER valid(PreclaimContext const &ctx, AccountID const &src)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
@ rpcTOO_BUSY
Definition: ErrorCodes.h:56
Json::Value rpcError(int iError)
Definition: RPCErr.cpp:31
@ jtPATH_FIND
Definition: Job.h:84
T remove_if(T... args)
T reset(T... args)
T size(T... args)