╭ changed ─────────╮ │src/event/Repo.zig│ ╰──────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │77 // first time we've seen this repo: add it to the ordered map the repos │ │78 // view paginates through │ │79 if (existing_cursor_maybe == null) { │ │80 - const timestamp_to_repo_id_cursor = try haxy_moment.putCursor(hash.hashInt(hash_kind, "timestamp->repo-id")); │ │81 - const timestamp_to_repo_id = try DB.SortedMap(.read_write).init(timestamp_to_repo_id_cursor); │ │80 + const created_ts_to_repo_id_cursor = try haxy_moment.putCursor(hash.hashInt(hash_kind, "created-ts->repo-id"));│ │81 + const created_ts_to_repo_id = try DB.SortedMap(.read_write).init(created_ts_to_repo_id_cursor); │ │82 const order_key = evt.orderKey(event_to_write.created_ts, event_id); │ │83 - try timestamp_to_repo_id.put(&order_key, .{ .bytes = event_id }); │ │83 + try created_ts_to_repo_id.put(&order_key, .{ .bytes = event_id }); │ │84 } │ │85 │ │86 const user_id_to_repos_cursor = try haxy_moment.putCursor(hash.hashInt(hash_kind, "user-id->repos")); │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 98 _ = try name_to_repo_id.remove(hash.hashInt(hash_kind, existing_path)); │ │ 99 │ │100 // drop it from the ordered map using its recorded creation timestamp │ │101 - const timestamp_to_repo_id_cursor = try haxy_moment.putCursor(hash.hashInt(hash_kind, "timestamp->repo-id")); │ │102 - const timestamp_to_repo_id = try DB.SortedMap(.read_write).init(timestamp_to_repo_id_cursor); │ │101 + const created_ts_to_repo_id_cursor = try haxy_moment.putCursor(hash.hashInt(hash_kind, "created-ts->repo-id"));│ │102 + const created_ts_to_repo_id = try DB.SortedMap(.read_write).init(created_ts_to_repo_id_cursor); │ │103 const order_key = evt.orderKey(existing_repo_event.created_ts, event_id); │ │104 - _ = try timestamp_to_repo_id.remove(&order_key); │ │104 + _ = try created_ts_to_repo_id.remove(&order_key); │ │105 │ │106 const user_id_to_repos_cursor = try haxy_moment.putCursor(hash.hashInt(hash_kind, "user-id->repos")); │ │107 const user_id_to_repos = try DB.HashMap(.read_write).init(user_id_to_repos_cursor); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─────────╮ │src/event/User.zig│ ╰──────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │86 // first time we've seen this user: add it to the ordered map the users │ │87 // view paginates through │ │88 if (existing_cursor_maybe == null) { │ │89 - const timestamp_to_user_id_cursor = try haxy_moment.putCursor(hash.hashInt(hash_kind, "timestamp->user-id")); │ │90 - const timestamp_to_user_id = try DB.SortedMap(.read_write).init(timestamp_to_user_id_cursor); │ │89 + const created_ts_to_user_id_cursor = try haxy_moment.putCursor(hash.hashInt(hash_kind, "created-ts->user-id"));│ │90 + const created_ts_to_user_id = try DB.SortedMap(.read_write).init(created_ts_to_user_id_cursor); │ │91 const order_key = evt.orderKey(event_to_write.created_ts, event_id); │ │92 - try timestamp_to_user_id.put(&order_key, .{ .bytes = event_id }); │ │92 + try created_ts_to_user_id.put(&order_key, .{ .bytes = event_id }); │ │93 } │ │94 } else { │ │95 // read the user's name so we can drop its name->id index entry │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 99 _ = try name_to_user_id.remove(hash.hashInt(hash_kind, existing_event.name)); │ │100 │ │101 // drop it from the ordered map using its recorded creation timestamp │ │102 - const timestamp_to_user_id_cursor = try haxy_moment.putCursor(hash.hashInt(hash_kind, "timestamp->user-id")); │ │103 - const timestamp_to_user_id = try DB.SortedMap(.read_write).init(timestamp_to_user_id_cursor); │ │102 + const created_ts_to_user_id_cursor = try haxy_moment.putCursor(hash.hashInt(hash_kind, "created-ts->user-id"));│ │103 + const created_ts_to_user_id = try DB.SortedMap(.read_write).init(created_ts_to_user_id_cursor); │ │104 const order_key = evt.orderKey(existing_event.created_ts, event_id); │ │105 - _ = try timestamp_to_user_id.remove(&order_key); │ │105 + _ = try created_ts_to_user_id.remove(&order_key); │ │106 } │ │107 │ │108 if (!try event_id_to_user.remove(user_key)) return error.EventNotFound; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─────────╮ │src/test/event.zig│ ╰──────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │852 moment: DB.HashMap(.read_only), │ │853 expected: []const *const [evt.event_id_size]u8, │ │854 ) !void { │ │855 - const cursor = try moment.getCursor(hash.hashInt(hash_kind, "timestamp->repo-id")) orelse return error.NotFound; │ │855 + const cursor = try moment.getCursor(hash.hashInt(hash_kind, "created-ts->repo-id")) orelse return error.NotFound;│ │856 const map = try DB.SortedMap(.read_only).init(cursor); │ │857 try std.testing.expectEqual(expected.len, try map.count()); │ │858 for (expected, 0..) |id, i| { │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │880 try Check.order(Repo.DB, repo_opts.hash, moment, &.{ &repo_ids[0], &repo_ids[1], &repo_ids[2], &repo_ids[3] }); │ │881 │ │882 // the single user shows up in its own ordered map │ │883 - const ucur = try moment.getCursor(hash.hashInt(repo_opts.hash, "timestamp->user-id")) orelse return error.NotFound; │ │883 + const ucur = try moment.getCursor(hash.hashInt(repo_opts.hash, "created-ts->user-id")) orelse return error.NotFound;│ │884 const umap = try Repo.DB.SortedMap(.read_only).init(ucur); │ │885 try std.testing.expectEqual(1, try umap.count()); │ │886 } │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ────────────╮ │src/ui/Home/Repos.zig│ ╰─────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │34 │ │35 // the repos ordered by creation time (oldest first); absent until the first │ │36 // repo exists. keyed by [timestamp][event-id], value = event-id. │ │37 - const timestamp_to_repo_id_cursor = try haxy_moment.getCursor(hash.hashInt(hash_kind, "timestamp->repo-id")) orelse return empty; │ │38 - const timestamp_to_repo_id = try DB.SortedMap(.read_only).init(timestamp_to_repo_id_cursor); │ │39 - const count = try timestamp_to_repo_id.count(); │ │37 + const created_ts_to_repo_id_cursor = try haxy_moment.getCursor(hash.hashInt(hash_kind, "created-ts->repo-id")) orelse return empty;│ │38 + const created_ts_to_repo_id = try DB.SortedMap(.read_only).init(created_ts_to_repo_id_cursor); │ │39 + const count = try created_ts_to_repo_id.count(); │ │40 │ │41 const event_id_to_repo_cursor = try haxy_moment.getCursor(hash.hashInt(hash_kind, "event-id->repo")) orelse return empty; │ │42 const event_id_to_repo = try DB.HashMap(.read_only).init(event_id_to_repo_cursor); │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │43 │ │44 - // read the window [after, after+page_size) by index — a direct O(log n) seek │ │45 - // per entry, never scanning the whole table. deletes remove their entry (no │ │46 - // tombstones), so the window is dense. │ │44 + // read the window [after, after+page_size) with one seek to the start rank, │ │45 + // then a sequential walk │ │46 const end = @min(after + page_size, count); │ │47 + var iter = try created_ts_to_repo_id.iteratorFromIndex(after); │ │48 var i = after; │ │49 while (i < end) : (i += 1) { │ │50 - const id_kv = try timestamp_to_repo_id.getIndexKeyValuePair(@intCast(i)) orelse continue; │ │50 + var id_cursor = (try iter.next()) orelse break; │ │51 + const id_kv = try id_cursor.readKeyValuePair(); │ │52 var event_id: [evt.event_id_size]u8 = undefined; │ │53 _ = try id_kv.value_cursor.readBytes(&event_id); │ │54 const repo_cursor = try event_id_to_repo.getCursor(hash.hashInt(hash_kind, &event_id)) orelse continue;│ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ────────────╮ │src/ui/Home/Users.zig│ ╰─────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │30 │ │31 // the users ordered by creation time (oldest first); absent until the first │ │32 // user exists. keyed by [timestamp][event-id], value = event-id. │ │33 - const timestamp_to_user_id_cursor = try haxy_moment.getCursor(hash.hashInt(hash_kind, "timestamp->user-id")) orelse │ │33 + const created_ts_to_user_id_cursor = try haxy_moment.getCursor(hash.hashInt(hash_kind, "created-ts->user-id")) orelse│ │34 return .{ .users = &.{}, .after = after, .next_after = null }; │ │35 - const timestamp_to_user_id = try DB.SortedMap(.read_only).init(timestamp_to_user_id_cursor); │ │36 - const count = try timestamp_to_user_id.count(); │ │35 + const created_ts_to_user_id = try DB.SortedMap(.read_only).init(created_ts_to_user_id_cursor); │ │36 + const count = try created_ts_to_user_id.count(); │ │37 │ │38 const event_id_to_user_cursor = try haxy_moment.getCursor(hash.hashInt(hash_kind, "event-id->user")) orelse │ │39 return .{ .users = &.{}, .after = after, .next_after = null }; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │40 const event_id_to_user = try DB.HashMap(.read_only).init(event_id_to_user_cursor); │ │41 │ │42 - // read the window [after, after+page_size) by index — a direct O(log n) seek │ │43 - // per entry, never scanning the whole table. deletes remove their entry (no │ │44 - // tombstones), so the window is dense. │ │42 + // read the window [after, after+page_size) with one seek to the start rank, │ │43 + // then a sequential walk │ │44 const end = @min(after + page_size, count); │ │45 + var iter = try created_ts_to_user_id.iteratorFromIndex(after); │ │46 var i = after; │ │47 while (i < end) : (i += 1) { │ │48 - const id_kv = try timestamp_to_user_id.getIndexKeyValuePair(@intCast(i)) orelse continue; │ │48 + var id_cursor = (try iter.next()) orelse break; │ │49 + const id_kv = try id_cursor.readKeyValuePair(); │ │50 var event_id: [evt.event_id_size]u8 = undefined; │ │51 _ = try id_kv.value_cursor.readBytes(&event_id); │ │52 const user_cursor = try event_id_to_user.getCursor(hash.hashInt(hash_kind, &event_id)) orelse continue;│ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