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  : Stoppable("InboundLedgers", parent)
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  {
62  }
63 
67  uint256 const& hash,
68  std::uint32_t seq,
69  InboundLedger::Reason reason) override
70  {
71  assert(hash.isNonZero());
72  assert(
73  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  find(uint256 const& hash) override
131  {
132  assert(hash.isNonZero());
133 
135 
136  {
137  ScopedLockType sl(mLock);
138 
139  auto it = mLedgers.find(hash);
140  if (it != mLedgers.end())
141  {
142  ret = it->second;
143  }
144  }
145 
146  return ret;
147  }
148 
149  /*
150  This gets called when
151  "We got some data from an inbound ledger"
152 
153  inboundLedgerTrigger:
154  "What do we do with this partial data?"
155  Figures out what to do with the responses to our requests for information.
156 
157  */
158  // means "We got some data from an inbound ledger"
159 
160  // VFALCO TODO Remove the dependency on the Peer object.
163  bool
165  LedgerHash const& hash,
168  {
169  if (auto ledger = find(hash))
170  {
171  JLOG(j_.trace()) << "Got data (" << packet->nodes().size()
172  << ") for acquiring ledger: " << hash;
173 
174  // Stash the data for later processing and see if we need to
175  // dispatch
176  if (ledger->gotData(std::weak_ptr<Peer>(peer), packet))
178  jtLEDGER_DATA, "processLedgerData", [ledger](Job&) {
179  ledger->runData();
180  });
181 
182  return true;
183  }
184 
185  JLOG(j_.trace()) << "Got data for ledger " << hash
186  << " which we're no longer acquiring";
187 
188  // If it's state node data, stash it because it still might be
189  // useful.
190  if (packet->type() == protocol::liAS_NODE)
191  {
193  jtLEDGER_DATA, "gotStaleData", [this, packet](Job&) {
194  gotStaleData(packet);
195  });
196  }
197 
198  return false;
199  }
200 
201  void
202  logFailure(uint256 const& h, std::uint32_t seq) override
203  {
204  ScopedLockType sl(mLock);
205 
206  mRecentFailures.emplace(h, seq);
207  }
208 
209  bool
210  isFailure(uint256 const& h) override
211  {
212  ScopedLockType sl(mLock);
213 
215  return mRecentFailures.find(h) != mRecentFailures.end();
216  }
217 
224  void
226  {
227  const uint256 uZero;
228  Serializer s;
229  try
230  {
231  for (int i = 0; i < packet_ptr->nodes().size(); ++i)
232  {
233  auto const& node = packet_ptr->nodes(i);
234 
235  if (!node.has_nodeid() || !node.has_nodedata())
236  return;
237 
238  auto newNode =
239  SHAMapTreeNode::makeFromWire(makeSlice(node.nodedata()));
240 
241  if (!newNode)
242  return;
243 
244  s.erase();
245  newNode->serializeWithPrefix(s);
246 
248  newNode->getHash().as_uint256(),
249  std::make_shared<Blob>(s.begin(), s.end()));
250  }
251  }
252  catch (std::exception const&)
253  {
254  }
255  }
256 
257  void
258  clearFailures() override
259  {
260  ScopedLockType sl(mLock);
261 
262  mRecentFailures.clear();
263  mLedgers.clear();
264  }
265 
267  fetchRate() override
268  {
270  return 60 * fetchRate_.value(m_clock.now());
271  }
272 
273  // Should only be called with an inboundledger that has
274  // a reason of history or shard
275  void
276  onLedgerFetched() override
277  {
279  fetchRate_.add(1, m_clock.now());
280  }
281 
283  getInfo() override
284  {
286 
288 
289  {
290  ScopedLockType sl(mLock);
291 
292  acqs.reserve(mLedgers.size());
293  for (auto const& it : mLedgers)
294  {
295  assert(it.second);
296  acqs.push_back(it);
297  }
298  for (auto const& it : mRecentFailures)
299  {
300  if (it.second > 1)
301  ret[std::to_string(it.second)][jss::failed] = true;
302  else
303  ret[to_string(it.first)][jss::failed] = true;
304  }
305  }
306 
307  for (auto const& it : acqs)
308  {
309  // getJson is expensive, so call without the lock
310  std::uint32_t seq = it.second->getSeq();
311  if (seq > 1)
312  ret[std::to_string(seq)] = it.second->getJson(0);
313  else
314  ret[to_string(it.first)] = it.second->getJson(0);
315  }
316 
317  return ret;
318  }
319 
320  void
321  gotFetchPack() override
322  {
324  {
325  ScopedLockType sl(mLock);
326 
327  acquires.reserve(mLedgers.size());
328  for (auto const& it : mLedgers)
329  {
330  assert(it.second);
331  acquires.push_back(it.second);
332  }
333  }
334 
335  for (auto const& acquire : acquires)
336  {
337  acquire->checkLocal();
338  }
339  }
340 
341  void
342  sweep() override
343  {
344  clock_type::time_point const now(m_clock.now());
345 
346  // Make a list of things to sweep, while holding the lock
348  std::size_t total;
349  {
350  ScopedLockType sl(mLock);
351  MapType::iterator it(mLedgers.begin());
352  total = mLedgers.size();
353  stuffToSweep.reserve(total);
354 
355  while (it != mLedgers.end())
356  {
357  if (it->second->getLastAction() > now)
358  {
359  it->second->touch();
360  ++it;
361  }
362  else if (
363  (it->second->getLastAction() + std::chrono::minutes(1)) <
364  now)
365  {
366  stuffToSweep.push_back(it->second);
367  // shouldn't cause the actual final delete
368  // since we are holding a reference in the vector.
369  it = mLedgers.erase(it);
370  }
371  else
372  {
373  ++it;
374  }
375  }
376 
378  }
379 
380  JLOG(j_.debug()) << "Swept " << stuffToSweep.size() << " out of "
381  << total << " inbound ledgers.";
382  }
383 
384  void
385  onStop() override
386  {
387  ScopedLockType lock(mLock);
388 
389  mLedgers.clear();
390  mRecentFailures.clear();
391 
392  stopped();
393  }
394 
395 private:
397 
400 
403 
405 
407 };
408 
409 //------------------------------------------------------------------------------
410 
413  Application& app,
415  Stoppable& parent,
416  beast::insight::Collector::ptr const& collector)
417 {
418  return std::make_unique<InboundLedgersImp>(app, clock, parent, collector);
419 }
420 
421 } // namespace ripple
ripple::InboundLedgersImp::getInfo
Json::Value getInfo() override
Definition: InboundLedgers.cpp:283
ripple::Application
Definition: Application.h:97
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:396
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
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:258
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:42
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:47
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:412
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:267
ripple::InboundLedgersImp::sweep
void sweep() override
Definition: InboundLedgers.cpp:342
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::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:202
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:66
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:82
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:321
beast::abstract_clock< std::chrono::steady_clock >
memory
ripple::InboundLedgersImp::mRecentFailures
beast::aged_map< uint256, std::uint32_t > mRecentFailures
Definition: InboundLedgers.cpp:404
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:276
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:210
ripple::LedgerMaster::addFetchPack
void addFetchPack(uint256 const &hash, std::shared_ptr< Blob > data)
Definition: LedgerMaster.cpp:2006
std::unordered_map::begin
T begin(T... args)
ripple::DecayWindow::add
void add(double value, time_point now)
Definition: DecayingSample.h:122
ripple::InboundLedgersImp::mLock
std::recursive_mutex mLock
Definition: InboundLedgers.cpp:399
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:225
mutex
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
ripple::InboundLedgersImp::mCounter
beast::insight::Counter mCounter
Definition: InboundLedgers.cpp:406
std::size_t
std::unordered_map::end
T end(T... args)
ripple::InboundLedger::Reason
Reason
Definition: InboundLedger.h:45
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:164
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::InboundLedgersImp::InboundLedgersImp
InboundLedgersImp(Application &app, clock_type &clock, Stoppable &parent, beast::insight::Collector::ptr const &collector)
Definition: InboundLedgers.cpp:49
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:402
ripple::InboundLedgersImp::onStop
void onStop() override
Definition: InboundLedgers.cpp:385
ripple::InboundLedgersImp::find
std::shared_ptr< InboundLedger > find(uint256 const &hash) override
Definition: InboundLedgers.cpp:130
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