跳转至

Mini Session Storage

从 5105 行的 src/utils/sessionStorage.ts 提炼到 ~150 行 的 file-based KV + TTL + 原子写 + 事务。 8 个测试场景:基本 / 持久化 / reload / TTL / 事务 / delete / 并发安全 / debounced flush。

文件

mini-session-storage/
├── src/
│   ├── storage.ts  SessionStorage 类(~150 行)
│   └── cli.ts      8 测试场景
└── README.md

npm install && npm start

真实代码对照

Demo 真实文件 简化
set/get sessionStorage.ts:200 直接 Map
load 启动恢复 sessionStorage.ts:500 (~300 行) 单文件 JSON
原子写 sessionStorage.ts:800 (~200 行) write tmp + rename
transaction sessionStorage.ts:1500 (~400 行) 内存批量 + 单次 flush
TTL 懒清理 sessionStorage.ts:2500 get 时检查
Crash recovery sessionStorage.ts:4000 简化为 tmp + rename

核心 4 件套

1️⃣ 内存 Map + 磁盘 JSON

  • 写:先改内存(同步),调度后台 flush(debounce 1s)
  • 读:只查内存(不 IO,O(1))
  • 启动:load 整个 JSON

2️⃣ 原子写 = write tmp + fsync + rename

const tmpPath = `${filePath}.${pid}.${rand}.tmp`;
await fs.writeFile(tmpPath, JSON.stringify(data));
await fd.sync();           // 强制刷盘(防断电)
await fs.rename(tmpPath, filePath);  // 原子替换
为什么 atomic:rename 是 POSIX 原子操作,不会留下半写文件。即使断电,重启后要么旧文件要么新文件,不会损坏

3️⃣ Debounced flush

private scheduleFlush() {
  if (this.flushTimer) return;
  this.flushTimer = setTimeout(() => this.flush(), 1000);
}
批量 set 只 flush 一次。100ms 内 1000 个 set 只产生 1 次磁盘 IO。

4️⃣ TTL 懒清理

if (entry.expiresAt && Date.now() > entry.expiresAt) {
  delete this.data.entries[key];
  return null;
}
不跑后台 timer,只在 get 时检查。0 资源占用

8 个场景输出

📌 Test 1: set / get
📌 Test 2: persistence (close → file)
  file exists: size=423 bytes
📌 Test 3: reload
  user.name (reloaded) = Alice
📌 Test 4: TTL expiration
  expired? ✅
📌 Test 5: transaction (batch)
  todo.1 = buy milk, todo.2 = learn CC, todo.3 = build demo
📌 Test 6: delete
  delete returned: true
📌 Test 7: concurrent flush safety
  ✅ file is valid JSON (atomic rename worked)
📌 Test 8: graceful close
  file size=171, final.value in file? true

进阶练习

  1. 换 SQLite:用 better-sqlite3 替代 JSON(更大数据 + 索引)
  2. 加 fsync on every write:金融场景每次写都 fsync(牺牲性能换安全)
  3. 加 WAL 模式:写前 log 防 crash 丢数据
  4. 加 compression:用 lz4 压缩大 value
  5. 加 change notification:写后触发订阅者(pub/sub)
  6. 加 watch:文件外部修改时自动 reload(inotify)

相关阅读