feat(ha-commit-barrier-rollout): persist_commit_barrier + legacy walAck retirement (task 2.2)
Barrier: watermark = current_lsn - 1 under p->lock (released before blocking), covered/nothing-appended/LSN-0 short-circuits, sync_timeout_ms fallback, engine code unmodified, ce==NULL vacuous. repl.c walAck track now engine-only (legacy acked_lsn>0 counting and walAck-reachable n_active==0 success deleted); configAck track byte-equivalent for task 5. 15/15 group; census 472/472.
This commit is contained in:
parent
611fbc8d7b
commit
8f688eace1
5 changed files with 106 additions and 54 deletions
|
|
@ -1042,10 +1042,13 @@ int persist_wal_sync_append(persist_t* p, uint32_t type,
|
|||
if (sync_err != 0)
|
||||
CTRL_METRIC_INC(ctrl_repl_degraded_count);
|
||||
} else {
|
||||
/* DEPRECATED legacy branch: engine-less (ce == NULL) unit-test
|
||||
* contexts plus the LSN-0 first entry. Connectivity-based counting;
|
||||
* committed_lsn is stored here only because no engine owns it.
|
||||
* Retired by ha-commit-barrier-rollout. */
|
||||
/* Residual non-engine branch: engine-less (ce == NULL) unit-test
|
||||
* contexts plus the LSN-0 first entry. The legacy connectivity-
|
||||
* based counting was retired by ha-commit-barrier-rollout task 2.2:
|
||||
* repl_wait_majority_ack now confirms LSN 0 immediately (documented
|
||||
* once-per-lifetime edge) and surfaces engine-less walAck waits as
|
||||
* -EINVAL via commit_submit, so the committed_lsn store below only
|
||||
* fires for the LSN-0 case (a no-op store of 0). */
|
||||
mylock_lock(&p->repl.lock);
|
||||
int has_standbys = (p->repl.nstandbys > 0);
|
||||
mylock_unlock(&p->repl.lock);
|
||||
|
|
@ -1171,19 +1174,58 @@ wal_commit_mode_t wal_classify(uint32_t wal_type, int detail)
|
|||
}
|
||||
}
|
||||
|
||||
/* Commit barrier helper — INERT RED stub (ha-commit-barrier-rollout task
|
||||
* 2.1; implemented in task 2.2). Returns a wrong sentinel so the task-2.1
|
||||
* tests fail on assertions, not linking. Task-2.2 contract (design.md
|
||||
* §Commit Barrier Helper): snapshot the appended watermark (current_lsn - 1
|
||||
* under p->lock), return 0 when committed_lsn already covers it (or nothing
|
||||
* appended), else commit_submit(WAIT, timeout_ms ? timeout_ms :
|
||||
* p->config.sync_timeout_ms) with the engine code passed through
|
||||
* unmodified. */
|
||||
/* Commit barrier helper (ha-commit-barrier-rollout task 2.2, design.md
|
||||
* §Commit Barrier Helper; Req 1.1, 1.2, 1.3).
|
||||
*
|
||||
* Handler-callable WAIT completion on the appended watermark: snapshot the
|
||||
* last-appended LSN, return 0 when the commit index already covers it,
|
||||
* else block in the commit engine until coverage or deadline. The engine
|
||||
* result is returned UNMODIFIED (0 / -ETIMEDOUT / -XCE_ERR_NOT_READY /
|
||||
* -EINVAL) so callers map it to their own error replies.
|
||||
*
|
||||
* Lock discipline: p->lock is held only for the current_lsn snapshot and
|
||||
* is released BEFORE commit_submit(WAIT) — the engine blocks on ce->lock
|
||||
* + condvar, and p->lock must never be held across it (engine
|
||||
* lock-ordering rule). */
|
||||
int persist_commit_barrier(persist_t* p, uint32_t timeout_ms)
|
||||
{
|
||||
(void)p;
|
||||
(void)timeout_ms;
|
||||
return -ENOSYS;
|
||||
uint64_t watermark;
|
||||
|
||||
if (p == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
/* Snapshot the last-appended watermark under p->lock. current_lsn is
|
||||
* the NEXT LSN to assign (persist.h invariant: committed_lsn <=
|
||||
* current_lsn - 1), so the highest appended entry is current_lsn - 1
|
||||
* (resolved contract, spec Implementation Notes 2.1). current_lsn ==
|
||||
* 0 means nothing was ever appended — vacuously satisfied. */
|
||||
pthread_mutex_lock(&p->lock);
|
||||
if (p->current_lsn == 0) {
|
||||
pthread_mutex_unlock(&p->lock);
|
||||
return 0;
|
||||
}
|
||||
watermark = p->current_lsn - 1;
|
||||
pthread_mutex_unlock(&p->lock);
|
||||
|
||||
/* Already covered — committed_lsn is monotone, so coverage observed
|
||||
* here can never regress. This check also absorbs the LSN-0 first
|
||||
* entry (watermark 0 vs committed_lsn 0): that once-per-lifetime entry
|
||||
* has no quorum contract (ha-commit-engine Implementation Notes) and
|
||||
* commit_submit would reject lsn == 0 anyway. */
|
||||
if (atomic_load_explicit(&p->committed_lsn, memory_order_acquire) >=
|
||||
watermark)
|
||||
return 0;
|
||||
|
||||
/* Engine not wired: legacy/bootstrap contexts have no engine commit
|
||||
* contract — there is nothing to wait on, so the barrier is a no-op.
|
||||
* Production always wires the engine (cluster_init_phase2). */
|
||||
if (p->repl.ce == NULL)
|
||||
return 0;
|
||||
|
||||
/* timeout_ms == 0 borrows the configured sync deadline (Req 1.2). */
|
||||
return commit_submit(p->repl.ce, watermark, COMMIT_MODE_WAIT,
|
||||
timeout_ms != 0 ? timeout_ms
|
||||
: p->config.sync_timeout_ms);
|
||||
}
|
||||
|
||||
/* Classified append at the hook seam (barrier-rollout task 1.2).
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue