void appendWriteConcernErrorToCmdResponse(const std::string& shardID, const BSONElement& wcErrorElem, BSONObjBuilder& responseBuilder) { WCErrorDetail wcError; std::string errMsg; auto wcErrorObj = wcErrorElem.Obj(); if (!wcError.parseBSON(wcErrorObj, &errMsg)) { wcError.setErrMessage("Failed to parse writeConcernError: " + wcErrorObj.toString() + ", Received error: " + errMsg); } wcError.setErrMessage(wcError.getErrMessage() + " at " + shardID); responseBuilder.append("writeConcernError", wcError.toBSON()); }
void Command::appendCommandWCStatus(BSONObjBuilder& result, const Status& status) { if (!status.isOK()) { WCErrorDetail wcError; wcError.setErrCode(status.code()); wcError.setErrMessage(status.reason()); result.append("writeConcernError", wcError.toBSON()); } }
void Command::appendCommandWCStatus(BSONObjBuilder& result, const Status& awaitReplicationStatus, const WriteConcernResult& wcResult) { if (!awaitReplicationStatus.isOK() && !result.hasField("writeConcernError")) { WCErrorDetail wcError; wcError.setErrCode(awaitReplicationStatus.code()); wcError.setErrMessage(awaitReplicationStatus.reason()); if (wcResult.wTimedOut) { wcError.setErrInfo(BSON("wtimeout" << true)); } result.append("writeConcernError", wcError.toBSON()); } }
void BatchWriteOp::buildClientResponse(BatchedCommandResponse* batchResp) { dassert(isFinished()); // Result is OK batchResp->setOk(true); // For non-verbose, it's all we need. if (!_clientRequest->isVerboseWC()) { dassert(batchResp->isValid(NULL)); return; } // // Find all the errors in the batch // vector<WriteOp*> errOps; size_t numWriteOps = _clientRequest->sizeWriteOps(); for (size_t i = 0; i < numWriteOps; ++i) { WriteOp& writeOp = _writeOps[i]; if (writeOp.getWriteState() == WriteOpState_Error) { errOps.push_back(&writeOp); } } // // Build the per-item errors. // if (!errOps.empty()) { for (vector<WriteOp*>::iterator it = errOps.begin(); it != errOps.end(); ++it) { WriteOp& writeOp = **it; WriteErrorDetail* error = new WriteErrorDetail(); writeOp.getOpError().cloneTo(error); batchResp->addToErrDetails(error); } } // Only return a write concern error if everything succeeded (unordered or ordered) // OR if something succeeded and we're unordered bool reportWCError = errOps.empty() || (!_clientRequest->getOrdered() && errOps.size() < _clientRequest->sizeWriteOps()); if (!_wcErrors.empty() && reportWCError) { WCErrorDetail* error = new WCErrorDetail; // Generate the multi-error message below stringstream msg; if (_wcErrors.size() > 1) { msg << "multiple errors reported : "; error->setErrCode(ErrorCodes::WriteConcernFailed); } else { error->setErrCode((*_wcErrors.begin())->error.getErrCode()); } for (vector<ShardWCError*>::const_iterator it = _wcErrors.begin(); it != _wcErrors.end(); ++it) { const ShardWCError* wcError = *it; if (it != _wcErrors.begin()) msg << " :: and :: "; msg << wcError->error.getErrMessage() << " at " << wcError->endpoint.shardName; } error->setErrMessage(msg.str()); batchResp->setWriteConcernError(error); } // // Append the upserted ids, if required // if (_upsertedIds.size() != 0) { batchResp->setUpsertDetails(_upsertedIds.vector()); } // Stats int nValue = _stats->numInserted + _stats->numUpserted + _stats->numMatched + _stats->numDeleted; batchResp->setN(nValue); if (_clientRequest->getBatchType() == BatchedCommandRequest::BatchType_Update && _stats->numModified >= 0) { batchResp->setNModified(_stats->numModified); } dassert(batchResp->isValid(NULL)); }