mirror of https://github.com/jackwener/wx-cli.git
review: preserve wal incremental reuse across restart
parent
b032b8be04
commit
e9f65ba71b
|
|
@ -98,12 +98,17 @@ impl DbCache {
|
|||
let wal_path = wal_path_for(&db_path);
|
||||
|
||||
let db_mt = mtime_nanos(&db_path);
|
||||
let wal_mt = if wal_path.exists() { mtime_nanos(&wal_path) } else { 0 };
|
||||
let _wal_mt = if wal_path.exists() { mtime_nanos(&wal_path) } else { 0 };
|
||||
|
||||
if db_mt == entry.db_mt && wal_mt == entry.wal_mt {
|
||||
// 只要主 .db 没变,就把 cached 产物载回来。
|
||||
// 如果 WAL mtime 变了,后续 `get()` 会自动走 Path 2:在已有 cached DB 上增量 apply_wal,
|
||||
// 而不是 daemon 重启后第一条请求又退回全量解密。
|
||||
if db_mt == entry.db_mt {
|
||||
inner.insert(rel_key.clone(), CacheEntry {
|
||||
db_mtime: db_mt,
|
||||
wal_mtime: wal_mt,
|
||||
// 保留"cached 产物构建时看到的 wal_mtime",让 `get()` 去比较当前 WAL
|
||||
// 是否发生了变化,从而决定 exact-hit 还是 WAL 增量。
|
||||
wal_mtime: entry.wal_mt,
|
||||
decrypted_path: dec_path,
|
||||
});
|
||||
reused += 1;
|
||||
|
|
@ -436,4 +441,57 @@ mod tests {
|
|||
new_size,
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn restart_with_wal_change_still_reuses_cached_db_then_applies_wal() {
|
||||
let root = unique_tmpdir("restart-wal");
|
||||
let db_dir = root.join("db_storage");
|
||||
let cache_dir = root.join("cache");
|
||||
std::fs::create_dir_all(&db_dir).unwrap();
|
||||
std::fs::create_dir_all(&cache_dir).unwrap();
|
||||
|
||||
let rel_key = "message_0.db".to_string();
|
||||
let db_path = db_dir.join(&rel_key);
|
||||
std::fs::write(&db_path, b"fake encrypted db").unwrap();
|
||||
|
||||
let wal_path = wal_path_for(&db_path);
|
||||
std::fs::write(&wal_path, [0u8; 31]).unwrap(); // WAL 增量仍是 noop
|
||||
|
||||
let cached_hash = format!("{:x}", md5::compute(rel_key.as_bytes()));
|
||||
let decrypted_path = cache_dir.join(format!("{}.db", cached_hash));
|
||||
std::fs::write(&decrypted_path, ORIGINAL_CACHED_BYTES).unwrap();
|
||||
|
||||
let db_mt = mtime_nanos(&db_path);
|
||||
let wal_mt0 = mtime_nanos(&wal_path);
|
||||
let mtime_file = cache_dir.join("_mtimes.json");
|
||||
let payload = serde_json::to_string(&serde_json::json!({
|
||||
&rel_key: {
|
||||
"db_mt": db_mt,
|
||||
"wal_mt": wal_mt0,
|
||||
"path": decrypted_path.display().to_string(),
|
||||
}
|
||||
}))
|
||||
.unwrap();
|
||||
std::fs::write(&mtime_file, payload).unwrap();
|
||||
|
||||
// 模拟 daemon 重启前又有新消息写入 WAL
|
||||
std::thread::sleep(std::time::Duration::from_millis(20));
|
||||
std::fs::write(&wal_path, [0xffu8; 31]).unwrap();
|
||||
let wal_mt1 = mtime_nanos(&wal_path);
|
||||
assert_ne!(wal_mt0, wal_mt1);
|
||||
|
||||
let mut all_keys = HashMap::new();
|
||||
all_keys.insert(rel_key.clone(), FAKE_KEY_HEX.to_string());
|
||||
let cache = DbCache::with_dirs(db_dir, cache_dir, mtime_file, all_keys)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let p = cache.get(&rel_key).await.unwrap().expect("cache should reuse persisted DB");
|
||||
assert_eq!(p, decrypted_path);
|
||||
let body = std::fs::read(&decrypted_path).unwrap();
|
||||
assert_eq!(
|
||||
body, ORIGINAL_CACHED_BYTES,
|
||||
"restart + WAL-only change should still reuse cached DB and avoid full_decrypt"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue