static Status getStatus(const BatchedCommandResponse& response) { if (response.getOk() != 1) { return Status(static_cast<ErrorCodes::Error>(response.getErrCode()), response.getErrMessage()); } if (response.isErrDetailsSet()) { const WriteErrorDetail* errDetail = response.getErrDetails().front(); return Status(static_cast<ErrorCodes::Error>(errDetail->getErrCode()), errDetail->getErrMessage()); } if (response.isWriteConcernErrorSet()) { const WCErrorDetail* errDetail = response.getWriteConcernError(); return Status(static_cast<ErrorCodes::Error>(errDetail->getErrCode()), errDetail->getErrMessage()); } return Status::OK(); }
Status SessionsCollectionSharded::removeRecords(OperationContext* opCtx, const LogicalSessionIdSet& sessions) { auto send = [&](BSONObj toSend) { auto opMsg = OpMsgRequest::fromDBAndBody(SessionsCollection::kSessionsDb, toSend); auto request = BatchedCommandRequest::parseDelete(opMsg); BatchedCommandResponse response; BatchWriteExecStats stats; ClusterWriter::write(opCtx, request, &stats, &response); if (response.getOk()) { return Status::OK(); } auto error = response.isErrCodeSet() ? ErrorCodes::fromInt(response.getErrCode()) : ErrorCodes::UnknownError; return Status(error, response.getErrMessage()); }; return doRemove(sessions, send); }
static void cloneCommandErrorTo(const BatchedCommandResponse& batchResp, WriteErrorDetail* details) { details->setErrCode(batchResp.getErrCode()); details->setErrMessage(batchResp.getErrMessage()); }
void buildErrorFromResponse( const BatchedCommandResponse& response, WriteErrorDetail* error ) { error->setErrCode( response.getErrCode() ); error->setErrMessage( response.getErrMessage() ); }
void batchErrorToLastError( const BatchedCommandRequest& request, const BatchedCommandResponse& response, LastError* error ) { scoped_ptr<BatchedErrorDetail> topLevelError; BatchedErrorDetail* lastBatchError = NULL; if ( !response.getOk() ) { int code = response.getErrCode(); // Check for batch error // We don't care about write concern errors, these happen in legacy mode in GLE if ( code != ErrorCodes::WriteConcernFailed && !response.isErrDetailsSet() ) { // Top-level error, all writes failed topLevelError.reset( new BatchedErrorDetail ); buildErrorFromResponse( response, topLevelError.get() ); lastBatchError = topLevelError.get(); } else if ( response.isErrDetailsSet() ) { // The last error in the batch is always reported - this matches expected COE // semantics for insert batches and works for single writes lastBatchError = response.getErrDetails().back(); } } // Record an error if one exists if ( lastBatchError ) { error->raiseError( lastBatchError->getErrCode(), lastBatchError->getErrMessage().c_str() ); return; } // Record write stats otherwise // NOTE: For multi-write batches, our semantics change a little because we don't have // un-aggregated "n" stats. if ( request.getBatchType() == BatchedCommandRequest::BatchType_Update ) { BSONObj upsertedId; if ( response.isSingleUpsertedSet() ) upsertedId = response.getSingleUpserted(); else if( response.isUpsertDetailsSet() ) { // Only report the very last item's upserted id if applicable if ( response.getUpsertDetails().back()->getIndex() + 1 == static_cast<int>( request.sizeWriteOps() ) ) { upsertedId = response.getUpsertDetails().back()->getUpsertedID(); } } int numUpserted = 0; if ( response.isSingleUpsertedSet() ) ++numUpserted; else if ( response.isUpsertDetailsSet() ) numUpserted += response.sizeUpsertDetails(); int numUpdated = response.getN() - numUpserted; dassert( numUpdated >= 0 ); error->recordUpdate( numUpdated > 0, response.getN(), upsertedId ); } else if ( request.getBatchType() == BatchedCommandRequest::BatchType_Delete ) { error->recordDelete( response.getN() ); } }
void buildErrorFromResponse( const BatchedCommandResponse& response, BatchedErrorDetail* error ) { error->setErrCode( response.getErrCode() ); if ( error->isErrInfoSet() ) error->setErrInfo( response.getErrInfo() ); error->setErrMessage( response.getErrMessage() ); }
void BatchWriteOp::noteBatchResponse( const TargetedWriteBatch& targetedBatch, const BatchedCommandResponse& response, TrackedErrors* trackedErrors ) { // // Organize errors based on error code. // We may have *either* a batch error or errors per-item. // (Write Concern errors are stored and handled later.) // vector<BatchedErrorDetail*> itemErrors; scoped_ptr<BatchedErrorDetail> batchError; if ( !response.getOk() ) { int errCode = response.getErrCode(); bool isWCError = isWCErrCode( errCode ); // Special handling for write concern errors, save for later if ( isWCError ) { BatchedErrorDetail error; cloneBatchErrorTo( response, &error ); ShardError* wcError = new ShardError( targetedBatch.getEndpoint(), error ); _wcErrors.mutableVector().push_back( wcError ); } // Handle batch and per-item errors if ( response.isErrDetailsSet() ) { // Per-item errors were set itemErrors.insert( itemErrors.begin(), response.getErrDetails().begin(), response.getErrDetails().end() ); // Sort per-item errors by index std::sort( itemErrors.begin(), itemErrors.end(), BatchedErrorDetailComp() ); } else if ( !isWCError ) { // Per-item errors were not set and this error is not a WC error // => this is a full-batch error batchError.reset( new BatchedErrorDetail ); cloneBatchErrorTo( response, batchError.get() ); } } // We can't have both a batch error and per-item errors dassert( !( batchError && !itemErrors.empty() ) ); // // Go through all pending responses of the op and sorted remote reponses, populate errors // This will either set all errors to the batch error or apply per-item errors as-needed // vector<BatchedErrorDetail*>::iterator itemErrorIt = itemErrors.begin(); int index = 0; for ( vector<TargetedWrite*>::const_iterator it = targetedBatch.getWrites().begin(); it != targetedBatch.getWrites().end(); ++it, ++index ) { const TargetedWrite* write = *it; WriteOp& writeOp = _writeOps[write->writeOpRef.first]; dassert( writeOp.getWriteState() == WriteOpState_Pending ); // See if we have an error for the write BatchedErrorDetail* writeError = NULL; if ( batchError ) { // Default to batch error, if it exists writeError = batchError.get(); } else if ( itemErrorIt != itemErrors.end() && ( *itemErrorIt )->getIndex() == index ) { // We have an per-item error for this write op's index writeError = *itemErrorIt; ++itemErrorIt; } // Finish the response (with error, if needed) if ( NULL == writeError ) { writeOp.noteWriteComplete( *write ); } else { writeOp.noteWriteError( *write, *writeError ); } } // Track errors we care about, whether batch or individual errors if ( NULL != trackedErrors ) { trackErrors( targetedBatch.getEndpoint(), batchError.get(), itemErrors, trackedErrors ); } // Stop tracking targeted batch _targeted.erase( &targetedBatch ); }
static void cloneBatchErrorTo( const BatchedCommandResponse& batchResp, BatchedErrorDetail* details ) { details->setErrCode( batchResp.getErrCode() ); if ( batchResp.isErrInfoSet() ) details->setErrInfo( batchResp.getErrInfo() ); details->setErrMessage( batchResp.getErrMessage() ); }