@@ -279,8 +279,48 @@ BOOST_AUTO_TEST_CASE(txn_close_failure_dangling_txn)
279279 BOOST_CHECK (!batch2->Exists (key));
280280}
281281
282- #endif // USE_SQLITE
282+ BOOST_AUTO_TEST_CASE (concurrent_txn_dont_interfere)
283+ {
284+ std::string key = " key" ;
285+ std::string value = " value" ;
286+ std::string value2 = " value_2" ;
283287
288+ DatabaseOptions options;
289+ DatabaseStatus status;
290+ bilingual_str error;
291+ const auto & database = MakeSQLiteDatabase (m_path_root / " sqlite" , options, status, error);
292+
293+ std::unique_ptr<DatabaseBatch> handler = Assert (database)->MakeBatch ();
294+
295+ // Verify concurrent db transactions does not interfere between each other.
296+ // Start db txn, write key and check the key does exist within the db txn.
297+ BOOST_CHECK (handler->TxnBegin ());
298+ BOOST_CHECK (handler->Write (key, value));
299+ BOOST_CHECK (handler->Exists (key));
300+
301+ // But, the same key, does not exist in another handler
302+ std::unique_ptr<DatabaseBatch> handler2 = Assert (database)->MakeBatch ();
303+ BOOST_CHECK (handler2->Exists (key));
304+
305+ // Attempt to commit the handler txn calling the handler2 methods.
306+ // Which, must not be possible.
307+ BOOST_CHECK (!handler2->TxnCommit ());
308+ BOOST_CHECK (!handler2->TxnAbort ());
309+
310+ // Only the first handler can commit the changes.
311+ BOOST_CHECK (handler->TxnCommit ());
312+ // And, once commit is completed, handler2 can read the record
313+ std::string read_value;
314+ BOOST_CHECK (handler2->Read (key, read_value));
315+ BOOST_CHECK_EQUAL (read_value, value);
316+
317+ // Also, once txn is committed, single write statements are re-enabled.
318+ // Which means that handler2 can read the record changes directly.
319+ BOOST_CHECK (handler->Write (key, value2, /* fOverwrite=*/ true ));
320+ BOOST_CHECK (handler2->Read (key, read_value));
321+ BOOST_CHECK_EQUAL (read_value, value2);
322+ }
323+ #endif // USE_SQLITE
284324
285325BOOST_AUTO_TEST_SUITE_END ()
286326} // namespace wallet
0 commit comments