21 #include <ripple/app/ledger/TransactionMaster.h>
22 #include <ripple/app/misc/NetworkOPs.h>
23 #include <ripple/app/misc/SHAMapStoreImp.h>
24 #include <ripple/beast/core/CurrentThreadName.h>
25 #include <ripple/core/ConfigSections.h>
26 #include <ripple/nodestore/impl/DatabaseRotatingImp.h>
28 #include <boost/algorithm/string/predicate.hpp>
38 session_ <<
"PRAGMA synchronous=FULL;";
41 "CREATE TABLE IF NOT EXISTS DbState ("
42 " Key INTEGER PRIMARY KEY,"
45 " LastRotatedLedger INTEGER"
50 "CREATE TABLE IF NOT EXISTS CanDelete ("
51 " Key INTEGER PRIMARY KEY,"
52 " CanDeleteSeq INTEGER"
58 boost::optional<std::int64_t> countO;
60 "SELECT COUNT(Key) FROM DbState WHERE Key = 1;"
61 , soci::into (countO);
63 Throw<std::runtime_error> (
"Failed to fetch Key Count from DbState.");
70 "INSERT INTO DbState VALUES (1, '', '', 0);";
75 boost::optional<std::int64_t> countO;
77 "SELECT COUNT(Key) FROM CanDelete WHERE Key = 1;"
78 , soci::into (countO);
80 Throw<std::runtime_error> (
"Failed to fetch Key Count from CanDelete.");
87 "INSERT INTO CanDelete VALUES (1, 0);";
98 "SELECT CanDeleteSeq FROM CanDelete WHERE Key = 1;"
111 "UPDATE CanDelete SET CanDeleteSeq = :canDelete WHERE Key = 1;"
112 , soci::use (canDelete)
126 "SELECT WritableDb, ArchiveDb, LastRotatedLedger"
127 " FROM DbState WHERE Key = 1;"
141 " SET WritableDb = :writableDb,"
142 " ArchiveDb = :archiveDb,"
143 " LastRotatedLedger = :lastRotated"
156 "UPDATE DbState SET LastRotatedLedger = :seq"
180 Throw<std::runtime_error>(
182 "] entry in configuration file");
188 get<std::string>(section,
"type"),
"RocksDB"))
190 if (!section.exists(
"cache_mb"))
196 if (!section.exists(
"filter_bits") && (config.NODE_SIZE >= 2))
197 section.set(
"filter_bits",
"10");
209 auto const minInterval = config.standalone() ?
213 Throw<std::runtime_error>(
"online_delete must be at least " +
219 Throw<std::runtime_error>(
220 "online_delete must not be less than ledger_history (currently " +
242 state.
writableDb = writableBackend->getName();
243 state.
archiveDb = archiveBackend->getName();
248 auto dbr = std::make_unique<NodeStore::DatabaseRotatingImp>(
253 std::move(writableBackend),
254 std::move(archiveBackend),
359 LedgerIndex const validatedSeq = validatedLedger->info().seq;
370 JLOG(
journal_.
warn()) <<
"rotating validatedSeq " << validatedSeq
371 <<
" lastRotated_ " <<
lastRotated_ <<
" deleteInterval "
376 case Health::stopping:
379 case Health::unhealthy:
389 case Health::stopping:
392 case Health::unhealthy:
400 validatedLedger->stateMap().snapShot (
403 std::ref(nodeCount), std::placeholders::_1));
405 <<
" nodecount " << nodeCount;
408 case Health::stopping:
411 case Health::unhealthy:
419 JLOG(
journal_.
debug()) << validatedSeq <<
" freshened caches";
422 case Health::stopping:
425 case Health::unhealthy:
434 << newBackend->getName();
439 case Health::stopping:
442 case Health::unhealthy:
460 std::move(newBackend),
463 JLOG(
journal_.
warn()) <<
"finished rotation " << validatedSeq;
465 oldBackend->setDeletePath();
474 boost::filesystem::path dbPath = get<std::string>(section,
"path");
476 if (boost::filesystem::exists (dbPath))
478 if (! boost::filesystem::is_directory (dbPath))
482 Throw<std::runtime_error> (
483 "node db path must be a directory.");
488 boost::filesystem::create_directories (dbPath);
500 using namespace boost::filesystem;
501 auto const stored {path(sPath)};
502 if (stored.parent_path() == dbPath)
505 sPath = (dbPath / stored.filename()).
string();
516 bool writableDbExists =
false;
517 bool archiveDbExists =
false;
519 for (boost::filesystem::directory_iterator it (dbPath);
520 it != boost::filesystem::directory_iterator(); ++it)
523 writableDbExists =
true;
525 archiveDbExists =
true;
527 boost::filesystem::remove_all (it->path());
532 (writableDbExists != archiveDbExists) ||
535 boost::filesystem::path stateDbPathName =
538 stateDbPathName +=
"*";
541 <<
" writableDbExists " << writableDbExists
542 <<
" archiveDbExists " << archiveDbExists <<
'\n'
544 <<
"' archiveDb '" << state.
archiveDb <<
"\n\n"
545 <<
"The existing data is in a corrupted state.\n"
546 <<
"To resume operation, remove the files matching "
547 << stateDbPathName.
string()
548 <<
" and contents of the directory "
549 << get<std::string>(section,
"path") <<
'\n'
550 <<
"Optionally, you can move those files to another\n"
551 <<
"location if you wish to analyze or back up the data.\n"
552 <<
"However, there is no guarantee that the data in its\n"
553 <<
"existing form is usable.";
555 Throw<std::runtime_error> (
"state db error");
563 boost::filesystem::path newPath;
571 boost::filesystem::path p = get<std::string>(section,
"path");
574 newPath = boost::filesystem::unique_path (p);
576 section.set(
"path", newPath.string());
594 boost::optional<std::uint64_t> m;
595 *db << minQuery, soci::into(m);
601 if(min > lastRotated ||
health() != Health::ok)
604 boost::format formattedDeleteQuery (deleteQuery);
607 "start: " << deleteQuery <<
" from " << min <<
" to " << lastRotated;
608 while (min < lastRotated)
613 *db << boost::str (formattedDeleteQuery % min);
617 if (min < lastRotated)
654 "SELECT MIN(LedgerSeq) FROM Ledgers;",
655 "DELETE FROM Ledgers WHERE LedgerSeq < %u;");
660 "SELECT MIN(LedgerSeq) FROM Transactions;",
661 "DELETE FROM Transactions WHERE LedgerSeq < %u;");
666 "SELECT MIN(LedgerSeq) FROM AccountTransactions;",
667 "DELETE FROM AccountTransactions WHERE LedgerSeq < %u;");
678 return Health::stopping;
690 <<
". age " << age.count() <<
's';
697 return Health::unhealthy;
743 return std::make_unique<SHAMapStoreImp>(app, parent, scheduler, journal);
Holds a collection of configuration values.
LedgerIndex setCanDelete(LedgerIndex canDelete)
SHAMapStoreImp(Application &app, Stoppable &parent, NodeStore::Scheduler &scheduler, beast::Journal journal)
NodeStore::Scheduler & scheduler_
Persistency layer for NodeObject.
void clearLedgerCachePrior(LedgerIndex seq)
void stopped()
Called by derived classes to indicate that the stoppable has stopped.
std::shared_ptr< Ledger const > newLedger_
void onLedgerClosed(std::shared_ptr< Ledger const > const &ledger) override
Called by LedgerMaster every time a ledger validates.
static const std::uint32_t minimumDeletionInterval_
const std::string dbPrefix_
LedgerMaster * ledgerMaster_
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_
LedgerIndex getCanDelete()
virtual std::unique_ptr< Backend > make_Backend(Section const ¶meters, Scheduler &scheduler, beast::Journal journal)=0
Create a backend.
static constexpr auto nodeStoreName_
std::int32_t ageThreshold_
virtual NetworkOPs & getOPs()=0
NodeStore::DatabaseRotating * dbRotating_
virtual std::shared_ptr< Backend > rotateBackends(std::shared_ptr< Backend > newBackend, std::lock_guard< std::mutex > const &)=0
bool get_if_exists(Section const §ion, std::string const &name, T &v)
Provides an interface for starting and stopping.
LockedSociSession checkoutDb()
virtual Family & family()=0
virtual LedgerMaster & getLedgerMaster()=0
SHAMapHash const & getNodeHash() const
std::uint32_t getSeq() const
virtual std::shared_ptr< NodeObject > fetch(uint256 const &hash, std::uint32_t seq)=0
Fetch an object.
virtual Config & config()=0
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.
virtual std::shared_ptr< Backend > const & getWritableBackend() const =0
void legacy(std::string const §ion, std::string value)
Set a value that is not a key/value pair.
bool copyNode(std::uint64_t &nodeCount, SHAMapAbstractNode const &node)
TaggedCache< uint256, Transaction > & getCache()
void clearPrior(LedgerIndex lastRotated)
A generic endpoint for log messages.
virtual DatabaseCon & getLedgerDB()=0
Scheduling for asynchronous backend activity.
const std::uint64_t checkHealthInterval_
virtual TreeNodeCache & treecache()=0
std::atomic< LedgerIndex > lastRotated_
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.
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_
virtual TaggedCache< uint256, NodeObject > const & getPositiveCache()=0
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())
virtual FullBelowCache & fullbelow()=0
std::unique_ptr< NodeStore::Database > makeNodeStore(std::string const &name, std::int32_t readThreads) override
uint256 const & as_uint256() const
virtual std::unique_ptr< Database > make_Database(std::string const &name, Scheduler &scheduler, int readThreads, Stoppable &parent, Section const &backendParameters, beast::Journal journal)=0
Construct a NodeStore database.
static Manager & instance()
Returns the instance of the manager singleton.
bool freshenCache(CacheInstance &cache)
void clearPriorLedgers(LedgerIndex seq)
virtual std::mutex & peekMutex() const =0
Holds unparsed configuration information.
static std::string nodeDatabase()
void rendezvous() const override
bool 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 pause briefly to extend access tim...
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