myxce/src/include/persist.h

160 lines
6.7 KiB
C

#pragma once
#include <pthread.h>
#include <stdarg.h>
#include <stdatomic.h>
#include <stddef.h>
#include <stdint.h>
#include "config.h"
#include "wal_types.h" /* wal_entry_hdr_t, wal_entry_type — P2-4: shared with repl.h */
#include "repl.h" /* replicator_t — P2-4: embedded in persist_t */
/* Forward declaration */
typedef struct cluster_s cluster_t;
/* ============================================================
* 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) */
uint32_t max_wal_records; /* checkpoint trigger: records since last snap (default 10000) */
} 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;
c.max_wal_records = DEFAULT_MAX_WAL_RECORDS;
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;
_Atomic uint64_t committed_lsn; /* highest LSN known committed; invariant: <= current_lsn - 1 */
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_uint wal_record_count; /* records appended since last checkpoint */
atomic_int checkpoint_in_progress; /* CAS guard: 0=idle, 1=scheduled/running */
atomic_int fsync_stop;
atomic_int fsync_thread_running;
pthread_t fsync_thread;
/* Checkpoint (stubs for now — wired in Task 10) */
atomic_int checkpoint_requested;
pthread_cond_t checkpoint_done;
pthread_mutex_t checkpoint_mutex;
pthread_t snap_thread;
/* Fan-out replicator — P2-4 */
replicator_t repl;
};
typedef struct persist_s persist_t;
/* Set workdir and controller name before persist_init().
* Derives wal_path and snap_path as <workdir>/<name>/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);
/* WAL truncation — remove all entries with LSN > cutoff_lsn.
* Idempotent; returns 0 on success, negative errno on I/O error. */
int persist_truncate_wal_above(persist_t* p, uint64_t cutoff_lsn);
/* 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);
/* Apply a single WAL entry to in-memory state (standby replay path).
* No hooks fire — hook system is empty on standbys until promotion.
* Returns 0 on success (including skip for checkpoint/unknown types),
* negative errno on error (oversized payload, NULL arguments). */
int apply_wal_entry(persist_t* p, const wal_entry_hdr_t* hdr, const void* payload);
/* GC retention predicates (P0-5a / P0-8 / P0-13) */
#include <stdbool.h>
#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);