╭ changed ────────────╮ │src/search_commit.zig│ ╰─────────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭────────────────────────────────────────────────────────────────────────────────╮ │ 7 const rf = xit.ref; │ │ 8 const obj = xit.object; │ │ 9 const mrg = xit.merge; │ │10 -const serve_common = @import("serve_common.zig"); │ │10 const progress = @import("./progress.zig"); │ │11 │ │12 // the repo moment key holding one commit-message index per ref tip. it sits│ ╰────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────╮ │13 // outside the haxy moment because pushes change it and events never do. each │ │14 // entry is keyed by its commit oid's hash: its value is the index as of that │ │16 -// commit, and its key slot holds the raw commit oid. │ │15 +// commit, and its key slot holds the raw commit oid followed by its timestamp.│ │16 pub const index_key = "haxy/commit-oid->word->time+oid"; │ │17 │ │19 -// a commit a version covers. │ │20 -pub fn Commit(comptime hash_kind: hash.HashKind) type { │ │21 - return struct { │ │22 - oid: [hash.hexLen(hash_kind)]u8, │ │23 - timestamp: u64, │ │24 - }; │ │25 -} │ │18 +// a ref move: the old tip's version, when it has one, is the base the new │ │19 +// tip's derives from │ │20 +pub const Move = struct { │ │21 + old_oid: []const u8, │ │22 + new_oid: []const u8, │ │23 +}; │ │24 │ │25 // `commit_oid`'s index, or null when it has none. a version is correct for its│ │26 // commit by construction, so there is nothing to check for staleness. │ ╰───────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────╮ │72 io: std.Io, │ │73 allocator: std.mem.Allocator, │ │74 repo: *rp.Repo(.xit, repo_opts), │ │77 - updates: ?[]const xit.net_server_receive_pack.AppliedRefUpdate,│ │75 ) !void { │ │76 const Repo = rp.Repo(.xit, repo_opts); │ │77 const DB = Repo.DB; │ ╰───────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────╮ │79 core: *Repo.Core, │ │80 io: std.Io, │ │81 allocator: std.mem.Allocator, │ │85 - updates: ?[]const xit.net_server_receive_pack.AppliedRefUpdate, │ │82 │ │83 pub fn run(ctx: @This(), cursor: *DB.Cursor(.read_write)) !void {│ │84 var moment = try DB.HashMap(.read_write).init(cursor.*); │ ╰─────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │85 const state = Repo.State(.read_write){ .core = ctx.core, .extra = .{ .moment = &moment } }; │ │90 - if (!try refreshInTransaction(repo_opts, state, &moment, ctx.io, ctx.allocator, ctx.updates, null)) return error.CancelTransaction; │ │86 + if (!try refreshInTransaction(repo_opts, state, &moment, ctx.io, ctx.allocator, &.{}, null)) return error.CancelTransaction; │ │87 │ │88 // record the user action for undo │ │89 try xit.undo.write(repo_opts, state, std.Io.Timestamp.now(ctx.io, .real).toSeconds(), .{ .custom = .{ .action_kind = undo_action } });│ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 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(); │ ╰─────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