authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-07 18:15:29-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-16 13:12:47-07:00
log5b57dca62d8094d58a21e5458b5095febce47dc5
treed1bbccbd776a509f301d233a426d215f5decc275
parent2c605872fc4fb5f4df99647ad7f4fbe7f65612a5

std.build.Cache: fix regressions from the branch


1 files changed, 53 insertions(+), 24 deletions(-)

lib/std/Build/Cache.zig+53-24
......@@ -67,7 +67,8 @@ fn appendPrefixedPath(cache: *const Cache, contents: *std.ArrayList(u8), prefixe
6767 const end = contents.items.len + prefixed_path.sub_path.len;
6868 const needed_alignment = @alignOf(Manifest.File) - (end % @alignOf(Manifest.File));
6969 assert(needed_alignment >= 1); // Always need at least a null byte.
70 try contents.ensureTotalCapacity(cache.gpa, end + needed_alignment);
70 // Extra +1 here is due to the requirement to keep at least 1 unused capacity in `Manifest.contents` at all times.
71 try contents.ensureTotalCapacity(cache.gpa, end + needed_alignment + 1);
7172 contents.appendSliceAssumeCapacity(prefixed_path.sub_path);
7273 contents.appendNTimesAssumeCapacity(0, needed_alignment);
7374 return prefixed_path.prefix;
......@@ -97,7 +98,10 @@ fn resolveAppendPath(cache: *const Cache, contents: *std.ArrayList(u8), path: Pa
9798
9899 const needed_alignment = @alignOf(Manifest.File) - (contents.items.len % @alignOf(Manifest.File));
99100 assert(needed_alignment >= 1); // Always need at least a null byte.
100 try contents.appendNTimes(gpa, 0, needed_alignment);
101 // Extra +1 here is due to the requirement to keep at least 1 unused capacity in `Manifest.contents` at all
102 // times.
103 try contents.ensureUnusedCapacity(gpa, needed_alignment + 1);
104 contents.appendNTimesAssumeCapacity(0, needed_alignment);
101105
102106 return @intCast(i);
103107 }
......@@ -107,7 +111,9 @@ fn resolveAppendPath(cache: *const Cache, contents: *std.ArrayList(u8), path: Pa
107111
108112 const needed_alignment = @alignOf(Manifest.File) - (contents.items.len % @alignOf(Manifest.File));
109113 assert(needed_alignment >= 1); // Always need at least a null byte.
110 try contents.appendNTimes(gpa, 0, needed_alignment);
114 // Extra +1 here is due to the requirement to keep at least 1 unused capacity in `Manifest.contents` at all times.
115 try contents.ensureUnusedCapacity(gpa, needed_alignment + 1);
116 contents.appendNTimesAssumeCapacity(0, needed_alignment);
111117
112118 return 0;
113119}
......@@ -127,10 +133,10 @@ pub const Hasher = crypto.auth.siphash.SipHash128(1, 3);
127133/// Refresh this with new random bytes when the manifest
128134/// format is modified in a non-backwards-compatible way.
129135pub const hasher_init: Hasher = Hasher.init(&.{
130 0x33, 0x52, 0xa2, 0x84,
131 0xcf, 0x17, 0x56, 0x57,
132 0x01, 0xbb, 0xcd, 0xe4,
133 0x77, 0xd6, 0xf0, 0x60,
136 0x02, 0xe9, 0xfa, 0xfe,
137 0xe0, 0x95, 0x81, 0x55,
138 0xf5, 0x5a, 0x15, 0xcb,
139 0x4a, 0xf4, 0x00, 0x09,
134140});
135141
136142pub const HashHelper = struct {
......@@ -487,7 +493,8 @@ pub const Manifest = struct {
487493 pub const Diagnostic = union(enum) {
488494 none,
489495 manifest_create: Io.File.OpenError,
490 manifest_read: Io.File.Reader.Error,
496 manifest_stat: Io.File.StatError,
497 manifest_read: Io.File.ReadPositionalError,
491498 manifest_lock: Io.File.LockError,
492499 file_open: FileOp,
493500 file_stat: FileOp,
......@@ -644,7 +651,7 @@ pub const Manifest = struct {
644651 return @fromBackingInt(@intCast(gop.index));
645652 }
646653
647 pub fn addInputFileOptional(m: *Manifest, opt_path: ?Path, options: AddInputPathOptions) Allocator.Error!void {
654 pub fn addInputPathOptional(m: *Manifest, opt_path: ?Path, options: AddInputPathOptions) Allocator.Error!void {
648655 m.hash.add(opt_path != null);
649656 _ = try addInputPath(m, opt_path orelse return, options);
650657 }
......@@ -824,24 +831,43 @@ pub const Manifest = struct {
824831 fn checkLocked(m: *Manifest) Check.Error!Check.Status {
825832 const gpa = m.cache.gpa;
826833 const io = m.cache.io;
834 const manifest_file = m.manifest_file.?;
827835
828 var manifest_reader = m.manifest_file.?.reader(io, &.{}); // Reads positionally from zero.
829 m.contents.clearRetainingCapacity();
830 manifest_reader.interface.appendRemainingUnlimited(gpa, &m.contents) catch |err| switch (err) {
831 error.OutOfMemory => |e| return e,
832 error.ReadFailed => {
833 m.diagnostic = .{ .manifest_read = manifest_reader.err.? };
836 const manifest_size = if (manifest_file.stat(io)) |stat| stat.size else |err| switch (err) {
837 error.Canceled => |e| return e,
838 else => |e| {
839 m.diagnostic = .{ .manifest_stat = e };
834840 return error.CacheCheckFailed;
835841 },
836842 };
843
844 // We always want to compute the input file hash digests, even on a cache miss, because they will be
845 // used in the manifest digest.
846
847 if (manifest_size == 0 or manifest_size < m.contents.items.len) {
848 // Don't clobber our input files by overwriting contents since it's a cache miss.
849 try m.contents.ensureUnusedCapacity(gpa, 1);
850 return .miss;
851 }
852
853 // Already supposedly includes the extra null byte that we have to maintain.
854 try m.contents.resize(gpa, manifest_size);
855
856 {
857 const n = manifest_file.readPositionalAll(io, m.contents.items, 0) catch |err| switch (err) {
858 error.Canceled => |e| return e,
859 else => |e| {
860 m.diagnostic = .{ .manifest_read = e };
861 return error.CacheCheckFailed;
862 },
863 };
864 m.contents.shrinkRetainingCapacity(n);
865 }
837866 const contents = m.contents.items;
838867
839868 var off: usize = 0;
840869 var c: Check = .{};
841870
842 // We always want to compute the input file hash digests, even on a cache miss, because they will be
843 // used in the manifest digest.
844
845871 // First the input files section, which must match our input files, otherwise it's invalid format.
846872 for (m.input_paths.items, m.files.keys()[0..m.input_paths.items.len]) |*input_path, input_file_off| {
847873 if (off + 1 >= contents.len) return error.InvalidFormat;
......@@ -1466,7 +1492,7 @@ pub const Manifest = struct {
14661492 const prev_contents_len = other.contents.items.len;
14671493 try other.contents.appendSlice(gpa, copy_bytes);
14681494
1469 const gop = other.files.getOrPutAssumeCapacity(@fromBackingInt(prev_contents_len), .{
1495 const gop = other.files.getOrPutAssumeCapacityContext(@fromBackingInt(prev_contents_len), .{
14701496 .manifest = other,
14711497 });
14721498
......@@ -1514,7 +1540,7 @@ pub const Manifest = struct {
15141540 var entries_list: std.ArrayList(u32) = .empty;
15151541 defer entries_list.deinit(gpa);
15161542
1517 while (true) {
1543 while (reader.state != .finished) {
15181544 const entries = entry_buffer[0..try reader.read(io, &entry_buffer)];
15191545 for (try entries_list.addManyAsSlice(gpa, entries.len), entries) |*off, entry| {
15201546 off.* = @intCast(contents.items.len);
......@@ -1528,12 +1554,15 @@ pub const Manifest = struct {
15281554 }
15291555
15301556 const Sort = struct {
1531 contents: []const u8,
1557 contents: [*:0]const u8,
15321558 pub fn lessThan(this: @This(), lhs: u32, rhs: u32) bool {
1533 return mem.lessThanZ(u8, this.contents[lhs + 1 ..], this.contents[rhs + 1 ..]); // +1 for kind byte
1559 // This comparison includes the kind byte.
1560 return mem.lessThanZ(u8, this.contents + lhs, this.contents + rhs);
15341561 }
15351562 };
1536 mem.sortUnstable(u32, entries_list.items, @as(Sort, .{ .contents = contents.items }), Sort.lessThan);
1563 mem.sortUnstable(u32, entries_list.items, @as(Sort, .{
1564 .contents = @ptrCast(contents.items.ptr),
1565 }), Sort.lessThan);
15371566
15381567 // Duplicate the contents such that we may refer to it while creating a
15391568 // sorted copy in the original position (at contents_start). We will then
......@@ -1546,7 +1575,7 @@ pub const Manifest = struct {
15461575 const offset = wrong_offset + contents_len;
15471576 // Includes the kind prefix which we also want to copy.
15481577 const entry: [*:0]const u8 = @ptrCast(contents.items[offset..]);
1549 new_offset += mem.copySentinel(u8, 0, contents.items[new_offset..], entry);
1578 new_offset += mem.copySentinelInclusive(u8, 0, contents.items[new_offset..], entry);
15501579 }
15511580 assert(new_offset == contents_start + contents_len);
15521581 contents.shrinkRetainingCapacity(contents_start + contents_len);