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