| ... | ... | @@ -375,6 +375,25 @@ pub const Node = extern struct { |
| 375 | 375 | } |
| 376 | 376 | } |
| 377 | 377 | |
| 378 | /// Shrink a node to `size`, exactly. |
| 379 | /// If the new size can't contain all the children, returns error.ShrinkImpossible. |
| 380 | /// If `shift_next` is set, then the following node is shifted backwards into |
| 381 | /// the free space as much as alignment allows. |
| 382 | pub fn shrink( |
| 383 | ni: Node.Index, |
| 384 | mf: *MappedFile, |
| 385 | gpa: std.mem.Allocator, |
| 386 | size: u64, |
| 387 | shift_next: bool, |
| 388 | ) !void { |
| 389 | try mf.shrinkNode(gpa, ni, size, shift_next); |
| 390 | var writers_it = mf.writers.first; |
| 391 | while (writers_it) |writer_node| : (writers_it = writer_node.next) { |
| 392 | const w: *Node.Writer = @fieldParentPtr("writer_node", writer_node); |
| 393 | w.interface.buffer = w.ni.slice(mf); |
| 394 | } |
| 395 | } |
| 396 | |
| 378 | 397 | pub fn writer(ni: Node.Index, mf: *MappedFile, gpa: std.mem.Allocator, w: *Writer) void { |
| 379 | 398 | w.* = .{ |
| 380 | 399 | .gpa = gpa, |
| ... | ... | @@ -582,7 +601,9 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct { |
| 582 | 601 | free_node.flags.resized = false; |
| 583 | 602 | } |
| 584 | 603 | _, const parent_size = opts.parent.location(mf).resolve(mf); |
| 585 | | if (offset > parent_size) try opts.parent.resize(mf, gpa, offset); |
| 604 | const required_parent_size = offset + opts.add_node.size; |
| 605 | if (required_parent_size > parent_size) |
| 606 | try opts.parent.resize(mf, gpa, required_parent_size); |
| 586 | 607 | try free_ni.resize(mf, gpa, opts.add_node.size); |
| 587 | 608 | } |
| 588 | 609 | if (opts.add_node.moved) free_ni.movedAssumeCapacity(mf); |
| ... | ... | @@ -670,11 +691,55 @@ pub fn addNodeAfter( |
| 670 | 691 | }); |
| 671 | 692 | } |
| 672 | 693 | |
| 694 | fn shrinkNode( |
| 695 | mf: *MappedFile, |
| 696 | gpa: std.mem.Allocator, |
| 697 | ni: Node.Index, |
| 698 | size: u64, |
| 699 | shrink_next: bool, |
| 700 | ) !void { |
| 701 | const node = ni.get(mf); |
| 702 | const old_offset, _ = node.location().resolve(mf); |
| 703 | |
| 704 | // This would require unmapping first |
| 705 | if (ni == Node.Index.root) return error.Unimplemented; |
| 706 | |
| 707 | if (node.last != .none) { |
| 708 | const last = node.last.get(mf); |
| 709 | const last_offset, const last_size = last.location().resolve(mf); |
| 710 | if (last_offset + last_size > size) return error.ShrinkImpossible; |
| 711 | } |
| 712 | |
| 713 | try mf.large.ensureUnusedCapacity(gpa, 4); |
| 714 | try mf.updates.ensureUnusedCapacity(gpa, 2); |
| 715 | |
| 716 | ni.setLocationAssumeCapacity(mf, old_offset, size); |
| 717 | if (!shrink_next or node.next == .none) return; |
| 718 | |
| 719 | const next = node.next.get(mf); |
| 720 | const old_next_offset, const next_size = next.location().resolve(mf); |
| 721 | const padding = old_next_offset - (old_offset + size); |
| 722 | const new_next_offset = next.flags.alignment.forward(@intCast(old_next_offset - padding)); |
| 723 | |
| 724 | if (next.flags.has_content and new_next_offset < old_next_offset) { |
| 725 | const old_file_offset = node.next.fileLocation(mf, false).offset; |
| 726 | const new_file_offset = (old_file_offset - old_next_offset) + new_next_offset; |
| 727 | @memmove( |
| 728 | mf.memory_map.memory[new_file_offset..][0..next_size], |
| 729 | mf.memory_map.memory[old_file_offset..][0..next_size], |
| 730 | ); |
| 731 | } |
| 732 | |
| 733 | node.next.setLocationAssumeCapacity(mf, new_next_offset, next_size); |
| 734 | } |
| 735 | |
| 673 | 736 | fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested_size: u64) (Allocator.Error || Io.Cancelable || IoError)!void { |
| 674 | 737 | const io = mf.io; |
| 675 | 738 | const node = ni.get(mf); |
| 676 | 739 | const old_offset, const old_size = node.location().resolve(mf); |
| 677 | 740 | const new_size = node.flags.alignment.forward(@intCast(requested_size)); |
| 741 | if (new_size <= old_size) return; |
| 742 | |
| 678 | 743 | // Resize the entire file |
| 679 | 744 | if (ni == Node.Index.root) { |
| 680 | 745 | try mf.ensureCapacityForSetLocation(gpa); |