Beispiel #1
0
    static void incBatchStats( BatchedCommandRequest::BatchType batchType,
                               const BatchedCommandResponse& response,
                               BatchWriteStats* stats ) {

        if ( batchType == BatchedCommandRequest::BatchType_Insert) {
            stats->numInserted += response.getN();
        }
        else if ( batchType == BatchedCommandRequest::BatchType_Update ) {
            int numUpserted = 0;
            if( response.isUpsertDetailsSet() ) {
                numUpserted = response.sizeUpsertDetails();
            }
            stats->numMatched += ( response.getN() - numUpserted );
            long long numModified = response.getNModified();

            if (numModified >= 0)
                stats->numModified += numModified;
            else
                stats->numModified = -1; // sentinel used to indicate we omit the field downstream

            stats->numUpserted += numUpserted;
        }
        else {
            dassert( batchType == BatchedCommandRequest::BatchType_Delete );
            stats->numDeleted += response.getN();
        }
    }
    static bool areResponsesEqual( const BatchedCommandResponse& responseA,
                                   const BatchedCommandResponse& responseB ) {

        // TODO: Better reporting of why not equal
        if ( responseA.getOk() != responseB.getOk() )
            return false;
        if ( responseA.getN() != responseB.getN() )
            return false;
        if ( responseA.isSingleUpsertedSet() != responseB.isSingleUpsertedSet() )
            return false;
        if ( responseA.isUpsertDetailsSet() != responseB.isUpsertDetailsSet() )
            return false;

        if ( responseA.isSingleUpsertedSet() ) {
            BSONObj upsertA = responseA.getSingleUpserted();
            BSONObj upsertB = responseB.getSingleUpserted();
            if ( upsertA.woCompare( upsertB ) != 0 )
                return false;
        }

        if ( responseA.isUpsertDetailsSet() ) {
            // TODO:
        }

        if ( responseA.getOk() )
            return true;

        // TODO: Compare errors here

        return true;
    }
    static bool areResponsesEqual( const BatchedCommandResponse& responseA,
                                   const BatchedCommandResponse& responseB ) {

        // TODO: Better reporting of why not equal
        if ( responseA.getOk() != responseB.getOk() )
            return false;
        if ( responseA.getN() != responseB.getN() )
            return false;
        if ( responseA.isUpsertDetailsSet() != responseB.isUpsertDetailsSet() )
            return false;

        if ( responseA.isUpsertDetailsSet() ) {
            // TODO:
        }

        if ( responseA.getOk() )
            return true;

        // TODO: Compare errors here

        return true;
    }
    Status AuthzManagerExternalStateMongos::remove(
            const NamespaceString& collectionName,
            const BSONObj& query,
            const BSONObj& writeConcern,
            int* numRemoved) {
        BatchedCommandResponse response;
        Status res = clusterDelete(collectionName, query, 0 /* limit */, writeConcern, &response);

        if (res.isOK()) {
            *numRemoved = response.getN();
        }

        return res;
    }
Beispiel #5
0
    static bool areResponsesEqual( const BatchedCommandResponse& responseA,
                                   const BatchedCommandResponse& responseB ) {

        // Note: This needs to also take into account comparing responses from legacy writes
        // and write commands.

        // TODO: Better reporting of why not equal
        if ( responseA.getOk() != responseB.getOk() )
            return false;
        if ( responseA.getN() != responseB.getN() )
            return false;

        if ( responseA.isUpsertDetailsSet() ) {
            // TODO:
        }

        if ( responseA.getOk() )
            return true;

        // TODO: Compare errors here

        return true;
    }
    Status AuthzManagerExternalStateMongos::update(const NamespaceString& collectionName,
                                                   const BSONObj& query,
                                                   const BSONObj& updatePattern,
                                                   bool upsert,
                                                   bool multi,
                                                   const BSONObj& writeConcern,
                                                   int* nMatched) {
        BatchedCommandResponse response;
        Status res = clusterUpdate(collectionName,
                query,
                updatePattern,
                upsert,
                multi,
                writeConcern,
                &response);

        if (res.isOK()) {
            *nMatched = response.getN();
        }

        return res;
    }
