17 if (own_ts != peer_ts)
19 return own_ts < peer_ts;
21 return own_id < peer_id;
29 negotiator->peer_startup_timestamp_ms = frame->
timestamp_ms;
30 negotiator->have_peer_startup_timestamp =
true;
33 negotiator->last_peer_seen_ms = now_ms;
34 negotiator->have_last_peer_seen =
true;
41 bool peer_contact_recent =
false;
43 if (negotiator->have_last_peer_seen)
48 if (now_ms >= negotiator->last_peer_seen_ms)
52 peer_contact_recent = (elapsed < (
rte_timestamp_ms_t)negotiator->peer_lost_timeout_ms);
60 if (!negotiator->have_last_peer_seen)
66 else if (!peer_contact_recent)
80 negotiator->peer_id, negotiator->peer_startup_timestamp_ms);
89 negotiator->peer_state =
105 negotiator->peer_state =
114 negotiator->own_state =
119 if (((negotiator->own_state != old_own) || (negotiator->peer_state != old_peer))
120 && (negotiator->state_change_callback != NULL))
122 negotiator->state_change_callback(negotiator->own_state, old_own, negotiator->peer_state, old_peer,
123 negotiator->state_change_callback_ctx);
132 if ((negotiator == NULL) || (config == NULL) || (config->
channel == NULL))
137 negotiator->channel = config->
channel;
138 negotiator->own_id = config->
own_id;
139 negotiator->peer_id = config->
peer_id;
145 negotiator->own_startup_timestamp_ms =
147 negotiator->own_channel_degraded =
false;
149 negotiator->have_peer_startup_timestamp =
false;
150 negotiator->peer_startup_timestamp_ms = 0U;
151 negotiator->peer_channel_degraded =
false;
156 negotiator->have_last_peer_seen =
false;
157 negotiator->last_peer_seen_ms = 0U;
167 if (negotiator == NULL)
172 negotiator->own_channel_degraded =
176 negotiator->own_channel_degraded,
177 negotiator->own_startup_timestamp_ms);
182 negotiator_process_peer_frame(negotiator, &frame);
189 negotiator_process_peer_frame(negotiator, &frame);
192 negotiator_update_states(negotiator);
199 if (negotiator == NULL)
203 return negotiator->own_state;
208 if (negotiator == NULL)
212 return negotiator->peer_state;
217 if (negotiator == NULL)
221 return negotiator->own_startup_timestamp_ms;
226 if (negotiator == NULL)
230 return negotiator->peer_startup_timestamp_ms;
235 if (negotiator == NULL)
239 return negotiator->own_id;
244 if (negotiator == NULL)
248 return negotiator->peer_id;
rte_status_t rte_dual_negotiator_init(rte_dual_negotiator_t *negotiator, const rte_dual_negotiator_config_t *config)
Initializes a rte_dual_negotiator_t. Captures this instance's own startup timestamp once (rte_timer_n...
rte_status_t rte_dual_channel_receive_state_frame(rte_dual_channel_t *channel, rte_duration_ms_t timeout_ms, rte_dual_state_frame_t *out_frame)
Returns the most recently staged inbound STATE frame, actively polling the configured links if none w...
uint32_t rte_dual_negotiator_get_own_id(const rte_dual_negotiator_t *negotiator)
Returns this instance's own tie-break identifier (rte_dual_negotiator_config_t::own_id at init time)....
uint32_t rte_dual_negotiator_get_peer_id(const rte_dual_negotiator_t *negotiator)
Returns the expected peer's tie-break identifier (rte_dual_negotiator_config_t::peer_id at init time)...
rte_dual_state_t rte_dual_negotiator_get_peer_state(const rte_dual_negotiator_t *negotiator)
Returns this instance's last-known view of the peer's rte_dual_state_t.
rte_status_t rte_dual_negotiator_execute(rte_dual_negotiator_t *negotiator, rte_duration_ms_t receive_timeout_ms)
Drives one round of state negotiation: refreshes own_channel_degraded from the attached channel's cur...
rte_dual_state_t
State of one instance in a dual (two-redundant-instance) relationship, as decided by rte_dual_negotia...
uint64_t rte_dual_negotiator_get_own_startup_timestamp_ms(const rte_dual_negotiator_t *negotiator)
Returns this instance's own startup timestamp (captured at rte_dual_negotiator_init() time,...
rte_dual_channel_status_t rte_dual_channel_get_status(const rte_dual_channel_t *channel)
Returns the aggregate connection status across every configured redundant link, as of the most recent...
rte_dual_state_t rte_dual_negotiator_get_own_state(const rte_dual_negotiator_t *negotiator)
Returns this instance's own current rte_dual_state_t.
uint64_t rte_dual_negotiator_get_peer_startup_timestamp_ms(const rte_dual_negotiator_t *negotiator)
Returns this instance's last-known view of the peer's own startup timestamp (0/unset until the first ...
rte_status_t rte_dual_channel_send_state_frame(rte_dual_channel_t *channel, rte_dual_state_t state, bool channel_degraded, uint64_t timestamp_ms)
Sends a rte_dual_state_frame_t (rte_dual_frames.h) on every configured redundant link - fire-and-forg...
@ RTE_DUAL_CHANNEL_STATUS_FULL
@ RTE_DUAL_STATE_HOTSTANDBY
@ RTE_DUAL_STATE_COLDSTANDBY
rte_status_t
Common result/status codes.
@ RTE_STATUS_INVALID_PARAM
rte_status_t rte_timer_now(rte_timestamp_ms_t *out_now_ms)
Returns the current monotonic time base used by all timers.
uint32_t rte_duration_ms_t
uint64_t rte_timestamp_ms_t
static bool negotiator_decide_online(uint32_t own_id, uint64_t own_ts, uint32_t peer_id, uint64_t peer_ts)
Older-timestamp-wins tie-break, own_id/peer_id as the deterministic fallback on an exact tie - same r...
Dual state negotiator of ADR-020: decides rte_dual_state_t for both this instance and its peer,...
OS Abstraction Layer - Timer service.
Configuration for rte_dual_negotiator_init().
void * state_change_callback_ctx
rte_duration_ms_t peer_lost_timeout_ms
rte_dual_negotiator_state_change_callback_t state_change_callback
rte_dual_channel_t * channel
rte_dual_state_t resume_own_state
uint64_t resume_own_startup_timestamp_ms
One rte_dual_negotiator_t instance's state. Caller-owned storage; every field is private - reach it o...
RTE_DUAL_FRAME_KIND_STATE payload - rte_dual_negotiator_t's own periodic beacon.