Status WriteOp::targetWrites(OperationContext* opCtx,
                             const NSTargeter& targeter,
                             std::vector<TargetedWrite*>* targetedWrites) {
    auto swEndpoints = [&]() -> StatusWith<std::vector<ShardEndpoint>> {
        if (_itemRef.getOpType() == BatchedCommandRequest::BatchType_Insert) {
            auto swEndpoint = targeter.targetInsert(opCtx, _itemRef.getDocument());
            if (!swEndpoint.isOK())
                return swEndpoint.getStatus();

            return std::vector<ShardEndpoint>{std::move(swEndpoint.getValue())};
        } else if (_itemRef.getOpType() == BatchedCommandRequest::BatchType_Update) {
            return targeter.targetUpdate(opCtx, _itemRef.getUpdate());
        } else if (_itemRef.getOpType() == BatchedCommandRequest::BatchType_Delete) {
            return targeter.targetDelete(opCtx, _itemRef.getDelete());
        } else {
            MONGO_UNREACHABLE;
        }
    }();

    // Unless executing as part of a transaction, if we're targeting more than one endpoint with an
    // update/delete, we have to target everywhere since we cannot currently retry partial results.
    //
    // NOTE: Index inserts are currently specially targeted only at the current collection to avoid
    // creating collections everywhere.
    const bool inTransaction = TransactionRouter::get(opCtx) != nullptr;
    if (swEndpoints.isOK() && swEndpoints.getValue().size() > 1u && !inTransaction) {
        swEndpoints = targeter.targetAllShards(opCtx);
    }

    // If we had an error, stop here
    if (!swEndpoints.isOK())
        return swEndpoints.getStatus();

    auto& endpoints = swEndpoints.getValue();

    for (auto&& endpoint : endpoints) {
        _childOps.emplace_back(this);

        WriteOpRef ref(_itemRef.getItemIndex(), _childOps.size() - 1);

        // Outside of a transaction, multiple endpoints currently imply no versioning, since we
        // can't retry half a regular multi-write.
        if (endpoints.size() > 1u && !inTransaction) {
            endpoint.shardVersion = ChunkVersion::IGNORED();
        }

        targetedWrites->push_back(new TargetedWrite(std::move(endpoint), ref));

        _childOps.back().pendingWrite = targetedWrites->back();
        _childOps.back().state = WriteOpState_Pending;
    }

    _state = WriteOpState_Pending;
    return Status::OK();
}
Exemplo n.º 2
0
    Status WriteOp::targetWrites( const NSTargeter& targeter,
                                  std::vector<TargetedWrite*>* targetedWrites ) {

        bool isUpdate = _itemRef.getOpType() == BatchedCommandRequest::BatchType_Update;
        bool isDelete = _itemRef.getOpType() == BatchedCommandRequest::BatchType_Delete;

        // In case of error, don't leak.
        OwnedPointerVector<ShardEndpoint> endpointsOwned;
        vector<ShardEndpoint*>& endpoints = endpointsOwned.mutableVector();

        if ( isUpdate || isDelete ) {

            // Updates/deletes targeted by query

            BSONObj queryDoc =
                isUpdate ? _itemRef.getUpdate()->getQuery() : _itemRef.getDelete()->getQuery();

            Status targetStatus = targeter.targetQuery( queryDoc, &endpoints );

            if ( targetStatus.isOK() ) {
                targetStatus =
                    isUpdate ?
                        updateTargetsOk( *this, endpoints ) : deleteTargetsOk( *this, endpoints );
            }

            if ( !targetStatus.isOK() ) return targetStatus;
        }
        else {
            dassert( _itemRef.getOpType() == BatchedCommandRequest::BatchType_Insert );

            // Inserts targeted by doc itself

            ShardEndpoint* endpoint = NULL;
            Status targetStatus = targeter.targetDoc( _itemRef.getDocument(), &endpoint );

            if ( !targetStatus.isOK() ) {
                dassert( NULL == endpoint );
                return targetStatus;
            }

            dassert( NULL != endpoint );
            endpoints.push_back( endpoint );
        }

        for ( vector<ShardEndpoint*>::iterator it = endpoints.begin(); it != endpoints.end();
            ++it ) {

            ShardEndpoint* endpoint = *it;

            _childOps.push_back( new ChildWriteOp( this ) );

            WriteOpRef ref( _itemRef.getItemIndex(), _childOps.size() - 1 );

            // For now, multiple endpoints imply no versioning
            if ( endpoints.size() == 1u ) {
                targetedWrites->push_back( new TargetedWrite( *endpoint, ref ) );
            }
            else {
                ShardEndpoint broadcastEndpoint( endpoint->shardName,
                                                 ChunkVersion::IGNORED(),
                                                 endpoint->shardHost );
                targetedWrites->push_back( new TargetedWrite( broadcastEndpoint, ref ) );
            }

            _childOps.back()->pendingWrite = targetedWrites->back();
            _childOps.back()->state = WriteOpState_Pending;
        }

        _state = WriteOpState_Pending;
        return Status::OK();
    }
Exemplo n.º 3
0
Status WriteOp::targetWrites( const NSTargeter& targeter,
                              std::vector<TargetedWrite*>* targetedWrites ) {

    bool isUpdate = _itemRef.getOpType() == BatchedCommandRequest::BatchType_Update;
    bool isDelete = _itemRef.getOpType() == BatchedCommandRequest::BatchType_Delete;
    bool isIndexInsert = _itemRef.getRequest()->isInsertIndexRequest();

    Status targetStatus = Status::OK();
    OwnedPointerVector<ShardEndpoint> endpointsOwned;
    vector<ShardEndpoint*>& endpoints = endpointsOwned.mutableVector();

    if ( isUpdate ) {
        targetStatus = targeter.targetUpdate( *_itemRef.getUpdate(), &endpoints );
    }
    else if ( isDelete ) {
        targetStatus = targeter.targetDelete( *_itemRef.getDelete(), &endpoints );
    }
    else {
        dassert( _itemRef.getOpType() == BatchedCommandRequest::BatchType_Insert );

        ShardEndpoint* endpoint = NULL;
        // TODO: Remove the index targeting stuff once there is a command for it
        if ( !isIndexInsert ) {
            targetStatus = targeter.targetInsert( _itemRef.getDocument(), &endpoint );
        }
        else {
            // TODO: Retry index writes with stale version?
            targetStatus = targeter.targetAll( &endpoints );
        }

        if ( !targetStatus.isOK() ) {
            dassert( NULL == endpoint );
            return targetStatus;
        }

        // Store single endpoint result if we targeted a single endpoint
        if ( endpoint ) endpoints.push_back( endpoint );
    }

    // If we had an error, stop here
    if ( !targetStatus.isOK() ) return targetStatus;

    for ( vector<ShardEndpoint*>::iterator it = endpoints.begin(); it != endpoints.end();
            ++it ) {

        ShardEndpoint* endpoint = *it;

        _childOps.push_back( new ChildWriteOp( this ) );

        WriteOpRef ref( _itemRef.getItemIndex(), _childOps.size() - 1 );

        // For now, multiple endpoints imply no versioning
        if ( endpoints.size() == 1u ) {
            targetedWrites->push_back( new TargetedWrite( *endpoint, ref ) );
        }
        else {
            ShardEndpoint broadcastEndpoint( endpoint->shardName,
                                             ChunkVersion::IGNORED() );
            targetedWrites->push_back( new TargetedWrite( broadcastEndpoint, ref ) );
        }

        _childOps.back()->pendingWrite = targetedWrites->back();
        _childOps.back()->state = WriteOpState_Pending;
    }

    _state = WriteOpState_Pending;
    return Status::OK();
}