Search in sources :

Example 1 with ReplicaSetConfig

use of com.torodb.mongodb.commands.pojos.ReplicaSetConfig in project torodb by torodb.

the class TopologyCoordinator method processHeartbeatResponse.

/**
   * Processes a heartbeat response from "target" that arrived around "now", having spent
   * "networkRoundTripTime" millis on the network.
   * <p>
   * Updates internal topology coordinator state, and returns instructions about what action to take
   * next.
   * <p>
   * If the next action is {@link HeartbeatResponseAction#makeNoAction() "NoAction"} then nothing
   * has to be done.
   * <p>
   * If the next action indicates {@link HeartbeatResponseAction#makeReconfigAction() "Reconfig"},
   * the caller should verify the configuration in hbResponse is acceptable, perform any other
   * reconfiguration actions it must, and call
   * {@link #updateConfig(
   * com.eightkdata.mongowp.mongoserver.api.safe.library.v3m0.pojos.ReplicaSetConfig,
   * java.time.Instant, com.eightkdata.mongowp.OpTime) updateConfig}
   * with the appropiate arguments.
   * <p>
   * This call should be paired (with intervening network communication) with a call to
   * prepareHeartbeatRequest for the same "target".
   *
   * @param now                  the aproximated time when the response has been recived
   * @param networkRoundTripTime the time spent on network
   * @param target               the host that send the respond
   * @param hbResponse
   */
HeartbeatResponseAction processHeartbeatResponse(Instant now, Duration networkRoundTripTime, HostAndPort target, RemoteCommandResponse<ReplSetHeartbeatReply> hbResponse) {
    PingStats hbStats = getPingOrDefault(target);
    Preconditions.checkState(hbStats.getLastHeartbeatStartDate() != null, "It seems that a hb " + "response has been recived before it has been prepared");
    if (!hbResponse.isOk()) {
        hbStats.miss();
    } else {
        hbStats.hit(networkRoundTripTime);
    }
    boolean isUnauthorized = (hbResponse.getErrorCode() == ErrorCode.UNAUTHORIZED) || (hbResponse.getErrorCode() == ErrorCode.AUTHENTICATION_FAILED);
    Duration alreadyElapsed = Duration.between(hbStats.getLastHeartbeatStartDate(), now);
    Duration nextHeartbeatDelay;
    // determine next start time
    if (_rsConfig != null && (hbStats.getNumFailuresSinceLastStart() <= MAX_HEARTBEAT_RETRIES) && (alreadyElapsed.toMillis() < _rsConfig.getHeartbeatTimeoutPeriod())) {
        if (isUnauthorized) {
            nextHeartbeatDelay = HEARTBEAT_INTERVAL;
        } else {
            nextHeartbeatDelay = Duration.ZERO;
        }
    } else {
        nextHeartbeatDelay = HEARTBEAT_INTERVAL;
    }
    Optional<ReplSetHeartbeatReply> commandReply = hbResponse.getCommandReply();
    if (hbResponse.isOk() && commandReply.get().getConfig().isPresent()) {
        long currentConfigVersion = _rsConfig != null ? _rsConfig.getConfigVersion() : -2;
        ReplicaSetConfig newConfig = commandReply.get().getConfig().get();
        assert newConfig != null;
        if (newConfig.getConfigVersion() > currentConfigVersion) {
            HeartbeatResponseAction nextAction = HeartbeatResponseAction.makeReconfigAction().setNextHeartbeatDelay(nextHeartbeatDelay);
            return nextAction;
        } else {
            // target erroneously sent us one, even through it isn't newer.
            if (newConfig.getConfigVersion() < currentConfigVersion) {
                LOGGER.debug("Config version from heartbeat was older than ours.");
                LOGGER.trace("Current config: {}. Config from heartbeat: {}", _rsConfig, newConfig);
            } else {
                LOGGER.trace("Config from heartbeat response was same as ours.");
            }
        }
    }
    // so return early.
    if (_rsConfig == null) {
        HeartbeatResponseAction nextAction = HeartbeatResponseAction.makeNoAction();
        nextAction.setNextHeartbeatDelay(nextHeartbeatDelay);
        return nextAction;
    }
    OptionalInt memberIndexOpt = _rsConfig.findMemberIndexByHostAndPort(target);
    if (!memberIndexOpt.isPresent()) {
        LOGGER.debug("replset: Could not find {} in current config so ignoring --" + " current config: {}", target, _rsConfig);
        HeartbeatResponseAction nextAction = HeartbeatResponseAction.makeNoAction();
        nextAction.setNextHeartbeatDelay(nextHeartbeatDelay);
        return nextAction;
    }
    assert memberIndexOpt.isPresent();
    int memberIndex = memberIndexOpt.getAsInt();
    MemberHeartbeatData hbData = _hbdata.get(memberIndex);
    assert hbData != null;
    MemberConfig member = _rsConfig.getMembers().get(memberIndex);
    if (!hbResponse.isOk()) {
        if (isUnauthorized) {
            LOGGER.debug("setAuthIssue: heartbeat response failed due to authentication" + " issue for member _id: {}", member.getId());
            hbData.setAuthIssue(now);
        } else if (hbStats.getNumFailuresSinceLastStart() > MAX_HEARTBEAT_RETRIES || alreadyElapsed.toMillis() >= _rsConfig.getHeartbeatTimeoutPeriod()) {
            LOGGER.debug("setDownValues: heartbeat response failed for member _id:{}" + ", msg: {}", member.getId(), hbResponse.getErrorDesc());
            hbData.setDownValues(now, hbResponse.getErrorDesc());
        } else {
            LOGGER.trace("Bad heartbeat response from {}; trying again; Retries left: {}; " + "{} ms have already elapsed", target, MAX_HEARTBEAT_RETRIES - hbStats.getNumFailuresSinceLastStart(), alreadyElapsed.toMillis());
        }
    } else {
        ReplSetHeartbeatReply nonNullReply = commandReply.get();
        LOGGER.trace("setUpValues: heartbeat response good for member _id:{}, msg:  {}", member.getId(), nonNullReply.getHbmsg());
        hbData.setUpValues(now, member.getHostAndPort(), nonNullReply);
    }
    HeartbeatResponseAction nextAction = updateHeartbeatDataImpl(memberIndex, now);
    nextAction.setNextHeartbeatDelay(nextHeartbeatDelay);
    return nextAction;
}
Also used : MemberHeartbeatData(com.torodb.mongodb.commands.pojos.MemberHeartbeatData) ReplSetHeartbeatReply(com.torodb.mongodb.commands.signatures.internal.ReplSetHeartbeatReply) ReplicaSetConfig(com.torodb.mongodb.commands.pojos.ReplicaSetConfig) Duration(java.time.Duration) OptionalInt(java.util.OptionalInt) MemberConfig(com.torodb.mongodb.commands.pojos.MemberConfig)

