@@ -22,13 +22,12 @@ pub const Branch = struct {
2222 agent_id : [64 ]u8 , // which agent owns this branch
2323 agent_id_len : u8 ,
2424
25- // Branch-local storage: key_hash -> value (only modified keys)
25+ // Branch-local storage: actual key string -> value (only modified keys)
2626 // This is the CoW layer — unmodified keys fall through to main
27- writes : std .AutoHashMap ( u64 , BranchWrite ),
27+ writes : std .StringHashMap ( BranchWrite ),
2828 allocator : Allocator ,
2929
3030 pub const BranchWrite = struct {
31- key : []const u8 , // owned copy
3231 value : []const u8 , // owned copy
3332 deleted : bool , // true = tombstone (deleted on branch)
3433 epoch : u64 , // when this write happened
@@ -45,28 +44,30 @@ pub const Branch = struct {
4544 pub fn deinit (self : * Branch ) void {
4645 var it = self .writes .iterator ();
4746 while (it .next ()) | entry | {
48- if (entry .value_ptr .key .len > 0 ) self .allocator .free (entry .value_ptr .key );
4947 if (entry .value_ptr .value .len > 0 ) self .allocator .free (entry .value_ptr .value );
48+ self .allocator .free (@constCast (entry .key_ptr .* ));
5049 }
5150 self .writes .deinit ();
5251 }
5352
5453 /// Write a key-value pair on this branch (CoW — only stores the delta)
5554 pub fn write (self : * Branch , key : []const u8 , value : []const u8 , epoch : u64 ) ! void {
56- const key_hash = fnv1a (key );
5755 // Allocate new copies BEFORE freeing old ones — if alloc fails,
5856 // the existing entry stays valid.
5957 const owned_key = try self .allocator .dupe (u8 , key );
6058 errdefer self .allocator .free (owned_key );
6159 const owned_val = try self .allocator .dupe (u8 , value );
6260 errdefer self .allocator .free (owned_val );
6361 // Free old write if exists (safe — new copies already allocated)
64- if (self .writes .getPtr (key_hash )) | old | {
65- if (old .key .len > 0 ) self .allocator .free (old .key );
62+ if (self .writes .getPtr (key )) | old | {
6663 if (old .value .len > 0 ) self .allocator .free (old .value );
64+ // Free the old key that was used as the map key.
65+ const old_map_key = self .writes .getKey (key ).? ;
66+ self .allocator .free (@constCast (old_map_key ));
67+ // Remove old entry so we can insert with new owned key.
68+ _ = self .writes .remove (key );
6769 }
68- try self .writes .put (key_hash , .{
69- .key = owned_key ,
70+ try self .writes .put (owned_key , .{
7071 .value = owned_val ,
7172 .deleted = false ,
7273 .epoch = epoch ,
@@ -75,14 +76,14 @@ pub const Branch = struct {
7576
7677 /// Mark a key as deleted on this branch
7778 pub fn delete (self : * Branch , key : []const u8 , epoch : u64 ) ! void {
78- const key_hash = fnv1a (key );
79- if (self .writes .getPtr (key_hash )) | old | {
80- if (old .key .len > 0 ) self .allocator .free (old .key );
79+ if (self .writes .getPtr (key )) | old | {
8180 if (old .value .len > 0 ) self .allocator .free (old .value );
81+ const old_map_key = self .writes .getKey (key ).? ;
82+ self .allocator .free (@constCast (old_map_key ));
83+ _ = self .writes .remove (key );
8284 }
8385 const owned_key = try self .allocator .dupe (u8 , key );
84- try self .writes .put (key_hash , .{
85- .key = owned_key ,
86+ try self .writes .put (owned_key , .{
8687 .value = &.{},
8788 .deleted = true ,
8889 .epoch = epoch ,
@@ -91,8 +92,7 @@ pub const Branch = struct {
9192
9293 /// Read a key on this branch. Returns branch-local value or null (fall through to main).
9394 pub fn read (self : * const Branch , key : []const u8 ) ? BranchRead {
94- const key_hash = fnv1a (key );
95- if (self .writes .get (key_hash )) | w | {
95+ if (self .writes .get (key )) | w | {
9696 if (w .deleted ) return .{ .deleted = true , .value = null };
9797 return .{ .deleted = false , .value = w .value };
9898 }
@@ -111,7 +111,7 @@ pub const Branch = struct {
111111 while (it .next ()) | entry | {
112112 const w = entry .value_ptr .* ;
113113 try entries .append (alloc , .{
114- .key = w . key ,
114+ .key = entry . key_ptr .* ,
115115 .value = w .value ,
116116 .deleted = w .deleted ,
117117 .epoch = w .epoch ,
@@ -168,7 +168,7 @@ pub fn compareBranches(branches: []*const Branch, alloc: Allocator) !CompareResu
168168 for (branches ) | br | {
169169 var it = br .writes .iterator ();
170170 while (it .next ()) | entry | {
171- try all_keys .put (entry .value_ptr . key , {});
171+ try all_keys .put (entry .key_ptr .* , {});
172172 }
173173 }
174174
@@ -186,7 +186,7 @@ pub fn compareBranches(branches: []*const Branch, alloc: Allocator) !CompareResu
186186 .agent_id = br .getAgentId (),
187187 .value = r .value ,
188188 .deleted = r .deleted ,
189- .epoch = if (br .writes .get (fnv1a ( key ) )) | w | w .epoch else 0 ,
189+ .epoch = if (br .writes .get (key )) | w | w .epoch else 0 ,
190190 });
191191 }
192192 }
@@ -435,7 +435,7 @@ pub const BranchManager = struct {
435435 .status = .active ,
436436 .agent_id = undefined ,
437437 .agent_id_len = aid_len ,
438- .writes = std .AutoHashMap ( u64 , Branch .BranchWrite ).init (self .allocator ),
438+ .writes = std .StringHashMap ( Branch .BranchWrite ).init (self .allocator ),
439439 .allocator = self .allocator ,
440440 };
441441 @memcpy (branch .name [0.. name_len ], name_arg [0.. name_len ]);
0 commit comments