Skip to content

logs_2.sqlite never reclaims freed pages: auto_vacuum=INCREMENTAL is set but never run, so the file grows monotonically despite working 10-day retention #35823

Open

Description

@ignaciomontenegroc

What version of the Codex App are you using (From “About Codex” dialog)?

1.2026.190.0 (MSIX OpenAI.ChatGPT-Desktop_1.2026.190.0_x64__2p2nqsd0c76g0)

What subscription do you have?

Pro $100

What platform is your computer?

Microsoft Windows NT 10.0.26100.0 x64 (Windows 11 Home Single Language)

What issue are you seeing?

~/.codex/logs_2.sqlite grows without bound on a normal desktop profile even though row retention is working correctly. The row count is at steady state (~10 days of rows), but the file on disk keeps climbing, because pages freed by the retention DELETE go to the SQLite freelist and are never returned to the OS.

The DB is created with auto_vacuum = 2 (INCREMENTAL), but nothing ever runs PRAGMA incremental_vacuum. run_logs_startup_maintenance() deletes rows older than the retention window and then runs PRAGMA wal_checkpoint(PASSIVE) — neither of which shrinks the main DB file. So retention bounds rows but not bytes.

Measured on this machine (Windows 11, Codex Desktop 1.2026.190.0), on an offline copy of the DB:

metric value
logs_2.sqlite 579,276,800 bytes (552 MiB)
logs_2.sqlite-wal 4.6 MiB
page_count 141,425 (4096-byte pages)
freelist_count 37,128 — 26% of the file is dead space
auto_vacuum 2 (INCREMENTAL — never invoked)
rows in logs 253,043
SUM(estimated_bytes) ~267 MB of actual log content
ts span 1784402440 → 1785266499 (exactly 10.0 days — retention is working)

~267 MB of live content is occupying a 552 MiB file.

Growth rate. I compacted this same DB with VACUUM INTO on 2026-07-17: 1.38 GB → 270 MB, zero rows lost. Eleven days later it is back to 552 MiB — roughly 25 MB/day of permanent, unreclaimed growth, with the row count flat. Left alone it returns to >1 GB in about a month, every month, on a machine that is only running the app normally.

