| ... | ... | @@ -95,14 +95,11 @@ pub fn init(file: Io.File, gpa: std.mem.Allocator, io: Io) (Allocator.Error || I |
| 95 | 95 | .fallocate_punch_hole_unsupported = false, |
| 96 | 96 | }; |
| 97 | 97 | try mf.nodes.ensureUnusedCapacity(gpa, 1); |
| 98 | | const root_ni = mf.addNode(gpa, .{ .add_node = .{ |
| 98 | const root_ni = try mf.addNode(gpa, .{ .add_node = .{ |
| 99 | 99 | .size = size, |
| 100 | 100 | .alignment = mf.flags.block_size, |
| 101 | 101 | .fixed = true, |
| 102 | | } }) catch |err| switch (err) { |
| 103 | | error.MappedFileIo => return mf.io_err.?, |
| 104 | | else => |e| return e, |
| 105 | | }; |
| 102 | } }); |
| 106 | 103 | assert(root_ni == Node.Index.root); |
| 107 | 104 | try mf.ensureTotalCapacityInner(@intCast(size)); |
| 108 | 105 | return mf; |
| ... | ... | @@ -355,9 +352,7 @@ pub const Node = extern struct { |
| 355 | 352 | |
| 356 | 353 | pub const RealignNodeOptions = struct { |
| 357 | 354 | /// Shift the node backwards if possible |
| 358 | | try_backwards: bool = true, |
| 359 | | /// If `set, persists `new_alignment` as the node's alignment for future operations. |
| 360 | | set_alignment: bool = true, |
| 355 | try_backwards: bool = false, |
| 361 | 356 | }; |
| 362 | 357 | |
| 363 | 358 | /// Moves and expands a node such that its offset and size are aligned to `new_alignment`. |
| ... | ... | @@ -378,11 +373,7 @@ pub const Node = extern struct { |
| 378 | 373 | return error.MappedFileIo; |
| 379 | 374 | }, |
| 380 | 375 | }; |
| 381 | | var writers_it = mf.writers.first; |
| 382 | | while (writers_it) |writer_node| : (writers_it = writer_node.next) { |
| 383 | | const w: *Node.Writer = @fieldParentPtr("writer_node", writer_node); |
| 384 | | w.interface.buffer = w.ni.slice(mf); |
| 385 | | } |
| 376 | mf.updateWriters(); |
| 386 | 377 | } |
| 387 | 378 | |
| 388 | 379 | /// Shrink a node to `size`, exactly. |
| ... | ... | @@ -398,11 +389,7 @@ pub const Node = extern struct { |
| 398 | 389 | shift_next: bool, |
| 399 | 390 | ) Error!void { |
| 400 | 391 | try mf.shrinkNode(gpa, ni, size, shift_next); |
| 401 | | var writers_it = mf.writers.first; |
| 402 | | while (writers_it) |writer_node| : (writers_it = writer_node.next) { |
| 403 | | const w: *Node.Writer = @fieldParentPtr("writer_node", writer_node); |
| 404 | | w.interface.buffer = w.ni.slice(mf); |
| 405 | | } |
| 392 | mf.updateWriters(); |
| 406 | 393 | } |
| 407 | 394 | |
| 408 | 395 | pub fn writer(ni: Node.Index, mf: *MappedFile, gpa: std.mem.Allocator, w: *Writer) void { |
| ... | ... | @@ -562,34 +549,15 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct { |
| 562 | 549 | next: Node.Index = .none, |
| 563 | 550 | offset: u64 = 0, |
| 564 | 551 | add_node: AddNodeOptions, |
| 565 | | }) Error!Node.Index { |
| 552 | }) (Allocator.Error || Io.Cancelable || IoError)!Node.Index { |
| 566 | 553 | if (opts.add_node.moved or opts.add_node.resized) try mf.updates.ensureUnusedCapacity(gpa, 1); |
| 567 | 554 | mf.nodes_lock.assertUnlocked(); |
| 568 | | const offset = opts.add_node.alignment.forward(@intCast(opts.offset)); |
| 569 | | if (opts.parent != .none) { |
| 570 | | const new_end = offset + opts.add_node.size; |
| 571 | | switch (opts.next) { |
| 572 | | .none => { |
| 573 | | _, const parent_size = opts.parent.location(mf).resolve(mf); |
| 574 | | if (new_end > parent_size) |
| 575 | | try opts.parent.resize(mf, gpa, new_end +| new_end / growth_factor); |
| 576 | | }, |
| 577 | | else => |next_ni| { |
| 578 | | const next_offset, _ = next_ni.location(mf).resolve(mf); |
| 579 | | if (new_end > next_offset) |
| 580 | | try next_ni.realign(mf, gpa, opts.add_node.alignment, .{ |
| 581 | | .try_backwards = false, |
| 582 | | .set_alignment = false, |
| 583 | | }); |
| 584 | | }, |
| 585 | | } |
| 586 | | } |
| 587 | 555 | const location_tag: Node.Location.Tag, const location_payload: Node.Location.Payload = location: { |
| 588 | | if (std.math.cast(u32, offset)) |small_offset| break :location .{ .small, .{ |
| 556 | if (std.math.cast(u32, opts.offset)) |small_offset| break :location .{ .small, .{ |
| 589 | 557 | .small = .{ .offset = small_offset, .size = 0 }, |
| 590 | 558 | } }; |
| 591 | 559 | try mf.large.ensureUnusedCapacity(gpa, 2); |
| 592 | | defer mf.large.appendSliceAssumeCapacity(&.{ offset, 0 }); |
| 560 | defer mf.large.appendSliceAssumeCapacity(&.{ opts.offset, 0 }); |
| 593 | 561 | break :location .{ .large, .{ .large = .{ .index = mf.large.items.len } } }; |
| 594 | 562 | }; |
| 595 | 563 | const free_ni: Node.Index, const free_node = free: switch (mf.free_ni) { |
| ... | ... | @@ -616,7 +584,7 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct { |
| 616 | 584 | .last = .none, |
| 617 | 585 | .flags = .{ |
| 618 | 586 | .location_tag = location_tag, |
| 619 | | .alignment = opts.add_node.alignment, |
| 587 | .alignment = .@"1", |
| 620 | 588 | .fixed = opts.add_node.fixed, |
| 621 | 589 | .moved = true, |
| 622 | 590 | .resized = true, |
| ... | ... | @@ -627,13 +595,15 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct { |
| 627 | 595 | }; |
| 628 | 596 | |
| 629 | 597 | { |
| 630 | | try free_ni.resize(mf, gpa, opts.add_node.size); |
| 598 | try mf.realignNode(gpa, free_ni, opts.add_node.alignment, .{}); |
| 599 | try mf.resizeNode(gpa, free_ni, opts.add_node.size); |
| 631 | 600 | if (opts.add_node.moved or opts.add_node.resized) try mf.updates.ensureUnusedCapacity(gpa, 1); |
| 632 | 601 | free_node.flags.moved = false; |
| 633 | 602 | free_node.flags.resized = false; |
| 634 | 603 | } |
| 635 | 604 | if (opts.add_node.moved) free_ni.movedAssumeCapacity(mf); |
| 636 | 605 | if (opts.add_node.resized) free_ni.resizedAssumeCapacity(mf); |
| 606 | mf.updateWriters(); |
| 637 | 607 | return free_ni; |
| 638 | 608 | } |
| 639 | 609 | |
| ... | ... | @@ -658,7 +628,15 @@ pub fn addOnlyChildNode( |
| 658 | 628 | return mf.addNode(gpa, .{ |
| 659 | 629 | .parent = parent_ni, |
| 660 | 630 | .add_node = opts, |
| 661 | | }); |
| 631 | }) catch |err| switch (err) { |
| 632 | error.OutOfMemory, |
| 633 | error.Canceled, |
| 634 | => |e| return e, |
| 635 | else => |e| { |
| 636 | mf.io_err = e; |
| 637 | return error.MappedFileIo; |
| 638 | }, |
| 639 | }; |
| 662 | 640 | } |
| 663 | 641 | |
| 664 | 642 | pub fn addFirstChildNode( |
| ... | ... | @@ -673,7 +651,15 @@ pub fn addFirstChildNode( |
| 673 | 651 | .parent = parent_ni, |
| 674 | 652 | .next = parent.first, |
| 675 | 653 | .add_node = opts, |
| 676 | | }); |
| 654 | }) catch |err| switch (err) { |
| 655 | error.OutOfMemory, |
| 656 | error.Canceled, |
| 657 | => |e| return e, |
| 658 | else => |e| { |
| 659 | mf.io_err = e; |
| 660 | return error.MappedFileIo; |
| 661 | }, |
| 662 | }; |
| 677 | 663 | } |
| 678 | 664 | |
| 679 | 665 | pub fn addLastChildNode( |
| ... | ... | @@ -695,7 +681,15 @@ pub fn addLastChildNode( |
| 695 | 681 | }, |
| 696 | 682 | }, |
| 697 | 683 | .add_node = opts, |
| 698 | | }); |
| 684 | }) catch |err| switch (err) { |
| 685 | error.OutOfMemory, |
| 686 | error.Canceled, |
| 687 | => |e| return e, |
| 688 | else => |e| { |
| 689 | mf.io_err = e; |
| 690 | return error.MappedFileIo; |
| 691 | }, |
| 692 | }; |
| 699 | 693 | } |
| 700 | 694 | |
| 701 | 695 | pub fn addNodeAfter( |
| ... | ... | @@ -714,7 +708,15 @@ pub fn addNodeAfter( |
| 714 | 708 | .next = prev.next, |
| 715 | 709 | .offset = prev_offset + prev_size, |
| 716 | 710 | .add_node = opts, |
| 717 | | }); |
| 711 | }) catch |err| switch (err) { |
| 712 | error.OutOfMemory, |
| 713 | error.Canceled, |
| 714 | => |e| return e, |
| 715 | else => |e| { |
| 716 | mf.io_err = e; |
| 717 | return error.MappedFileIo; |
| 718 | }, |
| 719 | }; |
| 718 | 720 | } |
| 719 | 721 | |
| 720 | 722 | fn shrinkNode( |
| ... | ... | @@ -1043,26 +1045,20 @@ fn realignNode( |
| 1043 | 1045 | new_alignment: std.mem.Alignment, |
| 1044 | 1046 | opts: Node.Index.RealignNodeOptions, |
| 1045 | 1047 | ) (Allocator.Error || Io.Cancelable || IoError)!void { |
| 1046 | | assert(ni != Node.Index.root); // currently unsupported |
| 1047 | 1048 | mf.nodes_lock.assertUnlocked(); |
| 1048 | 1049 | |
| 1049 | 1050 | const node = ni.get(mf); |
| 1050 | | const old_offset, const size = node.location().resolve(mf); |
| 1051 | | |
| 1052 | | assert(new_alignment.compare(.gt, node.flags.alignment)); |
| 1053 | | |
| 1054 | | const prev_alignment = node.flags.alignment; |
| 1055 | | node.flags.alignment = new_alignment; |
| 1056 | | defer { |
| 1057 | | // alignment needs to be temporarily set for the resizes below |
| 1058 | | if (!opts.set_alignment) node.flags.alignment = prev_alignment; |
| 1051 | { |
| 1052 | const prev_alignment = node.flags.alignment; |
| 1053 | node.flags.alignment = new_alignment; |
| 1054 | if (new_alignment.compare(.lte, prev_alignment)) return; |
| 1059 | 1055 | } |
| 1060 | 1056 | |
| 1061 | | const new_size = node.flags.alignment.forward(@intCast(size)); |
| 1062 | | if (new_alignment.check(@intCast(old_offset))) { |
| 1063 | | if (new_size > size) try mf.resizeNode(gpa, ni, new_size); |
| 1064 | | return; |
| 1065 | | } |
| 1057 | const old_offset, const size = node.location().resolve(mf); |
| 1058 | if (ni == Node.Index.root) return mf.resizeNode(gpa, ni, size); |
| 1059 | |
| 1060 | const new_size = new_alignment.forward(@intCast(size)); |
| 1061 | if (new_alignment.check(@intCast(old_offset))) return mf.resizeNode(gpa, ni, new_size); |
| 1066 | 1062 | |
| 1067 | 1063 | _, const parent_size = node.parent.location(mf).resolve(mf); |
| 1068 | 1064 | const trailing_end = trailing_end: switch (node.next) { |
| ... | ... | @@ -1122,7 +1118,7 @@ fn realignNode( |
| 1122 | 1118 | |
| 1123 | 1119 | ni.setLocationAssumeCapacity(mf, forward_offset, new_size); |
| 1124 | 1120 | } else { |
| 1125 | | const temp_size = node.flags.alignment.forward(@intCast(new_size + 1)); |
| 1121 | const temp_size = new_alignment.forward(@intCast(new_size + 1)); |
| 1126 | 1122 | try mf.resizeNode(gpa, ni, temp_size); |
| 1127 | 1123 | const new_offset, _ = ni.location(mf).resolve(mf); |
| 1128 | 1124 | |
| ... | ... | @@ -1148,6 +1144,14 @@ fn realignNode( |
| 1148 | 1144 | } |
| 1149 | 1145 | } |
| 1150 | 1146 | |
| 1147 | fn updateWriters(mf: *MappedFile) void { |
| 1148 | var writers_it = mf.writers.first; |
| 1149 | while (writers_it) |writer_node| : (writers_it = writer_node.next) { |
| 1150 | const w: *Node.Writer = @fieldParentPtr("writer_node", writer_node); |
| 1151 | w.interface.buffer = w.ni.slice(mf); |
| 1152 | } |
| 1153 | } |
| 1154 | |
| 1151 | 1155 | fn moveRange(mf: *MappedFile, old_file_offset: u64, new_file_offset: u64, size: u64) (Io.Cancelable || IoError)!void { |
| 1152 | 1156 | // make a copy of this node at the new location |
| 1153 | 1157 | try mf.copyRange(old_file_offset, new_file_offset, size); |