123456module exchange78import compress.zlib9import src.events10import src.history11import src.remote12import src.storage13141516pub fn fetch_missing(store &storage.Store, mut backend remote.Backend, repo string, ids []string) !int {17 mut fetched := Fetched{}18 mut wanted := ids.clone()19 mut seen := map[string]bool{}20 for wanted.len > 0 {21 id := wanted.pop()22 if id == '' || id in seen || history.by_id(store, id) != none {23 continue24 }25 seen[id] = true26 object := backend.get(save_key(repo, id))!27 if !object.found {28 return error('the remote does not have save ${id} either')29 }30 record := decode_save(object.body)!31 if record.id != id {32 return error('remote save ${id} holds the record of ${record.id}')33 }34 for file in record.files {35 if !store.has_object(file.hash)! && file.hash !in fetched.repo_objects {36 blob := backend.get(object_key(repo, file.hash))!37 if !blob.found {38 return error('the remote is missing object ${file.hash} that save ${id} needs')39 }40 fetched.repo_objects[file.hash] = blob.body41 }42 }43 fetched.saves << record44 wanted << record.parent45 wanted << record.restores46 }47 48 mut ordered := []SaveRecord{}49 mut placed := map[string]bool{}50 for ordered.len < fetched.saves.len {51 before := ordered.len52 for record in fetched.saves {53 if record.id !in placed && (record.parent !in seen || record.parent in placed) {54 ordered << record55 placed[record.id] = true56 }57 }58 if ordered.len == before {59 return error('the remote history has a parent cycle')60 }61 }62 fetched.saves = ordered63 store.begin()!64 write_fetched_records(store, fetched) or {65 store.rollback()66 return err67 }68 store.end()!69 return ordered.len70}71727374pub fn resend(store &storage.Store, mut backend remote.Backend, repo string, hashes []string, save_ids []string) !int {75 76 77 if unapplied_strips(store, mut backend, repo)!.len > 0 {78 return error(strip_not_applied)79 }80 mut sent := 081 for hash in hashes {82 key := object_key(repo, hash)83 existing := backend.get(key)!84 if existing.found {85 data := zlib.decompress(existing.body) or { []u8{} }86 87 if storage.hash_hex(data) == hash {88 continue89 }90 backend.delete(key)!91 }92 store.get_object(hash)!93 if backend.put_if_absent(key, store.object_blob(hash)!)! {94 sent++95 }96 }97 for id in save_ids {98 save := history.by_id(store, id) or { return error('save ${id} is missing here too') }99 for file in history.files_of(store, id)! {100 store.get_object(file.hash)!101 if backend.put_if_absent(object_key(repo, file.hash), store.object_blob(file.hash)!)! {102 sent++103 }104 }105 if backend.put_if_absent(save_key(repo, id), encode_save(save_record(store, save)!).bytes())! {106 sent++107 }108 }109 return sent110}111112113114pub fn reapply_strips(store &storage.Store) !int {115 store.begin()!116 mut removed := 0117 for event in events.strip_events(store) or {118 store.rollback()119 return err120 } {121 removed += remove_path(store, event.path, event.save_id) or {122 store.rollback()123 return err124 }125 }126 store.drop_unreferenced_objects() or {127 store.rollback()128 return err129 }130 store.end()!131 return removed132}