perf: implement lazy loading in FsStore (#85) #89
Reference in New Issue
Block a user
Delete Branch "fix/85-fsstore-lazy-loading"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What
Refactor
FsStoreto lazy-load CAS nodes on demand instead of CBOR-decoding the entire store at startup.Why
createFsStore()previously calledloadDir()at init, which read and CBOR-decoded every.binfile undernodes/into an in-memoryMap<Hash, CasNode>. This made cold-open O(n) in both time and memory, regardless of how many nodes the caller actually needed. For large stores, the startup cost dominated.Changes
packages/fs/src/store.ts— refactorcreateFsStore():nodes/into aSet<Hash>(no CBOR decoding)get(hash)— check cache → on miss, read + decode.binfile → cache → returnhas(hash)— O(1) Set membership check, no disk I/O on the node payloadlistAll()— return Set keys (filename-based)put()— write-through cache (immediately available without re-reading disk)delete()— clear cache + Set + disk file_index/is missing, perform a one-time scan + decode to rebuildpackages/fs/src/store.test.ts— add 12 new tests (L1-L12) covering startup-no-decode, lazy get, has/listAll without decode, write-through put, delete cleanup, list operations, migration, and bootstrap regression.changeset/fsstore-lazy-loading.md—@ocas/fspatch changesetAll 643 existing tests continue to pass.
Ref
Fixes #85
LGTM ✅
Lazy loading 设计合理:
hashSet,不碰 CBORhas()/listAll()纯 Set 操作,零 I/Oget()按需读盘 + cache,write-throughput()写入后直接进 cache 不回读loadNode()作为统一入口,cache hit → hashSet check → disk read,逻辑清晰迁移路径保留完整:
_index/缺失时buildTypeIndexFromDisk()做一次性全量 decode 重建,正确_meta缺失时同理扫盘重建delete() 处理得当:
loadNode拿 type 再清理 index,即使 node 文件损坏(decode 失败)也能正确从 hashSet/cache/disk 清除,只是跳过 index 清理 — 合理的降级测试 L1 很巧妙 — 用 corrupted .bin 证明 startup 确实没 decode。12 个测试覆盖了正常读写、损坏容错、各种 list 操作、migration、bootstrap 回归。
Changeset
patch正确 — 行为不变,纯内部性能优化。可以合。