| ... | @@ -795,10 +795,12 @@ pub const Manifest = struct { | ... | @@ -795,10 +795,12 @@ pub const Manifest = struct { |
| 795 | | 795 | |
| 796 | fn shrinkFilesToInput(m: *Manifest) void { | 796 | fn shrinkFilesToInput(m: *Manifest) void { |
| 797 | if (m.files.count() <= m.input_paths.items.len) return; | 797 | if (m.files.count() <= m.input_paths.items.len) return; |
| | 798 | // Reads from files hash map whose data is destroyed on the next line. |
| 798 | const off = m.files.keys()[m.input_paths.items.len]; | 799 | const off = m.files.keys()[m.input_paths.items.len]; |
| | 800 | // Reads from the unshrunken contents whose data is destroyed on the next line. |
| | 801 | m.files.shrinkRetainingCapacityContext(m.input_paths.items.len, .{ .contents = m.contents.items }); |
| 799 | m.contents.shrinkRetainingCapacity(@backingInt(off)); | 802 | m.contents.shrinkRetainingCapacity(@backingInt(off)); |
| 800 | assert(mem.isAligned(m.contents.items.len, @alignOf(File))); | 803 | assert(mem.isAligned(m.contents.items.len, @alignOf(File))); |
| 801 | m.files.shrinkRetainingCapacityContext(m.input_paths.items.len, .{ .contents = m.contents.items }); | | |
| 802 | } | 804 | } |
| 803 | | 805 | |
| 804 | /// Assumes that `self.hash.hasher` has been updated only with the original digest and that | 806 | /// Assumes that `self.hash.hasher` has been updated only with the original digest and that |
| ... | @@ -852,7 +854,7 @@ pub const Manifest = struct { | ... | @@ -852,7 +854,7 @@ pub const Manifest = struct { |
| 852 | const PostResult = union(enum) { | 854 | const PostResult = union(enum) { |
| 853 | checkFile: CheckFileError!Check.Status, | 855 | checkFile: CheckFileError!Check.Status, |
| 854 | }; | 856 | }; |
| 855 | var post_select_buffer: [10]PostResult = undefined; | 857 | var post_select_buffer: [16]PostResult = undefined; |
| 856 | var post_select: Io.Select(PostResult) = .init(io, &post_select_buffer); | 858 | var post_select: Io.Select(PostResult) = .init(io, &post_select_buffer); |
| 857 | var post_select_remaining: usize = 0; | 859 | var post_select_remaining: usize = 0; |
| 858 | defer post_select.cancelDiscard(); | 860 | defer post_select.cancelDiscard(); |
| ... | @@ -866,8 +868,33 @@ pub const Manifest = struct { | ... | @@ -866,8 +868,33 @@ pub const Manifest = struct { |
| 866 | | 868 | |
| 867 | try m.files.putContext(gpa, file_off, {}, .{ .contents = contents }); | 869 | try m.files.putContext(gpa, file_off, {}, .{ .contents = contents }); |
| 868 | | 870 | |
| 869 | post_select.async(.checkFile, checkFile, .{ m, &c, file_off, path }); | 871 | // In order to call async here we would need to ensure `post_select_buffer` |
| 870 | post_select_remaining += 1; | 872 | // has capacity for as many elements as files being checked. Since we don't want |
| | 873 | // to dynamically allocate that buffer, we use concurrent + fallback here. |
| | 874 | if (post_select.concurrent(.checkFile, checkFile, .{ m, &c, file_off, path })) |_| { |
| | 875 | post_select_remaining += 1; |
| | 876 | } else |err| switch (err) { |
| | 877 | error.ConcurrencyUnavailable => { |
| | 878 | // Detect if input group already had a miss. In this case we still wait |
| | 879 | // for those digests to be updated, but cancel the non input group. |
| | 880 | switch (@atomicLoad(Check.Status, &c.status, .unordered)) { |
| | 881 | .miss => { |
| | 882 | post_select.cancelDiscard(); |
| | 883 | try input_group.await(io); |
| | 884 | return .miss; |
| | 885 | }, |
| | 886 | .hit => {}, |
| | 887 | } |
| | 888 | switch (try checkFile(m, &c, file_off, path)) { |
| | 889 | .hit => continue, |
| | 890 | .miss => { |
| | 891 | post_select.cancelDiscard(); |
| | 892 | try input_group.await(io); |
| | 893 | return .miss; |
| | 894 | }, |
| | 895 | } |
| | 896 | }, |
| | 897 | } |
| 871 | | 898 | |
| 872 | off += File.sizeOf(path.len); | 899 | off += File.sizeOf(path.len); |
| 873 | } | 900 | } |
| ... | @@ -883,7 +910,7 @@ pub const Manifest = struct { | ... | @@ -883,7 +910,7 @@ pub const Manifest = struct { |
| 883 | // Don't track the trailing zero byte in contents. | 910 | // Don't track the trailing zero byte in contents. |
| 884 | m.contents.items.len -= 1; | 911 | m.contents.items.len -= 1; |
| 885 | | 912 | |
| 886 | var post_await_buffer: [10]PostResult = undefined; | 913 | var post_await_buffer: [16]PostResult = undefined; |
| 887 | while (post_select_remaining > 0) { | 914 | while (post_select_remaining > 0) { |
| 888 | const n = try post_select.awaitMany(&post_await_buffer, 1); | 915 | const n = try post_select.awaitMany(&post_await_buffer, 1); |
| 889 | post_select_remaining -= n; | 916 | post_select_remaining -= n; |
| ... | @@ -896,11 +923,11 @@ pub const Manifest = struct { | ... | @@ -896,11 +923,11 @@ pub const Manifest = struct { |
| 896 | try input_group.await(io); | 923 | try input_group.await(io); |
| 897 | return .miss; | 924 | return .miss; |
| 898 | }, | 925 | }, |
| 899 | .hit => continue, | 926 | .hit => {}, |
| 900 | } | 927 | } |
| 901 | | 928 | |
| 902 | for (post_await_buffer[0..n]) |u| switch (u) { | 929 | for (post_await_buffer[0..n]) |u| switch (u) { |
| 903 | .checkFile => |result| switch (result) { | 930 | .checkFile => |result| switch (try result) { |
| 904 | .hit => continue, | 931 | .hit => continue, |
| 905 | .miss => { | 932 | .miss => { |
| 906 | post_select.cancelDiscard(); | 933 | post_select.cancelDiscard(); |