write transaction hashes to separate table

This commit is contained in:
CJ Cobb
2021-06-29 17:33:42 +00:00
parent 416a3cc523
commit 9f8724b7ab
4 changed files with 94 additions and 36 deletions

View File

@@ -51,6 +51,13 @@ processAsyncWriteResponse(T& requestParams, CassFuture* fut, F func)
delete &requestParams; delete &requestParams;
} }
} }
template <class T>
void
processAsyncWrite(CassFuture* fut, void* cbData)
{
T& requestParams = *static_cast<T*>(cbData);
processAsyncWriteResponse(requestParams, fut, requestParams.retry);
}
// Process the result of an asynchronous write. Retry on error // Process the result of an asynchronous write. Retry on error
// @param fut cassandra future associated with the write // @param fut cassandra future associated with the write
// @param cbData struct that holds the request parameters // @param cbData struct that holds the request parameters
@@ -217,6 +224,54 @@ flatMapReadObjectCallback(CassFuture* fut, void* cbData)
} }
} }
template <class T, class F>
struct CallbackData
{
CassandraBackend const* backend;
T data;
F retry;
uint32_t currentRetries;
std::atomic<int> refs = 1;
CallbackData(CassandraBackend const* b, T&& d, F f)
: backend(b), data(std::move(d)), retry(f)
{
}
};
void
CassandraBackend::writeTransaction(
std::string&& hash,
uint32_t seq,
std::string&& transaction,
std::string&& metadata) const
{
BOOST_LOG_TRIVIAL(trace) << "Writing txn to cassandra";
std::string hashCpy = hash;
auto func = [this](auto& params, bool retry) {
CassandraStatement statement{insertLedgerTransaction_};
statement.bindInt(params.data.first);
statement.bindBytes(params.data.second);
executeAsyncWrite(
statement,
processAsyncWrite<
typename std::remove_reference<decltype(params)>::type>,
params,
retry);
};
auto* lgrSeqToHash =
new CallbackData(this, std::make_pair(seq, std::move(hashCpy)), func);
WriteTransactionCallbackData* data = new WriteTransactionCallbackData(
this,
std::move(hash),
seq,
std::move(transaction),
std::move(metadata));
writeTransaction(*data, false);
func(*lgrSeqToHash, false);
}
std::optional<LedgerRange> std::optional<LedgerRange>
CassandraBackend::fetchLedgerRange() const CassandraBackend::fetchLedgerRange() const
{ {
@@ -243,21 +298,8 @@ CassandraBackend::fetchLedgerRange() const
std::vector<TransactionAndMetadata> std::vector<TransactionAndMetadata>
CassandraBackend::fetchAllTransactionsInLedger(uint32_t ledgerSequence) const CassandraBackend::fetchAllTransactionsInLedger(uint32_t ledgerSequence) const
{ {
CassandraStatement statement{selectAllTransactionsInLedger_}; auto hashes = fetchAllTransactionHashesInLedger(ledgerSequence);
statement.bindInt(ledgerSequence); return fetchTransactions(hashes);
CassandraResult result = executeSyncRead(statement);
if (!result)
{
BOOST_LOG_TRIVIAL(error) << __func__ << " - no rows";
return {};
}
std::vector<TransactionAndMetadata> txns;
do
{
txns.push_back(
{result.getBytes(), result.getBytes(), result.getUInt32()});
} while (result.nextRow());
return txns;
} }
std::vector<ripple::uint256> std::vector<ripple::uint256>
CassandraBackend::fetchAllTransactionHashesInLedger( CassandraBackend::fetchAllTransactionHashesInLedger(
@@ -1373,6 +1415,14 @@ CassandraBackend::open(bool readOnly)
<< " WITH default_time_to_live = " << std::to_string(ttl); << " WITH default_time_to_live = " << std::to_string(ttl);
if (!executeSimpleStatement(query.str())) if (!executeSimpleStatement(query.str()))
continue; continue;
query.str("");
query << "CREATE TABLE IF NOT EXISTS " << tablePrefix
<< "ledger_transactions"
<< " ( ledger_sequence bigint, hash blob, PRIMARY "
"KEY(ledger_sequence, hash))"
<< " WITH default_time_to_live = " << std::to_string(ttl);
if (!executeSimpleStatement(query.str()))
continue;
query.str(""); query.str("");
query << "SELECT * FROM " << tablePrefix << "transactions" query << "SELECT * FROM " << tablePrefix << "transactions"
@@ -1483,6 +1533,12 @@ CassandraBackend::open(bool readOnly)
"?, ?)"; "?, ?)";
if (!insertTransaction_.prepareStatement(query, session_.get())) if (!insertTransaction_.prepareStatement(query, session_.get()))
continue; continue;
query.str("");
query << "INSERT INTO " << tablePrefix << "ledger_transactions"
<< " (ledger_sequence, hash) VALUES "
"(?, ?)";
if (!insertLedgerTransaction_.prepareStatement(query, session_.get()))
continue;
query.str(""); query.str("");
query << "INSERT INTO " << tablePrefix << "keys" query << "INSERT INTO " << tablePrefix << "keys"
@@ -1519,7 +1575,7 @@ CassandraBackend::open(bool readOnly)
query, session_.get())) query, session_.get()))
continue; continue;
query.str(""); query.str("");
query << "SELECT hash FROM " << tablePrefix << "transactions" query << "SELECT hash FROM " << tablePrefix << "ledger_transactions"
<< " WHERE ledger_sequence = ?"; << " WHERE ledger_sequence = ?";
if (!selectAllTransactionHashesInLedger_.prepareStatement( if (!selectAllTransactionHashesInLedger_.prepareStatement(
query, session_.get())) query, session_.get()))

View File

@@ -26,13 +26,13 @@
#include <boost/json.hpp> #include <boost/json.hpp>
#include <boost/log/trivial.hpp> #include <boost/log/trivial.hpp>
#include <atomic> #include <atomic>
#include <backend/BackendInterface.h>
#include <backend/DBHelpers.h>
#include <cassandra.h> #include <cassandra.h>
#include <cstddef> #include <cstddef>
#include <iostream> #include <iostream>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <backend/BackendInterface.h>
#include <backend/DBHelpers.h>
namespace Backend { namespace Backend {
@@ -633,6 +633,7 @@ private:
// than making a new statement // than making a new statement
CassandraPreparedStatement insertObject_; CassandraPreparedStatement insertObject_;
CassandraPreparedStatement insertTransaction_; CassandraPreparedStatement insertTransaction_;
CassandraPreparedStatement insertLedgerTransaction_;
CassandraPreparedStatement selectTransaction_; CassandraPreparedStatement selectTransaction_;
CassandraPreparedStatement selectAllTransactionsInLedger_; CassandraPreparedStatement selectAllTransactionsInLedger_;
CassandraPreparedStatement selectAllTransactionHashesInLedger_; CassandraPreparedStatement selectAllTransactionHashesInLedger_;
@@ -1319,18 +1320,7 @@ public:
std::string&& hash, std::string&& hash,
uint32_t seq, uint32_t seq,
std::string&& transaction, std::string&& transaction,
std::string&& metadata) const override std::string&& metadata) const override;
{
BOOST_LOG_TRIVIAL(trace) << "Writing txn to cassandra";
WriteTransactionCallbackData* data = new WriteTransactionCallbackData(
this,
std::move(hash),
seq,
std::move(transaction),
std::move(metadata));
writeTransaction(*data, false);
}
void void
startWrites() const override startWrites() const override

View File

