예제 #1
0
    void BatchSafeWriter::safeWriteBatch( DBClientBase* conn,
                                          const BatchedCommandRequest& request,
                                          BatchedCommandResponse* response ) {

        // N starts at zero, and we add to it for each item
        response->setN( 0 );

        for ( size_t i = 0; i < request.sizeWriteOps(); ++i ) {

            BatchItemRef itemRef( &request, static_cast<int>( i ) );
            LastError lastError;

            _safeWriter->safeWrite( conn, itemRef, &lastError );

            // Register the error if we need to
            BatchedErrorDetail* batchError = lastErrorToBatchError( lastError );
            if ( batchError ) {
                batchError->setIndex( i );
                response->addToErrDetails( batchError );
            }

            response->setN( response->getN() + lastError.nObjects );

            if ( !lastError.upsertedId.isEmpty() ) {
                BatchedUpsertDetail* upsertedId = new BatchedUpsertDetail;
                upsertedId->setIndex( i );
                upsertedId->setUpsertedID( lastError.upsertedId );
                response->addToUpsertDetails( upsertedId );
            }

            // Break on first error if we're ordered
            if ( request.getOrdered() && BatchSafeWriter::isFailedOp( lastError ) ) break;
        }

        if ( request.sizeWriteOps() == 1 && response->isErrDetailsSet()
             && !response->isErrCodeSet() ) {

            // Promote single error to batch error
            const BatchedErrorDetail* error = response->getErrDetailsAt( 0 );
            response->setErrCode( error->getErrCode() );
            if ( error->isErrInfoSet() ) response->setErrInfo( error->getErrInfo() );
            response->setErrMessage( error->getErrMessage() );

            response->unsetErrDetails();
        }

        if ( request.sizeWriteOps() == 1 && response->isUpsertDetailsSet() ) {

            // Promote single upsert to batch upsert
            const BatchedUpsertDetail* upsertedId = response->getUpsertDetailsAt( 0 );
            response->setSingleUpserted( upsertedId->getUpsertedID() );

            response->unsetUpsertDetails();
        }

        response->setOk( !response->isErrCodeSet() );
        dassert( response->isValid( NULL ) );
    }
예제 #2
0
    BatchedErrorDetail* BatchSafeWriter::lastErrorToBatchError( const LastError& lastError ) {

        if ( BatchSafeWriter::isFailedOp( lastError ) ) {
            BatchedErrorDetail* batchError = new BatchedErrorDetail;
            if ( lastError.code != 0 ) batchError->setErrCode( lastError.code );
            else batchError->setErrCode( ErrorCodes::UnknownError );
            batchError->setErrMessage( lastError.msg );
            return batchError;
        }

        return NULL;
    }
예제 #3
0
파일: write_op.cpp 프로젝트: ukd1/mongo
 void WriteOp::setOpError( const BatchedErrorDetail& error ) {
     dassert( _state == WriteOpState_Ready );
     _error.reset( new BatchedErrorDetail );
     error.cloneTo( _error.get() );
     _state = WriteOpState_Error;
     // No need to updateOpState, set directly
 }
예제 #4
0
    void BatchSafeWriter::safeWriteBatch( DBClientBase* conn,
                                          const BatchedCommandRequest& request,
                                          BatchedCommandResponse* response ) {

        for ( size_t i = 0; i < request.sizeWriteOps(); ++i ) {

            BatchItemRef itemRef( &request, static_cast<int>( i ) );
            LastError lastError;

            _safeWriter->safeWrite( conn, itemRef, &lastError );

            // Register the error if we need to
            BatchedErrorDetail* batchError = lastErrorToBatchError( lastError );
            batchError->setIndex( i );
            response->addToErrDetails( batchError );

            // TODO: Other stats, etc.

            // Break on first error if we're ordered
            if ( request.getOrdered() && BatchSafeWriter::isFailedOp( lastError ) ) break;
        }
    }
예제 #5
0
파일: write_op.cpp 프로젝트: ukd1/mongo
    void WriteOp::noteWriteError( const TargetedWrite& targetedWrite,
                                  const BatchedErrorDetail& error ) {

        const WriteOpRef& ref = targetedWrite.writeOpRef;
        ChildWriteOp& childOp = *_childOps.at( ref.second );

        childOp.pendingWrite = NULL;
        childOp.endpoint.reset( new ShardEndpoint( targetedWrite.endpoint ) );
        childOp.error.reset( new BatchedErrorDetail );
        error.cloneTo( childOp.error.get() );
        childOp.state = WriteOpState_Error;
        updateOpState();
    }
예제 #6
0
    BatchedErrorDetail* BatchSafeWriter::lastErrorToBatchError( const LastError& lastError ) {

        bool isFailedOp = lastError.msg != "";
        bool isStaleOp = lastError.writebackId.isSet();
        dassert( !( isFailedOp && isStaleOp ) );

        if ( isFailedOp ) {
            BatchedErrorDetail* batchError = new BatchedErrorDetail;
            if ( lastError.code != 0 ) batchError->setErrCode( lastError.code );
            else batchError->setErrCode( ErrorCodes::UnknownError );
            batchError->setErrMessage( lastError.msg );
            return batchError;
        }
        else if ( isStaleOp ) {
            BatchedErrorDetail* batchError = new BatchedErrorDetail;
            batchError->setErrCode( ErrorCodes::StaleShardVersion );
            batchError->setErrInfo( BSON( "downconvert" << true ) ); // For debugging
            batchError->setErrMessage( "shard version was stale" );
            return batchError;
        }

        return NULL;
    }
예제 #7
0
    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() );
        }
    }
예제 #8
0
 static void cloneBatchErrorFrom( const BatchedErrorDetail& details,
                                  BatchedCommandResponse* response ) {
     response->setErrCode( details.getErrCode() );
     if ( details.isErrInfoSet() ) response->setErrInfo( details.getErrInfo() );
     response->setErrMessage( details.getErrMessage() );
 }