╭ changed ────────────╮ │src/ui/Home/Users.zig│ ╰─────────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │28 │ │29 var users: std.ArrayList(evt.User.Safe) = .empty; │ │30 │ │31 - // the ordered user-list (oldest first); absent until the first user exists. │ │32 - const user_list_cursor = try haxy_moment.getCursor(hash.hashInt(hash_kind, "user-list")) orelse │ │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│ │34 return .{ .users = &.{}, .after = after, .next_after = null }; │ │34 - const user_list = try DB.ArrayList(.read_only).init(user_list_cursor); │ │35 - const count = try user_list.count(); │ │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(); │ │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 │ │41 - // read the window [after, after+page_size) by index — a direct O(log n) │ │42 - // seek per entry, never scanning the whole table. ids whose user has been │ │43 - // deleted (tombstones) are skipped. │ │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. │ │45 const end = @min(after + page_size, count); │ │46 var i = after; │ │47 while (i < end) : (i += 1) { │ ╰──────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │47 - const id_cursor = try user_list.getCursor(@intCast(i)) orelse continue; │ │48 + const id_kv = try timestamp_to_user_id.getIndexKeyValuePair(@intCast(i)) orelse continue; │ │49 var event_id: [evt.event_id_size]u8 = undefined; │ │49 - _ = try id_cursor.readBytes(&event_id); │ │50 + _ = try id_kv.value_cursor.readBytes(&event_id); │ │51 const user_cursor = try event_id_to_user.getCursor(hash.hashInt(hash_kind, &event_id)) orelse continue;│ │52 const user_map = try DB.HashMap(.read_only).init(user_cursor); │ │53 const user_event = try evt.read(evt.User, DB, hash_kind, arena, user_map); │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