void ClusterWriter::write(OperationContext* opCtx, const BatchedCommandRequest& request, BatchWriteExecStats* stats, BatchedCommandResponse* response) { const NamespaceString& nss = request.getNS(); LastError::Disabled disableLastError(&LastError::get(opCtx->getClient())); // Config writes and shard writes are done differently if (nss.db() == NamespaceString::kConfigDb || nss.db() == NamespaceString::kAdminDb) { Grid::get(opCtx)->catalogClient()->writeConfigServerDirect(opCtx, request, response); } else { TargeterStats targeterStats; { ChunkManagerTargeter targeter(request.getTargetingNS(), &targeterStats); Status targetInitStatus = targeter.init(opCtx); if (!targetInitStatus.isOK()) { toBatchError({targetInitStatus.code(), str::stream() << "unable to target" << (request.isInsertIndexRequest() ? " index" : "") << " write op for collection " << request.getTargetingNS().ns() << causedBy(targetInitStatus)}, response); return; } BatchWriteExec::executeBatch(opCtx, targeter, request, response, stats); } splitIfNeeded(opCtx, request.getNS(), targeterStats); } }
void clusterWrite( const BatchedCommandRequest& request, BatchedCommandResponse* response, bool autoSplit ) { ChunkManagerTargeter targeter; 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 ); if ( autoSplit ) splitIfNeeded( request.getNS(), *targeter.getStats() ); }
void ClusterWriter::write(OperationContext* opCtx, const BatchedCommandRequest& origRequest, BatchedCommandResponse* response) { // Add _ids to insert request if req'd std::unique_ptr<BatchedCommandRequest> idRequest( BatchedCommandRequest::cloneWithIds(origRequest)); const BatchedCommandRequest* request = idRequest ? idRequest.get() : &origRequest; const NamespaceString& nss = request->getNS(); if (!nss.isValid()) { toBatchError(Status(ErrorCodes::InvalidNamespace, nss.ns() + " is not a valid namespace"), response); return; } if (!NamespaceString::validCollectionName(nss.coll())) { toBatchError( Status(ErrorCodes::BadValue, str::stream() << "invalid collection name " << nss.coll()), response); return; } if (request->sizeWriteOps() == 0u) { toBatchError(Status(ErrorCodes::InvalidLength, "no write ops were included in the batch"), response); return; } if (request->sizeWriteOps() > BatchedCommandRequest::kMaxWriteBatchSize) { toBatchError(Status(ErrorCodes::InvalidLength, str::stream() << "exceeded maximum write batch size of " << BatchedCommandRequest::kMaxWriteBatchSize), response); return; } std::string errMsg; if (request->isInsertIndexRequest() && !request->isValidIndexRequest(&errMsg)) { toBatchError(Status(ErrorCodes::InvalidOptions, errMsg), response); return; } // Config writes and shard writes are done differently if (nss.db() == NamespaceString::kConfigDb || nss.db() == NamespaceString::kAdminDb) { Grid::get(opCtx)->catalogClient()->writeConfigServerDirect(opCtx, *request, response); } else { TargeterStats targeterStats; { ChunkManagerTargeter targeter(request->getTargetingNSS(), &targeterStats); Status targetInitStatus = targeter.init(opCtx); if (!targetInitStatus.isOK()) { toBatchError({targetInitStatus.code(), str::stream() << "unable to target" << (request->isInsertIndexRequest() ? " index" : "") << " write op for collection " << request->getTargetingNSS().toString() << causedBy(targetInitStatus)}, response); return; } BatchWriteExec::executeBatch(opCtx, targeter, *request, response, &_stats); } if (_autoSplit) { splitIfNeeded(opCtx, request->getNS(), targeterStats); } } }
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; }