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
179  pCache_->reset();
180  nCache_->reset();
183 
184  return true;
185 }
186 
187 boost::optional<std::uint32_t>
189 {
190  if (state_ != acquire)
191  {
192  JLOG(j_.warn()) << "shard " << index_
193  << " prepare called when not acquiring";
194  return boost::none;
195  }
196 
197  std::lock_guard lock(mutex_);
198  if (!acquireInfo_)
199  {
200  JLOG(j_.error()) << "shard " << index_
201  << " missing acquire SQLite database";
202  return boost::none;
203  }
204 
205  if (acquireInfo_->storedSeqs.empty())
206  return lastSeq_;
207  return prevMissing(acquireInfo_->storedSeqs, 1 + lastSeq_, firstSeq_);
208 }
209 
210 bool
212 {
213  if (state_ != acquire)
214  {
215  // The import node store case is an exception
216  if (nodeObject->getHash() != finalKey)
217  {
218  // Ignore residual calls from InboundLedgers
219  JLOG(j_.trace()) << "shard " << index_ << " not acquiring";
220  return false;
221  }
222  }
223 
224  auto const scopedCount{makeBackendCount()};
225  if (!scopedCount)
226  return false;
227 
228  pCache_->canonicalize_replace_cache(nodeObject->getHash(), nodeObject);
229 
230  try
231  {
232  backend_->store(nodeObject);
233  }
234  catch (std::exception const& e)
235  {
236  JLOG(j_.fatal()) << "shard " << index_
237  << ". Exception caught in function " << __func__
238  << ". Error: " << e.what();
239  return false;
240  }
241 
242  nCache_->erase(nodeObject->getHash());
243  return true;
244 }
245 
247 Shard::fetchNodeObject(uint256 const& hash, FetchReport& fetchReport)
248 {
249  auto const scopedCount{makeBackendCount()};
250  if (!scopedCount)
251  return nullptr;
252 
253  // See if the node object exists in the cache
254  auto nodeObject{pCache_->fetch(hash)};
255  if (!nodeObject && !nCache_->touch_if_exists(hash))
256  {
257  // Try the backend
258  fetchReport.wentToDisk = true;
259 
260  Status status;
261  try
262  {
263  status = backend_->fetch(hash.data(), &nodeObject);
264  }
265  catch (std::exception const& e)
266  {
267  JLOG(j_.fatal())
268  << "shard " << index_ << ". Exception caught in function "
269  << __func__ << ". Error: " << e.what();
270  return nullptr;
271  }
272 
273  switch (status)
274  {
275  case ok:
276  case notFound:
277  break;
278  case dataCorrupt: {
279  JLOG(j_.fatal())
280  << "shard " << index_ << ". Corrupt node object at hash "
281  << to_string(hash);
282  break;
283  }
284  default: {
285  JLOG(j_.warn())
286  << "shard " << index_ << ". Unknown status=" << status
287  << " fetching node object at hash " << to_string(hash);
288  break;
289  }
290  }
291 
292  if (!nodeObject)
293  {
294  // Just in case a write occurred
295  nodeObject = pCache_->fetch(hash);
296  if (!nodeObject)
297  // We give up
298  nCache_->insert(hash);
299  }
300  else
301  {
302  // Ensure all threads get the same object
303  pCache_->canonicalize_replace_client(hash, nodeObject);
304  fetchReport.wasFound = true;
305 
306  // Since this was a 'hard' fetch, we will log it
307  JLOG(j_.trace()) << "HOS: " << hash << " fetch: in shard db";
308  }
309  }
310 
311  return nodeObject;
312 }
313 
314 bool
316  uint256 const& hash,
317  std::shared_ptr<NodeObject>& nodeObject)
318 {
319  auto const scopedCount{makeBackendCount()};
320  if (!scopedCount)
321  return false;
322 
323  nodeObject = pCache_->fetch(hash);
324  if (nodeObject || nCache_->touch_if_exists(hash))
325  return true;
326  return false;
327 }
328 
331  std::shared_ptr<Ledger const> const& srcLedger,
332  std::shared_ptr<Ledger const> const& next)
333 {
334  StoreLedgerResult result;
335  if (state_ != acquire)
336  {
337  // Ignore residual calls from InboundLedgers
338  JLOG(j_.trace()) << "shard " << index_ << ". Not acquiring";
339  return result;
340  }
341  if (containsLedger(srcLedger->info().seq))
342  {
343  JLOG(j_.trace()) << "shard " << index_ << ". Ledger already stored";
344  return result;
345  }
346 
347  auto fail = [&](std::string const& msg) {
348  JLOG(j_.error()) << "shard " << index_ << ". Source ledger sequence "
349  << srcLedger->info().seq << ". " << msg;
350  result.error = true;
351  return result;
352  };
353 
354  if (srcLedger->info().hash.isZero())
355  return fail("Invalid hash");
356  if (srcLedger->info().accountHash.isZero())
357  return fail("Invalid account hash");
358 
359  auto& srcDB{const_cast<Database&>(srcLedger->stateMap().family().db())};
360  if (&srcDB == &(app_.getShardFamily()->db()))
361  return fail("Source and destination databases are the same");
362 
363  auto const scopedCount{makeBackendCount()};
364  if (!scopedCount)
365  return fail("Failed to lock backend");
366 
367  Batch batch;
369  auto storeBatch = [&]() {
370  std::uint64_t sz{0};
371  for (auto const& nodeObject : batch)
372  {
373  pCache_->canonicalize_replace_cache(
374  nodeObject->getHash(), nodeObject);
375  nCache_->erase(nodeObject->getHash());
376  sz += nodeObject->getData().size();
377  }
378 
379  try
380  {
381  backend_->storeBatch(batch);
382  }
383  catch (std::exception const& e)
384  {
385  fail(
386  std::string(". Exception caught in function ") + __func__ +
387  ". Error: " + e.what());
388  return false;
389  }
390 
391  result.count += batch.size();
392  result.size += sz;
393  batch.clear();
394  return true;
395  };
396 
397  // Store ledger header
398  {
399  Serializer s(sizeof(std::uint32_t) + sizeof(LedgerInfo));
401  addRaw(srcLedger->info(), s);
402  auto nodeObject = NodeObject::createObject(
403  hotLEDGER, std::move(s.modData()), srcLedger->info().hash);
404  batch.emplace_back(std::move(nodeObject));
405  }
406 
407  bool error = false;
408  auto visit = [&](SHAMapTreeNode const& node) {
409  if (!stop_)
410  {
411  if (auto nodeObject = srcDB.fetchNodeObject(
412  node.getHash().as_uint256(), srcLedger->info().seq))
413  {
414  batch.emplace_back(std::move(nodeObject));
415  if (batch.size() < batchWritePreallocationSize || storeBatch())
416  return true;
417  }
418  }
419 
420  error = true;
421  return false;
422  };
423 
424  // Store the state map
425  if (srcLedger->stateMap().getHash().isNonZero())
426  {
427  if (!srcLedger->stateMap().isValid())
428  return fail("Invalid state map");
429 
430  if (next && next->info().parentHash == srcLedger->info().hash)
431  {
432  auto have = next->stateMap().snapShot(false);
433  srcLedger->stateMap().snapShot(false)->visitDifferences(
434  &(*have), visit);
435  }
436  else
437  srcLedger->stateMap().snapShot(false)->visitNodes(visit);
438  if (error)
439  return fail("Failed to store state map");
440  }
441 
442  // Store the transaction map
443  if (srcLedger->info().txHash.isNonZero())
444  {
445  if (!srcLedger->txMap().isValid())
446  return fail("Invalid transaction map");
447 
448  srcLedger->txMap().snapShot(false)->visitNodes(visit);
449  if (error)
450  return fail("Failed to store transaction map");
451  }
452 
453  if (!batch.empty() && !storeBatch())
454  return fail("Failed to store");
455 
456  return result;
457 }
458 
459 bool
461 {
462  if (state_ != acquire)
463  {
464  // Ignore residual calls from InboundLedgers
465  JLOG(j_.trace()) << "shard " << index_ << " not acquiring";
466  return false;
467  }
468 
469  auto const ledgerSeq{ledger->info().seq};
470  if (ledgerSeq < firstSeq_ || ledgerSeq > lastSeq_)
471  {
472  JLOG(j_.error()) << "shard " << index_ << " invalid ledger sequence "
473  << ledgerSeq;
474  return false;
475  }
476 
477  std::lock_guard lock(mutex_);
478  if (!acquireInfo_)
479  {
480  JLOG(j_.error()) << "shard " << index_
481  << " missing acquire SQLite database";
482  return false;
483  }
484  if (boost::icl::contains(acquireInfo_->storedSeqs, ledgerSeq))
485  {
486  // Ignore redundant calls
487  JLOG(j_.debug()) << "shard " << index_ << " ledger sequence "
488  << ledgerSeq << " already stored";
489  return true;
490  }
491  // storeSQLite looks at storedSeqs so insert before the call
492  acquireInfo_->storedSeqs.insert(ledgerSeq);
493 
494  if (!storeSQLite(ledger, lock))
495  return false;
496 
497  if (boost::icl::length(acquireInfo_->storedSeqs) >= maxLedgers_)
498  {
499  if (!initSQLite(lock))
500  return false;
501 
502  state_ = complete;
503  }
504 
505  JLOG(j_.debug()) << "shard " << index_ << " stored ledger sequence "
506  << ledgerSeq;
507 
508  setFileStats(lock);
509  return true;
510 }
511 
512 bool
514 {
515  if (ledgerSeq < firstSeq_ || ledgerSeq > lastSeq_)
516  return false;
517  if (state_ != acquire)
518  return true;
519 
520  std::lock_guard lock(mutex_);
521  if (!acquireInfo_)
522  {
523  JLOG(j_.error()) << "shard " << index_
524  << " missing acquire SQLite database";
525  return false;
526  }
527  return boost::icl::contains(acquireInfo_->storedSeqs, ledgerSeq);
528 }
529 
530 void
532 {
533  boost::optional<Shard::Count> scopedCount;
534  {
535  std::lock_guard lock(mutex_);
536  if (!backend_ || !backend_->isOpen())
537  {
538  JLOG(j_.error()) << "shard " << index_ << " not initialized";
539  return;
540  }
541 
542  scopedCount.emplace(&backendCount_);
543  }
544 
545  pCache_->sweep();
546  nCache_->sweep();
547 }
548 
549 int
551 {
552  auto const scopedCount{makeBackendCount()};
553  if (!scopedCount)
554  return 0;
555  return pCache_->getTargetSize() / asyncDivider;
556 }
557 
558 float
560 {
561  auto const scopedCount{makeBackendCount()};
562  if (!scopedCount)
563  return 0;
564  return pCache_->getHitRate();
565 }
566 
567 std::chrono::steady_clock::time_point
569 {
570  std::lock_guard lock(mutex_);
571  return lastAccess_;
572 }
573 
576 {
577  std::lock_guard lock(mutex_);
578  return {fileSz_, fdRequired_};
579 }
580 
583 {
584  auto const scopedCount{makeBackendCount()};
585  if (!scopedCount)
586  return 0;
587  return backend_->getWriteLoad();
588 }
589 
590 bool
592 {
593  std::lock_guard lock(mutex_);
594  return legacy_;
595 }
596 
597 bool
599  bool const writeSQLite,
600  boost::optional<uint256> const& expectedHash)
601 {
602  uint256 hash{0};
603  std::uint32_t ledgerSeq{0};
604  auto fail =
605  [j = j_, index = index_, &hash, &ledgerSeq](std::string const& msg) {
606  JLOG(j.fatal())
607  << "shard " << index << ". " << msg
608  << (hash.isZero() ? "" : ". Ledger hash " + to_string(hash))
609  << (ledgerSeq == 0
610  ? ""
611  : ". Ledger sequence " + std::to_string(ledgerSeq));
612  return false;
613  };
614 
615  auto const scopedCount{makeBackendCount()};
616  if (!scopedCount)
617  return false;
618 
619  try
620  {
621  state_ = finalizing;
622 
623  /*
624  TODO MP
625  A lock is required when calling the NuDB verify function. Because
626  this can be a time consuming process, the server may desync.
627  Until this function is modified to work on an open database, we
628  are unable to use it from rippled.
629 
630  // Verify backend integrity
631  backend_->verify();
632  */
633 
634  // Check if a final key has been stored
635  if (std::shared_ptr<NodeObject> nodeObject;
636  backend_->fetch(finalKey.data(), &nodeObject) == Status::ok)
637  {
638  // Check final key's value
639  SerialIter sIt(
640  nodeObject->getData().data(), nodeObject->getData().size());
641  if (sIt.get32() != version)
642  return fail("invalid version");
643 
644  if (sIt.get32() != firstSeq_ || sIt.get32() != lastSeq_)
645  return fail("out of range ledger sequences");
646 
647  if (hash = sIt.get256(); hash.isZero())
648  return fail("invalid last ledger hash");
649  }
650  else
651  {
652  // In the absence of a final key, an acquire SQLite database
653  // must be present in order to validate the shard
654  if (!acquireInfo_)
655  return fail("missing acquire SQLite database");
656 
657  auto& session{acquireInfo_->SQLiteDB->getSession()};
658  boost::optional<std::uint32_t> index;
659  boost::optional<std::string> sHash;
660  soci::blob sociBlob(session);
661  soci::indicator blobPresent;
662  session << "SELECT ShardIndex, LastLedgerHash, StoredLedgerSeqs "
663  "FROM Shard "
664  "WHERE ShardIndex = :index;",
665  soci::into(index), soci::into(sHash),
666  soci::into(sociBlob, blobPresent), soci::use(index_);
667 
668  if (!index || index != index_)
669  return fail("missing or invalid ShardIndex");
670 
671  if (!sHash)
672  return fail("missing LastLedgerHash");
673 
674  if (!hash.parseHex(*sHash) || hash.isZero())
675  return fail("invalid LastLedgerHash");
676 
677  if (blobPresent != soci::i_ok)
678  return fail("missing StoredLedgerSeqs");
679 
680  std::string s;
681  convert(sociBlob, s);
682 
683  auto& storedSeqs{acquireInfo_->storedSeqs};
684  if (!from_string(storedSeqs, s) ||
685  boost::icl::first(storedSeqs) != firstSeq_ ||
686  boost::icl::last(storedSeqs) != lastSeq_ ||
687  storedSeqs.size() != maxLedgers_)
688  {
689  return fail("invalid StoredLedgerSeqs");
690  }
691  }
692  }
693  catch (std::exception const& e)
694  {
695  return fail(
696  std::string(". Exception caught in function ") + __func__ +
697  ". Error: " + e.what());
698  }
699 
700  // Validate the last ledger hash of a downloaded shard
701  // using a ledger hash obtained from the peer network
702  if (expectedHash && *expectedHash != hash)
703  return fail("invalid last ledger hash");
704 
705  // Validate every ledger stored in the backend
706  Config const& config{app_.config()};
709  auto const lastLedgerHash{hash};
710  auto& shardFamily{*app_.getShardFamily()};
711  auto const fullBelowCache{shardFamily.getFullBelowCache(lastSeq_)};
712  auto const treeNodeCache{shardFamily.getTreeNodeCache(lastSeq_)};
713 
714  // Reset caches to reduce memory usage
715  pCache_->reset();
716  nCache_->reset();
717  fullBelowCache->reset();
718  treeNodeCache->reset();
719 
720  // Start with the last ledger in the shard and walk backwards from
721  // child to parent until we reach the first ledger
722  ledgerSeq = lastSeq_;
723  while (ledgerSeq >= firstSeq_)
724  {
725  if (stop_)
726  return false;
727 
728  auto nodeObject{verifyFetch(hash)};
729  if (!nodeObject)
730  return fail("invalid ledger");
731 
732  ledger = std::make_shared<Ledger>(
733  deserializePrefixedHeader(makeSlice(nodeObject->getData())),
734  config,
735  shardFamily);
736  if (ledger->info().seq != ledgerSeq)
737  return fail("invalid ledger sequence");
738  if (ledger->info().hash != hash)
739  return fail("invalid ledger hash");
740 
741  ledger->stateMap().setLedgerSeq(ledgerSeq);
742  ledger->txMap().setLedgerSeq(ledgerSeq);
743  ledger->setImmutable(config);
744  if (!ledger->stateMap().fetchRoot(
745  SHAMapHash{ledger->info().accountHash}, nullptr))
746  {
747  return fail("missing root STATE node");
748  }
749  if (ledger->info().txHash.isNonZero() &&
750  !ledger->txMap().fetchRoot(
751  SHAMapHash{ledger->info().txHash}, nullptr))
752  {
753  return fail("missing root TXN node");
754  }
755 
756  if (!verifyLedger(ledger, next))
757  return fail("failed to validate ledger");
758 
759  if (writeSQLite)
760  {
761  std::lock_guard lock(mutex_);
762  if (!storeSQLite(ledger, lock))
763  return fail("failed storing to SQLite databases");
764  }
765 
766  hash = ledger->info().parentHash;
767  next = std::move(ledger);
768  --ledgerSeq;
769 
770  pCache_->reset();
771  nCache_->reset();
772  fullBelowCache->reset();
773  treeNodeCache->reset();
774  }
775 
776  JLOG(j_.debug()) << "shard " << index_ << " is valid";
777 
778  /*
779  TODO MP
780  SQLite VACUUM blocks all database access while processing.
781  Depending on the file size, that can take a while. Until we find
782  a non-blocking way of doing this, we cannot enable vacuum as
783  it can desync a server.
784 
785  try
786  {
787  // VACUUM the SQLite databases
788  auto const tmpDir {dir_ / "tmp_vacuum"};
789  create_directory(tmpDir);
790 
791  auto vacuum = [&tmpDir](std::unique_ptr<DatabaseCon>& sqliteDB)
792  {
793  auto& session {sqliteDB->getSession()};
794  session << "PRAGMA synchronous=OFF;";
795  session << "PRAGMA journal_mode=OFF;";
796  session << "PRAGMA temp_store_directory='" <<
797  tmpDir.string() << "';";
798  session << "VACUUM;";
799  };
800  vacuum(lgrSQLiteDB_);
801  vacuum(txSQLiteDB_);
802  remove_all(tmpDir);
803  }
804  catch (std::exception const& e)
805  {
806  return fail(
807  std::string(". Exception caught in function ") + __func__ +
808  ". Error: " + e.what());
809  }
810  */
811 
812  // Store final key's value, may already be stored
813  Serializer s;
814  s.add32(version);
815  s.add32(firstSeq_);
816  s.add32(lastSeq_);
817  s.addBitString(lastLedgerHash);
818  auto nodeObject{
820  try
821  {
822  backend_->store(nodeObject);
823 
824  std::lock_guard lock(mutex_);
825 
826  // Remove the acquire SQLite database
827  if (acquireInfo_)
828  {
829  acquireInfo_.reset();
830  remove_all(dir_ / AcquireShardDBName);
831  }
832 
833  if (!initSQLite(lock))
834  return fail("failed to initialize SQLite databases");
835 
836  setFileStats(lock);
838  }
839  catch (std::exception const& e)
840  {
841  return fail(
842  std::string(". Exception caught in function ") + __func__ +
843  ". Error: " + e.what());
844  }
845 
846  state_ = final;
847  return true;
848 }
849 
850 bool
852 {
853  using namespace boost::filesystem;
854  Config const& config{app_.config()};
855  auto preexist{false};
856  auto fail = [this, &preexist](std::string const& msg) {
857  backend_->close();
858  lgrSQLiteDB_.reset();
859  txSQLiteDB_.reset();
860  acquireInfo_.reset();
861 
862  pCache_.reset();
863  nCache_.reset();
864 
865  state_ = acquire;
866 
867  if (!preexist)
868  remove_all(dir_);
869 
870  if (!msg.empty())
871  {
872  JLOG(j_.fatal()) << "shard " << index_ << " " << msg;
873  }
874  return false;
875  };
876  auto createAcquireInfo = [this, &config]() {
877  acquireInfo_ = std::make_unique<AcquireInfo>();
878 
879  DatabaseCon::Setup setup;
880  setup.startUp = config.standalone() ? config.LOAD : config.START_UP;
881  setup.standAlone = config.standalone();
882  setup.dataDir = dir_;
883  setup.useGlobalPragma = true;
884 
885  acquireInfo_->SQLiteDB = std::make_unique<DatabaseCon>(
886  setup,
891  state_ = acquire;
892  };
893 
894  try
895  {
896  // Open or create the NuDB key/value store
897  preexist = exists(dir_);
898  backend_->open(!preexist);
899 
900  if (!preexist)
901  {
902  // A new shard
903  createAcquireInfo();
904  acquireInfo_->SQLiteDB->getSession()
905  << "INSERT INTO Shard (ShardIndex) "
906  "VALUES (:shardIndex);",
907  soci::use(index_);
908  }
909  else if (exists(dir_ / AcquireShardDBName))
910  {
911  // A shard being acquired, backend is likely incomplete
912  createAcquireInfo();
913 
914  auto& session{acquireInfo_->SQLiteDB->getSession()};
915  boost::optional<std::uint32_t> index;
916  soci::blob sociBlob(session);
917  soci::indicator blobPresent;
918 
919  session << "SELECT ShardIndex, StoredLedgerSeqs "
920  "FROM Shard "
921  "WHERE ShardIndex = :index;",
922  soci::into(index), soci::into(sociBlob, blobPresent),
923  soci::use(index_);
924 
925  if (!index || index != index_)
926  return fail("invalid acquire SQLite database");
927 
928  if (blobPresent == soci::i_ok)
929  {
930  std::string s;
931  auto& storedSeqs{acquireInfo_->storedSeqs};
932  if (convert(sociBlob, s); !from_string(storedSeqs, s))
933  return fail("invalid StoredLedgerSeqs");
934 
935  if (boost::icl::first(storedSeqs) < firstSeq_ ||
936  boost::icl::last(storedSeqs) > lastSeq_)
937  {
938  return fail("invalid StoredLedgerSeqs");
939  }
940 
941  // Check if backend is complete
942  if (boost::icl::length(storedSeqs) == maxLedgers_)
943  state_ = complete;
944  }
945  }
946  else
947  {
948  // A shard that is final or its backend is complete
949  // and ready to be finalized
950  std::shared_ptr<NodeObject> nodeObject;
951  if (backend_->fetch(finalKey.data(), &nodeObject) != Status::ok)
952  {
953  legacy_ = true;
954  return fail("incompatible, missing backend final key");
955  }
956 
957  // Check final key's value
958  SerialIter sIt(
959  nodeObject->getData().data(), nodeObject->getData().size());
960  if (sIt.get32() != version)
961  return fail("invalid version");
962 
963  if (sIt.get32() != firstSeq_ || sIt.get32() != lastSeq_)
964  return fail("out of range ledger sequences");
965 
966  if (sIt.get256().isZero())
967  return fail("invalid last ledger hash");
968 
969  if (exists(dir_ / LgrDBName) && exists(dir_ / TxDBName))
970  {
972  state_ = final;
973  }
974  else
975  state_ = complete;
976  }
977  }
978  catch (std::exception const& e)
979  {
980  return fail(
981  std::string(". Exception caught in function ") + __func__ +
982  ". Error: " + e.what());
983  }
984 
985  // Set backend caches
986  auto const size{config.getValueFor(SizedItem::nodeCacheSize, 0)};
987  auto const age{
988  std::chrono::seconds{config.getValueFor(SizedItem::nodeCacheAge, 0)}};
989  auto const name{"shard " + std::to_string(index_)};
990  pCache_ = std::make_unique<PCache>(name, size, age, stopwatch(), j_);
991  nCache_ = std::make_unique<NCache>(name, stopwatch(), size, age);
992 
993  if (!initSQLite(lock))
994  return fail({});
995 
996  setFileStats(lock);
997  return true;
998 }
999 
1000 bool
1002 {
1003  Config const& config{app_.config()};
1004  DatabaseCon::Setup const setup = [&]() {
1005  DatabaseCon::Setup setup;
1006  setup.startUp = config.standalone() ? config.LOAD : config.START_UP;
1007  setup.standAlone = config.standalone();
1008  setup.dataDir = dir_;
1009  setup.useGlobalPragma = (state_ != complete);
1010  return setup;
1011  }();
1012 
1013  try
1014  {
1015  if (lgrSQLiteDB_)
1016  lgrSQLiteDB_.reset();
1017 
1018  if (txSQLiteDB_)
1019  txSQLiteDB_.reset();
1020 
1021  if (state_ != acquire)
1022  {
1023  lgrSQLiteDB_ = std::make_unique<DatabaseCon>(
1025  lgrSQLiteDB_->getSession() << boost::str(
1026  boost::format("PRAGMA cache_size=-%d;") %
1027  kilobytes(
1028  config.getValueFor(SizedItem::lgrDBCache, boost::none)));
1029 
1030  txSQLiteDB_ = std::make_unique<DatabaseCon>(
1032  txSQLiteDB_->getSession() << boost::str(
1033  boost::format("PRAGMA cache_size=-%d;") %
1034  kilobytes(
1035  config.getValueFor(SizedItem::txnDBCache, boost::none)));
1036  }
1037  else
1038  {
1039  // The incomplete shard uses a Write Ahead Log for performance
1040  lgrSQLiteDB_ = std::make_unique<DatabaseCon>(
1041  setup,
1042  LgrDBName,
1043  LgrDBPragma,
1044  LgrDBInit,
1046  &app_.getJobQueue(), &app_.logs()});
1047  lgrSQLiteDB_->getSession() << boost::str(
1048  boost::format("PRAGMA cache_size=-%d;") %
1049  kilobytes(config.getValueFor(SizedItem::lgrDBCache)));
1050 
1051  txSQLiteDB_ = std::make_unique<DatabaseCon>(
1052  setup,
1053  TxDBName,
1054  TxDBPragma,
1055  TxDBInit,
1057  &app_.getJobQueue(), &app_.logs()});
1058  txSQLiteDB_->getSession() << boost::str(
1059  boost::format("PRAGMA cache_size=-%d;") %
1060  kilobytes(config.getValueFor(SizedItem::txnDBCache)));
1061  }
1062  }
1063  catch (std::exception const& e)
1064  {
1065  JLOG(j_.fatal()) << "shard " << index_
1066  << ". Exception caught in function " << __func__
1067  << ". Error: " << e.what();
1068  return false;
1069  }
1070 
1071  return true;
1072 }
1073 
1074 bool
1076  std::shared_ptr<Ledger const> const& ledger,
1078 {
1079  if (stop_)
1080  return false;
1081 
1082  auto const ledgerSeq{ledger->info().seq};
1083 
1084  try
1085  {
1086  // Update the transactions database
1087  {
1088  auto& session{txSQLiteDB_->getSession()};
1089  soci::transaction tr(session);
1090 
1091  session << "DELETE FROM Transactions "
1092  "WHERE LedgerSeq = :seq;",
1093  soci::use(ledgerSeq);
1094  session << "DELETE FROM AccountTransactions "
1095  "WHERE LedgerSeq = :seq;",
1096  soci::use(ledgerSeq);
1097 
1098  if (ledger->info().txHash.isNonZero())
1099  {
1100  auto const sSeq{std::to_string(ledgerSeq)};
1101  if (!ledger->txMap().isValid())
1102  {
1103  JLOG(j_.error()) << "shard " << index_
1104  << " has an invalid transaction map"
1105  << " on sequence " << sSeq;
1106  return false;
1107  }
1108 
1109  for (auto const& item : ledger->txs)
1110  {
1111  if (stop_)
1112  return false;
1113 
1114  auto const txID{item.first->getTransactionID()};
1115  auto const sTxID{to_string(txID)};
1116  auto const txMeta{std::make_shared<TxMeta>(
1117  txID, ledger->seq(), *item.second)};
1118 
1119  session << "DELETE FROM AccountTransactions "
1120  "WHERE TransID = :txID;",
1121  soci::use(sTxID);
1122 
1123  auto const& accounts = txMeta->getAffectedAccounts(j_);
1124  if (!accounts.empty())
1125  {
1126  auto const sTxnSeq{std::to_string(txMeta->getIndex())};
1127  auto const s{boost::str(
1128  boost::format("('%s','%s',%s,%s)") % sTxID % "%s" %
1129  sSeq % sTxnSeq)};
1130  std::string sql;
1131  sql.reserve((accounts.size() + 1) * 128);
1132  sql =
1133  "INSERT INTO AccountTransactions "
1134  "(TransID, Account, LedgerSeq, TxnSeq) VALUES ";
1135  sql += boost::algorithm::join(
1136  accounts |
1137  boost::adaptors::transformed(
1138  [&](AccountID const& accountID) {
1139  return boost::str(
1140  boost::format(s) %
1141  ripple::toBase58(accountID));
1142  }),
1143  ",");
1144  sql += ';';
1145  session << sql;
1146 
1147  JLOG(j_.trace()) << "shard " << index_
1148  << " account transaction: " << sql;
1149  }
1150  else
1151  {
1152  JLOG(j_.warn())
1153  << "shard " << index_ << " transaction in ledger "
1154  << sSeq << " affects no accounts";
1155  }
1156 
1157  Serializer s;
1158  item.second->add(s);
1159  session
1161  item.first->getMetaSQL(
1162  ledgerSeq, sqlBlobLiteral(s.modData())) +
1163  ';');
1164  }
1165  }
1166 
1167  tr.commit();
1168  }
1169 
1170  auto const sHash{to_string(ledger->info().hash)};
1171 
1172  // Update the ledger database
1173  {
1174  auto& session{lgrSQLiteDB_->getSession()};
1175  soci::transaction tr(session);
1176 
1177  auto const sParentHash{to_string(ledger->info().parentHash)};
1178  auto const sDrops{to_string(ledger->info().drops)};
1179  auto const sAccountHash{to_string(ledger->info().accountHash)};
1180  auto const sTxHash{to_string(ledger->info().txHash)};
1181 
1182  session << "DELETE FROM Ledgers "
1183  "WHERE LedgerSeq = :seq;",
1184  soci::use(ledgerSeq);
1185  session
1186  << "INSERT OR REPLACE INTO Ledgers ("
1187  "LedgerHash, LedgerSeq, PrevHash, TotalCoins, ClosingTime,"
1188  "PrevClosingTime, CloseTimeRes, CloseFlags, AccountSetHash,"
1189  "TransSetHash)"
1190  "VALUES ("
1191  ":ledgerHash, :ledgerSeq, :prevHash, :totalCoins,"
1192  ":closingTime, :prevClosingTime, :closeTimeRes,"
1193  ":closeFlags, :accountSetHash, :transSetHash);",
1194  soci::use(sHash), soci::use(ledgerSeq), soci::use(sParentHash),
1195  soci::use(sDrops),
1196  soci::use(ledger->info().closeTime.time_since_epoch().count()),
1197  soci::use(
1198  ledger->info().parentCloseTime.time_since_epoch().count()),
1199  soci::use(ledger->info().closeTimeResolution.count()),
1200  soci::use(ledger->info().closeFlags), soci::use(sAccountHash),
1201  soci::use(sTxHash);
1202 
1203  tr.commit();
1204  }
1205 
1206  // Update the acquire database if present
1207  if (acquireInfo_)
1208  {
1209  auto& session{acquireInfo_->SQLiteDB->getSession()};
1210  soci::blob sociBlob(session);
1211 
1212  if (!acquireInfo_->storedSeqs.empty())
1213  convert(to_string(acquireInfo_->storedSeqs), sociBlob);
1214 
1215  if (ledger->info().seq == lastSeq_)
1216  {
1217  // Store shard's last ledger hash
1218  session << "UPDATE Shard "
1219  "SET LastLedgerHash = :lastLedgerHash,"
1220  "StoredLedgerSeqs = :storedLedgerSeqs "
1221  "WHERE ShardIndex = :shardIndex;",
1222  soci::use(sHash), soci::use(sociBlob), soci::use(index_);
1223  }
1224  else
1225  {
1226  session << "UPDATE Shard "
1227  "SET StoredLedgerSeqs = :storedLedgerSeqs "
1228  "WHERE ShardIndex = :shardIndex;",
1229  soci::use(sociBlob), soci::use(index_);
1230  }
1231  }
1232  }
1233  catch (std::exception const& e)
1234  {
1235  JLOG(j_.fatal()) << "shard " << index_
1236  << ". Exception caught in function " << __func__
1237  << ". Error: " << e.what();
1238  return false;
1239  }
1240 
1241  return true;
1242 }
1243 
1244 void
1246 {
1247  fileSz_ = 0;
1248  fdRequired_ = 0;
1249  try
1250  {
1251  using namespace boost::filesystem;
1252  for (auto const& d : directory_iterator(dir_))
1253  {
1254  if (is_regular_file(d))
1255  {
1256  fileSz_ += file_size(d);
1257  ++fdRequired_;
1258  }
1259  }
1260  }
1261  catch (std::exception const& e)
1262  {
1263  JLOG(j_.fatal()) << "shard " << index_
1264  << ". Exception caught in function " << __func__
1265  << ". Error: " << e.what();
1266  }
1267 }
1268 
1269 bool
1271  std::shared_ptr<Ledger const> const& ledger,
1272  std::shared_ptr<Ledger const> const& next) const
1273 {
1274  auto fail = [j = j_, index = index_, &ledger](std::string const& msg) {
1275  JLOG(j.error()) << "shard " << index << ". " << msg
1276  << (ledger->info().hash.isZero() ? ""
1277  : ". Ledger hash " +
1278  to_string(ledger->info().hash))
1279  << (ledger->info().seq == 0 ? ""
1280  : ". Ledger sequence " +
1281  std::to_string(ledger->info().seq));
1282  return false;
1283  };
1284 
1285  if (ledger->info().hash.isZero())
1286  return fail("Invalid ledger hash");
1287  if (ledger->info().accountHash.isZero())
1288  return fail("Invalid ledger account hash");
1289 
1290  bool error{false};
1291  auto visit = [this, &error](SHAMapTreeNode const& node) {
1292  if (stop_)
1293  return false;
1294  if (!verifyFetch(node.getHash().as_uint256()))
1295  error = true;
1296  return !error;
1297  };
1298 
1299  // Validate the state map
1300  if (ledger->stateMap().getHash().isNonZero())
1301  {
1302  if (!ledger->stateMap().isValid())
1303  return fail("Invalid state map");
1304 
1305  try
1306  {
1307  if (next && next->info().parentHash == ledger->info().hash)
1308  ledger->stateMap().visitDifferences(&next->stateMap(), visit);
1309  else
1310  ledger->stateMap().visitNodes(visit);
1311  }
1312  catch (std::exception const& e)
1313  {
1314  return fail(
1315  std::string(". Exception caught in function ") + __func__ +
1316  ". Error: " + e.what());
1317  }
1318 
1319  if (stop_)
1320  return false;
1321  if (error)
1322  return fail("Invalid state map");
1323  }
1324 
1325  // Validate the transaction map
1326  if (ledger->info().txHash.isNonZero())
1327  {
1328  if (!ledger->txMap().isValid())
1329  return fail("Invalid transaction map");
1330 
1331  try
1332  {
1333  ledger->txMap().visitNodes(visit);
1334  }
1335  catch (std::exception const& e)
1336  {
1337  return fail(
1338  std::string(". Exception caught in function ") + __func__ +
1339  ". Error: " + e.what());
1340  }
1341  if (stop_)
1342  return false;
1343  if (error)
1344  return fail("Invalid transaction map");
1345  }
1346 
1347  return true;
1348 }
1349 
1351 Shard::verifyFetch(uint256 const& hash) const
1352 {
1353  std::shared_ptr<NodeObject> nodeObject;
1354  auto fail =
1355  [j = j_, index = index_, &hash, &nodeObject](std::string const& msg) {
1356  JLOG(j.error()) << "shard " << index << ". " << msg
1357  << ". Node object hash " << to_string(hash);
1358  nodeObject.reset();
1359  return nodeObject;
1360  };
1361 
1362  try
1363  {
1364  switch (backend_->fetch(hash.data(), &nodeObject))
1365  {
1366  case ok:
1367  // Verify that the hash of node object matches the payload
1368  if (nodeObject->getHash() !=
1369  sha512Half(makeSlice(nodeObject->getData())))
1370  return fail("Node object hash does not match payload");
1371  return nodeObject;
1372  case notFound:
1373  return fail("Missing node object");
1374  case dataCorrupt:
1375  return fail("Corrupt node object");
1376  default:
1377  return fail("Unknown error");
1378  }
1379  }
1380  catch (std::exception const& e)
1381  {
1382  return fail(
1383  std::string(". Exception caught in function ") + __func__ +
1384  ". Error: " + e.what());
1385  }
1386 }
1387 
1390 {
1391  if (stop_)
1392  return {nullptr};
1393 
1394  std::lock_guard lock(mutex_);
1395  if (!backend_)
1396  {
1397  JLOG(j_.error()) << "shard " << index_ << " not initialized";
1398  return {nullptr};
1399  }
1400  if (!backend_->isOpen())
1401  {
1402  if (!open(lock))
1403  return {nullptr};
1404  }
1405  else if (state_ == final)
1407 
1408  return Shard::Count(&backendCount_);
1409 }
1410 
1411 } // namespace NodeStore
1412 } // 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:288
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::NodeStore::Shard::getDesiredAsyncReadCount
int getDesiredAsyncReadCount()
Definition: Shard.cpp:550
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:266
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:53
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:302
ripple::NodeStore::Shard::removeOnDestroy_
std::atomic< bool > removeOnDestroy_
Definition: Shard.h:321
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:330
ripple::DatabaseCon::Setup
Definition: DatabaseCon.h:84
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:309
ripple::SizedItem::nodeCacheSize
@ nodeCacheSize
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:814
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
std::chrono::seconds
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:575
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::stopwatch
Stopwatch & stopwatch()
Returns an instance of a wall clock.
Definition: chrono.h:86
ripple::SizedItem::nodeCacheAge
@ nodeCacheAge
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:217
ripple::NodeStore::Shard::lastSeq_
const std::uint32_t lastSeq_
Definition: Shard.h:275
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:1351
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:132
ripple::NodeStore::Shard::backend_
std::unique_ptr< Backend > backend_
Definition: Shard.h:297
ripple::NodeStore::Shard::isLegacy
bool isLegacy() const
Returns true if shard is older, without final key data.
Definition: Shard.cpp:591
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:212
ripple::NodeStore::Shard::storeSQLite
bool storeSQLite(std::shared_ptr< Ledger const > const &ledger, std::lock_guard< std::mutex > const &)
Definition: Shard.cpp:1075
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:265
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:598
ripple::NodeStore::Shard::containsLedger
bool containsLedger(std::uint32_t ledgerSeq) const
Definition: Shard.cpp:513
ripple::NodeStore::Shard::fileSz_
std::uint64_t fileSz_
Definition: Shard.h:291
ripple::NodeStore::Shard::StoreLedgerResult::error
bool error
Definition: Shard.h:133
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:211
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:531
ripple::SerialIter::get256
uint256 get256()
Definition: Serializer.h:374
ripple::Config
Definition: Config.h:69
ripple::NodeStore::Shard::initSQLite
bool initSQLite(std::lock_guard< std::mutex > const &)
Definition: Shard.cpp:1001
ripple::Application::config
virtual Config & config()=0
ripple::NodeStore::Shard::fetchNodeObject
std::shared_ptr< NodeObject > fetchNodeObject(uint256 const &hash, FetchReport &fetchReport)
Definition: Shard.cpp:247
ripple::NodeStore::Shard::state_
std::atomic< State > state_
Definition: Shard.h:318
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::Shard::pCache_
std::unique_ptr< PCache > pCache_
Definition: Shard.h:282
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:272
beast::Journal::error
Stream error() const
Definition: Journal.h:333
ripple::NodeStore::batchWritePreallocationSize
@ batchWritePreallocationSize
Definition: nodestore/Types.h:34
ripple::Application::logs
virtual Logs & logs()=0
ripple::NodeStore::Shard::maxLedgers_
const std::uint32_t maxLedgers_
Definition: Shard.h:279
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:61
ripple::NodeStore::Shard::nCache_
std::unique_ptr< NCache > nCache_
Definition: Shard.h:285
ripple::NodeStore::Shard::StoreLedgerResult
Store a ledger.
Definition: Shard.h:129
ripple::SizedItem::txnDBCache
@ txnDBCache
ripple::NodeStore::Shard::acquireInfo_
std::unique_ptr< AcquireInfo > acquireInfo_
Definition: Shard.h:309
ripple::NodeStore::Shard::app_
Application & app_
Definition: Shard.h:264
ripple::NodeStore::Status
Status
Return codes from Backend operations.
Definition: nodestore/Types.h:44
ripple::Serializer
Definition: Serializer.h:39
ripple::NodeStore::Shard::fetchNodeObjectFromCache
bool fetchNodeObjectFromCache(uint256 const &hash, std::shared_ptr< NodeObject > &nodeObject)
Definition: Shard.cpp:315
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:324
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:1389
ripple::Application::getShardFamily
virtual Family * getShardFamily()=0
ripple::NodeStore::Shard::StoreLedgerResult::count
std::uint64_t count
Definition: Shard.h:131
ripple::NodeStore::Shard::prepare
boost::optional< std::uint32_t > prepare()
Definition: Shard.cpp:188
ripple::NodeStore::FetchReport::wasFound
bool wasFound
Definition: ripple/nodestore/Scheduler.h:41
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:851
ripple::TxDBPragma
constexpr std::array TxDBPragma
Definition: DBInit.h:76
ripple::NodeStore::Shard::legacy_
bool legacy_
Definition: Shard.h:313
std::vector::empty
T empty(T... args)
ripple::NodeStore::Shard::fdRequired_
std::uint32_t fdRequired_
Definition: Shard.h:294
ripple::NodeStore::Shard::index
std::uint32_t index() const
Definition: Shard.h:151
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:1270
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:1245
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:460
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:305
ripple::NodeStore::Shard::Count
Definition: Shard.h:220
ripple::NodeStore::Shard::index_
const std::uint32_t index_
Definition: Shard.h:269
ripple::NodeStore::FetchReport::wentToDisk
bool wentToDisk
Definition: ripple/nodestore/Scheduler.h:40
ripple::NodeStore::Shard::stop_
std::atomic< bool > stop_
Definition: Shard.h:316
ripple::NodeStore::Shard::backendCount_
std::atomic< std::uint32_t > backendCount_
Definition: Shard.h:299
ripple::NodeStore::Shard::getLastUse
std::chrono::steady_clock::time_point getLastUse() const
Definition: Shard.cpp:568
ripple::NodeStore::asyncDivider
@ asyncDivider
Definition: nodestore/impl/Tuning.h:32
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:582
std::exception::what
T what(T... args)
ripple::NodeStore::Shard::getCacheHitRate
float getCacheHitRate()
Definition: Shard.cpp:559
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)