Merge branch 'working' into job_peek_lchen
job_peek_lchen: Add fetchfile feature (job output/error peek proxy) working: HA/Raft infrastructure (consensus, replication, config mgmt) Conflict resolution summary: - controller.capnp: fetchfile @41, fetchfilereply @18, fetchfilemsg @30 - cluster.c: bifurcated OPCode_reply for fetchfile + config-push ACK - job.c: kept full fetchfile pending-request subsystem (~183 lines) - request.c: kept both xce_fetchfile_req() and XCE_RETRY_DEFAULTS - helper.c: added missing preVoteRequest/preVoteReply mappings - All 15 new test registrations (test_cbuf.c + 14 HA tests)
This commit is contained in:
commit
3a2094a461
529 changed files with 345174 additions and 5048 deletions
|
|
@ -18,11 +18,11 @@ meson build && ninja -C build
|
|||
Links against `libxce` from `src/lib/`.
|
||||
|
||||
## Conventions
|
||||
- C standard: C99 or later
|
||||
- C standard: gnu17
|
||||
- Format with `clang-format`
|
||||
- Headers in `include/`
|
||||
- Shared types defined in `src/include/xce/` (libxce)
|
||||
|
||||
## See Also
|
||||
- Shared library: `src/lib/CLAUDE.md`
|
||||
- Root guidelines: `/workspace/CLAUDE.md`
|
||||
- Root guidelines: `CLAUDE.md` (repo root)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include "client.h"
|
||||
#include "controller.capnp.h"
|
||||
#include "thread_pool.h"
|
||||
#include "xce/cluster.h"
|
||||
#include "xcecd_utils.h"
|
||||
#include "xcectx.h"
|
||||
|
||||
|
|
@ -13,14 +14,15 @@ typedef struct {
|
|||
} api_ctx_t;
|
||||
|
||||
typedef struct controller_connector_ctx_s {
|
||||
void* thread_pool;
|
||||
void* process_manager;
|
||||
char* remote_host;
|
||||
char* virtual_name;
|
||||
void** worker_list;
|
||||
int remote_port;
|
||||
int join_interval;
|
||||
bool running;
|
||||
void* thread_pool;
|
||||
void* process_manager;
|
||||
char* remote_host;
|
||||
char* virtual_name;
|
||||
void** worker_list;
|
||||
int remote_port;
|
||||
int join_interval;
|
||||
bool running;
|
||||
xce_cluster_config_t cluster_cfg; /* HA candidate list — empty means single-host mode */
|
||||
} controller_connector_ctx_t;
|
||||
extern controller_connector_ctx_t* cc_ctx;
|
||||
|
||||
|
|
|
|||
|
|
@ -229,6 +229,10 @@ int checking_connection()
|
|||
/**
|
||||
* @brief Joins the cluster using the provided host attributes.
|
||||
*
|
||||
* In HA mode (cc_ctx->cluster_cfg.candidates_count > 0), iterates through
|
||||
* all candidates until one accepts the join as primary. In single-host mode
|
||||
* the original path is taken unchanged.
|
||||
*
|
||||
* @param attrs Pointer to the host attributes structure.
|
||||
* @return int 0 on success, -1 on failure.
|
||||
*/
|
||||
|
|
@ -238,15 +242,65 @@ int xcecd_join_cluster(hostattrs_t* attrs)
|
|||
return -1;
|
||||
}
|
||||
|
||||
int rc;
|
||||
int role = HostRole_worker;
|
||||
|
||||
/* HA mode: try each candidate until we find the primary */
|
||||
if (cc_ctx != NULL && cc_ctx->cluster_cfg.candidates_count > 0) {
|
||||
for (int i = 0; i < cc_ctx->cluster_cfg.candidates_count; i++) {
|
||||
const char* host = cc_ctx->cluster_cfg.candidates[i].hostname;
|
||||
int port = cc_ctx->cluster_cfg.candidates[i].port;
|
||||
|
||||
/* Point cc_ctx at this candidate so init_client_config() picks it up */
|
||||
cc_ctx->remote_host = (char*)host;
|
||||
cc_ctx->remote_port = port;
|
||||
|
||||
XCECD_LOG(XCE_LOG_INFO,
|
||||
"xcecd_join_cluster: trying candidate %d: %s:%d",
|
||||
i, host, port);
|
||||
|
||||
init_client_config(&xce_client_cfg);
|
||||
xcecli_ctx_init(&xcecli_ctx, &xce_client_cfg);
|
||||
xcecli_set_handler(xcecli_ctx, &myreq_handler, NULL);
|
||||
|
||||
int rc = xcecli_start(xcecli_ctx);
|
||||
if (rc < 0) {
|
||||
XCECD_LOG(XCE_LOG_WARN,
|
||||
"xcecd_join_cluster: connect to %s:%d failed (rc=%d)",
|
||||
host, port, rc);
|
||||
xcecli_ctx_fini(xcecli_ctx); /* free context before next attempt */
|
||||
continue;
|
||||
}
|
||||
|
||||
rc = xcecli_join(xcecli_ctx, role, attrs);
|
||||
if (rc == 0) {
|
||||
XCECD_LOG(XCE_LOG_INFO,
|
||||
"xcecd_join_cluster: joined primary at %s:%d",
|
||||
host, port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Standby replied — try next candidate */
|
||||
XCECD_LOG(XCE_LOG_INFO,
|
||||
"xcecd_join_cluster: candidate %s:%d returned %d "
|
||||
"(likely standby redirect), trying next",
|
||||
host, port, rc);
|
||||
xcecli_stop(xcecli_ctx);
|
||||
xcecli_ctx_fini(xcecli_ctx); /* free context before next attempt */
|
||||
}
|
||||
|
||||
XCECD_LOG(XCE_LOG_ERROR,
|
||||
"xcecd_join_cluster: all %d candidates failed",
|
||||
cc_ctx->cluster_cfg.candidates_count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Single-host fallback (original path) */
|
||||
init_client_config(&xce_client_cfg);
|
||||
xcecli_ctx_init(&xcecli_ctx, &xce_client_cfg);
|
||||
xcecli_set_handler(xcecli_ctx, &myreq_handler, NULL);
|
||||
xcecli_start(xcecli_ctx);
|
||||
|
||||
rc = xcecli_join(xcecli_ctx, role, attrs);
|
||||
|
||||
int rc = xcecli_join(xcecli_ctx, role, attrs);
|
||||
if (rc < 0) {
|
||||
errno = -rc;
|
||||
XCECD_LOG(XCE_LOG_ERROR, "Call xcecli_join() failure: %s",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#include "sqlite3.h"
|
||||
#include "xcecd.h"
|
||||
#include "xce/cluster.h"
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
|
@ -248,6 +250,7 @@ static void master_rusages_callback(xce_job_rusages_t* rusages)
|
|||
free_xce_job_rusages(rusages);
|
||||
}
|
||||
|
||||
|
||||
static int check_xce_server_dir(char* myfile)
|
||||
{
|
||||
char* xce_server_dir = getenv("XCE_SERVER_DIR");
|
||||
|
|
@ -285,6 +288,10 @@ static int check_user(void)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* Long-option identifiers (beyond ASCII range to avoid collisions) */
|
||||
#define OPT_PEERS 256
|
||||
#define OPT_CA_CERT 257
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int opt;
|
||||
|
|
@ -293,6 +300,10 @@ int main(int argc, char* argv[])
|
|||
int config_flag = 0;
|
||||
char* custom_config_path = NULL;
|
||||
__attribute__((unused)) char worker_log[1024] = { 0 };
|
||||
const char* peers_str = NULL;
|
||||
const char* ca_cert_str = NULL;
|
||||
xce_cluster_config_t cluster_cfg = {0};
|
||||
int use_ha = 0; /* 1 when --peers given */
|
||||
|
||||
check_user();
|
||||
|
||||
|
|
@ -382,10 +393,18 @@ int main(int argc, char* argv[])
|
|||
return -1;
|
||||
}
|
||||
|
||||
while ((opt = getopt(argc, argv, "c:p:m:n:l:h")) != -1) {
|
||||
static struct option long_opts[] = {
|
||||
{ "peers", required_argument, NULL, OPT_PEERS },
|
||||
{ "ca-cert", required_argument, NULL, OPT_CA_CERT },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "c:p:m:n:l:h", long_opts, NULL))
|
||||
!= -1) {
|
||||
switch (opt) {
|
||||
case 'c':
|
||||
break; // Custom config file already handled above
|
||||
break; /* Custom config file already handled above */
|
||||
case 'p':
|
||||
if (config_flag) {
|
||||
fprintf(stderr, "Custom config file already specified, "
|
||||
|
|
@ -415,18 +434,25 @@ int main(int argc, char* argv[])
|
|||
if (logdir) {
|
||||
FREEUP(logdir);
|
||||
}
|
||||
|
||||
logdir = strdup(optarg);
|
||||
}
|
||||
break;
|
||||
case OPT_PEERS:
|
||||
peers_str = optarg;
|
||||
break;
|
||||
case OPT_CA_CERT:
|
||||
ca_cert_str = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
#ifdef VIRTUAL_CLUSTER
|
||||
printf("Usage: %s -n virtual_name [-p remote_port] [-m "
|
||||
"remote_host] [-l log_dir] [-h help]\n",
|
||||
"remote_host] [-l log_dir] [--peers list] "
|
||||
"[--ca-cert path] [-h help]\n",
|
||||
argv[0]);
|
||||
#else
|
||||
printf("Usage: %s [-p remote_port] [-m remote_host] [-l log_dir ] "
|
||||
printf("Usage: %s [-p remote_port] [-m remote_host] [-l log_dir] "
|
||||
"[--peers ctrl-1=host:port,...] [--ca-cert path] "
|
||||
"[-h help]\n",
|
||||
argv[0]);
|
||||
#endif
|
||||
|
|
@ -434,6 +460,47 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
}
|
||||
|
||||
/* P2.5-5: populate and validate xce_cluster_config_t when --peers given */
|
||||
if (peers_str) {
|
||||
if (xce_parse_peers(peers_str, &cluster_cfg) != 0) {
|
||||
fprintf(stderr,
|
||||
"xcecd: --peers parse error: expected "
|
||||
"\"[name=]host:port,...\" got \"%s\"\n",
|
||||
peers_str);
|
||||
return 1;
|
||||
}
|
||||
if (ca_cert_str) {
|
||||
strncpy(cluster_cfg.ca_cert_path, ca_cert_str,
|
||||
sizeof(cluster_cfg.ca_cert_path) - 1);
|
||||
}
|
||||
strncpy(cluster_cfg.identity, config.virutal_name,
|
||||
sizeof(cluster_cfg.identity) - 1);
|
||||
if (xce_cluster_config_validate(&cluster_cfg) != 0) {
|
||||
fprintf(stderr,
|
||||
"xcecd: invalid cluster config (missing ca-cert or "
|
||||
"identity?). Use --ca-cert and -n.\n");
|
||||
return 1;
|
||||
}
|
||||
if (cluster_cfg.candidates_count > 3) {
|
||||
fprintf(stderr,
|
||||
"xcecd: WARN: --peers has %d candidates; "
|
||||
"only <=3 validated for HA\n",
|
||||
cluster_cfg.candidates_count);
|
||||
}
|
||||
XCECD_LOG(XCE_LOG_INFO,
|
||||
"HA cluster config: %d candidate(s), identity=%s, "
|
||||
"ca_cert=%s",
|
||||
cluster_cfg.candidates_count, cluster_cfg.identity,
|
||||
cluster_cfg.ca_cert_path);
|
||||
use_ha = 1;
|
||||
} else {
|
||||
XCECD_LOG(XCE_LOG_INFO,
|
||||
"No --peers flag; using single-controller path "
|
||||
"(host=%s port=%d)",
|
||||
config.remote_host, config.remote_port);
|
||||
}
|
||||
/* use_ha and cluster_cfg are consumed after xcecd_start() sets cc_ctx */
|
||||
|
||||
struct stat st = { 0 };
|
||||
|
||||
if (stat(logdir, &st) == -1) {
|
||||
|
|
@ -539,6 +606,13 @@ int main(int argc, char* argv[])
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (use_ha && cc_ctx != NULL) {
|
||||
cc_ctx->cluster_cfg = cluster_cfg;
|
||||
XCECD_LOG(XCE_LOG_INFO,
|
||||
"HA mode active: %d candidates, primary will be auto-discovered",
|
||||
cluster_cfg.candidates_count);
|
||||
}
|
||||
|
||||
#ifndef VIRTUAL_CLUSTER
|
||||
if (!ipc_master_init(config.domain_sock_file)) {
|
||||
XCECD_LOG(XCE_LOG_ERROR, "Failed to initialize XCECD IPC.");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue