summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaloian Manassiev <kaloian.manassiev@mongodb.com>2014-06-04 22:32:33 -0400
committerKaloian Manassiev <kaloian.manassiev@mongodb.com>2014-06-09 12:09:09 -0400
commit7650ab7a985e23098270c8893320c5b151d16d7e (patch)
tree3ca76f2e0a6db84439ce78080d94c80f8cb3e5ff
parent36d1beca1267a47cf4e9d79742caec8e5ad608fa (diff)
downloadmongo-7650ab7a985e23098270c8893320c5b151d16d7e.tar.gz
SERVER-13922 Remove Context and dbtemprelease from the cloner
Substituting with plain TempRelease, combined with re-acquiring the database after lock is re-acquired. Since copydb/clonedb are not shard-aware operations, we skip the shard version check. The usages, which originate from replication are all from the secondaries, so there is no need for version check there either.
-rw-r--r--src/mongo/db/cloner.cpp96
-rw-r--r--src/mongo/db/cloner.h4
-rw-r--r--src/mongo/db/commands/clone.cpp3
-rw-r--r--src/mongo/db/commands/copydb.cpp3
-rw-r--r--src/mongo/db/repl/master_slave.cpp47
-rw-r--r--src/mongo/db/repl/master_slave.h3
-rw-r--r--src/mongo/db/repl/repl_set_impl.h2
-rw-r--r--src/mongo/db/repl/rs_initialsync.cpp21
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;