#pragma once #include #include #include #include #include #include "config.h" /* Forward declaration */ typedef struct cluster_s cluster_t; /* ============================================================ * WAL entry header — 40 bytes, 8-byte aligned (Part 2.2) * ============================================================ */ typedef struct { uint64_t term; /* Election term (incremented on failover) */ uint64_t lsn; /* Log sequence number within this term */ uint64_t timestamp; /* Epoch microseconds */ uint32_t type; /* wal_entry_type enum value */ uint32_t payload_len; /* Bytes of payload following this header */ uint32_t crc; /* CRC32(header[0..WAL_HDR_CRC_SIZE-1] + payload) */ uint32_t prev_crc; /* CRC of previous record; WAL_CRC_NONE for first in segment */ } wal_entry_hdr_t; _Static_assert(sizeof(wal_entry_hdr_t) == 40, "wal_entry_hdr_t must be 40 bytes for on-disk format stability"); /* ============================================================ * WAL entry types (Part 2.3) * ============================================================ */ typedef enum { WAL_JOB_SUBMIT = 1, /* SYNC replication */ WAL_JOB_START = 2, WAL_JOB_FINISH = 3, WAL_JOB_FAIL = 4, WAL_JOB_STOP = 5, WAL_JOB_RESUME = 6, WAL_JOB_UPDATE = 7, WAL_JOB_RUSAGE = 8, WAL_JOB_CKPT = 9, WAL_JOB_PREASON = 10, WAL_QUEUE_CTRL = 20, WAL_WORKER_CTRL = 30, WAL_CHECKPOINT = 100, /* Local WAL marker only — never replicated */ } wal_entry_type; /* ============================================================ * Persistence configuration (Part 2.6) * ============================================================ */ typedef struct { uint32_t wal_sync_ms; /* fsync interval in ms (default 10) */ uint32_t snap_interval_s; /* checkpoint interval in seconds (default 60) */ uint32_t snap_wal_size_mb; /* checkpoint when WAL exceeds this MB (default 64) */ uint32_t snap_keep_n; /* snapshots to retain (default 2) */ uint32_t transient_job_timeout_s; /* seconds before TRANSIENT job auto-terminates (default 300) */ uint32_t finished_retain_s; /* retain finished jobs N seconds (default 3600) */ uint32_t worker_retain_s; /* retain unavailable workers N seconds (default 86400) */ uint32_t sync_timeout_ms; /* sync replication ACK timeout ms (default 50) */ } persist_config_t; static inline persist_config_t persist_config_defaults(void) { persist_config_t c; c.wal_sync_ms = DEFAULT_WAL_SYNC_MS; c.snap_interval_s = DEFAULT_SNAP_INTERVAL_S; c.snap_wal_size_mb = DEFAULT_SNAP_WAL_SIZE_MB; c.snap_keep_n = DEFAULT_SNAP_KEEP_N; c.transient_job_timeout_s = DEFAULT_TRANSIENT_JOB_TIMEOUT_S; c.finished_retain_s = DEFAULT_FINISHED_RETAIN_S; c.worker_retain_s = DEFAULT_WORKER_RETAIN_S; c.sync_timeout_ms = DEFAULT_SYNC_TIMEOUT_MS; return c; } /* ============================================================ * Key→index mapping for checkpoint serialization (Part 3.8) * ============================================================ */ typedef struct { int index; /* shadow slot index in the frozen zarray */ char key[XCE_MAXNAME_LEN]; /* owned deep copy — not a borrowed kvtab pointer */ size_t key_len; /* length including null terminator */ } slot_key_t; /* ============================================================ * persist_t — concrete definition (exposed for stack/calloc allocation) * The opaque pattern can be restored in a later refactor once the * full API surface is stable. * ============================================================ */ struct persist_s { /* Back-pointer to owning cluster (set by persist_init, used in persist_start) */ cluster_t* cluster; /* WAL state */ int wal_fd; uint64_t current_lsn; uint32_t last_crc; uint32_t last_replicated_crc; uint64_t term; uint32_t seg_offset; uint64_t checkpoint_lsn; uint64_t total_wal_bytes; char seg_path[4096]; /* Paths (derived from workdir + name via persist_set_workdir) */ char wal_path[4096]; char snap_path[4096]; /* Config */ persist_config_t config; /* Concurrency */ pthread_mutex_t lock; atomic_int fsync_stop; atomic_int fsync_thread_running; pthread_t fsync_thread; /* Checkpoint (stubs for now — wired in Task 10) */ atomic_int checkpoint_in_progress; atomic_int checkpoint_requested; pthread_cond_t checkpoint_done; pthread_mutex_t checkpoint_mutex; pthread_t snap_thread; }; typedef struct persist_s persist_t; /* Set workdir and controller name before persist_init(). * Derives wal_path and snap_path as //data/{wal,snap}. */ void persist_set_workdir(persist_t* p, const char* workdir, const char* name); /* Lifecycle */ int persist_init(persist_t* p, persist_config_t* config, cluster_t* c); int persist_start(persist_t* p); void persist_stop(persist_t* p); void persist_fini(persist_t* p); int persist_recover(persist_t* p); /* WAL write paths */ int persist_wal_async(persist_t* p, uint32_t type, const void* payload, uint32_t len); int persist_wal_sync_append(persist_t* p, uint32_t type, const void* payload, uint32_t len, int* sync_rc_out); /* Force WAL fdatasync (for tests and clean shutdown) */ int persist_flush(persist_t* p); /* Checkpoint */ int persist_checkpoint(persist_t* p); /* Logging helper — never logs payload content (security invariant) */ void persist_log_entry_metadata(const wal_entry_hdr_t* hdr); /* ============================================================ * AFTER_EVENT hook functions — registered by persist_start() * * Signature matches hook_fn_t: int fn(int type, int situation, * int detail, void* data, va_list ap) * cls/data points to the persist_t instance. * * P0: writes a minimal 4-byte payload (detail value) to the WAL. * Full Cap'n Proto serialization is wired in Task 15. * ============================================================ */ int persist_job_hook_fun(int type, int situation, int detail, void* cls, va_list ap); int persist_queue_hook_fun(int type, int situation, int detail, void* cls, va_list ap); int persist_worker_hook_fun(int type, int situation, int detail, void* cls, va_list ap); /* GC retention predicates (P0-5a / P0-8 / P0-13) */ #include #include "xce/types.h" bool job_is_terminal(const job_t* j); bool job_should_retain(const job_t* j, const persist_config_t* cfg); bool worker_should_retain(const xce_worker_t* w, const persist_config_t* cfg);