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)))
60 index == db.earliestShardIndex() ? lastSeq_ - firstSeq_ + 1
61 : db.ledgersPerShard())
62 , dir_((dir.empty() ? db.getRootDir() : dir) /
std::
to_string(index_))
77 <<
" backend in use, unable to remove directory";
90 boost::filesystem::remove_all(
dir_);
95 <<
". Exception caught in function " << __func__
96 <<
". Error: " << e.
what();
104 std::string const type{get<std::string>(section,
"type",
"nudb")};
108 JLOG(
j_.
error()) <<
"shard " <<
index_ <<
" failed to find factory for "
112 section.set(
"path",
dir_.string());
117 JLOG(
j_.
error()) <<
"shard " <<
index_ <<
" already initialized";
138 JLOG(
j_.
error()) <<
"shard " <<
index_ <<
" not initialized";
160 JLOG(
j_.
error()) <<
"shard " <<
index_ <<
" not initialized";
173 <<
". Exception caught in function " << __func__
174 <<
". Error: " << e.
what();
195 <<
" prepare called when not acquiring";
203 <<
" missing acquire SQLite database";
218 if (nodeObject->getHash() !=
finalKey)
237 <<
". Exception caught in function " << __func__
238 <<
". Error: " << e.
what();
263 <<
". Exception caught in function " << __func__
264 <<
". Error: " << e.
what();
275 <<
"shard " <<
index_ <<
". Corrupt node object at hash "
281 <<
"shard " <<
index_ <<
". Unknown status=" << status
282 <<
" fetching node object at hash " <<
to_string(hash);
307 JLOG(
j_.
trace()) <<
"shard " <<
index_ <<
". Ledger already stored";
312 JLOG(
j_.
error()) <<
"shard " <<
index_ <<
". Source ledger sequence "
313 << srcLedger->info().seq <<
". " << msg;
318 if (srcLedger->info().hash.isZero())
319 return fail(
"Invalid hash");
320 if (srcLedger->info().accountHash.isZero())
321 return fail(
"Invalid account hash");
323 auto& srcDB{
const_cast<Database&
>(srcLedger->stateMap().family().db())};
325 return fail(
"Source and destination databases are the same");
329 return fail(
"Failed to lock backend");
333 auto storeBatch = [&]() {
335 for (
auto const& nodeObject : batch)
336 sz += nodeObject->getData().size();
345 std::string(
". Exception caught in function ") + __func__ +
346 ". Error: " + e.
what());
350 result.
count += batch.size();
360 addRaw(srcLedger->info(), s);
370 if (
auto nodeObject = srcDB.fetchNodeObject(
371 node.getHash().as_uint256(), srcLedger->info().seq))
384 if (srcLedger->stateMap().getHash().isNonZero())
386 if (!srcLedger->stateMap().isValid())
387 return fail(
"Invalid state map");
389 if (next && next->info().parentHash == srcLedger->info().hash)
391 auto have = next->stateMap().snapShot(
false);
392 srcLedger->stateMap().snapShot(
false)->visitDifferences(
396 srcLedger->stateMap().snapShot(
false)->visitNodes(visit);
398 return fail(
"Failed to store state map");
402 if (srcLedger->info().txHash.isNonZero())
404 if (!srcLedger->txMap().isValid())
405 return fail(
"Invalid transaction map");
407 srcLedger->txMap().snapShot(
false)->visitNodes(visit);
409 return fail(
"Failed to store transaction map");
412 if (!batch.
empty() && !storeBatch())
413 return fail(
"Failed to store");
428 auto const ledgerSeq{ledger->info().seq};
429 if (ledgerSeq < firstSeq_ || ledgerSeq >
lastSeq_)
431 JLOG(
j_.
error()) <<
"shard " <<
index_ <<
" invalid ledger sequence "
449 <<
"shard " <<
index_ <<
" missing acquire SQLite database";
452 if (boost::icl::contains(
acquireInfo_->storedSeqs, ledgerSeq))
455 JLOG(
j_.
debug()) <<
"shard " <<
index_ <<
" ledger sequence "
456 << ledgerSeq <<
" already stored";
472 soci::blob sociBlob(*session);
477 auto const sHash{
to_string(ledger->info().hash)};
478 *session <<
"UPDATE Shard "
479 "SET LastLedgerHash = :lastLedgerHash,"
480 "StoredLedgerSeqs = :storedLedgerSeqs "
481 "WHERE ShardIndex = :shardIndex;",
482 soci::use(sHash), soci::use(sociBlob), soci::use(
index_);
486 *session <<
"UPDATE Shard "
487 "SET StoredLedgerSeqs = :storedLedgerSeqs "
488 "WHERE ShardIndex = :shardIndex;",
489 soci::use(sociBlob), soci::use(
index_);
495 <<
". Exception caught in function " << __func__
496 <<
". Error: " << e.
what();
505 JLOG(
j_.
trace()) <<
"shard " <<
index_ <<
" stored ledger sequence "
513 if (ledgerSeq < firstSeq_ || ledgerSeq >
lastSeq_)
522 <<
" missing acquire SQLite database";
525 return boost::icl::contains(
acquireInfo_->storedSeqs, ledgerSeq);
534 std::chrono::steady_clock::time_point
577 << (hash.isZero() ?
""
579 << (ledgerSeq == 0 ?
""
580 :
". Ledger sequence " +
605 nodeObject->getData().data(), nodeObject->getData().size());
607 return fail(
"invalid version");
610 return fail(
"out of range ledger sequences");
613 return fail(
"invalid last ledger hash");
620 return fail(
"missing acquire SQLite database");
626 return fail(
"missing or invalid ShardIndex");
629 return fail(
"missing LastLedgerHash");
631 if (!hash.parseHex(*seqshash.hash) || hash.isZero())
632 return fail(
"invalid LastLedgerHash");
634 if (!seqshash.sequences)
635 return fail(
"missing StoredLedgerSeqs");
638 if (!
from_string(storedSeqs, *seqshash.sequences) ||
639 boost::icl::first(storedSeqs) !=
firstSeq_ ||
640 boost::icl::last(storedSeqs) !=
lastSeq_ ||
643 return fail(
"invalid StoredLedgerSeqs");
650 std::string(
". Exception caught in function ") + __func__ +
651 ". Error: " + e.
what());
656 if (referenceHash && *referenceHash != hash)
657 return fail(
"invalid last ledger hash");
663 auto const lastLedgerHash{hash};
666 auto const treeNodeCache{shardFamily.getTreeNodeCache(
lastSeq_)};
669 fullBelowCache->reset();
670 treeNodeCache->reset();
681 return fail(
"Failed to create deterministic shard");
693 return fail(
"invalid ledger");
695 ledger = std::make_shared<Ledger>(
699 if (ledger->info().seq != ledgerSeq)
700 return fail(
"invalid ledger sequence");
701 if (ledger->info().hash != hash)
702 return fail(
"invalid ledger hash");
704 ledger->stateMap().setLedgerSeq(ledgerSeq);
705 ledger->txMap().setLedgerSeq(ledgerSeq);
706 ledger->setImmutable(config);
707 if (!ledger->stateMap().fetchRoot(
708 SHAMapHash{ledger->info().accountHash},
nullptr))
710 return fail(
"missing root STATE node");
712 if (ledger->info().txHash.isNonZero() &&
713 !ledger->txMap().fetchRoot(
716 return fail(
"missing root TXN node");
720 return fail(
"failed to verify ledger");
722 if (!dShard->store(nodeObject))
723 return fail(
"failed to store node object");
726 return fail(
"failed storing to SQLite databases");
728 hash = ledger->info().parentHash;
729 next = std::move(ledger);
732 fullBelowCache->reset();
733 treeNodeCache->reset();
772 auto const nodeObject{
774 if (!dShard->store(nodeObject))
775 return fail(
"failed to store node object");
809 remove(
dir_ /
"nudb.key");
810 remove(
dir_ /
"nudb.dat");
811 rename(dShard->getDir() /
"nudb.key",
dir_ /
"nudb.key");
812 rename(dShard->getDir() /
"nudb.dat",
dir_ /
"nudb.dat");
824 std::string(
". Exception caught in function ") + __func__ +
825 ". Error: " + e.
what());
834 using namespace boost::filesystem;
836 auto preexist{
false};
837 auto fail = [
this, &preexist](
std::string const& msg) {
854 auto createAcquireInfo = [
this, &config]() {
858 setup.
startUp = config.standalone() ? config.LOAD : config.START_UP;
872 preexist = exists(
dir_);
889 return fail(
"invalid acquire SQLite database");
895 return fail(
"invalid StoredLedgerSeqs");
897 if (boost::icl::first(storedSeqs) <
firstSeq_ ||
898 boost::icl::last(storedSeqs) >
lastSeq_)
900 return fail(
"invalid StoredLedgerSeqs");
916 return fail(
"incompatible, missing backend final key");
921 nodeObject->getData().data(), nodeObject->getData().size());
923 return fail(
"invalid version");
926 return fail(
"out of range ledger sequences");
929 return fail(
"invalid last ledger hash");
943 std::string(
". Exception caught in function ") + __func__ +
944 ". Error: " + e.
what());
960 setup.
startUp = config.standalone() ? config.LOAD : config.START_UP;
995 <<
". Exception caught in function " << __func__
996 <<
". Error: " << e.
what();
1040 <<
". Exception caught in function " << __func__
1041 <<
". Error: " << e.
what();
1055 using namespace boost::filesystem;
1056 for (
auto const& d : directory_iterator(
dir_))
1058 if (is_regular_file(d))
1068 <<
". Exception caught in function " << __func__
1069 <<
". Error: " << e.
what();
1080 JLOG(j.error()) <<
"shard " <<
index <<
". " << msg
1081 << (ledger->info().hash.isZero() ?
""
1082 :
". Ledger hash " +
1084 << (ledger->info().seq == 0 ?
""
1085 :
". Ledger sequence " +
1090 if (ledger->info().hash.isZero())
1091 return fail(
"Invalid ledger hash");
1092 if (ledger->info().accountHash.isZero())
1093 return fail(
"Invalid ledger account hash");
1096 auto visit = [
this, &error, &dShard](
SHAMapTreeNode const& node) {
1100 auto nodeObject{
verifyFetch(node.getHash().as_uint256())};
1101 if (!nodeObject || !dShard->store(nodeObject))
1108 if (ledger->stateMap().getHash().isNonZero())
1110 if (!ledger->stateMap().isValid())
1111 return fail(
"Invalid state map");
1115 if (next && next->info().parentHash == ledger->info().hash)
1116 ledger->stateMap().visitDifferences(&next->stateMap(), visit);
1118 ledger->stateMap().visitNodes(visit);
1123 std::string(
". Exception caught in function ") + __func__ +
1124 ". Error: " + e.
what());
1130 return fail(
"Invalid state map");
1134 if (ledger->info().txHash.isNonZero())
1136 if (!ledger->txMap().isValid())
1137 return fail(
"Invalid transaction map");
1141 ledger->txMap().visitNodes(visit);
1146 std::string(
". Exception caught in function ") + __func__ +
1147 ". Error: " + e.
what());
1153 return fail(
"Invalid transaction map");
1165 JLOG(j.error()) <<
"shard " <<
index <<
". " << msg
1166 <<
". Node object hash " <<
to_string(hash);
1173 switch (
backend_->fetch(hash.data(), &nodeObject))
1177 if (nodeObject->getHash() !=
1179 return fail(
"Node object hash does not match payload");
1182 return fail(
"Missing node object");
1184 return fail(
"Corrupt node object");
1186 return fail(
"Unknown error");
1192 std::string(
". Exception caught in function ") + __func__ +
1193 ". Error: " + e.
what());
1206 JLOG(
j_.
error()) <<
"shard " <<
index_ <<
" not initialized";
1214 else if (
state_ ==
final)
1230 return callback(*db,
index_);
1243 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.
static constexpr State acquire
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()
static constexpr State finalizing
Shard(Application &app, DatabaseShard const &db, std::uint32_t index, boost::filesystem::path const &dir, beast::Journal j)
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()
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...
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_
static constexpr State complete
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)
std::atomic< State > state_
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::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.
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
bool callForTransactionSQL(std::function< bool(soci::session &session, std::uint32_t index)> const &callback)
callForTransactionSQL Checks out transaction database for the shard and calls given callback function...
bool callForLedgerSQL(std::function< bool(soci::session &session, std::uint32_t index)> const &callback)
callForLedgerSQL Checks out ledger database for the shard and calls given callback function passing s...
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::uint32_t fdRequired_
std::uint32_t index() const
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()
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_