╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ────────────╮ │src/search_commit.zig│ ╰─────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 96 defer repo.core.db_file.unlock(io); │ │ 97 │ │ 98 const history = try DB.ArrayList(.read_write).init(repo.core.db.rootCursor()); │ │103 - history.appendContext(.{ .slot = try history.getSlot(-1) }, Save{ .core = &repo.core, .io = io, .allocator = allocator, .updates = updates }) catch |err| switch (err) {│ │ 99 + history.appendContext(.{ .slot = try history.getSlot(-1) }, Save{ .core = &repo.core, .io = io, .allocator = allocator }) catch |err| switch (err) { │ │100 error.CancelTransaction => {}, │ │101 else => return err, │ │102 }; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────╮ │103 } │ │104 │ │105 // reconcile them inside the caller's transaction, so the index lands with the │ │110 -// push that invalidated it. `updates` is that push, whose old oids are the │ │111 -// cheapest bases to derive the new tips from. reports whether anything was │ │112 -// written, so a caller that owns an otherwise empty transaction can cancel it │ │106 +// change that invalidated it. `moves` are the refs that change moved, whose │ │107 +// old oids are the cheapest bases to derive the new tips from. reports whether│ │108 +// anything was written, so a caller that owns an otherwise empty transaction │ │109 +// can cancel it │ │110 pub fn refreshInTransaction( │ │111 comptime repo_opts: rp.RepoOpts(.xit), │ │112 state: rp.Repo(.xit, repo_opts).State(.read_write), │ ╰────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────╮ │113 moment: *rp.Repo(.xit, repo_opts).DB.HashMap(.read_write), │ │114 io: std.Io, │ │115 allocator: std.mem.Allocator, │ │119 - updates: ?[]const xit.net_server_receive_pack.AppliedRefUpdate,│ │116 + moves: []const Move, │ │117 progress_ctx_maybe: ?repo_opts.ProgressCtx, │ │118 ) !bool { │ │119 const Repo = rp.Repo(.xit, repo_opts); │ ╰────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────╮ │120 const DB = Repo.DB; │ │121 const Oid = [hash.hexLen(repo_opts.hash)]u8; │ │125 - const Tip = Commit(repo_opts.hash); │ │122 + const oid_len = comptime hash.byteLen(repo_opts.hash); │ │123 + // an entry's key slot: the raw commit oid followed by its timestamp │ │124 + const Entry = [oid_len + @sizeOf(u64)]u8; │ │125 │ │126 // one version to build: the commit it covers, and the commit whose version│ │127 // it derives from (null = walk the whole history). │ ╰────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────╮ │138 var work: std.ArrayList(Work) = .empty; │ │139 var gone: std.ArrayList(Oid) = .empty; │ │140 var default_tip: ?Oid = null; │ │142 - // the versions a new tip can derive from │ │143 - var versions: std.ArrayList(Tip) = .empty; │ │141 + // the versions in the index, each with its commit's timestamp. the ones│ │142 + // built here join them, so a later tip can derive from an earlier one. │ │143 + var versions: std.AutoArrayHashMapUnmanaged(Oid, u64) = .empty; │ │144 │ │145 { │ │146 const read_state = state.readOnly(); │ ╰─────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────╮ │147 │ │148 - // the commits that already have a version │ │149 - var existing: std.AutoArrayHashMapUnmanaged(Oid, void) = .empty; │ │148 if (try moment.getCursor(hash.hashInt(repo_opts.hash, index_key))) |index_cursor| {│ │149 const index = try DB.HashMap(.read_only).init(index_cursor); │ │150 var iter = try index.iterator(); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │151 while (try iter.next()) |cursor| { │ │152 const pair = try cursor.readKeyValuePair(); │ │155 - var oid_bytes: [hash.byteLen(repo_opts.hash)]u8 = undefined; │ │156 - if ((try pair.key_cursor.readBytes(&oid_bytes)).len != oid_bytes.len) return error.InvalidCommitIndex;│ │157 - try existing.put(aa, std.fmt.bytesToHex(oid_bytes, .lower), {}); │ │153 + var entry: Entry = undefined; │ │154 + if ((try pair.key_cursor.readBytes(&entry)).len != entry.len) return error.InvalidCommitIndex; │ │155 + const oid = std.fmt.bytesToHex(entry[0..oid_len].*, .lower); │ │156 + try versions.put(aa, oid, std.mem.readInt(u64, entry[oid_len..], .big)); │ │157 } │ │158 } │ │159 │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────╮ │181 var missing: std.AutoArrayHashMapUnmanaged(Oid, Work) = .empty;│ │182 for (tips.items) |tip| { │ │183 // a tip that already has a version needs no reading │ │185 - if (existing.contains(tip)) { │ │184 + if (versions.contains(tip)) { │ │185 try wanted.put(aa, tip, {}); │ │186 continue; │ │187 } │ ╰────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │188 var commit = obj.Object(.xit, repo_opts).initCommit(read_state, io, allocator, &tip) catch continue;│ │189 defer commit.deinit(); │ │190 try wanted.put(aa, commit.oid, {}); │ │192 - if (existing.contains(commit.oid)) continue; │ │191 + if (versions.contains(commit.oid)) continue; │ │192 const entry = try missing.getOrPut(aa, commit.oid); │ │193 if (!entry.found_existing) entry.value_ptr.* = .{ │ │194 .oid = commit.oid, │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │195 .timestamp = commit.content.commit.metadata.timestamp, │ │196 .base = null, │ │197 }; │ │199 - if (entry.value_ptr.base == null) entry.value_ptr.base = pushedFrom(repo_opts, updates, &tip, existing);│ │198 + if (entry.value_ptr.base == null) entry.value_ptr.base = movedFrom(repo_opts, moves, &tip, versions); │ │199 } │ │200 │ │201 var head_buffer: [rf.MAX_REF_CONTENT_SIZE]u8 = undefined; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