tigerbeetle-node 0.11.3 → 0.11.5

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 (74) hide show
  1. package/dist/.client.node.sha256 +1 -1
  2. package/package.json +1 -1
  3. package/src/node.zig +10 -5
  4. package/src/tigerbeetle/src/benchmark.zig +4 -4
  5. package/src/tigerbeetle/src/c/tb_client/context.zig +6 -6
  6. package/src/tigerbeetle/src/c/tb_client/echo_client.zig +2 -2
  7. package/src/tigerbeetle/src/c/tb_client/thread.zig +0 -1
  8. package/src/tigerbeetle/src/c/tb_client.h +97 -111
  9. package/src/tigerbeetle/src/c/tb_client.zig +30 -19
  10. package/src/tigerbeetle/src/c/tb_client_header.zig +218 -0
  11. package/src/tigerbeetle/src/c/test.zig +14 -14
  12. package/src/tigerbeetle/src/cli.zig +12 -12
  13. package/src/tigerbeetle/src/config.zig +183 -379
  14. package/src/tigerbeetle/src/constants.zig +394 -0
  15. package/src/tigerbeetle/src/demo.zig +4 -4
  16. package/src/tigerbeetle/src/ewah_fuzz.zig +2 -0
  17. package/src/tigerbeetle/src/io/darwin.zig +4 -4
  18. package/src/tigerbeetle/src/io/linux.zig +6 -6
  19. package/src/tigerbeetle/src/io/windows.zig +4 -4
  20. package/src/tigerbeetle/src/lsm/bloom_filter.zig +1 -1
  21. package/src/tigerbeetle/src/lsm/compaction.zig +15 -10
  22. package/src/tigerbeetle/src/lsm/forest.zig +2 -2
  23. package/src/tigerbeetle/src/lsm/forest_fuzz.zig +18 -15
  24. package/src/tigerbeetle/src/lsm/grid.zig +5 -5
  25. package/src/tigerbeetle/src/lsm/groove.zig +8 -42
  26. package/src/tigerbeetle/src/lsm/level_iterator.zig +2 -2
  27. package/src/tigerbeetle/src/lsm/manifest.zig +19 -23
  28. package/src/tigerbeetle/src/lsm/manifest_level.zig +2 -2
  29. package/src/tigerbeetle/src/lsm/manifest_log.zig +8 -8
  30. package/src/tigerbeetle/src/lsm/manifest_log_fuzz.zig +25 -12
  31. package/src/tigerbeetle/src/lsm/posted_groove.zig +4 -15
  32. package/src/tigerbeetle/src/lsm/segmented_array_benchmark.zig +13 -13
  33. package/src/tigerbeetle/src/lsm/set_associative_cache.zig +2 -2
  34. package/src/tigerbeetle/src/lsm/table.zig +43 -35
  35. package/src/tigerbeetle/src/lsm/table_immutable.zig +4 -4
  36. package/src/tigerbeetle/src/lsm/table_iterator.zig +17 -9
  37. package/src/tigerbeetle/src/lsm/table_mutable.zig +3 -3
  38. package/src/tigerbeetle/src/lsm/test.zig +6 -6
  39. package/src/tigerbeetle/src/lsm/tree.zig +75 -47
  40. package/src/tigerbeetle/src/lsm/tree_fuzz.zig +27 -28
  41. package/src/tigerbeetle/src/main.zig +32 -23
  42. package/src/tigerbeetle/src/message_bus.zig +25 -25
  43. package/src/tigerbeetle/src/message_pool.zig +17 -17
  44. package/src/tigerbeetle/src/simulator.zig +7 -12
  45. package/src/tigerbeetle/src/state_machine.zig +582 -1806
  46. package/src/tigerbeetle/src/storage.zig +12 -12
  47. package/src/tigerbeetle/src/test/accounting/auditor.zig +2 -2
  48. package/src/tigerbeetle/src/test/accounting/workload.zig +5 -5
  49. package/src/tigerbeetle/src/test/cluster.zig +8 -8
  50. package/src/tigerbeetle/src/test/conductor.zig +6 -5
  51. package/src/tigerbeetle/src/test/fuzz.zig +19 -0
  52. package/src/tigerbeetle/src/test/message_bus.zig +0 -2
  53. package/src/tigerbeetle/src/test/network.zig +5 -5
  54. package/src/tigerbeetle/src/test/state_checker.zig +2 -2
  55. package/src/tigerbeetle/src/test/storage.zig +54 -51
  56. package/src/tigerbeetle/src/test/storage_checker.zig +3 -3
  57. package/src/tigerbeetle/src/test/table.zig +226 -0
  58. package/src/tigerbeetle/src/time.zig +0 -1
  59. package/src/tigerbeetle/src/tracer.zig +402 -214
  60. package/src/tigerbeetle/src/unit_tests.zig +1 -0
  61. package/src/tigerbeetle/src/vsr/client.zig +5 -5
  62. package/src/tigerbeetle/src/vsr/clock.zig +9 -8
  63. package/src/tigerbeetle/src/vsr/journal.zig +47 -47
  64. package/src/tigerbeetle/src/vsr/journal_format_fuzz.zig +13 -11
  65. package/src/tigerbeetle/src/vsr/replica.zig +56 -54
  66. package/src/tigerbeetle/src/vsr/replica_format.zig +8 -8
  67. package/src/tigerbeetle/src/vsr/superblock.zig +55 -55
  68. package/src/tigerbeetle/src/vsr/superblock_client_table.zig +9 -9
  69. package/src/tigerbeetle/src/vsr/superblock_free_set.zig +4 -3
  70. package/src/tigerbeetle/src/vsr/superblock_free_set_fuzz.zig +2 -0
  71. package/src/tigerbeetle/src/vsr/superblock_fuzz.zig +9 -6
  72. package/src/tigerbeetle/src/vsr/superblock_manifest.zig +5 -5
  73. package/src/tigerbeetle/src/vsr/superblock_quorums_fuzz.zig +2 -0
  74. package/src/tigerbeetle/src/vsr.zig +20 -20
@@ -5,7 +5,7 @@ const assert = std.debug.assert;
5
5
  const log = std.log.scoped(.storage);
6
6
 
7
7
  const IO = @import("io.zig").IO;
8
- const config = @import("config.zig");
8
+ const constants = @import("constants.zig");
9
9
  const fatal = @import("cli.zig").fatal;
10
10
  const vsr = @import("vsr.zig");
11
11
 
@@ -50,10 +50,10 @@ pub const Storage = struct {
50
50
  // that we need to subtract from `target_max` to get back onto the boundary.
51
51
  var max = read.target_max;
52
52
 
53
- const partial_sector_read_remainder = read.buffer.len % config.sector_size;
53
+ const partial_sector_read_remainder = read.buffer.len % constants.sector_size;
54
54
  if (partial_sector_read_remainder != 0) {
55
55
  // TODO log.debug() because this is interesting, and to ensure fuzz test coverage.
56
- const partial_sector_read = config.sector_size - partial_sector_read_remainder;
56
+ const partial_sector_read = constants.sector_size - partial_sector_read_remainder;
57
57
  max -= partial_sector_read;
58
58
  }
59
59
 
@@ -151,7 +151,7 @@ pub const Storage = struct {
151
151
  // physical sectors than the logical sector size, so we cannot expect `target.len`
152
152
  // to be an exact logical sector multiple.
153
153
  const target = read.target();
154
- if (target.len > config.sector_size) {
154
+ if (target.len > constants.sector_size) {
155
155
  // We tried to read more than a logical sector and failed.
156
156
  log.err("latent sector error: offset={}, subdividing read...", .{read.offset});
157
157
 
@@ -164,10 +164,10 @@ pub const Storage = struct {
164
164
  // These lines both implement ceiling division e.g. `((3 - 1) / 2) + 1 == 2` and
165
165
  // require that the numerator is always greater than zero:
166
166
  assert(target.len > 0);
167
- const target_sectors = @divFloor(target.len - 1, config.sector_size) + 1;
167
+ const target_sectors = @divFloor(target.len - 1, constants.sector_size) + 1;
168
168
  assert(target_sectors > 0);
169
- read.target_max = (@divFloor(target_sectors - 1, 2) + 1) * config.sector_size;
170
- assert(read.target_max >= config.sector_size);
169
+ read.target_max = (@divFloor(target_sectors - 1, 2) + 1) * constants.sector_size;
170
+ assert(read.target_max >= constants.sector_size);
171
171
 
172
172
  // Pass 0 for `bytes_read`, we want to retry the read with smaller `target_max`:
173
173
  self.start_read(read, 0);
@@ -227,9 +227,9 @@ pub const Storage = struct {
227
227
  // then increase `target_max` according to AIMD now that we have read successfully and
228
228
  // hopefully cleared the faulty zone.
229
229
  // We assume that `target_max` may exceed `read.buffer.len` at any time.
230
- if (read.target_max == config.sector_size) {
230
+ if (read.target_max == constants.sector_size) {
231
231
  // TODO Add log.debug because this is interesting.
232
- read.target_max += config.sector_size;
232
+ read.target_max += constants.sector_size;
233
233
  }
234
234
 
235
235
  self.start_read(read, bytes_read);
@@ -319,9 +319,9 @@ pub const Storage = struct {
319
319
  /// We check this only at the start of a read or write because the physical sector size may be
320
320
  /// less than our logical sector size so that partial IOs then leave us no longer aligned.
321
321
  fn assert_alignment(buffer: []const u8, offset: u64) void {
322
- assert(@ptrToInt(buffer.ptr) % config.sector_size == 0);
323
- assert(buffer.len % config.sector_size == 0);
324
- assert(offset % config.sector_size == 0);
322
+ assert(@ptrToInt(buffer.ptr) % constants.sector_size == 0);
323
+ assert(buffer.len % constants.sector_size == 0);
324
+ assert(offset % constants.sector_size == 0);
325
325
  }
326
326
 
327
327
  /// Ensures that the read or write is within bounds and intends to read or write some bytes.
@@ -6,7 +6,7 @@ const std = @import("std");
6
6
  const assert = std.debug.assert;
7
7
  const log = std.log.scoped(.test_auditor);
8
8
 
9
- const config = @import("../../config.zig");
9
+ const constants = @import("../../constants.zig");
10
10
  const tb = @import("../../tigerbeetle.zig");
11
11
  const vsr = @import("../../vsr.zig");
12
12
  const RingBuffer = @import("../../ring_buffer.zig").RingBuffer;
@@ -16,7 +16,7 @@ const IdPermutation = @import("../id.zig").IdPermutation;
16
16
  const PriorityQueue = @import("../priority_queue.zig").PriorityQueue;
17
17
  const Storage = @import("../storage.zig").Storage;
18
18
  const StateMachine = @import("../../state_machine.zig").StateMachineType(Storage, .{
19
- .message_body_size_max = config.message_body_size_max,
19
+ .message_body_size_max = constants.message_body_size_max,
20
20
  });
21
21
 
22
22
  pub const CreateAccountResultSet = std.enums.EnumSet(tb.CreateAccountResult);
@@ -21,7 +21,7 @@ const std = @import("std");
21
21
  const assert = std.debug.assert;
22
22
  const log = std.log.scoped(.test_workload);
23
23
 
24
- const config = @import("../../config.zig");
24
+ const constants = @import("../../constants.zig");
25
25
  const tb = @import("../../tigerbeetle.zig");
26
26
  const vsr = @import("../../vsr.zig");
27
27
  const accounting_auditor = @import("./auditor.zig");
@@ -266,7 +266,7 @@ pub fn WorkloadType(comptime AccountingStateMachine: type) type {
266
266
  var transfers_delivered_recently = TransferBatchQueue.init(allocator, {});
267
267
  errdefer transfers_delivered_recently.deinit();
268
268
  try transfers_delivered_recently.ensureTotalCapacity(
269
- options.auditor_options.client_count * config.client_request_queue_max,
269
+ options.auditor_options.client_count * constants.client_request_queue_max,
270
270
  );
271
271
 
272
272
  for (auditor.accounts) |*account, i| {
@@ -308,7 +308,7 @@ pub fn WorkloadType(comptime AccountingStateMachine: type) type {
308
308
  size: usize,
309
309
  } {
310
310
  assert(client_index < self.auditor.options.client_count);
311
- assert(body.len == config.message_size_max - @sizeOf(vsr.Header));
311
+ assert(body.len == constants.message_size_max - @sizeOf(vsr.Header));
312
312
 
313
313
  const action = action: {
314
314
  if (!self.accounts_sent and self.random.boolean()) {
@@ -353,8 +353,8 @@ pub fn WorkloadType(comptime AccountingStateMachine: type) type {
353
353
  reply_body: []align(@alignOf(vsr.Header)) const u8,
354
354
  ) void {
355
355
  assert(timestamp != 0);
356
- assert(request_body.len <= config.message_size_max - @sizeOf(vsr.Header));
357
- assert(reply_body.len <= config.message_size_max - @sizeOf(vsr.Header));
356
+ assert(request_body.len <= constants.message_size_max - @sizeOf(vsr.Header));
357
+ assert(reply_body.len <= constants.message_size_max - @sizeOf(vsr.Header));
358
358
 
359
359
  switch (operation.cast(AccountingStateMachine)) {
360
360
  .create_accounts => self.auditor.on_create_accounts(
@@ -2,7 +2,7 @@ const std = @import("std");
2
2
  const assert = std.debug.assert;
3
3
  const mem = std.mem;
4
4
 
5
- const config = @import("../config.zig");
5
+ const constants = @import("../constants.zig");
6
6
 
7
7
  const message_pool = @import("../message_pool.zig");
8
8
  const MessagePool = message_pool.MessagePool;
@@ -12,7 +12,7 @@ const Network = @import("network.zig").Network;
12
12
  const NetworkOptions = @import("network.zig").NetworkOptions;
13
13
 
14
14
  pub const StateMachine = @import("../state_machine.zig").StateMachineType(Storage, .{
15
- .message_body_size_max = config.message_body_size_max,
15
+ .message_body_size_max = constants.message_body_size_max,
16
16
  });
17
17
  const MessageBus = @import("message_bus.zig").MessageBus;
18
18
  const Storage = @import("storage.zig").Storage;
@@ -77,7 +77,7 @@ pub const Cluster = struct {
77
77
  assert(options.replica_count > 0);
78
78
  assert(options.client_count > 0);
79
79
  assert(options.grid_size_max > 0);
80
- assert(options.grid_size_max % config.sector_size == 0);
80
+ assert(options.grid_size_max % constants.sector_size == 0);
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);
@@ -123,10 +123,10 @@ pub const Cluster = struct {
123
123
  .network = network,
124
124
  };
125
125
 
126
- var buffer: [config.replicas_max]Storage.FaultyAreas = undefined;
126
+ var buffer: [constants.replicas_max]Storage.FaultyAreas = undefined;
127
127
  const faulty_wal_areas = Storage.generate_faulty_wal_areas(
128
128
  prng,
129
- config.journal_size_max,
129
+ constants.journal_size_max,
130
130
  options.replica_count,
131
131
  &buffer,
132
132
  );
@@ -138,7 +138,7 @@ pub const Cluster = struct {
138
138
  storage_options.faulty_wal_areas = faulty_wal_areas[replica_index];
139
139
  storage.* = try Storage.init(
140
140
  allocator,
141
- superblock_zone_size + config.journal_size_max + options.grid_size_max,
141
+ superblock_zone_size + constants.journal_size_max + options.grid_size_max,
142
142
  storage_options,
143
143
  );
144
144
  }
@@ -161,7 +161,7 @@ pub const Cluster = struct {
161
161
 
162
162
  for (cluster.replicas) |_, replica_index| {
163
163
  try cluster.open_replica(@intCast(u8, replica_index), .{
164
- .resolution = config.tick_ms * std.time.ns_per_ms,
164
+ .resolution = constants.tick_ms * std.time.ns_per_ms,
165
165
  .offset_type = .linear,
166
166
  .offset_coefficient_A = 0,
167
167
  .offset_coefficient_B = 0,
@@ -238,7 +238,7 @@ pub const Cluster = struct {
238
238
 
239
239
  // This whole workaround doesn't handle log wrapping correctly.
240
240
  // If the log has wrapped, don't crash the replica.
241
- if (cluster_op_max >= config.journal_slot_count) {
241
+ if (cluster_op_max >= constants.journal_slot_count) {
242
242
  return false;
243
243
  }
244
244
 
@@ -9,7 +9,7 @@ const log = std.log.scoped(.test_conductor);
9
9
 
10
10
  const vsr = @import("../vsr.zig");
11
11
  const util = @import("../util.zig");
12
- const config = @import("../config.zig");
12
+ const constants = @import("../constants.zig");
13
13
  const IdPermutation = @import("id.zig").IdPermutation;
14
14
  const MessagePool = @import("../message_pool.zig").MessagePool;
15
15
  const Message = MessagePool.Message;
@@ -47,7 +47,8 @@ pub fn ConductorType(
47
47
  ///
48
48
  /// `Conduction.stalled_queue` hold replies (and corresponding requests) that are
49
49
  /// waiting to be processed.
50
- pub const stalled_queue_capacity = config.clients_max * config.client_request_queue_max * 2;
50
+ pub const stalled_queue_capacity =
51
+ constants.clients_max * constants.client_request_queue_max * 2;
51
52
 
52
53
  random: std.rand.Random,
53
54
  workload: *Workload,
@@ -225,7 +226,7 @@ pub fn ConductorType(
225
226
  var client = &self.clients[client_index];
226
227
 
227
228
  // Check for space in the client's own request queue.
228
- if (client.request_queue.count + 1 > config.client_request_queue_max) return;
229
+ if (client.request_queue.count + 1 > constants.client_request_queue_max) return;
229
230
 
230
231
  var request_message = client.get_message();
231
232
  defer client.unref(request_message);
@@ -234,10 +235,10 @@ pub fn ConductorType(
234
235
  client_index,
235
236
  @alignCast(
236
237
  @alignOf(vsr.Header),
237
- request_message.buffer[@sizeOf(vsr.Header)..config.message_size_max],
238
+ request_message.buffer[@sizeOf(vsr.Header)..constants.message_size_max],
238
239
  ),
239
240
  );
240
- assert(request_metadata.size <= config.message_size_max - @sizeOf(vsr.Header));
241
+ assert(request_metadata.size <= constants.message_size_max - @sizeOf(vsr.Header));
241
242
 
242
243
  client.request(
243
244
  0,
@@ -64,14 +64,18 @@ pub fn random_enum(
64
64
 
65
65
  pub const FuzzArgs = struct {
66
66
  seed: u64,
67
+ events_max: ?usize,
67
68
  };
68
69
 
69
70
  /// Parse common command-line arguments to fuzzers:
70
71
  ///
71
72
  /// [--seed u64]
72
73
  /// Sets the seed used for the random number generator.
74
+ /// [--events-max usize]
75
+ /// Override the fuzzer's default maximum number of generated events.
73
76
  pub fn parse_fuzz_args(allocator: mem.Allocator) !FuzzArgs {
74
77
  var seed: ?u64 = null;
78
+ var events_max: ?usize = null;
75
79
 
76
80
  var args = std.process.args();
77
81
 
@@ -96,6 +100,20 @@ pub fn parse_fuzz_args(allocator: mem.Allocator) !FuzzArgs {
96
100
  "Could not parse \"{}\" as an integer seed: {}",
97
101
  .{ std.zig.fmtEscapes(seed_string), err },
98
102
  );
103
+ } else if (std.mem.eql(u8, arg, "--events-max")) {
104
+ const events_string_or_err = args.next(allocator) orelse
105
+ std.debug.panic("Expected an argument to --events-max", .{});
106
+ const events_string = try events_string_or_err;
107
+ defer allocator.free(events_string);
108
+
109
+ if (events_max != null) {
110
+ std.debug.panic("Received more than one \"--events-max\"", .{});
111
+ }
112
+ events_max = std.fmt.parseInt(usize, events_string, 10) catch |err|
113
+ std.debug.panic(
114
+ "Could not parse \"{}\" as an integer events-max: {}",
115
+ .{ std.zig.fmtEscapes(events_string), err },
116
+ );
99
117
  } else {
100
118
  // When run with `--test-cmd`,
101
119
  // `zig run` also passes the location of the zig binary as an extra arg.
@@ -117,5 +135,6 @@ pub fn parse_fuzz_args(allocator: mem.Allocator) !FuzzArgs {
117
135
 
118
136
  return FuzzArgs{
119
137
  .seed = seed.?,
138
+ .events_max = events_max,
120
139
  };
121
140
  }
@@ -1,8 +1,6 @@
1
1
  const std = @import("std");
2
2
  const assert = std.debug.assert;
3
3
 
4
- const config = @import("../config.zig");
5
-
6
4
  const MessagePool = @import("../message_pool.zig").MessagePool;
7
5
  const Message = MessagePool.Message;
8
6
  const Header = @import("../vsr.zig").Header;
@@ -3,7 +3,7 @@ const math = std.math;
3
3
  const mem = std.mem;
4
4
  const assert = std.debug.assert;
5
5
 
6
- const config = @import("../config.zig");
6
+ const constants = @import("../constants.zig");
7
7
  const vsr = @import("../vsr.zig");
8
8
  const util = @import("../util.zig");
9
9
 
@@ -115,7 +115,7 @@ pub const Network = struct {
115
115
  const raw_process = switch (process) {
116
116
  .replica => |replica| replica,
117
117
  .client => |client| blk: {
118
- assert(client >= config.replicas_max);
118
+ assert(client >= constants.replicas_max);
119
119
  break :blk client;
120
120
  },
121
121
  };
@@ -194,7 +194,7 @@ pub const Network = struct {
194
194
  const sector_ceil = vsr.sector_ceil(target_message.header.size);
195
195
  if (target_message.header.size != sector_ceil) {
196
196
  assert(target_message.header.size < sector_ceil);
197
- assert(target_message.buffer.len == config.message_size_max + config.sector_size);
197
+ assert(target_message.buffer.len == constants.message_size_max + constants.sector_size);
198
198
  mem.set(u8, target_message.buffer[target_message.header.size..sector_ceil], 0);
199
199
  }
200
200
  }
@@ -204,9 +204,9 @@ pub const Network = struct {
204
204
 
205
205
  fn raw_process_to_process(raw: u128) Process {
206
206
  switch (raw) {
207
- 0...(config.replicas_max - 1) => return .{ .replica = @intCast(u8, raw) },
207
+ 0...(constants.replicas_max - 1) => return .{ .replica = @intCast(u8, raw) },
208
208
  else => {
209
- assert(raw >= config.replicas_max);
209
+ assert(raw >= constants.replicas_max);
210
210
  return .{ .client = raw };
211
211
  },
212
212
  }
@@ -2,7 +2,7 @@ const std = @import("std");
2
2
  const assert = std.debug.assert;
3
3
  const mem = std.mem;
4
4
 
5
- const config = @import("../config.zig");
5
+ const constants = @import("../constants.zig");
6
6
  const vsr = @import("../vsr.zig");
7
7
 
8
8
  const Cluster = @import("cluster.zig").Cluster;
@@ -23,7 +23,7 @@ const log = std.log.scoped(.state_checker);
23
23
 
24
24
  pub const StateChecker = struct {
25
25
  /// Indexed by replica index.
26
- replica_states: [config.replicas_max]u128 = [_]u128{0} ** config.replicas_max,
26
+ replica_states: [constants.replicas_max]u128 = [_]u128{0} ** constants.replicas_max,
27
27
 
28
28
  /// Keyed by committed `message.header.checksum`.
29
29
  ///