void DBClientCursor::commandDataReceived() { int op = batch.m.operation(); invariant(op == opReply || op == dbCommandReply); batch.nReturned = 1; batch.pos = 0; auto commandReply = rpc::makeReply(&batch.m); auto commandStatus = getStatusFromCommandResult(commandReply->getCommandReply()); if (ErrorCodes::SendStaleConfig == commandStatus) { throw RecvStaleConfigException("stale config in DBClientCursor::dataReceived()", commandReply->getCommandReply()); } else if (!commandStatus.isOK()) { wasError = true; } if (_client->getReplyMetadataReader()) { uassertStatusOK(_client->getReplyMetadataReader()(commandReply->getMetadata(), _client->getServerAddress())); } // HACK: If we got an OP_COMMANDREPLY, take the reply object // and shove it in to an OP_REPLY message. if (op == dbCommandReply) { // Need to take ownership here as we destroy the underlying message. BSONObj reply = commandReply->getCommandReply().getOwned(); batch.m.reset(); replyToQuery(0, batch.m, reply); } QueryResult::View qr = batch.m.singleData().view2ptr(); batch.data = qr.data(); }
BSONObj ClusterAggregate::aggRunCommand(DBClientBase* conn, const Namespaces& namespaces, BSONObj cmd, int queryOptions) { // Temporary hack. See comment on declaration for details. massert(17016, "should only be running an aggregate command here", str::equals(cmd.firstElementFieldName(), "aggregate")); auto cursor = conn->query(namespaces.executionNss.db() + ".$cmd", cmd, -1, // nToReturn 0, // nToSkip NULL, // fieldsToReturn queryOptions); massert(17014, str::stream() << "aggregate command didn't return results on host: " << conn->toString(), cursor && cursor->more()); BSONObj result = cursor->nextSafe().getOwned(); if (ErrorCodes::SendStaleConfig == getStatusFromCommandResult(result)) { throw RecvStaleConfigException("command failed because of stale config", result); } auto executorPool = grid.getExecutorPool(); result = uassertStatusOK(storePossibleCursor(HostAndPort(cursor->originalHost()), result, namespaces.requestedNss, executorPool->getArbitraryExecutor(), grid.getCursorManager())); return result; }
void Strategy::doQuery( Request& r , const Shard& shard ) { r.checkAuth( Auth::READ ); ShardConnection dbcon( shard , r.getns() ); DBClientBase &c = dbcon.conn(); string actualServer; Message response; bool ok = c.call( r.m(), response, true , &actualServer ); uassert( 10200 , "mongos: error calling db", ok ); { QueryResult *qr = (QueryResult *) response.singleData(); if ( qr->resultFlags() & ResultFlag_ShardConfigStale ) { dbcon.done(); // Version is zero b/c this is deprecated codepath throw RecvStaleConfigException( r.getns() , "Strategy::doQuery", ShardChunkVersion( 0 ), ShardChunkVersion( 0 ) ); } } r.reply( response , actualServer.size() ? actualServer : c.getServerAddress() ); dbcon.done(); }
/** * Returns true if request is a query for sharded indexes. */ static bool doShardedIndexQuery(OperationContext* txn, Request& r, const QuerySpec& qSpec) { // Extract the ns field from the query, which may be embedded within the "query" or // "$query" field. auto nsField = qSpec.filter()["ns"]; if (nsField.eoo()) { return false; } const NamespaceString indexNSSQuery(nsField.str()); auto status = grid.catalogCache()->getDatabase(txn, indexNSSQuery.db().toString()); if (!status.isOK()) { return false; } shared_ptr<DBConfig> config = status.getValue(); if (!config->isSharded(indexNSSQuery.ns())) { return false; } // if you are querying on system.indexes, we need to make sure we go to a shard // that actually has chunks. This is not a perfect solution (what if you just // look at all indexes), but better than doing nothing. ShardPtr shard; ChunkManagerPtr cm; config->getChunkManagerOrPrimary(indexNSSQuery.ns(), cm, shard); if (cm) { set<ShardId> shardIds; cm->getAllShardIds(&shardIds); verify(shardIds.size() > 0); shard = grid.shardRegistry()->getShard(*shardIds.begin()); } ShardConnection dbcon(shard->getConnString(), r.getns()); DBClientBase& c = dbcon.conn(); string actualServer; Message response; bool ok = c.call(r.m(), response, true, &actualServer); uassert(10200, "mongos: error calling db", ok); { QueryResult::View qr = response.singleData().view2ptr(); if (qr.getResultFlags() & ResultFlag_ShardConfigStale) { dbcon.done(); // Version is zero b/c this is deprecated codepath throw RecvStaleConfigException(r.getns(), "Strategy::doQuery", ChunkVersion(0, 0, OID()), ChunkVersion(0, 0, OID())); } } r.reply(response, actualServer.size() ? actualServer : c.getServerAddress()); dbcon.done(); return true; }
bool ShardConnection::runCommand( const string& db , const BSONObj& cmd , BSONObj& res ) { assert( _conn ); bool ok = _conn->runCommand( db , cmd , res ); if ( ! ok ) { if ( res["code"].numberInt() == SendStaleConfigCode ) { done(); throw RecvStaleConfigException( res["ns"].String() , res["errmsg"].String() ); } } return ok; }
void Strategy::insert( const Shard& shard , const char * ns , const vector<BSONObj>& v , int flags, bool safe ) { ShardConnection dbcon( shard , ns ); if ( dbcon.setVersion() ) { dbcon.done(); // Version is zero b/c we don't yet have a way to get the local version conflict throw RecvStaleConfigException( ns , "for insert", ShardChunkVersion( 0 ), ShardChunkVersion( 0 ) ); } dbcon->insert( ns , v , flags); if (safe) dbcon->getLastError(); dbcon.done(); }
void Strategy::doWrite( int op , Request& r , const Shard& shard , bool checkVersion ) { ShardConnection conn( shard , r.getns() ); if ( ! checkVersion ) conn.donotCheckVersion(); else if ( conn.setVersion() ) { conn.done(); // Version is zero b/c we don't yet have a way to get the local version conflict throw RecvStaleConfigException( r.getns() , "doWrite" , true, ShardChunkVersion( 0 ), ShardChunkVersion( 0 ) ); } conn->say( r.m() ); conn.done(); }
void DBClientCursor::dataReceived(bool& retry, string& host) { // If this is a reply to our initial command request. if (_isCommand && cursorId == 0) { commandDataReceived(); return; } QueryResult::View qr = batch.m.singleData().view2ptr(); resultFlags = qr.getResultFlags(); if (qr.getResultFlags() & ResultFlag_ErrSet) { wasError = true; } if (qr.getResultFlags() & ResultFlag_CursorNotFound) { // cursor id no longer valid at the server. invariant(qr.getCursorId() == 0); if (!(opts & QueryOption_CursorTailable)) { uasserted(13127, str::stream() << "cursor id " << cursorId << " didn't exist on server."); } // 0 indicates no longer valid (dead) cursorId = 0; } if (cursorId == 0 || !(opts & QueryOption_CursorTailable)) { // only set initially: we don't want to kill it on end of data // if it's a tailable cursor cursorId = qr.getCursorId(); } batch.nReturned = qr.getNReturned(); batch.pos = 0; batch.data = qr.data(); batch.remainingBytes = qr.dataLen(); _client->checkResponse(batch.data, batch.nReturned, &retry, &host); // watches for "not master" if (qr.getResultFlags() & ResultFlag_ShardConfigStale) { BSONObj error; verify(peekError(&error)); throw RecvStaleConfigException( (string) "stale config on lazy receive" + causedBy(getErrField(error)), error); } /* this assert would fire the way we currently work: verify( nReturned || cursorId == 0 ); */ }
/** * Returns true if request is a query for sharded indexes. */ static bool doShardedIndexQuery( Request& r, const QuerySpec& qSpec ) { // Extract the ns field from the query, which may be embedded within the "query" or // "$query" field. string indexNSQuery(qSpec.filter()["ns"].str()); DBConfigPtr config = grid.getDBConfig( r.getns() ); if ( !config->isSharded( indexNSQuery )) { return false; } // if you are querying on system.indexes, we need to make sure we go to a shard // that actually has chunks. This is not a perfect solution (what if you just // look at all indexes), but better than doing nothing. ShardPtr shard; ChunkManagerPtr cm; config->getChunkManagerOrPrimary( indexNSQuery, cm, shard ); if ( cm ) { set<Shard> shards; cm->getAllShards( shards ); verify( shards.size() > 0 ); shard.reset( new Shard( *shards.begin() ) ); } ShardConnection dbcon( *shard , r.getns() ); DBClientBase &c = dbcon.conn(); string actualServer; Message response; bool ok = c.call( r.m(), response, true , &actualServer ); uassert( 10200 , "mongos: error calling db", ok ); { QueryResult *qr = (QueryResult *) response.singleData(); if ( qr->resultFlags() & ResultFlag_ShardConfigStale ) { dbcon.done(); // Version is zero b/c this is deprecated codepath throw RecvStaleConfigException( r.getns(), "Strategy::doQuery", ChunkVersion( 0, 0, OID() ), ChunkVersion( 0, 0, OID() )); } } r.reply( response , actualServer.size() ? actualServer : c.getServerAddress() ); dbcon.done(); return true; }
void Strategy::update( const Shard& shard , const char * ns , const BSONObj& query , const BSONObj& toupdate , int flags, bool safe ) { bool upsert = flags & UpdateOption_Upsert; bool multi = flags & UpdateOption_Multi; ShardConnection dbcon( shard , ns ); if ( dbcon.setVersion() ) { dbcon.done(); // Version is zero b/c we don't yet have a way to get the local version conflict throw RecvStaleConfigException( ns , "for insert", ShardChunkVersion( 0 ), ShardChunkVersion( 0 ) ); } dbcon->update( ns , query , toupdate, upsert, multi); if (safe) dbcon->getLastError(); dbcon.done(); }
void DBClientCursor::dataReceived( bool& retry, string& host ) { QueryResult *qr = (QueryResult *) b.m->singleData(); resultFlags = qr->resultFlags(); if ( qr->resultFlags() & ResultFlag_ErrSet ) { wasError = true; } if ( qr->resultFlags() & ResultFlag_CursorNotFound ) { // cursor id no longer valid at the server. assert( qr->cursorId == 0 ); cursorId = 0; // 0 indicates no longer valid (dead) if ( ! ( opts & QueryOption_CursorTailable ) ) throw UserException( 13127 , "getMore: cursor didn't exist on server, possible restart or timeout?" ); } if ( cursorId == 0 || ! ( opts & QueryOption_CursorTailable ) ) { // only set initially: we don't want to kill it on end of data // if it's a tailable cursor cursorId = qr->cursorId; } b.nReturned = qr->nReturned; b.pos = 0; b.data = qr->data(); _client->checkResponse( b.data, b.nReturned, &retry, &host ); // watches for "not master" if( qr->resultFlags() & ResultFlag_ShardConfigStale ) { BSONObj error; assert( peekError( &error ) ); throw RecvStaleConfigException( error["ns"].String(), (string)"stale config on lazy receive" + causedBy( getErrField( error ) ) ); } /* this assert would fire the way we currently work: assert( nReturned || cursorId == 0 ); */ }