壓縮與垃圾回收
最後更新
本頁說明 ToriiDB 如何把資料庫重寫成新的 snapshot、移除被取代的檔案,以及 Store.Close() 關閉時做了什麼。
壓縮
compact() 只在持有資料庫寫鎖時執行(來自寫入路徑或 Store.Close()):
| 步驟 | 動作 |
|---|---|
| 1 | 重播失敗時以 loadErr 拒絕,避免不完整的 map 覆蓋良好的 snapshot |
| 2 | 無資料且資料庫目錄不存在時略過 |
| 3 | 將未過期項目序列化到 N.snap.tmp,執行 write + fsync + close |
| 4 | os.Rename 為 N.snap,再對目錄 fsync |
| 5 | 開啟 N+1.log 並換上,之後才關閉舊 log |
| 6 | 於背景執行垃圾回收 |
N 是目前的 log 編號。直接使用 os.Rename,因為 go-pkg 的搬移函式在跨裝置時會退化為複製 + 刪除,不是原子操作。先開新 log 再關舊 log,資料庫就不會出現 log handle 為 nil 的空窗。
序列化以 CreatedAt 作為時間戳且不帶 UpdatedAt,因此從 snapshot 重啟後,項目不會有更新時間。
垃圾回收
壓縮成 snapshot N 後,會刪除 < N-1 的 snapshot 與 <= N-1 的 log。前一世代(N-1.snap + N.log)保留在磁碟上,作為重播的退回來源。
Store.Close() 以 sync.Once 保證冪等,並對每個已載入資料庫:
- 等待背景向量工作。
- 停止過期計時器。
- 在寫鎖下壓縮。
- 僅在壓縮成功時同步執行垃圾回收,因為背景 goroutine 在 process 結束前不會被排程。
- 關閉 log 檔。
回傳第一個壓縮錯誤。壓縮失敗時略過垃圾回收,可避免一個異常的高編號 snapshot 導致有效的舊檔案被刪除。