@@ -529,7 +529,7 @@ ReportingETL::runETLPipeline(uint32_t startSequence, int numExtractors)
uint32_t currentSequence = startSequence; uint32_t currentSequence = startSequence;
int counter = 0; int counter = 0;
std::atomic_int per = 4; std::atomic_int per = 100;
auto startTimer = [this, &per]() { auto startTimer = [this, &per]() {
auto innerFunc = [this, &per](auto& f) -> void { auto innerFunc = [this, &per](auto& f) -> void {
std::shared_ptr<boost::asio::steady_timer> timer = std::shared_ptr<boost::asio::steady_timer> timer =
@@ -549,7 +549,8 @@ ReportingETL::runETLPipeline(uint32_t startSequence, int numExtractors)
}; };
innerFunc(innerFunc); innerFunc(innerFunc);
}; };
startTimer(); // startTimer();
auto begin = std::chrono::system_clock::now(); auto begin = std::chrono::system_clock::now();
while (!writeConflict) while (!writeConflict)
@@ -608,6 +609,7 @@ ReportingETL::runETLPipeline(uint32_t startSequence, int numExtractors)
deleting_ = false; deleting_ = false;
}); });
} }
/*
if (++counter >= per) if (++counter >= per)
{ {
std::chrono::milliseconds sleep = std::chrono::milliseconds sleep =
@@ -619,6 +621,7 @@ ReportingETL::runETLPipeline(uint32_t startSequence, int numExtractors)
counter = 0; counter = 0;
begin = std::chrono::system_clock::now(); begin = std::chrono::system_clock::now();
} }
*/
} }
}}; }};

17
test.py
View File

@@ -699,11 +699,14 @@ async def ledgers(ip, port, minLedger, maxLedger, transactions, expand, maxCalls
start = datetime.datetime.now().timestamp() start = datetime.datetime.now().timestamp()
await ws.send(json.dumps({"command":"ledger","ledger_index":int(ledger),"binary":True, "transactions":bool(transactions),"expand":bool(expand)})) await ws.send(json.dumps({"command":"ledger","ledger_index":int(ledger),"binary":True, "transactions":bool(transactions),"expand":bool(expand)}))
res = json.loads(await ws.recv()) res = json.loads(await ws.recv())
print(res["header"]["blob"])
end = datetime.datetime.now().timestamp() end = datetime.datetime.now().timestamp()
if (end - start) > 0.1: if (end - start) > 0.1:
print("request took more than 100ms") print("request took more than 100ms : " + str(end - start))
numCalls = numCalls + 1 numCalls = numCalls + 1
if "error" in res:
print(res["error"])
else:
print(res["header"]["blob"])
except websockets.exceptions.ConnectionClosedError as e: except websockets.exceptions.ConnectionClosedError as e:
print(e) print(e)
@@ -842,8 +845,13 @@ args = parser.parse_args()
def run(args): def run(args):
asyncio.set_event_loop(asyncio.new_event_loop()) asyncio.set_event_loop(asyncio.new_event_loop())
if(args.ledger is None): rng =asyncio.get_event_loop().run_until_complete(ledger_range(args.ip, args.port))
args.ledger = asyncio.get_event_loop().run_until_complete(ledger_range(args.ip, args.port))[1] if args.ledger is None:
args.ledger = rng[1]
if args.maxLedger == -1:
args.maxLedger = rng[1]
if args.minLedger == -1:
args.minLedger = rng[0]
if args.action == "fee": if args.action == "fee":
asyncio.get_event_loop().run_until_complete(fee(args.ip, args.port)) asyncio.get_event_loop().run_until_complete(fee(args.ip, args.port))
elif args.action == "server_info": elif args.action == "server_info":
@@ -891,6 +899,7 @@ def run(args):
end = datetime.datetime.now().timestamp() end = datetime.datetime.now().timestamp()
num = int(args.numRunners) * int(args.numCalls) num = int(args.numRunners) * int(args.numCalls)
print("Completed " + str(num) + " in " + str(end - start) + " seconds. Throughput = " + str(num / (end - start)) + " calls per second") print("Completed " + str(num) + " in " + str(end - start) + " seconds. Throughput = " + str(num / (end - start)) + " calls per second")
print("Latency = " + str((end - start) / int(args.numCalls)) + " seconds")
elif args.action == "ledger_entries": elif args.action == "ledger_entries":
keys = [] keys = []
ledger_index = 0 ledger_index = 0