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