From f620ec719c1cfd2cc50a64a984cac5eacb7b651d Mon Sep 17 00:00:00 2001 From: pasta Date: Tue, 11 Nov 2025 12:36:44 -0600 Subject: [PATCH] refactor: replace exclusive locks with shared locks in CInstantSendDb Updated CInstantSendDb to use shared locks instead of exclusive locks for read operations, improving concurrency. This change affects methods such as KnownInstantSendLock, GetInstantSendLockCount, and others, ensuring that multiple threads can read from the database simultaneously without blocking each other. The cs_db mutex has also been changed to a SharedMutex to support this new locking strategy. --- src/instantsend/db.cpp | 14 +++++++------- src/instantsend/db.h | 24 ++++++++++++------------ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/instantsend/db.cpp b/src/instantsend/db.cpp index 778596851385..a6c20febb9a9 100644 --- a/src/instantsend/db.cpp +++ b/src/instantsend/db.cpp @@ -236,14 +236,14 @@ void CInstantSendDb::RemoveBlockInstantSendLocks(const gsl::not_nullExists(std::make_tuple(DB_ARCHIVED_BY_HASH, islockHash)); } size_t CInstantSendDb::GetInstantSendLockCount() const { - LOCK(cs_db); + READ_LOCK(cs_db); auto it = std::unique_ptr(db->NewIterator()); auto firstKey = std::make_tuple(std::string{DB_ISLOCK_BY_HASH}, uint256()); @@ -266,7 +266,7 @@ size_t CInstantSendDb::GetInstantSendLockCount() const InstantSendLockPtr CInstantSendDb::GetInstantSendLockByHashInternal(const uint256& hash, bool use_cache) const { - AssertLockHeld(cs_db); + AssertSharedLockHeld(cs_db); if (hash.IsNull()) { return nullptr; } @@ -291,7 +291,7 @@ InstantSendLockPtr CInstantSendDb::GetInstantSendLockByHashInternal(const uint25 uint256 CInstantSendDb::GetInstantSendLockHashByTxidInternal(const uint256& txid) const { - AssertLockHeld(cs_db); + AssertSharedLockHeld(cs_db); uint256 islockHash; if (!txidCache.get(txid, islockHash)) { if (!db->Read(std::make_tuple(DB_HASH_BY_TXID, txid), islockHash)) { @@ -304,13 +304,13 @@ uint256 CInstantSendDb::GetInstantSendLockHashByTxidInternal(const uint256& txid InstantSendLockPtr CInstantSendDb::GetInstantSendLockByTxid(const uint256& txid) const { - LOCK(cs_db); + READ_LOCK(cs_db); return GetInstantSendLockByHashInternal(GetInstantSendLockHashByTxidInternal(txid)); } InstantSendLockPtr CInstantSendDb::GetInstantSendLockByInput(const COutPoint& outpoint) const { - LOCK(cs_db); + READ_LOCK(cs_db); uint256 islockHash; if (!outpointCache.get(outpoint, islockHash)) { if (!db->Read(std::make_tuple(DB_HASH_BY_OUTPOINT, outpoint), islockHash)) { @@ -323,7 +323,7 @@ InstantSendLockPtr CInstantSendDb::GetInstantSendLockByInput(const COutPoint& ou std::vector CInstantSendDb::GetInstantSendLocksByParent(const uint256& parent) const { - AssertLockHeld(cs_db); + AssertSharedLockHeld(cs_db); auto it = std::unique_ptr(db->NewIterator()); auto firstKey = std::make_tuple(std::string{DB_HASH_BY_OUTPOINT}, COutPoint(parent, 0)); it->Seek(firstKey); diff --git a/src/instantsend/db.h b/src/instantsend/db.h index e8b5deb405c6..e7c3048f6d95 100644 --- a/src/instantsend/db.h +++ b/src/instantsend/db.h @@ -32,7 +32,7 @@ namespace instantsend { class CInstantSendDb { private: - mutable Mutex cs_db; + mutable SharedMutex cs_db; static constexpr int CURRENT_VERSION{1}; @@ -68,17 +68,17 @@ class CInstantSendDb * @param parent The hash of the parent IS Lock * @return Returns a vector of IS Lock hashes */ - std::vector GetInstantSendLocksByParent(const uint256& parent) const EXCLUSIVE_LOCKS_REQUIRED(cs_db); + std::vector GetInstantSendLocksByParent(const uint256& parent) const SHARED_LOCKS_REQUIRED(cs_db); /** * See GetInstantSendLockByHash */ - InstantSendLockPtr GetInstantSendLockByHashInternal(const uint256& hash, bool use_cache = true) const EXCLUSIVE_LOCKS_REQUIRED(cs_db); + InstantSendLockPtr GetInstantSendLockByHashInternal(const uint256& hash, bool use_cache = true) const SHARED_LOCKS_REQUIRED(cs_db); /** * See GetInstantSendLockHashByTxid */ - uint256 GetInstantSendLockHashByTxidInternal(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(cs_db); + uint256 GetInstantSendLockHashByTxidInternal(const uint256& txid) const SHARED_LOCKS_REQUIRED(cs_db); void Upgrade(const util::DbWrapperParams& db_params) EXCLUSIVE_LOCKS_REQUIRED(!cs_db); @@ -112,21 +112,21 @@ class CInstantSendDb void RemoveArchivedInstantSendLocks(int nUntilHeight) EXCLUSIVE_LOCKS_REQUIRED(!cs_db); void WriteBlockInstantSendLocks(const gsl::not_null>& pblock, gsl::not_null pindexConnected) EXCLUSIVE_LOCKS_REQUIRED(!cs_db); void RemoveBlockInstantSendLocks(const gsl::not_null>& pblock, gsl::not_null pindexDisconnected) EXCLUSIVE_LOCKS_REQUIRED(!cs_db); - bool KnownInstantSendLock(const uint256& islockHash) const EXCLUSIVE_LOCKS_REQUIRED(!cs_db); + bool KnownInstantSendLock(const uint256& islockHash) const LOCKS_EXCLUDED(cs_db); /** * Gets the number of IS Locks which have not been confirmed by a block * @return size_t value of the number of IS Locks not confirmed by a block */ - size_t GetInstantSendLockCount() const EXCLUSIVE_LOCKS_REQUIRED(!cs_db); + size_t GetInstantSendLockCount() const LOCKS_EXCLUDED(cs_db); /** * Gets a pointer to the IS Lock based on the hash * @param hash The hash of the IS Lock * @param use_cache Should we try using the cache first or not * @return A Pointer object to the IS Lock, returns nullptr if it doesn't exist */ - InstantSendLockPtr GetInstantSendLockByHash(const uint256& hash, bool use_cache = true) const EXCLUSIVE_LOCKS_REQUIRED(!cs_db) + InstantSendLockPtr GetInstantSendLockByHash(const uint256& hash, bool use_cache = true) const LOCKS_EXCLUDED(cs_db) { - LOCK(cs_db); + READ_LOCK(cs_db); return GetInstantSendLockByHashInternal(hash, use_cache); }; /** @@ -134,9 +134,9 @@ class CInstantSendDb * @param txid The txid which is being searched for * @return Returns the hash the IS Lock of the specified txid, returns uint256() if it doesn't exist */ - uint256 GetInstantSendLockHashByTxid(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(!cs_db) + uint256 GetInstantSendLockHashByTxid(const uint256& txid) const LOCKS_EXCLUDED(cs_db) { - LOCK(cs_db); + READ_LOCK(cs_db); return GetInstantSendLockHashByTxidInternal(txid); }; /** @@ -144,13 +144,13 @@ class CInstantSendDb * @param txid The txid for which the IS Lock Pointer is being returned * @return Returns the IS Lock Pointer associated with the txid, returns nullptr if it doesn't exist */ - InstantSendLockPtr GetInstantSendLockByTxid(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(!cs_db); + InstantSendLockPtr GetInstantSendLockByTxid(const uint256& txid) const LOCKS_EXCLUDED(cs_db); /** * Gets an IS Lock pointer from an input given * @param outpoint Since all inputs are really just outpoints that are being spent * @return IS Lock Pointer associated with that input. */ - InstantSendLockPtr GetInstantSendLockByInput(const COutPoint& outpoint) const EXCLUSIVE_LOCKS_REQUIRED(!cs_db); + InstantSendLockPtr GetInstantSendLockByInput(const COutPoint& outpoint) const LOCKS_EXCLUDED(cs_db); /** * Called when a ChainLock invalidated a IS Lock, removes any chained/children IS Locks and the invalidated IS Lock * @param islockHash IS Lock hash which has been invalidated