20 #include <ripple/app/ledger/TransactionMaster.h>
21 #include <ripple/app/misc/NetworkOPs.h>
22 #include <ripple/app/misc/SHAMapStoreImp.h>
23 #include <ripple/beast/core/CurrentThreadName.h>
24 #include <ripple/core/ConfigSections.h>
25 #include <ripple/nodestore/impl/DatabaseRotatingImp.h>
27 #include <boost/algorithm/string/predicate.hpp>
39 session_ <<
"PRAGMA synchronous=FULL;";
41 session_ <<
"CREATE TABLE IF NOT EXISTS DbState ("
42 " Key INTEGER PRIMARY KEY,"
45 " LastRotatedLedger INTEGER"
48 session_ <<
"CREATE TABLE IF NOT EXISTS CanDelete ("
49 " Key INTEGER PRIMARY KEY,"
50 " CanDeleteSeq INTEGER"
55 boost::optional<std::int64_t> countO;
56 session_ <<
"SELECT COUNT(Key) FROM DbState WHERE Key = 1;",
59 Throw<std::runtime_error>(
60 "Failed to fetch Key Count from DbState.");
66 session_ <<
"INSERT INTO DbState VALUES (1, '', '', 0);";
70 boost::optional<std::int64_t> countO;
71 session_ <<
"SELECT COUNT(Key) FROM CanDelete WHERE Key = 1;",
74 Throw<std::runtime_error>(
75 "Failed to fetch Key Count from CanDelete.");
81 session_ <<
"INSERT INTO CanDelete VALUES (1, 0);";
91 session_ <<
"SELECT CanDeleteSeq FROM CanDelete WHERE Key = 1;",
103 session_ <<
"UPDATE CanDelete SET CanDeleteSeq = :canDelete WHERE Key = 1;",
104 soci::use(canDelete);
116 session_ <<
"SELECT WritableDb, ArchiveDb, LastRotatedLedger"
117 " FROM DbState WHERE Key = 1;",
128 session_ <<
"UPDATE DbState"
129 " SET WritableDb = :writableDb,"
130 " ArchiveDb = :archiveDb,"
131 " LastRotatedLedger = :lastRotated"
141 session_ <<
"UPDATE DbState SET LastRotatedLedger = :seq"
164 Throw<std::runtime_error>(
166 "] entry in configuration file");
170 if (boost::iequals(get<std::string>(section,
"type"),
"RocksDB"))
172 if (!section.exists(
"cache_mb"))
179 if (!section.exists(
"filter_bits") && (config.NODE_SIZE >= 2))
180 section.set(
"filter_bits",
"10");
203 auto const minInterval = config.standalone()
208 Throw<std::runtime_error>(
209 "online_delete must be at least " +
215 Throw<std::runtime_error>(
216 "online_delete must not be less than ledger_history "
239 state.
writableDb = writableBackend->getName();
240 state.
archiveDb = archiveBackend->getName();
245 auto dbr = std::make_unique<NodeStore::DatabaseRotatingImp>(
250 std::move(writableBackend),
251 std::move(archiveBackend),
353 LedgerIndex const validatedSeq = validatedLedger->info().seq;
356 lastRotated = validatedSeq;
365 <<
"rotating validatedSeq " << validatedSeq <<
" lastRotated "
374 case Health::stopping:
377 case Health::unhealthy:
385 validatedLedger->stateMap().snapShot(
false)->visitNodes(
std::bind(
389 std::placeholders::_1));
392 case Health::stopping:
395 case Health::unhealthy:
402 <<
" nodecount " << nodeCount;
408 case Health::stopping:
411 case Health::unhealthy:
417 JLOG(
journal_.
debug()) << validatedSeq <<
" freshened caches";
422 << validatedSeq <<
" new backend " << newBackend->getName();
427 case Health::stopping:
430 case Health::unhealthy:
436 lastRotated = validatedSeq;
441 savedState.
writableDb = newBackend->getName();
442 savedState.
archiveDb = writableBackendName;
448 return std::move(newBackend);
451 JLOG(
journal_.
warn()) <<
"finished rotation " << validatedSeq;
460 boost::filesystem::path dbPath = get<std::string>(section,
"path");
462 if (boost::filesystem::exists(dbPath))
464 if (!boost::filesystem::is_directory(dbPath))
467 <<
"node db path must be a directory. " << dbPath.string();
468 Throw<std::runtime_error>(
"node db path must be a directory.");
473 boost::filesystem::create_directories(dbPath);
484 using namespace boost::filesystem;
485 auto const stored{path(sPath)};
486 if (stored.parent_path() == dbPath)
489 sPath = (dbPath / stored.filename()).
string();
500 bool writableDbExists =
false;
501 bool archiveDbExists =
false;
503 for (boost::filesystem::directory_iterator it(dbPath);
504 it != boost::filesystem::directory_iterator();
508 writableDbExists =
true;
510 archiveDbExists =
true;
512 boost::filesystem::remove_all(it->path());
517 (writableDbExists != archiveDbExists) ||
520 boost::filesystem::path stateDbPathName =
523 stateDbPathName +=
"*";
526 <<
"state db error:\n"
527 <<
" writableDbExists " << writableDbExists <<
" archiveDbExists "
528 << archiveDbExists <<
'\n'
529 <<
" writableDb '" << state.
writableDb <<
"' archiveDb '"
531 <<
"The existing data is in a corrupted state.\n"
532 <<
"To resume operation, remove the files matching "
533 << stateDbPathName.
string() <<
" and contents of the directory "
534 << get<std::string>(section,
"path") <<
'\n'
535 <<
"Optionally, you can move those files to another\n"
536 <<
"location if you wish to analyze or back up the data.\n"
537 <<
"However, there is no guarantee that the data in its\n"
538 <<
"existing form is usable.";
540 Throw<std::runtime_error>(
"state db error");
548 boost::filesystem::path newPath;
556 boost::filesystem::path p = get<std::string>(section,
"path");
559 newPath = boost::filesystem::unique_path(p);
561 section.set(
"path", newPath.string());
583 boost::optional<std::uint64_t> m;
585 <<
"Begin: Look up lowest value of: " << minQuery;
588 *db << minQuery, soci::into(m);
590 JLOG(
journal_.
trace()) <<
"End: Look up lowest value of: " << minQuery;
596 if (min > lastRotated ||
health() != Health::ok)
598 if (min == lastRotated)
601 JLOG(
journal_.
trace()) <<
"Nothing to delete from " << deleteQuery;
605 boost::format formattedDeleteQuery(deleteQuery);
607 JLOG(
journal_.
debug()) <<
"start: " << deleteQuery <<
" from " << min
608 <<
" to " << lastRotated;
609 while (min < lastRotated)
613 <<
" rows with LedgerSeq < " << min
614 <<
" using query: " << deleteQuery;
617 *db << boost::str(formattedDeleteQuery % min);
620 <<
"End: Delete up to " <<
deleteBatch_ <<
" rows with LedgerSeq < "
621 << min <<
" using query: " << deleteQuery;
624 if (min < lastRotated)
654 JLOG(
journal_.
trace()) <<
"Begin: Clear internal ledgers up to "
657 JLOG(
journal_.
trace()) <<
"End: Clear internal ledgers up to "
665 "SELECT MIN(LedgerSeq) FROM Ledgers;",
666 "DELETE FROM Ledgers WHERE LedgerSeq < %u;");
673 "SELECT MIN(LedgerSeq) FROM Transactions;",
674 "DELETE FROM Transactions WHERE LedgerSeq < %u;");
681 "SELECT MIN(LedgerSeq) FROM AccountTransactions;",
682 "DELETE FROM AccountTransactions WHERE LedgerSeq < %u;");
693 return Health::stopping;
708 <<
"s for node to get back into sync with network. state: "
710 << age.count() <<
's';
720 <<
". age " << age.count() <<
's';
728 return Health::unhealthy;
765 boost::optional<LedgerIndex>
784 return std::make_unique<SHAMapStoreImp>(app, parent, scheduler, journal);
Holds a collection of configuration values.
LedgerIndex setCanDelete(LedgerIndex canDelete)
virtual Family & getNodeFamily()=0
virtual std::shared_ptr< TreeNodeCache > getTreeNodeCache(std::uint32_t ledgerSeq)=0
Return a pointer to the Family Tree Node Cache.
SHAMapStoreImp(Application &app, Stoppable &parent, NodeStore::Scheduler &scheduler, beast::Journal journal)
NodeStore::Scheduler & scheduler_
Persistency layer for NodeObject.
void clearLedgerCachePrior(LedgerIndex seq)
virtual std::unique_ptr< Database > make_Database(std::string const &name, std::size_t burstSize, Scheduler &scheduler, int readThreads, Stoppable &parent, Section const &backendParameters, beast::Journal journal)=0
Construct a NodeStore database.
void stopped()
Called by derived classes to indicate that the stoppable has stopped.
Stream trace() const
Severity stream access functions.
std::shared_ptr< Ledger const > newLedger_
void onLedgerClosed(std::shared_ptr< Ledger const > const &ledger) override
Called by LedgerMaster every time a ledger validates.
boost::optional< LedgerIndex > minSqlSeq()
static const std::uint32_t minimumDeletionInterval_
const std::string dbPrefix_
LedgerMaster * ledgerMaster_
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.
class to create database, launch online delete thread, and related SQLite database
DatabaseCon * transactionDb_
virtual OperatingMode getOperatingMode() const =0
const beast::Journal journal_
std::condition_variable cond_
virtual std::shared_ptr< FullBelowCache > getFullBelowCache(std::uint32_t ledgerSeq)=0
Return a pointer to the Family Full Below Cache.
LedgerIndex getCanDelete()
static constexpr auto nodeStoreName_
virtual NetworkOPs & getOPs()=0
bool copyNode(std::uint64_t &nodeCount, SHAMapTreeNode const &node)
NodeStore::DatabaseRotating * dbRotating_
bool get_if_exists(Section const §ion, std::string const &name, T &v)
@ SYNCING
fallen slightly behind
void clearSql(DatabaseCon &database, LedgerIndex lastRotated, std::string const &minQuery, std::string const &deleteQuery)
delete from sqlite table in batches to not lock the db excessively.
Provides an interface for starting and stopping.
LockedSociSession checkoutDb()
virtual LedgerMaster & getLedgerMaster()=0
virtual Config & config()=0
constexpr auto megabytes(T value) noexcept
std::atomic< LedgerIndex > minimumOnline_
void setState(SavedState const &state)
TreeNodeCache * treeNodeCache_
std::atomic< bool > working_
std::uint32_t deleteInterval_
virtual JobQueue & getJobQueue()=0
void onStop() override
Override called when the stop notification is issued.
std::chrono::seconds ageThreshold_
boost::optional< LedgerIndex > minimumOnline() const override
The minimum ledger to try and maintain in our database.
void legacy(std::string const §ion, std::string value)
Set a value that is not a key/value pair.
TaggedCache< uint256, Transaction > & getCache()
void clearPrior(LedgerIndex lastRotated)
A generic endpoint for log messages.
virtual DatabaseCon & getLedgerDB()=0
boost::optional< std::chrono::seconds > recoveryWaitTime_
If set, and the node is out of sync during an online_delete health check, sleep the thread for this t...
Scheduling for asynchronous backend activity.
std::shared_ptr< NodeObject > fetchNodeObject(uint256 const &hash, std::uint32_t ledgerSeq=0, FetchType fetchType=FetchType::synchronous)
Fetch a node object.
const std::uint64_t checkHealthInterval_
SHAMapHash const & getHash() const
Return the hash of this node.
std::chrono::milliseconds backOff_
void init(BasicConfig const &config, std::string const &dbName)
std::chrono::seconds getValidatedLedgerAge()
const std::string dbName_
void setCurrentThreadName(std::string_view name)
Changes the name of the caller thread.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
int fdRequired() const override
Returns the number of file descriptors that are needed.
virtual std::unique_ptr< Backend > make_Backend(Section const ¶meters, std::size_t burstSize, Scheduler &scheduler, beast::Journal journal)=0
Create a backend.
beast::Journal journal(std::string const &name)
std::unique_ptr< SHAMapStore > make_SHAMapStore(Application &app, Stoppable &parent, NodeStore::Scheduler &scheduler, beast::Journal journal)
void setLastRotated(LedgerIndex seq)
std::atomic< LedgerIndex > canDelete_
static const std::uint32_t minimumDeletionIntervalSA_
void onChildrenStopped() override
Override called when all children have stopped.
std::uint32_t deleteBatch_
FullBelowCache * fullBelowCache_
void clearCaches(LedgerIndex validatedSeq)
virtual std::string strOperatingMode(OperatingMode const mode, bool const admin=false) const =0
OperatingMode
Specifies the mode under which the server believes it's operating.
std::unique_ptr< NodeStore::Backend > makeBackendRotating(std::string path=std::string())
std::unique_ptr< NodeStore::Database > makeNodeStore(std::string const &name, std::int32_t readThreads) override
uint256 const & as_uint256() const
static Manager & instance()
Returns the instance of the manager singleton.
virtual void rotateWithLock(std::function< std::unique_ptr< NodeStore::Backend >(std::string const &writableBackendName)> const &f)=0
Rotates the backends.
bool freshenCache(CacheInstance &cache)
void clearPriorLedgers(LedgerIndex seq)
Holds unparsed configuration information.
static std::string nodeDatabase()
void rendezvous() const override
virtual DatabaseCon & getTxnDB()=0
void open(soci::session &s, BasicConfig const &config, std::string const &dbName)
Open a soci session.
Section & section(std::string const &name)
Returns the section with the given name.
std::condition_variable rendezvous_
virtual TransactionMaster & getMasterTransaction()=0
@ FULL
we have the ledger and can even validate