Ejemplo n.º 1
0
void FeatureCompatibilityVersion::set(OperationContext* txn, StringData version) {
    uassert(40284,
            "featureCompatibilityVersion must be '3.4' or '3.2'",
            version == FeatureCompatibilityVersion::kVersion34 ||
                version == FeatureCompatibilityVersion::kVersion32);

    // Update admin.system.version.
    NamespaceString nss(FeatureCompatibilityVersion::kCollection);
    BSONObjBuilder updateCmd;
    updateCmd.append("update", nss.coll());
    updateCmd.append(
        "updates",
        BSON_ARRAY(BSON("q" << BSON("_id" << FeatureCompatibilityVersion::kParameterName) << "u"
                            << BSON(FeatureCompatibilityVersion::kVersionField << version)
                            << "upsert"
                            << true)));
    updateCmd.append("writeConcern",
                     BSON("w"
                          << "majority"));
    DBDirectClient client(txn);
    BSONObj result;
    client.runCommand(nss.db().toString(), updateCmd.obj(), result);
    uassertStatusOK(getStatusFromCommandResult(result));
    uassertStatusOK(getWriteConcernStatusFromCommandResult(result));

    // Update server parameter.
    if (version == FeatureCompatibilityVersion::kVersion34) {
        serverGlobalParams.featureCompatibilityVersion.store(
            ServerGlobalParams::FeatureCompatibilityVersion_34);
    } else if (version == FeatureCompatibilityVersion::kVersion32) {
        serverGlobalParams.featureCompatibilityVersion.store(
            ServerGlobalParams::FeatureCompatibilityVersion_32);
    }
}
Ejemplo n.º 2
0
Shard::HostWithResponse ShardLocal::_runCommand(OperationContext* txn,
                                                const ReadPreferenceSetting& unused,
                                                const std::string& dbName,
                                                Milliseconds maxTimeMSOverrideUnused,
                                                const BSONObj& cmdObj) {
    repl::OpTime currentOpTimeFromClient =
        repl::ReplClientInfo::forClient(txn->getClient()).getLastOp();
    ON_BLOCK_EXIT([this, &txn, &currentOpTimeFromClient] {
        _updateLastOpTimeFromClient(txn, currentOpTimeFromClient);
    });

    try {
        DBDirectClient client(txn);
        rpc::UniqueReply commandResponse = client.runCommandWithMetadata(
            dbName, cmdObj.firstElementFieldName(), rpc::makeEmptyMetadata(), cmdObj);
        BSONObj responseReply = commandResponse->getCommandReply().getOwned();
        BSONObj responseMetadata = commandResponse->getMetadata().getOwned();

        Status commandStatus = getStatusFromCommandResult(responseReply);
        Status writeConcernStatus = getWriteConcernStatusFromCommandResult(responseReply);

        return Shard::HostWithResponse(boost::none,
                                       Shard::CommandResponse{std::move(responseReply),
                                                              std::move(responseMetadata),
                                                              std::move(commandStatus),
                                                              std::move(writeConcernStatus)});
    } catch (const DBException& ex) {
        return Shard::HostWithResponse(boost::none, ex.toStatus());
    }
}
Ejemplo n.º 3
0
StatusWith<Shard::CommandResponse> ShardLocal::_runCommand(OperationContext* txn,
                                                           const ReadPreferenceSetting& unused,
                                                           const std::string& dbName,
                                                           const BSONObj& cmdObj) {
    try {
        DBDirectClient client(txn);
        rpc::UniqueReply commandResponse = client.runCommandWithMetadata(
            dbName, cmdObj.firstElementFieldName(), rpc::makeEmptyMetadata(), cmdObj);
        BSONObj responseReply = commandResponse->getCommandReply().getOwned();
        BSONObj responseMetadata = commandResponse->getMetadata().getOwned();

        Status commandStatus = getStatusFromCommandResult(responseReply);
        Status writeConcernStatus = kInternalErrorStatus;
        if (commandStatus.isOK()) {
            writeConcernStatus = getWriteConcernStatusFromCommandResult(responseReply);
        }

        return Shard::CommandResponse{std::move(responseReply),
                                      std::move(responseMetadata),
                                      std::move(commandStatus),
                                      std::move(writeConcernStatus)};
    } catch (const DBException& ex) {
        return ex.toStatus();
    }
}
Ejemplo n.º 4
0
void AsyncRequestsSender::_scheduleRequests() {
    invariant(!_stopRetrying);
    // Schedule remote work on hosts for which we have not sent a request or need to retry.
    for (size_t i = 0; i < _remotes.size(); ++i) {
        auto& remote = _remotes[i];

        // First check if the remote had a retriable error, and if so, clear its response field so
        // it will be retried.
        if (remote.swResponse && !remote.done) {
            // We check both the response status and command status for a retriable error.
            Status status = remote.swResponse->getStatus();
            if (status.isOK()) {
                status = getStatusFromCommandResult(remote.swResponse->getValue().data);
            }

            if (status.isOK()) {
                status = getWriteConcernStatusFromCommandResult(remote.swResponse->getValue().data);
            }

            if (!status.isOK()) {
                // There was an error with either the response or the command.
                auto shard = remote.getShard();
                if (!shard) {
                    remote.swResponse =
                        Status(ErrorCodes::ShardNotFound,
                               str::stream() << "Could not find shard " << remote.shardId);
                } else {
                    if (remote.shardHostAndPort) {
                        shard->updateReplSetMonitor(*remote.shardHostAndPort, status);
                    }
                    if (shard->isRetriableError(status.code(), _retryPolicy) &&
                        remote.retryCount < kMaxNumFailedHostRetryAttempts) {
                        LOG(1) << "Command to remote " << remote.shardId << " at host "
                               << *remote.shardHostAndPort
                               << " failed with retriable error and will be retried "
                               << causedBy(redact(status));
                        ++remote.retryCount;
                        remote.swResponse.reset();
                    }
                }
            }
        }

        // If the remote does not have a response or pending request, schedule remote work for it.
        if (!remote.swResponse && !remote.cbHandle.isValid()) {
            auto scheduleStatus = _scheduleRequest(i);
            if (!scheduleStatus.isOK()) {
                remote.swResponse = std::move(scheduleStatus);

                // Push a noop response to the queue to indicate that a remote is ready for
                // re-processing due to failure.
                _responseQueue.producer.push(boost::none);
            }
        }
    }
}
Ejemplo n.º 5
0
void FeatureCompatibilityVersion::set(OperationContext* txn, StringData version) {
    uassert(40284,
            "featureCompatibilityVersion must be '3.4' or '3.2'. See "
            "http://dochub.mongodb.org/core/3.4-feature-compatibility.",
            version == FeatureCompatibilityVersionCommandParser::kVersion34 ||
                version == FeatureCompatibilityVersionCommandParser::kVersion32);

    DBDirectClient client(txn);
    NamespaceString nss(FeatureCompatibilityVersion::kCollection);

    if (version == FeatureCompatibilityVersionCommandParser::kVersion34) {
        // We build a v=2 index on the "admin.system.version" collection as part of setting the
        // featureCompatibilityVersion to 3.4. This is a new index version that isn't supported by
        // versions of MongoDB earlier than 3.4 that will cause 3.2 secondaries to crash when it is
        // replicated.
        std::vector<BSONObj> indexSpecs{k32IncompatibleIndexSpec};

        {
            ScopedTransaction transaction(txn, MODE_IX);
            AutoGetOrCreateDb autoDB(txn, nss.db(), MODE_X);

            uassert(ErrorCodes::NotMaster,
                    str::stream() << "Cannot set featureCompatibilityVersion to '" << version
                                  << "'. Not primary while attempting to create index on: "
                                  << nss.ns(),
                    repl::ReplicationCoordinator::get(txn->getServiceContext())
                        ->canAcceptWritesFor(nss));

            IndexBuilder builder(k32IncompatibleIndexSpec, false);
            auto status = builder.buildInForeground(txn, autoDB.getDb());
            uassertStatusOK(status);

            MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN {
                WriteUnitOfWork wuow(txn);
                getGlobalServiceContext()->getOpObserver()->onCreateIndex(
                    txn, autoDB.getDb()->getSystemIndexesName(), k32IncompatibleIndexSpec, false);
                wuow.commit();
            }
            MONGO_WRITE_CONFLICT_RETRY_LOOP_END(txn, "FeatureCompatibilityVersion::set", nss.ns());
        }

        // We then update the featureCompatibilityVersion document stored in the
        // "admin.system.version" collection. We do this after creating the v=2 index in order to
        // maintain the invariant that if the featureCompatibilityVersion is 3.4, then
        // 'k32IncompatibleIndexSpec' index exists on the "admin.system.version" collection.
        BSONObj updateResult;
        client.runCommand(nss.db().toString(),
                          makeUpdateCommand(version, WriteConcernOptions::Majority),
                          updateResult);
        uassertStatusOK(getStatusFromCommandResult(updateResult));
        uassertStatusOK(getWriteConcernStatusFromCommandResult(updateResult));

        // We then update the value of the featureCompatibilityVersion server parameter.
        serverGlobalParams.featureCompatibility.version.store(
            ServerGlobalParams::FeatureCompatibility::Version::k34);
    } else if (version == FeatureCompatibilityVersionCommandParser::kVersion32) {
Status getStatusFromWriteCommandReply(const BSONObj& cmdResponse) {
    auto status = getStatusFromCommandResult(cmdResponse);
    if (!status.isOK()) {
        return status;
    }
    status = getFirstWriteErrorStatusFromCommandResult(cmdResponse);
    if (!status.isOK()) {
        return status;
    }
    return getWriteConcernStatusFromCommandResult(cmdResponse);
}
StatusWith<Shard::CommandResponse> ShardingCatalogManagerImpl::_runCommandForAddShard(
    OperationContext* txn,
    RemoteCommandTargeter* targeter,
    const std::string& dbName,
    const BSONObj& cmdObj) {
    auto host = targeter->findHost(ReadPreferenceSetting{ReadPreference::PrimaryOnly},
                                   RemoteCommandTargeter::selectFindHostMaxWaitTime(txn));
    if (!host.isOK()) {
        return host.getStatus();
    }

    executor::RemoteCommandRequest request(
        host.getValue(), dbName, cmdObj, rpc::makeEmptyMetadata(), Seconds(30));
    StatusWith<executor::RemoteCommandResponse> swResponse =
        Status(ErrorCodes::InternalError, "Internal error running command");

    auto callStatus = _executorForAddShard->scheduleRemoteCommand(
    request, [&swResponse](const executor::TaskExecutor::RemoteCommandCallbackArgs& args) {
        swResponse = args.response;
    });
    if (!callStatus.isOK()) {
        return callStatus.getStatus();
    }

    // Block until the command is carried out
    _executorForAddShard->wait(callStatus.getValue());

    if (!swResponse.isOK()) {
        if (swResponse.getStatus().compareCode(ErrorCodes::ExceededTimeLimit)) {
            LOG(0) << "Operation for addShard timed out with status " << swResponse.getStatus();
        }
        return swResponse.getStatus();
    }

    BSONObj responseObj = swResponse.getValue().data.getOwned();
    BSONObj responseMetadata = swResponse.getValue().metadata.getOwned();
    Status commandStatus = getStatusFromCommandResult(responseObj);
    Status writeConcernStatus = getWriteConcernStatusFromCommandResult(responseObj);

    return Shard::CommandResponse(std::move(responseObj),
                                  std::move(responseMetadata),
                                  std::move(commandStatus),
                                  std::move(writeConcernStatus));
}
Ejemplo n.º 8
0
StatusWith<Shard::CommandResponse> RSLocalClient::runCommandOnce(OperationContext* opCtx,
                                                                 StringData dbName,
                                                                 const BSONObj& cmdObj) {
    const auto currentOpTimeFromClient =
        repl::ReplClientInfo::forClient(opCtx->getClient()).getLastOp();
    ON_BLOCK_EXIT([this, &opCtx, &currentOpTimeFromClient] {
        _updateLastOpTimeFromClient(opCtx, currentOpTimeFromClient);
    });

    try {
        DBDirectClient client(opCtx);

        rpc::UniqueReply commandResponse =
            client.runCommand(OpMsgRequest::fromDBAndBody(dbName, cmdObj));

        auto result = commandResponse->getCommandReply().getOwned();
        return Shard::CommandResponse(boost::none,
                                      result,
                                      getStatusFromCommandResult(result),
                                      getWriteConcernStatusFromCommandResult(result));
    } catch (const DBException& ex) {
        return ex.toStatus();
    }
}
StatusWith<Shard::CommandResponse> ShardingCatalogManager::_runCommandForAddShard(
    OperationContext* opCtx,
    RemoteCommandTargeter* targeter,
    StringData dbName,
    const BSONObj& cmdObj) {
    auto swHost = targeter->findHost(opCtx, ReadPreferenceSetting{ReadPreference::PrimaryOnly});
    if (!swHost.isOK()) {
        return swHost.getStatus();
    }
    auto host = std::move(swHost.getValue());

    executor::RemoteCommandRequest request(
        host, dbName.toString(), cmdObj, rpc::makeEmptyMetadata(), nullptr, Seconds(30));

    executor::RemoteCommandResponse response =
        Status(ErrorCodes::InternalError, "Internal error running command");

    auto swCallbackHandle = _executorForAddShard->scheduleRemoteCommand(
        request, [&response](const executor::TaskExecutor::RemoteCommandCallbackArgs& args) {
            response = args.response;
        });
    if (!swCallbackHandle.isOK()) {
        return swCallbackHandle.getStatus();
    }

    // Block until the command is carried out
    _executorForAddShard->wait(swCallbackHandle.getValue());

    if (response.status == ErrorCodes::ExceededTimeLimit) {
        LOG(0) << "Operation timed out with status " << redact(response.status);
    }

    if (!response.isOK()) {
        if (!Shard::shouldErrorBePropagated(response.status.code())) {
            return {ErrorCodes::OperationFailed,
                    str::stream() << "failed to run command " << cmdObj
                                  << " when attempting to add shard "
                                  << targeter->connectionString().toString()
                                  << causedBy(response.status)};
        }
        return response.status;
    }

    BSONObj result = response.data.getOwned();

    Status commandStatus = getStatusFromCommandResult(result);
    if (!Shard::shouldErrorBePropagated(commandStatus.code())) {
        commandStatus = {ErrorCodes::OperationFailed,
                         str::stream() << "failed to run command " << cmdObj
                                       << " when attempting to add shard "
                                       << targeter->connectionString().toString()
                                       << causedBy(commandStatus)};
    }

    Status writeConcernStatus = getWriteConcernStatusFromCommandResult(result);
    if (!Shard::shouldErrorBePropagated(writeConcernStatus.code())) {
        writeConcernStatus = {ErrorCodes::OperationFailed,
                              str::stream() << "failed to satisfy writeConcern for command "
                                            << cmdObj
                                            << " when attempting to add shard "
                                            << targeter->connectionString().toString()
                                            << causedBy(writeConcernStatus)};
    }

    return Shard::CommandResponse(std::move(host),
                                  std::move(result),
                                  std::move(commandStatus),
                                  std::move(writeConcernStatus));
}