From 1d9adbe639342c4e914b5ceb3054f5473d3f51ca Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Fri, 17 Jan 2020 16:01:22 +0100 Subject: [PATCH] Replace generic CScopedDBTransaction with specialized CEvoDBScopedCommitter (#3292) This has the wanted side effect of proper locking of "cs" inside CommitCurTransaction and RollbackCurTransaction, which was not easily possible to implement in the generic version. This fixes some rare crashes. --- src/dbwrapper.h | 45 --------------------------------------------- src/evo/evodb.cpp | 37 +++++++++++++++++++++++++++++++++++++ src/evo/evodb.h | 28 ++++++++++++++++++++++++---- 3 files changed, 61 insertions(+), 49 deletions(-) diff --git a/src/dbwrapper.h b/src/dbwrapper.h index 66efca4e4a..a722d92fc4 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -724,49 +724,4 @@ public: } }; -template -class CScopedDBTransaction { -public: - typedef CDBTransaction Transaction; - -private: - Transaction &dbTransaction; - std::function commitHandler; - std::function rollbackHandler; - bool didCommitOrRollback{}; - -public: - CScopedDBTransaction(Transaction &dbTx) : dbTransaction(dbTx) {} - ~CScopedDBTransaction() { - if (!didCommitOrRollback) - Rollback(); - } - void Commit() { - assert(!didCommitOrRollback); - didCommitOrRollback = true; - dbTransaction.Commit(); - if (commitHandler) - commitHandler(); - } - void Rollback() { - assert(!didCommitOrRollback); - didCommitOrRollback = true; - dbTransaction.Clear(); - if (rollbackHandler) - rollbackHandler(); - } - - static std::unique_ptr> Begin(Transaction &dbTx) { - assert(dbTx.IsClean()); - return std::make_unique>(dbTx); - } - - void SetCommitHandler(const std::function &h) { - commitHandler = h; - } - void SetRollbackHandler(const std::function &h) { - rollbackHandler = h; - } -}; - #endif // BITCOIN_DBWRAPPER_H diff --git a/src/evo/evodb.cpp b/src/evo/evodb.cpp index b46d6efcb1..b1bf157c2a 100644 --- a/src/evo/evodb.cpp +++ b/src/evo/evodb.cpp @@ -6,6 +6,31 @@ CEvoDB* evoDb; +CEvoDBScopedCommitter::CEvoDBScopedCommitter(CEvoDB &_evoDB) : + evoDB(_evoDB) +{ +} + +CEvoDBScopedCommitter::~CEvoDBScopedCommitter() +{ + if (!didCommitOrRollback) + Rollback(); +} + +void CEvoDBScopedCommitter::Commit() +{ + assert(!didCommitOrRollback); + didCommitOrRollback = true; + evoDB.CommitCurTransaction(); +} + +void CEvoDBScopedCommitter::Rollback() +{ + assert(!didCommitOrRollback); + didCommitOrRollback = true; + evoDB.RollbackCurTransaction(); +} + CEvoDB::CEvoDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(fMemory ? "" : (GetDataDir() / "evodb"), nCacheSize, fMemory, fWipe), rootBatch(db), @@ -14,6 +39,18 @@ CEvoDB::CEvoDB(size_t nCacheSize, bool fMemory, bool fWipe) : { } +void CEvoDB::CommitCurTransaction() +{ + LOCK(cs); + curDBTransaction.Commit(); +} + +void CEvoDB::RollbackCurTransaction() +{ + LOCK(cs); + curDBTransaction.Clear(); +} + bool CEvoDB::CommitRootTransaction() { assert(curDBTransaction.IsClean()); diff --git a/src/evo/evodb.h b/src/evo/evodb.h index 53e59712a7..ed6dc93aee 100644 --- a/src/evo/evodb.h +++ b/src/evo/evodb.h @@ -13,6 +13,22 @@ // "b_b2" was used after compact diffs were introduced static const std::string EVODB_BEST_BLOCK = "b_b2"; +class CEvoDB; + +class CEvoDBScopedCommitter +{ +private: + CEvoDB& evoDB; + bool didCommitOrRollback{false}; + +public: + explicit CEvoDBScopedCommitter(CEvoDB& _evoDB); + ~CEvoDBScopedCommitter(); + + void Commit(); + void Rollback(); +}; + class CEvoDB { private: @@ -21,7 +37,6 @@ private: typedef CDBTransaction RootTransaction; typedef CDBTransaction CurTransaction; - typedef CScopedDBTransaction ScopedTransaction; CDBBatch rootBatch; RootTransaction rootDBTransaction; @@ -30,11 +45,10 @@ private: public: CEvoDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false); - std::unique_ptr BeginTransaction() + std::unique_ptr BeginTransaction() { LOCK(cs); - auto t = ScopedTransaction::Begin(curDBTransaction); - return t; + return std::make_unique(*this); } CurTransaction& GetCurTransaction() @@ -84,6 +98,12 @@ public: bool VerifyBestBlock(const uint256& hash); void WriteBestBlock(const uint256& hash); + +private: + // only CEvoDBScopedCommitter is allowed to invoke these + friend class CEvoDBScopedCommitter; + void CommitCurTransaction(); + void RollbackCurTransaction(); }; extern CEvoDB* evoDb;