Merge branch 'persistent_ha' into scheduler

This commit is contained in:
Rongsong Shen 2026-05-12 10:52:46 +00:00
commit a07a74a943
106 changed files with 18528 additions and 637 deletions

View file

@ -71,4 +71,26 @@ typedef uint64_t jobid_t;
#define REGEX_JOBARRAY_ID \
"[ \t]*([0-9]+)-([0-9]+)-([0-9]+)-([0-9]+)\\[([0-9]+)\\][ \t]*"
/* ======================================================
* Persistence & HA system constants (Part 2.6, Appendix A.10)
* ====================================================== */
#define MAX_STANDBYS 3
#define MAX_HA_CANDIDATES 4
#define WAL_FORMAT_VERSION 1
#define WAL_ENTRY_TYPE_MAX 100 /* WAL_CHECKPOINT = 100, highest known type */
#define MAX_WAL_PAYLOAD_BYTES (1 << 20) /* 1 MB per replication entry */
#define MAX_SNAPSHOT_BYTES (256 * 1024 * 1024) /* 256 MB max snapshot size */
#define WAL_HDR_CRC_SIZE 32 /* sizeof(wal_entry_hdr_t) - 2*sizeof(uint32_t) */
#define WAL_CRC_NONE 0xFFFFFFFFu /* sentinel: no predecessor in chain */
#define DEFAULT_WAL_SYNC_MS 10
#define DEFAULT_SNAP_INTERVAL_S 60
#define DEFAULT_SNAP_WAL_SIZE_MB 64
#define DEFAULT_SNAP_KEEP_N 2
#define DEFAULT_TRANSIENT_JOB_TIMEOUT_S 300
#define DEFAULT_FINISHED_RETAIN_S 3600
#define DEFAULT_WORKER_RETAIN_S 86400
#define DEFAULT_SYNC_TIMEOUT_MS 50
#define DEFAULT_HB_INTERVAL_MS 3000
#endif

View file

@ -0,0 +1,47 @@
#pragma once
/*
* ctrl_metrics.h — P3-7: Operational metrics for the XCE controller.
*
* All metrics use C11 _Atomic uint64_t for lock-free, thread-safe access.
* Metric names use the ctrl_ prefix.
*
* Design doc: Part P3-7, review A8-007.
*/
#include <stdatomic.h>
#include <stdint.h>
/* ── Counter/gauge globals ──────────────────────────────────────────── */
extern _Atomic uint64_t ctrl_repl_degraded_count; /* counter */
extern _Atomic uint64_t ctrl_split_brain_detected; /* counter */
extern _Atomic uint64_t ctrl_async_events_lost; /* counter */
extern _Atomic uint64_t ctrl_transient_jobs_stuck; /* counter */
extern _Atomic uint64_t ctrl_wal_bytes; /* gauge */
extern _Atomic uint64_t ctrl_checkpoint_duration_ms; /* gauge */
extern _Atomic uint64_t ctrl_repl_lag_lsn; /* gauge */
/* ── Macros ─────────────────────────────────────────────────────────── */
/* Increment a monotonic counter by 1 (relaxed ordering — counters are
* sampled, not used for synchronization). */
#define CTRL_METRIC_INC(name) \
atomic_fetch_add_explicit(&(name), 1, memory_order_relaxed)
/* Overwrite a gauge with a new absolute value. */
#define CTRL_METRIC_SET(name, val) \
atomic_store_explicit(&(name), (uint64_t)(val), memory_order_relaxed)
/* ── Descriptor table for metric discovery ──────────────────────────── */
typedef struct {
const char* name;
_Atomic uint64_t* value;
const char* description;
int is_counter; /* 1 = counter (monotonic), 0 = gauge */
} ctrl_metric_desc_t;
/* Terminated by a { NULL, NULL, NULL, 0 } sentinel entry. */
extern const ctrl_metric_desc_t ctrl_metric_descriptors[];
/* ── Lifecycle ──────────────────────────────────────────────────────── */
/* Reset all metrics to zero. Call from persist_start() and ha_init(). */
void ctrl_metrics_init(void);

View file

