Fix issue with retry policy that lead to crashes (#620)

Fixes #621
This commit is contained in:
Alex Kremer
2023-05-03 11:04:30 +01:00
committed by GitHub
parent 36ac3215e2
commit 860d10cddc
9 changed files with 89 additions and 30 deletions

View File

@@ -44,12 +44,12 @@ TEST_F(BackendCassandraAsyncExecutorTest, CompletionCalledOnSuccess)
return FakeFutureWithCallback{};
});
EXPECT_CALL(handle, asyncExecute(An<FakeStatement const&>(), An<std::function<void(FakeResultOrError)>&&>()))
.Times(1);
.Times(AtLeast(1));
auto called = std::atomic_bool{false};
auto work = std::optional<boost::asio::io_context::work>{ctx};
AsyncExecutor<FakeStatement, MockHandle>::run(ctx, handle, statement, [&called, &work](auto&&) {
AsyncExecutor<FakeStatement, MockHandle>::run(ctx, handle, std::move(statement), [&called, &work](auto&&) {
called = true;
work.reset();
});
@@ -81,7 +81,7 @@ TEST_F(BackendCassandraAsyncExecutorTest, ExecutedMultipleTimesByRetryPolicyOnMa
auto called = std::atomic_bool{false};
auto work = std::optional<boost::asio::io_context::work>{ctx};
AsyncExecutor<FakeStatement, MockHandle>::run(ctx, handle, statement, [&called, &work](auto&&) {
AsyncExecutor<FakeStatement, MockHandle>::run(ctx, handle, std::move(statement), [&called, &work](auto&&) {
called = true;
work.reset();
});
@@ -118,11 +118,12 @@ TEST_F(BackendCassandraAsyncExecutorTest, ExecutedMultipleTimesByRetryPolicyOnOt
auto called = std::atomic_bool{false};
auto work2 = std::optional<boost::asio::io_context::work>{ctx};
AsyncExecutor<FakeStatement, MockHandle>::run(threadedCtx, handle, statement, [&called, &work, &work2](auto&&) {
called = true;
work.reset();
work2.reset();
});
AsyncExecutor<FakeStatement, MockHandle>::run(
threadedCtx, handle, std::move(statement), [&called, &work, &work2](auto&&) {
called = true;
work.reset();
work2.reset();
});
ctx.run();
ASSERT_TRUE(callCount >= 3);
@@ -150,7 +151,7 @@ TEST_F(BackendCassandraAsyncExecutorTest, CompletionCalledOnFailureAfterRetryCou
auto work = std::optional<boost::asio::io_context::work>{ctx};
AsyncExecutor<FakeStatement, MockHandle, FakeRetryPolicy>::run(
ctx, handle, statement, [&called, &work](auto&& res) {
ctx, handle, std::move(statement), [&called, &work](auto&& res) {
EXPECT_FALSE(res);
EXPECT_EQ(res.error().code(), CASS_ERROR_LIB_INTERNAL_ERROR);
EXPECT_EQ(res.error().message(), "not a timeout");

View File

@@ -465,7 +465,7 @@ TEST_F(BackendCassandraTest, Basic)
}
// obtain a time-based seed:
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
auto const seed = std::chrono::system_clock::now().time_since_epoch().count();
std::string accountBlobOld = accountBlob;
{
lgrInfoNext.seq = lgrInfoNext.seq + 1;
@@ -546,7 +546,7 @@ TEST_F(BackendCassandraTest, Basic)
auto generateObjects = [](size_t numObjects, uint32_t ledgerSequence) {
std::vector<std::pair<std::string, std::string>> res{numObjects};
ripple::uint256 key;
key = ledgerSequence * 100000;
key = ledgerSequence * 100000ul;
for (auto& blob : res)
{
@@ -567,7 +567,7 @@ TEST_F(BackendCassandraTest, Basic)
auto generateTxns = [](size_t numTxns, uint32_t ledgerSequence) {
std::vector<std::tuple<std::string, std::string, std::string>> res{numTxns};
ripple::uint256 base;
base = ledgerSequence * 100000;
base = ledgerSequence * 100000ul;
for (auto& blob : res)
{
++base;
@@ -581,7 +581,7 @@ TEST_F(BackendCassandraTest, Basic)
auto generateAccounts = [](uint32_t ledgerSequence, uint32_t numAccounts) {
std::vector<ripple::AccountID> accounts;
ripple::AccountID base;
base = ledgerSequence * 998765;
base = ledgerSequence * 998765ul;
for (size_t i = 0; i < numAccounts; ++i)
{
++base;
@@ -1130,7 +1130,7 @@ TEST_F(BackendCassandraTest, CacheIntegration)
EXPECT_FALSE(obj);
}
auto generateObjects = [](size_t numObjects, uint32_t ledgerSequence) {
auto generateObjects = [](size_t numObjects, uint64_t ledgerSequence) {
std::vector<std::pair<std::string, std::string>> res{numObjects};
ripple::uint256 key;
key = ledgerSequence * 100000;

View File

@@ -343,6 +343,58 @@ TEST_F(BackendCassandraBaseTest, BatchInsert)
dropKeyspace(handle, "test");
}
TEST_F(BackendCassandraBaseTest, BatchInsertAsync)
{
using std::to_string;
auto const entries = std::vector<std::string>{
"first",
"second",
"third",
"fourth",
"fifth",
};
auto handle = createHandle("127.0.0.1", "test");
std::string q1 =
"CREATE TABLE IF NOT EXISTS strings "
"(hash blob PRIMARY KEY, sequence bigint) "
"WITH default_time_to_live = " +
to_string(5000);
auto f1 = handle.asyncExecute(q1);
if (auto const rc = f1.await(); not rc)
std::cout << "oops: " << rc.error() << '\n';
std::string q2 = "INSERT INTO strings (hash, sequence) VALUES (?, ?)";
auto insert = handle.prepare(q2);
// write data in bulk
{
bool complete = false;
std::optional<Backend::Cassandra::FutureWithCallback> fut;
{
std::vector<Statement> statements;
int64_t idx = 1000;
for (auto const& entry : entries)
statements.push_back(insert.bind(entry, static_cast<int64_t>(idx++)));
ASSERT_EQ(statements.size(), entries.size());
fut.emplace(handle.asyncExecute(statements, [&](auto const res) {
complete = true;
EXPECT_TRUE(res);
}));
// statements are destructed here, async execute needs to survive
}
auto const res = fut.value().await(); // future should still signal it finished
EXPECT_TRUE(res);
ASSERT_TRUE(complete);
}
dropKeyspace(handle, "test");
}
TEST_F(BackendCassandraBaseTest, AlterTableAddColumn)
{
auto handle = createHandle("127.0.0.1", "test");

View File

@@ -376,12 +376,12 @@ TEST_F(BackendCassandraExecutionStrategyTest, WriteMultipleAndCallSyncSucceeds)
An<std::function<void(FakeResultOrError)>&&>()))
.Times(totalRequests); // one per write call
auto statements = std::vector<FakeStatement>(16);
auto makeStatements = [] { return std::vector<FakeStatement>(16); };
for (auto i = 0u; i < totalRequests; ++i)
strat.write(statements);
strat.write(makeStatements());
strat.sync(); // make sure all above writes are finished
ASSERT_EQ(callCount, totalRequests); // all requests should finish
EXPECT_EQ(callCount, totalRequests); // all requests should finish
work.reset();
thread.join();