diff options
author | Mathias Stearn <mathias@10gen.com> | 2014-05-01 15:09:02 -0400 |
---|---|---|
committer | Mathias Stearn <mathias@10gen.com> | 2014-05-14 13:58:01 -0400 |
commit | 6378da06b637dbf86f916274c8f0457d925af6a9 (patch) | |
tree | b07693c3b786ad9eef3e17fe1a6a670f9229cd44 /src/mongo/db | |
parent | 304534f11a265d8c18d788623185340c001cc26e (diff) | |
download | mongo-6378da06b637dbf86f916274c8f0457d925af6a9.tar.gz |
SERVER-13641 Pull TransactionExperiment up to top level request processor
Diffstat (limited to 'src/mongo/db')
44 files changed, 420 insertions, 263 deletions
diff --git a/src/mongo/db/cloner.cpp b/src/mongo/db/cloner.cpp index 37d28f334ad..96dfea73572 100644 --- a/src/mongo/db/cloner.cpp +++ b/src/mongo/db/cloner.cpp @@ -558,7 +558,7 @@ namespace mongo { return Status::OK(); } CmdClone() : Command("clone") { } - virtual bool run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { + virtual bool newRun(TransactionExperiment* txn, const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { string from = cmdObj.getStringField("clone"); if ( from.empty() ) return false; @@ -583,10 +583,9 @@ namespace mongo { Lock::DBWrite dbXLock(dbname); Client::Context context( dbname ); - DurTransaction txn; Cloner cloner; - bool rval = cloner.go(&txn, context, from, opts, &clonedColls, errmsg); + bool rval = cloner.go(txn, context, from, opts, &clonedColls, errmsg); BSONArrayBuilder barr; barr.append( clonedColls ); @@ -630,7 +629,7 @@ namespace mongo { "is placed at the same db.collection (namespace) as the source.\n" ; } - virtual bool run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { + virtual bool newRun(TransactionExperiment* txn, const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { string fromhost = cmdObj.getStringField("from"); if ( fromhost.empty() ) { errmsg = "missing 'from' parameter"; @@ -666,8 +665,7 @@ namespace mongo { cloner.setConnection( myconn.release() ); - DurTransaction txn; - return cloner.copyCollection(&txn, collection, query, errmsg, true, false, copyIndexes); + return cloner.copyCollection(txn, collection, query, errmsg, true, false, copyIndexes); } } cmdCloneCollection; @@ -782,7 +780,7 @@ namespace mongo { help << "usage: {copydb: 1, fromhost: <connection string>, fromdb: <db>, todb: <db>" << "[, slaveOk: <bool>, username: <username>, nonce: <nonce>, key: <key>]}"; } - virtual bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { + virtual bool newRun(TransactionExperiment* txn, const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { string fromhost = cmdObj.getStringField("fromhost"); bool fromSelf = fromhost.empty(); if ( fromSelf ) { @@ -813,7 +811,6 @@ namespace mongo { static_cast<Lock::ScopedLock*>( new Lock::GlobalWrite() ) : static_cast<Lock::ScopedLock*>( new Lock::DBWrite( todb ) ) ); - DurTransaction txn; Cloner cloner; string username = cmdObj.getStringField( "username" ); @@ -847,7 +844,7 @@ namespace mongo { cloner.setConnection(conn); } Client::Context ctx(todb); - return cloner.go(&txn, ctx, fromhost, cloneOptions, NULL, errmsg ); + return cloner.go(txn, ctx, fromhost, cloneOptions, NULL, errmsg ); } } cmdCopyDB; diff --git a/src/mongo/db/commands.cpp b/src/mongo/db/commands.cpp index 045e475568f..27aba2bf5ae 100644 --- a/src/mongo/db/commands.cpp +++ b/src/mongo/db/commands.cpp @@ -90,6 +90,15 @@ namespace mongo { return ResourcePattern::forExactNamespace(NamespaceString(ns)); } + bool Command::newRun(TransactionExperiment* txn, + const string& db, + BSONObj& cmdObj, + int options, + string& errmsg, + BSONObjBuilder& result, + bool fromRepl) { + return run(db, cmdObj, options, errmsg, result, fromRepl); + } void Command::htmlHelp(stringstream& ss) const { string helpStr; diff --git a/src/mongo/db/commands.h b/src/mongo/db/commands.h index a679dc3e5ff..36fc09d3bd1 100644 --- a/src/mongo/db/commands.h +++ b/src/mongo/db/commands.h @@ -33,6 +33,7 @@ namespace mongo { class Client; class Database; class Timer; + class TransactionExperiment; namespace mutablebson { class Document; @@ -70,8 +71,16 @@ namespace mutablebson { normally do not want to log the command to the local oplog. return value is true if succeeded. if false, set errmsg text. + + Default impl forwards to private run(). It will go away soon. */ - virtual bool run(const string& db, BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result, bool fromRepl = false ) = 0; + virtual bool newRun(TransactionExperiment* txn, + const string& db, + BSONObj& cmdObj, + int options, + string& errmsg, + BSONObjBuilder& result, + bool fromRepl = false ); /** * This designation for the command is only used by the 'help' call and has nothing to do @@ -192,7 +201,8 @@ namespace mutablebson { int queryOptions = 0); static Command * findCommand( const string& name ); // For mongod and webserver. - static void execCommand(Command* c, + static void execCommand(TransactionExperiment* txn, + Command* c, Client& client, int queryOptions, const char *ns, @@ -200,7 +210,8 @@ namespace mutablebson { BSONObjBuilder& result, bool fromRepl ); // For mongos - static void execCommandClientBasic(Command* c, + static void execCommandClientBasic(TransactionExperiment* txn, + Command* c, ClientBasic& client, int queryOptions, const char *ns, @@ -223,6 +234,11 @@ namespace mutablebson { static int testCommandsEnabled; private: + // This method is deprecated. It should only be used by commands that don't transactions + virtual bool run(const string& db, BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result, bool fromRepl = false ) { + invariant(false); + } + /** * Checks to see if the client is authorized to run the given command with the given * parameters on the given named database. @@ -242,6 +258,12 @@ namespace mutablebson { bool fromRepl); }; - bool _runCommands(const char *ns, BSONObj& jsobj, BufBuilder &b, BSONObjBuilder& anObjBuilder, bool fromRepl, int queryOptions); + bool _runCommands(TransactionExperiment* txn, + const char* ns, + BSONObj& jsobj, + BufBuilder& b, + BSONObjBuilder& anObjBuilder, + bool fromRepl, + int queryOptions); } // namespace mongo diff --git a/src/mongo/db/commands/apply_ops.cpp b/src/mongo/db/commands/apply_ops.cpp index a189af5db6f..b86d8716d08 100644 --- a/src/mongo/db/commands/apply_ops.cpp +++ b/src/mongo/db/commands/apply_ops.cpp @@ -59,7 +59,7 @@ namespace mongo { // applyOps can do pretty much anything, so require all privileges. RoleGraph::generateUniversalPrivileges(out); } - virtual bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { + virtual bool newRun(TransactionExperiment* txn, const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { if ( cmdObj.firstElement().type() != Array ) { errmsg = "ops has to be an array"; @@ -84,7 +84,6 @@ 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; - DurTransaction txn; // Preconditions check reads the database state, so needs to be done locked if ( cmdObj["preCondition"].type() == Array ) { @@ -132,7 +131,7 @@ namespace mongo { invariant(Lock::nested()); Client::Context ctx(ns); - bool failed = applyOperation_inlock(&txn, ctx.db(), temp, false, alwaysUpsert); + bool failed = applyOperation_inlock(txn, ctx.db(), temp, false, alwaysUpsert); ab.append(!failed); if ( failed ) errors++; @@ -163,7 +162,7 @@ namespace mongo { } } - logOp(&txn, "c", tempNS.c_str(), cmdBuilder.done()); + logOp(txn, "c", tempNS.c_str(), cmdBuilder.done()); } return errors == 0; diff --git a/src/mongo/db/commands/cleanup_orphaned_cmd.cpp b/src/mongo/db/commands/cleanup_orphaned_cmd.cpp index 5a851307535..fcc81a00c59 100644 --- a/src/mongo/db/commands/cleanup_orphaned_cmd.cpp +++ b/src/mongo/db/commands/cleanup_orphaned_cmd.cpp @@ -61,7 +61,8 @@ namespace mongo { * * If the collection is not sharded, returns CleanupResult_Done. */ - CleanupResult cleanupOrphanedData( const NamespaceString& ns, + CleanupResult cleanupOrphanedData( TransactionExperiment* txn, + const NamespaceString& ns, const BSONObj& startingFromKeyConst, bool secondaryThrottle, BSONObj* stoppedAtKey, @@ -116,7 +117,8 @@ namespace mongo { // Metadata snapshot may be stale now, but deleter checks metadata again in write lock // before delete. - if ( !getDeleter()->deleteNow( ns.toString(), + if ( !getDeleter()->deleteNow( txn, + ns.toString(), orphanRange.minKey, orphanRange.maxKey, keyPattern, @@ -177,7 +179,8 @@ namespace mongo { // Output static BSONField<BSONObj> stoppedAtKeyField; - bool run( string const &db, + bool newRun( TransactionExperiment* txn, + string const &db, BSONObj &cmdObj, int, string &errmsg, @@ -231,7 +234,8 @@ namespace mongo { } BSONObj stoppedAtKey; - CleanupResult cleanupResult = cleanupOrphanedData( NamespaceString( ns ), + CleanupResult cleanupResult = cleanupOrphanedData( txn, + NamespaceString( ns ), startingFromKey, secondaryThrottle, &stoppedAtKey, diff --git a/src/mongo/db/commands/collection_to_capped.cpp b/src/mongo/db/commands/collection_to_capped.cpp index 0ed6f1bc15d..f1a375e6694 100644 --- a/src/mongo/db/commands/collection_to_capped.cpp +++ b/src/mongo/db/commands/collection_to_capped.cpp @@ -142,7 +142,7 @@ namespace mongo { NamespaceString(dbname, collection)), targetActions)); } - bool run(const string& dbname, BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) { + bool newRun(TransactionExperiment* txn, const string& dbname, BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) { string from = jsobj.getStringField( "cloneCollectionAsCapped" ); string to = jsobj.getStringField( "toCollection" ); double size = jsobj.getField( "size" ).number(); @@ -155,9 +155,8 @@ namespace mongo { Lock::DBWrite dbXLock(dbname); Client::Context ctx(dbname); - DurTransaction txn; - Status status = cloneCollectionAsCapped( &txn, ctx.db(), from, to, size, temp, true ); + Status status = cloneCollectionAsCapped( txn, ctx.db(), from, to, size, temp, true ); return appendCommandStatus( result, status ); } } cmdCloneCollectionAsCapped; @@ -197,12 +196,11 @@ namespace mongo { return std::vector<BSONObj>(); } - bool run(const string& dbname, BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) { + bool newRun(TransactionExperiment* 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; Client::Context ctx(dbname); - DurTransaction txn; Database* db = ctx.db(); @@ -222,28 +220,28 @@ namespace mongo { string longTmpName = str::stream() << dbname << "." << shortTmpName; if ( db->getCollection( longTmpName ) ) { - Status status = db->dropCollection( &txn, longTmpName ); + Status status = db->dropCollection( txn, longTmpName ); if ( !status.isOK() ) return appendCommandStatus( result, status ); } - Status status = cloneCollectionAsCapped( &txn, db, shortSource, shortTmpName, size, true, false ); + Status status = cloneCollectionAsCapped( txn, db, shortSource, shortTmpName, size, true, false ); if ( !status.isOK() ) return appendCommandStatus( result, status ); verify( db->getCollection( longTmpName ) ); - status = db->dropCollection( &txn, longSource ); + status = db->dropCollection( txn, longSource ); if ( !status.isOK() ) return appendCommandStatus( result, status ); - status = db->renameCollection( &txn, longTmpName, longSource, false ); + status = db->renameCollection( txn, longTmpName, longSource, false ); if ( !status.isOK() ) return appendCommandStatus( result, status ); if (!fromRepl) - logOp(&txn, "c",(dbname + ".$cmd").c_str(), jsobj); + logOp(txn, "c",(dbname + ".$cmd").c_str(), jsobj); return true; } } cmdConvertToCapped; diff --git a/src/mongo/db/commands/compact.cpp b/src/mongo/db/commands/compact.cpp index 97508e62b5f..a469347d677 100644 --- a/src/mongo/db/commands/compact.cpp +++ b/src/mongo/db/commands/compact.cpp @@ -83,7 +83,7 @@ namespace mongo { return IndexBuilder::killMatchingIndexBuilds(db->getCollection(ns), criteria); } - virtual bool run(const string& db, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { + virtual bool newRun(TransactionExperiment* txn, const string& db, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { string coll = cmdObj.firstElement().valuestr(); if( coll.empty() || db.empty() ) { errmsg = "no collection name specified"; @@ -145,7 +145,6 @@ namespace mongo { Lock::DBWrite lk(ns.ns()); BackgroundOperation::assertNoBgOpInProgForNs(ns.ns()); Client::Context ctx(ns); - DurTransaction txn; Collection* collection = ctx.db()->getCollection(ns.ns()); if( ! collection ) { @@ -162,7 +161,7 @@ namespace mongo { std::vector<BSONObj> indexesInProg = stopIndexBuilds(ctx.db(), cmdObj); - StatusWith<CompactStats> status = collection->compact( &txn, &compactOptions ); + StatusWith<CompactStats> status = collection->compact( txn, &compactOptions ); if ( !status.isOK() ) return appendCommandStatus( result, status.getStatus() ); diff --git a/src/mongo/db/commands/create_indexes.cpp b/src/mongo/db/commands/create_indexes.cpp index ddc9fa9b535..06b0b6e20b7 100644 --- a/src/mongo/db/commands/create_indexes.cpp +++ b/src/mongo/db/commands/create_indexes.cpp @@ -70,7 +70,7 @@ namespace mongo { return b.obj(); } - virtual bool run( const string& dbname, BSONObj& cmdObj, int options, + virtual bool newRun(TransactionExperiment* txn, const string& dbname, BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result, bool fromRepl = false ) { @@ -167,13 +167,12 @@ namespace mongo { Client::WriteContext writeContext( ns.ns(), storageGlobalParams.dbpath, false /* doVersion */ ); - DurTransaction txn; Database* db = writeContext.ctx().db(); - Collection* collection = db->getCollection( &txn, ns.ns() ); + Collection* collection = db->getCollection( txn, ns.ns() ); result.appendBool( "createdCollectionAutomatically", collection == NULL ); if ( !collection ) { - collection = db->createCollection( &txn, ns.ns() ); + collection = db->createCollection( txn, ns.ns() ); invariant( collection ); } @@ -191,7 +190,7 @@ namespace mongo { } } - status = collection->getIndexCatalog()->createIndex(&txn, spec, true); + status = collection->getIndexCatalog()->createIndex(txn, spec, true); if ( status.code() == ErrorCodes::IndexAlreadyExists ) { if ( !result.hasField( "note" ) ) result.append( "note", "index already exists" ); @@ -205,7 +204,7 @@ namespace mongo { if ( !fromRepl ) { std::string systemIndexes = ns.getSystemIndexesCollection(); - logOp( &txn, "i", systemIndexes.c_str(), spec ); + logOp( txn, "i", systemIndexes.c_str(), spec ); } } diff --git a/src/mongo/db/commands/drop_indexes.cpp b/src/mongo/db/commands/drop_indexes.cpp index f7655fdbcb3..ea60d797f69 100644 --- a/src/mongo/db/commands/drop_indexes.cpp +++ b/src/mongo/db/commands/drop_indexes.cpp @@ -92,12 +92,11 @@ namespace mongo { } CmdDropIndexes() : Command("dropIndexes", false, "deleteIndexes") { } - bool run(const string& dbname, BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& anObjBuilder, bool fromRepl) { + bool newRun(TransactionExperiment* txn, const string& dbname, BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& anObjBuilder, bool fromRepl) { Lock::DBWrite dbXLock(dbname); - DurTransaction txn; - bool ok = wrappedRun(&txn, dbname, jsobj, errmsg, anObjBuilder); + bool ok = wrappedRun(txn, dbname, jsobj, errmsg, anObjBuilder); if (ok && !fromRepl) - logOp(&txn, "c",(dbname + ".$cmd").c_str(), jsobj); + logOp(txn, "c",(dbname + ".$cmd").c_str(), jsobj); return ok; } bool wrappedRun(TransactionExperiment* txn, @@ -213,7 +212,7 @@ namespace mongo { return IndexBuilder::killMatchingIndexBuilds(db->getCollection(ns), criteria); } - bool run(const string& dbname , BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool /*fromRepl*/) { + bool newRun(TransactionExperiment* txn, const string& dbname , BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool /*fromRepl*/) { static DBDirectClient db; BSONElement e = jsobj.firstElement(); @@ -223,7 +222,6 @@ namespace mongo { Lock::DBWrite dbXLock(dbname); Client::Context ctx(toDeleteNs); - DurTransaction txn; Collection* collection = ctx.db()->getCollection( toDeleteNs ); @@ -255,7 +253,7 @@ namespace mongo { } result.appendNumber( "nIndexesWas", collection->getIndexCatalog()->numIndexesTotal() ); - Status s = collection->getIndexCatalog()->dropAllIndexes(&txn, true); + Status s = collection->getIndexCatalog()->dropAllIndexes(txn, true); if ( !s.isOK() ) { errmsg = "dropIndexes failed"; return appendCommandStatus( result, s ); @@ -264,7 +262,7 @@ namespace mongo { for ( list<BSONObj>::iterator i=all.begin(); i!=all.end(); i++ ) { BSONObj o = *i; LOG(1) << "reIndex ns: " << toDeleteNs << " index: " << o << endl; - Status s = collection->getIndexCatalog()->createIndex(&txn, o, false); + Status s = collection->getIndexCatalog()->createIndex(txn, o, false); if ( !s.isOK() ) return appendCommandStatus( result, s ); } diff --git a/src/mongo/db/commands/find_and_modify.cpp b/src/mongo/db/commands/find_and_modify.cpp index 34370d6907a..98aab888860 100644 --- a/src/mongo/db/commands/find_and_modify.cpp +++ b/src/mongo/db/commands/find_and_modify.cpp @@ -65,7 +65,7 @@ namespace mongo { find_and_modify::addPrivilegesRequiredForFindAndModify(this, dbname, cmdObj, out); } /* this will eventually replace run, once sort is handled */ - bool runNoDirectClient( const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) { + bool runNoDirectClient( TransactionExperiment* txn, const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) { verify( cmdObj["sort"].eoo() ); const string ns = dbname + '.' + cmdObj.firstElement().valuestr(); @@ -96,7 +96,7 @@ namespace mongo { Lock::DBWrite dbXLock(dbname); Client::Context ctx(ns); - return runNoDirectClient( ns , + return runNoDirectClient( txn, ns , query , fields , update , upsert , returnNew , remove , result , errmsg ); @@ -122,7 +122,8 @@ namespace mongo { result.append( "value" , p.transform( doc ) ); } - static bool runNoDirectClient(const string& ns, + static bool runNoDirectClient(TransactionExperiment* txn, + const string& ns, const BSONObj& queryOriginal, const BSONObj& fields, const BSONObj& update, @@ -134,8 +135,7 @@ namespace mongo { Lock::DBWrite lk( ns ); Client::Context cx( ns ); - DurTransaction txn; - Collection* collection = cx.db()->getCollection( &txn, ns ); + Collection* collection = cx.db()->getCollection( txn, ns ); const WhereCallbackReal whereCallback = WhereCallbackReal(StringData(ns)); @@ -222,7 +222,7 @@ namespace mongo { if ( remove ) { _appendHelper(result, doc, found, fields, whereCallback); if ( found ) { - deleteObjects(&txn, cx.db(), ns, queryModified, true, true); + deleteObjects(txn, cx.db(), ns, queryModified, true, true); BSONObjBuilder le( result.subobjStart( "lastErrorObject" ) ); le.appendNumber( "n" , 1 ); le.done(); @@ -252,8 +252,7 @@ namespace mongo { // the shard version below, but for now no UpdateLifecycleImpl updateLifecycle(false, requestNs); request.setLifecycle(&updateLifecycle); - UpdateResult res = - mongo::update(&txn, cx.db(), request, &cc().curop()->debug()); + UpdateResult res = mongo::update(txn, cx.db(), request, &cc().curop()->debug()); if ( !collection ) { // collection created by an upsert collection = cx.db()->getCollection( ns ); @@ -298,11 +297,11 @@ namespace mongo { return true; } - virtual bool run(const string& dbname, BSONObj& cmdObj, int x, string& errmsg, BSONObjBuilder& result, bool y) { - static DBDirectClient db; + virtual bool newRun(TransactionExperiment* txn, const string& dbname, BSONObj& cmdObj, int x, string& errmsg, BSONObjBuilder& result, bool y) { + DBDirectClient db(txn); if (cmdObj["sort"].eoo()) { - return runNoDirectClient(dbname, cmdObj, x, errmsg, result, y); + return runNoDirectClient(txn, dbname, cmdObj, x, errmsg, result, y); } const string ns = dbname + '.' + cmdObj.firstElement().valuestr(); diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp index 7c39fee77e4..7a540a8a3ef 100644 --- a/src/mongo/db/commands/mr.cpp +++ b/src/mongo/db/commands/mr.cpp @@ -1208,7 +1208,7 @@ namespace mongo { addPrivilegesRequiredForMapReduce(this, dbname, cmdObj, out); } - bool run(const string& dbname , BSONObj& cmd, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) { + bool newRun(TransactionExperiment* txn, const string& dbname , BSONObj& cmd, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) { Timer t; Client& client = cc(); CurOp * op = client.curop(); @@ -1240,8 +1240,7 @@ namespace mongo { BSONObjBuilder countsBuilder; BSONObjBuilder timingBuilder; - DurTransaction txn; - State state( &txn, config ); + State state( txn, config ); if ( ! state.sourceExists() ) { errmsg = "ns doesn't exist"; return false; @@ -1354,7 +1353,7 @@ namespace mongo { reduceTime += t.micros(); - txn.checkForInterrupt(); + txn->checkForInterrupt(); } pm.hit(); @@ -1365,7 +1364,7 @@ namespace mongo { } pm.finished(); - txn.checkForInterrupt(); + txn->checkForInterrupt(); // update counters countsBuilder.appendNumber("input", numInputs); @@ -1447,7 +1446,7 @@ namespace mongo { actions.addAction(ActionType::internal); out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); } - bool run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) { + bool newRun(TransactionExperiment* txn, const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) { ShardedConnectionInfo::addHook(); // legacy name string shardedOutputCollection = cmdObj["shardedOutputCollection"].valuestrsafe(); @@ -1464,8 +1463,7 @@ namespace mongo { CurOp * op = client.curop(); Config config( dbname , cmdObj.firstElement().embeddedObjectUserCheck() ); - DurTransaction txn; - State state(&txn, config); + State state(txn, config); state.init(); // no need for incremental collection because records are already sorted diff --git a/src/mongo/db/commands/rename_collection.cpp b/src/mongo/db/commands/rename_collection.cpp index cd72f781707..07bf511141b 100644 --- a/src/mongo/db/commands/rename_collection.cpp +++ b/src/mongo/db/commands/rename_collection.cpp @@ -91,15 +91,14 @@ namespace mongo { IndexBuilder::restoreIndexes( indexesInProg ); } - virtual bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { + virtual bool newRun(TransactionExperiment* txn, const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { Lock::GlobalWrite globalWriteLock; - DurTransaction txn; - bool ok = wrappedRun(&txn, dbname, cmdObj, errmsg, result, fromRepl); + bool ok = wrappedRun(txn, dbname, cmdObj, errmsg, result, fromRepl); if (ok && !fromRepl) - logOp(&txn, "c",(dbname + ".$cmd").c_str(), cmdObj); + logOp(txn, "c",(dbname + ".$cmd").c_str(), cmdObj); return ok; } - virtual bool wrappedRun(DurTransaction* txn, + virtual bool wrappedRun(TransactionExperiment* txn, const string& dbname, BSONObj& cmdObj, string& errmsg, diff --git a/src/mongo/db/commands/test_commands.cpp b/src/mongo/db/commands/test_commands.cpp index 263b7af7f88..428298868b9 100644 --- a/src/mongo/db/commands/test_commands.cpp +++ b/src/mongo/db/commands/test_commands.cpp @@ -55,7 +55,7 @@ namespace mongo { virtual void help( stringstream &help ) const { help << "internal. for testing only."; } - virtual bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) { + virtual bool newRun(TransactionExperiment* txn, const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) { string coll = cmdObj[ "godinsert" ].valuestrsafe(); log() << "test only command godinsert invoked coll:" << coll << endl; uassert( 13049, "godinsert must specify a collection", !coll.empty() ); @@ -64,17 +64,16 @@ namespace mongo { Lock::DBWrite lk(ns); Client::Context ctx( ns ); - DurTransaction txn; Database* db = ctx.db(); Collection* collection = db->getCollection( ns ); if ( !collection ) { - collection = db->createCollection( &txn, ns ); + collection = db->createCollection( txn, ns ); if ( !collection ) { errmsg = "could not create collection"; return false; } } - StatusWith<DiskLoc> res = collection->insertDocument( &txn, obj, false ); + StatusWith<DiskLoc> res = collection->insertDocument( txn, obj, false ); return appendCommandStatus( result, res.getStatus() ); } }; @@ -134,7 +133,7 @@ namespace mongo { virtual void addRequiredPrivileges(const std::string& dbname, const BSONObj& cmdObj, std::vector<Privilege>* out) {} - virtual bool run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) { + virtual bool newRun(TransactionExperiment* txn, const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) { string coll = cmdObj[ "captrunc" ].valuestrsafe(); uassert( 13416, "captrunc must specify a collection", !coll.empty() ); NamespaceString nss( dbname, coll ); @@ -142,7 +141,6 @@ namespace mongo { bool inc = cmdObj.getBoolField( "inc" ); // inclusive range? Client::WriteContext ctx( nss.ns() ); - DurTransaction txn; Collection* collection = ctx.ctx().db()->getCollection( nss.ns() ); massert( 13417, "captrunc collection not found or empty", collection); @@ -155,7 +153,7 @@ namespace mongo { Runner::RunnerState state = runner->getNext(NULL, &end); massert( 13418, "captrunc invalid n", Runner::RUNNER_ADVANCED == state); } - collection->temp_cappedTruncateAfter( &txn, end, inc ); + collection->temp_cappedTruncateAfter( txn, end, inc ); return true; } }; @@ -182,27 +180,26 @@ namespace mongo { return IndexBuilder::killMatchingIndexBuilds(db->getCollection(ns), criteria); } - virtual bool run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { + virtual bool newRun(TransactionExperiment* txn, const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { string coll = cmdObj[ "emptycapped" ].valuestrsafe(); uassert( 13428, "emptycapped must specify a collection", !coll.empty() ); NamespaceString nss( dbname, coll ); Client::WriteContext ctx( nss.ns() ); - DurTransaction txn; Database* db = ctx.ctx().db(); Collection* collection = db->getCollection( nss.ns() ); massert( 13429, "emptycapped no such collection", collection ); std::vector<BSONObj> indexes = stopIndexBuilds(db, cmdObj); - Status status = collection->truncate(&txn); + Status status = collection->truncate(txn); if ( !status.isOK() ) return appendCommandStatus( result, status ); IndexBuilder::restoreIndexes(indexes); if (!fromRepl) - logOp(&txn, "c",(dbname + ".$cmd").c_str(), cmdObj); + logOp(txn, "c",(dbname + ".$cmd").c_str(), cmdObj); return true; } }; diff --git a/src/mongo/db/commands/touch.cpp b/src/mongo/db/commands/touch.cpp index 6427fba7b64..2011758f042 100644 --- a/src/mongo/db/commands/touch.cpp +++ b/src/mongo/db/commands/touch.cpp @@ -77,7 +77,8 @@ namespace mongo { } TouchCmd() : Command("touch") { } - virtual bool run(const string& dbname, + virtual bool newRun(TransactionExperiment* txn, + const string& dbname, BSONObj& cmdObj, int, string& errmsg, @@ -104,7 +105,6 @@ namespace mongo { } Client::ReadContext context( nss.ns() ); - DurTransaction txn; Database* db = context.ctx().db(); Collection* collection = db->getCollection( nss.ns() ); @@ -114,7 +114,7 @@ namespace mongo { } return appendCommandStatus( result, - collection->touch( &txn, + collection->touch( txn, touch_data, touch_indexes, &result ) ); } diff --git a/src/mongo/db/commands/validate.cpp b/src/mongo/db/commands/validate.cpp index d9d20610b45..3fba9dd4b00 100644 --- a/src/mongo/db/commands/validate.cpp +++ b/src/mongo/db/commands/validate.cpp @@ -59,7 +59,7 @@ namespace mongo { } //{ validate: "collectionnamewithoutthedbpart" [, scandata: <bool>] [, full: <bool> } */ - bool run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) { + bool newRun(TransactionExperiment* txn, const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) { string ns = dbname + "." + cmdObj.firstElement().valuestrsafe(); NamespaceString ns_string(ns); @@ -76,7 +76,6 @@ namespace mongo { } Client::ReadContext ctx(ns_string.ns()); - DurTransaction txn; Database* db = ctx.ctx().db(); if ( !db ) { @@ -93,7 +92,7 @@ namespace mongo { result.append( "ns", ns ); ValidateResults results; - Status status = collection->validate( &txn, full, scanData, &results, &result ); + Status status = collection->validate( txn, full, scanData, &results, &result ); if ( !status.isOK() ) return appendCommandStatus( result, status ); diff --git a/src/mongo/db/commands/write_commands/batch_executor.cpp b/src/mongo/db/commands/write_commands/batch_executor.cpp index 160ed358bab..d7295a5458f 100644 --- a/src/mongo/db/commands/write_commands/batch_executor.cpp +++ b/src/mongo/db/commands/write_commands/batch_executor.cpp @@ -89,10 +89,12 @@ namespace mongo { using mongoutils::str::stream; - WriteBatchExecutor::WriteBatchExecutor( const BSONObj& wc, + WriteBatchExecutor::WriteBatchExecutor( TransactionExperiment* txn, + const BSONObj& wc, Client* client, OpCounters* opCounters, LastError* le ) : + _txn(txn), _defaultWriteConcern( wc ), _client( client ), _opCounters( opCounters ), @@ -577,7 +579,10 @@ namespace mongo { } } - static void finishCurrentOp( Client* client, CurOp* currentOp, WriteErrorDetail* opError ) { + static void finishCurrentOp( TransactionExperiment* txn, + Client* client, + CurOp* currentOp, + WriteErrorDetail* opError ) { currentOp->done(); int executionTime = currentOp->debug().executionTime = currentOp->totalTimeMillis(); @@ -600,8 +605,7 @@ namespace mongo { } if ( currentOp->shouldDBProfile( executionTime ) ) { - DurTransaction txn; - profile( &txn, *client, currentOp->getOp(), *currentOp ); + profile( txn, *client, currentOp->getOp(), *currentOp ); } } @@ -614,18 +618,23 @@ namespace mongo { // - error // - static void singleInsert( const BSONObj& docToInsert, + static void singleInsert( TransactionExperiment* txn, + const BSONObj& docToInsert, Collection* collection, WriteOpResult* result ); - static void singleCreateIndex( const BSONObj& indexDesc, + static void singleCreateIndex( TransactionExperiment* txn, + const BSONObj& indexDesc, Collection* collection, WriteOpResult* result ); - static void multiUpdate( const BatchItemRef& updateItem, + static void multiUpdate( TransactionExperiment* txn, + const BatchItemRef& updateItem, WriteOpResult* result ); - static void multiRemove( const BatchItemRef& removeItem, WriteOpResult* result ); + static void multiRemove( TransactionExperiment* txn, + const BatchItemRef& removeItem, + WriteOpResult* result ); // // WRITE EXECUTION @@ -644,7 +653,8 @@ namespace mongo { /** * Constructs a new instance, for performing inserts described in "aRequest". */ - explicit ExecInsertsState(const BatchedCommandRequest* aRequest); + explicit ExecInsertsState(TransactionExperiment* txn, + const BatchedCommandRequest* aRequest); /** * Acquires the write lock and client context needed to perform the current write operation. @@ -677,6 +687,8 @@ namespace mongo { */ Collection* getCollection() { return _collection; } + TransactionExperiment* txn; + // Request object describing the inserts. const BatchedCommandRequest* request; @@ -796,7 +808,7 @@ namespace mongo { // particularly on operation interruption. These kinds of errors necessarily prevent // further insertOne calls, and stop the batch. As a result, the only expected source of // such exceptions are interruptions. - ExecInsertsState state(&request); + ExecInsertsState state(_txn, &request); normalizeInserts(request, &state.normalizedInserts); ElapsedTracker elapsedTracker(128, 10); // 128 hits or 10 ms, matching RunnerYieldPolicy's @@ -832,7 +844,7 @@ namespace mongo { incOpStats( updateItem ); WriteOpResult result; - multiUpdate( updateItem, &result ); + multiUpdate( _txn, updateItem, &result ); if ( !result.getStats().upsertedID.isEmpty() ) { *upsertedId = result.getStats().upsertedID; @@ -840,7 +852,7 @@ namespace mongo { // END CURRENT OP incWriteStats( updateItem, result.getStats(), result.getError(), currentOp.get() ); - finishCurrentOp( _client, currentOp.get(), result.getError() ); + finishCurrentOp( _txn, _client, currentOp.get(), result.getError() ); if ( result.getError() ) { result.getError()->setIndex( updateItem.getItemIndex() ); @@ -859,11 +871,11 @@ namespace mongo { WriteOpResult result; - multiRemove( removeItem, &result ); + multiRemove( _txn, removeItem, &result ); // END CURRENT OP incWriteStats( removeItem, result.getStats(), result.getError(), currentOp.get() ); - finishCurrentOp( _client, currentOp.get(), result.getError() ); + finishCurrentOp( _txn, _client, currentOp.get(), result.getError() ); if ( result.getError() ) { result.getError()->setIndex( removeItem.getItemIndex() ); @@ -875,7 +887,9 @@ namespace mongo { // IN-DB-LOCK CORE OPERATIONS // - WriteBatchExecutor::ExecInsertsState::ExecInsertsState(const BatchedCommandRequest* aRequest) : + WriteBatchExecutor::ExecInsertsState::ExecInsertsState(TransactionExperiment* txn, + const BatchedCommandRequest* aRequest) : + txn(txn), request(aRequest), currIndex(0), _collection(NULL) { @@ -906,8 +920,7 @@ namespace mongo { _collection = database->getCollection(request->getTargetingNS()); if (!_collection) { // Implicitly create if it doesn't exist - DurTransaction txn; - _collection = database->createCollection(&txn, request->getTargetingNS()); + _collection = database->createCollection(txn, request->getTargetingNS()); if (!_collection) { result->setError( toWriteError(Status(ErrorCodes::InternalError, @@ -948,10 +961,10 @@ namespace mongo { try { if (state->lockAndCheck(result)) { if (!state->request->isInsertIndexRequest()) { - singleInsert(insertDoc, state->getCollection(), result); + singleInsert(state->txn, insertDoc, state->getCollection(), result); } else { - singleCreateIndex(insertDoc, state->getCollection(), result); + singleCreateIndex(state->txn, insertDoc, state->getCollection(), result); } } } @@ -989,7 +1002,7 @@ namespace mongo { result.getStats(), result.getError(), currentOp.get()); - finishCurrentOp(_client, currentOp.get(), result.getError()); + finishCurrentOp(_txn, _client, currentOp.get(), result.getError()); if (result.getError()) { *error = result.releaseError(); @@ -1002,7 +1015,8 @@ namespace mongo { * * Might fault or error, otherwise populates the result. */ - static void singleInsert( const BSONObj& docToInsert, + static void singleInsert( TransactionExperiment* txn, + const BSONObj& docToInsert, Collection* collection, WriteOpResult* result ) { @@ -1010,15 +1024,14 @@ namespace mongo { Lock::assertWriteLocked( insertNS ); - DurTransaction txn; - StatusWith<DiskLoc> status = collection->insertDocument( &txn, docToInsert, true ); + StatusWith<DiskLoc> status = collection->insertDocument( txn, docToInsert, true ); if ( !status.isOK() ) { result->setError(toWriteError(status.getStatus())); } else { - logOp( &txn, "i", insertNS.c_str(), docToInsert ); - txn.commitIfNeeded(); + logOp( txn, "i", insertNS.c_str(), docToInsert ); + txn->commitIfNeeded(); result->getStats().n = 1; } } @@ -1029,16 +1042,16 @@ namespace mongo { * * Might fault or error, otherwise populates the result. */ - static void singleCreateIndex( const BSONObj& indexDesc, + static void singleCreateIndex( TransactionExperiment* txn, + const BSONObj& indexDesc, Collection* collection, WriteOpResult* result ) { - DurTransaction txn; const string indexNS = collection->ns().getSystemIndexesCollection(); Lock::assertWriteLocked( indexNS ); - Status status = collection->getIndexCatalog()->createIndex(&txn, indexDesc, true); + Status status = collection->getIndexCatalog()->createIndex(txn, indexDesc, true); if ( status.code() == ErrorCodes::IndexAlreadyExists ) { result->getStats().n = 0; @@ -1047,12 +1060,13 @@ namespace mongo { result->setError(toWriteError(status)); } else { - logOp( &txn, "i", indexNS.c_str(), indexDesc ); + logOp( txn, "i", indexNS.c_str(), indexDesc ); result->getStats().n = 1; } } - static void multiUpdate( const BatchItemRef& updateItem, + static void multiUpdate( TransactionExperiment* txn, + const BatchItemRef& updateItem, WriteOpResult* result ) { const NamespaceString nsString(updateItem.getRequest()->getNS()); @@ -1082,10 +1096,9 @@ namespace mongo { Client::Context ctx( nsString.ns(), storageGlobalParams.dbpath, false /* don't check version */ ); - DurTransaction txn; try { - UpdateResult res = executor.execute(&txn, ctx.db()); + UpdateResult res = executor.execute(txn, ctx.db()); const long long numDocsModified = res.numDocsModified; const long long numMatched = res.numMatched; @@ -1113,7 +1126,8 @@ namespace mongo { * * Might fault or error, otherwise populates the result. */ - static void multiRemove( const BatchItemRef& removeItem, + static void multiRemove( TransactionExperiment* txn, + const BatchItemRef& removeItem, WriteOpResult* result ) { const NamespaceString nss( removeItem.getRequest()->getNS() ); @@ -1145,10 +1159,9 @@ namespace mongo { Client::Context writeContext( nss.ns(), storageGlobalParams.dbpath, false /* don't check version */); - DurTransaction txn; try { - result->getStats().n = executor.execute(&txn, writeContext.db()); + result->getStats().n = executor.execute(txn, writeContext.db()); } catch ( const DBException& ex ) { status = ex.toStatus(); diff --git a/src/mongo/db/commands/write_commands/batch_executor.h b/src/mongo/db/commands/write_commands/batch_executor.h index c45443231ef..6406474e396 100644 --- a/src/mongo/db/commands/write_commands/batch_executor.h +++ b/src/mongo/db/commands/write_commands/batch_executor.h @@ -43,6 +43,7 @@ namespace mongo { class BSONObjBuilder; class CurOp; class OpCounters; + class TransactionExperiment; struct LastError; struct WriteOpStats; @@ -58,7 +59,8 @@ namespace mongo { // State object used by private execInserts. TODO: Do not expose this type. class ExecInsertsState; - WriteBatchExecutor( const BSONObj& defaultWriteConcern, + WriteBatchExecutor( TransactionExperiment* txn, + const BSONObj& defaultWriteConcern, Client* client, OpCounters* opCounters, LastError* le ); @@ -132,6 +134,8 @@ namespace mongo { const WriteErrorDetail* error, CurOp* currentOp ); + TransactionExperiment* _txn; + // Default write concern, if one isn't provide in the batches. const BSONObj _defaultWriteConcern; diff --git a/src/mongo/db/commands/write_commands/write_commands.cpp b/src/mongo/db/commands/write_commands/write_commands.cpp index f64c1fa7545..bcc297cf4b6 100644 --- a/src/mongo/db/commands/write_commands/write_commands.cpp +++ b/src/mongo/db/commands/write_commands/write_commands.cpp @@ -102,7 +102,8 @@ namespace mongo { // Write commands are counted towards their corresponding opcounters, not command opcounters. bool WriteCmd::shouldAffectCommandCounter() const { return false; } - bool WriteCmd::run(const string& dbName, + bool WriteCmd::newRun(TransactionExperiment* txn, + const string& dbName, BSONObj& cmdObj, int options, string& errMsg, @@ -132,7 +133,8 @@ namespace mongo { // TODO: fix this for sane behavior where we query repl set object if ( getLastErrorDefault ) defaultWriteConcern = *getLastErrorDefault; - WriteBatchExecutor writeBatchExecutor(defaultWriteConcern, + WriteBatchExecutor writeBatchExecutor(txn, + defaultWriteConcern, &cc(), &globalOpCounters, lastError.get()); diff --git a/src/mongo/db/commands/write_commands/write_commands.h b/src/mongo/db/commands/write_commands/write_commands.h index f8fccacc439..c94c505d5b5 100644 --- a/src/mongo/db/commands/write_commands/write_commands.h +++ b/src/mongo/db/commands/write_commands/write_commands.h @@ -72,7 +72,9 @@ namespace mongo { virtual bool shouldAffectCommandCounter() const; // Write command entry point. - virtual bool run(const string& dbname, + virtual bool newRun( + TransactionExperiment* txn, + const string& dbname, BSONObj& cmdObj, int options, string& errmsg, diff --git a/src/mongo/db/db.cpp b/src/mongo/db/db.cpp index 2ee1b36f091..8914bb981d0 100644 --- a/src/mongo/db/db.cpp +++ b/src/mongo/db/db.cpp @@ -188,6 +188,7 @@ namespace mongo { } virtual void process( Message& m , AbstractMessagingPort* port , LastError * le) { + DurTransaction txn; while ( true ) { if ( inShutdown() ) { log() << "got request after shutdown()" << endl; @@ -197,7 +198,7 @@ namespace mongo { lastError.startRequest( m , le ); DbResponse dbresponse; - assembleResponse( m, dbresponse, port->remote() ); + assembleResponse( &txn, m, dbresponse, port->remote() ); if ( dbresponse.response ) { port->reply(m, *dbresponse.response, dbresponse.responseTo); @@ -279,7 +280,9 @@ namespace mongo { logStartup(); startReplication(); if (serverGlobalParams.isHttpInterfaceEnabled) - boost::thread web( boost::bind(&webServerThread, new RestAdminAccess() /* takes ownership */)); + boost::thread web( boost::bind(&webServerThread, + new RestAdminAccess(), // takes ownership + DurTransaction::factory) ); // XXX SERVER-13931 #if(TESTEXHAUST) boost::thread thr(testExhaust); @@ -289,8 +292,8 @@ namespace mongo { void doDBUpgrade( const string& dbName, DataFileHeader* h ) { - static DBDirectClient db; DurTransaction txn; + DBDirectClient db(&txn); if ( h->version == 4 && h->versionMinor == 4 ) { verify( PDFILE_VERSION == 4 ); diff --git a/src/mongo/db/dbcommands.cpp b/src/mongo/db/dbcommands.cpp index 97ef4247644..16e59026bee 100644 --- a/src/mongo/db/dbcommands.cpp +++ b/src/mongo/db/dbcommands.cpp @@ -68,7 +68,6 @@ #include "mongo/db/repl/is_master.h" #include "mongo/db/repl/oplog.h" #include "mongo/db/storage/extent_manager.h" -#include "mongo/db/storage/mmap_v1/dur_transaction.h" #include "mongo/db/storage/mmap_v1/mmap_v1_extent_manager.h" #include "mongo/db/storage/record.h" #include "mongo/db/structure/catalog/namespace_details.h" @@ -192,7 +191,7 @@ namespace mongo { CmdDropDatabase() : Command("dropDatabase") {} - bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { + bool newRun(TransactionExperiment* txn, const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { // disallow dropping the config database if (serverGlobalParams.configsvr && (dbname == "config")) { errmsg = "Cannot drop 'config' database if mongod started with --configsvr"; @@ -211,17 +210,16 @@ namespace mongo { // and that may need a global lock. Lock::GlobalWrite lk; Client::Context context(dbname); - DurTransaction txn; log() << "dropDatabase " << dbname << " starting" << endl; stopIndexBuilds(context.db(), cmdObj); - dropDatabase(&txn, context.db()); + dropDatabase(txn, context.db()); log() << "dropDatabase " << dbname << " finished"; if (!fromRepl) - logOp(&txn, "c",(dbname + ".$cmd").c_str(), cmdObj); + logOp(txn, "c",(dbname + ".$cmd").c_str(), cmdObj); } result.append( "dropped" , dbname ); @@ -277,7 +275,7 @@ namespace mongo { return allKilledIndexes; } - bool run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { + bool newRun(TransactionExperiment* txn, const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { BSONElement e = cmdObj.firstElement(); if ( e.numberInt() != 1 ) { errmsg = "bad option"; @@ -288,7 +286,6 @@ namespace mongo { // called within, and that requires a global lock i believe. Lock::GlobalWrite lk; Client::Context context( dbname ); - DurTransaction txn; log() << "repairDatabase " << dbname; std::vector<BSONObj> indexesInProg = stopIndexBuilds(context.db(), cmdObj); @@ -298,7 +295,7 @@ namespace mongo { e = cmdObj.getField( "backupOriginalFiles" ); bool backupOriginalFiles = e.isBoolean() && e.boolean(); Status status = - repairDatabase( &txn, dbname, preserveClonedFilesOnFailure, backupOriginalFiles ); + repairDatabase( txn, dbname, preserveClonedFilesOnFailure, backupOriginalFiles ); IndexBuilder::restoreIndexes(indexesInProg); @@ -354,13 +351,12 @@ namespace mongo { } - bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { + bool newRun(TransactionExperiment* txn, const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { // Needs to be locked exclusively, because creates the system.profile collection // in the local database. // Lock::DBWrite dbXLock(dbname); Client::Context ctx(dbname); - DurTransaction txn; BSONElement e = cmdObj.firstElement(); result.append("was", ctx.db()->getProfilingLevel()); @@ -372,7 +368,7 @@ namespace mongo { if ( p == -1 ) ok = true; else if ( p >= 0 && p <= 2 ) { - ok = ctx.db()->setProfilingLevel( &txn, p , errmsg ); + ok = ctx.db()->setProfilingLevel( txn, p , errmsg ); } BSONElement slow = cmdObj["slowms"]; @@ -452,7 +448,7 @@ namespace mongo { return IndexBuilder::killMatchingIndexBuilds(db->getCollection(nsToDrop), criteria); } - virtual bool run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { + virtual bool newRun(TransactionExperiment* txn, const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { const string nsToDrop = dbname + '.' + cmdObj.firstElement().valuestr(); if (!serverGlobalParams.quiet) { MONGO_TLOG(0) << "CMD: drop " << nsToDrop << endl; @@ -465,10 +461,9 @@ namespace mongo { Lock::DBWrite dbXLock(dbname); Client::Context ctx(nsToDrop); - DurTransaction txn; Database* db = ctx.db(); - Collection* coll = db->getCollection( &txn, nsToDrop ); + Collection* coll = db->getCollection( txn, nsToDrop ); // If collection does not exist, short circuit and return. if ( !coll ) { errmsg = "ns not found"; @@ -482,11 +477,11 @@ namespace mongo { result.append( "ns", nsToDrop ); result.append( "nIndexesWas", numIndexes ); - Status s = db->dropCollection( &txn, nsToDrop ); + Status s = db->dropCollection( txn, nsToDrop ); if ( s.isOK() ) { if (!fromRepl) - logOp(&txn, "c",(dbname + ".$cmd").c_str(), cmdObj); + logOp(txn, "c",(dbname + ".$cmd").c_str(), cmdObj); return true; } @@ -600,7 +595,7 @@ namespace mongo { return Status(ErrorCodes::Unauthorized, "unauthorized"); } - virtual bool run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) { + virtual bool newRun(TransactionExperiment* txn, const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) { BSONObjIterator it(cmdObj); // Extract ns from first cmdObj element. @@ -630,11 +625,10 @@ namespace mongo { Lock::DBWrite dbXLock(dbname); Client::Context ctx(ns); - DurTransaction txn; // Create collection. return appendCommandStatus( result, - userCreateNS(&txn, ctx.db(), ns.c_str(), options, !fromRepl) ); + userCreateNS(txn, ctx.db(), ns.c_str(), options, !fromRepl) ); } } cmdCreate; @@ -1150,12 +1144,11 @@ namespace mongo { out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions)); } - bool run(const string& dbname, BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) { + bool newRun(TransactionExperiment* txn, const string& dbname, BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) { const string ns = dbname + "." + jsobj.firstElement().valuestr(); Lock::DBWrite dbXLock(dbname); Client::Context ctx( ns ); - DurTransaction txn; Collection* coll = ctx.db()->getCollection( ns ); if ( !coll ) { @@ -1181,9 +1174,9 @@ namespace mongo { result.appendBool( "usePowerOf2Sizes_old", oldPowerOf2 ); if ( newPowerOf2 ) - coll->setUserFlag( &txn, NamespaceDetails::Flag_UsePowerOf2Sizes ); + coll->setUserFlag( txn, NamespaceDetails::Flag_UsePowerOf2Sizes ); else - coll->clearUserFlag( &txn, NamespaceDetails::Flag_UsePowerOf2Sizes ); + coll->clearUserFlag( txn, NamespaceDetails::Flag_UsePowerOf2Sizes ); result.appendBool( "usePowerOf2Sizes_new", newPowerOf2 ); } @@ -1232,7 +1225,7 @@ namespace mongo { if ( oldExpireSecs != newExpireSecs ) { // change expireAfterSeconds result.appendAs( oldExpireSecs, "expireAfterSeconds_old" ); - coll->getIndexCatalog()->updateTTLSetting( &txn, idx, newExpireSecs.numberLong() ); + coll->getIndexCatalog()->updateTTLSetting( txn, idx, newExpireSecs.numberLong() ); result.appendAs( newExpireSecs , "expireAfterSeconds_new" ); } } @@ -1243,7 +1236,7 @@ namespace mongo { } if (ok && !fromRepl) - logOp(&txn, "c",(dbname + ".$cmd").c_str(), jsobj); + logOp(txn, "c",(dbname + ".$cmd").c_str(), jsobj); return ok; } @@ -1394,7 +1387,8 @@ namespace mongo { } cmdWhatsMyUri; - bool _execCommand(Command *c, + bool _execCommand(TransactionExperiment* txn, + Command *c, const string& dbname, BSONObj& cmdObj, int queryOptions, @@ -1403,7 +1397,7 @@ namespace mongo { bool fromRepl) { try { - return c->run(dbname, cmdObj, queryOptions, errmsg, result, fromRepl); + return c->newRun(txn, dbname, cmdObj, queryOptions, errmsg, result, fromRepl); } catch ( SendStaleConfigException& e ){ LOG(1) << "command failed because of stale config, can retry" << causedBy( e ) << endl; @@ -1483,7 +1477,8 @@ namespace mongo { - context then calls run() */ - void Command::execCommand(Command * c , + void Command::execCommand(TransactionExperiment* txn, + Command * c , Client& client, int queryOptions, const char *cmdns, @@ -1585,7 +1580,7 @@ namespace mongo { client.curop()->ensureStarted(); - retval = _execCommand(c, dbname, cmdObj, queryOptions, errmsg, result, fromRepl); + retval = _execCommand(txn, c, dbname, cmdObj, queryOptions, errmsg, result, fromRepl); appendCommandStatus(result, retval, errmsg); @@ -1608,7 +1603,12 @@ namespace mongo { returns true if ran a cmd */ - bool _runCommands(const char *ns, BSONObj& _cmdobj, BufBuilder &b, BSONObjBuilder& anObjBuilder, bool fromRepl, int queryOptions) { + bool _runCommands(TransactionExperiment* txn, + const char* ns, + BSONObj& _cmdobj, + BufBuilder& b, + BSONObjBuilder& anObjBuilder, + bool fromRepl, int queryOptions) { string dbname = nsToDatabase( ns ); LOG(2) << "run command " << ns << ' ' << _cmdobj << endl; @@ -1654,7 +1654,7 @@ namespace mongo { Command * c = e.type() ? Command::findCommand( e.fieldName() ) : 0; if ( c ) { - Command::execCommand(c, client, queryOptions, ns, jsobj, anObjBuilder, fromRepl); + Command::execCommand(txn, c, client, queryOptions, ns, jsobj, anObjBuilder, fromRepl); } else { Command::appendCommandStatus(anObjBuilder, diff --git a/src/mongo/db/dbhelpers.cpp b/src/mongo/db/dbhelpers.cpp index 38815864034..72d60dffbcd 100644 --- a/src/mongo/db/dbhelpers.cpp +++ b/src/mongo/db/dbhelpers.cpp @@ -318,7 +318,8 @@ namespace mongo { return true; } - long long Helpers::removeRange( const KeyRange& range, + long long Helpers::removeRange( TransactionExperiment* txn, + const KeyRange& range, bool maxInclusive, bool secondaryThrottle, RemoveSaver* callback, @@ -366,8 +367,7 @@ namespace mongo { // Scoping for write lock. { Client::WriteContext ctx(ns); - DurTransaction txn; - Collection* collection = ctx.ctx().db()->getCollection( &txn, ns ); + Collection* collection = ctx.ctx().db()->getCollection( txn, ns ); if ( !collection ) break; @@ -437,8 +437,8 @@ namespace mongo { if ( callback ) callback->goingToDelete( obj ); - logOp(&txn, "d", ns.c_str(), obj["_id"].wrap(), 0, 0, fromMigrate); - collection->deleteDocument( &txn, rloc ); + logOp(txn, "d", ns.c_str(), obj["_id"].wrap(), 0, 0, fromMigrate); + collection->deleteDocument( txn, rloc ); numDeleted++; } diff --git a/src/mongo/db/dbhelpers.h b/src/mongo/db/dbhelpers.h index 660ef27f926..c10c6f24a21 100644 --- a/src/mongo/db/dbhelpers.h +++ b/src/mongo/db/dbhelpers.h @@ -162,7 +162,8 @@ namespace mongo { * Does oplog the individual document deletions. * // TODO: Refactor this mechanism, it is growing too large */ - static long long removeRange( const KeyRange& range, + static long long removeRange( TransactionExperiment* txn, + const KeyRange& range, bool maxInclusive = false, bool secondaryThrottle = false, RemoveSaver* callback = NULL, diff --git a/src/mongo/db/dbwebserver.cpp b/src/mongo/db/dbwebserver.cpp index cfd6c747e38..e63ad58f0d8 100644 --- a/src/mongo/db/dbwebserver.cpp +++ b/src/mongo/db/dbwebserver.cpp @@ -50,6 +50,7 @@ #include "mongo/db/db.h" #include "mongo/db/instance.h" #include "mongo/db/stats/snapshots.h" +#include "mongo/db/storage/mmap_v1/dur_transaction.h" #include "mongo/util/admin_access.h" #include "mongo/util/md5.hpp" #include "mongo/util/mongoutils/html.h" @@ -73,13 +74,20 @@ namespace mongo { class DbWebServer : public MiniWebServer { public: - DbWebServer(const string& ip, int port, const AdminAccess* webUsers) - : MiniWebServer("admin web console", ip, port), _webUsers(webUsers) { + DbWebServer(const string& ip, + int port, + const AdminAccess* webUsers, + TransactionExperiment::Factory transactionFactory) + : MiniWebServer("admin web console", ip, port), + _webUsers(webUsers), + _transactionFactory(transactionFactory) { + WebStatusPlugin::initAll(); } private: const AdminAccess* _webUsers; // not owned here + const TransactionExperiment::Factory _transactionFactory; void doUnlockedStuff(stringstream& ss) { /* this is in the header already ss << "port: " << port << '\n'; */ @@ -179,6 +187,9 @@ namespace mongo { vector<string>& headers, // if completely empty, content-type: text/html will be added const SockAddr &from ) { + + boost::scoped_ptr<TransactionExperiment> txn(_transactionFactory()); // XXX SERVER-13931 + if ( url.size() > 1 ) { if ( ! allowed( rq , headers, from ) ) { @@ -206,7 +217,7 @@ namespace mongo { uassert(13453, "server not started with --jsonp", callback.empty() || serverGlobalParams.jsonp); - handler->handle( rq , url , params , responseMsg , responseCode , headers , from ); + handler->handle( txn.get(), rq , url , params , responseMsg , responseCode , headers , from ); if (responseCode == 200 && !callback.empty()) { responseMsg = callback + '(' + responseMsg + ')'; @@ -410,7 +421,8 @@ namespace mongo { public: FavIconHandler() : DbWebHandler( "favicon.ico" , 0 , false ) {} - virtual void handle( const char *rq, const std::string& url, BSONObj params, + virtual void handle( TransactionExperiment* txn, + const char *rq, const std::string& url, BSONObj params, string& responseMsg, int& responseCode, vector<string>& headers, const SockAddr &from ) { responseCode = 404; @@ -424,7 +436,8 @@ namespace mongo { public: StatusHandler() : DbWebHandler( "_status" , 1 , false ) {} - virtual void handle( const char *rq, const std::string& url, BSONObj params, + virtual void handle( TransactionExperiment* txn, + const char *rq, const std::string& url, BSONObj params, string& responseMsg, int& responseCode, vector<string>& headers, const SockAddr &from ) { headers.push_back( "Content-Type: application/json;charset=utf-8" ); @@ -459,7 +472,7 @@ namespace mongo { string errmsg; BSONObjBuilder sub; - if ( ! c->run( "admin.$cmd" , co , 0, errmsg , sub , false ) ) + if ( ! c->newRun( txn, "admin.$cmd" , co , 0, errmsg , sub , false ) ) buf.append( cmd , errmsg ); else buf.append( cmd , sub.obj() ); @@ -475,7 +488,8 @@ namespace mongo { public: CommandListHandler() : DbWebHandler( "_commands" , 1 , true ) {} - virtual void handle( const char *rq, const std::string& url, BSONObj params, + virtual void handle( TransactionExperiment* txn, + const char *rq, const std::string& url, BSONObj params, string& responseMsg, int& responseCode, vector<string>& headers, const SockAddr &from ) { headers.push_back( "Content-Type: text/html;charset=utf-8" ); @@ -527,7 +541,8 @@ namespace mongo { return _cmd(cmd) != 0; } - virtual void handle( const char *rq, const std::string& url, BSONObj params, + virtual void handle( TransactionExperiment* txn, + const char *rq, const std::string& url, BSONObj params, string& responseMsg, int& responseCode, vector<string>& headers, const SockAddr &from ) { string cmd; @@ -540,7 +555,7 @@ namespace mongo { Client& client = cc(); BSONObjBuilder result; - Command::execCommand(c, client, 0, "admin.", cmdObj , result, false); + Command::execCommand(txn, c, client, 0, "admin.", cmdObj , result, false); responseCode = 200; @@ -561,11 +576,12 @@ namespace mongo { // --- external ---- - void webServerThread(const AdminAccess* adminAccess) { + void webServerThread(const AdminAccess* adminAccess, + TransactionExperiment::Factory transactionFactory) { boost::scoped_ptr<const AdminAccess> adminAccessPtr(adminAccess); // adminAccess is owned here Client::initThread("websvr"); const int p = serverGlobalParams.port + 1000; - DbWebServer mini(serverGlobalParams.bind_ip, p, adminAccessPtr.get()); + DbWebServer mini(serverGlobalParams.bind_ip, p, adminAccessPtr.get(), transactionFactory); mini.setupSockets(); mini.initAndListen(); cc().shutdown(); diff --git a/src/mongo/db/dbwebserver.h b/src/mongo/db/dbwebserver.h index 894ad574baf..445f3f2ef33 100644 --- a/src/mongo/db/dbwebserver.h +++ b/src/mongo/db/dbwebserver.h @@ -34,6 +34,7 @@ #include "mongo/util/admin_access.h" #include "mongo/util/net/sock.h" +#include "mongo/db/storage/transaction.h" namespace mongo { @@ -54,7 +55,8 @@ namespace mongo { virtual bool requiresREST( const string& url ) const { return _requiresREST; } - virtual void handle( const char *rq, // the full request + virtual void handle( TransactionExperiment* txn, + const char *rq, // the full request const std::string& url, BSONObj params, // set these and return them: @@ -94,8 +96,7 @@ namespace mongo { static vector<WebStatusPlugin*> * _plugins; }; - - void webServerThread( const AdminAccess* admins ); + void webServerThread( const AdminAccess* admins, TransactionExperiment::Factory transactionFactory ); string prettyHostName(); }; diff --git a/src/mongo/db/instance.cpp b/src/mongo/db/instance.cpp index 4db14c1d689..ab711aab742 100644 --- a/src/mongo/db/instance.cpp +++ b/src/mongo/db/instance.cpp @@ -96,11 +96,11 @@ namespace mongo { inline void opread(Message& m) { if( _diaglog.getLevel() & 2 ) _diaglog.readop((char *) m.singleData(), m.header()->len); } inline void opwrite(Message& m) { if( _diaglog.getLevel() & 1 ) _diaglog.writeop((char *) m.singleData(), m.header()->len); } - void receivedKillCursors(Message& m); - void receivedUpdate(Message& m, CurOp& op); - void receivedDelete(Message& m, CurOp& op); - void receivedInsert(Message& m, CurOp& op); - bool receivedGetMore(DbResponse& dbresponse, Message& m, CurOp& curop ); + void receivedKillCursors(TransactionExperiment* txn, Message& m); + void receivedUpdate(TransactionExperiment* txn, Message& m, CurOp& op); + void receivedDelete(TransactionExperiment* txn, Message& m, CurOp& op); + void receivedInsert(TransactionExperiment* txn, Message& m, CurOp& op); + bool receivedGetMore(TransactionExperiment* txn, DbResponse& dbresponse, Message& m, CurOp& curop ); int nloggedsome = 0; #define LOGWITHRATELIMIT if( ++nloggedsome < 1000 || nloggedsome % 100 == 0 ) @@ -232,7 +232,7 @@ namespace mongo { replyToQuery(0, m, dbresponse, obj); } - static bool receivedQuery(Client& c, DbResponse& dbresponse, Message& m ) { + static bool receivedQuery(TransactionExperiment* txn, Client& c, DbResponse& dbresponse, Message& m ) { bool ok = true; MSGID responseTo = m.header()->id; @@ -253,7 +253,7 @@ namespace mongo { audit::logQueryAuthzCheck(client, ns, q.query, status.code()); uassertStatusOK(status); } - dbresponse.exhaustNS = newRunQuery(m, q, op, *resp); + dbresponse.exhaustNS = newRunQuery(txn, m, q, op, *resp); verify( !resp->empty() ); } catch ( SendStaleConfigException& e ){ @@ -329,7 +329,10 @@ namespace mongo { } // Returns false when request includes 'end' - void assembleResponse( Message &m, DbResponse &dbresponse, const HostAndPort& remote ) { + void assembleResponse( TransactionExperiment* txn, + Message& m, + DbResponse& dbresponse, + const HostAndPort& remote ) { // before we lock... int op = m.operation(); @@ -418,10 +421,10 @@ namespace mongo { if ( op == dbQuery ) { if ( handlePossibleShardedMessage( m , &dbresponse ) ) return; - receivedQuery(c , dbresponse, m ); + receivedQuery(txn, c , dbresponse, m ); } else if ( op == dbGetMore ) { - if ( ! receivedGetMore(dbresponse, m, currentOp) ) + if ( ! receivedGetMore(txn, dbresponse, m, currentOp) ) shouldLog = true; } else if ( op == dbMsg ) { @@ -451,20 +454,20 @@ namespace mongo { if ( op == dbKillCursors ) { currentOp.ensureStarted(); logThreshold = 10; - receivedKillCursors(m); + receivedKillCursors(txn, m); } else if ( !nsString.isValid() ) { // Only killCursors doesn't care about namespaces uassert( 16257, str::stream() << "Invalid ns [" << ns << "]", false ); } else if ( op == dbInsert ) { - receivedInsert(m, currentOp); + receivedInsert(txn, m, currentOp); } else if ( op == dbUpdate ) { - receivedUpdate(m, currentOp); + receivedUpdate(txn, m, currentOp); } else if ( op == dbDelete ) { - receivedDelete(m, currentOp); + receivedDelete(txn, m, currentOp); } else { mongo::log() << " operation isn't supported: " << op << endl; @@ -503,8 +506,7 @@ namespace mongo { LOG(1) << "note: not profiling because doing fsync+lock" << endl; } else { - DurTransaction txn; - profile(&txn, c, op, currentOp); + profile(txn, c, op, currentOp); } } @@ -512,7 +514,7 @@ namespace mongo { debug.reset(); } /* assembleResponse() */ - void receivedKillCursors(Message& m) { + void receivedKillCursors(TransactionExperiment* txn, Message& m) { int *x = (int *) m.singleData()->_data; x++; // reserved int n = *x++; @@ -561,7 +563,7 @@ namespace mongo { delete database; // closes files } - void receivedUpdate(Message& m, CurOp& op) { + void receivedUpdate(TransactionExperiment* txn, Message& m, CurOp& op) { DbMessage d(m); NamespaceString ns(d.getns()); uassertStatusOK( userAllowedWriteNS( ns ) ); @@ -609,15 +611,14 @@ namespace mongo { return; Client::Context ctx( ns ); - DurTransaction txn; - UpdateResult res = executor.execute(&txn, ctx.db()); + UpdateResult res = executor.execute(txn, ctx.db()); // for getlasterror lastError.getSafe()->recordUpdate( res.existing , res.numMatched , res.upserted ); } - void receivedDelete(Message& m, CurOp& op) { + void receivedDelete(TransactionExperiment* txn, Message& m, CurOp& op) { DbMessage d(m); NamespaceString ns(d.getns()); uassertStatusOK( userAllowedWriteNS( ns ) ); @@ -649,16 +650,15 @@ namespace mongo { return; Client::Context ctx(ns); - DurTransaction txn; - long long n = executor.execute(&txn, ctx.db()); + long long n = executor.execute(txn, ctx.db()); lastError.getSafe()->recordDelete( n ); op.debug().ndeleted = n; } QueryResult* emptyMoreResult(long long); - bool receivedGetMore(DbResponse& dbresponse, Message& m, CurOp& curop ) { + bool receivedGetMore(TransactionExperiment* txn, DbResponse& dbresponse, Message& m, CurOp& curop ) { bool ok = true; DbMessage d(m); @@ -854,7 +854,7 @@ namespace mongo { op.debug().ninserted = i; } - void receivedInsert(Message& m, CurOp& op) { + void receivedInsert(TransactionExperiment* txn, Message& m, CurOp& op) { DbMessage d(m); const char *ns = d.getns(); op.debug().ns = ns; @@ -889,13 +889,12 @@ namespace mongo { return; Client::Context ctx(ns); - DurTransaction txn; if (multi.size() > 1) { const bool keepGoing = d.reservedField() & InsertOption_ContinueOnError; - insertMulti(&txn, ctx, keepGoing, ns, multi, op); + insertMulti(txn, ctx, keepGoing, ns, multi, op); } else { - checkAndInsert(&txn, ctx, ns, multi[0]); + checkAndInsert(txn, ctx, ns, multi[0]); globalOpCounters.incInsertInWriteLock(1); op.debug().ninserted = 1; } @@ -942,6 +941,15 @@ namespace mongo { return false; } + DBDirectClient::DBDirectClient() + : _txnOwned(new DurTransaction), + _txn(_txnOwned.get()) + {} + + DBDirectClient::DBDirectClient(TransactionExperiment* txn) + : _txn(txn) + {} + QueryOptions DBDirectClient::_lookupAvailableOptions() { // Exhaust mode is not available in DBDirectClient. return QueryOptions(DBClientBase::_lookupAvailableOptions() & ~QueryOption_Exhaust); @@ -965,11 +973,11 @@ namespace { if ( lastError._get() ) lastError.startRequest( toSend, lastError._get() ); DbResponse dbResponse; - assembleResponse( toSend, dbResponse , _clientHost ); + assembleResponse( _txn, toSend, dbResponse , _clientHost ); verify( dbResponse.response ); dbResponse.response->concat(); // can get rid of this if we make response handling smarter response = *dbResponse.response; - getDur().commitIfNeeded(); + _txn->commitIfNeeded(); return true; } @@ -978,8 +986,8 @@ namespace { if ( lastError._get() ) lastError.startRequest( toSend, lastError._get() ); DbResponse dbResponse; - assembleResponse( toSend, dbResponse , _clientHost ); - getDur().commitIfNeeded(); + assembleResponse( _txn, toSend, dbResponse , _clientHost ); + _txn->commitIfNeeded(); } auto_ptr<DBClientCursor> DBDirectClient::query(const string &ns, Query query, int nToReturn , int nToSkip , diff --git a/src/mongo/db/instance.h b/src/mongo/db/instance.h index d848f6f1c09..50a988917ad 100644 --- a/src/mongo/db/instance.h +++ b/src/mongo/db/instance.h @@ -35,6 +35,7 @@ #include "mongo/db/client.h" #include "mongo/db/curop-inl.h" #include "mongo/db/dbmessage.h" +#include "mongo/db/storage/transaction.h" #include "mongo/db/storage_options.h" namespace mongo { @@ -67,7 +68,10 @@ namespace mongo { extern DiagLog _diaglog; - void assembleResponse( Message &m, DbResponse &dbresponse, const HostAndPort &client ); + void assembleResponse( TransactionExperiment* txn, + Message& m, + DbResponse& dbresponse, + const HostAndPort &client ); void getDatabaseNames(vector<std::string> &names, const std::string& usePath = storageGlobalParams.dbpath); @@ -82,6 +86,9 @@ namespace mongo { */ class DBDirectClient : public DBClientBase { public: + DBDirectClient(); // DEPRECATED + DBDirectClient(TransactionExperiment* txn); // txn must outlive this object + using DBClientBase::query; virtual auto_ptr<DBClientCursor> query(const string &ns, Query query, int nToReturn = 0, int nToSkip = 0, @@ -126,6 +133,8 @@ namespace mongo { private: static HostAndPort _clientHost; + boost::scoped_ptr<TransactionExperiment> _txnOwned; + TransactionExperiment* _txn; // Points either to _txnOwned or a passed-in transaction. }; extern int lockFile; diff --git a/src/mongo/db/query/new_find.cpp b/src/mongo/db/query/new_find.cpp index 40990a0baa6..9236cb92333 100644 --- a/src/mongo/db/query/new_find.cpp +++ b/src/mongo/db/query/new_find.cpp @@ -109,7 +109,8 @@ namespace { namespace mongo { // TODO: Move this and the other command stuff in newRunQuery outta here and up a level. - static bool runCommands(const char *ns, + static bool runCommands(TransactionExperiment* txn, + const char *ns, BSONObj& jsobj, CurOp& curop, BufBuilder &b, @@ -117,7 +118,7 @@ namespace mongo { bool fromRepl, int queryOptions) { try { - return _runCommands(ns, jsobj, b, anObjBuilder, fromRepl, queryOptions); + return _runCommands(txn, ns, jsobj, b, anObjBuilder, fromRepl, queryOptions); } catch( SendStaleConfigException& ){ throw; @@ -397,7 +398,11 @@ namespace mongo { return Status::OK(); } - std::string newRunQuery(Message& m, QueryMessage& q, CurOp& curop, Message &result) { + std::string newRunQuery(TransactionExperiment* txn, + Message& m, + QueryMessage& q, + CurOp& curop, + Message &result) { // Validate the namespace. const char *ns = q.ns; uassert(16332, "can't have an empty ns", ns[0]); @@ -424,7 +429,7 @@ namespace mongo { bb.skip(sizeof(QueryResult)); BSONObjBuilder cmdResBuf; - if (!runCommands(ns, q.query, curop, bb, cmdResBuf, false, q.queryOptions)) { + if (!runCommands(txn, ns, q.query, curop, bb, cmdResBuf, false, q.queryOptions)) { uasserted(13530, "bad or malformed command request?"); } diff --git a/src/mongo/db/query/new_find.h b/src/mongo/db/query/new_find.h index 2977a83ab51..149bcce9b0a 100644 --- a/src/mongo/db/query/new_find.h +++ b/src/mongo/db/query/new_find.h @@ -39,6 +39,8 @@ namespace mongo { + class TransactionExperiment; + /** * Called from the getMore entry point in ops/query.cpp. */ @@ -48,6 +50,10 @@ namespace mongo { /** * Run the query 'q' and place the result in 'result'. */ - std::string newRunQuery(Message& m, QueryMessage& q, CurOp& curop, Message &result); + std::string newRunQuery(TransactionExperiment* txn, + Message& m, + QueryMessage& q, + CurOp& curop, + Message &result); } // namespace mongo diff --git a/src/mongo/db/range_deleter.cpp b/src/mongo/db/range_deleter.cpp index 0ea7e44e4ec..229f7e82060 100644 --- a/src/mongo/db/range_deleter.cpp +++ b/src/mongo/db/range_deleter.cpp @@ -73,7 +73,8 @@ namespace mongo { struct RangeDeleter::RangeDeleteEntry { RangeDeleteEntry(): secondaryThrottle(true), - notifyDone(NULL) { + notifyDone(NULL), + transactionFactory(TransactionExperiment::factoryNULL) { // XXX SERVER-13931 } std::string ns; @@ -99,6 +100,8 @@ namespace mongo { // Important invariant: Can only be set and used by one thread. Notification* notifyDone; + TransactionExperiment::Factory transactionFactory; + // For debugging only BSONObj toBSON() const { return BSON("ns" << ns @@ -193,7 +196,8 @@ namespace mongo { } } - bool RangeDeleter::queueDelete(const std::string& ns, + bool RangeDeleter::queueDelete(TransactionExperiment::Factory transactionFactory, + const std::string& ns, const BSONObj& min, const BSONObj& max, const BSONObj& shardKeyPattern, @@ -204,6 +208,7 @@ namespace mongo { if (errMsg == NULL) errMsg = &dummy; auto_ptr<RangeDeleteEntry> toDelete(new RangeDeleteEntry); + toDelete->transactionFactory = transactionFactory; toDelete->ns = ns; toDelete->min = min.getOwned(); toDelete->max = max.getOwned(); @@ -247,7 +252,8 @@ namespace mongo { return true; } - bool RangeDeleter::deleteNow(const std::string& ns, + bool RangeDeleter::deleteNow(TransactionExperiment* txn, + const std::string& ns, const BSONObj& min, const BSONObj& max, const BSONObj& shardKeyPattern, @@ -323,7 +329,7 @@ namespace mongo { sleepmillis(checkIntervalMillis); } - bool result = _env->deleteRange(ns, min, max, shardKeyPattern, + bool result = _env->deleteRange(txn, ns, min, max, shardKeyPattern, secondaryThrottle, errMsg); { @@ -468,14 +474,18 @@ namespace mongo { _stats->incInProgressDeletes_inlock(); } - if (!_env->deleteRange(nextTask->ns, - nextTask->min, - nextTask->max, - nextTask->shardKeyPattern, - nextTask->secondaryThrottle, - &errMsg)) { - warning() << "Error encountered while trying to delete range: " - << errMsg << endl; + { + boost::scoped_ptr<TransactionExperiment> txn(nextTask->transactionFactory()); // XXX SERVER-13931 + if (!_env->deleteRange(txn.get(), + nextTask->ns, + nextTask->min, + nextTask->max, + nextTask->shardKeyPattern, + nextTask->secondaryThrottle, + &errMsg)) { + warning() << "Error encountered while trying to delete range: " + << errMsg << endl; + } } { diff --git a/src/mongo/db/range_deleter.h b/src/mongo/db/range_deleter.h index b8fd0789c5a..653fb0105b0 100644 --- a/src/mongo/db/range_deleter.h +++ b/src/mongo/db/range_deleter.h @@ -37,6 +37,7 @@ #include "mongo/base/string_data.h" #include "mongo/db/clientcursor.h" #include "mongo/db/jsobj.h" +#include "mongo/db/storage/transaction.h" #include "mongo/util/concurrency/mutex.h" #include "mongo/util/concurrency/synchronization.h" @@ -44,6 +45,7 @@ namespace mongo { struct RangeDeleterEnv; class RangeDeleterStats; + class TransactionExperiment; /** * Class for deleting documents for a given namespace and range. It contains a queue of @@ -129,7 +131,8 @@ namespace mongo { * Returns true if the task is queued and false If the given range is blacklisted, * is already queued, or stopWorkers() was called. */ - bool queueDelete(const std::string& ns, + bool queueDelete(TransactionExperiment::Factory transactionFactory, + const std::string& ns, const BSONObj& min, const BSONObj& max, const BSONObj& shardKeyPattern, @@ -144,7 +147,8 @@ namespace mongo { * Returns true if the deletion was performed. False if the range is blacklisted, * was already queued, or stopWorkers() was called. */ - bool deleteNow(const std::string& ns, + bool deleteNow(TransactionExperiment* txn, + const std::string& ns, const BSONObj& min, const BSONObj& max, const BSONObj& shardKeyPattern, @@ -284,7 +288,8 @@ namespace mongo { * Must be a synchronous call. Docs should be deleted after call ends. * Must not throw Exceptions. */ - virtual bool deleteRange(const StringData& ns, + virtual bool deleteRange(TransactionExperiment* txn, + const StringData& ns, const BSONObj& inclusiveLower, const BSONObj& exclusiveUpper, const BSONObj& shardKeyPattern, diff --git a/src/mongo/db/range_deleter_db_env.cpp b/src/mongo/db/range_deleter_db_env.cpp index 3d2f61c221c..71a0ca86796 100644 --- a/src/mongo/db/range_deleter_db_env.cpp +++ b/src/mongo/db/range_deleter_db_env.cpp @@ -54,7 +54,8 @@ namespace mongo { * 5. Delete range. * 6. Wait until the majority of the secondaries catch up. */ - bool RangeDeleterDBEnv::deleteRange(const StringData& ns, + bool RangeDeleterDBEnv::deleteRange(TransactionExperiment* txn, + const StringData& ns, const BSONObj& inclusiveLower, const BSONObj& exclusiveUpper, const BSONObj& keyPattern, @@ -80,7 +81,8 @@ namespace mongo { try { long long numDeleted = - Helpers::removeRange(KeyRange(ns.toString(), + Helpers::removeRange(txn, + KeyRange(ns.toString(), inclusiveLower, exclusiveUpper, keyPattern), diff --git a/src/mongo/db/range_deleter_db_env.h b/src/mongo/db/range_deleter_db_env.h index b55389e3edd..01089fc9d3d 100644 --- a/src/mongo/db/range_deleter_db_env.h +++ b/src/mongo/db/range_deleter_db_env.h @@ -51,7 +51,8 @@ namespace mongo { * * Does not throw Exceptions. */ - virtual bool deleteRange(const StringData& ns, + virtual bool deleteRange(TransactionExperiment* txn, + const StringData& ns, const BSONObj& inclusiveLower, const BSONObj& exclusiveUpper, const BSONObj& keyPattern, diff --git a/src/mongo/db/range_deleter_mock_env.cpp b/src/mongo/db/range_deleter_mock_env.cpp index 536d463417e..22ecff1bea4 100644 --- a/src/mongo/db/range_deleter_mock_env.cpp +++ b/src/mongo/db/range_deleter_mock_env.cpp @@ -100,7 +100,8 @@ namespace mongo { return _deleteList.back(); } - bool RangeDeleterMockEnv::deleteRange(const StringData& ns, + bool RangeDeleterMockEnv::deleteRange(TransactionExperiment* txn, + const StringData& ns, const BSONObj& min, const BSONObj& max, const BSONObj& shardKeyPattern, diff --git a/src/mongo/db/range_deleter_mock_env.h b/src/mongo/db/range_deleter_mock_env.h index 7b1cd3932e3..4ba3e686d9d 100644 --- a/src/mongo/db/range_deleter_mock_env.h +++ b/src/mongo/db/range_deleter_mock_env.h @@ -126,7 +126,8 @@ namespace mongo { * but simply keeps a record of it. Can also be paused by pauseDeletes and * resumed with resumeDeletes. */ - bool deleteRange(const StringData& ns, + bool deleteRange(TransactionExperiment* txn, + const StringData& ns, const BSONObj& min, const BSONObj& max, const BSONObj& shardKeyPattern, diff --git a/src/mongo/db/range_deleter_stat_test.cpp b/src/mongo/db/range_deleter_stat_test.cpp index 6de5f15d196..695da1d8a26 100644 --- a/src/mongo/db/range_deleter_stat_test.cpp +++ b/src/mongo/db/range_deleter_stat_test.cpp @@ -48,6 +48,9 @@ namespace { using mongo::RangeDeleter; using mongo::RangeDeleterMockEnv; using mongo::RangeDeleterStats; + using mongo::TransactionExperiment; + + TransactionExperiment* const noTxn = NULL; // MockEnv doesn't need txn XXX SERVER-13931 TEST(NoDeletes, InitialState) { RangeDeleterMockEnv* env = new RangeDeleterMockEnv(); @@ -85,7 +88,8 @@ namespace { string errMsg; Notification notifyDone; - ASSERT_TRUE(deleter.queueDelete(ns, + ASSERT_TRUE(deleter.queueDelete(TransactionExperiment::factoryNULL, + ns, BSON("x" << 0), BSON("x" << 10), BSON("x" << 1), @@ -127,7 +131,8 @@ namespace { Notification deleteDone; string errMsg; - ASSERT_TRUE(deleter.queueDelete(ns, + ASSERT_TRUE(deleter.queueDelete(TransactionExperiment::factoryNULL, // XXX SERVER-13931 + ns, BSON("x" << 0), BSON("x" << 10), BSON("x" << 1), @@ -170,7 +175,8 @@ namespace { string errMsg; Notification notifyDone; - ASSERT_TRUE(deleter.queueDelete(ns, + ASSERT_TRUE(deleter.queueDelete(TransactionExperiment::factoryNULL, // XXX SERVER-13931 + ns, BSON("x" << 0), BSON("x" << 10), BSON("x" << 1), @@ -213,6 +219,7 @@ namespace { string errMsg; boost::thread deleterThread = boost::thread(boost::bind(&RangeDeleter::deleteNow, &deleter, + noTxn, ns, BSON("x" << 0), BSON("x" << 10), @@ -256,6 +263,7 @@ namespace { string errMsg; boost::thread deleterThread = boost::thread(boost::bind(&RangeDeleter::deleteNow, &deleter, + noTxn, ns, BSON("x" << 0), BSON("x" << 10), @@ -296,7 +304,7 @@ namespace { const string ns("test.user"); string errMsg; - ASSERT_TRUE(deleter.deleteNow(ns, BSON("x" << 0), BSON("x" << 10), + ASSERT_TRUE(deleter.deleteNow(noTxn, ns, BSON("x" << 0), BSON("x" << 10), BSON("x" << 1), true, &errMsg)); const BSONObj stats(deleter.getStats()->toBSON()); diff --git a/src/mongo/db/range_deleter_test.cpp b/src/mongo/db/range_deleter_test.cpp index 23a93da14b0..1bc2ac0beae 100644 --- a/src/mongo/db/range_deleter_test.cpp +++ b/src/mongo/db/range_deleter_test.cpp @@ -49,6 +49,9 @@ namespace { using mongo::RangeDeleter; using mongo::RangeDeleterMockEnv; using mongo::RangeDeleterStats; + using mongo::TransactionExperiment; + + TransactionExperiment* const noTxn = NULL; // MockEnv doesn't need txn XXX SERVER-13931 // Capped sleep interval is 640 mSec, Nyquist frequency is 1280 mSec => round up to 2 sec. const int MAX_IMMEDIATE_DELETE_WAIT_SECS = 2; @@ -62,7 +65,8 @@ namespace { deleter.stopWorkers(); string errMsg; - ASSERT_FALSE(deleter.queueDelete("test.user", + ASSERT_FALSE(deleter.queueDelete(TransactionExperiment::factoryNULL, // XXX SERVER-13931 + "test.user", BSON("x" << 120), BSON("x" << 200), BSON("x" << 1), @@ -84,7 +88,8 @@ namespace { env->addCursorId(ns, 345); Notification notifyDone; - ASSERT_TRUE(deleter.queueDelete(ns, BSON("x" << 0), BSON("x" << 10), BSON("x" << 1), + ASSERT_TRUE(deleter.queueDelete(TransactionExperiment::factoryNULL, // XXX SERVER-13931 + ns, BSON("x" << 0), BSON("x" << 10), BSON("x" << 1), true, ¬ifyDone, NULL /* errMsg not needed */)); env->waitForNthGetCursor(1u); @@ -122,7 +127,8 @@ namespace { env->addCursorId(ns, 345); Notification notifyDone; - ASSERT_TRUE(deleter.queueDelete(ns, BSON("x" << 0), BSON("x" << 10), BSON("x" << 1), + ASSERT_TRUE(deleter.queueDelete(TransactionExperiment::factoryNULL, // XXX SERVER-13931 + ns, BSON("x" << 0), BSON("x" << 10), BSON("x" << 1), true, ¬ifyDone, NULL /* errMsg not needed */)); @@ -145,6 +151,7 @@ namespace { string errMsg; boost::thread deleterThread = boost::thread(boost::bind(&RangeDeleter::deleteNow, &deleter, + noTxn, ns, BSON("x" << 0), BSON("x" << 10), @@ -194,6 +201,7 @@ namespace { string errMsg; boost::thread deleterThread = boost::thread(boost::bind(&RangeDeleter::deleteNow, &deleter, + noTxn, ns, BSON("x" << 0), BSON("x" << 10), @@ -238,7 +246,8 @@ namespace { env->pauseDeletes(); Notification notifyDone1; - ASSERT_TRUE(deleter.queueDelete(ns, + ASSERT_TRUE(deleter.queueDelete(TransactionExperiment::factoryNULL, // XXX SERVER-13931 + ns, BSON("x" << 10), BSON("x" << 20), BSON("x" << 1), @@ -256,7 +265,8 @@ namespace { ASSERT_EQUALS(1, inProgressCount); Notification notifyDone2; - ASSERT_TRUE(deleter.queueDelete(blockedNS, + ASSERT_TRUE(deleter.queueDelete(TransactionExperiment::factoryNULL, // XXX SERVER-13931 + blockedNS, BSON("x" << 20), BSON("x" << 30), BSON("x" << 1), @@ -265,7 +275,8 @@ namespace { NULL /* don't care errMsg */)); Notification notifyDone3; - ASSERT_TRUE(deleter.queueDelete(ns, + ASSERT_TRUE(deleter.queueDelete(TransactionExperiment::factoryNULL, // XXX SERVER-13931 + ns, BSON("x" << 30), BSON("x" << 40), BSON("x" << 1), @@ -352,12 +363,13 @@ namespace { ASSERT_TRUE(errMsg.empty()); errMsg.clear(); - ASSERT_FALSE(deleter.queueDelete(ns, BSON("x" << 120), BSON("x" << 140), BSON("x" << 1), + ASSERT_FALSE(deleter.queueDelete(TransactionExperiment::factoryNULL, // XXX SERVER-13931 + ns, BSON("x" << 120), BSON("x" << 140), BSON("x" << 1), false, NULL /* notifier not needed */, &errMsg)); ASSERT_FALSE(errMsg.empty()); errMsg.clear(); - ASSERT_FALSE(deleter.deleteNow(ns, BSON("x" << 120), BSON("x" << 140), + ASSERT_FALSE(deleter.deleteNow(noTxn, ns, BSON("x" << 120), BSON("x" << 140), BSON("x" << 1), false, &errMsg)); ASSERT_FALSE(errMsg.empty()); @@ -400,7 +412,8 @@ namespace { env->addCursorId(ns, 58); Notification notifyDone; - deleter.queueDelete(ns, BSON("x" << 0), BSON("x" << 10), BSON("x" << 1), + deleter.queueDelete(TransactionExperiment::factoryNULL, // XXX SERVER-13931 + ns, BSON("x" << 0), BSON("x" << 10), BSON("x" << 1), false, ¬ifyDone, NULL /* errMsg not needed */); string errMsg; @@ -430,6 +443,7 @@ namespace { string delErrMsg; boost::thread deleterThread = boost::thread(boost::bind(&RangeDeleter::deleteNow, &deleter, + noTxn, ns, BSON("x" << 64), BSON("x" << 70), @@ -468,7 +482,7 @@ namespace { ASSERT_FALSE(deleter.removeFromBlackList(ns, BSON("x" << 1234), BSON("x" << 9000))); // Range should still be blacklisted - ASSERT_FALSE(deleter.deleteNow(ns, BSON("x" << 2000), BSON("x" << 4000), BSON("x" << 1), + ASSERT_FALSE(deleter.deleteNow(noTxn, ns, BSON("x" << 2000), BSON("x" << 4000), BSON("x" << 1), false, NULL /* errMsg not needed */)); deleter.stopWorkers(); @@ -485,14 +499,14 @@ namespace { ASSERT_TRUE(errMsg.empty()); errMsg.clear(); - ASSERT_FALSE(deleter.deleteNow(ns, BSON("x" << 600), BSON("x" << 700), + ASSERT_FALSE(deleter.deleteNow(noTxn, ns, BSON("x" << 600), BSON("x" << 700), BSON("x" << 1), false, &errMsg)); ASSERT_FALSE(errMsg.empty()); ASSERT_TRUE(deleter.removeFromBlackList(ns, BSON("x" << 500), BSON("x" << 801))); errMsg.clear(); - ASSERT_TRUE(deleter.deleteNow(ns, BSON("x" << 600), BSON("x" << 700), + ASSERT_TRUE(deleter.deleteNow(noTxn, ns, BSON("x" << 600), BSON("x" << 700), BSON("x" << 1), false, &errMsg)); ASSERT_TRUE(errMsg.empty()); @@ -507,7 +521,7 @@ namespace { deleter.addToBlackList("foo.bar", BSON("x" << 100), BSON("x" << 200), NULL /* errMsg not needed */); - ASSERT_TRUE(deleter.deleteNow("test.user", BSON("x" << 120), BSON("x" << 140), + ASSERT_TRUE(deleter.deleteNow(noTxn, "test.user", BSON("x" << 120), BSON("x" << 140), BSON("x" << 1), true, NULL /* errMsg not needed */)); deleter.stopWorkers(); diff --git a/src/mongo/db/repl/oplog.cpp b/src/mongo/db/repl/oplog.cpp index 0be9d7a9bd6..61cb23f914b 100644 --- a/src/mongo/db/repl/oplog.cpp +++ b/src/mongo/db/repl/oplog.cpp @@ -705,7 +705,7 @@ namespace mongo { while (!done) { BufBuilder bb; BSONObjBuilder ob; - _runCommands(ns, o, bb, ob, true, 0); + _runCommands(txn, ns, o, bb, ob, true, 0); // _runCommands takes care of adjusting opcounters for command counting. Status status = Command::getStatusFromCommandResult(ob.done()); switch (status.code()) { diff --git a/src/mongo/db/repl/replset_web_handler.cpp b/src/mongo/db/repl/replset_web_handler.cpp index 27ce6a61853..5cd7b14ae48 100644 --- a/src/mongo/db/repl/replset_web_handler.cpp +++ b/src/mongo/db/repl/replset_web_handler.cpp @@ -53,7 +53,8 @@ namespace { return startsWith( url , "/_replSet" ); } - virtual void handle( const char *rq, const std::string& url, BSONObj params, + virtual void handle( TransactionExperiment* txn, + const char *rq, const std::string& url, BSONObj params, string& responseMsg, int& responseCode, vector<string>& headers, const SockAddr &from ) { diff --git a/src/mongo/db/repl/resync.cpp b/src/mongo/db/repl/resync.cpp index 1adc44903e6..1c4322d81cd 100644 --- a/src/mongo/db/repl/resync.cpp +++ b/src/mongo/db/repl/resync.cpp @@ -57,7 +57,8 @@ namespace mongo { } CmdResync() : Command("resync") { } - virtual bool run(const string& dbname, + virtual bool newRun(TransactionExperiment* txn, + const string& dbname, BSONObj& cmdObj, int, string& errmsg, @@ -67,7 +68,6 @@ namespace mongo { const std::string ns = parseNs(dbname, cmdObj); Lock::GlobalWrite globalWriteLock; Client::Context ctx(ns); - DurTransaction txn; if (replSettings.usingReplSets()) { if (theReplSet->isPrimary()) { @@ -90,7 +90,7 @@ namespace mongo { if ( !waitForSyncToFinish( errmsg ) ) return false; - ReplSource::forceResyncDead( &txn, "client" ); + ReplSource::forceResyncDead( txn, "client" ); result.append( "info", "triggered resync for all sources" ); return true; } diff --git a/src/mongo/db/restapi.cpp b/src/mongo/db/restapi.cpp index bb06d522491..bb2243272ea 100644 --- a/src/mongo/db/restapi.cpp +++ b/src/mongo/db/restapi.cpp @@ -66,7 +66,8 @@ namespace mongo { url.find_last_of( '/' ) > 0; } - virtual void handle( const char *rq, const std::string& url, BSONObj params, + virtual void handle( TransactionExperiment* txn, + const char *rq, const std::string& url, BSONObj params, string& responseMsg, int& responseCode, vector<string>& headers, const SockAddr &from ) { diff --git a/src/mongo/db/storage/mmap_v1/dur_transaction.cpp b/src/mongo/db/storage/mmap_v1/dur_transaction.cpp index b4b904527c9..147dc9a71e2 100644 --- a/src/mongo/db/storage/mmap_v1/dur_transaction.cpp +++ b/src/mongo/db/storage/mmap_v1/dur_transaction.cpp @@ -74,4 +74,8 @@ namespace mongo { return Status( ErrorCodes::Interrupted, killed ); } + TransactionExperiment* DurTransaction::factory() { + return new DurTransaction(); + } + } // namespace mongo diff --git a/src/mongo/db/storage/mmap_v1/dur_transaction.h b/src/mongo/db/storage/mmap_v1/dur_transaction.h index c6fe30e98b4..b4a2bd009e3 100644 --- a/src/mongo/db/storage/mmap_v1/dur_transaction.h +++ b/src/mongo/db/storage/mmap_v1/dur_transaction.h @@ -62,6 +62,11 @@ namespace mongo { virtual Status checkForInterruptNoAssert() const; + /** + * Returns a DurTransaction. Caller takes ownership. + */ + static TransactionExperiment* factory(); + }; } // namespace mongo diff --git a/src/mongo/db/storage/transaction.h b/src/mongo/db/storage/transaction.h index a025b8f283f..2684342e542 100644 --- a/src/mongo/db/storage/transaction.h +++ b/src/mongo/db/storage/transaction.h @@ -125,6 +125,23 @@ namespace mongo { return x; } + /** + * Returns a TransactionExperiment. Caller takes ownership. + * + * This interface is used for functions that need to create transactions (aka OpCtx), but + * don't know which implementation they should create. It allows the calling code to make + * that decision for them. + * + * TODO come up with a better Factory API once we split this class up (SERVER-13931). + */ + typedef TransactionExperiment* (*Factory)(); + + /** + * A TransactionExperiment::Factory that always returns NULL. For things that shouldn't be + * touching their txns such as mongos or some unittests. + */ + static TransactionExperiment* factoryNULL() { return NULL; } + protected: TransactionExperiment() {} }; |