forked from lei.chen/myxce
feat(ha-term-safety): retire term-0 repl_broadcast live send; carry leader term on replication (task 3.4)
Closes bug-990: the live replicator repl_broadcast wire-encoded term=0 (entry.term was never set), so standbys persisted hdr.term=0 and took the legacy direct-apply path instead of the library (term,lsn) intake. Now the live broadcast and catch-up streamer carry the leader's real term + AE prev tuple; ha_apply_wal_catchup_entry routes every term-carrying entry through raft_on_append_entries_request -> on_persist_entry (leader term stamped), retiring the term-0 direct-apply. Standbys now persist the leader's real term and reconcile by (term,lsn); the live commit chain is end-to-end. 848/849/850 + persist-before-ACK + commit-barrier + bug-960 preserved. Proven at integration level; the definitive live STRICT_TERM failover run is env-blocked here (bug-924 overlayfs) and recommended on a real fs.
This commit is contained in:
parent
87242aa8e9
commit
efe621c124
11 changed files with 307 additions and 45 deletions
|
|
@ -440,6 +440,24 @@ static void record_entry_term(persist_t* p, uint64_t lsn, uint64_t term)
|
|||
p->term_index_count = lsn;
|
||||
}
|
||||
|
||||
/* entry_term_locked: the lock-free core of persist_entry_term — read the
|
||||
* recorded Raft term for `lsn` from the in-memory term index, applying the
|
||||
* legacy-0 rule (R1.8: a present term-0 entry maps to WAL_LEGACY_TERM; an absent
|
||||
* LSN returns 0). Caller MUST hold p->lock. Used by the append path
|
||||
* (persist_wal_async) to source the AppendEntries prev_log_term while already
|
||||
* under the lock — calling persist_entry_term there would re-acquire p->lock
|
||||
* and deadlock. */
|
||||
static uint64_t entry_term_locked(const persist_t* p, uint64_t lsn)
|
||||
{
|
||||
if (!p || lsn == 0)
|
||||
return 0;
|
||||
if (lsn <= p->term_index_count && p->term_index != NULL) {
|
||||
uint64_t raw = p->term_index[lsn - 1];
|
||||
return (raw == 0) ? WAL_LEGACY_TERM : raw;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Shrink the in-memory per-LSN term index so that every LSN > `keep_lsn` reads
|
||||
* back as absent (ha-term-safety task 2.2). Called from the truncate path after
|
||||
* the on-disk entries above keep_lsn are removed, keeping the term index
|
||||
|
|
@ -477,15 +495,11 @@ uint64_t persist_entry_term(const persist_t* p, uint64_t lsn)
|
|||
persist_t* mp = (persist_t*)p;
|
||||
pthread_mutex_lock(&mp->lock);
|
||||
|
||||
uint64_t result = 0;
|
||||
if (lsn <= mp->term_index_count && mp->term_index != NULL) {
|
||||
uint64_t raw = mp->term_index[lsn - 1];
|
||||
/* Legacy-zero rule (R1.8): a present entry carrying term 0 maps to the
|
||||
* single lowest-known real Raft term, applied uniformly so two legacy-0
|
||||
* entries at the same LSN match. Absent LSNs are caught by the bound
|
||||
* above and return 0. */
|
||||
result = (raw == 0) ? WAL_LEGACY_TERM : raw;
|
||||
}
|
||||
/* Legacy-zero rule (R1.8) lives in entry_term_locked: a present entry
|
||||
* carrying term 0 maps to the single lowest-known real Raft term, applied
|
||||
* uniformly so two legacy-0 entries at the same LSN match; absent LSNs
|
||||
* return 0. */
|
||||
uint64_t result = entry_term_locked(mp, lsn);
|
||||
|
||||
pthread_mutex_unlock(&mp->lock);
|
||||
return result;
|
||||
|
|
@ -744,7 +758,13 @@ int persist_wal_async(persist_t* p, uint32_t type,
|
|||
* Note: WAL_CHECKPOINT is blocked by the assert at function entry, so
|
||||
* every entry that reaches here is a replicable entry. */
|
||||
p->last_replicated_crc = hdr.crc;
|
||||
repl_broadcast(&p->repl, &hdr, payload, len);
|
||||
/* ha-term-safety task 3.4: source the AppendEntries prev_log_term (term of
|
||||
* the entry at hdr.lsn-1) under p->lock via the lock-free accessor, so the
|
||||
* live broadcast carries the leader's term + prev tuple and the standby
|
||||
* routes it through the library (raft_on_append_entries_request). 0 when
|
||||
* hdr.lsn == 1 (no predecessor). */
|
||||
uint64_t prev_log_term = entry_term_locked(p, hdr.lsn - 1);
|
||||
repl_broadcast(&p->repl, &hdr, payload, len, prev_log_term);
|
||||
|
||||
/* Rotate segment when full */
|
||||
if (p->seg_offset >= WAL_SEGMENT_SIZE_BYTES) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue