bool ClusterWriteCmd::run( const string& dbName, BSONObj& cmdObj, int options, string& errMsg, BSONObjBuilder& result, bool ) { BatchedCommandRequest request( _writeType ); BatchedCommandResponse response; // TODO: if we do namespace parsing, push this to the type if ( !request.parseBSON( cmdObj, &errMsg ) || !request.isValid( &errMsg ) ) { // Batch parse failure response.setOk( false ); response.setN( 0 ); response.setErrCode( ErrorCodes::FailedToParse ); response.setErrMessage( errMsg ); dassert( response.isValid( &errMsg ) ); result.appendElements( response.toBSON() ); // TODO // There's a pending issue about how to report response here. If we use // the command infra-structure, we should reuse the 'errmsg' field. But // we have already filed that message inside the BatchCommandResponse. // return response.getOk(); return true; } NamespaceString nss( dbName, request.getNS() ); request.setNS( nss.ns() ); // App-level validation of a create index insert if ( request.isInsertIndexRequest() ) { if ( request.sizeWriteOps() != 1 || request.isWriteConcernSet() ) { // Invalid request to create index response.setOk( false ); response.setN( 0 ); response.setErrCode( ErrorCodes::CannotCreateIndex ); response.setErrMessage( "invalid batch request for index creation" ); dassert( response.isValid( &errMsg ) ); result.appendElements( response.toBSON() ); return false; } } clusterWrite( request, &response, true /* autosplit */ ); result.appendElements( response.toBSON() ); // TODO // There's a pending issue about how to report response here. If we use // the command infra-structure, we should reuse the 'errmsg' field. But // we have already filed that message inside the BatchCommandResponse. // return response.getOk(); return true; }
bool WriteCmd::run(const string& dbName, BSONObj& cmdObj, int options, string& errMsg, BSONObjBuilder& result, bool fromRepl) { // Can't be run on secondaries (logTheOp() == false, slaveOk() == false). dassert( !fromRepl ); BatchedCommandRequest request( _writeType ); BatchedCommandResponse response; if ( !request.parseBSON( cmdObj, &errMsg ) || !request.isValid( &errMsg ) ) { // Batch parse failure response.setOk( false ); response.setErrCode( 99999 ); response.setErrMessage( errMsg ); result.appendElements( response.toBSON() ); // TODO // There's a pending issue about how to report response here. If we use // the command infra-structure, we should reuse the 'errmsg' field. But // we have already filed that message inside the BatchCommandResponse. // return response.getOk(); return true; } // Note that this is a runCommmand, and therefore, the database and the collection name // are in different parts of the grammar for the command. But it's more convenient to // work with a NamespaceString. We built it here and replace it in the parsed command. // Internally, everything work with the namespace string as opposed to just the // collection name. NamespaceString nss(dbName, request.getNS()); request.setNS(nss.ns()); { // Commands with locktype == NONE need to acquire a Context in order to set // CurOp::_ns. Setting a CurOp's namespace is necessary for higher-level // functionality (e.g. profiling) to operate on the correct database (note that // WriteBatchExecutor doesn't do this for us, since its job is to create child CurOp // objects and operate on them). // // Acquire ReadContext momentarily, for satisfying this purpose. Client::ReadContext ctx( dbName + ".$cmd" ); } WriteBatchExecutor writeBatchExecutor(&cc(), &globalOpCounters, lastError.get()); writeBatchExecutor.executeBatch( request, &response ); result.appendElements( response.toBSON() ); // TODO // There's a pending issue about how to report response here. If we use // the command infra-structure, we should reuse the 'errmsg' field. But // we have already filed that message inside the BatchCommandResponse. // return response.getOk(); return true; }
bool ClusterWriteCmd::run( const string& dbName, BSONObj& cmdObj, int options, string& errMsg, BSONObjBuilder& result, bool ) { BatchedCommandRequest request( _writeType ); BatchedCommandResponse response; ClusterWriter writer( true /* autosplit */, 0 /* timeout */ ); // TODO: if we do namespace parsing, push this to the type if ( !request.parseBSON( cmdObj, &errMsg ) || !request.isValid( &errMsg ) ) { // Batch parse failure response.setOk( false ); response.setErrCode( ErrorCodes::FailedToParse ); response.setErrMessage( errMsg ); } else { // Fixup the namespace to be a full ns internally NamespaceString nss( dbName, request.getNS() ); request.setNS( nss.ns() ); writer.write( request, &response ); } dassert( response.isValid( NULL ) ); // Save the last opTimes written on each shard for this client, to allow GLE to work if ( ClientInfo::exists() && writer.getStats().hasShardStats() ) { ClientInfo* clientInfo = ClientInfo::get( NULL ); clientInfo->addHostOpTimes( writer.getStats().getShardStats().getWriteOpTimes() ); } // TODO // There's a pending issue about how to report response here. If we use // the command infra-structure, we should reuse the 'errmsg' field. But // we have already filed that message inside the BatchCommandResponse. // return response.getOk(); result.appendElements( response.toBSON() ); return true; }
bool ClusterWriteCmd::run( const string& dbName, BSONObj& cmdObj, int options, string& errMsg, BSONObjBuilder& result, bool ) { BatchedCommandRequest request( _writeType ); BatchedCommandResponse response; // TODO: if we do namespace parsing, push this to the type if ( !request.parseBSON( cmdObj, &errMsg ) || !request.isValid( &errMsg ) ) { // Batch parse failure response.setOk( false ); response.setErrCode( ErrorCodes::FailedToParse ); response.setErrMessage( errMsg ); dassert( response.isValid( &errMsg ) ); } else { // Fixup the namespace to be a full ns internally NamespaceString nss( dbName, request.getNS() ); request.setNS( nss.ns() ); clusterWrite( request, &response, true /* autosplit */ ); } // Populate the lastError object based on the write dassert( response.isValid( NULL ) ); LastError* lastErrorForRequest = lastError.get( true /* create */ ); dassert( lastErrorForRequest ); lastErrorForRequest->reset(); batchErrorToLastError( request, response, lastErrorForRequest ); // TODO // There's a pending issue about how to report response here. If we use // the command infra-structure, we should reuse the 'errmsg' field. But // we have already filed that message inside the BatchCommandResponse. // return response.getOk(); result.appendElements( response.toBSON() ); return true; }
bool WriteCmd::run(const string& dbName, BSONObj& cmdObj, int options, string& errMsg, BSONObjBuilder& result, bool fromRepl) { // Can't be run on secondaries (logTheOp() == false, slaveOk() == false). dassert( !fromRepl ); BatchedCommandRequest request( _writeType ); BatchedCommandResponse response; if ( !request.parseBSON( cmdObj, &errMsg ) || !request.isValid( &errMsg ) ) { // Batch parse failure response.setOk( false ); response.setN( 0 ); response.setErrCode( ErrorCodes::FailedToParse ); response.setErrMessage( errMsg ); dassert( response.isValid( &errMsg ) ); result.appendElements( response.toBSON() ); // TODO // There's a pending issue about how to report response here. If we use // the command infra-structure, we should reuse the 'errmsg' field. But // we have already filed that message inside the BatchCommandResponse. // return response.getOk(); return true; } // Note that this is a runCommmand, and therefore, the database and the collection name // are in different parts of the grammar for the command. But it's more convenient to // work with a NamespaceString. We built it here and replace it in the parsed command. // Internally, everything work with the namespace string as opposed to just the // collection name. NamespaceString nss(dbName, request.getNS()); request.setNS(nss.ns()); if ( cc().curop() ) cc().curop()->setNS( nss.ns() ); BSONObj defaultWriteConcern; // This is really bad - it's only safe because we leak the defaults by overriding them with // new defaults and because we never reset to an empty default. // TODO: fix this for sane behavior where we query repl set object if ( getLastErrorDefault ) defaultWriteConcern = *getLastErrorDefault; if ( defaultWriteConcern.isEmpty() ) { BSONObjBuilder b; b.append( "w", 1 ); defaultWriteConcern = b.obj(); } WriteBatchExecutor writeBatchExecutor(defaultWriteConcern, &cc(), &globalOpCounters, lastError.get()); writeBatchExecutor.executeBatch( request, &response ); result.appendElements( response.toBSON() ); // TODO // There's a pending issue about how to report response here. If we use // the command infra-structure, we should reuse the 'errmsg' field. But // we have already filed that message inside the BatchCommandResponse. // return response.getOk(); return true; }
bool ClusterWriteCmd::run(OperationContext* txn, const string& dbName, BSONObj& cmdObj, int options, string& errMsg, BSONObjBuilder& result, bool ) { BatchedCommandRequest request( _writeType ); BatchedCommandResponse response; ClusterWriter writer( true /* autosplit */, 0 /* timeout */ ); // NOTE: Sometimes this command is invoked with LE disabled for legacy writes LastError* cmdLastError = lastError.get( false ); { // Disable the last error object for the duration of the write LastError::Disabled disableLastError( cmdLastError ); // TODO: if we do namespace parsing, push this to the type if ( !request.parseBSON( cmdObj, &errMsg ) || !request.isValid( &errMsg ) ) { // Batch parse failure response.setOk( false ); response.setErrCode( ErrorCodes::FailedToParse ); response.setErrMessage( errMsg ); } else { // Fixup the namespace to be a full ns internally NamespaceString nss( dbName, request.getNS() ); request.setNS( nss.ns() ); writer.write( request, &response ); } dassert( response.isValid( NULL ) ); } if ( cmdLastError ) { // Populate the lastError object based on the write response cmdLastError->reset(); batchErrorToLastError( request, response, cmdLastError ); } size_t numAttempts; if ( !response.getOk() ) { numAttempts = 0; } else if ( request.getOrdered() && response.isErrDetailsSet() ) { numAttempts = response.getErrDetailsAt(0)->getIndex() + 1; // Add one failed attempt } else { numAttempts = request.sizeWriteOps(); } // TODO: increase opcounters by more than one if ( _writeType == BatchedCommandRequest::BatchType_Insert ) { for( size_t i = 0; i < numAttempts; ++i ) { globalOpCounters.gotInsert(); } } else if ( _writeType == BatchedCommandRequest::BatchType_Update ) { for( size_t i = 0; i < numAttempts; ++i ) { globalOpCounters.gotUpdate(); } } else if ( _writeType == BatchedCommandRequest::BatchType_Delete ) { for( size_t i = 0; i < numAttempts; ++i ) { globalOpCounters.gotDelete(); } } // Save the last opTimes written on each shard for this client, to allow GLE to work if ( ClientInfo::exists() && writer.getStats().hasShardStats() ) { ClientInfo* clientInfo = ClientInfo::get( NULL ); clientInfo->addHostOpTimes( writer.getStats().getShardStats().getWriteOpTimes() ); } // TODO // There's a pending issue about how to report response here. If we use // the command infra-structure, we should reuse the 'errmsg' field. But // we have already filed that message inside the BatchCommandResponse. // return response.getOk(); result.appendElements( response.toBSON() ); return true; }
bool ClusterWriteCmd::run( const string& dbName, BSONObj& cmdObj, int options, string& errMsg, BSONObjBuilder& result, bool ) { BatchedCommandRequest request( _writeType ); BatchedCommandResponse response; // TODO: if we do namespace parsing, push this to the type if ( !request.parseBSON( cmdObj, &errMsg ) || !request.isValid( &errMsg ) ) { // Batch parse failure response.setOk( false ); response.setN( 0 ); response.setErrCode( ErrorCodes::FailedToParse ); response.setErrMessage( errMsg ); dassert( response.isValid( &errMsg ) ); result.appendElements( response.toBSON() ); // TODO // There's a pending issue about how to report response here. If we use // the command infra-structure, we should reuse the 'errmsg' field. But // we have already filed that message inside the BatchCommandResponse. // return response.getOk(); return true; } // App-level validation of a create index insert if ( request.isInsertIndexRequest() ) { if ( request.sizeWriteOps() != 1 || request.isWriteConcernSet() ) { // Invalid request to create index response.setOk( false ); response.setN( 0 ); response.setErrCode( ErrorCodes::CannotCreateIndex ); response.setErrMessage( "invalid batch request for index creation" ); dassert( response.isValid( &errMsg ) ); result.appendElements( response.toBSON() ); return false; } } // // Assemble the batch executor and run the batch // ChunkManagerTargeter targeter; NamespaceString nss( dbName, request.getNS() ); request.setNS( nss.ns() ); Status targetInitStatus = targeter.init( NamespaceString( request.getTargetingNS() ) ); if ( !targetInitStatus.isOK() ) { warning() << "could not initialize targeter for" << ( request.isInsertIndexRequest() ? " index" : "" ) << " write op in collection " << request.getTargetingNS() << endl; // Errors will be reported in response if we are unable to target } DBClientShardResolver resolver; DBClientMultiCommand dispatcher; BatchWriteExec exec( &targeter, &resolver, &dispatcher ); exec.executeBatch( request, &response ); result.appendElements( response.toBSON() ); splitIfNeeded( request.getNS(), *targeter.getStats() ); // TODO // There's a pending issue about how to report response here. If we use // the command infra-structure, we should reuse the 'errmsg' field. But // we have already filed that message inside the BatchCommandResponse. // return response.getOk(); return true; }