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