Example #1
0
 virtual bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
     BSONObj fromToken = cmdObj.getObjectField("finishCloneCollection");
     if ( fromToken.isEmpty() ) {
         errmsg = "missing finishCloneCollection finishToken spec";
         return false;
     }
     string fromhost = fromToken.getStringField( "fromhost" );
     if ( fromhost.empty() ) {
         errmsg = "missing fromhost spec";
         return false;
     }
     string collection = fromToken.getStringField("collection");
     if ( collection.empty() ) {
         errmsg = "missing collection spec";
         return false;
     }
     BSONObj query = fromToken.getObjectField("query");
     if ( query.isEmpty() ) {
         query = BSONObj();
     }
     long long cursorId = 0;
     BSONElement cursorIdToken = fromToken.getField( "cursorId" );
     if ( cursorIdToken.type() == Date ) {
         cursorId = cursorIdToken._numberLong();
     }
     
     setClient( collection.c_str() );
     
     log() << "finishCloneCollection.  db:" << ns << " collection:" << collection << " from: " << fromhost << " query: " << query << endl;
     
     Cloner c;
     return c.finishCloneCollection( fromhost.c_str(), collection.c_str(), query, cursorId, errmsg );
 }
Example #2
0
 virtual bool run(const string& dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
     string fromhost = cmdObj.getStringField("fromhost");
     if ( fromhost.empty() ) {
         /* copy from self */
         stringstream ss;
         ss << "localhost:" << cmdLine.port;
         fromhost = ss.str();
     }
     string fromdb = cmdObj.getStringField("fromdb");
     string todb = cmdObj.getStringField("todb");
     if ( fromhost.empty() || todb.empty() || fromdb.empty() ) {
         errmsg = "parms missing - {copydb: 1, fromhost: <hostname>, fromdb: <db>, todb: <db>}";
         return false;
     }
     Cloner c;
     string username = cmdObj.getStringField( "username" );
     string nonce = cmdObj.getStringField( "nonce" );
     string key = cmdObj.getStringField( "key" );
     if ( !username.empty() && !nonce.empty() && !key.empty() ) {
         uassert( 13008, "must call copydbgetnonce first", authConn_.get() );
         BSONObj ret;
         {
             dbtemprelease t;
             if ( !authConn_->runCommand( fromdb, BSON( "authenticate" << 1 << "user" << username << "nonce" << nonce << "key" << key ), ret ) ) {
                 errmsg = "unable to login " + string( ret );
                 return false;
             }
         }
         c.setConnection( authConn_.release() );
     }
     Client::Context ctx(todb);
     bool res = c.go(fromhost.c_str(), errmsg, fromdb, /*logForReplication=*/!fromRepl, /*slaveok*/false, /*replauth*/false, /*snapshot*/true);
     return res;
 }
