ascii-chat 0.11.33
Video chat in your terminal
Loading...
Searching...
No Matches
coordinator.h File Reference

Ring consensus coordinator orchestration. More...

Go to the source code of this file.

Typedefs

typedef asciichat_error_t(* consensus_election_func_t) (void *context, consensus_state_t *state)
 Election callback function type.
 
typedef struct consensus_coordinator consensus_coordinator_t
 Opaque consensus coordinator handle.
 

Functions

asciichat_error_t consensus_coordinator_create (const uint8_t my_id[16], const consensus_topology_t *topology, consensus_election_func_t election_func, void *election_context, consensus_coordinator_t **out_coordinator)
 Initialize ring consensus coordinator.
 
void consensus_coordinator_destroy (consensus_coordinator_t *coordinator)
 Destroy coordinator and free resources.
 
asciichat_error_t consensus_coordinator_process (consensus_coordinator_t *coordinator, uint32_t timeout_ms)
 Main orchestration loop - call periodically.
 
asciichat_error_t consensus_coordinator_on_ring_members (consensus_coordinator_t *coordinator, const consensus_topology_t *new_topology)
 Update ring topology when participants change.
 
asciichat_error_t consensus_coordinator_on_collection_start (consensus_coordinator_t *coordinator, uint32_t round_id, uint64_t deadline_ns)
 Handle STATS_COLLECTION_START packet.
 
asciichat_error_t consensus_coordinator_on_stats_update (consensus_coordinator_t *coordinator, const uint8_t sender_id[16], const participant_metrics_t *metrics, uint8_t num_metrics)
 Handle STATS_UPDATE packet (metrics relayed from another participant)
 
asciichat_error_t consensus_coordinator_on_election_result (consensus_coordinator_t *coordinator, const uint8_t host_id[16], const uint8_t backup_id[16])
 Handle ELECTION_RESULT packet.
 
asciichat_error_t consensus_coordinator_get_current_host (const consensus_coordinator_t *coordinator, uint8_t out_host_id[16], uint8_t out_backup_id[16])
 Get currently elected host.
 
consensus_state_machine_t consensus_coordinator_get_state (const consensus_coordinator_t *coordinator)
 Get current coordinator state.
 
uint64_t consensus_coordinator_time_until_next_round (const consensus_coordinator_t *coordinator)
 Get time until next round is due.
 
int consensus_coordinator_get_metrics_count (const consensus_coordinator_t *coordinator)
 Get count of metrics collected in current round.
 

Detailed Description

Ring consensus coordinator orchestration.

Orchestrates the entire ring consensus flow:

  • Periodic round scheduling (5 minute intervals)
  • Metrics collection and relay around the ring
  • Election computation by leader
  • Result broadcasting and storage

The coordinator manages the state machine and calls appropriate functions based on the current consensus state and participant role.

Definition in file coordinator.h.

Typedef Documentation

◆ consensus_coordinator_t

Opaque consensus coordinator handle.

Definition at line 40 of file coordinator.h.

◆ consensus_election_func_t

typedef asciichat_error_t(* consensus_election_func_t) (void *context, consensus_state_t *state)

Election callback function type.

Called by coordinator when election needs to be computed by leader. The callback can run the deterministic election algorithm.

Parameters
contextApplication context (passed to create)
stateState machine with collected metrics
Returns
ASCIICHAT_OK on success, error code otherwise

Definition at line 35 of file coordinator.h.

Function Documentation

◆ consensus_coordinator_create()

asciichat_error_t consensus_coordinator_create ( const uint8_t  my_id[16],
const consensus_topology_t *  topology,
consensus_election_func_t  election_func,
void *  election_context,
consensus_coordinator_t **  out_coordinator 
)

Initialize ring consensus coordinator.

Creates a new coordinator for managing consensus rounds. The coordinator will automatically schedule rounds every 5 minutes.

Parameters
my_idMy 16-byte UUID
topologyTopology handle (not owned, must remain valid during coordinator lifetime)
election_funcCallback to run election algorithm (leader only)
election_contextApplication context passed to election_func
out_coordinatorOutput coordinator handle (caller must destroy)
Returns
ASCIICHAT_OK on success, error code otherwise

Initialize ring consensus coordinator.

Definition at line 43 of file coordinator.c.

45 {
46 if (!my_id || !topology || !election_func || !out_coordinator) {
47 return SET_ERRNO(
48 ERROR_INVALID_PARAM, "Invalid parameter: my_id=%p, topology=%p, election_func=%p, out_coordinator=%p",
49 (const void *)my_id, (const void *)topology, (const void *)election_func, (const void *)out_coordinator);
50 }
51
53 if (!coordinator) {
54 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate coordinator");
55 }
56
57 memset(coordinator, 0, sizeof(*coordinator));
58 memcpy(coordinator->my_id, my_id, 16);
59 coordinator->topology = topology;
60 coordinator->election_func = election_func;
61 coordinator->election_context = election_context;
62
63 /* Initialize state machine */
64 asciichat_error_t err = consensus_state_create(my_id, topology, &coordinator->state);
65 if (err != ASCIICHAT_OK) {
66 SAFE_FREE(coordinator);
67 return err;
68 }
69
70 /* Initialize round scheduling */
71 coordinator->last_round_start_ns = time_get_ns();
72 coordinator->next_round_id = 1;
73 coordinator->has_stored_result = false;
74
75 /* Register coordinator with named registry */
76 char coordinator_name[64];
77 snprintf(coordinator_name, sizeof(coordinator_name), "consensus_coordinator:node_%u", my_id[0]);
78 NAMED_REGISTER(coordinator, coordinator_name, "consensus_coordinator_t", "0x%tx", NULL);
79
80 /* Register child state with coordinator as parent */
81 NAMED_REGISTER(coordinator->state, "state", "consensus_state_t", "0x%tx", (uintptr_t)(const void *)(coordinator));
82
83 log_debug("Coordinator created for node %u, first round in 5 minutes", my_id[0]);
84
85 *out_coordinator = coordinator;
86 return ASCIICHAT_OK;
87}
#define SAFE_FREE(ptr)
Definition common.h:376
#define SAFE_MALLOC(size, cast)
Definition common.h:264
#define NAMED_REGISTER(ptr, name, type, fmt, parent_ptr)
Register any pointer with base name, type, format spec, and location (auto-suffix)
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it, returning the error code.
asciichat_error_t
Error and exit codes - unified status values (0-255)
Definition error_codes.h:49
@ ERROR_MEMORY
Definition error_codes.h:56
@ ASCIICHAT_OK
Definition error_codes.h:51
@ ERROR_INVALID_PARAM
#define log_debug(...)
Log a DEBUG message.
Definition log/log.h:548
uint64_t time_get_ns(void)
Get current monotonic time in nanoseconds.
Definition util/time.c:108
asciichat_error_t consensus_state_create(const uint8_t my_id[16], const consensus_topology_t *topology, consensus_state_t **out_state)
Initialize state machine with topology.
Definition state.c:50
Internal coordinator structure.
Definition coordinator.c:22
uint64_t last_round_start_ns
Definition coordinator.c:30
const consensus_topology_t * topology
Definition coordinator.c:24
consensus_election_func_t election_func
Definition coordinator.c:26
consensus_state_t * state
Definition coordinator.c:25

References ASCIICHAT_OK, consensus_state_create(), consensus_coordinator::election_context, consensus_coordinator::election_func, ERROR_INVALID_PARAM, ERROR_MEMORY, consensus_coordinator::has_stored_result, consensus_coordinator::last_round_start_ns, log_debug, consensus_coordinator::my_id, NAMED_REGISTER, consensus_coordinator::next_round_id, SAFE_FREE, SAFE_MALLOC, SET_ERRNO, consensus_coordinator::state, time_get_ns(), and consensus_coordinator::topology.

Referenced by session_consensus_create().

◆ consensus_coordinator_destroy()

void consensus_coordinator_destroy ( consensus_coordinator_t *  coordinator)

Destroy coordinator and free resources.

Parameters
coordinatorCoordinator handle (safe to pass NULL)

Destroy coordinator and free resources.

Definition at line 92 of file coordinator.c.

92 {
93 if (!coordinator) {
94 return;
95 }
96 consensus_state_destroy(coordinator->state);
97 SAFE_FREE(coordinator);
98}
void consensus_state_destroy(consensus_state_t *state)
Destroy state machine and free resources.
Definition state.c:74

References consensus_state_destroy(), SAFE_FREE, and consensus_coordinator::state.

Referenced by session_consensus_destroy().

◆ consensus_coordinator_get_current_host()

asciichat_error_t consensus_coordinator_get_current_host ( const consensus_coordinator_t *  coordinator,
uint8_t  out_host_id[16],
uint8_t  out_backup_id[16] 
)

Get currently elected host.

Retrieves the host and backup elected in the most recent successful round. If no round has completed yet, returns stored previous result if available, or an error if no result exists.

Parameters
coordinatorCoordinator handle
out_host_idOutput 16-byte host UUID (caller provides buffer)
out_backup_idOutput 16-byte backup UUID (caller provides buffer)
Returns
ASCIICHAT_OK on success, error code otherwise

Definition at line 379 of file coordinator.c.

380 {
381 if (!coordinator || !out_host_id || !out_backup_id) {
382 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameter");
383 }
384
385 /* Try to get from current state first */
387 if (current_state == CONSENSUS_STATE_ELECTION_COMPLETE) {
388 asciichat_error_t err = consensus_state_get_elected_host(coordinator->state, out_host_id);
389 if (err == ASCIICHAT_OK) {
390 err = consensus_state_get_elected_backup(coordinator->state, out_backup_id);
391 }
392 if (err == ASCIICHAT_OK) {
393 return ASCIICHAT_OK;
394 }
395 }
396
397 /* Fall back to stored result */
398 if (coordinator->has_stored_result) {
399 memcpy(out_host_id, coordinator->stored_host_id, 16);
400 memcpy(out_backup_id, coordinator->stored_backup_id, 16);
401 return ASCIICHAT_OK;
402 }
403
404 return SET_ERRNO(ERROR_INVALID_STATE, "No election result available");
405}
@ ERROR_INVALID_STATE
asciichat_error_t consensus_state_get_elected_backup(const consensus_state_t *state, uint8_t out_backup_id[16])
Get elected backup host ID from last election.
Definition state.c:230
asciichat_error_t consensus_state_get_elected_host(const consensus_state_t *state, uint8_t out_host_id[16])
Get elected host ID from last election.
Definition state.c:217
consensus_state_machine_t consensus_state_get_current_state(const consensus_state_t *state)
Get current state machine state.
Definition state.c:210
consensus_state_machine_t
State machine lifecycle states.
Definition state.h:18
@ CONSENSUS_STATE_ELECTION_COMPLETE
Definition state.h:25
uint8_t stored_host_id[16]
Definition coordinator.c:35
uint8_t stored_backup_id[16]
Definition coordinator.c:36

References ASCIICHAT_OK, CONSENSUS_STATE_ELECTION_COMPLETE, consensus_state_get_current_state(), consensus_state_get_elected_backup(), consensus_state_get_elected_host(), ERROR_INVALID_PARAM, ERROR_INVALID_STATE, consensus_coordinator::has_stored_result, SET_ERRNO, consensus_coordinator::state, consensus_coordinator::stored_backup_id, and consensus_coordinator::stored_host_id.

Referenced by session_consensus_get_elected_host(), and session_consensus_is_ready().

◆ consensus_coordinator_get_metrics_count()

int consensus_coordinator_get_metrics_count ( const consensus_coordinator_t *  coordinator)

Get count of metrics collected in current round.

Used for testing and monitoring. Returns the number of metrics currently collected in the state machine.

Parameters
coordinatorCoordinator handle
Returns
Number of metrics collected, or -1 if invalid

Get count of metrics collected in current round.

Definition at line 438 of file coordinator.c.

438 {
439 if (!coordinator || !coordinator->state) {
440 return -1;
441 }
442 return consensus_state_get_metrics_count(coordinator->state);
443}
int consensus_state_get_metrics_count(const consensus_state_t *state)
Get count of metrics collected in current round.
Definition state.c:250

References consensus_state_get_metrics_count(), and consensus_coordinator::state.

Referenced by session_consensus_get_metrics_count().

◆ consensus_coordinator_get_state()

consensus_state_machine_t consensus_coordinator_get_state ( const consensus_coordinator_t *  coordinator)

Get current coordinator state.

Parameters
coordinatorCoordinator handle
Returns
Current state from internal state machine

Definition at line 410 of file coordinator.c.

410 {
411 if (!coordinator || !coordinator->state) {
413 }
414 return consensus_state_get_current_state(coordinator->state);
415}
@ CONSENSUS_STATE_FAILED
Definition state.h:26

References CONSENSUS_STATE_FAILED, consensus_state_get_current_state(), and consensus_coordinator::state.

Referenced by session_consensus_get_state().

◆ consensus_coordinator_on_collection_start()

asciichat_error_t consensus_coordinator_on_collection_start ( consensus_coordinator_t *  coordinator,
uint32_t  round_id,
uint64_t  deadline_ns 
)

Handle STATS_COLLECTION_START packet.

Called when receiving a collection start message from the previous ring member. Prepares to collect metrics and transitions state machine.

Parameters
coordinatorCoordinator handle
round_idCollection round ID
deadline_nsUnix nanosecond deadline for this round
Returns
ASCIICHAT_OK on success, error code otherwise

Definition at line 288 of file coordinator.c.

289 {
290 if (!coordinator) {
291 return SET_ERRNO(ERROR_INVALID_PARAM, "Coordinator is NULL");
292 }
293
295 if (current_state != CONSENSUS_STATE_IDLE) {
296 return SET_ERRNO(ERROR_INVALID_STATE, "Cannot start collection, state is %d", current_state);
297 }
298
299 /* Start collection */
301 if (err != ASCIICHAT_OK) {
302 return err;
303 }
304
305 coordinator->next_round_id = round_id;
306 coordinator->collection_deadline_ns = deadline_ns;
307
308 /* Measure and add our metrics */
309 err = measure_and_add_metrics(coordinator);
310 if (err != ASCIICHAT_OK) {
311 log_warn("Failed to measure metrics: %d", err);
312 }
313
314 log_dev("Collection started: round_id=%u, deadline in %u seconds", round_id,
315 (unsigned int)((deadline_ns - time_get_ns()) / NS_PER_SEC_INT));
316
317 return ASCIICHAT_OK;
318}
#define log_warn(...)
Log a WARN message.
Definition log/log.h:574
#define log_dev(...)
Log a DEV message (most verbose, development only)
Definition log/log.h:534
#define NS_PER_SEC_INT
Definition time.h:157
asciichat_error_t consensus_state_start_collection(consensus_state_t *state)
Transition to COLLECTION_START state.
Definition state.c:83
@ CONSENSUS_STATE_IDLE
Definition state.h:19
uint64_t collection_deadline_ns
Definition coordinator.c:32

References ASCIICHAT_OK, consensus_coordinator::collection_deadline_ns, consensus_state_get_current_state(), CONSENSUS_STATE_IDLE, consensus_state_start_collection(), ERROR_INVALID_PARAM, ERROR_INVALID_STATE, log_dev, log_warn, consensus_coordinator::next_round_id, NS_PER_SEC_INT, SET_ERRNO, consensus_coordinator::state, and time_get_ns().

Referenced by session_consensus_on_collection_start().

◆ consensus_coordinator_on_election_result()

asciichat_error_t consensus_coordinator_on_election_result ( consensus_coordinator_t *  coordinator,
const uint8_t  host_id[16],
const uint8_t  backup_id[16] 
)

Handle ELECTION_RESULT packet.

Called when election result is received from leader. Verifies the election, stores the elected host/backup, and stores for fallback.

Parameters
coordinatorCoordinator handle
host_idElected host UUID
backup_idElected backup UUID
Returns
ASCIICHAT_OK on success, error code otherwise

Definition at line 351 of file coordinator.c.

352 {
353 if (!coordinator || !host_id || !backup_id) {
354 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameter");
355 }
356
357 /* Store the elected host and backup */
358 memcpy(coordinator->stored_host_id, host_id, 16);
359 memcpy(coordinator->stored_backup_id, backup_id, 16);
360 coordinator->has_stored_result = true;
361
362 log_info("Election result received: host=%u, backup=%u", host_id[0], backup_id[0]);
363
364 /* Transition state back to IDLE */
366 if (current_state == CONSENSUS_STATE_ELECTION_COMPLETE) {
368 if (err != ASCIICHAT_OK) {
369 log_warn("Failed to reset state to IDLE: %d", err);
370 }
371 }
372
373 return ASCIICHAT_OK;
374}
#define log_info(...)
Log an INFO message.
Definition log/log.h:561
asciichat_error_t consensus_state_reset_to_idle(consensus_state_t *state)
Transition back to IDLE from ELECTION_COMPLETE.
Definition state.c:197

References ASCIICHAT_OK, CONSENSUS_STATE_ELECTION_COMPLETE, consensus_state_get_current_state(), consensus_state_reset_to_idle(), ERROR_INVALID_PARAM, consensus_coordinator::has_stored_result, log_info, log_warn, SET_ERRNO, consensus_coordinator::state, consensus_coordinator::stored_backup_id, and consensus_coordinator::stored_host_id.

Referenced by session_consensus_on_election_result().

◆ consensus_coordinator_on_ring_members()

asciichat_error_t consensus_coordinator_on_ring_members ( consensus_coordinator_t *  coordinator,
const consensus_topology_t *  new_topology 
)

Update ring topology when participants change.

Called when the ring topology changes (participants join/leave). Updates internal topology reference and resets any in-progress round.

Parameters
coordinatorCoordinator handle
new_topologyNew topology handle (not owned, must remain valid)
Returns
ASCIICHAT_OK on success, error code otherwise

Definition at line 259 of file coordinator.c.

260 {
261 if (!coordinator || !new_topology) {
262 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameter");
263 }
264
265 /* Update topology reference */
266 coordinator->topology = new_topology;
267
268 /* Reset state if we're in the middle of a round */
270 if (current_state != CONSENSUS_STATE_IDLE) {
271 log_warn("Ring topology changed during round, resetting state");
272 consensus_state_destroy(coordinator->state);
273 coordinator->state = NULL;
274
275 asciichat_error_t err = consensus_state_create(coordinator->my_id, new_topology, &coordinator->state);
276 if (err != ASCIICHAT_OK) {
277 return err;
278 }
279 }
280
281 log_info("Ring topology updated");
282 return ASCIICHAT_OK;
283}

References ASCIICHAT_OK, consensus_state_create(), consensus_state_destroy(), consensus_state_get_current_state(), CONSENSUS_STATE_IDLE, ERROR_INVALID_PARAM, log_info, log_warn, consensus_coordinator::my_id, SET_ERRNO, consensus_coordinator::state, and consensus_coordinator::topology.

Referenced by session_consensus_set_topology().

◆ consensus_coordinator_on_stats_update()

asciichat_error_t consensus_coordinator_on_stats_update ( consensus_coordinator_t *  coordinator,
const uint8_t  sender_id[16],
const participant_metrics_t *  metrics,
uint8_t  num_metrics 
)

Handle STATS_UPDATE packet (metrics relayed from another participant)

Called when receiving metrics from previous ring member. Adds metrics to state machine and forwards to next member.

Parameters
coordinatorCoordinator handle
sender_idWho is sending this metrics update
metricsMetrics to relay
num_metricsCount of metrics in packet
Returns
ASCIICHAT_OK on success, error code otherwise

Handle STATS_UPDATE packet (metrics relayed from another participant)

Definition at line 323 of file coordinator.c.

325 {
326 if (!coordinator || !sender_id || !metrics) {
327 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameter");
328 }
329
331 if (current_state != CONSENSUS_STATE_COLLECTING) {
332 return SET_ERRNO(ERROR_INVALID_STATE, "Cannot accept metrics, state is %d", current_state);
333 }
334
335 /* Add all metrics to state */
336 for (int i = 0; i < num_metrics; i++) {
337 asciichat_error_t err = consensus_state_add_metrics(coordinator->state, &metrics[i]);
338 if (err != ASCIICHAT_OK) {
339 log_warn("Failed to add metric %d: %d", i, err);
340 }
341 }
342
343 log_debug("Received %d metrics from sender %u", num_metrics, sender_id[0]);
344
345 return ASCIICHAT_OK;
346}
asciichat_error_t consensus_state_add_metrics(consensus_state_t *state, const participant_metrics_t *metrics)
Add collected metrics from a participant.
Definition state.c:100
@ CONSENSUS_STATE_COLLECTING
Definition state.h:21

References ASCIICHAT_OK, consensus_state_add_metrics(), CONSENSUS_STATE_COLLECTING, consensus_state_get_current_state(), ERROR_INVALID_PARAM, ERROR_INVALID_STATE, log_debug, log_warn, SET_ERRNO, and consensus_coordinator::state.

Referenced by session_consensus_on_stats_update().

◆ consensus_coordinator_process()

asciichat_error_t consensus_coordinator_process ( consensus_coordinator_t *  coordinator,
uint32_t  timeout_ms 
)

Main orchestration loop - call periodically.

Checks if a new collection round should start and processes the current state. Should be called regularly (at least once per second) to ensure timely round scheduling.

Handles:

  • Round scheduling (triggers every 5 minutes)
  • Collection deadline enforcement (30 second deadline)
  • Metrics measurement and relay
  • Election computation (leader only)
  • Result storage and broadcasting
Parameters
coordinatorCoordinator handle
timeout_msTimeout for operation in milliseconds
Returns
ASCIICHAT_OK on success, error code otherwise

Main orchestration loop - call periodically.

Definition at line 221 of file coordinator.c.

221 {
222 (void)timeout_ms; /* Currently unused, but kept for future use */
223
224 if (!coordinator) {
225 return SET_ERRNO(ERROR_INVALID_PARAM, "Coordinator is NULL");
226 }
227
228 uint64_t now_ns = time_get_ns();
229
230 /* Check if we should start a new round */
231 if (should_start_new_round(coordinator, now_ns)) {
232 /* Only leader starts rounds */
233 if (consensus_topology_am_leader(coordinator->topology)) {
234 asciichat_error_t err = start_collection_round(coordinator, now_ns);
235 if (err != ASCIICHAT_OK) {
236 log_warn("Failed to start collection round: %d", err);
237 return err;
238 }
239 }
240 }
241
243
244 /* Check for collection timeout */
245 if (current_state == CONSENSUS_STATE_COLLECTING && has_collection_timed_out(coordinator, now_ns)) {
246 log_warn("Collection round timed out, completing early");
247 asciichat_error_t err = complete_collection(coordinator);
248 if (err != ASCIICHAT_OK) {
249 log_error("Failed to complete collection on timeout: %d", err);
250 }
251 }
252
253 return ASCIICHAT_OK;
254}
unsigned long long uint64_t
Definition common.h:59
#define log_error(...)
Log an ERROR message.
Definition log/log.h:587
bool consensus_topology_am_leader(const consensus_topology_t *topology)
Check if I am the ring leader (last position)
Definition topology.c:76

References ASCIICHAT_OK, CONSENSUS_STATE_COLLECTING, consensus_state_get_current_state(), consensus_topology_am_leader(), ERROR_INVALID_PARAM, log_error, log_warn, SET_ERRNO, consensus_coordinator::state, time_get_ns(), and consensus_coordinator::topology.

Referenced by session_consensus_process().

◆ consensus_coordinator_time_until_next_round()

uint64_t consensus_coordinator_time_until_next_round ( const consensus_coordinator_t *  coordinator)

Get time until next round is due.

Returns the number of nanoseconds until the next collection round is scheduled.

Parameters
coordinatorCoordinator handle
Returns
Nanoseconds until next round, or 0 if round is due now

Get time until next round is due.

Definition at line 420 of file coordinator.c.

420 {
421 if (!coordinator) {
422 return 0;
423 }
424
425 uint64_t now_ns = time_get_ns();
426 uint64_t next_round_ns = coordinator->last_round_start_ns + CONSENSUS_ROUND_INTERVAL_NS;
427
428 if (now_ns >= next_round_ns) {
429 return 0;
430 }
431
432 return next_round_ns - now_ns;
433}
#define CONSENSUS_ROUND_INTERVAL_NS
Definition coordinator.c:16

References CONSENSUS_ROUND_INTERVAL_NS, consensus_coordinator::last_round_start_ns, and time_get_ns().

Referenced by session_consensus_time_until_next_round().