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/core/Pg.h>
26 #include <ripple/nodestore/impl/DatabaseRotatingImp.h>
28 #include <boost/algorithm/string/predicate.hpp>
40 session_ <<
"PRAGMA synchronous=FULL;";
42 session_ <<
"CREATE TABLE IF NOT EXISTS DbState ("
43 " Key INTEGER PRIMARY KEY,"
46 " LastRotatedLedger INTEGER"
49 session_ <<
"CREATE TABLE IF NOT EXISTS CanDelete ("
50 " Key INTEGER PRIMARY KEY,"
51 " CanDeleteSeq INTEGER"
56 boost::optional<std::int64_t> countO;
57 session_ <<
"SELECT COUNT(Key) FROM DbState WHERE Key = 1;",
60 Throw<std::runtime_error>(
61 "Failed to fetch Key Count from DbState.");
67 session_ <<
"INSERT INTO DbState VALUES (1, '', '', 0);";
71 boost::optional<std::int64_t> countO;
72 session_ <<
"SELECT COUNT(Key) FROM CanDelete WHERE Key = 1;",
75 Throw<std::runtime_error>(
76 "Failed to fetch Key Count from CanDelete.");
82 session_ <<
"INSERT INTO CanDelete VALUES (1, 0);";
92 session_ <<
"SELECT CanDeleteSeq FROM CanDelete WHERE Key = 1;",
104 session_ <<
"UPDATE CanDelete SET CanDeleteSeq = :canDelete WHERE Key = 1;",
105 soci::use(canDelete);
117 session_ <<
"SELECT WritableDb, ArchiveDb, LastRotatedLedger"
118 " FROM DbState WHERE Key = 1;",
129 session_ <<
"UPDATE DbState"
130 " SET WritableDb = :writableDb,"
131 " ArchiveDb = :archiveDb,"
132 " LastRotatedLedger = :lastRotated"
142 session_ <<
"UPDATE DbState SET LastRotatedLedger = :seq"
166 Throw<std::runtime_error>(
168 "] entry in configuration file");
172 if (boost::iequals(get<std::string>(section,
"type"),
"RocksDB"))
174 if (!section.exists(
"cache_mb"))
181 if (!section.exists(
"filter_bits") && (config.NODE_SIZE >= 2))
182 section.set(
"filter_bits",
"10");
191 Throw<std::runtime_error>(
192 "Reporting does not support online_delete. Remove "
193 "online_delete info from config");
212 auto const minInterval = config.standalone()
217 Throw<std::runtime_error>(
218 "online_delete must be at least " +
224 Throw<std::runtime_error>(
225 "online_delete must not be less than ledger_history "
245 Throw<std::runtime_error>(
246 "Reporting does not support online_delete. Remove "
247 "online_delete info from config");
254 state.
writableDb = writableBackend->getName();
255 state.
archiveDb = archiveBackend->getName();
260 auto dbr = std::make_unique<NodeStore::DatabaseRotatingImp>(
265 std::move(writableBackend),
266 std::move(archiveBackend),
336 Throw<std::runtime_error>(
337 "Reporting does not support online_delete. Remove "
338 "online_delete info from config");
374 LedgerIndex const validatedSeq = validatedLedger->info().seq;
377 lastRotated = validatedSeq;
386 <<
"rotating validatedSeq " << validatedSeq <<
" lastRotated "
395 case Health::stopping:
398 case Health::unhealthy:
406 validatedLedger->stateMap().snapShot(
false)->visitNodes(
std::bind(
410 std::placeholders::_1));
413 case Health::stopping:
416 case Health::unhealthy:
423 <<
" nodecount " << nodeCount;
429 case Health::stopping:
432 case Health::unhealthy:
438 JLOG(
journal_.
debug()) << validatedSeq <<
" freshened caches";
443 << validatedSeq <<
" new backend " << newBackend->getName();
448 case Health::stopping:
451 case Health::unhealthy:
457 lastRotated = validatedSeq;
462 savedState.
writableDb = newBackend->getName();
463 savedState.
archiveDb = writableBackendName;
469 return std::move(newBackend);
472 JLOG(
journal_.
warn()) <<
"finished rotation " << validatedSeq;
481 boost::filesystem::path dbPath = get<std::string>(section,
"path");
483 if (boost::filesystem::exists(dbPath))
485 if (!boost::filesystem::is_directory(dbPath))
488 <<
"node db path must be a directory. " << dbPath.string();
489 Throw<std::runtime_error>(
"node db path must be a directory.");
494 boost::filesystem::create_directories(dbPath);
505 using namespace boost::filesystem;
506 auto const stored{path(sPath)};
507 if (stored.parent_path() == dbPath)
510 sPath = (dbPath / stored.filename()).
string();
521 bool writableDbExists =
false;
522 bool archiveDbExists =
false;
524 for (boost::filesystem::directory_iterator it(dbPath);
525 it != boost::filesystem::directory_iterator();
529 writableDbExists =
true;
531 archiveDbExists =
true;
533 boost::filesystem::remove_all(it->path());
538 (writableDbExists != archiveDbExists) ||
541 boost::filesystem::path stateDbPathName =
544 stateDbPathName +=
"*";
547 <<
"state db error:\n"
548 <<
" writableDbExists " << writableDbExists <<
" archiveDbExists "
549 << archiveDbExists <<
'\n'
550 <<
" writableDb '" << state.
writableDb <<
"' archiveDb '"
552 <<
"The existing data is in a corrupted state.\n"
553 <<
"To resume operation, remove the files matching "
554 << stateDbPathName.
string() <<
" and contents of the directory "
555 << get<std::string>(section,
"path") <<
'\n'
556 <<
"Optionally, you can move those files to another\n"
557 <<
"location if you wish to analyze or back up the data.\n"
558 <<
"However, there is no guarantee that the data in its\n"
559 <<
"existing form is usable.";
561 Throw<std::runtime_error>(
"state db error");
569 boost::filesystem::path newPath;
577 boost::filesystem::path p = get<std::string>(section,
"path");
580 newPath = boost::filesystem::unique_path(p);
582 section.set(
"path", newPath.string());
604 boost::optional<std::uint64_t> m;
606 <<
"Begin: Look up lowest value of: " << minQuery;
609 *db << minQuery, soci::into(m);
611 JLOG(
journal_.
trace()) <<
"End: Look up lowest value of: " << minQuery;
617 if (min > lastRotated ||
health() != Health::ok)
619 if (min == lastRotated)
622 JLOG(
journal_.
trace()) <<
"Nothing to delete from " << deleteQuery;
626 boost::format formattedDeleteQuery(deleteQuery);
628 JLOG(
journal_.
debug()) <<
"start: " << deleteQuery <<
" from " << min
629 <<
" to " << lastRotated;
630 while (min < lastRotated)
634 <<
" rows with LedgerSeq < " << min
635 <<
" using query: " << deleteQuery;
638 *db << boost::str(formattedDeleteQuery % min);
641 <<
"End: Delete up to " <<
deleteBatch_ <<
" rows with LedgerSeq < "
642 << min <<
" using query: " << deleteQuery;
645 if (min < lastRotated)
675 Throw<std::runtime_error>(
676 "Reporting does not support online_delete. Remove "
677 "online_delete info from config");
682 JLOG(
journal_.
trace()) <<
"Begin: Clear internal ledgers up to "
685 JLOG(
journal_.
trace()) <<
"End: Clear internal ledgers up to "
693 "SELECT MIN(LedgerSeq) FROM Ledgers;",
694 "DELETE FROM Ledgers WHERE LedgerSeq < %u;");
701 "SELECT MIN(LedgerSeq) FROM Transactions;",
702 "DELETE FROM Transactions WHERE LedgerSeq < %u;");
709 "SELECT MIN(LedgerSeq) FROM AccountTransactions;",
710 "DELETE FROM AccountTransactions WHERE LedgerSeq < %u;");
721 return Health::stopping;
736 <<
"s for node to get back into sync with network. state: "
738 << age.count() <<
's';
748 <<
". age " << age.count() <<
's';
756 return Health::unhealthy;
780 boost::optional<LedgerIndex>
799 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.
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_
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