╭ changed ────╮ │src/patch.zig│ ╰─────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭───────────────────────────────────────────────────────╮ │237 return .unknown; │ │238 } │ │239 }; │ │240 - │ │241 -const mergeability_key = "patch-id->mergeability";│ │240 │ │241 const MergeCheck = struct { │ │242 revision: evt.Patch.Revision, │ ╰───────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────╮ │253 │ │254 fn readMergeCheck( │ │255 comptime repo_opts: rp.RepoOpts(.xit), │ │258 - moment: evt.EventDB(repo_opts.hash).HashMap(.read_only), │ │256 + haxy_moment: evt.EventDB(repo_opts.hash).HashMap(.read_only),│ │257 arena: *std.heap.ArenaAllocator, │ │258 id: *const [evt.event_id_size]u8, │ │259 ) !?MergeCheck { │ ╰──────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │260 const DB = evt.EventDB(repo_opts.hash); │ │263 - const map_cursor = try moment.getCursor(hash.hashInt(repo_opts.hash, mergeability_key)) orelse return null; │ │261 + const map_cursor = try haxy_moment.getCursor(hash.hashInt(repo_opts.hash, evt.Patch.patch_id_to_mergeability_key)) orelse return null;│ │262 const map = try DB.HashMap(.read_only).init(map_cursor); │ │263 const cursor = try map.getCursor(hash.hashInt(repo_opts.hash, id)) orelse return null; │ │264 return evt.read(MergeCheck, DB, repo_opts.hash, arena, try DB.HashMap(.read_only).init(cursor)) catch |err| switch (err) { │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │278 ) !Mergeability { │ │279 if (patch.source_branch != null and !try branchCurrent(repo_opts, state, io, arena, patch)) return .{}; │ │280 const target_oid = try rf.readRecur(.xit, repo_opts, state, io, .{ .ref = .{ .kind = .head, .name = patch.target_branch } }) orelse return .{};│ │283 - const cached = try readMergeCheck(repo_opts, state.extra.moment.*, arena, id) orelse return .{}; │ │281 + const haxy_moment = evt.currentMomentFromRepoMoment(repo_opts.hash, state.extra.moment.*) catch |err| switch (err) { │ │282 + error.NotFound => return .{}, │ │283 + else => return err, │ │284 + }; │ │285 + const cached = try readMergeCheck(repo_opts, haxy_moment, arena, id) orelse return .{}; │ │286 return if (cached.matches(patch, &target_oid)) cached.result else .{}; │ │287 } │ │288 │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │335 const DB = Repo.DB; │ │336 var arena = std.heap.ArenaAllocator.init(allocator); │ │337 defer arena.deinit(); │ │336 - const initial = try evt.readFromRepo(evt.Patch, .xit, repo_opts, io, allocator, &arena, target_repo, id); │ │337 - if (initial) |record| if (record.removed or record.event.status.kind() != .open) return; │ │338 + const initial = (try evt.readFromRepo(evt.Patch, .xit, repo_opts, io, allocator, &arena, target_repo, id)) orelse return; │ │339 + if (initial.removed or initial.event.status.kind() != .open) return; │ │340 const repo_root_path = std.fs.path.dirname(target_repo.core.work_path) orelse "."; │ │341 const path = try fork.forkPath(arena.allocator(), repo_root_path, &std.fmt.bytesToHex(id.*, .lower)); │ │340 - const branch_backed = if (initial) |record| record.event.source_branch != null else false; │ │342 + const branch_backed = initial.event.source_branch != null; │ │343 var fork_repo_maybe: ?Repo = if (branch_backed) null else Repo.open(io, allocator, .{ .path = path, .require_repo_root = true }) catch |err| blk: {│ │344 std.log.warn("mergeability fork unavailable: {s}", .{@errorName(err)}); │ │345 break :blk null; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │353 var target_moment = try target_repo.core.latestMoment(); │ │354 const target_state = Repo.State(.read_only){ .core = &target_repo.core, .extra = .{ .moment = &target_moment } }; │ │355 const target_events = evt.currentMomentFromRepoMoment(repo_opts.hash, target_moment) catch |err| switch (err) { │ │354 - error.NotFound => null, │ │356 + error.NotFound => return, │ │357 else => return err, │ │358 }; │ │357 - var record = if (target_events) |events| try evt.Patch.readById(DB, repo_opts.hash, events, &arena, id) else null;│ │359 + const patch_record = (try evt.Patch.readById(DB, repo_opts.hash, target_events, &arena, id)) orelse return; │ │360 + if (patch_record.removed or patch_record.event.status.kind() != .open) return; │ │361 var newest: ?evt.PatchRev.WithId = null; │ │362 if (fork_repo_maybe) |*repo| { │ │363 if (evt.currentMoment(repo_opts, repo)) |events| { │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │365 std.log.warn("mergeability revision unavailable: {s}", .{@errorName(err)}); │ │366 break :blk null; │ │367 }; │ │365 - if (record == null) record = try evt.Patch.readById(DB, repo_opts.hash, events, &arena, id); │ │368 } else |err| std.log.warn("mergeability revision unavailable: {s}", .{@errorName(err)}); │ │369 } │ │368 - const patch_record = record orelse return; │ │369 - if (patch_record.removed or patch_record.event.status.kind() != .open) return; │ │370 const patch = patch_record.event; │ │371 const revision = patch.revision orelse return; │ │372 const target_oid = try rf.readRecur(.xit, repo_opts, target_state, io, .{ .ref = .{ .kind = .head, .name = patch.target_branch } });│ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │373 var check = MergeCheck{ .revision = revision, .target_branch = patch.target_branch, .target_oid = if (target_oid) |*oid| oid else "" }; │ │374 - const cached = try readMergeCheck(repo_opts, target_moment, &arena, id); │ │374 + const cached = try readMergeCheck(repo_opts, target_events, &arena, id); │ │375 const current = if (patch.source_branch != null) try branchCurrent(repo_opts, target_state, io, &arena, patch) else if (newest) |latest| std.mem.eql(u8, &std.fmt.bytesToHex(latest.id, .lower), &revision.id) and revision.matches(latest.record) else false;│ │376 if (current and target_oid != null) { │ │377 if (cached) |value| if (value.matches(patch, check.target_oid) and value.result.source != .unknown and value.result.squash != .unknown) return; │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │421 │ │422 pub fn run(ctx: @This(), cursor: *DB.Cursor(.read_write)) !void { │ │423 const moment = try DB.HashMap(.read_write).init(cursor.*); │ │424 - const map = try DB.HashMap(.read_write).init(try moment.putCursor(hash.hashInt(repo_opts.hash, mergeability_key))); │ │424 + const last_object_id_cursor = try moment.getCursor(hash.hashInt(repo_opts.hash, evt.last_object_id_key)) orelse return error.NotFound; │ │425 + var last_object_id: [hash.byteLen(repo_opts.hash)]u8 = undefined; │ │426 + _ = try last_object_id_cursor.readBytes(&last_object_id); │ │427 + const haxy = try DB.ArrayList(.read_write).init(try moment.putCursor(hash.hashInt(repo_opts.hash, evt.materialized_key))); │ │428 + const haxy_moments = try DB.HashMap(.read_write).init(try haxy.putCursor(-1)); │ │429 + const haxy_moment = try DB.HashMap(.read_write).init(try haxy_moments.putCursor(hash.bytesToInt(repo_opts.hash, &last_object_id))); │ │430 + const map = try DB.HashMap(.read_write).init(try haxy_moment.putCursor(hash.hashInt(repo_opts.hash, evt.Patch.patch_id_to_mergeability_key)));│ │431 const entry = try DB.HashMap(.read_write).init(try map.putCursor(hash.hashInt(repo_opts.hash, &ctx.id))); │ │432 try evt.upsert(MergeCheck, DB, repo_opts.hash, entry, ctx.check); │ │433 + // discard the old repo-level cache as results are rebuilt here │ │434 + _ = try moment.remove(hash.hashInt(repo_opts.hash, evt.Patch.patch_id_to_mergeability_key)); │ │435 } │ │436 }; │ │437 const history = try DB.ArrayList(.read_write).init(target_repo.core.db.rootCursor()); │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