Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

v1.2.4: catalog WAL grows to metadata_bytes/4 (1 GiB here) before checkpointing; stage collection writes ~4× the WAL it reclaims

オープン
#214 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
5/5
見積もり時間
1週間以上
初心者へのやさしさ
35/100
issue の種類
バグ
明瞭さ
おおむね明確
活発さ
活発
技術スタック
rust, sqlite

調査の方向性

Start with tgrep-core/src/managed/catalog_io.rs checkpoint configuration and threshold, then trace catalog_io::begin() in catalog.rs; review the collection transaction and delete_member paths in collection.rs alongside the measurements. Reproduce WAL growth and collection behavior using the reported policy and workload. Done means identifying and validating a safe approach to the checkpoint and reclamation concerns raised in the issue.

索引モデルが issue の本文から書いたものです。

説明

Summary

We embed tgrep serve --shared (managed-v2, v1.2.4) in the Copilot runtime. On a large Windows repository, one namespace's catalog.sqlite has not been checkpointed in the 80 minutes since the namespace was created. The database file is still 4,096 bytes, and the whole 189 MiB catalog lives in a 427 MB WAL that keeps growing at about 110–125 MB/h.

Outside storage pressure, tgrep checkpoints only in catalog_io::begin(), with a no-wait attempt once the WAL reaches metadata_bytes / 4. This catalog needs a large metadata_bytes (ours is 4 GiB), so absent storage pressure the WAL will grow to about 1 GiB before its first checkpoint.

Most of the steady-state WAL appears to come from collecting a 1.83 GB build-stage object. Collection truncates members in 64 KiB steps, and each step costs two FULL-sync catalog commits plus a file sync_all. The WAL grows roughly 4× faster than collection reclaims, and collection reclaims about 31 MB/h.

Nothing has failed, and admission has plenty of headroom. The concern is steady-state disk use, read cost, crash-recovery time and reclamation speed.

Environment

  • tgrep 1.2.4 (tgrep serve --shared, managed-v2) on Windows 11 Enterprise, NTFS.

  • One repository namespace: about 293k files, with a 3.15 GB published generation.

  • Our policy differs from the illustrative policy in SHARED_WORKTREE_INDEXES.md. These differences look relevant here:

    Field Ours Illustrative
    retention bounded, 8 GiB target retain-all
    advancement adaptive fixed
    work.workers 1 2
    work.staging_bytes 8 GiB 512 MiB
    work.metadata_bytes 4 GiB 64 MiB
    collection.checkpoint_grace_ms 1 h 5 min
    collection.generation_grace_ms 24 h 1 h
    collection.retry_ms 5000 1000

    Most other work fields also differ; we can share the full policy if that helps. The collection schedule (periodic, 60 s), on_pressure and per-pass bounds match: max_duration_ms 200, max_examined 128, max_removed 16, max_delete_bytes 16 MiB, chunk_bytes 64 KiB and max_pages 16. A 64 MiB metadata_bytes can't hold this catalog, because database page payload is capped at one third of the budget and the database is already 189 MiB.

Observations

File sizes were sampled through shared read handles. Frame counts, commit counts and operation records come from read-only copies of catalog.sqlite and its WAL. Times are local.

Time catalog.sqlite catalog.sqlite-wal
16:15:48 namespace created
17:22:27 4,096 403,261,512
17:26:46 4,096 409,668,112
17:35:33 4,096 426,696,072
  • The live database (read from a copy) is 189 MiB, with 1.22 M member_seals rows. The WAL is already about 2.2× the database.
  • WAL growth samples ranged from 78 to 198 MB/h. From 17:22:27 to 17:35:33 it averaged about 107 MB/h, so the WAL reaches 1 GiB in roughly 5–6 more hours.
  • Between two copies taken 352 s apart, the WAL gained 2,967 frames (12.2 MB) in 525 commits, about 5.7 pages (23 KB) per commit. 39 collection passes were accepted in that window, which works out to about 13.5 commits and 313 KB of WAL per pass. This counts all writers; the catalog's retained operations at the time were 62 collection passes and 2 reconcile passes.

