tigerbeetle-node 0.11.8 → 0.11.9

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 (83) hide show
  1. package/dist/.client.node.sha256 +1 -1
  2. package/package.json +4 -3
  3. package/scripts/build_lib.sh +29 -0
  4. package/src/node.zig +1 -1
  5. package/src/tigerbeetle/scripts/validate_docs.sh +7 -1
  6. package/src/tigerbeetle/src/benchmark.zig +3 -3
  7. package/src/tigerbeetle/src/config.zig +29 -16
  8. package/src/tigerbeetle/src/constants.zig +30 -9
  9. package/src/tigerbeetle/src/ewah.zig +5 -5
  10. package/src/tigerbeetle/src/ewah_fuzz.zig +1 -1
  11. package/src/tigerbeetle/src/lsm/binary_search.zig +1 -1
  12. package/src/tigerbeetle/src/lsm/bloom_filter.zig +1 -1
  13. package/src/tigerbeetle/src/lsm/compaction.zig +34 -21
  14. package/src/tigerbeetle/src/lsm/forest_fuzz.zig +85 -103
  15. package/src/tigerbeetle/src/lsm/grid.zig +19 -13
  16. package/src/tigerbeetle/src/lsm/manifest_log.zig +8 -10
  17. package/src/tigerbeetle/src/lsm/manifest_log_fuzz.zig +12 -8
  18. package/src/tigerbeetle/src/lsm/merge_iterator.zig +1 -1
  19. package/src/tigerbeetle/src/lsm/segmented_array.zig +17 -17
  20. package/src/tigerbeetle/src/lsm/segmented_array_fuzz.zig +1 -1
  21. package/src/tigerbeetle/src/lsm/set_associative_cache.zig +1 -1
  22. package/src/tigerbeetle/src/lsm/table.zig +8 -20
  23. package/src/tigerbeetle/src/lsm/table_immutable.zig +1 -1
  24. package/src/tigerbeetle/src/lsm/table_iterator.zig +3 -3
  25. package/src/tigerbeetle/src/lsm/table_mutable.zig +14 -2
  26. package/src/tigerbeetle/src/lsm/tree.zig +31 -5
  27. package/src/tigerbeetle/src/lsm/tree_fuzz.zig +86 -114
  28. package/src/tigerbeetle/src/message_bus.zig +4 -4
  29. package/src/tigerbeetle/src/message_pool.zig +7 -10
  30. package/src/tigerbeetle/src/ring_buffer.zig +22 -12
  31. package/src/tigerbeetle/src/simulator.zig +360 -214
  32. package/src/tigerbeetle/src/state_machine/auditor.zig +5 -5
  33. package/src/tigerbeetle/src/state_machine/workload.zig +3 -3
  34. package/src/tigerbeetle/src/state_machine.zig +190 -178
  35. package/src/tigerbeetle/src/{util.zig → stdx.zig} +2 -0
  36. package/src/tigerbeetle/src/storage.zig +13 -6
  37. package/src/tigerbeetle/src/{test → testing/cluster}/message_bus.zig +3 -3
  38. package/src/tigerbeetle/src/{test → testing/cluster}/network.zig +46 -22
  39. package/src/tigerbeetle/src/testing/cluster/state_checker.zig +169 -0
  40. package/src/tigerbeetle/src/testing/cluster/storage_checker.zig +202 -0
  41. package/src/tigerbeetle/src/testing/cluster.zig +537 -0
  42. package/src/tigerbeetle/src/{test → testing}/fuzz.zig +0 -0
  43. package/src/tigerbeetle/src/testing/hash_log.zig +66 -0
  44. package/src/tigerbeetle/src/{test → testing}/id.zig +0 -0
  45. package/src/tigerbeetle/src/testing/packet_simulator.zig +365 -0
  46. package/src/tigerbeetle/src/{test → testing}/priority_queue.zig +1 -1
  47. package/src/tigerbeetle/src/testing/reply_sequence.zig +139 -0
  48. package/src/tigerbeetle/src/{test → testing}/state_machine.zig +3 -1
  49. package/src/tigerbeetle/src/testing/storage.zig +754 -0
  50. package/src/tigerbeetle/src/{test → testing}/table.zig +21 -0
  51. package/src/tigerbeetle/src/{test → testing}/time.zig +0 -0
  52. package/src/tigerbeetle/src/tigerbeetle.zig +2 -0
  53. package/src/tigerbeetle/src/tracer.zig +3 -3
  54. package/src/tigerbeetle/src/unit_tests.zig +4 -4
  55. package/src/tigerbeetle/src/vopr.zig +2 -2
  56. package/src/tigerbeetle/src/vsr/client.zig +5 -2
  57. package/src/tigerbeetle/src/vsr/clock.zig +93 -53
  58. package/src/tigerbeetle/src/vsr/journal.zig +29 -14
  59. package/src/tigerbeetle/src/vsr/journal_format_fuzz.zig +2 -2
  60. package/src/tigerbeetle/src/vsr/replica.zig +1383 -774
  61. package/src/tigerbeetle/src/vsr/replica_format.zig +2 -2
  62. package/src/tigerbeetle/src/vsr/superblock.zig +59 -43
  63. package/src/tigerbeetle/src/vsr/superblock_client_table.zig +7 -7
  64. package/src/tigerbeetle/src/vsr/superblock_free_set.zig +1 -1
  65. package/src/tigerbeetle/src/vsr/superblock_free_set_fuzz.zig +1 -1
  66. package/src/tigerbeetle/src/vsr/superblock_fuzz.zig +15 -7
  67. package/src/tigerbeetle/src/vsr/superblock_manifest.zig +38 -19
  68. package/src/tigerbeetle/src/vsr/superblock_quorums_fuzz.zig +1 -1
  69. package/src/tigerbeetle/src/vsr.zig +6 -4
  70. package/src/tigerbeetle/src/demo.zig +0 -132
  71. package/src/tigerbeetle/src/demo_01_create_accounts.zig +0 -35
  72. package/src/tigerbeetle/src/demo_02_lookup_accounts.zig +0 -7
  73. package/src/tigerbeetle/src/demo_03_create_transfers.zig +0 -37
  74. package/src/tigerbeetle/src/demo_04_create_pending_transfers.zig +0 -61
  75. package/src/tigerbeetle/src/demo_05_post_pending_transfers.zig +0 -37
  76. package/src/tigerbeetle/src/demo_06_void_pending_transfers.zig +0 -24
  77. package/src/tigerbeetle/src/demo_07_lookup_transfers.zig +0 -7
  78. package/src/tigerbeetle/src/test/cluster.zig +0 -352
  79. package/src/tigerbeetle/src/test/conductor.zig +0 -366
  80. package/src/tigerbeetle/src/test/packet_simulator.zig +0 -398
  81. package/src/tigerbeetle/src/test/state_checker.zig +0 -169
  82. package/src/tigerbeetle/src/test/storage.zig +0 -864
  83. package/src/tigerbeetle/src/test/storage_checker.zig +0 -204
