| ... | ... | @@ -866,15 +866,7 @@ pub const Manifest = struct { |
| 866 | 866 | .contents = contents, |
| 867 | 867 | }); |
| 868 | 868 | |
| 869 | | // This group we would like to cancel as soon as a cache miss is discovered. |
| 870 | | const PostResult = union(enum) { |
| 871 | | checkFile: CheckFileError!Check.Status, |
| 872 | | }; |
| 873 | | var post_select_buffer: [16]PostResult = undefined; |
| 874 | | var post_select: Io.Select(PostResult) = .init(io, &post_select_buffer); |
| 875 | | var post_select_remaining: usize = 0; |
| 876 | | defer post_select.cancelDiscard(); |
| 877 | | |
| 869 | // Validate and count discovered files. |
| 878 | 870 | while (off + 1 < contents.len) { |
| 879 | 871 | const file_off: File.Offset = @fromBackingInt(@intCast(off)); |
| 880 | 872 | const file = try file_off.getFallible(contents); |
| ... | ... | @@ -884,34 +876,6 @@ pub const Manifest = struct { |
| 884 | 876 | |
| 885 | 877 | try m.files.putContext(gpa, file_off, {}, .{ .contents = contents }); |
| 886 | 878 | |
| 887 | | // In order to call async here we would need to ensure `post_select_buffer` |
| 888 | | // has capacity for as many elements as files being checked. Since we don't want |
| 889 | | // to dynamically allocate that buffer, we use concurrent + fallback here. |
| 890 | | if (post_select.concurrent(.checkFile, checkFile, .{ m, &c, file_off, path })) |_| { |
| 891 | | post_select_remaining += 1; |
| 892 | | } else |err| switch (err) { |
| 893 | | error.ConcurrencyUnavailable => { |
| 894 | | // Detect if input group already had a miss. In this case we still wait |
| 895 | | // for those digests to be updated, but cancel the non input group. |
| 896 | | switch (@atomicLoad(Check.Status, &c.status, .unordered)) { |
| 897 | | .miss => { |
| 898 | | post_select.cancelDiscard(); |
| 899 | | try input_group.await(io); |
| 900 | | return .miss; |
| 901 | | }, |
| 902 | | .hit => {}, |
| 903 | | } |
| 904 | | switch (try checkFile(m, &c, file_off, path)) { |
| 905 | | .hit => continue, |
| 906 | | .miss => { |
| 907 | | post_select.cancelDiscard(); |
| 908 | | try input_group.await(io); |
| 909 | | return .miss; |
| 910 | | }, |
| 911 | | } |
| 912 | | }, |
| 913 | | } |
| 914 | | |
| 915 | 879 | off += File.sizeOf(path.len); |
| 916 | 880 | } |
| 917 | 881 | |
| ... | ... | @@ -925,6 +889,36 @@ pub const Manifest = struct { |
| 925 | 889 | |
| 926 | 890 | // Don't track the trailing zero byte in contents. |
| 927 | 891 | m.contents.items.len -= 1; |
| 892 | // Needed due to the length mutation above. |
| 893 | const refreshed_contents = m.contents.items; |
| 894 | |
| 895 | // This group we would like to cancel as soon as a cache miss is discovered. |
| 896 | const PostResult = union(enum) { |
| 897 | checkFile: CheckFileError!Check.Status, |
| 898 | }; |
| 899 | // In order to call async in the loop we need to ensure this buffer has capacity for as many elements as files |
| 900 | // being checked, otherwise a deadlock could occur since writing to the queue is waiting on the same task as |
| 901 | // would read from it. |
| 902 | const post_select_buffer = try gpa.alloc(PostResult, m.files.count() - m.input_paths.items.len); |
| 903 | defer gpa.free(post_select_buffer); |
| 904 | |
| 905 | var post_select: Io.Select(PostResult) = .init(io, post_select_buffer); |
| 906 | defer post_select.cancelDiscard(); |
| 907 | |
| 908 | var post_select_remaining: usize = 0; |
| 909 | for (m.files.keys()[m.input_paths.items.len..]) |file_off| { |
| 910 | post_select.async(.checkFile, checkFile, .{ m, &c, file_off, filePath(refreshed_contents, file_off) }); |
| 911 | post_select_remaining += 1; |
| 912 | // In case the async checkFile runs eagerly. |
| 913 | switch (@atomicLoad(Check.Status, &c.status, .unordered)) { |
| 914 | .miss => { |
| 915 | post_select.cancelDiscard(); |
| 916 | try input_group.await(io); |
| 917 | return .miss; |
| 918 | }, |
| 919 | .hit => {}, |
| 920 | } |
| 921 | } |
| 928 | 922 | |
| 929 | 923 | var post_await_buffer: [16]PostResult = undefined; |
| 930 | 924 | while (post_select_remaining > 0) { |
| ... | ... | @@ -958,9 +952,6 @@ pub const Manifest = struct { |
| 958 | 952 | if (c.status == .miss) return .miss; |
| 959 | 953 | if (m.diagnostic != .none) return error.CacheCheckFailed; |
| 960 | 954 | |
| 961 | | // Needed due to the length mutation above. |
| 962 | | const refreshed_contents = m.contents.items; |
| 963 | | |
| 964 | 955 | for (m.files.keys()) |file_off| { |
| 965 | 956 | m.hash.hasher.update(&file_off.get(refreshed_contents).digest); |
| 966 | 957 | } |