@ -23,7 +23,7 @@ typedef struct {
typedef struct {
pthread_t worker;
int running;
int precision;
int precision_ms;
task_run_fn_t runner_fn;
timer_t timerid;
ordq_t tasks;

View file

@ -3,6 +3,7 @@
#define __HOOK_H__ 1
#include <stdarg.h>
#include <stdatomic.h>
#include <stddef.h>
#include "xlist.h"
@ -12,8 +13,8 @@
typedef int (*hook_fn_t)(int, int, int, void*, va_list);
typedef struct {
hook_fn_t fn;
void* data;
_Atomic hook_fn_t fn;
void* data;
} hook_item_t;
typedef struct {
@ -23,6 +24,7 @@ typedef struct {
extern int xce_hook_init(hooksys_t*, int);
extern int xce_add_hook(hooksys_t*, int, hook_fn_t, void*);
extern int xce_disable_hook(hooksys_t*, int, hook_fn_t);
extern int xce_run_hooks(hooksys_t*, int, int, int, ...);
extern void xce_hook_fini(hooksys_t*);

View file

@ -30,4 +30,22 @@ extern kv_key_ops_t int_key_ops;
extern kv_key_ops_t string_key_ops;
extern int key_cmp_default(void*, void*, size_t);
/*
* kvtab_foreach — iterate every live entry in the kvtab (P0-14).
*
* For each entry, cb(key, index, arg) is called.
* - key : the raw key pointer stored in the entry (char* for
* string-keyed tables, (void*)(long)intval for int-keyed).
* - index : the slot index stored as the entry value.
* - arg : caller-supplied context.
*
* Iteration order is unspecified.
* Returns the number of entries visited, or -EINVAL if kvtab is NULL.
*/
typedef void (*kvtab_foreach_fn_t)(void* key, int index, void* arg);
extern int kvtab_foreach(var kvtab,
kvtab_foreach_fn_t cb,
void* arg);
#endif

View file

@ -7,6 +7,7 @@
#include "xce/types.h"
#include "xlist.h"
#include "zarray.h"
#include "persist.h"
typedef enum {
KVMGR_KEY_INT = 0,
@ -22,4 +23,22 @@ typedef struct {
extern typeinfo_t xkvmgr_type;
/*
* kvmgr_capture_keys — capture key→index mappings for checkpoint
* serialization (Part 3.8).
*
* Caller MUST hold the kvmgr write lock for the full duration of
* this call. The function allocates *keys_out and populates it with
* *n_keys_out entries. Each entry's key[] field is an owned deep
* copy that remains valid after the write lock is released.
*
* Caller must free(*keys_out) when done.
*
* Returns 0 on success.
* Returns -ENOMEM if allocation fails.
*/
int kvmgr_capture_keys(var kvmgr,
slot_key_t** keys_out,
size_t* n_keys_out);
#endif

View file

@ -7,6 +7,7 @@
#include <tlog.h>
#include "clusterconfig.h"
#include "xce/cluster.h"
struct logging {
char* logdir;
@ -14,10 +15,13 @@ struct logging {
};
typedef struct {
cluster_config_t* cluster_config;
char* conffile;
char* certfile;
char* keyfile;
cluster_config_t* cluster_config;
char* conffile;
char* certfile;
char* keyfile;
char* workdir; /* working directory for WAL/snapshot storage */
char* name; /* controller name (hostname by default) */
xce_cluster_config_t peers_cfg; /* HA peer list parsed from --peers; count==0 = single-node */
} myconf_t;
extern cluster_config_t* get_default_conf(void*);

152
src/include/persist.h Normal file
View file

@ -0,0 +1,152 @@
#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) */
} 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;
/* 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);
/* 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);

72
src/include/repl.h Normal file
View file

@ -0,0 +1,72 @@
#pragma once
/*
* repl.h — P2-1: Replicator structures and public API.
* Fan-out TCP replication via existing iomgr/SSL endpoint pipeline.
* ACKs processed in io_worker read callback (NOT vtaskmgr) to prevent deadlock.
*/
#include <pthread.h>
#include <stdatomic.h>
#include <stdint.h>
#include <time.h>
#include "config.h"
#include "mylock.h"
#include "wal_types.h" /* wal_entry_hdr_t — P2-4: use wal_types.h to break circular include */
/* Endpoint is an opaque pointer — full type in netio.h (avoid heavy include) */
typedef void* repl_ep_t;
/* Per-standby connection slot */
typedef struct {
repl_ep_t ep; /* NULL = slot empty */
_Atomic uint64_t acked_lsn; /* Last LSN ACKed by this standby */
_Atomic int in_catch_up; /* Non-zero while catching up */
uint64_t join_applied_lsn; /* LSN standby reported on reconnect */
char host[XCE_MAXNAME_LEN];
uint32_t port;
uint64_t last_disconnected_lsn;
time_t last_disconnect_time;
} standby_conn_t;
/* Replicator — embedded in persist_t or cluster_t (P2-4).
* Named tag replicator_s matches the forward declaration in persist.h. */
typedef struct replicator_s {
standby_conn_t standbys[MAX_STANDBYS];
int nstandbys; /* Active standby count */
mylock_t lock; /* Protects standbys[], nstandbys */
pthread_cond_t ack_cond; /* Signaled when any ACK arrives */
pthread_mutex_t ack_lock; /* Guards ack_cond */
} replicator_t;
/* Lifecycle */
int repl_init(replicator_t *r);
void repl_fini(replicator_t *r);
/* Standby management */
int repl_add_standby(replicator_t *r, repl_ep_t ep, const char *host, uint32_t port);
void repl_remove_standby(replicator_t *r, repl_ep_t ep);
void repl_expire_disconnect_slots(replicator_t *r, time_t now_s, uint32_t snap_interval_s);
/* Replication send (stub in P2-1; wired in P2-4) */
int repl_broadcast(replicator_t *r, const wal_entry_hdr_t *hdr,
const void *payload, uint32_t payload_len);
/* ACK handling — call from io_worker read callback ONLY */
void repl_on_ack(replicator_t *r, repl_ep_t ep, uint64_t acked_lsn);
/* Sync replication (stub in P2-1; wired in P2-3) */
int repl_wait_ack(replicator_t *r, uint64_t target_lsn, uint32_t timeout_ms);
/* WAL trim guard */
uint64_t repl_trim_lsn(replicator_t *r, uint64_t checkpoint_lsn, uint32_t snap_interval_s);
/* Catch-up state management */
/* Mark standby as entering catch-up mode; stores join_applied_lsn */
void repl_start_catchup(replicator_t *r, repl_ep_t ep, uint64_t join_applied_lsn);
/* Mark standby catch-up complete (called on OP_replCatchUpDone receipt) */
void repl_complete_catchup(replicator_t *r, repl_ep_t ep);
/* Returns 1 if standby needs a full snapshot transfer (its LSN predates oldest WAL).
* oldest_wal_lsn == 0 means no WAL exists — no snapshot needed for LSN 0 standbys. */
int repl_needs_snapshot(replicator_t *r, uint64_t standby_lsn, uint64_t oldest_wal_lsn);

View file

@ -200,4 +200,40 @@ typedef struct {
} body;
} xce_request_t;
/* ── Persistence Cap'n Proto mapped types (P0-9) ─────────────────────
* These are the C-side counterparts for the capnp encode/decode shims.
* Named with capnp_ prefix to avoid collision with the plain-C structs
* in persist.h (persist_config_t) and the on-disk binary formats. */
typedef struct {
uint32_t walSyncMs;
uint32_t snapIntervalS;
uint32_t snapWalSizeMb;
uint32_t finishedRetainS;
uint32_t workerRetainS;
uint32_t syncTimeoutMs;
uint32_t snapKeepN;
uint32_t transientJobTimeoutS;
} capnp_persist_cfg_t;
typedef struct {
uint64_t lsn;
uint64_t term;
uint64_t timestamp;
uint32_t version;
uint32_t nJobs;
uint32_t nQueues;
uint32_t nWorkers;
uint32_t checksum;
uint32_t headerChecksum;
} capnp_snap_hdr_t;
typedef struct {
uint64_t term;
uint64_t lsn;
uint32_t entryType;
xce_data_t* payload; /* owned; decoded via decode_Data_ptr */
uint32_t crc;
uint32_t prevCrc;
} capnp_repl_envelope_t;
#endif

58
src/include/wal_types.h Normal file
View file

@ -0,0 +1,58 @@
#pragma once
/*
* wal_types.h — WAL on-disk structures shared between persist.h and repl.h.
* Extracted in P2-4 to break the persist.h ↔ repl.h circular include.
*/
#include <stdint.h>
#include "config.h"
/* ── WAL payload helper structs ────────────────────────────────────────────
* These are the binary formats embedded after wal_entry_hdr_t for each type.
* All fields are native-endian (single-node WAL; replication uses capnp). */
/* WAL_JOB_START / FINISH / FAIL / STOP / RESUME / UPDATE / CKPT / PREASON / RUSAGE */
typedef struct {
uint64_t jobid;
uint32_t state; /* xce_job state flags after this transition */
uint32_t _pad;
} wal_jobstate_t;
/* WAL_QUEUE_CTRL — queue name is a NUL-terminated string immediately after
* this header. Total payload = sizeof(wal_queuehdr_t) + strlen(name)+1. */
typedef struct {
uint32_t status; /* xce_queue status flags after this transition */
} wal_queuehdr_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;

128
src/include/xce/cluster.h Normal file
View file

@ -0,0 +1,128 @@
/* src/include/xce/cluster.h — cluster discovery and reconnect API (P2.5-1)
*
* xce_connect_cluster() returns endpoint_t* (cast to void*).
* The SSL* is accessible as ((endpoint_t*)result)->ssl.
*/
#ifndef XCE_CLUSTER_H
#define XCE_CLUSTER_H
#include <stddef.h>
#include "config.h" /* MAX_HA_CANDIDATES, XCE_MAXHOSTNAME_LEN */
/**
* A single controller candidate.
* name: logical name from "name=host:port" syntax (empty if omitted).
* Matching against myconf->name allows multiple controllers on the same
* dev host to distinguish themselves by name rather than IP address.
*/
typedef struct {
char name[XCE_MAXNAME_LEN];
char hostname[XCE_MAXHOSTNAME_LEN];
int port;
} xce_candidate_t;
/**
* Cluster connection configuration.
* Populated by each caller (worker/scheduler/apiserver) from --peers and
* --ca-cert CLI flags. libxce never reads config files.
*
* candidates_count must be in [1, MAX_HA_CANDIDATES].
* A WARN is logged at startup if candidates_count > 3.
*/
typedef struct {
xce_candidate_t candidates[MAX_HA_CANDIDATES];
int candidates_count;
char ca_cert_path[4096]; /* path to CA cert for TLS verify */
char identity[256]; /* "from" name sent to controller */
char key[256]; /* authentication key */
} xce_cluster_config_t;
/**
* Reconnect state machine states.
*/
typedef enum {
XCE_RECONNECT_IDLE = 0,
XCE_RECONNECT_CONNECTING,
XCE_RECONNECT_BACKOFF,
XCE_RECONNECT_CONNECTED,
XCE_RECONNECT_FAILED
} xce_reconnect_state_t;
/**
* Reconnect context (use xce_reconnect_* functions to operate).
*/
typedef struct {
xce_cluster_config_t* config;
xce_reconnect_state_t state;
int attempt;
int backoff_ms; /* current backoff delay in ms */
void* endpoint; /* endpoint_t* when CONNECTED */
} xce_reconnect_ctx_t;
/* Redirect follow limit */
#define XCE_MAX_REDIRECTS 4
/* Backoff parameters — initial kept short so tests stay fast */
#define XCE_RECONNECT_INITIAL_BACKOFF_MS 100
#define XCE_RECONNECT_MAX_BACKOFF_MS 30000
#define XCE_RECONNECT_BACKOFF_MULTIPLIER 2
/* --- Public API --- */
/**
* xce_cluster_config_validate() — validate a populated xce_cluster_config_t.
*
* Returns 0 on success, -EINVAL if:
* - candidates_count < 1 or > MAX_HA_CANDIDATES
* - any candidate has empty hostname or port <= 0
* - ca_cert_path is empty
* - identity is empty
*/
int xce_cluster_config_validate(const xce_cluster_config_t* cfg);
/**
* xce_connect_cluster() — connect to the cluster via candidate list.
*
* Iterates candidates in order, attempting a TLS connection to each.
* Returns endpoint_t* (cast to void*) on success, NULL if all fail.
*/
void* xce_connect_cluster(xce_cluster_config_t* cfg);
/**
* xce_reconnect_init() — initialise a reconnect context.
* Returns 0 on success, -EINVAL on bad arguments.
*/
int xce_reconnect_init(xce_reconnect_ctx_t* rctx, xce_cluster_config_t* cfg);
/**
* xce_reconnect_step() — drive one step of the reconnect state machine.
*
* Call in a loop until state == XCE_RECONNECT_CONNECTED or FAILED.
* Sleeps backoff_ms in BACKOFF state (skipped when mock connect is set).
*
* Returns 0 to continue, -1 when in terminal state.
*/
int xce_reconnect_step(xce_reconnect_ctx_t* rctx);
/**
* xce_reconnect_fini() — release resources held by a reconnect context.
*/
void xce_reconnect_fini(xce_reconnect_ctx_t* rctx);
/**
* xce_parse_peers() — parse "--peers name=host:port,..." into cfg->candidates[].
*
* Each token may be "name=host:port" or bare "host:port".
* The name field is stored when present; it allows multiple daemons on the
* same host to identify themselves by logical name rather than IP address.
*
* Returns 0 on success, -1 on empty/NULL input or any parse error.
*/
int xce_parse_peers(const char* peers_str, xce_cluster_config_t* cfg);
/* Test seam: set to non-NULL to override the real connect (unit tests only) */
typedef void* (*xce_connect_fn_t)(const char* host, int port,
const char* ca_cert);
void xce_cluster_set_connect_fn(xce_connect_fn_t fn);
#endif /* XCE_CLUSTER_H */

View file

@ -14,7 +14,11 @@
#include "myconf.h"
#include "mylock.h"
#include "netio.h"
#include "persist.h"
#include "vtaskmgr.h"
/* ha.h forward-declares cluster_t; including it here is safe (no circular dep) */
#include "ha.h"
#include "xce/types.h"
#include "xlist.h"
#include "zarray.h"
@ -55,7 +59,9 @@ enum {
HOOK_DETAIL_QUEUE_UPDATE,
HOOK_DETAIL_USERGROUP_UPDATE,
HOOK_DETAIL_HOSTGROUP_UPDATE,
HOOK_DETAIL_JOB_RUSAGE_UPDATE
HOOK_DETAIL_JOB_RUSAGE_UPDATE,
HOOK_DETAIL_JOB_STOP,
HOOK_DETAIL_JOB_RESUME
};
#define XCE_NS_CONFIG (0)
@ -88,7 +94,7 @@ typedef struct {
endpoint_t* ep;
} cluster_apiserver_t;
typedef struct {
typedef struct cluster_s {
myconf_t* myconf;
xce_peerinfo_t* myhost;
hooksys_t hooksys;
@ -112,6 +118,8 @@ typedef struct {
vtaskmgr_t vtaskmgr;
cbuf_t wbuf;
int running;
persist_t persist; /* Persistence module — P0-F */
ha_state_t ha; /* HA role management — P1-5 */
} cluster_t;
#endif /* XCE_CLUSTER_DEF_H */

View file

@ -19,6 +19,8 @@ enum {
E_XCE_BAD_QUEUE,
E_XCE_BAD_GROUP,
E_XCE_INTERNAL,
E_XCE_NOMASTER, /* Standby has no known primary — client should retry */
E_XCE_REDIRECT, /* Standby is redirecting client to primary */
E_XCE_MAX
};

View file

@ -172,6 +172,7 @@ typedef struct {
#define XCE_WORKER_LOCKEDW (0x00040000)
#define XCE_WORKER_BUSY (0x00080000)
#define XCE_WORKER_CLOSED (0x00100000)
#define XCE_WORKER_HIDDEN (0x00200000) /* Admin explicitly removed — invisible but not yet cleaned up */
#define IS_WORKER_UNAVAIL(status) (((status) & XCE_WORKER_UNAVAIL) != 0)
#define IS_WORKER_LOCKEDU(status) (((status) & XCE_WORKER_LOCKEDU) != 0)
@ -353,7 +354,8 @@ typedef struct {
#define JOB_STAT_PDONE (0x80) /**< Post job process done successfully */
#define JOB_STAT_PERR (0x100) /**< Post job process has error */
#define JOB_STAT_WAIT (0x200) /**< Chunk job waiting its turn to exec */
#define JOB_STAT_WAIT (0x200) /**< Chunk job waiting its turn to exec */
#define JOB_STAT_TRANSIENT (0x400) /**< Job state uncertain after failover — awaiting worker re-join */
#define JOB_STAT_RUNKWN \
0x8000 /* Flag : Job status is UNKWN caused by losting contact with remote \
cluster */
@ -381,6 +383,7 @@ typedef struct {
#define QUEUE_STAT_DISC 0x10 /**< Remote queue status is disconnected. */
#define QUEUE_STAT_FAIRSHARE_DEFAULT \
0x20 /**< Fairshare queue with null user share defined*/
#define QUEUE_STAT_HIDDEN (0x0100) /**< Admin deleted — invisible but not yet cleaned up */
/* FIXME: improve following later */
#define JOB_IS_PEND(state) (((state) & JOB_STAT_PEND) != 0)
@ -472,6 +475,7 @@ typedef struct {
char* ckptinfo;
int64_t pending_ctrl;
xce_job_preason_t* pend_reasons;
uint64_t transient_since; /* epoch seconds; set when job enters JOB_STAT_TRANSIENT */
} xce_job_t;
typedef struct {