Example #3
0
 virtual bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
     string fromhost = cmdObj.getStringField("from");
     if ( fromhost.empty() ) {
         errmsg = "missing from spec";
         return false;
     }
     string collection = cmdObj.getStringField("cloneCollection");
     if ( collection.empty() ) {
         errmsg = "missing cloneCollection spec";
         return false;
     }
     BSONObj query = cmdObj.getObjectField("query");
     if ( query.isEmpty() )
         query = BSONObj();
     BSONElement copyIndexesSpec = cmdObj.getField("copyindexes");
     bool copyIndexes = copyIndexesSpec.isBoolean() ? copyIndexesSpec.boolean() : true;
     // Will not be used if doesn't exist.
     int logSizeMb = cmdObj.getIntField( "logSizeMb" );
     
     /* replication note: we must logOp() not the command, but the cloned data -- if the slave
      were to clone it would get a different point-in-time and not match.
      */
     setClient( collection.c_str() );
     
     log() << "cloneCollection.  db:" << ns << " collection:" << collection << " from: " << fromhost << " query: " << query << " logSizeMb: " << logSizeMb << ( copyIndexes ? "" : ", not copying indexes" ) << endl;
     
     Cloner c;
     long long cursorId;
     if ( !c.startCloneCollection( fromhost.c_str(), collection.c_str(), query, errmsg, !fromRepl, copyIndexes, logSizeMb, cursorId ) )
         return false;
     return c.finishCloneCollection( fromhost.c_str(), collection.c_str(), query, cursorId, errmsg);
 }
    virtual bool run(OperationContext* txn,
                     const string& dbname,
                     BSONObj& cmdObj,
                     int,
                     string& errmsg,
                     BSONObjBuilder& result) {
        boost::optional<DisableDocumentValidation> maybeDisableValidation;
        if (shouldBypassDocumentValidationForCommand(cmdObj))
            maybeDisableValidation.emplace(txn);

        string fromhost = cmdObj.getStringField("from");
        if (fromhost.empty()) {
            errmsg = "missing 'from' parameter";
            return false;
        }

        {
            HostAndPort h(fromhost);
            if (repl::isSelf(h)) {
                errmsg = "can't cloneCollection from self";
                return false;
            }
        }

        string collection = parseNs(dbname, cmdObj);
        Status allowedWriteStatus = userAllowedWriteNS(dbname, collection);
        if (!allowedWriteStatus.isOK()) {
            return appendCommandStatus(result, allowedWriteStatus);
        }

        BSONObj query = cmdObj.getObjectField("query");
        if (query.isEmpty())
            query = BSONObj();

        BSONElement copyIndexesSpec = cmdObj.getField("copyindexes");
        bool copyIndexes = copyIndexesSpec.isBoolean() ? copyIndexesSpec.boolean() : true;

        log() << "cloneCollection.  db:" << dbname << " collection:" << collection
              << " from: " << fromhost << " query: " << query << " "
              << (copyIndexes ? "" : ", not copying indexes") << endl;

        Cloner cloner;
        unique_ptr<DBClientConnection> myconn;
        myconn.reset(new DBClientConnection());
        if (!myconn->connect(HostAndPort(fromhost), errmsg))
            return false;

        cloner.setConnection(myconn.release());

        return cloner.copyCollection(
            txn, collection, query, errmsg, true, true /* interruptable */, copyIndexes);
    }
Example #5
0
void testCloner() {
	testing("Cloner");
	GameManager* gm = new GameManager();
	Item* i = new Item("Testing Item");
	gm->insertObject(i);
	i->setName("Test name")->setDescription("Some going to be cloned item");
	
	Cloner cl = Cloner(i);
	ObjectPointer other = cl.getShallowClone();
	Item* j = other.safeCast<Item>();
	assertEqual<string>(i->getName(), j->getName(), "Name is different");
	assertEqual<string>(i->getDescription(), j->getDescription(), "Description is different");
}
Example #6
0
void RollbackSourceImpl::copyCollectionFromRemote(OperationContext* opCtx,
                                                  const NamespaceString& nss) const {
    std::string errmsg;
    std::unique_ptr<DBClientConnection> tmpConn(new DBClientConnection());
    uassert(15908,
            errmsg,
            tmpConn->connect(_source, StringData(), errmsg) && replAuthenticate(tmpConn.get()));

    // cloner owns _conn in unique_ptr
    Cloner cloner;
    cloner.setConnection(tmpConn.release());
    uassert(15909,
            str::stream() << "replSet rollback error resyncing collection " << nss.ns() << ' '
                          << errmsg,
            cloner.copyCollection(opCtx, nss.ns(), BSONObj(), errmsg, true));
}
Example #7
0
        virtual bool run(OperationContext* 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";
                return false;
            }

            {
                HostAndPort h(fromhost);
                if (repl::isSelf(h)) {
                    errmsg = "can't cloneCollection from self";
                    return false;
                }
            }

            string collection = parseNs(dbname, cmdObj);
            if ( collection.empty() ) {
                errmsg = "bad 'cloneCollection' value";
                return false;
            }
            BSONObj query = cmdObj.getObjectField("query");
            if ( query.isEmpty() )
                query = BSONObj();

            BSONElement copyIndexesSpec = cmdObj.getField("copyindexes");
            bool copyIndexes = copyIndexesSpec.isBoolean() ? copyIndexesSpec.boolean() : true;

            log() << "cloneCollection.  db:" << dbname << " collection:" << collection << " from: " << fromhost
                  << " query: " << query << " " << ( copyIndexes ? "" : ", not copying indexes" ) << endl;

            Cloner cloner;
            auto_ptr<DBClientConnection> myconn;
            myconn.reset( new DBClientConnection() );
            if ( ! myconn->connect( fromhost , errmsg ) )
                return false;

            cloner.setConnection( myconn.release() );

            return cloner.copyCollection(txn, collection, query, errmsg, true, false, copyIndexes);
        }
