tigerbeetle-node 0.11.8 → 0.11.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/dist/.client.node.sha256 +1 -1
  2. package/package.json +4 -3
  3. package/scripts/build_lib.sh +41 -0
  4. package/src/node.zig +1 -1
  5. package/src/tigerbeetle/scripts/validate_docs.sh +7 -1
  6. package/src/tigerbeetle/src/benchmark.zig +3 -3
  7. package/src/tigerbeetle/src/config.zig +31 -16
  8. package/src/tigerbeetle/src/constants.zig +48 -9
  9. package/src/tigerbeetle/src/ewah.zig +5 -5
  10. package/src/tigerbeetle/src/ewah_fuzz.zig +1 -1
  11. package/src/tigerbeetle/src/lsm/binary_search.zig +1 -1
  12. package/src/tigerbeetle/src/lsm/bloom_filter.zig +1 -1
  13. package/src/tigerbeetle/src/lsm/compaction.zig +34 -21
  14. package/src/tigerbeetle/src/lsm/forest_fuzz.zig +84 -104
  15. package/src/tigerbeetle/src/lsm/grid.zig +19 -13
  16. package/src/tigerbeetle/src/lsm/manifest_log.zig +8 -10
  17. package/src/tigerbeetle/src/lsm/manifest_log_fuzz.zig +18 -13
  18. package/src/tigerbeetle/src/lsm/merge_iterator.zig +1 -1
  19. package/src/tigerbeetle/src/lsm/segmented_array.zig +17 -17
  20. package/src/tigerbeetle/src/lsm/segmented_array_fuzz.zig +1 -1
  21. package/src/tigerbeetle/src/lsm/set_associative_cache.zig +1 -1
  22. package/src/tigerbeetle/src/lsm/table.zig +8 -20
  23. package/src/tigerbeetle/src/lsm/table_immutable.zig +1 -1
  24. package/src/tigerbeetle/src/lsm/table_iterator.zig +3 -3
  25. package/src/tigerbeetle/src/lsm/table_mutable.zig +14 -2
  26. package/src/tigerbeetle/src/lsm/test.zig +5 -4
  27. package/src/tigerbeetle/src/lsm/tree.zig +1 -2
  28. package/src/tigerbeetle/src/lsm/tree_fuzz.zig +85 -115
  29. package/src/tigerbeetle/src/message_bus.zig +4 -4
  30. package/src/tigerbeetle/src/message_pool.zig +7 -10
  31. package/src/tigerbeetle/src/ring_buffer.zig +22 -12
  32. package/src/tigerbeetle/src/simulator.zig +366 -239
  33. package/src/tigerbeetle/src/state_machine/auditor.zig +5 -5
  34. package/src/tigerbeetle/src/state_machine/workload.zig +3 -3
  35. package/src/tigerbeetle/src/state_machine.zig +190 -178
  36. package/src/tigerbeetle/src/{util.zig → stdx.zig} +2 -0
  37. package/src/tigerbeetle/src/storage.zig +13 -6
  38. package/src/tigerbeetle/src/{test → testing/cluster}/message_bus.zig +3 -3
  39. package/src/tigerbeetle/src/{test → testing/cluster}/network.zig +46 -22
  40. package/src/tigerbeetle/src/testing/cluster/state_checker.zig +169 -0
  41. package/src/tigerbeetle/src/testing/cluster/storage_checker.zig +202 -0
  42. package/src/tigerbeetle/src/testing/cluster.zig +443 -0
  43. package/src/tigerbeetle/src/{test → testing}/fuzz.zig +0 -0
  44. package/src/tigerbeetle/src/testing/hash_log.zig +66 -0
  45. package/src/tigerbeetle/src/{test → testing}/id.zig +0 -0
  46. package/src/tigerbeetle/src/testing/packet_simulator.zig +365 -0
  47. package/src/tigerbeetle/src/{test → testing}/priority_queue.zig +1 -1
  48. package/src/tigerbeetle/src/testing/reply_sequence.zig +139 -0
  49. package/src/tigerbeetle/src/{test → testing}/state_machine.zig +3 -1
  50. package/src/tigerbeetle/src/testing/storage.zig +757 -0
  51. package/src/tigerbeetle/src/{test → testing}/table.zig +21 -0
  52. package/src/tigerbeetle/src/{test → testing}/time.zig +0 -0
  53. package/src/tigerbeetle/src/tigerbeetle.zig +2 -0
  54. package/src/tigerbeetle/src/tracer.zig +3 -3
  55. package/src/tigerbeetle/src/unit_tests.zig +4 -4
  56. package/src/tigerbeetle/src/vopr.zig +2 -2
  57. package/src/tigerbeetle/src/vsr/client.zig +5 -2
  58. package/src/tigerbeetle/src/vsr/clock.zig +93 -53
  59. package/src/tigerbeetle/src/vsr/journal.zig +109 -98
  60. package/src/tigerbeetle/src/vsr/journal_format_fuzz.zig +2 -2
  61. package/src/tigerbeetle/src/vsr/replica.zig +1983 -1430
  62. package/src/tigerbeetle/src/vsr/replica_format.zig +13 -13
  63. package/src/tigerbeetle/src/vsr/superblock.zig +240 -142
  64. package/src/tigerbeetle/src/vsr/superblock_client_table.zig +7 -7
  65. package/src/tigerbeetle/src/vsr/superblock_free_set.zig +1 -1
  66. package/src/tigerbeetle/src/vsr/superblock_free_set_fuzz.zig +1 -1
  67. package/src/tigerbeetle/src/vsr/superblock_fuzz.zig +49 -14
  68. package/src/tigerbeetle/src/vsr/superblock_manifest.zig +38 -19
  69. package/src/tigerbeetle/src/vsr/superblock_quorums.zig +48 -48
  70. package/src/tigerbeetle/src/vsr/superblock_quorums_fuzz.zig +51 -51
  71. package/src/tigerbeetle/src/vsr.zig +99 -33
  72. package/src/tigerbeetle/src/demo.zig +0 -132
  73. package/src/tigerbeetle/src/demo_01_create_accounts.zig +0 -35
  74. package/src/tigerbeetle/src/demo_02_lookup_accounts.zig +0 -7
  75. package/src/tigerbeetle/src/demo_03_create_transfers.zig +0 -37
  76. package/src/tigerbeetle/src/demo_04_create_pending_transfers.zig +0 -61
  77. package/src/tigerbeetle/src/demo_05_post_pending_transfers.zig +0 -37
  78. package/src/tigerbeetle/src/demo_06_void_pending_transfers.zig +0 -24
  79. package/src/tigerbeetle/src/demo_07_lookup_transfers.zig +0 -7
  80. package/src/tigerbeetle/src/test/cluster.zig +0 -352
  81. package/src/tigerbeetle/src/test/conductor.zig +0 -366
  82. package/src/tigerbeetle/src/test/packet_simulator.zig +0 -398
  83. package/src/tigerbeetle/src/test/state_checker.zig +0 -169
  84. package/src/tigerbeetle/src/test/storage.zig +0 -864
  85. package/src/tigerbeetle/src/test/storage_checker.zig +0 -204
@@ -66,6 +66,13 @@ fn parse_data(comptime Data: type, tokens: *std.mem.TokenIterator(u8)) Data {
66
66
  }
67
67
  return data;
68
68
  },
69
+ .Array => |info| {
70
+ var values: Data = undefined;
71
+ for (values[0..]) |*value| {
72
+ value.* = parse_data(info.child, tokens);
73
+ }
74
+ return values;
75
+ },
69
76
  .Union => |info| {
70
77
  const variant_string = tokens.next().?;
71
78
  inline for (info.fields) |variant_field| {
@@ -209,6 +216,20 @@ test "struct (nested)" {
209
216
  );
210
217
  }
211
218
 
219
+ test "array" {
220
+ try test_parse(struct {
221
+ a: u32,
222
+ b: [2]u32,
223
+ c: u32,
224
+ }, &.{
225
+ .{ .a = 1, .b = .{ 2, 3 }, .c = 4 },
226
+ .{ .a = 5, .b = .{ 6, 7 }, .c = 8 },
227
+ },
228
+ \\ 1 2 3 4
229
+ \\ 5 6 7 8
230
+ );
231
+ }
232
+
212
233
  test "union" {
213
234
  try test_parse(union(enum) {
214
235
  a: struct { b: u8, c: i8 },
File without changes
@@ -95,6 +95,7 @@ pub const CreateAccountResult = enum(u32) {
95
95
  ok,
96
96
  linked_event_failed,
97
97
  linked_event_chain_open,
98
+ timestamp_must_be_zero,
98
99
 
99
100
  reserved_flag,
100
101
  reserved_field,
@@ -121,6 +122,7 @@ pub const CreateTransferResult = enum(u32) {
121
122
  ok,
122
123
  linked_event_failed,
123
124
  linked_event_chain_open,
125
+ timestamp_must_be_zero,
124
126
 
125
127
  reserved_flag,
126
128
  reserved_field,
@@ -61,7 +61,7 @@ const log = std.log.scoped(.tracer);
61
61
 
62
62
  const constants = @import("./constants.zig");
63
63
  const Time = @import("./time.zig").Time;
64
- const util = @import("util.zig");
64
+ const stdx = @import("stdx.zig");
65
65
 
66
66
  /// All strings in Event must be comptime constants to ensure that they live until after `tracer.deinit` is called.
67
67
  pub const Event = union(enum) {
@@ -411,7 +411,7 @@ const TracerTracy = struct {
411
411
  c.___tracy_fiber_enter(event_group.name());
412
412
  const name = std.fmt.bufPrint(&print_buffer, "{}", .{event}) catch name: {
413
413
  const dots = "...";
414
- util.copy_disjoint(.exact, u8, print_buffer[print_buffer.len - dots.len ..], dots);
414
+ stdx.copy_disjoint(.exact, u8, print_buffer[print_buffer.len - dots.len ..], dots);
415
415
  break :name &print_buffer;
416
416
  };
417
417
  // TODO The alloc_srcloc here is not free and should be unnecessary,
@@ -454,7 +454,7 @@ const TracerTracy = struct {
454
454
  args,
455
455
  ) catch message: {
456
456
  const dots = "...";
457
- util.copy_disjoint(.exact, u8, print_buffer[print_buffer.len - dots.len ..], dots);
457
+ stdx.copy_disjoint(.exact, u8, print_buffer[print_buffer.len - dots.len ..], dots);
458
458
  break :message &print_buffer;
459
459
  };
460
460
  c.___tracy_fiber_enter((EventGroup{ .main = {} }).name());
@@ -19,7 +19,7 @@ test {
19
19
 
20
20
  _ = @import("io.zig");
21
21
  _ = @import("ewah.zig");
22
- _ = @import("util.zig");
22
+ _ = @import("stdx.zig");
23
23
 
24
24
  _ = @import("clients/c/test.zig");
25
25
  _ = @import("clients/c/tb_client_header_test.zig");
@@ -29,9 +29,9 @@ test {
29
29
  _ = @import("lsm/manifest_level.zig");
30
30
  _ = @import("lsm/segmented_array.zig");
31
31
 
32
- _ = @import("test/id.zig");
33
- _ = @import("test/storage.zig");
34
- _ = @import("test/table.zig");
32
+ _ = @import("testing/id.zig");
33
+ _ = @import("testing/storage.zig");
34
+ _ = @import("testing/table.zig");
35
35
 
36
36
  _ = @import("clients/go/go_bindings_test.zig");
37
37
  _ = @import("clients/dotnet/dotnet_bindings_test.zig");
@@ -8,7 +8,7 @@ const log = std.log;
8
8
 
9
9
  const simulator = @import("simulator.zig");
10
10
  const vsr = @import("vsr.zig");
11
- const util = @import("util.zig");
11
+ const stdx = @import("stdx.zig");
12
12
 
13
13
  // TODO use DNS instead since hard-coding an IP address isn't ideal.
14
14
  const default_send_address = net.Address.initIp4([4]u8{ 65, 21, 207, 251 }, 5555);
@@ -375,7 +375,7 @@ fn create_report(allocator: mem.Allocator, bug: Bug, seed: u64) Report {
375
375
 
376
376
  var hash: [32]u8 = undefined;
377
377
  std.crypto.hash.sha2.Sha256.hash(std.mem.asBytes(&message)[@sizeOf(u128)..45], hash[0..], .{});
378
- util.copy_disjoint(.exact, u8, message.checksum[0..], hash[0..message.checksum.len]);
378
+ stdx.copy_disjoint(.exact, u8, message.checksum[0..], hash[0..message.checksum.len]);
379
379
 
380
380
  return message;
381
381
  }
@@ -87,7 +87,6 @@ pub fn Client(comptime StateMachine_: type, comptime MessageBus: type) type {
87
87
  on_reply_context: ?*anyopaque = null,
88
88
  /// Used for testing. Called for replies to all operations (including `register`).
89
89
  on_reply_callback: ?fn (
90
- context: ?*anyopaque,
91
90
  client: *Self,
92
91
  request: *Message,
93
92
  reply: *Message,
@@ -194,6 +193,10 @@ pub fn Client(comptime StateMachine_: type, comptime MessageBus: type) type {
194
193
  message: *Message,
195
194
  message_body_size: usize,
196
195
  ) void {
196
+ assert(operation != .reserved);
197
+ assert(operation != .root);
198
+ assert(operation != .register);
199
+
197
200
  self.register();
198
201
  assert(self.request_number > 0);
199
202
 
@@ -367,7 +370,7 @@ pub fn Client(comptime StateMachine_: type, comptime MessageBus: type) type {
367
370
  }
368
371
 
369
372
  if (self.on_reply_callback) |on_reply_callback| {
370
- on_reply_callback(self.on_reply_context, self, inflight.message, reply);
373
+ on_reply_callback(self, inflight.message, reply);
371
374
  }
372
375
 
373
376
  if (inflight.callback) |callback| {
@@ -453,33 +453,35 @@ pub fn Clock(comptime Time: type) type {
453
453
  }
454
454
 
455
455
  const testing = std.testing;
456
- const OffsetType = @import("../test/time.zig").OffsetType;
457
- const DeterministicTime = @import("../test/time.zig").Time;
456
+ const OffsetType = @import("../testing/time.zig").OffsetType;
457
+ const DeterministicTime = @import("../testing/time.zig").Time;
458
458
  const DeterministicClock = Clock(DeterministicTime);
459
459
 
460
460
  const ClockUnitTestContainer = struct {
461
461
  const Self = @This();
462
+ time: DeterministicTime,
462
463
  clock: DeterministicClock,
463
464
  rtt: u64 = 300 * std.time.ns_per_ms,
464
465
  owd: u64 = 150 * std.time.ns_per_ms,
465
466
  learn_interval: u64 = 5,
466
467
 
467
468
  pub fn init(
469
+ self: *Self,
468
470
  allocator: std.mem.Allocator,
469
471
  offset_type: OffsetType,
470
472
  offset_coefficient_A: i64,
471
473
  offset_coefficient_B: i64,
472
- ) !Self {
473
- const time: DeterministicTime = .{
474
- .resolution = std.time.ns_per_s / 2,
475
- .offset_type = offset_type,
476
- .offset_coefficient_A = offset_coefficient_A,
477
- .offset_coefficient_B = offset_coefficient_B,
478
- };
479
- const self: Self = .{
480
- .clock = try DeterministicClock.init(allocator, 3, 0, time),
474
+ ) !void {
475
+ // TODO(Zig) Use @returnAddress() when available.
476
+ self.* = .{
477
+ .time = .{
478
+ .resolution = std.time.ns_per_s / 2,
479
+ .offset_type = offset_type,
480
+ .offset_coefficient_A = offset_coefficient_A,
481
+ .offset_coefficient_B = offset_coefficient_B,
482
+ },
483
+ .clock = try DeterministicClock.init(allocator, 3, 0, &self.time),
481
484
  };
482
- return self;
483
485
  }
484
486
 
485
487
  pub fn run_till_tick(self: *Self, tick: u64) void {
@@ -567,9 +569,10 @@ test "ideal clocks get clamped to cluster time" {
567
569
  std.testing.log_level = .err;
568
570
  var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
569
571
  defer arena.deinit();
570
- const allocator = &arena.allocator;
572
+ const allocator = arena.allocator();
571
573
 
572
- var ideal_constant_drift_clock = try ClockUnitTestContainer.init(
574
+ var ideal_constant_drift_clock: ClockUnitTestContainer = undefined;
575
+ try ideal_constant_drift_clock.init(
573
576
  allocator,
574
577
  OffsetType.linear,
575
578
  std.time.ns_per_ms, // loses 1ms per tick
@@ -585,7 +588,8 @@ test "ideal clocks get clamped to cluster time" {
585
588
  );
586
589
  }
587
590
 
588
- var ideal_periodic_drift_clock = try ClockUnitTestContainer.init(
591
+ var ideal_periodic_drift_clock: ClockUnitTestContainer = undefined;
592
+ try ideal_periodic_drift_clock.init(
589
593
  allocator,
590
594
  OffsetType.periodic,
591
595
  std.time.ns_per_s, // loses up to 1s
@@ -602,7 +606,8 @@ test "ideal clocks get clamped to cluster time" {
602
606
  );
603
607
  }
604
608
 
605
- var ideal_jumping_clock = try ClockUnitTestContainer.init(
609
+ var ideal_jumping_clock: ClockUnitTestContainer = undefined;
610
+ try ideal_jumping_clock.init(
606
611
  allocator,
607
612
  OffsetType.step,
608
613
  -5 * std.time.ns_per_day, // jumps 5 days ahead.
@@ -619,9 +624,10 @@ test "ideal clocks get clamped to cluster time" {
619
624
  }
620
625
  }
621
626
 
622
- const PacketSimulatorOptions = @import("../test/packet_simulator.zig").PacketSimulatorOptions;
623
- const PacketSimulator = @import("../test/packet_simulator.zig").PacketSimulator;
624
- const Path = @import("../test/packet_simulator.zig").Path;
627
+ const PacketSimulatorOptions = @import("../testing/packet_simulator.zig").PacketSimulatorOptions;
628
+ const PacketSimulatorType = @import("../testing/packet_simulator.zig").PacketSimulatorType;
629
+ const Path = @import("../testing/packet_simulator.zig").Path;
630
+ const Command = @import("../vsr.zig").Command;
625
631
  const ClockSimulator = struct {
626
632
  const Packet = struct {
627
633
  m0: u64,
@@ -629,9 +635,8 @@ const ClockSimulator = struct {
629
635
  clock_simulator: *ClockSimulator,
630
636
 
631
637
  /// PacketSimulator requires this function, but we don't actually have anything to deinit.
632
- pub fn deinit(packet: *const Packet, path: Path) void {
638
+ pub fn deinit(packet: *const Packet) void {
633
639
  _ = packet;
634
- _ = path;
635
640
  }
636
641
  };
637
642
 
@@ -644,39 +649,62 @@ const ClockSimulator = struct {
644
649
  allocator: std.mem.Allocator,
645
650
  options: Options,
646
651
  ticks: u64 = 0,
647
- network: PacketSimulator(Packet),
652
+ network: PacketSimulatorType(Packet),
653
+ times: []DeterministicTime,
648
654
  clocks: []DeterministicClock,
649
655
  prng: std.rand.DefaultPrng,
650
656
 
651
657
  pub fn init(allocator: std.mem.Allocator, options: Options) !ClockSimulator {
652
- var self = ClockSimulator{
653
- .allocator = allocator,
654
- .options = options,
655
- .network = try PacketSimulator(Packet).init(allocator, options.network_options),
656
- .clocks = try allocator.alloc(DeterministicClock, options.clock_count),
657
- .prng = std.rand.DefaultPrng.init(options.network_options.seed),
658
- };
658
+ var network = try PacketSimulatorType(Packet).init(allocator, options.network_options);
659
+ errdefer network.deinit(allocator);
659
660
 
660
- for (self.clocks) |*clock, index| {
661
- clock.* = try self.create_clock(@intCast(u8, index));
662
- }
661
+ var times = try allocator.alloc(DeterministicTime, options.clock_count);
662
+ errdefer allocator.free(times);
663
663
 
664
- return self;
665
- }
664
+ var clocks = try allocator.alloc(DeterministicClock, options.clock_count);
665
+ errdefer allocator.free(clocks);
666
+
667
+ var prng = std.rand.DefaultPrng.init(options.network_options.seed);
668
+
669
+ for (clocks) |*clock, replica| {
670
+ errdefer for (clocks[0..replica]) |*c| c.deinit(allocator);
671
+
672
+ const amplitude = prng.random().intRangeAtMost(i64, -10, 10) * std.time.ns_per_s;
673
+ const phase = prng.random().intRangeAtMost(i64, 100, 1000) +
674
+ @floatToInt(i64, prng.random().floatNorm(f64) * 50);
675
+ times[replica] = .{
676
+ .resolution = std.time.ns_per_s / 2, // delta_t = 0.5s
677
+ .offset_type = OffsetType.non_ideal,
678
+ .offset_coefficient_A = amplitude,
679
+ .offset_coefficient_B = phase,
680
+ .offset_coefficient_C = 10,
681
+ };
666
682
 
667
- fn create_clock(self: *ClockSimulator, replica: u8) !DeterministicClock {
668
- const amplitude = self.prng.random.intRangeAtMost(i64, -10, 10) * std.time.ns_per_s;
669
- const phase = self.prng.random.intRangeAtMost(i64, 100, 1000) +
670
- @floatToInt(i64, self.prng.random.floatNorm(f64) * 50);
671
- const time: DeterministicTime = .{
672
- .resolution = std.time.ns_per_s / 2, // delta_t = 0.5s
673
- .offset_type = OffsetType.non_ideal,
674
- .offset_coefficient_A = amplitude,
675
- .offset_coefficient_B = phase,
676
- .offset_coefficient_C = 10,
683
+ clock.* = try DeterministicClock.init(
684
+ allocator,
685
+ options.clock_count,
686
+ @intCast(u8, replica),
687
+ &times[replica],
688
+ );
689
+ errdefer clock.deinit(allocator);
690
+ }
691
+ errdefer for (clocks) |*clock| clock.deinit(allocator);
692
+
693
+ return ClockSimulator{
694
+ .allocator = allocator,
695
+ .options = options,
696
+ .network = network,
697
+ .times = times,
698
+ .clocks = clocks,
699
+ .prng = prng,
677
700
  };
701
+ }
678
702
 
679
- return try DeterministicClock.init(self.allocator, self.options.clock_count, replica, time);
703
+ pub fn deinit(self: *ClockSimulator) void {
704
+ for (self.clocks) |*clock| clock.deinit(self.allocator);
705
+ self.allocator.free(self.clocks);
706
+ self.allocator.free(self.times);
707
+ self.network.deinit(self.allocator);
680
708
  }
681
709
 
682
710
  pub fn tick(self: *ClockSimulator) void {
@@ -738,24 +766,29 @@ const ClockSimulator = struct {
738
766
  }
739
767
  };
740
768
 
741
- test "fuzz test" {
769
+ test "clock: fuzz test" {
742
770
  std.testing.log_level = .err; // silence all clock logs
743
- var arena_allocator = std.heap.ArenaAllocator.init(std.heap.page_allocator);
744
- defer arena_allocator.deinit();
745
- const allocator = &arena_allocator.allocator;
771
+
746
772
  const ticks_max: u64 = 1_000_000;
747
773
  const clock_count: u8 = 3;
748
- const SystemTime = @import("../test/time.zig").Time;
749
- var system_time = SystemTime{};
774
+ const SystemTime = @import("../testing/time.zig").Time;
775
+ var system_time = SystemTime{
776
+ .resolution = constants.tick_ms * std.time.ns_per_ms,
777
+ .offset_type = .linear,
778
+ .offset_coefficient_A = 0,
779
+ .offset_coefficient_B = 0,
780
+ };
750
781
  var seed = @intCast(u64, system_time.realtime());
751
782
  var min_sync_error: u64 = 1_000_000_000;
752
783
  var max_sync_error: u64 = 0;
753
784
  var max_clock_offset: u64 = 0;
754
785
  var min_clock_offset: u64 = 1_000_000_000;
755
- var simulator = try ClockSimulator.init(allocator, .{
786
+ var simulator = try ClockSimulator.init(std.testing.allocator, .{
756
787
  .network_options = .{
757
- .node_count = clock_count,
788
+ .replica_count = 3,
789
+ .client_count = 0,
758
790
  .seed = seed,
791
+
759
792
  .one_way_delay_mean = 25,
760
793
  .one_way_delay_min = 10,
761
794
  .packet_loss_probability = 10,
@@ -763,10 +796,17 @@ test "fuzz test" {
763
796
  .path_clog_duration_mean = 200,
764
797
  .path_clog_probability = 2,
765
798
  .packet_replay_probability = 2,
799
+
800
+ .partition_mode = .isolate_single,
801
+ .partition_probability = 25,
802
+ .unpartition_probability = 5,
803
+ .partition_stability = 100,
804
+ .unpartition_stability = 10,
766
805
  },
767
806
  .clock_count = clock_count,
768
807
  .ping_timeout = 20,
769
808
  });
809
+ defer simulator.deinit();
770
810
 
771
811
  var clock_ticks_without_synchronization = [_]u32{0} ** clock_count;
772
812
  while (simulator.ticks < ticks_max) {