tigerbeetle-node 0.11.13 → 0.12.0
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.
- package/dist/bin/aarch64-linux-gnu/client.node +0 -0
- package/dist/bin/aarch64-linux-musl/client.node +0 -0
- package/dist/bin/aarch64-macos/client.node +0 -0
- package/dist/bin/x86_64-linux-gnu/client.node +0 -0
- package/dist/bin/x86_64-linux-musl/client.node +0 -0
- package/dist/bin/x86_64-macos/client.node +0 -0
- package/dist/index.js +33 -1
- package/dist/index.js.map +1 -1
- package/package-lock.json +66 -0
- package/package.json +6 -16
- package/src/index.ts +56 -1
- package/src/node.zig +9 -9
- package/dist/.client.node.sha256 +0 -1
- package/scripts/build_lib.sh +0 -61
- package/scripts/download_node_headers.sh +0 -32
- package/src/tigerbeetle/scripts/benchmark.bat +0 -55
- package/src/tigerbeetle/scripts/benchmark.sh +0 -66
- package/src/tigerbeetle/scripts/confirm_image.sh +0 -44
- package/src/tigerbeetle/scripts/fail_on_diff.sh +0 -9
- package/src/tigerbeetle/scripts/fuzz_loop.sh +0 -15
- package/src/tigerbeetle/scripts/fuzz_loop_hash_log.sh +0 -12
- package/src/tigerbeetle/scripts/fuzz_unique_errors.sh +0 -7
- package/src/tigerbeetle/scripts/install.bat +0 -7
- package/src/tigerbeetle/scripts/install.sh +0 -21
- package/src/tigerbeetle/scripts/install_zig.bat +0 -113
- package/src/tigerbeetle/scripts/install_zig.sh +0 -90
- package/src/tigerbeetle/scripts/lint.zig +0 -199
- package/src/tigerbeetle/scripts/pre-commit.sh +0 -9
- package/src/tigerbeetle/scripts/scripts/benchmark.bat +0 -55
- package/src/tigerbeetle/scripts/scripts/benchmark.sh +0 -66
- package/src/tigerbeetle/scripts/scripts/confirm_image.sh +0 -44
- package/src/tigerbeetle/scripts/scripts/fail_on_diff.sh +0 -9
- package/src/tigerbeetle/scripts/scripts/fuzz_loop.sh +0 -15
- package/src/tigerbeetle/scripts/scripts/fuzz_loop_hash_log.sh +0 -12
- package/src/tigerbeetle/scripts/scripts/fuzz_unique_errors.sh +0 -7
- package/src/tigerbeetle/scripts/scripts/install.bat +0 -7
- package/src/tigerbeetle/scripts/scripts/install.sh +0 -21
- package/src/tigerbeetle/scripts/scripts/install_zig.bat +0 -113
- package/src/tigerbeetle/scripts/scripts/install_zig.sh +0 -90
- package/src/tigerbeetle/scripts/scripts/lint.zig +0 -199
- package/src/tigerbeetle/scripts/scripts/pre-commit.sh +0 -9
- package/src/tigerbeetle/scripts/scripts/shellcheck.sh +0 -5
- package/src/tigerbeetle/scripts/scripts/tests_on_alpine.sh +0 -10
- package/src/tigerbeetle/scripts/scripts/tests_on_ubuntu.sh +0 -14
- package/src/tigerbeetle/scripts/scripts/upgrade_ubuntu_kernel.sh +0 -48
- package/src/tigerbeetle/scripts/scripts/validate_docs.sh +0 -23
- package/src/tigerbeetle/scripts/scripts/vr_state_enumerate +0 -46
- package/src/tigerbeetle/scripts/shellcheck.sh +0 -5
- package/src/tigerbeetle/scripts/tests_on_alpine.sh +0 -10
- package/src/tigerbeetle/scripts/tests_on_ubuntu.sh +0 -14
- package/src/tigerbeetle/scripts/upgrade_ubuntu_kernel.sh +0 -48
- package/src/tigerbeetle/scripts/validate_docs.sh +0 -23
- package/src/tigerbeetle/scripts/vr_state_enumerate +0 -46
- package/src/tigerbeetle/src/benchmark.zig +0 -336
- package/src/tigerbeetle/src/config.zig +0 -233
- package/src/tigerbeetle/src/constants.zig +0 -428
- package/src/tigerbeetle/src/ewah.zig +0 -286
- package/src/tigerbeetle/src/ewah_benchmark.zig +0 -120
- package/src/tigerbeetle/src/ewah_fuzz.zig +0 -130
- package/src/tigerbeetle/src/fifo.zig +0 -120
- package/src/tigerbeetle/src/io/benchmark.zig +0 -213
- package/src/tigerbeetle/src/io/darwin.zig +0 -814
- package/src/tigerbeetle/src/io/linux.zig +0 -1071
- package/src/tigerbeetle/src/io/test.zig +0 -643
- package/src/tigerbeetle/src/io/windows.zig +0 -1183
- package/src/tigerbeetle/src/io.zig +0 -34
- package/src/tigerbeetle/src/iops.zig +0 -107
- package/src/tigerbeetle/src/lsm/README.md +0 -308
- package/src/tigerbeetle/src/lsm/binary_search.zig +0 -341
- package/src/tigerbeetle/src/lsm/bloom_filter.zig +0 -125
- package/src/tigerbeetle/src/lsm/compaction.zig +0 -603
- package/src/tigerbeetle/src/lsm/composite_key.zig +0 -77
- package/src/tigerbeetle/src/lsm/direction.zig +0 -11
- package/src/tigerbeetle/src/lsm/eytzinger.zig +0 -587
- package/src/tigerbeetle/src/lsm/eytzinger_benchmark.zig +0 -330
- package/src/tigerbeetle/src/lsm/forest.zig +0 -205
- package/src/tigerbeetle/src/lsm/forest_fuzz.zig +0 -450
- package/src/tigerbeetle/src/lsm/grid.zig +0 -573
- package/src/tigerbeetle/src/lsm/groove.zig +0 -1036
- package/src/tigerbeetle/src/lsm/k_way_merge.zig +0 -474
- package/src/tigerbeetle/src/lsm/level_iterator.zig +0 -332
- package/src/tigerbeetle/src/lsm/manifest.zig +0 -617
- package/src/tigerbeetle/src/lsm/manifest_level.zig +0 -878
- package/src/tigerbeetle/src/lsm/manifest_log.zig +0 -789
- package/src/tigerbeetle/src/lsm/manifest_log_fuzz.zig +0 -691
- package/src/tigerbeetle/src/lsm/merge_iterator.zig +0 -106
- package/src/tigerbeetle/src/lsm/node_pool.zig +0 -235
- package/src/tigerbeetle/src/lsm/posted_groove.zig +0 -381
- package/src/tigerbeetle/src/lsm/segmented_array.zig +0 -1329
- package/src/tigerbeetle/src/lsm/segmented_array_benchmark.zig +0 -148
- package/src/tigerbeetle/src/lsm/segmented_array_fuzz.zig +0 -9
- package/src/tigerbeetle/src/lsm/set_associative_cache.zig +0 -850
- package/src/tigerbeetle/src/lsm/table.zig +0 -1009
- package/src/tigerbeetle/src/lsm/table_immutable.zig +0 -192
- package/src/tigerbeetle/src/lsm/table_iterator.zig +0 -340
- package/src/tigerbeetle/src/lsm/table_mutable.zig +0 -203
- package/src/tigerbeetle/src/lsm/test.zig +0 -439
- package/src/tigerbeetle/src/lsm/tree.zig +0 -1169
- package/src/tigerbeetle/src/lsm/tree_fuzz.zig +0 -479
- package/src/tigerbeetle/src/message_bus.zig +0 -1013
- package/src/tigerbeetle/src/message_pool.zig +0 -156
- package/src/tigerbeetle/src/ring_buffer.zig +0 -399
- package/src/tigerbeetle/src/simulator.zig +0 -580
- package/src/tigerbeetle/src/state_machine/auditor.zig +0 -578
- package/src/tigerbeetle/src/state_machine/workload.zig +0 -883
- package/src/tigerbeetle/src/state_machine.zig +0 -2099
- package/src/tigerbeetle/src/static_allocator.zig +0 -65
- package/src/tigerbeetle/src/stdx.zig +0 -171
- package/src/tigerbeetle/src/storage.zig +0 -393
- package/src/tigerbeetle/src/testing/cluster/message_bus.zig +0 -82
- package/src/tigerbeetle/src/testing/cluster/network.zig +0 -237
- package/src/tigerbeetle/src/testing/cluster/state_checker.zig +0 -169
- package/src/tigerbeetle/src/testing/cluster/storage_checker.zig +0 -202
- package/src/tigerbeetle/src/testing/cluster.zig +0 -444
- package/src/tigerbeetle/src/testing/fuzz.zig +0 -140
- package/src/tigerbeetle/src/testing/hash_log.zig +0 -66
- package/src/tigerbeetle/src/testing/id.zig +0 -99
- package/src/tigerbeetle/src/testing/packet_simulator.zig +0 -374
- package/src/tigerbeetle/src/testing/priority_queue.zig +0 -645
- package/src/tigerbeetle/src/testing/reply_sequence.zig +0 -139
- package/src/tigerbeetle/src/testing/state_machine.zig +0 -250
- package/src/tigerbeetle/src/testing/storage.zig +0 -757
- package/src/tigerbeetle/src/testing/table.zig +0 -247
- package/src/tigerbeetle/src/testing/time.zig +0 -84
- package/src/tigerbeetle/src/tigerbeetle.zig +0 -227
- package/src/tigerbeetle/src/time.zig +0 -112
- package/src/tigerbeetle/src/tracer.zig +0 -529
- package/src/tigerbeetle/src/unit_tests.zig +0 -40
- package/src/tigerbeetle/src/vopr.zig +0 -495
- package/src/tigerbeetle/src/vsr/README.md +0 -209
- package/src/tigerbeetle/src/vsr/client.zig +0 -544
- package/src/tigerbeetle/src/vsr/clock.zig +0 -855
- package/src/tigerbeetle/src/vsr/journal.zig +0 -2415
- package/src/tigerbeetle/src/vsr/journal_format_fuzz.zig +0 -111
- package/src/tigerbeetle/src/vsr/marzullo.zig +0 -309
- package/src/tigerbeetle/src/vsr/replica.zig +0 -6616
- package/src/tigerbeetle/src/vsr/replica_format.zig +0 -219
- package/src/tigerbeetle/src/vsr/superblock.zig +0 -1631
- package/src/tigerbeetle/src/vsr/superblock_client_table.zig +0 -256
- package/src/tigerbeetle/src/vsr/superblock_free_set.zig +0 -929
- package/src/tigerbeetle/src/vsr/superblock_free_set_fuzz.zig +0 -334
- package/src/tigerbeetle/src/vsr/superblock_fuzz.zig +0 -390
- package/src/tigerbeetle/src/vsr/superblock_manifest.zig +0 -615
- package/src/tigerbeetle/src/vsr/superblock_quorums.zig +0 -394
- package/src/tigerbeetle/src/vsr/superblock_quorums_fuzz.zig +0 -314
- package/src/tigerbeetle/src/vsr.zig +0 -1425
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
const std = @import("std");
|
|
2
|
-
|
|
3
|
-
/// Permute indices (or other encoded data) into ids to:
|
|
4
|
-
///
|
|
5
|
-
/// * test different patterns of ids (e.g. random, ascending, descending), and
|
|
6
|
-
/// * allow the original index to recovered from the id, enabling less stateful testing.
|
|
7
|
-
///
|
|
8
|
-
pub const IdPermutation = union(enum) {
|
|
9
|
-
/// Ascending indices become ascending ids.
|
|
10
|
-
identity: void,
|
|
11
|
-
|
|
12
|
-
/// Ascending indices become descending ids.
|
|
13
|
-
inversion: void,
|
|
14
|
-
|
|
15
|
-
/// Ascending indices alternate between ascending/descending (e.g. 1,100,3,98,…).
|
|
16
|
-
zigzag: void,
|
|
17
|
-
|
|
18
|
-
/// Ascending indices become pseudo-UUIDs.
|
|
19
|
-
///
|
|
20
|
-
/// Sandwich the index "data" between random bits — this randomizes the id's prefix and suffix,
|
|
21
|
-
/// but the index is easily recovered:
|
|
22
|
-
///
|
|
23
|
-
/// * id_bits[_0.._32] = random
|
|
24
|
-
/// * id_bits[32.._96] = data
|
|
25
|
-
/// * id_bits[96..128] = random
|
|
26
|
-
random: u64,
|
|
27
|
-
|
|
28
|
-
pub fn encode(self: *const IdPermutation, data: usize) u128 {
|
|
29
|
-
return switch (self.*) {
|
|
30
|
-
.identity => data,
|
|
31
|
-
.inversion => std.math.maxInt(u128) - @as(u128, data),
|
|
32
|
-
.zigzag => {
|
|
33
|
-
if (data % 2 == 0) {
|
|
34
|
-
return data;
|
|
35
|
-
} else {
|
|
36
|
-
// -1 to stay odd.
|
|
37
|
-
return std.math.maxInt(u128) - @as(u128, data) -% 1;
|
|
38
|
-
}
|
|
39
|
-
},
|
|
40
|
-
.random => |seed| {
|
|
41
|
-
var prng = std.rand.DefaultPrng.init(seed +% data);
|
|
42
|
-
const random = prng.random();
|
|
43
|
-
const random_mask = ~@as(u128, std.math.maxInt(u64) << 32);
|
|
44
|
-
const random_bits = random_mask & random.int(u128);
|
|
45
|
-
return @as(u128, data) << 32 | random_bits;
|
|
46
|
-
},
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
pub fn decode(self: *const IdPermutation, id: u128) usize {
|
|
51
|
-
return switch (self.*) {
|
|
52
|
-
.identity => @intCast(usize, id),
|
|
53
|
-
.inversion => @intCast(usize, std.math.maxInt(u128) - id),
|
|
54
|
-
.zigzag => {
|
|
55
|
-
if (id % 2 == 0) {
|
|
56
|
-
return @intCast(usize, id);
|
|
57
|
-
} else {
|
|
58
|
-
// -1 to stay odd.
|
|
59
|
-
return @intCast(usize, std.math.maxInt(u128) - id -% 1);
|
|
60
|
-
}
|
|
61
|
-
},
|
|
62
|
-
.random => @truncate(usize, id >> 32),
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
pub fn generate(random: std.rand.Random) IdPermutation {
|
|
67
|
-
return switch (random.uintLessThan(usize, 4)) {
|
|
68
|
-
0 => .{ .identity = {} },
|
|
69
|
-
1 => .{ .inversion = {} },
|
|
70
|
-
2 => .{ .zigzag = {} },
|
|
71
|
-
3 => .{ .random = random.int(u64) },
|
|
72
|
-
else => unreachable,
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
test "IdPermutation" {
|
|
78
|
-
var prng = std.rand.DefaultPrng.init(123);
|
|
79
|
-
const random = prng.random();
|
|
80
|
-
|
|
81
|
-
for ([_]IdPermutation{
|
|
82
|
-
.{ .identity = {} },
|
|
83
|
-
.{ .inversion = {} },
|
|
84
|
-
.{ .zigzag = {} },
|
|
85
|
-
.{ .random = random.int(u64) },
|
|
86
|
-
}) |permutation| {
|
|
87
|
-
var i: usize = 0;
|
|
88
|
-
while (i < 20) : (i += 1) {
|
|
89
|
-
const r = random.int(usize);
|
|
90
|
-
try test_id_permutation(permutation, r);
|
|
91
|
-
try test_id_permutation(permutation, i);
|
|
92
|
-
try test_id_permutation(permutation, std.math.maxInt(usize) - i);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
fn test_id_permutation(permutation: IdPermutation, value: usize) !void {
|
|
98
|
-
try std.testing.expectEqual(value, permutation.decode(permutation.encode(value)));
|
|
99
|
-
}
|
|
@@ -1,374 +0,0 @@
|
|
|
1
|
-
const std = @import("std");
|
|
2
|
-
const assert = std.debug.assert;
|
|
3
|
-
const math = std.math;
|
|
4
|
-
|
|
5
|
-
const log = std.log.scoped(.packet_simulator);
|
|
6
|
-
const vsr = @import("../vsr.zig");
|
|
7
|
-
const PriorityQueue = @import("./priority_queue.zig").PriorityQueue;
|
|
8
|
-
const fuzz = @import("./fuzz.zig");
|
|
9
|
-
|
|
10
|
-
pub const PacketSimulatorOptions = struct {
|
|
11
|
-
replica_count: u8,
|
|
12
|
-
client_count: u8,
|
|
13
|
-
seed: u64,
|
|
14
|
-
|
|
15
|
-
/// Mean for the exponential distribution used to calculate forward delay.
|
|
16
|
-
one_way_delay_mean: u64,
|
|
17
|
-
one_way_delay_min: u64,
|
|
18
|
-
|
|
19
|
-
packet_loss_probability: u8 = 0,
|
|
20
|
-
packet_replay_probability: u8 = 0,
|
|
21
|
-
|
|
22
|
-
/// How the partitions should be generated
|
|
23
|
-
partition_mode: PartitionMode = .none,
|
|
24
|
-
|
|
25
|
-
partition_symmetry: PartitionSymmetry = .symmetric,
|
|
26
|
-
|
|
27
|
-
/// Probability per tick that a partition will occur
|
|
28
|
-
partition_probability: u8 = 0,
|
|
29
|
-
|
|
30
|
-
/// Probability per tick that a partition will resolve
|
|
31
|
-
unpartition_probability: u8 = 0,
|
|
32
|
-
|
|
33
|
-
/// Minimum time a partition lasts
|
|
34
|
-
partition_stability: u32 = 0,
|
|
35
|
-
|
|
36
|
-
/// Minimum time the cluster is fully connected until it is partitioned again
|
|
37
|
-
unpartition_stability: u32 = 0,
|
|
38
|
-
|
|
39
|
-
/// The maximum number of in-flight packets a path can have before packets are randomly dropped.
|
|
40
|
-
path_maximum_capacity: u8,
|
|
41
|
-
|
|
42
|
-
/// Mean for the exponential distribution used to calculate how long a path is clogged for.
|
|
43
|
-
path_clog_duration_mean: u64,
|
|
44
|
-
path_clog_probability: u8,
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
pub const Path = struct {
|
|
48
|
-
source: u8,
|
|
49
|
-
target: u8,
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
/// Determines how the partitions are created. Partitions
|
|
53
|
-
/// are two-way, i.e. if i cannot communicate with j, then
|
|
54
|
-
/// j cannot communicate with i.
|
|
55
|
-
///
|
|
56
|
-
/// Only replicas are partitioned. There will always be exactly two partitions.
|
|
57
|
-
pub const PartitionMode = enum {
|
|
58
|
-
/// Disable automatic partitioning.
|
|
59
|
-
none,
|
|
60
|
-
|
|
61
|
-
/// Draws the size of the partition uniformly at random from (1, n-1).
|
|
62
|
-
/// Replicas are randomly assigned a partition.
|
|
63
|
-
uniform_size,
|
|
64
|
-
|
|
65
|
-
/// Assigns each node to a partition uniformly at random. This biases towards
|
|
66
|
-
/// equal-size partitions.
|
|
67
|
-
uniform_partition,
|
|
68
|
-
|
|
69
|
-
/// Isolates exactly one replica.
|
|
70
|
-
isolate_single,
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
pub const PartitionSymmetry = enum { symmetric, asymmetric };
|
|
74
|
-
|
|
75
|
-
pub fn PacketSimulatorType(comptime Packet: type) type {
|
|
76
|
-
return struct {
|
|
77
|
-
const Self = @This();
|
|
78
|
-
|
|
79
|
-
const LinkPacket = struct {
|
|
80
|
-
expiry: u64,
|
|
81
|
-
callback: fn (packet: Packet, path: Path) void,
|
|
82
|
-
packet: Packet,
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
const Link = struct {
|
|
86
|
-
queue: PriorityQueue(LinkPacket, void, Self.order_packets),
|
|
87
|
-
/// When false, packets sent on the path are not delivered.
|
|
88
|
-
enabled: bool = true,
|
|
89
|
-
/// We can arbitrary clog a path until a tick.
|
|
90
|
-
clogged_till: u64 = 0,
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
options: PacketSimulatorOptions,
|
|
94
|
-
prng: std.rand.DefaultPrng,
|
|
95
|
-
ticks: u64 = 0,
|
|
96
|
-
|
|
97
|
-
/// A send and receive path between each node in the network.
|
|
98
|
-
/// Indexed by path_index().
|
|
99
|
-
links: []Link,
|
|
100
|
-
|
|
101
|
-
/// Scratch space for automatically generating partitions.
|
|
102
|
-
/// The "source of truth" for partitions is links[*].enabled.
|
|
103
|
-
auto_partition: []bool,
|
|
104
|
-
auto_partition_active: bool,
|
|
105
|
-
auto_partition_replicas: []u8,
|
|
106
|
-
auto_partition_stability: u32,
|
|
107
|
-
|
|
108
|
-
pub fn init(allocator: std.mem.Allocator, options: PacketSimulatorOptions) !Self {
|
|
109
|
-
assert(options.replica_count > 0);
|
|
110
|
-
assert(options.one_way_delay_mean >= options.one_way_delay_min);
|
|
111
|
-
|
|
112
|
-
const node_count_ = options.replica_count + options.client_count;
|
|
113
|
-
const links = try allocator.alloc(Link, @as(usize, node_count_) * node_count_);
|
|
114
|
-
errdefer allocator.free(links);
|
|
115
|
-
|
|
116
|
-
for (links) |*link, i| {
|
|
117
|
-
errdefer for (links[0..i]) |l| l.queue.deinit();
|
|
118
|
-
|
|
119
|
-
const queue = PriorityQueue(LinkPacket, void, Self.order_packets).init(allocator, {});
|
|
120
|
-
try link.queue.ensureTotalCapacity(options.path_maximum_capacity);
|
|
121
|
-
link.* = .{ .queue = queue };
|
|
122
|
-
}
|
|
123
|
-
errdefer for (links) |link| link.queue.deinit();
|
|
124
|
-
|
|
125
|
-
const auto_partition = try allocator.alloc(bool, @as(usize, options.replica_count));
|
|
126
|
-
errdefer allocator.free(auto_partition);
|
|
127
|
-
std.mem.set(bool, auto_partition, false);
|
|
128
|
-
|
|
129
|
-
const auto_partition_replicas = try allocator.alloc(u8, @as(usize, options.replica_count));
|
|
130
|
-
errdefer allocator.free(auto_partition_replicas);
|
|
131
|
-
for (auto_partition_replicas) |*replica, i| replica.* = @intCast(u8, i);
|
|
132
|
-
|
|
133
|
-
return Self{
|
|
134
|
-
.options = options,
|
|
135
|
-
.prng = std.rand.DefaultPrng.init(options.seed),
|
|
136
|
-
.links = links,
|
|
137
|
-
|
|
138
|
-
.auto_partition_active = false,
|
|
139
|
-
.auto_partition = auto_partition,
|
|
140
|
-
.auto_partition_replicas = auto_partition_replicas,
|
|
141
|
-
.auto_partition_stability = options.unpartition_stability,
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
|
|
146
|
-
for (self.links) |*link| {
|
|
147
|
-
while (link.queue.peek()) |_| link.queue.remove().packet.deinit();
|
|
148
|
-
link.queue.deinit();
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
allocator.free(self.links);
|
|
152
|
-
allocator.free(self.auto_partition);
|
|
153
|
-
allocator.free(self.auto_partition_replicas);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
fn order_packets(context: void, a: LinkPacket, b: LinkPacket) math.Order {
|
|
157
|
-
_ = context;
|
|
158
|
-
|
|
159
|
-
return math.order(a.expiry, b.expiry);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
fn node_count(self: Self) usize {
|
|
163
|
-
return self.options.replica_count + self.options.client_count;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
fn path_index(self: Self, path: Path) usize {
|
|
167
|
-
assert(path.source < self.node_count());
|
|
168
|
-
assert(path.target < self.node_count());
|
|
169
|
-
|
|
170
|
-
return @as(usize, path.source) * self.node_count() + path.target;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
fn should_drop(self: *Self) bool {
|
|
174
|
-
return self.prng.random().uintAtMost(u8, 100) < self.options.packet_loss_probability;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
fn is_clogged(self: *Self, path: Path) bool {
|
|
178
|
-
return self.links[self.path_index(path)].clogged_till > self.ticks;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
fn should_clog(self: *Self, path: Path) bool {
|
|
182
|
-
_ = path;
|
|
183
|
-
|
|
184
|
-
return self.prng.random().uintAtMost(u8, 100) < self.options.path_clog_probability;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
fn clog_for(self: *Self, path: Path, ticks: u64) void {
|
|
188
|
-
const clog_expiry = &self.links[self.path_index(path)].clogged_till;
|
|
189
|
-
clog_expiry.* = self.ticks + ticks;
|
|
190
|
-
log.debug("Path path.source={} path.target={} clogged for ticks={}", .{
|
|
191
|
-
path.source,
|
|
192
|
-
path.target,
|
|
193
|
-
ticks,
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
fn should_replay(self: *Self) bool {
|
|
198
|
-
return self.prng.random().uintAtMost(u8, 100) < self.options.packet_replay_probability;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
fn should_partition(self: *Self) bool {
|
|
202
|
-
return self.prng.random().uintAtMost(u8, 100) < self.options.partition_probability;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
fn should_unpartition(self: *Self) bool {
|
|
206
|
-
return self.prng.random().uintAtMost(u8, 100) < self.options.unpartition_probability;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/// Return a value produced using an exponential distribution with
|
|
210
|
-
/// the minimum and mean specified in self.options
|
|
211
|
-
fn one_way_delay(self: *Self) u64 {
|
|
212
|
-
const min = self.options.one_way_delay_min;
|
|
213
|
-
const mean = self.options.one_way_delay_mean;
|
|
214
|
-
return min + fuzz.random_int_exponential(self.prng.random(), u64, mean - min);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/// Partitions the network. Guaranteed to isolate at least one replica.
|
|
218
|
-
fn auto_partition_network(self: *Self) void {
|
|
219
|
-
assert(self.options.replica_count > 1);
|
|
220
|
-
|
|
221
|
-
const random = self.prng.random();
|
|
222
|
-
var partition = self.auto_partition;
|
|
223
|
-
switch (self.options.partition_mode) {
|
|
224
|
-
.none => std.mem.set(bool, partition, false),
|
|
225
|
-
.uniform_size => {
|
|
226
|
-
// Exclude cases partition_size == 0 and partition_size == replica_count
|
|
227
|
-
const partition_size =
|
|
228
|
-
1 + random.uintAtMost(u8, self.options.replica_count - 2);
|
|
229
|
-
random.shuffle(u8, self.auto_partition_replicas);
|
|
230
|
-
for (self.auto_partition_replicas) |r, i| {
|
|
231
|
-
partition[r] = i < partition_size;
|
|
232
|
-
}
|
|
233
|
-
},
|
|
234
|
-
.uniform_partition => {
|
|
235
|
-
var only_same = true;
|
|
236
|
-
partition[0] = random.uintLessThan(u8, 2) == 1;
|
|
237
|
-
|
|
238
|
-
var i: usize = 1;
|
|
239
|
-
while (i < self.options.replica_count) : (i += 1) {
|
|
240
|
-
partition[i] = random.uintLessThan(u8, 2) == 1;
|
|
241
|
-
only_same =
|
|
242
|
-
only_same and (partition[i - 1] == partition[i]);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
if (only_same) {
|
|
246
|
-
const n = random.uintLessThan(u8, self.options.replica_count);
|
|
247
|
-
partition[n] = true;
|
|
248
|
-
}
|
|
249
|
-
},
|
|
250
|
-
.isolate_single => {
|
|
251
|
-
std.mem.set(bool, partition, false);
|
|
252
|
-
const n = random.uintLessThan(u8, self.options.replica_count);
|
|
253
|
-
partition[n] = true;
|
|
254
|
-
},
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
self.auto_partition_active = true;
|
|
258
|
-
self.auto_partition_stability = self.options.partition_stability;
|
|
259
|
-
|
|
260
|
-
const asymmetric_partition_side = random.boolean();
|
|
261
|
-
var from: u8 = 0;
|
|
262
|
-
while (from < self.node_count()) : (from += 1) {
|
|
263
|
-
var to: u8 = 0;
|
|
264
|
-
while (to < self.node_count()) : (to += 1) {
|
|
265
|
-
const path = .{ .source = from, .target = to };
|
|
266
|
-
self.links[self.path_index(path)].enabled =
|
|
267
|
-
from >= self.options.replica_count or
|
|
268
|
-
to >= self.options.replica_count or
|
|
269
|
-
partition[from] == partition[to] or
|
|
270
|
-
(self.options.partition_symmetry == .asymmetric and
|
|
271
|
-
partition[from] == asymmetric_partition_side);
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
pub fn tick(self: *Self) void {
|
|
277
|
-
self.ticks += 1;
|
|
278
|
-
|
|
279
|
-
if (self.auto_partition_stability > 0) {
|
|
280
|
-
self.auto_partition_stability -= 1;
|
|
281
|
-
} else {
|
|
282
|
-
if (self.auto_partition_active) {
|
|
283
|
-
if (self.should_unpartition()) {
|
|
284
|
-
self.auto_partition_active = false;
|
|
285
|
-
self.auto_partition_stability = self.options.unpartition_stability;
|
|
286
|
-
std.mem.set(bool, self.auto_partition, false);
|
|
287
|
-
for (self.links) |*link| link.enabled = true;
|
|
288
|
-
log.warn("unpartitioned network: partition={d}", .{self.auto_partition});
|
|
289
|
-
}
|
|
290
|
-
} else {
|
|
291
|
-
if (self.options.replica_count > 1 and self.should_partition()) {
|
|
292
|
-
self.auto_partition_network();
|
|
293
|
-
log.warn("partitioned network: partition={d}", .{self.auto_partition});
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
var from: u8 = 0;
|
|
299
|
-
while (from < self.node_count()) : (from += 1) {
|
|
300
|
-
var to: u8 = 0;
|
|
301
|
-
while (to < self.node_count()) : (to += 1) {
|
|
302
|
-
const path = .{ .source = from, .target = to };
|
|
303
|
-
if (self.is_clogged(path)) continue;
|
|
304
|
-
|
|
305
|
-
const queue = &self.links[self.path_index(path)].queue;
|
|
306
|
-
while (queue.peek()) |*link_packet| {
|
|
307
|
-
if (link_packet.expiry > self.ticks) break;
|
|
308
|
-
_ = queue.remove();
|
|
309
|
-
|
|
310
|
-
if (!self.links[self.path_index(path)].enabled) {
|
|
311
|
-
log.warn("dropped packet (different partitions): from={} to={}", .{ from, to });
|
|
312
|
-
link_packet.packet.deinit();
|
|
313
|
-
continue;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
if (self.should_drop()) {
|
|
317
|
-
log.warn("dropped packet from={} to={}", .{ from, to });
|
|
318
|
-
link_packet.packet.deinit();
|
|
319
|
-
continue;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
if (self.should_replay()) {
|
|
323
|
-
self.submit_packet(link_packet.packet, link_packet.callback, path);
|
|
324
|
-
|
|
325
|
-
log.debug("replayed packet from={} to={}", .{ from, to });
|
|
326
|
-
|
|
327
|
-
link_packet.callback(link_packet.packet, path);
|
|
328
|
-
} else {
|
|
329
|
-
log.debug("delivering packet from={} to={}", .{ from, to });
|
|
330
|
-
link_packet.callback(link_packet.packet, path);
|
|
331
|
-
link_packet.packet.deinit();
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
const reverse_path: Path = .{ .source = to, .target = from };
|
|
336
|
-
|
|
337
|
-
if (self.should_clog(reverse_path)) {
|
|
338
|
-
const ticks = fuzz.random_int_exponential(
|
|
339
|
-
self.prng.random(),
|
|
340
|
-
u64,
|
|
341
|
-
self.options.path_clog_duration_mean,
|
|
342
|
-
);
|
|
343
|
-
self.clog_for(reverse_path, ticks);
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
pub fn submit_packet(
|
|
350
|
-
self: *Self,
|
|
351
|
-
packet: Packet,
|
|
352
|
-
callback: fn (packet: Packet, path: Path) void,
|
|
353
|
-
path: Path,
|
|
354
|
-
) void {
|
|
355
|
-
const queue = &self.links[self.path_index(path)].queue;
|
|
356
|
-
var queue_length = queue.count();
|
|
357
|
-
if (queue_length + 1 > self.options.path_maximum_capacity) {
|
|
358
|
-
const index = self.prng.random().uintLessThanBiased(u64, queue_length);
|
|
359
|
-
const link_packet = queue.removeIndex(index);
|
|
360
|
-
link_packet.packet.deinit();
|
|
361
|
-
log.warn("submit_packet: {} reached capacity, dropped packet={}", .{
|
|
362
|
-
path,
|
|
363
|
-
index,
|
|
364
|
-
});
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
queue.add(.{
|
|
368
|
-
.expiry = self.ticks + self.one_way_delay(),
|
|
369
|
-
.packet = packet,
|
|
370
|
-
.callback = callback,
|
|
371
|
-
}) catch unreachable;
|
|
372
|
-
}
|
|
373
|
-
};
|
|
374
|
-
}
|