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 {
60  auto event =
61  app_.getJobQueue().makeLoadEvent(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()) << "updateAll seq=" << cache->getLedger()->seq()
77  << ", " << requests.size() << " requests";
78 
79  int processed = 0, removed = 0;
80 
81  do
82  {
83  for (auto const& wr : requests)
84  {
85  if (app_.getJobQueue().isStopping())
86  break;
87 
88  auto request = wr.lock();
89  bool remove = true;
90 
91  if (request)
92  {
93  if (!request->needsUpdate(
94  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 =
103  request->doUpdate(cache, false);
104  request->updateComplete();
105  update[jss::type] = "path_find";
106  ipSub->send(update, false);
107  remove = false;
108  ++processed;
109  }
110  }
111  else if (request->hasCompletion())
112  {
113  // One-shot request with completion function
114  request->doUpdate(cache, false);
115  request->updateComplete();
116  ++processed;
117  }
118  }
119  }
120 
121  if (remove)
122  {
124 
125  // Remove any dangling weak pointers or weak
126  // pointers that refer to this path request.
127  auto ret = std::remove_if(
128  requests_.begin(),
129  requests_.end(),
130  [&removed, &request](auto const& wl) {
131  auto r = wl.lock();
132 
133  if (r && r != request)
134  return false;
135  ++removed;
136  return true;
137  });
138 
139  requests_.erase(ret, requests_.end());
140  }
141 
142  mustBreak =
143  !newRequests && app_.getLedgerMaster().isNewPathRequest();
144 
145  // We weren't handling new requests and then
146  // there was a new request
147  if (mustBreak)
148  break;
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
169 
170  if (requests_.empty())
171  break;
172  requests = requests_;
173  cache = getLineCache(cache->getLedger(), false);
174  }
175  } while (!app_.getJobQueue().isStopping());
176 
177  JLOG(mJournal.debug()) << "updateAll complete: " << processed
178  << " processed and " << removed << " removed";
179 }
180 
181 void
183 {
185 
186  // Insert after any older unserviced requests but before
187  // any serviced requests
188  auto ret =
189  std::find_if(requests_.begin(), requests_.end(), [](auto const& wl) {
190  auto r = wl.lock();
191 
192  // We come before handled requests
193  return r && !r->isNew();
194  });
195 
196  requests_.emplace(ret, req);
197 }
198 
199 // Make a new-style path_find request
202  std::shared_ptr<InfoSub> const& subscriber,
203  std::shared_ptr<ReadView const> const& inLedger,
204  Json::Value const& requestJson)
205 {
206  auto req = std::make_shared<PathRequest>(
207  app_, subscriber, ++mLastIdentifier, *this, mJournal);
208 
209  auto [valid, jvRes] =
210  req->doCreate(getLineCache(inLedger, false), requestJson);
211 
212  if (valid)
213  {
214  subscriber->setPathRequest(req);
215  insertPathRequest(req);
217  }
218  return std::move(jvRes);
219 }
220 
221 // Make an old-style ripple_path_find request
225  std::function<void(void)> completion,
226  Resource::Consumer& consumer,
227  std::shared_ptr<ReadView const> const& inLedger,
228  Json::Value const& request)
229 {
230  // This assignment must take place before the
231  // completion function is called
232  req = std::make_shared<PathRequest>(
233  app_, completion, consumer, ++mLastIdentifier, *this, mJournal);
234 
235  auto [valid, jvRes] = req->doCreate(getLineCache(inLedger, false), request);
236 
237  if (!valid)
238  {
239  req.reset();
240  }
241  else
242  {
243  insertPathRequest(req);
245  {
246  // The newPathRequest failed. Tell the caller.
247  jvRes = rpcError(rpcTOO_BUSY);
248  req.reset();
249  }
250  }
251 
252  return std::move(jvRes);
253 }
254 
257  Resource::Consumer& consumer,
258  std::shared_ptr<ReadView const> const& inLedger,
259  Json::Value const& request)
260 {
261  auto cache = std::make_shared<RippleLineCache>(inLedger);
262 
263  auto req = std::make_shared<PathRequest>(
264  app_, [] {}, consumer, ++mLastIdentifier, *this, mJournal);
265 
266  auto [valid, jvRes] = req->doCreate(cache, request);
267  if (valid)
268  jvRes = req->doUpdate(cache, false);
269  return std::move(jvRes);
270 }
271 
272 } // 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:256
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:201
ripple::rpcError
Json::Value rpcError(int iError)
Definition: RPCErr.cpp:29
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:309
ripple::jtPATH_FIND
@ jtPATH_FIND
Definition: Job.h:83
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:223
std::lock_guard
STL class.
ripple::rpcTOO_BUSY
@ rpcTOO_BUSY
Definition: ErrorCodes.h:56
ripple::LedgerMaster::isNewPathRequest
bool isNewPathRequest()
Definition: LedgerMaster.cpp:1564
std::function
std::shared_ptr::reset
T reset(T... args)
algorithm
ripple::PathRequests::mLastIdentifier
std::atomic< int > mLastIdentifier
Definition: PathRequests.h:114
ripple::PathRequests::app_
Application & app_
Definition: PathRequests.h:102
ripple::Application::getLedgerMaster
virtual LedgerMaster & getLedgerMaster()=0
ripple::PathRequests::insertPathRequest
void insertPathRequest(PathRequest::pointer const &)
Definition: PathRequests.cpp:182
ripple::Application::getJobQueue
virtual JobQueue & getJobQueue()=0
ripple::JobQueue::isStopping
bool isStopping() const
Definition: JobQueue.h:230
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:1556
ripple::PathRequests::mJournal
beast::Journal mJournal
Definition: PathRequests.h:103
std::uint32_t
std::remove_if
T remove_if(T... args)
ripple::PathRequests::mLock
std::recursive_mutex mLock
Definition: PathRequests.h:116
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:34
ripple::PathRequests::updateAll
void updateAll(std::shared_ptr< ReadView const > const &ledger)
Update all of the contained PathRequest instances.
Definition: PathRequests.cpp:58
ripple::PathRequests::mLineCache
std::shared_ptr< RippleLineCache > mLineCache
Definition: PathRequests.h:112
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
ripple::JobQueue::makeLoadEvent
std::unique_ptr< LoadEvent > makeLoadEvent(JobType t, std::string const &name)
Return a scoped LoadEvent.
Definition: JobQueue.cpp:165
ripple::PathRequests::requests_
std::vector< PathRequest::wptr > requests_
Definition: PathRequests.h:109
Json::Value
Represents a JSON value.
Definition: json_value.h:145