tigerbeetle-node 0.11.5 → 0.11.7
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/.client.node.sha256 +1 -1
- package/dist/index.d.ts +41 -42
- package/dist/index.js +41 -42
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +0 -1
- package/src/tigerbeetle/scripts/benchmark.bat +7 -3
- package/src/tigerbeetle/scripts/benchmark.sh +2 -3
- package/src/tigerbeetle/scripts/install.bat +7 -0
- package/src/tigerbeetle/scripts/install.sh +2 -3
- package/src/tigerbeetle/src/benchmark.zig +3 -3
- package/src/tigerbeetle/src/config.zig +24 -3
- package/src/tigerbeetle/src/constants.zig +8 -5
- package/src/tigerbeetle/src/ewah.zig +6 -5
- package/src/tigerbeetle/src/ewah_fuzz.zig +1 -1
- package/src/tigerbeetle/src/io/darwin.zig +19 -0
- package/src/tigerbeetle/src/io/linux.zig +8 -0
- package/src/tigerbeetle/src/io/windows.zig +20 -2
- package/src/tigerbeetle/src/iops.zig +7 -1
- package/src/tigerbeetle/src/lsm/compaction.zig +27 -72
- package/src/tigerbeetle/src/lsm/forest_fuzz.zig +10 -11
- package/src/tigerbeetle/src/lsm/grid.zig +267 -267
- package/src/tigerbeetle/src/lsm/groove.zig +3 -0
- package/src/tigerbeetle/src/lsm/level_iterator.zig +18 -1
- package/src/tigerbeetle/src/lsm/manifest.zig +29 -1
- package/src/tigerbeetle/src/lsm/manifest_level.zig +1 -0
- package/src/tigerbeetle/src/lsm/manifest_log.zig +5 -5
- package/src/tigerbeetle/src/lsm/manifest_log_fuzz.zig +19 -11
- package/src/tigerbeetle/src/lsm/merge_iterator.zig +106 -0
- package/src/tigerbeetle/src/lsm/posted_groove.zig +1 -0
- package/src/tigerbeetle/src/lsm/segmented_array.zig +1 -0
- package/src/tigerbeetle/src/lsm/set_associative_cache.zig +26 -70
- package/src/tigerbeetle/src/lsm/table.zig +56 -0
- package/src/tigerbeetle/src/lsm/table_iterator.zig +29 -2
- package/src/tigerbeetle/src/lsm/table_mutable.zig +49 -15
- package/src/tigerbeetle/src/lsm/test.zig +10 -7
- package/src/tigerbeetle/src/lsm/tree.zig +27 -6
- package/src/tigerbeetle/src/lsm/tree_fuzz.zig +302 -263
- package/src/tigerbeetle/src/message_pool.zig +2 -1
- package/src/tigerbeetle/src/simulator.zig +22 -84
- package/src/tigerbeetle/src/{test/accounting → state_machine}/auditor.zig +8 -8
- package/src/tigerbeetle/src/{test/accounting → state_machine}/workload.zig +108 -48
- package/src/tigerbeetle/src/state_machine.zig +20 -14
- package/src/tigerbeetle/src/storage.zig +58 -6
- package/src/tigerbeetle/src/test/cluster.zig +14 -11
- package/src/tigerbeetle/src/test/conductor.zig +2 -3
- package/src/tigerbeetle/src/test/id.zig +10 -0
- package/src/tigerbeetle/src/test/state_checker.zig +1 -1
- package/src/tigerbeetle/src/test/state_machine.zig +151 -46
- package/src/tigerbeetle/src/test/storage.zig +22 -1
- package/src/tigerbeetle/src/tigerbeetle.zig +0 -1
- package/src/tigerbeetle/src/tracer.zig +50 -28
- package/src/tigerbeetle/src/unit_tests.zig +11 -6
- package/src/tigerbeetle/src/vopr.zig +4 -4
- package/src/tigerbeetle/src/vsr/client.zig +5 -5
- package/src/tigerbeetle/src/vsr/clock.zig +2 -2
- package/src/tigerbeetle/src/vsr/journal.zig +647 -537
- package/src/tigerbeetle/src/vsr/replica.zig +333 -333
- package/src/tigerbeetle/src/vsr/replica_format.zig +7 -4
- package/src/tigerbeetle/src/vsr/superblock.zig +87 -39
- package/src/tigerbeetle/src/vsr/superblock_free_set.zig +114 -93
- package/src/tigerbeetle/src/vsr/superblock_free_set_fuzz.zig +1 -1
- package/src/tigerbeetle/src/vsr/superblock_fuzz.zig +11 -8
- package/src/tigerbeetle/src/vsr/superblock_quorums_fuzz.zig +3 -3
- package/src/tigerbeetle/src/vsr.zig +60 -13
- package/src/tigerbeetle/src/c/tb_client/context.zig +0 -304
- package/src/tigerbeetle/src/c/tb_client/echo_client.zig +0 -108
- package/src/tigerbeetle/src/c/tb_client/packet.zig +0 -80
- package/src/tigerbeetle/src/c/tb_client/signal.zig +0 -286
- package/src/tigerbeetle/src/c/tb_client/thread.zig +0 -88
- package/src/tigerbeetle/src/c/tb_client.h +0 -221
- package/src/tigerbeetle/src/c/tb_client.zig +0 -177
- package/src/tigerbeetle/src/c/tb_client_header.zig +0 -218
- package/src/tigerbeetle/src/c/tb_client_header_test.zig +0 -135
- package/src/tigerbeetle/src/c/test.zig +0 -371
- package/src/tigerbeetle/src/cli.zig +0 -375
- package/src/tigerbeetle/src/main.zig +0 -245
|
@@ -11,7 +11,7 @@ const Message = MessagePool.Message;
|
|
|
11
11
|
const Network = @import("network.zig").Network;
|
|
12
12
|
const NetworkOptions = @import("network.zig").NetworkOptions;
|
|
13
13
|
|
|
14
|
-
pub const StateMachine =
|
|
14
|
+
pub const StateMachine = constants.StateMachineType(Storage, .{
|
|
15
15
|
.message_body_size_max = constants.message_body_size_max,
|
|
16
16
|
});
|
|
17
17
|
const MessageBus = @import("message_bus.zig").MessageBus;
|
|
@@ -29,7 +29,7 @@ pub const ClusterOptions = struct {
|
|
|
29
29
|
cluster: u32,
|
|
30
30
|
replica_count: u8,
|
|
31
31
|
client_count: u8,
|
|
32
|
-
|
|
32
|
+
storage_size_limit: u64,
|
|
33
33
|
|
|
34
34
|
seed: u64,
|
|
35
35
|
on_change_state: fn (replica: *const Replica) void,
|
|
@@ -76,8 +76,8 @@ pub const Cluster = struct {
|
|
|
76
76
|
pub fn create(allocator: mem.Allocator, prng: std.rand.Random, options: ClusterOptions) !*Cluster {
|
|
77
77
|
assert(options.replica_count > 0);
|
|
78
78
|
assert(options.client_count > 0);
|
|
79
|
-
assert(options.
|
|
80
|
-
assert(options.
|
|
79
|
+
assert(options.storage_size_limit % constants.sector_size == 0);
|
|
80
|
+
assert(options.storage_size_limit <= constants.storage_size_max);
|
|
81
81
|
assert(options.health_options.crash_probability < 1.0);
|
|
82
82
|
assert(options.health_options.crash_probability >= 0.0);
|
|
83
83
|
assert(options.health_options.restart_probability < 1.0);
|
|
@@ -136,17 +136,19 @@ pub const Cluster = struct {
|
|
|
136
136
|
var storage_options = options.storage_options;
|
|
137
137
|
storage_options.replica_index = @intCast(u8, replica_index);
|
|
138
138
|
storage_options.faulty_wal_areas = faulty_wal_areas[replica_index];
|
|
139
|
-
storage.* = try Storage.init(
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
storage_options,
|
|
143
|
-
);
|
|
139
|
+
storage.* = try Storage.init(allocator, options.storage_size_limit, storage_options);
|
|
140
|
+
// Disable most faults at startup, so that the replicas don't get stuck in recovery mode.
|
|
141
|
+
storage.faulty = replica_index >= vsr.quorums(options.replica_count).view_change;
|
|
144
142
|
}
|
|
145
143
|
errdefer for (cluster.storages) |*storage| storage.deinit(allocator);
|
|
146
144
|
|
|
147
145
|
// Format each replica's storage (equivalent to "tigerbeetle format ...").
|
|
148
146
|
for (cluster.storages) |*storage, replica_index| {
|
|
149
|
-
var superblock = try SuperBlock.init(allocator,
|
|
147
|
+
var superblock = try SuperBlock.init(allocator, .{
|
|
148
|
+
.storage = storage,
|
|
149
|
+
.message_pool = &cluster.pools[replica_index],
|
|
150
|
+
.storage_size_limit = options.storage_size_limit,
|
|
151
|
+
});
|
|
150
152
|
defer superblock.deinit(allocator);
|
|
151
153
|
|
|
152
154
|
try vsr.format(
|
|
@@ -330,6 +332,8 @@ pub const Cluster = struct {
|
|
|
330
332
|
.{
|
|
331
333
|
.replica_count = @intCast(u8, cluster.replicas.len),
|
|
332
334
|
.storage = &cluster.storages[replica_index],
|
|
335
|
+
// TODO Test restarting with a higher storage limit.
|
|
336
|
+
.storage_size_limit = cluster.options.storage_size_limit,
|
|
333
337
|
.message_pool = &cluster.pools[replica_index],
|
|
334
338
|
.time = time,
|
|
335
339
|
.state_machine_options = cluster.options.state_machine_options,
|
|
@@ -339,7 +343,6 @@ pub const Cluster = struct {
|
|
|
339
343
|
assert(replica.cluster == cluster.options.cluster);
|
|
340
344
|
assert(replica.replica == replica_index);
|
|
341
345
|
assert(replica.replica_count == cluster.replicas.len);
|
|
342
|
-
assert(replica.status == .recovering);
|
|
343
346
|
|
|
344
347
|
replica.on_change_state = cluster.options.on_change_state;
|
|
345
348
|
replica.on_compact = cluster.options.on_compact;
|
|
@@ -36,7 +36,6 @@ pub fn ConductorType(
|
|
|
36
36
|
comptime Client: type,
|
|
37
37
|
comptime MessageBus: type,
|
|
38
38
|
comptime StateMachine: type,
|
|
39
|
-
comptime Workload: type,
|
|
40
39
|
) type {
|
|
41
40
|
return struct {
|
|
42
41
|
const Self = @This();
|
|
@@ -51,7 +50,7 @@ pub fn ConductorType(
|
|
|
51
50
|
constants.clients_max * constants.client_request_queue_max * 2;
|
|
52
51
|
|
|
53
52
|
random: std.rand.Random,
|
|
54
|
-
workload: *Workload,
|
|
53
|
+
workload: *StateMachine.Workload,
|
|
55
54
|
options: Options,
|
|
56
55
|
client_id_permutation: IdPermutation,
|
|
57
56
|
|
|
@@ -90,7 +89,7 @@ pub fn ConductorType(
|
|
|
90
89
|
pub fn init(
|
|
91
90
|
allocator: std.mem.Allocator,
|
|
92
91
|
random: std.rand.Random,
|
|
93
|
-
workload: *Workload,
|
|
92
|
+
workload: *StateMachine.Workload,
|
|
94
93
|
options: Options,
|
|
95
94
|
) !Self {
|
|
96
95
|
assert(options.replica_count >= 1);
|
|
@@ -62,6 +62,16 @@ pub const IdPermutation = union(enum) {
|
|
|
62
62
|
.random => @truncate(usize, id >> 32),
|
|
63
63
|
};
|
|
64
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
|
+
}
|
|
65
75
|
};
|
|
66
76
|
|
|
67
77
|
test "IdPermutation" {
|
|
@@ -70,7 +70,7 @@ pub const StateChecker = struct {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
pub fn check_state(state_checker: *StateChecker, replica_index: u8) !void {
|
|
73
|
-
const replica = state_checker.replicas[replica_index];
|
|
73
|
+
const replica = &state_checker.replicas[replica_index];
|
|
74
74
|
const commit_header = header: {
|
|
75
75
|
if (replica.journal.status == .recovered) {
|
|
76
76
|
const commit_header = replica.journal.header_with_op(replica.commit_min);
|
|
@@ -1,68 +1,65 @@
|
|
|
1
1
|
const std = @import("std");
|
|
2
2
|
const assert = std.debug.assert;
|
|
3
3
|
|
|
4
|
+
const constants = @import("../constants.zig");
|
|
5
|
+
const vsr = @import("../vsr.zig");
|
|
4
6
|
const log = std.log.scoped(.state_machine);
|
|
5
7
|
|
|
6
|
-
pub fn StateMachineType(comptime Storage: type
|
|
8
|
+
pub fn StateMachineType(comptime Storage: type, comptime constants_: struct {
|
|
9
|
+
message_body_size_max: usize,
|
|
10
|
+
}) type {
|
|
7
11
|
_ = Storage;
|
|
12
|
+
_ = constants_;
|
|
13
|
+
|
|
8
14
|
return struct {
|
|
9
15
|
const StateMachine = @This();
|
|
10
16
|
const Grid = @import("../lsm/grid.zig").GridType(Storage);
|
|
11
17
|
|
|
18
|
+
pub const Workload = WorkloadType(StateMachine);
|
|
19
|
+
|
|
12
20
|
pub const Operation = enum(u8) {
|
|
13
21
|
/// Operations reserved by VR protocol (for all state machines):
|
|
14
22
|
reserved,
|
|
15
23
|
root,
|
|
16
24
|
register,
|
|
17
25
|
|
|
18
|
-
|
|
26
|
+
echo,
|
|
19
27
|
};
|
|
20
28
|
|
|
21
|
-
|
|
22
|
-
/// Each mean must be greater-or-equal-to their respective minimum.
|
|
23
|
-
pub const Options = struct {
|
|
24
|
-
seed: u64,
|
|
25
|
-
prefetch_mean: u64,
|
|
26
|
-
compact_mean: u64,
|
|
27
|
-
checkpoint_mean: u64,
|
|
28
|
-
};
|
|
29
|
+
pub const Options = struct {};
|
|
29
30
|
|
|
30
31
|
options: Options,
|
|
31
|
-
|
|
32
|
+
grid: *Grid,
|
|
33
|
+
grid_block: Grid.BlockPtr,
|
|
34
|
+
grid_write: Grid.Write = undefined,
|
|
32
35
|
prepare_timestamp: u64 = 0,
|
|
33
36
|
commit_timestamp: u64 = 0,
|
|
34
37
|
|
|
35
38
|
callback: ?fn (state_machine: *StateMachine) void = null,
|
|
36
|
-
callback_ticks: usize = 0,
|
|
37
39
|
|
|
38
|
-
pub fn init(
|
|
40
|
+
pub fn init(allocator: std.mem.Allocator, grid: *Grid, options: Options) !StateMachine {
|
|
41
|
+
const grid_block = try allocator.alignedAlloc(
|
|
42
|
+
u8,
|
|
43
|
+
constants.sector_size,
|
|
44
|
+
constants.block_size,
|
|
45
|
+
);
|
|
46
|
+
errdefer allocator.free(grid_block);
|
|
47
|
+
std.mem.set(u8, grid_block, 0);
|
|
48
|
+
|
|
39
49
|
return StateMachine{
|
|
40
50
|
.options = options,
|
|
41
|
-
.
|
|
51
|
+
.grid = grid,
|
|
52
|
+
.grid_block = grid_block[0..constants.block_size],
|
|
42
53
|
};
|
|
43
54
|
}
|
|
44
55
|
|
|
45
|
-
pub fn deinit(
|
|
46
|
-
|
|
47
|
-
// TODO This is dead code — tick() has been removed from the StateMachine
|
|
48
|
-
// interface. If we start using the test StateMachine again, tick will need
|
|
49
|
-
// to be called explicitly from the simulator to ensure async operations can
|
|
50
|
-
// finish.
|
|
51
|
-
pub fn tick(state_machine: *StateMachine) void {
|
|
52
|
-
if (state_machine.callback) |callback| {
|
|
53
|
-
if (state_machine.callback_ticks == 0) {
|
|
54
|
-
state_machine.callback = null;
|
|
55
|
-
callback(state_machine);
|
|
56
|
-
} else {
|
|
57
|
-
state_machine.callback_ticks -= 1;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
56
|
+
pub fn deinit(state_machine: *StateMachine, allocator: std.mem.Allocator) void {
|
|
57
|
+
allocator.free(state_machine.grid_block);
|
|
60
58
|
}
|
|
61
59
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
callback(self);
|
|
60
|
+
// TODO Grid.next_tick
|
|
61
|
+
pub fn open(state_machine: *StateMachine, callback: fn (*StateMachine) void) void {
|
|
62
|
+
callback(state_machine);
|
|
66
63
|
}
|
|
67
64
|
|
|
68
65
|
pub fn prepare(
|
|
@@ -86,10 +83,8 @@ pub fn StateMachineType(comptime Storage: type) type {
|
|
|
86
83
|
_ = op;
|
|
87
84
|
_ = operation;
|
|
88
85
|
_ = input;
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
state_machine.callback = callback;
|
|
92
|
-
state_machine.callback_ticks = state_machine.latency(state_machine.options.prefetch_mean);
|
|
86
|
+
|
|
87
|
+
state_machine.next_tick(callback);
|
|
93
88
|
}
|
|
94
89
|
|
|
95
90
|
pub fn commit(
|
|
@@ -109,34 +104,144 @@ pub fn StateMachineType(comptime Storage: type) type {
|
|
|
109
104
|
switch (operation) {
|
|
110
105
|
.reserved, .root => unreachable,
|
|
111
106
|
.register => return 0,
|
|
112
|
-
.
|
|
107
|
+
.echo => {
|
|
108
|
+
std.mem.copy(u8, output, input);
|
|
109
|
+
return input.len;
|
|
110
|
+
},
|
|
113
111
|
}
|
|
114
112
|
}
|
|
115
113
|
|
|
114
|
+
// TODO(Grid Recovery): Actually write blocks so that this state machine can be used
|
|
115
|
+
// to test grid recovery.
|
|
116
116
|
pub fn compact(
|
|
117
117
|
state_machine: *StateMachine,
|
|
118
118
|
callback: fn (*StateMachine) void,
|
|
119
119
|
op: u64,
|
|
120
120
|
) void {
|
|
121
121
|
_ = op;
|
|
122
|
-
|
|
123
|
-
assert(state_machine.callback_ticks == 0);
|
|
124
|
-
state_machine.callback = callback;
|
|
125
|
-
state_machine.callback_ticks = state_machine.latency(state_machine.options.compact_mean);
|
|
122
|
+
state_machine.next_tick(callback);
|
|
126
123
|
}
|
|
127
124
|
|
|
128
125
|
pub fn checkpoint(
|
|
129
126
|
state_machine: *StateMachine,
|
|
130
127
|
callback: fn (*StateMachine) void,
|
|
131
128
|
) void {
|
|
129
|
+
state_machine.next_tick(callback);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// TODO Replace with Grid.next_tick()
|
|
133
|
+
fn next_tick(state_machine: *StateMachine, callback: fn (*StateMachine) void) void {
|
|
134
|
+
// TODO This is a hack to defer till the next tick; use Grid.next_tick instead.
|
|
135
|
+
var free_set = state_machine.grid.superblock.free_set;
|
|
136
|
+
const reservation = free_set.reserve(1).?;
|
|
137
|
+
defer free_set.forfeit(reservation);
|
|
138
|
+
|
|
139
|
+
const address = free_set.acquire(reservation).?;
|
|
140
|
+
const header = std.mem.bytesAsValue(
|
|
141
|
+
vsr.Header,
|
|
142
|
+
state_machine.grid_block[0..@sizeOf(vsr.Header)],
|
|
143
|
+
);
|
|
144
|
+
header.op = address;
|
|
145
|
+
|
|
132
146
|
assert(state_machine.callback == null);
|
|
133
|
-
assert(state_machine.callback_ticks == 0);
|
|
134
147
|
state_machine.callback = callback;
|
|
135
|
-
state_machine.
|
|
148
|
+
state_machine.grid.write_block(
|
|
149
|
+
next_tick_callback,
|
|
150
|
+
&state_machine.grid_write,
|
|
151
|
+
state_machine.grid_block,
|
|
152
|
+
address,
|
|
153
|
+
);
|
|
136
154
|
}
|
|
137
155
|
|
|
138
|
-
fn
|
|
139
|
-
|
|
156
|
+
fn next_tick_callback(write: *Grid.Write) void {
|
|
157
|
+
const state_machine = @fieldParentPtr(StateMachine, "grid_write", write);
|
|
158
|
+
const callback = state_machine.callback.?;
|
|
159
|
+
state_machine.callback = null;
|
|
160
|
+
callback(state_machine);
|
|
140
161
|
}
|
|
141
162
|
};
|
|
142
163
|
}
|
|
164
|
+
|
|
165
|
+
fn WorkloadType(comptime StateMachine: type) type {
|
|
166
|
+
return struct {
|
|
167
|
+
const Workload = @This();
|
|
168
|
+
|
|
169
|
+
random: std.rand.Random,
|
|
170
|
+
requests_sent: usize = 0,
|
|
171
|
+
requests_delivered: usize = 0,
|
|
172
|
+
|
|
173
|
+
pub fn init(
|
|
174
|
+
allocator: std.mem.Allocator,
|
|
175
|
+
random: std.rand.Random,
|
|
176
|
+
options: Options,
|
|
177
|
+
) !Workload {
|
|
178
|
+
_ = allocator;
|
|
179
|
+
_ = options;
|
|
180
|
+
|
|
181
|
+
return Workload{
|
|
182
|
+
.random = random,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
pub fn deinit(workload: *Workload, allocator: std.mem.Allocator) void {
|
|
187
|
+
_ = workload;
|
|
188
|
+
_ = allocator;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
pub fn done(workload: *const Workload) bool {
|
|
192
|
+
return workload.requests_sent == workload.requests_delivered;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
pub fn build_request(
|
|
196
|
+
workload: *Workload,
|
|
197
|
+
client_index: usize,
|
|
198
|
+
body: []align(@alignOf(vsr.Header)) u8,
|
|
199
|
+
) struct {
|
|
200
|
+
operation: StateMachine.Operation,
|
|
201
|
+
size: usize,
|
|
202
|
+
} {
|
|
203
|
+
_ = client_index;
|
|
204
|
+
|
|
205
|
+
workload.requests_sent += 1;
|
|
206
|
+
|
|
207
|
+
// +1 for inclusive limit.
|
|
208
|
+
const size = workload.random.uintLessThan(usize, constants.message_body_size_max + 1);
|
|
209
|
+
workload.random.bytes(body[0..size]);
|
|
210
|
+
|
|
211
|
+
return .{
|
|
212
|
+
.operation = .echo,
|
|
213
|
+
.size = size,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
pub fn on_reply(
|
|
218
|
+
workload: *Workload,
|
|
219
|
+
client_index: usize,
|
|
220
|
+
operation: vsr.Operation,
|
|
221
|
+
timestamp: u64,
|
|
222
|
+
request_body: []align(@alignOf(vsr.Header)) const u8,
|
|
223
|
+
reply_body: []align(@alignOf(vsr.Header)) const u8,
|
|
224
|
+
) void {
|
|
225
|
+
_ = workload;
|
|
226
|
+
_ = client_index;
|
|
227
|
+
_ = timestamp;
|
|
228
|
+
|
|
229
|
+
workload.requests_delivered += 1;
|
|
230
|
+
assert(workload.requests_delivered <= workload.requests_sent);
|
|
231
|
+
|
|
232
|
+
assert(operation.cast(StateMachine) == .echo);
|
|
233
|
+
assert(std.mem.eql(u8, request_body, reply_body));
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
pub const Options = struct {
|
|
237
|
+
pub fn generate(random: std.rand.Random, options: struct {
|
|
238
|
+
client_count: usize,
|
|
239
|
+
in_flight_max: usize,
|
|
240
|
+
}) Options {
|
|
241
|
+
_ = random;
|
|
242
|
+
_ = options;
|
|
243
|
+
return .{};
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
};
|
|
247
|
+
}
|
|
@@ -25,6 +25,7 @@ const assert = std.debug.assert;
|
|
|
25
25
|
const math = std.math;
|
|
26
26
|
const mem = std.mem;
|
|
27
27
|
|
|
28
|
+
const FIFO = @import("../fifo.zig").FIFO;
|
|
28
29
|
const constants = @import("../constants.zig");
|
|
29
30
|
const vsr = @import("../vsr.zig");
|
|
30
31
|
const superblock = @import("../vsr/superblock.zig");
|
|
@@ -119,6 +120,11 @@ pub const Storage = struct {
|
|
|
119
120
|
}
|
|
120
121
|
};
|
|
121
122
|
|
|
123
|
+
pub const NextTick = struct {
|
|
124
|
+
next: ?*NextTick = null,
|
|
125
|
+
callback: fn (next_tick: *NextTick) void,
|
|
126
|
+
};
|
|
127
|
+
|
|
122
128
|
/// Faulty areas are always sized to message_size_max
|
|
123
129
|
/// If the faulty areas of all replicas are superimposed, the padding between them is always message_size_max.
|
|
124
130
|
/// For a single replica, the padding between faulty areas depends on the number of other replicas.
|
|
@@ -148,6 +154,7 @@ pub const Storage = struct {
|
|
|
148
154
|
writes: std.PriorityQueue(*Storage.Write, void, Storage.Write.less_than),
|
|
149
155
|
|
|
150
156
|
ticks: u64 = 0,
|
|
157
|
+
next_tick_queue: FIFO(NextTick) = .{},
|
|
151
158
|
|
|
152
159
|
pub fn init(allocator: mem.Allocator, size: u64, options: Storage.Options) !Storage {
|
|
153
160
|
assert(options.write_latency_mean >= options.write_latency_min);
|
|
@@ -222,6 +229,7 @@ pub const Storage = struct {
|
|
|
222
229
|
}
|
|
223
230
|
|
|
224
231
|
pub fn deinit(storage: *Storage, allocator: mem.Allocator) void {
|
|
232
|
+
assert(storage.next_tick_queue.empty());
|
|
225
233
|
allocator.free(storage.memory);
|
|
226
234
|
storage.memory_written.deinit(allocator);
|
|
227
235
|
storage.faults.deinit(allocator);
|
|
@@ -280,6 +288,19 @@ pub const Storage = struct {
|
|
|
280
288
|
_ = storage.writes.remove();
|
|
281
289
|
storage.write_sectors_finish(write);
|
|
282
290
|
}
|
|
291
|
+
|
|
292
|
+
var queue = storage.next_tick_queue;
|
|
293
|
+
storage.next_tick_queue = .{};
|
|
294
|
+
while (queue.pop()) |next_tick| next_tick.callback(next_tick);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
pub fn on_next_tick(
|
|
298
|
+
storage: *Storage,
|
|
299
|
+
callback: fn (next_tick: *Storage.NextTick) void,
|
|
300
|
+
next_tick: *Storage.NextTick,
|
|
301
|
+
) void {
|
|
302
|
+
next_tick.* = .{ .callback = callback };
|
|
303
|
+
storage.next_tick_queue.push(next_tick);
|
|
283
304
|
}
|
|
284
305
|
|
|
285
306
|
/// * Verifies that the read fits within the target sector.
|
|
@@ -787,7 +808,7 @@ pub const Storage = struct {
|
|
|
787
808
|
pub fn grid_block(
|
|
788
809
|
storage: *const Storage,
|
|
789
810
|
address: u64,
|
|
790
|
-
) *align(constants.sector_size)
|
|
811
|
+
) *align(constants.sector_size) [constants.block_size]u8 {
|
|
791
812
|
assert(address > 0);
|
|
792
813
|
|
|
793
814
|
const block_offset = vsr.Zone.grid.offset((address - 1) * constants.block_size);
|
|
@@ -73,15 +73,11 @@ pub const Event = union(enum) {
|
|
|
73
73
|
state_machine_prefetch,
|
|
74
74
|
state_machine_commit,
|
|
75
75
|
state_machine_compact,
|
|
76
|
-
tree_compaction_beat
|
|
77
|
-
tree_name: []const u8,
|
|
78
|
-
},
|
|
76
|
+
tree_compaction_beat,
|
|
79
77
|
tree_compaction_tick: struct {
|
|
80
|
-
tree_name: []const u8,
|
|
81
78
|
level_b: u8,
|
|
82
79
|
},
|
|
83
80
|
tree_compaction_merge: struct {
|
|
84
|
-
tree_name: []const u8,
|
|
85
81
|
level_b: u8,
|
|
86
82
|
},
|
|
87
83
|
|
|
@@ -95,24 +91,50 @@ pub const Event = union(enum) {
|
|
|
95
91
|
_ = options;
|
|
96
92
|
|
|
97
93
|
switch (event) {
|
|
98
|
-
.tracer_flush
|
|
94
|
+
.tracer_flush,
|
|
95
|
+
.checkpoint,
|
|
96
|
+
.state_machine_prefetch,
|
|
97
|
+
.state_machine_commit,
|
|
98
|
+
.state_machine_compact,
|
|
99
|
+
.tree_compaction_beat,
|
|
100
|
+
=> try writer.writeAll(@tagName(event)),
|
|
99
101
|
.commit => |commit| try writer.print("commit({})", .{commit.op}),
|
|
100
|
-
.
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
102
|
+
.tree_compaction_tick => |args| {
|
|
103
|
+
if (args.level_b == 0)
|
|
104
|
+
try writer.print(
|
|
105
|
+
"tree_compaction_tick({s}->{})",
|
|
106
|
+
.{
|
|
107
|
+
"immutable",
|
|
108
|
+
args.level_b,
|
|
109
|
+
},
|
|
110
|
+
)
|
|
111
|
+
else
|
|
112
|
+
try writer.print(
|
|
113
|
+
"tree_compaction_tick({}->{})",
|
|
114
|
+
.{
|
|
115
|
+
args.level_b - 1,
|
|
116
|
+
args.level_b,
|
|
117
|
+
},
|
|
118
|
+
);
|
|
119
|
+
},
|
|
120
|
+
.tree_compaction_merge => |args| {
|
|
121
|
+
if (args.level_b == 0)
|
|
122
|
+
try writer.print(
|
|
123
|
+
"tree_compaction_merge({s}->{})",
|
|
124
|
+
.{
|
|
125
|
+
"immutable",
|
|
126
|
+
args.level_b,
|
|
127
|
+
},
|
|
128
|
+
)
|
|
129
|
+
else
|
|
130
|
+
try writer.print(
|
|
131
|
+
"tree_compaction_merge({}->{})",
|
|
132
|
+
.{
|
|
133
|
+
args.level_b - 1,
|
|
134
|
+
args.level_b,
|
|
135
|
+
},
|
|
136
|
+
);
|
|
137
|
+
},
|
|
116
138
|
}
|
|
117
139
|
}
|
|
118
140
|
};
|
|
@@ -124,12 +146,16 @@ pub const EventGroup = union(enum) {
|
|
|
124
146
|
tree: struct {
|
|
125
147
|
tree_name: [:0]const u8,
|
|
126
148
|
},
|
|
149
|
+
tree_compaction: struct {
|
|
150
|
+
compaction_name: [:0]const u8,
|
|
151
|
+
},
|
|
127
152
|
|
|
128
153
|
fn name(event_group: EventGroup) [:0]const u8 {
|
|
129
154
|
return switch (event_group) {
|
|
130
155
|
.main => "main",
|
|
131
156
|
.tracer => "tracer",
|
|
132
|
-
.tree => |
|
|
157
|
+
.tree => |args| args.tree_name,
|
|
158
|
+
.tree_compaction => |args| args.compaction_name,
|
|
133
159
|
};
|
|
134
160
|
}
|
|
135
161
|
};
|
|
@@ -317,11 +343,7 @@ pub const TracerPerfetto = struct {
|
|
|
317
343
|
},
|
|
318
344
|
};
|
|
319
345
|
|
|
320
|
-
const tid_64 =
|
|
321
|
-
.main => 0,
|
|
322
|
-
.tracer => 1,
|
|
323
|
-
.tree => |tree| std.hash_map.hashString(tree.tree_name),
|
|
324
|
-
};
|
|
346
|
+
const tid_64 = std.hash_map.hashString(span.group.name());
|
|
325
347
|
const tid = @truncate(u32, tid_64) ^ @truncate(u32, tid_64 >> 32);
|
|
326
348
|
|
|
327
349
|
var buffered_writer = std.io.bufferedWriter(log_file.writer());
|
|
@@ -11,18 +11,18 @@ test {
|
|
|
11
11
|
//_ = @import("vsr/clock.zig");
|
|
12
12
|
|
|
13
13
|
_ = @import("state_machine.zig");
|
|
14
|
+
_ = @import("state_machine/auditor.zig");
|
|
15
|
+
_ = @import("state_machine/workload.zig");
|
|
14
16
|
|
|
15
17
|
_ = @import("fifo.zig");
|
|
16
18
|
_ = @import("ring_buffer.zig");
|
|
17
19
|
|
|
18
20
|
_ = @import("io.zig");
|
|
19
|
-
|
|
20
|
-
_ = @import("cli.zig");
|
|
21
21
|
_ = @import("ewah.zig");
|
|
22
22
|
_ = @import("util.zig");
|
|
23
23
|
|
|
24
|
-
_ = @import("c/test.zig");
|
|
25
|
-
_ = @import("c/tb_client_header_test.zig");
|
|
24
|
+
_ = @import("clients/c/test.zig");
|
|
25
|
+
_ = @import("clients/c/tb_client_header_test.zig");
|
|
26
26
|
|
|
27
27
|
// TODO Add remaining unit tests from lsm namespace.
|
|
28
28
|
_ = @import("lsm/forest.zig");
|
|
@@ -30,8 +30,13 @@ test {
|
|
|
30
30
|
_ = @import("lsm/segmented_array.zig");
|
|
31
31
|
|
|
32
32
|
_ = @import("test/id.zig");
|
|
33
|
-
_ = @import("test/accounting/auditor.zig");
|
|
34
|
-
_ = @import("test/accounting/workload.zig");
|
|
35
33
|
_ = @import("test/storage.zig");
|
|
36
34
|
_ = @import("test/table.zig");
|
|
35
|
+
|
|
36
|
+
_ = @import("clients/go/go_bindings_test.zig");
|
|
37
|
+
_ = @import("clients/dotnet/dotnet_bindings_test.zig");
|
|
38
|
+
_ = @import("clients/java/java_bindings.zig");
|
|
39
|
+
|
|
40
|
+
// This one is a bit sketchy: we rely on tests not actually using the `vsr` package.
|
|
41
|
+
_ = @import("tigerbeetle/cli.zig");
|
|
37
42
|
}
|
|
@@ -138,14 +138,14 @@ fn build_simulator(
|
|
|
138
138
|
mode: std.builtin.Mode,
|
|
139
139
|
) void {
|
|
140
140
|
const mode_str = switch (mode) {
|
|
141
|
-
.Debug => "-
|
|
142
|
-
.ReleaseSafe => "-
|
|
141
|
+
.Debug => "-Ddebug",
|
|
142
|
+
.ReleaseSafe => "-Drelease-safe",
|
|
143
143
|
else => unreachable,
|
|
144
144
|
};
|
|
145
145
|
|
|
146
146
|
const exec_result = std.ChildProcess.exec(.{
|
|
147
147
|
.allocator = allocator,
|
|
148
|
-
.argv = &.{ "zig/zig", "build
|
|
148
|
+
.argv = &.{ "zig/zig", "build", "simulator", mode_str },
|
|
149
149
|
}) catch |err| {
|
|
150
150
|
fatal("unable to build the simulator binary. Error: {}", .{err});
|
|
151
151
|
};
|
|
@@ -184,7 +184,7 @@ fn run_simulator(
|
|
|
184
184
|
// simulator's exit code.
|
|
185
185
|
const exit_code = run_child_process(
|
|
186
186
|
allocator,
|
|
187
|
-
&.{ "./simulator", seed_str.items },
|
|
187
|
+
&.{ "./zig-out/bin/simulator", seed_str.items },
|
|
188
188
|
);
|
|
189
189
|
|
|
190
190
|
const result = switch (exit_code) {
|