diff options
author | Kaloian Manassiev <kaloian.manassiev@mongodb.com> | 2015-01-06 16:21:02 -0500 |
---|---|---|
committer | Kaloian Manassiev <kaloian.manassiev@mongodb.com> | 2015-01-07 15:04:36 -0500 |
commit | 67c550459e416a9ec7eabe35e38c1fed9aeccb8f (patch) | |
tree | e44abef8854250ed04f6a8759f015d8f63ee3b90 /src | |
parent | 8197195ce0faee1df316b2b45649cbc61dcf3ec8 (diff) | |
download | mongo-67c550459e416a9ec7eabe35e38c1fed9aeccb8f.tar.gz |
SERVER-16711 Do not require a non-empty intent set
This allows us to not have to write a bogus write intent just so we can
keep the journaling system happy.
The change in namespace_index.cpp is preparation for splitting the
database creation work into two parts - file creation and on disk
structure initialization.
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/db/storage/mmap_v1/catalog/namespace_index.cpp | 7 | ||||
-rw-r--r-- | src/mongo/db/storage/mmap_v1/dur.cpp | 1036 | ||||
-rw-r--r-- | src/mongo/db/storage/mmap_v1/dur_commitjob.h | 3 | ||||
-rw-r--r-- | src/mongo/db/storage/mmap_v1/dur_journal.cpp | 1 | ||||
-rw-r--r-- | src/mongo/db/storage/mmap_v1/dur_preplogbuffer.cpp | 52 | ||||
-rw-r--r-- | src/mongo/db/storage/mmap_v1/durable_mapped_file.cpp | 10 | ||||
-rw-r--r-- | src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.cpp | 128 | ||||
-rw-r--r-- | src/mongo/dbtests/threadedtests.cpp | 2 |
8 files changed, 617 insertions, 622 deletions
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 c77f2154e0d..cf5011e6b2b 100644 --- a/src/mongo/db/storage/mmap_v1/catalog/namespace_index.cpp +++ b/src/mongo/db/storage/mmap_v1/catalog/namespace_index.cpp @@ -233,13 +233,6 @@ namespace mongo { invariant(len == mmapv1GlobalOptions.lenForNewNsFiles); p = _f.getView(); - - if (p) { - // we do this so the durability system isn't mad at us for - // only initiating file and not doing a write - // grep for 17388 - getDur().writingPtr( p, 5 ); // throw away - } } } diff --git a/src/mongo/db/storage/mmap_v1/dur.cpp b/src/mongo/db/storage/mmap_v1/dur.cpp index 288341ae52b..f3e69be8408 100644 --- a/src/mongo/db/storage/mmap_v1/dur.cpp +++ b/src/mongo/db/storage/mmap_v1/dur.cpp @@ -96,8 +96,6 @@ namespace mongo { namespace dur { - using boost::shared_ptr; - namespace { // Used to activate the flush thread @@ -141,642 +139,646 @@ namespace { } durSSS; -} +} // namespace + + + // Declared in dur_preplogbuffer.cpp + void PREPLOGBUFFER(JSectHeader& outHeader, AlignedBuilder& outBuffer); + void WRITETOJOURNAL(const JSectHeader& h, const AlignedBuilder& uncompressed); + void WRITETODATAFILES(const JSectHeader& h, const AlignedBuilder& uncompressed); + + // Declared in dur_journal.cpp + boost::filesystem::path getJournalDir(); + void preallocateFiles(); + + // Durability activity statistics + Stats stats; + + // Reference to the write intents tracking object + CommitJob& commitJob = *(new CommitJob()); // don't destroy + + // The durability interface to use + DurableInterface* DurableInterface::_impl = &nonDurableImpl; + + + // + // Stats + // + + void Stats::S::reset() { + memset(this, 0, sizeof(*this)); + } + + Stats::Stats() { + _a.reset(); + _b.reset(); + curr = &_a; + _intervalMicros = 3000000; + } + + Stats::S * Stats::other() { + return curr == &_a ? &_b : &_a; + } + + string Stats::S::_CSVHeader() { + return "cmts jrnMB\twrDFMB\tcIWLk\tearly\tprpLgB wrToJ\twrToDF\trmpPrVw"; + } + + string Stats::S::_asCSV() { + stringstream ss; + ss << setprecision(2) + << _commits << '\t' + << fixed << _journaledBytes / 1000000.0 << '\t' + << _writeToDataFilesBytes / 1000000.0 << '\t' + << 0 << '\t' + << 0 << '\t' + << (unsigned) (_prepLogBufferMicros/1000) << '\t' + << (unsigned) (_writeToJournalMicros/1000) << '\t' + << (unsigned) (_writeToDataFilesMicros/1000) << '\t' + << (unsigned) (_remapPrivateViewMicros/1000); + + return ss.str(); + } + + BSONObj Stats::S::_asObj() { + BSONObjBuilder b; + b << "commits" << _commits + << "journaledMB" << _journaledBytes / 1000000.0 + << "writeToDataFilesMB" << _writeToDataFilesBytes / 1000000.0 + << "compression" << _journaledBytes / (_uncompressedBytes+1.0) + << "commitsInWriteLock" << 0 + << "earlyCommits" << 0 + << "timeMs" << BSON("dt" << _dtMillis << + "prepLogBuffer" << (unsigned) (_prepLogBufferMicros/1000) << + "writeToJournal" << (unsigned) (_writeToJournalMicros/1000) << + "writeToDataFiles" << (unsigned) (_writeToDataFilesMicros/1000) << + "remapPrivateView" << (unsigned) (_remapPrivateViewMicros/1000)); + + if (mmapv1GlobalOptions.journalCommitInterval != 0) { + b << "journalCommitIntervalMs" << mmapv1GlobalOptions.journalCommitInterval; + } - // Declared in dur_preplogbuffer.cpp - void PREPLOGBUFFER(JSectHeader& outHeader, AlignedBuilder& outBuffer); - void WRITETOJOURNAL(const JSectHeader& h, const AlignedBuilder& uncompressed); - void WRITETODATAFILES(const JSectHeader& h, const AlignedBuilder& uncompressed); + return b.obj(); + } + + BSONObj Stats::asObj() { + return other()->_asObj(); + } + + void Stats::rotate() { + unsigned long long now = curTimeMicros64(); + unsigned long long dt = now - _lastRotate; + if( dt >= _intervalMicros && _intervalMicros ) { + // rotate + curr->_dtMillis = (unsigned) (dt/1000); + _lastRotate = now; + curr = other(); + curr->reset(); + } + } - // Declared in dur_journal.cpp - boost::filesystem::path getJournalDir(); - void preallocateFiles(); - // Durability activity statistics - Stats stats; + // + // DurableInterface + // - // Reference to the write intents tracking object - CommitJob& commitJob = *(new CommitJob()); // don't destroy + DurableInterface::DurableInterface() { - // The durability interface to use - DurableInterface* DurableInterface::_impl = &nonDurableImpl; + } + DurableInterface::~DurableInterface() { - // - // Stats - // + } - void Stats::S::reset() { - memset(this, 0, sizeof(*this)); - } + void DurableInterface::enableDurability() { + _impl = &durableImpl; + } - Stats::Stats() { - _a.reset(); - _b.reset(); - curr = &_a; - _intervalMicros = 3000000; - } - Stats::S * Stats::other() { - return curr == &_a ? &_b : &_a; - } + // + // NonDurableImpl + // - string Stats::S::_CSVHeader() { - return "cmts jrnMB\twrDFMB\tcIWLk\tearly\tprpLgB wrToJ\twrToDF\trmpPrVw"; - } + void* NonDurableImpl::writingPtr(void *x, unsigned len) { + return x; + } - string Stats::S::_asCSV() { - stringstream ss; - ss << - setprecision(2) << - _commits << '\t' << fixed << - _journaledBytes / 1000000.0 << '\t' << - _writeToDataFilesBytes / 1000000.0 << '\t' << - 0 << '\t' << - 0 << '\t' << - (unsigned) (_prepLogBufferMicros/1000) << '\t' << - (unsigned) (_writeToJournalMicros/1000) << '\t' << - (unsigned) (_writeToDataFilesMicros/1000) << '\t' << - (unsigned) (_remapPrivateViewMicros/1000); - return ss.str(); - } + void NonDurableImpl::declareWriteIntent(void *, unsigned) { - BSONObj Stats::S::_asObj() { - BSONObjBuilder b; - b << - "commits" << _commits << - "journaledMB" << _journaledBytes / 1000000.0 << - "writeToDataFilesMB" << _writeToDataFilesBytes / 1000000.0 << - "compression" << _journaledBytes / (_uncompressedBytes+1.0) << - "commitsInWriteLock" << 0 << - "earlyCommits" << 0 << - "timeMs" << - BSON( "dt" << _dtMillis << - "prepLogBuffer" << (unsigned) (_prepLogBufferMicros/1000) << - "writeToJournal" << (unsigned) (_writeToJournalMicros/1000) << - "writeToDataFiles" << (unsigned) (_writeToDataFilesMicros/1000) << - "remapPrivateView" << (unsigned) (_remapPrivateViewMicros/1000) - ); - if (mmapv1GlobalOptions.journalCommitInterval != 0) - b << "journalCommitIntervalMs" << mmapv1GlobalOptions.journalCommitInterval; - return b.obj(); - } + } - BSONObj Stats::asObj() { - return other()->_asObj(); - } - - void Stats::rotate() { - unsigned long long now = curTimeMicros64(); - unsigned long long dt = now - _lastRotate; - if( dt >= _intervalMicros && _intervalMicros ) { - // rotate - curr->_dtMillis = (unsigned) (dt/1000); - _lastRotate = now; - curr = other(); - curr->reset(); - } - } + bool NonDurableImpl::commitNow(OperationContext* txn) { + return false; + } + bool NonDurableImpl::commitIfNeeded() { + return false; + } - // - // DurableInterface - // - DurableInterface::DurableInterface() { + // + // DurableImpl + // - } - - DurableInterface::~DurableInterface() { - - } - - void DurableInterface::enableDurability() { - _impl = &durableImpl; - } + bool DurableImpl::commitNow(OperationContext* txn) { + NotifyAll::When when = commitJob._notify.now(); + AutoYieldFlushLockForMMAPV1Commit flushLockYield(txn->lockState()); - // - // NonDurableImpl - // + // There is always just one waiting anyways + flushRequested.notify_one(); + commitJob._notify.waitFor(when); - void* NonDurableImpl::writingPtr(void *x, unsigned len) { - return x; - } + return true; + } - void NonDurableImpl::declareWriteIntent(void *, unsigned) { + bool DurableImpl::awaitCommit() { + commitJob._notify.awaitBeyondNow(); + return true; + } - } + void DurableImpl::createdFile(const std::string& filename, unsigned long long len) { + boost::shared_ptr<DurOp> op(new FileCreatedOp(filename, len)); + commitJob.noteOp(op); + } - bool NonDurableImpl::commitNow(OperationContext* txn) { - return false; - } + void* DurableImpl::writingPtr(void* x, unsigned len) { + declareWriteIntent(x, len); + return x; + } - bool NonDurableImpl::commitIfNeeded() { + bool DurableImpl::commitIfNeeded() { + if (MONGO_likely(commitJob.bytes() < UncommittedBytesLimit)) { return false; } + // Just wake up the flush thread + flushRequested.notify_one(); + return true; + } - // - // DurableImpl - // + void DurableImpl::syncDataAndTruncateJournal(OperationContext* txn) { + invariant(txn->lockState()->isW()); - bool DurableImpl::commitNow(OperationContext* txn) { - NotifyAll::When when = commitJob._notify.now(); + commitNow(txn); + MongoFile::flushAll(true); + journalCleanup(); - AutoYieldFlushLockForMMAPV1Commit flushLockYield(txn->lockState()); + // Double check post-conditions + invariant(!haveJournalFiles()); + } - // There is always just one waiting anyways - flushRequested.notify_one(); - commitJob._notify.waitFor(when); + void DurableImpl::commitAndStopDurThread() { + NotifyAll::When when = commitJob._notify.now(); - return true; - } + // There is always just one waiting anyways + flushRequested.notify_one(); + commitJob._notify.waitFor(when); - bool DurableImpl::awaitCommit() { - commitJob._notify.awaitBeyondNow(); - return true; - } + shutdownRequested.store(1); + } - void DurableImpl::createdFile(const std::string& filename, unsigned long long len) { - shared_ptr<DurOp> op(new FileCreatedOp(filename, len)); - commitJob.noteOp(op); - } - void* DurableImpl::writingPtr(void* x, unsigned len) { - declareWriteIntent(x, len); - return x; - } - - bool DurableImpl::commitIfNeeded() { - if (MONGO_likely(commitJob.bytes() < UncommittedBytesLimit)) { - return false; - } + /** + * Diagnostic to check that the private view and the non-private view are in sync after + * applying the journal changes. This function is very slow and only runs when paranoid checks + * are enabled. + * + * Must be called under at least S flush lock to ensure that there are no concurrent writes + * happening. + */ + static void debugValidateFileMapsMatch(const DurableMappedFile* mmf) { + const unsigned char *p = (const unsigned char *)mmf->getView(); + const unsigned char *w = (const unsigned char *)mmf->view_write(); - // Just wake up the flush thread - flushRequested.notify_one(); - return true; + // Ignore pre-allocated files that are not fully created yet + if (!p || !w) { + return; } - void DurableImpl::syncDataAndTruncateJournal(OperationContext* txn) { - invariant(txn->lockState()->isW()); - - commitNow(txn); - MongoFile::flushAll(true); - journalCleanup(); - - // Double check post-conditions - invariant(!haveJournalFiles()); + if (memcmp(p, w, (unsigned)mmf->length()) == 0) { + return; } - void DurableImpl::commitAndStopDurThread() { - NotifyAll::When when = commitJob._notify.now(); + unsigned low = 0xffffffff; + unsigned high = 0; - // There is always just one waiting anyways - flushRequested.notify_one(); - commitJob._notify.waitFor(when); - - shutdownRequested.store(1); - } + log() << "DurParanoid mismatch in " << mmf->filename(); + int logged = 0; + unsigned lastMismatch = 0xffffffff; - /** - * Diagnostic to check that the private view and the non-private view are in sync after - * applying the journal changes. This function is very slow and only runs when paranoid - * checks are enabled. - * - * Must be called under at least S flush lock to ensure that there are no concurrent - * writes happening. - */ - static void debugValidateFileMapsMatch(const DurableMappedFile* mmf) { - const unsigned char *p = (const unsigned char *)mmf->getView(); - const unsigned char *w = (const unsigned char *)mmf->view_write(); - - // Ignore pre-allocated files that are not fully created yet - if (!p || !w) { - return; - } - - if (memcmp(p, w, (unsigned)mmf->length()) == 0) { - return; - } + for (unsigned i = 0; i < mmf->length(); i++) { + if (p[i] != w[i]) { - unsigned low = 0xffffffff; - unsigned high = 0; - - log() << "DurParanoid mismatch in " << mmf->filename(); - - int logged = 0; - unsigned lastMismatch = 0xffffffff; + if (lastMismatch != 0xffffffff && lastMismatch + 1 != i) { + // Separate blocks of mismatches + log() << std::endl; + } - for (unsigned i = 0; i < mmf->length(); i++) { - if (p[i] != w[i]) { + lastMismatch = i; - if (lastMismatch != 0xffffffff && lastMismatch + 1 != i) { - // Separate blocks of mismatches - log() << std::endl; + if (++logged < 60) { + if (logged == 1) { + // For .ns files to find offset in record + log() << "ofs % 628 = 0x" << hex << (i % 628) << endl; } - lastMismatch = i; - - if (++logged < 60) { - if (logged == 1) { - // For .ns files to find offset in record - log() << "ofs % 628 = 0x" << hex << (i % 628) << endl; - } - - stringstream ss; - ss << "mismatch ofs:" << hex << i - << "\tfilemap:" << setw(2) << (unsigned)w[i] - << "\tprivmap:" << setw(2) << (unsigned)p[i]; + stringstream ss; + ss << "mismatch ofs:" << hex << i + << "\tfilemap:" << setw(2) << (unsigned)w[i] + << "\tprivmap:" << setw(2) << (unsigned)p[i]; - if (p[i] > 32 && p[i] <= 126) { - ss << '\t' << p[i]; - } - - log() << ss.str() << endl; + if (p[i] > 32 && p[i] <= 126) { + ss << '\t' << p[i]; } - if (logged == 60) { - log() << "..." << endl; - } + log() << ss.str() << endl; + } - if (i < low) low = i; - if (i > high) high = i; + if (logged == 60) { + log() << "..." << endl; } + + if (i < low) low = i; + if (i > high) high = i; } + } - if (low != 0xffffffff) { - std::stringstream ss; - ss << "journal error warning views mismatch " << mmf->filename() << ' ' - << hex << low << ".." << high - << " len:" << high - low + 1; + if (low != 0xffffffff) { + std::stringstream ss; + ss << "journal error warning views mismatch " << mmf->filename() << ' ' + << hex << low << ".." << high + << " len:" << high - low + 1; - log() << ss.str() << endl; - log() << "priv loc: " << (void*)(p + low) << ' ' << endl; + log() << ss.str() << endl; + log() << "priv loc: " << (void*)(p + low) << ' ' << endl; - severe() << "Written data does not match in-memory view. Missing WriteIntent?"; - invariant(false); - } + severe() << "Written data does not match in-memory view. Missing WriteIntent?"; + invariant(false); } + } - static void _remapPrivateView(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 we hold the flush lock in X mode. For files to go away, a database needs to - // be dropped, which means acquiring the flush lock in at least IX mode. - // - // However, the record fetcher logic unfortunately operates without any locks and on - // Windows and Solaris remap is not atomic and there is a window where the record - // fetcher might get an access violation. That's why we acquire the mongo files mutex - // here in X mode and the record fetcher takes in in S-mode (see MmapV1RecordFetcher - // for more detail). - // - // See SERVER-5723 for performance improvement. - // See SERVER-5680 to see why this code is necessary on Windows. - // See SERVER-8795 to see why this code is necessary on Solaris. + /** + * Main code of the remap private view function. + */ + static void _remapPrivateView(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 + // we hold the flush lock in X mode. For files to go away, a database needs to be dropped, + // which means acquiring the flush lock in at least IX mode. + // + // However, the record fetcher logic unfortunately operates without any locks and on + // Windows and Solaris remap is not atomic and there is a window where the record fetcher + // might get an access violation. That's why we acquire the mongo files mutex here in X + // mode and the record fetcher takes in in S-mode (see MmapV1RecordFetcher for more + // detail). + // + // See SERVER-5723 for performance improvement. + // 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(__sunos__) - LockMongoFilesExclusive lk; + LockMongoFilesExclusive lk; #else - LockMongoFilesShared lk; + LockMongoFilesShared lk; #endif - std::set<MongoFile*>& files = MongoFile::getAllFiles(); + std::set<MongoFile*>& files = MongoFile::getAllFiles(); - const unsigned sz = files.size(); - if (sz == 0) { - return; - } + const unsigned sz = files.size(); + if (sz == 0) { + return; + } - unsigned ntodo = (unsigned) (sz * fraction); - if( ntodo < 1 ) ntodo = 1; - if( ntodo > sz ) ntodo = sz; + unsigned ntodo = (unsigned) (sz * fraction); + if( ntodo < 1 ) ntodo = 1; + if( ntodo > sz ) ntodo = sz; - const set<MongoFile*>::iterator b = files.begin(); - const set<MongoFile*>::iterator e = files.end(); - set<MongoFile*>::iterator i = b; + const set<MongoFile*>::iterator b = files.begin(); + const set<MongoFile*>::iterator e = files.end(); + set<MongoFile*>::iterator i = b; - // Skip to our starting position as remembered from the last remap cycle - for( unsigned x = 0; x < remapFileToStartAt; x++ ) { - i++; - if( i == e ) i = b; - } + // Skip to our starting position as remembered from the last remap cycle + for (unsigned x = 0; x < remapFileToStartAt; x++) { + i++; + if( i == e ) i = b; + } - // Mark where to start on the next cycle - const unsigned startedAt = remapFileToStartAt; - remapFileToStartAt = (remapFileToStartAt + ntodo) % sz; + // Mark where to start on the next cycle + const unsigned startedAt = remapFileToStartAt; + remapFileToStartAt = (remapFileToStartAt + ntodo) % sz; - Timer t; + Timer t; - for( unsigned x = 0; x < ntodo; x++ ) { - dassert( i != e ); - if ((*i)->isDurableMappedFile()) { - DurableMappedFile *mmf = (DurableMappedFile*) *i; + for (unsigned x = 0; x < ntodo; x++) { + if ((*i)->isDurableMappedFile()) { + DurableMappedFile* const mmf = (DurableMappedFile*) *i; - // Sanity check that the contents of the shared and the private view match so - // we don't end up overwriting data. - if (mmapv1GlobalOptions.journalOptions & MMAPV1Options::JournalParanoid) { - debugValidateFileMapsMatch(mmf); - } + // Sanity check that the contents of the shared and the private view match so we + // don't end up overwriting data. + if (mmapv1GlobalOptions.journalOptions & MMAPV1Options::JournalParanoid) { + debugValidateFileMapsMatch(mmf); + } - if (mmf->willNeedRemap()) { - mmf->remapThePrivateView(); - } + if (mmf->willNeedRemap()) { + mmf->remapThePrivateView(); + } - i++; + i++; - if( i == e ) i = b; - } + if( i == e ) i = b; } - - LOG(3) << "journal REMAPPRIVATEVIEW done startedAt: " << startedAt << " n:" << ntodo - << ' ' << t.millis() << "ms"; } + LOG(3) << "journal REMAPPRIVATEVIEW done startedAt: " << startedAt << " n:" << ntodo + << ' ' << t.millis() << "ms"; + } - /** - * Remaps the private view from the shared view so that it does not consume too much - * copy-on-write/swap space. Must only be called after the in-memory journal has been - * flushed to disk and applied on top of the shared view. - * - * @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) { - // Remapping private views must occur after WRITETODATAFILES otherwise we wouldn't see - // any newly written data on reads. - invariant(!commitJob.hasWritten()); - try { - Timer t; - _remapPrivateView(fraction); - stats.curr->_remapPrivateViewMicros += t.micros(); + /** + * Remaps the private view from the shared view so that it does not consume too much + * copy-on-write/swap space. Must only be called after the in-memory journal has been flushed + * to disk and applied on top of the shared view. + * + * @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) { + // Remapping private views must occur after WRITETODATAFILES otherwise we wouldn't see any + // newly written data on reads. + invariant(!commitJob.hasWritten()); - LOG(4) << "remapPrivateView end"; - return; - } - catch (DBException& e) { - severe() << "dbexception in remapPrivateView causing immediate shutdown: " - << e.toString(); - } - catch (std::ios_base::failure& e) { - severe() << "ios_base exception in remapPrivateView causing immediate shutdown: " - << e.what(); - } - catch (std::bad_alloc& e) { - severe() << "bad_alloc exception in remapPrivateView causing immediate shutdown: " - << e.what(); - } - catch (std::exception& e) { - severe() << "exception in remapPrivateView causing immediate shutdown: " - << e.what(); - } - catch (...) { - severe() << "unknown exception in remapPrivateView causing immediate shutdown: "; - } + try { + Timer t; + _remapPrivateView(fraction); + stats.curr->_remapPrivateViewMicros += t.micros(); - invariant(false); + LOG(4) << "remapPrivateView end"; + return; + } + catch (DBException& e) { + severe() << "dbexception in remapPrivateView causing immediate shutdown: " + << e.toString(); + } + catch (std::ios_base::failure& e) { + severe() << "ios_base exception in remapPrivateView causing immediate shutdown: " + << e.what(); + } + catch (std::bad_alloc& e) { + severe() << "bad_alloc exception in remapPrivateView causing immediate shutdown: " + << e.what(); + } + catch (std::exception& e) { + severe() << "exception in remapPrivateView causing immediate shutdown: " + << e.what(); + } + catch (...) { + severe() << "unknown exception in remapPrivateView causing immediate shutdown: "; } + invariant(false); + } - /** - * Called when a DurableMappedFile is closing and must only happen under a global lock (at - * least R, so that no writes can happen). Asserts that there are no unwritten changes, - * because that would mean journal replay on recovery would try to write to non-existent - * files and fail. - */ - void closingFileNotification() { - if (commitJob.hasWritten()) { - severe() << "journal warning files are closing outside locks with writes pending"; - // File is closing while there are unwritten changes - invariant(false); - } + /** + * The main durability thread loop. There is a single instance of this function running. + */ + static void durThread() { + Client::initThread("journal"); + + bool samePartition = true; + try { + const std::string dbpathDir = + boost::filesystem::path(storageGlobalParams.dbpath).string(); + samePartition = onSamePartition(getJournalDir().string(), dbpathDir); } + catch(...) { + } - static void durThread() { - Client::initThread("journal"); + // Pre-allocated buffer for building the journal + AlignedBuilder journalBuilder(4 * 1024 * 1024); - bool samePartition = true; - try { - const std::string dbpathDir = - boost::filesystem::path(storageGlobalParams.dbpath).string(); - samePartition = onSamePartition(getJournalDir().string(), dbpathDir); - } - catch(...) { + // Used as an estimate of how much / how fast to remap + uint64_t commitCounter(0); + uint64_t estimatedPrivateMapSize(0); + uint64_t remapLastTimestamp(0); + while (shutdownRequested.loadRelaxed() == 0) { + unsigned ms = mmapv1GlobalOptions.journalCommitInterval; + if (ms == 0) { + ms = samePartition ? 100 : 30; } - // Pre-allocated buffer for building the journal - AlignedBuilder journalBuilder(4 * 1024 * 1024); - - // Used as an estimate of how much / how fast to remap - uint64_t commitCounter(0); - uint64_t estimatedPrivateMapSize(0); - uint64_t remapLastTimestamp(0); + // +1 so it never goes down to zero + const unsigned oneThird = (ms / 3) + 1; - while (shutdownRequested.loadRelaxed() == 0) { - unsigned ms = mmapv1GlobalOptions.journalCommitInterval; - if( ms == 0 ) { - ms = samePartition ? 100 : 30; - } - - unsigned oneThird = (ms / 3) + 1; // +1 so never zero - - stats.rotate(); + stats.rotate(); - try { - boost::mutex::scoped_lock lock(flushMutex); + try { + boost::mutex::scoped_lock lock(flushMutex); - for (unsigned i = 0; i <= 2; i++) { - if (flushRequested.timed_wait(lock, Milliseconds(oneThird))) { - // Someone forced a flush - break; - } + for (unsigned i = 0; i <= 2; i++) { + if (flushRequested.timed_wait(lock, Milliseconds(oneThird))) { + // Someone forced a flush + break; + } - if (commitJob._notify.nWaiting()) { - // One or more getLastError j:true is pending - break; - } + if (commitJob._notify.nWaiting()) { + // One or more getLastError j:true is pending + break; + } - if (commitJob.bytes() > UncommittedBytesLimit / 2) { - // The number of written bytes is growing - break; - } + if (commitJob.bytes() > UncommittedBytesLimit / 2) { + // The number of written bytes is growing + break; } + } - // The commit logic itself - LOG(4) << "groupCommit begin"; + // The commit logic itself + LOG(4) << "groupCommit begin"; - OperationContextImpl txn; - AutoAcquireFlushLockForMMAPV1Commit autoFlushLock(txn.lockState()); + OperationContextImpl txn; + AutoAcquireFlushLockForMMAPV1Commit autoFlushLock(txn.lockState()); - commitJob.commitingBegin(); + commitJob.commitingBegin(); - if (!commitJob.hasWritten()) { - // getlasterror request could have came after the data was already - // committed. No need to call committingReset though, because we have not - // done any writes (hasWritten == false). - commitJob.committingNotifyCommitted(); - } - else { - JSectHeader h; - PREPLOGBUFFER(h, journalBuilder); - - estimatedPrivateMapSize += commitJob.bytes(); - commitCounter++; - - // Need to reset the commit job's contents while under the S flush lock, - // because otherwise someone might have done a write and this would wipe - // out their changes without ever being committed. - commitJob.committingReset(); - - const bool shouldRemap = - (estimatedPrivateMapSize >= UncommittedBytesLimit) || - (commitCounter % NumCommitsBeforeRemap == 0) || - (mmapv1GlobalOptions.journalOptions & - MMAPV1Options::JournalAlwaysRemap); - - double remapFraction = 0.0; - - // Now that the in-memory modifications have been collected, we can - // potentially release the flush lock if remap is not necessary. - if (shouldRemap) { - // We want to remap all private views about every 2 seconds. There - // could be ~1000 views so we do a little each pass. There will be copy - // on write faults after remapping, so doing a little bit at a time - // will avoid big load spikes when the pages are touched. - // - // TODO: Instead of the time-based logic above, consider using - // ProcessInfo and watching for getResidentSize to drop, which is - // more precise. - remapFraction = (curTimeMicros64() - remapLastTimestamp) / 2000000.0; - - if (mmapv1GlobalOptions.journalOptions & - MMAPV1Options::JournalAlwaysRemap) { - remapFraction = 1; - } - else { - // We don't want to get close to the UncommittedBytesLimit - const double f = - estimatedPrivateMapSize / ((double)UncommittedBytesLimit); - if (f > remapFraction) { - remapFraction = f; - } - } + if (!commitJob.hasWritten()) { + // getlasterror request could have came after the data was already committed. + // No need to call committingReset though, because we have not done any + // writes (hasWritten == false). + commitJob.committingNotifyCommitted(); + } + else { + JSectHeader h; + PREPLOGBUFFER(h, journalBuilder); + + estimatedPrivateMapSize += commitJob.bytes(); + commitCounter++; + + // Need to reset the commit job's contents while under the S flush lock, + // because otherwise someone might have done a write and this would wipe out + // their changes without ever being committed. + commitJob.committingReset(); + + const bool shouldRemap = + (estimatedPrivateMapSize >= UncommittedBytesLimit) || + (commitCounter % NumCommitsBeforeRemap == 0) || + (mmapv1GlobalOptions.journalOptions & + MMAPV1Options::JournalAlwaysRemap); + + double remapFraction = 0.0; + + // Now that the in-memory modifications have been collected, we can potentially + // release the flush lock if remap is not necessary. + if (shouldRemap) { + // We want to remap all private views about every 2 seconds. There could be + // ~1000 views so we do a little each pass. There will be copy on write + // faults after remapping, so doing a little bit at a time will avoid big + // load spikes when the pages are touched. + // + // TODO: Instead of the time-based logic above, consider using ProcessInfo + // and watching for getResidentSize to drop, which is more precise. + remapFraction = (curTimeMicros64() - remapLastTimestamp) / 2000000.0; + + if (mmapv1GlobalOptions.journalOptions & + MMAPV1Options::JournalAlwaysRemap) { + remapFraction = 1; } else { - LOG(4) << "groupCommit early release flush lock"; - - // We will not be doing a remap so drop the flush lock. That way we - // will be doing the journal I/O outside of lock, so other threads can - // proceed. - invariant(!shouldRemap); - autoFlushLock.release(); + // We don't want to get close to the UncommittedBytesLimit + const double f = + estimatedPrivateMapSize / ((double)UncommittedBytesLimit); + if (f > remapFraction) { + remapFraction = f; + } } + } + else { + LOG(4) << "groupCommit early release flush lock"; - // This performs an I/O to the journal file - WRITETOJOURNAL(h, journalBuilder); - - // Data is now in the journal, which is sufficient for acknowledging - // getLastError. Note that we are doing this outside of the flush lock, - // which is alright because we will acknowledge the previous commit. If - // any writes happened after we released the flush lock, those will not be - // in the journalBuilder and hence will not be persisted, but in this case - // commitJob.commitingBegin() bumps the commit number, so those writers - // will wait for the next run of this loop. - commitJob.committingNotifyCommitted(); - - // Apply the journal entries on top of the shared view so that when flush - // is requested it would write the latest. - WRITETODATAFILES(h, journalBuilder); - - // Data has now been written to the shared view. If remap was requested, - // we would still be holding the S flush lock, so just upgrade it and - // perform the remap. - if (shouldRemap) { - autoFlushLock.upgradeFlushLockToExclusive(); - remapPrivateView(remapFraction); - - autoFlushLock.release(); - - // Reset the private map estimate outside of the lock - estimatedPrivateMapSize = 0; - remapLastTimestamp = curTimeMicros64(); - } + // We will not be doing a remap so drop the flush lock. That way we will be + // doing the journal I/O outside of lock, so other threads can proceed. + invariant(!shouldRemap); + autoFlushLock.release(); + } - // Do this reset after all locks have been released in order to not do - // unnecessary work under lock. - journalBuilder.reset(); + // This performs an I/O to the journal file + WRITETOJOURNAL(h, journalBuilder); + + // Data is now in the journal, which is sufficient for acknowledging + // getLastError. Note that we are doing this outside of the flush lock, which + // is alright because we will acknowledge the previous commit. If any writes + // happened after we released the flush lock, those will not be in the + // journalBuilder and hence will not be persisted, but in this case + // commitJob.commitingBegin() bumps the commit number, so those writers will + // wait for the next run of this loop. + commitJob.committingNotifyCommitted(); + + // Apply the journal entries on top of the shared view so that when flush + // is requested it would write the latest. + WRITETODATAFILES(h, journalBuilder); + + // Data has now been written to the shared view. If remap was requested, we + // would still be holding the S flush lock here, so just upgrade it and + // perform the remap. + if (shouldRemap) { + autoFlushLock.upgradeFlushLockToExclusive(); + remapPrivateView(remapFraction); + + autoFlushLock.release(); + + // Reset the private map estimate outside of the lock + estimatedPrivateMapSize = 0; + remapLastTimestamp = curTimeMicros64(); } - LOG(4) << "groupCommit end"; - } - catch (DBException& e) { - severe() << "dbexception in durThread causing immediate shutdown: " - << e.toString(); - invariant(false); - } - catch (std::ios_base::failure& e) { - severe() << "ios_base exception in durThread causing immediate shutdown: " - << e.what(); - invariant(false); + // Do this reset after all locks have been released in order to not do + // unnecessary work under lock. + journalBuilder.reset(); } - catch (std::bad_alloc& e) { - severe() << "bad_alloc exception in durThread causing immediate shutdown: " - << e.what(); - invariant(false); - } - catch (std::exception& e) { - severe() << "exception in durThread causing immediate shutdown: " - << e.what(); - invariant(false); - } - catch (...) { - severe() << "unhandled exception in durThread causing immediate shutdown"; - invariant(false); - } - } - - cc().shutdown(); - } - - /** - * Invoked at server startup. Recovers the database by replaying journal files and then - * starts the durability thread. - */ - void startup() { - if (!storageGlobalParams.dur) { - return; + LOG(4) << "groupCommit end"; } - - journalMakeDir(); - - try { - replayJournalFilesAtStartup(); + catch (DBException& e) { + severe() << "dbexception in durThread causing immediate shutdown: " + << e.toString(); + invariant(false); } - catch(DBException& e) { - severe() << "dbexception during recovery: " << e.toString(); - throw; + catch (std::ios_base::failure& e) { + severe() << "ios_base exception in durThread causing immediate shutdown: " + << e.what(); + invariant(false); } - catch(std::exception& e) { - severe() << "std::exception during recovery: " << e.what(); - throw; + catch (std::bad_alloc& e) { + severe() << "bad_alloc exception in durThread causing immediate shutdown: " + << e.what(); + invariant(false); } - catch(...) { - severe() << "exception during recovery"; - throw; + catch (std::exception& e) { + severe() << "exception in durThread causing immediate shutdown: " + << e.what(); + invariant(false); } + catch (...) { + severe() << "unhandled exception in durThread causing immediate shutdown"; + invariant(false); + } + } + + cc().shutdown(); + } + + + /** + * Called when a DurableMappedFile is closing. Asserts that there are no unwritten changes, + * because that would mean journal replay on recovery would try to write to non-existent files + * and fail. + */ + void closingFileNotification() { + if (commitJob.hasWritten()) { + severe() << "journal warning files are closing outside locks with writes pending"; + + // File is closing while there are unwritten changes + invariant(false); + } + } + + + /** + * Invoked at server startup. Recovers the database by replaying journal files and then + * starts the durability thread. + */ + void startup() { + if (!storageGlobalParams.dur) { + return; + } - preallocateFiles(); + journalMakeDir(); - DurableInterface::enableDurability(); - boost::thread t(durThread); + try { + replayJournalFilesAtStartup(); } + catch (DBException& e) { + severe() << "dbexception during recovery: " << e.toString(); + throw; + } + catch (std::exception& e) { + severe() << "std::exception during recovery: " << e.what(); + throw; + } + catch (...) { + severe() << "exception during recovery"; + throw; + } + + preallocateFiles(); + + DurableInterface::enableDurability(); + boost::thread t(durThread); + } } // namespace dur } // namespace mongo diff --git a/src/mongo/db/storage/mmap_v1/dur_commitjob.h b/src/mongo/db/storage/mmap_v1/dur_commitjob.h index a9d433fe724..d683cd12b32 100644 --- a/src/mongo/db/storage/mmap_v1/dur_commitjob.h +++ b/src/mongo/db/storage/mmap_v1/dur_commitjob.h @@ -147,8 +147,7 @@ namespace mongo { /** record/note an intent to write */ void note(void* p, int len); - std::vector< boost::shared_ptr<DurOp> >& ops() { - groupCommitMutex.dassertLocked(); // this is what really makes the below safe + const std::vector<boost::shared_ptr<DurOp> >& ops() const { return _intentsAndDurOps._durOps; } diff --git a/src/mongo/db/storage/mmap_v1/dur_journal.cpp b/src/mongo/db/storage/mmap_v1/dur_journal.cpp index 02889e3632b..fb1b1e8e549 100644 --- a/src/mongo/db/storage/mmap_v1/dur_journal.cpp +++ b/src/mongo/db/storage/mmap_v1/dur_journal.cpp @@ -46,7 +46,6 @@ #include "mongo/db/storage/mmap_v1/mmap_v1_options.h" #include "mongo/db/storage_options.h" #include "mongo/platform/random.h" -#include "mongo/server.h" #include "mongo/util/alignedbuilder.h" #include "mongo/util/checksum.h" #include "mongo/util/compress.h" diff --git a/src/mongo/db/storage/mmap_v1/dur_preplogbuffer.cpp b/src/mongo/db/storage/mmap_v1/dur_preplogbuffer.cpp index f1a68af494e..aa0285e2c5a 100644 --- a/src/mongo/db/storage/mmap_v1/dur_preplogbuffer.cpp +++ b/src/mongo/db/storage/mmap_v1/dur_preplogbuffer.cpp @@ -38,10 +38,7 @@ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kStorage -#define MONGO_PCH_WHITELISTED #include "mongo/platform/basic.h" -#include "mongo/pch.h" -#undef MONGO_PCH_WHITELISTED #include <boost/shared_ptr.hpp> @@ -51,19 +48,14 @@ #include "mongo/db/storage/mmap_v1/dur_journalimpl.h" #include "mongo/db/storage/mmap_v1/dur_stats.h" #include "mongo/db/storage_options.h" -#include "mongo/server.h" #include "mongo/util/alignedbuilder.h" #include "mongo/util/log.h" #include "mongo/util/mongoutils/str.h" #include "mongo/util/stacktrace.h" #include "mongo/util/timer.h" -using namespace mongoutils; - namespace mongo { - using boost::shared_ptr; - namespace dur { extern Journal j; @@ -140,34 +132,34 @@ namespace mongo { two writes to the same location during the group commit interval, it is likely (although not assured) that it is journaled here once. */ - static void prepBasicWrites(AlignedBuilder& bb) { + static void prepBasicWrites(AlignedBuilder& bb, const std::vector<WriteIntent>& intents) { scoped_lock lk(privateViews._mutex()); - // each time events switch to a different database we journal a JDbContext - // switches will be rare as we sort by memory location first and we batch commit. + // Each time write intents switch to a different database we journal a JDbContext. + // Switches will be rare as we sort by memory location first and we batch commit. RelativePath lastDbPath; - const vector<WriteIntent>& _intents = commitJob.getIntentsSorted(); - - // right now the durability code assumes there is at least one write intent - // this does not have to be true in theory as i could just add or delete a file - // callers have to ensure they do at least something for now even though its ugly - // until this can be addressed - fassert( 17388, !_intents.empty() ); + invariant(!intents.empty()); WriteIntent last; - for( vector<WriteIntent>::const_iterator i = _intents.begin(); i != _intents.end(); i++ ) { + for (std::vector<WriteIntent>::const_iterator i = intents.begin(); + i != intents.end(); + i++) { + if( i->start() < last.end() ) { // overlaps last.absorb(*i); } else { // discontinuous - if( i != _intents.begin() ) + if (i != intents.begin()) { prepBasicWrite_inlock(bb, &last, lastDbPath); + } + last = *i; } } + prepBasicWrite_inlock(bb, &last, lastDbPath); } @@ -190,22 +182,26 @@ namespace mongo { resetLogBuffer(h, bb); // adds JSectHeader // ops other than basic writes (DurOp's) - { - for( vector< shared_ptr<DurOp> >::iterator i = commitJob.ops().begin(); i != commitJob.ops().end(); ++i ) { - (*i)->serialize(bb); - } - } + const std::vector<boost::shared_ptr<DurOp> >& durOps = commitJob.ops(); + for (std::vector<boost::shared_ptr<DurOp> >::const_iterator i = durOps.begin(); + i != durOps.end(); + i++) { - prepBasicWrites(bb); + (*i)->serialize(bb); + } - return; + // Write intents + const std::vector<WriteIntent>& intents = commitJob.getIntentsSorted(); + if (!intents.empty()) { + prepBasicWrites(bb, intents); + } } + void PREPLOGBUFFER(/*out*/ JSectHeader& outHeader, AlignedBuilder& outBuffer) { Timer t; j.assureLogFileOpen(); // so fileId is set _PREPLOGBUFFER(outHeader, outBuffer); stats.curr->_prepLogBufferMicros += t.micros(); } - } } 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 3ac29072120..f0546a63f35 100644 --- a/src/mongo/db/storage/mmap_v1/durable_mapped_file.cpp +++ b/src/mongo/db/storage/mmap_v1/durable_mapped_file.cpp @@ -285,16 +285,16 @@ namespace mongo { try { LOG(3) << "mmf close " << filename(); - // Only notifiy the durability system if the file was actually opened - if (view_write()) { - dur::closingFileNotification(); - } + // Notify the durability system that we are closing a file. + dur::closingFileNotification(); LockMongoFilesExclusive lk; privateViews.remove(_view_private, length()); _view_write = _view_private = 0; MemoryMappedFile::close(); } - catch(...) { error() << "exception in ~DurableMappedFile"; } + catch (...) { + error() << "exception in ~DurableMappedFile"; + } } } 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 f747e2437a3..5b3c35fb59b 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 @@ -168,8 +168,6 @@ namespace { invariant(txn->lockState()->isDbLockedForMode(name, MODE_X)); try { - WriteUnitOfWork wunit(txn); - _init( txn ); std::list<std::string> namespaces; @@ -177,10 +175,12 @@ namespace { for ( std::list<std::string>::const_iterator i = namespaces.begin(); i != namespaces.end(); // we add to the list in the loop so can't cache end(). ++i ) { + const std::string& ns = *i; Entry*& entry = _collections[ns]; - // entry was already loaded for system.indexes and system.namespaces in - // _init. That is ok, since they can't have indexes on them anyway. + + // Entry was already loaded for system.indexes and system.namespaces in _init. That + // is ok, since they can't have indexes on them anyway. if (!entry) { entry = new Entry(); _insertInCache(txn, ns, entry); @@ -193,26 +193,17 @@ namespace { IndexDescriptor::makeIndexNamespace(ns, indexNames[i])); } } - - DataFileVersion version = _extentManager.getFileFormat(txn); - if (version.isCompatibleWithCurrentCode() && !version.mayHave28Freelist()) { - // Any DB that can be opened and written to gets this flag set. - version.setMayHave28Freelist(); - _extentManager.setFileFormat(txn, version); - } } - - wunit.commit(); } - catch(std::exception& e) { - log() << "warning database " << path << " " << name << " could not be opened"; - DBException* dbe = dynamic_cast<DBException*>(&e); - if (dbe) { - log() << "DBException " << dbe->getCode() << ": " << e.what() << endl; - } - else { - log() << e.what() << endl; - } + catch (const DBException& dbe) { + warning() << "database " << path << " " << name + << " could not be opened due to DBException " << dbe.getCode() << ": " + << dbe.what(); + throw; + } + catch (const std::exception& e) { + warning() << "database " << path << " " << name + << " could not be opened " << e.what(); throw; } } @@ -523,7 +514,7 @@ namespace { _namespaceIndex.add_ns( txn, ns, DiskLoc(), false ); } - void MMAPV1DatabaseCatalogEntry::_init( OperationContext* txn ) { + void MMAPV1DatabaseCatalogEntry::_init(OperationContext* txn) { // First init the .ns file _namespaceIndex.init(txn); @@ -533,6 +524,8 @@ namespace { msgasserted(16966, str::stream() << "_extentManager.init failed: " << s.toString()); } + WriteUnitOfWork wunit(txn); + // Upgrade freelist const NamespaceString oldFreeList(name(), "$freelist"); NamespaceDetails* freeListDetails = _namespaceIndex.details(oldFreeList.ns()); @@ -546,82 +539,97 @@ namespace { _namespaceIndex.kill_ns(txn, oldFreeList.ns()); } - const NamespaceString nsi( name(), "system.indexes" ); - const NamespaceString nsn( name(), "system.namespaces" ); + DataFileVersion version = _extentManager.getFileFormat(txn); + if (version.isCompatibleWithCurrentCode() && !version.mayHave28Freelist()) { + // Any DB that can be opened and written to gets this flag set. + version.setMayHave28Freelist(); + _extentManager.setFileFormat(txn, version); + } + + const NamespaceString nsi(name(), "system.indexes"); + const NamespaceString nsn(name(), "system.namespaces"); - bool isSystemNamespacesGoingToBeNew = _namespaceIndex.details( nsn.toString() ) == NULL; - bool isSystemIndexesGoingToBeNew = _namespaceIndex.details( nsi.toString() ) == NULL; + bool isSystemNamespacesGoingToBeNew = _namespaceIndex.details(nsn.toString()) == NULL; + bool isSystemIndexesGoingToBeNew = _namespaceIndex.details(nsi.toString()) == NULL; _ensureSystemCollection(txn, nsn.toString()); _ensureSystemCollection(txn, nsi.toString()); - if ( isSystemNamespacesGoingToBeNew ) { + if (isSystemNamespacesGoingToBeNew) { txn->recoveryUnit()->registerChange(new EntryInsertion(nsn.toString(), this)); } - if ( isSystemIndexesGoingToBeNew ) { + if (isSystemIndexesGoingToBeNew) { txn->recoveryUnit()->registerChange(new EntryInsertion(nsi.toString(), this)); } Entry*& indexEntry = _collections[nsi.toString()]; Entry*& nsEntry = _collections[nsn.toString()]; - NamespaceDetails* indexDetails = _namespaceIndex.details( nsi.toString() ); - NamespaceDetails* nsDetails = _namespaceIndex.details( nsn.toString() ); + NamespaceDetails* const indexDetails = _namespaceIndex.details(nsi.toString()); + NamespaceDetails* const nsDetails = _namespaceIndex.details(nsn.toString()); // order has to be: // 1) ns rs // 2) i rs // 3) catalog entries - if ( !nsEntry ) { + if (!nsEntry) { nsEntry = new Entry(); - NamespaceDetailsRSV1MetaData* md = new NamespaceDetailsRSV1MetaData( nsn.toString(), - nsDetails, - NULL ); - nsEntry->recordStore.reset( new SimpleRecordStoreV1( txn, - nsn.toString(), - md, - &_extentManager, - false ) ); + NamespaceDetailsRSV1MetaData* md = new NamespaceDetailsRSV1MetaData(nsn.toString(), + nsDetails, + NULL); + nsEntry->recordStore.reset(new SimpleRecordStoreV1(txn, + nsn.toString(), + md, + &_extentManager, + false)); if (nsEntry->recordStore->storageSize(txn) == 0) { nsEntry->recordStore->increaseStorageSize(txn, _extentManager.initialSize(128), false); } } - if ( !indexEntry ) { + if (!indexEntry) { indexEntry = new Entry(); - NamespaceDetailsRSV1MetaData* md = new NamespaceDetailsRSV1MetaData( nsi.toString(), - indexDetails, - nsEntry->recordStore.get() ); - indexEntry->recordStore.reset( new SimpleRecordStoreV1( txn, - nsi.toString(), - md, - &_extentManager, - true ) ); + NamespaceDetailsRSV1MetaData* md = + new NamespaceDetailsRSV1MetaData(nsi.toString(), + indexDetails, + nsEntry->recordStore.get()); + + indexEntry->recordStore.reset(new SimpleRecordStoreV1(txn, + nsi.toString(), + md, + &_extentManager, + true)); if (indexEntry->recordStore->storageSize(txn) == 0) { indexEntry->recordStore->increaseStorageSize(txn, _extentManager.initialSize(128), false); } } - if ( isSystemIndexesGoingToBeNew ) { + if (isSystemIndexesGoingToBeNew) { _addNamespaceToNamespaceCollection(txn, nsi.toString(), NULL); } - if ( !nsEntry->catalogEntry ) - nsEntry->catalogEntry.reset( new NamespaceDetailsCollectionCatalogEntry( nsn.toString(), - nsDetails, - indexEntry->recordStore.get(), - this ) ); + if (!nsEntry->catalogEntry) { + nsEntry->catalogEntry.reset( + new NamespaceDetailsCollectionCatalogEntry(nsn.toString(), + nsDetails, + indexEntry->recordStore.get(), + this)); + } + + if (!indexEntry->catalogEntry) { + indexEntry->catalogEntry.reset( + new NamespaceDetailsCollectionCatalogEntry(nsi.toString(), + indexDetails, + indexEntry->recordStore.get(), + this)); + } - if ( !indexEntry->catalogEntry ) - indexEntry->catalogEntry.reset( new NamespaceDetailsCollectionCatalogEntry( nsi.toString(), - indexDetails, - indexEntry->recordStore.get(), - this ) ); + wunit.commit(); } Status MMAPV1DatabaseCatalogEntry::createCollection( OperationContext* txn, diff --git a/src/mongo/dbtests/threadedtests.cpp b/src/mongo/dbtests/threadedtests.cpp index b952dd41f11..c317906edc6 100644 --- a/src/mongo/dbtests/threadedtests.cpp +++ b/src/mongo/dbtests/threadedtests.cpp @@ -50,8 +50,6 @@ #include "mongo/util/concurrency/synchronization.h" #include "mongo/util/concurrency/ticketholder.h" #include "mongo/util/log.h" -#include "mongo/server.h" - namespace ThreadedTests { |