fix bug-1060 bug-1067
This commit is contained in:
parent
6067ba6c94
commit
61e1391cd0
28 changed files with 7021 additions and 2926 deletions
|
|
@ -123,30 +123,59 @@ int xcecli_try_wakeup(xcecli_ctx_t c, int status)
|
|||
|
||||
int xcecli_start(xcecli_ctx_t c)
|
||||
{
|
||||
int rc;
|
||||
int rc = -ECONNREFUSED;
|
||||
api_ctx_t* ctx = (api_ctx_t*)c;
|
||||
int i;
|
||||
int connected_idx = -1;
|
||||
|
||||
if (c == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = endpoint_connect(&(ctx->ep), ctx->conf->masters[0],
|
||||
ctx->conf->master_ports[0]);
|
||||
if (rc < 0) {
|
||||
/* Initial connect rotates through ALL configured masters, not just
|
||||
* masters[0] (bug-854 dead-first-master): if the first master is down
|
||||
* (connection-refused after a failover that killed it), a hardcoded
|
||||
* masters[0] connect fails the whole `client` session before the failover
|
||||
* loop — which only runs on an ALREADY-connected ctx — ever gets a chance
|
||||
* to rotate. Try each master in order; the first that connects becomes the
|
||||
* sticky cursor start. The subsequent ctrlstatus/op failover loop then
|
||||
* rotates onward to the authoritative primary as needed.
|
||||
*
|
||||
* ctx->ep was endpoint_init'd + bound to the iomgr in xcecli_init. A failed
|
||||
* endpoint_connect leaves the socket fd unusable, so before retrying the
|
||||
* NEXT master we must rebuild the endpoint exactly as xce_ctx_reconnect
|
||||
* does: endpoint_fini → endpoint_init (fresh fd) → re-set peer + re-bind the
|
||||
* iomgr (endpoint_connect needs ep->iomgr->ssl_ctx). */
|
||||
for (i = 0; i < ctx->conf->nmasters; i++) {
|
||||
if (i > 0) {
|
||||
endpoint_fini(&(ctx->ep));
|
||||
if (endpoint_init(&(ctx->ep), AF_INET, SOCK_STREAM, 0, 0) < 0)
|
||||
continue;
|
||||
endpoint_set_peer(&(ctx->ep), &(ctx->ctx.myinfo));
|
||||
ctx->ep.iomgr = &(ctx->ctx.iomgr);
|
||||
}
|
||||
rc = endpoint_connect(&(ctx->ep), ctx->conf->masters[i],
|
||||
ctx->conf->master_ports[i]);
|
||||
if (rc >= 0) {
|
||||
connected_idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (connected_idx < 0) {
|
||||
/* No master reachable at all — surface the last transport error. */
|
||||
endpoint_fini(&(ctx->ep));
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Initialize per-context failover state: sticky primary starts at
|
||||
* masters[0] (the initial connect target above), retry tunables default
|
||||
* to XCE_RETRY_DEFAULTS, and no rejoin hook is installed for pure clients.
|
||||
*/
|
||||
/* Initialize per-context failover state: sticky primary starts at the master
|
||||
* we actually connected to (not always index 0), retry tunables default to
|
||||
* XCE_RETRY_DEFAULTS, and no rejoin hook is installed for pure clients. */
|
||||
rc = mylock_init(&(ctx->failover.lock));
|
||||
if (rc < 0) {
|
||||
endpoint_fini(&(ctx->ep));
|
||||
return rc;
|
||||
}
|
||||
ctx->failover.cur_master = 0;
|
||||
ctx->failover.cur_master = connected_idx;
|
||||
ctx->failover.retry = XCE_RETRY_DEFAULTS;
|
||||
ctx->failover.rejoin_cb = NULL;
|
||||
ctx->failover.rejoin_arg = NULL;
|
||||
|
|
@ -414,11 +443,17 @@ int xcecli_ctrlstatus_primary(xcecli_ctx_t c, xce_ctrlstatus_t** status)
|
|||
|
||||
/* Bound the redirect loop by the configured failover retry budget so we
|
||||
* never spin unbounded chasing a never-appearing primary (each inner
|
||||
* xcecli_ctrlstatus already runs its own full reach-some-node failover). */
|
||||
* xcecli_ctrlstatus already runs its own full reach-some-node failover).
|
||||
* Floor it at the master-ring size so a standby-first / dead-first master
|
||||
* list is always traversable in full before giving up (bug-854): one extra
|
||||
* attempt lets the rotation that lands on the primary actually query it. */
|
||||
max_attempts = ctx->failover.retry.max_retries;
|
||||
if (max_attempts < 1) {
|
||||
max_attempts = 1;
|
||||
}
|
||||
if (ctx->conf != NULL && ctx->conf->nmasters + 1 > max_attempts) {
|
||||
max_attempts = ctx->conf->nmasters + 1;
|
||||
}
|
||||
|
||||
for (attempt = 0; attempt < max_attempts; attempt++) {
|
||||
hint = NULL;
|
||||
|
|
@ -436,21 +471,34 @@ int xcecli_ctrlstatus_primary(xcecli_ctx_t c, xce_ctrlstatus_t** status)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Non-authoritative HINT (standby/electing/init). Direct the next query
|
||||
* at the reported primary if we can map it to an address; otherwise let
|
||||
* the next xcecli_ctrlstatus rotate the configured master list. The
|
||||
* redirect hint is consumed one-shot by xce_failover_next_target. */
|
||||
/* Non-authoritative reply (standby/electing/init). The inner
|
||||
* xcecli_ctrlstatus SUCCEEDS against ANY reachable node — ctrlstatus is
|
||||
* answerable in every role — so it classifies the standby's status-0
|
||||
* reply as success and NEVER rotates off it on its own. We must advance
|
||||
* the endpoint here, or the loop re-queries the same non-primary every
|
||||
* attempt and exhausts the budget without ever reaching the primary
|
||||
* (bug-854). Capture a redirect hint when the responder named the primary
|
||||
* (1-hop direct redirect), then FORCE rotation: xce_failover_rotate
|
||||
* consumes the hint when set, else advances to the next configured
|
||||
* master; recover repairs the ctx so the next attempt's send proceeds.
|
||||
* Mirror xcecli_retry_next: only recover when the rotate succeeded — a
|
||||
* failed rotate leaves the ctx for the next inner call's own transport-
|
||||
* error failover to heal. All under failover.lock (the inner call takes
|
||||
* and releases it itself, so it is not held here). */
|
||||
{
|
||||
char phost[XCE_MAXHOSTNAME_LEN];
|
||||
uint16_t pport = 0;
|
||||
|
||||
mylock_lock(&ctx->failover.lock);
|
||||
if (xcecli_ctrlstatus_primary_addr(hint, phost, sizeof(phost),
|
||||
&pport)
|
||||
== 0) {
|
||||
mylock_lock(&ctx->failover.lock);
|
||||
xce_ctx_capture_redirect_hint(&ctx->ctx, phost, pport);
|
||||
mylock_unlock(&ctx->failover.lock);
|
||||
}
|
||||
if (xce_failover_rotate(ctx) == 0) {
|
||||
xcecli_ctx_recover(ctx);
|
||||
}
|
||||
mylock_unlock(&ctx->failover.lock);
|
||||
}
|
||||
|
||||
/* Free the non-authoritative interim reply before the next attempt — no
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue