rippled
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 <ripple/app/ledger/LedgerMaster.h>
21 #include <ripple/app/main/Application.h>
22 #include <ripple/app/paths/PathRequests.h>
23 #include <ripple/basics/Log.h>
24 #include <ripple/core/JobQueue.h>
25 #include <ripple/net/RPCErr.h>
26 #include <ripple/protocol/ErrorCodes.h>
27 #include <ripple/protocol/jss.h>
28 #include <ripple/resource/Fees.h>
29 #include <algorithm>
30 
31 namespace ripple {
32 
38  std::shared_ptr<ReadView const> const& ledger,
39  bool authoritative)
40 {
42 
43  std::uint32_t lineSeq = mLineCache ? mLineCache->getLedger()->seq() : 0;
44  std::uint32_t lgrSeq = ledger->seq();
45 
46  if ((lineSeq == 0) || // no ledger
47  (authoritative && (lgrSeq > lineSeq)) || // newer authoritative ledger
48  (authoritative &&
49  ((lgrSeq + 8) < lineSeq)) || // we jumped way back for some reason
50  (lgrSeq > (lineSeq + 8))) // we jumped way forward for some reason
51  {
52  mLineCache = std::make_shared<RippleLineCache>(ledger);
53  }
54  return mLineCache;
55 }
56 
57 void
59  std::shared_ptr<ReadView const> const& inLedger,
60  Job::CancelCallback shouldCancel)
61 {
62  auto event =
63  app_.getJobQueue().makeLoadEvent(jtPATH_FIND, "PathRequest::updateAll");
64 
67 
68  // Get the ledger and cache we should be using
69  {
71  requests = requests_;
72  cache = getLineCache(inLedger, true);
73  }
74 
75  bool newRequests = app_.getLedgerMaster().isNewPathRequest();
76  bool mustBreak = false;
77 
78  JLOG(mJournal.trace()) << "updateAll seq=" << cache->getLedger()->seq()
79  << ", " << requests.size() << " requests";
80 
81  int processed = 0, removed = 0;
82 
83  do
84  {
85  for (auto const& wr : requests)
86  {
87  if (shouldCancel())
88  break;
89 
90  auto request = wr.lock();
91  bool remove = true;
92 
93  if (request)
94  {
95  if (!request->needsUpdate(
96  newRequests, cache->getLedger()->seq()))
97  remove = false;
98  else
99  {
100  if (auto ipSub = request->getSubscriber())
101  {
102  if (!ipSub->getConsumer().warn())
103  {
104  Json::Value update =
105  request->doUpdate(cache, false);
106  request->updateComplete();
107  update[jss::type] = "path_find";
108  ipSub->send(update, false);
109  remove = false;
110  ++processed;
111  }
112  }
113  else if (request->hasCompletion())
114  {
115  // One-shot request with completion function
116  request->doUpdate(cache, false);
117  request->updateComplete();
118  ++processed;
119  }
120  }
121  }
122 
123  if (remove)
124  {
126 
127  // Remove any dangling weak pointers or weak
128  // pointers that refer to this path request.
129  auto ret = std::remove_if(
130  requests_.begin(),
131  requests_.end(),
132  [&removed, &request](auto const& wl) {
133  auto r = wl.lock();
134 
135  if (r && r != request)
136  return false;
137  ++removed;
138  return true;
139  });
140 
141  requests_.erase(ret, requests_.end());
142  }
143 
144  mustBreak =
145  !newRequests && app_.getLedgerMaster().isNewPathRequest();
146 
147  // We weren't handling new requests and then
148  // there was a new request
149  if (mustBreak)
150  break;
151  }
152 
153  if (mustBreak)
154  { // a new request came in while we were working
155  newRequests = true;
156  }
157  else if (newRequests)
158  { // we only did new requests, so we always need a last pass
159  newRequests = app_.getLedgerMaster().isNewPathRequest();
160  }
161  else
162  { // if there are no new requests, we are done
163  newRequests = app_.getLedgerMaster().isNewPathRequest();
164  if (!newRequests)
165  break;
166  }
167 
168  {
169  // Get the latest requests, cache, and ledger for next pass
171 
172  if (requests_.empty())
173  break;
174  requests = requests_;
175  cache = getLineCache(cache->getLedger(), false);
176  }
177  } while (!shouldCancel());
178 
179  JLOG(mJournal.debug()) << "updateAll complete: " << processed
180  << " processed and " << removed << " removed";
181 }
182 
183 void
185 {
187 
188  // Insert after any older unserviced requests but before
189  // any serviced requests
190  auto ret =
191  std::find_if(requests_.begin(), requests_.end(), [](auto const& wl) {
192  auto r = wl.lock();
193 
194  // We come before handled requests
195  return r && !r->isNew();
196  });
197 
198  requests_.emplace(ret, req);
199 }
200 
201 // Make a new-style path_find request
204  std::shared_ptr<InfoSub> const& subscriber,
205  std::shared_ptr<ReadView const> const& inLedger,
206  Json::Value const& requestJson)
207 {
208  auto req = std::make_shared<PathRequest>(
209  app_, subscriber, ++mLastIdentifier, *this, mJournal);
210 
211  auto [valid, jvRes] =
212  req->doCreate(getLineCache(inLedger, false), requestJson);
213 
214  if (valid)
215  {
216  subscriber->setPathRequest(req);
217  insertPathRequest(req);
219  }
220  return std::move(jvRes);
221 }
222 
223 // Make an old-style ripple_path_find request
227  std::function<void(void)> completion,
228  Resource::Consumer& consumer,
229  std::shared_ptr<ReadView const> const& inLedger,
230  Json::Value const& request)
231 {
232  // This assignment must take place before the
233  // completion function is called
234  req = std::make_shared<PathRequest>(
235  app_, completion, consumer, ++mLastIdentifier, *this, mJournal);
236 
237  auto [valid, jvRes] = req->doCreate(getLineCache(inLedger, false), request);
238 
239  if (!valid)
240  {
241  req.reset();
242  }
243  else
244  {
245  insertPathRequest(req);
247  {
248  // The newPathRequest failed. Tell the caller.
249  jvRes = rpcError(rpcTOO_BUSY);
250  req.reset();
251  }
252  }
253 
254  return std::move(jvRes);
255 }
256 
259  Resource::Consumer& consumer,
260  std::shared_ptr<ReadView const> const& inLedger,
261  Json::Value const& request)
262 {
263  auto cache = std::make_shared<RippleLineCache>(inLedger);
264 
265  auto req = std::make_shared<PathRequest>(
266  app_, [] {}, consumer, ++mLastIdentifier, *this, mJournal);
267 
268  auto [valid, jvRes] = req->doCreate(cache, request);
269  if (valid)
270  jvRes = req->doUpdate(cache, false);
271  return std::move(jvRes);
272 }
273 
274 } // namespace ripple
ripple::PathRequests::doLegacyPathRequest
Json::Value doLegacyPathRequest(Resource::Consumer &consumer, std::shared_ptr< ReadView const > const &inLedger, Json::Value const &request)
Definition: PathRequests.cpp:258
std::shared_ptr
STL class.
ripple::PathRequests::makePathRequest
Json::Value makePathRequest(std::shared_ptr< InfoSub > const &subscriber, std::shared_ptr< ReadView const > const &ledger, Json::Value const &request)
Definition: PathRequests.cpp:203
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:309
ripple::jtPATH_FIND
@ jtPATH_FIND
Definition: Job.h:74
std::vector
STL class.
std::find_if
T find_if(T... args)
std::vector::size
T size(T... args)
ripple::PathRequests::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: PathRequests.cpp:225
std::lock_guard
STL class.
ripple::rpcTOO_BUSY
@ rpcTOO_BUSY
Definition: ErrorCodes.h:56
ripple::LedgerMaster::isNewPathRequest
bool isNewPathRequest()
Definition: LedgerMaster.cpp:1555
std::function
std::shared_ptr::reset
T reset(T... args)
algorithm
ripple::PathRequests::mLastIdentifier
std::atomic< int > mLastIdentifier
Definition: PathRequests.h:117
ripple::PathRequests::app_
Application & app_
Definition: PathRequests.h:105
ripple::Application::getLedgerMaster
virtual LedgerMaster & getLedgerMaster()=0
ripple::PathRequests::insertPathRequest
void insertPathRequest(PathRequest::pointer const &)
Definition: PathRequests.cpp:184
ripple::Application::getJobQueue
virtual JobQueue & getJobQueue()=0
ripple::PathRequests::getLineCache
std::shared_ptr< RippleLineCache > getLineCache(std::shared_ptr< ReadView const > const &ledger, bool authoritative)
Get the current RippleLineCache, updating it if necessary.
Definition: PathRequests.cpp:37
ripple::LedgerMaster::newPathRequest
bool newPathRequest()
Definition: LedgerMaster.cpp:1547
ripple::PathRequests::mJournal
beast::Journal mJournal
Definition: PathRequests.h:106
std::uint32_t
std::remove_if
T remove_if(T... args)
ripple::PathRequests::mLock
std::recursive_mutex mLock
Definition: PathRequests.h:119
ripple::rpcError
Json::Value rpcError(int iError, Json::Value jvResult)
Definition: RPCErr.cpp:29
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::Resource::Consumer
An endpoint that consumes resources.
Definition: Consumer.h:33
ripple::PathRequests::mLineCache
std::shared_ptr< RippleLineCache > mLineCache
Definition: PathRequests.h:115
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
ripple::PathRequests::updateAll
void updateAll(std::shared_ptr< ReadView const > const &ledger, Job::CancelCallback shouldCancel)
Update all of the contained PathRequest instances.
Definition: PathRequests.cpp:58
ripple::JobQueue::makeLoadEvent
std::unique_ptr< LoadEvent > makeLoadEvent(JobType t, std::string const &name)
Return a scoped LoadEvent.
Definition: JobQueue.cpp:166
ripple::PathRequests::requests_
std::vector< PathRequest::wptr > requests_
Definition: PathRequests.h:112
Json::Value
Represents a JSON value.
Definition: json_value.h:145