ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
state.h File Reference

Ring consensus state machine. More...

Go to the source code of this file.

Enumerations

enum  consensus_state_machine_t {
  CONSENSUS_STATE_IDLE = 0 , CONSENSUS_STATE_COLLECTION_START = 1 , CONSENSUS_STATE_COLLECTING = 2 , CONSENSUS_STATE_COLLECTION_COMPLETE = 3 ,
  CONSENSUS_STATE_ELECTION_START = 4 , CONSENSUS_STATE_ELECTING = 5 , CONSENSUS_STATE_ELECTION_COMPLETE = 6 , CONSENSUS_STATE_FAILED = 7
}
 State machine lifecycle states. More...

Functions

asciichat_error_t consensus_state_create (const uint8_t my_id[SESSION_ID_SIZE], const consensus_topology_t *topology, consensus_state_t **out_state)
 Initialize state machine with topology.
void consensus_state_destroy (consensus_state_t *state)
 Destroy state machine and free resources.
asciichat_error_t consensus_state_start_collection (consensus_state_t *state)
 Transition to COLLECTION_START state.
asciichat_error_t consensus_state_add_metrics (consensus_state_t *state, const participant_metrics_t *metrics)
 Add collected metrics from a participant.
asciichat_error_t consensus_state_collection_complete (consensus_state_t *state)
 Transition to COLLECTION_COMPLETE state.
asciichat_error_t consensus_state_compute_election (consensus_state_t *state)
 Run election algorithm and transition to ELECTION_COMPLETE.
asciichat_error_t consensus_state_reset_to_idle (consensus_state_t *state)
 Transition back to IDLE from ELECTION_COMPLETE.
consensus_state_machine_t consensus_state_get_current_state (const consensus_state_t *state)
 Get current state machine state.
asciichat_error_t consensus_state_get_elected_host (const consensus_state_t *state, uint8_t out_host_id[SESSION_ID_SIZE])
 Get elected host ID from last election.
asciichat_error_t consensus_state_get_elected_backup (const consensus_state_t *state, uint8_t out_backup_id[SESSION_ID_SIZE])
 Get elected backup host ID from last election.
bool consensus_state_is_leader (const consensus_state_t *state)
 Check if we are the elected leader for this round.
int consensus_state_get_metrics_count (const consensus_state_t *state)
 Get count of metrics collected in current round.
asciichat_error_t consensus_state_get_metric_at (const consensus_state_t *state, int index, participant_metrics_t *out_metrics)
 Get collected metrics at index.
asciichat_error_t consensus_state_store_election (consensus_state_t *state, int best, int backup)

Detailed Description

Ring consensus state machine.

Definition in file state.h.

Enumeration Type Documentation

◆ consensus_state_machine_t

State machine lifecycle states.

Enumerator
CONSENSUS_STATE_IDLE 

Waiting for round to start

CONSENSUS_STATE_COLLECTION_START 

Round started, prepare collection

CONSENSUS_STATE_COLLECTING 

Collecting metrics

CONSENSUS_STATE_COLLECTION_COMPLETE 

All metrics received

CONSENSUS_STATE_ELECTION_START 

Preparing election (leader only)

CONSENSUS_STATE_ELECTING 

Running election algorithm

CONSENSUS_STATE_ELECTION_COMPLETE 

Election result computed

CONSENSUS_STATE_FAILED 

Error state

Definition at line 19 of file state.h.

19 {
consensus_state_machine_t
State machine lifecycle states.
Definition state.h:19
@ CONSENSUS_STATE_COLLECTION_COMPLETE
Definition state.h:23
@ CONSENSUS_STATE_COLLECTION_START
Definition state.h:21
@ CONSENSUS_STATE_ELECTION_COMPLETE
Definition state.h:26
@ CONSENSUS_STATE_FAILED
Definition state.h:27
@ CONSENSUS_STATE_ELECTING
Definition state.h:25
@ CONSENSUS_STATE_ELECTION_START
Definition state.h:24
@ CONSENSUS_STATE_IDLE
Definition state.h:20
@ CONSENSUS_STATE_COLLECTING
Definition state.h:22

Function Documentation

◆ consensus_state_add_metrics()

asciichat_error_t consensus_state_add_metrics ( consensus_state_t * state,
const participant_metrics_t * metrics )

Add collected metrics from a participant.

Valid in: COLLECTING state Stores metrics in dynamic array (grows as needed, initial capacity 10)

Parameters
stateState machine handle
metricsParticipant metrics to store
Returns
ASCIICHAT_OK on success, ERROR_INVALID_STATE if not in COLLECTING state

Definition at line 93 of file state.c.

93 {
94 if (!state || !metrics) {
95 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters");
96 }
97
98 if (state->current_state != CONSENSUS_STATE_COLLECTING) {
99 return SET_ERRNO(ERROR_INVALID_STATE, "Invalid state for adding metrics: %d", state->current_state);
100 }
101
102 /* Grow array if needed */
103 if (state->metrics_count >= state->metrics_capacity) {
104 int new_capacity = state->metrics_capacity * 2;
105 participant_metrics_t *new_metrics =
106 SAFE_REALLOC(state->metrics, new_capacity * sizeof(participant_metrics_t), participant_metrics_t *);
107 state->metrics = new_metrics;
108 state->metrics_capacity = new_capacity;
109 }
110
111 /* Copy metrics into array */
112 memcpy(&state->metrics[state->metrics_count], metrics, sizeof(participant_metrics_t));
113 state->metrics_count++;
114
115 return ASCIICHAT_OK;
116}
#define SET_ERRNO(code,...)
#define SAFE_REALLOC(ptr, size, cast)
Definition common.h:285
@ ERROR_INVALID_STATE
@ ASCIICHAT_OK
Definition error_codes.h:46
@ ERROR_INVALID_PARAM

References ASCIICHAT_OK, CONSENSUS_STATE_COLLECTING, ERROR_INVALID_PARAM, ERROR_INVALID_STATE, SAFE_REALLOC, and SET_ERRNO.

Referenced by consensus_coordinator_on_stats_update().

◆ consensus_state_collection_complete()

asciichat_error_t consensus_state_collection_complete ( consensus_state_t * state)

Transition to COLLECTION_COMPLETE state.

Valid from: COLLECTING Transitions to: ELECTION_START (if leader) or IDLE (if not leader)

Parameters
stateState machine handle
Returns
ASCIICHAT_OK on success, ERROR_INVALID_STATE if transition invalid

Definition at line 118 of file state.c.

118 {
119 if (!state) {
120 return SET_ERRNO(ERROR_INVALID_PARAM, "State is NULL");
121 }
122
123 if (state->current_state != CONSENSUS_STATE_COLLECTING) {
124 return SET_ERRNO(ERROR_INVALID_STATE, "Invalid transition from state %d", state->current_state);
125 }
126
127 /* Transition: if we're leader, go to ELECTION_START; otherwise go to IDLE */
128 if (consensus_topology_am_leader(state->topology)) {
129 state->current_state = CONSENSUS_STATE_ELECTION_START;
130 } else {
131 state->current_state = CONSENSUS_STATE_IDLE;
132 }
133
134 return ASCIICHAT_OK;
135}
bool consensus_topology_am_leader(const consensus_topology_t *topology)
Check if I am the ring leader (last position).
Definition topology.c:85

References ASCIICHAT_OK, CONSENSUS_STATE_COLLECTING, CONSENSUS_STATE_ELECTION_START, CONSENSUS_STATE_IDLE, consensus_topology_am_leader(), ERROR_INVALID_PARAM, ERROR_INVALID_STATE, and SET_ERRNO.

◆ consensus_state_compute_election()

asciichat_error_t consensus_state_compute_election ( consensus_state_t * state)

Run election algorithm and transition to ELECTION_COMPLETE.

Valid from: ELECTION_START or ELECTION_COMPLETE Processes collected metrics to select best host and backup. Election selects host as participant with best score, backup as second-best. Score is computed from metrics: lower RTT + higher bandwidth = better score. Only leader should call this.

Parameters
stateState machine handle
Returns
ASCIICHAT_OK on success, ERROR_INVALID_STATE if not in ELECTION_START state

Definition at line 137 of file state.c.

137 {
138 if (!state) {
139 return SET_ERRNO(ERROR_INVALID_PARAM, "State is NULL");
140 }
141
142 if (state->current_state != CONSENSUS_STATE_ELECTION_START) {
143 return SET_ERRNO(ERROR_INVALID_STATE, "Invalid transition from state %d", state->current_state);
144 }
145
146 int best_idx = -1, backup_idx = -1;
147 asciichat_error_t result =
148 consensus_election_choose_hosts(state->metrics, state->metrics_count, &best_idx, &backup_idx);
149 if (result != ASCIICHAT_OK)
150 return result;
151 return consensus_state_store_election(state, best_idx, backup_idx);
152}
asciichat_error_t consensus_election_choose_hosts(const participant_metrics_t *metrics, int num_metrics, int *out_best_index, int *out_backup_index)
Elect best and backup host from metrics.
Definition election.c:79
asciichat_error_t
Error and exit codes - unified status values (0-255).
Definition error_codes.h:44
asciichat_error_t consensus_state_store_election(consensus_state_t *state, int best_idx, int backup_idx)
Definition state.c:154

References ASCIICHAT_OK, consensus_election_choose_hosts(), CONSENSUS_STATE_ELECTION_START, consensus_state_store_election(), ERROR_INVALID_PARAM, ERROR_INVALID_STATE, and SET_ERRNO.

◆ consensus_state_create()

asciichat_error_t consensus_state_create ( const uint8_t my_id[SESSION_ID_SIZE],
const consensus_topology_t * topology,
consensus_state_t ** out_state )

Initialize state machine with topology.

Creates a new state machine for managing consensus rounds. Initial state is CONSENSUS_STATE_IDLE.

Parameters
my_idMy 16-byte UUID
topologyTopology handle (not owned by state machine)
out_stateOutput state machine handle (caller must destroy)
Returns
ASCIICHAT_OK on success, error code otherwise

Definition at line 43 of file state.c.

44 {
45 if (!my_id || !topology || !out_state) {
46 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid state creation parameters");
47 }
48
49 consensus_state_t *state = SAFE_MALLOC(sizeof(*state), consensus_state_t *);
50 memset(state, 0, sizeof(*state));
51
52 state->current_state = CONSENSUS_STATE_IDLE;
53 state->topology = (consensus_topology_t *)topology; /* Cast away const for storage */
54 memcpy(state->my_id, my_id, SESSION_ID_SIZE);
55
56 /* Initialize metrics array with initial capacity of 10 */
57 state->metrics_capacity = 10;
58 state->metrics_count = 0;
59 state->metrics = SAFE_MALLOC(state->metrics_capacity * sizeof(participant_metrics_t), participant_metrics_t *);
60
61 memset(&state->election_result, 0, sizeof(election_result_t));
62
63 *out_state = state;
64 return ASCIICHAT_OK;
65}
#define SAFE_MALLOC(size, cast)
Definition common.h:265
#define SESSION_ID_SIZE
struct consensus_state consensus_state_t
State machine instance.
Election result storage.
Definition state.c:20
struct consensus_topology consensus_topology_t
Ring topology for consensus participants.

References ASCIICHAT_OK, CONSENSUS_STATE_IDLE, ERROR_INVALID_PARAM, SAFE_MALLOC, SESSION_ID_SIZE, and SET_ERRNO.

Referenced by consensus_coordinator_create(), and consensus_coordinator_on_ring_members().

◆ consensus_state_destroy()

void consensus_state_destroy ( consensus_state_t * state)

Destroy state machine and free resources.

Parameters
stateState machine handle (safe to pass NULL)

Definition at line 67 of file state.c.

67 {
68 if (state) {
69 if (state->metrics) {
70 SAFE_FREE(state->metrics);
71 }
72 SAFE_FREE(state);
73 }
74}
#define SAFE_FREE(ptr)
Definition common.h:377

References SAFE_FREE.

Referenced by consensus_coordinator_destroy(), and consensus_coordinator_on_ring_members().

◆ consensus_state_get_current_state()

consensus_state_machine_t consensus_state_get_current_state ( const consensus_state_t * state)

Get current state machine state.

Parameters
stateState machine handle
Returns
Current state (FAILED if state is NULL)

Definition at line 181 of file state.c.

181 {
182 if (!state) {
184 }
185 return state->current_state;
186}

References CONSENSUS_STATE_FAILED.

Referenced by consensus_coordinator_get_current_host(), consensus_coordinator_get_state(), consensus_coordinator_on_collection_start(), consensus_coordinator_on_election_result(), consensus_coordinator_on_ring_members(), consensus_coordinator_on_stats_update(), and consensus_coordinator_process().

◆ consensus_state_get_elected_backup()

asciichat_error_t consensus_state_get_elected_backup ( const consensus_state_t * state,
uint8_t out_backup_id[SESSION_ID_SIZE] )

Get elected backup host ID from last election.

Valid from: ELECTION_COMPLETE state

Parameters
stateState machine handle
out_backup_idOutput 16-byte backup UUID (caller provides buffer)
Returns
ASCIICHAT_OK on success, ERROR_INVALID_STATE if election not complete

Definition at line 202 of file state.c.

203 {
204 if (!state || !out_backup_id) {
205 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters");
206 }
207
208 if (state->current_state != CONSENSUS_STATE_ELECTION_COMPLETE) {
209 return SET_ERRNO(ERROR_INVALID_STATE, "Election not complete, current state: %d", state->current_state);
210 }
211
212 memcpy(out_backup_id, state->election_result.backup_id, SESSION_ID_SIZE);
213 return ASCIICHAT_OK;
214}

References ASCIICHAT_OK, CONSENSUS_STATE_ELECTION_COMPLETE, ERROR_INVALID_PARAM, ERROR_INVALID_STATE, SESSION_ID_SIZE, and SET_ERRNO.

Referenced by consensus_coordinator_get_current_host().

◆ consensus_state_get_elected_host()

asciichat_error_t consensus_state_get_elected_host ( const consensus_state_t * state,
uint8_t out_host_id[SESSION_ID_SIZE] )

Get elected host ID from last election.

Valid from: ELECTION_COMPLETE state

Parameters
stateState machine handle
out_host_idOutput 16-byte host UUID (caller provides buffer)
Returns
ASCIICHAT_OK on success, ERROR_INVALID_STATE if election not complete

Definition at line 188 of file state.c.

189 {
190 if (!state || !out_host_id) {
191 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters");
192 }
193
194 if (state->current_state != CONSENSUS_STATE_ELECTION_COMPLETE) {
195 return SET_ERRNO(ERROR_INVALID_STATE, "Election not complete, current state: %d", state->current_state);
196 }
197
198 memcpy(out_host_id, state->election_result.host_id, SESSION_ID_SIZE);
199 return ASCIICHAT_OK;
200}

References ASCIICHAT_OK, CONSENSUS_STATE_ELECTION_COMPLETE, ERROR_INVALID_PARAM, ERROR_INVALID_STATE, SESSION_ID_SIZE, and SET_ERRNO.

Referenced by consensus_coordinator_get_current_host().

◆ consensus_state_get_metric_at()

asciichat_error_t consensus_state_get_metric_at ( const consensus_state_t * state,
int index,
participant_metrics_t * out_metrics )

Get collected metrics at index.

Valid from: COLLECTING, COLLECTION_COMPLETE, or ELECTION states

Parameters
stateState machine handle
indexIndex of metric to retrieve (0-based)
out_metricsOutput metrics structure
Returns
ASCIICHAT_OK on success, error code otherwise

Definition at line 230 of file state.c.

231 {
232 if (!state || !out_metrics || index < 0) {
233 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters");
234 }
235
236 if (index >= state->metrics_count) {
237 return SET_ERRNO(ERROR_INVALID_PARAM, "Index %d out of bounds (count: %d)", index, state->metrics_count);
238 }
239
240 /* Valid to retrieve metrics in COLLECTING, COLLECTION_COMPLETE, or ELECTION states */
241 if (state->current_state != CONSENSUS_STATE_COLLECTING &&
242 state->current_state != CONSENSUS_STATE_COLLECTION_COMPLETE &&
243 state->current_state != CONSENSUS_STATE_ELECTION_START && state->current_state != CONSENSUS_STATE_ELECTING &&
244 state->current_state != CONSENSUS_STATE_ELECTION_COMPLETE) {
245 return SET_ERRNO(ERROR_INVALID_STATE, "Cannot retrieve metrics in state %d", state->current_state);
246 }
247
248 memcpy(out_metrics, &state->metrics[index], sizeof(participant_metrics_t));
249 return ASCIICHAT_OK;
250}
static bool size_t index
Definition queries.h:8

References ASCIICHAT_OK, CONSENSUS_STATE_COLLECTING, CONSENSUS_STATE_COLLECTION_COMPLETE, CONSENSUS_STATE_ELECTING, CONSENSUS_STATE_ELECTION_COMPLETE, CONSENSUS_STATE_ELECTION_START, ERROR_INVALID_PARAM, ERROR_INVALID_STATE, index, and SET_ERRNO.

◆ consensus_state_get_metrics_count()

int consensus_state_get_metrics_count ( const consensus_state_t * state)

Get count of metrics collected in current round.

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

Definition at line 223 of file state.c.

223 {
224 if (!state) {
225 return -1;
226 }
227 return state->metrics_count;
228}

Referenced by consensus_coordinator_get_metrics_count().

◆ consensus_state_is_leader()

bool consensus_state_is_leader ( const consensus_state_t * state)

Check if we are the elected leader for this round.

Parameters
stateState machine handle
Returns
true if we are the ring leader, false otherwise

Definition at line 216 of file state.c.

216 {
217 if (!state) {
218 return false;
219 }
220 return consensus_topology_am_leader(state->topology);
221}

References consensus_topology_am_leader().

◆ consensus_state_reset_to_idle()

asciichat_error_t consensus_state_reset_to_idle ( consensus_state_t * state)

Transition back to IDLE from ELECTION_COMPLETE.

Valid from: ELECTION_COMPLETE Transitions to: IDLE

Parameters
stateState machine handle
Returns
ASCIICHAT_OK on success, ERROR_INVALID_STATE if transition invalid

Definition at line 168 of file state.c.

168 {
169 if (!state) {
170 return SET_ERRNO(ERROR_INVALID_PARAM, "State is NULL");
171 }
172
173 if (state->current_state != CONSENSUS_STATE_ELECTION_COMPLETE) {
174 return SET_ERRNO(ERROR_INVALID_STATE, "Invalid transition from state %d", state->current_state);
175 }
176
177 state->current_state = CONSENSUS_STATE_IDLE;
178 return ASCIICHAT_OK;
179}

References ASCIICHAT_OK, CONSENSUS_STATE_ELECTION_COMPLETE, CONSENSUS_STATE_IDLE, ERROR_INVALID_PARAM, ERROR_INVALID_STATE, and SET_ERRNO.

Referenced by consensus_coordinator_on_election_result().

◆ consensus_state_start_collection()

asciichat_error_t consensus_state_start_collection ( consensus_state_t * state)

Transition to COLLECTION_START state.

Valid from: IDLE Transitions to: COLLECTING

Parameters
stateState machine handle
Returns
ASCIICHAT_OK on success, ERROR_INVALID_STATE if transition invalid

Definition at line 76 of file state.c.

76 {
77 if (!state) {
78 return SET_ERRNO(ERROR_INVALID_PARAM, "State is NULL");
79 }
80
81 if (state->current_state != CONSENSUS_STATE_IDLE) {
82 return SET_ERRNO(ERROR_INVALID_STATE, "Invalid transition from state %d", state->current_state);
83 }
84
85 /* Reset metrics from previous round */
86 state->metrics_count = 0;
87 memset(&state->election_result, 0, sizeof(election_result_t));
88
89 state->current_state = CONSENSUS_STATE_COLLECTING;
90 return ASCIICHAT_OK;
91}

References ASCIICHAT_OK, CONSENSUS_STATE_COLLECTING, CONSENSUS_STATE_IDLE, ERROR_INVALID_PARAM, ERROR_INVALID_STATE, and SET_ERRNO.

Referenced by consensus_coordinator_on_collection_start().

◆ consensus_state_store_election()

asciichat_error_t consensus_state_store_election ( consensus_state_t * state,
int best,
int backup )

Store a selector result while completing the current election.

Definition at line 154 of file state.c.

154 {
155 if (!state || state->current_state != CONSENSUS_STATE_ELECTION_START || best_idx < 0 ||
156 best_idx >= state->metrics_count || backup_idx < -1 || backup_idx >= state->metrics_count ||
157 backup_idx == best_idx)
158 return SET_ERRNO(ERROR_INVALID_STATE, "Invalid election result");
159 memcpy(state->election_result.host_id, state->metrics[best_idx].participant_id, SESSION_ID_SIZE);
160 memset(state->election_result.backup_id, 0, SESSION_ID_SIZE);
161 if (backup_idx >= 0)
162 memcpy(state->election_result.backup_id, state->metrics[backup_idx].participant_id, SESSION_ID_SIZE);
163 state->election_result.timestamp_ns = time_get_realtime_ns();
164 state->current_state = CONSENSUS_STATE_ELECTION_COMPLETE;
165 return ASCIICHAT_OK;
166}

References ASCIICHAT_OK, CONSENSUS_STATE_ELECTION_COMPLETE, CONSENSUS_STATE_ELECTION_START, ERROR_INVALID_STATE, SESSION_ID_SIZE, and SET_ERRNO.

Referenced by consensus_state_compute_election().