fix: avoid history reclamation during structure-only upgrades

Ordinary database schema upgrades previously ran VACUUM on free pages and
showed misleading history-cleanup progress. Separate structure upgrades from
required legacy conversions, retaining reclamation intent only for retries
within the same startup. Preserve released data without new schema versions
or persistent migration markers; Agent and normal writes remain unchanged.

Add real SQLite and Worker regressions, bilingual operation-specific startup
copy, and migration documentation. Synchronize native Electron drag input
with actual resize state without weakening layout assertions.

Validation: 47 focused migration tests passed; typecheck, lint and diff checks
passed. Final full suite: 5137 passed, 74 skipped, 2 unrelated Electron failures.
Both failing Electron tests passed an isolated rerun; full CI remains unverified.

Release note: 修复普通数据库结构升级再次整理历史和回收空间的问题;仅在需要转换旧数据时执行相关处理,启动页准确显示当前升级操作。
This commit is contained in:
mesalogo
2026-09-26 12:42:08 +08:00
parent e6ac0734de
commit 4c7193e1ea
21 changed files with 441 additions and 61 deletions
+10 -7
View File
@@ -1846,21 +1846,24 @@ export class AssistantDatabase {
}
// Called by the existing startup worker before the business connection opens.
upgradeMagicNoteStorage(
upgradeStorage(
onProgress: (progress: AssistantStorageProgress) => void,
isCancelled: () => boolean
isCancelled: () => boolean,
upgrade: { migrateNotes: boolean; reclaimSpace: boolean }
): void {
const database = new DatabaseSync(this.databasePath, { timeout: 5_000 })
try {
database.exec('PRAGMA journal_mode = WAL; PRAGMA foreign_keys = ON;')
this.migrate(database, onProgress, isCancelled)
this.database = database
this.repairMagicNoteStorage(onProgress, isCancelled)
if (upgrade.migrateNotes) this.repairMagicNoteStorage(onProgress, isCancelled)
if (isCancelled()) throw new DOMException('Upgrade cancelled', 'AbortError')
const free = database.prepare('PRAGMA freelist_count').get() as { freelist_count: number }
if (free.freelist_count > 0) {
onProgress({ stage: 'compacting', processed: 0, total: 0, bytesBefore: statSync(this.databasePath).size })
database.exec('PRAGMA wal_checkpoint(TRUNCATE); VACUUM;')
if (upgrade.reclaimSpace) {
const free = database.prepare('PRAGMA freelist_count').get() as { freelist_count: number }
if (free.freelist_count > 0) {
onProgress({ stage: 'compacting', processed: 0, total: 0, bytesBefore: statSync(this.databasePath).size })
database.exec('PRAGMA wal_checkpoint(TRUNCATE); VACUUM;')
}
}
database.exec('PRAGMA wal_checkpoint(TRUNCATE)')
} finally {