f56639ba17
Mirrors SpoolStore: per-record file with atomic .tmp+rename, magic+ version-prefixed binary layout, replay on enable, delete on remove. FSMs gain a restore_state() that bypasses the transition table and handlers since a replay isn't a transition. Six new tests cover write+restart+replay across every CIDS/CSMS/CAS axis, remove-deletes-journal, malformed-record drop-not-poison, and the persistence-disabled no-op path. Closes #1 in the test-gap backlog. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
128 lines
4.4 KiB
C++
128 lines
4.4 KiB
C++
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "secsgem/gem/carrier_state.hpp" // shared CarrierTransition template
|
|
|
|
// E87 §6 Load Port state models — three independent FSMs per port:
|
|
//
|
|
// LPTS LoadPortTransferState - is a carrier being moved on/off?
|
|
// LRS LoadPortReservationStatus - host reservation
|
|
// LAS LoadPortAssociationStatus - is a carrier associated?
|
|
//
|
|
// Wire-byte values match E87-0716 §10.3.5-7.
|
|
namespace secsgem::gem {
|
|
|
|
enum class LoadPortTransferState : uint8_t {
|
|
OutOfService = 0,
|
|
InService = 1, // ready, no carrier in motion
|
|
Loading = 2, // carrier arriving
|
|
Unloading = 3, // carrier leaving
|
|
NoState = 255,
|
|
};
|
|
|
|
const char* load_port_transfer_state_name(LoadPortTransferState s);
|
|
|
|
enum class LoadPortTransferEvent {
|
|
EnterService, // OutOfService -> InService
|
|
LeaveService, // any -> OutOfService
|
|
StartLoading, // InService -> Loading
|
|
CompleteLoading, // Loading -> InService
|
|
StartUnloading, // InService -> Unloading
|
|
CompleteUnloading, // Unloading -> InService
|
|
};
|
|
|
|
const char* load_port_transfer_event_name(LoadPortTransferEvent e);
|
|
|
|
enum class LoadPortReservationStatus : uint8_t {
|
|
NotReserved = 0,
|
|
Reserved = 1,
|
|
NoState = 255,
|
|
};
|
|
|
|
const char* load_port_reservation_status_name(LoadPortReservationStatus s);
|
|
|
|
enum class LoadPortReservationEvent {
|
|
Reserve, // NotReserved -> Reserved
|
|
Release, // Reserved -> NotReserved
|
|
};
|
|
|
|
const char* load_port_reservation_event_name(LoadPortReservationEvent e);
|
|
|
|
enum class LoadPortAssociationStatus : uint8_t {
|
|
NotAssociated = 0,
|
|
Associated = 1,
|
|
NoState = 255,
|
|
};
|
|
|
|
const char* load_port_association_status_name(LoadPortAssociationStatus s);
|
|
|
|
enum class LoadPortAssociationEvent {
|
|
Associate, // NotAssociated -> Associated
|
|
Disassociate, // Associated -> NotAssociated
|
|
};
|
|
|
|
const char* load_port_association_event_name(LoadPortAssociationEvent e);
|
|
|
|
using LoadPortTransferTable =
|
|
CarrierTransitionTable<LoadPortTransferState, LoadPortTransferEvent>;
|
|
using LoadPortReservationTable =
|
|
CarrierTransitionTable<LoadPortReservationStatus, LoadPortReservationEvent>;
|
|
using LoadPortAssociationTable =
|
|
CarrierTransitionTable<LoadPortAssociationStatus, LoadPortAssociationEvent>;
|
|
|
|
LoadPortTransferTable default_load_port_transfer_table();
|
|
LoadPortReservationTable default_load_port_reservation_table();
|
|
LoadPortAssociationTable default_load_port_association_table();
|
|
|
|
class LoadPortStateMachine {
|
|
public:
|
|
using TransferChangeHandler =
|
|
std::function<void(LoadPortTransferState from, LoadPortTransferState to,
|
|
LoadPortTransferEvent)>;
|
|
using ReservationChangeHandler =
|
|
std::function<void(LoadPortReservationStatus from, LoadPortReservationStatus to,
|
|
LoadPortReservationEvent)>;
|
|
using AssociationChangeHandler =
|
|
std::function<void(LoadPortAssociationStatus from, LoadPortAssociationStatus to,
|
|
LoadPortAssociationEvent)>;
|
|
|
|
LoadPortStateMachine();
|
|
|
|
LoadPortTransferState transfer_state() const { return tx_state_; }
|
|
LoadPortReservationStatus reservation_state() const { return rs_state_; }
|
|
LoadPortAssociationStatus association_state() const { return as_state_; }
|
|
|
|
void set_transfer_handler(TransferChangeHandler h) { on_tx_ = std::move(h); }
|
|
void set_reservation_handler(ReservationChangeHandler h) { on_rs_ = std::move(h); }
|
|
void set_association_handler(AssociationChangeHandler h) { on_as_ = std::move(h); }
|
|
|
|
bool on_transfer_event(LoadPortTransferEvent e);
|
|
bool on_reservation_event(LoadPortReservationEvent e);
|
|
bool on_association_event(LoadPortAssociationEvent e);
|
|
|
|
// Direct state-restore (persistence replay only). See carrier_state.hpp.
|
|
void restore_state(LoadPortTransferState tx, LoadPortReservationStatus rs,
|
|
LoadPortAssociationStatus as) {
|
|
tx_state_ = tx;
|
|
rs_state_ = rs;
|
|
as_state_ = as;
|
|
}
|
|
|
|
private:
|
|
LoadPortTransferTable tx_table_;
|
|
LoadPortReservationTable rs_table_;
|
|
LoadPortAssociationTable as_table_;
|
|
LoadPortTransferState tx_state_ = LoadPortTransferState::InService;
|
|
LoadPortReservationStatus rs_state_ = LoadPortReservationStatus::NotReserved;
|
|
LoadPortAssociationStatus as_state_ = LoadPortAssociationStatus::NotAssociated;
|
|
TransferChangeHandler on_tx_;
|
|
ReservationChangeHandler on_rs_;
|
|
AssociationChangeHandler on_as_;
|
|
};
|
|
|
|
} // namespace secsgem::gem
|