feat(libxce-failover): wrap 18 reply-bearing xcecli_* ops in failover loop under per-ctx lock; correct nop OpCategory (task 5.1)

This commit is contained in:
Rongsong Shen 2026-06-17 03:57:51 +00:00
parent 8783ce5a9d
commit 4345974b54
5 changed files with 202 additions and 22 deletions

View file

@ -136,6 +136,41 @@ bool xcecli_retry_decide(api_ctx_t* ac, int* rc, bool is_write,
bool xcecli_retry_next(api_ctx_t* ac, int* rc, bool is_write,
xcecli_retry_t* st);
/*
* XCECLI_FAILOVER_CALL(ac, is_write, EXPR) — the shared XcecliRetryLoop wrapper
* (task 5.1). Turns a one-shot reply-bearing xce_* call into a transparent
* failover loop, holding the per-ctx lock (ac->failover.lock) for the FULL loop
* duration so concurrent ops on a shared ctx are serialised (CI2): the
* single-slot wbuf already implies one in-flight request per ctx; the lock makes
* that explicit and covers the reconnect/rotate window.
*
* ac — api_ctx_t* (already NULL-checked by the caller's guard)
* is_write — true for mutating ops (DUP-on-replay → success, 5.2), false reads
* EXPR — the unchanged one-shot xce_* call, evaluated each iteration; its
* rc is what the loop classifies and ultimately returns
*
* Evaluates to the final rc (>=0 success; -E_XCE_NOT_READY on no-primary budget
* exhaustion; terminal errors surfaced as-is). Used as the RHS of `return`.
*
* Implemented as a GCC/clang statement-expression so it yields a value and keeps
* each public xcecli_* signature/return convention intact (R1.3). The lock is
* released on every exit path because the do/while always falls through to the
* unlock before the result is produced.
*/
#define XCECLI_FAILOVER_CALL(ac, is_write, EXPR) \
__extension__({ \
api_ctx_t* _fo_ac = (ac); \
xcecli_retry_t _fo_st = XCECLI_RETRY_INIT(_fo_ac); \
int _fo_rc; \
mylock_lock(&_fo_ac->failover.lock); \
do { \
_fo_rc = (EXPR); \
} while ( \
xcecli_retry_next(_fo_ac, &_fo_rc, (is_write), &_fo_st)); \
mylock_unlock(&_fo_ac->failover.lock); \
_fo_rc; \
})
/*
* xcecli_ctx_recover (task 3.2) — repair the inner xce_ctx_t after a successful
* reconnect so the next xce_* attempt can proceed. Socket-free (no I/O, no