use of io.atomix.protocols.raft.service.RaftServiceContext in project atomix by atomix.
the class RaftServiceManager method applyKeepAlive.
/**
* Applies a session keep alive entry to the state machine.
* <p>
* Keep alive entries are applied to the internal state machine to reset the timeout for a specific session.
* If the session indicated by the KeepAliveEntry is still held in memory, we mark the session as trusted,
* indicating that the client has committed a keep alive within the required timeout. Additionally, we check
* all other sessions for expiration based on the timestamp provided by this KeepAliveEntry. Note that sessions
* are never completely expired via this method. Leaders must explicitly commit an UnregisterEntry to expire
* a session.
* <p>
* When a KeepAliveEntry is committed to the internal state machine, two specific fields provided in the entry
* are used to update server-side session state. The {@code commandSequence} indicates the highest command for
* which the session has received a successful response in the proper sequence. By applying the {@code commandSequence}
* to the server session, we clear command output held in memory up to that point. The {@code eventVersion} indicates
* the index up to which the client has received event messages in sequence for the session. Applying the
* {@code eventVersion} to the server-side session results in events up to that index being removed from memory
* as they were acknowledged by the client. It's essential that both of these fields be applied via entries committed
* to the Raft log to ensure they're applied on all servers in sequential order.
* <p>
* Keep alive entries are retained in the log until the next time the client sends a keep alive entry or until the
* client's session is expired. This ensures for sessions that have long timeouts, keep alive entries cannot be cleaned
* from the log before they're replicated to some servers.
*/
private long[] applyKeepAlive(Indexed<KeepAliveEntry> entry) {
// Store the session/command/event sequence and event index instead of acquiring a reference to the entry.
long[] sessionIds = entry.entry().sessionIds();
long[] commandSequences = entry.entry().commandSequenceNumbers();
long[] eventIndexes = entry.entry().eventIndexes();
// Iterate through session identifiers and keep sessions alive.
List<Long> successfulSessionIds = new ArrayList<>(sessionIds.length);
for (int i = 0; i < sessionIds.length; i++) {
long sessionId = sessionIds[i];
long commandSequence = commandSequences[i];
long eventIndex = eventIndexes[i];
RaftSession session = raft.getSessions().getSession(sessionId);
if (session != null) {
if (session.getService().keepAlive(entry.index(), entry.entry().timestamp(), session, commandSequence, eventIndex)) {
successfulSessionIds.add(sessionId);
}
}
}
// Iterate through services and complete keep-alives, causing sessions to be expired if necessary.
for (RaftServiceContext service : raft.getServices()) {
service.completeKeepAlive(entry.index(), entry.entry().timestamp());
}
return Longs.toArray(successfulSessionIds);
}
use of io.atomix.protocols.raft.service.RaftServiceContext in project atomix by atomix.
the class RaftServiceManager method initializeService.
/**
* Initializes a new service.
*/
private RaftServiceContext initializeService(PrimitiveId primitiveId, PrimitiveType primitiveType, String serviceName) {
RaftServiceContext oldService = raft.getServices().getService(serviceName);
RaftServiceContext service = new RaftServiceContext(primitiveId, serviceName, primitiveType, primitiveType.newService(), raft, threadContextFactory);
raft.getServices().registerService(service);
// If a service with this name was already registered, remove all of its sessions.
if (oldService != null) {
raft.getSessions().removeSessions(oldService.serviceId());
}
return service;
}
use of io.atomix.protocols.raft.service.RaftServiceContext 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.service.RaftServiceContext in project atomix by atomix.
the class RaftServiceManager method installService.
/**
* Restores the service associated with the given snapshot.
*
* @param reader the snapshot reader
*/
private void installService(SnapshotReader reader) {
PrimitiveId primitiveId = PrimitiveId.from(reader.readLong());
PrimitiveType primitiveType = raft.getPrimitiveTypes().get(reader.readString());
String serviceName = reader.readString();
// Get or create the service associated with the snapshot.
logger.debug("Installing service {} {}", primitiveId, serviceName);
RaftServiceContext service = initializeService(primitiveId, primitiveType, serviceName);
if (service != null) {
service.installSnapshot(reader);
}
}
use of io.atomix.protocols.raft.service.RaftServiceContext 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