authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-06-28 01:31:07 -07:00
committergravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-06-28 01:31:07 -07:00
log1313631aae874c8fa83624cb9538118de62584e7
tree5b6e669b2301a92de9f9c4ab2f51ba3d012966c5
parent00f78a59fc822ae595132f3a01dee19a30d8d23d
signaturebadge-check Signed by SSH key SHA256:4hHJbtBRU58AYXwjL7fkz2fnQHdiye8x1QpTCQ0sHNw

turn unpacked_objects into a sliding window of cached objects


1 files changed, 81 insertions(+), 44 deletions(-)

git.zig+81-44
......@@ -721,11 +721,13 @@ pub const Repository = struct {
721721 gpa: std.mem.Allocator,
722722 unpacked_loose_objects: std.StringArrayHashMapUnmanaged(GitObject),
723723 unpacked_objects: std.AutoArrayHashMapUnmanaged(u64, GitObject),
724 unpacked_objects_window: usize,
724725 idx_content: std.StringArrayHashMapUnmanaged([]const u8),
725726 pack_content: std.StringArrayHashMapUnmanaged([]const u8),
726727 commits: std.StringArrayHashMapUnmanaged(*Commit),
727728 trees: std.StringArrayHashMapUnmanaged(*Tree),
728729 tags: std.StringArrayHashMapUnmanaged(*Tag),
730 mailmap_content: []const u8,
729731 mailmap: std.hash_map.StringHashMapUnmanaged([]const u8),
730732 mailmap_names: std.hash_map.StringHashMapUnmanaged([]const u8),
731733
......@@ -737,11 +739,13 @@ pub const Repository = struct {
737739 .gpa = gpa,
738740 .unpacked_loose_objects = .empty,
739741 .unpacked_objects = .empty,
742 .unpacked_objects_window = 0,
740743 .idx_content = .empty,
741744 .pack_content = .empty,
742745 .commits = .empty,
743746 .trees = .empty,
744747 .tags = .empty,
748 .mailmap_content = "",
745749 .mailmap = .empty,
746750 .mailmap_names = .empty,
747751 };
......@@ -795,6 +799,7 @@ pub const Repository = struct {
795799 }
796800 }
797801 }
802 r.mailmap_content = mailmap_content;
798803 r.mailmap = mailmap;
799804 r.mailmap_names = mailmap_names;
800805 }
......@@ -966,7 +971,19 @@ pub const Repository = struct {
966971 const _type = std.meta.stringToEnum(RefType, @tagName(ty)).?;
967972 const content = try list.toOwnedSlice();
968973 const obj: GitObject = .{ .type = _type, .content = content };
969 if (cache_behavior == .cache) try r.unpacked_objects.put(r.gpa, key, obj);
974 const window_max = 1024 * 128;
975 if (cache_behavior == .cache) {
976 if (r.unpacked_objects.count() < window_max) {
977 try r.unpacked_objects.put(r.gpa, key, obj);
978 } else {
979 const item = &r.unpacked_objects.values()[r.unpacked_objects_window];
980 r.gpa.free(item.content);
981 r.unpacked_objects.keys()[r.unpacked_objects_window] = key;
982 item.* = obj;
983 }
984 r.unpacked_objects_window += 1;
985 r.unpacked_objects_window %= window_max;
986 }
970987 return obj;
971988 },
972989 .ofs_delta => {
......@@ -1064,7 +1081,19 @@ pub const Repository = struct {
10641081 const _type = base_obj.type;
10651082 const content = try list2.toOwnedSlice(r.gpa);
10661083 const obj: GitObject = .{ .type = _type, .content = content };
1067 if (cache_behavior == .cache) try r.unpacked_objects.put(r.gpa, key, obj);
1084 const window_max = 1024 * 128;
1085 if (cache_behavior == .cache) {
1086 if (r.unpacked_objects.count() < window_max) {
1087 try r.unpacked_objects.put(r.gpa, key, obj);
1088 } else {
1089 const item = &r.unpacked_objects.values()[r.unpacked_objects_window];
1090 r.gpa.free(item.content);
1091 r.unpacked_objects.keys()[r.unpacked_objects_window] = key;
1092 item.* = obj;
1093 }
1094 r.unpacked_objects_window += 1;
1095 r.unpacked_objects_window %= window_max;
1096 }
10681097 return obj;
10691098 }
10701099
......@@ -1090,9 +1119,9 @@ pub const Repository = struct {
10901119 pub fn getBlob(r: *Repository, id: BlobId, cache_behavior: CacheBehavior) !?[]const u8 {
10911120 if (try r.getObject(id.id, cache_behavior)) |obj| {
10921121 if (obj.type == .blob) {
1122 if (cache_behavior == .cache) return try r.gpa.dupe(u8, obj.content);
10931123 return obj.content;
10941124 }
1095 if (cache_behavior == .no_cache) r.gpa.free(obj.content);
10961125 }
10971126 return null;
10981127 }
......@@ -1108,18 +1137,16 @@ pub const Repository = struct {
11081137 if (cache_behavior == .cache) if (r.commits.get(id.id)) |val| {
11091138 return .{ id, val };
11101139 };
1111 if (try r.getObject(id.id, cache_behavior)) |obj| {
1140 if (try r.getObject(id.id, .cache)) |obj| {
11121141 if (obj.type == .commit) {
1113 errdefer if (cache_behavior == .no_cache) r.gpa.free(obj.content);
11141142 const raw = try r.gpa.dupe(u8, obj.content);
11151143 errdefer r.gpa.free(raw);
11161144 const commit = try r.gpa.create(Commit);
11171145 errdefer r.gpa.destroy(commit);
1118 commit.* = try parseCommit(r.gpa, obj.content, &r.mailmap, &r.mailmap_names);
1119 try r.commits.put(r.gpa, id.id, commit);
1146 commit.* = try parseCommit(r.gpa, raw, &r.mailmap, &r.mailmap_names);
1147 if (cache_behavior == .cache) try r.commits.put(r.gpa, id.id, commit);
11201148 return .{ id, commit };
11211149 }
1122 if (cache_behavior == .no_cache) r.gpa.free(obj.content);
11231150 }
11241151 return null;
11251152 }
......@@ -1135,25 +1162,24 @@ pub const Repository = struct {
11351162 if (cache_behavior == .cache) if (r.trees.get(id.id)) |val| {
11361163 return .{ id, val };
11371164 };
1138 if (try r.getObject(id.id, cache_behavior)) |obj| {
1165 if (try r.getObject(id.id, .cache)) |obj| {
11391166 if (obj.type == .tree) {
1140 errdefer if (cache_behavior == .no_cache) r.gpa.free(obj.content);
11411167 const raw = try r.gpa.dupe(u8, obj.content);
11421168 errdefer r.gpa.free(raw);
11431169 var children: std.ArrayList(Tree.Object) = .empty;
11441170 errdefer children.deinit(r.gpa);
11451171 try children.ensureUnusedCapacity(r.gpa, 33);
11461172 var i: usize = 0;
1147 while (i < obj.content.len) {
1148 const mode_end = std.mem.indexOfScalar(u8, obj.content[i..], ' ').?;
1149 const mode = obj.content[i..][0..mode_end];
1173 while (i < raw.len) {
1174 const mode_end = std.mem.indexOfScalar(u8, raw[i..], ' ').?;
1175 const mode = raw[i..][0..mode_end];
11501176 i += mode_end + 1;
11511177
1152 const name_end = std.mem.indexOfScalar(u8, obj.content[i..], 0).?;
1153 const name = obj.content[i..][0..name_end :0];
1178 const name_end = std.mem.indexOfScalar(u8, raw[i..], 0).?;
1179 const name = raw[i..][0..name_end :0];
11541180 i += name_end + 1;
11551181
1156 const oid_raw = obj.content[i..][0..20].*;
1182 const oid_raw = raw[i..][0..20].*;
11571183 const oid_hex = extras.to_hex(oid_raw);
11581184 i += 20;
11591185
......@@ -1180,11 +1206,10 @@ pub const Repository = struct {
11801206 };
11811207 const tree = try r.gpa.create(Tree);
11821208 errdefer r.gpa.destroy(tree);
1183 tree.* = .{ .raw = obj.content, .children = children_slice };
1209 tree.* = .{ .raw = raw, .children = children_slice };
11841210 if (cache_behavior == .cache) try r.trees.put(r.gpa, id.id, tree);
11851211 return .{ id, tree };
11861212 }
1187 if (cache_behavior == .no_cache) r.gpa.free(obj.content);
11881213 }
11891214 return null;
11901215 }
......@@ -1200,18 +1225,16 @@ pub const Repository = struct {
12001225 if (cache_behavior == .cache) if (r.tags.get(id.id)) |val| {
12011226 return .{ id, val };
12021227 };
1203 if (try r.getObject(id.id, cache_behavior)) |obj| {
1228 if (try r.getObject(id.id, .cache)) |obj| {
12041229 if (obj.type == .tag) {
1205 errdefer if (cache_behavior == .no_cache) r.gpa.free(obj.content);
12061230 const raw = try r.gpa.dupe(u8, obj.content);
12071231 errdefer r.gpa.free(raw);
12081232 const tag = try r.gpa.create(Tag);
12091233 errdefer r.gpa.destroy(tag);
1210 tag.* = try parseTag(obj.content);
1234 tag.* = try parseTag(raw);
12111235 if (cache_behavior == .cache) try r.tags.put(r.gpa, id.id, tag);
12121236 return .{ id, tag };
12131237 }
1214 if (cache_behavior == .no_cache) r.gpa.free(obj.content);
12151238 }
12161239 return null;
12171240 }
......@@ -1301,9 +1324,10 @@ pub const Repository = struct {
13011324
13021325 // const start = time.milliTimestamp();
13031326
1304 const base = try r.getCommitA(base_oid.id, .cache);
1305 const base_tree_id = (try traverseTo(r, base.tree, dir_path)).?;
1306 const base_tree = try r.getTreeA(base_tree_id.id, .cache);
1327 const base = try r.getCommitA(base_oid.id, .no_cache);
1328 const base_tree_id, const base_tree_id_parent = try traverseTo(r, base.tree, dir_path);
1329 defer if (base_tree_id_parent) |p| p.destroy(r);
1330 const base_tree = try r.getTreeA(base_tree_id.?.id, .cache);
13071331 const total = base_tree.children.len;
13081332
13091333 var found: usize = 0;
......@@ -1317,29 +1341,38 @@ pub const Repository = struct {
13171341 var searched: usize = 1;
13181342 var commit_id_prev = base_oid;
13191343 var commit_id = base_oid;
1344 var commit_prev_prev: ?*Commit = null;
1345 var commit_prev: ?*Commit = null;
13201346 var commit = base;
1321 var tree_id = base_tree_id;
1322 while (true) {
1323 if (commit.parents.len == 0) break;
1324 commit_id, commit = (try r.getCommit(commit.parents[0], .cache)).?;
1347 var tree_id = base_tree_id.?;
1348 while (true) : ({
1349 if (commit_prev_prev) |p| p.destroy(r);
1350 commit_prev_prev = commit_prev;
1351 commit_prev = commit;
1352 commit_id_prev = commit_id;
1353 commit_id, commit = (try r.getCommit(commit.parents[0], .no_cache)).?;
1354 }) {
13251355 searched += 1;
1326 defer commit_id_prev = commit_id;
1327 const new_tree_id = try traverseTo(r, commit.tree, dir_path) orelse {
1356 if (commit.parents.len == 0) break;
1357 const new_tree_id, const new_tree_id_parent = try traverseTo(r, commit.tree, dir_path);
1358 defer if (new_tree_id_parent) |p| p.destroy(r);
1359 if (new_tree_id == null) {
13281360 var i: usize = 0;
13291361 while (findFirstUnset(set, i)) |j| : (i += 1) {
13301362 i = j;
13311363 const k = result.keys()[i];
13321364 found += 1;
1333 result.putAssumeCapacity(k, commit_id_prev);
1365 result.putAssumeCapacity(k, .{ .id = (try r.gpa.dupe(u8, commit_id_prev.id))[0..40] });
13341366 set.set(i);
13351367 // std.log.debug("found [{d}/{d}] objects after searching {d} commits, found {s}", .{ found, total, searched, k });
13361368 continue;
13371369 }
13381370 break;
1339 };
1340 if (new_tree_id.eql(tree_id)) continue;
1341 tree_id = new_tree_id;
1342 const tree = try r.getTreeA(tree_id.id, .cache);
1371 }
1372 if (new_tree_id.?.eql(tree_id)) continue;
1373 tree_id = new_tree_id.?;
1374 const tree = try r.getTreeA(tree_id.id, .no_cache);
1375 defer tree.destroy(r);
13431376 var i: usize = 0;
13441377 while (findFirstUnset(set, i)) |j| : (i += 1) {
13451378 i = j;
......@@ -1347,14 +1380,14 @@ pub const Repository = struct {
13471380 const new = tree.get(k);
13481381 if (new == null) {
13491382 found += 1;
1350 result.putAssumeCapacity(k, commit_id_prev);
1383 result.putAssumeCapacity(k, .{ .id = (try r.gpa.dupe(u8, commit_id_prev.id))[0..40] });
13511384 set.set(i);
13521385 // std.log.debug("found [{d}/{d}] objects after searching {d} commits, at {d} found {s}", .{ found, total, searched, i, k });
13531386 continue;
13541387 }
13551388 if (!std.mem.eql(u8, new.?.id.erase(), base_tree.children[i].id.erase())) {
13561389 found += 1;
1357 result.putAssumeCapacity(k, commit_id_prev);
1390 result.putAssumeCapacity(k, .{ .id = (try r.gpa.dupe(u8, commit_id_prev.id))[0..40] });
13581391 set.set(i);
13591392 // std.log.debug("found [{d}/{d}] objects after searching {d} commits, at {d} found {s}", .{ found, total, searched, i, k });
13601393 continue;
......@@ -1709,17 +1742,21 @@ const ZlibCode = enum(c_int) {
17091742 Z_VERSION_ERROR = -6,
17101743};
17111744
1712fn traverseTo(r: *Repository, treestart_id: TreeId, dir_path: []const u8) !?TreeId {
1745fn traverseTo(r: *Repository, treestart_id: TreeId, dir_path: []const u8) !struct { ?TreeId, ?*Tree } {
17131746 var id = treestart_id;
1714 if (dir_path.len == 0) return id;
1747 if (dir_path.len == 0) return .{ id, null };
17151748 var iter = std.mem.splitScalar(u8, dir_path, '/');
1749 var prev: ?*Tree = null;
17161750 while (iter.next()) |segment| {
1717 const tree = try r.getTreeA(id.id, .cache);
1718 const o = tree.get(segment) orelse return null;
1719 if (o.id != .tree) return null;
1751 const p = prev;
1752 const tree = try r.getTreeA(id.id, .no_cache);
1753 defer prev = tree;
1754 if (p) |_| p.?.destroy(r);
1755 const o = tree.get(segment) orelse return .{ null, tree };
1756 if (o.id != .tree) return .{ null, tree };
17201757 id = o.id.tree;
17211758 }
1722 return id;
1759 return .{ id, prev };
17231760}
17241761
17251762pub const Tree = struct {