Example 2 with ReplicaSetConfig

use of com.torodb.mongodb.commands.pojos.ReplicaSetConfig in project torodb by torodb.

the class ReplSetInitiateCommand method unmarshallArg.

@Override
public ReplicaSetConfig unmarshallArg(BsonDocument requestDoc) throws TypesMismatchException, BadValueException, NoSuchKeyException, FailedToParseException {
    ReplicaSetConfig config;
    BsonDocument configDoc;
    configDoc = BsonReaderTool.getDocument(requestDoc, getCommandName());
    config = ReplicaSetConfig.fromDocument(configDoc);
    return config;
}
Also used : ReplicaSetConfig(com.torodb.mongodb.commands.pojos.ReplicaSetConfig) BsonDocument(com.eightkdata.mongowp.bson.BsonDocument)

Example 3 with ReplicaSetConfig

use of com.torodb.mongodb.commands.pojos.ReplicaSetConfig in project torodb by torodb.

the class TopologyCoordinator method updateConfig.

/**
   * Updates the topology coordinator's notion of the replica set configuration.
   *
   * @param newConfig the new configuration. It should be not null except for testing purpose.
   * @param now
   */
void updateConfig(ReplicaSetConfig newConfig, Instant now) {
    final ReplicaSetConfig oldConfig = _rsConfig;
    updateHeartbeatDataForReconfig(newConfig, now);
    _rsConfig = newConfig;
    _forceSyncSourceIndex = -1;
    // force secondaries to re-detect who the primary is
    _currentPrimaryIndex = -1;
    versionListeners.forEach(listener -> listener.onVersionChange(this, oldConfig));
}
Also used : ReplicaSetConfig(com.torodb.mongodb.commands.pojos.ReplicaSetConfig)

Example 4 with ReplicaSetConfig

use of com.torodb.mongodb.commands.pojos.ReplicaSetConfig in project torodb by torodb.

the class TopologyHeartbeatHandler method start.

CompletableFuture<Status<ReplicaSetConfig>> start(HostAndPort seed) {
    executor.addVersionChangeListener(versionChangeListener);
    return executor.onCurrentVersion().andThenApplyAsync(networkHandler.askForConfig(new RemoteCommandRequest<>(seed, "admin", Empty.getInstance())), (coord, remoteConfig) -> {
        Status<ReplicaSetConfig> result = remoteConfig.asStatus();
        if (!result.isOk()) {
            return result;
        }
        ReplicaSetConfig replConfig = result.getResult();
        try {
            checkRemoteReplSetConfig(replConfig);
            updateConfig(coord, replConfig);
            return result;
        } catch (InconsistentReplicaSetNamesException ex) {
            return Status.from(ex);
        }
    });
}
Also used : ReplicaSetConfig(com.torodb.mongodb.commands.pojos.ReplicaSetConfig) InconsistentReplicaSetNamesException(com.eightkdata.mongowp.exceptions.InconsistentReplicaSetNamesException) FromExceptionRemoteCommandRequest(com.eightkdata.mongowp.client.core.MongoConnection.FromExceptionRemoteCommandRequest)

Aggregations

ReplicaSetConfig (com.torodb.mongodb.commands.pojos.ReplicaSetConfig)4 BsonDocument (com.eightkdata.mongowp.bson.BsonDocument)1 FromExceptionRemoteCommandRequest (com.eightkdata.mongowp.client.core.MongoConnection.FromExceptionRemoteCommandRequest)1 InconsistentReplicaSetNamesException (com.eightkdata.mongowp.exceptions.InconsistentReplicaSetNamesException)1 MemberConfig (com.torodb.mongodb.commands.pojos.MemberConfig)1 MemberHeartbeatData (com.torodb.mongodb.commands.pojos.MemberHeartbeatData)1 ReplSetHeartbeatReply (com.torodb.mongodb.commands.signatures.internal.ReplSetHeartbeatReply)1 Duration (java.time.Duration)1 OptionalInt (java.util.OptionalInt)1