Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

sqlite-persistence: leader term write on every page load delays reading rows

已关闭
#2,205 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

已经有一个关联 PR 被合并了。

  • #2219 来自 @KyleAMathews —— 已合并

评估

难度
4/5
预计耗时
3-5 天
新手友好度
50/100
Issue 类型
缺陷
描述清晰度
基本清楚
活跃度
活跃
技术栈
sqlite, typescript

调研方向

Start in BroadcastCollectionCoordinator, where the issue says collection election and term reservation occur, and trace subscribe through ensureCollectionState to acquireLeadership. Then follow the listed route waits and first-read completion path to see where ensureLeadership could start election; compare the two described patch shapes. Done means rows can be read before an eager collection reserves its term, while route waits still trigger election and terms, locks, and heartbeats retain their behavior.

由索引模型根据 Issue 内容生成。

描述

  • I've validated the bug against the latest version of DB packages
Describe the bug

Every page load, each persisted collection starts leader election as soon as it subscribes (subscribe → ensureCollectionState → acquireLeadership) and reserves a new term, a durable write, even though nothing has asked for a leader yet. On the browser OPFS adapter the driver runs one operation at a time and a transaction counts as one, so the term transaction sits in the queue ahead of the rows being read. Eager collections don't need a leader to read their rows, so this is time spent waiting on a write they don't use yet.

Trace of one collection's term on a reload (start ms, duration ms):

181.1  0.9  BEGIN IMMEDIATE
182.0  0.6  SELECT schema_version FROM collection_registry …
182.6  3.9  INSERT INTO leader_term (collection_id, latest_term) VALUES (?, ? + 1) ON CONFLICT …
186.5  0.4  SELECT latest_term FROM leader_term …
186.6  0.4  SELECT MAX(seq) AS max_seq FROM applied_tx …
186.6  0.6  SELECT latest_row_version FROM collection_version …
187.2  5.0  COMMIT
192.2  0.7  BEGIN IMMEDIATE
193.1  0.4  SELECT key, value, metadata, row_version FROM "c_qvzbpr_8"

That's about 11 ms for this collection, and every collection pays it before its rows are read.

To reproduce
  1. @tanstack/browser-db-sqlite-persistence 0.2.36, @tanstack/db-sqlite-persistence-core 0.4.11
  2. OPFS database, 8 persisted collections (syncMode: "eager", schemaVersion: 1, BrowserCollectionCoordinator), all preloaded at once, fill them once, reload
  3. Log the database's execute calls
Expected behavior

Start a collection's election the first time it needs a leader instead of when it subscribes: when its first read finishes, or when something waits for a route (requestEnsureRemoteSubset, requestApplyCommittedTx, requestApplyLocalMutations, reconcileCommittedTx). Terms, locks and heartbeats stay as they are, only the timing changes.

Every route wait would need to start the election through ensureLeadership, or a single tab could wait for a leader that never gets elected. A first write would then wait for the read plus the term instead of just the term, a few ms.

A second option: keep electing at subscribe, but send the term write through the shared scheduler, so it waits behind reads that are already queued. I'm less sure of this one. A comment in main says election skips the scheduler on purpose, because a hydrate can be waiting for its first writer route. If the term write queued behind that hydrate, each would wait for the other. My test has no remote sync, so it never hit that case. The first option avoids it.

Numbers

Both shapes take 18–26 ms off the time until the first three collections have read their rows from disk, and both keep every term write.

I tried both as small patches to BroadcastCollectionCoordinator: one starts a collection's election once its first read finishes, the other runs reserveLeadershipTerm through adapter.runInRegularScope. Headless Chromium, 8 collections, 3 runs of 15 reloads, all variants alternating. Medians in ms from creating the collections until their rows were read.

First 3 collections read:

Run Election after first read Term through the scheduler
1 134 → 108 (−26) 134 → 113 (−21)
2 133 → 110 (−23) 133 → 107 (−26)
3 129 → 110 (−19) 129 → 111 (−18)

All 8 read:

Run Election after first read Term through the scheduler
1 234 → 213 (−21) 234 → 224 (−10)
2 237 → 228 (−9) 237 → 214 (−23)
3 234 → 214 (−20) 234 → 215 (−19)
Desktop

Headless Chromium 141 on Linux.

Additional context

Related to #2204, which is about the table setup each collection runs on the same path.

Happy to send a PR with an oracle test if you want this.

主要语言
TypeScript
星标
3.9k
派生
277
平均合并
18 小时 7 分钟
30 天内合并 PR
228

环境准备

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

TanStack/db 的其他 Issue

查看 TanStack/db 的全部 Issue

相似的 Issue

更多 TypeScript Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。