1a8e4215f494
offer only the objects each save adds over its parent, so an auto-offer costs one write per changed file, not per file (3.0.41, codex review pending)
- time
- 2026-09-24 04:48 UTC · 2 weeks ago
- machine
- koh2
- agent
- claude-opus-5-5
- session
- koh 3 reliability campaign
- parent
- cc776360f741
↓ koh-1a8e4215.tar.gzatlas at this save
files changed4 files
VERSION+1 −1src/sync/sync.v+13 −0src/sync/sync_test.v+29 −0v.mod+1 −1src/sync/sync.v+13 −0
@@ -118,7 +118,20 @@118118 119119 fn upload_save(store &storage.Store, mut backend remote.Backend, repo string, save history.Save, mut report OfferReport) ! {120120 files := history.files_of(store, save.id)!121+ // Saves go up oldest first and head moves only once all of them landed, so122+ // the parent and its objects are on the remote already: only content new123+ // in this save travels, not a round trip per file in the repo.124+ mut sent := map[string]bool{}125+ if save.parent != '' {126+ for file in history.files_of(store, save.parent)! {127+ sent[file.hash] = true128+ }129+ }121130 for file in files {131+ if file.hash in sent {132+ continue133+ }134+ sent[file.hash] = true122135 if backend.put_if_absent(object_key(repo, file.hash), store.object_blob(file.hash)!)! {123136 report.objects++124137 }src/sync/sync_test.v+29 −0
@@ -629,6 +629,35 @@629629 f.inner.delete(key)!630630 }631631 632+// Every save offers after it is made, so a one-file change must cost one633+// object, not one conditional write per file in the repo: on S3 each of those634+// is a round trip.635+fn test_an_offer_sends_only_the_objects_a_save_adds() {636+ base := scratch('offer_diff')!637+ defer {638+ os.rmdir_all(base) or {}639+ }640+ mut a := open_repo(machine('offer_diff_a')!)!641+ defer {642+ a.close()643+ }644+ for i in 0 .. 20 {645+ put(a.root, 'f${i}.txt', 'file ${i}\n')!646+ }647+ commit(a, 'twenty files')!648+ mut backend := FaultyBackend{649+ inner: remote.new_folder(os.join_path(base, 'remote'))!650+ }651+ offer(a, mut backend)!652+ put(a.root, 'f3.txt', 'changed\n')!653+ commit(a, 'one change')!654+ before := backend.writes655+ report := offer(a, mut backend)!656+ assert report.objects == 1657+ // One object, one save record, one head swap.658+ assert backend.writes - before == 3659+}660+632661 fn test_a_failed_offer_is_safe_to_re_run() {633662 base := scratch('fault_offer')!634663 defer {v.mod+1 −1
@@ -1,6 +1,6 @@11 Module {22 name: 'koh3'3- version: '3.0.40'3+ version: '3.0.41'44 description: 'One SQLite file per repo, one line of history.'55 license: 'MIT'66 }