diff options
-rw-r--r-- | src/mongo/db/storage/wiredtiger/wiredtiger_session_cache.cpp | 16 | ||||
-rw-r--r-- | src/mongo/db/storage/wiredtiger/wiredtiger_session_cache.h | 17 |
2 files changed, 25 insertions, 8 deletions
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_session_cache.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_session_cache.cpp index d7997dee2c5..3ed1d4e985b 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_session_cache.cpp +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_session_cache.cpp @@ -137,6 +137,10 @@ WT_CURSOR* WiredTigerSession::getNewCursor(const std::string& uri, const char* c } void WiredTigerSession::releaseCursor(uint64_t id, WT_CURSOR* cursor, const std::string& config) { + // When releasing the cursor, we would want to check if the session cache is already in shutdown + // and prevent the race condition that the shutdown starts after the check. + WiredTigerSessionCache::BlockShutdown blockShutdown(_cache); + // Avoids the cursor already being destroyed during the shutdown. if (_cache->isShuttingDown()) { return; @@ -230,7 +234,7 @@ void WiredTigerSessionCache::shuttingDown() { if (_shuttingDown.fetchAndBitOr(kShuttingDownMask) & kShuttingDownMask) return; - // Spin as long as there are threads in releaseSession + // Spin as long as there are threads blocking shutdown. while (_shuttingDown.load() != kShuttingDownMask) { sleepmillis(1); } @@ -265,12 +269,11 @@ void WiredTigerSessionCache::waitUntilDurable(OperationContext* opCtx, return; } - const int shuttingDown = _shuttingDown.fetchAndAdd(1); - ON_BLOCK_EXIT([this] { _shuttingDown.fetchAndSubtract(1); }); + BlockShutdown blockShutdown(this); uassert(ErrorCodes::ShutdownInProgress, "Cannot wait for durability because a shutdown is in progress", - !(shuttingDown & kShuttingDownMask)); + !isShuttingDown()); // Stable checkpoints are only meaningful in a replica set. Replication sets the "stable // timestamp". If the stable timestamp is unset, WiredTiger takes a full checkpoint, which is @@ -486,10 +489,9 @@ void WiredTigerSessionCache::releaseSession(WiredTigerSession* session) { // We might have skipped releasing some cursors during the shutdown. invariant(session->cursorsOut() == 0 || isShuttingDown()); - const int shuttingDown = _shuttingDown.fetchAndAdd(1); - ON_BLOCK_EXIT([this] { _shuttingDown.fetchAndSubtract(1); }); + BlockShutdown blockShutdown(this); - if (shuttingDown & kShuttingDownMask) { + if (isShuttingDown()) { // There is a race condition with clean shutdown, where the storage engine is ripped from // underneath OperationContexts, which are not "active" (i.e., do not have any locks), but // are just about to delete the recovery unit. See SERVER-16031 for more information. Since diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_session_cache.h b/src/mongo/db/storage/wiredtiger/wiredtiger_session_cache.h index 960ad11e75c..18da44e3246 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_session_cache.h +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_session_cache.h @@ -245,6 +245,21 @@ public: */ enum class UseJournalListener { kUpdate, kSkip }; + // RAII type to block and unblock the WiredTigerSessionCache to shut down. + class BlockShutdown { + public: + BlockShutdown(WiredTigerSessionCache* cache) : _cache(cache) { + _cache->_shuttingDown.fetchAndAdd(1); + } + + ~BlockShutdown() { + _cache->_shuttingDown.fetchAndSubtract(1); + } + + private: + WiredTigerSessionCache* _cache; + }; + /** * Indicates that WiredTiger should be configured to cache cursors. */ @@ -374,7 +389,7 @@ private: WiredTigerSnapshotManager _snapshotManager; // Used as follows: - // The low 31 bits are a count of active calls to releaseSession. + // The low 31 bits are a count of active calls that need to block shutdown. // The high bit is a flag that is set if and only if we're shutting down. AtomicWord<unsigned> _shuttingDown; static const uint32_t kShuttingDownMask = 1 << 31; |