1/* @ajax/mesh-jobs-copies: who keeps a payload's durable copies before its result is sent (jobs.rs
2 * `copies_for`, `COPIES`, and the resend times of pushes and fetches). Freestanding. */
3#ifndef MESH_JOBS_COPIES_H
4#define MESH_JOBS_COPIES_H
56#include <stdbool.h>
7#include <stdint.h>
89/* Durable copies of a payload before its result is sent (the member that ran it and the leader
10 * among them, when that many members are up). */
11#define MESH_JOBS_COPIES 3u
12/* A push not acknowledged is sent again after this long (ms). */
13#define MESH_JOBS_PUSH_RESEND_MS 2000u
14/* The leader asks the holders again for a blob it still lacks after this long (ms). */
15#define MESH_JOBS_FETCH_RESEND_MS 3000u
16/* Results the leader parks waiting for their blobs, at most (more are dropped: resent later). */
17#define MESH_JOBS_PARKED_MAX 100000u
1819static inline unsigned mj_popcount(uint32_t x) {
20 unsigned n = 0;
21 for (; x; x &= x - 1) n++;
22 return n;
23}
2425/* Who keeps the copies of a payload that member `me` ran: `me`, the leader, then the members after
26 * `me` (in id order, wrapping) that are `alive`, up to COPIES distinct members, none of `refused` (a
27 * full store) but the leader. False without a leader. */
28static inline bool mj_copies_for(uint32_t me, uint32_t n, bool has_leader, uint32_t leader, uint32_t alive, uint32_t refused,
29 uint32_t *out) {
30 if (!has_leader) return false;
31 uint32_t want = (uint32_t)1 << leader;
32 if ((refused >> me & 1) == 0) want |= (uint32_t)1 << me;
33 for (uint32_t i = 1; i < n; i++) {
34 uint32_t k = (me + i) % n;
35 if (mj_popcount(want) >= MESH_JOBS_COPIES) break;
36 if ((alive >> k & 1) != 0 && (refused >> k & 1) == 0) want |= (uint32_t)1 << k;
37 }
38 *out = want;
39 return true;
40}
4142#endif