Example #8
0
        virtual bool run(OperationContext* txn,
                         const string& dbname,
                         BSONObj& cmdObj,
                         int,
                         string& errmsg,
                         BSONObjBuilder& result) {

            boost::optional<DisableDocumentValidation> maybeDisableValidation;
            if (shouldBypassDocumentValidationforCommand(cmdObj))
                maybeDisableValidation.emplace(txn);

            string from = cmdObj.getStringField("clone");
            if ( from.empty() )
                return false;

            CloneOptions opts;
            opts.fromDB = dbname;
            opts.slaveOk = cmdObj["slaveOk"].trueValue();

            // See if there's any collections we should ignore
            if( cmdObj["collsToIgnore"].type() == Array ){
                BSONObjIterator it( cmdObj["collsToIgnore"].Obj() );

                while( it.more() ){
                    BSONElement e = it.next();
                    if( e.type() == String ){
                        opts.collsToIgnore.insert( e.String() );
                    }
                }
            }

            set<string> clonedColls;

            ScopedTransaction transaction(txn, MODE_IX);
            Lock::DBLock dbXLock(txn->lockState(), dbname, MODE_X);

            Cloner cloner;
            bool rval = cloner.go(txn, dbname, from, opts, &clonedColls, errmsg);

            BSONArrayBuilder barr;
            barr.append( clonedColls );

            result.append( "clonedColls", barr.arr() );

            return rval;

        }
void RollbackSourceImpl::copyCollectionFromRemote(OperationContext* opCtx,
                                                  const NamespaceString& nss) const {
    std::string errmsg;
    auto tmpConn = stdx::make_unique<DBClientConnection>();
    uassert(15908,
            errmsg,
            tmpConn->connect(_source, StringData(), errmsg) && replAuthenticate(tmpConn.get()));

    // cloner owns _conn in unique_ptr
    Cloner cloner;
    cloner.setConnection(std::move(tmpConn));
    uassert(15909,
            str::stream() << "replSet rollback error resyncing collection " << nss.ns() << ' '
                          << errmsg,
            cloner.copyCollection(
                opCtx, nss.ns(), BSONObj(), errmsg, true, CollectionOptions::parseForStorage));
}
Example #10
0
 virtual bool run(const string& dbname , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
     string fromhost = cmdObj.getStringField("from");
     if ( fromhost.empty() ) {
         errmsg = "missing from spec";
         return false;
     }
     string collection = cmdObj.getStringField("startCloneCollection");
     if ( collection.empty() ) {
         errmsg = "missing startCloneCollection spec";
         return false;
     }
     BSONObj query = cmdObj.getObjectField("query");
     if ( query.isEmpty() )
         query = BSONObj();
     BSONElement copyIndexesSpec = cmdObj.getField("copyindexes");
     bool copyIndexes = copyIndexesSpec.isBoolean() ? copyIndexesSpec.boolean() : true;
     // Will not be used if doesn't exist.
     int logSizeMb = cmdObj.getIntField( "logSizeMb" );
     
     /* replication note: we must logOp() not the command, but the cloned data -- if the slave
      were to clone it would get a different point-in-time and not match.
      */
     Client::Context ctx(collection);
     
     log() << "startCloneCollection.  db:" << dbname << " collection:" << collection << " from: " << fromhost << " query: " << query << endl;
     
     Cloner c;
     long long cursorId;
     bool res = c.startCloneCollection( fromhost.c_str(), collection.c_str(), query, errmsg, !fromRepl, copyIndexes, logSizeMb, cursorId );
     
     if ( res ) {
         BSONObjBuilder b;
         b << "fromhost" << fromhost;
         b << "collection" << collection;
         b << "query" << query;
         b.appendDate( "cursorId", cursorId );
         BSONObj token = b.done();
         result << "finishToken" << token;
     }
     return res;
 }
