| ... | @@ -95,14 +95,11 @@ pub fn init(file: Io.File, gpa: std.mem.Allocator, io: Io) (Allocator.Error || I | ... | @@ -95,14 +95,11 @@ pub fn init(file: Io.File, gpa: std.mem.Allocator, io: Io) (Allocator.Error || I |
| 95 | .fallocate_punch_hole_unsupported = false, | 95 | .fallocate_punch_hole_unsupported = false, |
| 96 | }; | 96 | }; |
| 97 | try mf.nodes.ensureUnusedCapacity(gpa, 1); | 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 | .size = size, | 99 | .size = size, |
| 100 | .alignment = mf.flags.block_size, | 100 | .alignment = mf.flags.block_size, |
| 101 | .fixed = true, | 101 | .fixed = true, |
| 102 | } }) catch |err| switch (err) { | 102 | } }); |
| 103 | error.MappedFileIo => return mf.io_err.?, | | |
| 104 | else => |e| return e, | | |
| 105 | }; | | |
| 106 | assert(root_ni == Node.Index.root); | 103 | assert(root_ni == Node.Index.root); |
| 107 | try mf.ensureTotalCapacityInner(@intCast(size)); | 104 | try mf.ensureTotalCapacityInner(@intCast(size)); |
| 108 | return mf; | 105 | return mf; |
| ... | @@ -355,9 +352,7 @@ pub const Node = extern struct { | ... | @@ -355,9 +352,7 @@ pub const Node = extern struct { |
| 355 | | 352 | |
| 356 | pub const RealignNodeOptions = struct { | 353 | pub const RealignNodeOptions = struct { |
| 357 | /// Shift the node backwards if possible | 354 | /// Shift the node backwards if possible |
| 358 | try_backwards: bool = true, | 355 | try_backwards: bool = false, |
| 359 | /// If `set, persists `new_alignment` as the node's alignment for future operations. | | |
| 360 | set_alignment: bool = true, | | |
| 361 | }; | 356 | }; |
| 362 | | 357 | |
| 363 | /// Moves and expands a node such that its offset and size are aligned to `new_alignment`. | 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,11 +373,7 @@ pub const Node = extern struct { |
| 378 | return error.MappedFileIo; | 373 | return error.MappedFileIo; |
| 379 | }, | 374 | }, |
| 380 | }; | 375 | }; |
| 381 | var writers_it = mf.writers.first; | 376 | mf.updateWriters(); |
| 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 | } | | |
| 386 | } | 377 | } |
| 387 | | 378 | |
| 388 | /// Shrink a node to `size`, exactly. | 379 | /// Shrink a node to `size`, exactly. |
| ... | @@ -398,11 +389,7 @@ pub const Node = extern struct { | ... | @@ -398,11 +389,7 @@ pub const Node = extern struct { |
| 398 | shift_next: bool, | 389 | shift_next: bool, |
| 399 | ) Error!void { | 390 | ) Error!void { |
| 400 | try mf.shrinkNode(gpa, ni, size, shift_next); | 391 | try mf.shrinkNode(gpa, ni, size, shift_next); |
| 401 | var writers_it = mf.writers.first; | 392 | mf.updateWriters(); |
| 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 | } | | |
| 406 | } | 393 | } |
| 407 | | 394 | |
| 408 | pub fn writer(ni: Node.Index, mf: *MappedFile, gpa: std.mem.Allocator, w: *Writer) void { | 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,34 +549,15 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct { |
| 562 | next: Node.Index = .none, | 549 | next: Node.Index = .none, |
| 563 | offset: u64 = 0, | 550 | offset: u64 = 0, |
| 564 | add_node: AddNodeOptions, | 551 | add_node: AddNodeOptions, |
| 565 | }) Error!Node.Index { | 552 | }) (Allocator.Error || Io.Cancelable || IoError)!Node.Index { |
| 566 | if (opts.add_node.moved or opts.add_node.resized) try mf.updates.ensureUnusedCapacity(gpa, 1); | 553 | if (opts.add_node.moved or opts.add_node.resized) try mf.updates.ensureUnusedCapacity(gpa, 1); |
| 567 | mf.nodes_lock.assertUnlocked(); | 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 | const location_tag: Node.Location.Tag, const location_payload: Node.Location.Payload = location: { | 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 | .small = .{ .offset = small_offset, .size = 0 }, | 557 | .small = .{ .offset = small_offset, .size = 0 }, |
| 590 | } }; | 558 | } }; |
| 591 | try mf.large.ensureUnusedCapacity(gpa, 2); | 559 | try mf.large.ensureUnusedCapacity(gpa, 2); |
| 592 | defer mf.large.appendSliceAssumeCapacity(&.{ offset, 0 }); | 560 | defer mf.large.appendSliceAssumeCapacity(&.{ opts.offset, 0 }); |
| 593 | break :location .{ .large, .{ .large = .{ .index = mf.large.items.len } } }; | 561 | break :location .{ .large, .{ .large = .{ .index = mf.large.items.len } } }; |
| 594 | }; | 562 | }; |
| 595 | const free_ni: Node.Index, const free_node = free: switch (mf.free_ni) { | 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,7 +584,7 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct { |
| 616 | .last = .none, | 584 | .last = .none, |
| 617 | .flags = .{ | 585 | .flags = .{ |
| 618 | .location_tag = location_tag, | 586 | .location_tag = location_tag, |
| 619 | .alignment = opts.add_node.alignment, | 587 | .alignment = .@"1", |
| 620 | .fixed = opts.add_node.fixed, | 588 | .fixed = opts.add_node.fixed, |
| 621 | .moved = true, | 589 | .moved = true, |
| 622 | .resized = true, | 590 | .resized = true, |
| ... | @@ -627,13 +595,15 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct { | ... | @@ -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 | if (opts.add_node.moved or opts.add_node.resized) try mf.updates.ensureUnusedCapacity(gpa, 1); | 600 | if (opts.add_node.moved or opts.add_node.resized) try mf.updates.ensureUnusedCapacity(gpa, 1); |
| 632 | free_node.flags.moved = false; | 601 | free_node.flags.moved = false; |
| 633 | free_node.flags.resized = false; | 602 | free_node.flags.resized = false; |
| 634 | } | 603 | } |
| 635 | if (opts.add_node.moved) free_ni.movedAssumeCapacity(mf); | 604 | if (opts.add_node.moved) free_ni.movedAssumeCapacity(mf); |
| 636 | if (opts.add_node.resized) free_ni.resizedAssumeCapacity(mf); | 605 | if (opts.add_node.resized) free_ni.resizedAssumeCapacity(mf); |
| | 606 | mf.updateWriters(); |
| 637 | return free_ni; | 607 | return free_ni; |
| 638 | } | 608 | } |
| 639 | | 609 | |
| ... | @@ -658,7 +628,15 @@ pub fn addOnlyChildNode( | ... | @@ -658,7 +628,15 @@ pub fn addOnlyChildNode( |
| 658 | return mf.addNode(gpa, .{ | 628 | return mf.addNode(gpa, .{ |
| 659 | .parent = parent_ni, | 629 | .parent = parent_ni, |
| 660 | .add_node = opts, | 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 | pub fn addFirstChildNode( | 642 | pub fn addFirstChildNode( |
| ... | @@ -673,7 +651,15 @@ pub fn addFirstChildNode( | ... | @@ -673,7 +651,15 @@ pub fn addFirstChildNode( |
| 673 | .parent = parent_ni, | 651 | .parent = parent_ni, |
| 674 | .next = parent.first, | 652 | .next = parent.first, |
| 675 | .add_node = opts, | 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 | pub fn addLastChildNode( | 665 | pub fn addLastChildNode( |
| ... | @@ -695,7 +681,15 @@ pub fn addLastChildNode( | ... | @@ -695,7 +681,15 @@ pub fn addLastChildNode( |
| 695 | }, | 681 | }, |
| 696 | }, | 682 | }, |
| 697 | .add_node = opts, | 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 | pub fn addNodeAfter( | 695 | pub fn addNodeAfter( |
| ... | @@ -714,7 +708,15 @@ pub fn addNodeAfter( | ... | @@ -714,7 +708,15 @@ pub fn addNodeAfter( |
| 714 | .next = prev.next, | 708 | .next = prev.next, |
| 715 | .offset = prev_offset + prev_size, | 709 | .offset = prev_offset + prev_size, |
| 716 | .add_node = opts, | 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 | fn shrinkNode( | 722 | fn shrinkNode( |
| ... | @@ -1043,26 +1045,20 @@ fn realignNode( | ... | @@ -1043,26 +1045,20 @@ fn realignNode( |
| 1043 | new_alignment: std.mem.Alignment, | 1045 | new_alignment: std.mem.Alignment, |
| 1044 | opts: Node.Index.RealignNodeOptions, | 1046 | opts: Node.Index.RealignNodeOptions, |
| 1045 | ) (Allocator.Error || Io.Cancelable || IoError)!void { | 1047 | ) (Allocator.Error || Io.Cancelable || IoError)!void { |
| 1046 | assert(ni != Node.Index.root); // currently unsupported | | |
| 1047 | mf.nodes_lock.assertUnlocked(); | 1048 | mf.nodes_lock.assertUnlocked(); |
| 1048 | | 1049 | |
| 1049 | const node = ni.get(mf); | 1050 | const node = ni.get(mf); |
| 1050 | const old_offset, const size = node.location().resolve(mf); | 1051 | { |
| 1051 | | 1052 | const prev_alignment = node.flags.alignment; |
| 1052 | assert(new_alignment.compare(.gt, node.flags.alignment)); | 1053 | node.flags.alignment = new_alignment; |
| 1053 | | 1054 | if (new_alignment.compare(.lte, prev_alignment)) return; |
| 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; | | |
| 1059 | } | 1055 | } |
| 1060 | | 1056 | |
| 1061 | const new_size = node.flags.alignment.forward(@intCast(size)); | 1057 | const old_offset, const size = node.location().resolve(mf); |
| 1062 | if (new_alignment.check(@intCast(old_offset))) { | 1058 | if (ni == Node.Index.root) return mf.resizeNode(gpa, ni, size); |
| 1063 | if (new_size > size) try mf.resizeNode(gpa, ni, new_size); | 1059 | |
| 1064 | return; | 1060 | const new_size = new_alignment.forward(@intCast(size)); |
| 1065 | } | 1061 | if (new_alignment.check(@intCast(old_offset))) return mf.resizeNode(gpa, ni, new_size); |
| 1066 | | 1062 | |
| 1067 | _, const parent_size = node.parent.location(mf).resolve(mf); | 1063 | _, const parent_size = node.parent.location(mf).resolve(mf); |
| 1068 | const trailing_end = trailing_end: switch (node.next) { | 1064 | const trailing_end = trailing_end: switch (node.next) { |
| ... | @@ -1122,7 +1118,7 @@ fn realignNode( | ... | @@ -1122,7 +1118,7 @@ fn realignNode( |
| 1122 | | 1118 | |
| 1123 | ni.setLocationAssumeCapacity(mf, forward_offset, new_size); | 1119 | ni.setLocationAssumeCapacity(mf, forward_offset, new_size); |
| 1124 | } else { | 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 | try mf.resizeNode(gpa, ni, temp_size); | 1122 | try mf.resizeNode(gpa, ni, temp_size); |
| 1127 | const new_offset, _ = ni.location(mf).resolve(mf); | 1123 | const new_offset, _ = ni.location(mf).resolve(mf); |
| 1128 | | 1124 | |
| ... | @@ -1148,6 +1144,14 @@ fn realignNode( | ... | @@ -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 | fn moveRange(mf: *MappedFile, old_file_offset: u64, new_file_offset: u64, size: u64) (Io.Cancelable || IoError)!void { | 1155 | fn moveRange(mf: *MappedFile, old_file_offset: u64, new_file_offset: u64, size: u64) (Io.Cancelable || IoError)!void { |
| 1152 | // make a copy of this node at the new location | 1156 | // make a copy of this node at the new location |
| 1153 | try mf.copyRange(old_file_offset, new_file_offset, size); | 1157 | try mf.copyRange(old_file_offset, new_file_offset, size); |