diff options
-rw-r--r-- | src/mongo/db/cloner.cpp | 96 | ||||
-rw-r--r-- | src/mongo/db/cloner.h | 4 | ||||
-rw-r--r-- | src/mongo/db/commands/clone.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/commands/copydb.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/repl/master_slave.cpp | 47 | ||||
-rw-r--r-- | src/mongo/db/repl/master_slave.h | 3 | ||||
-rw-r--r-- | src/mongo/db/repl/repl_set_impl.h | 2 | ||||
-rw-r--r-- | src/mongo/db/repl/rs_initialsync.cpp | 21 |
8 files changed, 102 insertions, 77 deletions
diff --git a/src/mongo/db/cloner.cpp b/src/mongo/db/cloner.cpp index 861eb00368f..2ec997888e2 100644 --- a/src/mongo/db/cloner.cpp +++ b/src/mongo/db/cloner.cpp @@ -28,7 +28,7 @@ * it in the license file. */ -#include "mongo/pch.h" +#include "mongo/platform/basic.h" #include "mongo/base/init.h" #include "mongo/base/status.h" @@ -42,7 +42,6 @@ #include "mongo/db/commands.h" #include "mongo/db/commands/copydb.h" #include "mongo/db/commands/rename_collection.h" -#include "mongo/db/db.h" #include "mongo/db/dbhelpers.h" #include "mongo/db/index_builder.h" #include "mongo/db/instance.h" @@ -51,9 +50,9 @@ #include "mongo/db/repl/oplog.h" #include "mongo/db/repl/oplogreader.h" #include "mongo/db/pdfile.h" -#include "mongo/db/operation_context_impl.h" #include "mongo/db/storage_options.h" + namespace mongo { BSONElement getErrField(const BSONObj& o); @@ -95,22 +94,26 @@ namespace mongo { Cloner::Cloner() { } struct Cloner::Fun { - Fun( OperationContext* txn, Client::Context& ctx ) + Fun(OperationContext* txn, const string& dbName) :lastLog(0), txn(txn), - context(ctx) + _dbName(dbName) {} void operator()( DBClientCursorBatchIterator &i ) { // XXX: can probably take dblock instead Lock::GlobalWrite lk(txn->lockState()); - context.relocked(); + + // Make sure database still exists after we resume from the temp release + bool unused; + Database* db = dbHolder().getOrCreate( + txn, _dbName, storageGlobalParams.dbpath, unused); bool createdCollection = false; Collection* collection = NULL; if ( isindex == false ) { - collection = context.db()->getCollection( txn, to_collection ); + collection = db->getCollection( txn, to_collection ); if ( !collection ) { massert( 17321, str::stream() @@ -118,7 +121,7 @@ namespace mongo { << to_collection << "]", !createdCollection ); createdCollection = true; - collection = context.db()->createCollection( txn, to_collection ); + collection = db->createCollection( txn, to_collection ); verify( collection ); } } @@ -149,7 +152,7 @@ namespace mongo { BSONObj js = tmp; if ( isindex ) { verify(nsToCollectionSubstring(from_collection) == "system.indexes"); - js = fixindex(context.db()->name(), tmp); + js = fixindex(db->name(), tmp); indexesToBuild->push_back( js.getOwned() ); continue; } @@ -176,7 +179,7 @@ namespace mongo { time_t lastLog; OperationContext* txn; - Client::Context& context; + const string _dbName; int64_t numSeen; bool isindex; @@ -193,7 +196,7 @@ namespace mongo { isindex - if true, this is system.indexes collection, in which we do some transformation when copying. */ void Cloner::copy(OperationContext* txn, - Client::Context& ctx, + const string& toDBName, const char *from_collection, const char *to_collection, bool isindex, @@ -207,7 +210,7 @@ namespace mongo { list<BSONObj> indexesToBuild; LOG(2) << "\t\tcloning collection " << from_collection << " to " << to_collection << " on " << _conn->getServerAddress() << " with filter " << query.toString() << endl; - Fun f( txn, ctx ); + Fun f(txn, toDBName); f.numSeen = 0; f.isindex = isindex; f.from_collection = from_collection; @@ -220,11 +223,16 @@ namespace mongo { int options = QueryOption_NoCursorTimeout | ( slaveOk ? QueryOption_SlaveOk : 0 ); { - dbtemprelease r(txn->lockState()); + Lock::TempRelease tempRelease(txn->lockState()); _conn->query(stdx::function<void(DBClientCursorBatchIterator &)>(f), from_collection, query, 0, options); } + // We are under lock here again, so reload the database in case it may have disappeared + // during the temp release + bool unused; + Database* db = dbHolder().getOrCreate(txn, toDBName, storageGlobalParams.dbpath, unused); + if ( indexesToBuild.size() ) { for (list<BSONObj>::const_iterator i = indexesToBuild.begin(); i != indexesToBuild.end(); @@ -232,9 +240,9 @@ namespace mongo { BSONObj spec = *i; string ns = spec["ns"].String(); // this was fixed when pulled off network - Collection* collection = f.context.db()->getCollection( txn, ns ); + Collection* collection = db->getCollection( txn, ns ); if ( !collection ) { - collection = f.context.db()->createCollection( txn, ns ); + collection = db->createCollection( txn, ns ); verify( collection ); } @@ -291,13 +299,19 @@ namespace mongo { bool copyIndexes, bool logForRepl) { - Client::WriteContext ctx(txn, ns); + const NamespaceString nss(ns); + Lock::DBWrite dbWrite(txn->lockState(), nss.db()); + + const string dbName = nss.db().toString(); + + bool unused; + Database* db = dbHolder().getOrCreate(txn, dbName, storageGlobalParams.dbpath, unused); // config - string temp = ctx.ctx().db()->name() + ".system.namespaces"; + string temp = dbName + ".system.namespaces"; BSONObj config = _conn->findOne(temp , BSON("name" << ns)); if (config["options"].isABSONObj()) { - Status status = userCreateNS(txn, ctx.ctx().db(), ns, config["options"].Obj(), logForRepl, 0); + Status status = userCreateNS(txn, db, ns, config["options"].Obj(), logForRepl, 0); if ( !status.isOK() ) { errmsg = status.toString(); return false; @@ -305,7 +319,7 @@ namespace mongo { } // main data - copy(txn, ctx.ctx(), + copy(txn, dbName, ns.c_str(), ns.c_str(), false, logForRepl, false, true, mayYield, mayBeInterrupted, Query(query).snapshot()); @@ -315,8 +329,8 @@ namespace mongo { } // indexes - temp = ctx.ctx().db()->name() + ".system.indexes"; - copy(txn, ctx.ctx(), temp.c_str(), temp.c_str(), true, logForRepl, false, true, mayYield, + temp = dbName + ".system.indexes"; + copy(txn, dbName, temp.c_str(), temp.c_str(), true, logForRepl, false, true, mayYield, mayBeInterrupted, BSON( "ns" << ns )); txn->recoveryUnit()->commitIfNeeded(); @@ -326,18 +340,18 @@ namespace mongo { extern bool inDBRepair; bool Cloner::go(OperationContext* txn, - Client::Context& context, + const std::string& toDBName, const string& masterHost, const CloneOptions& opts, set<string>* clonedColls, string& errmsg, int* errCode) { + if ( errCode ) { *errCode = 0; } massert( 10289 , "useReplAuth is not written to replication log", !opts.useReplAuth || !opts.logForRepl ); - string todb = context.db()->name(); #if !defined(_WIN32) && !defined(__sunos__) // isSelf() only does the necessary comparisons on os x and linux (SERVER-14165) bool masterSameProcess = HostAndPort(masterHost).isSelf(); @@ -347,8 +361,9 @@ namespace mongo { b << "127.0.0.1:" << serverGlobalParams.port; bool masterSameProcess = (a.str() == masterHost || b.str() == masterHost); #endif + if (masterSameProcess) { - if (opts.fromDB == todb && context.db()->path() == storageGlobalParams.dbpath) { + if (opts.fromDB == toDBName) { // guard against an "infinite" loop /* if you are replicating, the local.sources config may be wrong if you get this */ errmsg = "can't clone from self (localhost)."; @@ -384,7 +399,7 @@ namespace mongo { /* todo: we can put these releases inside dbclient or a dbclient specialization. or just wait until we get rid of global lock anyway. */ - dbtemprelease r(txn->lockState()); + Lock::TempRelease tempRelease(txn->lockState()); // just using exhaust for collection copying right now @@ -461,10 +476,17 @@ namespace mongo { /* change name "<fromdb>.collection" -> <todb>.collection */ const char *p = strchr(from_name, '.'); verify(p); - string to_name = todb + p; + const string to_name = toDBName + p; + + // Copy releases the lock, so we need to re-load the database. This should probably + // throw if the database has changed in between, but for now preserve the existing + // behaviour. + bool unused; + Database* db = + dbHolder().getOrCreate(txn, toDBName, storageGlobalParams.dbpath, unused); /* we defer building id index for performance - building it in batch is much faster */ - Status createStatus = userCreateNS( txn, context.db(), to_name, options, + Status createStatus = userCreateNS( txn, db, to_name, options, opts.logForRepl, false ); if ( !createStatus.isOK() ) { errmsg = str::stream() << "failed to create collection \"" << to_name << "\": " @@ -476,8 +498,18 @@ namespace mongo { Query q; if( opts.snapshot ) q.snapshot(); - copy(txn, context,from_name, to_name.c_str(), false, opts.logForRepl, masterSameProcess, - opts.slaveOk, opts.mayYield, opts.mayBeInterrupted, q); + + copy(txn, + toDBName, + from_name, + to_name.c_str(), + false, + opts.logForRepl, + masterSameProcess, + opts.slaveOk, + opts.mayYield, + opts.mayBeInterrupted, + q); { /* we need dropDups to be true as we didn't do a true snapshot and this is before applying oplog operations @@ -486,7 +518,7 @@ namespace mongo { bool old = inDBRepair; try { inDBRepair = true; - Collection* c = context.db()->getCollection( txn, to_name ); + Collection* c = db->getCollection( txn, to_name ); if ( c ) c->getIndexCatalog()->ensureHaveIdIndex(txn); inDBRepair = old; @@ -502,7 +534,7 @@ namespace mongo { if ( opts.syncIndexes ) { string system_indexes_from = opts.fromDB + ".system.indexes"; - string system_indexes_to = todb + ".system.indexes"; + string system_indexes_to = toDBName + ".system.indexes"; /* [dm]: is the ID index sometimes not called "_id_"? There is other code in the system that looks for a "_id" prefix rather than this exact value. we should standardize. OR, remove names - which is in the bugdb. Anyway, this @@ -518,7 +550,7 @@ namespace mongo { BSONObj query = BSON( "name" << NE << "_id_" << "ns" << NIN << arr ); // won't need a snapshot of the query of system.indexes as there can never be very many. - copy(txn, context,system_indexes_from.c_str(), system_indexes_to.c_str(), true, + copy(txn, toDBName, system_indexes_from.c_str(), system_indexes_to.c_str(), true, opts.logForRepl, masterSameProcess, opts.slaveOk, opts.mayYield, opts.mayBeInterrupted, query ); } return true; diff --git a/src/mongo/db/cloner.h b/src/mongo/db/cloner.h index f30429ca99f..bf66b51e688 100644 --- a/src/mongo/db/cloner.h +++ b/src/mongo/db/cloner.h @@ -52,7 +52,7 @@ namespace mongo { /** copy the entire database */ bool go(OperationContext* txn, - Client::Context& ctx, + const std::string& toDBName, const std::string& masterHost, const CloneOptions& opts, std::set<std::string>* clonedColls, @@ -70,7 +70,7 @@ namespace mongo { private: void copy(OperationContext* txn, - Client::Context& ctx, + const std::string& toDBName, const char *from_ns, const char *to_ns, bool isindex, diff --git a/src/mongo/db/commands/clone.cpp b/src/mongo/db/commands/clone.cpp index 0154e863a31..bd0523dfa7d 100644 --- a/src/mongo/db/commands/clone.cpp +++ b/src/mongo/db/commands/clone.cpp @@ -118,10 +118,9 @@ namespace mongo { set<string> clonedColls; Lock::DBWrite dbXLock(txn->lockState(), dbname); - Client::Context context( dbname ); Cloner cloner; - bool rval = cloner.go(txn, context, from, opts, &clonedColls, errmsg); + bool rval = cloner.go(txn, dbname, from, opts, &clonedColls, errmsg); BSONArrayBuilder barr; barr.append( clonedColls ); diff --git a/src/mongo/db/commands/copydb.cpp b/src/mongo/db/commands/copydb.cpp index cbea25eb47f..9dd674765cc 100644 --- a/src/mongo/db/commands/copydb.cpp +++ b/src/mongo/db/commands/copydb.cpp @@ -190,8 +190,7 @@ namespace mongo { static_cast<Lock::ScopedLock*>(new Lock::GlobalWrite(txn->lockState())) : static_cast<Lock::ScopedLock*>(new Lock::DBWrite(txn->lockState(), todb))); - Client::Context ctx(todb); - return cloner.go(txn, ctx, fromhost, cloneOptions, NULL, errmsg ); + return cloner.go(txn, todb, fromhost, cloneOptions, NULL, errmsg ); } } cmdCopyDB; diff --git a/src/mongo/db/repl/master_slave.cpp b/src/mongo/db/repl/master_slave.cpp index 69a154d30fb..1288729cd40 100644 --- a/src/mongo/db/repl/master_slave.cpp +++ b/src/mongo/db/repl/master_slave.cpp @@ -332,7 +332,9 @@ namespace repl { BSONObj info; { // This is always a GlobalWrite lock (so no ns/db used from the context) - dbtemprelease t(txn->lockState()); + invariant(txn->lockState()->isW()); + Lock::TempRelease tempRelease(txn->lockState()); + if (!oplogReader.connect(hostName, _me)) { msgassertedNoTrace( 14051 , "unable to connect to resync"); } @@ -365,34 +367,11 @@ namespace repl { dropDatabase(txn, ctx.db()); } - /** - * @param errmsg out - Error message (if encountered). - * @param errCode out - If provided, this will be set on error to the server's error code. - * Currently this will only be set if there is an error in the initial - * system.namespaces query. - */ - static bool cloneFrom(OperationContext* txn, - Client::Context& context, - const string& masterHost, - const CloneOptions& options, - string& errmsg, - int* errCode) { - - Cloner cloner; - return cloner.go(txn, - context, - masterHost.c_str(), - options, - NULL, - errmsg, - errCode); - } - /* grab initial copy of a database from the master */ void ReplSource::resync(OperationContext* txn, const std::string& dbName) { const std::string db(dbName); // need local copy of the name, we're dropping the original resyncDrop( txn, db ); - Client::Context ctx( db ); + { log() << "resync: cloning database " << db << " to get an initial copy" << endl; ReplInfo r("resync: cloning a database"); @@ -406,7 +385,15 @@ namespace repl { cloneOptions.snapshot = true; cloneOptions.mayYield = true; cloneOptions.mayBeInterrupted = false; - bool ok = cloneFrom(txn, ctx,hostName, cloneOptions, errmsg, &errCode); + + Cloner cloner; + bool ok = cloner.go(txn, + db, + hostName.c_str(), + cloneOptions, + NULL, + errmsg, + &errCode); if ( !ok ) { if ( errCode == DatabaseDifferCaseCode ) { @@ -471,7 +458,8 @@ namespace repl { bool dbOk = false; { // This is always a GlobalWrite lock (so no ns/db used from the context) - dbtemprelease release(txn->lockState()); + invariant(txn->lockState()->isW()); + Lock::TempRelease(txn->lockState()); // We always log an operation after executing it (never before), so // a database list will always be valid as of an oplog entry generated @@ -638,7 +626,10 @@ namespace repl { return; } - Client::Context ctx( ns ); + // This code executes on the slaves only, so it doesn't need to be sharding-aware since + // mongos will not send requests there. That's why the last argument is false (do not do + // version checking). + Client::Context ctx(ns, storageGlobalParams.dbpath, false); ctx.getClient()->curop()->reset(); bool empty = ctx.db()->isEmpty(); diff --git a/src/mongo/db/repl/master_slave.h b/src/mongo/db/repl/master_slave.h index f30f9f2bdd5..65e9384732c 100644 --- a/src/mongo/db/repl/master_slave.h +++ b/src/mongo/db/repl/master_slave.h @@ -123,6 +123,8 @@ namespace repl { // populates _me so that it can be passed to oplogreader for handshakes void ensureMe(); + void forceResync(OperationContext* txn, const char *requester); + public: OplogReader oplogReader; @@ -165,7 +167,6 @@ namespace repl { static bool throttledForceResyncDead( OperationContext* txn, const char *requester ); static void forceResyncDead( OperationContext* txn, const char *requester ); - void forceResync( OperationContext* txn, const char *requester ); }; /** diff --git a/src/mongo/db/repl/repl_set_impl.h b/src/mongo/db/repl/repl_set_impl.h index 5a33df4b01f..181e41194d8 100644 --- a/src/mongo/db/repl/repl_set_impl.h +++ b/src/mongo/db/repl/repl_set_impl.h @@ -281,7 +281,7 @@ namespace repl { friend class Consensus; private: - bool _syncDoInitialSync_clone(Cloner &cloner, const char *master, + bool _syncDoInitialSync_clone(OperationContext* txn, Cloner &cloner, const char *master, const list<string>& dbs, bool dataPass); bool _syncDoInitialSync_applyToHead( SyncTail& syncer, OplogReader* r , const Member* source, const BSONObj& lastOp, diff --git a/src/mongo/db/repl/rs_initialsync.cpp b/src/mongo/db/repl/rs_initialsync.cpp index 5faea85e949..adef1647dfe 100644 --- a/src/mongo/db/repl/rs_initialsync.cpp +++ b/src/mongo/db/repl/rs_initialsync.cpp @@ -86,11 +86,14 @@ namespace repl { fassert( 16233, failedAttempts < maxFailedAttempts); } - bool ReplSetImpl::_syncDoInitialSync_clone(Cloner& cloner, const char *master, - const list<string>& dbs, bool dataPass) { + bool ReplSetImpl::_syncDoInitialSync_clone(OperationContext* txn, + Cloner& cloner, + const char *master, + const list<string>& dbs, + bool dataPass) { for( list<string>::const_iterator i = dbs.begin(); i != dbs.end(); i++ ) { - string db = *i; + const string db = *i; if( db == "local" ) continue; @@ -99,9 +102,6 @@ namespace repl { else sethbmsg( str::stream() << "initial sync cloning indexes for : " << db , 0); - OperationContextImpl txn; - Client::WriteContext ctx(&txn, db); - string err; int errCode; CloneOptions options; @@ -115,7 +115,10 @@ namespace repl { options.syncData = dataPass; options.syncIndexes = ! dataPass; - if (!cloner.go(&txn, ctx.ctx(), master, options, NULL, err, &errCode)) { + // Make database stable + Lock::DBWrite dbWrite(txn->lockState(), db); + + if (!cloner.go(txn, db, master, options, NULL, err, &errCode)) { sethbmsg(str::stream() << "initial sync: error while " << (dataPass ? "cloning " : "indexing ") << db << ". " << (err.empty() ? "" : err + ". ") @@ -417,7 +420,7 @@ namespace repl { list<string> dbs = r.conn()->getDatabaseNames(); Cloner cloner; - if (!_syncDoInitialSync_clone(cloner, sourceHostname.c_str(), dbs, true)) { + if (!_syncDoInitialSync_clone(&txn, cloner, sourceHostname.c_str(), dbs, true)) { veto(source->fullName(), 600); sleepsecs(300); return; @@ -444,7 +447,7 @@ namespace repl { lastOp = minValid; sethbmsg("initial sync building indexes",0); - if (!_syncDoInitialSync_clone(cloner, sourceHostname.c_str(), dbs, false)) { + if (!_syncDoInitialSync_clone(&txn, cloner, sourceHostname.c_str(), dbs, false)) { veto(source->fullName(), 600); sleepsecs(300); return; |