private static RaftRequestMessage randomRequest(){ RaftRequestMessage request = new RaftRequestMessage(); request.setMessageType(randomMessageType());; request.setCommitIndex(random.nextLong()); request.setDestination(random.nextInt()); request.setLastLogIndex(random.nextLong()); request.setLastLogTerm(random.nextLong()); request.setSource(random.nextInt()); request.setTerm(random.nextLong()); LogEntry[] entries = new LogEntry[random.nextInt(20) + 1]; for(int i = 0; i < entries.length; ++i){ entries[i] = randomLogEntry(); } request.setLogEntries(entries); return request; }
@Override public RaftResponseMessage processRequest(RaftRequestMessage request) { String log = String.format( "Receive a request(Source: %d, Destination: %d, Term: %d, LLI: %d, LLT: %d, CI: %d, LEL: %d", request.getSource(), request.getDestination(), request.getTerm(), request.getLastLogIndex(), request.getLastLogTerm(), request.getCommitIndex(), request.getLogEntries() == null ? 0 : request.getLogEntries().length); logger.debug(log); System.out.println(log); return this.randomResponse(request.getSource(), request.getTerm()); }
@Override public CompletableFuture<Boolean> appendEntries(byte[][] values) { if(values == null || values.length == 0){ return CompletableFuture.completedFuture(false); } LogEntry[] logEntries = new LogEntry[values.length]; for(int i = 0; i < values.length; ++i){ logEntries[i] = new LogEntry(0, values[i]); } RaftRequestMessage request = new RaftRequestMessage(); request.setMessageType(RaftMessageType.ClientRequest); request.setLogEntries(logEntries); return this.sendMessageToLeader(request); }
private RaftResponseMessage handleInstallSnapshotRequest(RaftRequestMessage request){ this.updateTerm(request.getTerm()); if(request.getTerm() == this.state.getTerm() && !this.catchingUp){ if(this.role == ServerRole.Candidate){ this.becomeFollower(); }else if(this.role == ServerRole.Leader){ this.logger.error("Receive InstallSnapshotRequest from another leader(%d) with same term, there must be a bug, server exits", request.getSource()); System.exit(-1); }else{ response.setTerm(this.state.getTerm()); response.setSource(this.id); response.setDestination(request.getSource()); if(!this.catchingUp && request.getTerm() < this.state.getTerm()){ this.logger.info("received an install snapshot request which has lower term than this server, decline the request"); response.setAccepted(false); LogEntry logEntries[] = request.getLogEntries(); if(logEntries == null || logEntries.length != 1 || logEntries[0].getValueType() != LogValueType.SnapshotSyncRequest){ this.logger.warning("Receive an invalid InstallSnapshotRequest due to bad log entries or bad log entry value");
private synchronized RaftResponseMessage handleVoteRequest(RaftRequestMessage request){ // we allow the server to be continue after term updated to save a round message this.updateTerm(request.getTerm()); // Reset stepping down value to prevent this server goes down when leader crashes after sending a LeaveClusterRequest if(this.steppingDown > 0){ this.steppingDown = 2; } RaftResponseMessage response = new RaftResponseMessage(); response.setMessageType(RaftMessageType.RequestVoteResponse); response.setSource(this.id); response.setDestination(request.getSource()); response.setTerm(this.state.getTerm()); boolean logOkay = request.getLastLogTerm() > this.logStore.getLastLogEntry().getTerm() || (request.getLastLogTerm() == this.logStore.getLastLogEntry().getTerm() && this.logStore.getFirstAvailableIndex() - 1 <= request.getLastLogIndex()); boolean grant = request.getTerm() == this.state.getTerm() && logOkay && (this.state.getVotedFor() == request.getSource() || this.state.getVotedFor() == -1); response.setAccepted(grant); if(grant){ this.state.setVotedFor(request.getSource()); this.context.getServerStateManager().persistState(this.state); } return response; }
private RaftResponseMessage handleLogSyncRequest(RaftRequestMessage request){ LogEntry[] logEntries = request.getLogEntries(); RaftResponseMessage response = new RaftResponseMessage(); response.setSource(this.id); response.setDestination(request.getSource()); response.setTerm(this.state.getTerm()); response.setMessageType(RaftMessageType.SyncLogResponse); response.setNextIndex(this.logStore.getFirstAvailableIndex()); response.setAccepted(false); if(logEntries == null || logEntries.length != 1 || logEntries[0].getValueType() != LogValueType.LogPack || logEntries[0].getValue() == null || logEntries[0].getValue().length == 0){ this.logger.info("receive an invalid LogSyncRequest as the log entry value doesn't meet the requirements"); return response; } if(!this.catchingUp){ this.logger.debug("This server is ready for cluster, ignore the request"); return response; } this.logStore.applyLogPack(request.getLastLogIndex() + 1, logEntries[0].getValue()); this.commit(this.logStore.getFirstAvailableIndex() -1); response.setNextIndex(this.logStore.getFirstAvailableIndex()); response.setAccepted(true); return response; }
@Override public synchronized CompletableFuture<RaftResponseMessage> send(final RaftRequestMessage request) { this.logger.debug(String.format("trying to send message %s to server %d at endpoint %s", request.getMessageType().toString(), request.getDestination(), this.remote.toString())); CompletableFuture<RaftResponseMessage> result = new CompletableFuture<RaftResponseMessage>(); if(this.connection == null || !this.connection.isOpen()){ try{ this.connection = AsynchronousSocketChannel.open(this.channelGroup); this.connection.connect(this.remote, new AsyncTask<RaftRequestMessage>(request, result), handlerFrom((Void v, AsyncTask<RaftRequestMessage> task) -> { sendAndRead(task, false); })); }catch(Throwable error){ closeSocket(); result.completeExceptionally(error); } }else{ this.sendAndRead(new AsyncTask<RaftRequestMessage>(request, result), false); } return result; }
for(int i = 0; i < batchSize; ++i){ RaftRequestMessage request = randomRequest(); request.setSource(i); CompletableFuture<RaftResponseMessage> response = client.send(request); list.add(new Pair<RaftRequestMessage, CompletableFuture<RaftResponseMessage>>(request, response)); response.getTerm())); if(request.getTerm() != response.getTerm()){ System.out.printf("fatal: request and response are mismatched, %d v.s. %d @ %s!\n", request.getTerm(), response.getTerm(), item.item2.toString()); reader.readLine(); return;
private RaftResponseMessage handleAddServerRequest(RaftRequestMessage request){ LogEntry[] logEntries = request.getLogEntries(); RaftResponseMessage response = new RaftResponseMessage(); response.setSource(this.id);
private RaftResponseMessage handleLeaveClusterRequest(RaftRequestMessage request){ RaftResponseMessage response = new RaftResponseMessage(); response.setSource(this.id); response.setDestination(request.getSource()); response.setTerm(this.state.getTerm()); response.setMessageType(RaftMessageType.LeaveClusterResponse); response.setNextIndex(this.logStore.getFirstAvailableIndex()); if(!this.configChanging){ this.steppingDown = 2; response.setAccepted(true); }else{ response.setAccepted(false); } return response; }
@Override public CompletableFuture<Boolean> appendEntries(byte[][] values) { if(values == null || values.length == 0){ return CompletableFuture.completedFuture(false); } LogEntry[] logEntries = new LogEntry[values.length]; for(int i = 0; i < values.length; ++i){ logEntries[i] = new LogEntry(0, values[i]); } RaftRequestMessage request = new RaftRequestMessage(); request.setMessageType(RaftMessageType.ClientRequest); request.setLogEntries(logEntries); return this.sendMessageToLeader(request); }
private RaftResponseMessage handleInstallSnapshotRequest(RaftRequestMessage request){ this.updateTerm(request.getTerm()); if(request.getTerm() == this.state.getTerm() && !this.catchingUp){ if(this.role == ServerRole.Candidate){ this.becomeFollower(); }else if(this.role == ServerRole.Leader){ this.logger.error("Receive InstallSnapshotRequest from another leader(%d) with same term, there must be a bug, server exits", request.getSource()); this.stateMachine.exit(-1); }else{ response.setTerm(this.state.getTerm()); response.setSource(this.id); response.setDestination(request.getSource()); if(!this.catchingUp && request.getTerm() < this.state.getTerm()){ this.logger.info("received an install snapshot request which has lower term than this server, decline the request"); response.setAccepted(false); LogEntry logEntries[] = request.getLogEntries(); if(logEntries == null || logEntries.length != 1 || logEntries[0].getValueType() != LogValueType.SnapshotSyncRequest){ this.logger.warning("Receive an invalid InstallSnapshotRequest due to bad log entries or bad log entry value");
private synchronized RaftResponseMessage handleVoteRequest(RaftRequestMessage request){ // we allow the server to be continue after term updated to save a round message this.updateTerm(request.getTerm()); // Reset stepping down value to prevent this server goes down when leader crashes after sending a LeaveClusterRequest if(this.steppingDown > 0){ this.steppingDown = 2; } RaftResponseMessage response = new RaftResponseMessage(); response.setMessageType(RaftMessageType.RequestVoteResponse); response.setSource(this.id); response.setDestination(request.getSource()); response.setTerm(this.state.getTerm()); boolean logOkay = request.getLastLogTerm() > this.logStore.getLastLogEntry().getTerm() || (request.getLastLogTerm() == this.logStore.getLastLogEntry().getTerm() && this.logStore.getFirstAvailableIndex() - 1 <= request.getLastLogIndex()); boolean grant = request.getTerm() == this.state.getTerm() && logOkay && (this.state.getVotedFor() == request.getSource() || this.state.getVotedFor() == -1); response.setAccepted(grant); if(grant){ this.state.setVotedFor(request.getSource()); this.context.getServerStateManager().persistState(this.state); } return response; }
private RaftResponseMessage handleLogSyncRequest(RaftRequestMessage request){ LogEntry[] logEntries = request.getLogEntries(); RaftResponseMessage response = new RaftResponseMessage(); response.setSource(this.id); response.setDestination(request.getSource()); response.setTerm(this.state.getTerm()); response.setMessageType(RaftMessageType.SyncLogResponse); response.setNextIndex(this.logStore.getFirstAvailableIndex()); response.setAccepted(false); if(logEntries == null || logEntries.length != 1 || logEntries[0].getValueType() != LogValueType.LogPack || logEntries[0].getValue() == null || logEntries[0].getValue().length == 0){ this.logger.info("receive an invalid LogSyncRequest as the log entry value doesn't meet the requirements"); return response; } if(!this.catchingUp){ this.logger.debug("This server is ready for cluster, ignore the request"); return response; } this.logStore.applyLogPack(request.getLastLogIndex() + 1, logEntries[0].getValue()); this.commit(this.logStore.getFirstAvailableIndex() -1); response.setNextIndex(this.logStore.getFirstAvailableIndex()); response.setAccepted(true); return response; }
@Override public synchronized CompletableFuture<RaftResponseMessage> send(final RaftRequestMessage request) { this.logger.debug(String.format("trying to send message %s to server %d at endpoint %s", request.getMessageType().toString(), request.getDestination(), this.remote.toString())); CompletableFuture<RaftResponseMessage> result = new CompletableFuture<RaftResponseMessage>(); if(this.connection == null || !this.connection.isOpen()){ try{ this.connection = AsynchronousSocketChannel.open(this.channelGroup); this.connection.connect(this.remote, new AsyncTask<RaftRequestMessage>(request, result), handlerFrom((Void v, AsyncTask<RaftRequestMessage> task) -> { sendAndRead(task, false); })); }catch(Throwable error){ closeSocket(); result.completeExceptionally(error); } }else{ this.sendAndRead(new AsyncTask<RaftRequestMessage>(request, result), false); } return result; }
for(int i = 0; i < batchSize; ++i){ RaftRequestMessage request = randomRequest(); request.setSource(i); CompletableFuture<RaftResponseMessage> response = client.send(request); list.add(new Pair<RaftRequestMessage, CompletableFuture<RaftResponseMessage>>(request, response)); response.getTerm())); if(request.getTerm() != response.getTerm()){ System.out.printf("fatal: request and response are mismatched, %d v.s. %d @ %s!\n", request.getTerm(), response.getTerm(), item.item2.toString()); reader.readLine(); return;
private RaftResponseMessage handleAddServerRequest(RaftRequestMessage request){ LogEntry[] logEntries = request.getLogEntries(); RaftResponseMessage response = new RaftResponseMessage(); response.setSource(this.id);
private RaftResponseMessage handleLeaveClusterRequest(RaftRequestMessage request){ RaftResponseMessage response = new RaftResponseMessage(); response.setSource(this.id); response.setDestination(request.getSource()); response.setTerm(this.state.getTerm()); response.setMessageType(RaftMessageType.LeaveClusterResponse); response.setNextIndex(this.logStore.getFirstAvailableIndex()); if(!this.configChanging){ this.steppingDown = 2; response.setAccepted(true); }else{ response.setAccepted(false); } return response; }
private static RaftRequestMessage randomRequest(){ RaftRequestMessage request = new RaftRequestMessage(); request.setMessageType(randomMessageType());; request.setCommitIndex(random.nextLong()); request.setDestination(random.nextInt()); request.setLastLogIndex(random.nextLong()); request.setLastLogTerm(random.nextLong()); request.setSource(random.nextInt()); request.setTerm(random.nextLong()); LogEntry[] entries = new LogEntry[random.nextInt(20) + 1]; for(int i = 0; i < entries.length; ++i){ entries[i] = randomLogEntry(); } request.setLogEntries(entries); return request; }
@Override public RaftResponseMessage processRequest(RaftRequestMessage request) { String log = String.format( "Receive a request(Source: %d, Destination: %d, Term: %d, LLI: %d, LLT: %d, CI: %d, LEL: %d", request.getSource(), request.getDestination(), request.getTerm(), request.getLastLogIndex(), request.getLastLogTerm(), request.getCommitIndex(), request.getLogEntries() == null ? 0 : request.getLogEntries().length); logger.debug(log); System.out.println(log); return this.randomResponse(request.getSource(), request.getTerm()); }