rippled
InboundLedgers.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/InboundLedgers.h>
21 #include <ripple/app/ledger/LedgerMaster.h>
22 #include <ripple/app/main/Application.h>
23 #include <ripple/app/misc/NetworkOPs.h>
24 #include <ripple/basics/DecayingSample.h>
25 #include <ripple/basics/Log.h>
26 #include <ripple/core/JobQueue.h>
27 #include <ripple/nodestore/DatabaseShard.h>
28 #include <ripple/protocol/jss.h>
29 #include <ripple/beast/core/LexicalCast.h>
30 #include <ripple/beast/container/aged_map.h>
31 #include <memory>
32 #include <mutex>
33 
34 namespace ripple {
35 
37  : public InboundLedgers
38  , public Stoppable
39 {
40 private:
43  // measures ledgers per second, constants are important
46 
47 public:
48  using u256_acq_pair = std::pair<
49  uint256,
51 
52  // How long before we try again to acquire the same ledger
54 
56  beast::insight::Collector::ptr const& collector)
57  : Stoppable ("InboundLedgers", parent)
58  , app_ (app)
59  , fetchRate_(clock.now())
60  , j_ (app.journal ("InboundLedger"))
61  , m_clock (clock)
62  , mRecentFailures (clock)
63  , mCounter(collector->make_counter("ledger_fetches"))
64  {
65  }
66 
69  acquire(uint256 const& hash, std::uint32_t seq,
70  InboundLedger::Reason reason) override
71  {
72  assert(hash.isNonZero());
73  assert(reason != InboundLedger::Reason::SHARD ||
74  (seq != 0 && app_.getShardStore()));
75  if (isStopping())
76  return {};
77 
78  bool isNew = true;
80  {
82  auto it = mLedgers.find(hash);
83  if (it != mLedgers.end())
84  {
85  isNew = false;
86  inbound = it->second;
87  }
88  else
89  {
90  inbound = std::make_shared <InboundLedger>(
91  app_, hash, seq, reason, std::ref(m_clock));
92  mLedgers.emplace(hash, inbound);
93  inbound->init(sl);
94  ++mCounter;
95  }
96  }
97 
98  if (inbound->isFailed())
99  return {};
100 
101  if (! isNew)
102  inbound->update(seq);
103 
104  if (! inbound->isComplete())
105  return {};
106 
107  if (reason == InboundLedger::Reason::HISTORY)
108  {
109  if (inbound->getLedger()->stateMap().family().isShardBacked())
110  app_.getNodeStore().storeLedger(inbound->getLedger());
111  }
112  else if (reason == InboundLedger::Reason::SHARD)
113  {
114  auto shardStore = app_.getShardStore();
115  if (!shardStore)
116  {
117  JLOG(j_.error()) <<
118  "Acquiring shard with no shard store available";
119  return {};
120  }
121  if (inbound->getLedger()->stateMap().family().isShardBacked())
122  shardStore->setStored(inbound->getLedger());
123  else
124  shardStore->storeLedger(inbound->getLedger());
125  }
126  return inbound->getLedger();
127  }
128 
130  {
131  assert (hash.isNonZero ());
132 
134 
135  {
136  ScopedLockType sl (mLock);
137 
138  auto it = mLedgers.find (hash);
139  if (it != mLedgers.end ())
140  {
141  ret = it->second;
142  }
143  }
144 
145  return ret;
146  }
147 
148  /*
149  This gets called when
150  "We got some data from an inbound ledger"
151 
152  inboundLedgerTrigger:
153  "What do we do with this partial data?"
154  Figures out what to do with the responses to our requests for information.
155 
156  */
157  // means "We got some data from an inbound ledger"
158 
159  // VFALCO TODO Remove the dependency on the Peer object.
162  bool gotLedgerData (LedgerHash const& hash,
164  std::shared_ptr<protocol::TMLedgerData> packet_ptr) override
165  {
166  protocol::TMLedgerData& packet = *packet_ptr;
167 
168  JLOG (j_.trace())
169  << "Got data (" << packet.nodes ().size ()
170  << ") for acquiring ledger: " << hash;
171 
172  auto ledger = find (hash);
173 
174  if (!ledger)
175  {
176  JLOG (j_.trace())
177  << "Got data for ledger we're no longer acquiring";
178 
179  // If it's state node data, stash it because it still might be
180  // useful.
181  if (packet.type () == protocol::liAS_NODE)
182  {
184  jtLEDGER_DATA, "gotStaleData",
185  [this, packet_ptr] (Job&) { gotStaleData(packet_ptr); });
186  }
187 
188  return false;
189  }
190 
191  // Stash the data for later processing and see if we need to dispatch
192  if (ledger->gotData(std::weak_ptr<Peer>(peer), packet_ptr))
194  jtLEDGER_DATA, "processLedgerData",
195  [this, hash] (Job&) { doLedgerData(hash); });
196 
197  return true;
198  }
199 
200  int getFetchCount (int& timeoutCount) override
201  {
202  timeoutCount = 0;
203  int ret = 0;
204 
205  std::vector<u256_acq_pair> inboundLedgers;
206 
207  {
208  ScopedLockType sl (mLock);
209 
210  inboundLedgers.reserve(mLedgers.size());
211  for (auto const& it : mLedgers)
212  {
213  inboundLedgers.push_back(it);
214  }
215  }
216 
217  for (auto const& it : inboundLedgers)
218  {
219  if (it.second->isActive ())
220  {
221  ++ret;
222  timeoutCount += it.second->getTimeouts ();
223  }
224  }
225  return ret;
226  }
227 
228  void logFailure (uint256 const& h, std::uint32_t seq) override
229  {
230  ScopedLockType sl (mLock);
231 
232  mRecentFailures.emplace(h, seq);
233  }
234 
235  bool isFailure (uint256 const& h) override
236  {
237  ScopedLockType sl (mLock);
238 
240  return mRecentFailures.find (h) != mRecentFailures.end();
241  }
242 
243  void doLedgerData (LedgerHash hash) override
244  {
245  if (auto ledger = find (hash))
246  ledger->runData ();
247  }
248 
256  {
257  const uint256 uZero;
258  Serializer s;
259  try
260  {
261  for (int i = 0; i < packet_ptr->nodes ().size (); ++i)
262  {
263  auto const& node = packet_ptr->nodes (i);
264 
265  if (!node.has_nodeid () || !node.has_nodedata ())
266  return;
267 
268  auto id_string = node.nodeid();
269  auto newNode = SHAMapAbstractNode::make(
270  makeSlice(node.nodedata()),
271  0, snfWIRE, SHAMapHash{uZero}, false, app_.journal ("SHAMapNodeID"),
272  SHAMapNodeID(id_string.data(), id_string.size()));
273 
274  if (!newNode)
275  return;
276 
277  s.erase();
278  newNode->addRaw(s, snfPREFIX);
279 
280  auto blob = std::make_shared<Blob> (s.begin(), s.end());
281 
283  newNode->getNodeHash().as_uint256(), blob);
284  }
285  }
286  catch (std::exception const&)
287  {
288  }
289  }
290 
291  void clearFailures () override
292  {
293  ScopedLockType sl (mLock);
294 
295  mRecentFailures.clear();
296  mLedgers.clear();
297  }
298 
300  {
302  return 60 * fetchRate_.value(
303  m_clock.now());
304  }
305 
306  // Should only be called with an inboundledger that has
307  // a reason of history or shard
308  void onLedgerFetched() override
309  {
311  fetchRate_.add(1, m_clock.now());
312  }
313 
314  Json::Value getInfo() override
315  {
317 
319  {
320  ScopedLockType sl (mLock);
321 
322  acquires.reserve (mLedgers.size ());
323  for (auto const& it : mLedgers)
324  {
325  assert (it.second);
326  acquires.push_back (it);
327  }
328  for (auto const& it : mRecentFailures)
329  {
330  if (it.second > 1)
331  ret[beast::lexicalCastThrow <std::string>(
332  it.second)][jss::failed] = true;
333  else
334  ret[to_string (it.first)][jss::failed] = true;
335  }
336  }
337 
338  for (auto const& it : acquires)
339  {
340  // getJson is expensive, so call without the lock
341  std::uint32_t seq = it.second->getSeq();
342  if (seq > 1)
343  ret[std::to_string(seq)] = it.second->getJson(0);
344  else
345  ret[to_string (it.first)] = it.second->getJson(0);
346  }
347 
348  return ret;
349  }
350 
351  void gotFetchPack () override
352  {
354  {
355  ScopedLockType sl (mLock);
356 
357  acquires.reserve (mLedgers.size ());
358  for (auto const& it : mLedgers)
359  {
360  assert (it.second);
361  acquires.push_back (it.second);
362  }
363  }
364 
365  for (auto const& acquire : acquires)
366  {
367  acquire->checkLocal ();
368  }
369  }
370 
371  void sweep () override
372  {
373  clock_type::time_point const now (m_clock.now());
374 
375  // Make a list of things to sweep, while holding the lock
377  std::size_t total;
378  {
379  ScopedLockType sl (mLock);
380  MapType::iterator it (mLedgers.begin ());
381  total = mLedgers.size ();
382  stuffToSweep.reserve (total);
383 
384  while (it != mLedgers.end ())
385  {
386  if (it->second->getLastAction () > now)
387  {
388  it->second->touch ();
389  ++it;
390  }
391  else if ((it->second->getLastAction () +
392  std::chrono::minutes (1)) < now)
393  {
394  stuffToSweep.push_back (it->second);
395  // shouldn't cause the actual final delete
396  // since we are holding a reference in the vector.
397  it = mLedgers.erase (it);
398  }
399  else
400  {
401  ++it;
402  }
403  }
404 
406 
407  }
408 
409  JLOG (j_.debug()) <<
410  "Swept " << stuffToSweep.size () <<
411  " out of " << total << " inbound ledgers.";
412  }
413 
414  void onStop () override
415  {
416  ScopedLockType lock (mLock);
417 
418  mLedgers.clear();
419  mRecentFailures.clear();
420 
421  stopped();
422  }
423 
424 private:
426 
429 
432 
434 
436 };
437 
438 //------------------------------------------------------------------------------
439 
442 
444 
447  InboundLedgers::clock_type& clock, Stoppable& parent,
448  beast::insight::Collector::ptr const& collector)
449 {
450  return std::make_unique<InboundLedgersImp> (app, clock, parent, collector);
451 }
452 
453 } // ripple
ripple::InboundLedgersImp::getInfo
Json::Value getInfo() override
Definition: InboundLedgers.cpp:314
ripple::InboundLedgersImp::doLedgerData
void doLedgerData(LedgerHash hash) override
Definition: InboundLedgers.cpp:243
ripple::Application
Definition: Application.h:85
ripple::InboundLedgersImp::fetchRate_
DecayWindow< 30, clock_type > fetchRate_
Definition: InboundLedgers.cpp:44
ripple::InboundLedger::Reason::HISTORY
@ HISTORY
ripple::Serializer::end
Blob ::iterator end()
Definition: Serializer.h:222
ripple::makeSlice
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition: Slice.h:199
std::shared_ptr< InboundLedger >
std::exception
STL class.
ripple::base_uint::isNonZero
bool isNonZero() const
Definition: base_uint.h:430
ripple::Stoppable::stopped
void stopped()
Called by derived classes to indicate that the stoppable has stopped.
Definition: Stoppable.cpp:71
beast::insight::Counter
A metric for measuring an integral value.
Definition: Counter.h:38
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:287
ripple::InboundLedgersImp::m_clock
clock_type & m_clock
Definition: InboundLedgers.cpp:425
ripple::SHAMapAbstractNode::make
static std::shared_ptr< SHAMapAbstractNode > make(Slice const &rawNode, std::uint32_t seq, SHANodeFormat format, SHAMapHash const &hash, bool hashValid, beast::Journal j, SHAMapNodeID const &id=SHAMapNodeID{})
Definition: SHAMapTreeNode.cpp:76
ripple::InboundLedgersImp::app_
Application & app_
Definition: InboundLedgers.cpp:41
ripple::Serializer::erase
void erase()
Definition: Serializer.h:211
std::pair
std::vector::reserve
T reserve(T... args)
std::vector
STL class.
std::unordered_map::find
T find(T... args)
std::unordered_map::size
T size(T... args)
ripple::snfPREFIX
@ snfPREFIX
Definition: SHAMapTreeNode.h:37
ripple::InboundLedgersImp
Definition: InboundLedgers.cpp:36
std::chrono::minutes
ripple::DecayWindow< 30, clock_type >
std::unordered_map::emplace
T emplace(T... args)
std::recursive_mutex
STL class.
std::lock_guard
STL class.
ripple::Application::getShardStore
virtual NodeStore::DatabaseShard * getShardStore()=0
ripple::InboundLedgersImp::clearFailures
void clearFailures() override
Definition: InboundLedgers.cpp:291
ripple::JobQueue::addJob
bool addJob(JobType type, std::string const &name, JobHandler &&jobHandler)
Adds a job to the JobQueue.
Definition: JobQueue.h:156
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:41
ripple::SHAMapNodeID
Definition: SHAMapNodeID.h:33
ripple::Serializer::begin
Blob ::iterator begin()
Definition: Serializer.h:218
ripple::SHAMapHash
Definition: SHAMapTreeNode.h:44
ripple::jtLEDGER_DATA
@ jtLEDGER_DATA
Definition: Job.h:48
ripple::make_InboundLedgers
std::unique_ptr< InboundLedgers > make_InboundLedgers(Application &app, InboundLedgers::clock_type &clock, Stoppable &parent, beast::insight::Collector::ptr const &collector)
Definition: InboundLedgers.cpp:446
std::unordered_map::clear
T clear(T... args)
beast::abstract_clock::now
virtual time_point now() const =0
Returns the current time.
ripple::uint256
base_uint< 256 > uint256
Definition: base_uint.h:436
ripple::InboundLedgersImp::fetchRate
std::size_t fetchRate() override
Returns the rate of historical ledger fetches per minute.
Definition: InboundLedgers.cpp:299
ripple::InboundLedgersImp::sweep
void sweep() override
Definition: InboundLedgers.cpp:371
ripple::InboundLedgersImp::j_
const beast::Journal j_
Definition: InboundLedgers.cpp:45
std::vector::push_back
T push_back(T... args)
ripple::InboundLedgers::clock_type
beast::abstract_clock< std::chrono::steady_clock > clock_type
Definition: InboundLedgers.h:37
ripple::base_uint< 256 >
ripple::Stoppable
Provides an interface for starting and stopping.
Definition: Stoppable.h:200
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:45
ripple::InboundLedgersImp::logFailure
void logFailure(uint256 const &h, std::uint32_t seq) override
Definition: InboundLedgers.cpp:228
ripple::Application::getLedgerMaster
virtual LedgerMaster & getLedgerMaster()=0
std::unique_lock
STL class.
ripple::InboundLedgersImp::acquire
std::shared_ptr< Ledger const > acquire(uint256 const &hash, std::uint32_t seq, InboundLedger::Reason reason) override
Definition: InboundLedgers.cpp:69
std::to_string
T to_string(T... args)
ripple::Application::getJobQueue
virtual JobQueue & getJobQueue()=0
beast::Journal::error
Stream error() const
Definition: Journal.h:307
std::unordered_map::erase
T erase(T... args)
ripple::Job
Definition: Job.h:83
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:60
std::uint32_t
ripple::InboundLedgersImp::gotFetchPack
void gotFetchPack() override
Definition: InboundLedgers.cpp:351
beast::abstract_clock< std::chrono::steady_clock >
memory
ripple::InboundLedgersImp::mRecentFailures
beast::aged_map< uint256, std::uint32_t > mRecentFailures
Definition: InboundLedgers.cpp:433
ripple::InboundLedgers
Manages the lifetime of inbound ledgers.
Definition: InboundLedgers.h:34
ripple::InboundLedgersImp::onLedgerFetched
void onLedgerFetched() override
Called when a complete ledger is obtained.
Definition: InboundLedgers.cpp:308
ripple::InboundLedgersImp::fetchRateMutex_
std::mutex fetchRateMutex_
Definition: InboundLedgers.cpp:42
std::weak_ptr
STL class.
ripple::Serializer
Definition: Serializer.h:43
ripple::InboundLedgersImp::gotLedgerData
bool gotLedgerData(LedgerHash const &hash, std::shared_ptr< Peer > peer, std::shared_ptr< protocol::TMLedgerData > packet_ptr) override
We received a TMLedgerData from a peer.
Definition: InboundLedgers.cpp:162
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::DecayWindow::value
double value(time_point now)
Definition: DecayingSample.h:130
ripple::NodeStore::Database::storeLedger
virtual bool storeLedger(std::shared_ptr< Ledger const > const &srcLedger)=0
Copies a ledger stored in a different database to this one.
ripple::Application::getNodeStore
virtual NodeStore::Database & getNodeStore()=0
ripple::Application::journal
virtual beast::Journal journal(std::string const &name)=0
beast::detail::aged_ordered_container
Associative container where each element is also indexed by time.
Definition: aged_ordered_container.h:86
ripple::InboundLedgersImp::isFailure
bool isFailure(uint256 const &h) override
Definition: InboundLedgers.cpp:235
std::unordered_map::begin
T begin(T... args)
ripple::DecayWindow::add
void add(double value, time_point now)
Definition: DecayingSample.h:123
ripple::snfWIRE
@ snfWIRE
Definition: SHAMapTreeNode.h:38
ripple::InboundLedgersImp::mLock
std::recursive_mutex mLock
Definition: InboundLedgers.cpp:428
beast::expire
std::enable_if< is_aged_container< AgedContainer >::value, std::size_t >::type expire(AgedContainer &c, std::chrono::duration< Rep, Period > const &age)
Expire aged container items past the specified age.
Definition: aged_container_utility.h:35
ripple::InboundLedgersImp::gotStaleData
void gotStaleData(std::shared_ptr< protocol::TMLedgerData > packet_ptr) override
We got some data for a ledger we are no longer acquiring Since we paid the price to receive it,...
Definition: InboundLedgers.cpp:255
mutex
beast::Journal::debug
Stream debug() const
Definition: Journal.h:292
ripple::InboundLedgersImp::mCounter
beast::insight::Counter mCounter
Definition: InboundLedgers.cpp:435
std::size_t
std::unordered_map::end
T end(T... args)
ripple::InboundLedger::Reason
Reason
Definition: InboundLedger.h:47
std::unique_ptr
STL class.
ripple::InboundLedger::Reason::SHARD
@ SHARD
std::unordered_map
STL class.
ripple::InboundLedgersImp::getFetchCount
int getFetchCount(int &timeoutCount) override
Definition: InboundLedgers.cpp:200
beast::abstract_clock< std::chrono::steady_clock >::time_point
typename std::chrono::steady_clock ::time_point time_point
Definition: abstract_clock.h:63
ripple::InboundLedgersImp::InboundLedgersImp
InboundLedgersImp(Application &app, clock_type &clock, Stoppable &parent, beast::insight::Collector::ptr const &collector)
Definition: InboundLedgers.cpp:55
ripple::InboundLedgersImp::mLedgers
MapType mLedgers
Definition: InboundLedgers.cpp:431
ripple::InboundLedgersImp::onStop
void onStop() override
Definition: InboundLedgers.cpp:414
ripple::LedgerMaster::addFetchPack
void addFetchPack(uint256 const &hash, std::shared_ptr< Blob > &data)
Definition: LedgerMaster.cpp:1975
ripple::InboundLedgersImp::find
std::shared_ptr< InboundLedger > find(uint256 const &hash) override
Definition: InboundLedgers.cpp:129
std::ref
T ref(T... args)
ripple::InboundLedgersImp::kReacquireInterval
static const std::chrono::minutes kReacquireInterval
Definition: InboundLedgers.cpp:53
Json::Value
Represents a JSON value.
Definition: json_value.h:141
ripple::InboundLedgers::~InboundLedgers
virtual ~InboundLedgers()=0
ripple::Stoppable::isStopping
bool isStopping() const
Returns true if the stoppable should stop.
Definition: Stoppable.cpp:56