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");
192 auto const minInterval = config.standalone()
197 Throw<std::runtime_error>(
198 "online_delete must be at least " +
204 Throw<std::runtime_error>(
205 "online_delete must not be less than ledger_history "
228 state.
writableDb = writableBackend->getName();
229 state.
archiveDb = archiveBackend->getName();
234 auto dbr = std::make_unique<NodeStore::DatabaseRotatingImp>(
239 std::move(writableBackend),
240 std::move(archiveBackend),
342 LedgerIndex const validatedSeq = validatedLedger->info().seq;
345 lastRotated = validatedSeq;
354 <<
"rotating validatedSeq " << validatedSeq <<
" lastRotated "
360 case Health::stopping:
363 case Health::unhealthy:
372 case Health::stopping:
375 case Health::unhealthy:
382 validatedLedger->stateMap().snapShot(
false)->visitNodes(
std::bind(
386 std::placeholders::_1));
388 <<
" nodecount " << nodeCount;
391 case Health::stopping:
394 case Health::unhealthy:
401 JLOG(
journal_.
debug()) << validatedSeq <<
" freshened caches";
404 case Health::stopping:
407 case Health::unhealthy:
415 << validatedSeq <<
" new backend " << newBackend->getName();
420 case Health::stopping:
423 case Health::unhealthy:
429 lastRotated = validatedSeq;
434 savedState.
writableDb = newBackend->getName();
435 savedState.
archiveDb = writableBackendName;
441 return std::move(newBackend);
444 JLOG(
journal_.
warn()) <<
"finished rotation " << validatedSeq;
453 boost::filesystem::path dbPath = get<std::string>(section,
"path");
455 if (boost::filesystem::exists(dbPath))
457 if (!boost::filesystem::is_directory(dbPath))
460 <<
"node db path must be a directory. " << dbPath.string();
461 Throw<std::runtime_error>(
"node db path must be a directory.");
466 boost::filesystem::create_directories(dbPath);
477 using namespace boost::filesystem;
478 auto const stored{path(sPath)};
479 if (stored.parent_path() == dbPath)
482 sPath = (dbPath / stored.filename()).
string();
493 bool writableDbExists =
false;
494 bool archiveDbExists =
false;
496 for (boost::filesystem::directory_iterator it(dbPath);
497 it != boost::filesystem::directory_iterator();
501 writableDbExists =
true;
503 archiveDbExists =
true;
505 boost::filesystem::remove_all(it->path());
510 (writableDbExists != archiveDbExists) ||
513 boost::filesystem::path stateDbPathName =
516 stateDbPathName +=
"*";
519 <<
"state db error:\n"
520 <<
" writableDbExists " << writableDbExists <<
" archiveDbExists "
521 << archiveDbExists <<
'\n'
522 <<
" writableDb '" << state.
writableDb <<
"' archiveDb '"
524 <<
"The existing data is in a corrupted state.\n"
525 <<
"To resume operation, remove the files matching "
526 << stateDbPathName.
string() <<
" and contents of the directory "
527 << get<std::string>(section,
"path") <<
'\n'
528 <<
"Optionally, you can move those files to another\n"
529 <<
"location if you wish to analyze or back up the data.\n"
530 <<
"However, there is no guarantee that the data in its\n"
531 <<
"existing form is usable.";
533 Throw<std::runtime_error>(
"state db error");
541 boost::filesystem::path newPath;
549 boost::filesystem::path p = get<std::string>(section,
"path");
552 newPath = boost::filesystem::unique_path(p);
554 section.set(
"path", newPath.string());
573 boost::optional<std::uint64_t> m;
574 *db << minQuery, soci::into(m);
580 if (min > lastRotated ||
health() != Health::ok)
583 boost::format formattedDeleteQuery(deleteQuery);
585 JLOG(
journal_.
debug()) <<
"start: " << deleteQuery <<
" from " << min
586 <<
" to " << lastRotated;
587 while (min < lastRotated)
592 *db << boost::str(formattedDeleteQuery % min);
596 if (min < lastRotated)
637 "SELECT MIN(LedgerSeq) FROM Ledgers;",
638 "DELETE FROM Ledgers WHERE LedgerSeq < %u;");
645 "SELECT MIN(LedgerSeq) FROM Transactions;",
646 "DELETE FROM Transactions WHERE LedgerSeq < %u;");
653 "SELECT MIN(LedgerSeq) FROM AccountTransactions;",
654 "DELETE FROM AccountTransactions WHERE LedgerSeq < %u;");
665 return Health::stopping;
677 <<
". age " << age.count() <<
's';
684 return Health::unhealthy;
721 boost::optional<LedgerIndex>
740 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.
boost::optional< LedgerIndex > minSqlSeq()
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_
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
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.
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.
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
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.
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
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