Files
rippled/src/xrpld/app/rdb/backend/detail/SQLiteDatabase.cpp
2026-01-08 13:13:20 +00:00

643 lines
14 KiB
C++

#include <xrpld/app/ledger/LedgerMaster.h>
#include <xrpld/app/ledger/TransactionMaster.h>
#include <xrpld/app/misc/detail/AccountTxPaging.h>
#include <xrpld/app/rdb/backend/SQLiteDatabase.h>
#include <xrpld/app/rdb/backend/detail/Node.h>
#include <xrpl/basics/StringUtilities.h>
#include <xrpl/rdb/DatabaseCon.h>
#include <xrpl/rdb/SociDB.h>
namespace xrpl {
bool
SQLiteDatabase::makeLedgerDBs(
Config const& config,
DatabaseCon::Setup const& setup,
DatabaseCon::CheckpointerSetup const& checkpointerSetup)
{
auto [lgr, tx, res] =
detail::makeLedgerDBs(config, setup, checkpointerSetup, j_);
txdb_ = std::move(tx);
lgrdb_ = std::move(lgr);
return res;
}
std::optional<LedgerIndex>
SQLiteDatabase::getMinLedgerSeq()
{
/* if databases exists, use it */
if (existsLedger())
{
auto db = checkoutLedger();
return detail::getMinLedgerSeq(*db, detail::TableType::Ledgers);
}
/* else return empty value */
return {};
}
std::optional<LedgerIndex>
SQLiteDatabase::getTransactionsMinLedgerSeq()
{
if (!useTxTables_)
return {};
if (existsTransaction())
{
auto db = checkoutTransaction();
return detail::getMinLedgerSeq(*db, detail::TableType::Transactions);
}
return {};
}
std::optional<LedgerIndex>
SQLiteDatabase::getAccountTransactionsMinLedgerSeq()
{
if (!useTxTables_)
return {};
if (existsTransaction())
{
auto db = checkoutTransaction();
return detail::getMinLedgerSeq(
*db, detail::TableType::AccountTransactions);
}
return {};
}
std::optional<LedgerIndex>
SQLiteDatabase::getMaxLedgerSeq()
{
if (existsLedger())
{
auto db = checkoutLedger();
return detail::getMaxLedgerSeq(*db, detail::TableType::Ledgers);
}
return {};
}
void
SQLiteDatabase::deleteTransactionByLedgerSeq(LedgerIndex ledgerSeq)
{
if (!useTxTables_)
return;
if (existsTransaction())
{
auto db = checkoutTransaction();
detail::deleteByLedgerSeq(
*db, detail::TableType::Transactions, ledgerSeq);
return;
}
}
void
SQLiteDatabase::deleteBeforeLedgerSeq(LedgerIndex ledgerSeq)
{
if (existsLedger())
{
auto db = checkoutLedger();
detail::deleteBeforeLedgerSeq(
*db, detail::TableType::Ledgers, ledgerSeq);
return;
}
}
void
SQLiteDatabase::deleteTransactionsBeforeLedgerSeq(LedgerIndex ledgerSeq)
{
if (!useTxTables_)
return;
if (existsTransaction())
{
auto db = checkoutTransaction();
detail::deleteBeforeLedgerSeq(
*db, detail::TableType::Transactions, ledgerSeq);
return;
}
}
void
SQLiteDatabase::deleteAccountTransactionsBeforeLedgerSeq(LedgerIndex ledgerSeq)
{
if (!useTxTables_)
return;
if (existsTransaction())
{
auto db = checkoutTransaction();
detail::deleteBeforeLedgerSeq(
*db, detail::TableType::AccountTransactions, ledgerSeq);
return;
}
}
std::size_t
SQLiteDatabase::getTransactionCount()
{
if (!useTxTables_)
return 0;
if (existsTransaction())
{
auto db = checkoutTransaction();
return detail::getRows(*db, detail::TableType::Transactions);
}
return 0;
}
std::size_t
SQLiteDatabase::getAccountTransactionCount()
{
if (!useTxTables_)
return 0;
if (existsTransaction())
{
auto db = checkoutTransaction();
return detail::getRows(*db, detail::TableType::AccountTransactions);
}
return 0;
}
RelationalDatabase::CountMinMax
SQLiteDatabase::getLedgerCountMinMax()
{
if (existsLedger())
{
auto db = checkoutLedger();
return detail::getRowsMinMax(*db, detail::TableType::Ledgers);
}
return {0, 0, 0};
}
bool
SQLiteDatabase::saveValidatedLedger(
std::shared_ptr<Ledger const> const& ledger,
bool current)
{
if (existsLedger())
{
if (!detail::saveValidatedLedger(
*lgrdb_, txdb_, registry_, ledger, current))
return false;
}
return true;
}
std::optional<LedgerHeader>
SQLiteDatabase::getLedgerInfoByIndex(LedgerIndex ledgerSeq)
{
if (existsLedger())
{
auto db = checkoutLedger();
auto const res = detail::getLedgerInfoByIndex(*db, ledgerSeq, j_);
if (res.has_value())
return res;
}
return {};
}
std::optional<LedgerHeader>
SQLiteDatabase::getNewestLedgerInfo()
{
if (existsLedger())
{
auto db = checkoutLedger();
auto const res = detail::getNewestLedgerInfo(*db, j_);
if (res.has_value())
return res;
}
return {};
}
std::optional<LedgerHeader>
SQLiteDatabase::getLimitedOldestLedgerInfo(LedgerIndex ledgerFirstIndex)
{
if (existsLedger())
{
auto db = checkoutLedger();
auto const res =
detail::getLimitedOldestLedgerInfo(*db, ledgerFirstIndex, j_);
if (res.has_value())
return res;
}
return {};
}
std::optional<LedgerHeader>
SQLiteDatabase::getLimitedNewestLedgerInfo(LedgerIndex ledgerFirstIndex)
{
if (existsLedger())
{
auto db = checkoutLedger();
auto const res =
detail::getLimitedNewestLedgerInfo(*db, ledgerFirstIndex, j_);
if (res.has_value())
return res;
}
return {};
}
std::optional<LedgerHeader>
SQLiteDatabase::getLedgerInfoByHash(uint256 const& ledgerHash)
{
if (existsLedger())
{
auto db = checkoutLedger();
auto const res = detail::getLedgerInfoByHash(*db, ledgerHash, j_);
if (res.has_value())
return res;
}
return {};
}
uint256
SQLiteDatabase::getHashByIndex(LedgerIndex ledgerIndex)
{
if (existsLedger())
{
auto db = checkoutLedger();
auto const res = detail::getHashByIndex(*db, ledgerIndex);
if (res.isNonZero())
return res;
}
return uint256();
}
std::optional<LedgerHashPair>
SQLiteDatabase::getHashesByIndex(LedgerIndex ledgerIndex)
{
if (existsLedger())
{
auto db = checkoutLedger();
auto const res = detail::getHashesByIndex(*db, ledgerIndex, j_);
if (res.has_value())
return res;
}
return {};
}
std::map<LedgerIndex, LedgerHashPair>
SQLiteDatabase::getHashesByIndex(LedgerIndex minSeq, LedgerIndex maxSeq)
{
if (existsLedger())
{
auto db = checkoutLedger();
auto const res = detail::getHashesByIndex(*db, minSeq, maxSeq, j_);
if (!res.empty())
return res;
}
return {};
}
std::vector<std::shared_ptr<Transaction>>
SQLiteDatabase::getTxHistory(LedgerIndex startIndex)
{
if (!useTxTables_)
return {};
if (existsTransaction())
{
auto db = checkoutTransaction();
auto const res =
detail::getTxHistory(*db, registry_, startIndex, 20).first;
if (!res.empty())
return res;
}
return {};
}
RelationalDatabase::AccountTxs
SQLiteDatabase::getOldestAccountTxs(AccountTxOptions const& options)
{
if (!useTxTables_)
return {};
LedgerMaster& ledgerMaster = registry_.getLedgerMaster();
if (existsTransaction())
{
auto db = checkoutTransaction();
return detail::getOldestAccountTxs(
*db, registry_, ledgerMaster, options, j_)
.first;
}
return {};
}
RelationalDatabase::AccountTxs
SQLiteDatabase::getNewestAccountTxs(AccountTxOptions const& options)
{
if (!useTxTables_)
return {};
LedgerMaster& ledgerMaster = registry_.getLedgerMaster();
if (existsTransaction())
{
auto db = checkoutTransaction();
return detail::getNewestAccountTxs(
*db, registry_, ledgerMaster, options, j_)
.first;
}
return {};
}
RelationalDatabase::MetaTxsList
SQLiteDatabase::getOldestAccountTxsB(AccountTxOptions const& options)
{
if (!useTxTables_)
return {};
if (existsTransaction())
{
auto db = checkoutTransaction();
return detail::getOldestAccountTxsB(*db, registry_, options, j_).first;
}
return {};
}
RelationalDatabase::MetaTxsList
SQLiteDatabase::getNewestAccountTxsB(AccountTxOptions const& options)
{
if (!useTxTables_)
return {};
if (existsTransaction())
{
auto db = checkoutTransaction();
return detail::getNewestAccountTxsB(*db, registry_, options, j_).first;
}
return {};
}
std::pair<
RelationalDatabase::AccountTxs,
std::optional<RelationalDatabase::AccountTxMarker>>
SQLiteDatabase::oldestAccountTxPage(AccountTxPageOptions const& options)
{
if (!useTxTables_)
return {};
static std::uint32_t const page_length(200);
auto onUnsavedLedger =
std::bind(saveLedgerAsync, std::ref(registry_), std::placeholders::_1);
AccountTxs ret;
auto onTransaction = [&ret, &registry = registry_](
std::uint32_t ledger_index,
std::string const& status,
Blob&& rawTxn,
Blob&& rawMeta) {
convertBlobsToTxResult(
ret, ledger_index, status, rawTxn, rawMeta, registry);
};
if (existsTransaction())
{
auto db = checkoutTransaction();
auto newmarker =
detail::oldestAccountTxPage(
*db, onUnsavedLedger, onTransaction, options, page_length)
.first;
return {ret, newmarker};
}
return {};
}
std::pair<
RelationalDatabase::AccountTxs,
std::optional<RelationalDatabase::AccountTxMarker>>
SQLiteDatabase::newestAccountTxPage(AccountTxPageOptions const& options)
{
if (!useTxTables_)
return {};
static std::uint32_t const page_length(200);
auto onUnsavedLedger =
std::bind(saveLedgerAsync, std::ref(registry_), std::placeholders::_1);
AccountTxs ret;
auto onTransaction = [&ret, &registry = registry_](
std::uint32_t ledger_index,
std::string const& status,
Blob&& rawTxn,
Blob&& rawMeta) {
convertBlobsToTxResult(
ret, ledger_index, status, rawTxn, rawMeta, registry);
};
if (existsTransaction())
{
auto db = checkoutTransaction();
auto newmarker =
detail::newestAccountTxPage(
*db, onUnsavedLedger, onTransaction, options, page_length)
.first;
return {ret, newmarker};
}
return {};
}
std::pair<
RelationalDatabase::MetaTxsList,
std::optional<RelationalDatabase::AccountTxMarker>>
SQLiteDatabase::oldestAccountTxPageB(AccountTxPageOptions const& options)
{
if (!useTxTables_)
return {};
static std::uint32_t const page_length(500);
auto onUnsavedLedger =
std::bind(saveLedgerAsync, std::ref(registry_), std::placeholders::_1);
MetaTxsList ret;
auto onTransaction = [&ret](
std::uint32_t ledgerIndex,
std::string const& status,
Blob&& rawTxn,
Blob&& rawMeta) {
ret.emplace_back(std::move(rawTxn), std::move(rawMeta), ledgerIndex);
};
if (existsTransaction())
{
auto db = checkoutTransaction();
auto newmarker =
detail::oldestAccountTxPage(
*db, onUnsavedLedger, onTransaction, options, page_length)
.first;
return {ret, newmarker};
}
return {};
}
std::pair<
RelationalDatabase::MetaTxsList,
std::optional<RelationalDatabase::AccountTxMarker>>
SQLiteDatabase::newestAccountTxPageB(AccountTxPageOptions const& options)
{
if (!useTxTables_)
return {};
static std::uint32_t const page_length(500);
auto onUnsavedLedger =
std::bind(saveLedgerAsync, std::ref(registry_), std::placeholders::_1);
MetaTxsList ret;
auto onTransaction = [&ret](
std::uint32_t ledgerIndex,
std::string const& status,
Blob&& rawTxn,
Blob&& rawMeta) {
ret.emplace_back(std::move(rawTxn), std::move(rawMeta), ledgerIndex);
};
if (existsTransaction())
{
auto db = checkoutTransaction();
auto newmarker =
detail::newestAccountTxPage(
*db, onUnsavedLedger, onTransaction, options, page_length)
.first;
return {ret, newmarker};
}
return {};
}
std::variant<RelationalDatabase::AccountTx, TxSearched>
SQLiteDatabase::getTransaction(
uint256 const& id,
std::optional<ClosedInterval<std::uint32_t>> const& range,
error_code_i& ec)
{
if (!useTxTables_)
return TxSearched::unknown;
if (existsTransaction())
{
auto db = checkoutTransaction();
return detail::getTransaction(*db, registry_, id, range, ec);
}
return TxSearched::unknown;
}
bool
SQLiteDatabase::ledgerDbHasSpace(Config const& config)
{
if (existsLedger())
{
auto db = checkoutLedger();
return detail::dbHasSpace(*db, config, j_);
}
return true;
}
bool
SQLiteDatabase::transactionDbHasSpace(Config const& config)
{
if (!useTxTables_)
return true;
if (existsTransaction())
{
auto db = checkoutTransaction();
return detail::dbHasSpace(*db, config, j_);
}
return true;
}
std::uint32_t
SQLiteDatabase::getKBUsedAll()
{
if (existsLedger())
{
return xrpl::getKBUsedAll(lgrdb_->getSession());
}
return 0;
}
std::uint32_t
SQLiteDatabase::getKBUsedLedger()
{
if (existsLedger())
{
return xrpl::getKBUsedDB(lgrdb_->getSession());
}
return 0;
}
std::uint32_t
SQLiteDatabase::getKBUsedTransaction()
{
if (!useTxTables_)
return 0;
if (existsTransaction())
{
return xrpl::getKBUsedDB(txdb_->getSession());
}
return 0;
}
void
SQLiteDatabase::closeLedgerDB()
{
lgrdb_.reset();
}
void
SQLiteDatabase::closeTransactionDB()
{
txdb_.reset();
}
std::unique_ptr<SQLiteDatabase>
setup_RelationalDatabase(
ServiceRegistry& registry,
Config const& config,
JobQueue& jobQueue)
{
return std::make_unique<SQLiteDatabase>(registry, config, jobQueue);
}
} // namespace xrpl