7b2e6110eed5
keep files written in the last 3 seconds out of the file cache, so a coarse-clock rewrite cannot hide behind a stale hash (3.0.29, codex review pending)
- time
- 2026-09-23 22:44 UTC · 2 weeks ago
- machine
- koh2
- agent
- claude-opus-5-5
- session
- koh 3 reliability campaign
- parent
- 5222a7c6691a
↓ koh-7b2e6110.tar.gzatlas at this save
files changed4 files
VERSION+1 −1src/snapshot/snapshot_test.v+20 −0src/snapshot/tree.v+10 −0v.mod+1 −1src/snapshot/snapshot_test.v+20 −0
@@ -1,6 +1,7 @@11 module snapshot22 33 import os4+import time45 import src.storage56 67 fn temp_root(name string) !string {@@ -120,6 +121,25 @@120121 second := walk(store, root, Ignore{})!121122 assert second[0].hash == storage.hash_hex('bbbb\n'.bytes())122123 assert second[0].hash != first[0].hash124+}125+126+// Linux stamps files from a clock that ticks every few milliseconds, so a127+// same-size rewrite in the tick the file was hashed in leaves size, mtime and128+// ctime unchanged. A hash taken that close to the last write is never cached;129+// the next walk hashes again.130+fn test_cache_skips_a_file_written_moments_ago() {131+ mut store := storage.create(temp_root('racy')!)!132+ root := store.root133+ defer {134+ store.close()135+ os.rmdir_all(root) or {}136+ }137+ put(root, 'fresh.txt', 'new\n')!138+ put(root, 'old.txt', 'old\n')!139+ hour_ago := time.now().unix() - 3600140+ os.utime(os.join_path(root, 'old.txt'), hour_ago, hour_ago)!141+ walk(store, root, Ignore{})!142+ assert store.load_cache()!.keys() == ['old.txt']123143 }124144 125145 fn test_restore_writes_removes_and_leaves_ignored_files_alone() {src/snapshot/tree.v+10 −0
@@ -3,8 +3,12 @@33 module snapshot44 55 import os6+import time67 import src.storage78 9+// FAT filesystems keep mtime in 2-second steps; three covers them too.10+const racy_window_ns = i64(3_000_000_000)11+812 // One tracked file in one tree.913 pub struct FileEntry {1014 pub:@@ -74,6 +78,12 @@7478 }7579 data := os.read_bytes(os.join_path(root, rel))!7680 hash := storage.hash_hex(data)81+ // Linux stamps files from a clock that ticks every few milliseconds, so82+ // a same-size rewrite in this tick would look unchanged to the cache.83+ // A file written this recently is hashed again next time instead.84+ if time.now().unix_nano() - st.mtime_ns < racy_window_ns {85+ return hash86+ }7787 s.save_cache(storage.CacheRow{7888 path: rel7989 size: st.sizev.mod+1 −1
@@ -1,6 +1,6 @@11 Module {22 name: 'koh3'3- version: '3.0.28'3+ version: '3.0.29'44 description: 'One SQLite file per repo, one line of history.'55 license: 'MIT'66 }