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