public static SnapshotSyncRequest fromBytes(byte[] bytes){ ByteBuffer buffer = ByteBuffer.wrap(bytes); long lastLogIndex = buffer.getLong(); long lastLogTerm = buffer.getLong(); int configSize = buffer.getInt(); ClusterConfiguration config = ClusterConfiguration.fromBytes(ByteBuffer.wrap(bytes, buffer.position(), configSize)); buffer.position(buffer.position() + configSize); long offset = buffer.getLong(); int dataSize = buffer.getInt(); byte[] data = new byte[dataSize]; buffer.get(data); boolean done = buffer.get() == 1; return new SnapshotSyncRequest(new Snapshot(lastLogIndex, lastLogTerm, config), offset, data, done); } }
public byte[] toBytes(){ byte[] configData = this.snapshot.getLastConfig().toBytes(); int size = Long.BYTES * 3 + configData.length + Integer.BYTES * 2 + data.length + 1; ByteBuffer buffer = ByteBuffer.allocate(size); buffer.putLong(snapshot.getLastLogIndex()); buffer.putLong(snapshot.getLastLogTerm()); buffer.putInt(configData.length); buffer.put(configData); buffer.putLong(this.offset); buffer.putInt(this.data.length); buffer.put(this.data); buffer.put(this.done ? (byte)1 : (byte)0); return buffer.array(); }
@Override public int readSnapshotData(Snapshot snapshot, long offset, byte[] buffer) { Path filePath = this.snapshotStore.resolve(String.format("%d-%d.s", snapshot.getLastLogIndex(), snapshot.getLastLogTerm())); if(!Files.exists(filePath)){ return -1; } try{ RandomAccessFile snapshotFile = new RandomAccessFile(filePath.toString(), "rw"); snapshotFile.seek(offset); int bytesRead = read(snapshotFile, buffer); snapshotFile.close(); return bytesRead; }catch(Exception error){ LogManager.getLogger(getClass()).error("failed read data from snapshot", error); return -1; } }
snapshotInAction = true; Snapshot currentSnapshot = this.stateMachine.getLastSnapshot(); if(currentSnapshot != null && indexCommitted - currentSnapshot.getLastLogIndex() < this.context.getRaftParameters().getSnapshotDistance()){ this.logger.info("a very recent snapshot is available at index %d, will skip this one", currentSnapshot.getLastLogIndex()); this.snapshotInProgress.set(0); snapshotInAction = false; config = lastSnapshot.getLastConfig(); }else if(config.getLogIndex() > indexCommitted && config.getLastLogIndex() == 0){ this.logger.error("BUG!!! stop the system, there must be a configuration at index one"); Snapshot snapshot = new Snapshot(indexToCompact, logTermToCompact, config); this.stateMachine.createSnapshot(snapshot).whenCompleteAsync((Boolean result, Throwable error) -> { try{ this.logger.debug("snapshot created, compact the log store"); try{ this.logStore.compact(snapshot.getLastLogIndex()); }catch(Throwable ex){ this.logger.error("failed to compact the log store, no worries, the system still in a good shape", ex);
Snapshot snapshot = context == null ? null : context.getSnapshot(); Snapshot lastSnapshot = this.stateMachine.getLastSnapshot(); if(snapshot == null || (lastSnapshot != null && lastSnapshot.getLastLogIndex() > snapshot.getLastLogIndex())){ snapshot = lastSnapshot; if(snapshot == null || lastLogIndex > snapshot.getLastLogIndex()){ this.logger.error("system is running into fatal errors, failed to find a snapshot for peer %d(snapshot null: %s, snapshot doesn't contais lastLogIndex: %s)", peer.getId(), String.valueOf(snapshot == null), String.valueOf(lastLogIndex > snapshot.getLastLogIndex())); System.exit(-1); return null; if(snapshot.getSize() < 1L){ this.logger.error("invalid snapshot, this usually means a bug from state machine implementation, stop the system to prevent further errors"); System.exit(-1); this.logger.info("trying to sync snapshot with last index %d to peer %d", snapshot.getLastLogIndex(), peer.getId()); peer.setSnapshotInSync(snapshot); long sizeLeft = snapshot.getSize() - offset; int blockSize = this.getSnapshotSyncBlockSize(); byte[] data = new byte[sizeLeft > blockSize ? blockSize : (int)sizeLeft]; SnapshotSyncRequest syncRequest = new SnapshotSyncRequest(snapshot, offset, data, (offset + data.length) >= snapshot.getSize()); RaftRequestMessage requestMessage = new RaftRequestMessage(); requestMessage.setMessageType(RaftMessageType.InstallSnapshotRequest); requestMessage.setSource(this.id); requestMessage.setDestination(peer.getId()); requestMessage.setLastLogIndex(snapshot.getLastLogIndex()); requestMessage.setLastLogTerm(snapshot.getLastLogTerm()); requestMessage.setLogEntries(new LogEntry[] { new LogEntry(term, syncRequest.toBytes(), LogValueType.SnapshotSyncRequest) });
needToCatchup = false; }else{ if(response.getNextIndex() >= context.getSnapshot().getSize()){ this.logger.debug("snapshot sync is done"); peer.setNextLogIndex(context.getSnapshot().getLastLogIndex() + 1); peer.setMatchedIndex(context.getSnapshot().getLastLogIndex()); peer.setSnapshotInSync(null); needToCatchup = peer.clearPendingCommit() || response.getNextIndex() < this.logStore.getFirstAvailableIndex();
if(this.logStore.compact(snapshotSyncRequest.getSnapshot().getLastLogIndex())){ this.reconfigure(snapshotSyncRequest.getSnapshot().getLastConfig()); this.context.getServerStateManager().saveClusterConfiguration(this.config); this.state.setCommitIndex(snapshotSyncRequest.getSnapshot().getLastLogIndex()); this.quickCommitIndex = snapshotSyncRequest.getSnapshot().getLastLogIndex(); this.context.getServerStateManager().persistState(this.state); this.logger.info("snapshot is successfully applied");
if(snapshotSyncRequest.getSnapshot().getLastLogIndex() <= this.quickCommitIndex){ this.logger.error("Received a snapshot which is older than this server (%d)", this.id); response.setNextIndex(0);
@Override public int readSnapshotData(Snapshot snapshot, long offset, byte[] buffer) { Path filePath = this.snapshotStore.resolve(String.format("%d-%d.s", snapshot.getLastLogIndex(), snapshot.getLastLogTerm())); if(!Files.exists(filePath)){ return -1; } try{ RandomAccessFile snapshotFile = new RandomAccessFile(filePath.toString(), "rw"); snapshotFile.seek(offset); int bytesRead = read(snapshotFile, buffer); snapshotFile.close(); return bytesRead; }catch(Exception error){ LogManager.getLogger(getClass()).error("failed read data from snapshot", error); return -1; } }
snapshotInAction = true; Snapshot currentSnapshot = this.stateMachine.getLastSnapshot(); if(currentSnapshot != null && indexCommitted - currentSnapshot.getLastLogIndex() < this.context.getRaftParameters().getSnapshotDistance()){ this.logger.info("a very recent snapshot is available at index %d, will skip this one", currentSnapshot.getLastLogIndex()); this.snapshotInProgress.set(0); snapshotInAction = false; config = lastSnapshot.getLastConfig(); }else if(config.getLogIndex() > indexCommitted && config.getLastLogIndex() == 0){ this.logger.error("BUG!!! stop the system, there must be a configuration at index one"); Snapshot snapshot = new Snapshot(indexToCompact, logTermToCompact, config); this.stateMachine.createSnapshot(snapshot).whenCompleteAsync((Boolean result, Throwable error) -> { try{ this.logger.debug("snapshot created, compact the log store"); try{ this.logStore.compact(snapshot.getLastLogIndex()); }catch(Throwable ex){ this.logger.error("failed to compact the log store, no worries, the system still in a good shape", ex);
Snapshot snapshot = context == null ? null : context.getSnapshot(); Snapshot lastSnapshot = this.stateMachine.getLastSnapshot(); if(snapshot == null || (lastSnapshot != null && lastSnapshot.getLastLogIndex() > snapshot.getLastLogIndex())){ snapshot = lastSnapshot; if(snapshot == null || lastLogIndex > snapshot.getLastLogIndex()){ this.logger.error("system is running into fatal errors, failed to find a snapshot for peer %d(snapshot null: %s, snapshot doesn't contais lastLogIndex: %s)", peer.getId(), String.valueOf(snapshot == null), String.valueOf(lastLogIndex > snapshot.getLastLogIndex())); this.stateMachine.exit(-1); return null; if(snapshot.getSize() < 1L){ this.logger.error("invalid snapshot, this usually means a bug from state machine implementation, stop the system to prevent further errors"); this.stateMachine.exit(-1); this.logger.info("trying to sync snapshot with last index %d to peer %d", snapshot.getLastLogIndex(), peer.getId()); peer.setSnapshotInSync(snapshot); long sizeLeft = snapshot.getSize() - offset; int blockSize = this.getSnapshotSyncBlockSize(); byte[] data = new byte[sizeLeft > blockSize ? blockSize : (int)sizeLeft]; SnapshotSyncRequest syncRequest = new SnapshotSyncRequest(snapshot, offset, data, (offset + data.length) >= snapshot.getSize()); RaftRequestMessage requestMessage = new RaftRequestMessage(); requestMessage.setMessageType(RaftMessageType.InstallSnapshotRequest); requestMessage.setSource(this.id); requestMessage.setDestination(peer.getId()); requestMessage.setLastLogIndex(snapshot.getLastLogIndex()); requestMessage.setLastLogTerm(snapshot.getLastLogTerm()); requestMessage.setLogEntries(new LogEntry[] { new LogEntry(term, syncRequest.toBytes(), LogValueType.SnapshotSyncRequest) });
needToCatchup = false; }else{ if(response.getNextIndex() >= context.getSnapshot().getSize()){ this.logger.debug("snapshot sync is done"); peer.setNextLogIndex(context.getSnapshot().getLastLogIndex() + 1); peer.setMatchedIndex(context.getSnapshot().getLastLogIndex()); peer.setSnapshotInSync(null); needToCatchup = peer.clearPendingCommit() || response.getNextIndex() < this.logStore.getFirstAvailableIndex();
if(this.logStore.compact(snapshotSyncRequest.getSnapshot().getLastLogIndex())){ this.reconfigure(snapshotSyncRequest.getSnapshot().getLastConfig()); this.context.getServerStateManager().saveClusterConfiguration(this.config); this.state.setCommitIndex(snapshotSyncRequest.getSnapshot().getLastLogIndex()); this.quickCommitIndex = snapshotSyncRequest.getSnapshot().getLastLogIndex(); this.context.getServerStateManager().persistState(this.state); this.logger.info("snapshot is successfully applied");
if(snapshotSyncRequest.getSnapshot().getLastLogIndex() <= this.quickCommitIndex){ this.logger.error("Received a snapshot which is older than this server (%d)", this.id); response.setNextIndex(0);
@Override public void saveSnapshotData(Snapshot snapshot, long offset, byte[] data) { Path filePath = this.snapshotStore.resolve(String.format("%d-%d.s", snapshot.getLastLogIndex(), snapshot.getLastLogTerm())); try{ if(!Files.exists(filePath)){ Files.write(this.snapshotStore.resolve(String.format("%d.cnf", snapshot.getLastLogIndex())), snapshot.getLastConfig().toBytes(), StandardOpenOption.CREATE); } RandomAccessFile snapshotFile = new RandomAccessFile(filePath.toString(), "rw"); snapshotFile.seek(offset); snapshotFile.write(data); snapshotFile.close(); }catch(Exception error){ throw new RuntimeException(error.getMessage()); } }
@Override public boolean applySnapshot(Snapshot snapshot) { Path filePath = this.snapshotStore.resolve(String.format("%d-%d.s", snapshot.getLastLogIndex(), snapshot.getLastLogTerm())); if(!Files.exists(filePath)){ return false; } try{ FileInputStream input = new FileInputStream(filePath.toString()); InputStreamReader reader = new InputStreamReader(input, StandardCharsets.UTF_8); BufferedReader bufferReader = new BufferedReader(reader); synchronized(this.messages){ this.messages.clear(); String line = null; while((line = bufferReader.readLine()) != null){ if(line.length() > 0){ System.out.printf("from snapshot: %s\n", line); this.addMessage(line); } } this.commitIndex = snapshot.getLastLogIndex(); } bufferReader.close(); reader.close(); input.close(); }catch(Exception error){ LogManager.getLogger(getClass()).error("failed to apply the snapshot", error); return false; } return true; }
snapshotInAction = true; Snapshot currentSnapshot = this.stateMachine.getLastSnapshot(); if(currentSnapshot != null && indexCommitted - currentSnapshot.getLastLogIndex() < this.context.getRaftParameters().getSnapshotDistance()){ this.logger.info("a very recent snapshot is available at index %d, will skip this one", currentSnapshot.getLastLogIndex()); this.snapshotInProgress.set(0); snapshotInAction = false; config = lastSnapshot.getLastConfig(); }else if(config.getLogIndex() > indexCommitted && config.getLastLogIndex() == 0){ this.logger.error("BUG!!! stop the system, there must be a configuration at index one"); Snapshot snapshot = new Snapshot(indexToCompact, logTermToCompact, config); this.stateMachine.createSnapshot(snapshot).whenCompleteAsync((Boolean result, Throwable error) -> { try{ this.logger.debug("snapshot created, compact the log store"); try{ this.logStore.compact(snapshot.getLastLogIndex()); }catch(Throwable ex){ this.logger.error("failed to compact the log store, no worries, the system still in a good shape", ex);
Snapshot snapshot = context == null ? null : context.getSnapshot(); Snapshot lastSnapshot = this.stateMachine.getLastSnapshot(); if(snapshot == null || (lastSnapshot != null && lastSnapshot.getLastLogIndex() > snapshot.getLastLogIndex())){ snapshot = lastSnapshot; if(snapshot == null || lastLogIndex > snapshot.getLastLogIndex()){ this.logger.error("system is running into fatal errors, failed to find a snapshot for peer %d(snapshot null: %s, snapshot doesn't contais lastLogIndex: %s)", peer.getId(), String.valueOf(snapshot == null), String.valueOf(lastLogIndex > snapshot.getLastLogIndex())); this.stateMachine.exit(-1); return null; if(snapshot.getSize() < 1L){ this.logger.error("invalid snapshot, this usually means a bug from state machine implementation, stop the system to prevent further errors"); this.stateMachine.exit(-1); this.logger.info("trying to sync snapshot with last index %d to peer %d", snapshot.getLastLogIndex(), peer.getId()); peer.setSnapshotInSync(snapshot); long sizeLeft = snapshot.getSize() - offset; int blockSize = this.getSnapshotSyncBlockSize(); byte[] data = new byte[sizeLeft > blockSize ? blockSize : (int)sizeLeft]; SnapshotSyncRequest syncRequest = new SnapshotSyncRequest(snapshot, offset, data, (offset + data.length) >= snapshot.getSize()); RaftRequestMessage requestMessage = new RaftRequestMessage(); requestMessage.setMessageType(RaftMessageType.InstallSnapshotRequest); requestMessage.setSource(this.id); requestMessage.setDestination(peer.getId()); requestMessage.setLastLogIndex(snapshot.getLastLogIndex()); requestMessage.setLastLogTerm(snapshot.getLastLogTerm()); requestMessage.setLogEntries(new LogEntry[] { new LogEntry(term, syncRequest.toBytes(), LogValueType.SnapshotSyncRequest) });
needToCatchup = false; }else{ if(response.getNextIndex() >= context.getSnapshot().getSize()){ this.logger.debug("snapshot sync is done"); peer.setNextLogIndex(context.getSnapshot().getLastLogIndex() + 1); peer.setMatchedIndex(context.getSnapshot().getLastLogIndex()); peer.setSnapshotInSync(null); needToCatchup = peer.clearPendingCommit() || response.getNextIndex() < this.logStore.getFirstAvailableIndex();
if(this.logStore.compact(snapshotSyncRequest.getSnapshot().getLastLogIndex())){ this.reconfigure(snapshotSyncRequest.getSnapshot().getLastConfig()); this.context.getServerStateManager().saveClusterConfiguration(this.config); this.state.setCommitIndex(snapshotSyncRequest.getSnapshot().getLastLogIndex()); this.quickCommitIndex = snapshotSyncRequest.getSnapshot().getLastLogIndex(); this.context.getServerStateManager().persistState(this.state); this.logger.info("snapshot is successfully applied");