Persistence: a follower shows its leader's rows after a cache-claim rotation
Mantenedores costumam responder em até 1 dia
Ninguém assumiu esta issue ainda.
Avaliação
- Dificuldade
- 5/5
- Tempo estimado
- Mais de uma semana
- Facilidade para iniciantes
- 5/100
- Tipo de issue
- Bug
- Clareza
- Precisa de esclarecimento
- Status de atividade
- Ativa
- Stack de tecnologia
- sqlite, typescript
- Domínio
- databases
Direção de pesquisa
Start on the branch fix/persisted-follower-rotation (03b8c15ee) and read persisted.ts around scoped recovery and the commit-notice handling. The oracle lanes are in packages/db-sqlite-persistence-core/tests/persisted-oracle.test.ts, which you can run to see which mutant cells fail. Done means the open questions are resolved, the six mutants are still killed, and persisted.ts is reduced in code weight.
Escrita pelo modelo de indexação a partir do texto da issue.
Descrição
Summary
A follower tab whose persisted cache claim rotates can fail to show its leader's rows. #2128 fixes the follower's load ordering. Its review rounds also found a group of follower bugs that occur only around a cache-claim rotation. That work is too large to ship with #2128, so it moved to this issue. The work so far is on the branch fix/persisted-follower-rotation (03b8c15ee).
The problem
When a follower's cache claim rotates, the follower enters scoped recovery. Scoped recovery assumes that the Collection's own source supplies fresh rows, so it:
- refuses durable rows (
loadSubsetRowsUnsafereturns[]during scoped recovery). - turns every commit notice into another refetch (
invalidateFromCommittedTxUnsafecallsrefreshScopedSubsets).
A follower has no source of its own. Its rows arrive from the leader as durable commits and notices, and scoped recovery refuses both. The follower therefore never shows the leader's rows. Against a leader that commits on every ensure, each refetch causes another commit and another notice, so the follower loops. On main, the probe showed 10 ensures in 50 ms and no rows.
The design on the branch
The maintainer chose a root-cause design over threading an "owner evidence" flag through every reload path:
- While a rotated follower's reacquisition ensures are in flight, it holds the new generation's commit notices.
- When every active demand reacquires, it ends scoped recovery for that generation and applies the held notices through the normal path.
- If a reacquisition fails, scoped recovery stays, and the source reports the failure.
- Each scoped recovery owns its own reacquisition record. A newer recovery finishes the older record.
- Recovery can end only if this recovery rotated into a fresh generation and the node follows a leader.
- A demand that is released or aborted during reacquisition is ignored, and its
AbortErroris not reported. - A load that starts during reacquisition waits until reacquisition ends and its commits apply.
This design needs no getLeaderId() on the coordinator, so it has no public API change.
Bugs that the review rounds found and that the branch fixes
- The reconciliation reload, the seq-gap recovery, and the reset-term fence dropped the notice's evidence, so the follower looped or took an extra refetch round.
- A recovery with no rotation and no active demand ended scoped recovery at once and trusted the old cache again.
- A second rotation during reacquisition, with a leadership change, could leave notices held forever.
- A demand released during reacquisition kept scoped recovery in place and reported a false sync error.
- A load during reacquisition could settle while the leader's commits were still held.
- A queue flush could process held notices during reacquisition. In one topology the follower spun without yielding, on
mainas well.
Open questions
- A new demand after a superseded rotation as leader. In the cell "superseded as leader", a new demand
cloads and settles. It ends with no row. The node stays in scoped recovery after it rotates as leader, and the owner wrotecinto the superseded generation. The branch changed the cell to check only that the load settles. This is unproven. Before anyone accepts that expectation, decide whether it follows from the law or is a bug. - No retry after a failed reacquisition. Scoped recovery stays until a later rotation or cleanup. The lane prose records this as a limit. Decide whether this is the intended behavior.
- Code weight.
persisted.tson the branch is +119 net code lines againstmain. Look for reductions before review.
Oracle coverage on the branch
packages/db-sqlite-persistence-core/tests/persisted-oracle.test.ts has these lanes:
persistence.follower-generation-notice: commit before or after rotation, then a leader update, a gap notice, a reconciliation notice, or a peer notice.- Rotated reacquisition: two demands reacquire in either order, and an owner update can arrive between them. Any reacquisition can fail or be released. A new demand can start during reacquisition, and a rotation can be superseded as leader.
The branch kills these mutants:
| Mutant | Cells that fail |
|---|---|
| Notices are not held | 19 |
| Scoped recovery never ends | 21 |
| Recovery ends before every reacquisition settles | 19 |
| Recovery ends after a failure | 25 |
| A load does not wait during reacquisition | 20 |
| A superseded record never finishes | 18 |
#2128 keeps these lanes and pins the cells that its cut-down scope does not satisfy, with a comment that points to this issue.
Next steps
- Rebase or merge
fix/persisted-follower-rotationontomainafter #2128 merges. - Resolve the open questions above.
- Run a code review and an oracle review that reruns the mutants independently.
- Reduce code weight, then open the pull request.
Related: #2128, #2115.
- Linguagem predominante
- TypeScript
- Estrelas
- 3.9k
- Forks
- 272
- Merge médio
- 1d 48min
- PRs com merge (30d)
- 238
Preparar o ambiente
- Sem Dockerfile nem arquivo Docker Compose
- Tem um modelo de pull request
- Ler o guia de contribuição
Primeiros passos
- Leia a issue inteira e depois o guia de contribuição do projeto.
- Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
- Faça um fork do repositório e trabalhe em uma branch.
- Abra um pull request que referencie o número da issue.
Mais de TanStack/db
-
Dificuldade 5/5 Mais de uma semana Facilidade para iniciantes 12/100
Mantenedores costumam responder em até 1 dia
-
Ordered, limited live query over a string key commits `loading` first (and `orderBy().findOne()` since 0.11.1)Talvez já em andamento @KyleAMathews assumiu há 1 dia. Aberta
Dificuldade 4/5 3-5 dias Facilidade para iniciantes 18/100
Mantenedores costumam responder em até 1 dia
-
Dificuldade 5/5 Mais de uma semana Facilidade para iniciantes 18/100
Mantenedores costumam responder em até 1 dia
-
Dificuldade 4/5 3-5 dias Facilidade para iniciantes 18/100
Mantenedores costumam responder em até 1 dia
-
Dificuldade 5/5 Mais de uma semana Facilidade para iniciantes 8/100
Mantenedores costumam responder em até 1 dia
Todas as issues de TanStack/db
Issues semelhantes
-
test: make the #3408 Claude OAuth token fixture obviously fake so secret scanners stop flagging itAberta
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 76/100
code-yeongyu/senpi#3436 ·
Mantenedores costumam responder em até 1 dia
-
community first-timers-only good first issue hacktoberfest help wanted low hanging fruit up-for-grabs
Dificuldade 1/5 Menos de uma hora Facilidade para iniciantes 78/100
lingdojo/kana-dojo#32505 · 1 comentário · 5 reações ·
Mantenedores costumam responder em até 1 dia
-
code-quality refactoring
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 68/100
github/gh-aw-firewall#10040 ·
Mantenedores costumam responder em até 1 dia
-
review-followup
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 82/100
griffinwork40/agent-afk#3868 ·
Mantenedores costumam responder em até 1 dia
-
area: import-export bug status: needs-triage
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 78/100
amatya-aditya/obsidian-rss-dashboard#1191 ·
Mantenedores costumam responder em até 1 dia