Example #11
0
/* 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);

    {
        log() << "resync: cloning database " << db << " to get an initial copy" << endl;
        ReplInfo r("resync: cloning a database");
        string errmsg;
        int errCode = 0;
        CloneOptions cloneOptions;
        cloneOptions.fromDB = db;
        cloneOptions.logForRepl = false;
        cloneOptions.slaveOk = true;
        cloneOptions.useReplAuth = true;
        cloneOptions.snapshot = true;
        cloneOptions.mayYield = true;
        cloneOptions.mayBeInterrupted = false;

        Cloner cloner;
        bool ok = cloner.go(txn, db, hostName.c_str(), cloneOptions, NULL, errmsg, &errCode);

        if (!ok) {
            if (errCode == DatabaseDifferCaseCode) {
                resyncDrop(txn, db);
                log() << "resync: database " << db
                      << " not valid on the master due to a name conflict, dropping." << endl;
                return;
            } else {
                log() << "resync of " << db << " from " << hostName << " failed " << errmsg << endl;
                throw SyncException();
            }
        }
    }

    log() << "resync: done with initial clone for db: " << db << endl;

    return;
}
Example #12
0
    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++ ) {
            const string db = *i;
            if( db == "local" ) 
                continue;
            
            if ( dataPass )
                sethbmsg( str::stream() << "initial sync cloning db: " << db , 0);
            else
                sethbmsg( str::stream() << "initial sync cloning indexes for : " << db , 0);

            string err;
            int errCode;
            CloneOptions options;
            options.fromDB = db;
            options.logForRepl = false;
            options.slaveOk = true;
            options.useReplAuth = true;
            options.snapshot = false;
            options.mayYield = true;
            options.mayBeInterrupted = false;
            options.syncData = dataPass;
            options.syncIndexes = ! dataPass;

            // Make database stable
            Lock::DBWrite dbWrite(txn->lockState(), db);
            WriteUnitOfWork wunit(txn->recoveryUnit());

            if (!cloner.go(txn, db, master, options, NULL, err, &errCode)) {
                sethbmsg(str::stream() << "initial sync: error while "
                                       << (dataPass ? "cloning " : "indexing ") << db
                                       << ".  " << (err.empty() ? "" : err + ".  ")
                                       << "sleeping 5 minutes" ,0);
                return false;
            }
            wunit.commit();
        }

        return true;
    }
Example #13
0
    bool ReplSetImpl::_syncDoInitialSync_clone(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;
            if( db == "local" ) 
                continue;
            
            if ( dataPass )
                sethbmsg( str::stream() << "initial sync cloning db: " << db , 0);
            else
                sethbmsg( str::stream() << "initial sync cloning indexes for : " << db , 0);

            Client::WriteContext ctx(db);
            OperationContextImpl txn;

            string err;
            int errCode;
            CloneOptions options;
            options.fromDB = db;
            options.logForRepl = false;
            options.slaveOk = true;
            options.useReplAuth = true;
            options.snapshot = false;
            options.mayYield = true;
            options.mayBeInterrupted = false;
            options.syncData = dataPass;
            options.syncIndexes = ! dataPass;

            if (!cloner.go(&txn, ctx.ctx(), master, options, NULL, err, &errCode)) {
                sethbmsg(str::stream() << "initial sync: error while "
                                       << (dataPass ? "cloning " : "indexing ") << db
                                       << ".  " << (err.empty() ? "" : err + ".  ")
                                       << "sleeping 5 minutes" ,0);
                return false;
            }
        }

        return true;
    }
Example #14
0
        virtual bool run(OperationContext* txn,
                         const string& dbname,
                         BSONObj& cmdObj,
                         int,
                         string& errmsg,
                         BSONObjBuilder& result,
                         bool fromRepl) {

            string fromhost = cmdObj.getStringField("fromhost");
            bool fromSelf = fromhost.empty();
            if ( fromSelf ) {
                /* copy from self */
                stringstream ss;
                ss << "localhost:" << serverGlobalParams.port;
                fromhost = ss.str();
            }

            CloneOptions cloneOptions;
            cloneOptions.fromDB = cmdObj.getStringField("fromdb");
            cloneOptions.logForRepl = !fromRepl;
            cloneOptions.slaveOk = cmdObj["slaveOk"].trueValue();
            cloneOptions.useReplAuth = false;
            cloneOptions.snapshot = true;
            cloneOptions.mayYield = true;
            cloneOptions.mayBeInterrupted = false;

            string todb = cmdObj.getStringField("todb");
            if ( fromhost.empty() || todb.empty() || cloneOptions.fromDB.empty() ) {
                errmsg = "params missing - {copydb: 1, fromhost: <connection string>, "
                         "fromdb: <db>, todb: <db>}";
                return false;
            }

            if ( !NamespaceString::validDBName( todb ) ) {
                errmsg = "invalid todb name: " + todb;
                return false;
            }

            Cloner cloner;

            // Get MONGODB-CR parameters
            string username = cmdObj.getStringField( "username" );
            string nonce = cmdObj.getStringField( "nonce" );
            string key = cmdObj.getStringField( "key" );

            if ( !username.empty() && !nonce.empty() && !key.empty() ) {
                uassert( 13008, "must call copydbgetnonce first", authConn_.get() );
                BSONObj ret;
                {
                    if ( !authConn_->runCommand( cloneOptions.fromDB,
                                                 BSON( "authenticate" << 1 << "user" << username
                                                       << "nonce" << nonce << "key" << key ), ret ) ) {
                        errmsg = "unable to login " + ret.toString();
                        return false;
                    }
                }
                cloner.setConnection( authConn_.release() );
            }
            else if (cmdObj.hasField(saslCommandConversationIdFieldName) &&
                     cmdObj.hasField(saslCommandPayloadFieldName)) {
                uassert( 25487, "must call copydbsaslstart first", authConn_.get() );
                BSONObj ret;
                if ( !authConn_->runCommand( cloneOptions.fromDB,
                                             BSON( "saslContinue" << 1 <<
                                                   cmdObj[saslCommandConversationIdFieldName] <<
                                                   cmdObj[saslCommandPayloadFieldName] ),
                                             ret ) ) {
                    errmsg = "unable to login " + ret.toString();
                    return false;
                }

                if (!ret["done"].Bool()) {
                    result.appendElements( ret );
                    return true;
                }

                result.append("done", true);
                cloner.setConnection( authConn_.release() );
            }
            else if (!fromSelf) {
                // If fromSelf leave the cloner's conn empty, it will use a DBDirectClient instead.

                ConnectionString cs = ConnectionString::parse(fromhost, errmsg);
                if (!cs.isValid()) {
                    return false;
                }

                DBClientBase* conn = cs.connect(errmsg);
                if (!conn) {
                    return false;
                }
                cloner.setConnection(conn);
            }

            if (fromSelf) {
                // SERVER-4328 todo lock just the two db's not everything for the fromself case
                Lock::GlobalWrite lk(txn->lockState());
                return cloner.go(txn, todb, fromhost, cloneOptions, NULL, errmsg);
            }

            Lock::DBLock lk (txn->lockState(), todb, MODE_X);
            return cloner.go(txn, todb, fromhost, cloneOptions, NULL, errmsg);
        }
