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
4 files VERSION+1 −1src/snapshot/snapshot_test.v+20 −0src/snapshot/tree.v+10 −0v.mod+1 −1
VERSION+1 −1
@@ -1 +1 @@1-3.0.281+3.0.29

view file

src/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() {

view file

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.size

view file

v.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 }

view file