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