rippled
Shard.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/InboundLedger.h>
21 #include <ripple/app/main/DBInit.h>
22 #include <ripple/basics/StringUtilities.h>
23 #include <ripple/core/ConfigSections.h>
24 #include <ripple/nodestore/Manager.h>
25 #include <ripple/nodestore/impl/Shard.h>
26 #include <ripple/protocol/digest.h>
27 
28 #include <boost/algorithm/string.hpp>
29 #include <boost/range/adaptor/transformed.hpp>
30 
31 namespace ripple {
32 namespace NodeStore {
33 
34 uint256 const Shard::finalKey{0};
35 
37  Application& app,
38  DatabaseShard const& db,
39  std::uint32_t index,
41  : Shard(app, db, index, "", j)
42 {
43 }
44 
46  Application& app,
47  DatabaseShard const& db,
48  std::uint32_t index,
49  boost::filesystem::path const& dir,
51  : app_(app)
52  , j_(j)
53  , index_(index)
54  , firstSeq_(db.firstLedgerSeq(index))
55  , lastSeq_(std::max(firstSeq_, db.lastLedgerSeq(index)))
56  , maxLedgers_(
57  index == db.earliestShardIndex() ? lastSeq_ - firstSeq_ + 1
58  : db.ledgersPerShard())
59  , dir_((dir.empty() ? db.getRootDir() : dir) / std::to_string(index_))
60 {
61 }
62 
64 {
65  if (!removeOnDestroy_)
66  return;
67 
68  if (backend_)
69  {
70  // Abort removal if the backend is in use
71  if (backendCount_ > 0)
72  {
73  JLOG(j_.error()) << "shard " << index_
74  << " backend in use, unable to remove directory";
75  return;
76  }
77 
78  // Release database files first otherwise remove_all may fail
79  backend_.reset();
80  lgrSQLiteDB_.reset();
81  txSQLiteDB_.reset();
82  acquireInfo_.reset();
83  }
84 
85  try
86  {
87  boost::filesystem::remove_all(dir_);
88  }
89  catch (std::exception const& e)
90  {
91  JLOG(j_.fatal()) << "shard " << index_
92  << ". Exception caught in function " << __func__
93  << ". Error: " << e.what();
94  }
95 }
96 
97 bool
98 Shard::init(Scheduler& scheduler, nudb::context& context)
99 {
101  std::string const type{get<std::string>(section, "type", "nudb")};
102  auto const factory{Manager::instance().find(type)};
103  if (!factory)
104  {
105  JLOG(j_.error()) << "shard " << index_ << " failed to find factory for "
106  << type;
107  return false;
108  }
109  section.set("path", dir_.string());
110 
111  std::lock_guard lock{mutex_};
112  if (backend_)
113  {
114  JLOG(j_.error()) << "shard " << index_ << " already initialized";
115  return false;
116  }
117  backend_ = factory->createInstance(
119  section,
121  scheduler,
122  context,
123  j_);
124 
125  return open(lock);
126 }
127 
128 bool
130 {
131  std::lock_guard lock(mutex_);
132  if (!backend_)
133  {
134  JLOG(j_.error()) << "shard " << index_ << " not initialized";
135  return false;
136  }
137 
138  return backend_->isOpen();
139 }
140 
141 bool
143 {
144  // Keep database open if being acquired or finalized
145  if (state_ != final)
146  return false;
147 
148  std::lock_guard lock(mutex_);
149 
150  // Keep database open if in use
151  if (backendCount_ > 0)
152  return false;
153 
154  if (!backend_)
155  {
156  JLOG(j_.error()) << "shard " << index_ << " not initialized";
157  return false;
158  }
159  if (!backend_->isOpen())
160  return false;
161 
162  try
163  {
164  backend_->close();
165  }
166  catch (std::exception const& e)
167  {
168  JLOG(j_.fatal()) << "shard " << index_
169  << ". Exception caught in function " << __func__
170  << ". Error: " << e.what();
171  return false;
172  }
173 
174  lgrSQLiteDB_.reset();
175  txSQLiteDB_.reset();
176  acquireInfo_.reset();
177 
178  // Reset caches to reduce memory use
181 
182  return true;
183 }
184 
185 boost::optional<std::uint32_t>
187 {
188  if (state_ != acquire)
189  {
190  JLOG(j_.warn()) << "shard " << index_
191  << " prepare called when not acquiring";
192  return boost::none;
193  }
194 
195  std::lock_guard lock(mutex_);
196  if (!acquireInfo_)
197  {
198  JLOG(j_.error()) << "shard " << index_
199  << " missing acquire SQLite database";
200  return boost::none;
201  }
202 
203  if (acquireInfo_->storedSeqs.empty())
204  return lastSeq_;
205  return prevMissing(acquireInfo_->storedSeqs, 1 + lastSeq_, firstSeq_);
206 }
207 
208 bool
210 {
211  if (state_ != acquire)
212  {
213  // The import node store case is an exception
214  if (nodeObject->getHash() != finalKey)
215  {
216  // Ignore residual calls from InboundLedgers
217  JLOG(j_.trace()) << "shard " << index_ << " not acquiring";
218  return false;
219  }
220  }
221 
222  auto const scopedCount{makeBackendCount()};
223  if (!scopedCount)
224  return false;
225 
226  try
227  {
228  backend_->store(nodeObject);
229  }
230  catch (std::exception const& e)
231  {
232  JLOG(j_.fatal()) << "shard " << index_
233  << ". Exception caught in function " << __func__
234  << ". Error: " << e.what();
235  return false;
236  }
237 
238  return true;
239 }
240 
242 Shard::fetchNodeObject(uint256 const& hash, FetchReport& fetchReport)
243 {
244  auto const scopedCount{makeBackendCount()};
245  if (!scopedCount)
246  return nullptr;
247 
248  std::shared_ptr<NodeObject> nodeObject;
249 
250  // Try the backend
251  Status status;
252  try
253  {
254  status = backend_->fetch(hash.data(), &nodeObject);
255  }
256  catch (std::exception const& e)
257  {
258  JLOG(j_.fatal()) << "shard " << index_
259  << ". Exception caught in function " << __func__
260  << ". Error: " << e.what();
261  return nullptr;
262  }
263 
264  switch (status)
265  {
266  case ok:
267  case notFound:
268  break;
269  case dataCorrupt: {
270  JLOG(j_.fatal())
271  << "shard " << index_ << ". Corrupt node object at hash "
272  << to_string(hash);
273  break;
274  }
275  default: {
276  JLOG(j_.warn())
277  << "shard " << index_ << ". Unknown status=" << status
278  << " fetching node object at hash " << to_string(hash);
279  break;
280  }
281  }
282 
283  if (nodeObject)
284  fetchReport.wasFound = true;
285 
286  return nodeObject;
287 }
288 
291  std::shared_ptr<Ledger const> const& srcLedger,
292  std::shared_ptr<Ledger const> const& next)
293 {
294  StoreLedgerResult result;
295  if (state_ != acquire)
296  {
297  // Ignore residual calls from InboundLedgers
298  JLOG(j_.trace()) << "shard " << index_ << ". Not acquiring";
299  return result;
300  }
301  if (containsLedger(srcLedger->info().seq))
302  {
303  JLOG(j_.trace()) << "shard " << index_ << ". Ledger already stored";
304  return result;
305  }
306 
307  auto fail = [&](std::string const& msg) {
308  JLOG(j_.error()) << "shard " << index_ << ". Source ledger sequence "
309  << srcLedger->info().seq << ". " << msg;
310  result.error = true;
311  return result;
312  };
313 
314  if (srcLedger->info().hash.isZero())
315  return fail("Invalid hash");
316  if (srcLedger->info().accountHash.isZero())
317  return fail("Invalid account hash");
318 
319  auto& srcDB{const_cast<Database&>(srcLedger->stateMap().family().db())};
320  if (&srcDB == &(app_.getShardFamily()->db()))
321  return fail("Source and destination databases are the same");
322 
323  auto const scopedCount{makeBackendCount()};
324  if (!scopedCount)
325  return fail("Failed to lock backend");
326 
327  Batch batch;
329  auto storeBatch = [&]() {
330  std::uint64_t sz{0};
331  for (auto const& nodeObject : batch)
332  sz += nodeObject->getData().size();
333 
334  try
335  {
336  backend_->storeBatch(batch);
337  }
338  catch (std::exception const& e)
339  {
340  fail(
341  std::string(". Exception caught in function ") + __func__ +
342  ". Error: " + e.what());
343  return false;
344  }
345 
346  result.count += batch.size();
347  result.size += sz;
348  batch.clear();
349  return true;
350  };
351 
352  // Store ledger header
353  {
354  Serializer s(sizeof(std::uint32_t) + sizeof(LedgerInfo));
356  addRaw(srcLedger->info(), s);
357  auto nodeObject = NodeObject::createObject(
358  hotLEDGER, std::move(s.modData()), srcLedger->info().hash);
359  batch.emplace_back(std::move(nodeObject));
360  }
361 
362  bool error = false;
363  auto visit = [&](SHAMapTreeNode const& node) {
364  if (!stop_)
365  {
366  if (auto nodeObject = srcDB.fetchNodeObject(
367  node.getHash().as_uint256(), srcLedger->info().seq))
368  {
369  batch.emplace_back(std::move(nodeObject));
370  if (batch.size() < batchWritePreallocationSize || storeBatch())
371  return true;
372  }
373  }
374 
375  error = true;
376  return false;
377  };
378 
379  // Store the state map
380  if (srcLedger->stateMap().getHash().isNonZero())
381  {
382  if (!srcLedger->stateMap().isValid())
383  return fail("Invalid state map");
384 
385  if (next && next->info().parentHash == srcLedger->info().hash)
386  {
387  auto have = next->stateMap().snapShot(false);
388  srcLedger->stateMap().snapShot(false)->visitDifferences(
389  &(*have), visit);
390  }
391  else
392  srcLedger->stateMap().snapShot(false)->visitNodes(visit);
393  if (error)
394  return fail("Failed to store state map");
395  }
396 
397  // Store the transaction map
398  if (srcLedger->info().txHash.isNonZero())
399  {
400  if (!srcLedger->txMap().isValid())
401  return fail("Invalid transaction map");
402 
403  srcLedger->txMap().snapShot(false)->visitNodes(visit);
404  if (error)
405  return fail("Failed to store transaction map");
406  }
407 
408  if (!batch.empty() && !storeBatch())
409  return fail("Failed to store");
410 
411  return result;
412 }
413 
414 bool
416 {
417  if (state_ != acquire)
418  {
419  // Ignore residual calls from InboundLedgers
420  JLOG(j_.trace()) << "shard " << index_ << " not acquiring";
421  return false;
422  }
423 
424  auto const ledgerSeq{ledger->info().seq};
425  if (ledgerSeq < firstSeq_ || ledgerSeq > lastSeq_)
426  {
427  JLOG(j_.error()) << "shard " << index_ << " invalid ledger sequence "
428  << ledgerSeq;
429  return false;
430  }
431 
432  std::lock_guard lock(mutex_);
433  if (!acquireInfo_)
434  {
435  JLOG(j_.error()) << "shard " << index_
436  << " missing acquire SQLite database";
437  return false;
438  }
439  if (boost::icl::contains(acquireInfo_->storedSeqs, ledgerSeq))
440  {
441  // Ignore redundant calls
442  JLOG(j_.debug()) << "shard " << index_ << " ledger sequence "
443  << ledgerSeq << " already stored";
444  return true;
445  }
446  // storeSQLite looks at storedSeqs so insert before the call
447  acquireInfo_->storedSeqs.insert(ledgerSeq);
448 
449  if (!storeSQLite(ledger, lock))
450  return false;
451 
452  if (boost::icl::length(acquireInfo_->storedSeqs) >= maxLedgers_)
453  {
454  if (!initSQLite(lock))
455  return false;
456 
457  state_ = complete;
458  }
459 
460  JLOG(j_.debug()) << "shard " << index_ << " stored ledger sequence "
461  << ledgerSeq;
462 
463  setFileStats(lock);
464  return true;
465 }
466 
467 bool
469 {
470  if (ledgerSeq < firstSeq_ || ledgerSeq > lastSeq_)
471  return false;
472  if (state_ != acquire)
473  return true;
474 
475  std::lock_guard lock(mutex_);
476  if (!acquireInfo_)
477  {
478  JLOG(j_.error()) << "shard " << index_
479  << " missing acquire SQLite database";
480  return false;
481  }
482  return boost::icl::contains(acquireInfo_->storedSeqs, ledgerSeq);
483 }
484 
485 void
487 {
488  // nothing to do
489 }
490 
491 std::chrono::steady_clock::time_point
493 {
494  std::lock_guard lock(mutex_);
495  return lastAccess_;
496 }
497 
500 {
501  std::lock_guard lock(mutex_);
502  return {fileSz_, fdRequired_};
503 }
504 
507 {
508  auto const scopedCount{makeBackendCount()};
509  if (!scopedCount)
510  return 0;
511  return backend_->getWriteLoad();
512 }
513 
514 bool
516 {
517  std::lock_guard lock(mutex_);
518  return legacy_;
519 }
520 
521 bool
523  bool const writeSQLite,
524  boost::optional<uint256> const& expectedHash)
525 {
526  uint256 hash{0};
527  std::uint32_t ledgerSeq{0};
528  auto fail =
529  [j = j_, index = index_, &hash, &ledgerSeq](std::string const& msg) {
530  JLOG(j.fatal())
531  << "shard " << index << ". " << msg
532  << (hash.isZero() ? "" : ". Ledger hash " + to_string(hash))
533  << (ledgerSeq == 0
534  ? ""
535  : ". Ledger sequence " + std::to_string(ledgerSeq));
536  return false;
537  };
538 
539  auto const scopedCount{makeBackendCount()};
540  if (!scopedCount)
541  return false;
542 
543  try
544  {
545  state_ = finalizing;
546 
547  /*
548  TODO MP
549  A lock is required when calling the NuDB verify function. Because
550  this can be a time consuming process, the server may desync.
551  Until this function is modified to work on an open database, we
552  are unable to use it from rippled.
553 
554  // Verify backend integrity
555  backend_->verify();
556  */
557 
558  // Check if a final key has been stored
559  if (std::shared_ptr<NodeObject> nodeObject;
560  backend_->fetch(finalKey.data(), &nodeObject) == Status::ok)
561  {
562  // Check final key's value
563  SerialIter sIt(
564  nodeObject->getData().data(), nodeObject->getData().size());
565  if (sIt.get32() != version)
566  return fail("invalid version");
567 
568  if (sIt.get32() != firstSeq_ || sIt.get32() != lastSeq_)
569  return fail("out of range ledger sequences");
570 
571  if (hash = sIt.get256(); hash.isZero())
572  return fail("invalid last ledger hash");
573  }
574  else
575  {
576  // In the absence of a final key, an acquire SQLite database
577  // must be present in order to validate the shard
578  if (!acquireInfo_)
579  return fail("missing acquire SQLite database");
580 
581  auto& session{acquireInfo_->SQLiteDB->getSession()};
582  boost::optional<std::uint32_t> index;
583  boost::optional<std::string> sHash;
584  soci::blob sociBlob(session);
585  soci::indicator blobPresent;
586  session << "SELECT ShardIndex, LastLedgerHash, StoredLedgerSeqs "
587  "FROM Shard "
588  "WHERE ShardIndex = :index;",
589  soci::into(index), soci::into(sHash),
590  soci::into(sociBlob, blobPresent), soci::use(index_);
591 
592  if (!index || index != index_)
593  return fail("missing or invalid ShardIndex");
594 
595  if (!sHash)
596  return fail("missing LastLedgerHash");
597 
598  if (!hash.parseHex(*sHash) || hash.isZero())
599  return fail("invalid LastLedgerHash");
600 
601  if (blobPresent != soci::i_ok)
602  return fail("missing StoredLedgerSeqs");
603 
604  std::string s;
605  convert(sociBlob, s);
606 
607  auto& storedSeqs{acquireInfo_->storedSeqs};
608  if (!from_string(storedSeqs, s) ||
609  boost::icl::first(storedSeqs) != firstSeq_ ||
610  boost::icl::last(storedSeqs) != lastSeq_ ||
611  storedSeqs.size() != maxLedgers_)
612  {
613  return fail("invalid StoredLedgerSeqs");
614  }
615  }
616  }
617  catch (std::exception const& e)
618  {
619  return fail(
620  std::string(". Exception caught in function ") + __func__ +
621  ". Error: " + e.what());
622  }
623 
624  // Validate the last ledger hash of a downloaded shard
625  // using a ledger hash obtained from the peer network
626  if (expectedHash && *expectedHash != hash)
627  return fail("invalid last ledger hash");
628 
629  // Validate every ledger stored in the backend
630  Config const& config{app_.config()};
633  auto const lastLedgerHash{hash};
634  auto& shardFamily{*app_.getShardFamily()};
635  auto const fullBelowCache{shardFamily.getFullBelowCache(lastSeq_)};
636  auto const treeNodeCache{shardFamily.getTreeNodeCache(lastSeq_)};
637 
638  // Reset caches to reduce memory usage
639  fullBelowCache->reset();
640  treeNodeCache->reset();
641 
642  // Start with the last ledger in the shard and walk backwards from
643  // child to parent until we reach the first ledger
644  ledgerSeq = lastSeq_;
645  while (ledgerSeq >= firstSeq_)
646  {
647  if (stop_)
648  return false;
649 
650  auto nodeObject{verifyFetch(hash)};
651  if (!nodeObject)
652  return fail("invalid ledger");
653 
654  ledger = std::make_shared<Ledger>(
655  deserializePrefixedHeader(makeSlice(nodeObject->getData())),
656  config,
657  shardFamily);
658  if (ledger->info().seq != ledgerSeq)
659  return fail("invalid ledger sequence");
660  if (ledger->info().hash != hash)
661  return fail("invalid ledger hash");
662 
663  ledger->stateMap().setLedgerSeq(ledgerSeq);
664  ledger->txMap().setLedgerSeq(ledgerSeq);
665  ledger->setImmutable(config);
666  if (!ledger->stateMap().fetchRoot(
667  SHAMapHash{ledger->info().accountHash}, nullptr))
668  {
669  return fail("missing root STATE node");
670  }
671  if (ledger->info().txHash.isNonZero() &&
672  !ledger->txMap().fetchRoot(
673  SHAMapHash{ledger->info().txHash}, nullptr))
674  {
675  return fail("missing root TXN node");
676  }
677 
678  if (!verifyLedger(ledger, next))
679  return fail("failed to validate ledger");
680 
681  if (writeSQLite)
682  {
683  std::lock_guard lock(mutex_);
684  if (!storeSQLite(ledger, lock))
685  return fail("failed storing to SQLite databases");
686  }
687 
688  hash = ledger->info().parentHash;
689  next = std::move(ledger);
690  --ledgerSeq;
691 
692  fullBelowCache->reset();
693  treeNodeCache->reset();
694  }
695 
696  JLOG(j_.debug()) << "shard " << index_ << " is valid";
697 
698  /*
699  TODO MP
700  SQLite VACUUM blocks all database access while processing.
701  Depending on the file size, that can take a while. Until we find
702  a non-blocking way of doing this, we cannot enable vacuum as
703  it can desync a server.
704 
705  try
706  {
707  // VACUUM the SQLite databases
708  auto const tmpDir {dir_ / "tmp_vacuum"};
709  create_directory(tmpDir);
710 
711  auto vacuum = [&tmpDir](std::unique_ptr<DatabaseCon>& sqliteDB)
712  {
713  auto& session {sqliteDB->getSession()};
714  session << "PRAGMA synchronous=OFF;";
715  session << "PRAGMA journal_mode=OFF;";
716  session << "PRAGMA temp_store_directory='" <<
717  tmpDir.string() << "';";
718  session << "VACUUM;";
719  };
720  vacuum(lgrSQLiteDB_);
721  vacuum(txSQLiteDB_);
722  remove_all(tmpDir);
723  }
724  catch (std::exception const& e)
725  {
726  return fail(
727  std::string(". Exception caught in function ") + __func__ +
728  ". Error: " + e.what());
729  }
730  */
731 
732  // Store final key's value, may already be stored
733  Serializer s;
734  s.add32(version);
735  s.add32(firstSeq_);
736  s.add32(lastSeq_);
737  s.addBitString(lastLedgerHash);
738  auto nodeObject{
740  try
741  {
742  backend_->store(nodeObject);
743 
744  std::lock_guard lock(mutex_);
745 
746  // Remove the acquire SQLite database
747  if (acquireInfo_)
748  {
749  acquireInfo_.reset();
750  remove_all(dir_ / AcquireShardDBName);
751  }
752 
753  if (!initSQLite(lock))
754  return fail("failed to initialize SQLite databases");
755 
756  setFileStats(lock);
758  }
759  catch (std::exception const& e)
760  {
761  return fail(
762  std::string(". Exception caught in function ") + __func__ +
763  ". Error: " + e.what());
764  }
765 
766  state_ = final;
767  return true;
768 }
769 
770 bool
772 {
773  using namespace boost::filesystem;
774  Config const& config{app_.config()};
775  auto preexist{false};
776  auto fail = [this, &preexist](std::string const& msg) {
777  backend_->close();
778  lgrSQLiteDB_.reset();
779  txSQLiteDB_.reset();
780  acquireInfo_.reset();
781 
782  state_ = acquire;
783 
784  if (!preexist)
785  remove_all(dir_);
786 
787  if (!msg.empty())
788  {
789  JLOG(j_.fatal()) << "shard " << index_ << " " << msg;
790  }
791  return false;
792  };
793  auto createAcquireInfo = [this, &config]() {
794  acquireInfo_ = std::make_unique<AcquireInfo>();
795 
796  DatabaseCon::Setup setup;
797  setup.startUp = config.standalone() ? config.LOAD : config.START_UP;
798  setup.standAlone = config.standalone();
799  setup.dataDir = dir_;
800  setup.useGlobalPragma = true;
801 
802  acquireInfo_->SQLiteDB = std::make_unique<DatabaseCon>(
803  setup,
808  state_ = acquire;
809  };
810 
811  try
812  {
813  // Open or create the NuDB key/value store
814  preexist = exists(dir_);
815  backend_->open(!preexist);
816 
817  if (!preexist)
818  {
819  // A new shard
820  createAcquireInfo();
821  acquireInfo_->SQLiteDB->getSession()
822  << "INSERT INTO Shard (ShardIndex) "
823  "VALUES (:shardIndex);",
824  soci::use(index_);
825  }
826  else if (exists(dir_ / AcquireShardDBName))
827  {
828  // A shard being acquired, backend is likely incomplete
829  createAcquireInfo();
830 
831  auto& session{acquireInfo_->SQLiteDB->getSession()};
832  boost::optional<std::uint32_t> index;
833  soci::blob sociBlob(session);
834  soci::indicator blobPresent;
835 
836  session << "SELECT ShardIndex, StoredLedgerSeqs "
837  "FROM Shard "
838  "WHERE ShardIndex = :index;",
839  soci::into(index), soci::into(sociBlob, blobPresent),
840  soci::use(index_);
841 
842  if (!index || index != index_)
843  return fail("invalid acquire SQLite database");
844 
845  if (blobPresent == soci::i_ok)
846  {
847  std::string s;
848  auto& storedSeqs{acquireInfo_->storedSeqs};
849  if (convert(sociBlob, s); !from_string(storedSeqs, s))
850  return fail("invalid StoredLedgerSeqs");
851 
852  if (boost::icl::first(storedSeqs) < firstSeq_ ||
853  boost::icl::last(storedSeqs) > lastSeq_)
854  {
855  return fail("invalid StoredLedgerSeqs");
856  }
857 
858  // Check if backend is complete
859  if (boost::icl::length(storedSeqs) == maxLedgers_)
860  state_ = complete;
861  }
862  }
863  else
864  {
865  // A shard that is final or its backend is complete
866  // and ready to be finalized
867  std::shared_ptr<NodeObject> nodeObject;
868  if (backend_->fetch(finalKey.data(), &nodeObject) != Status::ok)
869  {
870  legacy_ = true;
871  return fail("incompatible, missing backend final key");
872  }
873 
874  // Check final key's value
875  SerialIter sIt(
876  nodeObject->getData().data(), nodeObject->getData().size());
877  if (sIt.get32() != version)
878  return fail("invalid version");
879 
880  if (sIt.get32() != firstSeq_ || sIt.get32() != lastSeq_)
881  return fail("out of range ledger sequences");
882 
883  if (sIt.get256().isZero())
884  return fail("invalid last ledger hash");
885 
886  if (exists(dir_ / LgrDBName) && exists(dir_ / TxDBName))
887  {
889  state_ = final;
890  }
891  else
892  state_ = complete;
893  }
894  }
895  catch (std::exception const& e)
896  {
897  return fail(
898  std::string(". Exception caught in function ") + __func__ +
899  ". Error: " + e.what());
900  }
901 
902  if (!initSQLite(lock))
903  return fail({});
904 
905  setFileStats(lock);
906  return true;
907 }
908 
909 bool
911 {
912  Config const& config{app_.config()};
913  DatabaseCon::Setup const setup = [&]() {
914  DatabaseCon::Setup setup;
915  setup.startUp = config.standalone() ? config.LOAD : config.START_UP;
916  setup.standAlone = config.standalone();
917  setup.dataDir = dir_;
918  setup.useGlobalPragma = (state_ != complete);
919  return setup;
920  }();
921 
922  try
923  {
924  if (lgrSQLiteDB_)
925  lgrSQLiteDB_.reset();
926 
927  if (txSQLiteDB_)
928  txSQLiteDB_.reset();
929 
930  if (state_ != acquire)
931  {
932  lgrSQLiteDB_ = std::make_unique<DatabaseCon>(
934  lgrSQLiteDB_->getSession() << boost::str(
935  boost::format("PRAGMA cache_size=-%d;") %
936  kilobytes(
937  config.getValueFor(SizedItem::lgrDBCache, boost::none)));
938 
939  txSQLiteDB_ = std::make_unique<DatabaseCon>(
941  txSQLiteDB_->getSession() << boost::str(
942  boost::format("PRAGMA cache_size=-%d;") %
943  kilobytes(
944  config.getValueFor(SizedItem::txnDBCache, boost::none)));
945  }
946  else
947  {
948  // The incomplete shard uses a Write Ahead Log for performance
949  lgrSQLiteDB_ = std::make_unique<DatabaseCon>(
950  setup,
951  LgrDBName,
952  LgrDBPragma,
953  LgrDBInit,
955  &app_.getJobQueue(), &app_.logs()});
956  lgrSQLiteDB_->getSession() << boost::str(
957  boost::format("PRAGMA cache_size=-%d;") %
958  kilobytes(config.getValueFor(SizedItem::lgrDBCache)));
959 
960  txSQLiteDB_ = std::make_unique<DatabaseCon>(
961  setup,
962  TxDBName,
963  TxDBPragma,
964  TxDBInit,
966  &app_.getJobQueue(), &app_.logs()});
967  txSQLiteDB_->getSession() << boost::str(
968  boost::format("PRAGMA cache_size=-%d;") %
969  kilobytes(config.getValueFor(SizedItem::txnDBCache)));
970  }
971  }
972  catch (std::exception const& e)
973  {
974  JLOG(j_.fatal()) << "shard " << index_
975  << ". Exception caught in function " << __func__
976  << ". Error: " << e.what();
977  return false;
978  }
979 
980  return true;
981 }
982 
983 bool
985  std::shared_ptr<Ledger const> const& ledger,
987 {
988  if (stop_)
989  return false;
990 
991  auto const ledgerSeq{ledger->info().seq};
992 
993  try
994  {
995  // Update the transactions database
996  {
997  auto& session{txSQLiteDB_->getSession()};
998  soci::transaction tr(session);
999 
1000  session << "DELETE FROM Transactions "
1001  "WHERE LedgerSeq = :seq;",
1002  soci::use(ledgerSeq);
1003  session << "DELETE FROM AccountTransactions "
1004  "WHERE LedgerSeq = :seq;",
1005  soci::use(ledgerSeq);
1006 
1007  if (ledger->info().txHash.isNonZero())
1008  {
1009  auto const sSeq{std::to_string(ledgerSeq)};
1010  if (!ledger->txMap().isValid())
1011  {
1012  JLOG(j_.error()) << "shard " << index_
1013  << " has an invalid transaction map"
1014  << " on sequence " << sSeq;
1015  return false;
1016  }
1017 
1018  for (auto const& item : ledger->txs)
1019  {
1020  if (stop_)
1021  return false;
1022 
1023  auto const txID{item.first->getTransactionID()};
1024  auto const sTxID{to_string(txID)};
1025  auto const txMeta{std::make_shared<TxMeta>(
1026  txID, ledger->seq(), *item.second)};
1027 
1028  session << "DELETE FROM AccountTransactions "
1029  "WHERE TransID = :txID;",
1030  soci::use(sTxID);
1031 
1032  auto const& accounts = txMeta->getAffectedAccounts(j_);
1033  if (!accounts.empty())
1034  {
1035  auto const sTxnSeq{std::to_string(txMeta->getIndex())};
1036  auto const s{boost::str(
1037  boost::format("('%s','%s',%s,%s)") % sTxID % "%s" %
1038  sSeq % sTxnSeq)};
1039  std::string sql;
1040  sql.reserve((accounts.size() + 1) * 128);
1041  sql =
1042  "INSERT INTO AccountTransactions "
1043  "(TransID, Account, LedgerSeq, TxnSeq) VALUES ";
1044  sql += boost::algorithm::join(
1045  accounts |
1046  boost::adaptors::transformed(
1047  [&](AccountID const& accountID) {
1048  return boost::str(
1049  boost::format(s) %
1050  ripple::toBase58(accountID));
1051  }),
1052  ",");
1053  sql += ';';
1054  session << sql;
1055 
1056  JLOG(j_.trace()) << "shard " << index_
1057  << " account transaction: " << sql;
1058  }
1059  else
1060  {
1061  JLOG(j_.warn())
1062  << "shard " << index_ << " transaction in ledger "
1063  << sSeq << " affects no accounts";
1064  }
1065 
1066  Serializer s;
1067  item.second->add(s);
1068  session
1070  item.first->getMetaSQL(
1071  ledgerSeq, sqlBlobLiteral(s.modData())) +
1072  ';');
1073  }
1074  }
1075 
1076  tr.commit();
1077  }
1078 
1079  auto const sHash{to_string(ledger->info().hash)};
1080 
1081  // Update the ledger database
1082  {
1083  auto& session{lgrSQLiteDB_->getSession()};
1084  soci::transaction tr(session);
1085 
1086  auto const sParentHash{to_string(ledger->info().parentHash)};
1087  auto const sDrops{to_string(ledger->info().drops)};
1088  auto const sAccountHash{to_string(ledger->info().accountHash)};
1089  auto const sTxHash{to_string(ledger->info().txHash)};
1090 
1091  session << "DELETE FROM Ledgers "
1092  "WHERE LedgerSeq = :seq;",
1093  soci::use(ledgerSeq);
1094  session
1095  << "INSERT OR REPLACE INTO Ledgers ("
1096  "LedgerHash, LedgerSeq, PrevHash, TotalCoins, ClosingTime,"
1097  "PrevClosingTime, CloseTimeRes, CloseFlags, AccountSetHash,"
1098  "TransSetHash)"
1099  "VALUES ("
1100  ":ledgerHash, :ledgerSeq, :prevHash, :totalCoins,"
1101  ":closingTime, :prevClosingTime, :closeTimeRes,"
1102  ":closeFlags, :accountSetHash, :transSetHash);",
1103  soci::use(sHash), soci::use(ledgerSeq), soci::use(sParentHash),
1104  soci::use(sDrops),
1105  soci::use(ledger->info().closeTime.time_since_epoch().count()),
1106  soci::use(
1107  ledger->info().parentCloseTime.time_since_epoch().count()),
1108  soci::use(ledger->info().closeTimeResolution.count()),
1109  soci::use(ledger->info().closeFlags), soci::use(sAccountHash),
1110  soci::use(sTxHash);
1111 
1112  tr.commit();
1113  }
1114 
1115  // Update the acquire database if present
1116  if (acquireInfo_)
1117  {
1118  auto& session{acquireInfo_->SQLiteDB->getSession()};
1119  soci::blob sociBlob(session);
1120 
1121  if (!acquireInfo_->storedSeqs.empty())
1122  convert(to_string(acquireInfo_->storedSeqs), sociBlob);
1123 
1124  if (ledger->info().seq == lastSeq_)
1125  {
1126  // Store shard's last ledger hash
1127  session << "UPDATE Shard "
1128  "SET LastLedgerHash = :lastLedgerHash,"
1129  "StoredLedgerSeqs = :storedLedgerSeqs "
1130  "WHERE ShardIndex = :shardIndex;",
1131  soci::use(sHash), soci::use(sociBlob), soci::use(index_);
1132  }
1133  else
1134  {
1135  session << "UPDATE Shard "
1136  "SET StoredLedgerSeqs = :storedLedgerSeqs "
1137  "WHERE ShardIndex = :shardIndex;",
1138  soci::use(sociBlob), soci::use(index_);
1139  }
1140  }
1141  }
1142  catch (std::exception const& e)
1143  {
1144  JLOG(j_.fatal()) << "shard " << index_
1145  << ". Exception caught in function " << __func__
1146  << ". Error: " << e.what();
1147  return false;
1148  }
1149 
1150  return true;
1151 }
1152 
1153 void
1155 {
1156  fileSz_ = 0;
1157  fdRequired_ = 0;
1158  try
1159  {
1160  using namespace boost::filesystem;
1161  for (auto const& d : directory_iterator(dir_))
1162  {
1163  if (is_regular_file(d))
1164  {
1165  fileSz_ += file_size(d);
1166  ++fdRequired_;
1167  }
1168  }
1169  }
1170  catch (std::exception const& e)
1171  {
1172  JLOG(j_.fatal()) << "shard " << index_
1173  << ". Exception caught in function " << __func__
1174  << ". Error: " << e.what();
1175  }
1176 }
1177 
1178 bool
1180  std::shared_ptr<Ledger const> const& ledger,
1181  std::shared_ptr<Ledger const> const& next) const
1182 {
1183  auto fail = [j = j_, index = index_, &ledger](std::string const& msg) {
1184  JLOG(j.error()) << "shard " << index << ". " << msg
1185  << (ledger->info().hash.isZero() ? ""
1186  : ". Ledger hash " +
1187  to_string(ledger->info().hash))
1188  << (ledger->info().seq == 0 ? ""
1189  : ". Ledger sequence " +
1190  std::to_string(ledger->info().seq));
1191  return false;
1192  };
1193 
1194  if (ledger->info().hash.isZero())
1195  return fail("Invalid ledger hash");
1196  if (ledger->info().accountHash.isZero())
1197  return fail("Invalid ledger account hash");
1198 
1199  bool error{false};
1200  auto visit = [this, &error](SHAMapTreeNode const& node) {
1201  if (stop_)
1202  return false;
1203  if (!verifyFetch(node.getHash().as_uint256()))
1204  error = true;
1205  return !error;
1206  };
1207 
1208  // Validate the state map
1209  if (ledger->stateMap().getHash().isNonZero())
1210  {
1211  if (!ledger->stateMap().isValid())
1212  return fail("Invalid state map");
1213 
1214  try
1215  {
1216  if (next && next->info().parentHash == ledger->info().hash)
1217  ledger->stateMap().visitDifferences(&next->stateMap(), visit);
1218  else
1219  ledger->stateMap().visitNodes(visit);
1220  }
1221  catch (std::exception const& e)
1222  {
1223  return fail(
1224  std::string(". Exception caught in function ") + __func__ +
1225  ". Error: " + e.what());
1226  }
1227 
1228  if (stop_)
1229  return false;
1230  if (error)
1231  return fail("Invalid state map");
1232  }
1233 
1234  // Validate the transaction map
1235  if (ledger->info().txHash.isNonZero())
1236  {
1237  if (!ledger->txMap().isValid())
1238  return fail("Invalid transaction map");
1239 
1240  try
1241  {
1242  ledger->txMap().visitNodes(visit);
1243  }
1244  catch (std::exception const& e)
1245  {
1246  return fail(
1247  std::string(". Exception caught in function ") + __func__ +
1248  ". Error: " + e.what());
1249  }
1250  if (stop_)
1251  return false;
1252  if (error)
1253  return fail("Invalid transaction map");
1254  }
1255 
1256  return true;
1257 }
1258 
1260 Shard::verifyFetch(uint256 const& hash) const
1261 {
1262  std::shared_ptr<NodeObject> nodeObject;
1263  auto fail =
1264  [j = j_, index = index_, &hash, &nodeObject](std::string const& msg) {
1265  JLOG(j.error()) << "shard " << index << ". " << msg
1266  << ". Node object hash " << to_string(hash);
1267  nodeObject.reset();
1268  return nodeObject;
1269  };
1270 
1271  try
1272  {
1273  switch (backend_->fetch(hash.data(), &nodeObject))
1274  {
1275  case ok:
1276  // Verify that the hash of node object matches the payload
1277  if (nodeObject->getHash() !=
1278  sha512Half(makeSlice(nodeObject->getData())))
1279  return fail("Node object hash does not match payload");
1280  return nodeObject;
1281  case notFound:
1282  return fail("Missing node object");
1283  case dataCorrupt:
1284  return fail("Corrupt node object");
1285  default:
1286  return fail("Unknown error");
1287  }
1288  }
1289  catch (std::exception const& e)
1290  {
1291  return fail(
1292  std::string(". Exception caught in function ") + __func__ +
1293  ". Error: " + e.what());
1294  }
1295 }
1296 
1299 {
1300  if (stop_)
1301  return {nullptr};
1302 
1303  std::lock_guard lock(mutex_);
1304  if (!backend_)
1305  {
1306  JLOG(j_.error()) << "shard " << index_ << " not initialized";
1307  return {nullptr};
1308  }
1309  if (!backend_->isOpen())
1310  {
1311  if (!open(lock))
1312  return {nullptr};
1313  }
1314  else if (state_ == final)
1316 
1317  return Shard::Count(&backendCount_);
1318 }
1319 
1320 } // namespace NodeStore
1321 } // namespace ripple
beast::Journal::fatal
Stream fatal() const
Definition: Journal.h:339
ripple::AcquireShardDBPragma
constexpr std::array< char const *, 1 > AcquireShardDBPragma
Definition: DBInit.h:120
ripple::Section
Holds a collection of configuration values.
Definition: BasicConfig.h:43
ripple::NodeStore::Shard::dir_
const boost::filesystem::path dir_
Definition: Shard.h:271
ripple::Application
Definition: Application.h:97
ripple::AcquireShardDBName
constexpr auto AcquireShardDBName
Definition: DBInit.h:118
ripple::hotUNKNOWN
@ hotUNKNOWN
Definition: NodeObject.h:33
ripple::HashPrefix::ledgerMaster
@ ledgerMaster
ledger master data for signing
ripple::Family::getTreeNodeCache
virtual std::shared_ptr< TreeNodeCache > getTreeNodeCache(std::uint32_t ledgerSeq)=0
Return a pointer to the Family Tree Node Cache.
ripple::NodeStore::Shard::mutex_
std::mutex mutex_
Definition: Shard.h:255
ripple::makeSlice
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition: Slice.h:240
ripple::NodeStore::Database
Persistency layer for NodeObject.
Definition: Database.h:52
ripple::NodeStore::Shard::acquire
static constexpr State acquire
Definition: Shard.h:61
std::string
STL class.
std::shared_ptr< NodeObject >
ripple::NodeStore::Shard::lgrSQLiteDB_
std::unique_ptr< DatabaseCon > lgrSQLiteDB_
Definition: Shard.h:285
ripple::NodeStore::Shard::removeOnDestroy_
std::atomic< bool > removeOnDestroy_
Definition: Shard.h:304
std::exception
STL class.
ripple::NodeStore::Shard::storeLedger
StoreLedgerResult storeLedger(std::shared_ptr< Ledger const > const &srcLedger, std::shared_ptr< Ledger const > const &next)
Definition: Shard.cpp:290
ripple::DatabaseCon::Setup
Definition: DatabaseCon.h:84
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:309
ripple::NodeStore::Shard::finalizing
static constexpr State finalizing
Definition: Shard.h:63
ripple::NodeStore::ok
@ ok
Definition: nodestore/Types.h:45
ripple::Serializer::modData
Blob & modData()
Definition: Serializer.h:176
ripple::NodeStore::Shard::Shard
Shard(Application &app, DatabaseShard const &db, std::uint32_t index, boost::filesystem::path const &dir, beast::Journal j)
Definition: Shard.cpp:45
std::pair
std::vector::reserve
T reserve(T... args)
ripple::convert
void convert(soci::blob &from, std::vector< std::uint8_t > &to)
Definition: SociDB.cpp:156
ripple::DatabaseCon::Setup::startUp
Config::StartUpType startUp
Definition: DatabaseCon.h:88
std::vector< std::shared_ptr< NodeObject > >
ripple::ConfigSection::shardDatabase
static std::string shardDatabase()
Definition: ConfigSections.h:38
std::vector::size
T size(T... args)
ripple::Config::getValueFor
int getValueFor(SizedItem item, boost::optional< std::size_t > node=boost::none) const
Retrieve the default value for the item at the specified node size.
Definition: Config.cpp:812
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::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:29
ripple::DatabaseCon::CheckpointerSetup
Definition: DatabaseCon.h:106
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::NodeStore::Shard::getFileInfo
std::pair< std::uint64_t, std::uint32_t > getFileInfo() const
Returns a pair where the first item describes the storage space utilized and the second item is the n...
Definition: Shard.cpp:499
std::lock_guard
STL class.
ripple::kilobytes
constexpr auto kilobytes(T value) noexcept
Definition: ByteUtilities.h:27
ripple::AcquireShardDBInit
constexpr std::array< char const *, 1 > AcquireShardDBInit
Definition: DBInit.h:123
ripple::NodeStore::FetchReport
Contains information about a fetch operation.
Definition: ripple/nodestore/Scheduler.h:32
ripple::NodeStore::Shard::isOpen
bool isOpen() const
Returns true if the database are open.
Definition: Shard.cpp:129
ripple::addRaw
void addRaw(LedgerInfo const &info, Serializer &s)
Definition: View.cpp:43
ripple::DatabaseCon::Setup::dataDir
boost::filesystem::path dataDir
Definition: DatabaseCon.h:90
ripple::STTx::getMetaSQLInsertReplaceHeader
static std::string const & getMetaSQLInsertReplaceHeader()
Definition: STTx.cpp:232
ripple::from_string
bool from_string(RangeSet< T > &rs, std::string const &s)
Convert the given styled string to a RangeSet.
Definition: RangeSet.h:126
ripple::Family::getFullBelowCache
virtual std::shared_ptr< FullBelowCache > getFullBelowCache(std::uint32_t ledgerSeq)=0
Return a pointer to the Family Full Below Cache.
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:42
ripple::NodeStore::Shard::finalKey
static const uint256 finalKey
Definition: Shard.h:206
ripple::NodeStore::Shard::lastSeq_
const std::uint32_t lastSeq_
Definition: Shard.h:264
ripple::NodeStore::Shard::complete
static constexpr State complete
Definition: Shard.h:62
ripple::Family::db
virtual NodeStore::Database & db()=0
ripple::NodeStore::Shard::verifyFetch
std::shared_ptr< NodeObject > verifyFetch(uint256 const &hash) const
Definition: Shard.cpp:1260
std::shared_ptr::reset
T reset(T... args)
ripple::base_uint::data
pointer data()
Definition: base_uint.h:113
ripple::LgrDBInit
constexpr std::array< char const *, 5 > LgrDBInit
Definition: DBInit.h:48
ripple::SHAMapHash
Definition: SHAMapTreeNode.h:47
ripple::NodeStore::Shard::tryClose
bool tryClose()
Try to close databases if not in use.
Definition: Shard.cpp:142
ripple::NodeStore::Shard::StoreLedgerResult::size
std::uint64_t size
Definition: Shard.h:127
ripple::NodeStore::Shard::backend_
std::unique_ptr< Backend > backend_
Definition: Shard.h:280
ripple::NodeStore::batchWritePreallocationSize
@ batchWritePreallocationSize
Definition: nodestore/Types.h:34
ripple::NodeStore::Shard::isLegacy
bool isLegacy() const
Returns true if shard is older, without final key data.
Definition: Shard.cpp:515
ripple::uint256
base_uint< 256 > uint256
Definition: base_uint.h:457
ripple::deserializePrefixedHeader
LedgerInfo deserializePrefixedHeader(Slice data)
Deserialize a ledger header (prefixed with 4 bytes) from a byte array.
Definition: InboundLedger.cpp:298
ripple::NodeStore::Shard::version
static constexpr std::uint32_t version
Definition: Shard.h:201
ripple::NodeStore::Shard::storeSQLite
bool storeSQLite(std::shared_ptr< Ledger const > const &ledger, std::lock_guard< std::mutex > const &)
Definition: Shard.cpp:984
ripple::NodeStore::notFound
@ notFound
Definition: nodestore/Types.h:46
ripple::TxDBName
constexpr auto TxDBName
Definition: DBInit.h:73
ripple::base_uint< 256 >
ripple::DatabaseCon::Setup::useGlobalPragma
bool useGlobalPragma
Definition: DatabaseCon.h:93
ripple::NodeStore::Shard::j_
const beast::Journal j_
Definition: Shard.h:254
ripple::NodeStore::Shard::finalize
bool finalize(bool const writeSQLite, boost::optional< uint256 > const &referenceHash)
Finalize shard by walking its ledgers and verifying each Merkle tree.
Definition: Shard.cpp:522
ripple::NodeStore::Shard::containsLedger
bool containsLedger(std::uint32_t ledgerSeq) const
Definition: Shard.cpp:468
ripple::NodeStore::Shard::fileSz_
std::uint64_t fileSz_
Definition: Shard.h:274
ripple::NodeStore::Shard::StoreLedgerResult::error
bool error
Definition: Shard.h:128
ripple::DatabaseCon::Setup::standAlone
bool standAlone
Definition: DatabaseCon.h:89
ripple::NodeStore::Shard::storeNodeObject
bool storeNodeObject(std::shared_ptr< NodeObject > const &nodeObject)
Definition: Shard.cpp:209
ripple::base_uint::isZero
bool isZero() const
Definition: base_uint.h:439
ripple::LgrDBPragma
constexpr std::array< char const *, 1 > LgrDBPragma
Definition: DBInit.h:45
ripple::NodeStore::Shard::sweep
void sweep()
Definition: Shard.cpp:486
ripple::SerialIter::get256
uint256 get256()
Definition: Serializer.h:374
ripple::Config
Definition: Config.h:67
ripple::NodeStore::Shard::initSQLite
bool initSQLite(std::lock_guard< std::mutex > const &)
Definition: Shard.cpp:910
ripple::Application::config
virtual Config & config()=0
ripple::NodeStore::Shard::fetchNodeObject
std::shared_ptr< NodeObject > fetchNodeObject(uint256 const &hash, FetchReport &fetchReport)
Definition: Shard.cpp:242
ripple::NodeStore::Shard::state_
std::atomic< State > state_
Definition: Shard.h:301
ripple::megabytes
constexpr auto megabytes(T value) noexcept
Definition: ByteUtilities.h:34
ripple::prevMissing
boost::optional< T > prevMissing(RangeSet< T > const &rs, T t, T minVal=0)
Find the largest value not in the set that is less than a given value.
Definition: RangeSet.h:184
ripple::NodeStore::DatabaseShard
A collection of historical shards.
Definition: DatabaseShard.h:37
ripple::SHAMapTreeNode
Definition: SHAMapTreeNode.h:133
std::to_string
T to_string(T... args)
ripple::Application::getJobQueue
virtual JobQueue & getJobQueue()=0
ripple::NodeStore::Shard::firstSeq_
const std::uint32_t firstSeq_
Definition: Shard.h:261
beast::Journal::error
Stream error() const
Definition: Journal.h:333
ripple::Application::logs
virtual Logs & logs()=0
ripple::NodeStore::Shard::maxLedgers_
const std::uint32_t maxLedgers_
Definition: Shard.h:268
ripple::SerialIter
Definition: Serializer.h:308
ripple::SizedItem::lgrDBCache
@ lgrDBCache
ripple::NodeStore::Shard::~Shard
~Shard()
Definition: Shard.cpp:63
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
ripple::SizedItem::burstSize
@ burstSize
ripple::NodeStore::dataCorrupt
@ dataCorrupt
Definition: nodestore/Types.h:47
std::uint32_t
ripple::NodeStore::Scheduler
Scheduling for asynchronous backend activity.
Definition: ripple/nodestore/Scheduler.h:60
ripple::NodeStore::Shard::StoreLedgerResult
Store a ledger.
Definition: Shard.h:124
ripple::SizedItem::txnDBCache
@ txnDBCache
ripple::NodeStore::Shard::acquireInfo_
std::unique_ptr< AcquireInfo > acquireInfo_
Definition: Shard.h:292
ripple::NodeStore::Shard::app_
Application & app_
Definition: Shard.h:253
ripple::NodeStore::Status
Status
Return codes from Backend operations.
Definition: nodestore/Types.h:44
ripple::Serializer
Definition: Serializer.h:39
ripple::NodeStore::Manager::find
virtual Factory * find(std::string const &name)=0
Return a pointer to the matching factory if it exists.
std::vector::emplace_back
T emplace_back(T... args)
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::NodeStore::Shard::lastAccess_
std::chrono::steady_clock::time_point lastAccess_
Definition: Shard.h:307
ripple::Serializer::addBitString
int addBitString(base_uint< Bits, Tag > const &v)
Definition: Serializer.h:97
ripple::NodeObject::keyBytes
static constexpr std::size_t keyBytes
Definition: NodeObject.h:51
ripple::NodeStore::Shard::makeBackendCount
Shard::Count makeBackendCount()
Definition: Shard.cpp:1298
ripple::Application::getShardFamily
virtual Family * getShardFamily()=0
ripple::NodeStore::Shard::StoreLedgerResult::count
std::uint64_t count
Definition: Shard.h:126
ripple::NodeStore::Shard::prepare
boost::optional< std::uint32_t > prepare()
Definition: Shard.cpp:186
ripple::NodeStore::FetchReport::wasFound
bool wasFound
Definition: ripple/nodestore/Scheduler.h:40
std
STL namespace.
ripple::sha512Half
sha512_half_hasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
Definition: digest.h:216
ripple::NodeStore::Shard::open
bool open(std::lock_guard< std::mutex > const &lock)
Definition: Shard.cpp:771
ripple::TxDBPragma
constexpr std::array TxDBPragma
Definition: DBInit.h:76
ripple::NodeStore::Shard::legacy_
bool legacy_
Definition: Shard.h:296
std::vector::empty
T empty(T... args)
ripple::NodeStore::Shard::fdRequired_
std::uint32_t fdRequired_
Definition: Shard.h:277
ripple::NodeStore::Shard::index
std::uint32_t index() const
Definition: Shard.h:146
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
ripple::NodeStore::Shard::init
bool init(Scheduler &scheduler, nudb::context &context)
Initialize shard.
Definition: Shard.cpp:98
ripple::NodeStore::Shard::verifyLedger
bool verifyLedger(std::shared_ptr< Ledger const > const &ledger, std::shared_ptr< Ledger const > const &next) const
Definition: Shard.cpp:1179
ripple::hotLEDGER
@ hotLEDGER
Definition: NodeObject.h:34
ripple::Serializer::add32
int add32(std::uint32_t i)
Definition: Serializer.cpp:38
ripple::LedgerInfo
Information about the notional ledger backing the view.
Definition: ReadView.h:84
ripple::NodeStore::Shard::setFileStats
void setFileStats(std::lock_guard< std::mutex > const &)
Definition: Shard.cpp:1154
ripple::CompleteShardDBPragma
constexpr std::array< char const *, 2 > CompleteShardDBPragma
Definition: DBInit.h:134
ripple::TxDBInit
constexpr std::array< char const *, 8 > TxDBInit
Definition: DBInit.h:84
ripple::NodeStore::Manager::instance
static Manager & instance()
Returns the instance of the manager singleton.
Definition: ManagerImp.cpp:119
ripple::NodeStore::Shard::setLedgerStored
bool setLedgerStored(std::shared_ptr< Ledger const > const &ledger)
Definition: Shard.cpp:415
ripple::NodeStore::Shard
Definition: Shard.h:51
ripple::SerialIter::get32
std::uint32_t get32()
Definition: Serializer.cpp:378
ripple::NodeStore::Shard::txSQLiteDB_
std::unique_ptr< DatabaseCon > txSQLiteDB_
Definition: Shard.h:288
ripple::NodeStore::Shard::Count
Definition: Shard.h:209
ripple::NodeStore::Shard::index_
const std::uint32_t index_
Definition: Shard.h:258
ripple::NodeStore::Shard::stop_
std::atomic< bool > stop_
Definition: Shard.h:299
ripple::NodeStore::Shard::backendCount_
std::atomic< std::uint32_t > backendCount_
Definition: Shard.h:282
ripple::NodeStore::Shard::getLastUse
std::chrono::steady_clock::time_point getLastUse() const
Definition: Shard.cpp:492
ripple::sqlBlobLiteral
std::string sqlBlobLiteral(Blob const &blob)
Format arbitrary binary data as an SQLite "blob literal".
Definition: StringUtilities.cpp:33
ripple::NodeStore::Shard::getWriteLoad
std::int32_t getWriteLoad()
Definition: Shard.cpp:506
std::exception::what
T what(T... args)
ripple::BasicConfig::section
Section & section(std::string const &name)
Returns the section with the given name.
Definition: BasicConfig.cpp:138
ripple::LgrDBName
constexpr auto LgrDBName
Definition: DBInit.h:43
std::chrono::steady_clock::now
T now(T... args)