bool batchErrorToLastError(const BatchedCommandRequest& request,
                           const BatchedCommandResponse& response,
                           LastError* error) {
    unique_ptr<WriteErrorDetail> commandError;
    WriteErrorDetail* lastBatchError = NULL;

    if (!response.getOk()) {
        // Command-level error, all writes failed

        commandError.reset(new WriteErrorDetail);
        buildErrorFromResponse(response, commandError.get());
        lastBatchError = commandError.get();
    } else if (response.isErrDetailsSet()) {
        // The last error in the batch is always reported - this matches expected COE
        // semantics for insert batches. For updates and deletes, error is only reported
        // if the error was on the last item.

        const bool lastOpErrored = response.getErrDetails().back()->getIndex() ==
            static_cast<int>(request.sizeWriteOps() - 1);
        if (request.getBatchType() == BatchedCommandRequest::BatchType_Insert || lastOpErrored) {
            lastBatchError = response.getErrDetails().back();
        }
    } else {
        // We don't care about write concern errors, these happen in legacy mode in GLE.
    }

    // Record an error if one exists
    if (lastBatchError) {
        string errMsg = lastBatchError->getErrMessage();
        error->setLastError(lastBatchError->getErrCode(),
                            errMsg.empty() ? "see code for details" : errMsg.c_str());
        return true;
    }

    // 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.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.isUpsertDetailsSet())
            numUpserted = response.sizeUpsertDetails();

        int numMatched = response.getN() - numUpserted;
        dassert(numMatched >= 0);

        // Wrap upserted id in "upserted" field
        BSONObj leUpsertedId;
        if (!upsertedId.isEmpty())
            leUpsertedId = upsertedId.firstElement().wrap(kUpsertedFieldName);

        error->recordUpdate(numMatched > 0, response.getN(), leUpsertedId);
    } else if (request.getBatchType() == BatchedCommandRequest::BatchType_Delete) {
        error->recordDelete(response.getN());
    }

    return false;
}
Status CatalogManagerReplicaSet::initConfigVersion(OperationContext* txn) {
    for (int x = 0; x < kMaxConfigVersionInitRetry; x++) {
        auto versionStatus = _getConfigVersion(txn);
        if (!versionStatus.isOK()) {
            return versionStatus.getStatus();
        }

        auto versionInfo = versionStatus.getValue();
        if (versionInfo.getMinCompatibleVersion() > CURRENT_CONFIG_VERSION) {
            return {ErrorCodes::IncompatibleShardingConfigVersion,
                    str::stream() << "current version v" << CURRENT_CONFIG_VERSION
                                  << " is older than the cluster min compatible v"
                                  << versionInfo.getMinCompatibleVersion()};
        }

        if (versionInfo.getCurrentVersion() == UpgradeHistory_EmptyVersion) {
            VersionType newVersion;
            newVersion.setClusterId(OID::gen());
            newVersion.setMinCompatibleVersion(MIN_COMPATIBLE_CONFIG_VERSION);
            newVersion.setCurrentVersion(CURRENT_CONFIG_VERSION);

            BSONObj versionObj(newVersion.toBSON());
            BatchedCommandResponse response;
            auto upsertStatus = update(txn,
                                       VersionType::ConfigNS,
                                       versionObj,
                                       versionObj,
                                       true /* upsert*/,
                                       false /* multi */,
                                       &response);

            if ((upsertStatus.isOK() && response.getN() < 1) ||
                upsertStatus == ErrorCodes::DuplicateKey) {
                // Do the check again as someone inserted a new config version document
                // and the upsert neither inserted nor updated a config version document.
                // Note: you can get duplicate key errors on upsert because of SERVER-14322.
                continue;
            }

            return upsertStatus;
        }

        if (versionInfo.getCurrentVersion() == UpgradeHistory_UnreportedVersion) {
            return {ErrorCodes::IncompatibleShardingConfigVersion,
                    "Assuming config data is old since the version document cannot be found in the "
                    "config server and it contains databases aside 'local' and 'admin'. "
                    "Please upgrade if this is the case. Otherwise, make sure that the config "
                    "server is clean."};
        }

        if (versionInfo.getCurrentVersion() < CURRENT_CONFIG_VERSION) {
            return {ErrorCodes::IncompatibleShardingConfigVersion,
                    str::stream() << "need to upgrade current cluster version to v"
                                  << CURRENT_CONFIG_VERSION << "; currently at v"
                                  << versionInfo.getCurrentVersion()};
        }

        return Status::OK();
    }

    return {ErrorCodes::IncompatibleShardingConfigVersion,
            str::stream() << "unable to create new config version document after "
                          << kMaxConfigVersionInitRetry << " retries"};
}
    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() );
        }
    }