예제 #1
0
    void BatchWriteOp::noteBatchResponse( const TargetedWriteBatch& targetedBatch,
                                          const BatchedCommandResponse& response,
                                          TrackedErrors* trackedErrors ) {

        if ( !response.getOk() ) {

            WriteErrorDetail error;
            cloneCommandErrorTo( response, &error );

            // Treat command errors exactly like other failures of the batch
            // Note that no errors will be tracked from these failures - as-designed
            noteBatchError( targetedBatch, error );
            return;
        }

        dassert( response.getOk() );

        // Stop tracking targeted batch
        _targeted.erase( &targetedBatch );

        // Increment stats for this batch
        incBatchStats( _clientRequest->getBatchType(), response, _stats.get() );

        //
        // Assign errors to particular items.
        // Write Concern errors are stored and handled later.
        //

        // Special handling for write concern errors, save for later
        if ( response.isWriteConcernErrorSet() ) {
            auto_ptr<ShardWCError> wcError( new ShardWCError( targetedBatch.getEndpoint(),
                                                              *response.getWriteConcernError() ));
            _wcErrors.mutableVector().push_back( wcError.release() );
        }

        vector<WriteErrorDetail*> itemErrors;

        // 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(), WriteErrorDetailComp() );
        }

        //
        // 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
        //
        // If the batch is ordered, cancel all writes after the first error for retargeting.
        //

        bool ordered = _clientRequest->getOrdered();

        vector<WriteErrorDetail*>::iterator itemErrorIt = itemErrors.begin();
        int index = 0;
        WriteErrorDetail* lastError = NULL;
        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
            WriteErrorDetail* writeError = NULL;

            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 ) {
                if ( !ordered || !lastError ){
                    writeOp.noteWriteComplete( *write );
                }
                else {
                    // We didn't actually apply this write - cancel so we can retarget
                    dassert( writeOp.getNumTargeted() == 1u );
                    writeOp.cancelWrites( lastError );
                }
            }
            else {
                writeOp.noteWriteError( *write, *writeError );
                lastError = writeError;
            }
        }

        // Track errors we care about, whether batch or individual errors
        if ( NULL != trackedErrors ) {
            trackErrors( targetedBatch.getEndpoint(), itemErrors, trackedErrors );
        }

        // Track upserted ids if we need to
        if ( response.isUpsertDetailsSet() ) {

            const vector<BatchedUpsertDetail*>& upsertedIds = response.getUpsertDetails();
            for ( vector<BatchedUpsertDetail*>::const_iterator it = upsertedIds.begin();
                it != upsertedIds.end(); ++it ) {

                // The child upserted details don't have the correct index for the full batch
                const BatchedUpsertDetail* childUpsertedId = *it;

                // Work backward from the child batch item index to the batch item index
                int childBatchIndex = childUpsertedId->getIndex();
                int batchIndex = targetedBatch.getWrites()[childBatchIndex]->writeOpRef.first;

                // Push the upserted id with the correct index into the batch upserted ids
                BatchedUpsertDetail* upsertedId = new BatchedUpsertDetail;
                upsertedId->setIndex( batchIndex );
                upsertedId->setUpsertedID( childUpsertedId->getUpsertedID() );
                _upsertedIds.mutableVector().push_back( upsertedId );
            }
        }
    }
예제 #2
0
    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 );
    }