20 #include <ripple/app/ledger/InboundLedger.h>
21 #include <ripple/app/main/DBInit.h>
22 #include <ripple/app/rdb/RelationalDBInterface_global.h>
23 #include <ripple/app/rdb/RelationalDBInterface_shards.h>
24 #include <ripple/basics/StringUtilities.h>
25 #include <ripple/core/ConfigSections.h>
26 #include <ripple/nodestore/Manager.h>
27 #include <ripple/nodestore/impl/DeterministicShard.h>
28 #include <ripple/nodestore/impl/Shard.h>
29 #include <ripple/protocol/digest.h>
31 #include <boost/algorithm/string.hpp>
32 #include <boost/range/adaptor/transformed.hpp>
44 :
Shard(app, db, index,
"", j)
52 boost::filesystem::path
const& dir,
57 , firstSeq_(db.firstLedgerSeq(index))
58 , lastSeq_(
std::max(firstSeq_, db.lastLedgerSeq(index)))
59 , maxLedgers_(db.maxLedgers(index))
60 , dir_((dir.empty() ? db.getRootDir() : dir) /
std::
to_string(index_))
75 <<
" backend in use, unable to remove directory";
88 boost::filesystem::remove_all(
dir_);
93 <<
". Exception caught in function " << __func__
94 <<
". Error: " << e.
what();
106 JLOG(
j_.
error()) <<
"shard " <<
index_ <<
" failed to find factory for "
110 section.set(
"path",
dir_.string());
115 JLOG(
j_.
error()) <<
"shard " <<
index_ <<
" already initialized";
136 JLOG(
j_.
error()) <<
"shard " <<
index_ <<
" not initialized";
158 JLOG(
j_.
error()) <<
"shard " <<
index_ <<
" not initialized";
171 <<
". Exception caught in function " << __func__
172 <<
". Error: " << e.
what();
193 <<
" prepare called when not acquiring";
201 <<
" missing acquire SQLite database";
216 if (nodeObject->getHash() !=
finalKey)
235 <<
". Exception caught in function " << __func__
236 <<
". Error: " << e.
what();
261 <<
". Exception caught in function " << __func__
262 <<
". Error: " << e.
what();
273 <<
"shard " <<
index_ <<
". Corrupt node object at hash "
279 <<
"shard " <<
index_ <<
". Unknown status=" << status
280 <<
" fetching node object at hash " <<
to_string(hash);
305 JLOG(
j_.
trace()) <<
"shard " <<
index_ <<
". Ledger already stored";
310 JLOG(
j_.
error()) <<
"shard " <<
index_ <<
". Source ledger sequence "
311 << srcLedger->info().seq <<
". " << msg;
316 if (srcLedger->info().hash.isZero())
317 return fail(
"Invalid hash");
318 if (srcLedger->info().accountHash.isZero())
319 return fail(
"Invalid account hash");
321 auto& srcDB{
const_cast<Database&
>(srcLedger->stateMap().family().db())};
323 return fail(
"Source and destination databases are the same");
327 return fail(
"Failed to lock backend");
331 auto storeBatch = [&]() {
333 for (
auto const& nodeObject : batch)
334 sz += nodeObject->getData().size();
343 std::string(
". Exception caught in function ") + __func__ +
344 ". Error: " + e.
what());
348 result.
count += batch.size();
358 addRaw(srcLedger->info(), s);
368 if (
auto nodeObject = srcDB.fetchNodeObject(
369 node.getHash().as_uint256(), srcLedger->info().seq))
382 if (srcLedger->stateMap().getHash().isNonZero())
384 if (!srcLedger->stateMap().isValid())
385 return fail(
"Invalid state map");
387 if (next && next->info().parentHash == srcLedger->info().hash)
389 auto have = next->stateMap().snapShot(
false);
390 srcLedger->stateMap().snapShot(
false)->visitDifferences(
394 srcLedger->stateMap().snapShot(
false)->visitNodes(visit);
396 return fail(
"Failed to store state map");
400 if (srcLedger->info().txHash.isNonZero())
402 if (!srcLedger->txMap().isValid())
403 return fail(
"Invalid transaction map");
405 srcLedger->txMap().snapShot(
false)->visitNodes(visit);
407 return fail(
"Failed to store transaction map");
410 if (!batch.
empty() && !storeBatch())
411 return fail(
"Failed to store");
431 auto const ledgerSeq{ledger->info().seq};
432 if (ledgerSeq < firstSeq_ || ledgerSeq >
lastSeq_)
433 return fail(
"Invalid ledger sequence " +
std::to_string(ledgerSeq));
446 return fail(
"Missing acquire SQLite database");
448 if (boost::icl::contains(
acquireInfo_->storedSeqs, ledgerSeq))
451 JLOG(
j_.
debug()) <<
"shard " <<
index_ <<
" ledger sequence "
452 << ledgerSeq <<
" already stored";
458 return fail(
"Failed to store ledger");
468 soci::blob sociBlob(*session);
473 auto const sHash{
to_string(ledger->info().hash)};
474 *session <<
"UPDATE Shard "
475 "SET LastLedgerHash = :lastLedgerHash,"
476 "StoredLedgerSeqs = :storedLedgerSeqs "
477 "WHERE ShardIndex = :shardIndex;",
478 soci::use(sHash), soci::use(sociBlob), soci::use(
index_);
482 *session <<
"UPDATE Shard "
483 "SET StoredLedgerSeqs = :storedLedgerSeqs "
484 "WHERE ShardIndex = :shardIndex;",
485 soci::use(sociBlob), soci::use(
index_);
492 std::string(
". Exception caught in function ") + __func__ +
493 ". Error: " + e.
what());
502 JLOG(
j_.
trace()) <<
"shard " <<
index_ <<
" stored ledger sequence "
510 if (ledgerSeq < firstSeq_ || ledgerSeq >
lastSeq_)
519 <<
" missing acquire SQLite database";
522 return boost::icl::contains(
acquireInfo_->storedSeqs, ledgerSeq);
525 std::chrono::steady_clock::time_point
566 << (hash.isZero() ?
""
568 << (ledgerSeq == 0 ?
""
569 :
". Ledger sequence " +
588 nodeObject->getData().data(), nodeObject->getData().size());
590 return fail(
"invalid version");
593 return fail(
"out of range ledger sequences");
596 return fail(
"invalid last ledger hash");
603 return fail(
"missing acquire SQLite database");
609 return fail(
"missing or invalid ShardIndex");
612 return fail(
"missing LastLedgerHash");
614 if (!hash.parseHex(*seqshash.hash) || hash.isZero())
615 return fail(
"invalid LastLedgerHash");
617 if (!seqshash.sequences)
618 return fail(
"missing StoredLedgerSeqs");
621 if (!
from_string(storedSeqs, *seqshash.sequences) ||
622 boost::icl::first(storedSeqs) !=
firstSeq_ ||
623 boost::icl::last(storedSeqs) !=
lastSeq_ ||
626 return fail(
"invalid StoredLedgerSeqs");
633 std::string(
". Exception caught in function ") + __func__ +
634 ". Error: " + e.
what());
639 if (referenceHash && *referenceHash != hash)
640 return fail(
"invalid last ledger hash");
646 auto const lastLedgerHash{hash};
649 auto const treeNodeCache{shardFamily.getTreeNodeCache(
lastSeq_)};
652 fullBelowCache->reset();
653 treeNodeCache->reset();
664 return fail(
"Failed to create deterministic shard");
676 return fail(
"invalid ledger");
678 ledger = std::make_shared<Ledger>(
682 if (ledger->info().seq != ledgerSeq)
683 return fail(
"invalid ledger sequence");
684 if (ledger->info().hash != hash)
685 return fail(
"invalid ledger hash");
687 ledger->stateMap().setLedgerSeq(ledgerSeq);
688 ledger->txMap().setLedgerSeq(ledgerSeq);
689 ledger->setImmutable(config);
690 if (!ledger->stateMap().fetchRoot(
691 SHAMapHash{ledger->info().accountHash},
nullptr))
693 return fail(
"missing root STATE node");
695 if (ledger->info().txHash.isNonZero() &&
696 !ledger->txMap().fetchRoot(
699 return fail(
"missing root TXN node");
703 return fail(
"failed to verify ledger");
705 if (!dShard->store(nodeObject))
706 return fail(
"failed to store node object");
709 return fail(
"failed storing to SQLite databases");
711 hash = ledger->info().parentHash;
712 next = std::move(ledger);
719 fullBelowCache->reset();
720 treeNodeCache->reset();
759 auto const nodeObject{
761 if (!dShard->store(nodeObject))
762 return fail(
"failed to store node object");
796 remove(
dir_ /
"nudb.key");
797 remove(
dir_ /
"nudb.dat");
798 rename(dShard->getDir() /
"nudb.key",
dir_ /
"nudb.key");
799 rename(dShard->getDir() /
"nudb.dat",
dir_ /
"nudb.dat");
803 return fail(
"failed to open");
813 std::string(
". Exception caught in function ") + __func__ +
814 ". Error: " + e.
what());
823 using namespace boost::filesystem;
825 auto preexist{
false};
826 auto fail = [
this, &preexist](
std::string const& msg) {
844 auto createAcquireInfo = [
this, &config]() {
846 setup.
startUp = config.standalone() ? config.LOAD : config.START_UP;
863 preexist = exists(
dir_);
880 return fail(
"invalid acquire SQLite database");
886 return fail(
"invalid StoredLedgerSeqs");
888 if (boost::icl::first(storedSeqs) <
firstSeq_ ||
889 boost::icl::last(storedSeqs) >
lastSeq_)
891 return fail(
"invalid StoredLedgerSeqs");
895 progress_ = boost::icl::length(storedSeqs);
907 return fail(
"incompatible, missing backend final key");
912 nodeObject->getData().data(), nodeObject->getData().size());
914 return fail(
"invalid version");
917 return fail(
"out of range ledger sequences");
920 return fail(
"invalid last ledger hash");
936 std::string(
". Exception caught in function ") + __func__ +
937 ". Error: " + e.
what());
953 setup.
startUp = config.standalone() ? config.LOAD : config.START_UP;
977 boost::format(
"PRAGMA cache_size=-%d;") %
983 boost::format(
"PRAGMA cache_size=-%d;") %
1001 boost::format(
"PRAGMA cache_size=-%d;") %
1006 boost::format(
"PRAGMA cache_size=-%d;") %
1015 <<
". Exception caught in function " << __func__
1016 <<
". Error: " << e.
what();
1060 <<
". Exception caught in function " << __func__
1061 <<
". Error: " << e.
what();
1075 using namespace boost::filesystem;
1076 for (
auto const& d : directory_iterator(
dir_))
1078 if (is_regular_file(d))
1088 <<
". Exception caught in function " << __func__
1089 <<
". Error: " << e.
what();
1100 JLOG(j.error()) <<
"shard " <<
index <<
". " << msg
1101 << (ledger->info().hash.isZero() ?
""
1102 :
". Ledger hash " +
1104 << (ledger->info().seq == 0 ?
""
1105 :
". Ledger sequence " +
1110 if (ledger->info().hash.isZero())
1111 return fail(
"Invalid ledger hash");
1112 if (ledger->info().accountHash.isZero())
1113 return fail(
"Invalid ledger account hash");
1116 auto visit = [
this, &error, &dShard](
SHAMapTreeNode const& node) {
1120 auto nodeObject{
verifyFetch(node.getHash().as_uint256())};
1121 if (!nodeObject || !dShard->store(nodeObject))
1128 if (ledger->stateMap().getHash().isNonZero())
1130 if (!ledger->stateMap().isValid())
1131 return fail(
"Invalid state map");
1135 if (next && next->info().parentHash == ledger->info().hash)
1136 ledger->stateMap().visitDifferences(&next->stateMap(), visit);
1138 ledger->stateMap().visitNodes(visit);
1143 std::string(
". Exception caught in function ") + __func__ +
1144 ". Error: " + e.
what());
1150 return fail(
"Invalid state map");
1154 if (ledger->info().txHash.isNonZero())
1156 if (!ledger->txMap().isValid())
1157 return fail(
"Invalid transaction map");
1161 ledger->txMap().visitNodes(visit);
1166 std::string(
". Exception caught in function ") + __func__ +
1167 ". Error: " + e.
what());
1173 return fail(
"Invalid transaction map");
1185 JLOG(j.error()) <<
"shard " <<
index <<
". " << msg
1186 <<
". Node object hash " <<
to_string(hash);
1193 switch (
backend_->fetch(hash.data(), &nodeObject))
1197 if (nodeObject->getHash() !=
1199 return fail(
"Node object hash does not match payload");
1202 return fail(
"Missing node object");
1204 return fail(
"Corrupt node object");
1206 return fail(
"Unknown error");
1212 std::string(
". Exception caught in function ") + __func__ +
1213 ". Error: " + e.
what());
1226 JLOG(
j_.
error()) <<
"shard " <<
index_ <<
" not initialized";
1242 std::function<
bool(soci::session& session)>
const& callback,
1245 return callback(*db);
1254 return callback(*db,
index_);
Holds a collection of configuration values.
const boost::filesystem::path dir_
constexpr auto AcquireShardDBName
@ ledgerMaster
ledger master data for signing
virtual std::shared_ptr< TreeNodeCache > getTreeNodeCache(std::uint32_t ledgerSeq)=0
Return a pointer to the Family Tree Node Cache.
std::unique_ptr< DatabaseCon > makeAcquireDB(DatabaseCon::Setup const &setup, DatabaseCon::CheckpointerSetup const &checkpointerSetup)
makeAcquireDB Opens shard acquire DB and returns its descriptor.
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)
Persistency layer for NodeObject.
std::unique_ptr< DatabaseCon > lgrSQLiteDB_
std::atomic< bool > removeOnDestroy_
StoreLedgerResult storeLedger(std::shared_ptr< Ledger const > const &srcLedger, std::shared_ptr< Ledger const > const &next)
Stream trace() const
Severity stream access functions.
std::optional< std::uint32_t > prepare()
void convert(soci::blob &from, std::vector< std::uint8_t > &to)
void addRaw(LedgerInfo const &info, Serializer &s, bool includeHash)
std::pair< bool, AcquireShardSeqsHash > selectAcquireDBLedgerSeqsHash(soci::session &session, std::uint32_t index)
selectAcquireDBLedgerSeqsHash Returns set of acquired ledgers and hash for given shard.
void insertAcquireDBIndex(soci::session &session, std::uint32_t index)
insertAcquireDBIndex Adds new shard index to shard acquire DB.
Config::StartUpType startUp
static std::string shardDatabase()
Shard(Shard const &)=delete
Copy constructor (disallowed)
static std::shared_ptr< NodeObject > createObject(NodeObjectType type, Blob &&data, uint256 const &hash)
Create an object from fields.
std::shared_ptr< DeterministicShard > make_DeterministicShard(Application &app, boost::filesystem::path const &shardDir, std::uint32_t shardIndex, Serializer const &finalKey, beast::Journal j)
Creates shared pointer to deterministic shard and initializes it.
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...
constexpr auto kilobytes(T value) noexcept
Contains information about a fetch operation.
bool isOpen() const
Returns true if the database are open.
boost::filesystem::path dataDir
bool from_string(RangeSet< T > &rs, std::string const &s)
Convert the given styled string to a RangeSet.
virtual std::shared_ptr< FullBelowCache > getFullBelowCache(std::uint32_t ledgerSeq)=0
Return a pointer to the Family Full Below Cache.
static const uint256 finalKey
const std::uint32_t lastSeq_
LedgerInfo deserializePrefixedHeader(Slice data, bool hasHash)
Deserialize a ledger header (prefixed with 4 bytes) from a byte array.
virtual NodeStore::Database & db()=0
std::shared_ptr< NodeObject > verifyFetch(uint256 const &hash) const
bool tryClose()
Try to close databases if not in use.
std::unique_ptr< Backend > backend_
@ batchWritePreallocationSize
bool isLegacy() const
Returns true if shard is older, without final key data.
static constexpr std::uint32_t version
bool storeSQLite(std::shared_ptr< Ledger const > const &ledger)
void updateAcquireDB(soci::session &session, std::shared_ptr< Ledger const > const &ledger, std::uint32_t index, std::uint32_t lastSeq, std::optional< std::string > const &seqs)
updateAcquireDB Updates information in acquire DB.
bool containsLedger(std::uint32_t ledgerSeq) const
int getValueFor(SizedItem item, std::optional< std::size_t > node=std::nullopt) const
Retrieve the default value for the item at the specified node size.
bool storeNodeObject(std::shared_ptr< NodeObject > const &nodeObject)
bool initSQLite(std::lock_guard< std::mutex > const &)
virtual Config & config()=0
std::shared_ptr< NodeObject > fetchNodeObject(uint256 const &hash, FetchReport &fetchReport)
constexpr auto megabytes(T value) noexcept
A collection of historical shards.
virtual JobQueue & getJobQueue()=0
const std::uint32_t firstSeq_
const std::uint32_t maxLedgers_
A generic endpoint for log messages.
bool verifyLedger(std::shared_ptr< Ledger const > const &ledger, std::shared_ptr< Ledger const > const &next, std::shared_ptr< DeterministicShard > const &dShard) const
Scheduling for asynchronous backend activity.
std::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.
std::uint32_t index() const noexcept
std::unique_ptr< AcquireInfo > acquireInfo_
Status
Return codes from Backend operations.
bool updateLedgerDBs(soci::session &txsession, soci::session &lgrsession, std::shared_ptr< Ledger const > const &ledger, std::uint32_t index, std::atomic< bool > &stop, beast::Journal j)
updateLedgerDBs Save given ledger to shard databases.
virtual Factory * find(std::string const &name)=0
Return a pointer to the matching factory if it exists.
std::atomic< std::uint32_t > progress_
T emplace_back(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
std::chrono::steady_clock::time_point lastAccess_
int addBitString(base_uint< Bits, Tag > const &v)
static constexpr std::size_t keyBytes
Shard::Count makeBackendCount()
virtual Family * getShardFamily()=0
sha512_half_hasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
bool open(std::lock_guard< std::mutex > const &lock)
std::atomic< ShardState > state_
bool doCallForSQL(std::function< bool(soci::session &session)> const &callback, LockedSociSession &&db)
std::uint32_t fdRequired_
DatabasePair makeShardIncompleteLedgerDBs(Config const &config, DatabaseCon::Setup const &setup, DatabaseCon::CheckpointerSetup const &checkpointerSetup)
makeShardIncompleteLedgerDBs Opens shard databases for not fully downloaded or verified shard and ret...
bool init(Scheduler &scheduler, nudb::context &context)
Initialize shard.
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
int add32(std::uint32_t i)
Information about the notional ledger backing the view.
void setFileStats(std::lock_guard< std::mutex > const &)
bool finalize(bool writeSQLite, std::optional< uint256 > const &referenceHash)
Finalize shard by walking its ledgers, verifying each Merkle tree and creating a deterministic backen...
std::pair< bool, std::optional< std::string > > selectAcquireDBLedgerSeqs(soci::session &session, std::uint32_t index)
selectAcquireDBLedgerSeqs Returns set of acquired ledgers for given shard.
static Manager & instance()
Returns the instance of the manager singleton.
bool setLedgerStored(std::shared_ptr< Ledger const > const &ledger)
std::unique_ptr< DatabaseCon > txSQLiteDB_
const std::uint32_t index_
std::atomic< bool > stop_
std::atomic< std::uint32_t > backendCount_
std::chrono::steady_clock::time_point getLastUse() const
std::int32_t getWriteLoad()
T & get(EitherAmount &amt)
DatabasePair makeShardCompleteLedgerDBs(Config const &config, DatabaseCon::Setup const &setup)
makeShardCompleteLedgerDBs Opens shard databases for already verified shard and returns its descripto...
Section & section(std::string const &name)
Returns the section with the given name.
std::atomic< bool > busy_