private static LogEntry randomLogEntry(){ byte[] value = new byte[random.nextInt(20) + 1]; long term = random.nextLong(); random.nextBytes(value); return new LogEntry(term, value, LogValueType.fromByte((byte)(random.nextInt(4) + 1))); }
@Override public long append(LogEntry logEntry) { try{ PreparedStatement ps = this.connection.prepareStatement(INSERT_ENTRY_SQL); ps.setLong(1, logEntry.getTerm()); ps.setByte(2, logEntry.getValueType().toByte()); ps.setBytes(3, logEntry.getValue()); ps.execute(); this.connection.commit(); this.lastEntry = logEntry; return this.nextIndex.getAndIncrement(); }catch(Throwable error){ this.logger.error("failed to insert a new entry", error); throw new RuntimeException("log store error", error); } }
currentCommitIndex += 1; LogEntry logEntry = server.logStore.getLogEntryAt(currentCommitIndex); if(logEntry.getValueType() == LogValueType.Application){ server.stateMachine.commit(currentCommitIndex, logEntry.getValue()); }else if(logEntry.getValueType() == LogValueType.Configuration){ synchronized(server){ ClusterConfiguration newConfig = ClusterConfiguration.fromBytes(logEntry.getValue()); server.logger.info("configuration at index %d is committed", newConfig.getLogIndex()); server.context.getServerStateManager().saveClusterConfiguration(newConfig);
private RaftResponseMessage handleClientRequest(RaftRequestMessage request){ RaftResponseMessage response = new RaftResponseMessage(); response.setMessageType(RaftMessageType.AppendEntriesResponse); response.setSource(this.id); response.setDestination(this.leader); response.setTerm(this.state.getTerm()); long term; synchronized(this){ if(this.role != ServerRole.Leader){ response.setAccepted(false); return response; } term = this.state.getTerm(); } LogEntry[] logEntries = request.getLogEntries(); if(logEntries != null && logEntries.length > 0){ for(int i = 0; i < logEntries.length; ++i){ this.stateMachine.preCommit(this.logStore.append(new LogEntry(term, logEntries[i].getValue())), logEntries[i].getValue()); } } // Urgent commit, so that the commit will not depend on heartbeat this.requestAppendEntries(); response.setAccepted(true); response.setNextIndex(this.logStore.getFirstAvailableIndex()); return response; }
config = ClusterConfiguration.fromBytes(this.logStore.getLogEntryAt(config.getLastLogIndex()).getValue()); long logTermToCompact = this.logStore.getLogEntryAt(indexToCompact).getTerm(); Snapshot snapshot = new Snapshot(indexToCompact, logTermToCompact, config); this.stateMachine.createSnapshot(snapshot).whenCompleteAsync((Boolean result, Throwable error) -> {
private long termForLastLog(long logIndex){ if(logIndex == 0){ return 0; } if(logIndex >= this.logStore.getStartIndex()){ return this.logStore.getLogEntryAt(logIndex).getTerm(); } Snapshot lastSnapshot = this.stateMachine.getLastSnapshot(); if(lastSnapshot == null || logIndex != lastSnapshot.getLastLogIndex()){ throw new IllegalArgumentException("logIndex is beyond the range that no term could be retrieved"); } return lastSnapshot.getLastLogTerm(); }
response.setNextIndex(this.logStore.getFirstAvailableIndex()); response.setAccepted(false); if(logEntries.length != 1 || logEntries[0].getValue() == null || logEntries[0].getValue().length != Integer.BYTES){ this.logger.info("bad remove server request as we are expecting one log entry with value type of Integer"); return response; int serverId = ByteBuffer.wrap(logEntries[0].getValue()).getInt(); if(serverId == this.id){ this.logger.info("cannot request to remove leader");
if(logEntry.getValueType() == LogValueType.Configuration){ this.logger.info("detect a configuration change that is not committed yet at index %d", i); this.configChanging = true;
currentCommitIndex += 1; LogEntry logEntry = server.logStore.getLogEntryAt(currentCommitIndex); if(logEntry.getValueType() == LogValueType.Application){ server.stateMachine.commit(currentCommitIndex, logEntry.getValue()); }else if(logEntry.getValueType() == LogValueType.Configuration){ synchronized(server){ ClusterConfiguration newConfig = ClusterConfiguration.fromBytes(logEntry.getValue()); server.logger.info("configuration at index %d is committed", newConfig.getLogIndex()); server.context.getServerStateManager().saveClusterConfiguration(newConfig);
private RaftResponseMessage handleClientRequest(RaftRequestMessage request){ RaftResponseMessage response = new RaftResponseMessage(); response.setMessageType(RaftMessageType.AppendEntriesResponse); response.setSource(this.id); response.setDestination(this.leader); response.setTerm(this.state.getTerm()); long term; synchronized(this){ if(this.role != ServerRole.Leader){ response.setAccepted(false); return response; } term = this.state.getTerm(); } LogEntry[] logEntries = request.getLogEntries(); if(logEntries != null && logEntries.length > 0){ for(int i = 0; i < logEntries.length; ++i){ this.stateMachine.preCommit(this.logStore.append(new LogEntry(term, logEntries[i].getValue())), logEntries[i].getValue()); } } // Urgent commit, so that the commit will not depend on heartbeat this.requestAppendEntries(); response.setAccepted(true); response.setNextIndex(this.logStore.getFirstAvailableIndex()); return response; }
config = ClusterConfiguration.fromBytes(this.logStore.getLogEntryAt(config.getLastLogIndex()).getValue()); long logTermToCompact = this.logStore.getLogEntryAt(indexToCompact).getTerm(); Snapshot snapshot = new Snapshot(indexToCompact, logTermToCompact, config); this.stateMachine.createSnapshot(snapshot).whenCompleteAsync((Boolean result, Throwable error) -> {
private long termForLastLog(long logIndex){ if(logIndex == 0){ return 0; } if(logIndex >= this.logStore.getStartIndex()){ return this.logStore.getLogEntryAt(logIndex).getTerm(); } Snapshot lastSnapshot = this.stateMachine.getLastSnapshot(); if(lastSnapshot == null || logIndex != lastSnapshot.getLastLogIndex()){ throw new IllegalArgumentException("logIndex is beyond the range that no term could be retrieved"); } return lastSnapshot.getLastLogTerm(); }
response.setNextIndex(this.logStore.getFirstAvailableIndex()); response.setAccepted(false); if(logEntries.length != 1 || logEntries[0].getValue() == null || logEntries[0].getValue().length != Integer.BYTES){ this.logger.info("bad remove server request as we are expecting one log entry with value type of Integer"); return response; int serverId = ByteBuffer.wrap(logEntries[0].getValue()).getInt(); if(serverId == this.id){ this.logger.info("cannot request to remove leader");
if(logEntry.getValueType() == LogValueType.Configuration){ this.logger.info("detect a configuration change that is not committed yet at index %d", i); this.configChanging = true;
@Override public long append(LogEntry logEntry) { try{ PreparedStatement ps = this.connection.prepareStatement(INSERT_ENTRY_SQL); ps.setLong(1, logEntry.getTerm()); ps.setByte(2, logEntry.getValueType().toByte()); ps.setBytes(3, logEntry.getValue()); ps.execute(); this.connection.commit(); this.lastEntry = logEntry; return this.nextIndex.getAndIncrement(); }catch(Throwable error){ this.logger.error("failed to insert a new entry", error); throw new RuntimeException("log store error", error); } }
private static LogEntry randomLogEntry(){ byte[] value = new byte[random.nextInt(20) + 1]; long term = random.nextLong(); random.nextBytes(value); return new LogEntry(term, value, LogValueType.fromByte((byte)(random.nextInt(4) + 1))); }
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; }
private RaftResponseMessage handleClientRequest(RaftRequestMessage request){ RaftResponseMessage response = new RaftResponseMessage(); response.setMessageType(RaftMessageType.AppendEntriesResponse); response.setSource(this.id); response.setDestination(this.leader); response.setTerm(this.state.getTerm()); long term; synchronized(this){ if(this.role != ServerRole.Leader){ response.setAccepted(false); return response; } term = this.state.getTerm(); } LogEntry[] logEntries = request.getLogEntries(); if(logEntries != null && logEntries.length > 0){ for(int i = 0; i < logEntries.length; ++i){ this.stateMachine.preCommit(this.logStore.append(new LogEntry(term, logEntries[i].getValue())), logEntries[i].getValue()); } } // Urgent commit, so that the commit will not depend on heartbeat this.requestAppendEntries(); response.setAccepted(true); response.setNextIndex(this.logStore.getFirstAvailableIndex()); return response; }
config = ClusterConfiguration.fromBytes(this.logStore.getLogEntryAt(config.getLastLogIndex()).getValue()); long logTermToCompact = this.logStore.getLogEntryAt(indexToCompact).getTerm(); Snapshot snapshot = new Snapshot(indexToCompact, logTermToCompact, config); this.stateMachine.createSnapshot(snapshot).whenCompleteAsync((Boolean result, Throwable error) -> {
private long termForLastLog(long logIndex){ if(logIndex == 0){ return 0; } if(logIndex >= this.logStore.getStartIndex()){ return this.logStore.getLogEntryAt(logIndex).getTerm(); } Snapshot lastSnapshot = this.stateMachine.getLastSnapshot(); if(lastSnapshot == null || logIndex != lastSnapshot.getLastLogIndex()){ throw new IllegalArgumentException("logIndex is beyond the range that no term could be retrieved"); } return lastSnapshot.getLastLogTerm(); }