1#include <xrpld/app/ledger/TransactionMaster.h>
2#include <xrpld/app/misc/SHAMapStoreImp.h>
3#include <xrpld/app/rdb/backend/SQLiteDatabase.h>
4#include <xrpld/core/ConfigSections.h>
6#include <xrpl/beast/core/CurrentThreadName.h>
7#include <xrpl/nodestore/Scheduler.h>
8#include <xrpl/nodestore/detail/DatabaseRotatingImp.h>
9#include <xrpl/server/NetworkOPs.h>
10#include <xrpl/server/State.h>
11#include <xrpl/shamap/SHAMapMissingNode.h>
13#include <boost/algorithm/string/predicate.hpp>
78 Throw<std::runtime_error>(
83 if (boost::iequals(
get(section,
"type"),
"RocksDB"))
85 if (!section.exists(
"cache_mb"))
90 if (!section.exists(
"filter_bits") && (config.NODE_SIZE >= 2))
91 section.set(
"filter_bits",
"10");
114 auto const minInterval =
118 Throw<std::runtime_error>(
124 Throw<std::runtime_error>(
125 "online_delete must not be less than ledger_history "
148 state.
writableDb = writableBackend->getName();
149 state.
archiveDb = archiveBackend->getName();
158 std::move(writableBackend),
159 std::move(archiveBackend),
256 LedgerIndex const validatedSeq = validatedLedger->header().seq;
257 if (lastRotated == 0u)
259 lastRotated = validatedSeq;
263 bool const readyToRotate = validatedSeq >= lastRotated +
deleteInterval_ &&
269 JLOG(
journal_.
warn()) <<
"rotating validatedSeq " << validatedSeq <<
" lastRotated "
284 validatedLedger->stateMap().snapShot(
false)->visitNodes(
289 std::placeholders::_1));
294 <<
"Missing node while copying ledger before rotate: " << e.
what();
302 <<
"copied ledger " << validatedSeq <<
" nodecount " << nodeCount;
309 JLOG(
journal_.
debug()) << validatedSeq <<
" freshened caches";
313 JLOG(
journal_.
debug()) << validatedSeq <<
" new backend " << newBackend->getName();
319 lastRotated = validatedSeq;
322 std::move(newBackend),
333 JLOG(
journal_.
warn()) <<
"finished rotation " << validatedSeq;
342 boost::filesystem::path dbPath =
get(section,
"path");
344 if (boost::filesystem::exists(dbPath))
346 if (!boost::filesystem::is_directory(dbPath))
348 journal_.
error() <<
"node db path must be a directory. " << dbPath.string();
349 Throw<std::runtime_error>(
"node db path must be a directory.");
354 boost::filesystem::create_directories(dbPath);
365 using namespace boost::filesystem;
366 auto const stored{path(sPath)};
367 if (stored.parent_path() == dbPath)
370 sPath = (dbPath / stored.filename()).
string();
381 bool writableDbExists =
false;
382 bool archiveDbExists =
false;
385 for (boost::filesystem::directory_iterator it(dbPath);
386 it != boost::filesystem::directory_iterator();
391 writableDbExists =
true;
395 archiveDbExists =
true;
404 (!archiveDbExists && !state.
archiveDb.
empty()) || (writableDbExists != archiveDbExists) ||
407 boost::filesystem::path stateDbPathName =
app_.
config().
legacy(
"database_path");
409 stateDbPathName +=
"*";
412 <<
" writableDbExists " << writableDbExists <<
" archiveDbExists "
413 << archiveDbExists <<
'\n'
414 <<
" writableDb '" << state.
writableDb <<
"' archiveDb '"
416 <<
"The existing data is in a corrupted state.\n"
417 <<
"To resume operation, remove the files matching "
418 << stateDbPathName.
string() <<
" and contents of the directory "
419 <<
get(section,
"path") <<
'\n'
420 <<
"Optionally, you can move those files to another\n"
421 <<
"location if you wish to analyze or back up the data.\n"
422 <<
"However, there is no guarantee that the data in its\n"
423 <<
"existing form is usable.";
425 Throw<std::runtime_error>(
"state db error");
429 for (boost::filesystem::path
const& p : pathsToDelete)
430 boost::filesystem::remove_all(p);
437 boost::filesystem::path newPath;
445 boost::filesystem::path p =
get(section,
"path");
448 newPath = boost::filesystem::unique_path(p);
450 section.set(
"path", newPath.string());
468 XRPL_ASSERT(
deleteInterval_,
"xrpl::SHAMapStoreImp::clearSql : nonzero delete interval");
472 JLOG(
journal_.
trace()) <<
"Begin: Look up lowest value of: " << TableName;
473 auto m = getMinSeq();
474 JLOG(
journal_.
trace()) <<
"End: Look up lowest value of: " << TableName;
482 if (min == lastRotated)
485 JLOG(
journal_.
trace()) <<
"Nothing to delete from " << TableName;
489 JLOG(
journal_.
debug()) <<
"start deleting in: " << TableName <<
" from " << min <<
" to "
491 while (min < lastRotated)
495 <<
" rows with LedgerSeq < " << min <<
" from: " << TableName;
496 deleteBeforeSeq(min);
498 << min <<
" from: " << TableName;
501 if (min < lastRotated)
506 JLOG(
journal_.
debug()) <<
"finished deleting from: " << TableName;
534 JLOG(
journal_.
trace()) <<
"Begin: Clear internal ledgers up to " << lastRotated;
536 JLOG(
journal_.
trace()) <<
"End: Clear internal ledgers up to " << lastRotated;
546 [&db](
LedgerIndex min) ->
void { db.deleteBeforeLedgerSeq(min); });
557 [&db](
LedgerIndex min) ->
void { db.deleteTransactionsBeforeLedgerSeq(min); });
563 "AccountTransactions",
565 [&db](
LedgerIndex min) ->
void { db.deleteAccountTransactionsBeforeLedgerSeq(min); });
580 <<
"s for node to stabilize. state: "
582 << age.count() <<
's';
A generic endpoint for log messages.
Stream trace() const
Severity stream access functions.
virtual Config & config()=0
Holds unparsed configuration information.
void legacy(std::string const §ion, std::string value)
Set a value that is not a key/value pair.
Section & section(std::string const &name)
Returns the section with the given name.
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.
virtual std::shared_ptr< TreeNodeCache > getTreeNodeCache()=0
Return a pointer to the Family Tree Node Cache.
virtual std::shared_ptr< FullBelowCache > getFullBelowCache()=0
Return a pointer to the Family Full Below Cache.
std::optional< LedgerIndex > minSqlSeq()
std::chrono::seconds getValidatedLedgerAge()
void clearPriorLedgers(LedgerIndex seq)
void clearLedgerCachePrior(LedgerIndex seq)
virtual OperatingMode getOperatingMode() const =0
virtual std::string strOperatingMode(OperatingMode const mode, bool const admin=false) const =0
virtual void rotate(std::unique_ptr< NodeStore::Backend > &&newBackend, std::function< void(std::string const &writableName, std::string const &archiveName)> const &f)=0
Rotates the backends.
Persistency layer for NodeObject.
std::shared_ptr< NodeObject > fetchNodeObject(uint256 const &hash, std::uint32_t ledgerSeq=0, FetchType fetchType=FetchType::synchronous, bool duplicate=false)
Fetch a node object.
static Manager & instance()
Returns the instance of the manager singleton.
virtual std::unique_ptr< Database > make_Database(std::size_t burstSize, Scheduler &scheduler, int readThreads, Section const &backendParameters, beast::Journal journal)=0
Construct a NodeStore database.
virtual std::unique_ptr< Backend > make_Backend(Section const ¶meters, std::size_t burstSize, Scheduler &scheduler, beast::Journal journal)=0
Create a backend.
Scheduling for asynchronous backend activity.
uint256 const & as_uint256() const
void setState(SavedState const &state)
void init(BasicConfig const &config, std::string const &dbName)
LedgerIndex setCanDelete(LedgerIndex canDelete)
void setLastRotated(LedgerIndex seq)
LedgerIndex getCanDelete()
void clearSql(LedgerIndex lastRotated, std::string const &TableName, std::function< std::optional< LedgerIndex >()> const &getMinSeq, std::function< void(LedgerIndex)> const &deleteBeforeSeq)
delete from sqlite table in batches to not lock the db excessively.
bool copyNode(std::uint64_t &nodeCount, SHAMapTreeNode const &node)
std::unique_ptr< NodeStore::Backend > makeBackendRotating(std::string path=std::string())
std::atomic< bool > working_
std::condition_variable cond_
std::uint32_t deleteBatch_
std::atomic< LedgerIndex > minimumOnline_
std::chrono::seconds recoveryWaitTime_
If the node is out of sync during an online_delete healthWait() call, sleep the thread for this time,...
std::optional< LedgerIndex > minimumOnline() const override
The minimum ledger to try and maintain in our database.
static constexpr auto nodeStoreName_
std::uint32_t deleteInterval_
int fdRequired() const override
Returns the number of file descriptors that are needed.
static std::uint32_t const minimumDeletionInterval_
std::unique_ptr< NodeStore::Database > makeNodeStore(int readThreads) override
std::chrono::milliseconds backOff_
std::atomic< LedgerIndex > canDelete_
NodeStore::DatabaseRotating * dbRotating_
std::shared_ptr< Ledger const > newLedger_
std::string const dbName_
std::condition_variable rendezvous_
static std::uint32_t const minimumDeletionIntervalSA_
std::uint64_t const checkHealthInterval_
HealthResult healthWait()
void clearCaches(LedgerIndex validatedSeq)
std::chrono::seconds ageThreshold_
void rendezvous() const override
LedgerMaster * ledgerMaster_
beast::Journal const journal_
std::string const dbPrefix_
NodeStore::Scheduler & scheduler_
HealthResult
This is a health check for online deletion that waits until rippled is stable before returning.
void onLedgerClosed(std::shared_ptr< Ledger const > const &ledger) override
Called by LedgerMaster every time a ledger validates.
bool freshenCache(CacheInstance &cache)
void clearPrior(LedgerIndex lastRotated)
SHAMapStoreImp(Application &app, NodeStore::Scheduler &scheduler, beast::Journal journal)
SHAMapHash const & getHash() const
Return the hash of this node.
Holds a collection of configuration values.
virtual RelationalDatabase & getRelationalDatabase()=0
virtual beast::Journal getJournal(std::string const &name)=0
virtual NetworkOPs & getOPs()=0
virtual TransactionMaster & getMasterTransaction()=0
virtual LedgerMaster & getLedgerMaster()=0
virtual Family & getNodeFamily()=0
TaggedCache< uint256, Transaction > & getCache()
void setCurrentThreadName(std::string_view newThreadName)
Changes the name of the caller thread.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
void initStateDB(soci::session &session, BasicConfig const &config, std::string const &dbName)
initStateDB Opens a session with the State database.
void setSavedState(soci::session &session, SavedState const &state)
setSavedState Saves the given state.
T get(Section const §ion, std::string const &name, T const &defaultValue=T{})
Retrieve a key/value pair from a section.
void setLastRotated(soci::session &session, LedgerIndex seq)
setLastRotated Updates the last rotated ledger sequence.
std::unique_ptr< SHAMapStore > make_SHAMapStore(Application &app, NodeStore::Scheduler &scheduler, beast::Journal journal)
SavedState getSavedState(soci::session &session)
getSavedState Returns the saved state.
constexpr auto megabytes(T value) noexcept
bool get_if_exists(Section const §ion, std::string const &name, T &v)
LedgerIndex setCanDelete(soci::session &session, LedgerIndex canDelete)
setCanDelete Updates the ledger sequence which can be deleted.
OperatingMode
Specifies the mode under which the server believes it's operating.
@ FULL
we have the ledger and can even validate
LedgerIndex getCanDelete(soci::session &session)
getCanDelete Returns the ledger sequence which can be deleted.
static std::string nodeDatabase()