Collection, over the last 62 completed passes (540 s), from the copied operations table:

  • Every pass resumed the same build-stage object in pending-deletion: 1,828,781,245 bytes in 358 files. Totals were 62 examined, 0 removed and 0 retired.
  • Together they reclaimed 4,605,029 logical bytes (741,376 allocated), about 30.7 MB/h. Extrapolated, the stage takes about 2.5 days to delete, and until then it keeps about 1.8 GB on disk alongside the 3.15 GB generation.
  • The WAL grows roughly 3.5–4× faster than collection reclaims (107–125 MB/h against 30.7 MB/h).
  • Every pass used its whole 200 ms max_duration_ms budget (elapsed 200–278 ms, average 220 ms). No pass reclaimed more than 196,608 bytes (3 × 64 KiB).
  • 33 of the 62 passes reclaimed nothing. Those verified more (on average 7.2 pages and 261 KiB) than the 29 passes that reclaimed bytes (3.1 pages and 155 KiB). In total, verification covered 3,616 proof rows and 9.1 MB to reclaim 4.6 MB, with 1 verification restart, 0 skips and 0 errors.
  • Passes started on average every 8.85 s.

Code pointers (v1.2.4)

Impact

  • Disk: each namespace can hold up to metadata_bytes / 4 of WAL before its first checkpoint. Here that is 1 GiB, about 5× the database, and it multiplies across repositories.
  • Reads: SQLite notes that read performance "still falls off with increasing WAL file size" (wal.html §2.3). With mmap_size=0 and a 256 KiB cache, more catalog reads go through the wal-index and file reads. We haven't measured this.
  • Crash recovery: after an unclean exit, the first opener runs WAL recovery under an exclusive lock (wal.html §9), which rebuilds the wal-index from the WAL. That cost grows with WAL size and sits on the readiness path (see #210). We haven't measured this.
  • First checkpoint: the whole catalog currently exists only in the WAL, so the first checkpoint will copy all of it inside one mutation's begin(). TRUNCATE checkpoints block new writers while they run, and the other writers' busy timeout is WRITER_WAIT (250 ms). We haven't measured this stall.
  • Reclamation: a 1.8 GB stage takes about 2.5 days to delete at the observed rate.

Suggestions and questions

These keep the documented rule that "WAL truncation is attempted without waiting before catalog mutations, never after a successful commit" (SHARED_WORKTREE_INDEXES.md#L1793-L1794).

  1. Decouple the checkpoint threshold from metadata_bytes. metadata_bytes has to be sized for the largest catalog, so metadata_bytes / 4 grows with it. Options include a cap such as min(metadata_bytes / 4, 64 MiB), a threshold relative to the live database size, or a separate policy field. Checkpoints would still be attempted at the same point, before a mutation and without waiting, just with a smaller WAL.
  2. Fewer commits per reclaimed chunk. Could the per-object progress save share the first intent's transaction? Could chunk N's credit share a transaction with chunk N+1's intent?
  3. Chunk size and cadence. On NTFS, the cost of a truncation doesn't depend on its length. With 64 KiB steps, each pass appears to be bound by flush latency; we infer this from the cap of 3 steps per 200 ms pass, but haven't profiled it. Is there a constraint that keeps chunk_bytes small, such as the crash window, authentication-block alignment or verification granularity? What chunk_bytes, max_duration_ms, retry_ms and metadata_bytes would you recommend for repositories this size?
  4. Verification-only passes. Is it expected that about half the passes verify without reclaiming anything? Could that verification carry over, so the next pass truncates immediately?

You know the invariants much better than we do. We're happy to test a build or collect more data. We can also tune our own retry_ms, chunk_bytes and metadata_bytes, and would welcome guidance on safe values.

Related

  • #210: cold readiness on v1.2.3.
  • #212: reconcile starvation under storage pressure on v1.2.4.
主要言語
Rust
スター
3.5k
フォーク
140
平均マージ
14時間 59分
マージ済み PR(30日)
28

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

microsoft/tgrep のほかの issue

microsoft/tgrep の issue をすべて見る

似ている issue

Rust の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。