void DBClientMultiCommand::sendAll() { for ( deque<PendingCommand*>::iterator it = _pendingCommands.begin(); it != _pendingCommands.end(); ++it ) { PendingCommand* command = *it; dassert( NULL == command->conn ); try { // TODO: Figure out how to handle repl sets, configs dassert( command->endpoint.type() == ConnectionString::MASTER || command->endpoint.type() == ConnectionString::CUSTOM ); command->conn = shardConnectionPool.get( command->endpoint, 0 /*timeout*/); if ( hasBatchWriteFeature( command->conn ) || !isBatchWriteCommand( command->cmdObj ) ) { // Do normal command dispatch sayAsCmd( command->conn, command->dbName, command->cmdObj ); } else { // Sending a batch as safe writes necessarily blocks, so we can't do anything // here. Instead we do the safe writes in recvAny(), which can block. } } catch ( const DBException& ex ) { command->status = ex.toStatus(); if ( NULL != command->conn ) delete command->conn; command->conn = NULL; } } }
Status DBClientMultiCommand::recvAny( ConnectionString* endpoint, BSONSerializable* response ) { scoped_ptr<PendingCommand> command( _pendingCommands.front() ); _pendingCommands.pop_front(); *endpoint = command->endpoint; if ( !command->status.isOK() ) return command->status; dassert( NULL != command->conn ); try { // Holds the data and BSONObj for the command result Message toRecv; BSONObj result; if ( hasBatchWriteFeature( command->conn ) || !isBatchWriteCommand( command->cmdObj ) ) { // Recv data from command sent earlier recvAsCmd( command->conn, &toRecv, &result ); } else { // We can safely block in recvAny, so dispatch writes as safe writes for hosts // that don't understand batch write commands. legacySafeWrite( command->conn, command->dbName, command->cmdObj, &result ); } shardConnectionPool.release( command->endpoint.toString(), command->conn ); command->conn = NULL; string errMsg; if ( !response->parseBSON( result, &errMsg ) || !response->isValid( &errMsg ) ) { return Status( ErrorCodes::FailedToParse, errMsg ); } } catch ( const DBException& ex ) { // Confusingly, the pool needs to know about failed connections so that it can // invalidate other connections which might be bad. But if the connection doesn't seem // bad, don't send it back, because we don't want to reuse it. if ( !command->conn->isFailed() ) { delete command->conn; } else { shardConnectionPool.release( command->endpoint.toString(), command->conn ); } command->conn = NULL; return ex.toStatus(); } return Status::OK(); }
void DBClientMultiCommand::sendAll() { for ( deque<PendingCommand*>::iterator it = _pendingCommands.begin(); it != _pendingCommands.end(); ++it ) { PendingCommand* command = *it; dassert( NULL == command->conn ); try { dassert( command->endpoint.type() == ConnectionString::MASTER || command->endpoint.type() == ConnectionString::CUSTOM ); // TODO: Fix the pool up to take millis directly int timeoutSecs = _timeoutMillis / 1000; command->conn = shardConnectionPool.get( command->endpoint, timeoutSecs ); if ( hasBatchWriteFeature( command->conn ) || !isBatchWriteCommand( command->cmdObj ) ) { // Do normal command dispatch sayAsCmd( command->conn, command->dbName, command->cmdObj ); } else { // Sending a batch as safe writes necessarily blocks, so we can't do anything // here. Instead we do the safe writes in recvAny(), which can block. } } catch ( const DBException& ex ) { command->status = ex.toStatus(); if ( NULL != command->conn ) { // Confusingly, the pool needs to know about failed connections so that it can // invalidate other connections which might be bad. But if the connection // doesn't seem bad, don't send it back, because we don't want to reuse it. if ( !command->conn->isFailed() ) { delete command->conn; } else { shardConnectionPool.release( command->endpoint.toString(), command->conn ); } command->conn = NULL; } } } }
Status DBClientMultiCommand::recvAny( ConnectionString* endpoint, BSONSerializable* response ) { scoped_ptr<PendingCommand> command( _pendingCommands.front() ); _pendingCommands.pop_front(); *endpoint = command->endpoint; if ( !command->status.isOK() ) return command->status; dassert( NULL != command->conn ); try { // Holds the data and BSONObj for the command result Message toRecv; BSONObj result; if ( hasBatchWriteFeature( command->conn ) || !isBatchWriteCommand( command->cmdObj ) ) { // Recv data from command sent earlier recvAsCmd( command->conn, &toRecv, &result ); } else { // We can safely block in recvAny, so dispatch writes as safe writes for hosts // that don't understand batch write commands. legacySafeWrite( command->conn, command->dbName, command->cmdObj, &result ); } shardConnectionPool.release( command->endpoint.toString(), command->conn ); command->conn = NULL; string errMsg; if ( !response->parseBSON( result, &errMsg ) || !response->isValid( &errMsg ) ) { return Status( ErrorCodes::FailedToParse, errMsg ); } } catch ( const DBException& ex ) { delete command->conn; command->conn = NULL; return ex.toStatus(); } return Status::OK(); }