diff options
author | Eliot Horowitz <eliot@10gen.com> | 2014-11-03 11:41:00 -0500 |
---|---|---|
committer | Eliot Horowitz <eliot@10gen.com> | 2014-11-03 14:01:16 -0500 |
commit | 1537472fc8ce3068671f826fde6ca6c934165d15 (patch) | |
tree | 73c93f4222085eddd7927babd86fd6207cda0a1d /src/mongo/db/introspect.cpp | |
parent | 0e0441723f325469f7ed582a9ba90cb9b3a002b1 (diff) | |
download | mongo-1537472fc8ce3068671f826fde6ca6c934165d15.tar.gz |
SERVER-15888: fix lock for collection creation in profiling
Diffstat (limited to 'src/mongo/db/introspect.cpp')
-rw-r--r-- | src/mongo/db/introspect.cpp | 73 |
1 files changed, 48 insertions, 25 deletions
diff --git a/src/mongo/db/introspect.cpp b/src/mongo/db/introspect.cpp index 15e8ccdee84..0b3afeb947d 100644 --- a/src/mongo/db/introspect.cpp +++ b/src/mongo/db/introspect.cpp @@ -81,7 +81,10 @@ namespace { } } // namespace - static void _profile(OperationContext* txn, + /** + * @return if collection existed or was created + */ + static bool _profile(OperationContext* txn, const Client& c, Database* db, CurOp& currentOp, @@ -128,7 +131,9 @@ namespace { Collection* profileCollection = getOrCreateProfileCollection(txn, db); if ( profileCollection ) { profileCollection->insertDocument( txn, p, false ); + return true; } + return false; } void profile(OperationContext* txn, const Client& c, int op, CurOp& currentOp) { @@ -136,32 +141,45 @@ namespace { // doing this outside the dblock to improve performance BufBuilder profileBufBuilder(1024); - try { - // NOTE: It's kind of weird that we lock the op's namespace, but have to for now - // since we're sometimes inside the lock already - const string dbname(nsToDatabase(currentOp.getNS())); - scoped_ptr<Lock::DBLock> lk; - if ( !txn->lockState()->isDbLockedForMode( dbname, MODE_IX ) ) { - lk.reset( new Lock::DBLock( txn->lockState(), dbname, MODE_IX) ); + bool tryAgain = false; + while ( 1 ) { + try { + // NOTE: It's kind of weird that we lock the op's namespace, but have to for now + // since we're sometimes inside the lock already + const string dbname(nsToDatabase(currentOp.getNS())); + scoped_ptr<Lock::DBLock> lk; + + // todo: this can be slow, perhaps can re-work + if ( !txn->lockState()->isDbLockedForMode( dbname, MODE_IX ) ) { + lk.reset( new Lock::DBLock( txn->lockState(), + dbname, + tryAgain ? MODE_X : MODE_IX) ); + } + Database* db = dbHolder().get(txn, dbname); + if (db != NULL) { + // We want the profiling to happen in a different WUOW from the actual op. + Lock::CollectionLock clk(txn->lockState(), db->getProfilingNS(), MODE_X); + WriteUnitOfWork wunit(txn); + Client::Context cx(txn, currentOp.getNS(), false); + if ( !_profile(txn, c, cx.db(), currentOp, profileBufBuilder ) && lk.get() ) { + // we took an IX lock, so now we try again with an X lock + tryAgain = true; + continue; + } + wunit.commit(); + } + else { + mongo::log() << "note: not profiling because db went away - " + << "probably a close on: " << currentOp.getNS(); + } + return; } - Database* db = dbHolder().get(txn, dbname); - if (db != NULL) { - // We are ok with the profiling happening in a different WUOW from the actual op. - Lock::CollectionLock clk(txn->lockState(), db->getProfilingNS(), MODE_X); - WriteUnitOfWork wunit(txn); - Client::Context cx(txn, currentOp.getNS(), false); - _profile(txn, c, cx.db(), currentOp, profileBufBuilder); - wunit.commit(); + catch (const AssertionException& assertionEx) { + warning() << "Caught Assertion while trying to profile " << opToString(op) + << " against " << currentOp.getNS() + << ": " << assertionEx.toString() << endl; + return; } - else { - mongo::log() << "note: not profiling because db went away - probably a close on: " - << currentOp.getNS() << endl; - } - } - catch (const AssertionException& assertionEx) { - warning() << "Caught Assertion while trying to profile " << opToString(op) - << " against " << currentOp.getNS() - << ": " << assertionEx.toString() << endl; } } @@ -196,6 +214,11 @@ namespace { return NULL; } + if ( !txn->lockState()->isDbLockedForMode( db->name(), MODE_X ) ) { + // can't create here + return NULL; + } + // system.profile namespace doesn't exist; create it log() << "creating profile collection: " << profileName << endl; |