Search in sources :

Example 1 with PendingCommand

use of io.atomix.protocols.raft.impl.PendingCommand in project atomix by atomix.

the class LeaderRole method onCommand.

@Override
public CompletableFuture<CommandResponse> onCommand(final CommandRequest request) {
    raft.checkThread();
    logRequest(request);
    if (transferring) {
        return CompletableFuture.completedFuture(logResponse(CommandResponse.builder().withStatus(RaftResponse.Status.ERROR).withError(RaftError.Type.ILLEGAL_MEMBER_STATE).build()));
    }
    // Get the client's server session. If the session doesn't exist, return an unknown session error.
    RaftSession session = raft.getSessions().getSession(request.session());
    if (session == null) {
        return CompletableFuture.completedFuture(logResponse(CommandResponse.builder().withStatus(RaftResponse.Status.ERROR).withError(RaftError.Type.UNKNOWN_SESSION).build()));
    }
    final long sequenceNumber = request.sequenceNumber();
    // If a command with the given sequence number is already pending, return the existing future to ensure
    // duplicate requests aren't committed as duplicate entries in the log.
    PendingCommand existingCommand = session.getCommand(sequenceNumber);
    if (existingCommand != null) {
        if (sequenceNumber == session.nextRequestSequence()) {
            session.removeCommand(sequenceNumber);
            commitCommand(existingCommand.request(), existingCommand.future());
            session.setRequestSequence(sequenceNumber);
            drainCommands(session);
        }
        log.trace("Returning pending result for command sequence {}", sequenceNumber);
        return existingCommand.future();
    }
    final CompletableFuture<CommandResponse> future = new CompletableFuture<>();
    // to force it to be resent by the client.
    if (sequenceNumber > session.nextRequestSequence()) {
        if (session.getCommands().size() < MAX_PENDING_COMMANDS) {
            log.trace("Registered sequence command {} > {}", sequenceNumber, session.nextRequestSequence());
            session.registerCommand(request.sequenceNumber(), new PendingCommand(request, future));
            return future;
        } else {
            return CompletableFuture.completedFuture(logResponse(CommandResponse.builder().withStatus(RaftResponse.Status.ERROR).withError(RaftError.Type.COMMAND_FAILURE).withLastSequence(session.getRequestSequence()).build()));
        }
    }
    // return null.
    if (sequenceNumber <= session.getCommandSequence()) {
        OperationResult result = session.getResult(sequenceNumber);
        if (result != null) {
            completeOperation(result, CommandResponse.builder(), null, future);
        } else {
            future.complete(CommandResponse.builder().withStatus(RaftResponse.Status.ERROR).withError(RaftError.Type.PROTOCOL_ERROR).build());
        }
    } else // Otherwise, commit the command and update the request sequence number.
    {
        commitCommand(request, future);
        session.setRequestSequence(sequenceNumber);
    }
    return future.thenApply(this::logResponse);
}
Also used : CompletableFuture(java.util.concurrent.CompletableFuture) RaftSession(io.atomix.protocols.raft.session.RaftSession) OperationResult(io.atomix.protocols.raft.impl.OperationResult) CommandResponse(io.atomix.protocols.raft.protocol.CommandResponse) PendingCommand(io.atomix.protocols.raft.impl.PendingCommand)

Example 2 with PendingCommand

use of io.atomix.protocols.raft.impl.PendingCommand in project atomix by atomix.

the class LeaderRole method drainCommands.

/**
 * Sequentially drains pending commands from the session's command request queue.
 *
 * @param session the session for which to drain commands
 */
private void drainCommands(RaftSession session) {
    long nextSequence = session.nextRequestSequence();
    PendingCommand nextCommand = session.removeCommand(nextSequence);
    while (nextCommand != null) {
        commitCommand(nextCommand.request(), nextCommand.future());
        session.setRequestSequence(nextSequence);
        nextSequence = session.nextRequestSequence();
        nextCommand = session.removeCommand(nextSequence);
    }
}
Also used : PendingCommand(io.atomix.protocols.raft.impl.PendingCommand)

Aggregations

PendingCommand (io.atomix.protocols.raft.impl.PendingCommand)2 OperationResult (io.atomix.protocols.raft.impl.OperationResult)1 CommandResponse (io.atomix.protocols.raft.protocol.CommandResponse)1 RaftSession (io.atomix.protocols.raft.session.RaftSession)1 CompletableFuture (java.util.concurrent.CompletableFuture)1