Repository navigation
fix(server): migrated databases can return freed space to disk - #30066
advaitpaliwal wants to merge 3 commits into
Conversation
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — First-time V1 imports now create compacted copies that support the existing disk-space reclamation mechanism, with copying moved off the event loop. The original database remains read-only, and existing V2 databases are not replaced. You can add or adjust custom eligibility rules. Learn more. |
|
No actionable comments were generated in the recent review. Walkthrough
Merge Risk:
|
|
Note Written by Verified in a real dev environmentverified unchanged head created a genuine v1 database using the last v1 app ( read-only queries against each running server database showed: the pr returned 500 pages (2,048,000 bytes) through normal background maintenance. main retained its freed pages. the source v1 database and both input copies retained the same sha256 throughout. nearby behavior also passed: both clients displayed the migrated messages; the pr completed a real continuation ( blacksmith passed all 6 focused import/storage tests and Not verifiedmacos/windows desktop, native ios/android, multi-gb imports, worker cancellation on windows, and simulated crash/corruption scenarios were not exercised on this linux vm. the existing windows cancellation review finding remains outside this verification result. Takeover update (
|
# Conflicts: # apps/server/src/persistence/initializeV2Database.ts


Databases migrated from V1 never return freed space to disk. This is a small fix for an obvious bug, so I'm submitting it without a prior issue.
The bug
initializeV2Databasecreatesstatev2.sqlitewithNodeSqlite.backup. A page-level backup keeps the V1 file'sauto_vacuum = NONE. The check inSqlite.tsthat setsauto_vacuum = INCREMENTALonly runs on an empty database, so it never runs on a migrated one. Because of that, the existingincremental_vacuumloop inDatabaseStoragedoes nothing on every install that migrated from V1. Space freed later, for example by migration 063 dropping the V1 projections or by history compaction, stays in the file.Evidence
I saw this on a macOS install running 0.1.2:
statev2.sqlitehad grown to 14.4 GB, with 2,111,248 of its 3,526,806 pages (60%) on the freelist.PRAGMA auto_vacuumreturned0.VACUUM INTO, the file was 5.6 GB. Aftert3 doctor --fix,auto_vacuumwas2.The fix
The import now runs
PRAGMA auto_vacuum = INCREMENTALfollowed byVACUUM INTOon a read-only connection tostate.sqlite. This happens in a worker thread, so the event loop stays free. The copy comes out compacted and already INCREMENTAL, so the existing reclaim loop works from the first start.VACUUM INTOcan renumber rowids. That is safe here because nothing in the V1 tables depends on rowids, and the message search index that is keyed on them is created later, by migration 69.t3 doctor. This PR doesn't change that design.Verification
initializeV2Database.test.tsto assert that the copy hasauto_vacuum = 2andfreelist_count = 0. It fails onmain(auto_vacuum: 0) and passes with this change.VACUUM INTOtook 7.8 s, against 4.5 s forbackup. It runs once and off the event loop. The output was 414 MB instead of 1,034 MB, andintegrity_checkreturned ok.