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 #include <vector>
34 
35 namespace ripple {
36 
38 {
39 private:
42  // measures ledgers per second, constants are important
45 
46 public:
47  // How long before we try again to acquire the same ledger
48  static constexpr std::chrono::minutes const kReacquireInterval{5};
49 
51  Application& app,
52  clock_type& clock,
53  beast::insight::Collector::ptr const& collector,
54  std::unique_ptr<PeerSetBuilder> peerSetBuilder)
55  : app_(app)
56  , fetchRate_(clock.now())
57  , j_(app.journal("InboundLedger"))
58  , m_clock(clock)
59  , mRecentFailures(clock)
60  , mCounter(collector->make_counter("ledger_fetches"))
61  , mPeerSetBuilder(std::move(peerSetBuilder))
62  {
63  }
64 
68  uint256 const& hash,
69  std::uint32_t seq,
70  InboundLedger::Reason reason) override
71  {
72  assert(hash.isNonZero());
73  assert(
74  reason != InboundLedger::Reason::SHARD ||
75  (seq != 0 && app_.getShardStore()));
76 
77  bool isNew = true;
79  {
81  if (stopping_)
82  {
83  return {};
84  }
85  auto it = mLedgers.find(hash);
86  if (it != mLedgers.end())
87  {
88  isNew = false;
89  inbound = it->second;
90  }
91  else
92  {
93  inbound = std::make_shared<InboundLedger>(
94  app_,
95  hash,
96  seq,
97  reason,
99  mPeerSetBuilder->build());
100  mLedgers.emplace(hash, inbound);
101  inbound->init(sl);
102  ++mCounter;
103  }
104  }
105 
106  if (inbound->isFailed())
107  return {};
108 
109  if (!isNew)
110  inbound->update(seq);
111 
112  if (!inbound->isComplete())
113  return {};
114 
115  if (reason == InboundLedger::Reason::HISTORY)
116  {
117  if (inbound->getLedger()->stateMap().family().isShardBacked())
118  app_.getNodeStore().storeLedger(inbound->getLedger());
119  }
120  else if (reason == InboundLedger::Reason::SHARD)
121  {
122  auto shardStore = app_.getShardStore();
123  if (!shardStore)
124  {
125  JLOG(j_.error())
126  << "Acquiring shard with no shard store available";
127  return {};
128  }
129  if (inbound->getLedger()->stateMap().family().isShardBacked())
130  shardStore->setStored(inbound->getLedger());
131  else
132  shardStore->storeLedger(inbound->getLedger());
133  }
134  return inbound->getLedger();
135  }
136 
138  find(uint256 const& hash) override
139  {
140  assert(hash.isNonZero());
141 
143 
144  {
145  ScopedLockType sl(mLock);
146 
147  auto it = mLedgers.find(hash);
148  if (it != mLedgers.end())
149  {
150  ret = it->second;
151  }
152  }
153 
154  return ret;
155  }
156 
157  /*
158  This gets called when
159  "We got some data from an inbound ledger"
160 
161  inboundLedgerTrigger:
162  "What do we do with this partial data?"
163  Figures out what to do with the responses to our requests for information.
164 
165  */
166  // means "We got some data from an inbound ledger"
167 
168  // VFALCO TODO Remove the dependency on the Peer object.
171  bool
173  LedgerHash const& hash,
176  {
177  if (auto ledger = find(hash))
178  {
179  JLOG(j_.trace()) << "Got data (" << packet->nodes().size()
180  << ") for acquiring ledger: " << hash;
181 
182  // Stash the data for later processing and see if we need to
183  // dispatch
184  if (ledger->gotData(std::weak_ptr<Peer>(peer), packet))
186  jtLEDGER_DATA, "processLedgerData", [ledger](Job&) {
187  ledger->runData();
188  });
189 
190  return true;
191  }
192 
193  JLOG(j_.trace()) << "Got data for ledger " << hash
194  << " which we're no longer acquiring";
195 
196  // If it's state node data, stash it because it still might be
197  // useful.
198  if (packet->type() == protocol::liAS_NODE)
199  {
201  jtLEDGER_DATA, "gotStaleData", [this, packet](Job&) {
202  gotStaleData(packet);
203  });
204  }
205 
206  return false;
207  }
208 
209  void
210  logFailure(uint256 const& h, std::uint32_t seq) override
211  {
212  ScopedLockType sl(mLock);
213 
214  mRecentFailures.emplace(h, seq);
215  }
216 
217  bool
218  isFailure(uint256 const& h) override
219  {
220  ScopedLockType sl(mLock);
221 
223  return mRecentFailures.find(h) != mRecentFailures.end();
224  }
225 
232  void
234  {
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  auto const start = m_clock.now();
352 
353  // Make a list of things to sweep, while holding the lock
355  std::size_t total;
356 
357  {
358  ScopedLockType sl(mLock);
359  MapType::iterator it(mLedgers.begin());
360  total = mLedgers.size();
361 
362  stuffToSweep.reserve(total);
363 
364  while (it != mLedgers.end())
365  {
366  auto const la = it->second->getLastAction();
367 
368  if (la > start)
369  {
370  it->second->touch();
371  ++it;
372  }
373  else if ((la + std::chrono::minutes(1)) < start)
374  {
375  stuffToSweep.push_back(it->second);
376  // shouldn't cause the actual final delete
377  // since we are holding a reference in the vector.
378  it = mLedgers.erase(it);
379  }
380  else
381  {
382  ++it;
383  }
384  }
385 
387  }
388 
389  JLOG(j_.debug())
390  << "Swept " << stuffToSweep.size() << " out of " << total
391  << " inbound ledgers. Duration: "
392  << std::chrono::duration_cast<std::chrono::milliseconds>(
393  m_clock.now() - start)
394  .count()
395  << "ms";
396  }
397 
398  void
399  stop() override
400  {
401  ScopedLockType lock(mLock);
402  stopping_ = true;
403  mLedgers.clear();
404  mRecentFailures.clear();
405  }
406 
407 private:
409 
412 
413  bool stopping_ = false;
416 
418 
420 
422 };
423 
424 //------------------------------------------------------------------------------
425 
428  Application& app,
430  beast::insight::Collector::ptr const& collector)
431 {
432  return std::make_unique<InboundLedgersImp>(
433  app, clock, collector, make_PeerSetBuilder(app));
434 }
435 
436 } // namespace ripple
ripple::InboundLedgersImp::getInfo
Json::Value getInfo() override
Definition: InboundLedgers.cpp:290
ripple::Application
Definition: Application.h:115
ripple::InboundLedgersImp::fetchRate_
DecayWindow< 30, clock_type > fetchRate_
Definition: InboundLedgers.cpp:43
ripple::InboundLedger::Reason::HISTORY
@ HISTORY
ripple::Serializer::end
Blob ::iterator end()
Definition: Serializer.h:223
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:516
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:408
ripple::InboundLedgersImp::app_
Application & app_
Definition: InboundLedgers.cpp:40
ripple::Serializer::erase
void erase()
Definition: Serializer.h:209
std::vector::reserve
T reserve(T... args)
vector
std::unordered_map::find
T find(T... args)
std::unordered_map::size
T size(T... args)
ripple::InboundLedgersImp::stop
void stop() override
Definition: InboundLedgers.cpp:399
ripple::InboundLedgersImp::mPeerSetBuilder
std::unique_ptr< PeerSetBuilder > mPeerSetBuilder
Definition: InboundLedgers.cpp:421
ripple::make_InboundLedgers
std::unique_ptr< InboundLedgers > make_InboundLedgers(Application &app, InboundLedgers::clock_type &clock, beast::insight::Collector::ptr const &collector)
Definition: InboundLedgers.cpp:427
ripple::InboundLedgersImp
Definition: InboundLedgers.cpp:37
std::chrono::minutes
ripple::InboundLedgersImp::kReacquireInterval
static constexpr const std::chrono::minutes kReacquireInterval
Definition: InboundLedgers.cpp:48
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::SHAMapTreeNode::makeFromWire
static std::shared_ptr< SHAMapTreeNode > makeFromWire(Slice rawNode)
Definition: SHAMapTreeNode.cpp:116
ripple::InboundLedgersImp::stopping_
bool stopping_
Definition: InboundLedgers.cpp:413
ripple::Serializer::begin
Blob ::iterator begin()
Definition: Serializer.h:218
ripple::jtLEDGER_DATA
@ jtLEDGER_DATA
Definition: Job.h:61
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:44
std::vector::push_back
T push_back(T... args)
ripple::base_uint< 256 >
ripple::InboundLedgersImp::InboundLedgersImp
InboundLedgersImp(Application &app, clock_type &clock, beast::insight::Collector::ptr const &collector, std::unique_ptr< PeerSetBuilder > peerSetBuilder)
Definition: InboundLedgers.cpp:50
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:210
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:67
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:94
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:417
ripple::InboundLedgers
Manages the lifetime of inbound ledgers.
Definition: InboundLedgers.h:33
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:41
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:218
ripple::LedgerMaster::addFetchPack
void addFetchPack(uint256 const &hash, std::shared_ptr< Blob > data)
Definition: LedgerMaster.cpp:2104
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:411
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:233
mutex
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
ripple::InboundLedgersImp::mCounter
beast::insight::Counter mCounter
Definition: InboundLedgers.cpp:419
std::size_t
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:38
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:172
std::unique_ptr
STL class.
ripple::InboundLedger::Reason::SHARD
@ SHARD
std::unordered_map
STL class.
ripple::InboundLedgers::clock_type
beast::abstract_clock< std::chrono::steady_clock > clock_type
Definition: InboundLedgers.h:36
ripple::InboundLedgersImp::mLedgers
MapType mLedgers
Definition: InboundLedgers.cpp:415
ripple::InboundLedgersImp::find
std::shared_ptr< InboundLedger > find(uint256 const &hash) override
Definition: InboundLedgers.cpp:138
std::ref
T ref(T... args)
Json::Value
Represents a JSON value.
Definition: json_value.h:145