Example #15
0
    /* slaveOk     - if true it is ok if the source of the data is !ismaster.
       useReplAuth - use the credentials we normally use as a replication slave for the cloning
       snapshot    - use $snapshot mode for copying collections.  note this should not be used when it isn't required, as it will be slower.
                     for example repairDatabase need not use it.
    */
    bool cloneFrom(const char *masterHost, string& errmsg, const string& fromdb, bool logForReplication, 
				   bool slaveOk, bool useReplAuth, bool snapshot)
    {
        Cloner c;
        return c.go(masterHost, errmsg, fromdb, logForReplication, slaveOk, useReplAuth, snapshot);
    }
Example #16
0
        virtual bool run(OperationContext* txn,
                         const string& dbname,
                         BSONObj& cmdObj,
                         int,
                         string& errmsg,
                         BSONObjBuilder& result,
                         bool fromRepl) {

            string fromhost = cmdObj.getStringField("fromhost");
            bool fromSelf = fromhost.empty();
            if ( fromSelf ) {
                /* copy from self */
                stringstream ss;
                ss << "localhost:" << serverGlobalParams.port;
                fromhost = ss.str();
            }

            CloneOptions cloneOptions;
            cloneOptions.fromDB = cmdObj.getStringField("fromdb");
            cloneOptions.logForRepl = !fromRepl;
            cloneOptions.slaveOk = cmdObj["slaveOk"].trueValue();
            cloneOptions.useReplAuth = false;
            cloneOptions.snapshot = true;
            cloneOptions.mayYield = true;
            cloneOptions.mayBeInterrupted = false;

            string todb = cmdObj.getStringField("todb");
            if ( fromhost.empty() || todb.empty() || cloneOptions.fromDB.empty() ) {
                errmsg = "parms missing - {copydb: 1, fromhost: <connection string>, "
                         "fromdb: <db>, todb: <db>}";
                return false;
            }

            Cloner cloner;
            string username = cmdObj.getStringField( "username" );
            string nonce = cmdObj.getStringField( "nonce" );
            string key = cmdObj.getStringField( "key" );
            if ( !username.empty() && !nonce.empty() && !key.empty() ) {
                uassert( 13008, "must call copydbgetnonce first", authConn_.get() );
                BSONObj ret;
                {
                    if ( !authConn_->runCommand( cloneOptions.fromDB,
                                                 BSON( "authenticate" << 1 << "user" << username
                                                       << "nonce" << nonce << "key" << key ), ret ) ) {
                        errmsg = "unable to login " + ret.toString();
                        return false;
                    }
                }
                cloner.setConnection( authConn_.release() );
            }
            else if (!fromSelf) {
                // If fromSelf leave the cloner's conn empty, it will use a DBDirectClient instead.

                ConnectionString cs = ConnectionString::parse(fromhost, errmsg);
                if (!cs.isValid()) {
                    return false;
                }

                DBClientBase* conn = cs.connect(errmsg);
                if (!conn) {
                    return false;
                }
                cloner.setConnection(conn);
            }


            // SERVER-4328 todo lock just the two db's not everything for the fromself case
            scoped_ptr<Lock::ScopedLock> lk( fromSelf ?
                                             static_cast<Lock::ScopedLock*>(new Lock::GlobalWrite(txn->lockState())) :
                                             static_cast<Lock::ScopedLock*>(new Lock::DBWrite(txn->lockState(), todb)));
            WriteUnitOfWork wunit(txn);
            if (!cloner.go(txn, todb, fromhost, cloneOptions, NULL, errmsg )) {
                return false;
            }
            wunit.commit();
            return true;
        }