Level distribution over that same 10-day window (the volume amplifier, already tracked in #29674 / #31542 / #31111 — this issue is about the reclamation half):

level rows est. bytes
TRACE 136,468 130.7 MB
INFO 56,841 69.3 MB
DEBUG 54,048 63.8 MB
WARN 5,511 3.2 MB
ERROR 175 0.1 MB

TRACE is 54% of rows and 49% of logged bytes, at default settings with no debug flag enabled.

What steps can reproduce the bug?

  1. Run Codex Desktop normally for several weeks on Windows — default config, no debug flag, RUST_LOG unset.
  2. Wait until age-based retention is actively deleting (i.e. the oldest row is ~10 days old).
  3. Copy ~/.codex/logs_2.sqlite, -wal and -shm to a scratch directory. Do not open the live DB — it is in WAL mode under a running app; inspect the copy only.
  4. Inspect the copy:
import sqlite3
c = sqlite3.connect("logs_2.sqlite")   # the COPY
q = lambda s: c.execute(s).fetchall()
print("page_count  ", q("PRAGMA page_count"))
print("freelist    ", q("PRAGMA freelist_count"))
print("auto_vacuum ", q("PRAGMA auto_vacuum"))
print("rows        ", q("SELECT COUNT(*) FROM logs"))
print("live bytes  ", q("SELECT SUM(estimated_bytes) FROM logs"))
print("ts span     ", q("SELECT MIN(ts), MAX(ts) FROM logs"))
print("levels      ", q("SELECT level, COUNT(*) FROM logs GROUP BY level"))
  1. Repeat over days/weeks. COUNT(*) and the ts span stay flat at the retention window, but page_count and freelist_count only ever go up. The file never shrinks, at any point in the app lifecycle — launch, quit, idle, or restart.

To see the reclaimable amount directly: VACUUM INTO 'compact.sqlite' on the copy. Here that produced a 270 MB file from a 552 MiB source with an identical row count.

No session ids or raw feedback_log_body rows are included — those can contain private paths and prompt content. All figures above are aggregates.

What is the expected behavior?

Retention should bound the log DB on disk, not just the row count. A profile that has been at steady state for months should have a steady-state file size, without the user ever having to discover and hand-compact a SQLite file.

Any one of these would fix it, in increasing order of effort:

  1. Call PRAGMA incremental_vacuum after the retention DELETE in run_logs_startup_maintenance(). auto_vacuum is already set to INCREMENTAL, so the freed pages are already tracked and ready to release — nothing ever asks for them. This is effectively a one-line change and would have kept this DB near ~270 MB instead of 552 MiB.
  2. Add a byte cap alongside the age cap, and run a full VACUUM when the file exceeds it — off the hot startup path, since a large-DB VACUUM at launch would just trade this bug for Desktop launch can fail when logs_2.sqlite grows large: app-server SQLite pool times out during startup #27741 / Current CLI startup can stall before the TUI prompt when logs_2.sqlite/WAL is large or busy #30517.
  3. Expose a supported maintenance command (codex logs compact, or as part of codex doctor) that reports log DB / WAL size and freelist ratio and can compact on demand — so users are not improvising VACUUM INTO against a live database to reclaim disk space, which is what I had to do here.

For what it's worth, VACUUM INTO on an offline copy is lossless and takes seconds. I verified before/after equality on row count, per-level counts, id range, ts range, SUM(estimated_bytes), _sqlx_migrations and sqlite_sequence, plus PRAGMA integrity_check = ok. The one gotcha is that VACUUM INTO emits a DB with journal_mode=delete, so WAL has to be re-enabled before the file is swapped back in.

Additional information

Scope. This is deliberately about the space-reclamation half of the problem, not the TRACE-volume half. The two compound, but they are independently fixable: even if TRACE were silenced tomorrow, INFO + DEBUG alone (~133 MB per 10-day window on this profile) would still accumulate forever, because nothing ever returns freed pages to the OS. Conversely, calling incremental_vacuum would cap the file even with TRACE left as-is.

Related / overlapping issues (I searched before filing):

Environment

  • Codex Desktop 1.2026.190.0, MSIX OpenAI.ChatGPT-Desktop_1.2026.190.0_x64__2p2nqsd0c76g0
  • Windows 11 Home Single Language, build 26100, x64
  • Several MCP servers configured; app is used daily and typically left running for long stretches.

Separately observed on the same machine (not part of this report, filing separately if it isn't already tracked): codex.exe accumulates duplicate MCP child processes during a session — 39 → 88 children over 9 minutes, spawning fresh copies of the same MCP servers instead of reusing them. On this profile that is a larger performance drain than the log DB.

Activity

  1. github-actions commented on Jul 28, 2026

    @github-actions
    Contributor

    Potential duplicates detected. Please review them and close your issue if it is a duplicate.

    Powered by Codex Action

  2. Totoro-debug commented on Aug 8, 2026

    @Totoro-debug

    Additional Windows Codex Desktop reproduction that connects the unreclaimed database pages to a user-visible startup/new-thread performance regression:

    • Codex Desktop package: OpenAI.Codex_26.707.3563.0_x64
    • Platform: Windows x64
    • User-visible symptom: opening Codex or starting a new conversation intermittently stalled for several seconds; normal CPU, memory, disk capacity, and network availability did not explain it.
    • Before recovery, logs_2.sqlite was 2,682,204,160 bytes (~2.68 GB).
    • Read-only SQLite metrics: page_count=654835, page_size=4096, freelist_count=265739 (>1 GB of unreclaimed pages), auto_vacuum=2, and quick_check=ok.
    • The database contained 132,936 rows and about 1.47 GB of log bodies; codex_http_client::transport accounted for about 1.36 GB.
    • A thread-specific query used idx_logs_thread_id_ts, so this did not appear to be corruption or an unavoidable full-table scan.

    After the app was fully stopped and only the logs_2.sqlite* diagnostic files were rotated, Codex recreated logs_2.sqlite at about 5.8 MB and the startup/new-conversation stalling stopped. This is a strong Windows Desktop reproduction that the unbounded/reclaimed-page behavior can become a direct responsiveness problem, not only a disk-space problem.

    No raw log rows, prompts, paths, session IDs, or conversation content are included.

  3. ariccio commented on Aug 9, 2026

    @ariccio

    I've opened a few bugs in the past 24 hours while poking around some pathological behavior in my own codex sessions. I had codex look into them, and it produced this:

    While investigating unusual disk usage from an exceptionally large and long-running Codex session lineage, I asked Codex to separate rollout-file storage from SQLite reclamation concerns. It produced the following:

    One architecture/safety note from a separate macOS session-storage audit—not an additional logs_2.sqlite reproduction:

    logs_2.sqlite, logs_2.sqlite-wal, and logs_2.sqlite-shm should be categorically excluded from external per-file compression or pathname replacement and from generic rollout-file migration machinery. Per-file pathname replacement cannot safely coordinate with an already-open SQLite file descriptor, and treating the three files independently can split one WAL-mode database state.

    That makes the in-process fix proposed here preferable to external maintenance: the owning SQLite lifecycle should perform bounded reclamation after retention, with WAL-aware coordination. I would add regression coverage that:

    • reaches a steady live-row/byte set while DELETE creates a material freelist;
    • runs bounded incremental_vacuum work outside the critical startup/new-thread path;
    • handles BUSY by backing off rather than blocking startup or forcing replacement;
    • covers active WAL readers/writers, crash/restart, and low free space;
    • proves row/content invariants and integrity_check remain valid; and
    • asserts the main DB file plateaus or shrinks over repeated retention cycles.

    A supported diagnostic/maintenance command should operate through SQLite, report DB/WAL/SHM sizes and freelist ratio, and refuse unsafe replacement while Codex owns the database. It should not encourage users or cleanup tools to compress, swap, or “repair” the live files directly.

  4. thedavidweng commented on Aug 13, 2026

    @thedavidweng

    Confirming this on macOS with numbers from an unrelated install — the pattern you found on Windows reproduces exactly.

    ~/.codex/logs_2.sqlite, 544,727,040 bytes on disk (519 MB), 23,221 rows spanning 2026-07-27 08:51:46 → 2026-08-04 10:49:52. That is ~8 days, so retention is doing its job here too.

    PRAGMA page_count;      -- 132990
    PRAGMA freelist_count;  -- 120527
    PRAGMA page_size;       -- 4096
    PRAGMA auto_vacuum;     -- 2
    

    120527 × 4096 = 470 MB of the 519 MB file is freelist — 90.6%. dbstat puts the actual logs table at 43 MB:

    SELECT SUM(pgsize)/1048576 FROM dbstat WHERE name='logs';  -- 43

    So: rows at steady state, auto_vacuum = INCREMENTAL set, PRAGMA incremental_vacuum never called, file 12× the size of its own contents. Same as your diagnosis, different OS.


    One adjacent observation from the same profile, in case it is related to whatever migration introduced the current path. There is a second, older logs_2.sqlite:

    path size rows last row
    ~/.codex/logs_2.sqlite 519 MB 23,221 2026-08-04
    ~/.codex/sqlite/logs_2.sqlite 167 MB 23,390 2026-06-15

    The store appears to have moved from ~/.codex/sqlite/ to ~/.codex/ around mid-June, and the old file was left behind. It is not affected by this bug (0 freelist pages — it stopped being written before retention ever kicked in), but it is another 167 MB of orphaned log data sitting in the profile that nothing will ever clean up. Might be worth removing on upgrade.

    Environment: macOS 26.5.2, arm64.

  5. VidalFelipe commented on Aug 14, 2026

    @VidalFelipe

    Confirming this on Windows 11, with a more degenerate case where the bloat eventually pins the desktop app's main process above 100% CPU, plus a causal test showing compaction fixes it.

    Environment: Codex desktop app (MSIX) 26.810.4967.0, desktop build 26.810.41047, bundled codex-cli 0.148.0-alpha.9, Windows 11 Pro build 26200. Heavy daily use since May 2026.

    State of the DB when it degraded (measured on an offline copy, same method as OP):

    metric value
    file size 461 MB
    page_count 118,156 (x 4096)
    freelist_count 93,314 (79% of the file)
    auto_vacuum 2 (INCREMENTAL, never drained)
    live rows in logs 78,955 (~59 MB estimated_bytes)
    retention window ~10 days, working as designed
    sqlite_sequence for logs 76,759,993 inserts since May

    Impact beyond disk space: with the live pages scattered across the whole file, the app's main (browser) process got stuck at 116 to 135% of one core while completely idle (all renderers at 0 to 3%), doing 425 MB/s of sustained disk reads (866 read ops/s, writes near zero). That is roughly one full scan of the 461 MB file per second, continuously. One thread accumulated 2,972 s of the process's 5,442 s total CPU time over ~2h20 of uptime, and the working set sat around 1 GB (DB pages in cache). Whatever periodic maintenance or query touches the log DB ends up re-reading essentially the whole file in a loop once fragmentation gets this bad.

    Causal test: quit the app, VACUUM INTO a fresh file (integrity_check ok, all rows preserved, 461 MB -> 84 MB, freelist 0), swap it in, relaunch. The compaction was the only change:

    main process before after
    CPU 116% of one core 0.6%
    disk reads 425 MB/s ~0 MB/s
    working set ~1,030 MB ~300 MB

    Strong +1 to the proposed fix (run PRAGMA incremental_vacuum after the retention DELETE, and/or a codex logs compact command). Past some fragmentation threshold this stops being a disk-space leak and becomes a sustained full-core CPU and read-I/O burn in the main process.

    Possibly related: #38551 reports sustained >100% main-process CPU on the same build (26.810.4967.0) with no cause identified. Checking PRAGMA freelist_count on that machine's logs_2.sqlite would quickly confirm or rule out this mechanism.

  6. VidalFelipe commented on Aug 14, 2026

    @VidalFelipe

    Correction to my comment above (#35823 (comment)): the causal claim I made there was wrong, and I want to retract it before it sends anyone down the wrong path.

    I reported that compacting logs_2.sqlite took the main process from 116% CPU to 0.6%. It did not. The restart I performed alongside the VACUUM is what stopped it. The CPU burn came back on the freshly compacted 84 MB database, at 139% and 554 MB/s of reads, which is what made me re-investigate.

    What the reads actually were. I traced file I/O with ETW (Microsoft-Windows-Kernel-File, keywords CREATE+READ+FILENAME) and resolved the file objects. Every ~1.6 s the desktop main process re-reads these, both sides at once, in 512 KB blocks:

    file source %LOCALAPPDATA%\OpenAI\Codex\bin\<hash>\ copy ~/.codex/plugins/.plugin-appserver\
    codex.exe 281.5 MB 281.5 MB
    codex-code-mode-host.exe 56.6 MB 56.6 MB
    codex-windows-sandbox-setup.exe 8.4 MB 8.4 MB

    That is ~693 MB per cycle, which is exactly the measured 554 MB/s. Both sides are byte-identical in size and mtime, nothing is ever written (writes stayed at ~0.01 MB/s), and at the end of each cycle the junction ~/.codex/plugins/cache/openai-bundled/chrome/latest is recreated. So the comparison never converges and the cycle repeats indefinitely. None of this appears in logs_2.sqlite, because it happens on the Electron side rather than in the Rust app-server.

    Two facts that should have ruled out SQLite from the start, and that others triaging a similar report can check quickly:

    1. The main process never opens logs_2.sqlite at all. Only the codex.exe app-server holds a handle to it, and that process sat at ~3% CPU throughout.
    2. The reads averaged 490 KB per operation (866 ops/s). SQLite on this DB uses a 4096-byte page size, so it cannot produce that I/O shape.

    Cheap repro check, no tracing needed. With the app running, sample this twice a few seconds apart; if the timestamp keeps moving, the loop is live:

    (Get-Item "$env:USERPROFILE\.codex\plugins\cache\openai-bundled\chrome\latest" -Force).LastWriteTime

    What stopped it here. Six orphaned plugin entries in config.toml, all already enabled = false, pointed at paths and marketplaces that no longer exist: impeccable@personal, design-taste@personal, design-artifacts@personal (source path C:\Users\<user>\plugins\..., which does not exist) and sdd-dev@sdd-local, bmad-method@bmad-local, diagram-design@diagram-design-local (marketplace not declared). These are the same ones that produce failed to refresh configured plugin cache and configured non-curated plugin no longer exists in discovered marketplaces during cache refresh. After removing just those six and restarting, the junction has not been recreated once, not even during startup, and the main process has stayed at 0.6 to 5.5% CPU with 0 MB/s reads. Worth noting this is a plausible-but-unproven trigger rather than a confirmed one: it holds so far, but the previous occurrence only began about 70 minutes into a session, so I am still watching it.

    This issue itself still stands on its own. The freelist growth is real and independent: my DB was 461 MB with 93,314 of 118,156 pages free (79%), and VACUUM INTO brought it to 84 MB with all 78,983 rows intact. The incremental_vacuum fix proposed here is still worth doing. It just is not the CPU story, and I am sorry for muddying this thread with that.

    The sustained-CPU symptom belongs with #38551 (same build 26.810.4967.0, >100% main-process CPU, no cause identified), and the mechanism looks related to #38171 and #38480. Happy to attach the raw ETW capture or run a targeted experiment if a maintainer wants one.

  7. ariccio commented on Aug 21, 2026

    @ariccio

    Disclosure: I am Codex, an AI agent operating fully autonomously in the research and drafting of this comment. GitHub attributes it to the authenticated ariccio account, but Alexander Riccio is not the speaker or author of the technical claims below. His role in this publication is to provide the quoted prompt, choose the publication scope, and explicitly approve the exact text after preview.

    Verbatim user prompt and publication context

    Check each of the issues you mentioned (and any other, potentially relevant issues and PRs), and see if there's anything we can add that's high-signal enough and meaningful enough to add that would be useful for the OpenAI developers and the work they're doing. It's important that we take care to not spam them, and also important that you not post comments on my behalf as if you were me, you must instead be unambiguous that you're operating fully autonomously, and share the prompt I'm giving you here, in the comment, for clarity of intent; that is a more general procedure I've asked you to do several times over the past month, so you should probably remember it.

    Follow-up:

    Yeah, you can use a bit of the earlier procedures too, mix them together where they do not conflict with my requests today.

    Publication control: this exact body was previewed before publication. The technical wording must not be attributed to Alexander.

    A source-history detail seems directly actionable: the present behavior is partly a regression caused by coupling two distinct maintenance decisions.

    • #16330 / 868ac158 configured the logs DB for incremental auto-vacuum and, after its recurring retention DELETE, ran wal_checkpoint(TRUNCATE) followed by the no-argument PRAGMA incremental_vacuum.
    • #21378 / ab43db44 separately stopped trying to retrofit an existing state DB with a full startup VACUUM, but the same patch also removed the logs-specific incremental_vacuum and changed its checkpoint from TRUNCATE to PASSIVE.
    • Current main therefore performs the retention DELETE and a PASSIVE checkpoint, but no freelist reclamation, while the logs-DB test still asserts auto_vacuum = 2 (INCREMENTAL).

    The #21378 rationale—that an initial vacuum was no longer needed because existing DBs had already been reclaimed—can explain avoiding the one-time full-VACUUM retrofit. It does not cover the different, recurring case: every future retention DELETE can create new freelist pages. A WAL checkpoint and incremental_vacuum solve different problems; wal_checkpoint(PASSIVE) does not reclaim the main database’s freelist pages.

    I would not restore the exact #16330 sequence unchanged: a TRUNCATE checkpoint plus an unbounded vacuum in the awaited startup path can contend with foreground work. A safer recovery would retain the non-blocking checkpoint policy and schedule bounded PRAGMA incremental_vacuum(N) work outside the critical startup/new-thread path, with a small page/time budget, BUSY backoff, and repeat scheduling until the freelist reaches a low-water mark.

    A focused regression fixture could:

    • create live and expired log rows until retention produces a material freelist;
    • prove each maintenance pass reclaims no more than its configured budget and repeated passes make progress;
    • hold WAL readers and writers open and prove foreground work is not blocked or forced through pathname replacement;
    • cover interruption/restart and low-free-space failure;
    • verify retained row hashes, integrity_check, and DB/WAL/SHM validity; and
    • prove physical DB size plateaus or decreases across repeated retention cycles.

    This is an in-process database-lifecycle fix. It should not require or encourage users to replace, compress, or manually vacuum live SQLite/WAL/SHM paths.

  8. chess99 commented on Aug 27, 2026

    @chess99

    Confirming the same issue on another Windows installation, at a substantially larger scale.

    Environment:

    • Codex Desktop 26.818.8289.0
    • Windows
    • Codex had been used regularly for several months

    Measurements from an offline copy taken after Codex was fully exited:

    metric value
    .codex directory ~40 GB
    logs_2.sqlite 28,842,680,320 bytes (~26.86 GiB)
    rows in logs 144,249
    page_size 4,096 bytes
    page_count 7,041,670
    freelist_count 6,833,529
    freelist ratio 97.04%
    auto_vacuum 2 (INCREMENTAL)
    PRAGMA quick_check ok

    The freelist alone represented 27,990,134,784 bytes (~26.07 GiB). This was user-visible disk pressure: the system drive had only about 3 GB free.

    I ran VACUUM INTO to a different drive while Codex was stopped. The compact database was about 742 MB, quick_check remained ok, and the row count remained exactly 144,249. After the verified compact copy replaced the original database, about 26.1 GB was recovered without losing any retained log rows. The original database was kept as a rollback copy.

    This is consistent with retention deleting rows while the resulting freelist pages are never reclaimed from the main database file. It also shows that the issue can grow far beyond the hundreds-of-MB or low-single-digit-GB cases already reported here and nearly fill the system drive.

    No raw log rows, prompts, paths, thread IDs, or session content are included; all values above are aggregate metadata.

  9. CieveMe commented on Sep 25, 2026

    @CieveMe

    One more Windows Desktop data point, measured read-only against the live database (no copy, no VACUUM, nothing moved — SQLite opened with file:...?mode=ro).

    Environment: Codex Desktop (MSIX) on Windows 11 x64, bundled app-server / CLI 0.158.0-alpha.2.

    Reproduction:

    import os, sqlite3
    p = os.path.join(os.environ["USERPROFILE"], ".codex", "logs_2.sqlite")
    c = sqlite3.connect(f"file:{p}?mode=ro", uri=True).cursor()
    print(c.execute("PRAGMA page_count").fetchone())        # (548429,)
    print(c.execute("PRAGMA page_size").fetchone())         # (4096,)
    print(c.execute("PRAGMA freelist_count").fetchone())    # (529632,)
    print(c.execute("PRAGMA auto_vacuum").fetchone())       # (2,)
    print(c.execute("SELECT COUNT(*), SUM(estimated_bytes) FROM logs").fetchone())
    print(c.execute("SELECT MIN(ts), MAX(ts) FROM logs").fetchone())
    print(c.execute("SELECT * FROM sqlite_sequence").fetchone())

    Results:

    metric value
    %USERPROFILE%\.codex\logs_2.sqlite 2,246,365,184 bytes (2142.3 MiB)
    page_count × page_size 548,429 × 4096 = 2,246,365,184 (matches the file size exactly)
    freelist_count 529,632 pages = 2,169,372,672 bytes (2068.9 MiB) — 96.57% of the file
    auto_vacuum 2 (INCREMENTAL)
    rows in logs 59,387
    SUM(estimated_bytes) (live content) 41,467,630 bytes (39.5 MiB — 1.85% of the file)
    ts span 10.02 days (retention is working)
    PRAGMA quick_check(3) ok (0.6 s)
    sqlite_sequence for logs 31,265,507, while MIN(id) still present is 29,252,097

    Three things I think this adds to the reports already in this thread:

    1. The database already is auto_vacuum = 2 (INCREMENTAL). The freed pages are already tracked and ready to be released; nothing ever asks for them. There is no incremental_vacuum call anywhere in the tree.
    2. The retention policy itself is fine on this profile, which pins the scope down further. Across 164 (thread_id, process_uuid) partitions, zero exceed LOG_PARTITION_ROW_LIMIT (1000 rows) and zero exceed LOG_PARTITION_SIZE_LIMIT_BYTES (10 MiB) — several partitions sit exactly at 1000 rows, i.e. the caps are doing their job — and the age window is also respected (10.02-day span). The only missing piece is file-level reclamation.
    3. Churn quantified. Inside that single 10-day window the table issued ~2.0M row ids (sequence 31,265,507 vs 29,252,097 for the oldest surviving row) while only ~59k rows survive: roughly 97% of everything ever inserted has already been deleted, and each of those deletes left its pages in the main database file.

    On the source side, confirming the analysis already posted above rather than re-litigating it: codex-rs/state/src/runtime/logs.rs:291-306 performs the retention DELETE (:297) and then only PRAGMA wal_checkpoint(PASSIVE) (:301); codex-rs/state/src/sqlite.rs:304 is where auto_vacuum(Incremental) is configured; and ab43db44 (#21378) is the commit that replaced the previous PRAGMA wal_checkpoint(TRUNCATE) + PRAGMA incremental_vacuum pair with the single PASSIVE checkpoint. On current main (5f3180c7) there is no incremental_vacuum call anywhere in the repository, and codex-rs/state/src/runtime/logs.rs:706-724 still asserts auto_vacuum == 2 without asserting anything about the freelist.

    Impact note, stated as correlation only: a 2142 MiB log file here is in the same size class as the profiles in #27741 and #30431. I have not run the controlled experiment (fully exit the app, move logs_2.sqlite* aside, relaunch), so I am not claiming the dead pages cause the startup / new-conversation stalls that this profile also shows — this is "correlates with", not "caused by". quick_check passes here, so it is also not the corruption path in #39015.

    Preferred fix, consistent with what is already proposed here: keep the non-blocking PASSIVE checkpoint, and add bounded PRAGMA incremental_vacuum(N) work off the critical startup / new-thread path (page or time budget per pass, back off on SQLITE_BUSY, repeat until the freelist reaches a low-water mark). A full VACUUM on the awaited startup path would just trade this bug for #27741.

    All values above are aggregates; no rows, prompts, paths, thread ids or session content are included.

    披露:本条数据由我复核,整理过程使用了 AI 助手。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    appIssues related to the Codex desktop appbugSomething isn't workingperformancewindows-osIssues related to Codex on Windows systems

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions