feat(libxce-failover): 4-action status classifier with attempt-aware DUP-replay rule (task 2.1)
This commit is contained in:
parent
d11c6e1d89
commit
fa2ac05036
5 changed files with 222 additions and 1 deletions
60
src/lib/client_failover.c
Normal file
60
src/lib/client_failover.c
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* client_failover.c — StatusClassifier for the libxce-failover spec (task 2.1).
|
||||
*
|
||||
* Pure mapping from a reply status / transport rc to a failover action. No I/O,
|
||||
* no globals. See design.md "Components and Interfaces → StatusClassifier" and
|
||||
* requirements 2.5, 4.1, 4.2, 4.3, 4.5, 5.2.
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include "xce/client_failover.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "xce/errnox.h"
|
||||
|
||||
/*
|
||||
* Controller status codes (E_XCE_*) are positive enum values, but the failover
|
||||
* loop may observe them as negative -errno-style rc. Accept either sign by
|
||||
* comparing against the magnitude.
|
||||
*/
|
||||
static int fo_abs(int v)
|
||||
{
|
||||
return v < 0 ? -v : v;
|
||||
}
|
||||
|
||||
xce_fo_action_t xce_failover_classify(int status, bool is_write, int attempt)
|
||||
{
|
||||
/* Success: served by the primary. */
|
||||
if (status == 0)
|
||||
return XCE_FO_SUCCESS;
|
||||
|
||||
int code = fo_abs(status);
|
||||
|
||||
/* Idempotent-replay rule (5.2): a duplicate on a re-sent write means the
|
||||
* controller's client-jobid replay guard already applied our write — treat
|
||||
* it as success. On the first send (or a non-write), it is a genuine
|
||||
* duplicate and is surfaced unchanged. */
|
||||
if (code == E_XCE_DUP_JOB || code == EEXIST) {
|
||||
if (is_write && attempt > 0)
|
||||
return XCE_FO_SUCCESS;
|
||||
return XCE_FO_TERMINAL;
|
||||
}
|
||||
|
||||
/* Redirect / standby: a primary exists elsewhere, or this op is
|
||||
* primary-only — rotate promptly, no backoff (4.2, 4.3). */
|
||||
if (code == E_XCE_REDIRECT || code == E_XCE_STANDBY)
|
||||
return XCE_FO_RETRY_NOW;
|
||||
|
||||
/* No primary known yet / controller initializing or electing — rotate after
|
||||
* jittered backoff (4.1). */
|
||||
if (code == E_XCE_NOMASTER || code == E_XCE_NOT_READY)
|
||||
return XCE_FO_RETRY_BACKOFF;
|
||||
|
||||
/* Transport-level failures — reconnect/rotate and retry now (4.4). */
|
||||
if (code == ECONNREFUSED || code == ETIMEDOUT || code == ECONNRESET)
|
||||
return XCE_FO_RETRY_NOW;
|
||||
|
||||
/* Everything else — auth/permission/invalid/not-found and any unrecognized
|
||||
* status — is non-retriable and surfaced to the caller (4.5). */
|
||||
return XCE_FO_TERMINAL;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue