diff options
64 files changed, 352 insertions, 37 deletions
diff --git a/src/mongo/db/auth/auth_index_d.cpp b/src/mongo/db/auth/auth_index_d.cpp index 07f692149fe..694530f535b 100644 --- a/src/mongo/db/auth/auth_index_d.cpp +++ b/src/mongo/db/auth/auth_index_d.cpp @@ -95,6 +95,7 @@ namespace { while ((oldIndex = indexCatalog->findIndexByKeyPattern(v1SystemUsersKeyPattern))) { indexCatalog->dropIndex(txn, oldIndex); } + wctx.commit(); } } diff --git a/src/mongo/db/catalog/database.cpp b/src/mongo/db/catalog/database.cpp index 8c6dd84cf67..d1fbc8c8bd9 100644 --- a/src/mongo/db/catalog/database.cpp +++ b/src/mongo/db/catalog/database.cpp @@ -503,8 +503,10 @@ namespace mongo { log() << "dropAllDatabasesExceptLocal " << n.size() << endl; for( vector<string>::iterator i = n.begin(); i != n.end(); i++ ) { if( *i != "local" ) { + WriteUnitOfWork wunit(txn->recoveryUnit()); Client::Context ctx(txn, *i); dropDatabase(txn, ctx.db()); + wunit.commit(); } } } diff --git a/src/mongo/db/client.cpp b/src/mongo/db/client.cpp index 6cfefce96a6..8bfe80850a7 100644 --- a/src/mongo/db/client.cpp +++ b/src/mongo/db/client.cpp @@ -205,14 +205,18 @@ namespace mongo { DEV log() << "_DEBUG ReadContext db wasn't open, will try to open " << ns << endl; if (txn->lockState()->isW()) { // write locked already + WriteUnitOfWork wunit(txn->recoveryUnit()); DEV RARELY log() << "write locked on ReadContext construction " << ns << endl; _c.reset(new Context(txn, ns, doVersion)); + wunit.commit(); } else if (!txn->lockState()->isRecursive()) { _lk.reset(0); { Lock::GlobalWrite w(txn->lockState()); + WriteUnitOfWork wunit(txn->recoveryUnit()); Context c(txn, ns, doVersion); + wunit.commit(); } // db could be closed at this interim point -- that is ok, we will throw, and don't mind throwing. @@ -232,10 +236,13 @@ namespace mongo { Client::WriteContext::WriteContext( OperationContext* opCtx, const std::string& ns, bool doVersion) : _lk(opCtx->lockState(), ns), + _wunit(opCtx->recoveryUnit()), _c(opCtx, ns, doVersion) { - } + void Client::WriteContext::commit() { + _wunit.commit(); + } void Client::Context::checkNotStale() const { switch ( _client->_curOp->getOp() ) { diff --git a/src/mongo/db/client.h b/src/mongo/db/client.h index cf5c9f38964..570807c6ccb 100644 --- a/src/mongo/db/client.h +++ b/src/mongo/db/client.h @@ -207,10 +207,15 @@ namespace mongo { class WriteContext : boost::noncopyable { public: WriteContext(OperationContext* opCtx, const std::string& ns, bool doVersion = true); + + /** Commit any writes done so far in this context. */ + void commit(); + Context& ctx() { return _c; } private: Lock::DBWrite _lk; + WriteUnitOfWork _wunit; Context _c; }; diff --git a/src/mongo/db/cloner.cpp b/src/mongo/db/cloner.cpp index 6888c82eb46..368c986d908 100644 --- a/src/mongo/db/cloner.cpp +++ b/src/mongo/db/cloner.cpp @@ -119,9 +119,11 @@ namespace mongo { << "collection dropped during clone [" << to_collection << "]", !createdCollection ); + WriteUnitOfWork wunit(txn->recoveryUnit()); createdCollection = true; collection = db->createCollection( txn, to_collection ); verify( collection ); + wunit.commit(); } } @@ -147,6 +149,7 @@ namespace mongo { } ++numSeen; + WriteUnitOfWork wunit(txn->recoveryUnit()); BSONObj js = tmp; if ( isindex ) { @@ -167,6 +170,7 @@ namespace mongo { if (logForRepl) repl::logOp(txn, "i", to_collection, js); + wunit.commit(); txn->recoveryUnit()->commitIfNeeded(); RARELY if ( time( 0 ) - saveLast > 60 ) { @@ -300,6 +304,7 @@ namespace mongo { const NamespaceString nss(ns); Lock::DBWrite dbWrite(txn->lockState(), nss.db()); + WriteUnitOfWork wunit(txn->recoveryUnit()); const string dbName = nss.db().toString(); @@ -332,6 +337,7 @@ namespace mongo { copy(txn, dbName, temp.c_str(), temp.c_str(), true, logForRepl, false, true, mayYield, mayBeInterrupted, BSON( "ns" << ns )); + wunit.commit(); txn->recoveryUnit()->commitIfNeeded(); return true; } diff --git a/src/mongo/db/commands/apply_ops.cpp b/src/mongo/db/commands/apply_ops.cpp index b3fa1b6ce2e..bd69352c350 100644 --- a/src/mongo/db/commands/apply_ops.cpp +++ b/src/mongo/db/commands/apply_ops.cpp @@ -84,6 +84,7 @@ namespace mongo { // SERVER-4328 todo : is global ok or does this take a long time? i believe multiple // ns used so locking individually requires more analysis Lock::GlobalWrite globalWriteLock(txn->lockState()); + WriteUnitOfWork wunit(txn->recoveryUnit()); DBDirectClient db(txn); @@ -172,7 +173,12 @@ namespace mongo { repl::logOp(txn, "c", tempNS.c_str(), cmdBuilder.done()); } - return errors == 0; + if (errors != 0) { + return false; + } + + wunit.commit(); + return true; } } applyOpsCmd; diff --git a/src/mongo/db/commands/clone.cpp b/src/mongo/db/commands/clone.cpp index 29a0dbd0dd5..cefe28ba570 100644 --- a/src/mongo/db/commands/clone.cpp +++ b/src/mongo/db/commands/clone.cpp @@ -117,6 +117,8 @@ namespace mongo { set<string> clonedColls; Lock::DBWrite dbXLock(txn->lockState(), dbname); + // SERVER-14085: This unit of work should go away and be put in the individual ops + WriteUnitOfWork wunit(txn->recoveryUnit()); Cloner cloner; bool rval = cloner.go(txn, dbname, from, opts, &clonedColls, errmsg); @@ -125,6 +127,7 @@ namespace mongo { barr.append( clonedColls ); result.append( "clonedColls", barr.arr() ); + wunit.commit(); return rval; diff --git a/src/mongo/db/commands/collection_to_capped.cpp b/src/mongo/db/commands/collection_to_capped.cpp index 476d80edf08..3a26bbdc852 100644 --- a/src/mongo/db/commands/collection_to_capped.cpp +++ b/src/mongo/db/commands/collection_to_capped.cpp @@ -153,9 +153,13 @@ namespace mongo { } Lock::DBWrite dbXLock(txn->lockState(), dbname); + WriteUnitOfWork wunit(txn->recoveryUnit()); Client::Context ctx(txn, dbname); Status status = cloneCollectionAsCapped( txn, ctx.db(), from, to, size, temp, true ); + if (status.isOK()) { + wunit.commit(); + } return appendCommandStatus( result, status ); } } cmdCloneCollectionAsCapped; @@ -196,10 +200,17 @@ namespace mongo { return std::vector<BSONObj>(); } - bool run(OperationContext* txn, const string& dbname, BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) { + bool run(OperationContext* txn, + const string& dbname, + BSONObj& jsobj, + int, + string& errmsg, + BSONObjBuilder& result, + bool fromRepl ) { // calls renamecollection which does a global lock, so we must too: // Lock::GlobalWrite globalWriteLock(txn->lockState()); + WriteUnitOfWork wunit(txn->recoveryUnit()); Client::Context ctx(txn, dbname); Database* db = ctx.db(); @@ -242,6 +253,8 @@ namespace mongo { if (!fromRepl) repl::logOp(txn, "c",(dbname + ".$cmd").c_str(), jsobj); + + wunit.commit(); return true; } } cmdConvertToCapped; diff --git a/src/mongo/db/commands/compact.cpp b/src/mongo/db/commands/compact.cpp index c0df090d29a..0400321d239 100644 --- a/src/mongo/db/commands/compact.cpp +++ b/src/mongo/db/commands/compact.cpp @@ -141,6 +141,8 @@ namespace mongo { Lock::DBWrite lk(txn->lockState(), ns.ns()); + // SERVER-14085: The following will have to go as we push down WOUW + WriteUnitOfWork wunit(txn->recoveryUnit()); BackgroundOperation::assertNoBgOpInProgForNs(ns.ns()); Client::Context ctx(txn, ns); @@ -169,6 +171,7 @@ namespace mongo { log() << "compact " << ns << " end"; IndexBuilder::restoreIndexes(indexesInProg); + wunit.commit(); return true; } diff --git a/src/mongo/db/commands/copydb.cpp b/src/mongo/db/commands/copydb.cpp index 6582c1172eb..597cbf62d93 100644 --- a/src/mongo/db/commands/copydb.cpp +++ b/src/mongo/db/commands/copydb.cpp @@ -188,8 +188,12 @@ namespace mongo { scoped_ptr<Lock::ScopedLock> lk( fromSelf ? static_cast<Lock::ScopedLock*>(new Lock::GlobalWrite(txn->lockState())) : static_cast<Lock::ScopedLock*>(new Lock::DBWrite(txn->lockState(), todb))); - - return cloner.go(txn, todb, fromhost, cloneOptions, NULL, errmsg ); + WriteUnitOfWork wunit(txn->recoveryUnit()); + if (!cloner.go(txn, todb, fromhost, cloneOptions, NULL, errmsg )) { + return false; + } + wunit.commit(); + return true; } } cmdCopyDB; diff --git a/src/mongo/db/commands/cpuprofile.cpp b/src/mongo/db/commands/cpuprofile.cpp index de614b8a553..f2d79da97a7 100644 --- a/src/mongo/db/commands/cpuprofile.cpp +++ b/src/mongo/db/commands/cpuprofile.cpp @@ -136,6 +136,7 @@ namespace mongo { BSONObjBuilder &result, bool fromRepl ) { Lock::DBWrite dbXLock(db); + // The lock here is just to prevent concurrency, nothing will write. Client::Context ctx(txn, db); std::string profileFilename = cmdObj[commandName]["profileFilename"].String(); @@ -154,9 +155,11 @@ namespace mongo { BSONObjBuilder &result, bool fromRepl ) { Lock::DBWrite dbXLock(db); + WriteUnitOfWork wunit(txn->recoveryUnit()); Client::Context ctx(txn, db); ::ProfilerStop(); + wunit.commit(); return true; } diff --git a/src/mongo/db/commands/create_indexes.cpp b/src/mongo/db/commands/create_indexes.cpp index 502f3e94f79..53db0748a77 100644 --- a/src/mongo/db/commands/create_indexes.cpp +++ b/src/mongo/db/commands/create_indexes.cpp @@ -206,6 +206,7 @@ namespace mongo { result.append( "numIndexesAfter", collection->getIndexCatalog()->numIndexesTotal() ); + writeContext.commit(); return true; } diff --git a/src/mongo/db/commands/drop_indexes.cpp b/src/mongo/db/commands/drop_indexes.cpp index d5491d166e7..b44708d5c6b 100644 --- a/src/mongo/db/commands/drop_indexes.cpp +++ b/src/mongo/db/commands/drop_indexes.cpp @@ -94,11 +94,17 @@ namespace mongo { CmdDropIndexes() : Command("dropIndexes", false, "deleteIndexes") { } bool run(OperationContext* txn, const string& dbname, BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& anObjBuilder, bool fromRepl) { Lock::DBWrite dbXLock(txn->lockState(), dbname); + WriteUnitOfWork wunit(txn->recoveryUnit()); bool ok = wrappedRun(txn, dbname, jsobj, errmsg, anObjBuilder); - if (ok && !fromRepl) + if (!ok) { + return false; + } + if (!fromRepl) repl::logOp(txn, "c",(dbname + ".$cmd").c_str(), jsobj); - return ok; + wunit.commit(); + return true; } + bool wrappedRun(OperationContext* txn, const string& dbname, BSONObj& jsobj, @@ -222,6 +228,7 @@ namespace mongo { LOG(0) << "CMD: reIndex " << toDeleteNs << endl; Lock::DBWrite dbXLock(txn->lockState(), dbname); + WriteUnitOfWork wunit(txn->recoveryUnit()); Client::Context ctx(txn, toDeleteNs); Collection* collection = ctx.db()->getCollection( txn, toDeleteNs ); @@ -272,6 +279,7 @@ namespace mongo { result.appendArray( "indexes" , b.obj() ); IndexBuilder::restoreIndexes(indexesInProg); + wunit.commit(); return true; } } cmdReIndex; diff --git a/src/mongo/db/commands/find_and_modify.cpp b/src/mongo/db/commands/find_and_modify.cpp index 3981705ed00..6de75da79f5 100644 --- a/src/mongo/db/commands/find_and_modify.cpp +++ b/src/mongo/db/commands/find_and_modify.cpp @@ -134,7 +134,9 @@ namespace mongo { string& errmsg) { Lock::DBWrite lk(txn->lockState(), ns); + WriteUnitOfWork wunit(txn->recoveryUnit()); Client::Context cx(txn, ns); + Collection* collection = cx.db()->getCollection( txn, ns ); const WhereCallbackReal whereCallback = WhereCallbackReal(StringData(ns)); @@ -297,7 +299,7 @@ namespace mongo { } } - + wunit.commit(); return true; } @@ -330,6 +332,7 @@ namespace mongo { } Lock::DBWrite dbXLock(txn->lockState(), dbname); + WriteUnitOfWork wunit(txn->recoveryUnit()); Client::Context ctx(txn, ns); BSONObj out = db.findOne(ns, q, fields); @@ -423,9 +426,9 @@ namespace mongo { result.append("value", out); + wunit.commit(); return true; } } cmdFindAndModify; - } diff --git a/src/mongo/db/commands/fsync.cpp b/src/mongo/db/commands/fsync.cpp index 2f40aac1fe2..9b7b16e4e7e 100644 --- a/src/mongo/db/commands/fsync.cpp +++ b/src/mongo/db/commands/fsync.cpp @@ -135,6 +135,7 @@ namespace mongo { // can this be GlobalRead? and if it can, it should be nongreedy. Lock::GlobalWrite w(txn->lockState()); getDur().commitNow(txn); + // No WriteUnitOfWork needed, as this does no writes of its own. } result.append( "numFiles" , globalStorageEngine->flushAllFiles( sync ) ); } @@ -148,7 +149,7 @@ namespace mongo { SimpleMutex::scoped_lock lkf(filesLockedFsync); OperationContextImpl txn; // XXX? - Lock::GlobalWrite global(txn.lockState()); + Lock::GlobalWrite global(txn.lockState()); // No WriteUnitOfWork needed SimpleMutex::scoped_lock lk(fsyncCmd.m); diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp index b359a6fa3e4..776b86c3819 100644 --- a/src/mongo/db/commands/mr.cpp +++ b/src/mongo/db/commands/mr.cpp @@ -389,6 +389,7 @@ namespace mongo { indexesToInsert.push_back( b.obj() ); } } + finalCtx.commit(); } { @@ -415,6 +416,7 @@ namespace mongo { string logNs = nsToDatabase( _config.tempNamespace ) + ".system.indexes"; repl::logOp(_txn, "i", logNs.c_str(), *it); } + tempCtx.commit(); } } @@ -565,9 +567,11 @@ namespace mongo { auto_ptr<DBClientCursor> cursor = _db.query( _config.tempNamespace , BSONObj() ); while ( cursor->more() ) { Lock::DBWrite lock(_txn->lockState(), _config.outputOptions.finalNamespace); + WriteUnitOfWork wunit(_txn->recoveryUnit()); BSONObj o = cursor->nextSafe(); Helpers::upsert( _txn, _config.outputOptions.finalNamespace , o ); _txn->recoveryUnit()->commitIfNeeded(); + wunit.commit(); pm.hit(); } _db.dropCollection( _config.tempNamespace ); @@ -583,6 +587,7 @@ namespace mongo { auto_ptr<DBClientCursor> cursor = _db.query( _config.tempNamespace , BSONObj() ); while ( cursor->more() ) { Lock::GlobalWrite lock(txn->lockState()); // TODO(erh) why global? + WriteUnitOfWork wunit(txn->recoveryUnit()); BSONObj temp = cursor->nextSafe(); BSONObj old; @@ -611,6 +616,7 @@ namespace mongo { else { Helpers::upsert( _txn, _config.outputOptions.finalNamespace , temp ); } + wunit.commit(); _txn->recoveryUnit()->commitIfNeeded(); pm.hit(); } @@ -644,6 +650,7 @@ namespace mongo { coll->insertDocument( _txn, bo, true ); repl::logOp(_txn, "i", ns.c_str(), bo); + ctx.commit(); } /** @@ -660,6 +667,7 @@ namespace mongo { " collection expected: " << _config.incLong ); coll->insertDocument( _txn, o, true ); + ctx.commit(); _txn->recoveryUnit()->commitIfNeeded(); } @@ -944,6 +952,7 @@ namespace mongo { break; } } + incCtx.commit(); verify( foundIndex ); } @@ -1069,6 +1078,7 @@ namespace mongo { return; Lock::DBWrite kl(_txn->lockState(), _config.incLong); + WriteUnitOfWork wunit(_txn->recoveryUnit()); for ( InMemory::iterator i=_temp->begin(); i!=_temp->end(); i++ ) { BSONList& all = i->second; @@ -1080,6 +1090,7 @@ namespace mongo { } _temp->clear(); _size = 0; + wunit.commit(); } diff --git a/src/mongo/db/commands/rename_collection.cpp b/src/mongo/db/commands/rename_collection.cpp index a25b2e19a09..a878e8222f1 100644 --- a/src/mongo/db/commands/rename_collection.cpp +++ b/src/mongo/db/commands/rename_collection.cpp @@ -94,10 +94,15 @@ namespace mongo { virtual bool run(OperationContext* txn, const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { Lock::GlobalWrite globalWriteLock(txn->lockState()); - bool ok = wrappedRun(txn, dbname, cmdObj, errmsg, result, fromRepl); - if (ok && !fromRepl) + WriteUnitOfWork wunit(txn->recoveryUnit()); + if (!wrappedRun(txn, dbname, cmdObj, errmsg, result, fromRepl)) { + return false; + } + if (!fromRepl) { repl::logOp(txn, "c",(dbname + ".$cmd").c_str(), cmdObj); - return ok; + } + wunit.commit(); + return true; } virtual bool wrappedRun(OperationContext* txn, const string& dbname, diff --git a/src/mongo/db/commands/test_commands.cpp b/src/mongo/db/commands/test_commands.cpp index 20175588afc..60164663ff7 100644 --- a/src/mongo/db/commands/test_commands.cpp +++ b/src/mongo/db/commands/test_commands.cpp @@ -62,6 +62,7 @@ namespace mongo { BSONObj obj = cmdObj[ "obj" ].embeddedObjectUserCheck(); Lock::DBWrite lk(txn->lockState(), ns); + WriteUnitOfWork wunit(txn->recoveryUnit()); Client::Context ctx(txn, ns ); Database* db = ctx.db(); Collection* collection = db->getCollection( txn, ns ); @@ -73,6 +74,10 @@ namespace mongo { } } StatusWith<DiskLoc> res = collection->insertDocument( txn, obj, false ); + Status status = res.getStatus(); + if (status.isOK()) { + wunit.commit(); + } return appendCommandStatus( result, res.getStatus() ); } }; @@ -153,6 +158,7 @@ namespace mongo { massert( 13418, "captrunc invalid n", Runner::RUNNER_ADVANCED == state); } collection->temp_cappedTruncateAfter( txn, end, inc ); + ctx.commit(); return true; } }; @@ -200,6 +206,7 @@ namespace mongo { if (!fromRepl) repl::logOp(txn, "c",(dbname + ".$cmd").c_str(), cmdObj); + ctx.commit(); return true; } }; diff --git a/src/mongo/db/commands/write_commands/batch_executor.cpp b/src/mongo/db/commands/write_commands/batch_executor.cpp index 39b5e7c0014..a35603e7db8 100644 --- a/src/mongo/db/commands/write_commands/batch_executor.cpp +++ b/src/mongo/db/commands/write_commands/batch_executor.cpp @@ -850,12 +850,14 @@ namespace mongo { incOpStats( updateItem ); WriteOpResult result; + + WriteUnitOfWork wunit(_txn->recoveryUnit()); multiUpdate( _txn, updateItem, &result ); + wunit.commit(); if ( !result.getStats().upsertedID.isEmpty() ) { *upsertedId = result.getStats().upsertedID; } - // END CURRENT OP incWriteStats( updateItem, result.getStats(), result.getError(), currentOp.get() ); finishCurrentOp( _txn, _client, currentOp.get(), result.getError() ); @@ -925,6 +927,7 @@ namespace mongo { dassert(database); _collection = database->getCollection(txn, request->getTargetingNS()); if (!_collection) { + WriteUnitOfWork wunit (txn->recoveryUnit()); // Implicitly create if it doesn't exist _collection = database->createCollection(txn, request->getTargetingNS()); if (!_collection) { @@ -934,6 +937,7 @@ namespace mongo { request->getTargetingNS()))); return false; } + wunit.commit(); } return true; } @@ -966,12 +970,14 @@ namespace mongo { try { if (state->lockAndCheck(result)) { + WriteUnitOfWork wunit (state->txn->recoveryUnit()); if (!state->request->isInsertIndexRequest()) { singleInsert(state->txn, insertDoc, state->getCollection(), result); } else { singleCreateIndex(state->txn, insertDoc, state->getCollection(), result); } + wunit.commit(); } } catch (const DBException& ex) { @@ -1096,6 +1102,7 @@ namespace mongo { Lock::DBWrite writeLock(txn->lockState(), nsString.ns(), useExperimentalDocLocking); /////////////////////////////////////////// + WriteUnitOfWork wunit(txn->recoveryUnit()); if (!checkShardVersion(txn, &shardingState, *updateItem.getRequest(), result)) return; @@ -1122,6 +1129,7 @@ namespace mongo { } result->setError(toWriteError(status)); } + wunit.commit(); } /** @@ -1150,6 +1158,7 @@ namespace mongo { /////////////////////////////////////////// Lock::DBWrite writeLock(txn->lockState(), nss.ns()); /////////////////////////////////////////// + WriteUnitOfWork wunit(txn->recoveryUnit()); // Check version once we're locked @@ -1172,6 +1181,7 @@ namespace mongo { } result->setError(toWriteError(status)); } + wunit.commit(); } } // namespace mongo diff --git a/src/mongo/db/db.cpp b/src/mongo/db/db.cpp index 75242557c32..becde7a04b5 100644 --- a/src/mongo/db/db.cpp +++ b/src/mongo/db/db.cpp @@ -255,6 +255,7 @@ namespace mongo { OperationContextImpl txn; Lock::GlobalWrite lk(txn.lockState()); + // No WriteUnitOfWork, as DirectClient creates its own units of work DBDirectClient c(&txn); static const char* name = "local.startup_log"; @@ -327,6 +328,7 @@ namespace mongo { OperationContextImpl txn; Lock::GlobalWrite lk(txn.lockState()); + WriteUnitOfWork wunit(txn.recoveryUnit()); vector< string > dbNames; globalStorageEngine->listDatabases( &dbNames ); @@ -396,6 +398,7 @@ namespace mongo { Database::closeDatabase(&txn, dbName.c_str()); } } + wunit.commit(); LOG(1) << "done repairDatabases" << endl; } diff --git a/src/mongo/db/dbcommands.cpp b/src/mongo/db/dbcommands.cpp index aaaec51e0a7..6a8484e68e2 100644 --- a/src/mongo/db/dbcommands.cpp +++ b/src/mongo/db/dbcommands.cpp @@ -182,6 +182,7 @@ namespace mongo { // and that may need a global lock. Lock::GlobalWrite lk(txn->lockState()); Client::Context context(txn, dbname); + WriteUnitOfWork wunit(txn->recoveryUnit()); log() << "dropDatabase " << dbname << " starting" << endl; @@ -192,6 +193,8 @@ namespace mongo { if (!fromRepl) repl::logOp(txn, "c",(dbname + ".$cmd").c_str(), cmdObj); + + wunit.commit(); } result.append( "dropped" , dbname ); @@ -331,6 +334,7 @@ namespace mongo { // in the local database. // Lock::DBWrite dbXLock(txn->lockState(), dbname); + WriteUnitOfWork wunit(txn->recoveryUnit()); Client::Context ctx(txn, dbname); BSONElement e = cmdObj.firstElement(); @@ -350,6 +354,7 @@ namespace mongo { if ( slow.isNumber() ) serverGlobalParams.slowMS = slow.numberInt(); + wunit.commit(); return ok; } } cmdProfile; @@ -436,6 +441,7 @@ namespace mongo { } Lock::DBWrite dbXLock(txn->lockState(), dbname); + WriteUnitOfWork wunit(txn->recoveryUnit()); Client::Context ctx(txn, nsToDrop); Database* db = ctx.db(); @@ -455,15 +461,16 @@ namespace mongo { Status s = db->dropCollection( txn, nsToDrop ); - if ( s.isOK() ) { - if (!fromRepl) - repl::logOp(txn, "c",(dbname + ".$cmd").c_str(), cmdObj); - return true; + if ( !s.isOK() ) { + return appendCommandStatus( result, s ); } - appendCommandStatus( result, s ); + if ( !fromRepl ) { + repl::logOp(txn, "c",(dbname + ".$cmd").c_str(), cmdObj); + } + wunit.commit(); + return true; - return false; } } cmdDrop; @@ -534,11 +541,17 @@ namespace mongo { options.hasField("$nExtents")); Lock::DBWrite dbXLock(txn->lockState(), dbname); + WriteUnitOfWork wunit(txn->recoveryUnit()); Client::Context ctx(txn, ns); // Create collection. - return appendCommandStatus( result, - userCreateNS(txn, ctx.db(), ns.c_str(), options, !fromRepl) ); + status = userCreateNS(txn, ctx.db(), ns.c_str(), options, !fromRepl); + if ( !status.isOK() ) { + return appendCommandStatus( result, status ); + } + + wunit.commit(); + return true; } } cmdCreate; @@ -570,6 +583,7 @@ namespace mongo { bool run(OperationContext* txn, const string& dbname , BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool /*fromRepl*/) { Lock::GlobalWrite globalWriteLock(txn->lockState()); + // No WriteUnitOfWork necessary, as no actual writes happen. Client::Context ctx(txn, dbname); try { @@ -954,6 +968,7 @@ namespace mongo { const string ns = dbname + "." + jsobj.firstElement().valuestr(); Lock::DBWrite dbXLock(txn->lockState(), dbname); + WriteUnitOfWork wunit(txn->recoveryUnit()); Client::Context ctx(txn, ns ); Collection* coll = ctx.db()->getCollection( txn, ns ); @@ -1035,11 +1050,17 @@ namespace mongo { } } } + + if (!ok) { + return false; + } - if (ok && !fromRepl) + if (!fromRepl) { repl::logOp(txn, "c",(dbname + ".$cmd").c_str(), jsobj); + } - return ok; + wunit.commit(); + return true; } } collectionModCommand; diff --git a/src/mongo/db/dbeval.cpp b/src/mongo/db/dbeval.cpp index e5bd01890e7..41069802f1d 100644 --- a/src/mongo/db/dbeval.cpp +++ b/src/mongo/db/dbeval.cpp @@ -1,4 +1,4 @@ -// commands.cpp +// dbeval.cpp /** * Copyright (C) 2012 10gen Inc. @@ -143,6 +143,7 @@ namespace mongo { } Lock::GlobalWrite lk(txn->lockState()); + // No WriteUnitOfWork necessary, as dbEval will create its own, see "nolock" case above Client::Context ctx(txn, dbname ); return dbEval(dbname, cmdObj, result, errmsg); diff --git a/src/mongo/db/dbhelpers.cpp b/src/mongo/db/dbhelpers.cpp index 0de77233f93..a587d1084a4 100644 --- a/src/mongo/db/dbhelpers.cpp +++ b/src/mongo/db/dbhelpers.cpp @@ -423,6 +423,7 @@ namespace mongo { collection->deleteDocument( txn, rloc, false, false, &deletedId ); // The above throws on failure, and so is not logged repl::logOp(txn, "d", ns.c_str(), deletedId, 0, 0, fromMigrate); + ctx.commit(); numDeleted++; } diff --git a/src/mongo/db/index_builder.cpp b/src/mongo/db/index_builder.cpp index c99a51d15be..0486baf8abd 100644 --- a/src/mongo/db/index_builder.cpp +++ b/src/mongo/db/index_builder.cpp @@ -72,6 +72,7 @@ namespace mongo { if ( !status.isOK() ) { log() << "IndexBuilder could not build index: " << status.toString(); } + ctx.commit(); cc().shutdown(); } diff --git a/src/mongo/db/index_rebuilder.cpp b/src/mongo/db/index_rebuilder.cpp index c85c6b66f3f..d85a0379042 100644 --- a/src/mongo/db/index_rebuilder.cpp +++ b/src/mongo/db/index_rebuilder.cpp @@ -145,6 +145,7 @@ namespace mongo { } } + ctx.commit(); } } diff --git a/src/mongo/db/instance.cpp b/src/mongo/db/instance.cpp index 3edb27e5e65..bd35e4f2bd6 100644 --- a/src/mongo/db/instance.cpp +++ b/src/mongo/db/instance.cpp @@ -609,6 +609,7 @@ namespace mongo { uassertStatusOK(executor.prepare()); Lock::DBWrite lk(txn->lockState(), ns.ns(), useExperimentalDocLocking); + WriteUnitOfWork wunit(txn->recoveryUnit()); // if this ever moves to outside of lock, need to adjust check // Client::Context::_finishInit @@ -621,6 +622,7 @@ namespace mongo { // for getlasterror lastError.getSafe()->recordUpdate( res.existing , res.numMatched , res.upserted ); + wunit.commit(); } void receivedDelete(OperationContext* txn, Message& m, CurOp& op) { @@ -649,6 +651,7 @@ namespace mongo { DeleteExecutor executor(&request); uassertStatusOK(executor.prepare()); Lock::DBWrite lk(txn->lockState(), ns.ns()); + WriteUnitOfWork wunit(txn->recoveryUnit()); // if this ever moves to outside of lock, need to adjust check Client::Context::_finishInit if ( ! broadcast && handlePossibleShardedMessage( m , 0 ) ) @@ -659,6 +662,7 @@ namespace mongo { long long n = executor.execute(txn, ctx.db()); lastError.getSafe()->recordDelete( n ); op.debug().ndeleted = n; + wunit.commit(); } QueryResult* emptyMoreResult(long long); @@ -895,6 +899,7 @@ namespace mongo { if ( handlePossibleShardedMessage( m , 0 ) ) return; + WriteUnitOfWork wunit(txn->recoveryUnit()); Client::Context ctx(txn, ns); if (multi.size() > 1) { @@ -905,6 +910,7 @@ namespace mongo { globalOpCounters.incInsertInWriteLock(1); op.debug().ninserted = 1; } + wunit.commit(); } /* returns true if there is data on this server. useful when starting replication. diff --git a/src/mongo/db/introspect.cpp b/src/mongo/db/introspect.cpp index 87b74e6201a..3c3bb24353d 100644 --- a/src/mongo/db/introspect.cpp +++ b/src/mongo/db/introspect.cpp @@ -138,8 +138,11 @@ namespace { // we're sometimes inside the lock already Lock::DBWrite lk(txn->lockState(), currentOp.getNS() ); if (dbHolder().get(txn, nsToDatabase(currentOp.getNS())) != NULL) { + // We are ok with the profiling happening in a different WUOW from the actual op. + WriteUnitOfWork wunit(txn->recoveryUnit()); Client::Context cx(txn, currentOp.getNS(), false); _profile(txn, c, cx.db(), currentOp, profileBufBuilder); + wunit.commit(); } else { mongo::log() << "note: not profiling because db went away - probably a close on: " diff --git a/src/mongo/db/repl/master_slave.cpp b/src/mongo/db/repl/master_slave.cpp index bdbbc14cc41..3199c82d4db 100644 --- a/src/mongo/db/repl/master_slave.cpp +++ b/src/mongo/db/repl/master_slave.cpp @@ -180,6 +180,7 @@ namespace repl { _me = b.obj(); Helpers::putSingleton(&txn, "local.me", _me); } + ctx.commit(); } } diff --git a/src/mongo/db/repl/oplog.cpp b/src/mongo/db/repl/oplog.cpp index 18754046e2f..5206c3f613b 100644 --- a/src/mongo/db/repl/oplog.cpp +++ b/src/mongo/db/repl/oplog.cpp @@ -117,6 +117,9 @@ namespace repl { void _logOpObjRS(const BSONObj& op) { OperationContextImpl txn; Lock::DBWrite lk(txn.lockState(), "local"); + // XXX soon this needs to be part of an outer WUOW not its own. + // We can't do this yet due to locking limitations. + WriteUnitOfWork wunit(txn.recoveryUnit()); const OpTime ts = op["ts"]._opTime(); long long h = op["h"].numberLong(); @@ -160,6 +163,7 @@ namespace repl { } setNewOptime(ts); + wunit.commit(); } /** @@ -236,6 +240,7 @@ namespace repl { bool *bb, bool fromMigrate ) { Lock::DBWrite lk1(txn->lockState(), "local"); + WriteUnitOfWork wunit(txn->recoveryUnit()); if ( strncmp(ns, "local.", 6) == 0 ) { if ( strncmp(ns, "local.slaves", 12) == 0 ) @@ -314,6 +319,7 @@ namespace repl { theReplSet->lastH = hashNew; ctx.getClient()->setLastOp( ts ); } + wunit.commit(); } @@ -326,6 +332,7 @@ namespace repl { bool *bb, bool fromMigrate ) { Lock::DBWrite lk(txn->lockState(), "local"); + WriteUnitOfWork wunit(txn->recoveryUnit()); static BufBuilder bufbuilder(8*1024); // todo there is likely a mutex on this constructor if ( strncmp(ns, "local.", 6) == 0 ) { @@ -374,6 +381,7 @@ namespace repl { checkOplogInsert( localOplogMainCollection->insertDocument( txn, &writer, false ) ); ctx.getClient()->setLastOp( ts ); + wunit.commit(); } static void (*_logOp)(OperationContext* txn, @@ -512,9 +520,11 @@ namespace repl { options.cappedSize = sz; options.autoIndexId = CollectionOptions::NO; + WriteUnitOfWork wunit(txn.recoveryUnit()); invariant( ctx.db()->createCollection( &txn, ns, options ) ); if( !rs ) logOp( &txn, "n", "", BSONObj() ); + wunit.commit(); /* sync here so we don't get any surprising lag later when we try to sync */ globalStorageEngine->flushAllFiles(true); diff --git a/src/mongo/db/repl/repl_set_impl.cpp b/src/mongo/db/repl/repl_set_impl.cpp index 030da5fc532..1cedecf0880 100644 --- a/src/mongo/db/repl/repl_set_impl.cpp +++ b/src/mongo/db/repl/repl_set_impl.cpp @@ -871,13 +871,17 @@ namespace { void ReplSetImpl::clearInitialSyncFlag() { OperationContextImpl txn; // XXX? Lock::DBWrite lk(txn.lockState(), "local"); + WriteUnitOfWork wunit(txn.recoveryUnit()); Helpers::putSingleton(&txn, "local.replset.minvalid", BSON("$unset" << _initialSyncFlag)); + wunit.commit(); } void ReplSetImpl::setInitialSyncFlag() { OperationContextImpl txn; // XXX? Lock::DBWrite lk(txn.lockState(), "local"); + WriteUnitOfWork wunit(txn.recoveryUnit()); Helpers::putSingleton(&txn, "local.replset.minvalid", BSON("$set" << _initialSyncFlag)); + wunit.commit(); } bool ReplSetImpl::getInitialSyncFlag() { @@ -898,7 +902,9 @@ namespace { OperationContextImpl txn; // XXX? Lock::DBWrite lk(txn.lockState(), "local"); + WriteUnitOfWork wunit(txn.recoveryUnit()); Helpers::putSingleton(&txn, "local.replset.minvalid", builder.obj()); + wunit.commit(); } OpTime ReplSetImpl::getMinValid() { diff --git a/src/mongo/db/repl/resync.cpp b/src/mongo/db/repl/resync.cpp index ca16a00139a..5267532e17e 100644 --- a/src/mongo/db/repl/resync.cpp +++ b/src/mongo/db/repl/resync.cpp @@ -68,6 +68,7 @@ namespace repl { const std::string ns = parseNs(dbname, cmdObj); Lock::GlobalWrite globalWriteLock(txn->lockState()); + WriteUnitOfWork wunit(txn->recoveryUnit()); Client::Context ctx(txn, ns); if (replSettings.usingReplSets()) { if (!theReplSet) { @@ -96,6 +97,7 @@ namespace repl { ReplSource::forceResyncDead( txn, "client" ); result.append( "info", "triggered resync for all sources" ); + wunit.commit(); return true; } diff --git a/src/mongo/db/repl/rs_config.cpp b/src/mongo/db/repl/rs_config.cpp index a064289ab86..b92e665b2b1 100644 --- a/src/mongo/db/repl/rs_config.cpp +++ b/src/mongo/db/repl/rs_config.cpp @@ -94,6 +94,7 @@ namespace { false/*logOp=false; local db so would work regardless...*/); if( !comment.isEmpty() && (!theReplSet || theReplSet->isPrimary()) ) logOpInitiate(&txn, comment); + cx.commit(); } log() << "replSet saveConfigLocally done" << rsLog; } diff --git a/src/mongo/db/repl/rs_initialsync.cpp b/src/mongo/db/repl/rs_initialsync.cpp index f045a6155f7..b685325a1c4 100644 --- a/src/mongo/db/repl/rs_initialsync.cpp +++ b/src/mongo/db/repl/rs_initialsync.cpp @@ -115,6 +115,7 @@ namespace repl { // Make database stable Lock::DBWrite dbWrite(txn->lockState(), db); + WriteUnitOfWork wunit(txn->recoveryUnit()); if (!cloner.go(txn, db, master, options, NULL, err, &errCode)) { sethbmsg(str::stream() << "initial sync: error while " @@ -123,6 +124,7 @@ namespace repl { << "sleeping 5 minutes" ,0); return false; } + wunit.commit(); } return true; @@ -142,6 +144,7 @@ namespace repl { LOG(1) << "replSet empty oplog" << rsLog; uassertStatusOK( collection->truncate(&txn) ); + ctx.commit(); } const Member* ReplSetImpl::getMemberToSyncTo() { @@ -477,6 +480,7 @@ namespace repl { // Clear the initial sync flag. theReplSet->clearInitialSyncFlag(); + cx.commit(); } { boost::unique_lock<boost::mutex> lock(theReplSet->initialSyncMutex); diff --git a/src/mongo/db/repl/sync.cpp b/src/mongo/db/repl/sync.cpp index c9f43ebf894..a112603aed0 100644 --- a/src/mongo/db/repl/sync.cpp +++ b/src/mongo/db/repl/sync.cpp @@ -124,6 +124,7 @@ namespace repl { return false; } else { + WriteUnitOfWork wunit(txn->recoveryUnit()); Collection* collection = ctx.db()->getOrCreateCollection(txn, ns); invariant(collection != NULL); // should never happen @@ -133,6 +134,7 @@ namespace repl { result.isOK() ); LOG(1) << "replication inserted missing doc: " << missingObj.toString() << endl; + wunit.commit(); return true; } } diff --git a/src/mongo/db/repl/sync_source_feedback.cpp b/src/mongo/db/repl/sync_source_feedback.cpp index 774748288b5..0062fe20f20 100644 --- a/src/mongo/db/repl/sync_source_feedback.cpp +++ b/src/mongo/db/repl/sync_source_feedback.cpp @@ -84,6 +84,7 @@ namespace repl { _me = b.obj(); Helpers::putSingleton(&txn, "local.me", _me); } + ctx.commit(); // _me is used outside of a read lock, so we must copy it out of the mmap _me = _me.getOwned(); } diff --git a/src/mongo/db/repl/sync_tail.cpp b/src/mongo/db/repl/sync_tail.cpp index ce4e3902a59..742fa123412 100644 --- a/src/mongo/db/repl/sync_tail.cpp +++ b/src/mongo/db/repl/sync_tail.cpp @@ -107,11 +107,13 @@ namespace repl { } Client::Context ctx(txn, ns); + WriteUnitOfWork wunit(txn->recoveryUnit()); ctx.getClient()->curop()->reset(); // For non-initial-sync, we convert updates to upserts // to suppress errors when replaying oplog entries. bool ok = !applyOperation_inlock(txn, ctx.db(), op, true, convertUpdateToUpsert); opsAppliedStats.increment(); + wunit.commit(); txn->recoveryUnit()->commitIfNeeded(); return ok; @@ -478,6 +480,7 @@ namespace repl { { OperationContextImpl txn; // XXX? Lock::DBWrite lk(txn.lockState(), "local"); + WriteUnitOfWork wunit(txn.recoveryUnit()); while (!ops->empty()) { const BSONObj& op = ops->front(); @@ -485,6 +488,7 @@ namespace repl { _logOpObjRS(op); ops->pop_front(); } + wunit.commit(); } if (BackgroundSync::get()->isAssumingPrimary()) { diff --git a/src/mongo/db/ttl.cpp b/src/mongo/db/ttl.cpp index a3e1d7ccea3..8fb39e89642 100644 --- a/src/mongo/db/ttl.cpp +++ b/src/mongo/db/ttl.cpp @@ -138,6 +138,7 @@ namespace mongo { n = deleteObjects(&txn, ctx.ctx().db(), ns, query, false, true); ttlDeletedDocuments.increment( n ); + ctx.commit(); } LOG(1) << "\tTTL deleted: " << n << endl; diff --git a/src/mongo/dbtests/basictests.cpp b/src/mongo/dbtests/basictests.cpp index 1fbd27763c4..fc8ec367167 100644 --- a/src/mongo/dbtests/basictests.cpp +++ b/src/mongo/dbtests/basictests.cpp @@ -379,7 +379,9 @@ namespace BasicTests { OperationContextImpl txn; Lock::GlobalWrite lk(txn.lockState()); + WriteUnitOfWork wunit(txn.recoveryUnit()); Database db( &txn, "dbtests_basictests_ownsns", NULL ); + wunit.commit(); ASSERT( db.ownsNS( "dbtests_basictests_ownsns.x" ) ); ASSERT( db.ownsNS( "dbtests_basictests_ownsns.x.y" ) ); diff --git a/src/mongo/dbtests/clienttests.cpp b/src/mongo/dbtests/clienttests.cpp index 1ba539f0266..4f4e7a96f15 100644 --- a/src/mongo/dbtests/clienttests.cpp +++ b/src/mongo/dbtests/clienttests.cpp @@ -160,6 +160,7 @@ namespace ClientTests { ASSERT_EQUALS(3U, db.count("test.system.namespaces")); db.ensureIndex(ns(), BSON("x" << 1), true); + ctx.commit(); ASSERT_EQUALS(2, indexCatalog->numIndexesReady()); ASSERT_EQUALS(2U, db.count("test.system.indexes")); diff --git a/src/mongo/dbtests/counttests.cpp b/src/mongo/dbtests/counttests.cpp index f8119b632a1..879d4353a0e 100644 --- a/src/mongo/dbtests/counttests.cpp +++ b/src/mongo/dbtests/counttests.cpp @@ -42,7 +42,7 @@ namespace CountTests { class Base { public: - Base() : lk(_txn.lockState(), ns()), _context(&_txn, ns()) { + Base() : lk(_txn.lockState(), ns()), _wunit(_txn.recoveryUnit()), _context(&_txn, ns()) { _database = _context.db(); _collection = _database->getCollection( &_txn, ns() ); if ( _collection ) { @@ -55,6 +55,7 @@ namespace CountTests { ~Base() { try { uassertStatusOK( _database->dropCollection( &_txn, ns() ) ); + _wunit.commit(); } catch ( ... ) { FAIL( "Exception while cleaning up collection" ); @@ -97,6 +98,7 @@ namespace CountTests { private: Lock::DBWrite lk; + WriteUnitOfWork _wunit; Client::Context _context; diff --git a/src/mongo/dbtests/dbhelper_tests.cpp b/src/mongo/dbtests/dbhelper_tests.cpp index 88c04aece66..33d190ed34c 100644 --- a/src/mongo/dbtests/dbhelper_tests.cpp +++ b/src/mongo/dbtests/dbhelper_tests.cpp @@ -61,6 +61,7 @@ namespace mongo { { // Remove _id range [_min, _max). Lock::DBWrite lk(txn.lockState(), ns); + WriteUnitOfWork wunit(txn.recoveryUnit()); Client::Context ctx(&txn, ns ); KeyRange range( ns, @@ -68,6 +69,7 @@ namespace mongo { BSON( "_id" << _max ), BSON( "_id" << 1 ) ); Helpers::removeRange( &txn, range ); + wunit.commit(); } // Check that the expected documents remain. diff --git a/src/mongo/dbtests/indexcatalogtests.cpp b/src/mongo/dbtests/indexcatalogtests.cpp index bf9b61cf5d3..21fb94ca24b 100644 --- a/src/mongo/dbtests/indexcatalogtests.cpp +++ b/src/mongo/dbtests/indexcatalogtests.cpp @@ -37,6 +37,7 @@ namespace IndexCatalogTests { _db = ctx.ctx().db(); _coll = _db->createCollection(&txn, _ns); _catalog = _coll->getIndexCatalog(); + ctx.commit(); } ~IndexIteratorTests() { @@ -44,6 +45,7 @@ namespace IndexCatalogTests { Client::WriteContext ctx(&txn, _ns); _db->dropCollection(&txn, _ns); + ctx.commit(); } void run() { @@ -83,6 +85,7 @@ namespace IndexCatalogTests { } } + ctx.commit(); ASSERT_TRUE(indexesIterated == _catalog->numIndexesReady()); ASSERT_TRUE(foundIndex); } diff --git a/src/mongo/dbtests/indexupdatetests.cpp b/src/mongo/dbtests/indexupdatetests.cpp index 3458181887a..f5c24e3ce59 100644 --- a/src/mongo/dbtests/indexupdatetests.cpp +++ b/src/mongo/dbtests/indexupdatetests.cpp @@ -59,6 +59,7 @@ namespace IndexUpdateTests { } ~IndexBuildBase() { _client.dropCollection( _ns ); + _ctx.commit(); // just for testing purposes getGlobalEnvironment()->unsetKillAllOperations(); } Collection* collection() { @@ -469,6 +470,7 @@ namespace IndexUpdateTests { public: void run() { OperationContextImpl txn; + WriteUnitOfWork wunit (txn.recoveryUnit()); // Insert some documents. int32_t nDocs = 1000; for( int32_t i = 0; i < nDocs; ++i ) { @@ -481,6 +483,7 @@ namespace IndexUpdateTests { // The call is not interrupted. Helpers::ensureIndex( &txn, collection(), BSON( "a" << 1 ), false, "a_1" ); // only want to interrupt the index build + wunit.commit(); getGlobalEnvironment()->unsetKillAllOperations(); // The new index is listed in system.indexes because the index build completed. ASSERT_EQUALS( 1U, diff --git a/src/mongo/dbtests/oplogstarttests.cpp b/src/mongo/dbtests/oplogstarttests.cpp index 45015afe883..4f4f88c1ccc 100644 --- a/src/mongo/dbtests/oplogstarttests.cpp +++ b/src/mongo/dbtests/oplogstarttests.cpp @@ -38,6 +38,7 @@ namespace OplogStartTests { class Base { public: Base() : _lk(_txn.lockState()), + _wunit(_txn.recoveryUnit()), _context(&_txn, ns()), _client(&_txn) { @@ -50,6 +51,7 @@ namespace OplogStartTests { ~Base() { client()->dropCollection(ns()); + _wunit.commit(); } protected: @@ -94,6 +96,7 @@ namespace OplogStartTests { // The order of these is important in order to ensure order of destruction OperationContextImpl _txn; Lock::GlobalWrite _lk; + WriteUnitOfWork _wunit; Client::Context _context; DBDirectClient _client; diff --git a/src/mongo/dbtests/pdfiletests.cpp b/src/mongo/dbtests/pdfiletests.cpp index d954c801fdd..aa6026d3d40 100644 --- a/src/mongo/dbtests/pdfiletests.cpp +++ b/src/mongo/dbtests/pdfiletests.cpp @@ -48,14 +48,15 @@ namespace PdfileTests { class Base { public: Base() : _lk(_txn.lockState()), + _wunit(_txn.recoveryUnit()), _context(&_txn, ns()) { - } virtual ~Base() { if ( !collection() ) return; _context.db()->dropCollection( &_txn, ns() ); + _wunit.commit(); } protected: @@ -68,7 +69,7 @@ namespace PdfileTests { OperationContextImpl _txn; Lock::GlobalWrite _lk; - + WriteUnitOfWork _wunit; Client::Context _context; }; diff --git a/src/mongo/dbtests/plan_ranking.cpp b/src/mongo/dbtests/plan_ranking.cpp index 79419bb60fa..7b8f01add03 100644 --- a/src/mongo/dbtests/plan_ranking.cpp +++ b/src/mongo/dbtests/plan_ranking.cpp @@ -66,6 +66,7 @@ namespace PlanRankingTests { Client::WriteContext ctx(&_txn, ns); _client.dropCollection(ns); + ctx.commit(); } virtual ~PlanRankingTestBase() { @@ -76,11 +77,13 @@ namespace PlanRankingTests { void insert(const BSONObj& obj) { Client::WriteContext ctx(&_txn, ns); _client.insert(ns, obj); + ctx.commit(); } void addIndex(const BSONObj& obj) { Client::WriteContext ctx(&_txn, ns); _client.ensureIndex(ns, obj); + ctx.commit(); } /** diff --git a/src/mongo/dbtests/query_multi_plan_runner.cpp b/src/mongo/dbtests/query_multi_plan_runner.cpp index f47d08ecfe8..81982df6768 100644 --- a/src/mongo/dbtests/query_multi_plan_runner.cpp +++ b/src/mongo/dbtests/query_multi_plan_runner.cpp @@ -164,6 +164,7 @@ namespace QueryMultiPlanRunner { ASSERT_EQUALS(obj["foo"].numberInt(), 7); ++results; } + ctx.commit(); ASSERT_EQUALS(results, N / 10); } diff --git a/src/mongo/dbtests/query_single_solution_runner.cpp b/src/mongo/dbtests/query_single_solution_runner.cpp index d5290853151..91596c5cf49 100644 --- a/src/mongo/dbtests/query_single_solution_runner.cpp +++ b/src/mongo/dbtests/query_single_solution_runner.cpp @@ -205,6 +205,7 @@ namespace QuerySingleSolutionRunner { ASSERT_EQUALS(Runner::RUNNER_DEAD, ssr->getNext(&objOut, NULL)); deregisterRunner(ssr.get()); + ctx.commit(); } }; @@ -235,6 +236,7 @@ namespace QuerySingleSolutionRunner { ASSERT_EQUALS(Runner::RUNNER_DEAD, ssr->getNext(&objOut, NULL)); deregisterRunner(ssr.get()); + ctx.commit(); } }; @@ -300,6 +302,7 @@ namespace QuerySingleSolutionRunner { int ids[] = {3, 4, 2}; checkIds(ids, ssr.get()); + ctx.commit(); } }; @@ -329,6 +332,7 @@ namespace QuerySingleSolutionRunner { // we should not see the moved document again. int ids[] = {3, 4}; checkIds(ids, ssr.get()); + ctx.commit(); } }; @@ -357,6 +361,7 @@ namespace QuerySingleSolutionRunner { ASSERT_EQUALS(1U, numCursors()); ctx.ctx().db()->getCollection( &_txn, ns() )->cursorCache()->invalidateAll(false); ASSERT_EQUALS(0U, numCursors()); + ctx.commit(); } }; @@ -394,6 +399,7 @@ namespace QuerySingleSolutionRunner { // number of cursors to return to 0. ccPin.deleteUnderlying(); ASSERT_EQUALS(0U, numCursors()); + ctx.commit(); } }; @@ -407,6 +413,7 @@ namespace QuerySingleSolutionRunner { { Client::WriteContext ctx(&_txn, ns()); insert(BSON("a" << 1 << "b" << 1)); + ctx.commit(); } { diff --git a/src/mongo/dbtests/query_stage_and.cpp b/src/mongo/dbtests/query_stage_and.cpp index 59a5ae3819f..75b144c7e45 100644 --- a/src/mongo/dbtests/query_stage_and.cpp +++ b/src/mongo/dbtests/query_stage_and.cpp @@ -222,6 +222,7 @@ namespace QueryStageAnd { ASSERT_GREATER_THAN_OR_EQUALS(elt.numberInt(), 10); } + ctx.commit(); ASSERT_EQUALS(10, count); } }; @@ -308,6 +309,7 @@ namespace QueryStageAnd { ++count; } + ctx.commit(); ASSERT_EQUALS(count, 20); } }; @@ -351,6 +353,7 @@ namespace QueryStageAnd { params.bounds.endKeyInclusive = true; params.direction = 1; ah->addChild(new IndexScan(params, &ws, NULL)); + ctx.commit(); // foo == bar == baz, and foo<=20, bar>=10, so our values are: // foo == 10, 11, 12, 13, 14, 15. 16, 17, 18, 19, 20 @@ -405,6 +408,7 @@ namespace QueryStageAnd { params.bounds.endKeyInclusive = true; params.direction = 1; ah->addChild(new IndexScan(params, &ws, NULL)); + ctx.commit(); // Stage execution should fail. ASSERT_EQUALS(-1, countResults(ah.get())); @@ -457,6 +461,7 @@ namespace QueryStageAnd { params.bounds.endKeyInclusive = true; params.direction = 1; ah->addChild(new IndexScan(params, &ws, NULL)); + ctx.commit(); // foo == bar == baz, and foo<=20, bar>=10, so our values are: // foo == 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20. @@ -512,6 +517,7 @@ namespace QueryStageAnd { params.bounds.endKeyInclusive = true; params.direction = 1; ah->addChild(new IndexScan(params, &ws, NULL)); + ctx.commit(); // foo == bar == baz, and foo<=20, bar>=10, 5<=baz<=15, so our values are: // foo == 10, 11, 12, 13, 14, 15. @@ -578,6 +584,7 @@ namespace QueryStageAnd { params.bounds.endKeyInclusive = true; params.direction = 1; ah->addChild(new IndexScan(params, &ws, NULL)); + ctx.commit(); // Stage execution should fail. ASSERT_EQUALS(-1, countResults(ah.get())); @@ -633,6 +640,7 @@ namespace QueryStageAnd { if (PlanStage::ADVANCED != status) { continue; } ++count; } + ctx.commit(); ASSERT_EQUALS(0, count); @@ -686,6 +694,7 @@ namespace QueryStageAnd { params.bounds.endKeyInclusive = false; params.direction = -1; ah->addChild(new IndexScan(params, &ws, NULL)); + ctx.commit(); ASSERT_EQUALS(0, countResults(ah.get())); } @@ -734,6 +743,7 @@ namespace QueryStageAnd { params.bounds.endKeyInclusive = true; params.direction = 1; ah->addChild(new IndexScan(params, &ws, NULL)); + ctx.commit(); // Bar == 97 ASSERT_EQUALS(1, countResults(ah.get())); @@ -856,6 +866,7 @@ namespace QueryStageAnd { ASSERT_TRUE(member->getFieldDotted("bar", &elt)); ASSERT_EQUALS(1, elt.numberInt()); } + ctx.commit(); ASSERT_EQUALS(count, 48); @@ -912,6 +923,7 @@ namespace QueryStageAnd { // baz == 1 params.descriptor = getIndex(BSON("baz" << 1), coll); ah->addChild(new IndexScan(params, &ws, NULL)); + ctx.commit(); ASSERT_EQUALS(50, countResults(ah.get())); } @@ -957,6 +969,7 @@ namespace QueryStageAnd { params.bounds.endKeyInclusive = true; params.direction = 1; ah->addChild(new IndexScan(params, &ws, NULL)); + ctx.commit(); ASSERT_EQUALS(0, countResults(ah.get())); } @@ -1005,6 +1018,7 @@ namespace QueryStageAnd { params.bounds.endKeyInclusive = true; params.direction = 1; ah->addChild(new IndexScan(params, &ws, NULL)); + ctx.commit(); ASSERT_EQUALS(0, countResults(ah.get())); } @@ -1049,6 +1063,7 @@ namespace QueryStageAnd { // bar == 1 params.descriptor = getIndex(BSON("bar" << 1), coll); ah->addChild(new IndexScan(params, &ws, NULL)); + ctx.commit(); // Filter drops everything. ASSERT_EQUALS(0, countResults(ah.get())); @@ -1109,6 +1124,7 @@ namespace QueryStageAnd { } lastId = id; } + ctx.commit(); ASSERT_EQUALS(count, 43); } diff --git a/src/mongo/dbtests/query_stage_collscan.cpp b/src/mongo/dbtests/query_stage_collscan.cpp index 647b721f878..06088bf425a 100644 --- a/src/mongo/dbtests/query_stage_collscan.cpp +++ b/src/mongo/dbtests/query_stage_collscan.cpp @@ -59,6 +59,7 @@ namespace QueryStageCollectionScan { virtual ~QueryStageCollectionScanCappedBase() { _context.db()->dropCollection( &_txn, ns() ); + wunit.commit(); } void run() { @@ -175,6 +176,7 @@ namespace QueryStageCollectionScan { Lock::GlobalWrite lk_; Client::Context _context; OperationContextImpl _txn; + WriteUnitOfWork wunit(_txn.recoveryUnit()); }; class QueryStageCollscanEmpty : public QueryStageCollectionScanCappedBase { @@ -321,11 +323,13 @@ namespace QueryStageCollectionScan { bob.append("foo", i); _client.insert(ns(), bob.obj()); } + ctx.commit(); } virtual ~QueryStageCollectionScanBase() { Client::WriteContext ctx(&_txn, ns()); _client.dropCollection(ns()); + ctx.commit(); } void remove(const BSONObj& obj) { @@ -552,6 +556,7 @@ namespace QueryStageCollectionScan { ++count; } } + ctx.commit(); ASSERT_EQUALS(numObj(), count); } @@ -613,6 +618,7 @@ namespace QueryStageCollectionScan { ++count; } } + ctx.commit(); ASSERT_EQUALS(numObj(), count); } diff --git a/src/mongo/dbtests/query_stage_count.cpp b/src/mongo/dbtests/query_stage_count.cpp index 04a45d98044..b4a86309568 100644 --- a/src/mongo/dbtests/query_stage_count.cpp +++ b/src/mongo/dbtests/query_stage_count.cpp @@ -55,6 +55,7 @@ namespace QueryStageCount { virtual ~CountBase() { Client::WriteContext ctx(&_txn, ns()); _client.dropCollection(ns()); + ctx.commit(); } void addIndex(const BSONObj& obj) { @@ -116,6 +117,7 @@ namespace QueryStageCount { // Add an index on a:1 addIndex(BSON("a" << 1)); + ctx.commit(); // Set up the count stage CountParams params; @@ -149,6 +151,7 @@ namespace QueryStageCount { // Add an index addIndex(BSON("a" << 1)); + ctx.commit(); // Set up the count stage CountParams params; @@ -181,6 +184,7 @@ namespace QueryStageCount { // Add an index addIndex(BSON("a" << 1)); + ctx.commit(); // Set up the count stage CountParams params; @@ -209,6 +213,7 @@ namespace QueryStageCount { // Insert doc, add index insert(BSON("a" << 2)); addIndex(BSON("a" << 1)); + ctx.commit(); // Set up count, and run CountParams params; @@ -238,6 +243,7 @@ namespace QueryStageCount { insert(BSON("a" << 2)); insert(BSON("a" << 3)); addIndex(BSON("a" << 1)); + ctx.commit(); // Set up count, and run CountParams params; @@ -268,6 +274,7 @@ namespace QueryStageCount { insert(BSON("a" << 2)); insert(BSON("a" << 4)); addIndex(BSON("a" << 1)); + ctx.commit(); // Set up count, and run CountParams params; @@ -299,6 +306,7 @@ namespace QueryStageCount { insert(BSON("a" << i)); } addIndex(BSON("a" << 1)); + ctx.commit(); // Set up count stage CountParams params; @@ -350,6 +358,7 @@ namespace QueryStageCount { insert(BSON("a" << i)); } addIndex(BSON("a" << 1)); + ctx.commit(); // Set up count stage CountParams params; @@ -404,6 +413,7 @@ namespace QueryStageCount { insert(BSON("a" << i)); } addIndex(BSON("a" << 1)); + ctx.commit(); // Set up count stage CountParams params; @@ -461,6 +471,7 @@ namespace QueryStageCount { insert(BSON("a" << i)); } addIndex(BSON("a" << 1)); + ctx.commit(); // Set up count stage CountParams params; @@ -514,6 +525,7 @@ namespace QueryStageCount { insert(BSON("a" << 1 << "b" << i)); } addIndex(BSON("a" << 1)); + ctx.commit(); // Mark several keys as 'unused' remove(BSON("a" << 1 << "b" << 0)); @@ -552,6 +564,7 @@ namespace QueryStageCount { // Mark key at end position as 'unused' by deleting remove(BSON("a" << 1 << "b" << 9)); + ctx.commit(); // Run count and check CountParams params; @@ -582,6 +595,7 @@ namespace QueryStageCount { insert(BSON("a" << 1 << "b" << i)); } addIndex(BSON("a" << 1)); + ctx.commit(); // Set up count stage CountParams params; diff --git a/src/mongo/dbtests/query_stage_distinct.cpp b/src/mongo/dbtests/query_stage_distinct.cpp index 942c87b264a..ac61fc55fce 100644 --- a/src/mongo/dbtests/query_stage_distinct.cpp +++ b/src/mongo/dbtests/query_stage_distinct.cpp @@ -53,16 +53,19 @@ namespace QueryStageDistinct { virtual ~DistinctBase() { Client::WriteContext ctx(&_txn, ns()); _client.dropCollection(ns()); + ctx.commit(); } void addIndex(const BSONObj& obj) { Client::WriteContext ctx(&_txn, ns()); _client.ensureIndex(ns(), obj); + ctx.commit(); } void insert(const BSONObj& obj) { Client::WriteContext ctx(&_txn, ns()); _client.insert(ns(), obj); + ctx.commit(); } IndexDescriptor* getIndex(const BSONObj& obj) { diff --git a/src/mongo/dbtests/query_stage_fetch.cpp b/src/mongo/dbtests/query_stage_fetch.cpp index 4bea8b9e004..bc95554164a 100644 --- a/src/mongo/dbtests/query_stage_fetch.cpp +++ b/src/mongo/dbtests/query_stage_fetch.cpp @@ -103,6 +103,7 @@ namespace QueryStageFetch { set<DiskLoc> locs; getLocs(&locs, coll); ASSERT_EQUALS(size_t(1), locs.size()); + ctx.commit(); // Create a mock stage that returns the WSM. auto_ptr<MockStage> mockStage(new MockStage(&ws)); @@ -199,6 +200,7 @@ namespace QueryStageFetch { // No more data to fetch, so, EOF. state = fetchStage->work(&id); ASSERT_EQUALS(PlanStage::IS_EOF, state); + ctx.commit(); } }; diff --git a/src/mongo/dbtests/query_stage_keep.cpp b/src/mongo/dbtests/query_stage_keep.cpp index 3283b66ab8c..eca675d6966 100644 --- a/src/mongo/dbtests/query_stage_keep.cpp +++ b/src/mongo/dbtests/query_stage_keep.cpp @@ -127,6 +127,7 @@ namespace QueryStageKeep { member->obj = BSON("x" << 2); ws.flagForReview(id); } + ctx.commit(); // Create a collscan to provide the 10 objects in the collection. CollectionScanParams params; diff --git a/src/mongo/dbtests/query_stage_merge_sort.cpp b/src/mongo/dbtests/query_stage_merge_sort.cpp index 11161a5c6be..2aa83912515 100644 --- a/src/mongo/dbtests/query_stage_merge_sort.cpp +++ b/src/mongo/dbtests/query_stage_merge_sort.cpp @@ -54,6 +54,7 @@ namespace QueryStageMergeSortTests { virtual ~QueryStageMergeSortTestBase() { Client::WriteContext ctx(&_txn, ns()); _client.dropCollection(ns()); + ctx.commit(); } void addIndex(const BSONObj& obj) { @@ -149,6 +150,7 @@ namespace QueryStageMergeSortTests { // b:1 params.descriptor = getIndex(secondIndex, coll); ms->addChild(new IndexScan(params, ws, NULL)); + ctx.commit(); // Must fetch if we want to easily pull out an obj. PlanExecutor runner(ws, new FetchStage(ws, ms, NULL, coll), coll); @@ -212,6 +214,7 @@ namespace QueryStageMergeSortTests { // b:1 params.descriptor = getIndex(secondIndex, coll); ms->addChild(new IndexScan(params, ws, NULL)); + ctx.commit(); PlanExecutor runner(ws, new FetchStage(ws, ms, NULL, coll), coll); @@ -274,6 +277,7 @@ namespace QueryStageMergeSortTests { // b:1 params.descriptor = getIndex(secondIndex, coll); ms->addChild(new IndexScan(params, ws, NULL)); + ctx.commit(); PlanExecutor runner(ws, new FetchStage(ws, ms, NULL, coll), coll); @@ -339,6 +343,7 @@ namespace QueryStageMergeSortTests { // b:1 params.descriptor = getIndex(secondIndex, coll); ms->addChild(new IndexScan(params, ws, NULL)); + ctx.commit(); PlanExecutor runner(ws, new FetchStage(ws, ms, NULL, coll), coll); @@ -403,6 +408,7 @@ namespace QueryStageMergeSortTests { params.bounds.startKey = BSON("" << 51 << "" << MinKey); params.bounds.endKey = BSON("" << 51 << "" << MaxKey); ms->addChild(new IndexScan(params, ws, NULL)); + ctx.commit(); PlanExecutor runner(ws, new FetchStage(ws, ms, NULL, coll), coll); @@ -455,6 +461,7 @@ namespace QueryStageMergeSortTests { params.descriptor = getIndex(indexSpec, coll); ms->addChild(new IndexScan(params, ws, NULL)); } + ctx.commit(); PlanExecutor runner(ws, new FetchStage(ws, ms, NULL, coll), coll); @@ -514,6 +521,7 @@ namespace QueryStageMergeSortTests { getLocs(&locs, coll); set<DiskLoc>::iterator it = locs.begin(); + ctx.commit(); // Get 10 results. Should be getting results in order of 'locs'. int count = 0; diff --git a/src/mongo/dbtests/query_stage_sort.cpp b/src/mongo/dbtests/query_stage_sort.cpp index 6ae66a0b7bb..60838f5df77 100644 --- a/src/mongo/dbtests/query_stage_sort.cpp +++ b/src/mongo/dbtests/query_stage_sort.cpp @@ -193,6 +193,7 @@ namespace QueryStageSortTests { fillData(); sortAndCheck(1, coll); + ctx.commit(); } }; @@ -212,6 +213,7 @@ namespace QueryStageSortTests { fillData(); sortAndCheck(-1, coll); + ctx.commit(); } }; @@ -240,6 +242,7 @@ namespace QueryStageSortTests { fillData(); sortAndCheck(-1, coll); + ctx.commit(); } }; @@ -315,6 +318,7 @@ namespace QueryStageSortTests { ASSERT(!member->hasLoc()); ++count; } + ctx.commit(); // Returns all docs. ASSERT_EQUALS(limit() ? limit() : numObj(), count); @@ -371,6 +375,7 @@ namespace QueryStageSortTests { ws, new FetchStage(ws, new SortStage(params, ws, ms), NULL, coll), coll); Runner::RunnerState runnerState = runner.getNext(NULL, NULL); ASSERT_EQUALS(Runner::RUNNER_ERROR, runnerState); + ctx.commit(); } }; diff --git a/src/mongo/dbtests/query_stage_tests.cpp b/src/mongo/dbtests/query_stage_tests.cpp index fc5ee43ea50..91640817f74 100644 --- a/src/mongo/dbtests/query_stage_tests.cpp +++ b/src/mongo/dbtests/query_stage_tests.cpp @@ -59,16 +59,19 @@ namespace QueryStageTests { addIndex(BSON("foo" << 1)); addIndex(BSON("foo" << 1 << "baz" << 1)); + ctx.commit(); } virtual ~IndexScanBase() { Client::WriteContext ctx(&_txn, ns()); _client.dropCollection(ns()); + ctx.commit(); } void addIndex(const BSONObj& obj) { Client::WriteContext ctx(&_txn, ns()); _client.ensureIndex(ns(), obj); + ctx.commit(); } int countResults(const IndexScanParams& params, BSONObj filterObj = BSONObj()) { @@ -99,6 +102,7 @@ namespace QueryStageTests { double lng = double(rand()) / RAND_MAX; _client.insert(ns(), BSON("geo" << BSON_ARRAY(lng << lat))); } + ctx.commit(); } IndexDescriptor* getIndex(const BSONObj& obj) { diff --git a/src/mongo/dbtests/querytests.cpp b/src/mongo/dbtests/querytests.cpp index ef3d859a260..f18e9121713 100644 --- a/src/mongo/dbtests/querytests.cpp +++ b/src/mongo/dbtests/querytests.cpp @@ -57,7 +57,7 @@ namespace QueryTests { protected: OperationContextImpl _txn; Lock::GlobalWrite _lk; - + WriteUnitOfWork _wunit; Client::Context _context; Database* _database; @@ -65,8 +65,8 @@ namespace QueryTests { public: Base() : _lk(_txn.lockState()), + _wunit(_txn.recoveryUnit()), _context(&_txn, ns()) { - _database = _context.db(); _collection = _database->getCollection( &_txn, ns() ); if ( _collection ) { @@ -78,6 +78,7 @@ namespace QueryTests { ~Base() { try { uassertStatusOK( _database->dropCollection( &_txn, ns() ) ); + _wunit.commit(); } catch ( ... ) { FAIL( "Exception while cleaning up collection" ); @@ -245,12 +246,14 @@ namespace QueryTests { { // Check internal server handoff to getmore. Lock::DBWrite lk(_txn.lockState(), ns); + WriteUnitOfWork wunit(_txn.recoveryUnit()); Client::Context ctx(&_txn, ns ); ClientCursorPin clientCursor( ctx.db()->getCollection(&_txn, ns), cursorId ); // pq doesn't exist if it's a runner inside of the clientcursor. // ASSERT( clientCursor.c()->pq ); // ASSERT_EQUALS( 2, clientCursor.c()->pq->getNumToReturn() ); ASSERT_EQUALS( 2, clientCursor.c()->pos() ); + wunit.commit(); } cursor = _client.getMore( ns, cursorId ); @@ -593,8 +596,9 @@ namespace QueryTests { void run() { const char *ns = "unittests.querytests.OplogReplaySlaveReadTill"; Lock::DBWrite lk(_txn.lockState(), ns); + WriteUnitOfWork wunit(_txn.recoveryUnit()); Client::Context ctx(&_txn, ns ); - + BSONObj info; _client.runCommand( "unittests", BSON( "create" << "querytests.OplogReplaySlaveReadTill" << @@ -616,6 +620,7 @@ namespace QueryTests { ClientCursorPin clientCursor( ctx.db()->getCollection( &_txn, ns ), cursorId ); ASSERT_EQUALS( three.millis, clientCursor.c()->getSlaveReadTill().asDate() ); + wunit.commit(); } }; @@ -1057,7 +1062,9 @@ namespace QueryTests { void run() { Lock::GlobalWrite lk(_txn.lockState()); Client::Context ctx(&_txn, "unittests.DirectLocking"); + WriteUnitOfWork wunit(_txn.recoveryUnit()); _client.remove( "a.b", BSONObj() ); + wunit.commit(); ASSERT_EQUALS( "unittests", ctx.db()->name() ); } const char *ns; @@ -1208,6 +1215,7 @@ namespace QueryTests { for ( int i=0; i<90; i++ ) { insertNext(); } + ctx.commit(); while ( c->more() ) { c->next(); } ASSERT( c->isDead() ); @@ -1235,6 +1243,7 @@ namespace QueryTests { for ( int i=0; i<50; i++ ) { insert( ns() , BSON( "_id" << i << "x" << i * 2 ) ); } + ctx.commit(); ASSERT_EQUALS( 50 , count() ); @@ -1289,6 +1298,7 @@ namespace QueryTests { for ( int i=0; i<1000; i+=2 ) { _client.remove( ns() , BSON( "_id" << i ) ); } + ctx.commit(); BSONObj res; for ( int i=0; i<1000; i++ ) { @@ -1309,7 +1319,7 @@ namespace QueryTests { for ( int i=0; i<1000; i++ ) { insert( ns() , BSON( "_id" << i << "x" << i * 2 ) ); } - + ctx.commit(); } }; @@ -1421,11 +1431,16 @@ namespace QueryTests { CollectionInternalBase( const char *nsLeaf ) : CollectionBase( nsLeaf ), _lk(_txn.lockState(), ns() ), + _wunit( _txn.recoveryUnit() ), _ctx(&_txn, ns()) { - } + ~CollectionInternalBase() { + _wunit.commit(); + } + private: Lock::DBWrite _lk; + WriteUnitOfWork _wunit; Client::Context _ctx; }; @@ -1511,6 +1526,7 @@ namespace QueryTests { string expectedAssertion = str::stream() << "Cannot kill active cursor " << cursorId; ASSERT_EQUALS( expectedAssertion, _client.getLastError() ); + ctx.commit(); } // Verify that the remaining document is read from the cursor. diff --git a/src/mongo/dbtests/replsettests.cpp b/src/mongo/dbtests/replsettests.cpp index 0cd3597f34c..3e6b7ef7ad7 100644 --- a/src/mongo/dbtests/replsettests.cpp +++ b/src/mongo/dbtests/replsettests.cpp @@ -161,6 +161,7 @@ namespace ReplSetTests { } db->dropCollection(&_txn, ns()); + c.commit(); } static void setup() { @@ -315,15 +316,19 @@ namespace ReplSetTests { void create() { Client::Context c(&_txn, _cappedNs); + WriteUnitOfWork wunit(_txn.recoveryUnit()); ASSERT( userCreateNS( &_txn, c.db(), _cappedNs, fromjson( spec() ), false ).isOK() ); + wunit.commit(); } void dropCapped() { Client::Context c(&_txn, _cappedNs); + WriteUnitOfWork wunit(_txn.recoveryUnit()); Database* db = c.db(); if ( db->getCollection( &_txn, _cappedNs ) ) { db->dropCollection( &_txn, _cappedNs ); } + wunit.commit(); } BSONObj updateFail() { @@ -358,17 +363,24 @@ namespace ReplSetTests { // returns true on success, false on failure bool apply(const BSONObj& op) { Client::Context ctx(&_txn, _cappedNs ); + WriteUnitOfWork wunit(_txn.recoveryUnit()); // in an annoying twist of api, returns true on failure - return !applyOperation_inlock(&_txn, ctx.db(), op, true); + if (applyOperation_inlock(&_txn, ctx.db(), op, true)) { + return false; + } + wunit.commit(); + return true; } void run() { Lock::DBWrite lk(_txn.lockState(), _cappedNs); + WriteUnitOfWork wunit(_txn.recoveryUnit()); BSONObj op = updateFail(); Sync s(""); verify(!s.shouldRetry(&_txn, op)); + wunit.commit(); } }; @@ -388,6 +400,7 @@ namespace ReplSetTests { void insert(OperationContext* txn) { Client::Context ctx(txn, cappedNs()); + WriteUnitOfWork wunit(txn->recoveryUnit()); Database* db = ctx.db(); Collection* coll = db->getCollection(txn, cappedNs()); if (!coll) { @@ -397,6 +410,7 @@ namespace ReplSetTests { BSONObj o = BSON(GENOID << "x" << 456); DiskLoc loc = coll->insertDocument(txn, o, true).getValue(); verify(!loc.isNull()); + wunit.commit(); } public: virtual ~CappedUpdate() {} @@ -432,6 +446,7 @@ namespace ReplSetTests { public: virtual ~CappedInsert() {} void run() { + WriteUnitOfWork wunit(_txn.recoveryUnit()); // This will succeed, but not insert anything because they are changed to upserts for (int i=0; i<150; i++) { insertSucceed(); @@ -442,6 +457,7 @@ namespace ReplSetTests { Client::Context ctx(&_txn, cappedNs()); Collection* collection = ctx.db()->getCollection( &_txn, cappedNs() ); verify(collection->getIndexCatalog()->findIdIndex()); + wunit.commit(); } }; diff --git a/src/mongo/dbtests/repltests.cpp b/src/mongo/dbtests/repltests.cpp index 11338a61225..4694c942f73 100644 --- a/src/mongo/dbtests/repltests.cpp +++ b/src/mongo/dbtests/repltests.cpp @@ -58,12 +58,14 @@ namespace ReplTests { protected: mutable OperationContextImpl _txn; Lock::GlobalWrite _lk; + WriteUnitOfWork _wunit; mutable DBDirectClient _client; Client::Context _context; public: Base() : _lk(_txn.lockState()), + _wunit( _txn.recoveryUnit()), _client(&_txn), _context(&_txn, ns()) { @@ -73,6 +75,7 @@ namespace ReplTests { replSettings.master = true; createOplog(); + Collection* c = _context.db()->getCollection( &_txn, ns() ); if ( ! c ) { c = _context.db()->createCollection( &_txn, ns() ); @@ -84,6 +87,7 @@ namespace ReplTests { replSettings.master = false; deleteAll( ns() ); deleteAll( cllNS() ); + _wunit.commit(); } catch ( ... ) { FAIL( "Exception while cleaning up test" ); @@ -140,6 +144,7 @@ namespace ReplTests { static int opCount() { OperationContextImpl txn; Lock::GlobalWrite lk(txn.lockState()); + WriteUnitOfWork wunit(txn.recoveryUnit()); Client::Context ctx(&txn, cllNS() ); Database* db = ctx.db(); @@ -155,12 +160,13 @@ namespace ReplTests { ++count; } delete it; + wunit.commit(); return count; } static void applyAllOperations() { OperationContextImpl txn; Lock::GlobalWrite lk(txn.lockState()); - + WriteUnitOfWork wunit(txn.recoveryUnit()); vector< BSONObj > ops; { Client::Context ctx(&txn, cllNS() ); @@ -188,10 +194,12 @@ namespace ReplTests { a.applyOperation( &txn, ctx.db(), *i ); } } + wunit.commit(); } static void printAll( const char *ns ) { OperationContextImpl txn; Lock::GlobalWrite lk(txn.lockState()); + WriteUnitOfWork wunit(txn.recoveryUnit()); Client::Context ctx(&txn, ns ); Database* db = ctx.db(); @@ -208,13 +216,14 @@ namespace ReplTests { ::mongo::log() << coll->docFor(currLoc).toString() << endl; } delete it; + wunit.commit(); } // These deletes don't get logged. static void deleteAll( const char *ns ) { OperationContextImpl txn; Lock::GlobalWrite lk(txn.lockState()); Client::Context ctx(&txn, ns ); - + WriteUnitOfWork wunit(txn.recoveryUnit()); Database* db = ctx.db(); Collection* coll = db->getCollection( &txn, ns ); if ( !coll ) { @@ -231,12 +240,13 @@ namespace ReplTests { for( vector< DiskLoc >::iterator i = toDelete.begin(); i != toDelete.end(); ++i ) { coll->deleteDocument( &txn, *i, true ); } + wunit.commit(); } static void insert( const BSONObj &o ) { OperationContextImpl txn; Lock::GlobalWrite lk(txn.lockState()); Client::Context ctx(&txn, ns() ); - + WriteUnitOfWork wunit(txn.recoveryUnit()); Database* db = ctx.db(); Collection* coll = db->getCollection( &txn, ns() ); if ( !coll ) { @@ -254,6 +264,7 @@ namespace ReplTests { b.appendOID( "_id", &id ); b.appendElements( o ); coll->insertDocument( &txn, b.obj(), true ); + wunit.commit(); } static BSONObj wid( const char *json ) { class BSONObjBuilder b; diff --git a/src/mongo/dbtests/runner_registry.cpp b/src/mongo/dbtests/runner_registry.cpp index b7c5981a27f..a6c2b4dfac6 100644 --- a/src/mongo/dbtests/runner_registry.cpp +++ b/src/mongo/dbtests/runner_registry.cpp @@ -60,6 +60,12 @@ namespace RunnerRegistry { } } + ~RunnerRegistryBase() { + if (_ctx.get()) { + _ctx->commit(); + } + } + /** * Return a runner that is going over the collection in ns(). */ @@ -270,6 +276,7 @@ namespace RunnerRegistry { // Drop a DB that's not ours. We can't have a lock at all to do this as dropping a DB // requires a "global write lock." + _ctx->commit(); _ctx.reset(); _client.dropDatabase("somesillydb"); _ctx.reset(new Client::WriteContext(&_opCtx, ns())); @@ -286,6 +293,7 @@ namespace RunnerRegistry { registerRunner(run.get()); // Drop our DB. Once again, must give up the lock. + _ctx->commit(); _ctx.reset(); _client.dropDatabase("unittests"); _ctx.reset(new Client::WriteContext(&_opCtx, ns())); @@ -293,6 +301,8 @@ namespace RunnerRegistry { // Unregister and restore state. deregisterRunner(run.get()); run->restoreState(&_opCtx); + _ctx->commit(); + _ctx.reset(); // Runner was killed. ASSERT_EQUALS(Runner::RUNNER_DEAD, run->getNext(&obj, NULL)); diff --git a/src/mongo/dbtests/threadedtests.cpp b/src/mongo/dbtests/threadedtests.cpp index 0e36df8f43f..8c6f5d7c2fa 100644 --- a/src/mongo/dbtests/threadedtests.cpp +++ b/src/mongo/dbtests/threadedtests.cpp @@ -220,6 +220,7 @@ namespace ThreadedTests { } { Lock::DBWrite x(&lockState, "local"); + // No actual writing here, so no WriteUnitOfWork if( sometimes ) { Lock::TempRelease t(&lockState); } diff --git a/src/mongo/s/d_migrate.cpp b/src/mongo/s/d_migrate.cpp index 47facbfc02a..fef22237850 100644 --- a/src/mongo/s/d_migrate.cpp +++ b/src/mongo/s/d_migrate.cpp @@ -1671,6 +1671,7 @@ namespace mongo { db->createCollection( txn, ns ); } } + ctx.commit(); } { @@ -1710,6 +1711,7 @@ namespace mongo { // make sure to create index on secondaries as well repl::logOp(txn, "i", db->getSystemIndexesName().c_str(), idx, NULL, NULL, true /* fromMigrate */); + ctx.commit(); } timing.done(1); @@ -1809,6 +1811,7 @@ namespace mongo { } Helpers::upsert( txn, ns, o, true ); + cx.commit(); } thisTime++; numCloned++; @@ -2046,6 +2049,7 @@ namespace mongo { true ); /*fromMigrate*/ *lastOpApplied = cx.ctx().getClient()->getLastOp().asDate(); + cx.commit(); didAnything = true; } } @@ -2075,6 +2079,7 @@ namespace mongo { Helpers::upsert( txn, ns , it , true ); *lastOpApplied = cx.ctx().getClient()->getLastOp().asDate(); + cx.commit(); didAnything = true; } } diff --git a/src/mongo/tools/dump.cpp b/src/mongo/tools/dump.cpp index c4aab6b1bf4..ba3ff655092 100644 --- a/src/mongo/tools/dump.cpp +++ b/src/mongo/tools/dump.cpp @@ -408,6 +408,7 @@ public: toolError() << "ERROR recovering: " << ns << " " << e.toString() << std::endl; } } + cx.commit(); return 0; } |