summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKaloian Manassiev <kaloian.manassiev@mongodb.com>2015-01-06 16:21:02 -0500
committerKaloian Manassiev <kaloian.manassiev@mongodb.com>2015-01-07 15:04:36 -0500
commit67c550459e416a9ec7eabe35e38c1fed9aeccb8f (patch)
treee44abef8854250ed04f6a8759f015d8f63ee3b90 /src
parent8197195ce0faee1df316b2b45649cbc61dcf3ec8 (diff)
downloadmongo-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.cpp7
-rw-r--r--src/mongo/db/storage/mmap_v1/dur.cpp1036
-rw-r--r--src/mongo/db/storage/mmap_v1/dur_commitjob.h3
-rw-r--r--src/mongo/db/storage/mmap_v1/dur_journal.cpp1
-rw-r--r--src/mongo/db/storage/mmap_v1/dur_preplogbuffer.cpp52
-rw-r--r--src/mongo/db/storage/mmap_v1/durable_mapped_file.cpp10
-rw-r--r--src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.cpp128
-rw-r--r--src/mongo/dbtests/threadedtests.cpp2
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 {