diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2025-07-01 09:06:54 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2025-07-07 22:43:52 -0700 |
| commit | 4bca5faca60df971712e538758315a0e0afe89a0 (patch) | |
| tree | fe0b8bac0ec070c00b46706edc84ee4c7b997e37 /lib/std | |
| parent | d6ac04c47811f162ca662f43d3c93a5dc0dcce86 (diff) | |
| download | zig-4bca5faca60df971712e538758315a0e0afe89a0.tar.gz zig-4bca5faca60df971712e538758315a0e0afe89a0.zip | |
std.Build.Cache: write manifest without heap allocating
Now that the buffered writing interface is not generic.
Diffstat (limited to 'lib/std')
| -rw-r--r-- | lib/std/Build/Cache.zig | 64 | ||||
| -rw-r--r-- | lib/std/fs/File.zig | 14 |
2 files changed, 47 insertions, 31 deletions
diff --git a/lib/std/Build/Cache.zig b/lib/std/Build/Cache.zig index 81a72a11c6..dfc1b14742 100644 --- a/lib/std/Build/Cache.zig +++ b/lib/std/Build/Cache.zig @@ -2,6 +2,18 @@ //! This is not a general-purpose cache. It is designed to be fast and simple, //! not to withstand attacks using specially-crafted input. +const Cache = @This(); +const std = @import("std"); +const builtin = @import("builtin"); +const crypto = std.crypto; +const fs = std.fs; +const assert = std.debug.assert; +const testing = std.testing; +const mem = std.mem; +const fmt = std.fmt; +const Allocator = std.mem.Allocator; +const log = std.log.scoped(.cache); + gpa: Allocator, manifest_dir: fs.Dir, hash: HashHelper = .{}, @@ -21,18 +33,6 @@ pub const Path = @import("Cache/Path.zig"); pub const Directory = @import("Cache/Directory.zig"); pub const DepTokenizer = @import("Cache/DepTokenizer.zig"); -const Cache = @This(); -const std = @import("std"); -const builtin = @import("builtin"); -const crypto = std.crypto; -const fs = std.fs; -const assert = std.debug.assert; -const testing = std.testing; -const mem = std.mem; -const fmt = std.fmt; -const Allocator = std.mem.Allocator; -const log = std.log.scoped(.cache); - pub fn addPrefix(cache: *Cache, directory: Directory) void { cache.prefixes_buffer[cache.prefixes_len] = directory; cache.prefixes_len += 1; @@ -1118,25 +1118,12 @@ pub const Manifest = struct { if (self.manifest_dirty) { self.manifest_dirty = false; - const gpa = self.cache.gpa; - var contents: std.ArrayListUnmanaged(u8) = .empty; - defer contents.deinit(gpa); - - try contents.appendSlice(gpa, manifest_header ++ "\n"); - for (self.files.keys()) |file| { - try contents.print(gpa, "{d} {d} {d} {x} {d} {s}\n", .{ - file.stat.size, - file.stat.inode, - file.stat.mtime, - &file.bin_digest, - file.prefixed_path.prefix, - file.prefixed_path.sub_path, - }); - } - - try manifest_file.setEndPos(contents.items.len); - var pos: usize = 0; - while (pos < contents.items.len) pos += try manifest_file.pwrite(contents.items[pos..], pos); + var buffer: [4000]u8 = undefined; + var fw = manifest_file.writer(&buffer); + writeDirtyManifestToStream(self, &fw) catch |err| switch (err) { + error.WriteFailed => return fw.err.?, + else => |e| return e, + }; } if (self.want_shared_lock) { @@ -1144,6 +1131,21 @@ pub const Manifest = struct { } } + fn writeDirtyManifestToStream(self: *Manifest, fw: *fs.File.Writer) !void { + try fw.interface.writeAll(manifest_header ++ "\n"); + for (self.files.keys()) |file| { + try fw.interface.print("{d} {d} {d} {x} {d} {s}\n", .{ + file.stat.size, + file.stat.inode, + file.stat.mtime, + &file.bin_digest, + file.prefixed_path.prefix, + file.prefixed_path.sub_path, + }); + } + try fw.end(); + } + fn downgradeToSharedLock(self: *Manifest) !void { if (!self.have_exclusive_lock) return; diff --git a/lib/std/fs/File.zig b/lib/std/fs/File.zig index 2972c86722..8a761c2e98 100644 --- a/lib/std/fs/File.zig +++ b/lib/std/fs/File.zig @@ -1894,6 +1894,20 @@ pub const Writer = struct { }, } } + + pub const EndError = SetEndPosError || std.io.Writer.Error; + + /// Flushes any buffered data and sets the end position of the file. + /// + /// If not overwriting existing contents, then calling `interface.flush` + /// directly is sufficient. + /// + /// Flush failure is handled by setting `err` so that it can be handled + /// along with other write failures. + pub fn end(w: *Writer) EndError!void { + try w.interface.flush(); + return w.file.setEndPos(w.pos); + } }; /// Defaults to positional reading; falls back to streaming. |
