use of io.atomix.primitive.partition.PrimaryTerm in project atomix by atomix.
the class PrimaryElectorService method enter.
/**
* Applies an {@link PrimaryElectorOperations.Enter} commit.
*
* @param commit commit entry
* @return topic leader. If no previous leader existed this is the node that just entered the race.
*/
protected PrimaryTerm enter(Commit<? extends PrimaryElectorOperations.Enter> commit) {
try {
PartitionId partitionId = commit.value().partitionId();
PrimaryTerm oldTerm = term(partitionId);
Registration registration = new Registration(commit.value().member(), commit.session().sessionId().id());
PrimaryTerm newTerm = elections.compute(partitionId, (k, v) -> {
if (v == null) {
return new ElectionState(partitionId, registration, elections);
} else {
if (!v.isDuplicate(registration)) {
return new ElectionState(v).addRegistration(registration);
} else {
return v;
}
}
}).term();
if (!Objects.equals(oldTerm, newTerm)) {
notifyTermChange(partitionId, newTerm);
scheduleRebalance();
}
return newTerm;
} catch (Exception e) {
getLogger().error("State machine operation failed", e);
throw Throwables.propagate(e);
}
}
use of io.atomix.primitive.partition.PrimaryTerm in project atomix by atomix.
the class PrimaryElectorService method rebalance.
/**
* Periodically rebalances primaries.
*/
private void rebalance() {
boolean rebalanced = false;
for (ElectionState election : elections.values()) {
// Count the total number of primaries for this election's primary.
int primaryCount = election.countPrimaries(election.primary);
// Find the registration with the fewest number of primaries.
int minCandidateCount = 0;
for (Registration candidate : election.registrations) {
if (minCandidateCount == 0) {
minCandidateCount = election.countPrimaries(candidate);
} else {
minCandidateCount = Math.min(minCandidateCount, election.countPrimaries(candidate));
}
}
// primaries then transfer leadership to the candidate.
if (minCandidateCount < primaryCount) {
for (Registration candidate : election.registrations) {
if (election.countPrimaries(candidate) < primaryCount) {
PrimaryTerm oldTerm = election.term();
elections.put(election.partitionId, election.transfer(candidate.member()));
PrimaryTerm newTerm = term(election.partitionId);
if (!Objects.equals(oldTerm, newTerm)) {
notifyTermChange(election.partitionId, newTerm);
rebalanced = true;
}
}
}
}
}
// change to recognize the primary change and replicate state first.
if (rebalanced) {
scheduleRebalance();
}
}
use of io.atomix.primitive.partition.PrimaryTerm in project atomix by atomix.
the class PrimaryBackupProxy method execute.
private void execute(PrimitiveOperation operation, ComposableFuture<byte[]> future) {
ExecuteRequest request = ExecuteRequest.request(descriptor, sessionId.id(), clusterService.getLocalNode().id(), operation);
log.trace("Sending {} to {}", request, term.primary());
PrimaryTerm term = this.term;
if (term.primary() != null) {
protocol.execute(term.primary().nodeId(), request).whenCompleteAsync((response, error) -> {
if (error == null) {
log.trace("Received {}", response);
if (response.status() == Status.OK) {
future.complete(response.result());
} else {
if (this.term.term() > term.term()) {
execute(operation).whenComplete(future);
} else {
primaryElection.getTerm().whenComplete((newTerm, termError) -> {
if (termError == null) {
if (newTerm.term() > term.term() && newTerm.primary() != null) {
execute(operation).whenComplete(future);
} else {
future.completeExceptionally(new PrimitiveException.Unavailable());
}
} else {
future.completeExceptionally(new PrimitiveException.Unavailable());
}
});
}
}
} else {
future.completeExceptionally(error);
}
}, threadContext);
} else {
future.completeExceptionally(new ConnectException());
}
}
use of io.atomix.primitive.partition.PrimaryTerm in project atomix by atomix.
the class PrimaryElectorService method onSessionEnd.
private void onSessionEnd(Session session) {
listeners.remove(session.sessionId().id());
Set<PartitionId> partitions = elections.keySet();
partitions.forEach(partitionId -> {
PrimaryTerm oldTerm = term(partitionId);
elections.compute(partitionId, (k, v) -> v.cleanup(session));
PrimaryTerm newTerm = term(partitionId);
if (!Objects.equals(oldTerm, newTerm)) {
notifyTermChange(partitionId, newTerm);
scheduleRebalance();
}
});
}
Aggregations