| ... | @@ -305,12 +305,20 @@ pub const Node = extern struct { | ... | @@ -305,12 +305,20 @@ pub const Node = extern struct { |
| 305 | } | 305 | } |
| 306 | } | 306 | } |
| 307 | | 307 | |
| 308 | pub fn realign(ni: Node.Index, mf: *MappedFile, new_alignment: std.mem.Alignment) void { | 308 | /// Moves and expands a node such that its offset and size are aligned to `new_alignment`. |
| 309 | ni.get(mf).flags.alignment = new_alignment; | 309 | /// |
| 310 | | 310 | /// Asserts that `ni` is not `Node.Index.root`. |
| 311 | const old_offset, const old_size = ni.location(mf).resolve(mf); | 311 | pub fn realign( |
| 312 | if (!new_alignment.check(@intCast(old_offset)) or !new_alignment.check(@intCast(old_size))) { | 312 | ni: Node.Index, |
| 313 | @panic("TODO MappedFile.realign"); | 313 | mf: *MappedFile, |
| | 314 | gpa: std.mem.Allocator, |
| | 315 | new_alignment: std.mem.Alignment, |
| | 316 | ) !void { |
| | 317 | try mf.realignNode(gpa, ni, new_alignment); |
| | 318 | var writers_it = mf.writers.first; |
| | 319 | while (writers_it) |writer_node| : (writers_it = writer_node.next) { |
| | 320 | const w: *Node.Writer = @fieldParentPtr("writer_node", writer_node); |
| | 321 | w.interface.buffer = w.ni.slice(mf); |
| 314 | } | 322 | } |
| 315 | } | 323 | } |
| 316 | | 324 | |
| ... | @@ -852,6 +860,82 @@ fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested | ... | @@ -852,6 +860,82 @@ fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested |
| 852 | } | 860 | } |
| 853 | } | 861 | } |
| 854 | | 862 | |
| | 863 | fn realignNode( |
| | 864 | mf: *MappedFile, |
| | 865 | gpa: std.mem.Allocator, |
| | 866 | ni: Node.Index, |
| | 867 | new_alignment: std.mem.Alignment, |
| | 868 | ) !void { |
| | 869 | assert(ni != Node.Index.root); // currently unsupported |
| | 870 | |
| | 871 | const node = ni.get(mf); |
| | 872 | const old_offset, const size = node.location().resolve(mf); |
| | 873 | |
| | 874 | assert(new_alignment.compare(.gt, node.flags.alignment)); |
| | 875 | |
| | 876 | defer if (std.debug.runtime_safety) mf.verify(); |
| | 877 | |
| | 878 | node.flags.alignment = new_alignment; |
| | 879 | |
| | 880 | const new_size = node.flags.alignment.forward(@intCast(size)); |
| | 881 | if (new_alignment.check(@intCast(old_offset))) { |
| | 882 | if (new_size > size) try mf.resizeNode(gpa, ni, new_size); |
| | 883 | return; |
| | 884 | } |
| | 885 | |
| | 886 | _, const parent_size = node.parent.location(mf).resolve(mf); |
| | 887 | const trailing_end = trailing_end: switch (node.next) { |
| | 888 | .none => parent_size, |
| | 889 | else => |next_ni| { |
| | 890 | const next_offset, _ = next_ni.location(mf).resolve(mf); |
| | 891 | break :trailing_end next_offset; |
| | 892 | }, |
| | 893 | }; |
| | 894 | |
| | 895 | const forward_offset = new_alignment.forward(@intCast(old_offset)); |
| | 896 | if (forward_offset + new_size <= trailing_end) { |
| | 897 | // Shift into the free space if possible |
| | 898 | try mf.ensureCapacityForSetLocation(gpa); |
| | 899 | if (node.flags.has_content) { |
| | 900 | const old_file_offset = ni.fileLocation(mf, false).offset; |
| | 901 | const new_file_offset = (old_file_offset - old_offset) + forward_offset; |
| | 902 | if (new_file_offset < old_file_offset + size) { |
| | 903 | @memmove( |
| | 904 | mf.memory_map.memory[@intCast(new_file_offset)..][0..@intCast(size)], |
| | 905 | mf.memory_map.memory[@intCast(old_file_offset)..][0..@intCast(size)], |
| | 906 | ); |
| | 907 | } else try mf.moveRange(old_file_offset, new_file_offset, size); |
| | 908 | @memset(mf.memory_map.memory[@intCast(new_file_offset + size)..][0..@intCast(new_size - size)], 0); |
| | 909 | } |
| | 910 | |
| | 911 | ni.setLocationAssumeCapacity(mf, forward_offset, new_size); |
| | 912 | } else { |
| | 913 | const temp_size = node.flags.alignment.forward(@intCast(new_size + 1)); |
| | 914 | try mf.resizeNode(gpa, ni, temp_size); |
| | 915 | const new_offset, _ = ni.location(mf).resolve(mf); |
| | 916 | |
| | 917 | try mf.ensureCapacityForSetLocation(gpa); |
| | 918 | |
| | 919 | // Non-fixed nodes may now be aligned if the resize moved them |
| | 920 | const new_forward_offset = new_alignment.forward(@intCast(new_offset)); |
| | 921 | const final_offset = if (new_forward_offset != new_offset) final_offset: { |
| | 922 | if (node.flags.has_content) { |
| | 923 | const old_file_offset = ni.fileLocation(mf, false).offset; |
| | 924 | const new_file_offset = (old_file_offset - new_offset) + new_forward_offset; |
| | 925 | @memmove( |
| | 926 | mf.memory_map.memory[@intCast(new_file_offset)..][0..@intCast(size)], |
| | 927 | mf.memory_map.memory[@intCast(old_file_offset)..][0..@intCast(size)], |
| | 928 | ); |
| | 929 | @memset(mf.memory_map.memory[@intCast(old_file_offset)..@intCast(new_file_offset)], 0); |
| | 930 | } |
| | 931 | |
| | 932 | break :final_offset new_forward_offset; |
| | 933 | } else new_offset; |
| | 934 | |
| | 935 | ni.setLocationAssumeCapacity(mf, final_offset, new_size); |
| | 936 | } |
| | 937 | } |
| | 938 | |
| 855 | fn moveRange(mf: *MappedFile, old_file_offset: u64, new_file_offset: u64, size: u64) !void { | 939 | fn moveRange(mf: *MappedFile, old_file_offset: u64, new_file_offset: u64, size: u64) !void { |
| 856 | // make a copy of this node at the new location | 940 | // make a copy of this node at the new location |
| 857 | try mf.copyRange(old_file_offset, new_file_offset, size); | 941 | try mf.copyRange(old_file_offset, new_file_offset, size); |