rippled
DatabaseShardImp.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2017 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/misc/NetworkOPs.h>
23 #include <ripple/basics/ByteUtilities.h>
24 #include <ripple/basics/chrono.h>
25 #include <ripple/basics/random.h>
26 #include <ripple/core/ConfigSections.h>
27 #include <ripple/nodestore/DummyScheduler.h>
28 #include <ripple/nodestore/impl/DatabaseShardImp.h>
29 #include <ripple/overlay/Overlay.h>
30 #include <ripple/overlay/predicates.h>
31 #include <ripple/protocol/HashPrefix.h>
32 
33 #include <boost/algorithm/string/predicate.hpp>
34 
35 namespace ripple {
36 namespace NodeStore {
37 
39  Application& app,
40  Stoppable& parent,
41  std::string const& name,
42  Scheduler& scheduler,
43  int readThreads,
45  : DatabaseShard(
46  name,
47  parent,
48  scheduler,
49  readThreads,
50  app.config().section(ConfigSection::shardDatabase()),
51  j)
52  , app_(app)
53  , parent_(parent)
54  , taskQueue_(std::make_unique<TaskQueue>(*this))
55  , earliestShardIndex_(seqToShardIndex(earliestLedgerSeq()))
56  , avgShardFileSz_(ledgersPerShard_ * kilobytes(192))
57 {
58 }
59 
61 {
62  onStop();
63 }
64 
65 bool
67 {
68  {
69  std::lock_guard lock(mutex_);
70  if (init_)
71  {
72  JLOG(j_.error()) << "already initialized";
73  return false;
74  }
75 
76  if (!initConfig(lock))
77  {
78  JLOG(j_.error()) << "invalid configuration file settings";
79  return false;
80  }
81 
82  try
83  {
84  using namespace boost::filesystem;
85  if (exists(dir_))
86  {
87  if (!is_directory(dir_))
88  {
89  JLOG(j_.error()) << "'path' must be a directory";
90  return false;
91  }
92  }
93  else
94  create_directories(dir_);
95 
96  ctx_ = std::make_unique<nudb::context>();
97  ctx_->start();
98 
99  // Find shards
100  for (auto const& d : directory_iterator(dir_))
101  {
102  if (!is_directory(d))
103  continue;
104 
105  // Check shard directory name is numeric
106  auto dirName = d.path().stem().string();
107  if (!std::all_of(dirName.begin(), dirName.end(), [](auto c) {
108  return ::isdigit(static_cast<unsigned char>(c));
109  }))
110  {
111  continue;
112  }
113 
114  auto const shardIndex{std::stoul(dirName)};
115  if (shardIndex < earliestShardIndex())
116  {
117  JLOG(j_.error()) << "shard " << shardIndex
118  << " comes before earliest shard index "
119  << earliestShardIndex();
120  return false;
121  }
122 
123  auto const shardDir{dir_ / std::to_string(shardIndex)};
124 
125  // Check if a previous import failed
126  if (is_regular_file(shardDir / importMarker_))
127  {
128  JLOG(j_.warn()) << "shard " << shardIndex
129  << " previously failed import, removing";
130  remove_all(shardDir);
131  continue;
132  }
133 
134  auto shard{
135  std::make_unique<Shard>(app_, *this, shardIndex, j_)};
136  if (!shard->open(scheduler_, *ctx_))
137  {
138  // Remove corrupted or legacy shard
139  shard->removeOnDestroy();
140  JLOG(j_.warn())
141  << "shard " << shardIndex << " removed, "
142  << (shard->isLegacy() ? "legacy" : "corrupted")
143  << " shard";
144  continue;
145  }
146 
147  if (shard->isFinal())
148  {
149  shards_.emplace(
150  shardIndex,
151  ShardInfo(std::move(shard), ShardInfo::State::final));
152  }
153  else if (shard->isBackendComplete())
154  {
155  auto const result{shards_.emplace(
156  shardIndex,
157  ShardInfo(std::move(shard), ShardInfo::State::none))};
159  result.first->second, true, lock, boost::none);
160  }
161  else
162  {
163  if (acquireIndex_ != 0)
164  {
165  JLOG(j_.error())
166  << "more than one shard being acquired";
167  return false;
168  }
169 
170  shards_.emplace(
171  shardIndex,
172  ShardInfo(std::move(shard), ShardInfo::State::acquire));
173  acquireIndex_ = shardIndex;
174  }
175  }
176  }
177  catch (std::exception const& e)
178  {
179  JLOG(j_.error())
180  << "exception " << e.what() << " in function " << __func__;
181  }
182 
183  updateStatus(lock);
185  init_ = true;
186  }
187 
188  setFileStats();
189  return true;
190 }
191 
192 boost::optional<std::uint32_t>
194 {
195  boost::optional<std::uint32_t> shardIndex;
196 
197  {
198  std::lock_guard lock(mutex_);
199  assert(init_);
200 
201  if (acquireIndex_ != 0)
202  {
203  if (auto it{shards_.find(acquireIndex_)}; it != shards_.end())
204  return it->second.shard->prepare();
205  assert(false);
206  return boost::none;
207  }
208 
209  if (!canAdd_)
210  return boost::none;
211 
212  // Check available storage space
214  {
215  JLOG(j_.debug()) << "maximum storage size reached";
216  canAdd_ = false;
217  return boost::none;
218  }
219  if (avgShardFileSz_ > available())
220  {
221  JLOG(j_.error()) << "insufficient storage space available";
222  canAdd_ = false;
223  return boost::none;
224  }
225 
226  shardIndex = findAcquireIndex(validLedgerSeq, lock);
227  }
228 
229  if (!shardIndex)
230  {
231  JLOG(j_.debug()) << "no new shards to add";
232  {
233  std::lock_guard lock(mutex_);
234  canAdd_ = false;
235  }
236  return boost::none;
237  }
238 
239  auto shard{std::make_unique<Shard>(app_, *this, *shardIndex, j_)};
240  if (!shard->open(scheduler_, *ctx_))
241  return boost::none;
242 
243  auto const seq{shard->prepare()};
244  {
245  std::lock_guard lock(mutex_);
246  shards_.emplace(
247  *shardIndex,
248  ShardInfo(std::move(shard), ShardInfo::State::acquire));
249  acquireIndex_ = *shardIndex;
250  }
251  return seq;
252 }
253 
254 bool
256 {
257  auto fail = [j = j_, shardIndex](std::string const& msg) {
258  JLOG(j.error()) << "shard " << shardIndex << " " << msg;
259  return false;
260  };
261  std::lock_guard lock(mutex_);
262  assert(init_);
263 
264  if (!canAdd_)
265  return fail("cannot be stored at this time");
266 
267  if (shardIndex < earliestShardIndex())
268  {
269  return fail(
270  "comes before earliest shard index " +
272  }
273 
274  // If we are synced to the network, check if the shard index
275  // is greater or equal to the current shard.
276  auto seqCheck = [&](std::uint32_t seq) {
277  // seq will be greater than zero if valid
278  if (seq >= earliestLedgerSeq() && shardIndex >= seqToShardIndex(seq))
279  return fail("has an invalid index");
280  return true;
281  };
282  if (!seqCheck(app_.getLedgerMaster().getValidLedgerIndex() + 1) ||
284  {
285  return false;
286  }
287 
288  if (shards_.find(shardIndex) != shards_.end())
289  {
290  JLOG(j_.debug()) << "shard " << shardIndex
291  << " is already stored or queued for import";
292  return false;
293  }
294 
295  // Check available storage space
297  return fail("maximum storage size reached");
298  if (avgShardFileSz_ > available())
299  return fail("insufficient storage space available");
300 
301  shards_.emplace(shardIndex, ShardInfo(nullptr, ShardInfo::State::import));
302  return true;
303 }
304 
305 void
307 {
308  std::lock_guard lock(mutex_);
309  assert(init_);
310 
311  if (auto const it{shards_.find(shardIndex)};
312  it != shards_.end() && it->second.state == ShardInfo::State::import)
313  {
314  shards_.erase(it);
315  }
316 }
317 
320 {
322  {
323  std::lock_guard lock(mutex_);
324  assert(init_);
325 
326  for (auto const& e : shards_)
327  if (e.second.state == ShardInfo::State::import)
328  rs.insert(e.first);
329  }
330 
331  if (rs.empty())
332  return {};
333 
334  return to_string(rs);
335 };
336 
337 bool
339  std::uint32_t shardIndex,
340  boost::filesystem::path const& srcDir)
341 {
342  using namespace boost::filesystem;
343  try
344  {
345  if (!is_directory(srcDir) || is_empty(srcDir))
346  {
347  JLOG(j_.error()) << "invalid source directory " << srcDir.string();
348  return false;
349  }
350  }
351  catch (std::exception const& e)
352  {
353  JLOG(j_.error()) << "exception " << e.what() << " in function "
354  << __func__;
355  return false;
356  }
357 
358  auto expectedHash =
360 
361  if (!expectedHash)
362  {
363  JLOG(j_.error()) << "shard " << shardIndex
364  << " expected hash not found";
365  return false;
366  }
367 
368  auto renameDir = [&](path const& src, path const& dst) {
369  try
370  {
371  rename(src, dst);
372  }
373  catch (std::exception const& e)
374  {
375  JLOG(j_.error())
376  << "exception " << e.what() << " in function " << __func__;
377  return false;
378  }
379  return true;
380  };
381 
382  path dstDir;
383  {
384  std::lock_guard lock(mutex_);
385  assert(init_);
386 
387  // Check shard is prepared
388  if (auto const it{shards_.find(shardIndex)}; it == shards_.end() ||
389  it->second.shard || it->second.state != ShardInfo::State::import)
390  {
391  JLOG(j_.error()) << "shard " << shardIndex << " failed to import";
392  return false;
393  }
394 
395  dstDir = dir_ / std::to_string(shardIndex);
396  }
397 
398  // Rename source directory to the shard database directory
399  if (!renameDir(srcDir, dstDir))
400  return false;
401 
402  // Create the new shard
403  auto shard{std::make_unique<Shard>(app_, *this, shardIndex, j_)};
404  if (!shard->open(scheduler_, *ctx_) || !shard->isBackendComplete())
405  {
406  JLOG(j_.error()) << "shard " << shardIndex << " failed to import";
407  shard.reset();
408  renameDir(dstDir, srcDir);
409  return false;
410  }
411 
412  {
413  std::lock_guard lock(mutex_);
414  auto const it{shards_.find(shardIndex)};
415  if (it == shards_.end() || it->second.shard ||
416  it->second.state != ShardInfo::State::import)
417  {
418  JLOG(j_.error()) << "shard " << shardIndex << " failed to import";
419  shard.reset();
420  renameDir(dstDir, srcDir);
421  return false;
422  }
423 
424  it->second.shard = std::move(shard);
425  finalizeShard(it->second, true, lock, expectedHash);
426  }
427 
428  return true;
429 }
430 
433 {
434  auto const shardIndex{seqToShardIndex(seq)};
435  {
437  ShardInfo::State state;
438  {
439  std::lock_guard lock(mutex_);
440  assert(init_);
441 
442  if (auto const it{shards_.find(shardIndex)}; it != shards_.end())
443  {
444  shard = it->second.shard;
445  state = it->second.state;
446  }
447  else
448  return {};
449  }
450 
451  // Check if the ledger is stored in a final shard
452  // or in the shard being acquired
453  switch (state)
454  {
456  break;
458  if (shard->containsLedger(seq))
459  break;
460  [[fallthrough]];
461  default:
462  return {};
463  }
464  }
465 
466  auto nObj{fetch(hash, seq)};
467  if (!nObj)
468  return {};
469 
470  auto fail = [this, seq](std::string const& msg) -> std::shared_ptr<Ledger> {
471  JLOG(j_.error()) << "shard " << seqToShardIndex(seq) << " " << msg;
472  return {};
473  };
474 
475  auto ledger{std::make_shared<Ledger>(
476  deserializePrefixedHeader(makeSlice(nObj->getData())),
477  app_.config(),
478  *app_.shardFamily())};
479 
480  if (ledger->info().seq != seq)
481  {
482  return fail(
483  "encountered invalid ledger sequence " + std::to_string(seq));
484  }
485  if (ledger->info().hash != hash)
486  {
487  return fail(
488  "encountered invalid ledger hash " + to_string(hash) +
489  " on sequence " + std::to_string(seq));
490  }
491 
492  ledger->setFull();
493  if (!ledger->stateMap().fetchRoot(
494  SHAMapHash{ledger->info().accountHash}, nullptr))
495  {
496  return fail(
497  "is missing root STATE node on hash " + to_string(hash) +
498  " on sequence " + std::to_string(seq));
499  }
500 
501  if (ledger->info().txHash.isNonZero())
502  {
503  if (!ledger->txMap().fetchRoot(
504  SHAMapHash{ledger->info().txHash}, nullptr))
505  {
506  return fail(
507  "is missing root TXN node on hash " + to_string(hash) +
508  " on sequence " + std::to_string(seq));
509  }
510  }
511  return ledger;
512 }
513 
514 void
516 {
517  if (ledger->info().hash.isZero())
518  {
519  JLOG(j_.error()) << "zero ledger hash for ledger sequence "
520  << ledger->info().seq;
521  return;
522  }
523  if (ledger->info().accountHash.isZero())
524  {
525  JLOG(j_.error()) << "zero account hash for ledger sequence "
526  << ledger->info().seq;
527  return;
528  }
529  if (ledger->stateMap().getHash().isNonZero() &&
530  !ledger->stateMap().isValid())
531  {
532  JLOG(j_.error()) << "invalid state map for ledger sequence "
533  << ledger->info().seq;
534  return;
535  }
536  if (ledger->info().txHash.isNonZero() && !ledger->txMap().isValid())
537  {
538  JLOG(j_.error()) << "invalid transaction map for ledger sequence "
539  << ledger->info().seq;
540  return;
541  }
542 
543  auto const shardIndex{seqToShardIndex(ledger->info().seq)};
545  {
546  std::lock_guard lock(mutex_);
547  assert(init_);
548 
549  if (shardIndex != acquireIndex_)
550  {
551  JLOG(j_.trace())
552  << "shard " << shardIndex << " is not being acquired";
553  return;
554  }
555 
556  if (auto const it{shards_.find(shardIndex)}; it != shards_.end())
557  shard = it->second.shard;
558  else
559  {
560  JLOG(j_.error())
561  << "shard " << shardIndex << " is not being acquired";
562  return;
563  }
564  }
565 
566  storeLedgerInShard(shard, ledger);
567 }
568 
571 {
572  std::lock_guard lock(mutex_);
573  assert(init_);
574 
575  return status_;
576 }
577 
578 void
580 {
582  {
583  std::lock_guard lock(mutex_);
584  assert(init_);
585 
586  // Only shards with a state of final should be validated
587  for (auto& e : shards_)
588  if (e.second.state == ShardInfo::State::final)
589  shards.push_back(e.second.shard);
590 
591  if (shards.empty())
592  return;
593 
594  JLOG(j_.debug()) << "Validating shards " << status_;
595  }
596 
597  for (auto const& e : shards)
598  {
599  if (auto shard{e.lock()}; shard)
600  shard->finalize(true, boost::none);
601  }
602 
603  app_.shardFamily()->reset();
604 }
605 
606 void
608 {
609  // Stop read threads in base before data members are destroyed
610  stopThreads();
611 
612  std::lock_guard lock(mutex_);
613  if (shards_.empty())
614  return;
615 
616  // Notify and destroy shards
617  for (auto& e : shards_)
618  {
619  if (e.second.shard)
620  e.second.shard->stop();
621  }
622  shards_.clear();
623 }
624 
625 void
627 {
628  {
629  std::lock_guard lock(mutex_);
630  assert(init_);
631 
632  // Only the application local node store can be imported
633  if (&source != &app_.getNodeStore())
634  {
635  assert(false);
636  JLOG(j_.error()) << "invalid source database";
637  return;
638  }
639 
640  std::uint32_t earliestIndex;
641  std::uint32_t latestIndex;
642  {
643  auto loadLedger = [&](bool ascendSort =
644  true) -> boost::optional<std::uint32_t> {
646  std::uint32_t seq;
647  std::tie(ledger, seq, std::ignore) = loadLedgerHelper(
648  "WHERE LedgerSeq >= " +
650  " order by LedgerSeq " + (ascendSort ? "asc" : "desc") +
651  " limit 1",
652  app_,
653  false);
654  if (!ledger || seq == 0)
655  {
656  JLOG(j_.error()) << "no suitable ledgers were found in"
657  " the SQLite database to import";
658  return boost::none;
659  }
660  return seq;
661  };
662 
663  // Find earliest ledger sequence stored
664  auto seq{loadLedger()};
665  if (!seq)
666  return;
667  earliestIndex = seqToShardIndex(*seq);
668 
669  // Consider only complete shards
670  if (seq != firstLedgerSeq(earliestIndex))
671  ++earliestIndex;
672 
673  // Find last ledger sequence stored
674  seq = loadLedger(false);
675  if (!seq)
676  return;
677  latestIndex = seqToShardIndex(*seq);
678 
679  // Consider only complete shards
680  if (seq != lastLedgerSeq(latestIndex))
681  --latestIndex;
682 
683  if (latestIndex < earliestIndex)
684  {
685  JLOG(j_.error()) << "no suitable ledgers were found in"
686  " the SQLite database to import";
687  return;
688  }
689  }
690 
691  // Import the shards
692  for (std::uint32_t shardIndex = earliestIndex;
693  shardIndex <= latestIndex;
694  ++shardIndex)
695  {
697  {
698  JLOG(j_.error()) << "maximum storage size reached";
699  canAdd_ = false;
700  break;
701  }
702  if (avgShardFileSz_ > available())
703  {
704  JLOG(j_.error()) << "insufficient storage space available";
705  canAdd_ = false;
706  break;
707  }
708 
709  // Skip if already stored
710  if (shardIndex == acquireIndex_ ||
711  shards_.find(shardIndex) != shards_.end())
712  {
713  JLOG(j_.debug()) << "shard " << shardIndex << " already exists";
714  continue;
715  }
716 
717  // Verify SQLite ledgers are in the node store
718  {
719  auto const firstSeq{firstLedgerSeq(shardIndex)};
720  auto const lastSeq{
721  std::max(firstSeq, lastLedgerSeq(shardIndex))};
722  auto const numLedgers{
723  shardIndex == earliestShardIndex() ? lastSeq - firstSeq + 1
724  : ledgersPerShard_};
725  auto ledgerHashes{getHashesByIndex(firstSeq, lastSeq, app_)};
726  if (ledgerHashes.size() != numLedgers)
727  continue;
728 
729  bool valid{true};
730  for (std::uint32_t n = firstSeq; n <= lastSeq; n += 256)
731  {
732  if (!source.fetch(ledgerHashes[n].first, n))
733  {
734  JLOG(j_.warn()) << "SQLite ledger sequence " << n
735  << " mismatches node store";
736  valid = false;
737  break;
738  }
739  }
740  if (!valid)
741  continue;
742  }
743 
744  // Create the new shard
745  app_.shardFamily()->reset();
746  auto shard{std::make_unique<Shard>(app_, *this, shardIndex, j_)};
747  if (!shard->open(scheduler_, *ctx_))
748  continue;
749 
750  // Create a marker file to signify an import in progress
751  auto const shardDir{dir_ / std::to_string(shardIndex)};
752  auto const markerFile{shardDir / importMarker_};
753  {
754  std::ofstream ofs{markerFile.string()};
755  if (!ofs.is_open())
756  {
757  JLOG(j_.error()) << "shard " << shardIndex
758  << " failed to create temp marker file";
759  shard->removeOnDestroy();
760  continue;
761  }
762  ofs.close();
763  }
764 
765  // Copy the ledgers from node store
766  std::shared_ptr<Ledger> recentStored;
767  boost::optional<uint256> lastLedgerHash;
768 
769  while (auto seq = shard->prepare())
770  {
771  auto ledger{loadByIndex(*seq, app_, false)};
772  if (!ledger || ledger->info().seq != seq)
773  break;
774 
776  *ledger,
777  shard->getBackend(),
778  nullptr,
779  nullptr,
780  recentStored))
781  {
782  break;
783  }
784 
785  if (!shard->store(ledger))
786  break;
787 
788  if (!lastLedgerHash && seq == lastLedgerSeq(shardIndex))
789  lastLedgerHash = ledger->info().hash;
790 
791  recentStored = ledger;
792  }
793 
794  using namespace boost::filesystem;
795  if (lastLedgerHash && shard->isBackendComplete())
796  {
797  // Store shard final key
798  Serializer s;
800  s.add32(firstLedgerSeq(shardIndex));
801  s.add32(lastLedgerSeq(shardIndex));
802  s.addBitString(*lastLedgerHash);
803  auto nObj{NodeObject::createObject(
804  hotUNKNOWN, std::move(s.modData()), Shard::finalKey)};
805 
806  try
807  {
808  shard->getBackend()->store(nObj);
809 
810  // The import process is complete and the
811  // marker file is no longer required
812  remove_all(markerFile);
813 
814  JLOG(j_.debug()) << "shard " << shardIndex
815  << " was successfully imported";
816 
817  auto const result{shards_.emplace(
818  shardIndex,
819  ShardInfo(std::move(shard), ShardInfo::State::none))};
821  result.first->second, true, lock, boost::none);
822  }
823  catch (std::exception const& e)
824  {
825  JLOG(j_.error()) << "exception " << e.what()
826  << " in function " << __func__;
827  shard->removeOnDestroy();
828  }
829  }
830  else
831  {
832  JLOG(j_.error())
833  << "shard " << shardIndex << " failed to import";
834  shard->removeOnDestroy();
835  }
836  }
837 
838  updateStatus(lock);
839  }
840 
841  setFileStats();
842 }
843 
846 {
848  {
849  std::lock_guard lock(mutex_);
850  assert(init_);
851 
852  if (auto const it{shards_.find(acquireIndex_)}; it != shards_.end())
853  shard = it->second.shard;
854  else
855  return 0;
856  }
857 
858  return shard->getBackend()->getWriteLoad();
859 }
860 
861 void
863  NodeObjectType type,
864  Blob&& data,
865  uint256 const& hash,
866  std::uint32_t seq)
867 {
868  auto const shardIndex{seqToShardIndex(seq)};
870  {
871  std::lock_guard lock(mutex_);
872  assert(init_);
873 
874  if (shardIndex != acquireIndex_)
875  {
876  JLOG(j_.trace())
877  << "shard " << shardIndex << " is not being acquired";
878  return;
879  }
880 
881  if (auto const it{shards_.find(shardIndex)}; it != shards_.end())
882  shard = it->second.shard;
883  else
884  {
885  JLOG(j_.error())
886  << "shard " << shardIndex << " is not being acquired";
887  return;
888  }
889  }
890 
891  auto [backend, pCache, nCache] = shard->getBackendAll();
892  auto nObj{NodeObject::createObject(type, std::move(data), hash)};
893 
894  pCache->canonicalize_replace_cache(hash, nObj);
895  backend->store(nObj);
896  nCache->erase(hash);
897 
898  storeStats(nObj->getData().size());
899 }
900 
903 {
904  auto cache{getCache(seq)};
905  if (cache.first)
906  return doFetch(hash, seq, *cache.first, *cache.second, false);
907  return {};
908 }
909 
910 bool
912  uint256 const& hash,
913  std::uint32_t seq,
915 {
916  auto cache{getCache(seq)};
917  if (cache.first)
918  {
919  // See if the object is in cache
920  object = cache.first->fetch(hash);
921  if (object || cache.second->touch_if_exists(hash))
922  return true;
923  // Otherwise post a read
924  Database::asyncFetch(hash, seq, cache.first, cache.second);
925  }
926  return false;
927 }
928 
929 bool
931 {
932  auto const seq{srcLedger->info().seq};
933  auto const shardIndex{seqToShardIndex(seq)};
935  {
936  std::lock_guard lock(mutex_);
937  assert(init_);
938 
939  if (shardIndex != acquireIndex_)
940  {
941  JLOG(j_.trace())
942  << "shard " << shardIndex << " is not being acquired";
943  return false;
944  }
945 
946  if (auto const it{shards_.find(shardIndex)}; it != shards_.end())
947  shard = it->second.shard;
948  else
949  {
950  JLOG(j_.error())
951  << "shard " << shardIndex << " is not being acquired";
952  return false;
953  }
954  }
955 
956  if (shard->containsLedger(seq))
957  {
958  JLOG(j_.trace()) << "shard " << shardIndex << " ledger already stored";
959  return false;
960  }
961 
962  {
963  auto [backend, pCache, nCache] = shard->getBackendAll();
965  *srcLedger, backend, pCache, nCache, nullptr))
966  {
967  return false;
968  }
969  }
970 
971  return storeLedgerInShard(shard, srcLedger);
972 }
973 
974 int
976 {
977  auto const shardIndex{seqToShardIndex(seq)};
979  {
980  std::lock_guard lock(mutex_);
981  assert(init_);
982 
983  if (auto const it{shards_.find(shardIndex)}; it != shards_.end() &&
984  (it->second.state == ShardInfo::State::final ||
985  it->second.state == ShardInfo::State::acquire))
986  {
987  shard = it->second.shard;
988  }
989  else
990  return 0;
991  }
992 
993  return shard->pCache()->getTargetSize() / asyncDivider;
994 }
995 
996 float
998 {
1000  {
1001  std::lock_guard lock(mutex_);
1002  assert(init_);
1003 
1004  if (auto const it{shards_.find(acquireIndex_)}; it != shards_.end())
1005  shard = it->second.shard;
1006  else
1007  return 0;
1008  }
1009 
1010  return shard->pCache()->getHitRate();
1011 }
1012 
1013 void
1015 {
1017  {
1018  std::lock_guard lock(mutex_);
1019  assert(init_);
1020 
1021  for (auto const& e : shards_)
1022  if (e.second.state == ShardInfo::State::final ||
1023  e.second.state == ShardInfo::State::acquire)
1024  {
1025  shards.push_back(e.second.shard);
1026  }
1027  }
1028 
1029  for (auto const& e : shards)
1030  {
1031  if (auto shard{e.lock()}; shard)
1032  shard->sweep();
1033  }
1034 }
1035 
1036 bool
1038 {
1039  auto fail = [j = j_](std::string const& msg) {
1040  JLOG(j.error()) << "[" << ConfigSection::shardDatabase() << "] " << msg;
1041  return false;
1042  };
1043 
1044  Config const& config{app_.config()};
1045  Section const& section{config.section(ConfigSection::shardDatabase())};
1046 
1047  {
1048  // The earliest ledger sequence defaults to XRP_LEDGER_EARLIEST_SEQ.
1049  // A custom earliest ledger sequence can be set through the
1050  // configuration file using the 'earliest_seq' field under the
1051  // 'node_db' and 'shard_db' stanzas. If specified, this field must
1052  // have a value greater than zero and be equally assigned in
1053  // both stanzas.
1054 
1055  std::uint32_t shardDBEarliestSeq{0};
1056  get_if_exists<std::uint32_t>(
1057  section, "earliest_seq", shardDBEarliestSeq);
1058 
1059  std::uint32_t nodeDBEarliestSeq{0};
1060  get_if_exists<std::uint32_t>(
1061  config.section(ConfigSection::nodeDatabase()),
1062  "earliest_seq",
1063  nodeDBEarliestSeq);
1064 
1065  if (shardDBEarliestSeq != nodeDBEarliestSeq)
1066  {
1067  return fail(
1068  "and [" + ConfigSection::nodeDatabase() +
1069  "] define different 'earliest_seq' values");
1070  }
1071  }
1072 
1073  using namespace boost::filesystem;
1074  if (!get_if_exists<path>(section, "path", dir_))
1075  return fail("'path' missing");
1076 
1077  {
1078  std::uint64_t sz;
1079  if (!get_if_exists<std::uint64_t>(section, "max_size_gb", sz))
1080  return fail("'max_size_gb' missing");
1081 
1082  if ((sz << 30) < sz)
1083  return fail("'max_size_gb' overflow");
1084 
1085  // Minimum storage space required (in gigabytes)
1086  if (sz < 10)
1087  return fail("'max_size_gb' must be at least 10");
1088 
1089  // Convert to bytes
1090  maxFileSz_ = sz << 30;
1091  }
1092 
1093  if (section.exists("ledgers_per_shard"))
1094  {
1095  // To be set only in standalone for testing
1096  if (!config.standalone())
1097  return fail("'ledgers_per_shard' only honored in stand alone");
1098 
1099  ledgersPerShard_ = get<std::uint32_t>(section, "ledgers_per_shard");
1100  if (ledgersPerShard_ == 0 || ledgersPerShard_ % 256 != 0)
1101  return fail("'ledgers_per_shard' must be a multiple of 256");
1102 
1105  }
1106 
1107  // NuDB is the default and only supported permanent storage backend
1108  backendName_ = get<std::string>(section, "type", "nudb");
1109  if (!boost::iequals(backendName_, "NuDB"))
1110  return fail("'type' value unsupported");
1111 
1112  return true;
1113 }
1114 
1117 {
1118  auto const shardIndex{seqToShardIndex(seq)};
1119  std::shared_ptr<Shard> shard;
1120  {
1121  std::lock_guard lock(mutex_);
1122  assert(init_);
1123 
1124  if (auto const it{shards_.find(shardIndex)};
1125  it != shards_.end() && it->second.shard)
1126  {
1127  shard = it->second.shard;
1128  }
1129  else
1130  return {};
1131  }
1132 
1133  return fetchInternal(hash, shard->getBackend());
1134 }
1135 
1136 boost::optional<std::uint32_t>
1138  std::uint32_t validLedgerSeq,
1140 {
1141  if (validLedgerSeq < earliestLedgerSeq())
1142  return boost::none;
1143 
1144  auto const maxShardIndex{[this, validLedgerSeq]() {
1145  auto shardIndex{seqToShardIndex(validLedgerSeq)};
1146  if (validLedgerSeq != lastLedgerSeq(shardIndex))
1147  --shardIndex;
1148  return shardIndex;
1149  }()};
1150  auto const maxNumShards{maxShardIndex - earliestShardIndex() + 1};
1151 
1152  // Check if the shard store has all shards
1153  if (shards_.size() >= maxNumShards)
1154  return boost::none;
1155 
1156  if (maxShardIndex < 1024 ||
1157  static_cast<float>(shards_.size()) / maxNumShards > 0.5f)
1158  {
1159  // Small or mostly full index space to sample
1160  // Find the available indexes and select one at random
1162  available.reserve(maxNumShards - shards_.size());
1163 
1164  for (auto shardIndex = earliestShardIndex();
1165  shardIndex <= maxShardIndex;
1166  ++shardIndex)
1167  {
1168  if (shards_.find(shardIndex) == shards_.end())
1169  available.push_back(shardIndex);
1170  }
1171 
1172  if (available.empty())
1173  return boost::none;
1174 
1175  if (available.size() == 1)
1176  return available.front();
1177 
1178  return available[rand_int(
1179  0u, static_cast<std::uint32_t>(available.size() - 1))];
1180  }
1181 
1182  // Large, sparse index space to sample
1183  // Keep choosing indexes at random until an available one is found
1184  // chances of running more than 30 times is less than 1 in a billion
1185  for (int i = 0; i < 40; ++i)
1186  {
1187  auto const shardIndex{rand_int(earliestShardIndex(), maxShardIndex)};
1188  if (shards_.find(shardIndex) == shards_.end())
1189  return shardIndex;
1190  }
1191 
1192  assert(false);
1193  return boost::none;
1194 }
1195 
1196 void
1198  ShardInfo& shardInfo,
1199  bool writeSQLite,
1201  boost::optional<uint256> const& expectedHash)
1202 {
1203  assert(shardInfo.shard);
1204  assert(shardInfo.shard->index() != acquireIndex_);
1205  assert(shardInfo.shard->isBackendComplete());
1206  assert(shardInfo.state != ShardInfo::State::finalize);
1207 
1208  auto const shardIndex{shardInfo.shard->index()};
1209 
1210  shardInfo.state = ShardInfo::State::finalize;
1211  taskQueue_->addTask([this, shardIndex, writeSQLite, expectedHash]() {
1212  if (isStopping())
1213  return;
1214 
1215  std::shared_ptr<Shard> shard;
1216  {
1217  std::lock_guard lock(mutex_);
1218  if (auto const it{shards_.find(shardIndex)}; it != shards_.end())
1219  {
1220  shard = it->second.shard;
1221  }
1222  else
1223  {
1224  JLOG(j_.error()) << "Unable to finalize shard " << shardIndex;
1225  return;
1226  }
1227  }
1228 
1229  if (!shard->finalize(writeSQLite, expectedHash))
1230  {
1231  if (isStopping())
1232  return;
1233 
1234  // Invalid or corrupt shard, remove it
1235  removeFailedShard(shard);
1236  return;
1237  }
1238 
1239  if (isStopping())
1240  return;
1241 
1242  {
1243  std::lock_guard lock(mutex_);
1244  auto const it{shards_.find(shardIndex)};
1245  if (it == shards_.end())
1246  return;
1247  it->second.state = ShardInfo::State::final;
1248  updateStatus(lock);
1249  }
1250 
1251  setFileStats();
1252 
1253  // Update peers with new shard index
1254  if (!app_.config().standalone() &&
1256  {
1257  protocol::TMPeerShardInfo message;
1258  PublicKey const& publicKey{app_.nodeIdentity().first};
1259  message.set_nodepubkey(publicKey.data(), publicKey.size());
1260  message.set_shardindexes(std::to_string(shardIndex));
1261  app_.overlay().foreach(send_always(std::make_shared<Message>(
1262  message, protocol::mtPEER_SHARD_INFO)));
1263  }
1264  });
1265 }
1266 
1267 void
1269 {
1271  {
1272  std::lock_guard lock(mutex_);
1273  assert(init_);
1274 
1275  if (shards_.empty())
1276  return;
1277 
1278  for (auto const& e : shards_)
1279  if (e.second.shard)
1280  shards.push_back(e.second.shard);
1281  }
1282 
1283  std::uint64_t sumSz{0};
1284  std::uint32_t sumFd{0};
1285  std::uint32_t numShards{0};
1286  for (auto const& e : shards)
1287  {
1288  if (auto shard{e.lock()}; shard)
1289  {
1290  auto [sz, fd] = shard->fileInfo();
1291  sumSz += sz;
1292  sumFd += fd;
1293  ++numShards;
1294  }
1295  }
1296 
1297  std::lock_guard lock(mutex_);
1298  fileSz_ = sumSz;
1299  fdRequired_ = sumFd;
1300  avgShardFileSz_ = (numShards == 0 ? fileSz_ : fileSz_ / numShards);
1301 
1302  if (fileSz_ >= maxFileSz_)
1303  {
1304  JLOG(j_.warn()) << "maximum storage size reached";
1305  canAdd_ = false;
1306  }
1307  else if (maxFileSz_ - fileSz_ > available())
1308  {
1309  JLOG(j_.warn())
1310  << "maximum shard store size exceeds available storage space";
1311  }
1312 }
1313 
1314 void
1316 {
1317  if (!shards_.empty())
1318  {
1320  for (auto const& e : shards_)
1321  if (e.second.state == ShardInfo::State::final)
1322  rs.insert(e.second.shard->index());
1323  status_ = to_string(rs);
1324  }
1325  else
1326  status_.clear();
1327 }
1328 
1331 {
1332  auto const shardIndex{seqToShardIndex(seq)};
1333  std::shared_ptr<Shard> shard;
1334  {
1335  std::lock_guard lock(mutex_);
1336  assert(init_);
1337 
1338  if (auto const it{shards_.find(shardIndex)};
1339  it != shards_.end() && it->second.shard)
1340  {
1341  shard = it->second.shard;
1342  }
1343  else
1344  return {};
1345  }
1346 
1347  std::shared_ptr<PCache> pCache;
1348  std::shared_ptr<NCache> nCache;
1349  std::tie(std::ignore, pCache, nCache) = shard->getBackendAll();
1350 
1351  return std::make_pair(pCache, nCache);
1352 }
1353 
1356 {
1357  try
1358  {
1359  return boost::filesystem::space(dir_).available;
1360  }
1361  catch (std::exception const& e)
1362  {
1363  JLOG(j_.error()) << "exception " << e.what() << " in function "
1364  << __func__;
1365  return 0;
1366  }
1367 }
1368 
1369 bool
1371  std::shared_ptr<Shard>& shard,
1372  std::shared_ptr<Ledger const> const& ledger)
1373 {
1374  bool result{true};
1375 
1376  if (!shard->store(ledger))
1377  {
1378  // Invalid or corrupt shard, remove it
1379  removeFailedShard(shard);
1380  result = false;
1381  }
1382  else if (shard->isBackendComplete())
1383  {
1384  std::lock_guard lock(mutex_);
1385 
1386  if (auto const it{shards_.find(shard->index())}; it != shards_.end())
1387  {
1388  if (shard->index() == acquireIndex_)
1389  acquireIndex_ = 0;
1390 
1391  if (it->second.state != ShardInfo::State::finalize)
1392  finalizeShard(it->second, false, lock, boost::none);
1393  }
1394  else
1395  {
1396  JLOG(j_.debug())
1397  << "shard " << shard->index() << " is no longer being acquired";
1398  }
1399  }
1400 
1401  setFileStats();
1402  return result;
1403 }
1404 
1405 void
1407 {
1408  {
1409  std::lock_guard lock(mutex_);
1410 
1411  if (shard->index() == acquireIndex_)
1412  acquireIndex_ = 0;
1413 
1414  if ((shards_.erase(shard->index()) > 0) && shard->isFinal())
1415  updateStatus(lock);
1416  }
1417 
1418  shard->removeOnDestroy();
1419  shard.reset();
1420  setFileStats();
1421 }
1422 
1423 //------------------------------------------------------------------------------
1424 
1427  Application& app,
1428  Stoppable& parent,
1429  Scheduler& scheduler,
1430  int readThreads,
1431  beast::Journal j)
1432 {
1433  // The shard store is optional. Future changes will require it.
1434  Section const& section{
1436  if (section.empty())
1437  return nullptr;
1438 
1439  return std::make_unique<DatabaseShardImp>(
1440  app, parent, "ShardStore", scheduler, readThreads, j);
1441 }
1442 
1443 } // namespace NodeStore
1444 } // namespace ripple
ripple::NodeStore::DatabaseShardImp::ShardInfo::State
State
Definition: DatabaseShardImp.h:178
ripple::NodeStore::make_ShardStore
std::unique_ptr< DatabaseShard > make_ShardStore(Application &app, Stoppable &parent, Scheduler &scheduler, int readThreads, beast::Journal j)
Definition: DatabaseShardImp.cpp:1426
ripple::Section
Holds a collection of configuration values.
Definition: BasicConfig.h:43
ripple::loadLedgerHelper
std::tuple< std::shared_ptr< Ledger >, std::uint32_t, uint256 > loadLedgerHelper(std::string const &sqlSuffix, Application &app, bool acquire)
Definition: Ledger.cpp:1009
ripple::Application
Definition: Application.h:97
ripple::NodeStore::DatabaseShardImp::earliestShardIndex_
std::uint32_t earliestShardIndex_
Definition: DatabaseShardImp.h:237
ripple::NodeStore::DatabaseShardImp::ledgersPerShard_
std::uint32_t ledgersPerShard_
Definition: DatabaseShardImp.h:234
ripple::NodeStore::DatabaseShardImp::finalizeShard
void finalizeShard(ShardInfo &shardInfo, bool writeSQLite, std::lock_guard< std::mutex > &, boost::optional< uint256 > const &expectedHash)
Definition: DatabaseShardImp.cpp:1197
ripple::hotUNKNOWN
@ hotUNKNOWN
Definition: NodeObject.h:33
ripple::NodeStore::DatabaseShardImp::lastLedgerSeq
std::uint32_t lastLedgerSeq(std::uint32_t shardIndex) const override
Calculates the last ledger sequence for a given shard index.
Definition: DatabaseShardImp.h:113
ripple::NodeStore::DatabaseShardImp::earliestShardIndex
std::uint32_t earliestShardIndex() const override
Definition: DatabaseShardImp.h:91
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:194
ripple::NodeStore::DatabaseShardImp::mutex_
std::mutex mutex_
Definition: DatabaseShardImp.h:198
ripple::NodeStore::DatabaseShardImp::prepareLedger
boost::optional< std::uint32_t > prepareLedger(std::uint32_t validLedgerSeq) override
Prepare to store a new ledger in the shard being acquired.
Definition: DatabaseShardImp.cpp:193
ripple::NodeStore::DatabaseShardImp::app_
Application & app_
Definition: DatabaseShardImp.h:196
ripple::NodeStore::DatabaseShardImp::storeLedger
bool storeLedger(std::shared_ptr< Ledger const > const &srcLedger) override
Copies a ledger stored in a different database to this one.
Definition: DatabaseShardImp.cpp:930
ripple::NodeStore::Database
Persistency layer for NodeObject.
Definition: Database.h:53
std::string
STL class.
ripple::NodeStore::DatabaseShardImp::fetch
std::shared_ptr< NodeObject > fetch(uint256 const &hash, std::uint32_t seq) override
Fetch an object.
Definition: DatabaseShardImp.cpp:902
std::shared_ptr
STL class.
ripple::NodeStore::Database::doFetch
std::shared_ptr< NodeObject > doFetch(uint256 const &hash, std::uint32_t seq, TaggedCache< uint256, NodeObject > &pCache, KeyCache< uint256 > &nCache, bool isAsync)
Definition: Database.cpp:184
ripple::loadByIndex
std::shared_ptr< Ledger > loadByIndex(std::uint32_t ledgerIndex, Application &app, bool acquire)
Definition: Ledger.cpp:1101
ripple::NodeStore::DatabaseShardImp::seqToShardIndex
std::uint32_t seqToShardIndex(std::uint32_t seq) const override
Calculates the shard index for a given ledger sequence.
Definition: DatabaseShardImp.h:97
std::exception
STL class.
std::stoul
T stoul(T... args)
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:309
ripple::NodeStore::DatabaseShardImp::removeFailedShard
void removeFailedShard(std::shared_ptr< Shard > shard)
Definition: DatabaseShardImp.cpp:1406
ripple::NodeStore::DatabaseShardImp::ShardInfo::State::none
@ none
ripple::Family::reset
virtual void reset()=0
ripple::Serializer::modData
Blob & modData()
Definition: Serializer.h:176
std::pair
ripple::NodeStore::DatabaseShardImp::getCache
std::pair< std::shared_ptr< PCache >, std::shared_ptr< NCache > > getCache(std::uint32_t seq)
Definition: DatabaseShardImp.cpp:1330
ripple::NodeStore::DatabaseShardImp::removePreShard
void removePreShard(std::uint32_t shardIndex) override
Remove a previously prepared shard index for import.
Definition: DatabaseShardImp.cpp:306
ripple::LedgerMaster::getValidLedgerIndex
LedgerIndex getValidLedgerIndex()
Definition: LedgerMaster.cpp:209
ripple::NodeStore::Database::fdRequired_
int fdRequired_
Definition: Database.h:244
ripple::NodeStore::DatabaseShardImp::fileSz_
std::uint64_t fileSz_
Definition: DatabaseShardImp.h:229
std::vector
STL class.
ripple::ConfigSection::shardDatabase
static std::string shardDatabase()
Definition: ConfigSections.h:38
ripple::NodeObjectType
NodeObjectType
The types of node objects.
Definition: NodeObject.h:32
ripple::NodeObject::createObject
static std::shared_ptr< NodeObject > createObject(NodeObjectType type, Blob &&data, uint256 const &hash)
Create an object from fields.
Definition: NodeObject.cpp:37
ripple::NodeStore::DatabaseShardImp::taskQueue_
std::unique_ptr< TaskQueue > taskQueue_
Definition: DatabaseShardImp.h:205
ripple::NodeStore::DatabaseShardImp::ShardInfo::state
State state
Definition: DatabaseShardImp.h:193
ripple::NodeStore::DatabaseShardImp::setStored
void setStored(std::shared_ptr< Ledger const > const &ledger) override
Notifies the database that the given ledger has been fully acquired and stored.
Definition: DatabaseShardImp.cpp:515
ripple::NodeStore::DatabaseShardImp::ShardInfo::State::acquire
@ acquire
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::NodeStore::DatabaseShardImp::prepareShard
bool prepareShard(std::uint32_t shardIndex) override
Prepare a shard index to be imported into the database.
Definition: DatabaseShardImp.cpp:255
std::lock_guard
STL class.
ripple::kilobytes
constexpr auto kilobytes(T value) noexcept
Definition: ByteUtilities.h:27
ripple::NetworkOPs::getOperatingMode
virtual OperatingMode getOperatingMode() const =0
ripple::NodeStore::DatabaseShardImp::available
std::uint64_t available() const
Definition: DatabaseShardImp.cpp:1355
ripple::NodeStore::DatabaseShardImp::ShardInfo::State::final
@ final
ripple::NodeStore::DatabaseShardImp::asyncFetch
bool asyncFetch(uint256 const &hash, std::uint32_t seq, std::shared_ptr< NodeObject > &object) override
Fetch an object without waiting.
Definition: DatabaseShardImp.cpp:911
std::all_of
T all_of(T... args)
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:41
ripple::NodeStore::Shard::finalKey
static const uint256 finalKey
Definition: Shard.h:158
std::shared_ptr::reset
T reset(T... args)
ripple::SHAMapHash
Definition: SHAMapTreeNode.h:43
ripple::Application::getOPs
virtual NetworkOPs & getOPs()=0
ripple::NodeStore::DatabaseShardImp::sweep
void sweep() override
Remove expired entries from the positive and negative caches.
Definition: DatabaseShardImp.cpp:1014
std::string::clear
T clear(T... args)
ripple::NodeStore::DatabaseShardImp::ShardInfo::State::finalize
@ finalize
ripple::send_always
Sends a message to all peers.
Definition: predicates.h:31
ripple::Stoppable::setParent
void setParent(Stoppable &parent)
Set the parent of this Stoppable.
Definition: Stoppable.cpp:43
ripple::deserializePrefixedHeader
LedgerInfo deserializePrefixedHeader(Slice data)
Deserialize a ledger header (prefixed with 4 bytes) from a byte array.
Definition: InboundLedger.cpp:288
ripple::NodeStore::Shard::version
static constexpr std::uint32_t version
Definition: Shard.h:153
std::tie
T tie(T... args)
std::vector::push_back
T push_back(T... args)
ripple::NodeStore::DatabaseShardImp::getDesiredAsyncReadCount
int getDesiredAsyncReadCount(std::uint32_t seq) override
Get the maximum number of async reads the node store prefers.
Definition: DatabaseShardImp.cpp:975
ripple::NodeStore::DatabaseShardImp::firstLedgerSeq
std::uint32_t firstLedgerSeq(std::uint32_t shardIndex) const override
Calculates the first ledger sequence for a given shard index.
Definition: DatabaseShardImp.h:104
ripple::NodeStore::DatabaseShardImp::getCacheHitRate
float getCacheHitRate() override
Get the positive cache hits to total attempts ratio.
Definition: DatabaseShardImp.cpp:997
ripple::NodeStore::DatabaseShardImp::avgShardFileSz_
std::uint64_t avgShardFileSz_
Definition: DatabaseShardImp.h:240
ripple::base_uint< 256 >
ripple::NodeStore::DatabaseShardImp::status_
std::string status_
Definition: DatabaseShardImp.h:220
ripple::NodeStore::DatabaseShardImp::fetchFrom
std::shared_ptr< NodeObject > fetchFrom(uint256 const &hash, std::uint32_t seq) override
Definition: DatabaseShardImp.cpp:1116
ripple::NodeStore::DatabaseShardImp::getPreShards
std::string getPreShards() override
Get shard indexes being imported.
Definition: DatabaseShardImp.cpp:319
ripple::NodeStore::DatabaseShardImp::getWriteLoad
std::int32_t getWriteLoad() const override
Retrieve the estimated number of pending write operations.
Definition: DatabaseShardImp.cpp:845
ripple::NodeStore::DatabaseShardImp::maxFileSz_
std::uint64_t maxFileSz_
Definition: DatabaseShardImp.h:226
ripple::NodeStore::TaskQueue
Definition: TaskQueue.h:32
ripple::OperatingMode::DISCONNECTED
@ DISCONNECTED
not ready to process requests
ripple::Stoppable
Provides an interface for starting and stopping.
Definition: Stoppable.h:200
ripple::Application::shardFamily
virtual Family * shardFamily()=0
ripple::NodeStore::DatabaseShardImp::ShardInfo::shard
std::shared_ptr< Shard > shard
Definition: DatabaseShardImp.h:192
ripple::rand_int
std::enable_if_t< std::is_integral< Integral >::value &&detail::is_engine< Engine >::value, Integral > rand_int(Engine &engine, Integral min, Integral max)
Return a uniformly distributed random integer.
Definition: ripple/basics/random.h:115
ripple::NodeStore::DatabaseShardImp::initConfig
bool initConfig(std::lock_guard< std::mutex > &)
Definition: DatabaseShardImp.cpp:1037
ripple::NodeStore::DatabaseShardImp::init_
bool init_
Definition: DatabaseShardImp.h:199
ripple::NodeStore::DatabaseShardImp::getCompleteShards
std::string getCompleteShards() override
Query which complete shards are stored.
Definition: DatabaseShardImp.cpp:570
ripple::Application::getLedgerMaster
virtual LedgerMaster & getLedgerMaster()=0
ripple::PublicKey
A public key.
Definition: PublicKey.h:59
ripple::Config
Definition: Config.h:66
ripple::NodeStore::DatabaseShardImp::shards_
std::map< std::uint32_t, ShardInfo > shards_
Definition: DatabaseShardImp.h:208
std::ofstream
STL class.
ripple::NodeStore::Database::fetch
virtual std::shared_ptr< NodeObject > fetch(uint256 const &hash, std::uint32_t seq)=0
Fetch an object.
ripple::NodeStore::DatabaseShardImp::~DatabaseShardImp
~DatabaseShardImp() override
Definition: DatabaseShardImp.cpp:60
ripple::Application::config
virtual Config & config()=0
ripple::NodeStore::DatabaseShardImp::dir_
boost::filesystem::path dir_
Definition: DatabaseShardImp.h:214
ripple::NodeStore::DatabaseShardImp::updateStatus
void updateStatus(std::lock_guard< std::mutex > &)
Definition: DatabaseShardImp.cpp:1315
ripple::Config::standalone
bool standalone() const
Definition: Config.h:218
ripple::NodeStore::seqToShardIndex
constexpr std::uint32_t seqToShardIndex(std::uint32_t seq, std::uint32_t ledgersPerShard=DatabaseShard::ledgersPerShardDefault)
Definition: DatabaseShard.h:190
ripple::Application::nodeIdentity
virtual std::pair< PublicKey, SecretKey > const & nodeIdentity()=0
ripple::NodeStore::DatabaseShard
A collection of historical shards.
Definition: DatabaseShard.h:37
std::to_string
T to_string(T... args)
ripple::NodeStore::DatabaseShardImp::importShard
bool importShard(std::uint32_t shardIndex, boost::filesystem::path const &srcDir) override
Import a shard into the shard database.
Definition: DatabaseShardImp.cpp:338
ripple::NodeStore::Database::storeStats
void storeStats(size_t sz)
Definition: Database.h:250
beast::Journal::error
Stream error() const
Definition: Journal.h:333
ripple::ConfigSection
Definition: ConfigSections.h:28
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
std::uint32_t
ripple::NodeStore::Database::earliestLedgerSeq
std::uint32_t earliestLedgerSeq() const
Definition: Database.h:236
ripple::NodeStore::DatabaseShardImp::setFileStats
void setFileStats()
Definition: DatabaseShardImp.cpp:1268
ripple::NodeStore::DatabaseShardImp::acquireIndex_
std::uint32_t acquireIndex_
Definition: DatabaseShardImp.h:211
ripple::Overlay::foreach
void foreach(Function f) const
Visit every active peer.
Definition: Overlay.h:167
ripple::NodeStore::Scheduler
Scheduling for asynchronous backend activity.
Definition: ripple/nodestore/Scheduler.h:57
ripple::NodeStore::DatabaseShardImp::findAcquireIndex
boost::optional< std::uint32_t > findAcquireIndex(std::uint32_t validLedgerSeq, std::lock_guard< std::mutex > &)
Definition: DatabaseShardImp.cpp:1137
ripple::NodeStore::Database::fetchInternal
std::shared_ptr< NodeObject > fetchInternal(uint256 const &hash, std::shared_ptr< Backend > backend)
Definition: Database.cpp:123
ripple::NodeStore::DatabaseShardImp::init
bool init() override
Initialize the database.
Definition: DatabaseShardImp.cpp:66
ripple::Serializer
Definition: Serializer.h:39
ripple::NodeStore::DatabaseShardImp::store
void store(NodeObjectType type, Blob &&data, uint256 const &hash, std::uint32_t seq) override
Store the object.
Definition: DatabaseShardImp.cpp:862
ripple::NodeStore::DatabaseShardImp::parent_
Stoppable & parent_
Definition: DatabaseShardImp.h:197
ripple::NodeStore::DatabaseShardImp::importMarker_
static constexpr auto importMarker_
Definition: DatabaseShardImp.h:243
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::Serializer::addBitString
int addBitString(base_uint< Bits, Tag > const &v)
Definition: Serializer.h:97
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::NodeStore::DatabaseShardImp::import
void import(Database &source) override
Import the application local node store.
Definition: DatabaseShardImp.cpp:626
ripple::NodeStore::Database::j_
const beast::Journal j_
Definition: Database.h:242
ripple::NodeStore::DatabaseShardImp::fetchLedger
std::shared_ptr< Ledger > fetchLedger(uint256 const &hash, std::uint32_t seq) override
Fetch a ledger from the shard store.
Definition: DatabaseShardImp.cpp:432
ripple::NodeStore::Database::stopThreads
void stopThreads()
Definition: Database.cpp:93
std
STL namespace.
ripple::NodeStore::Database::asyncFetch
virtual bool asyncFetch(uint256 const &hash, std::uint32_t seq, std::shared_ptr< NodeObject > &object)=0
Fetch an object without waiting.
ripple::LedgerMaster::getCurrentLedgerIndex
LedgerIndex getCurrentLedgerIndex()
Definition: LedgerMaster.cpp:203
ripple::Application::overlay
virtual Overlay & overlay()=0
std::vector::empty
T empty(T... args)
ripple::NodeStore::DatabaseShardImp::validate
void validate() override
Verifies shard store data is valid.
Definition: DatabaseShardImp.cpp:579
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
ripple::getHashesByIndex
bool getHashesByIndex(std::uint32_t ledgerIndex, uint256 &ledgerHash, uint256 &parentHash, Application &app)
Definition: Ledger.cpp:1163
ripple::NodeStore::DatabaseShardImp::canAdd_
bool canAdd_
Definition: DatabaseShardImp.h:217
std::make_pair
T make_pair(T... args)
ripple::Serializer::add32
int add32(std::uint32_t i)
Definition: Serializer.cpp:38
ripple::NodeStore::Database::scheduler_
Scheduler & scheduler_
Definition: Database.h:243
ripple::RangeSet
boost::icl::interval_set< T, std::less, ClosedInterval< T > > RangeSet
A set of closed intervals over the domain T.
Definition: RangeSet.h:69
std::max
T max(T... args)
ripple::NodeStore::DatabaseShardImp::DatabaseShardImp
DatabaseShardImp()=delete
std::unique_ptr
STL class.
ripple::LedgerMaster::walkHashBySeq
boost::optional< LedgerHash > walkHashBySeq(std::uint32_t index)
Walk to a ledger's hash using the skip list.
Definition: LedgerMaster.cpp:1550
ripple::NodeStore::DatabaseShardImp::ShardInfo::State::import
@ import
ripple::NodeStore::asyncDivider
@ asyncDivider
Definition: nodestore/impl/Tuning.h:32
ripple::ConfigSection::nodeDatabase
static std::string nodeDatabase()
Definition: ConfigSections.h:33
ripple::NodeStore::DatabaseShardImp::ShardInfo
Definition: DatabaseShardImp.h:176
std::exception::what
T what(T... args)
ripple::NodeStore::DatabaseShardImp::onStop
void onStop() override
Override called when the stop notification is issued.
Definition: DatabaseShardImp.cpp:607
ripple::NodeStore::DatabaseShardImp::ctx_
std::unique_ptr< nudb::context > ctx_
Definition: DatabaseShardImp.h:202
ripple::BasicConfig::section
Section & section(std::string const &name)
Returns the section with the given name.
Definition: BasicConfig.cpp:138
ripple::Stoppable::isStopping
bool isStopping() const
Returns true if the stoppable should stop.
Definition: Stoppable.cpp:54
ripple::NodeStore::DatabaseShardImp::storeLedgerInShard
bool storeLedgerInShard(std::shared_ptr< Shard > &shard, std::shared_ptr< Ledger const > const &ledger)
Definition: DatabaseShardImp.cpp:1370
ripple::NodeStore::DatabaseShardImp::backendName_
std::string backendName_
Definition: DatabaseShardImp.h:223