| ... | ... | @@ -324,7 +324,7 @@ var global_progress: Progress = .{ |
| 324 | 324 | .node_end_index = 0, |
| 325 | 325 | }; |
| 326 | 326 | |
| 327 | | const node_storage_buffer_len = 200; |
| 327 | const node_storage_buffer_len = 83; |
| 328 | 328 | var node_parents_buffer: [node_storage_buffer_len]Node.Parent = undefined; |
| 329 | 329 | var node_storage_buffer: [node_storage_buffer_len]Node.Storage = undefined; |
| 330 | 330 | var node_freelist_buffer: [node_storage_buffer_len]Node.OptionalIndex = undefined; |
| ... | ... | @@ -755,8 +755,10 @@ const Serialized = struct { |
| 755 | 755 | |
| 756 | 756 | parents_copy: [node_storage_buffer_len]Node.Parent, |
| 757 | 757 | storage_copy: [node_storage_buffer_len]Node.Storage, |
| 758 | ipc_metadata_fds_copy: [node_storage_buffer_len]Fd, |
| 758 | 759 | ipc_metadata_copy: [node_storage_buffer_len]SavedMetadata, |
| 759 | 760 | |
| 761 | ipc_metadata_fds: [node_storage_buffer_len]Fd, |
| 760 | 762 | ipc_metadata: [node_storage_buffer_len]SavedMetadata, |
| 761 | 763 | }; |
| 762 | 764 | }; |
| ... | ... | @@ -810,36 +812,39 @@ fn serialize(serialized_buffer: *Serialized.Buffer) Serialized { |
| 810 | 812 | } |
| 811 | 813 | |
| 812 | 814 | const SavedMetadata = struct { |
| 813 | | ipc_fd: u16, |
| 815 | remaining_read_trash_bytes: u16, |
| 814 | 816 | main_index: u8, |
| 815 | 817 | start_index: u8, |
| 816 | 818 | nodes_len: u8, |
| 819 | }; |
| 817 | 820 | |
| 818 | | fn getIpcFd(metadata: SavedMetadata) posix.fd_t { |
| 819 | | return if (is_windows) |
| 820 | | @ptrFromInt(@as(usize, metadata.ipc_fd) << 2) |
| 821 | | else |
| 822 | | metadata.ipc_fd; |
| 821 | const Fd = enum(i32) { |
| 822 | _, |
| 823 | |
| 824 | fn init(fd: posix.fd_t) Fd { |
| 825 | return @enumFromInt(if (is_windows) @as(isize, @bitCast(@intFromPtr(fd))) else fd); |
| 823 | 826 | } |
| 824 | 827 | |
| 825 | | fn setIpcFd(fd: posix.fd_t) u16 { |
| 826 | | return @intCast(if (is_windows) |
| 827 | | @shrExact(@intFromPtr(fd), 2) |
| 828 | fn get(fd: Fd) posix.fd_t { |
| 829 | return if (is_windows) |
| 830 | @ptrFromInt(@as(usize, @bitCast(@as(isize, @intFromEnum(fd))))) |
| 828 | 831 | else |
| 829 | | fd); |
| 832 | @intFromEnum(fd); |
| 830 | 833 | } |
| 831 | 834 | }; |
| 832 | 835 | |
| 833 | 836 | var ipc_metadata_len: u8 = 0; |
| 834 | | var remaining_read_trash_bytes: usize = 0; |
| 835 | 837 | |
| 836 | 838 | fn serializeIpc(start_serialized_len: usize, serialized_buffer: *Serialized.Buffer) usize { |
| 839 | const ipc_metadata_fds_copy = &serialized_buffer.ipc_metadata_fds_copy; |
| 837 | 840 | const ipc_metadata_copy = &serialized_buffer.ipc_metadata_copy; |
| 841 | const ipc_metadata_fds = &serialized_buffer.ipc_metadata_fds; |
| 838 | 842 | const ipc_metadata = &serialized_buffer.ipc_metadata; |
| 839 | 843 | |
| 840 | 844 | var serialized_len = start_serialized_len; |
| 841 | | var pipe_buf: [2 * 4096]u8 align(4) = undefined; |
| 845 | var pipe_buf: [2 * 4096]u8 = undefined; |
| 842 | 846 | |
| 847 | const old_ipc_metadata_fds = ipc_metadata_fds_copy[0..ipc_metadata_len]; |
| 843 | 848 | const old_ipc_metadata = ipc_metadata_copy[0..ipc_metadata_len]; |
| 844 | 849 | ipc_metadata_len = 0; |
| 845 | 850 | |
| ... | ... | @@ -850,6 +855,7 @@ fn serializeIpc(start_serialized_len: usize, serialized_buffer: *Serialized.Buff |
| 850 | 855 | ) |main_parent, *main_storage, main_index| { |
| 851 | 856 | if (main_parent == .unused) continue; |
| 852 | 857 | const fd = main_storage.getIpcFd() orelse continue; |
| 858 | const opt_saved_metadata = findOld(fd, old_ipc_metadata_fds, old_ipc_metadata); |
| 853 | 859 | var bytes_read: usize = 0; |
| 854 | 860 | while (true) { |
| 855 | 861 | const n = posix.read(fd, pipe_buf[bytes_read..]) catch |err| switch (err) { |
| ... | ... | @@ -862,24 +868,26 @@ fn serializeIpc(start_serialized_len: usize, serialized_buffer: *Serialized.Buff |
| 862 | 868 | }, |
| 863 | 869 | }; |
| 864 | 870 | if (n == 0) break; |
| 865 | | if (remaining_read_trash_bytes > 0) { |
| 866 | | assert(bytes_read == 0); |
| 867 | | if (remaining_read_trash_bytes >= n) { |
| 868 | | remaining_read_trash_bytes -= n; |
| 871 | if (opt_saved_metadata) |m| { |
| 872 | if (m.remaining_read_trash_bytes > 0) { |
| 873 | assert(bytes_read == 0); |
| 874 | if (m.remaining_read_trash_bytes >= n) { |
| 875 | m.remaining_read_trash_bytes = @intCast(m.remaining_read_trash_bytes - n); |
| 876 | continue; |
| 877 | } |
| 878 | const src = pipe_buf[m.remaining_read_trash_bytes..n]; |
| 879 | std.mem.copyForwards(u8, &pipe_buf, src); |
| 880 | m.remaining_read_trash_bytes = 0; |
| 881 | bytes_read = src.len; |
| 869 | 882 | continue; |
| 870 | 883 | } |
| 871 | | const src = pipe_buf[remaining_read_trash_bytes..n]; |
| 872 | | std.mem.copyForwards(u8, &pipe_buf, src); |
| 873 | | remaining_read_trash_bytes = 0; |
| 874 | | bytes_read = src.len; |
| 875 | | continue; |
| 876 | 884 | } |
| 877 | 885 | bytes_read += n; |
| 878 | 886 | } |
| 879 | 887 | // Ignore all but the last message on the pipe. |
| 880 | 888 | var input: []u8 = pipe_buf[0..bytes_read]; |
| 881 | 889 | if (input.len == 0) { |
| 882 | | serialized_len = useSavedIpcData(serialized_len, serialized_buffer, main_storage, main_index, old_ipc_metadata); |
| 890 | serialized_len = useSavedIpcData(serialized_len, serialized_buffer, main_storage, main_index, opt_saved_metadata, 0, fd); |
| 883 | 891 | continue; |
| 884 | 892 | } |
| 885 | 893 | |
| ... | ... | @@ -888,9 +896,8 @@ fn serializeIpc(start_serialized_len: usize, serialized_buffer: *Serialized.Buff |
| 888 | 896 | const expected_bytes = 1 + subtree_len * (@sizeOf(Node.Storage) + @sizeOf(Node.Parent)); |
| 889 | 897 | if (input.len < expected_bytes) { |
| 890 | 898 | // Ignore short reads. We'll handle the next full message when it comes instead. |
| 891 | | assert(remaining_read_trash_bytes == 0); |
| 892 | | remaining_read_trash_bytes = expected_bytes - input.len; |
| 893 | | serialized_len = useSavedIpcData(serialized_len, serialized_buffer, main_storage, main_index, old_ipc_metadata); |
| 899 | const remaining_read_trash_bytes: u16 = @intCast(expected_bytes - input.len); |
| 900 | serialized_len = useSavedIpcData(serialized_len, serialized_buffer, main_storage, main_index, opt_saved_metadata, remaining_read_trash_bytes, fd); |
| 894 | 901 | continue :main_loop; |
| 895 | 902 | } |
| 896 | 903 | if (input.len > expected_bytes) { |
| ... | ... | @@ -908,8 +915,9 @@ fn serializeIpc(start_serialized_len: usize, serialized_buffer: *Serialized.Buff |
| 908 | 915 | const nodes_len: u8 = @intCast(@min(parents.len - 1, serialized_buffer.storage.len - serialized_len)); |
| 909 | 916 | |
| 910 | 917 | // Remember in case the pipe is empty on next update. |
| 918 | ipc_metadata_fds[ipc_metadata_len] = Fd.init(fd); |
| 911 | 919 | ipc_metadata[ipc_metadata_len] = .{ |
| 912 | | .ipc_fd = SavedMetadata.setIpcFd(fd), |
| 920 | .remaining_read_trash_bytes = 0, |
| 913 | 921 | .start_index = @intCast(serialized_len), |
| 914 | 922 | .nodes_len = nodes_len, |
| 915 | 923 | .main_index = @intCast(main_index), |
| ... | ... | @@ -950,6 +958,7 @@ fn serializeIpc(start_serialized_len: usize, serialized_buffer: *Serialized.Buff |
| 950 | 958 | // Save a copy in case any pipes are empty on the next update. |
| 951 | 959 | @memcpy(serialized_buffer.parents_copy[0..serialized_len], serialized_buffer.parents[0..serialized_len]); |
| 952 | 960 | @memcpy(serialized_buffer.storage_copy[0..serialized_len], serialized_buffer.storage[0..serialized_len]); |
| 961 | @memcpy(ipc_metadata_fds_copy[0..ipc_metadata_len], ipc_metadata_fds[0..ipc_metadata_len]); |
| 953 | 962 | @memcpy(ipc_metadata_copy[0..ipc_metadata_len], ipc_metadata[0..ipc_metadata_len]); |
| 954 | 963 | |
| 955 | 964 | return serialized_len; |
| ... | ... | @@ -963,9 +972,13 @@ fn copyRoot(dest: *Node.Storage, src: *align(1) Node.Storage) void { |
| 963 | 972 | }; |
| 964 | 973 | } |
| 965 | 974 | |
| 966 | | fn findOld(ipc_fd: posix.fd_t, old_metadata: []const SavedMetadata) ?*const SavedMetadata { |
| 967 | | for (old_metadata) |*m| { |
| 968 | | if (m.getIpcFd() == ipc_fd) |
| 975 | fn findOld( |
| 976 | ipc_fd: posix.fd_t, |
| 977 | old_metadata_fds: []Fd, |
| 978 | old_metadata: []SavedMetadata, |
| 979 | ) ?*SavedMetadata { |
| 980 | for (old_metadata_fds, old_metadata) |fd, *m| { |
| 981 | if (fd.get() == ipc_fd) |
| 969 | 982 | return m; |
| 970 | 983 | } |
| 971 | 984 | return null; |
| ... | ... | @@ -976,16 +989,28 @@ fn useSavedIpcData( |
| 976 | 989 | serialized_buffer: *Serialized.Buffer, |
| 977 | 990 | main_storage: *Node.Storage, |
| 978 | 991 | main_index: usize, |
| 979 | | old_metadata: []const SavedMetadata, |
| 992 | opt_saved_metadata: ?*SavedMetadata, |
| 993 | remaining_read_trash_bytes: u16, |
| 994 | fd: posix.fd_t, |
| 980 | 995 | ) usize { |
| 981 | 996 | const parents_copy = &serialized_buffer.parents_copy; |
| 982 | 997 | const storage_copy = &serialized_buffer.storage_copy; |
| 998 | const ipc_metadata_fds = &serialized_buffer.ipc_metadata_fds; |
| 983 | 999 | const ipc_metadata = &serialized_buffer.ipc_metadata; |
| 984 | 1000 | |
| 985 | | const ipc_fd = main_storage.getIpcFd().?; |
| 986 | | const saved_metadata = findOld(ipc_fd, old_metadata) orelse { |
| 1001 | const saved_metadata = opt_saved_metadata orelse { |
| 987 | 1002 | main_storage.completed_count = 0; |
| 988 | 1003 | main_storage.estimated_total_count = 0; |
| 1004 | if (remaining_read_trash_bytes > 0) { |
| 1005 | ipc_metadata_fds[ipc_metadata_len] = Fd.init(fd); |
| 1006 | ipc_metadata[ipc_metadata_len] = .{ |
| 1007 | .remaining_read_trash_bytes = remaining_read_trash_bytes, |
| 1008 | .start_index = @intCast(start_serialized_len), |
| 1009 | .nodes_len = 0, |
| 1010 | .main_index = @intCast(main_index), |
| 1011 | }; |
| 1012 | ipc_metadata_len += 1; |
| 1013 | } |
| 989 | 1014 | return start_serialized_len; |
| 990 | 1015 | }; |
| 991 | 1016 | |
| ... | ... | @@ -993,8 +1018,9 @@ fn useSavedIpcData( |
| 993 | 1018 | const nodes_len = @min(saved_metadata.nodes_len, serialized_buffer.storage.len - start_serialized_len); |
| 994 | 1019 | const old_main_index = saved_metadata.main_index; |
| 995 | 1020 | |
| 1021 | ipc_metadata_fds[ipc_metadata_len] = Fd.init(fd); |
| 996 | 1022 | ipc_metadata[ipc_metadata_len] = .{ |
| 997 | | .ipc_fd = SavedMetadata.setIpcFd(ipc_fd), |
| 1023 | .remaining_read_trash_bytes = remaining_read_trash_bytes, |
| 998 | 1024 | .start_index = @intCast(start_serialized_len), |
| 999 | 1025 | .nodes_len = nodes_len, |
| 1000 | 1026 | .main_index = @intCast(main_index), |
| ... | ... | @@ -1209,6 +1235,11 @@ fn writeIpc(fd: posix.fd_t, serialized: Serialized) error{BrokenPipe}!void { |
| 1209 | 1235 | .{ .base = parents.ptr, .len = parents.len }, |
| 1210 | 1236 | }; |
| 1211 | 1237 | |
| 1238 | // Ensures the packet can fit in the pipe buffer. |
| 1239 | const upper_bound_msg_len = 1 + node_storage_buffer_len * @sizeOf(Node.Storage) + |
| 1240 | node_storage_buffer_len * @sizeOf(Node.OptionalIndex); |
| 1241 | comptime assert(upper_bound_msg_len <= 4096); |
| 1242 | |
| 1212 | 1243 | while (remaining_write_trash_bytes > 0) { |
| 1213 | 1244 | // We do this in a separate write call to give a better chance for the |
| 1214 | 1245 | // writev below to be in a single packet. |
| ... | ... | @@ -1228,7 +1259,7 @@ fn writeIpc(fd: posix.fd_t, serialized: Serialized) error{BrokenPipe}!void { |
| 1228 | 1259 | |
| 1229 | 1260 | // If this write would block we do not want to keep trying, but we need to |
| 1230 | 1261 | // know if a partial message was written. |
| 1231 | | if (posix.writev(fd, &vecs)) |written| { |
| 1262 | if (writevNonblock(fd, &vecs)) |written| { |
| 1232 | 1263 | const total = header.len + storage.len + parents.len; |
| 1233 | 1264 | if (written < total) { |
| 1234 | 1265 | remaining_write_trash_bytes = total - written; |
| ... | ... | @@ -1243,6 +1274,23 @@ fn writeIpc(fd: posix.fd_t, serialized: Serialized) error{BrokenPipe}!void { |
| 1243 | 1274 | } |
| 1244 | 1275 | } |
| 1245 | 1276 | |
| 1277 | fn writevNonblock(fd: posix.fd_t, iov: []posix.iovec_const) posix.WriteError!usize { |
| 1278 | var iov_index: usize = 0; |
| 1279 | var written: usize = 0; |
| 1280 | var total_written: usize = 0; |
| 1281 | while (true) { |
| 1282 | while (if (iov_index < iov.len) |
| 1283 | written >= iov[iov_index].len |
| 1284 | else |
| 1285 | return total_written) : (iov_index += 1) written -= iov[iov_index].len; |
| 1286 | iov[iov_index].base += written; |
| 1287 | iov[iov_index].len -= written; |
| 1288 | written = try posix.writev(fd, iov[iov_index..]); |
| 1289 | if (written == 0) return total_written; |
| 1290 | total_written += written; |
| 1291 | } |
| 1292 | } |
| 1293 | |
| 1246 | 1294 | fn maybeUpdateSize(resize_flag: bool) void { |
| 1247 | 1295 | if (!resize_flag) return; |
| 1248 | 1296 | |