tigerbeetle-node 0.5.0 → 0.5.1

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 (46) hide show
  1. package/package.json +2 -2
  2. package/scripts/postinstall.sh +2 -2
  3. package/src/node.zig +17 -15
  4. package/src/tigerbeetle/scripts/install.sh +1 -1
  5. package/src/tigerbeetle/scripts/install_zig.bat +3 -3
  6. package/src/tigerbeetle/scripts/install_zig.sh +4 -2
  7. package/src/tigerbeetle/scripts/lint.zig +8 -2
  8. package/src/tigerbeetle/src/benchmark.zig +8 -6
  9. package/src/tigerbeetle/src/cli.zig +6 -4
  10. package/src/tigerbeetle/src/config.zig +2 -2
  11. package/src/tigerbeetle/src/demo.zig +119 -97
  12. package/src/tigerbeetle/src/demo_01_create_accounts.zig +5 -3
  13. package/src/tigerbeetle/src/demo_02_lookup_accounts.zig +2 -3
  14. package/src/tigerbeetle/src/demo_03_create_transfers.zig +5 -3
  15. package/src/tigerbeetle/src/demo_04_create_transfers_two_phase_commit.zig +5 -3
  16. package/src/tigerbeetle/src/demo_05_accept_transfers.zig +5 -3
  17. package/src/tigerbeetle/src/demo_06_reject_transfers.zig +5 -3
  18. package/src/tigerbeetle/src/demo_07_lookup_transfers.zig +2 -3
  19. package/src/tigerbeetle/src/io/benchmark.zig +238 -0
  20. package/src/tigerbeetle/src/{io_darwin.zig → io/darwin.zig} +88 -127
  21. package/src/tigerbeetle/src/io/linux.zig +933 -0
  22. package/src/tigerbeetle/src/io/test.zig +621 -0
  23. package/src/tigerbeetle/src/io.zig +7 -1328
  24. package/src/tigerbeetle/src/main.zig +18 -10
  25. package/src/tigerbeetle/src/message_bus.zig +43 -54
  26. package/src/tigerbeetle/src/message_pool.zig +3 -2
  27. package/src/tigerbeetle/src/simulator.zig +41 -37
  28. package/src/tigerbeetle/src/state_machine.zig +58 -27
  29. package/src/tigerbeetle/src/storage.zig +49 -46
  30. package/src/tigerbeetle/src/test/cluster.zig +2 -2
  31. package/src/tigerbeetle/src/test/message_bus.zig +6 -6
  32. package/src/tigerbeetle/src/test/network.zig +3 -3
  33. package/src/tigerbeetle/src/test/packet_simulator.zig +32 -29
  34. package/src/tigerbeetle/src/test/state_checker.zig +1 -1
  35. package/src/tigerbeetle/src/test/state_machine.zig +4 -0
  36. package/src/tigerbeetle/src/test/storage.zig +23 -19
  37. package/src/tigerbeetle/src/test/time.zig +2 -2
  38. package/src/tigerbeetle/src/tigerbeetle.zig +6 -128
  39. package/src/tigerbeetle/src/time.zig +6 -5
  40. package/src/tigerbeetle/src/vsr/client.zig +7 -7
  41. package/src/tigerbeetle/src/vsr/clock.zig +26 -43
  42. package/src/tigerbeetle/src/vsr/journal.zig +7 -6
  43. package/src/tigerbeetle/src/vsr/marzullo.zig +6 -3
  44. package/src/tigerbeetle/src/vsr/replica.zig +49 -46
  45. package/src/tigerbeetle/src/vsr.zig +24 -20
  46. package/src/translate.zig +55 -55
@@ -20,12 +20,20 @@ const vsr = @import("vsr.zig");
20
20
  const Replica = vsr.Replica(StateMachine, MessageBus, Storage, Time);
21
21
 
22
22
  pub fn main() !void {
23
- var arena_allocator = std.heap.ArenaAllocator.init(std.heap.page_allocator);
24
- const arena = &arena_allocator.allocator;
23
+ var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
24
+ defer arena.deinit();
25
25
 
26
- switch (cli.parse_args(arena)) {
27
- .init => |args| try init(arena, args.cluster, args.replica, args.dir_fd),
28
- .start => |args| try start(arena, args.cluster, args.replica, args.addresses, args.dir_fd),
26
+ const allocator = arena.allocator();
27
+
28
+ switch (cli.parse_args(allocator)) {
29
+ .init => |args| try init(args.cluster, args.replica, args.dir_fd),
30
+ .start => |args| try start(
31
+ allocator,
32
+ args.cluster,
33
+ args.replica,
34
+ args.addresses,
35
+ args.dir_fd,
36
+ ),
29
37
  }
30
38
  }
31
39
 
@@ -34,7 +42,7 @@ const filename_fmt = "cluster_{d:0>10}_replica_{d:0>3}.tigerbeetle";
34
42
  const filename_len = fmt.count(filename_fmt, .{ 0, 0 });
35
43
 
36
44
  /// Create a .tigerbeetle data file for the given args and exit
37
- fn init(arena: *mem.Allocator, cluster: u32, replica: u8, dir_fd: os.fd_t) !void {
45
+ fn init(cluster: u32, replica: u8, dir_fd: os.fd_t) !void {
38
46
  // Add 1 for the terminating null byte
39
47
  var buffer: [filename_len + 1]u8 = undefined;
40
48
  const filename = fmt.bufPrintZ(&buffer, filename_fmt, .{ cluster, replica }) catch unreachable;
@@ -53,7 +61,7 @@ fn init(arena: *mem.Allocator, cluster: u32, replica: u8, dir_fd: os.fd_t) !void
53
61
 
54
62
  /// Run as a replica server defined by the given args
55
63
  fn start(
56
- arena: *mem.Allocator,
64
+ allocator: mem.Allocator,
57
65
  cluster: u32,
58
66
  replica_index: u8,
59
67
  addresses: []std.net.Address,
@@ -75,14 +83,14 @@ fn start(
75
83
  );
76
84
  var io = try IO.init(128, 0);
77
85
  var state_machine = try StateMachine.init(
78
- arena,
86
+ allocator,
79
87
  config.accounts_max,
80
88
  config.transfers_max,
81
89
  config.commits_max,
82
90
  );
83
91
  var storage = try Storage.init(config.journal_size_max, storage_fd, &io);
84
92
  var message_bus = try MessageBus.init(
85
- arena,
93
+ allocator,
86
94
  cluster,
87
95
  addresses,
88
96
  replica_index,
@@ -90,7 +98,7 @@ fn start(
90
98
  );
91
99
  var time: Time = .{};
92
100
  var replica = try Replica.init(
93
- arena,
101
+ allocator,
94
102
  cluster,
95
103
  @intCast(u8, addresses.len),
96
104
  replica_index,
@@ -1,10 +1,10 @@
1
1
  const std = @import("std");
2
+ const builtin = @import("builtin");
2
3
  const assert = std.debug.assert;
3
4
  const mem = std.mem;
4
5
  const os = std.os;
5
6
 
6
- const is_darwin = std.Target.current.isDarwin();
7
- const sock_flags = os.SOCK_CLOEXEC | (if (is_darwin) os.SOCK_NONBLOCK else 0);
7
+ const is_linux = builtin.target.os.tag == .linux;
8
8
 
9
9
  const config = @import("config.zig");
10
10
  const log = std.log.scoped(.message_bus);
@@ -54,8 +54,8 @@ fn MessageBusImpl(comptime process_type: ProcessType) type {
54
54
 
55
55
  /// The callback to be called when a message is received. Use set_on_message() to set
56
56
  /// with type safety for the context pointer.
57
- on_message_callback: ?fn (context: ?*c_void, message: *Message) void = null,
58
- on_message_context: ?*c_void = null,
57
+ on_message_callback: ?fn (context: ?*anyopaque, message: *Message) void = null,
58
+ on_message_context: ?*anyopaque = null,
59
59
 
60
60
  /// This slice is allocated with a fixed size in the init function and never reallocated.
61
61
  connections: []Connection,
@@ -75,7 +75,7 @@ fn MessageBusImpl(comptime process_type: ProcessType) type {
75
75
 
76
76
  /// Initialize the MessageBus for the given cluster, configuration and replica/client process.
77
77
  pub fn init(
78
- allocator: *mem.Allocator,
78
+ allocator: mem.Allocator,
79
79
  cluster: u32,
80
80
  configuration: []std.net.Address,
81
81
  process: switch (process_type) {
@@ -124,7 +124,7 @@ fn MessageBusImpl(comptime process_type: ProcessType) type {
124
124
 
125
125
  // Pre-allocate enough memory to hold all possible connections in the client map.
126
126
  if (process_type == .replica) {
127
- try bus.process.clients.ensureCapacity(allocator, config.connections_max);
127
+ try bus.process.clients.ensureTotalCapacity(allocator, config.connections_max);
128
128
  }
129
129
 
130
130
  return bus;
@@ -140,7 +140,7 @@ fn MessageBusImpl(comptime process_type: ProcessType) type {
140
140
  assert(bus.on_message_context == null);
141
141
 
142
142
  bus.on_message_callback = struct {
143
- fn wrapper(_context: ?*c_void, message: *Message) void {
143
+ fn wrapper(_context: ?*anyopaque, message: *Message) void {
144
144
  on_message(@intToPtr(Context, @ptrToInt(_context)), message);
145
145
  }
146
146
  }.wrapper;
@@ -148,13 +148,13 @@ fn MessageBusImpl(comptime process_type: ProcessType) type {
148
148
  }
149
149
 
150
150
  /// TODO This is required by the Client.
151
- pub fn deinit(bus: *Self) void {}
151
+ pub fn deinit(_: *Self) void {}
152
152
 
153
153
  fn init_tcp(address: std.net.Address) !os.socket_t {
154
- const fd = try os.socket(
154
+ const fd = try IO.openSocket(
155
155
  address.any.family,
156
- os.SOCK_STREAM | sock_flags,
157
- os.IPPROTO_TCP,
156
+ os.SOCK.STREAM,
157
+ os.IPPROTO.TCP,
158
158
  );
159
159
  errdefer os.close(fd);
160
160
 
@@ -164,71 +164,61 @@ fn MessageBusImpl(comptime process_type: ProcessType) type {
164
164
  }
165
165
  }.set;
166
166
 
167
- // darwin doesn't support os.MSG_NOSIGNAL, but instead a socket option to avoid SIGPIPE.
168
- if (is_darwin) {
169
- try set(fd, os.SOL_SOCKET, os.SO_NOSIGPIPE, 1);
170
- }
171
-
172
167
  // Set tcp recv buffer size
173
168
  if (config.tcp_rcvbuf > 0) rcvbuf: {
174
- if (!is_darwin) {
169
+ if (is_linux) {
175
170
  // Requires CAP_NET_ADMIN privilege (settle for SO_RCVBUF in case of an EPERM):
176
- if (set(fd, os.SOL_SOCKET, os.SO_RCVBUFFORCE, config.tcp_rcvbuf)) |_| {
171
+ if (set(fd, os.SOL.SOCKET, os.SO.RCVBUFFORCE, config.tcp_rcvbuf)) |_| {
177
172
  break :rcvbuf;
178
173
  } else |err| switch (err) {
179
174
  error.PermissionDenied => {},
180
175
  else => |e| return e,
181
176
  }
182
177
  }
183
- try set(fd, os.SOL_SOCKET, os.SO_RCVBUF, config.tcp_rcvbuf);
178
+ try set(fd, os.SOL.SOCKET, os.SO.RCVBUF, config.tcp_rcvbuf);
184
179
  }
185
180
 
186
181
  // Set tcp send buffer size
187
182
  if (config.tcp_sndbuf > 0) sndbuf: {
188
- if (!is_darwin) {
183
+ if (is_linux) {
189
184
  // Requires CAP_NET_ADMIN privilege (settle for SO_SNDBUF in case of an EPERM):
190
- if (set(fd, os.SOL_SOCKET, os.SO_SNDBUFFORCE, config.tcp_sndbuf)) |_| {
185
+ if (set(fd, os.SOL.SOCKET, os.SO.SNDBUFFORCE, config.tcp_sndbuf)) |_| {
191
186
  break :sndbuf;
192
187
  } else |err| switch (err) {
193
188
  error.PermissionDenied => {},
194
189
  else => |e| return e,
195
190
  }
196
191
  }
197
- try set(fd, os.SOL_SOCKET, os.SO_SNDBUF, config.tcp_sndbuf);
192
+ try set(fd, os.SOL.SOCKET, os.SO.SNDBUF, config.tcp_sndbuf);
198
193
  }
199
194
 
200
195
  // Set tcp keep alive
201
196
  if (config.tcp_keepalive) {
202
- try set(fd, os.SOL_SOCKET, os.SO_KEEPALIVE, 1);
203
- if (!is_darwin) {
204
- try set(fd, os.IPPROTO_TCP, os.TCP_KEEPIDLE, config.tcp_keepidle);
205
- try set(fd, os.IPPROTO_TCP, os.TCP_KEEPINTVL, config.tcp_keepintvl);
206
- try set(fd, os.IPPROTO_TCP, os.TCP_KEEPCNT, config.tcp_keepcnt);
197
+ try set(fd, os.SOL.SOCKET, os.SO.KEEPALIVE, 1);
198
+ if (is_linux) {
199
+ try set(fd, os.IPPROTO.TCP, os.TCP_KEEPIDLE, config.tcp_keepidle);
200
+ try set(fd, os.IPPROTO.TCP, os.TCP_KEEPINTVL, config.tcp_keepintvl);
201
+ try set(fd, os.IPPROTO.TCP, os.TCP_KEEPCNT, config.tcp_keepcnt);
207
202
  }
208
203
  }
209
204
 
210
205
  // Set tcp user timeout
211
206
  if (config.tcp_user_timeout > 0) {
212
- if (!is_darwin) {
213
- try set(fd, os.IPPROTO_TCP, os.TCP_USER_TIMEOUT, config.tcp_user_timeout);
207
+ if (is_linux) {
208
+ try set(fd, os.IPPROTO.TCP, os.TCP_USER_TIMEOUT, config.tcp_user_timeout);
214
209
  }
215
210
  }
216
211
 
217
212
  // Set tcp no-delay
218
213
  if (config.tcp_nodelay) {
219
- const TCP_NODELAY: ?u32 = if (@hasDecl(os, "TCP_NODELAY"))
220
- @as(u32, os.TCP_NODELAY)
221
- else if (is_darwin)
222
- @as(u32, 1)
223
- else
224
- null;
225
-
226
- if (TCP_NODELAY) |tcp_nodelay| {
227
- try set(fd, os.IPPROTO_TCP, tcp_nodelay, 1);
228
- }
214
+ // TODO: use the version in the zig standard library when upgrading to 0.9
215
+ // https://github.com/rust-lang/libc/search?q=TCP_NODELAY
216
+ // https://github.com/ziglang/zig/search?q=TCP_NODELAY
217
+ const TCP_NODELAY: u32 = 1;
218
+ try set(fd, os.IPPROTO.TCP, TCP_NODELAY, 1);
229
219
  }
230
220
 
231
- try set(fd, os.SOL_SOCKET, os.SO_REUSEADDR, 1);
221
+ try set(fd, os.SOL.SOCKET, os.SO.REUSEADDR, 1);
232
222
  try os.bind(fd, &address.any, address.getOsSockLen());
233
223
  try os.listen(fd, config.tcp_backlog);
234
224
 
@@ -289,7 +279,7 @@ fn MessageBusImpl(comptime process_type: ProcessType) type {
289
279
  if (connection.state == .terminating) return;
290
280
  }
291
281
 
292
- log.notice("all connections in use but not all replicas are connected, " ++
282
+ log.info("all connections in use but not all replicas are connected, " ++
293
283
  "attempting to disconnect a client", .{});
294
284
  for (bus.connections) |*connection| {
295
285
  if (connection.peer == .client) {
@@ -298,7 +288,7 @@ fn MessageBusImpl(comptime process_type: ProcessType) type {
298
288
  }
299
289
  }
300
290
 
301
- log.notice("failed to disconnect a client as no peer was a known client, " ++
291
+ log.info("failed to disconnect a client as no peer was a known client, " ++
302
292
  "attempting to disconnect an unknown peer.", .{});
303
293
  for (bus.connections) |*connection| {
304
294
  if (connection.peer == .unknown) {
@@ -332,7 +322,6 @@ fn MessageBusImpl(comptime process_type: ProcessType) type {
332
322
  on_accept,
333
323
  &bus.process.accept_completion,
334
324
  bus.process.accept_fd,
335
- sock_flags,
336
325
  );
337
326
  }
338
327
 
@@ -341,6 +330,8 @@ fn MessageBusImpl(comptime process_type: ProcessType) type {
341
330
  completion: *IO.Completion,
342
331
  result: IO.AcceptError!os.socket_t,
343
332
  ) void {
333
+ _ = completion;
334
+
344
335
  comptime assert(process_type == .replica);
345
336
  assert(bus.process.accept_connection != null);
346
337
  defer bus.process.accept_connection = null;
@@ -459,7 +450,7 @@ fn MessageBusImpl(comptime process_type: ProcessType) type {
459
450
  // The first replica's network address family determines the
460
451
  // family for all other replicas:
461
452
  const family = bus.configuration[0].any.family;
462
- connection.fd = os.socket(family, os.SOCK_STREAM | sock_flags, 0) catch return;
453
+ connection.fd = IO.openSocket(family, os.SOCK.STREAM, os.IPPROTO.TCP) catch return;
463
454
  connection.peer = .{ .replica = replica };
464
455
  connection.state = .connecting;
465
456
  bus.connections_used += 1;
@@ -469,7 +460,7 @@ fn MessageBusImpl(comptime process_type: ProcessType) type {
469
460
 
470
461
  var attempts = &bus.replicas_connect_attempts[replica];
471
462
  const ms = vsr.exponential_backoff_with_jitter(
472
- &bus.prng,
463
+ bus.prng.random(),
473
464
  config.connection_delay_min_ms,
474
465
  config.connection_delay_max_ms,
475
466
  attempts.*,
@@ -600,7 +591,7 @@ fn MessageBusImpl(comptime process_type: ProcessType) type {
600
591
  connection.send_queue.push(message.ref()) catch |err| switch (err) {
601
592
  error.NoSpaceLeft => {
602
593
  bus.unref(message);
603
- log.notice("message queue for peer {} full, dropping message", .{
594
+ log.info("message queue for peer {} full, dropping message", .{
604
595
  connection.peer,
605
596
  });
606
597
  return;
@@ -633,12 +624,12 @@ fn MessageBusImpl(comptime process_type: ProcessType) type {
633
624
  //
634
625
  // TODO: Investigate differences between shutdown() on Linux vs Darwin.
635
626
  // Especially how this interacts with our assumptions around pending I/O.
636
- const rc = os.system.shutdown(connection.fd, os.SHUT_RDWR);
627
+ const rc = os.system.shutdown(connection.fd, os.SHUT.RDWR);
637
628
  switch (os.errno(rc)) {
638
- 0 => {},
639
- os.EBADF => unreachable,
640
- os.EINVAL => unreachable,
641
- os.ENOTCONN => {
629
+ .SUCCESS => {},
630
+ .BADF => unreachable,
631
+ .INVAL => unreachable,
632
+ .NOTCONN => {
642
633
  // This should only happen if we for some reason decide to terminate
643
634
  // a connection while a connect operation is in progress.
644
635
  // This is fine though, we simply continue with the logic below and
@@ -653,7 +644,7 @@ fn MessageBusImpl(comptime process_type: ProcessType) type {
653
644
  //assert(connection.recv_submitted);
654
645
  //assert(!connection.send_submitted);
655
646
  },
656
- os.ENOTSOCK => unreachable,
647
+ .NOTSOCK => unreachable,
657
648
  else => |err| os.unexpectedErrno(err) catch {},
658
649
  }
659
650
  },
@@ -886,7 +877,6 @@ fn MessageBusImpl(comptime process_type: ProcessType) type {
886
877
  &connection.recv_completion,
887
878
  connection.fd,
888
879
  connection.recv_message.?.buffer[connection.recv_progress..config.message_size_max],
889
- if (is_darwin) 0 else os.MSG_NOSIGNAL,
890
880
  );
891
881
  }
892
882
 
@@ -929,7 +919,6 @@ fn MessageBusImpl(comptime process_type: ProcessType) type {
929
919
  &connection.send_completion,
930
920
  connection.fd,
931
921
  message.buffer[connection.send_progress..message.header.size],
932
- if (is_darwin) 0 else os.MSG_NOSIGNAL,
933
922
  );
934
923
  }
935
924
 
@@ -1,4 +1,5 @@
1
1
  const std = @import("std");
2
+ const builtin = @import("builtin");
2
3
  const assert = std.debug.assert;
3
4
  const mem = std.mem;
4
5
 
@@ -51,7 +52,7 @@ pub const MessagePool = struct {
51
52
  /// List of currently usused header-sized messages
52
53
  header_only_free_list: ?*Message,
53
54
 
54
- pub fn init(allocator: *mem.Allocator) error{OutOfMemory}!MessagePool {
55
+ pub fn init(allocator: mem.Allocator) error{OutOfMemory}!MessagePool {
55
56
  var ret: MessagePool = .{
56
57
  .free_list = null,
57
58
  .header_only_free_list = null,
@@ -119,7 +120,7 @@ pub const MessagePool = struct {
119
120
  pub fn unref(pool: *MessagePool, message: *Message) void {
120
121
  message.references -= 1;
121
122
  if (message.references == 0) {
122
- if (std.builtin.mode == .Debug) mem.set(u8, message.buffer, undefined);
123
+ if (builtin.mode == .Debug) mem.set(u8, message.buffer, undefined);
123
124
  if (message.header_only()) {
124
125
  message.next = pool.header_only_free_list;
125
126
  pool.header_only_free_list = message;
@@ -1,4 +1,5 @@
1
1
  const std = @import("std");
2
+ const builtin = @import("builtin");
2
3
  const assert = std.debug.assert;
3
4
  const mem = std.mem;
4
5
 
@@ -17,7 +18,7 @@ const output = std.log.scoped(.state_checker);
17
18
 
18
19
  /// Set this to `false` if you want to see how literally everything works.
19
20
  /// This will run much slower but will trace all logic across the cluster.
20
- const log_state_transitions_only = std.builtin.mode != .Debug;
21
+ const log_state_transitions_only = builtin.mode != .Debug;
21
22
 
22
23
  /// You can fine tune your log levels even further (debug/info/notice/warn/err/crit/alert/emerg):
23
24
  pub const log_level: std.log.Level = if (log_state_transitions_only) .info else .debug;
@@ -40,13 +41,13 @@ pub fn main() !void {
40
41
  break :seed_from_arg parse_seed(arg_two);
41
42
  };
42
43
 
43
- if (std.builtin.mode == .ReleaseFast or std.builtin.mode == .ReleaseSmall) {
44
+ if (builtin.mode == .ReleaseFast or builtin.mode == .ReleaseSmall) {
44
45
  // We do not support ReleaseFast or ReleaseSmall because they disable assertions.
45
46
  @panic("the simulator must be run with -OReleaseSafe");
46
47
  }
47
48
 
48
49
  if (seed == seed_random) {
49
- if (std.builtin.mode != .ReleaseSafe) {
50
+ if (builtin.mode != .ReleaseSafe) {
50
51
  // If no seed is provided, than Debug is too slow and ReleaseSafe is much faster.
51
52
  @panic("no seed provided: the simulator must be run with -OReleaseSafe");
52
53
  }
@@ -56,53 +57,53 @@ pub fn main() !void {
56
57
  }
57
58
 
58
59
  var prng = std.rand.DefaultPrng.init(seed);
59
- const random = &prng.random;
60
+ const random = prng.random();
60
61
 
61
- const replica_count = 1 + prng.random.uintLessThan(u8, config.replicas_max);
62
- const client_count = 1 + prng.random.uintLessThan(u8, config.clients_max);
62
+ const replica_count = 1 + random.uintLessThan(u8, config.replicas_max);
63
+ const client_count = 1 + random.uintLessThan(u8, config.clients_max);
63
64
  const node_count = replica_count + client_count;
64
65
 
65
66
  const ticks_max = 100_000_000;
66
67
  const transitions_max = config.journal_size_max / config.message_size_max;
67
- const request_probability = 1 + prng.random.uintLessThan(u8, 99);
68
- const idle_on_probability = prng.random.uintLessThan(u8, 20);
69
- const idle_off_probability = 10 + prng.random.uintLessThan(u8, 10);
68
+ const request_probability = 1 + random.uintLessThan(u8, 99);
69
+ const idle_on_probability = random.uintLessThan(u8, 20);
70
+ const idle_off_probability = 10 + random.uintLessThan(u8, 10);
70
71
 
71
- cluster = try Cluster.create(allocator, &prng.random, .{
72
+ cluster = try Cluster.create(allocator, random, .{
72
73
  .cluster = 0,
73
74
  .replica_count = replica_count,
74
75
  .client_count = client_count,
75
- .seed = prng.random.int(u64),
76
+ .seed = random.int(u64),
76
77
  .network_options = .{
77
78
  .packet_simulator_options = .{
78
79
  .replica_count = replica_count,
79
80
  .client_count = client_count,
80
81
  .node_count = node_count,
81
82
 
82
- .seed = prng.random.int(u64),
83
- .one_way_delay_mean = 3 + prng.random.uintLessThan(u16, 10),
84
- .one_way_delay_min = prng.random.uintLessThan(u16, 3),
85
- .packet_loss_probability = prng.random.uintLessThan(u8, 30),
86
- .path_maximum_capacity = 20 + prng.random.uintLessThan(u8, 20),
87
- .path_clog_duration_mean = prng.random.uintLessThan(u16, 500),
88
- .path_clog_probability = prng.random.uintLessThan(u8, 2),
89
- .packet_replay_probability = prng.random.uintLessThan(u8, 50),
83
+ .seed = random.int(u64),
84
+ .one_way_delay_mean = 3 + random.uintLessThan(u16, 10),
85
+ .one_way_delay_min = random.uintLessThan(u16, 3),
86
+ .packet_loss_probability = random.uintLessThan(u8, 30),
87
+ .path_maximum_capacity = 20 + random.uintLessThan(u8, 20),
88
+ .path_clog_duration_mean = random.uintLessThan(u16, 500),
89
+ .path_clog_probability = random.uintLessThan(u8, 2),
90
+ .packet_replay_probability = random.uintLessThan(u8, 50),
90
91
 
91
92
  .partition_mode = random_partition_mode(random),
92
- .partition_probability = prng.random.uintLessThan(u8, 3),
93
- .unpartition_probability = 1 + prng.random.uintLessThan(u8, 10),
94
- .partition_stability = 100 + prng.random.uintLessThan(u32, 100),
95
- .unpartition_stability = prng.random.uintLessThan(u32, 20),
93
+ .partition_probability = random.uintLessThan(u8, 3),
94
+ .unpartition_probability = 1 + random.uintLessThan(u8, 10),
95
+ .partition_stability = 100 + random.uintLessThan(u32, 100),
96
+ .unpartition_stability = random.uintLessThan(u32, 20),
96
97
  },
97
98
  },
98
99
  .storage_options = .{
99
- .seed = prng.random.int(u64),
100
- .read_latency_min = prng.random.uintLessThan(u16, 3),
101
- .read_latency_mean = 3 + prng.random.uintLessThan(u16, 10),
102
- .write_latency_min = prng.random.uintLessThan(u16, 3),
103
- .write_latency_mean = 3 + prng.random.uintLessThan(u16, 10),
104
- .read_fault_probability = prng.random.uintLessThan(u8, 10),
105
- .write_fault_probability = prng.random.uintLessThan(u8, 10),
100
+ .seed = random.int(u64),
101
+ .read_latency_min = random.uintLessThan(u16, 3),
102
+ .read_latency_mean = 3 + random.uintLessThan(u16, 10),
103
+ .write_latency_min = random.uintLessThan(u16, 3),
104
+ .write_latency_mean = 3 + random.uintLessThan(u16, 10),
105
+ .read_fault_probability = random.uintLessThan(u8, 10),
106
+ .write_fault_probability = random.uintLessThan(u8, 10),
106
107
  },
107
108
  });
108
109
  defer cluster.destroy();
@@ -206,7 +207,7 @@ pub fn main() !void {
206
207
  }
207
208
 
208
209
  if (cluster.state_checker.transitions < transitions_max) {
209
- output.emerg("you can reproduce this failure with seed={}", .{seed});
210
+ output.err("you can reproduce this failure with seed={}", .{seed});
210
211
  @panic("unable to complete transitions_max before ticks_max");
211
212
  }
212
213
 
@@ -216,13 +217,13 @@ pub fn main() !void {
216
217
  }
217
218
 
218
219
  /// Returns true, `p` percent of the time, else false.
219
- fn chance(random: *std.rand.Random, p: u8) bool {
220
+ fn chance(random: std.rand.Random, p: u8) bool {
220
221
  assert(p <= 100);
221
222
  return random.uintLessThan(u8, 100) < p;
222
223
  }
223
224
 
224
225
  /// Returns the next argument for the simulator or null (if none available)
225
- fn args_next(args: *std.process.ArgIterator, allocator: *std.mem.Allocator) ?[:0]const u8 {
226
+ fn args_next(args: *std.process.ArgIterator, allocator: std.mem.Allocator) ?[:0]const u8 {
226
227
  const err_or_bytes = args.next(allocator) orelse return null;
227
228
  return err_or_bytes catch @panic("Unable to extract next value from args");
228
229
  }
@@ -232,7 +233,7 @@ fn on_change_replica(replica: *Replica) void {
232
233
  cluster.state_checker.check_state(replica.replica);
233
234
  }
234
235
 
235
- fn send_request(random: *std.rand.Random) bool {
236
+ fn send_request(random: std.rand.Random) bool {
236
237
  const client_index = random.uintLessThan(u8, cluster.options.client_count);
237
238
 
238
239
  const client = &cluster.clients[client_index];
@@ -280,11 +281,14 @@ fn client_callback(
280
281
  operation: StateMachine.Operation,
281
282
  results: Client.Error![]const u8,
282
283
  ) void {
284
+ _ = operation;
285
+ _ = results catch unreachable;
286
+
283
287
  assert(user_data == 0);
284
288
  }
285
289
 
286
290
  /// Returns a random partitioning mode, excluding .custom
287
- fn random_partition_mode(random: *std.rand.Random) PartitionMode {
291
+ fn random_partition_mode(random: std.rand.Random) PartitionMode {
288
292
  const typeInfo = @typeInfo(PartitionMode).Enum;
289
293
  var enumAsInt = random.uintAtMost(typeInfo.tag_type, typeInfo.fields.len - 2);
290
294
  if (enumAsInt >= @enumToInt(PartitionMode.custom)) enumAsInt += 1;
@@ -310,8 +314,8 @@ pub fn log(
310
314
  const prefix = if (log_state_transitions_only) "" else prefix_default;
311
315
 
312
316
  // Print the message to stdout, silently ignoring any errors
313
- const held = std.debug.getStderrMutex().acquire();
314
- defer held.release();
315
317
  const stderr = std.io.getStdErr().writer();
318
+ std.debug.getStderrMutex().lock();
319
+ defer std.debug.getStderrMutex().unlock();
316
320
  nosuspend stderr.print(prefix ++ format ++ "\n", args) catch return;
317
321
  }