authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-06-18 16:39:53 -07:00
committergravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-06-18 16:41:41 -07:00
logc171ea63e41ea81f9e9c973aa7cc05f45673849b
treed95093388756ba794e2b7ec3472e3c3fb38f97d8
parente1771f0b7a6ef37fc342a46f1dc8233bc5b2d1af
signaturebadge-check Signed by SSH key SHA256:4hHJbtBRU58AYXwjL7fkz2fnQHdiye8x1QpTCQ0sHNw

add CacheBehavior


1 files changed, 51 insertions(+), 40 deletions(-)

git.zig+51-40
......@@ -703,6 +703,8 @@ pub const Repository = struct {
703703 trees: std.StringArrayHashMapUnmanaged(Tree),
704704 tags: std.StringArrayHashMapUnmanaged(Tag),
705705
706 pub const CacheBehavior = enum { no_cache, cache };
707
706708 pub fn init(gitdir: nfs.Dir, gpa: std.mem.Allocator) Repository {
707709 return .{
708710 .gitdir = gitdir,
......@@ -732,7 +734,7 @@ pub const Repository = struct {
732734 r.tags.deinit(r.gpa);
733735 }
734736
735 pub fn getObject(r: *Repository, arena: std.mem.Allocator, oid: Id) anyerror!?GitObject {
737 pub fn getObject(r: *Repository, arena: std.mem.Allocator, oid: Id, cache_behavior: CacheBehavior) anyerror!?GitObject {
736738 const t = tracer.trace(@src(), " {s}", .{oid});
737739 defer t.end();
738740
......@@ -764,7 +766,7 @@ pub const Repository = struct {
764766 const content = try list.toOwnedSlice(r.gpa);
765767 std.debug.assert(content.len == content_len);
766768 const obj: GitObject = .{ .type = _type, .content = content };
767 try r.unpacked_loose_objects.put(r.gpa, oid, obj);
769 if (cache_behavior == .cache) try r.unpacked_loose_objects.put(r.gpa, oid, obj);
768770 return obj;
769771 }
770772
......@@ -795,7 +797,7 @@ pub const Repository = struct {
795797 }
796798 const pack_index, const pack_offset = try r.getObjectPackIndex(oid) orelse return null;
797799 // parse .pack
798 return try r.getPackedObject(arena, oid, pack_index, pack_offset);
800 return try r.getPackedObject(arena, oid, pack_index, pack_offset, cache_behavior);
799801 }
800802
801803 fn getObjectPackIndex(r: *Repository, oid: Id) !?[2]usize {
......@@ -857,7 +859,7 @@ pub const Repository = struct {
857859 return null;
858860 }
859861
860 fn getPackedObject(r: *Repository, arena: std.mem.Allocator, maybe_oid: ?Id, pack_index: usize, pack_offset: usize) !GitObject {
862 fn getPackedObject(r: *Repository, arena: std.mem.Allocator, maybe_oid: ?Id, pack_index: usize, pack_offset: usize, cache_behavior: CacheBehavior) !GitObject {
861863 const t = tracer.trace(@src(), " {?s} {d} {d} {s}", .{ maybe_oid, pack_index, pack_offset, r.pack_content.keys()[pack_index] });
862864 defer t.end();
863865
......@@ -901,7 +903,7 @@ pub const Repository = struct {
901903 const _type = std.meta.stringToEnum(RefType, @tagName(ty)).?;
902904 const content = try list.toOwnedSlice(r.gpa);
903905 const obj: GitObject = .{ .type = _type, .content = content };
904 try r.unpacked_objects.put(r.gpa, key, obj);
906 if (cache_behavior == .cache) try r.unpacked_objects.put(r.gpa, key, obj);
905907 return obj;
906908 },
907909 .ofs_delta => {
......@@ -913,13 +915,15 @@ pub const Repository = struct {
913915 offset += 1;
914916 }
915917 const base_pack_offset = pack_offset - offset;
916 const base_obj = try r.getPackedObject(arena, null, pack_index, base_pack_offset);
917 return r.getDeltadObject(maybe_oid, key, &packedobj_fbs, size, base_obj);
918 const base_obj = try r.getPackedObject(arena, null, pack_index, base_pack_offset, cache_behavior);
919 defer if (cache_behavior == .no_cache) r.gpa.free(base_obj.content);
920 return r.getDeltadObject(maybe_oid, key, &packedobj_fbs, size, base_obj, cache_behavior);
918921 },
919922 .ref_delta => {
920923 const base_oid = extras.to_hex(packedobj_fbs.takeSlice(20)[0..20].*);
921 const base_obj = (try r.getObject(arena, &base_oid)).?;
922 return r.getDeltadObject(maybe_oid, key, &packedobj_fbs, size, base_obj);
924 const base_obj = (try r.getObject(arena, &base_oid, cache_behavior)).?;
925 defer if (cache_behavior == .no_cache) r.gpa.free(base_obj.content);
926 return r.getDeltadObject(maybe_oid, key, &packedobj_fbs, size, base_obj, cache_behavior);
923927 },
924928 }
925929 comptime unreachable;
......@@ -931,7 +935,7 @@ pub const Repository = struct {
931935 }
932936 }
933937
934 fn getDeltadObject(r: *Repository, maybe_oid: ?Id, key: u64, packedobj_fbs: *nio.FixedBufferStream([]const u8), size: usize, base_obj: GitObject) !GitObject {
938 fn getDeltadObject(r: *Repository, maybe_oid: ?Id, key: u64, packedobj_fbs: *nio.FixedBufferStream([]const u8), size: usize, base_obj: GitObject, cache_behavior: CacheBehavior) !GitObject {
935939 const compressed_content = packedobj_fbs.rest();
936940 var list: std.ArrayListUnmanaged(u8) = .empty;
937941 defer list.deinit(r.gpa);
......@@ -999,20 +1003,22 @@ pub const Repository = struct {
9991003 const content = try list2.toOwnedSlice(r.gpa);
10001004 const obj: GitObject = .{ .type = _type, .content = content };
10011005 _ = maybe_oid;
1002 try r.unpacked_objects.put(r.gpa, key, obj);
1006 if (cache_behavior == .cache) try r.unpacked_objects.put(r.gpa, key, obj);
10031007 return obj;
10041008 }
10051009
1006 pub fn getObjectA(r: *Repository, arena: std.mem.Allocator, oid: Id) !GitObject {
1007 return (try r.getObject(arena, oid)).?;
1010 pub fn getObjectA(r: *Repository, arena: std.mem.Allocator, oid: Id, cache_behavior: CacheBehavior) !GitObject {
1011 return (try r.getObject(arena, oid, cache_behavior)).?;
10081012 }
10091013
1010 pub fn getObjectC(r: *Repository, arena: std.mem.Allocator, oid: Id) ![]const u8 {
1011 return (try r.getObjectA(arena, oid)).content;
1014 pub fn getObjectC(r: *Repository, arena: std.mem.Allocator, oid: Id, cache_behavior: CacheBehavior) ![]const u8 {
1015 return (try r.getObjectA(arena, oid, cache_behavior)).content;
10121016 }
10131017
1014 pub fn getObjectS(r: *Repository, arena: std.mem.Allocator, oid: Id) !usize {
1015 return (try r.getObjectC(arena, oid)).len;
1018 pub fn getObjectS(r: *Repository, arena: std.mem.Allocator, oid: Id, cache_behavior: CacheBehavior) !usize {
1019 const content = try r.getObjectC(arena, oid, cache_behavior);
1020 defer if (cache_behavior == .no_cache) r.gpa.free(content);
1021 return content.len;
10161022 }
10171023
10181024 const GitObject = struct {
......@@ -1020,17 +1026,18 @@ pub const Repository = struct {
10201026 content: []const u8,
10211027 };
10221028
1023 pub fn getBlob(r: *Repository, arena: std.mem.Allocator, id: BlobId) !?[]const u8 {
1024 if (try r.getObject(arena, id.id)) |obj| {
1029 pub fn getBlob(r: *Repository, arena: std.mem.Allocator, id: BlobId, cache_behavior: CacheBehavior) !?[]const u8 {
1030 if (try r.getObject(arena, id.id, cache_behavior)) |obj| {
10251031 if (obj.type == .blob) {
10261032 return obj.content;
10271033 }
1034 if (cache_behavior == .no_cache) r.gpa.free(obj.content);
10281035 }
10291036 return null;
10301037 }
10311038
1032 pub fn getBlobA(r: *Repository, arena: std.mem.Allocator, id: Id) ![]const u8 {
1033 return (try r.getBlob(arena, .{ .id = id })).?;
1039 pub fn getBlobA(r: *Repository, arena: std.mem.Allocator, id: Id, cache_behavior: CacheBehavior) ![]const u8 {
1040 return (try r.getBlob(arena, .{ .id = id }, cache_behavior)).?;
10341041 }
10351042
10361043 pub fn getCommit(r: *Repository, arena: std.mem.Allocator, id: CommitId) !?struct { CommitId, CommitIdx } {
......@@ -1040,7 +1047,7 @@ pub const Repository = struct {
10401047 if (r.commits.getIndex(id.id)) |idx| {
10411048 return .{ id, @enumFromInt(idx) };
10421049 }
1043 if (try r.getObject(arena, id.id)) |obj| {
1050 if (try r.getObject(arena, id.id, .cache)) |obj| {
10441051 if (obj.type == .commit) {
10451052 const commit = try parseCommit(arena, obj.content);
10461053 try r.commits.put(r.gpa, id.id, commit);
......@@ -1055,15 +1062,16 @@ pub const Repository = struct {
10551062 return (try r.getCommit(arena, .{ .id = id })).?.@"1";
10561063 }
10571064
1058 pub fn getTree(r: *Repository, arena: std.mem.Allocator, id: TreeId) !?struct { TreeId, Tree } {
1065 pub fn getTree(r: *Repository, arena: std.mem.Allocator, id: TreeId, cache_behavior: CacheBehavior) !?struct { TreeId, Tree } {
10591066 const t = tracer.trace(@src(), " {s}", .{id.id});
10601067 defer t.end();
10611068
10621069 if (r.trees.getPtr(id.id)) |val| {
10631070 return .{ id, val.* };
10641071 }
1065 if (try r.getObject(arena, id.id)) |obj| {
1072 if (try r.getObject(arena, id.id, cache_behavior)) |obj| {
10661073 if (obj.type == .tree) {
1074 errdefer if (cache_behavior == .no_cache) r.gpa.free(obj.content);
10671075 var children: std.ArrayList(Tree.Object) = .empty;
10681076 errdefer children.deinit(r.gpa);
10691077 try children.ensureUnusedCapacity(r.gpa, 33);
......@@ -1103,36 +1111,39 @@ pub const Repository = struct {
11031111 .none => unreachable,
11041112 };
11051113 const tree: Tree = .{ .children = children_slice };
1106 try r.trees.put(r.gpa, id.id, tree);
1114 if (cache_behavior == .cache) try r.trees.put(r.gpa, id.id, tree);
11071115 return .{ id, tree };
11081116 }
1117 if (cache_behavior == .no_cache) r.gpa.free(obj.content);
11091118 }
11101119 return null;
11111120 }
11121121
1113 pub fn getTreeA(r: *Repository, arena: std.mem.Allocator, id: Id) !Tree {
1114 return (try r.getTree(arena, .{ .id = id })).?.@"1";
1122 pub fn getTreeA(r: *Repository, arena: std.mem.Allocator, id: Id, cache_behavior: CacheBehavior) !Tree {
1123 return (try r.getTree(arena, .{ .id = id }, cache_behavior)).?.@"1";
11151124 }
11161125
1117 pub fn getTag(r: *Repository, arena: std.mem.Allocator, id: TagId) !?struct { TagId, Tag } {
1126 pub fn getTag(r: *Repository, arena: std.mem.Allocator, id: TagId, cache_behavior: CacheBehavior) !?struct { TagId, Tag } {
11181127 const t = tracer.trace(@src(), " {s}", .{id.id});
11191128 defer t.end();
11201129
11211130 if (r.tags.getPtr(id.id)) |val| {
11221131 return .{ id, val.* };
11231132 }
1124 if (try r.getObject(arena, id.id)) |obj| {
1133 if (try r.getObject(arena, id.id, cache_behavior)) |obj| {
11251134 if (obj.type == .tag) {
1135 errdefer if (cache_behavior == .no_cache) r.gpa.free(obj.content);
11261136 const tag = try parseTag(obj.content);
1127 try r.tags.put(r.gpa, id.id, tag);
1137 if (cache_behavior == .cache) try r.tags.put(r.gpa, id.id, tag);
11281138 return .{ id, tag };
11291139 }
1140 if (cache_behavior == .no_cache) r.gpa.free(obj.content);
11301141 }
11311142 return null;
11321143 }
11331144
1134 pub fn getTagA(r: *Repository, arena: std.mem.Allocator, id: Id) !Tag {
1135 return (try r.getTag(arena, .{ .id = id })).?.@"1";
1145 pub fn getTagA(r: *Repository, arena: std.mem.Allocator, id: Id, cache_behavior: CacheBehavior) !Tag {
1146 return (try r.getTag(arena, .{ .id = id }, cache_behavior)).?.@"1";
11361147 }
11371148
11381149 pub fn getHeads(r: *Repository, arena: std.mem.Allocator) ![]Ref {
......@@ -1214,7 +1225,7 @@ pub const Repository = struct {
12141225 const base_idx = try r.getCommitA(arena, base_oid.id);
12151226 const base = base_idx.reify(r);
12161227 const base_tree_id = (try traverseTo(r, arena, base.tree, dir_path)).?;
1217 const base_tree = try r.getTreeA(arena, base_tree_id.id);
1228 const base_tree = try r.getTreeA(arena, base_tree_id.id, .cache);
12181229 const total = base_tree.children.len;
12191230
12201231 var found: usize = 0;
......@@ -1252,7 +1263,7 @@ pub const Repository = struct {
12521263 };
12531264 if (new_tree_id.eql(tree_id)) continue;
12541265 tree_id = new_tree_id;
1255 const tree = try r.getTreeA(arena, tree_id.id);
1266 const tree = try r.getTreeA(arena, tree_id.id, .cache);
12561267 var i: usize = 0;
12571268 while (findFirstUnset(set, i)) |j| : (i += 1) {
12581269 i = j;
......@@ -1295,7 +1306,7 @@ pub const Repository = struct {
12951306 try S.item(e, w, .none, mode, &@splat('0'), id, .A, p, name);
12961307 }
12971308 fn dir(e: *Repository, w: anytype, t: Id, p: ?*const PathListNode, o: usize) !void {
1298 const tree = try e.getTreeA(e.gpa, t);
1309 const tree = try e.getTreeA(e.gpa, t, .cache);
12991310 for (tree.children[o..]) |obj| {
13001311 if (obj.mode.type == .directory) {
13011312 try dir(e, w, obj.id.tree.id, &.{ .prev = p, .data = obj.name }, 0);
......@@ -1316,7 +1327,7 @@ pub const Repository = struct {
13161327 try S.item(e, w, mode, .none, id, &@splat('0'), .D, p, name);
13171328 }
13181329 fn dir(e: *Repository, w: anytype, t: Id, p: ?*const PathListNode, o: usize) !void {
1319 const tree = try e.getTreeA(e.gpa, t);
1330 const tree = try e.getTreeA(e.gpa, t, .cache);
13201331 for (tree.children[o..]) |obj| {
13211332 if (obj.mode.type == .directory) {
13221333 try dir(e, w, obj.id.tree.id, &.{ .prev = p, .data = obj.name }, 0);
......@@ -1335,11 +1346,11 @@ pub const Repository = struct {
13351346 const M = struct {
13361347 fn dir(e: *Repository, w: anytype, b_t: Id, a_t: Id, p: ?*const PathListNode) !void {
13371348 var before_i: usize = 0;
1338 const before_tree = try e.getTreeA(e.gpa, b_t);
1349 const before_tree = try e.getTreeA(e.gpa, b_t, .cache);
13391350 const before_children = before_tree.children;
13401351
13411352 var after_i: usize = 0;
1342 const after_tree = try e.getTreeA(e.gpa, a_t);
1353 const after_tree = try e.getTreeA(e.gpa, a_t, .cache);
13431354 const after_children = after_tree.children;
13441355
13451356 while (true) {
......@@ -1610,7 +1621,7 @@ fn traverseTo(r: *Repository, arena: std.mem.Allocator, treestart_id: TreeId, di
16101621 if (dir_path.len == 0) return id;
16111622 var iter = std.mem.splitScalar(u8, dir_path, '/');
16121623 while (iter.next()) |segment| {
1613 const tree = try r.getTreeA(arena, id.id);
1624 const tree = try r.getTreeA(arena, id.id, .cache);
16141625 const o = tree.get(segment) orelse return null;
16151626 if (o.id != .tree) return null;
16161627 id = o.id.tree;
......@@ -1869,7 +1880,7 @@ pub const Tree = struct {
18691880 self.name_buffer.appendSliceAssumeCapacity(base.name);
18701881 self.name_buffer.appendAssumeCapacity(0);
18711882 if (base.id == .tree) {
1872 const new_tree = try self.repo.getTreeA(arena, base.id.tree.id);
1883 const new_tree = try self.repo.getTreeA(arena, base.id.tree.id, .cache);
18731884 {
18741885 // errdefer new_dir.close();
18751886 try self.stack.append(gpa, .{