use of io.atomix.protocols.raft.session.RaftSession in project atomix by atomix.
the class RaftServiceManager method applyCloseSession.
/**
* Applies a close session entry to the state machine.
*/
private void applyCloseSession(Indexed<CloseSessionEntry> entry) {
RaftSession session = raft.getSessions().getSession(entry.entry().session());
// If the server session is null, the session either never existed or already expired.
if (session == null) {
throw new RaftException.UnknownSession("Unknown session: " + entry.entry().session());
}
// Get the state machine executor associated with the session and unregister the session.
RaftServiceContext service = session.getService();
service.closeSession(entry.index(), entry.entry().timestamp(), session, entry.entry().expired());
}
use of io.atomix.protocols.raft.session.RaftSession in project atomix by atomix.
the class RaftServiceManager method applyMetadata.
/**
* Applies a metadata entry to the state machine.
*/
private MetadataResult applyMetadata(Indexed<MetadataEntry> entry) {
// If the session ID is non-zero, read the metadata for the associated state machine.
if (entry.entry().session() > 0) {
RaftSession session = raft.getSessions().getSession(entry.entry().session());
// If the session is null, return an UnknownSessionException.
if (session == null) {
logger.warn("Unknown session: " + entry.entry().session());
throw new RaftException.UnknownSession("Unknown session: " + entry.entry().session());
}
Set<SessionMetadata> sessions = new HashSet<>();
for (RaftSession s : raft.getSessions().getSessions()) {
if (s.serviceName().equals(session.serviceName())) {
sessions.add(new SessionMetadata(s.sessionId().id(), s.serviceName(), s.serviceType().id()));
}
}
return new MetadataResult(sessions);
} else {
Set<SessionMetadata> sessions = new HashSet<>();
for (RaftSession session : raft.getSessions().getSessions()) {
sessions.add(new SessionMetadata(session.sessionId().id(), session.serviceName(), session.serviceType().id()));
}
return new MetadataResult(sessions);
}
}
use of io.atomix.protocols.raft.session.RaftSession in project atomix by atomix.
the class RaftServiceManager method applyOpenSession.
/**
* Applies an open session entry to the state machine.
*/
private long applyOpenSession(Indexed<OpenSessionEntry> entry) {
PrimitiveType primitiveType = raft.getPrimitiveTypes().get(entry.entry().serviceType());
if (primitiveType == null) {
throw new RaftException.UnknownService("Unknown service type " + entry.entry().serviceType());
}
// Get the state machine executor or create one if it doesn't already exist.
RaftServiceContext service = getOrInitializeService(PrimitiveId.from(entry.index()), raft.getPrimitiveTypes().get(entry.entry().serviceType()), entry.entry().serviceName());
if (service == null) {
throw new RaftException.UnknownService("Unknown service type " + entry.entry().serviceType());
}
SessionId sessionId = SessionId.from(entry.index());
RaftSession session = raft.getSessions().addSession(new RaftSession(sessionId, NodeId.from(entry.entry().memberId()), entry.entry().serviceName(), primitiveType, entry.entry().readConsistency(), entry.entry().minTimeout(), entry.entry().maxTimeout(), entry.entry().timestamp(), service, raft, threadContextFactory));
return service.openSession(entry.index(), entry.entry().timestamp(), session);
}
use of io.atomix.protocols.raft.session.RaftSession in project atomix by atomix.
the class RaftServiceManager method applyCommand.
/**
* Applies a command entry to the state machine.
* <p>
* Command entries result in commands being executed on the user provided {@link PrimitiveService} and a
* response being sent back to the client by completing the returned future. All command responses are
* cached in the command's {@link RaftSession} for fault tolerance. In the event that the same command
* is applied to the state machine more than once, the original response will be returned.
* <p>
* Command entries are written with a sequence number. The sequence number is used to ensure that
* commands are applied to the state machine in sequential order. If a command entry has a sequence
* number that is less than the next sequence number for the session, that indicates that it is a
* duplicate of a command that was already applied. Otherwise, commands are assumed to have been
* received in sequential order. The reason for this assumption is because leaders always sequence
* commands as they're written to the log, so no sequence number will be skipped.
*/
private OperationResult applyCommand(Indexed<CommandEntry> entry) {
// First check to ensure that the session exists.
RaftSession session = raft.getSessions().getSession(entry.entry().session());
// to log warnings here.
if (session == null) {
logger.debug("Unknown session: " + entry.entry().session());
throw new RaftException.UnknownSession("unknown session: " + entry.entry().session());
}
// Increment the load counter to avoid snapshotting under high load.
raft.getLoadMonitor().recordEvent();
// Execute the command using the state machine associated with the session.
return session.getService().executeCommand(entry.index(), entry.entry().sequenceNumber(), entry.entry().timestamp(), session, entry.entry().operation());
}
use of io.atomix.protocols.raft.session.RaftSession in project atomix by atomix.
the class LeaderRole method onQuery.
@Override
public CompletableFuture<QueryResponse> onQuery(final QueryRequest request) {
raft.checkThread();
logRequest(request);
// doesn't exist if the follower hasn't had a chance to see the session's registration entry.
if (raft.getLastApplied() < request.session()) {
return CompletableFuture.completedFuture(logResponse(QueryResponse.builder().withStatus(RaftResponse.Status.ERROR).withError(RaftError.Type.UNKNOWN_SESSION, "Session has not yet been created. You're seeing into the future!").build()));
}
// Look up the client's session.
RaftSession session = raft.getSessions().getSession(request.session());
if (session == null) {
log.warn("Unknown session {}", request.session());
return CompletableFuture.completedFuture(logResponse(QueryResponse.builder().withStatus(RaftResponse.Status.ERROR).withError(RaftError.Type.UNKNOWN_SESSION).build()));
}
final Indexed<QueryEntry> entry = new Indexed<>(request.index(), new QueryEntry(raft.getTerm(), System.currentTimeMillis(), request.session(), request.sequenceNumber(), request.operation()), 0);
final CompletableFuture<QueryResponse> future;
switch(session.readConsistency()) {
case SEQUENTIAL:
future = queryLocal(entry);
break;
case LINEARIZABLE_LEASE:
future = queryBoundedLinearizable(entry);
break;
case LINEARIZABLE:
future = queryLinearizable(entry);
break;
default:
future = Futures.exceptionalFuture(new IllegalStateException("Unknown consistency level: " + session.readConsistency()));
break;
}
return future.thenApply(this::logResponse);
}
Aggregations