/** * Creates a snapshot ID from the given string. * * @param id the string from which to create the identifier * @return the snapshot identifier */ public static PrimitiveId from(String id) { return from(Hashing.sha256().hashString(id, StandardCharsets.UTF_8).asLong()); }
/** * Creates a snapshot ID from the given number. * * @param id the number from which to create the identifier * @return the snapshot identifier */ public static PrimitiveId from(long id) { return new PrimitiveId(id); }
/** * Removes all sessions registered for the given service. * * @param primitiveId the service identifier */ public void removeSessions(PrimitiveId primitiveId) { sessions.entrySet().removeIf(e -> e.getValue().getService().serviceId().equals(primitiveId)); } }
/** * Takes a snapshot of the given service. * * @param writer the snapshot writer * @param service the service to snapshot */ private void snapshotService(SnapshotWriter writer, RaftServiceContext service) { writer.writeLong(service.serviceId().id()); writer.writeString(service.serviceType().name()); writer.writeString(service.serviceName()); byte[] config = Serializer.using(service.serviceType().namespace()).encode(service.serviceConfig()); writer.writeInt(config.length).writeBytes(config); try { service.takeSnapshot(writer); } catch (Exception e) { logger.error("Failed to take snapshot of service {}", service.serviceId(), e); } }
/** * Takes a snapshot of the service state. */ public void takeSnapshot(SnapshotWriter writer) { log.debug("Taking snapshot {}", writer.snapshot().index()); // Serialize sessions to the in-memory snapshot and request a snapshot from the state machine. writer.writeLong(primitiveId.id()); writer.writeString(primitiveType.name()); writer.writeString(serviceName); writer.writeLong(currentIndex); writer.writeLong(currentTimestamp); writer.writeLong(timestampDelta); writer.writeInt(sessions.getSessions().size()); for (RaftSession session : sessions.getSessions()) { writer.writeLong(session.sessionId().id()); writer.writeString(session.memberId().id()); writer.writeString(session.readConsistency().name()); writer.writeLong(session.minTimeout()); writer.writeLong(session.maxTimeout()); writer.writeLong(session.getLastUpdated()); writer.writeLong(session.getRequestSequence()); writer.writeLong(session.getCommandSequence()); writer.writeLong(session.getEventIndex()); writer.writeLong(session.getLastCompleted()); } service.backup(new DefaultBackupOutput(writer, service.serializer())); }
/** * Restores the service associated with the given snapshot. * * @param reader the snapshot reader */ private void installService(SnapshotReader reader) { PrimitiveId primitiveId = PrimitiveId.from(reader.readLong()); try { PrimitiveType primitiveType = raft.getPrimitiveTypes().getPrimitiveType(reader.readString()); String serviceName = reader.readString(); byte[] serviceConfig = reader.readBytes(reader.readInt()); // Get or create the service associated with the snapshot. logger.debug("Installing service {} {}", primitiveId, serviceName); RaftServiceContext service = initializeService(primitiveId, primitiveType, serviceName, serviceConfig); if (service != null) { try { service.installSnapshot(reader); } catch (Exception e) { logger.error("Failed to install snapshot for service {}", serviceName, e); } } } catch (ConfigurationException e) { logger.error(e.getMessage(), e); } }
/** * Returns a set of sessions associated with the given service. * * @param primitiveId the service identifier * @return a collection of sessions associated with the given service */ public Collection<RaftSession> getSessions(PrimitiveId primitiveId) { return sessions.values().stream() .filter(session -> session.getService().serviceId().equals(primitiveId)) .filter(session -> session.getState().active()) .collect(Collectors.toSet()); }
/** * Returns the service context for the given request. */ private CompletableFuture<PrimaryBackupServiceContext> getService(PrimitiveRequest request) { return services.computeIfAbsent(request.primitive().name(), n -> { PrimitiveType primitiveType = primitiveTypes.getPrimitiveType(request.primitive().type()); PrimaryBackupServiceContext service = new PrimaryBackupServiceContext( serverName, PrimitiveId.from(request.primitive().name()), primitiveType, request.primitive(), threadContextFactory.createContext(), clusterMembershipService, memberGroupService, protocol, primaryElection); OrderedFuture<PrimaryBackupServiceContext> newOrderFuture = new OrderedFuture<>(); service.open().whenComplete((v, e) -> { if (e != null) { newOrderFuture.completeExceptionally(e); } else { newOrderFuture.complete(service); } }); return newOrderFuture; }); }
/** * Applies an open session entry to the state machine. */ private long applyOpenSession(Indexed<OpenSessionEntry> entry) { PrimitiveType primitiveType = raft.getPrimitiveTypes().getPrimitiveType(entry.entry().serviceType()); // Get the state machine executor or create one if it doesn't already exist. RaftServiceContext service = getOrInitializeService( PrimitiveId.from(entry.index()), primitiveType, entry.entry().serviceName(), entry.entry().serviceConfig()); 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, MemberId.from(entry.entry().memberId()), entry.entry().serviceName(), primitiveType, entry.entry().readConsistency(), entry.entry().minTimeout(), entry.entry().maxTimeout(), entry.entry().timestamp(), service.serializer(), service, raft, threadContextFactory)); return service.openSession(entry.index(), entry.entry().timestamp(), session); }