mirror of
https://github.com/Xahau/xahaud.git
synced 2025-11-11 06:05:49 +00:00
Compare commits
12 Commits
add-clang-
...
fixup-rwdb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
317549ec54 | ||
|
|
3e57c72dc5 | ||
|
|
28e20215c7 | ||
|
|
a6f9c700ee | ||
|
|
849413eb1b | ||
|
|
c5f6242187 | ||
|
|
deeb8a0ec8 | ||
|
|
de1d5a3a2d | ||
|
|
559d32f04d | ||
|
|
9c2cc9f5f3 | ||
|
|
7bd82eef55 | ||
|
|
472c19418f |
@@ -118,9 +118,7 @@ SHAMapStoreImp::SHAMapStoreImp(
|
|||||||
|
|
||||||
get_if_exists(section, "online_delete", deleteInterval_);
|
get_if_exists(section, "online_delete", deleteInterval_);
|
||||||
|
|
||||||
bool const isMem = config.mem_backend();
|
if (deleteInterval_)
|
||||||
|
|
||||||
if (deleteInterval_ || isMem)
|
|
||||||
{
|
{
|
||||||
if (app_.config().reporting())
|
if (app_.config().reporting())
|
||||||
{
|
{
|
||||||
@@ -129,9 +127,6 @@ SHAMapStoreImp::SHAMapStoreImp(
|
|||||||
"online_delete info from config");
|
"online_delete info from config");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isMem)
|
|
||||||
deleteInterval_ = config.LEDGER_HISTORY;
|
|
||||||
|
|
||||||
// Configuration that affects the behavior of online delete
|
// Configuration that affects the behavior of online delete
|
||||||
get_if_exists(section, "delete_batch", deleteBatch_);
|
get_if_exists(section, "delete_batch", deleteBatch_);
|
||||||
std::uint32_t temp;
|
std::uint32_t temp;
|
||||||
@@ -167,7 +162,7 @@ SHAMapStoreImp::SHAMapStoreImp(
|
|||||||
}
|
}
|
||||||
|
|
||||||
state_db_.init(config, dbName_);
|
state_db_.init(config, dbName_);
|
||||||
if (!isMem)
|
if (!config.mem_backend())
|
||||||
dbPaths();
|
dbPaths();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -649,6 +644,33 @@ SHAMapStoreImp::clearPrior(LedgerIndex lastRotated)
|
|||||||
if (!db)
|
if (!db)
|
||||||
Throw<std::runtime_error>("Failed to get relational database");
|
Throw<std::runtime_error>("Failed to get relational database");
|
||||||
|
|
||||||
|
if (app_.config().useTxTables())
|
||||||
|
{
|
||||||
|
clearSql(
|
||||||
|
lastRotated,
|
||||||
|
"Transactions",
|
||||||
|
[&db]() -> std::optional<LedgerIndex> {
|
||||||
|
return db->getTransactionsMinLedgerSeq();
|
||||||
|
},
|
||||||
|
[&db](LedgerIndex min) -> void {
|
||||||
|
db->deleteTransactionsBeforeLedgerSeq(min);
|
||||||
|
});
|
||||||
|
if (healthWait() == stopping)
|
||||||
|
return;
|
||||||
|
|
||||||
|
clearSql(
|
||||||
|
lastRotated,
|
||||||
|
"AccountTransactions",
|
||||||
|
[&db]() -> std::optional<LedgerIndex> {
|
||||||
|
return db->getAccountTransactionsMinLedgerSeq();
|
||||||
|
},
|
||||||
|
[&db](LedgerIndex min) -> void {
|
||||||
|
db->deleteAccountTransactionsBeforeLedgerSeq(min);
|
||||||
|
});
|
||||||
|
if (healthWait() == stopping)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
clearSql(
|
clearSql(
|
||||||
lastRotated,
|
lastRotated,
|
||||||
"Ledgers",
|
"Ledgers",
|
||||||
@@ -656,33 +678,6 @@ SHAMapStoreImp::clearPrior(LedgerIndex lastRotated)
|
|||||||
[db](LedgerIndex min) -> void { db->deleteBeforeLedgerSeq(min); });
|
[db](LedgerIndex min) -> void { db->deleteBeforeLedgerSeq(min); });
|
||||||
if (healthWait() == stopping)
|
if (healthWait() == stopping)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!app_.config().useTxTables())
|
|
||||||
return;
|
|
||||||
|
|
||||||
clearSql(
|
|
||||||
lastRotated,
|
|
||||||
"Transactions",
|
|
||||||
[&db]() -> std::optional<LedgerIndex> {
|
|
||||||
return db->getTransactionsMinLedgerSeq();
|
|
||||||
},
|
|
||||||
[&db](LedgerIndex min) -> void {
|
|
||||||
db->deleteTransactionsBeforeLedgerSeq(min);
|
|
||||||
});
|
|
||||||
if (healthWait() == stopping)
|
|
||||||
return;
|
|
||||||
|
|
||||||
clearSql(
|
|
||||||
lastRotated,
|
|
||||||
"AccountTransactions",
|
|
||||||
[&db]() -> std::optional<LedgerIndex> {
|
|
||||||
return db->getAccountTransactionsMinLedgerSeq();
|
|
||||||
},
|
|
||||||
[&db](LedgerIndex min) -> void {
|
|
||||||
db->deleteAccountTransactionsBeforeLedgerSeq(min);
|
|
||||||
});
|
|
||||||
if (healthWait() == stopping)
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SHAMapStoreImp::HealthResult
|
SHAMapStoreImp::HealthResult
|
||||||
|
|||||||
@@ -3,7 +3,10 @@
|
|||||||
|
|
||||||
#include <ripple/app/ledger/AcceptedLedger.h>
|
#include <ripple/app/ledger/AcceptedLedger.h>
|
||||||
#include <ripple/app/ledger/LedgerMaster.h>
|
#include <ripple/app/ledger/LedgerMaster.h>
|
||||||
|
#include <ripple/app/ledger/LedgerToJson.h>
|
||||||
|
#include <ripple/app/ledger/PendingSaves.h>
|
||||||
#include <ripple/app/ledger/TransactionMaster.h>
|
#include <ripple/app/ledger/TransactionMaster.h>
|
||||||
|
#include <ripple/app/misc/impl/AccountTxPaging.h>
|
||||||
#include <ripple/app/rdb/backend/SQLiteDatabase.h>
|
#include <ripple/app/rdb/backend/SQLiteDatabase.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <map>
|
#include <map>
|
||||||
@@ -31,6 +34,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
Application& app_;
|
Application& app_;
|
||||||
|
bool const useTxTables_;
|
||||||
|
|
||||||
mutable std::shared_mutex mutex_;
|
mutable std::shared_mutex mutex_;
|
||||||
|
|
||||||
@@ -41,7 +45,7 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
RWDBDatabase(Application& app, Config const& config, JobQueue& jobQueue)
|
RWDBDatabase(Application& app, Config const& config, JobQueue& jobQueue)
|
||||||
: app_(app)
|
: app_(app), useTxTables_(config.useTxTables())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,6 +61,9 @@ public:
|
|||||||
std::optional<LedgerIndex>
|
std::optional<LedgerIndex>
|
||||||
getTransactionsMinLedgerSeq() override
|
getTransactionsMinLedgerSeq() override
|
||||||
{
|
{
|
||||||
|
if (!useTxTables_)
|
||||||
|
return {};
|
||||||
|
|
||||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
std::shared_lock<std::shared_mutex> lock(mutex_);
|
||||||
if (transactionMap_.empty())
|
if (transactionMap_.empty())
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
@@ -66,6 +73,9 @@ public:
|
|||||||
std::optional<LedgerIndex>
|
std::optional<LedgerIndex>
|
||||||
getAccountTransactionsMinLedgerSeq() override
|
getAccountTransactionsMinLedgerSeq() override
|
||||||
{
|
{
|
||||||
|
if (!useTxTables_)
|
||||||
|
return {};
|
||||||
|
|
||||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
std::shared_lock<std::shared_mutex> lock(mutex_);
|
||||||
if (accountTxMap_.empty())
|
if (accountTxMap_.empty())
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
@@ -92,6 +102,9 @@ public:
|
|||||||
void
|
void
|
||||||
deleteTransactionByLedgerSeq(LedgerIndex ledgerSeq) override
|
deleteTransactionByLedgerSeq(LedgerIndex ledgerSeq) override
|
||||||
{
|
{
|
||||||
|
if (!useTxTables_)
|
||||||
|
return;
|
||||||
|
|
||||||
std::unique_lock<std::shared_mutex> lock(mutex_);
|
std::unique_lock<std::shared_mutex> lock(mutex_);
|
||||||
auto it = ledgers_.find(ledgerSeq);
|
auto it = ledgers_.find(ledgerSeq);
|
||||||
if (it != ledgers_.end())
|
if (it != ledgers_.end())
|
||||||
@@ -102,18 +115,6 @@ public:
|
|||||||
}
|
}
|
||||||
it->second.transactions.clear();
|
it->second.transactions.clear();
|
||||||
}
|
}
|
||||||
for (auto& [_, accountData] : accountTxMap_)
|
|
||||||
{
|
|
||||||
accountData.ledgerTxMap.erase(ledgerSeq);
|
|
||||||
accountData.transactions.erase(
|
|
||||||
std::remove_if(
|
|
||||||
accountData.transactions.begin(),
|
|
||||||
accountData.transactions.end(),
|
|
||||||
[ledgerSeq](const AccountTx& tx) {
|
|
||||||
return tx.second->getLgrSeq() == ledgerSeq;
|
|
||||||
}),
|
|
||||||
accountData.transactions.end());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -123,69 +124,36 @@ public:
|
|||||||
auto it = ledgers_.begin();
|
auto it = ledgers_.begin();
|
||||||
while (it != ledgers_.end() && it->first < ledgerSeq)
|
while (it != ledgers_.end() && it->first < ledgerSeq)
|
||||||
{
|
{
|
||||||
for (const auto& [txHash, _] : it->second.transactions)
|
|
||||||
{
|
|
||||||
transactionMap_.erase(txHash);
|
|
||||||
}
|
|
||||||
ledgerHashToSeq_.erase(it->second.info.hash);
|
ledgerHashToSeq_.erase(it->second.info.hash);
|
||||||
it = ledgers_.erase(it);
|
it = ledgers_.erase(it);
|
||||||
}
|
}
|
||||||
for (auto& [_, accountData] : accountTxMap_)
|
|
||||||
{
|
|
||||||
auto txIt = accountData.ledgerTxMap.begin();
|
|
||||||
while (txIt != accountData.ledgerTxMap.end() &&
|
|
||||||
txIt->first < ledgerSeq)
|
|
||||||
{
|
|
||||||
txIt = accountData.ledgerTxMap.erase(txIt);
|
|
||||||
}
|
|
||||||
accountData.transactions.erase(
|
|
||||||
std::remove_if(
|
|
||||||
accountData.transactions.begin(),
|
|
||||||
accountData.transactions.end(),
|
|
||||||
[ledgerSeq](const AccountTx& tx) {
|
|
||||||
return tx.second->getLgrSeq() < ledgerSeq;
|
|
||||||
}),
|
|
||||||
accountData.transactions.end());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
deleteTransactionsBeforeLedgerSeq(LedgerIndex ledgerSeq) override
|
deleteTransactionsBeforeLedgerSeq(LedgerIndex ledgerSeq) override
|
||||||
{
|
{
|
||||||
|
if (!useTxTables_)
|
||||||
|
return;
|
||||||
|
|
||||||
std::unique_lock<std::shared_mutex> lock(mutex_);
|
std::unique_lock<std::shared_mutex> lock(mutex_);
|
||||||
for (auto& [seq, ledgerData] : ledgers_)
|
auto it = ledgers_.begin();
|
||||||
|
while (it != ledgers_.end() && it->first < ledgerSeq)
|
||||||
{
|
{
|
||||||
if (seq < ledgerSeq)
|
for (const auto& [txHash, _] : it->second.transactions)
|
||||||
{
|
{
|
||||||
for (const auto& [txHash, _] : ledgerData.transactions)
|
transactionMap_.erase(txHash);
|
||||||
{
|
|
||||||
transactionMap_.erase(txHash);
|
|
||||||
}
|
|
||||||
ledgerData.transactions.clear();
|
|
||||||
}
|
}
|
||||||
}
|
it->second.transactions.clear();
|
||||||
for (auto& [_, accountData] : accountTxMap_)
|
++it;
|
||||||
{
|
|
||||||
auto txIt = accountData.ledgerTxMap.begin();
|
|
||||||
while (txIt != accountData.ledgerTxMap.end() &&
|
|
||||||
txIt->first < ledgerSeq)
|
|
||||||
{
|
|
||||||
txIt = accountData.ledgerTxMap.erase(txIt);
|
|
||||||
}
|
|
||||||
accountData.transactions.erase(
|
|
||||||
std::remove_if(
|
|
||||||
accountData.transactions.begin(),
|
|
||||||
accountData.transactions.end(),
|
|
||||||
[ledgerSeq](const AccountTx& tx) {
|
|
||||||
return tx.second->getLgrSeq() < ledgerSeq;
|
|
||||||
}),
|
|
||||||
accountData.transactions.end());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
deleteAccountTransactionsBeforeLedgerSeq(LedgerIndex ledgerSeq) override
|
deleteAccountTransactionsBeforeLedgerSeq(LedgerIndex ledgerSeq) override
|
||||||
{
|
{
|
||||||
|
if (!useTxTables_)
|
||||||
|
return;
|
||||||
|
|
||||||
std::unique_lock<std::shared_mutex> lock(mutex_);
|
std::unique_lock<std::shared_mutex> lock(mutex_);
|
||||||
for (auto& [_, accountData] : accountTxMap_)
|
for (auto& [_, accountData] : accountTxMap_)
|
||||||
{
|
{
|
||||||
@@ -208,6 +176,9 @@ public:
|
|||||||
std::size_t
|
std::size_t
|
||||||
getTransactionCount() override
|
getTransactionCount() override
|
||||||
{
|
{
|
||||||
|
if (!useTxTables_)
|
||||||
|
return 0;
|
||||||
|
|
||||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
std::shared_lock<std::shared_mutex> lock(mutex_);
|
||||||
return transactionMap_.size();
|
return transactionMap_.size();
|
||||||
}
|
}
|
||||||
@@ -215,6 +186,9 @@ public:
|
|||||||
std::size_t
|
std::size_t
|
||||||
getAccountTransactionCount() override
|
getAccountTransactionCount() override
|
||||||
{
|
{
|
||||||
|
if (!useTxTables_)
|
||||||
|
return 0;
|
||||||
|
|
||||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
std::shared_lock<std::shared_mutex> lock(mutex_);
|
||||||
std::size_t count = 0;
|
std::size_t count = 0;
|
||||||
for (const auto& [_, accountData] : accountTxMap_)
|
for (const auto& [_, accountData] : accountTxMap_)
|
||||||
@@ -242,131 +216,100 @@ public:
|
|||||||
std::unique_lock<std::shared_mutex> lock(mutex_);
|
std::unique_lock<std::shared_mutex> lock(mutex_);
|
||||||
LedgerData ledgerData;
|
LedgerData ledgerData;
|
||||||
ledgerData.info = ledger->info();
|
ledgerData.info = ledger->info();
|
||||||
auto aLedger = std::make_shared<AcceptedLedger>(ledger, app_);
|
auto j = app_.journal("Ledger");
|
||||||
|
auto seq = ledger->info().seq;
|
||||||
|
|
||||||
for (auto const& acceptedLedgerTx : *aLedger)
|
JLOG(j.trace()) << "saveValidatedLedger "
|
||||||
|
<< (current ? "" : "fromAcquire ") << seq;
|
||||||
|
|
||||||
|
if (!ledger->info().accountHash.isNonZero())
|
||||||
{
|
{
|
||||||
auto const& txn = acceptedLedgerTx->getTxn();
|
JLOG(j.fatal()) << "AH is zero: " << getJson({*ledger, {}});
|
||||||
auto const& meta = acceptedLedgerTx->getMeta();
|
assert(false);
|
||||||
auto const& id = txn->getTransactionID();
|
}
|
||||||
std::string reason;
|
|
||||||
|
|
||||||
auto accTx = std::make_pair(
|
if (ledger->info().accountHash !=
|
||||||
std::make_shared<ripple::Transaction>(txn, reason, app_),
|
ledger->stateMap().getHash().as_uint256())
|
||||||
std::make_shared<ripple::TxMeta>(meta));
|
{
|
||||||
|
JLOG(j.fatal()) << "sAL: " << ledger->info().accountHash
|
||||||
|
<< " != " << ledger->stateMap().getHash();
|
||||||
|
JLOG(j.fatal())
|
||||||
|
<< "saveAcceptedLedger: seq=" << seq << ", current=" << current;
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
ledgerData.transactions.emplace(id, accTx);
|
assert(ledger->info().txHash == ledger->txMap().getHash().as_uint256());
|
||||||
transactionMap_.emplace(id, accTx);
|
|
||||||
|
|
||||||
for (auto const& account : meta.getAffectedAccounts())
|
// Save the ledger header in the hashed object store
|
||||||
|
{
|
||||||
|
Serializer s(128);
|
||||||
|
s.add32(HashPrefix::ledgerMaster);
|
||||||
|
addRaw(ledger->info(), s);
|
||||||
|
app_.getNodeStore().store(
|
||||||
|
hotLEDGER, std::move(s.modData()), ledger->info().hash, seq);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<AcceptedLedger> aLedger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
aLedger = app_.getAcceptedLedgerCache().fetch(ledger->info().hash);
|
||||||
|
if (!aLedger)
|
||||||
{
|
{
|
||||||
if (accountTxMap_.find(account) == accountTxMap_.end())
|
aLedger = std::make_shared<AcceptedLedger>(ledger, app_);
|
||||||
accountTxMap_[account] = AccountTxData();
|
app_.getAcceptedLedgerCache().canonicalize_replace_client(
|
||||||
auto& accountData = accountTxMap_[account];
|
ledger->info().hash, aLedger);
|
||||||
accountData.transactions.push_back(accTx);
|
}
|
||||||
accountData.ledgerTxMap[ledger->info().seq]
|
}
|
||||||
[acceptedLedgerTx->getTxnSeq()] =
|
catch (std::exception const&)
|
||||||
accountData.transactions.size() - 1;
|
{
|
||||||
}
|
JLOG(j.warn()) << "An accepted ledger was missing nodes";
|
||||||
}
|
app_.getLedgerMaster().failedSave(seq, ledger->info().hash);
|
||||||
|
// Clients can now trust the database for information about this
|
||||||
ledgers_[ledger->info().seq] = std::move(ledgerData);
|
// ledger sequence.
|
||||||
ledgerHashToSeq_[ledger->info().hash] = ledger->info().seq;
|
app_.pendingSaves().finishWork(seq);
|
||||||
|
return false;
|
||||||
if (current)
|
}
|
||||||
{
|
|
||||||
auto const cutoffSeq =
|
// Overwrite Current Ledger Transactions
|
||||||
ledger->info().seq > app_.config().LEDGER_HISTORY
|
if (useTxTables_)
|
||||||
? ledger->info().seq - app_.config().LEDGER_HISTORY
|
{
|
||||||
: 0;
|
for (auto const& acceptedLedgerTx : *aLedger)
|
||||||
|
{
|
||||||
if (cutoffSeq > 0)
|
auto const& txn = acceptedLedgerTx->getTxn();
|
||||||
{
|
auto const& meta = acceptedLedgerTx->getMeta();
|
||||||
const std::size_t BATCH_SIZE = 128;
|
auto const& id = txn->getTransactionID();
|
||||||
std::size_t deleted = 0;
|
std::string reason;
|
||||||
|
|
||||||
std::vector<std::uint32_t> ledgersToDelete;
|
auto accTx = std::make_pair(
|
||||||
for (const auto& item : ledgers_)
|
std::make_shared<ripple::Transaction>(txn, reason, app_),
|
||||||
{
|
std::make_shared<ripple::TxMeta>(meta));
|
||||||
if (deleted >= BATCH_SIZE)
|
|
||||||
break;
|
ledgerData.transactions.emplace(id, accTx);
|
||||||
if (item.first < cutoffSeq)
|
transactionMap_.emplace(id, accTx);
|
||||||
{
|
|
||||||
ledgersToDelete.push_back(item.first);
|
for (auto const& account : meta.getAffectedAccounts())
|
||||||
deleted++;
|
{
|
||||||
}
|
if (accountTxMap_.find(account) == accountTxMap_.end())
|
||||||
}
|
accountTxMap_[account] = AccountTxData();
|
||||||
|
|
||||||
for (auto seq : ledgersToDelete)
|
auto& accountData = accountTxMap_[account];
|
||||||
{
|
accountData.transactions.push_back(accTx);
|
||||||
auto& ledgerToDelete = ledgers_[seq];
|
accountData
|
||||||
|
.ledgerTxMap[seq][acceptedLedgerTx->getTxnSeq()] =
|
||||||
for (const auto& txPair : ledgerToDelete.transactions)
|
accountData.transactions.size() - 1;
|
||||||
{
|
}
|
||||||
transactionMap_.erase(txPair.first);
|
|
||||||
}
|
app_.getMasterTransaction().inLedger(
|
||||||
|
id,
|
||||||
ledgerHashToSeq_.erase(ledgerToDelete.info.hash);
|
seq,
|
||||||
ledgers_.erase(seq);
|
acceptedLedgerTx->getTxnSeq(),
|
||||||
}
|
app_.config().NETWORK_ID);
|
||||||
|
|
||||||
if (deleted > 0)
|
|
||||||
{
|
|
||||||
for (auto& [account, data] : accountTxMap_)
|
|
||||||
{
|
|
||||||
auto it = data.ledgerTxMap.begin();
|
|
||||||
while (it != data.ledgerTxMap.end())
|
|
||||||
{
|
|
||||||
if (it->first < cutoffSeq)
|
|
||||||
{
|
|
||||||
for (const auto& seqPair : it->second)
|
|
||||||
{
|
|
||||||
if (seqPair.second <
|
|
||||||
data.transactions.size())
|
|
||||||
{
|
|
||||||
auto& txPair =
|
|
||||||
data.transactions[seqPair.second];
|
|
||||||
txPair.first.reset();
|
|
||||||
txPair.second.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
it = data.ledgerTxMap.erase(it);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data.transactions.erase(
|
|
||||||
std::remove_if(
|
|
||||||
data.transactions.begin(),
|
|
||||||
data.transactions.end(),
|
|
||||||
[](const auto& tx) {
|
|
||||||
return !tx.first && !tx.second;
|
|
||||||
}),
|
|
||||||
data.transactions.end());
|
|
||||||
|
|
||||||
for (auto& [ledgerSeq, txMap] : data.ledgerTxMap)
|
|
||||||
{
|
|
||||||
for (auto& [txSeq, index] : txMap)
|
|
||||||
{
|
|
||||||
auto newIndex = std::distance(
|
|
||||||
data.transactions.begin(),
|
|
||||||
std::find(
|
|
||||||
data.transactions.begin(),
|
|
||||||
data.transactions.end(),
|
|
||||||
data.transactions[index]));
|
|
||||||
index = newIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
app_.getLedgerMaster().clearPriorLedgers(cutoffSeq);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Overwrite Current Ledger
|
||||||
|
ledgers_[seq] = std::move(ledgerData);
|
||||||
|
ledgerHashToSeq_[ledger->info().hash] = seq;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -462,29 +405,35 @@ public:
|
|||||||
std::optional<ClosedInterval<std::uint32_t>> const& range,
|
std::optional<ClosedInterval<std::uint32_t>> const& range,
|
||||||
error_code_i& ec) override
|
error_code_i& ec) override
|
||||||
{
|
{
|
||||||
|
if (!useTxTables_)
|
||||||
|
return TxSearched::unknown;
|
||||||
|
|
||||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
std::shared_lock<std::shared_mutex> lock(mutex_);
|
||||||
auto it = transactionMap_.find(id);
|
auto it = transactionMap_.find(id);
|
||||||
if (it != transactionMap_.end())
|
if (it != transactionMap_.end())
|
||||||
{
|
{
|
||||||
const auto& [txn, txMeta] = it->second;
|
const auto& [txn, txMeta] = it->second;
|
||||||
if (!range ||
|
std::uint32_t inLedger =
|
||||||
(range->lower() <= txMeta->getLgrSeq() &&
|
rangeCheckedCast<std::uint32_t>(txMeta->getLgrSeq());
|
||||||
txMeta->getLgrSeq() <= range->upper()))
|
it->second.first->setStatus(COMMITTED);
|
||||||
return it->second;
|
it->second.first->setLedger(inLedger);
|
||||||
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (range)
|
if (range)
|
||||||
{
|
{
|
||||||
bool allPresent = true;
|
std::size_t count = 0;
|
||||||
for (LedgerIndex seq = range->lower(); seq <= range->upper(); ++seq)
|
for (LedgerIndex seq = range->first(); seq <= range->last(); ++seq)
|
||||||
{
|
{
|
||||||
if (ledgers_.find(seq) == ledgers_.end())
|
if (ledgers_.find(seq) != ledgers_.end())
|
||||||
{
|
{
|
||||||
allPresent = false;
|
if (ledgers_[seq].transactions.size() > 0)
|
||||||
break;
|
++count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return allPresent ? TxSearched::all : TxSearched::some;
|
return (count == (range->last() - range->first() + 1))
|
||||||
|
? TxSearched::all
|
||||||
|
: TxSearched::some;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TxSearched::unknown;
|
return TxSearched::unknown;
|
||||||
@@ -538,6 +487,9 @@ public:
|
|||||||
std::uint32_t
|
std::uint32_t
|
||||||
getKBUsedTransaction() override
|
getKBUsedTransaction() override
|
||||||
{
|
{
|
||||||
|
if (!useTxTables_)
|
||||||
|
return 0;
|
||||||
|
|
||||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
std::shared_lock<std::shared_mutex> lock(mutex_);
|
||||||
std::uint32_t size = 0;
|
std::uint32_t size = 0;
|
||||||
size += transactionMap_.size() * (sizeof(uint256) + sizeof(AccountTx));
|
size += transactionMap_.size() * (sizeof(uint256) + sizeof(AccountTx));
|
||||||
@@ -582,22 +534,45 @@ public:
|
|||||||
std::vector<std::shared_ptr<Transaction>>
|
std::vector<std::shared_ptr<Transaction>>
|
||||||
getTxHistory(LedgerIndex startIndex) override
|
getTxHistory(LedgerIndex startIndex) override
|
||||||
{
|
{
|
||||||
|
if (!useTxTables_)
|
||||||
|
return {};
|
||||||
|
|
||||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
std::shared_lock<std::shared_mutex> lock(mutex_);
|
||||||
std::vector<std::shared_ptr<Transaction>> result;
|
std::vector<std::shared_ptr<Transaction>> result;
|
||||||
auto it = ledgers_.lower_bound(startIndex);
|
|
||||||
int count = 0;
|
int skipped = 0;
|
||||||
while (it != ledgers_.end() && count < 20)
|
int collected = 0;
|
||||||
|
|
||||||
|
for (auto it = ledgers_.rbegin(); it != ledgers_.rend(); ++it)
|
||||||
{
|
{
|
||||||
for (const auto& [txHash, accountTx] : it->second.transactions)
|
const auto& transactions = it->second.transactions;
|
||||||
|
for (const auto& [txHash, accountTx] : transactions)
|
||||||
{
|
{
|
||||||
result.push_back(accountTx.first);
|
if (skipped < startIndex)
|
||||||
if (++count >= 20)
|
{
|
||||||
|
++skipped;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (collected >= 20)
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint32_t const inLedger = rangeCheckedCast<std::uint32_t>(
|
||||||
|
accountTx.second->getLgrSeq());
|
||||||
|
accountTx.first->setStatus(COMMITTED);
|
||||||
|
accountTx.first->setLedger(inLedger);
|
||||||
|
result.push_back(accountTx.first);
|
||||||
|
++collected;
|
||||||
}
|
}
|
||||||
++it;
|
|
||||||
|
if (collected >= 20)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to handle limits
|
// Helper function to handle limits
|
||||||
template <typename Container>
|
template <typename Container>
|
||||||
void
|
void
|
||||||
@@ -612,6 +587,9 @@ public:
|
|||||||
AccountTxs
|
AccountTxs
|
||||||
getOldestAccountTxs(AccountTxOptions const& options) override
|
getOldestAccountTxs(AccountTxOptions const& options) override
|
||||||
{
|
{
|
||||||
|
if (!useTxTables_)
|
||||||
|
return {};
|
||||||
|
|
||||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
std::shared_lock<std::shared_mutex> lock(mutex_);
|
||||||
auto it = accountTxMap_.find(options.account);
|
auto it = accountTxMap_.find(options.account);
|
||||||
if (it == accountTxMap_.end())
|
if (it == accountTxMap_.end())
|
||||||
@@ -634,7 +612,12 @@ public:
|
|||||||
++skipped;
|
++skipped;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
result.push_back(accountData.transactions[txIndex]);
|
AccountTx const accountTx = accountData.transactions[txIndex];
|
||||||
|
std::uint32_t const inLedger = rangeCheckedCast<std::uint32_t>(
|
||||||
|
accountTx.second->getLgrSeq());
|
||||||
|
accountTx.first->setStatus(COMMITTED);
|
||||||
|
accountTx.first->setLedger(inLedger);
|
||||||
|
result.push_back(accountTx);
|
||||||
if (!options.bUnlimited && result.size() >= options.limit)
|
if (!options.bUnlimited && result.size() >= options.limit)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -646,6 +629,9 @@ public:
|
|||||||
AccountTxs
|
AccountTxs
|
||||||
getNewestAccountTxs(AccountTxOptions const& options) override
|
getNewestAccountTxs(AccountTxOptions const& options) override
|
||||||
{
|
{
|
||||||
|
if (!useTxTables_)
|
||||||
|
return {};
|
||||||
|
|
||||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
std::shared_lock<std::shared_mutex> lock(mutex_);
|
||||||
auto it = accountTxMap_.find(options.account);
|
auto it = accountTxMap_.find(options.account);
|
||||||
if (it == accountTxMap_.end())
|
if (it == accountTxMap_.end())
|
||||||
@@ -671,7 +657,12 @@ public:
|
|||||||
++skipped;
|
++skipped;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
result.push_back(accountData.transactions[innerRIt->second]);
|
AccountTx const accountTx =
|
||||||
|
accountData.transactions[innerRIt->second];
|
||||||
|
std::uint32_t const inLedger = rangeCheckedCast<std::uint32_t>(
|
||||||
|
accountTx.second->getLgrSeq());
|
||||||
|
accountTx.first->setLedger(inLedger);
|
||||||
|
result.push_back(accountTx);
|
||||||
if (!options.bUnlimited && result.size() >= options.limit)
|
if (!options.bUnlimited && result.size() >= options.limit)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -683,6 +674,9 @@ public:
|
|||||||
MetaTxsList
|
MetaTxsList
|
||||||
getOldestAccountTxsB(AccountTxOptions const& options) override
|
getOldestAccountTxsB(AccountTxOptions const& options) override
|
||||||
{
|
{
|
||||||
|
if (!useTxTables_)
|
||||||
|
return {};
|
||||||
|
|
||||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
std::shared_lock<std::shared_mutex> lock(mutex_);
|
||||||
auto it = accountTxMap_.find(options.account);
|
auto it = accountTxMap_.find(options.account);
|
||||||
if (it == accountTxMap_.end())
|
if (it == accountTxMap_.end())
|
||||||
@@ -721,6 +715,9 @@ public:
|
|||||||
MetaTxsList
|
MetaTxsList
|
||||||
getNewestAccountTxsB(AccountTxOptions const& options) override
|
getNewestAccountTxsB(AccountTxOptions const& options) override
|
||||||
{
|
{
|
||||||
|
if (!useTxTables_)
|
||||||
|
return {};
|
||||||
|
|
||||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
std::shared_lock<std::shared_mutex> lock(mutex_);
|
||||||
auto it = accountTxMap_.find(options.account);
|
auto it = accountTxMap_.find(options.account);
|
||||||
if (it == accountTxMap_.end())
|
if (it == accountTxMap_.end())
|
||||||
@@ -759,197 +756,270 @@ public:
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
std::pair<AccountTxs, std::optional<AccountTxMarker>>
|
|
||||||
oldestAccountTxPage(AccountTxPageOptions const& options) override
|
std::pair<std::optional<RelationalDatabase::AccountTxMarker>, int>
|
||||||
|
accountTxPage(
|
||||||
|
std::function<void(std::uint32_t)> const& onUnsavedLedger,
|
||||||
|
std::function<
|
||||||
|
void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const&
|
||||||
|
onTransaction,
|
||||||
|
RelationalDatabase::AccountTxPageOptions const& options,
|
||||||
|
int limit_used,
|
||||||
|
std::uint32_t page_length,
|
||||||
|
bool forward)
|
||||||
{
|
{
|
||||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
std::shared_lock<std::shared_mutex> lock(mutex_);
|
||||||
auto it = accountTxMap_.find(options.account);
|
auto it = accountTxMap_.find(options.account);
|
||||||
if (it == accountTxMap_.end())
|
if (it == accountTxMap_.end())
|
||||||
return {{}, std::nullopt};
|
return {std::nullopt, 0};
|
||||||
|
|
||||||
AccountTxs result;
|
int total = 0;
|
||||||
std::optional<AccountTxMarker> marker;
|
|
||||||
const auto& accountData = it->second;
|
|
||||||
auto txIt = accountData.ledgerTxMap.lower_bound(options.minLedger);
|
|
||||||
auto txEnd = accountData.ledgerTxMap.upper_bound(options.maxLedger);
|
|
||||||
|
|
||||||
bool lookingForMarker = options.marker.has_value();
|
bool lookingForMarker = options.marker.has_value();
|
||||||
std::size_t count = 0;
|
|
||||||
|
|
||||||
for (; txIt != txEnd && (options.limit == 0 || count < options.limit);
|
std::uint32_t numberOfResults;
|
||||||
++txIt)
|
|
||||||
|
if (options.limit == 0 || options.limit == UINT32_MAX ||
|
||||||
|
(options.limit > page_length && !options.bAdmin))
|
||||||
|
numberOfResults = page_length;
|
||||||
|
else
|
||||||
|
numberOfResults = options.limit;
|
||||||
|
|
||||||
|
if (numberOfResults < limit_used)
|
||||||
|
return {options.marker, -1};
|
||||||
|
numberOfResults -= limit_used;
|
||||||
|
|
||||||
|
// As an account can have many thousands of transactions, there is a
|
||||||
|
// limit placed on the amount of transactions returned. If the limit is
|
||||||
|
// reached before the result set has been exhausted (we always query for
|
||||||
|
// one more than the limit), then we return an opaque marker that can be
|
||||||
|
// supplied in a subsequent query.
|
||||||
|
std::uint32_t queryLimit = numberOfResults + 1;
|
||||||
|
std::uint32_t findLedger = 0, findSeq = 0;
|
||||||
|
|
||||||
|
if (lookingForMarker)
|
||||||
{
|
{
|
||||||
for (const auto& [txSeq, txIndex] : txIt->second)
|
findLedger = options.marker->ledgerSeq;
|
||||||
|
findSeq = options.marker->txnSeq;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<RelationalDatabase::AccountTxMarker> newmarker;
|
||||||
|
if (limit_used > 0)
|
||||||
|
newmarker = options.marker;
|
||||||
|
|
||||||
|
if (forward)
|
||||||
|
{
|
||||||
|
// Oldest (forward = true)
|
||||||
|
const auto& accountData = it->second;
|
||||||
|
auto txIt = accountData.ledgerTxMap.lower_bound(
|
||||||
|
findLedger == 0 ? options.minLedger : findLedger);
|
||||||
|
auto txEnd = accountData.ledgerTxMap.upper_bound(options.maxLedger);
|
||||||
|
for (; txIt != txEnd; ++txIt)
|
||||||
{
|
{
|
||||||
if (lookingForMarker)
|
std::uint32_t const ledgerSeq = txIt->first;
|
||||||
|
for (auto seqIt = txIt->second.begin();
|
||||||
|
seqIt != txIt->second.end();
|
||||||
|
++seqIt)
|
||||||
{
|
{
|
||||||
if (txIt->first == options.marker->ledgerSeq &&
|
const auto& [txnSeq, index] = *seqIt;
|
||||||
txSeq == options.marker->txnSeq)
|
if (lookingForMarker)
|
||||||
lookingForMarker = false;
|
{
|
||||||
continue;
|
if (findLedger == ledgerSeq && findSeq == txnSeq)
|
||||||
}
|
{
|
||||||
|
lookingForMarker = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (numberOfResults == 0)
|
||||||
|
{
|
||||||
|
newmarker = {
|
||||||
|
rangeCheckedCast<std::uint32_t>(ledgerSeq), txnSeq};
|
||||||
|
return {newmarker, total};
|
||||||
|
}
|
||||||
|
|
||||||
result.push_back(accountData.transactions[txIndex]);
|
Blob rawTxn = accountData.transactions[index]
|
||||||
++count;
|
.first->getSTransaction()
|
||||||
|
->getSerializer()
|
||||||
|
.peekData();
|
||||||
|
Blob rawMeta = accountData.transactions[index]
|
||||||
|
.second->getAsObject()
|
||||||
|
.getSerializer()
|
||||||
|
.peekData();
|
||||||
|
|
||||||
if (options.limit > 0 && count >= options.limit)
|
if (rawMeta.size() == 0)
|
||||||
{
|
onUnsavedLedger(ledgerSeq);
|
||||||
marker = AccountTxMarker{txIt->first, txSeq};
|
|
||||||
break;
|
onTransaction(
|
||||||
|
rangeCheckedCast<std::uint32_t>(ledgerSeq),
|
||||||
|
"COMMITTED",
|
||||||
|
std::move(rawTxn),
|
||||||
|
std::move(rawMeta));
|
||||||
|
--numberOfResults;
|
||||||
|
++total;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Newest (forward = false)
|
||||||
|
const auto& accountData = it->second;
|
||||||
|
auto txIt = accountData.ledgerTxMap.lower_bound(options.minLedger);
|
||||||
|
auto txEnd = accountData.ledgerTxMap.upper_bound(
|
||||||
|
findLedger == 0 ? options.maxLedger : findLedger);
|
||||||
|
auto rtxIt = std::make_reverse_iterator(txEnd);
|
||||||
|
auto rtxEnd = std::make_reverse_iterator(txIt);
|
||||||
|
for (; rtxIt != rtxEnd; ++rtxIt)
|
||||||
|
{
|
||||||
|
std::uint32_t const ledgerSeq = rtxIt->first;
|
||||||
|
for (auto innerRIt = rtxIt->second.rbegin();
|
||||||
|
innerRIt != rtxIt->second.rend();
|
||||||
|
++innerRIt)
|
||||||
|
{
|
||||||
|
const auto& [txnSeq, index] = *innerRIt;
|
||||||
|
if (lookingForMarker)
|
||||||
|
{
|
||||||
|
if (findLedger == ledgerSeq && findSeq == txnSeq)
|
||||||
|
{
|
||||||
|
lookingForMarker = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (numberOfResults == 0)
|
||||||
|
{
|
||||||
|
newmarker = {
|
||||||
|
rangeCheckedCast<std::uint32_t>(ledgerSeq), txnSeq};
|
||||||
|
return {newmarker, total};
|
||||||
|
}
|
||||||
|
|
||||||
return {result, marker};
|
Blob rawTxn = accountData.transactions[index]
|
||||||
|
.first->getSTransaction()
|
||||||
|
->getSerializer()
|
||||||
|
.peekData();
|
||||||
|
Blob rawMeta = accountData.transactions[index]
|
||||||
|
.second->getAsObject()
|
||||||
|
.getSerializer()
|
||||||
|
.peekData();
|
||||||
|
|
||||||
|
if (rawMeta.size() == 0)
|
||||||
|
onUnsavedLedger(ledgerSeq);
|
||||||
|
|
||||||
|
onTransaction(
|
||||||
|
rangeCheckedCast<std::uint32_t>(ledgerSeq),
|
||||||
|
"COMMITTED",
|
||||||
|
std::move(rawTxn),
|
||||||
|
std::move(rawMeta));
|
||||||
|
--numberOfResults;
|
||||||
|
++total;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {newmarker, total};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<AccountTxs, std::optional<AccountTxMarker>>
|
||||||
|
oldestAccountTxPage(AccountTxPageOptions const& options) override
|
||||||
|
{
|
||||||
|
if (!useTxTables_)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
static std::uint32_t const page_length(200);
|
||||||
|
auto onUnsavedLedger =
|
||||||
|
std::bind(saveLedgerAsync, std::ref(app_), std::placeholders::_1);
|
||||||
|
AccountTxs ret;
|
||||||
|
Application& app = app_;
|
||||||
|
auto onTransaction = [&ret, &app](
|
||||||
|
std::uint32_t ledger_index,
|
||||||
|
std::string const& status,
|
||||||
|
Blob&& rawTxn,
|
||||||
|
Blob&& rawMeta) {
|
||||||
|
convertBlobsToTxResult(
|
||||||
|
ret, ledger_index, status, rawTxn, rawMeta, app);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto newmarker =
|
||||||
|
accountTxPage(
|
||||||
|
onUnsavedLedger, onTransaction, options, 0, page_length, true)
|
||||||
|
.first;
|
||||||
|
return {ret, newmarker};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<AccountTxs, std::optional<AccountTxMarker>>
|
std::pair<AccountTxs, std::optional<AccountTxMarker>>
|
||||||
newestAccountTxPage(AccountTxPageOptions const& options) override
|
newestAccountTxPage(AccountTxPageOptions const& options) override
|
||||||
{
|
{
|
||||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
if (!useTxTables_)
|
||||||
auto it = accountTxMap_.find(options.account);
|
return {};
|
||||||
if (it == accountTxMap_.end())
|
|
||||||
return {{}, std::nullopt};
|
|
||||||
|
|
||||||
AccountTxs result;
|
static std::uint32_t const page_length(200);
|
||||||
std::optional<AccountTxMarker> marker;
|
auto onUnsavedLedger =
|
||||||
const auto& accountData = it->second;
|
std::bind(saveLedgerAsync, std::ref(app_), std::placeholders::_1);
|
||||||
auto txIt = accountData.ledgerTxMap.lower_bound(options.minLedger);
|
AccountTxs ret;
|
||||||
auto txEnd = accountData.ledgerTxMap.upper_bound(options.maxLedger);
|
Application& app = app_;
|
||||||
|
auto onTransaction = [&ret, &app](
|
||||||
|
std::uint32_t ledger_index,
|
||||||
|
std::string const& status,
|
||||||
|
Blob&& rawTxn,
|
||||||
|
Blob&& rawMeta) {
|
||||||
|
convertBlobsToTxResult(
|
||||||
|
ret, ledger_index, status, rawTxn, rawMeta, app);
|
||||||
|
};
|
||||||
|
|
||||||
bool lookingForMarker = options.marker.has_value();
|
auto newmarker =
|
||||||
std::size_t count = 0;
|
accountTxPage(
|
||||||
|
onUnsavedLedger, onTransaction, options, 0, page_length, false)
|
||||||
for (auto rIt = std::make_reverse_iterator(txEnd);
|
.first;
|
||||||
rIt != std::make_reverse_iterator(txIt) &&
|
return {ret, newmarker};
|
||||||
(options.limit == 0 || count < options.limit);
|
|
||||||
++rIt)
|
|
||||||
{
|
|
||||||
for (auto innerRIt = rIt->second.rbegin();
|
|
||||||
innerRIt != rIt->second.rend();
|
|
||||||
++innerRIt)
|
|
||||||
{
|
|
||||||
if (lookingForMarker)
|
|
||||||
{
|
|
||||||
if (rIt->first == options.marker->ledgerSeq &&
|
|
||||||
innerRIt->first == options.marker->txnSeq)
|
|
||||||
lookingForMarker = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
result.push_back(accountData.transactions[innerRIt->second]);
|
|
||||||
++count;
|
|
||||||
|
|
||||||
if (options.limit > 0 && count >= options.limit)
|
|
||||||
{
|
|
||||||
marker = AccountTxMarker{rIt->first, innerRIt->first};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {result, marker};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<MetaTxsList, std::optional<AccountTxMarker>>
|
std::pair<MetaTxsList, std::optional<AccountTxMarker>>
|
||||||
oldestAccountTxPageB(AccountTxPageOptions const& options) override
|
oldestAccountTxPageB(AccountTxPageOptions const& options) override
|
||||||
{
|
{
|
||||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
if (!useTxTables_)
|
||||||
auto it = accountTxMap_.find(options.account);
|
return {};
|
||||||
if (it == accountTxMap_.end())
|
|
||||||
return {{}, std::nullopt};
|
|
||||||
|
|
||||||
MetaTxsList result;
|
static std::uint32_t const page_length(500);
|
||||||
std::optional<AccountTxMarker> marker;
|
auto onUnsavedLedger =
|
||||||
const auto& accountData = it->second;
|
std::bind(saveLedgerAsync, std::ref(app_), std::placeholders::_1);
|
||||||
auto txIt = accountData.ledgerTxMap.lower_bound(options.minLedger);
|
MetaTxsList ret;
|
||||||
auto txEnd = accountData.ledgerTxMap.upper_bound(options.maxLedger);
|
auto onTransaction = [&ret](
|
||||||
|
std::uint32_t ledgerIndex,
|
||||||
bool lookingForMarker = options.marker.has_value();
|
std::string const& status,
|
||||||
std::size_t count = 0;
|
Blob&& rawTxn,
|
||||||
|
Blob&& rawMeta) {
|
||||||
for (; txIt != txEnd && (options.limit == 0 || count < options.limit);
|
ret.emplace_back(
|
||||||
++txIt)
|
std::move(rawTxn), std::move(rawMeta), ledgerIndex);
|
||||||
{
|
};
|
||||||
for (const auto& [txSeq, txIndex] : txIt->second)
|
auto newmarker =
|
||||||
{
|
accountTxPage(
|
||||||
if (lookingForMarker)
|
onUnsavedLedger, onTransaction, options, 0, page_length, true)
|
||||||
{
|
.first;
|
||||||
if (txIt->first == options.marker->ledgerSeq &&
|
return {ret, newmarker};
|
||||||
txSeq == options.marker->txnSeq)
|
|
||||||
lookingForMarker = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& [txn, txMeta] = accountData.transactions[txIndex];
|
|
||||||
result.emplace_back(
|
|
||||||
txn->getSTransaction()->getSerializer().peekData(),
|
|
||||||
txMeta->getAsObject().getSerializer().peekData(),
|
|
||||||
txIt->first);
|
|
||||||
++count;
|
|
||||||
|
|
||||||
if (options.limit > 0 && count >= options.limit)
|
|
||||||
{
|
|
||||||
marker = AccountTxMarker{txIt->first, txSeq};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {result, marker};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<MetaTxsList, std::optional<AccountTxMarker>>
|
std::pair<MetaTxsList, std::optional<AccountTxMarker>>
|
||||||
newestAccountTxPageB(AccountTxPageOptions const& options) override
|
newestAccountTxPageB(AccountTxPageOptions const& options) override
|
||||||
{
|
{
|
||||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
if (!useTxTables_)
|
||||||
auto it = accountTxMap_.find(options.account);
|
return {};
|
||||||
if (it == accountTxMap_.end())
|
|
||||||
return {{}, std::nullopt};
|
|
||||||
|
|
||||||
MetaTxsList result;
|
static std::uint32_t const page_length(500);
|
||||||
std::optional<AccountTxMarker> marker;
|
auto onUnsavedLedger =
|
||||||
const auto& accountData = it->second;
|
std::bind(saveLedgerAsync, std::ref(app_), std::placeholders::_1);
|
||||||
auto txIt = accountData.ledgerTxMap.lower_bound(options.minLedger);
|
MetaTxsList ret;
|
||||||
auto txEnd = accountData.ledgerTxMap.upper_bound(options.maxLedger);
|
auto onTransaction = [&ret](
|
||||||
|
std::uint32_t ledgerIndex,
|
||||||
bool lookingForMarker = options.marker.has_value();
|
std::string const& status,
|
||||||
std::size_t count = 0;
|
Blob&& rawTxn,
|
||||||
|
Blob&& rawMeta) {
|
||||||
for (auto rIt = std::make_reverse_iterator(txEnd);
|
ret.emplace_back(
|
||||||
rIt != std::make_reverse_iterator(txIt) &&
|
std::move(rawTxn), std::move(rawMeta), ledgerIndex);
|
||||||
(options.limit == 0 || count < options.limit);
|
};
|
||||||
++rIt)
|
auto newmarker =
|
||||||
{
|
accountTxPage(
|
||||||
for (auto innerRIt = rIt->second.rbegin();
|
onUnsavedLedger, onTransaction, options, 0, page_length, false)
|
||||||
innerRIt != rIt->second.rend();
|
.first;
|
||||||
++innerRIt)
|
return {ret, newmarker};
|
||||||
{
|
|
||||||
if (lookingForMarker)
|
|
||||||
{
|
|
||||||
if (rIt->first == options.marker->ledgerSeq &&
|
|
||||||
innerRIt->first == options.marker->txnSeq)
|
|
||||||
lookingForMarker = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& [txn, txMeta] =
|
|
||||||
accountData.transactions[innerRIt->second];
|
|
||||||
result.emplace_back(
|
|
||||||
txn->getSTransaction()->getSerializer().peekData(),
|
|
||||||
txMeta->getAsObject().getSerializer().peekData(),
|
|
||||||
rIt->first);
|
|
||||||
++count;
|
|
||||||
|
|
||||||
if (options.limit > 0 && count >= options.limit)
|
|
||||||
{
|
|
||||||
marker = AccountTxMarker{rIt->first, innerRIt->first};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {result, marker};
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,9 @@ class LedgerLoad_test : public beast::unit_test::suite
|
|||||||
cfg->START_UP = type;
|
cfg->START_UP = type;
|
||||||
assert(!dbPath.empty());
|
assert(!dbPath.empty());
|
||||||
cfg->legacy("database_path", dbPath);
|
cfg->legacy("database_path", dbPath);
|
||||||
|
auto& sectionNode = cfg->section(ConfigSection::nodeDatabase());
|
||||||
|
sectionNode.set("type", "memory");
|
||||||
|
cfg->overwrite(SECTION_RELATIONAL_DB, "backend", "sqlite");
|
||||||
return cfg;
|
return cfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,7 +65,13 @@ class LedgerLoad_test : public beast::unit_test::suite
|
|||||||
|
|
||||||
retval.ledgerFile = td.file("ledgerdata.json");
|
retval.ledgerFile = td.file("ledgerdata.json");
|
||||||
|
|
||||||
Env env{*this};
|
Env env{*this, envconfig([](std::unique_ptr<Config> cfg) {
|
||||||
|
auto& sectionNode =
|
||||||
|
cfg->section(ConfigSection::nodeDatabase());
|
||||||
|
sectionNode.set("type", "memory");
|
||||||
|
cfg->overwrite(SECTION_RELATIONAL_DB, "backend", "sqlite");
|
||||||
|
return cfg;
|
||||||
|
})};
|
||||||
Account prev;
|
Account prev;
|
||||||
|
|
||||||
for (auto i = 0; i < 20; ++i)
|
for (auto i = 0; i < 20; ++i)
|
||||||
|
|||||||
@@ -50,7 +50,13 @@ struct LedgerReplay_test : public beast::unit_test::suite
|
|||||||
auto const alice = Account("alice");
|
auto const alice = Account("alice");
|
||||||
auto const bob = Account("bob");
|
auto const bob = Account("bob");
|
||||||
|
|
||||||
Env env(*this);
|
Env env = [&] {
|
||||||
|
auto c = jtx::envconfig();
|
||||||
|
auto& sectionNode = c->section(ConfigSection::nodeDatabase());
|
||||||
|
sectionNode.set("type", "memory");
|
||||||
|
c->overwrite(SECTION_RELATIONAL_DB, "backend", "sqlite");
|
||||||
|
return jtx::Env(*this, std::move(c));
|
||||||
|
}();
|
||||||
env.fund(XRP(100000), alice, bob);
|
env.fund(XRP(100000), alice, bob);
|
||||||
env.close();
|
env.close();
|
||||||
|
|
||||||
|
|||||||
@@ -49,8 +49,9 @@ setupConfigForUnitTests(Config& cfg)
|
|||||||
cfg.FEES.account_reserve = XRP(200).value().xrp().drops();
|
cfg.FEES.account_reserve = XRP(200).value().xrp().drops();
|
||||||
cfg.FEES.owner_reserve = XRP(50).value().xrp().drops();
|
cfg.FEES.owner_reserve = XRP(50).value().xrp().drops();
|
||||||
|
|
||||||
cfg.overwrite(ConfigSection::nodeDatabase(), "type", "memory");
|
cfg.overwrite(ConfigSection::nodeDatabase(), "type", "rwdb");
|
||||||
cfg.overwrite(ConfigSection::nodeDatabase(), "path", "main");
|
cfg.overwrite(ConfigSection::nodeDatabase(), "path", "main");
|
||||||
|
cfg.overwrite(SECTION_RELATIONAL_DB, "backend", "rwdb");
|
||||||
cfg.deprecatedClearSection(ConfigSection::importNodeDatabase());
|
cfg.deprecatedClearSection(ConfigSection::importNodeDatabase());
|
||||||
cfg.legacy("database_path", "");
|
cfg.legacy("database_path", "");
|
||||||
cfg.setupControl(true, true, true);
|
cfg.setupControl(true, true, true);
|
||||||
|
|||||||
@@ -564,7 +564,7 @@ public:
|
|||||||
BEAST_EXPECT(areBatchesEqual(batch, copy));
|
BEAST_EXPECT(areBatchesEqual(batch, copy));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == "memory")
|
if (type == "memory" || type == "rwdb")
|
||||||
{
|
{
|
||||||
// Verify default earliest ledger sequence
|
// Verify default earliest ledger sequence
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -47,9 +47,6 @@ class GetCounts_test : public beast::unit_test::suite
|
|||||||
BEAST_EXPECT(
|
BEAST_EXPECT(
|
||||||
result.isMember(jss::uptime) &&
|
result.isMember(jss::uptime) &&
|
||||||
!result[jss::uptime].asString().empty());
|
!result[jss::uptime].asString().empty());
|
||||||
BEAST_EXPECT(
|
|
||||||
result.isMember(jss::dbKBTotal) &&
|
|
||||||
result[jss::dbKBTotal].asInt() > 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// create some transactions
|
// create some transactions
|
||||||
|
|||||||
@@ -63,9 +63,11 @@ public:
|
|||||||
jtx::Env env = [&] {
|
jtx::Env env = [&] {
|
||||||
auto c = jtx::envconfig();
|
auto c = jtx::envconfig();
|
||||||
auto& sectionNode = c->section(ConfigSection::nodeDatabase());
|
auto& sectionNode = c->section(ConfigSection::nodeDatabase());
|
||||||
|
sectionNode.set("type", "memory");
|
||||||
sectionNode.set("earliest_seq", "257");
|
sectionNode.set("earliest_seq", "257");
|
||||||
sectionNode.set("ledgers_per_shard", "256");
|
sectionNode.set("ledgers_per_shard", "256");
|
||||||
c->setupControl(true, true, true);
|
c->setupControl(true, true, true);
|
||||||
|
c->overwrite(SECTION_RELATIONAL_DB, "backend", "sqlite");
|
||||||
|
|
||||||
return jtx::Env(*this, std::move(c));
|
return jtx::Env(*this, std::move(c));
|
||||||
}();
|
}();
|
||||||
@@ -138,9 +140,11 @@ public:
|
|||||||
section.set("ledgers_per_shard", "256");
|
section.set("ledgers_per_shard", "256");
|
||||||
section.set("earliest_seq", "257");
|
section.set("earliest_seq", "257");
|
||||||
auto& sectionNode = c->section(ConfigSection::nodeDatabase());
|
auto& sectionNode = c->section(ConfigSection::nodeDatabase());
|
||||||
|
sectionNode.set("type", "memory");
|
||||||
sectionNode.set("earliest_seq", "257");
|
sectionNode.set("earliest_seq", "257");
|
||||||
sectionNode.set("ledgers_per_shard", "256");
|
sectionNode.set("ledgers_per_shard", "256");
|
||||||
c->setupControl(true, true, true);
|
c->setupControl(true, true, true);
|
||||||
|
c->overwrite(SECTION_RELATIONAL_DB, "backend", "sqlite");
|
||||||
|
|
||||||
return jtx::Env(*this, std::move(c));
|
return jtx::Env(*this, std::move(c));
|
||||||
}();
|
}();
|
||||||
@@ -282,9 +286,11 @@ public:
|
|||||||
section.set("ledgers_per_shard", "256");
|
section.set("ledgers_per_shard", "256");
|
||||||
section.set("earliest_seq", "257");
|
section.set("earliest_seq", "257");
|
||||||
auto& sectionNode = c->section(ConfigSection::nodeDatabase());
|
auto& sectionNode = c->section(ConfigSection::nodeDatabase());
|
||||||
|
sectionNode.set("type", "memory");
|
||||||
sectionNode.set("earliest_seq", "257");
|
sectionNode.set("earliest_seq", "257");
|
||||||
sectionNode.set("ledgers_per_shard", "256");
|
sectionNode.set("ledgers_per_shard", "256");
|
||||||
c->setupControl(true, true, true);
|
c->setupControl(true, true, true);
|
||||||
|
c->overwrite(SECTION_RELATIONAL_DB, "backend", "sqlite");
|
||||||
|
|
||||||
return jtx::Env(
|
return jtx::Env(
|
||||||
*this, std::move(c), nullptr, beast::severities::kDisabled);
|
*this, std::move(c), nullptr, beast::severities::kDisabled);
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ public:
|
|||||||
, j_(j)
|
, j_(j)
|
||||||
{
|
{
|
||||||
Section testSection;
|
Section testSection;
|
||||||
testSection.set("type", "memory");
|
testSection.set("type", "rwdb");
|
||||||
testSection.set("path", "SHAMap_test");
|
testSection.set("path", "SHAMap_test");
|
||||||
db_ = NodeStore::Manager::instance().make_Database(
|
db_ = NodeStore::Manager::instance().make_Database(
|
||||||
megabytes(4), scheduler_, 1, testSection, j);
|
megabytes(4), scheduler_, 1, testSection, j);
|
||||||
|
|||||||
Reference in New Issue
Block a user