use of io.atomix.protocols.raft.storage.snapshot.SnapshotWriter in project atomix by atomix.
the class PassiveRole method onInstall.
@Override
public CompletableFuture<InstallResponse> onInstall(InstallRequest request) {
raft.checkThread();
logRequest(request);
updateTermAndLeader(request.term(), request.leader());
// If the request is for a lesser term, reject the request.
if (request.term() < raft.getTerm()) {
return CompletableFuture.completedFuture(logResponse(InstallResponse.builder().withStatus(RaftResponse.Status.ERROR).withError(RaftError.Type.ILLEGAL_MEMBER_STATE, "Request term is less than the local term " + request.term()).build()));
}
// If the snapshot already exists locally, do not overwrite it with a replicated snapshot. Simply reply to the
// request successfully.
Snapshot existingSnapshot = raft.getSnapshotStore().getSnapshot(request.snapshotIndex());
if (existingSnapshot != null) {
return CompletableFuture.completedFuture(logResponse(InstallResponse.builder().withStatus(RaftResponse.Status.OK).build()));
}
// leader dictates when a snapshot needs to be sent.
if (pendingSnapshot != null && request.snapshotIndex() != pendingSnapshot.snapshot().index()) {
pendingSnapshot.rollback();
pendingSnapshot = null;
}
// If there is no pending snapshot, create a new snapshot.
if (pendingSnapshot == null) {
// For new snapshots, the initial snapshot offset must be 0.
if (request.chunkOffset() > 0) {
return CompletableFuture.completedFuture(logResponse(InstallResponse.builder().withStatus(RaftResponse.Status.ERROR).withError(RaftError.Type.ILLEGAL_MEMBER_STATE, "Request chunk offset is invalid").build()));
}
Snapshot snapshot = raft.getSnapshotStore().newSnapshot(request.snapshotIndex(), WallClockTimestamp.from(request.snapshotTimestamp()));
pendingSnapshot = new PendingSnapshot(snapshot);
}
// If the request offset is greater than the next expected snapshot offset, fail the request.
if (request.chunkOffset() > pendingSnapshot.nextOffset()) {
return CompletableFuture.completedFuture(logResponse(InstallResponse.builder().withStatus(RaftResponse.Status.ERROR).withError(RaftError.Type.ILLEGAL_MEMBER_STATE, "Request chunk offset does not match the next chunk offset").build()));
} else // If the request offset has already been written, return OK to skip to the next chunk.
if (request.chunkOffset() < pendingSnapshot.nextOffset()) {
return CompletableFuture.completedFuture(logResponse(InstallResponse.builder().withStatus(RaftResponse.Status.OK).build()));
}
// Write the data to the snapshot.
try (SnapshotWriter writer = pendingSnapshot.snapshot().openWriter()) {
writer.write(request.data());
}
// If the snapshot is complete, store the snapshot and reset state, otherwise update the next snapshot offset.
if (request.complete()) {
pendingSnapshot.commit();
pendingSnapshot = null;
} else {
pendingSnapshot.incrementOffset();
}
return CompletableFuture.completedFuture(logResponse(InstallResponse.builder().withStatus(RaftResponse.Status.OK).build()));
}
use of io.atomix.protocols.raft.storage.snapshot.SnapshotWriter in project atomix by atomix.
the class RaftServiceManager method snapshot.
/**
* Takes snapshots for the given index.
*
* @param index the index for which to take snapshots
*/
private Snapshot snapshot(long index) {
Snapshot snapshot = raft.getSnapshotStore().newTemporarySnapshot(index, new WallClockTimestamp());
try (SnapshotWriter writer = snapshot.openWriter()) {
for (RaftServiceContext service : raft.getServices()) {
writer.buffer().mark();
SnapshotWriter serviceWriter = new SnapshotWriter(writer.buffer().writeInt(0).slice(), writer.snapshot());
snapshotService(serviceWriter, service);
int length = serviceWriter.buffer().position();
writer.buffer().reset().writeInt(length).skip(length);
}
} catch (Exception e) {
snapshot.close();
throw e;
}
return snapshot;
}
Aggregations