| ... | @@ -55,7 +55,15 @@ pub fn prefixes(cache: *const Cache) []const Directory { | ... | @@ -55,7 +55,15 @@ pub fn prefixes(cache: *const Cache) []const Directory { |
| 55 | | 55 | |
| 56 | const PrefixedPath = struct { | 56 | const PrefixedPath = struct { |
| 57 | prefix: u8, | 57 | prefix: u8, |
| 58 | sub_path: []u8, | 58 | sub_path: []const u8, |
| | 59 | |
| | 60 | fn eql(a: PrefixedPath, b: PrefixedPath) bool { |
| | 61 | return a.prefix == b.prefix and std.mem.eql(u8, a.sub_path, b.sub_path); |
| | 62 | } |
| | 63 | |
| | 64 | fn hash(pp: PrefixedPath) u32 { |
| | 65 | return @truncate(std.hash.Wyhash.hash(pp.prefix, pp.sub_path)); |
| | 66 | } |
| 59 | }; | 67 | }; |
| 60 | | 68 | |
| 61 | fn findPrefix(cache: *const Cache, file_path: []const u8) !PrefixedPath { | 69 | fn findPrefix(cache: *const Cache, file_path: []const u8) !PrefixedPath { |
| ... | @@ -132,7 +140,7 @@ pub const hasher_init: Hasher = Hasher.init(&[_]u8{ | ... | @@ -132,7 +140,7 @@ pub const hasher_init: Hasher = Hasher.init(&[_]u8{ |
| 132 | }); | 140 | }); |
| 133 | | 141 | |
| 134 | pub const File = struct { | 142 | pub const File = struct { |
| 135 | prefixed_path: ?PrefixedPath, | 143 | prefixed_path: PrefixedPath, |
| 136 | max_file_size: ?usize, | 144 | max_file_size: ?usize, |
| 137 | stat: Stat, | 145 | stat: Stat, |
| 138 | bin_digest: BinDigest, | 146 | bin_digest: BinDigest, |
| ... | @@ -145,16 +153,18 @@ pub const File = struct { | ... | @@ -145,16 +153,18 @@ pub const File = struct { |
| 145 | }; | 153 | }; |
| 146 | | 154 | |
| 147 | pub fn deinit(self: *File, gpa: Allocator) void { | 155 | pub fn deinit(self: *File, gpa: Allocator) void { |
| 148 | if (self.prefixed_path) |pp| { | 156 | gpa.free(self.prefixed_path.sub_path); |
| 149 | gpa.free(pp.sub_path); | | |
| 150 | self.prefixed_path = null; | | |
| 151 | } | | |
| 152 | if (self.contents) |contents| { | 157 | if (self.contents) |contents| { |
| 153 | gpa.free(contents); | 158 | gpa.free(contents); |
| 154 | self.contents = null; | 159 | self.contents = null; |
| 155 | } | 160 | } |
| 156 | self.* = undefined; | 161 | self.* = undefined; |
| 157 | } | 162 | } |
| | 163 | |
| | 164 | pub fn updateMaxSize(file: *File, new_max_size: ?usize) void { |
| | 165 | const new = new_max_size orelse return; |
| | 166 | file.max_file_size = if (file.max_file_size) |old| @max(old, new) else new; |
| | 167 | } |
| 158 | }; | 168 | }; |
| 159 | | 169 | |
| 160 | pub const HashHelper = struct { | 170 | pub const HashHelper = struct { |
| ... | @@ -296,7 +306,7 @@ pub const Manifest = struct { | ... | @@ -296,7 +306,7 @@ pub const Manifest = struct { |
| 296 | // order to obtain a problematic timestamp for the next call. Calls after that | 306 | // order to obtain a problematic timestamp for the next call. Calls after that |
| 297 | // will then use the same timestamp, to avoid unnecessary filesystem writes. | 307 | // will then use the same timestamp, to avoid unnecessary filesystem writes. |
| 298 | want_refresh_timestamp: bool = true, | 308 | want_refresh_timestamp: bool = true, |
| 299 | files: std.ArrayListUnmanaged(File) = .{}, | 309 | files: Files = .{}, |
| 300 | hex_digest: HexDigest, | 310 | hex_digest: HexDigest, |
| 301 | /// Populated when hit() returns an error because of one | 311 | /// Populated when hit() returns an error because of one |
| 302 | /// of the files listed in the manifest. | 312 | /// of the files listed in the manifest. |
| ... | @@ -305,6 +315,34 @@ pub const Manifest = struct { | ... | @@ -305,6 +315,34 @@ pub const Manifest = struct { |
| 305 | /// what time the file system thinks it is, according to its own granularity. | 315 | /// what time the file system thinks it is, according to its own granularity. |
| 306 | recent_problematic_timestamp: i128 = 0, | 316 | recent_problematic_timestamp: i128 = 0, |
| 307 | | 317 | |
| | 318 | pub const Files = std.ArrayHashMapUnmanaged(File, void, FilesContext, false); |
| | 319 | |
| | 320 | pub const FilesContext = struct { |
| | 321 | pub fn hash(fc: FilesContext, file: File) u32 { |
| | 322 | _ = fc; |
| | 323 | return file.prefixed_path.hash(); |
| | 324 | } |
| | 325 | |
| | 326 | pub fn eql(fc: FilesContext, a: File, b: File, b_index: usize) bool { |
| | 327 | _ = fc; |
| | 328 | _ = b_index; |
| | 329 | return a.prefixed_path.eql(b.prefixed_path); |
| | 330 | } |
| | 331 | }; |
| | 332 | |
| | 333 | const FilesAdapter = struct { |
| | 334 | pub fn eql(context: @This(), a: PrefixedPath, b: File, b_index: usize) bool { |
| | 335 | _ = context; |
| | 336 | _ = b_index; |
| | 337 | return a.eql(b.prefixed_path); |
| | 338 | } |
| | 339 | |
| | 340 | pub fn hash(context: @This(), key: PrefixedPath) u32 { |
| | 341 | _ = context; |
| | 342 | return key.hash(); |
| | 343 | } |
| | 344 | }; |
| | 345 | |
| 308 | /// Add a file as a dependency of process being cached. When `hit` is | 346 | /// Add a file as a dependency of process being cached. When `hit` is |
| 309 | /// called, the file's contents will be checked to ensure that it matches | 347 | /// called, the file's contents will be checked to ensure that it matches |
| 310 | /// the contents from previous times. | 348 | /// the contents from previous times. |
| ... | @@ -317,7 +355,7 @@ pub const Manifest = struct { | ... | @@ -317,7 +355,7 @@ pub const Manifest = struct { |
| 317 | /// to access the contents of the file after calling `hit()` like so: | 355 | /// to access the contents of the file after calling `hit()` like so: |
| 318 | /// | 356 | /// |
| 319 | /// ``` | 357 | /// ``` |
| 320 | /// var file_contents = cache_hash.files.items[file_index].contents.?; | 358 | /// var file_contents = cache_hash.files.keys()[file_index].contents.?; |
| 321 | /// ``` | 359 | /// ``` |
| 322 | pub fn addFile(self: *Manifest, file_path: []const u8, max_file_size: ?usize) !usize { | 360 | pub fn addFile(self: *Manifest, file_path: []const u8, max_file_size: ?usize) !usize { |
| 323 | assert(self.manifest_file == null); | 361 | assert(self.manifest_file == null); |
| ... | @@ -327,7 +365,12 @@ pub const Manifest = struct { | ... | @@ -327,7 +365,12 @@ pub const Manifest = struct { |
| 327 | const prefixed_path = try self.cache.findPrefix(file_path); | 365 | const prefixed_path = try self.cache.findPrefix(file_path); |
| 328 | errdefer gpa.free(prefixed_path.sub_path); | 366 | errdefer gpa.free(prefixed_path.sub_path); |
| 329 | | 367 | |
| 330 | self.files.addOneAssumeCapacity().* = .{ | 368 | const gop = self.files.getOrPutAssumeCapacityAdapted(prefixed_path, FilesAdapter{}); |
| | 369 | if (gop.found_existing) { |
| | 370 | gop.key_ptr.updateMaxSize(max_file_size); |
| | 371 | return gop.index; |
| | 372 | } |
| | 373 | gop.key_ptr.* = .{ |
| 331 | .prefixed_path = prefixed_path, | 374 | .prefixed_path = prefixed_path, |
| 332 | .contents = null, | 375 | .contents = null, |
| 333 | .max_file_size = max_file_size, | 376 | .max_file_size = max_file_size, |
| ... | @@ -338,7 +381,7 @@ pub const Manifest = struct { | ... | @@ -338,7 +381,7 @@ pub const Manifest = struct { |
| 338 | self.hash.add(prefixed_path.prefix); | 381 | self.hash.add(prefixed_path.prefix); |
| 339 | self.hash.addBytes(prefixed_path.sub_path); | 382 | self.hash.addBytes(prefixed_path.sub_path); |
| 340 | | 383 | |
| 341 | return self.files.items.len - 1; | 384 | return gop.index; |
| 342 | } | 385 | } |
| 343 | | 386 | |
| 344 | pub fn addOptionalFile(self: *Manifest, optional_file_path: ?[]const u8) !void { | 387 | pub fn addOptionalFile(self: *Manifest, optional_file_path: ?[]const u8) !void { |
| ... | @@ -418,7 +461,7 @@ pub const Manifest = struct { | ... | @@ -418,7 +461,7 @@ pub const Manifest = struct { |
| 418 | | 461 | |
| 419 | self.want_refresh_timestamp = true; | 462 | self.want_refresh_timestamp = true; |
| 420 | | 463 | |
| 421 | const input_file_count = self.files.items.len; | 464 | const input_file_count = self.files.entries.len; |
| 422 | while (true) : (self.unhit(bin_digest, input_file_count)) { | 465 | while (true) : (self.unhit(bin_digest, input_file_count)) { |
| 423 | const file_contents = try self.manifest_file.?.reader().readAllAlloc(gpa, manifest_file_size_max); | 466 | const file_contents = try self.manifest_file.?.reader().readAllAlloc(gpa, manifest_file_size_max); |
| 424 | defer gpa.free(file_contents); | 467 | defer gpa.free(file_contents); |
| ... | @@ -430,7 +473,7 @@ pub const Manifest = struct { | ... | @@ -430,7 +473,7 @@ pub const Manifest = struct { |
| 430 | if (try self.upgradeToExclusiveLock()) continue; | 473 | if (try self.upgradeToExclusiveLock()) continue; |
| 431 | self.manifest_dirty = true; | 474 | self.manifest_dirty = true; |
| 432 | while (idx < input_file_count) : (idx += 1) { | 475 | while (idx < input_file_count) : (idx += 1) { |
| 433 | const ch_file = &self.files.items[idx]; | 476 | const ch_file = &self.files.keys()[idx]; |
| 434 | self.populateFileHash(ch_file) catch |err| { | 477 | self.populateFileHash(ch_file) catch |err| { |
| 435 | self.failed_file_index = idx; | 478 | self.failed_file_index = idx; |
| 436 | return err; | 479 | return err; |
| ... | @@ -441,18 +484,6 @@ pub const Manifest = struct { | ... | @@ -441,18 +484,6 @@ pub const Manifest = struct { |
| 441 | while (line_iter.next()) |line| { | 484 | while (line_iter.next()) |line| { |
| 442 | defer idx += 1; | 485 | defer idx += 1; |
| 443 | | 486 | |
| 444 | const cache_hash_file = if (idx < input_file_count) &self.files.items[idx] else blk: { | | |
| 445 | const new = try self.files.addOne(gpa); | | |
| 446 | new.* = .{ | | |
| 447 | .prefixed_path = null, | | |
| 448 | .contents = null, | | |
| 449 | .max_file_size = null, | | |
| 450 | .stat = undefined, | | |
| 451 | .bin_digest = undefined, | | |
| 452 | }; | | |
| 453 | break :blk new; | | |
| 454 | }; | | |
| 455 | | | |
| 456 | var iter = mem.tokenizeScalar(u8, line, ' '); | 487 | var iter = mem.tokenizeScalar(u8, line, ' '); |
| 457 | const size = iter.next() orelse return error.InvalidFormat; | 488 | const size = iter.next() orelse return error.InvalidFormat; |
| 458 | const inode = iter.next() orelse return error.InvalidFormat; | 489 | const inode = iter.next() orelse return error.InvalidFormat; |
| ... | @@ -461,30 +492,61 @@ pub const Manifest = struct { | ... | @@ -461,30 +492,61 @@ pub const Manifest = struct { |
| 461 | const prefix_str = iter.next() orelse return error.InvalidFormat; | 492 | const prefix_str = iter.next() orelse return error.InvalidFormat; |
| 462 | const file_path = iter.rest(); | 493 | const file_path = iter.rest(); |
| 463 | | 494 | |
| 464 | cache_hash_file.stat.size = fmt.parseInt(u64, size, 10) catch return error.InvalidFormat; | 495 | const stat_size = fmt.parseInt(u64, size, 10) catch return error.InvalidFormat; |
| 465 | cache_hash_file.stat.inode = fmt.parseInt(fs.File.INode, inode, 10) catch return error.InvalidFormat; | 496 | const stat_inode = fmt.parseInt(fs.File.INode, inode, 10) catch return error.InvalidFormat; |
| 466 | cache_hash_file.stat.mtime = fmt.parseInt(i64, mtime_nsec_str, 10) catch return error.InvalidFormat; | 497 | const stat_mtime = fmt.parseInt(i64, mtime_nsec_str, 10) catch return error.InvalidFormat; |
| 467 | _ = fmt.hexToBytes(&cache_hash_file.bin_digest, digest_str) catch return error.InvalidFormat; | 498 | const file_bin_digest = b: { |
| | 499 | if (digest_str.len != hex_digest_len) return error.InvalidFormat; |
| | 500 | var bd: BinDigest = undefined; |
| | 501 | _ = fmt.hexToBytes(&bd, digest_str) catch return error.InvalidFormat; |
| | 502 | break :b bd; |
| | 503 | }; |
| | 504 | |
| 468 | const prefix = fmt.parseInt(u8, prefix_str, 10) catch return error.InvalidFormat; | 505 | const prefix = fmt.parseInt(u8, prefix_str, 10) catch return error.InvalidFormat; |
| 469 | if (prefix >= self.cache.prefixes_len) return error.InvalidFormat; | 506 | if (prefix >= self.cache.prefixes_len) return error.InvalidFormat; |
| 470 | | 507 | |
| 471 | if (file_path.len == 0) { | 508 | if (file_path.len == 0) return error.InvalidFormat; |
| 472 | return error.InvalidFormat; | | |
| 473 | } | | |
| 474 | if (cache_hash_file.prefixed_path) |pp| { | | |
| 475 | if (pp.prefix != prefix or !mem.eql(u8, file_path, pp.sub_path)) { | | |
| 476 | return error.InvalidFormat; | | |
| 477 | } | | |
| 478 | } | | |
| 479 | | 509 | |
| 480 | if (cache_hash_file.prefixed_path == null) { | 510 | const cache_hash_file = f: { |
| 481 | cache_hash_file.prefixed_path = .{ | 511 | const prefixed_path: PrefixedPath = .{ |
| 482 | .prefix = prefix, | 512 | .prefix = prefix, |
| 483 | .sub_path = try gpa.dupe(u8, file_path), | 513 | .sub_path = file_path, // expires with file_contents |
| 484 | }; | 514 | }; |
| 485 | } | 515 | if (idx < input_file_count) { |
| | 516 | const file = &self.files.keys()[idx]; |
| | 517 | if (!file.prefixed_path.eql(prefixed_path)) |
| | 518 | return error.InvalidFormat; |
| | 519 | |
| | 520 | file.stat = .{ |
| | 521 | .size = stat_size, |
| | 522 | .inode = stat_inode, |
| | 523 | .mtime = stat_mtime, |
| | 524 | }; |
| | 525 | file.bin_digest = file_bin_digest; |
| | 526 | break :f file; |
| | 527 | } |
| | 528 | const gop = try self.files.getOrPutAdapted(gpa, prefixed_path, FilesAdapter{}); |
| | 529 | errdefer assert(self.files.popOrNull() != null); |
| | 530 | if (!gop.found_existing) { |
| | 531 | gop.key_ptr.* = .{ |
| | 532 | .prefixed_path = .{ |
| | 533 | .prefix = prefix, |
| | 534 | .sub_path = try gpa.dupe(u8, file_path), |
| | 535 | }, |
| | 536 | .contents = null, |
| | 537 | .max_file_size = null, |
| | 538 | .stat = .{ |
| | 539 | .size = stat_size, |
| | 540 | .inode = stat_inode, |
| | 541 | .mtime = stat_mtime, |
| | 542 | }, |
| | 543 | .bin_digest = file_bin_digest, |
| | 544 | }; |
| | 545 | } |
| | 546 | break :f gop.key_ptr; |
| | 547 | }; |
| 486 | | 548 | |
| 487 | const pp = cache_hash_file.prefixed_path.?; | 549 | const pp = cache_hash_file.prefixed_path; |
| 488 | const dir = self.cache.prefixes()[pp.prefix].handle; | 550 | const dir = self.cache.prefixes()[pp.prefix].handle; |
| 489 | const this_file = dir.openFile(pp.sub_path, .{ .mode = .read_only }) catch |err| switch (err) { | 551 | const this_file = dir.openFile(pp.sub_path, .{ .mode = .read_only }) catch |err| switch (err) { |
| 490 | error.FileNotFound => { | 552 | error.FileNotFound => { |
| ... | @@ -548,7 +610,7 @@ pub const Manifest = struct { | ... | @@ -548,7 +610,7 @@ pub const Manifest = struct { |
| 548 | if (try self.upgradeToExclusiveLock()) continue; | 610 | if (try self.upgradeToExclusiveLock()) continue; |
| 549 | self.manifest_dirty = true; | 611 | self.manifest_dirty = true; |
| 550 | while (idx < input_file_count) : (idx += 1) { | 612 | while (idx < input_file_count) : (idx += 1) { |
| 551 | const ch_file = &self.files.items[idx]; | 613 | const ch_file = &self.files.keys()[idx]; |
| 552 | self.populateFileHash(ch_file) catch |err| { | 614 | self.populateFileHash(ch_file) catch |err| { |
| 553 | self.failed_file_index = idx; | 615 | self.failed_file_index = idx; |
| 554 | return err; | 616 | return err; |
| ... | @@ -571,12 +633,12 @@ pub const Manifest = struct { | ... | @@ -571,12 +633,12 @@ pub const Manifest = struct { |
| 571 | self.hash.hasher.update(&bin_digest); | 633 | self.hash.hasher.update(&bin_digest); |
| 572 | | 634 | |
| 573 | // Remove files not in the initial hash. | 635 | // Remove files not in the initial hash. |
| 574 | for (self.files.items[input_file_count..]) |*file| { | 636 | for (self.files.keys()[input_file_count..]) |*file| { |
| 575 | file.deinit(self.cache.gpa); | 637 | file.deinit(self.cache.gpa); |
| 576 | } | 638 | } |
| 577 | self.files.shrinkRetainingCapacity(input_file_count); | 639 | self.files.shrinkRetainingCapacity(input_file_count); |
| 578 | | 640 | |
| 579 | for (self.files.items) |file| { | 641 | for (self.files.keys()) |file| { |
| 580 | self.hash.hasher.update(&file.bin_digest); | 642 | self.hash.hasher.update(&file.bin_digest); |
| 581 | } | 643 | } |
| 582 | } | 644 | } |
| ... | @@ -616,7 +678,7 @@ pub const Manifest = struct { | ... | @@ -616,7 +678,7 @@ pub const Manifest = struct { |
| 616 | } | 678 | } |
| 617 | | 679 | |
| 618 | fn populateFileHash(self: *Manifest, ch_file: *File) !void { | 680 | fn populateFileHash(self: *Manifest, ch_file: *File) !void { |
| 619 | const pp = ch_file.prefixed_path.?; | 681 | const pp = ch_file.prefixed_path; |
| 620 | const dir = self.cache.prefixes()[pp.prefix].handle; | 682 | const dir = self.cache.prefixes()[pp.prefix].handle; |
| 621 | const file = try dir.openFile(pp.sub_path, .{}); | 683 | const file = try dir.openFile(pp.sub_path, .{}); |
| 622 | defer file.close(); | 684 | defer file.close(); |
| ... | @@ -682,7 +744,7 @@ pub const Manifest = struct { | ... | @@ -682,7 +744,7 @@ pub const Manifest = struct { |
| 682 | .bin_digest = undefined, | 744 | .bin_digest = undefined, |
| 683 | .contents = null, | 745 | .contents = null, |
| 684 | }; | 746 | }; |
| 685 | errdefer self.files.shrinkRetainingCapacity(self.files.items.len - 1); | 747 | errdefer self.files.shrinkRetainingCapacity(self.files.entries.len - 1); |
| 686 | | 748 | |
| 687 | try self.populateFileHash(new_ch_file); | 749 | try self.populateFileHash(new_ch_file); |
| 688 | | 750 | |
| ... | @@ -690,9 +752,11 @@ pub const Manifest = struct { | ... | @@ -690,9 +752,11 @@ pub const Manifest = struct { |
| 690 | } | 752 | } |
| 691 | | 753 | |
| 692 | /// Add a file as a dependency of process being cached, after the initial hash has been | 754 | /// Add a file as a dependency of process being cached, after the initial hash has been |
| 693 | /// calculated. This is useful for processes that don't know the all the files that | 755 | /// calculated. |
| 694 | /// are depended on ahead of time. For example, a source file that can import other files | 756 | /// |
| 695 | /// will need to be recompiled if the imported file is changed. | 757 | /// This is useful for processes that don't know the all the files that are |
| | 758 | /// depended on ahead of time. For example, a source file that can import |
| | 759 | /// other files will need to be recompiled if the imported file is changed. |
| 696 | pub fn addFilePost(self: *Manifest, file_path: []const u8) !void { | 760 | pub fn addFilePost(self: *Manifest, file_path: []const u8) !void { |
| 697 | assert(self.manifest_file != null); | 761 | assert(self.manifest_file != null); |
| 698 | | 762 | |
| ... | @@ -700,17 +764,26 @@ pub const Manifest = struct { | ... | @@ -700,17 +764,26 @@ pub const Manifest = struct { |
| 700 | const prefixed_path = try self.cache.findPrefix(file_path); | 764 | const prefixed_path = try self.cache.findPrefix(file_path); |
| 701 | errdefer gpa.free(prefixed_path.sub_path); | 765 | errdefer gpa.free(prefixed_path.sub_path); |
| 702 | | 766 | |
| 703 | const new_ch_file = try self.files.addOne(gpa); | 767 | const gop = try self.files.getOrPutAdapted(gpa, prefixed_path, FilesAdapter{}); |
| 704 | new_ch_file.* = .{ | 768 | errdefer assert(self.files.popOrNull() != null); |
| | 769 | |
| | 770 | if (gop.found_existing) { |
| | 771 | gpa.free(prefixed_path.sub_path); |
| | 772 | return; |
| | 773 | } |
| | 774 | |
| | 775 | gop.key_ptr.* = .{ |
| 705 | .prefixed_path = prefixed_path, | 776 | .prefixed_path = prefixed_path, |
| 706 | .max_file_size = null, | 777 | .max_file_size = null, |
| 707 | .stat = undefined, | 778 | .stat = undefined, |
| 708 | .bin_digest = undefined, | 779 | .bin_digest = undefined, |
| 709 | .contents = null, | 780 | .contents = null, |
| 710 | }; | 781 | }; |
| 711 | errdefer self.files.shrinkRetainingCapacity(self.files.items.len - 1); | | |
| 712 | | 782 | |
| 713 | try self.populateFileHash(new_ch_file); | 783 | self.files.lockPointers(); |
| | 784 | defer self.files.unlockPointers(); |
| | 785 | |
| | 786 | try self.populateFileHash(gop.key_ptr); |
| 714 | } | 787 | } |
| 715 | | 788 | |
| 716 | /// Like `addFilePost` but when the file contents have already been loaded from disk. | 789 | /// Like `addFilePost` but when the file contents have already been loaded from disk. |
| ... | @@ -724,13 +797,20 @@ pub const Manifest = struct { | ... | @@ -724,13 +797,20 @@ pub const Manifest = struct { |
| 724 | assert(self.manifest_file != null); | 797 | assert(self.manifest_file != null); |
| 725 | const gpa = self.cache.gpa; | 798 | const gpa = self.cache.gpa; |
| 726 | | 799 | |
| 727 | const ch_file = try self.files.addOne(gpa); | | |
| 728 | errdefer self.files.shrinkRetainingCapacity(self.files.items.len - 1); | | |
| 729 | | | |
| 730 | const prefixed_path = try self.cache.findPrefixResolved(resolved_path); | 800 | const prefixed_path = try self.cache.findPrefixResolved(resolved_path); |
| 731 | errdefer gpa.free(prefixed_path.sub_path); | 801 | errdefer gpa.free(prefixed_path.sub_path); |
| 732 | | 802 | |
| 733 | ch_file.* = .{ | 803 | const gop = try self.files.getOrPutAdapted(gpa, prefixed_path, FilesAdapter{}); |
| | 804 | errdefer assert(self.files.popOrNull() != null); |
| | 805 | |
| | 806 | if (gop.found_existing) { |
| | 807 | gpa.free(prefixed_path.sub_path); |
| | 808 | return; |
| | 809 | } |
| | 810 | |
| | 811 | const new_file = gop.key_ptr; |
| | 812 | |
| | 813 | new_file.* = .{ |
| 734 | .prefixed_path = prefixed_path, | 814 | .prefixed_path = prefixed_path, |
| 735 | .max_file_size = null, | 815 | .max_file_size = null, |
| 736 | .stat = stat, | 816 | .stat = stat, |
| ... | @@ -738,19 +818,19 @@ pub const Manifest = struct { | ... | @@ -738,19 +818,19 @@ pub const Manifest = struct { |
| 738 | .contents = null, | 818 | .contents = null, |
| 739 | }; | 819 | }; |
| 740 | | 820 | |
| 741 | if (self.isProblematicTimestamp(ch_file.stat.mtime)) { | 821 | if (self.isProblematicTimestamp(new_file.stat.mtime)) { |
| 742 | // The actual file has an unreliable timestamp, force it to be hashed | 822 | // The actual file has an unreliable timestamp, force it to be hashed |
| 743 | ch_file.stat.mtime = 0; | 823 | new_file.stat.mtime = 0; |
| 744 | ch_file.stat.inode = 0; | 824 | new_file.stat.inode = 0; |
| 745 | } | 825 | } |
| 746 | | 826 | |
| 747 | { | 827 | { |
| 748 | var hasher = hasher_init; | 828 | var hasher = hasher_init; |
| 749 | hasher.update(bytes); | 829 | hasher.update(bytes); |
| 750 | hasher.final(&ch_file.bin_digest); | 830 | hasher.final(&new_file.bin_digest); |
| 751 | } | 831 | } |
| 752 | | 832 | |
| 753 | self.hash.hasher.update(&ch_file.bin_digest); | 833 | self.hash.hasher.update(&new_file.bin_digest); |
| 754 | } | 834 | } |
| 755 | | 835 | |
| 756 | pub fn addDepFilePost(self: *Manifest, dir: fs.Dir, dep_file_basename: []const u8) !void { | 836 | pub fn addDepFilePost(self: *Manifest, dir: fs.Dir, dep_file_basename: []const u8) !void { |
| ... | @@ -816,14 +896,14 @@ pub const Manifest = struct { | ... | @@ -816,14 +896,14 @@ pub const Manifest = struct { |
| 816 | | 896 | |
| 817 | const writer = contents.writer(); | 897 | const writer = contents.writer(); |
| 818 | try writer.writeAll(manifest_header ++ "\n"); | 898 | try writer.writeAll(manifest_header ++ "\n"); |
| 819 | for (self.files.items) |file| { | 899 | for (self.files.keys()) |file| { |
| 820 | try writer.print("{d} {d} {d} {} {d} {s}\n", .{ | 900 | try writer.print("{d} {d} {d} {} {d} {s}\n", .{ |
| 821 | file.stat.size, | 901 | file.stat.size, |
| 822 | file.stat.inode, | 902 | file.stat.inode, |
| 823 | file.stat.mtime, | 903 | file.stat.mtime, |
| 824 | fmt.fmtSliceHexLower(&file.bin_digest), | 904 | fmt.fmtSliceHexLower(&file.bin_digest), |
| 825 | file.prefixed_path.?.prefix, | 905 | file.prefixed_path.prefix, |
| 826 | file.prefixed_path.?.sub_path, | 906 | file.prefixed_path.sub_path, |
| 827 | }); | 907 | }); |
| 828 | } | 908 | } |
| 829 | | 909 | |
| ... | @@ -892,7 +972,7 @@ pub const Manifest = struct { | ... | @@ -892,7 +972,7 @@ pub const Manifest = struct { |
| 892 | | 972 | |
| 893 | file.close(); | 973 | file.close(); |
| 894 | } | 974 | } |
| 895 | for (self.files.items) |*file| { | 975 | for (self.files.keys()) |*file| { |
| 896 | file.deinit(self.cache.gpa); | 976 | file.deinit(self.cache.gpa); |
| 897 | } | 977 | } |
| 898 | self.files.deinit(self.cache.gpa); | 978 | self.files.deinit(self.cache.gpa); |
| ... | @@ -1061,7 +1141,7 @@ test "check that changing a file makes cache fail" { | ... | @@ -1061,7 +1141,7 @@ test "check that changing a file makes cache fail" { |
| 1061 | // There should be nothing in the cache | 1141 | // There should be nothing in the cache |
| 1062 | try testing.expectEqual(false, try ch.hit()); | 1142 | try testing.expectEqual(false, try ch.hit()); |
| 1063 | | 1143 | |
| 1064 | try testing.expect(mem.eql(u8, original_temp_file_contents, ch.files.items[temp_file_idx].contents.?)); | 1144 | try testing.expect(mem.eql(u8, original_temp_file_contents, ch.files.keys()[temp_file_idx].contents.?)); |
| 1065 | | 1145 | |
| 1066 | digest1 = ch.final(); | 1146 | digest1 = ch.final(); |
| 1067 | | 1147 | |
| ... | @@ -1081,7 +1161,7 @@ test "check that changing a file makes cache fail" { | ... | @@ -1081,7 +1161,7 @@ test "check that changing a file makes cache fail" { |
| 1081 | try testing.expectEqual(false, try ch.hit()); | 1161 | try testing.expectEqual(false, try ch.hit()); |
| 1082 | | 1162 | |
| 1083 | // The cache system does not keep the contents of re-hashed input files. | 1163 | // The cache system does not keep the contents of re-hashed input files. |
| 1084 | try testing.expect(ch.files.items[temp_file_idx].contents == null); | 1164 | try testing.expect(ch.files.keys()[temp_file_idx].contents == null); |
| 1085 | | 1165 | |
| 1086 | digest2 = ch.final(); | 1166 | digest2 = ch.final(); |
| 1087 | | 1167 | |