diff options
author | Daniel Gottlieb <daniel.gottlieb@10gen.com> | 2017-02-24 09:51:25 -0500 |
---|---|---|
committer | Daniel Gottlieb <daniel.gottlieb@10gen.com> | 2017-02-24 09:51:25 -0500 |
commit | 9c9bbf3318113cfdd4d9b72f493b6ebd23f1837e (patch) | |
tree | 659bf628856f2da219319b11ffafad7aa2dbbc8d /src/mongo/db | |
parent | f89ede4cc81a1307dec4b9e901fc91eb3f7f8992 (diff) | |
download | mongo-9c9bbf3318113cfdd4d9b72f493b6ebd23f1837e.tar.gz |
SERVER-18410: Replace RWLock with OperationContext/LockManager
Diffstat (limited to 'src/mongo/db')
40 files changed, 447 insertions, 247 deletions
diff --git a/src/mongo/db/commands/fsync.cpp b/src/mongo/db/commands/fsync.cpp index a2d4c3c2651..01d922cec02 100644 --- a/src/mongo/db/commands/fsync.cpp +++ b/src/mongo/db/commands/fsync.cpp @@ -150,7 +150,7 @@ public: // Take a global IS lock to ensure the storage engine is not shutdown Lock::GlobalLock global(txn->lockState(), MODE_IS, UINT_MAX); StorageEngine* storageEngine = getGlobalServiceContext()->getGlobalStorageEngine(); - result.append("numFiles", storageEngine->flushAllFiles(sync)); + result.append("numFiles", storageEngine->flushAllFiles(txn, sync)); return true; } @@ -362,7 +362,7 @@ void FSyncLockThread::run() { StorageEngine* storageEngine = getGlobalServiceContext()->getGlobalStorageEngine(); try { - storageEngine->flushAllFiles(true); + storageEngine->flushAllFiles(&txn, true); } catch (const std::exception& e) { error() << "error doing flushAll: " << e.what(); fsyncCmd.threadStatus = Status(ErrorCodes::CommandFailed, e.what()); diff --git a/src/mongo/db/concurrency/d_concurrency.cpp b/src/mongo/db/concurrency/d_concurrency.cpp index a2aead7cdb4..4a11ecdba2b 100644 --- a/src/mongo/db/concurrency/d_concurrency.cpp +++ b/src/mongo/db/concurrency/d_concurrency.cpp @@ -127,6 +127,14 @@ std::string Lock::ResourceMutex::getName(ResourceId resourceId) { return ResourceIdFactory::nameForId(resourceId); } +bool Lock::ResourceMutex::isExclusivelyLocked(Locker* locker) { + return locker->isLockHeldForMode(_rid, MODE_X); +} + +bool Lock::ResourceMutex::isAtLeastReadLocked(Locker* locker) { + return locker->isLockHeldForMode(_rid, MODE_IS); +} + Lock::GlobalLock::GlobalLock(Locker* locker, LockMode lockMode, unsigned timeoutMs) : GlobalLock(locker, lockMode, EnqueueOnly()) { waitForLock(timeoutMs); diff --git a/src/mongo/db/concurrency/d_concurrency.h b/src/mongo/db/concurrency/d_concurrency.h index 9617bc985a0..fe8ac0f49a1 100644 --- a/src/mongo/db/concurrency/d_concurrency.h +++ b/src/mongo/db/concurrency/d_concurrency.h @@ -119,6 +119,10 @@ public: static std::string getName(ResourceId resourceId); + bool isExclusivelyLocked(Locker* locker); + + bool isAtLeastReadLocked(Locker* locker); + private: friend class Lock::SharedLock; friend class Lock::ExclusiveLock; diff --git a/src/mongo/db/query/query_yield.cpp b/src/mongo/db/query/query_yield.cpp index 893184fb14f..6548a662a17 100644 --- a/src/mongo/db/query/query_yield.cpp +++ b/src/mongo/db/query/query_yield.cpp @@ -60,7 +60,7 @@ void QueryYield::yieldAllLocks(OperationContext* txn, Locker::LockSnapshot snapshot; if (fetcher) { - fetcher->setup(); + fetcher->setup(txn); } // Nothing was unlocked, just return, yielding is pointless. diff --git a/src/mongo/db/repl/oplog.cpp b/src/mongo/db/repl/oplog.cpp index 1cb67f64a53..908febd4c76 100644 --- a/src/mongo/db/repl/oplog.cpp +++ b/src/mongo/db/repl/oplog.cpp @@ -534,7 +534,7 @@ void createOplog(OperationContext* txn, const std::string& oplogCollectionName, /* sync here so we don't get any surprising lag later when we try to sync */ StorageEngine* storageEngine = getGlobalServiceContext()->getGlobalStorageEngine(); - storageEngine->flushAllFiles(true); + storageEngine->flushAllFiles(txn, true); log() << "******" << endl; } diff --git a/src/mongo/db/storage/kv/kv_engine.h b/src/mongo/db/storage/kv/kv_engine.h index e6dd1f8cbbe..04c5acb1dfa 100644 --- a/src/mongo/db/storage/kv/kv_engine.h +++ b/src/mongo/db/storage/kv/kv_engine.h @@ -91,7 +91,7 @@ public: virtual Status dropIdent(OperationContext* opCtx, StringData ident) = 0; // optional - virtual int flushAllFiles(bool sync) { + virtual int flushAllFiles(OperationContext* txn, bool sync) { return 0; } diff --git a/src/mongo/db/storage/kv/kv_storage_engine.cpp b/src/mongo/db/storage/kv/kv_storage_engine.cpp index f825cb3a1c2..ee02c447bdf 100644 --- a/src/mongo/db/storage/kv/kv_storage_engine.cpp +++ b/src/mongo/db/storage/kv/kv_storage_engine.cpp @@ -251,8 +251,8 @@ Status KVStorageEngine::dropDatabase(OperationContext* txn, StringData db) { return Status::OK(); } -int KVStorageEngine::flushAllFiles(bool sync) { - return _engine->flushAllFiles(sync); +int KVStorageEngine::flushAllFiles(OperationContext* txn, bool sync) { + return _engine->flushAllFiles(txn, sync); } Status KVStorageEngine::beginBackup(OperationContext* txn) { diff --git a/src/mongo/db/storage/kv/kv_storage_engine.h b/src/mongo/db/storage/kv/kv_storage_engine.h index 32bab2ee252..ba656ae85c1 100644 --- a/src/mongo/db/storage/kv/kv_storage_engine.h +++ b/src/mongo/db/storage/kv/kv_storage_engine.h @@ -93,7 +93,7 @@ public: virtual Status dropDatabase(OperationContext* txn, StringData db); - virtual int flushAllFiles(bool sync); + virtual int flushAllFiles(OperationContext* txn, bool sync); virtual Status beginBackup(OperationContext* txn); diff --git a/src/mongo/db/storage/mmap_v1/SConscript b/src/mongo/db/storage/mmap_v1/SConscript index 4fa273fe408..ba8fd96c097 100644 --- a/src/mongo/db/storage/mmap_v1/SConscript +++ b/src/mongo/db/storage/mmap_v1/SConscript @@ -115,9 +115,11 @@ env.Library( 'mmap_${TARGET_OS_FAMILY}.cpp', ], LIBDEPS=[ - 'file_allocator', + '$BUILD_DIR/mongo/db/concurrency/lock_manager', + '$BUILD_DIR/mongo/db/service_context', + '$BUILD_DIR/mongo/db/storage/storage_options', '$BUILD_DIR/mongo/util/progress_meter', - '$BUILD_DIR/mongo/db/storage/storage_options' + 'file_allocator', ], ) diff --git a/src/mongo/db/storage/mmap_v1/catalog/namespace_index.cpp b/src/mongo/db/storage/mmap_v1/catalog/namespace_index.cpp index ffca8474db3..173c2afceca 100644 --- a/src/mongo/db/storage/mmap_v1/catalog/namespace_index.cpp +++ b/src/mongo/db/storage/mmap_v1/catalog/namespace_index.cpp @@ -51,8 +51,10 @@ using std::endl; using std::list; using std::string; -NamespaceIndex::NamespaceIndex(const std::string& dir, const std::string& database) - : _dir(dir), _database(database), _ht(nullptr) {} +NamespaceIndex::NamespaceIndex(OperationContext* txn, + const std::string& dir, + const std::string& database) + : _dir(dir), _database(database), _f(txn, MongoFile::Options::SEQUENTIAL), _ht(nullptr) {} NamespaceIndex::~NamespaceIndex() {} @@ -156,7 +158,7 @@ void NamespaceIndex::init(OperationContext* txn) { void* p = 0; if (boost::filesystem::exists(nsPath)) { - if (_f.open(pathString)) { + if (_f.open(txn, pathString)) { len = _f.length(); if (len % (1024 * 1024) != 0) { @@ -215,7 +217,7 @@ void NamespaceIndex::init(OperationContext* txn) { massert(18826, str::stream() << "failure writing file " << pathString, !file.bad()); } - if (_f.create(pathString, l)) { + if (_f.create(txn, pathString, l)) { // The writes done in this function must not be rolled back. This will leave the // file empty, but available for future use. That is why we go directly to the // global dur dirty list rather than going through the OperationContext. diff --git a/src/mongo/db/storage/mmap_v1/catalog/namespace_index.h b/src/mongo/db/storage/mmap_v1/catalog/namespace_index.h index 8bcf836518c..51aae08ea61 100644 --- a/src/mongo/db/storage/mmap_v1/catalog/namespace_index.h +++ b/src/mongo/db/storage/mmap_v1/catalog/namespace_index.h @@ -51,9 +51,17 @@ class NamespaceIndex { MONGO_DISALLOW_COPYING(NamespaceIndex); public: - NamespaceIndex(const std::string& dir, const std::string& database); + NamespaceIndex(OperationContext* txn, const std::string& dir, const std::string& database); ~NamespaceIndex(); + /** + * Must be called before destruction. + */ + void close(OperationContext* txn) { + LockMongoFilesExclusive lock(txn); + _f.close(txn); + } + /* returns true if the file represented by this file exists on disk */ bool pathExists() const; @@ -86,7 +94,7 @@ private: const std::string _dir; const std::string _database; - DurableMappedFile _f{MongoFile::Options::SEQUENTIAL}; + DurableMappedFile _f; std::unique_ptr<NamespaceHashTable> _ht; }; } diff --git a/src/mongo/db/storage/mmap_v1/data_file.cpp b/src/mongo/db/storage/mmap_v1/data_file.cpp index c90ff1f74da..d81aa591817 100644 --- a/src/mongo/db/storage/mmap_v1/data_file.cpp +++ b/src/mongo/db/storage/mmap_v1/data_file.cpp @@ -104,14 +104,14 @@ int DataFile::_defaultSize() const { } /** @return true if found and opened. if uninitialized (prealloc only) does not open. */ -Status DataFile::openExisting(const char* filename) { +Status DataFile::openExisting(OperationContext* txn, const char* filename) { invariant(_mb == 0); if (!boost::filesystem::exists(filename)) { return Status(ErrorCodes::InvalidPath, "DataFile::openExisting - file does not exist"); } - if (!mmf.open(filename)) { + if (!mmf.open(txn, filename)) { return Status(ErrorCodes::InternalError, "DataFile::openExisting - mmf.open failed"); } @@ -170,7 +170,7 @@ void DataFile::open(OperationContext* txn, { invariant(_mb == 0); unsigned long long sz = size; - if (mmf.create(filename, sz)) { + if (mmf.create(txn, filename, sz)) { _mb = mmf.getView(); } diff --git a/src/mongo/db/storage/mmap_v1/data_file.h b/src/mongo/db/storage/mmap_v1/data_file.h index e28a5ebcc6e..57b5fb223f9 100644 --- a/src/mongo/db/storage/mmap_v1/data_file.h +++ b/src/mongo/db/storage/mmap_v1/data_file.h @@ -195,10 +195,10 @@ public: class DataFile { public: - DataFile(int fn) : _fileNo(fn), _mb(NULL) {} + DataFile(OperationContext* txn, int fn) : _fileNo(fn), mmf(txn), _mb(NULL) {} /** @return true if found and opened. if uninitialized (prealloc only) does not open. */ - Status openExisting(const char* filename); + Status openExisting(OperationContext* txn, const char* filename); /** creates if DNE */ void open(OperationContext* txn, @@ -206,6 +206,14 @@ public: int requestedDataSize = 0, bool preallocateOnly = false); + /** + * Must be called before destruction. + */ + void close(OperationContext* txn) { + LockMongoFilesExclusive lock(txn); + mmf.close(txn); + } + DiskLoc allocExtentArea(OperationContext* txn, int size); DataFileHeader* getHeader() { diff --git a/src/mongo/db/storage/mmap_v1/data_file_sync.cpp b/src/mongo/db/storage/mmap_v1/data_file_sync.cpp index 24be15045f0..e1bc51d29f3 100644 --- a/src/mongo/db/storage/mmap_v1/data_file_sync.cpp +++ b/src/mongo/db/storage/mmap_v1/data_file_sync.cpp @@ -35,6 +35,7 @@ #include "mongo/db/client.h" #include "mongo/db/commands/server_status_metric.h" #include "mongo/db/diag_log.h" +#include "mongo/db/operation_context.h" #include "mongo/db/service_context.h" #include "mongo/db/storage/mmap_v1/dur_journal.h" #include "mongo/db/storage/mmap_v1/mmap.h" @@ -80,11 +81,12 @@ void DataFileSync::run() { break; } + auto txn = cc().makeOperationContext(); Date_t start = jsTime(); StorageEngine* storageEngine = getGlobalServiceContext()->getGlobalStorageEngine(); dur::notifyPreDataFileFlush(); - int numFiles = storageEngine->flushAllFiles(true); + int numFiles = storageEngine->flushAllFiles(txn.get(), true); dur::notifyPostDataFileFlush(); time_flushing = durationCount<Milliseconds>(jsTime() - start); @@ -125,7 +127,7 @@ class MemJournalServerStatusMetric : public ServerStatusMetric { public: MemJournalServerStatusMetric() : ServerStatusMetric(".mem.mapped") {} virtual void appendAtLeaf(BSONObjBuilder& b) const { - int m = static_cast<int>(MemoryMappedFile::totalMappedLength() / (1024 * 1024)); + int m = MemoryMappedFile::totalMappedLengthInMB(); b.appendNumber("mapped", m); if (storageGlobalParams.dur) { @@ -133,6 +135,5 @@ public: b.appendNumber("mappedWithJournal", m); } } - } memJournalServerStatusMetric; } diff --git a/src/mongo/db/storage/mmap_v1/dur.cpp b/src/mongo/db/storage/mmap_v1/dur.cpp index ab1d1988cba..1ed496c3a6d 100644 --- a/src/mongo/db/storage/mmap_v1/dur.cpp +++ b/src/mongo/db/storage/mmap_v1/dur.cpp @@ -204,7 +204,7 @@ public: return false; } virtual void closingFileNotification() {} - virtual void commitAndStopDurThread() {} + virtual void commitAndStopDurThread(OperationContext* txn) {} }; @@ -226,7 +226,7 @@ public: return true; } virtual void closingFileNotification(); - virtual void commitAndStopDurThread(); + virtual void commitAndStopDurThread(OperationContext* txn); void start(ClockSource* cs, int64_t serverStartMs); @@ -318,7 +318,7 @@ void debugValidateFileMapsMatch(const DurableMappedFile* mmf) { /** * Main code of the remap private view function. */ -void remapPrivateViewImpl(double fraction) { +void remapPrivateViewImpl(OperationContext* txn, double fraction) { LOG(4) << "journal REMAPPRIVATEVIEW" << endl; // There is no way that the set of files can change while we are in this method, because @@ -335,9 +335,9 @@ void remapPrivateViewImpl(double fraction) { // See SERVER-5680 to see why this code is necessary on Windows. // See SERVER-8795 to see why this code is necessary on Solaris. #if defined(_WIN32) || defined(__sun) - LockMongoFilesExclusive lk; + LockMongoFilesExclusive lk(txn); #else - LockMongoFilesShared lk; + LockMongoFilesShared lk(txn); #endif std::set<MongoFile*>& files = MongoFile::getAllFiles(); @@ -381,7 +381,7 @@ void remapPrivateViewImpl(double fraction) { } if (mmf->willNeedRemap()) { - mmf->remapThePrivateView(); + mmf->remapThePrivateView(txn); } i++; @@ -570,7 +570,7 @@ void DurableImpl::syncDataAndTruncateJournal(OperationContext* txn) { commitNow(txn); // Flush the shared view to disk. - MongoFile::flushAll(true); + MongoFile::flushAll(txn, true); // Once the shared view has been flushed, we do not need the journal files anymore. journalCleanup(true); @@ -588,7 +588,7 @@ void DurableImpl::closingFileNotification() { } } -void DurableImpl::commitAndStopDurThread() { +void DurableImpl::commitAndStopDurThread(OperationContext* txn) { CommitNotifier::When when = commitNotify.now(); // There is always just one waiting anyways @@ -600,7 +600,7 @@ void DurableImpl::commitAndStopDurThread() { applyToDataFilesNotify.waitFor(when); // Flush the shared view to disk. - MongoFile::flushAll(true); + MongoFile::flushAll(txn, true); // Once the shared view has been flushed, we do not need the journal files anymore. journalCleanup(true); @@ -630,14 +630,14 @@ void DurableImpl::start(ClockSource* cs, int64_t serverStartMs) { * @param fraction Value between (0, 1] indicating what fraction of the memory to remap. * Remapping too much or too frequently incurs copy-on-write page fault cost. */ -static void remapPrivateView(double fraction) { +static void remapPrivateView(OperationContext* txn, double fraction) { // Remapping private views must occur after WRITETODATAFILES otherwise we wouldn't see any // newly written data on reads. invariant(!commitJob.hasWritten()); try { Timer t; - remapPrivateViewImpl(fraction); + remapPrivateViewImpl(txn, fraction); stats.curr()->_remapPrivateViewMicros += t.micros(); LOG(4) << "remapPrivateView end"; @@ -828,7 +828,7 @@ static void durThread(ClockSource* cs, int64_t serverStartMs) { // accessing it. Technically this step could be avoided on systems, which // support atomic remap. autoFlushLock.upgradeFlushLockToExclusive(); - remapPrivateView(remapFraction); + remapPrivateView(txnPtr.get(), remapFraction); autoFlushLock.release(); diff --git a/src/mongo/db/storage/mmap_v1/dur.h b/src/mongo/db/storage/mmap_v1/dur.h index cf5e4ec2b14..e4aec954749 100644 --- a/src/mongo/db/storage/mmap_v1/dur.h +++ b/src/mongo/db/storage/mmap_v1/dur.h @@ -112,7 +112,7 @@ public: * * Must be called under the global X lock. */ - virtual void commitAndStopDurThread() = 0; + virtual void commitAndStopDurThread(OperationContext* txn) = 0; /** * Commits pending changes, flushes all changes to main data files, then removes the diff --git a/src/mongo/db/storage/mmap_v1/dur_journal_writer.cpp b/src/mongo/db/storage/mmap_v1/dur_journal_writer.cpp index 4eb0b4ea16b..5c9fe117d52 100644 --- a/src/mongo/db/storage/mmap_v1/dur_journal_writer.cpp +++ b/src/mongo/db/storage/mmap_v1/dur_journal_writer.cpp @@ -56,12 +56,14 @@ namespace { * (2) TODO should we do this using N threads? Would be quite easy see Hackenberg paper table * 5 and 6. 2 threads might be a good balance. */ -void WRITETODATAFILES(const JSectHeader& h, const AlignedBuilder& uncompressed) { +void WRITETODATAFILES(OperationContext* txn, + const JSectHeader& h, + const AlignedBuilder& uncompressed) { Timer t; LOG(4) << "WRITETODATAFILES BEGIN"; - RecoveryJob::get().processSection(&h, uncompressed.buf(), uncompressed.len(), NULL); + RecoveryJob::get().processSection(txn, &h, uncompressed.buf(), uncompressed.len(), NULL); const long long m = t.micros(); stats.curr()->_writeToDataFilesMicros += m; @@ -244,7 +246,7 @@ void JournalWriter::_journalWriterThread() { // Apply the journal entries on top of the shared view so that when flush is // requested it would write the latest. - WRITETODATAFILES(buffer->_header, buffer->_builder); + WRITETODATAFILES(cc().makeOperationContext().get(), buffer->_header, buffer->_builder); // Data is now persisted on the shared view, so notify any potential journal file // cleanup waiters. diff --git a/src/mongo/db/storage/mmap_v1/dur_recover.cpp b/src/mongo/db/storage/mmap_v1/dur_recover.cpp index ec6b945455e..cdd3d4e3db2 100644 --- a/src/mongo/db/storage/mmap_v1/dur_recover.cpp +++ b/src/mongo/db/storage/mmap_v1/dur_recover.cpp @@ -58,6 +58,7 @@ #include "mongo/util/hex.h" #include "mongo/util/log.h" #include "mongo/util/mongoutils/str.h" +#include "mongo/util/scopeguard.h" #include "mongo/util/startup_test.h" namespace mongo { @@ -264,22 +265,26 @@ RecoveryJob::RecoveryJob() _appliedAnySections(false) {} RecoveryJob::~RecoveryJob() { - DESTRUCTOR_GUARD(if (!_mmfs.empty()) {} close();) + invariant(!"RecoveryJob is intentionally leaked with a bare call to operator new()"); } -void RecoveryJob::close() { +void RecoveryJob::close(OperationContext* txn) { stdx::lock_guard<stdx::mutex> lk(_mx); - _close(); + _close(txn); } -void RecoveryJob::_close() { - MongoFile::flushAll(true); +void RecoveryJob::_close(OperationContext* txn) { + MongoFile::flushAll(txn, true); + LockMongoFilesExclusive lock(txn); + for (auto& durFile : _mmfs) { + durFile->close(txn); + } _mmfs.clear(); } -RecoveryJob::Last::Last() : mmf(NULL), fileNo(-1) { +RecoveryJob::Last::Last(OperationContext* txn) : _txn(txn), mmf(NULL), fileNo(-1) { // Make sure the files list does not change from underneath - LockMongoFilesShared::assertAtLeastReadLocked(); + LockMongoFilesShared::assertAtLeastReadLocked(txn); } DurableMappedFile* RecoveryJob::Last::newEntry(const dur::ParsedJournalEntry& entry, @@ -291,7 +296,7 @@ DurableMappedFile* RecoveryJob::Last::newEntry(const dur::ParsedJournalEntry& en string fn = fileName(entry.dbName, num); MongoFile* file; { - MongoFileFinder finder; // must release lock before creating new DurableMappedFile + MongoFileFinder finder(_txn); // must release lock before creating new DurableMappedFile file = finder.findByPath(fn); } @@ -303,8 +308,8 @@ DurableMappedFile* RecoveryJob::Last::newEntry(const dur::ParsedJournalEntry& en log() << "journal error applying writes, file " << fn << " is not open" << endl; verify(false); } - std::shared_ptr<DurableMappedFile> sp(new DurableMappedFile); - verify(sp->open(fn)); + std::shared_ptr<DurableMappedFile> sp(new DurableMappedFile(_txn)); + verify(sp->open(_txn, fn)); rj._mmfs.push_back(sp); mmf = sp.get(); } @@ -358,14 +363,14 @@ void RecoveryJob::applyEntry(Last& last, const ParsedJournalEntry& entry, bool a } if (apply) { if (entry.op->needFilesClosed()) { - _close(); // locked in processSection + _close(last.txn()); // locked in processSection } entry.op->replay(); } } } -void RecoveryJob::applyEntries(const vector<ParsedJournalEntry>& entries) { +void RecoveryJob::applyEntries(OperationContext* txn, const vector<ParsedJournalEntry>& entries) { const bool apply = (mmapv1GlobalOptions.journalOptions & MMAPV1Options::JournalScanOnly) == 0; const bool dump = (mmapv1GlobalOptions.journalOptions & MMAPV1Options::JournalDumpJournal); @@ -373,7 +378,7 @@ void RecoveryJob::applyEntries(const vector<ParsedJournalEntry>& entries) { log() << "BEGIN section" << endl; } - Last last; + Last last(txn); for (vector<ParsedJournalEntry>::const_iterator i = entries.begin(); i != entries.end(); ++i) { applyEntry(last, *i, apply, dump); } @@ -383,11 +388,12 @@ void RecoveryJob::applyEntries(const vector<ParsedJournalEntry>& entries) { } } -void RecoveryJob::processSection(const JSectHeader* h, +void RecoveryJob::processSection(OperationContext* txn, + const JSectHeader* h, const void* p, unsigned len, const JSectFooter* f) { - LockMongoFilesShared lkFiles; // for RecoveryJob::Last + LockMongoFilesShared lkFiles(txn); // for RecoveryJob::Last stdx::lock_guard<stdx::mutex> lk(_mx); if (_recovering) { @@ -461,14 +467,14 @@ void RecoveryJob::processSection(const JSectHeader* h, } // got all the entries for one group commit. apply them: - applyEntries(entries); + applyEntries(txn, entries); } /** apply a specific journal file, that is already mmap'd @param p start of the memory mapped file @return true if this is detected to be the last file (ends abruptly) */ -bool RecoveryJob::processFileBuffer(const void* p, unsigned len) { +bool RecoveryJob::processFileBuffer(OperationContext* txn, const void* p, unsigned len) { try { unsigned long long fileId; BufReader br(p, len); @@ -523,7 +529,7 @@ bool RecoveryJob::processFileBuffer(const void* p, unsigned len) { const char* hdr = (const char*)br.skip(h.sectionLenWithPadding()); const char* data = hdr + sizeof(JSectHeader); const char* footer = data + dataLen; - processSection((const JSectHeader*)hdr, data, dataLen, (const JSectFooter*)footer); + processSection(txn, (const JSectHeader*)hdr, data, dataLen, (const JSectFooter*)footer); // ctrl c check uassert(ErrorCodes::Interrupted, @@ -544,7 +550,7 @@ bool RecoveryJob::processFileBuffer(const void* p, unsigned len) { } /** apply a specific journal file */ -bool RecoveryJob::processFile(boost::filesystem::path journalfile) { +bool RecoveryJob::processFile(OperationContext* txn, boost::filesystem::path journalfile) { log() << "recover " << journalfile.string() << endl; try { @@ -558,16 +564,20 @@ bool RecoveryJob::processFile(boost::filesystem::path journalfile) { log() << "recover exception checking filesize" << endl; } - MemoryMappedFile f{MongoFile::Options::READONLY | MongoFile::Options::SEQUENTIAL}; - void* p = f.map(journalfile.string().c_str()); + MemoryMappedFile f{txn, MongoFile::Options::READONLY | MongoFile::Options::SEQUENTIAL}; + ON_BLOCK_EXIT([&f, &txn] { + LockMongoFilesExclusive lock(txn); + f.close(txn); + }); + void* p = f.map(txn, journalfile.string().c_str()); massert(13544, str::stream() << "recover error couldn't open " << journalfile.string(), p); - return processFileBuffer(p, (unsigned)f.length()); + return processFileBuffer(txn, p, (unsigned)f.length()); } /** @param files all the j._0 style files we need to apply for recovery */ -void RecoveryJob::go(vector<boost::filesystem::path>& files) { +void RecoveryJob::go(OperationContext* txn, vector<boost::filesystem::path>& files) { log() << "recover begin" << endl; - LockMongoFilesExclusive lkFiles; // for RecoveryJob::Last + LockMongoFilesExclusive lkFiles(txn); // for RecoveryJob::Last _recovering = true; // load the last sequence number synced to the datafiles on disk before the last crash @@ -575,11 +585,11 @@ void RecoveryJob::go(vector<boost::filesystem::path>& files) { log() << "recover lsn: " << _lastDataSyncedFromLastRun << endl; for (unsigned i = 0; i != files.size(); ++i) { - bool abruptEnd = processFile(files[i]); + bool abruptEnd = processFile(txn, files[i]); if (abruptEnd && i + 1 < files.size()) { log() << "recover error: abrupt end to file " << files[i].string() << ", yet it isn't the last journal file" << endl; - close(); + close(txn); uasserted(13535, "recover abrupt journal file end"); } } @@ -590,7 +600,7 @@ void RecoveryJob::go(vector<boost::filesystem::path>& files) { << "Last skipped sections had sequence number " << _lastSeqSkipped; } - close(); + close(txn); if (mmapv1GlobalOptions.journalOptions & MMAPV1Options::JournalScanOnly) { uasserted(13545, @@ -605,7 +615,7 @@ void RecoveryJob::go(vector<boost::filesystem::path>& files) { _recovering = false; } -void _recover() { +void _recover(OperationContext* txn) { verify(storageGlobalParams.dur); boost::filesystem::path p = getJournalDir(); @@ -625,7 +635,7 @@ void _recover() { return; } - RecoveryJob::get().go(journalFiles); + RecoveryJob::get().go(txn, journalFiles); } /** recover from a crash @@ -635,18 +645,18 @@ void _recover() { void replayJournalFilesAtStartup() { // we use a lock so that exitCleanly will wait for us // to finish (or at least to notice what is up and stop) - const ServiceContext::UniqueOperationContext txnPtr = cc().makeOperationContext(); - OperationContext& txn = *txnPtr; - ScopedTransaction transaction(&txn, MODE_X); - Lock::GlobalWrite lk(txn.lockState()); + auto txn = cc().makeOperationContext(); + ScopedTransaction transaction(txn.get(), MODE_X); + Lock::GlobalWrite lk(txn->lockState()); - _recover(); // throws on interruption + _recover(txn.get()); // throws on interruption } struct BufReaderY { int a, b; }; class BufReaderUnitTest : public StartupTest { + public: void run() { BufReader r((void*)"abcdabcdabcd", 12); diff --git a/src/mongo/db/storage/mmap_v1/dur_recover.h b/src/mongo/db/storage/mmap_v1/dur_recover.h index b9b7c5ddfdb..9447044b607 100644 --- a/src/mongo/db/storage/mmap_v1/dur_recover.h +++ b/src/mongo/db/storage/mmap_v1/dur_recover.h @@ -34,6 +34,7 @@ #include <list> #include <memory> +#include "mongo/db/service_context.h" #include "mongo/db/storage/mmap_v1/dur_journalformat.h" #include "mongo/stdx/mutex.h" #include "mongo/util/concurrency/mutex.h" @@ -55,13 +56,17 @@ public: RecoveryJob(); ~RecoveryJob(); - void go(std::vector<boost::filesystem::path>& files); + void go(OperationContext* txn, std::vector<boost::filesystem::path>& files); /** @param data data between header and footer. compressed if recovering. */ - void processSection(const JSectHeader* h, const void* data, unsigned len, const JSectFooter* f); + void processSection(OperationContext* txn, + const JSectHeader* h, + const void* data, + unsigned len, + const JSectFooter* f); // locks and calls _close() - void close(); + void close(OperationContext* txn); static RecoveryJob& get() { return _instance; @@ -70,10 +75,16 @@ public: private: class Last { public: - Last(); + Last(OperationContext* txn); + DurableMappedFile* newEntry(const ParsedJournalEntry&, RecoveryJob&); + OperationContext* txn() { + return _txn; + } + private: + OperationContext* _txn; DurableMappedFile* mmf; std::string dbName; int fileNo; @@ -82,11 +93,10 @@ private: void write(Last& last, const ParsedJournalEntry& entry); // actually writes to the file void applyEntry(Last& last, const ParsedJournalEntry& entry, bool apply, bool dump); - void applyEntries(const std::vector<ParsedJournalEntry>& entries); - bool processFileBuffer(const void*, unsigned len); - bool processFile(boost::filesystem::path journalfile); - void _close(); // doesn't lock - + void applyEntries(OperationContext* txn, const std::vector<ParsedJournalEntry>& entries); + bool processFileBuffer(OperationContext* txn, const void*, unsigned len); + bool processFile(OperationContext* txn, boost::filesystem::path journalfile); + void _close(OperationContext* txn); // doesn't lock // Set of memory mapped files and a mutex to protect them stdx::mutex _mx; diff --git a/src/mongo/db/storage/mmap_v1/durable_mapped_file.cpp b/src/mongo/db/storage/mmap_v1/durable_mapped_file.cpp index a7e8e2e429f..548cb8c9f05 100644 --- a/src/mongo/db/storage/mmap_v1/durable_mapped_file.cpp +++ b/src/mongo/db/storage/mmap_v1/durable_mapped_file.cpp @@ -61,7 +61,7 @@ using std::map; using std::pair; using std::string; -void DurableMappedFile::remapThePrivateView() { +void DurableMappedFile::remapThePrivateView(OperationContext* txn) { verify(storageGlobalParams.dur); _willNeedRemap = false; @@ -70,7 +70,7 @@ void DurableMappedFile::remapThePrivateView() { // so the remove / add isn't necessary and can be removed? void* old = _view_private; // privateViews.remove(_view_private); - _view_private = remapPrivateView(_view_private); + _view_private = remapPrivateView(txn, _view_private); // privateViews.add(_view_private, this); fassert(16112, _view_private == old); } @@ -241,22 +241,24 @@ void DurableMappedFile::setPath(const std::string& f) { _p = RelativePath::fromFullPath(storageGlobalParams.dbpath, prefix); } -bool DurableMappedFile::open(const std::string& fname) { +bool DurableMappedFile::open(OperationContext* txn, const std::string& fname) { LOG(3) << "mmf open " << fname; invariant(!_view_write); setPath(fname); - _view_write = map(fname.c_str()); + _view_write = map(txn, fname.c_str()); fassert(16333, _view_write); return finishOpening(); } -bool DurableMappedFile::create(const std::string& fname, unsigned long long& len) { +bool DurableMappedFile::create(OperationContext* txn, + const std::string& fname, + unsigned long long& len) { LOG(3) << "mmf create " << fname; invariant(!_view_write); setPath(fname); - _view_write = map(fname.c_str(), len); + _view_write = map(txn, fname.c_str(), len); fassert(16332, _view_write); return finishOpening(); } @@ -283,12 +285,7 @@ bool DurableMappedFile::finishOpening() { return false; } -DurableMappedFile::DurableMappedFile(OptionSet options) - : MemoryMappedFile(options), _willNeedRemap(false) { - _view_write = _view_private = 0; -} - -DurableMappedFile::~DurableMappedFile() { +void DurableMappedFile::close(OperationContext* txn) { try { LOG(3) << "mmf close " << filename(); @@ -299,12 +296,20 @@ DurableMappedFile::~DurableMappedFile() { getDur().closingFileNotification(); } - LockMongoFilesExclusive lk; privateViews.remove(_view_private, length()); - MemoryMappedFile::close(); + MemoryMappedFile::close(txn); } catch (...) { - error() << "exception in ~DurableMappedFile"; + error() << "exception in DurableMappedFile::close"; } } + +DurableMappedFile::DurableMappedFile(OperationContext* txn, OptionSet options) + : MemoryMappedFile(txn, options), _willNeedRemap(false) { + _view_write = _view_private = 0; +} + +DurableMappedFile::~DurableMappedFile() { + invariant(isClosed()); +} } diff --git a/src/mongo/db/storage/mmap_v1/durable_mapped_file.h b/src/mongo/db/storage/mmap_v1/durable_mapped_file.h index 3175fa8fa73..7c6e99bfc7e 100644 --- a/src/mongo/db/storage/mmap_v1/durable_mapped_file.h +++ b/src/mongo/db/storage/mmap_v1/durable_mapped_file.h @@ -32,6 +32,7 @@ #pragma once #include "mongo/base/static_assert.h" +#include "mongo/db/operation_context.h" #include "mongo/db/storage/mmap_v1/mmap.h" #include "mongo/db/storage/paths.h" #include "mongo/stdx/mutex.h" @@ -50,11 +51,16 @@ protected: } public: - DurableMappedFile(OptionSet options = NONE); + explicit DurableMappedFile(OperationContext* txn, OptionSet options = NONE); virtual ~DurableMappedFile(); + /** + * Callers must be holding a `LockMongoFilesExclusive`. + */ + virtual void close(OperationContext* txn); + /** @return true if opened ok. */ - bool open(const std::string& fname); + bool open(OperationContext* txn, const std::string& fname); /** @return file length */ unsigned long long length() const { @@ -73,7 +79,7 @@ public: passed length. @return true for ok */ - bool create(const std::string& fname, unsigned long long& len); + bool create(OperationContext* txn, const std::string& fname, unsigned long long& len); /* Get the "standard" view (which is the private one). @return the private view. @@ -117,7 +123,7 @@ public: _willNeedRemap = true; } - void remapThePrivateView(); + void remapThePrivateView(OperationContext* txn); virtual bool isDurableMappedFile() { return true; diff --git a/src/mongo/db/storage/mmap_v1/extent_manager.h b/src/mongo/db/storage/mmap_v1/extent_manager.h index 4ce623ffc8a..1ca0ab7b9f1 100644 --- a/src/mongo/db/storage/mmap_v1/extent_manager.h +++ b/src/mongo/db/storage/mmap_v1/extent_manager.h @@ -77,6 +77,8 @@ public: virtual ~ExtentManager() {} + virtual void close(OperationContext* txn) = 0; + /** * opens all current files */ diff --git a/src/mongo/db/storage/mmap_v1/mmap.cpp b/src/mongo/db/storage/mmap_v1/mmap.cpp index c8eaacd2f63..bdce2bd6468 100644 --- a/src/mongo/db/storage/mmap_v1/mmap.cpp +++ b/src/mongo/db/storage/mmap_v1/mmap.cpp @@ -36,8 +36,10 @@ #include <boost/filesystem/operations.hpp> #include "mongo/base/owned_pointer_vector.h" +#include "mongo/db/client.h" +#include "mongo/db/concurrency/locker.h" +#include "mongo/db/operation_context.h" #include "mongo/db/storage/storage_options.h" -#include "mongo/util/concurrency/rwlock.h" #include "mongo/util/log.h" #include "mongo/util/map_util.h" #include "mongo/util/mongoutils/str.h" @@ -67,16 +69,33 @@ map<string, MongoFile*> pathToFile; mongo::AtomicUInt64 mmfNextId(0); } // namespace -MemoryMappedFile::MemoryMappedFile(OptionSet options) +MemoryMappedFile::MemoryMappedFile(OperationContext* txn, OptionSet options) : MongoFile(options), _uniqueId(mmfNextId.fetchAndAdd(1)) { - created(); + created(txn); } -void* MemoryMappedFile::create(const std::string& filename, unsigned long long len, bool zero) { +MemoryMappedFile::~MemoryMappedFile() { + invariant(isClosed()); + + auto txn = cc().getOperationContext(); + invariant(txn); + + LockMongoFilesShared lock(txn); + for (std::set<MongoFile*>::const_iterator it = mmfiles.begin(); it != mmfiles.end(); it++) { + invariant(*it != this); + } +} + +/*static*/ AtomicUInt64 MemoryMappedFile::totalMappedLength; + +void* MemoryMappedFile::create(OperationContext* txn, + const std::string& filename, + unsigned long long len, + bool zero) { uassert(13468, string("can't create file already exists ") + filename, !boost::filesystem::exists(filename)); - void* p = map(filename.c_str(), len); + void* p = map(txn, filename.c_str(), len); fassert(16331, p); if (zero) { size_t sz = (size_t)len; @@ -94,7 +113,7 @@ void* MemoryMappedFile::create(const std::string& filename, unsigned long long l length = l; } -void* MemoryMappedFile::map(const char* filename) { +void* MemoryMappedFile::map(OperationContext* txn, const char* filename) { unsigned long long l; try { l = boost::filesystem::file_size(filename); @@ -106,7 +125,7 @@ void* MemoryMappedFile::map(const char* filename) { << e.what()); } - void* ret = map(filename, l); + void* ret = map(txn, filename, l); fassert(16334, ret); return ret; } @@ -119,7 +138,7 @@ MongoFile::MongoFile(OptionSet options) : _options(storageGlobalParams.readOnly ? (options | READONLY) : options) {} -RWLockRecursiveNongreedy LockMongoFilesShared::mmmutex("mmmutex", 10 * 60 * 1000 /* 10 minutes */); +Lock::ResourceMutex LockMongoFilesShared::mmmutex("MMapMutex"); unsigned LockMongoFilesShared::era = 99; // note this rolls over set<MongoFile*>& MongoFile::getAllFiles() { @@ -131,14 +150,14 @@ set<MongoFile*>& MongoFile::getAllFiles() { safe to call more than once, albeit might be wasted work ideal to call close to the close, if the close is well before object destruction */ -void MongoFile::destroyed() { - LockMongoFilesShared::assertExclusivelyLocked(); +void MongoFile::destroyed(OperationContext* txn) { + LockMongoFilesShared::assertExclusivelyLocked(txn); mmfiles.erase(this); pathToFile.erase(filename()); } /*static*/ -void MongoFile::closeAllFiles(stringstream& message) { +void MongoFile::closeAllFiles(OperationContext* txn, stringstream& message) { static int closingAllFiles = 0; if (closingAllFiles) { message << "warning closingAllFiles=" << closingAllFiles << endl; @@ -146,37 +165,26 @@ void MongoFile::closeAllFiles(stringstream& message) { } ++closingAllFiles; - LockMongoFilesExclusive lk; + LockMongoFilesExclusive lk(txn); ProgressMeter pm(mmfiles.size(), 2, 1, "files", "File Closing Progress"); set<MongoFile*> temp = mmfiles; for (set<MongoFile*>::iterator i = temp.begin(); i != temp.end(); i++) { - (*i)->close(); // close() now removes from mmfiles + (*i)->close(txn); // close() now removes from mmfiles pm.hit(); } message << "closeAllFiles() finished"; --closingAllFiles; } -/*static*/ long long MongoFile::totalMappedLength() { - unsigned long long total = 0; - - LockMongoFilesShared lk; - - for (set<MongoFile*>::iterator i = mmfiles.begin(); i != mmfiles.end(); i++) - total += (*i)->length(); - - return total; -} - -/*static*/ int MongoFile::flushAll(bool sync) { - return _flushAll(sync); +/*static*/ int MongoFile::flushAll(OperationContext* txn, bool sync) { + return _flushAll(txn, sync); } -/*static*/ int MongoFile::_flushAll(bool sync) { +/*static*/ int MongoFile::_flushAll(OperationContext* txn, bool sync) { if (!sync) { int num = 0; - LockMongoFilesShared lk; + LockMongoFilesShared lk(txn); for (set<MongoFile*>::iterator i = mmfiles.begin(); i != mmfiles.end(); i++) { num++; MongoFile* mmf = *i; @@ -196,7 +204,7 @@ void MongoFile::closeAllFiles(stringstream& message) { OwnedPointerVector<Flushable> thingsToFlushWrapper; vector<Flushable*>& thingsToFlush = thingsToFlushWrapper.mutableVector(); { - LockMongoFilesShared lk; + LockMongoFilesShared lk(txn); for (set<MongoFile*>::iterator i = mmfiles.begin(); i != mmfiles.end(); i++) { MongoFile* mmf = *i; if (!mmf) @@ -206,22 +214,22 @@ void MongoFile::closeAllFiles(stringstream& message) { } for (size_t i = 0; i < thingsToFlush.size(); i++) { - thingsToFlush[i]->flush(); + thingsToFlush[i]->flush(txn); } return thingsToFlush.size(); } -void MongoFile::created() { +void MongoFile::created(OperationContext* txn) { // If we're a READONLY mapping, we don't want to ever flush. if (!isOptionSet(READONLY)) { - LockMongoFilesExclusive lk; + LockMongoFilesExclusive lk(txn); mmfiles.insert(this); } } -void MongoFile::setFilename(const std::string& fn) { - LockMongoFilesExclusive lk; +void MongoFile::setFilename(OperationContext* txn, const std::string& fn) { + LockMongoFilesExclusive lk(txn); verify(_filename.empty()); _filename = boost::filesystem::absolute(fn).generic_string(); MongoFile*& ptf = pathToFile[_filename]; @@ -235,23 +243,6 @@ MongoFile* MongoFileFinder::findByPath(const std::string& path) const { static_cast<MongoFile*>(NULL)); } - -void printMemInfo(const char* where) { - LogstreamBuilder out = log(); - out << "mem info: "; - if (where) - out << where << " "; - - ProcessInfo pi; - if (!pi.supported()) { - out << " not supported"; - return; - } - - out << "vsize: " << pi.getVirtualMemorySize() << " resident: " << pi.getResidentSize() - << " mapped: " << (MemoryMappedFile::totalMappedLength() / (1024 * 1024)); -} - void dataSyncFailedHandler() { log() << "error syncing data to disk, probably a disk error"; log() << " shutting down immediately to avoid corruption"; diff --git a/src/mongo/db/storage/mmap_v1/mmap.h b/src/mongo/db/storage/mmap_v1/mmap.h index af559c7db63..fc28d56e1d9 100644 --- a/src/mongo/db/storage/mmap_v1/mmap.h +++ b/src/mongo/db/storage/mmap_v1/mmap.h @@ -33,7 +33,10 @@ #include <sstream> #include <vector> -#include "mongo/util/concurrency/rwlock.h" +#include "mongo/base/disallow_copying.h" +#include "mongo/db/client.h" +#include "mongo/db/concurrency/d_concurrency.h" +#include "mongo/db/operation_context.h" namespace mongo { @@ -62,12 +65,24 @@ private: // lock order: lock dbMutex before this if you lock both class LockMongoFilesShared { friend class LockMongoFilesExclusive; - static RWLockRecursiveNongreedy mmmutex; + static Lock::ResourceMutex mmmutex; static unsigned era; - RWLockRecursive::Shared lk; + + Lock::SharedLock lk; public: - LockMongoFilesShared() : lk(mmmutex) {} + explicit LockMongoFilesShared(OperationContext* txn) : lk(txn->lockState(), mmmutex) { + // JS worker threads may not have cc() setup, as they work on behalf of other clients + dassert(txn == cc().getOperationContext() || !cc().getOperationContext()); + } + + static void assertExclusivelyLocked(OperationContext* txn) { + invariant(mmmutex.isExclusivelyLocked(txn->lockState())); + } + + static void assertAtLeastReadLocked(OperationContext* txn) { + invariant(mmmutex.isAtLeastReadLocked(txn->lockState())); + } /** era changes anytime memory maps come and go. thus you can use this as a cheap way to check if nothing has changed since the last time you locked. Of course you must be shared locked @@ -78,20 +93,16 @@ public: static unsigned getEra() { return era; } - - static void assertExclusivelyLocked() { - mmmutex.assertExclusivelyLocked(); - } - static void assertAtLeastReadLocked() { - mmmutex.assertAtLeastReadLocked(); - } }; class LockMongoFilesExclusive { - RWLockRecursive::Exclusive lk; + Lock::ExclusiveLock lk; public: - LockMongoFilesExclusive() : lk(LockMongoFilesShared::mmmutex) { + explicit LockMongoFilesExclusive(OperationContext* txn) + : lk(txn->lockState(), LockMongoFilesShared::mmmutex) { + // JS worker threads may not have cc() setup, as they work on behalf of other clients + dassert(txn == cc().getOperationContext() || !cc().getOperationContext()); LockMongoFilesShared::era++; } }; @@ -105,7 +116,7 @@ public: class Flushable { public: virtual ~Flushable() {} - virtual void flush() = 0; + virtual void flush(OperationContext* txn) = 0; }; enum Options { @@ -124,7 +135,7 @@ public: called from within a mutex that MongoFile uses. so be careful not to deadlock. */ template <class F> - static void forEach(F fun); + static void forEach(OperationContext* txn, F fun); /** * note: you need to be in mmmutex when using this. forEach (above) handles that for you @@ -132,9 +143,8 @@ public: */ static std::set<MongoFile*>& getAllFiles(); - static int flushAll(bool sync); // returns n flushed - static long long totalMappedLength(); - static void closeAllFiles(std::stringstream& message); + static int flushAll(OperationContext* txn, bool sync); // returns n flushed + static void closeAllFiles(OperationContext* txn, std::stringstream& message); virtual bool isDurableMappedFile() { return false; @@ -143,17 +153,20 @@ public: std::string filename() const { return _filename; } - void setFilename(const std::string& fn); + void setFilename(OperationContext* txn, const std::string& fn); virtual uint64_t getUniqueId() const = 0; private: std::string _filename; - static int _flushAll(bool sync); // returns n flushed + static int _flushAll(OperationContext* txn, bool sync); // returns n flushed const OptionSet _options; protected: - virtual void close() = 0; + /** + * Implementations may assume this is called from within `LockMongoFilesExclusive`. + */ + virtual void close(OperationContext* txn) = 0; virtual void flush(bool sync) = 0; /** * returns a thread safe object that you can call flush on @@ -161,14 +174,22 @@ protected: */ virtual Flushable* prepareFlush() = 0; - void created(); /* subclass must call after create */ + /** + * Returns true iff the file is closed. + */ + virtual bool isClosed() = 0; + + void created(OperationContext* txn); /* subclass must call after create */ - /* subclass must call in destructor (or at close). - removes this from pathToFile and other maps - safe to call more than once, albeit might be wasted work - ideal to call close to the close, if the close is well before object destruction - */ - void destroyed(); + /** + * Implementations may assume this is called from within `LockMongoFilesExclusive`. + * + * subclass must call in destructor (or at close). + * removes this from pathToFile and other maps + * safe to call more than once, albeit might be wasted work + * ideal to call close to the close, if the close is well before object destruction + */ + void destroyed(OperationContext* txn); virtual unsigned long long length() const = 0; @@ -187,7 +208,7 @@ class MongoFileFinder { MONGO_DISALLOW_COPYING(MongoFileFinder); public: - MongoFileFinder() {} + MongoFileFinder(OperationContext* txn) : _lk(txn) {} /** @return The MongoFile object associated with the specified file name. If no file is open with the specified name, returns null. @@ -208,27 +229,33 @@ protected: } public: - MemoryMappedFile(OptionSet options = NONE); + MemoryMappedFile(OperationContext* txn, OptionSet options = NONE); - virtual ~MemoryMappedFile() { - LockMongoFilesExclusive lk; - close(); - } + virtual ~MemoryMappedFile(); - virtual void close(); + /** + * Callers must be holding a `LockMongoFilesExclusive`. + */ + virtual void close(OperationContext* txn); /** * uasserts if file doesn't exist. fasserts on mmap error. */ - void* map(const char* filename); + void* map(OperationContext* txn, const char* filename); /** * uasserts if file exists. fasserts on mmap error. * @param zero fill file with zeros when true */ - void* create(const std::string& filename, unsigned long long len, bool zero); + void* create(OperationContext* txn, + const std::string& filename, + unsigned long long len, + bool zero); void flush(bool sync); + + virtual bool isClosed(); + virtual Flushable* prepareFlush(); long shortLength() const { @@ -251,6 +278,10 @@ public: return _uniqueId; } + static int totalMappedLengthInMB() { + return static_cast<int>(totalMappedLength.load() / 1024 / 1024); + } + private: static void updateLength(const char* filename, unsigned long long& length); @@ -258,6 +289,7 @@ private: HANDLE maphandle = 0; std::vector<void*> views; unsigned long long len = 0u; + static AtomicUInt64 totalMappedLength; const uint64_t _uniqueId; #ifdef _WIN32 // flush Mutex @@ -275,18 +307,18 @@ protected: * Creates with length if DNE, otherwise validates input length. Returns nullptr on mmap * error. */ - void* map(const char* filename, unsigned long long& length); + void* map(OperationContext* txn, const char* filename, unsigned long long& length); /** * Close the current private view and open a new replacement. Returns nullptr on mmap error. */ - void* remapPrivateView(void* oldPrivateAddr); + void* remapPrivateView(OperationContext* txn, void* oldPrivateAddr); }; /** p is called from within a mutex that MongoFile uses. so be careful not to deadlock. */ template <class F> -inline void MongoFile::forEach(F p) { - LockMongoFilesShared lklk; +inline void MongoFile::forEach(OperationContext* txn, F p) { + LockMongoFilesShared lklk(txn); const std::set<MongoFile*>& mmfiles = MongoFile::getAllFiles(); for (std::set<MongoFile*>::const_iterator i = mmfiles.begin(); i != mmfiles.end(); i++) p(*i); diff --git a/src/mongo/db/storage/mmap_v1/mmap_posix.cpp b/src/mongo/db/storage/mmap_v1/mmap_posix.cpp index e63e74923a7..02589421b44 100644 --- a/src/mongo/db/storage/mmap_v1/mmap_posix.cpp +++ b/src/mongo/db/storage/mmap_v1/mmap_posix.cpp @@ -54,6 +54,23 @@ using namespace mongoutils; namespace mongo { + +namespace { +void printMemInfo() { + LogstreamBuilder out = log(); + out << "mem info: "; + + ProcessInfo pi; + if (!pi.supported()) { + out << " not supported"; + return; + } + + out << "vsize: " << pi.getVirtualMemorySize() << " resident: " << pi.getResidentSize() + << " mapped: " << MemoryMappedFile::totalMappedLengthInMB(); +} +} // namespace + static size_t fetchMinOSPageSizeBytes() { size_t minOSPageSizeBytes = sysconf(_SC_PAGESIZE); minOSPageSizeBytesTest(minOSPageSizeBytes); @@ -62,17 +79,19 @@ static size_t fetchMinOSPageSizeBytes() { const size_t g_minOSPageSizeBytes = fetchMinOSPageSizeBytes(); -void MemoryMappedFile::close() { - LockMongoFilesShared::assertExclusivelyLocked(); +void MemoryMappedFile::close(OperationContext* txn) { for (vector<void*>::iterator i = views.begin(); i != views.end(); i++) { munmap(*i, len); } views.clear(); + totalMappedLength.fetchAndSubtract(len); + len = 0; - if (fd) + if (fd) { ::close(fd); - fd = 0; - destroyed(); // cleans up from the master list of mmaps + fd = 0; + } + destroyed(txn); // cleans up from the master list of mmaps } #ifndef O_NOATIME @@ -140,11 +159,12 @@ MAdvise::~MAdvise() { } #endif -void* MemoryMappedFile::map(const char* filename, unsigned long long& length) { +void* MemoryMappedFile::map(OperationContext* txn, + const char* filename, + unsigned long long& length) { // length may be updated by callee. - setFilename(filename); + setFilename(txn, filename); FileAllocator::get()->allocateAsap(filename, length); - len = length; const bool readOnly = isOptionSet(READONLY); @@ -193,6 +213,10 @@ void* MemoryMappedFile::map(const char* filename, unsigned long long& length) { } #endif + // MemoryMappedFile successfully created, now update state. + len = length; + MemoryMappedFile::totalMappedLength.fetchAndAdd(len); + views.push_back(view); return view; @@ -219,9 +243,9 @@ void* MemoryMappedFile::createPrivateMap() { return x; } -void* MemoryMappedFile::remapPrivateView(void* oldPrivateAddr) { +void* MemoryMappedFile::remapPrivateView(OperationContext* txn, void* oldPrivateAddr) { #if defined(__sun) // SERVER-8795 - LockMongoFilesExclusive lockMongoFiles; + LockMongoFilesExclusive lockMongoFiles(txn); #endif // don't unmap, just mmap over the old region @@ -255,12 +279,16 @@ void MemoryMappedFile::flush(bool sync) { } } +bool MemoryMappedFile::isClosed() { + return !len && !fd && !views.size(); +} + class PosixFlushable : public MemoryMappedFile::Flushable { public: PosixFlushable(MemoryMappedFile* theFile, void* view, HANDLE fd, long len) : _theFile(theFile), _view(view), _fd(fd), _len(len), _id(_theFile->getUniqueId()) {} - void flush() { + void flush(OperationContext* txn) { if (_view == NULL || _fd == 0) return; @@ -275,7 +303,7 @@ public: } // some error, lets see if we're supposed to exist - LockMongoFilesShared mmfilesLock; + LockMongoFilesShared mmfilesLock(txn); std::set<MongoFile*> mmfs = MongoFile::getAllFiles(); std::set<MongoFile*>::const_iterator it = mmfs.find(_theFile); if ((it == mmfs.end()) || ((*it)->getUniqueId() != _id)) { @@ -301,5 +329,4 @@ MemoryMappedFile::Flushable* MemoryMappedFile::prepareFlush() { return new PosixFlushable(this, viewForFlushing(), fd, len); } - } // namespace mongo diff --git a/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.cpp b/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.cpp index f27dcc935e8..69978fb4b53 100644 --- a/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.cpp +++ b/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.cpp @@ -56,6 +56,7 @@ #include "mongo/db/storage/mmap_v1/record_store_v1_simple.h" #include "mongo/db/storage/record_data.h" #include "mongo/util/log.h" +#include "mongo/util/scopeguard.h" namespace mongo { @@ -162,8 +163,12 @@ MMAPV1DatabaseCatalogEntry::MMAPV1DatabaseCatalogEntry(OperationContext* txn, std::unique_ptr<ExtentManager> extentManager) : DatabaseCatalogEntry(name), _path(path.toString()), - _namespaceIndex(_path, name.toString()), + _namespaceIndex(txn, _path, name.toString()), _extentManager(std::move(extentManager)) { + ScopeGuard onErrorClose = MakeGuard([&] { + _namespaceIndex.close(txn); + _extentManager->close(txn); + }); massert(34469, str::stream() << name << " is not a valid database name", NamespaceString::validDBName(name)); @@ -193,6 +198,8 @@ MMAPV1DatabaseCatalogEntry::MMAPV1DatabaseCatalogEntry(OperationContext* txn, warning() << "database " << path << " " << name << " could not be opened " << e.what(); throw; } + + onErrorClose.Dismiss(); } MMAPV1DatabaseCatalogEntry::~MMAPV1DatabaseCatalogEntry() { diff --git a/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.h b/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.h index 5934ded8a11..ea4342bb868 100644 --- a/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.h +++ b/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.h @@ -62,6 +62,14 @@ public: virtual ~MMAPV1DatabaseCatalogEntry(); + /** + * Must be called before destruction. + */ + virtual void close(OperationContext* txn) { + _extentManager->close(txn); + _namespaceIndex.close(txn); + } + // these two seem the same and yet different // TODO(ERH): consolidate into one ideally virtual bool exists() const { diff --git a/src/mongo/db/storage/mmap_v1/mmap_v1_engine.cpp b/src/mongo/db/storage/mmap_v1/mmap_v1_engine.cpp index e185afe03c7..36af8f3f06a 100644 --- a/src/mongo/db/storage/mmap_v1/mmap_v1_engine.cpp +++ b/src/mongo/db/storage/mmap_v1/mmap_v1_engine.cpp @@ -36,7 +36,9 @@ #include <boost/filesystem/path.hpp> #include <fstream> +#include "mongo/db/client.h" #include "mongo/db/mongod_options.h" +#include "mongo/db/operation_context.h" #include "mongo/db/storage/mmap_v1/data_file_sync.h" #include "mongo/db/storage/mmap_v1/dur.h" #include "mongo/db/storage/mmap_v1/dur_journal.h" @@ -311,6 +313,9 @@ Status MMAPV1Engine::closeDatabase(OperationContext* txn, StringData db) { stdx::lock_guard<stdx::mutex> lk(_entryMapMutex); MMAPV1DatabaseCatalogEntry* entry = _entryMap[db.toString()]; + if (entry) { + entry->close(txn); + } delete entry; _entryMap.erase(db.toString()); return Status::OK(); @@ -345,8 +350,8 @@ void MMAPV1Engine::_listDatabases(const std::string& directory, std::vector<std: } } -int MMAPV1Engine::flushAllFiles(bool sync) { - return MongoFile::flushAll(sync); +int MMAPV1Engine::flushAllFiles(OperationContext* txn, bool sync) { + return MongoFile::flushAll(txn, sync); } Status MMAPV1Engine::beginBackup(OperationContext* txn) { @@ -374,21 +379,32 @@ void MMAPV1Engine::cleanShutdown() { // we would only hang here if the file_allocator code generates a // synchronous signal, which we don't expect log() << "shutdown: waiting for fs preallocator..." << endl; + auto txn = cc().getOperationContext(); + + // In some cases we may shutdown early before we have any operation context yet, but we need + // one for synchronization purposes. + ServiceContext::UniqueOperationContext newTxn; + if (!txn) { + newTxn = cc().makeOperationContext(); + txn = newTxn.get(); + invariant(txn); + } + FileAllocator::get()->waitUntilFinished(); if (storageGlobalParams.dur) { log() << "shutdown: final commit..." << endl; - getDur().commitAndStopDurThread(); + getDur().commitAndStopDurThread(txn); } log() << "shutdown: closing all files..." << endl; stringstream ss3; - MemoryMappedFile::closeAllFiles(ss3); + MemoryMappedFile::closeAllFiles(txn, ss3); log() << ss3.str() << endl; } void MMAPV1Engine::setJournalListener(JournalListener* jl) { dur::setJournalListener(jl); } -} +} // namespace diff --git a/src/mongo/db/storage/mmap_v1/mmap_v1_engine.h b/src/mongo/db/storage/mmap_v1/mmap_v1_engine.h index 54e8594e053..b5d19950d7b 100644 --- a/src/mongo/db/storage/mmap_v1/mmap_v1_engine.h +++ b/src/mongo/db/storage/mmap_v1/mmap_v1_engine.h @@ -57,7 +57,7 @@ public: RecoveryUnit* newRecoveryUnit(); void listDatabases(std::vector<std::string>* out) const; - int flushAllFiles(bool sync); + int flushAllFiles(OperationContext* txn, bool sync); Status beginBackup(OperationContext* txn); void endBackup(OperationContext* txn); diff --git a/src/mongo/db/storage/mmap_v1/mmap_v1_extent_manager.cpp b/src/mongo/db/storage/mmap_v1/mmap_v1_extent_manager.cpp index 761fecfb075..3f9b6019802 100644 --- a/src/mongo/db/storage/mmap_v1/mmap_v1_extent_manager.cpp +++ b/src/mongo/db/storage/mmap_v1/mmap_v1_extent_manager.cpp @@ -79,9 +79,9 @@ class MmapV1RecordFetcher : public RecordFetcher { public: explicit MmapV1RecordFetcher(const MmapV1RecordHeader* record) : _record(record) {} - virtual void setup() { + virtual void setup(OperationContext* txn) { invariant(!_filesLock.get()); - _filesLock.reset(new LockMongoFilesShared()); + _filesLock.reset(new LockMongoFilesShared(txn)); } virtual void fetch() { @@ -172,10 +172,11 @@ Status MmapV1ExtentManager::init(OperationContext* txn) { } } - unique_ptr<DataFile> df(new DataFile(n)); + unique_ptr<DataFile> df(new DataFile(txn, n)); - Status s = df->openExisting(fullNameString.c_str()); + Status s = df->openExisting(txn, fullNameString.c_str()); if (!s.isOK()) { + df->close(txn); return s; } @@ -240,12 +241,17 @@ DataFile* MmapV1ExtentManager::_addAFile(OperationContext* txn, } { - unique_ptr<DataFile> allocFile(new DataFile(allocFileId)); + unique_ptr<DataFile> allocFile(new DataFile(txn, allocFileId)); const string allocFileName = _fileName(allocFileId).string(); Timer t; - allocFile->open(txn, allocFileName.c_str(), minSize, false); + try { + allocFile->open(txn, allocFileName.c_str(), minSize, false); + } catch (...) { + allocFile->close(txn); + throw; + } if (t.seconds() > 1) { log() << "MmapV1ExtentManager took " << t.seconds() << " seconds to open: " << allocFileName; @@ -257,10 +263,15 @@ DataFile* MmapV1ExtentManager::_addAFile(OperationContext* txn, // Preallocate is asynchronous if (preallocateNextFile) { - unique_ptr<DataFile> nextFile(new DataFile(allocFileId + 1)); + unique_ptr<DataFile> nextFile(new DataFile(txn, allocFileId + 1)); const string nextFileName = _fileName(allocFileId + 1).string(); - nextFile->open(txn, nextFileName.c_str(), minSize, false); + try { + nextFile->open(txn, nextFileName.c_str(), minSize, false); + } catch (...) { + nextFile->close(txn); + throw; + } } // Returns the last file added @@ -633,6 +644,12 @@ MmapV1ExtentManager::FilesArray::~FilesArray() { } } +void MmapV1ExtentManager::FilesArray::close(OperationContext* txn) { + for (int i = 0; i < size(); i++) { + _files[i]->close(txn); + } +} + void MmapV1ExtentManager::FilesArray::push_back(DataFile* val) { stdx::lock_guard<stdx::mutex> lk(_writersMutex); const int n = _size.load(); diff --git a/src/mongo/db/storage/mmap_v1/mmap_v1_extent_manager.h b/src/mongo/db/storage/mmap_v1/mmap_v1_extent_manager.h index 573396f76af..fb891ee8227 100644 --- a/src/mongo/db/storage/mmap_v1/mmap_v1_extent_manager.h +++ b/src/mongo/db/storage/mmap_v1/mmap_v1_extent_manager.h @@ -90,6 +90,13 @@ public: MmapV1ExtentManager(StringData dbname, StringData path, bool directoryPerDB); /** + * Must be called before destruction. + */ + void close(OperationContext* txn) { + _files.close(txn); + } + + /** * opens all current files, not thread safe */ Status init(OperationContext* txn); @@ -210,6 +217,11 @@ private: ~FilesArray(); /** + * Must be called before destruction. + */ + void close(OperationContext* txn); + + /** * Returns file at location 'n' in the array, with 'n' less than number of files added. * Will always return the same pointer for a given file. */ diff --git a/src/mongo/db/storage/mmap_v1/mmap_windows.cpp b/src/mongo/db/storage/mmap_v1/mmap_windows.cpp index 0922e5de7ea..d8e8d61e624 100644 --- a/src/mongo/db/storage/mmap_v1/mmap_windows.cpp +++ b/src/mongo/db/storage/mmap_v1/mmap_windows.cpp @@ -148,8 +148,8 @@ static void* getNextMemoryMappedFileLocation(unsigned long long mmfSize) { return reinterpret_cast<void*>(static_cast<uintptr_t>(thisMemoryMappedFileLocation)); } -void MemoryMappedFile::close() { - LockMongoFilesShared::assertExclusivelyLocked(); +void MemoryMappedFile::close(OperationContext* txn) { + LockMongoFilesShared::assertExclusivelyLocked(txn); // Prevent flush and close from concurrently running stdx::lock_guard<stdx::mutex> lk(_flushMutex); @@ -163,20 +163,29 @@ void MemoryMappedFile::close() { } views.clear(); + totalMappedLength.fetchAndSubtract(len); + len = 0; + if (maphandle) CloseHandle(maphandle); maphandle = 0; - if (fd) + if (fd) { CloseHandle(fd); - fd = 0; - destroyed(); // cleans up from the master list of mmaps + fd = 0; + } + + destroyed(txn); // cleans up from the master list of mmaps } -unsigned long long mapped = 0; +bool MemoryMappedFile::isClosed() { + return !len && !fd && !views.size(); +} -void* MemoryMappedFile::map(const char* filenameIn, unsigned long long& length) { +void* MemoryMappedFile::map(OperationContext* txn, + const char* filenameIn, + unsigned long long& length) { verify(fd == 0 && len == 0); // can't open more than once - setFilename(filenameIn); + setFilename(txn, filenameIn); FileAllocator::get()->allocateAsap(filenameIn, length); /* big hack here: Babble uses db names with colons. doesn't seem to work on windows. temporary * perhaps. */ @@ -222,8 +231,6 @@ void* MemoryMappedFile::map(const char* filenameIn, unsigned long long& length) } } - mapped += length; - { DWORD flProtect = readOnly ? PAGE_READONLY : PAGE_READWRITE; maphandle = CreateFileMappingW(fd, @@ -237,7 +244,8 @@ void* MemoryMappedFile::map(const char* filenameIn, unsigned long long& length) severe() << "CreateFileMappingW for " << filename << " failed with " << errnoWithDescription(dosError) << " (file size is " << length << ")" << " in MemoryMappedFile::map" << endl; - close(); + LockMongoFilesExclusive lock(txn); + close(txn); fassertFailed(16225); } } @@ -288,7 +296,8 @@ void* MemoryMappedFile::map(const char* filenameIn, unsigned long long& length) << length << ")" << " in MemoryMappedFile::map" << endl; - close(); + LockMongoFilesExclusive lock(txn); + close(txn); fassertFailed(16166); } @@ -296,8 +305,12 @@ void* MemoryMappedFile::map(const char* filenameIn, unsigned long long& length) } } - views.push_back(view); + // MemoryMappedFile successfully created, now update state. len = length; + totalMappedLength.fetchAndAdd(len); + + views.push_back(view); + return view; } @@ -346,8 +359,8 @@ void* MemoryMappedFile::createPrivateMap() { return privateMapAddress; } -void* MemoryMappedFile::remapPrivateView(void* oldPrivateAddr) { - LockMongoFilesExclusive lockMongoFiles; +void* MemoryMappedFile::remapPrivateView(OperationContext* txn, void* oldPrivateAddr) { + LockMongoFilesExclusive lockMongoFiles(txn); privateViews.clearWritableBits(oldPrivateAddr, len); @@ -393,12 +406,12 @@ public: _filename(filename), _flushMutex(flushMutex) {} - void flush() { + void flush(OperationContext* txn) { if (!_view || !_fd) return; { - LockMongoFilesShared mmfilesLock; + LockMongoFilesShared mmfilesLock(txn); std::set<MongoFile*> mmfs = MongoFile::getAllFiles(); std::set<MongoFile*>::const_iterator it = mmfs.find(_theFile); @@ -462,7 +475,9 @@ void MemoryMappedFile::flush(bool sync) { uassert(13056, "Async flushing not supported on windows", sync); if (!views.empty()) { WindowsFlushable f(this, viewForFlushing(), fd, _uniqueId, filename(), _flushMutex); - f.flush(); + auto txn = cc().getOperationContext(); + invariant(txn); + f.flush(txn); } } diff --git a/src/mongo/db/storage/mmap_v1/record_store_v1_test_help.cpp b/src/mongo/db/storage/mmap_v1/record_store_v1_test_help.cpp index 0c56ef9e6f1..6f4d3993cbe 100644 --- a/src/mongo/db/storage/mmap_v1/record_store_v1_test_help.cpp +++ b/src/mongo/db/storage/mmap_v1/record_store_v1_test_help.cpp @@ -204,6 +204,8 @@ DummyExtentManager::~DummyExtentManager() { } } +void DummyExtentManager::close(OperationContext* txn) {} + Status DummyExtentManager::init(OperationContext* txn) { return Status::OK(); } diff --git a/src/mongo/db/storage/mmap_v1/record_store_v1_test_help.h b/src/mongo/db/storage/mmap_v1/record_store_v1_test_help.h index 1f29b59334c..eac135dd24a 100644 --- a/src/mongo/db/storage/mmap_v1/record_store_v1_test_help.h +++ b/src/mongo/db/storage/mmap_v1/record_store_v1_test_help.h @@ -113,6 +113,8 @@ class DummyExtentManager : public ExtentManager { public: virtual ~DummyExtentManager(); + virtual void close(OperationContext* txn); + virtual Status init(OperationContext* txn); virtual int numFiles() const; diff --git a/src/mongo/db/storage/mmap_v1/repair_database.cpp b/src/mongo/db/storage/mmap_v1/repair_database.cpp index d82a89031d6..3ae8e9d7fdc 100644 --- a/src/mongo/db/storage/mmap_v1/repair_database.cpp +++ b/src/mongo/db/storage/mmap_v1/repair_database.cpp @@ -253,7 +253,7 @@ public: getDur().syncDataAndTruncateJournal(_txn); // need both in case journaling is disabled - MongoFile::flushAll(true); + MongoFile::flushAll(_txn, true); MONGO_ASSERT_ON_EXCEPTION(boost::filesystem::remove_all(_path)); } catch (DBException& e) { @@ -320,6 +320,7 @@ Status MMAPV1Engine::repairDatabase(OperationContext* txn, // Must call this before MMAPV1DatabaseCatalogEntry's destructor closes the DB files ON_BLOCK_EXIT(&dur::DurableInterface::syncDataAndTruncateJournal, &getDur(), txn); + ON_BLOCK_EXIT([&dbEntry, &txn] { dbEntry->close(txn); }); { dbEntry.reset(new MMAPV1DatabaseCatalogEntry( @@ -431,7 +432,7 @@ Status MMAPV1Engine::repairDatabase(OperationContext* txn, getDur().syncDataAndTruncateJournal(txn); // need both in case journaling is disabled - MongoFile::flushAll(true); + MongoFile::flushAll(txn, true); txn->checkForInterrupt(); } diff --git a/src/mongo/db/storage/record_fetcher.h b/src/mongo/db/storage/record_fetcher.h index 66c626ea4d5..e133e28bdf0 100644 --- a/src/mongo/db/storage/record_fetcher.h +++ b/src/mongo/db/storage/record_fetcher.h @@ -30,6 +30,8 @@ namespace mongo { +class OperationContext; + /** * Used for yielding while data is fetched from disk. * @@ -42,7 +44,7 @@ public: /** * Performs any setup which is needed prior to yielding locks. */ - virtual void setup() = 0; + virtual void setup(OperationContext* txn) = 0; /** * Called after locks are yielded in order to bring data into memory. diff --git a/src/mongo/db/storage/storage_engine.h b/src/mongo/db/storage/storage_engine.h index f3dc6b1bf0f..02e9c1ff7aa 100644 --- a/src/mongo/db/storage/storage_engine.h +++ b/src/mongo/db/storage/storage_engine.h @@ -207,7 +207,7 @@ public: /** * @return number of files flushed */ - virtual int flushAllFiles(bool sync) = 0; + virtual int flushAllFiles(OperationContext* txn, bool sync) = 0; /** * Transitions the storage engine into backup mode. diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.cpp index 0c3c006a6fa..682fd842aaf 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.cpp +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.cpp @@ -401,7 +401,7 @@ Status WiredTigerKVEngine::_salvageIfNeeded(const char* uri) { return wtRCToStatus(session->salvage(session, uri, NULL), "Salvage failed:"); } -int WiredTigerKVEngine::flushAllFiles(bool sync) { +int WiredTigerKVEngine::flushAllFiles(OperationContext* txn, bool sync) { LOG(1) << "WiredTigerKVEngine::flushAllFiles"; if (_ephemeral) { return 0; diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.h b/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.h index f46b677f218..8f632ef537c 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.h +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.h @@ -108,7 +108,7 @@ public: StringData ident, const RecordStore* originalRecordStore) const; - virtual int flushAllFiles(bool sync); + virtual int flushAllFiles(OperationContext* txn, bool sync); virtual Status beginBackup(OperationContext* txn); diff --git a/src/mongo/db/write_concern.cpp b/src/mongo/db/write_concern.cpp index 6886bed64ca..77a90f0e396 100644 --- a/src/mongo/db/write_concern.cpp +++ b/src/mongo/db/write_concern.cpp @@ -199,7 +199,7 @@ Status waitForWriteConcern(OperationContext* txn, case WriteConcernOptions::SyncMode::FSYNC: { StorageEngine* storageEngine = getGlobalServiceContext()->getGlobalStorageEngine(); if (!storageEngine->isDurable()) { - result->fsyncFiles = storageEngine->flushAllFiles(true); + result->fsyncFiles = storageEngine->flushAllFiles(txn, true); } else { // We only need to commit the journal if we're durable txn->recoveryUnit()->waitUntilDurable(); |