void BatchWriteOp::buildClientResponse( BatchedCommandResponse* batchResp ) { dassert( isFinished() ); // // Find all the errors in the batch // vector<WriteOp*> errOps; size_t numWriteOps = _clientRequest->sizeWriteOps(); for ( size_t i = 0; i < numWriteOps; ++i ) { WriteOp& writeOp = _writeOps[i]; if ( writeOp.getWriteState() == WriteOpState_Error ) { errOps.push_back( &writeOp ); } } // // Build the top-level batch error // This will be either the write concern error, the special "multiple item errors" error, // or a promoted single-item error. Top-level parsing/targeting errors handled elsewhere. // if ( !_wcErrors.empty() ) { BatchedErrorDetail comboWCError; combineWCErrors( _wcErrors.vector(), &comboWCError ); cloneBatchErrorFrom( comboWCError, batchResp ); } else if ( !errOps.empty() ) { BatchedErrorDetail comboBatchError; combineOpErrors( errOps, &comboBatchError ); cloneBatchErrorFrom( comboBatchError, batchResp ); // Suppress further error details if only one error if ( _clientRequest->sizeWriteOps() == 1u ) errOps.clear(); } // // Build the per-item errors, if needed // if ( !errOps.empty() ) { for ( vector<WriteOp*>::iterator it = errOps.begin(); it != errOps.end(); ++it ) { WriteOp& writeOp = **it; BatchedErrorDetail* error = new BatchedErrorDetail(); writeOp.getOpError().cloneTo( error ); batchResp->addToErrDetails( error ); } } batchResp->setOk( !batchResp->isErrCodeSet() ); }
/** * This is the core function which aggregates all the results of a write operation on multiple * shards and updates the write operation's state. */ void WriteOp::updateOpState() { vector<ChildWriteOp*> childErrors; bool isRetryError = true; for ( vector<ChildWriteOp*>::iterator it = _childOps.begin(); it != _childOps.end(); it++ ) { ChildWriteOp* childOp = *it; // Don't do anything till we have all the info if ( childOp->state != WriteOpState_Completed && childOp->state != WriteOpState_Error ) { return; } if ( childOp->state == WriteOpState_Error ) { childErrors.push_back( childOp ); // Any non-retry error aborts all if ( !isRetryErrCode( childOp->error->getErrCode() ) ) isRetryError = false; } } if ( !childErrors.empty() && isRetryError ) { // Since we're using broadcast mode for multi-shard writes, which cannot SCE dassert( childErrors.size() == 1u ); _state = WriteOpState_Ready; } else if ( !childErrors.empty() ) { _error.reset( new BatchedErrorDetail ); combineOpErrors( childErrors, _error.get() ); _state = WriteOpState_Error; } else { _state = WriteOpState_Completed; } // Now that we're done with the child ops, do something with them // TODO: Don't store unlimited history? dassert( _state != WriteOpState_Pending ); _history.insert( _history.end(), _childOps.begin(), _childOps.end() ); _childOps.clear(); }