package org.rakam.kume; import org.rakam.kume.transport.OperationContext; import org.rakam.kume.transport.Request; import java.util.ArrayList; import java.util.HashSet; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; public class AppendLogEntryRequest<R> implements Request<InternalService, Boolean> { private final Request request; private final int serviceId; public AppendLogEntryRequest(Request request, int serviceId) { this.request = request; this.serviceId = serviceId; } @Override public void run(InternalService service, OperationContext<Boolean> ctx) { // synchronized (service.cluster) { Set<Member> counter = new HashSet<>(); Set<Member> members = service.cluster.getMembers(); AtomicInteger size = new AtomicInteger(members.size()); long index = service.cluster.getLastCommitIndex().get(); ArrayList<CompletableFuture> reqs = new ArrayList(members.size()); for (Member member : members) { CompletableFuture<R> f = new CompletableFuture<>(); service.cluster.tryAskUntilDoneInternal(member, new UncommittedLogRequest(index, request), 5, 0, f); reqs.add(f.whenComplete((result, ex) -> { int lastSize; if (ex != null) { service.cluster.removeMemberAsMaster(member, true); lastSize = size.decrementAndGet(); } else { counter.add(member); lastSize = counter.size(); } if (lastSize == members.size()) { commit(service.cluster, index); ctx.reply(true); } })); } reqs.forEach(f -> f.join()); // } } public void commit(Cluster cluster, long index) { for (Member member : cluster.getMembers()) { CompletableFuture<Object> f0 = new CompletableFuture<>(); cluster.tryAskUntilDoneInternal(member, new CommitLogRequest(index, serviceId), 5, 0, f0); f0.whenComplete((result0, ex0) -> { if (ex0 != null && ex0 instanceof TimeoutException) { cluster.removeMemberAsMaster(member, true); } }); } } public static class UncommittedLogRequest implements Request<InternalService, Boolean> { long index; Request request; public UncommittedLogRequest(long index, Request request) { this.index = index; this.request = request; } @Override public void run(InternalService service, OperationContext<Boolean> ctx) { service.cluster.pendingConsensusMessages().put(index, request); ctx.reply(true); } } public static class CommitLogRequest implements Request<InternalService, Boolean> { private final int serviceId; long index; public CommitLogRequest(long index, int serviceId) { this.index = index; this.serviceId = serviceId; } @Override public void run(InternalService service, OperationContext<Boolean> ctx) { Cluster cluster = service.cluster; cluster.pendingConsensusMessages().get(index).run(cluster.getServices().get(serviceId), ctx); } } }