diff options
author | Geert Bosch <geert@mongodb.com> | 2016-02-01 10:01:27 -0500 |
---|---|---|
committer | Ramon Fernandez <ramon@mongodb.com> | 2016-02-02 17:19:49 -0500 |
commit | 9e55fe2085f8627ae7791b8a4b55e0c6114feac3 (patch) | |
tree | 7727ee7a6c318444be3e8a82ea15bef4054c6d9c | |
parent | dd1d0205b7e92947953c6846ee4642f662b8df88 (diff) | |
download | mongo-9e55fe2085f8627ae7791b8a4b55e0c6114feac3.tar.gz |
SERVER-22011: Obtain tickets at outermost global lock in WT
(cherry picked from commit 2969c83e3dcd4ca26e81b27454938e1c2aa7fe53)
12 files changed, 185 insertions, 117 deletions
diff --git a/jstests/noPassthrough/write_local.js b/jstests/noPassthrough/write_local.js new file mode 100644 index 00000000000..66b50f968ca --- /dev/null +++ b/jstests/noPassthrough/write_local.js @@ -0,0 +1,47 @@ +// SERVER-22011: Deadlock in ticket distribution +(function() { + 'use strict' + + // Limit concurrent WiredTiger transactions to maximize locking issues, harmless for other SEs. + var options = { verbose: 1 }; + + // Create a new single node replicaSet + var replTest = new ReplSetTest({ name: "write_local", + nodes: 1, + oplogSize: 1, + nodeOptions: options }); + replTest.startSet(); + replTest.initiate(); + var mongod = replTest.getPrimary(); + mongod.adminCommand({ setParameter: 1, wiredTigerConcurrentWriteTransactions: 1 }); + + var local = mongod.getDB('local'); + + // Start inserting documents in test.capped and local.capped capped collections. + var shells = ['test', 'local'].map(function(dbname){ + var mydb = local.getSiblingDB(dbname); + mydb.capped.drop(); + mydb.createCollection('capped', { capped: true, size: 20*1000 }); + return startParallelShell( + 'var mydb=db.getSiblingDB("' + dbname + '"); ' + + '(function() { ' + + ' for(var i=0; i < 10*1000; i++) { ' + + ' mydb.capped.insert({ x: i }); ' + + ' } ' + + '})();', mongod.port); + }); + + // The following causes inconsistent locking order in the ticket system, depending on + // timeouts to avoid deadlock. + var oldObjects = 0; + for (var i = 0; i < 1000; i++) { + print(local.stats().objects); + sleep(1); + }; + + // Wait for parallel shells to terminate and stop our replset. + shells.forEach((function(f) { + f(); + })); + replTest.stopSet(); +}()) diff --git a/src/mongo/db/concurrency/lock_state.cpp b/src/mongo/db/concurrency/lock_state.cpp index ea2b9b9c63a..04512bce9bd 100644 --- a/src/mongo/db/concurrency/lock_state.cpp +++ b/src/mongo/db/concurrency/lock_state.cpp @@ -39,6 +39,7 @@ #include "mongo/platform/compiler.h" #include "mongo/util/background.h" #include "mongo/util/concurrency/synchronization.h" +#include "mongo/util/concurrency/ticketholder.h" #include "mongo/util/debug_util.h" #include "mongo/util/log.h" #include "mongo/util/mongoutils/str.h" @@ -188,6 +189,7 @@ void LockerImpl<IsForMMAPV1>::assertEmptyAndReset() { invariant(!inAWriteUnitOfWork()); invariant(_resourcesToUnlockAtEndOfUnitOfWork.empty()); invariant(_requests.empty()); + invariant(_modeForTicket == MODE_NONE); // Reset the locking statistics so the object can be reused _stats.reset(); @@ -243,11 +245,38 @@ void CondVarLockGrantNotification::notify(ResourceId resId, LockResult result) { _cond.notify_all(); } +namespace { +TicketHolder* ticketHolders[LockModesCount] = {}; + +void acquireTicket(LockMode mode) { + auto holder = ticketHolders[mode]; + if (holder) { + holder->waitForTicket(); + } +} + +void releaseTicket(LockMode* mode) { + invariant(*mode != MODE_NONE); + auto holder = ticketHolders[*mode]; + *mode = MODE_NONE; + if (holder) { + holder->release(); + } +} +} // namespace + // // Locker // +/* static */ +void Locker::setGlobalThrottling(class TicketHolder* reading, class TicketHolder* writing) { + ticketHolders[MODE_S] = reading; + ticketHolders[MODE_IS] = reading; + ticketHolders[MODE_IX] = writing; +} + template <bool IsForMMAPV1> LockerImpl<IsForMMAPV1>::LockerImpl() : _id(idCounter.addAndFetch(1)), _wuowNestingLevel(0), _batchWriter(false) {} @@ -276,6 +305,11 @@ LockResult LockerImpl<IsForMMAPV1>::lockGlobal(LockMode mode, unsigned timeoutMs template <bool IsForMMAPV1> LockResult LockerImpl<IsForMMAPV1>::lockGlobalBegin(LockMode mode) { + dassert(isLocked() == (_modeForTicket != MODE_NONE)); + if (_modeForTicket == MODE_NONE) { + acquireTicket(mode); + _modeForTicket = mode; + } const LockResult result = lockBegin(resourceIdGlobal, mode); if (result == LOCK_OK) return LOCK_OK; @@ -315,6 +349,10 @@ void LockerImpl<IsForMMAPV1>::downgradeGlobalXtoSForMMAPV1() { LockRequest* globalLockRequest = _requests.find(resourceIdGlobal).objAddr(); invariant(globalLockRequest->mode == MODE_X); invariant(globalLockRequest->recursiveCount == 1); + invariant(_modeForTicket == MODE_X); + // Note that this locker will not actually have a ticket (as MODE_X has no TicketHolder) or + // acquire one now, but at most a single thread can be in this downgraded MODE_S situation, + // so it's OK. // Making this call here will record lock downgrades as acquisitions, which is acceptable globalStats.recordAcquisition(_id, resourceIdGlobal, MODE_S); @@ -561,6 +599,7 @@ bool LockerImpl<IsForMMAPV1>::saveLockStateAndUnlock(Locker::LockSnapshot* state invariant(unlock(resId)); } + invariant(!isLocked()); // Sort locks by ResourceId. They'll later be acquired in this canonical locking order. std::sort(stateOut->locks.begin(), stateOut->locks.end()); @@ -572,6 +611,7 @@ template <bool IsForMMAPV1> void LockerImpl<IsForMMAPV1>::restoreLockState(const Locker::LockSnapshot& state) { // We shouldn't be saving and restoring lock state from inside a WriteUnitOfWork. invariant(!inAWriteUnitOfWork()); + invariant(_modeForTicket == MODE_NONE); std::vector<OneLock>::const_iterator it = state.locks.begin(); // If we locked the PBWM, it must be locked before the resourceIdGlobal resource. @@ -590,6 +630,7 @@ void LockerImpl<IsForMMAPV1>::restoreLockState(const Locker::LockSnapshot& state invariant(LOCK_OK == lock(it->resourceId, it->mode)); } } + invariant(_modeForTicket != MODE_NONE); } template <bool IsForMMAPV1> @@ -722,6 +763,8 @@ LockResult LockerImpl<IsForMMAPV1>::lockComplete(ResourceId resId, if (result != LOCK_OK) { LockRequestsMap::Iterator it = _requests.find(resId); if (globalLockManager.unlock(it.objAddr())) { + if (resId == resourceIdGlobal) + releaseTicket(&_modeForTicket); scoped_spinlock scopedLock(_lock); it.remove(); } @@ -744,6 +787,9 @@ bool LockerImpl<IsForMMAPV1>::_unlockImpl(LockRequestsMap::Iterator& it) { } if (globalLockManager.unlock(it.objAddr())) { + if (it.key() == resourceIdGlobal) + releaseTicket(&_modeForTicket); + scoped_spinlock scopedLock(_lock); it.remove(); diff --git a/src/mongo/db/concurrency/lock_state.h b/src/mongo/db/concurrency/lock_state.h index cf634fd3168..de19f38ae44 100644 --- a/src/mongo/db/concurrency/lock_state.h +++ b/src/mongo/db/concurrency/lock_state.h @@ -214,6 +214,8 @@ private: int _wuowNestingLevel; std::queue<ResourceId> _resourcesToUnlockAtEndOfUnitOfWork; + // Mode for which the Locker acquired a ticket, or MODE_NONE if no ticket was acquired. + LockMode _modeForTicket = MODE_NONE; ////////////////////////////////////////////////////////////////////////////////////////// // diff --git a/src/mongo/db/concurrency/locker.h b/src/mongo/db/concurrency/locker.h index 7c19f421e5c..be9f3ea0730 100644 --- a/src/mongo/db/concurrency/locker.h +++ b/src/mongo/db/concurrency/locker.h @@ -48,6 +48,15 @@ class Locker { public: virtual ~Locker() {} + /** + * Require global lock attempts with obtain tickets from 'reading' (for MODE_S and MODE_IS), + * and from 'writing' (for MODE_IX), which must have static lifetimes. There is no throttling + * for MODE_X, as there can only ever be a single locker using this mode. The throttling is + * intended to defend against arge drops in throughput under high load due to too much + * concurrency. + */ + static void setGlobalThrottling(class TicketHolder* reading, class TicketHolder* writing); + virtual LockerId getId() const = 0; /** diff --git a/src/mongo/db/storage/wiredtiger/SConscript b/src/mongo/db/storage/wiredtiger/SConscript index 15a1aeb9003..26e4435c956 100644 --- a/src/mongo/db/storage/wiredtiger/SConscript +++ b/src/mongo/db/storage/wiredtiger/SConscript @@ -37,6 +37,7 @@ if wiredtiger: '$BUILD_DIR/mongo/base', '$BUILD_DIR/mongo/db/namespace_string', '$BUILD_DIR/mongo/db/catalog/collection_options', + '$BUILD_DIR/mongo/db/concurrency/lock_manager', '$BUILD_DIR/mongo/db/concurrency/write_conflict_exception', '$BUILD_DIR/mongo/db/index/index_descriptor', '$BUILD_DIR/mongo/db/service_context', @@ -44,10 +45,10 @@ if wiredtiger: '$BUILD_DIR/mongo/db/storage/key_string', '$BUILD_DIR/mongo/db/storage/oplog_hack', '$BUILD_DIR/mongo/db/storage/storage_options', + '$BUILD_DIR/mongo/util/concurrency/ticketholder', '$BUILD_DIR/mongo/util/elapsed_tracker', '$BUILD_DIR/mongo/util/foundation', '$BUILD_DIR/mongo/util/processinfo', - '$BUILD_DIR/mongo/util/concurrency/ticketholder', '$BUILD_DIR/third_party/shim_wiredtiger', '$BUILD_DIR/third_party/shim_snappy', '$BUILD_DIR/third_party/shim_zlib', diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.cpp index 5a9ab07b36a..8420434cf4e 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.cpp +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.cpp @@ -42,10 +42,14 @@ #include <valgrind/valgrind.h> #include "mongo/base/error_codes.h" +#include "mongo/bson/bsonobjbuilder.h" #include "mongo/db/catalog/collection_catalog_entry.h" #include "mongo/db/client.h" +#include "mongo/db/concurrency/locker.h" #include "mongo/db/concurrency/write_conflict_exception.h" +#include "mongo/db/commands/server_status_metric.h" #include "mongo/db/index/index_descriptor.h" +#include "mongo/db/server_parameters.h" #include "mongo/db/service_context.h" #include "mongo/db/storage/wiredtiger/wiredtiger_customization_hooks.h" #include "mongo/db/storage/wiredtiger/wiredtiger_global_options.h" @@ -58,6 +62,7 @@ #include "mongo/db/storage/storage_options.h" #include "mongo/util/log.h" #include "mongo/util/background.h" +#include "mongo/util/concurrency/ticketholder.h" #include "mongo/util/exit.h" #include "mongo/util/processinfo.h" #include "mongo/util/scopeguard.h" @@ -113,6 +118,55 @@ private: std::atomic<bool> _shuttingDown{false}; // NOLINT }; +namespace { + +class TicketServerParameter : public ServerParameter { + MONGO_DISALLOW_COPYING(TicketServerParameter); + +public: + TicketServerParameter(TicketHolder* holder, const std::string& name) + : ServerParameter(ServerParameterSet::getGlobal(), name, true, true), _holder(holder) {} + + virtual void append(OperationContext* txn, BSONObjBuilder& b, const std::string& name) { + b.append(name, _holder->outof()); + } + + virtual Status set(const BSONElement& newValueElement) { + if (!newValueElement.isNumber()) + return Status(ErrorCodes::BadValue, str::stream() << name() << " has to be a number"); + return _set(newValueElement.numberInt()); + } + + virtual Status setFromString(const std::string& str) { + int num = 0; + Status status = parseNumberFromString(str, &num); + if (!status.isOK()) + return status; + return _set(num); + } + + Status _set(int newNum) { + if (newNum <= 0) { + return Status(ErrorCodes::BadValue, str::stream() << name() << " has to be > 0"); + } + + return _holder->resize(newNum); + } + +private: + TicketHolder* _holder; +}; + +TicketHolder openWriteTransaction(128); +TicketServerParameter openWriteTransactionParam(&openWriteTransaction, + "wiredTigerConcurrentWriteTransactions"); + +TicketHolder openReadTransaction(128); +TicketServerParameter openReadTransactionParam(&openReadTransaction, + "wiredTigerConcurrentReadTransactions"); + +} // namespace + WiredTigerKVEngine::WiredTigerKVEngine(const std::string& canonicalName, const std::string& path, const std::string& extraOpenOptions, @@ -208,6 +262,8 @@ WiredTigerKVEngine::WiredTigerKVEngine(const std::string& canonicalName, _sizeStorer.reset(new WiredTigerSizeStorer(_conn, _sizeStorerUri)); _sizeStorer->fillCache(); } + + Locker::setGlobalThrottling(&openReadTransaction, &openWriteTransaction); } @@ -219,6 +275,25 @@ WiredTigerKVEngine::~WiredTigerKVEngine() { _sessionCache.reset(NULL); } +void WiredTigerKVEngine::appendGlobalStats(BSONObjBuilder& b) { + BSONObjBuilder bb(b.subobjStart("concurrentTransactions")); + { + BSONObjBuilder bbb(bb.subobjStart("write")); + bbb.append("out", openWriteTransaction.used()); + bbb.append("available", openWriteTransaction.available()); + bbb.append("totalTickets", openWriteTransaction.outof()); + bbb.done(); + } + { + BSONObjBuilder bbb(bb.subobjStart("read")); + bbb.append("out", openReadTransaction.used()); + bbb.append("available", openReadTransaction.available()); + bbb.append("totalTickets", openReadTransaction.outof()); + bbb.done(); + } + bb.done(); +} + void WiredTigerKVEngine::cleanShutdown() { log() << "WiredTigerKVEngine shutting down"; syncSizeInfo(true); diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.h b/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.h index f17c060220f..bc0a5f71301 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.h +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.h @@ -142,6 +142,8 @@ public: */ static bool initRsOplogBackgroundThread(StringData ns); + static void appendGlobalStats(BSONObjBuilder& b); + private: class WiredTigerJournalFlusher; diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp index a38a6fd517b..d37bc706093 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp @@ -1062,7 +1062,6 @@ int64_t WiredTigerRecordStore::cappedDeleteAsNeeded_inlock(OperationContext* txn OperationContext::RecoveryUnitState const realRUstate = txn->setRecoveryUnit(new WiredTigerRecoveryUnit(sc), OperationContext::kNotInUnitOfWork); - WiredTigerRecoveryUnit::get(txn)->markNoTicketRequired(); // realRecoveryUnit already has WT_SESSION* session = WiredTigerRecoveryUnit::get(txn)->getSession(txn)->getSession(); int64_t dataSize = _dataSize.load(); @@ -1220,7 +1219,6 @@ void WiredTigerRecordStore::reclaimOplog(OperationContext* txn) { << " records totaling to " << stone->bytes << " bytes"; WiredTigerRecoveryUnit* ru = WiredTigerRecoveryUnit::get(txn); - ru->markNoTicketRequired(); // No ticket is needed for internal operations. WT_SESSION* session = ru->getSession(txn)->getSession(); try { diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_mongod.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_mongod.cpp index 449714aca6e..ce089a38ce9 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_mongod.cpp +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_mongod.cpp @@ -78,7 +78,6 @@ public: } OperationContextImpl txn; - checked_cast<WiredTigerRecoveryUnit*>(txn.recoveryUnit())->markNoTicketRequired(); try { ScopedTransaction transaction(&txn, MODE_IX); diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.cpp index 7d5d277e5c9..7a41d0d7341 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.cpp +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.cpp @@ -33,8 +33,6 @@ #include "mongo/base/checked_cast.h" #include "mongo/base/init.h" #include "mongo/bson/bsonobjbuilder.h" -#include "mongo/db/commands/server_status_metric.h" -#include "mongo/db/server_parameters.h" #include "mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.h" #include "mongo/db/storage/wiredtiger/wiredtiger_session_cache.h" #include "mongo/db/storage/wiredtiger/wiredtiger_util.h" @@ -53,8 +51,7 @@ WiredTigerRecoveryUnit::WiredTigerRecoveryUnit(WiredTigerSessionCache* sc) _inUnitOfWork(false), _active(false), _myTransactionCount(1), - _everStartedWrite(false), - _noTicketNeeded(false) {} + _everStartedWrite(false) {} WiredTigerRecoveryUnit::~WiredTigerRecoveryUnit() { invariant(!_inUnitOfWork); @@ -69,7 +66,6 @@ void WiredTigerRecoveryUnit::reportState(BSONObjBuilder* b) const { b->append("wt_inUnitOfWork", _inUnitOfWork); b->append("wt_active", _active); b->append("wt_everStartedWrite", _everStartedWrite); - b->append("wt_hasTicket", _ticket.hasTicket()); b->appendNumber("wt_myTransactionCount", static_cast<long long>(_myTransactionCount)); if (_active) b->append("wt_millisSinceCommit", _timer.millis()); @@ -128,7 +124,6 @@ void WiredTigerRecoveryUnit::beginUnitOfWork(OperationContext* opCtx) { invariant(!_inUnitOfWork); _inUnitOfWork = true; _everStartedWrite = true; - _getTicket(opCtx); } void WiredTigerRecoveryUnit::commitUnitOfWork() { @@ -205,74 +200,6 @@ void WiredTigerRecoveryUnit::setOplogReadTill(const RecordId& id) { _oplogReadTill = id; } -namespace { - -class TicketServerParameter : public ServerParameter { - MONGO_DISALLOW_COPYING(TicketServerParameter); - -public: - TicketServerParameter(TicketHolder* holder, const std::string& name) - : ServerParameter(ServerParameterSet::getGlobal(), name, true, true), _holder(holder) {} - - virtual void append(OperationContext* txn, BSONObjBuilder& b, const std::string& name) { - b.append(name, _holder->outof()); - } - - virtual Status set(const BSONElement& newValueElement) { - if (!newValueElement.isNumber()) - return Status(ErrorCodes::BadValue, str::stream() << name() << " has to be a number"); - return _set(newValueElement.numberInt()); - } - - virtual Status setFromString(const std::string& str) { - int num = 0; - Status status = parseNumberFromString(str, &num); - if (!status.isOK()) - return status; - return _set(num); - } - - Status _set(int newNum) { - if (newNum <= 0) { - return Status(ErrorCodes::BadValue, str::stream() << name() << " has to be > 0"); - } - - return _holder->resize(newNum); - } - -private: - TicketHolder* _holder; -}; - -TicketHolder openWriteTransaction(128); -TicketServerParameter openWriteTransactionParam(&openWriteTransaction, - "wiredTigerConcurrentWriteTransactions"); - -TicketHolder openReadTransaction(128); -TicketServerParameter openReadTransactionParam(&openReadTransaction, - "wiredTigerConcurrentReadTransactions"); - -} // namespace - -void WiredTigerRecoveryUnit::appendGlobalStats(BSONObjBuilder& b) { - BSONObjBuilder bb(b.subobjStart("concurrentTransactions")); - { - BSONObjBuilder bbb(bb.subobjStart("write")); - bbb.append("out", openWriteTransaction.used()); - bbb.append("available", openWriteTransaction.available()); - bbb.append("totalTickets", openWriteTransaction.outof()); - bbb.done(); - } - { - BSONObjBuilder bbb(bb.subobjStart("read")); - bbb.append("out", openReadTransaction.used()); - bbb.append("available", openReadTransaction.available()); - bbb.append("totalTickets", openReadTransaction.outof()); - bbb.done(); - } - bb.done(); -} - void WiredTigerRecoveryUnit::_txnClose(bool commit) { invariant(_active); WT_SESSION* s = _session->getSession(); @@ -285,7 +212,6 @@ void WiredTigerRecoveryUnit::_txnClose(bool commit) { } _active = false; _myTransactionCount++; - _ticket.reset(NULL); } SnapshotId WiredTigerRecoveryUnit::getSnapshotId() const { @@ -311,39 +237,8 @@ boost::optional<SnapshotName> WiredTigerRecoveryUnit::getMajorityCommittedSnapsh return _majorityCommittedSnapshot; } -void WiredTigerRecoveryUnit::markNoTicketRequired() { - invariant(!_ticket.hasTicket()); - _noTicketNeeded = true; -} - -void WiredTigerRecoveryUnit::_getTicket(OperationContext* opCtx) { - // already have a ticket - if (_ticket.hasTicket()) - return; - - if (_noTicketNeeded) - return; - - bool writeLocked; - - // If we have a strong lock, waiting for a ticket can cause a deadlock. - if (opCtx != NULL && opCtx->lockState() != NULL) { - if (opCtx->lockState()->hasStrongLocks()) - return; - writeLocked = opCtx->lockState()->isWriteLocked(); - } else { - writeLocked = _everStartedWrite; - } - - TicketHolder* holder = writeLocked ? &openWriteTransaction : &openReadTransaction; - - holder->waitForTicket(); - _ticket.reset(holder); -} - void WiredTigerRecoveryUnit::_txnOpen(OperationContext* opCtx) { invariant(!_active); - _getTicket(opCtx); _ensureSession(); WT_SESSION* s = _session->getSession(); diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.h b/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.h index af9872fa96b..b70b4bebfea 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.h +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.h @@ -107,8 +107,6 @@ public: return _oplogReadTill; } - void markNoTicketRequired(); - static WiredTigerRecoveryUnit* get(OperationContext* txn); static void appendGlobalStats(BSONObjBuilder& b); @@ -143,10 +141,6 @@ private: typedef OwnedPointerVector<Change> Changes; Changes _changes; - - bool _noTicketNeeded; - void _getTicket(OperationContext* opCtx); - TicketHolderReleaser _ticket; }; /** diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_server_status.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_server_status.cpp index fc62b8d84f9..4967dfc2f86 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_server_status.cpp +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_server_status.cpp @@ -74,7 +74,7 @@ BSONObj WiredTigerServerStatusSection::generateSection(OperationContext* txn, bob.append("reason", status.reason()); } - WiredTigerRecoveryUnit::appendGlobalStats(bob); + WiredTigerKVEngine::appendGlobalStats(bob); return bob.obj(); } |