Search in sources :

Example 1 with SnapshotWriter

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()));
}
Also used : Snapshot(io.atomix.protocols.raft.storage.snapshot.Snapshot) SnapshotWriter(io.atomix.protocols.raft.storage.snapshot.SnapshotWriter)

Example 2 with SnapshotWriter

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;
}
Also used : Snapshot(io.atomix.protocols.raft.storage.snapshot.Snapshot) WallClockTimestamp(io.atomix.utils.time.WallClockTimestamp) SnapshotWriter(io.atomix.protocols.raft.storage.snapshot.SnapshotWriter) RaftServiceContext(io.atomix.protocols.raft.service.RaftServiceContext) RaftException(io.atomix.protocols.raft.RaftException)

Aggregations

Snapshot (io.atomix.protocols.raft.storage.snapshot.Snapshot)2 SnapshotWriter (io.atomix.protocols.raft.storage.snapshot.SnapshotWriter)2 RaftException (io.atomix.protocols.raft.RaftException)1 RaftServiceContext (io.atomix.protocols.raft.service.RaftServiceContext)1 WallClockTimestamp (io.atomix.utils.time.WallClockTimestamp)1