Skip to content

backport(2026.10.7): rep __rep_cmp_vote total order (election can elect older data) - #267

Merged
gburd merged 2 commits into
lts/2026.10.7from
backport/2026.10.7/rep-elect-datagen
Nov 4, 2026
Merged

gburd merged 2 commits into
lts/2026.10.7from
backport/2026.10.7/rep-elect-datagen

Conversation

@gburd

@gburd gburd commented Nov 4, 2026

Copy link
Copy Markdown
Collaborator

Backport to lts/2026.10.7: __rep_cmp_vote total order (election can elect older data)

Cherry-pick (-x) of the master fix for the __rep_cmp_vote election
comparator defect. lts/2026.10.7 has the identical function
(src/rep/rep_elect.c, byte-for-byte the same as master pre-fix).

The comparator was not a total order: the first vote was adopted outright and
the equal-LSN arm bypassed data_gen, so a site with an OLDER data_gen but an
equal last-commit LSN and a higher priority/tiebreaker could be elected over a
newer site — rolling back a durable commit on sync (__rep_verify memcmp).
Fixed as a single total order (electable > not; non-zero priority > zero;
data_gen; LSN; priority; tiebreaker; eid). See the master PR and
test/rep/E1-FINDINGS.md for the full analysis, reachability write-up, and the
mixed-version rolling-upgrade note.

Depends on master PR #266 (merge there first; the -x trailer points at
9b31ea4ec).

LTS gates (dev box, Debian 12)

  • L1 region signature: 0xe67a9de8 on both lts/2026.10.7 base and this
    backport — unchanged.
  • L2 soname + ABI: libdb-2026.0.so, 1972 exported symbols, identical
    symbol set to base. Comparator-only change; no format/ABI/region change.
  • L3 gate FAIL→PASS: test/db/run_rep_cmpvote_order.sh PASSES on the
    backport (copy-check ok against the now-fixed LTS src); the pre-fix arm
    (-DCMPVOTE_OLD) FAILS (bug reproduced), so the gate has teeth.
  • L4: cherry-picked with -x (cherry picked from commit 9b31ea4ec…).
  • Regressions: the election set
    (rep002/005/016/020/022/026/063/067/069/076/093/094) all PASS on the
    backport (non-diagnostic --enable-test --enable-tcl).

Note: --enable-diagnostic rep election tests panic on a pre-existing RFC
0010 A3 lock-order artifact in src/rep/rep_backup.c, reproducing identically
on the lts/2026.10.7 base — unrelated to this change (flagged to the lead).

…gen bypass)

The election winner comparator __rep_cmp_vote (src/rep/rep_elect.c) was not a
consistent order, with two defects:

  1. The first vote (rep->sites == 1) was adopted outright, so the winner
     depended on which vote a site tallied first.
  2. The last arm (equal LSN => higher priority / tiebreaker) fired regardless
     of data_gen, so a vote with an OLDER data_gen but an equal LSN and a
     higher priority or tiebreaker could beat a vote with a NEWER data_gen.

Defect 2 is a durability bug, not just a failure to settle: electing a site
with older data rolls back a commit the newer site already had (a client
memcmp's the log bytes at its verify LSN in __rep_verify, so a wrong winner
genuinely truncates the loser's tail).  The precondition -- two electable
sites with EQUAL last-commit LSN and DIFFERENT data_gen -- was reproduced
against the live engine (test/rep/E1-FINDINGS.md): a VOTE1 carries the LSN of
the last __txn_regop and the highest gen in REPLSNHIST, and these are
independent, so equal LSN with different data_gen is reachable.

Rewrite __rep_cmp_vote as a single TOTAL ORDER, applied uniformly to every
vote including the first: electable > not; non-zero priority > zero (the
mixed-version ELECTABLE semantics are preserved); then data_gen, LSN, priority,
tiebreaker, and finally eid as the always-distinct discriminator so the
relation is total even if two sites draw equal random tiebreakers.  Because
rep->winner is not reset between elections, the first vote is detected by
rep->sites == 1 (reset in __rep_elect_done), not by rep->winner.

Gate: test/db/run_rep_cmpvote_order.sh drives a verbatim copy of the real
comparator (drift-checked by check_rep_cmpvote_copy.sh) over the captured vote
vectors in every arrival order; it PASSES on the fix and FAILS with -DCMPVOTE_OLD
(the pre-fix comparator).  lts/2026.10.7 has the identical function; backport to
follow.

(cherry picked from commit 9b31ea4)
@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

Coccinelle convention checks

No new violations. ✅

Resolved since baseline (3) -- update dist/cocci/baseline.txt to lock these in.
rule_mutex_unbalanced|MUTEX_UNBALANCED|src/btree/bt_curadj.c|return (ret);
rule_mutex_unbalanced|MUTEX_UNBALANCED|src/crypto/mersenne/mt19937db.c|return (ret);
rule_mutex_unbalanced|MUTEX_UNBALANCED|src/mp/mp_register.c|return (ret);

@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

ABI diff vs v2026.10.7.2 (libabigail — authoritative)

abidiff exit bitmask: 0

Removed exported symbols (nm -D, _NNNN version suffix normalized)

None.


Advisory: libabigail/nm is the authoritative binary-ABI check; Coccinelle is complementary source-level early warning. See dist/cocci/README.md.

…s not do

The comment called eid an always-distinct discriminator that makes every
site agree on the winner.  eids are local: repmgr numbers sites in the order
it learns of them, so two sites can give the same peer different eids.  The
eid step makes each site's order total, which is what order independence
needs.  Agreement between sites rests on the random 32-bit tiebreaker, as it
did before; an exact collision costs an extra election round, not a second
master.  Comment-only; the copy in rep_cmpvote_order.c follows.

(cherry picked from commit c6e1030)
@gburd

gburd commented Nov 4, 2026

Copy link
Copy Markdown
Collaborator Author

Lead: cherry-picked c6e1030 with -x as 9ae6f38 (comment-only). test/rep/E1-FINDINGS.md is master-only, so the cherry-pick drops it.

@gburd
gburd marked this pull request as ready for review November 4, 2026 21:56
@gburd
gburd merged commit 4b02ada into lts/2026.10.7 Nov 4, 2026
60 of 61 checks passed
@gburd
gburd deleted the backport/2026.10.7/rep-elect-datagen branch November 4, 2026 21:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant