Search in sources :

Example 1 with Snapshot

use of io.atomix.protocols.raft.storage.snapshot.Snapshot in project atomix by atomix.

the class LeaderAppender method appendEntries.

@Override
protected void appendEntries(RaftMemberContext member) {
    // Prevent recursive, asynchronous appends from being executed if the appender has been closed.
    if (!open) {
        return;
    }
    // to prevent having to read from disk to configure, install, or append to an unavailable member.
    if (member.getFailureCount() >= MIN_BACKOFF_FAILURE_COUNT) {
        // use exponential backoff to back off up to 60 second heartbeat intervals.
        if (System.currentTimeMillis() - member.getFailureTime() > Math.min(heartbeatInterval * Math.pow(2, member.getFailureCount()), MAX_HEARTBEAT_WAIT)) {
            sendAppendRequest(member, buildAppendEmptyRequest(member));
        }
    } else // Once the configuration is complete sendAppendRequest will be called recursively.
    if (member.getConfigTerm() < raft.getTerm() || member.getConfigIndex() < raft.getCluster().getConfiguration().index()) {
        if (member.canConfigure()) {
            sendConfigureRequest(member, buildConfigureRequest(member));
        } else if (member.canHeartbeat()) {
            sendAppendRequest(member, buildAppendEmptyRequest(member));
        }
    } else // If there's a snapshot at the member's nextIndex, replicate the snapshot.
    if (member.getMember().getType() == RaftMember.Type.ACTIVE || member.getMember().getType() == RaftMember.Type.PROMOTABLE || member.getMember().getType() == RaftMember.Type.PASSIVE) {
        Snapshot snapshot = raft.getSnapshotStore().getCurrentSnapshot();
        if (snapshot != null && member.getSnapshotIndex() < snapshot.index() && snapshot.index() >= member.getLogReader().getCurrentIndex()) {
            if (!member.canInstall()) {
                return;
            }
            log.debug("Replicating snapshot {} to {}", snapshot.index(), member.getMember().nodeId());
            sendInstallRequest(member, buildInstallRequest(member, snapshot));
        } else if (member.canAppend()) {
            sendAppendRequest(member, buildAppendRequest(member, -1));
        }
    } else // If no AppendRequest is already being sent, send an AppendRequest.
    if (member.canAppend()) {
        sendAppendRequest(member, buildAppendRequest(member, -1));
    }
}
Also used : Snapshot(io.atomix.protocols.raft.storage.snapshot.Snapshot)

Example 2 with Snapshot

use of io.atomix.protocols.raft.storage.snapshot.Snapshot 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 3 with Snapshot

use of io.atomix.protocols.raft.storage.snapshot.Snapshot in project atomix by atomix.

the class RaftServiceManager method install.

/**
 * Prepares sessions for the given index.
 *
 * @param index the index for which to install snapshots
 */
private void install(long index) {
    Snapshot snapshot = raft.getSnapshotStore().getSnapshot(index - 1);
    // If snapshots exist for the prior index, iterate through snapshots and populate services/sessions.
    if (snapshot != null) {
        logger.debug("Installing snapshot {}", snapshot);
        try (SnapshotReader reader = snapshot.openReader()) {
            while (reader.hasRemaining()) {
                int length = reader.readInt();
                if (length > 0) {
                    SnapshotReader serviceReader = new SnapshotReader(reader.buffer().slice(length), reader.snapshot());
                    installService(serviceReader);
                    reader.skip(length);
                }
            }
        }
    }
}
Also used : Snapshot(io.atomix.protocols.raft.storage.snapshot.Snapshot) SnapshotReader(io.atomix.protocols.raft.storage.snapshot.SnapshotReader)

Example 4 with Snapshot

use of io.atomix.protocols.raft.storage.snapshot.Snapshot 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)4 SnapshotWriter (io.atomix.protocols.raft.storage.snapshot.SnapshotWriter)2 RaftException (io.atomix.protocols.raft.RaftException)1 RaftServiceContext (io.atomix.protocols.raft.service.RaftServiceContext)1 SnapshotReader (io.atomix.protocols.raft.storage.snapshot.SnapshotReader)1 WallClockTimestamp (io.atomix.utils.time.WallClockTimestamp)1