bool Cloner::finishCloneCollection( const char *fromhost, const char *ns, const BSONObj &query, long long cursorId, string &errmsg ) { char db[256]; nsToClient( ns, db ); auto_ptr< DBClientCursor > cur; { dbtemprelease r; auto_ptr< DBClientConnection > c( new DBClientConnection() ); if ( !c->connect( fromhost, errmsg ) ) return false; if( !replAuthenticate(c.get()) ) return false; conn = c; string logNS = "local.temp.oplog." + string( ns ); if ( cursorId != 0 ) cur = conn->getMore( logNS.c_str(), cursorId ); else cur = conn->query( logNS.c_str(), Query() ); } replayOpLog( cur.get(), query ); { dbtemprelease t; BSONObj info; if ( !conn->runCommand( db, BSON( "logCollection" << ns << "validateComplete" << 1 ), info ) ) { errmsg = "logCollection failed: " + (string)info; return false; } } return true; }
bool DBClientWithCommands::createCollection(const string &ns, unsigned size, bool capped, int max, BSONObj *info) { BSONObj o; if ( info == 0 ) info = &o; BSONObjBuilder b; b.append("create", ns); if ( size ) b.append("size", size); if ( capped ) b.append("capped", true); if ( max ) b.append("max", max); string db = nsToClient(ns.c_str()); return runCommand(db.c_str(), b.done(), *info); }
bool Cloner::startCloneCollection( const char *fromhost, const char *ns, const BSONObj &query, string &errmsg, bool logForRepl, bool copyIndexes, int logSizeMb, long long &cursorId ) { char db[256]; nsToClient( ns, db ); { dbtemprelease r; auto_ptr< DBClientConnection > c( new DBClientConnection() ); if ( !c->connect( fromhost, errmsg ) ) return false; if( !replAuthenticate(c.get()) ) return false; conn = c; // Start temporary op log BSONObjBuilder cmdSpec; cmdSpec << "logCollection" << ns << "start" << 1; if ( logSizeMb != INT_MIN ) cmdSpec << "logSizeMb" << logSizeMb; BSONObj info; if ( !conn->runCommand( db, cmdSpec.done(), info ) ) { errmsg = "logCollection failed: " + (string)info; return false; } } BSONObj spec = conn->findOne( string( db ) + ".system.namespaces", BSON( "name" << ns ) ); if ( !userCreateNS( ns, spec.getObjectField( "options" ), errmsg, true ) ) return false; copy( ns, ns, false, logForRepl, false, false, query ); if ( copyIndexes ) { string indexNs = string( db ) + ".system.indexes"; copy( indexNs.c_str(), indexNs.c_str(), true, logForRepl, false, false, BSON( "ns" << ns << "name" << NE << "_id_" ) ); } auto_ptr< DBClientCursor > c; { dbtemprelease r; string logNS = "local.temp.oplog." + string( ns ); c = conn->query( logNS.c_str(), Query(), 0, 0, 0, Option_CursorTailable ); } if ( c->more() ) { replayOpLog( c.get(), query ); cursorId = c->getCursorId(); massert( "Expected valid tailing cursor", cursorId != 0 ); } else { massert( "Did not expect valid cursor for empty query result", c->getCursorId() == 0 ); cursorId = 0; } c->decouple(); return true; }
// Returns false when request includes 'end' bool assembleResponse( Message &m, DbResponse &dbresponse, const sockaddr_in &client ) { // before we lock... if ( m.data->operation() == dbQuery ) { const char *ns = m.data->_data + 4; if( strstr(ns, "$cmd.sys.") ) { if( strstr(ns, "$cmd.sys.inprog") ) { inProgCmd(m, dbresponse); return true; } if( strstr(ns, "$cmd.sys.killop") ) { killOp(m, dbresponse); return true; } } } if ( handlePossibleShardedMessage( m , dbresponse ) ){ /* important to do this before we lock so if a message has to be forwarded, doesn't block for that */ return true; } dblock lk; stringstream ss; char buf[64]; time_t now = time(0); CurOp& currentOp = *cc().curop(); currentOp.reset(now, client); time_t_to_String(now, buf); buf[20] = 0; // don't want the year ss << buf; Timer t; Client& c = cc(); c.clearns(); int logThreshold = 100; int ms; bool log = logLevel >= 1; c.curop()->op = m.data->operation(); #if 0 /* use this if you only want to process operations for a particular namespace. maybe add to cmd line parms or something fancier. */ DbMessage ddd(m); if ( strncmp(ddd.getns(), "clusterstock", 12) != 0 ) { static int q; if ( ++q < 20 ) out() << "TEMP skip " << ddd.getns() << endl; goto skip; } #endif if ( m.data->operation() == dbQuery ) { // receivedQuery() does its own authorization processing. receivedQuery(dbresponse, m, ss, true); } else if ( m.data->operation() == dbGetMore ) { // receivedQuery() does its own authorization processing. OPREAD; DEV log = true; ss << "getmore "; receivedGetMore(dbresponse, m, ss); } else if ( m.data->operation() == dbMsg ) { /* deprecated / rarely used. intended for connection diagnostics. */ ss << "msg "; char *p = m.data->_data; int len = strlen(p); if ( len > 400 ) out() << curTimeMillis() % 10000 << " long msg received, len:" << len << " ends with: " << p + len - 10 << endl; bool end = false; //strcmp("end", p) == 0; Message *resp = new Message(); resp->setData(opReply, "i am fine"); dbresponse.response = resp; dbresponse.responseTo = m.data->id; //dbMsgPort.reply(m, resp); if ( end ) return false; } else { const char *ns = m.data->_data + 4; char cl[256]; nsToClient(ns, cl); strncpy(currentOp.ns, ns, Namespace::MaxNsLen); AuthenticationInfo *ai = currentClient.get()->ai; if( !ai->isAuthorized(cl) ) { uassert_nothrow("unauthorized"); } else if ( m.data->operation() == dbInsert ) { OPWRITE; try { ss << "insert "; receivedInsert(m, ss); } catch ( AssertionException& e ) { LOGSOME problem() << " Caught Assertion insert, continuing\n"; ss << " exception " + e.toString(); } } else if ( m.data->operation() == dbUpdate ) { OPWRITE; try { ss << "update "; receivedUpdate(m, ss); } catch ( AssertionException& e ) { LOGSOME problem() << " Caught Assertion update, continuing" << endl; ss << " exception " + e.toString(); } } else if ( m.data->operation() == dbDelete ) { OPWRITE; try { ss << "remove "; receivedDelete(m, ss); } catch ( AssertionException& e ) { LOGSOME problem() << " Caught Assertion receivedDelete, continuing" << endl; ss << " exception " + e.toString(); } } else if ( m.data->operation() == dbKillCursors ) { OPREAD; try { logThreshold = 10; ss << "killcursors "; receivedKillCursors(m); } catch ( AssertionException& e ) { problem() << " Caught Assertion in kill cursors, continuing" << endl; ss << " exception " + e.toString(); } } else { out() << " operation isn't supported: " << m.data->operation() << endl; currentOp.active = false; assert(false); } } ms = t.millis(); log = log || (logLevel >= 2 && ++ctr % 512 == 0); DEV log = true; if ( log || ms > logThreshold ) { ss << ' ' << t.millis() << "ms"; out() << ss.str().c_str() << endl; } Database *database = cc().database(); if ( database && database->profile >= 1 ) { if ( database->profile >= 2 || ms >= 100 ) { // profile it profile(ss.str().c_str()+20/*skip ts*/, ms); } } currentOp.active = false; return true; }
virtual bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) { string source = cmdObj.getStringField( name.c_str() ); string target = cmdObj.getStringField( "to" ); if ( source.empty() || target.empty() ) { errmsg = "invalid command syntax"; return false; } setClient( source.c_str() ); NamespaceDetails *nsd = nsdetails( source.c_str() ); uassert( "source namespace does not exist", nsd ); bool capped = nsd->capped; long long size = 0; if ( capped ) for( DiskLoc i = nsd->firstExtent; !i.isNull(); i = i.ext()->xnext ) size += i.ext()->length; setClient( target.c_str() ); uassert( "target namespace exists", !nsdetails( target.c_str() ) ); { char from[256]; nsToClient( source.c_str(), from ); char to[256]; nsToClient( target.c_str(), to ); if ( strcmp( from, to ) == 0 ) { renameNamespace( source.c_str(), target.c_str() ); return true; } } BSONObjBuilder spec; if ( capped ) { spec.appendBool( "capped", true ); spec.append( "size", double( size ) ); } if ( !userCreateNS( target.c_str(), spec.done(), errmsg, false ) ) return false; auto_ptr< DBClientCursor > c; DBDirectClient bridge; { c = bridge.query( source, BSONObj() ); } while( 1 ) { { if ( !c->more() ) break; } BSONObj o = c->next(); theDataFileMgr.insert( target.c_str(), o ); } char cl[256]; nsToClient( source.c_str(), cl ); string sourceIndexes = string( cl ) + ".system.indexes"; nsToClient( target.c_str(), cl ); string targetIndexes = string( cl ) + ".system.indexes"; { c = bridge.query( sourceIndexes, QUERY( "ns" << source ) ); } while( 1 ) { { if ( !c->more() ) break; } BSONObj o = c->next(); BSONObjBuilder b; BSONObjIterator i( o ); while( i.moreWithEOO() ) { BSONElement e = i.next(); if ( e.eoo() ) break; if ( strcmp( e.fieldName(), "ns" ) == 0 ) { b.append( "ns", target ); } else { b.append( e ); } } BSONObj n = b.done(); theDataFileMgr.insert( targetIndexes.c_str(), n ); } setClient( source.c_str() ); dropCollection( source, errmsg, result ); return true; }
bool Cloner::startCloneCollection( const char *fromhost, const char *ns, const BSONObj &query, string &errmsg, bool logForRepl, bool copyIndexes, int logSizeMb, long long &cursorId ) { char db[256]; nsToClient( ns, db ); NamespaceDetails *nsd = nsdetails( ns ); if ( nsd ){ /** note: its ok to clone into a collection, but only if the range you're copying doesn't exist on this server */ string err; if ( runCount( ns , BSON( "query" << query ) , err ) > 0 ){ log() << "WARNING: data already exists for: " << ns << " in range : " << query << " deleting..." << endl; deleteObjects( ns , query , false , logForRepl , false ); } } { dbtemprelease r; auto_ptr< DBClientConnection > c( new DBClientConnection() ); if ( !c->connect( fromhost, errmsg ) ) return false; if( !replAuthenticate(c.get()) ) return false; conn = c; // Start temporary op log BSONObjBuilder cmdSpec; cmdSpec << "logCollection" << ns << "start" << 1; if ( logSizeMb != INT_MIN ) cmdSpec << "logSizeMb" << logSizeMb; BSONObj info; if ( !conn->runCommand( db, cmdSpec.done(), info ) ) { errmsg = "logCollection failed: " + (string)info; return false; } } if ( ! nsd ) { BSONObj spec = conn->findOne( string( db ) + ".system.namespaces", BSON( "name" << ns ) ); if ( !userCreateNS( ns, spec.getObjectField( "options" ), errmsg, true ) ) return false; } copy( ns, ns, false, logForRepl, false, false, query ); if ( copyIndexes ) { string indexNs = string( db ) + ".system.indexes"; copy( indexNs.c_str(), indexNs.c_str(), true, logForRepl, false, false, BSON( "ns" << ns << "name" << NE << "_id_" ) ); } auto_ptr< DBClientCursor > c; { dbtemprelease r; string logNS = "local.temp.oplog." + string( ns ); c = conn->query( logNS.c_str(), Query(), 0, 0, 0, Option_CursorTailable ); } if ( c->more() ) { replayOpLog( c.get(), query ); cursorId = c->getCursorId(); massert( "Expected valid tailing cursor", cursorId != 0 ); } else { massert( "Did not expect valid cursor for empty query result", c->getCursorId() == 0 ); cursorId = 0; } c->decouple(); return true; }