@@ -4,7 +4,7 @@ const allocator = testing.allocator;
4
4
  const assert = std.debug.assert;
5
5
 
6
6
  const constants = @import("../constants.zig");
7
- const fuzz = @import("../test/fuzz.zig");
7
+ const fuzz = @import("../testing/fuzz.zig");
8
8
  const vsr = @import("../vsr.zig");
9
9
 
10
10
  const log = std.log.scoped(.lsm_forest_fuzz);
@@ -13,7 +13,7 @@ const tracer = @import("../tracer.zig");
13
13
  const MessagePool = @import("../message_pool.zig").MessagePool;
14
14
  const Transfer = @import("../tigerbeetle.zig").Transfer;
15
15
  const Account = @import("../tigerbeetle.zig").Account;
16
- const Storage = @import("../test/storage.zig").Storage;
16
+ const Storage = @import("../testing/storage.zig").Storage;
17
17
  const StateMachine = @import("../state_machine.zig").StateMachineType(Storage, .{
18
18
  .message_body_size_max = constants.message_body_size_max,
19
19
  });
@@ -62,77 +62,48 @@ const Environment = struct {
62
62
  ) catch unreachable;
63
63
 
64
64
  const State = enum {
65
- uninit,
66
65
  init,
67
- formatted,
66
+ superblock_format,
68
67
  superblock_open,
68
+ forest_init,
69
69
  forest_open,
70
- forest_compacting,
71
- forest_checkpointing,
72
- superblock_checkpointing,
70
+ fuzzing,
71
+ forest_compact,
72
+ forest_checkpoint,
73
+ superblock_checkpoint,
73
74
  };
74
75
 
75
76
  state: State,
76
77
  storage: *Storage,
77
78
  message_pool: MessagePool,
78
79
  superblock: SuperBlock,
79
- superblock_context: SuperBlock.Context = undefined,
80
+ superblock_context: SuperBlock.Context,
80
81
  grid: Grid,
81
82
  forest: Forest,
82
- // We need @fieldParentPtr() of forest, so we can't use an optional Forest.
83
- forest_exists: bool,
84
- checkpoint_op: ?u64 = null,
85
-
86
- fn init(env: *Environment, storage: *Storage) !void {
87
- env.state = .uninit;
83
+ checkpoint_op: ?u64,
88
84
 
85
+ pub fn run(storage: *Storage, fuzz_ops: []const FuzzOp) !void {
86
+ var env: Environment = undefined;
87
+ env.state = .init;
89
88
  env.storage = storage;
90
- errdefer env.storage.deinit(allocator);
91
89
 
92
90
  env.message_pool = try MessagePool.init(allocator, .replica);
93
- errdefer env.message_pool.deinit(allocator);
91
+ defer env.message_pool.deinit(allocator);
94
92
 
95
93
  env.superblock = try SuperBlock.init(allocator, .{
96
94
  .storage = env.storage,
97
95
  .storage_size_limit = constants.storage_size_max,
98
96
  .message_pool = &env.message_pool,
99
97
  });
100
- errdefer env.superblock.deinit(allocator);
98
+ defer env.superblock.deinit(allocator);
101
99
 
102
100
  env.grid = try Grid.init(allocator, &env.superblock);
103
- errdefer env.grid.deinit(allocator);
101
+ defer env.grid.deinit(allocator);
104
102
 
105
- // Forest must be initialized with an open superblock.
106
103
  env.forest = undefined;
107
- env.forest_exists = false;
108
-
109
- env.state = .init;
110
- }
111
-
112
- fn deinit(env: *Environment) void {
113
- assert(env.state != .uninit);
114
-
115
- if (env.forest_exists) {
116
- env.forest.deinit(allocator);
117
- env.forest_exists = false;
118
- }
119
- env.grid.deinit(allocator);
120
- env.superblock.deinit(allocator);
121
- env.message_pool.deinit(allocator);
122
-
123
- env.state = .uninit;
124
- }
125
-
126
- fn tick(env: *Environment) void {
127
- // env.grid.tick();
128
- env.storage.tick();
129
- }
104
+ env.checkpoint_op = null;
130
105
 
131
- fn tick_until_state_change(env: *Environment, current_state: State, next_state: State) void {
132
- // Sometimes IO completes synchronously (eg if cached), so we might already be in next_state before ticking.
133
- assert(env.state == current_state or env.state == next_state);
134
- while (env.state == current_state) env.tick();
135
- assert(env.state == next_state);
106
+ try env.open_then_apply(fuzz_ops);
136
107
  }
137
108
 
138
109
  fn change_state(env: *Environment, current_state: State, next_state: State) void {
@@ -140,79 +111,88 @@ const Environment = struct {
140
111
  env.state = next_state;
141
112
  }
142
113
 
143
- pub fn format(storage: *Storage) !void {
144
- var env: Environment = undefined;
145
-
146
- try env.init(storage);
147
- defer env.deinit();
114
+ fn tick_until_state_change(env: *Environment, current_state: State, next_state: State) void {
115
+ // Sometimes operations complete synchronously so we might already be in next_state before ticking.
116
+ //assert(env.state == current_state or env.state == next_state);
117
+ while (env.state == current_state) env.storage.tick();
118
+ assert(env.state == next_state);
119
+ }
148
120
 
149
- assert(env.state == .init);
121
+ pub fn open_then_apply(env: *Environment, fuzz_ops: []const FuzzOp) !void {
122
+ env.change_state(.init, .superblock_format);
150
123
  env.superblock.format(superblock_format_callback, &env.superblock_context, .{
151
124
  .cluster = cluster,
152
125
  .replica = replica,
153
126
  });
154
- env.tick_until_state_change(.init, .formatted);
127
+
128
+ env.tick_until_state_change(.superblock_format, .superblock_open);
129
+ env.superblock.open(superblock_open_callback, &env.superblock_context);
130
+
131
+ env.tick_until_state_change(.superblock_open, .forest_init);
132
+ env.forest = try Forest.init(allocator, &env.grid, node_count, forest_options);
133
+ defer env.forest.deinit(allocator);
134
+
135
+ env.change_state(.forest_init, .forest_open);
136
+ env.forest.open(forest_open_callback);
137
+
138
+ env.tick_until_state_change(.forest_open, .fuzzing);
139
+ try env.apply(fuzz_ops);
155
140
  }
156
141
 
157
142
  fn superblock_format_callback(superblock_context: *SuperBlock.Context) void {
158
143
  const env = @fieldParentPtr(@This(), "superblock_context", superblock_context);
159
- env.change_state(.init, .formatted);
160
- }
161
-
162
- pub fn open(env: *Environment) void {
163
- assert(env.state == .init);
164
- env.superblock.open(superblock_open_callback, &env.superblock_context);
165
- env.tick_until_state_change(.init, .forest_open);
144
+ env.change_state(.superblock_format, .superblock_open);
166
145
  }
167
146
 
168
147
  fn superblock_open_callback(superblock_context: *SuperBlock.Context) void {
169
148
  const env = @fieldParentPtr(@This(), "superblock_context", superblock_context);
170
- env.change_state(.init, .superblock_open);
171
- env.forest = Forest.init(allocator, &env.grid, node_count, forest_options) catch unreachable;
172
- env.forest_exists = true;
173
- env.forest.open(forest_open_callback);
149
+ env.change_state(.superblock_open, .forest_init);
174
150
  }
175
151
 
176
152
  fn forest_open_callback(forest: *Forest) void {
177
153
  const env = @fieldParentPtr(@This(), "forest", forest);
178
- env.change_state(.superblock_open, .forest_open);
154
+ env.change_state(.forest_open, .fuzzing);
179
155
  }
180
156
 
181
157
  pub fn compact(env: *Environment, op: u64) void {
182
- env.change_state(.forest_open, .forest_compacting);
158
+ env.change_state(.fuzzing, .forest_compact);
183
159
  env.forest.compact(forest_compact_callback, op);
184
- env.tick_until_state_change(.forest_compacting, .forest_open);
160
+ env.tick_until_state_change(.forest_compact, .fuzzing);
185
161
  }
186
162
 
187
163
  fn forest_compact_callback(forest: *Forest) void {
188
164
  const env = @fieldParentPtr(@This(), "forest", forest);
189
- env.change_state(.forest_compacting, .forest_open);
165
+ env.change_state(.forest_compact, .fuzzing);
190
166
  }
191
167
 
192
168
  pub fn checkpoint(env: *Environment, op: u64) void {
169
+ assert(env.checkpoint_op == null);
193
170
  env.checkpoint_op = op - constants.lsm_batch_multiple;
194
- env.change_state(.forest_open, .forest_checkpointing);
171
+
172
+ env.change_state(.fuzzing, .forest_checkpoint);
195
173
  env.forest.checkpoint(forest_checkpoint_callback);
196
- env.tick_until_state_change(.forest_checkpointing, .superblock_checkpointing);
197
- env.tick_until_state_change(.superblock_checkpointing, .forest_open);
174
+ env.tick_until_state_change(.forest_checkpoint, .superblock_checkpoint);
175
+ env.tick_until_state_change(.superblock_checkpoint, .fuzzing);
198
176
  }
199
177
 
200
178
  fn forest_checkpoint_callback(forest: *Forest) void {
201
179
  const env = @fieldParentPtr(@This(), "forest", forest);
202
- env.change_state(.forest_checkpointing, .superblock_checkpointing);
180
+ const op = env.checkpoint_op.?;
181
+ env.checkpoint_op = null;
182
+
183
+ env.change_state(.forest_checkpoint, .superblock_checkpoint);
203
184
  env.superblock.checkpoint(superblock_checkpoint_callback, &env.superblock_context, .{
204
185
  .commit_min_checksum = env.superblock.working.vsr_state.commit_min_checksum + 1,
205
- .commit_min = env.checkpoint_op.?,
206
- .commit_max = env.checkpoint_op.? + 1,
207
- .view_normal = 0,
186
+ .commit_min = op,
187
+ .commit_max = op + 1,
188
+ .log_view = 0,
208
189
  .view = 0,
209
190
  });
210
- env.checkpoint_op = null;
211
191
  }
212
192
 
213
193
  fn superblock_checkpoint_callback(superblock_context: *SuperBlock.Context) void {
214
194
  const env = @fieldParentPtr(@This(), "superblock_context", superblock_context);
215
- env.change_state(.superblock_checkpointing, .forest_open);
195
+ env.change_state(.superblock_checkpoint, .fuzzing);
216
196
  }
217
197
 
218
198
  fn prefetch_account(env: *Environment, id: u128) void {
@@ -230,31 +210,27 @@ const Environment = struct {
230
210
  groove.prefetch_setup(null);
231
211
  groove.prefetch_enqueue(id);
232
212
  groove.prefetch(Getter.prefetch_callback, &getter.prefetch_context);
233
- while (!getter.finished) env.tick();
213
+ while (!getter.finished) env.storage.tick();
234
214
  }
235
215
 
236
- fn run(storage: *Storage, fuzz_ops: []const FuzzOp) !void {
237
- var env: Environment = undefined;
238
-
239
- try env.init(storage);
240
- defer env.deinit();
241
-
242
- // Open the superblock then forest.
243
- env.open();
244
-
216
+ fn apply(env: *Environment, fuzz_ops: []const FuzzOp) !void {
245
217
  // The forest should behave like a simple key-value data-structure.
246
218
  // We'll compare it to a hash map.
247
219
  var model = std.hash_map.AutoHashMap(u128, Account).init(allocator);
248
220
  defer model.deinit();
249
221
 
250
222
  for (fuzz_ops) |fuzz_op, fuzz_op_index| {
223
+ assert(env.state == .fuzzing);
251
224
  log.debug("Running fuzz_ops[{}/{}] == {}", .{ fuzz_op_index, fuzz_ops.len, fuzz_op });
252
- const storage_size_used = storage.size_used();
253
- log.debug("storage.size_used = {}/{}", .{ storage_size_used, storage.size });
225
+
226
+ const storage_size_used = env.storage.size_used();
227
+ log.debug("storage.size_used = {}/{}", .{ storage_size_used, env.storage.size });
228
+
254
229
  const model_size = model.count() * @sizeOf(Account);
255
230
  log.debug("space_amplification = {d:.2}", .{
256
231
  @intToFloat(f64, storage_size_used) / @intToFloat(f64, model_size),
257
232
  });
233
+
258
234
  // Apply fuzz_op to the forest and the model.
259
235
  switch (fuzz_op) {
260
236
  .compact => |compact| {
@@ -294,7 +270,6 @@ pub fn run_fuzz_ops(storage_options: Storage.Options, fuzz_ops: []const FuzzOp)
294
270
  var storage = try Storage.init(allocator, constants.storage_size_max, storage_options);
295
271
  defer storage.deinit(allocator);
296
272
 
297
- try Environment.format(&storage);
298
273
  try Environment.run(&storage, fuzz_ops);
299
274
  }
300
275
 
@@ -328,8 +303,8 @@ pub fn generate_fuzz_ops(random: std.rand.Random, fuzz_op_count: usize) ![]const
328
303
  log.info("puts_since_compact_max = {}", .{Environment.puts_since_compact_max});
329
304
  log.info("compacts_per_checkpoint = {}", .{Environment.compacts_per_checkpoint});
330
305
 
331
- var id_to_timestamp = std.hash_map.AutoHashMap(u128, u64).init(allocator);
332
- defer id_to_timestamp.deinit();
306
+ var id_to_account = std.hash_map.AutoHashMap(u128, Account).init(allocator);
307
+ defer id_to_account.deinit();
333
308
 
334
309
  var op: u64 = 1;
335
310
  var puts_since_compact: usize = 0;
@@ -359,12 +334,10 @@ pub fn generate_fuzz_ops(random: std.rand.Random, fuzz_op_count: usize) ![]const
359
334
  },
360
335
  .put_account => put_account: {
361
336
  const id = random_id(random, u128);
362
- // `timestamp` just needs to be unique, but we're not allowed to change the timestamp of an existing account.
363
- const timestamp = id_to_timestamp.get(id) orelse fuzz_op_index;
364
- try id_to_timestamp.put(id, timestamp);
365
- break :put_account FuzzOp{ .put_account = Account{
337
+ var account = id_to_account.get(id) orelse Account{
366
338
  .id = id,
367
- .timestamp = timestamp,
339
+ // `timestamp` must be unique.
340
+ .timestamp = fuzz_op_index,
368
341
  .user_data = random_id(random, u128),
369
342
  .reserved = [_]u8{0} ** 48,
370
343
  .ledger = random_id(random, u32),
@@ -373,11 +346,20 @@ pub fn generate_fuzz_ops(random: std.rand.Random, fuzz_op_count: usize) ![]const
373
346
  .debits_must_not_exceed_credits = random.boolean(),
374
347
  .credits_must_not_exceed_debits = random.boolean(),
375
348
  },
376
- .debits_pending = random.int(u64),
377
- .debits_posted = random.int(u64),
378
- .credits_pending = random.int(u64),
379
- .credits_posted = random.int(u64),
380
- } };
349
+ .debits_pending = 0,
350
+ .debits_posted = 0,
351
+ .credits_pending = 0,
352
+ .credits_posted = 0,
353
+ };
354
+
355
+ // These are the only fields we are allowed to change on existing accounts.
356
+ account.debits_pending = random.int(u64);
357
+ account.debits_posted = random.int(u64);
358
+ account.credits_pending = random.int(u64);
359
+ account.credits_posted = random.int(u64);
360
+
361
+ try id_to_account.put(account.id, account);
362
+ break :put_account FuzzOp{ .put_account = account };
381
363
  },
382
364
  .get_account => FuzzOp{
383
365
  .get_account = random_id(random, u128),
@@ -10,7 +10,7 @@ const SuperBlockType = vsr.SuperBlockType;
10
10
  const FIFO = @import("../fifo.zig").FIFO;
11
11
  const IOPS = @import("../iops.zig").IOPS;
12
12
  const SetAssociativeCache = @import("set_associative_cache.zig").SetAssociativeCache;
13
- const util = @import("../util.zig");
13
+ const stdx = @import("../stdx.zig");
14
14
 
15
15
  const log = std.log.scoped(.grid);
16
16
 
@@ -36,6 +36,15 @@ pub const BlockType = enum(u8) {
36
36
  }
37
37
  };
38
38
 
39
+ // Leave this outside GridType so we can call it from modules that don't know about Storage.
40
+ pub fn alloc_block(
41
+ allocator: mem.Allocator,
42
+ ) !*align(constants.sector_size) [constants.block_size]u8 {
43
+ const block = try allocator.alignedAlloc(u8, constants.sector_size, constants.block_size);
44
+ mem.set(u8, block, 0);
45
+ return block[0..constants.block_size];
46
+ }
47
+
39
48
  /// The Grid provides access to on-disk blocks (blobs of `block_size` bytes).
40
49
  /// Each block is identified by an "address" (`u64`, beginning at 1).
41
50
  ///
@@ -180,11 +189,6 @@ pub fn GridType(comptime Storage: type) type {
180
189
  };
181
190
  }
182
191
 
183
- pub fn alloc_block(allocator: mem.Allocator) !BlockPtr {
184
- const block = try allocator.alignedAlloc(u8, constants.sector_size, block_size);
185
- return block[0..block_size];
186
- }
187
-
188
192
  pub fn deinit(grid: *Grid, allocator: mem.Allocator) void {
189
193
  for (&grid.read_iop_blocks) |block| allocator.free(block);
190
194
 
@@ -292,6 +296,12 @@ pub fn GridType(comptime Storage: type) type {
292
296
  grid.assert_not_writing(address, block.*);
293
297
  grid.assert_not_reading(address, block.*);
294
298
 
299
+ if (constants.verify) {
300
+ for (grid.cache_blocks) |cache_block| {
301
+ assert(cache_block != block.*);
302
+ }
303
+ }
304
+
295
305
  assert(grid.superblock.opened);
296
306
  assert(!grid.superblock.free_set.is_free(address));
297
307
 
@@ -340,9 +350,7 @@ pub fn GridType(comptime Storage: type) type {
340
350
  const cache_index = grid.cache.insert_index(&completed_write.address);
341
351
  const cache_block = &grid.cache_blocks[cache_index];
342
352
  std.mem.swap(BlockPtr, cache_block, completed_write.block);
343
- if (constants.verify) {
344
- std.mem.set(u8, completed_write.block.*, undefined);
345
- }
353
+ std.mem.set(u8, completed_write.block.*, 0);
346
354
 
347
355
  // Start a queued write if possible *before* calling the completed
348
356
  // write's callback. This ensures that if the callback calls
@@ -462,9 +470,7 @@ pub fn GridType(comptime Storage: type) type {
462
470
  const cache_index = grid.cache.insert_index(&read.address);
463
471
  const cache_block = &grid.cache_blocks[cache_index];
464
472
  std.mem.swap(BlockPtr, iop_block, cache_block);
465
- if (constants.verify) {
466
- std.mem.set(u8, iop_block.*, undefined);
467
- }
473
+ std.mem.set(u8, iop_block.*, 0);
468
474
 
469
475
  // Handoff the iop to a pending read or release it before resolving the callbacks below.
470
476
  if (grid.read_pending_queue.pop()) |pending| {
@@ -556,7 +562,7 @@ pub fn GridType(comptime Storage: type) type {
556
562
  }
557
563
 
558
564
  fn verify_cached_read(grid: *Grid, address: u64, cached_block: BlockPtrConst) void {
559
- if (Storage != @import("../test/storage.zig").Storage)
565
+ if (Storage != @import("../testing/storage.zig").Storage)
560
566
  // Too complicated to do async verification
561
567
  return;
562
568
 
@@ -28,11 +28,12 @@ const log = std.log.scoped(.manifest_log);
28
28
 
29
29
  const constants = @import("../constants.zig");
30
30
  const vsr = @import("../vsr.zig");
31
- const util = @import("../util.zig");
31
+ const stdx = @import("../stdx.zig");
32
32
 
33
33
  const SuperBlockType = vsr.SuperBlockType;
34
34
  const GridType = @import("grid.zig").GridType;
35
35
  const BlockType = @import("grid.zig").BlockType;
36
+ const alloc_block = @import("grid.zig").alloc_block;
36
37
  const tree = @import("tree.zig");
37
38
  const RingBuffer = @import("../ring_buffer.zig").RingBuffer;
38
39
 
@@ -93,7 +94,7 @@ pub fn ManifestLogType(comptime Storage: type, comptime TableInfo: type) type {
93
94
  tree.compaction_tables_input_max + // Remove.
94
95
  tree.compaction_tables_output_max);
95
96
 
96
- const blocks_count_appends = util.div_ceil(compaction_appends_max, Block.entry_count_max);
97
+ const blocks_count_appends = stdx.div_ceil(compaction_appends_max, Block.entry_count_max);
97
98
 
98
99
  /// The upper-bound of manifest log blocks we must buffer.
99
100
  ///
@@ -151,10 +152,7 @@ pub fn ManifestLogType(comptime Storage: type, comptime TableInfo: type) type {
151
152
  var blocks: [blocks_count_max]BlockPtr = undefined;
152
153
  for (blocks) |*block, i| {
153
154
  errdefer for (blocks[0..i]) |b| allocator.free(b);
154
-
155
- const block_slice =
156
- try allocator.alignedAlloc(u8, constants.sector_size, constants.block_size);
157
- block.* = block_slice[0..constants.block_size];
155
+ block.* = try alloc_block(allocator);
158
156
  }
159
157
  errdefer for (blocks) |b| allocator.free(b);
160
158
 
@@ -255,7 +253,7 @@ pub fn ManifestLogType(comptime Storage: type, comptime TableInfo: type) type {
255
253
  const label = labels_used[entry];
256
254
  const table = &tables_used[entry];
257
255
 
258
- if (manifest.insert_table_extent(table.address, block_reference.address, entry)) {
256
+ if (manifest.insert_table_extent(manifest_log.tree_hash, table.address, block_reference.address, entry)) {
259
257
  switch (label.event) {
260
258
  .insert => manifest_log.open_event(manifest_log, label.level, table),
261
259
  .remove => manifest.queue_for_compaction(block_reference.address),
@@ -332,7 +330,7 @@ pub fn ManifestLogType(comptime Storage: type, comptime TableInfo: type) type {
332
330
 
333
331
  const manifest: *SuperBlock.Manifest = &manifest_log.superblock.manifest;
334
332
  const address = Block.address(block);
335
- if (manifest.update_table_extent(table.address, address, entry)) |previous_block| {
333
+ if (manifest.update_table_extent(manifest_log.tree_hash, table.address, address, entry)) |previous_block| {
336
334
  manifest.queue_for_compaction(previous_block);
337
335
  if (label.event == .remove) manifest.queue_for_compaction(address);
338
336
  } else {
@@ -433,6 +431,7 @@ pub fn ManifestLogType(comptime Storage: type, comptime TableInfo: type) type {
433
431
  block,
434
432
  address,
435
433
  );
434
+ manifest_log.blocks.advance_head();
436
435
  }
437
436
 
438
437
  fn write_block_callback(write: *Grid.Write) void {
@@ -441,7 +440,6 @@ pub fn ManifestLogType(comptime Storage: type, comptime TableInfo: type) type {
441
440
  assert(manifest_log.writing);
442
441
 
443
442
  manifest_log.blocks_closed -= 1;
444
- manifest_log.blocks.advance_head();
445
443
  assert(manifest_log.blocks_closed <= manifest_log.blocks.count);
446
444
 
447
445
  manifest_log.write_block();
@@ -547,7 +545,7 @@ pub fn ManifestLogType(comptime Storage: type, comptime TableInfo: type) type {
547
545
  // Remove the extent if the table is the latest version.
548
546
  // We must iterate entries in forward order to drop the extent here.
549
547
  // Otherwise, stale versions earlier in the block may reappear.
550
- if (manifest.remove_table_extent(table.address, block_reference.address, entry)) {
548
+ if (manifest.remove_table_extent(manifest_log.tree_hash, table.address, block_reference.address, entry)) {
551
549
  switch (label.event) {
552
550
  // Append the table, updating the table extent:
553
551
  .insert => manifest_log.append(label, table),
@@ -22,11 +22,11 @@ const MessagePool = @import("../message_pool.zig").MessagePool;
22
22
  const SuperBlock = @import("../vsr/superblock.zig").SuperBlockType(Storage);
23
23
  const data_file_size_min = @import("../vsr/superblock.zig").data_file_size_min;
24
24
  const TableExtent = @import("../vsr/superblock_manifest.zig").Manifest.TableExtent;
25
- const Storage = @import("../test/storage.zig").Storage;
25
+ const Storage = @import("../testing/storage.zig").Storage;
26
26
  const Grid = @import("grid.zig").GridType(Storage);
27
27
  const BlockType = @import("grid.zig").BlockType;
28
28
  const ManifestLog = @import("manifest_log.zig").ManifestLogType(Storage, TableInfo);
29
- const fuzz = @import("../test/fuzz.zig");
29
+ const fuzz = @import("../testing/fuzz.zig");
30
30
 
31
31
  pub const tigerbeetle_config = @import("../config.zig").configs.test_min;
32
32
 
@@ -198,7 +198,7 @@ fn generate_events(
198
198
  event.* = switch (event_type) {
199
199
  .insert_new => insert: {
200
200
  const level = random.uintLessThan(u7, constants.lsm_levels);
201
- const table = .{
201
+ const table = TableInfo{
202
202
  .checksum = 0,
203
203
  .address = i + 1,
204
204
  .snapshot_min = 1,
@@ -210,10 +210,11 @@ fn generate_events(
210
210
  .level = level,
211
211
  .table = table,
212
212
  });
213
- break :insert ManifestEvent{ .insert = .{
213
+ const insert = ManifestEvent{ .insert = .{
214
214
  .level = level,
215
215
  .table = table,
216
216
  } };
217
+ break :insert insert;
217
218
  },
218
219
 
219
220
  .insert_change_level => insert: {
@@ -223,27 +224,30 @@ fn generate_events(
223
224
  }
224
225
 
225
226
  table.level += 1;
226
- break :insert ManifestEvent{ .insert = .{
227
+ const insert = ManifestEvent{ .insert = .{
227
228
  .level = table.level,
228
229
  .table = table.table,
229
230
  } };
231
+ break :insert insert;
230
232
  },
231
233
 
232
234
  .insert_change_snapshot => insert: {
233
235
  const table = &tables.items[random.uintLessThan(usize, tables.items.len)];
234
236
  table.table.snapshot_max += 1;
235
- break :insert ManifestEvent{ .insert = .{
237
+ const insert = ManifestEvent{ .insert = .{
236
238
  .level = table.level,
237
239
  .table = table.table,
238
240
  } };
241
+ break :insert insert;
239
242
  },
240
243
 
241
244
  .remove => remove: {
242
245
  const table = tables.swapRemove(random.uintLessThan(usize, tables.items.len));
243
- break :remove ManifestEvent{ .remove = .{
246
+ const remove = ManifestEvent{ .remove = .{
244
247
  .level = table.level,
245
248
  .table = table.table,
246
249
  } };
250
+ break :remove remove;
247
251
  },
248
252
 
249
253
  .compact => ManifestEvent{ .compact = {} },
@@ -615,7 +619,7 @@ fn verify_manifest(
615
619
  try std.testing.expect(std.mem.eql(u64, expect.addresses[0..c], actual.addresses[0..c]));
616
620
 
617
621
  try std.testing.expect(hash_map_equals(
618
- u64,
622
+ SuperBlock.Manifest.TableExtentKey,
619
623
  SuperBlock.Manifest.TableExtent,
620
624
  &expect.tables,
621
625
  &actual.tables,
@@ -1,7 +1,7 @@
1
1
  const std = @import("std");
2
2
  const assert = std.debug.assert;
3
3
 
4
- const util = @import("../util.zig");
4
+ const stdx = @import("../stdx.zig");
5
5
 
6
6
  const k_max = 2;
7
7