tigerbeetle-node 0.11.2 → 0.11.4

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 (75) hide show
  1. package/dist/.client.node.sha256 +1 -1
  2. package/package.json +1 -1
  3. package/src/node.zig +6 -1
  4. package/src/tigerbeetle/src/benchmark.zig +1 -1
  5. package/src/tigerbeetle/src/c/tb_client/context.zig +1 -1
  6. package/src/tigerbeetle/src/c/tb_client/echo_client.zig +1 -1
  7. package/src/tigerbeetle/src/c/tb_client/thread.zig +1 -1
  8. package/src/tigerbeetle/src/c/tb_client.h +97 -111
  9. package/src/tigerbeetle/src/c/tb_client.zig +29 -18
  10. package/src/tigerbeetle/src/c/tb_client_header.zig +218 -0
  11. package/src/tigerbeetle/src/c/test.zig +7 -7
  12. package/src/tigerbeetle/src/cli.zig +4 -4
  13. package/src/tigerbeetle/src/config.zig +184 -374
  14. package/src/tigerbeetle/src/constants.zig +394 -0
  15. package/src/tigerbeetle/src/demo.zig +1 -1
  16. package/src/tigerbeetle/src/ewah.zig +18 -29
  17. package/src/tigerbeetle/src/ewah_fuzz.zig +130 -0
  18. package/src/tigerbeetle/src/io/darwin.zig +1 -1
  19. package/src/tigerbeetle/src/io/linux.zig +2 -2
  20. package/src/tigerbeetle/src/io/windows.zig +1 -1
  21. package/src/tigerbeetle/src/lsm/bloom_filter.zig +1 -1
  22. package/src/tigerbeetle/src/lsm/compaction.zig +55 -2
  23. package/src/tigerbeetle/src/lsm/forest.zig +1 -1
  24. package/src/tigerbeetle/src/lsm/forest_fuzz.zig +15 -7
  25. package/src/tigerbeetle/src/lsm/grid.zig +1 -1
  26. package/src/tigerbeetle/src/lsm/groove.zig +5 -39
  27. package/src/tigerbeetle/src/lsm/level_iterator.zig +1 -1
  28. package/src/tigerbeetle/src/lsm/manifest.zig +1 -6
  29. package/src/tigerbeetle/src/lsm/manifest_level.zig +1 -1
  30. package/src/tigerbeetle/src/lsm/manifest_log.zig +1 -1
  31. package/src/tigerbeetle/src/lsm/manifest_log_fuzz.zig +14 -9
  32. package/src/tigerbeetle/src/lsm/posted_groove.zig +2 -13
  33. package/src/tigerbeetle/src/lsm/segmented_array_benchmark.zig +1 -1
  34. package/src/tigerbeetle/src/lsm/set_associative_cache.zig +1 -1
  35. package/src/tigerbeetle/src/lsm/table.zig +25 -17
  36. package/src/tigerbeetle/src/lsm/table_immutable.zig +1 -1
  37. package/src/tigerbeetle/src/lsm/table_iterator.zig +1 -1
  38. package/src/tigerbeetle/src/lsm/table_mutable.zig +1 -1
  39. package/src/tigerbeetle/src/lsm/test.zig +1 -1
  40. package/src/tigerbeetle/src/lsm/tree.zig +47 -5
  41. package/src/tigerbeetle/src/lsm/tree_fuzz.zig +22 -18
  42. package/src/tigerbeetle/src/main.zig +22 -16
  43. package/src/tigerbeetle/src/message_bus.zig +1 -1
  44. package/src/tigerbeetle/src/message_pool.zig +2 -2
  45. package/src/tigerbeetle/src/simulator.zig +3 -10
  46. package/src/tigerbeetle/src/state_machine.zig +627 -1806
  47. package/src/tigerbeetle/src/storage.zig +1 -1
  48. package/src/tigerbeetle/src/test/accounting/auditor.zig +1 -1
  49. package/src/tigerbeetle/src/test/accounting/workload.zig +1 -1
  50. package/src/tigerbeetle/src/test/cluster.zig +1 -1
  51. package/src/tigerbeetle/src/test/conductor.zig +1 -1
  52. package/src/tigerbeetle/src/test/fuzz.zig +19 -0
  53. package/src/tigerbeetle/src/test/message_bus.zig +1 -1
  54. package/src/tigerbeetle/src/test/network.zig +1 -1
  55. package/src/tigerbeetle/src/test/state_checker.zig +2 -2
  56. package/src/tigerbeetle/src/test/storage.zig +14 -5
  57. package/src/tigerbeetle/src/test/storage_checker.zig +1 -1
  58. package/src/tigerbeetle/src/test/table.zig +226 -0
  59. package/src/tigerbeetle/src/time.zig +1 -1
  60. package/src/tigerbeetle/src/tracer.zig +507 -0
  61. package/src/tigerbeetle/src/unit_tests.zig +2 -0
  62. package/src/tigerbeetle/src/vsr/client.zig +1 -1
  63. package/src/tigerbeetle/src/vsr/clock.zig +1 -1
  64. package/src/tigerbeetle/src/vsr/journal.zig +46 -115
  65. package/src/tigerbeetle/src/vsr/journal_format_fuzz.zig +111 -0
  66. package/src/tigerbeetle/src/vsr/replica.zig +50 -159
  67. package/src/tigerbeetle/src/vsr/replica_format.zig +216 -0
  68. package/src/tigerbeetle/src/vsr/superblock.zig +1 -1
  69. package/src/tigerbeetle/src/vsr/superblock_client_table.zig +1 -1
  70. package/src/tigerbeetle/src/vsr/superblock_free_set.zig +3 -2
  71. package/src/tigerbeetle/src/vsr/superblock_free_set_fuzz.zig +2 -0
  72. package/src/tigerbeetle/src/vsr/superblock_fuzz.zig +8 -5
  73. package/src/tigerbeetle/src/vsr/superblock_manifest.zig +1 -1
  74. package/src/tigerbeetle/src/vsr/superblock_quorums_fuzz.zig +2 -0
  75. package/src/tigerbeetle/src/vsr.zig +2 -2
@@ -36,7 +36,9 @@ const math = std.math;
36
36
  const assert = std.debug.assert;
37
37
 
38
38
  const log = std.log.scoped(.compaction);
39
- const config = @import("../config.zig");
39
+ const tracer = @import("../tracer.zig");
40
+
41
+ const config = @import("../constants.zig");
40
42
 
41
43
  const GridType = @import("grid.zig").GridType;
42
44
  const ManifestType = @import("manifest.zig").ManifestType;
@@ -120,6 +122,8 @@ pub fn CompactionType(
120
122
  done,
121
123
  };
122
124
 
125
+ tree_name: [:0]const u8,
126
+
123
127
  grid: *Grid,
124
128
  grid_reservation: Grid.Reservation,
125
129
  range: Manifest.CompactionRange,
@@ -155,7 +159,9 @@ pub fn CompactionType(
155
159
 
156
160
  tables_output_count: usize = 0,
157
161
 
158
- pub fn init(allocator: mem.Allocator) !Compaction {
162
+ tracer_slot: ?tracer.SpanStart = null,
163
+
164
+ pub fn init(allocator: mem.Allocator, tree_name: [:0]const u8) !Compaction {
159
165
  var iterator_a = try IteratorA.init(allocator);
160
166
  errdefer iterator_a.deinit(allocator);
161
167
 
@@ -166,6 +172,8 @@ pub fn CompactionType(
166
172
  errdefer table_builder.deinit(allocator);
167
173
 
168
174
  return Compaction{
175
+ .tree_name = tree_name,
176
+
169
177
  // Assigned by start()
170
178
  .grid = undefined,
171
179
  .grid_reservation = undefined,
@@ -216,6 +224,7 @@ pub fn CompactionType(
216
224
  assert(compaction.callback == null);
217
225
  assert(compaction.io_pending == 0);
218
226
  assert(!compaction.merge_done and compaction.merge_iterator == null);
227
+ assert(compaction.tracer_slot == null);
219
228
 
220
229
  assert(op_min % @divExact(config.lsm_batch_multiple, 2) == 0);
221
230
  assert(range.table_count > 0);
@@ -230,6 +239,8 @@ pub fn CompactionType(
230
239
  assert(drop_tombstones or level_b < config.lsm_levels - 1);
231
240
 
232
241
  compaction.* = .{
242
+ .tree_name = compaction.tree_name,
243
+
233
244
  .grid = grid,
234
245
  // Reserve enough blocks to write our output tables in the worst case, where:
235
246
  // - no tombstones are dropped,
@@ -337,6 +348,16 @@ pub fn CompactionType(
337
348
 
338
349
  compaction.callback = callback;
339
350
 
351
+ tracer.start(
352
+ &compaction.tracer_slot,
353
+ .{ .tree = .{ .tree_name = compaction.tree_name } },
354
+ .{ .tree_compaction_tick = .{
355
+ .tree_name = compaction.tree_name,
356
+ .level_b = compaction.level_b,
357
+ } },
358
+ @src(),
359
+ );
360
+
340
361
  // Generate fake IO to make sure io_pending doesn't reach zero multiple times from
341
362
  // IO being completed inline down below.
342
363
  // The fake IO is immediately resolved and triggers the cpu_merge_start if all
@@ -405,6 +426,17 @@ pub fn CompactionType(
405
426
  assert(compaction.io_pending == 0);
406
427
  assert(!compaction.merge_done);
407
428
 
429
+ var tracer_slot: ?tracer.SpanStart = null;
430
+ tracer.start(
431
+ &tracer_slot,
432
+ .{ .tree = .{ .tree_name = compaction.tree_name } },
433
+ .{ .tree_compaction_merge = .{
434
+ .tree_name = compaction.tree_name,
435
+ .level_b = compaction.level_b,
436
+ } },
437
+ @src(),
438
+ );
439
+
408
440
  // Create the merge iterator only when we can peek() from the read iterators.
409
441
  // This happens after IO for the first reads complete.
410
442
  if (compaction.merge_iterator == null) {
@@ -422,6 +454,23 @@ pub fn CompactionType(
422
454
  compaction.cpu_merge_finish();
423
455
  }
424
456
 
457
+ tracer.end(
458
+ &tracer_slot,
459
+ .{ .tree = .{ .tree_name = compaction.tree_name } },
460
+ .{ .tree_compaction_merge = .{
461
+ .tree_name = compaction.tree_name,
462
+ .level_b = compaction.level_b,
463
+ } },
464
+ );
465
+ tracer.end(
466
+ &compaction.tracer_slot,
467
+ .{ .tree = .{ .tree_name = compaction.tree_name } },
468
+ .{ .tree_compaction_tick = .{
469
+ .tree_name = compaction.tree_name,
470
+ .level_b = compaction.level_b,
471
+ } },
472
+ );
473
+
425
474
  // TODO Implement pacing here by deciding if we should do another compact_tick()
426
475
  // instead of invoking the callback, using compaction.range.table_count as the heuristic.
427
476
 
@@ -455,6 +504,8 @@ pub fn CompactionType(
455
504
  // Finalize the data block if it's full or if it contains pending values when there's
456
505
  // no more left to merge.
457
506
  if (compaction.table_builder.data_block_full() or
507
+ compaction.table_builder.filter_block_full() or
508
+ compaction.table_builder.index_block_full() or
458
509
  (merge_iterator.empty() and !compaction.table_builder.data_block_empty()))
459
510
  {
460
511
  compaction.table_builder.data_block_finish(.{
@@ -471,6 +522,7 @@ pub fn CompactionType(
471
522
  // Finalize the filter block if it's full or if it contains pending data blocks
472
523
  // when there's no more merged values to fill them.
473
524
  if (compaction.table_builder.filter_block_full() or
525
+ compaction.table_builder.index_block_full() or
474
526
  (merge_iterator.empty() and !compaction.table_builder.filter_block_empty()))
475
527
  {
476
528
  compaction.table_builder.filter_block_finish(.{
@@ -560,6 +612,7 @@ pub fn CompactionType(
560
612
  assert(compaction.callback == null);
561
613
  assert(compaction.io_pending == 0);
562
614
  assert(compaction.merge_done);
615
+ assert(compaction.tracer_slot == null);
563
616
 
564
617
  // TODO(Beat Pacing) This should really be where the compaction callback is invoked,
565
618
  // but currently that can occur multiple times per beat.
@@ -4,7 +4,7 @@ const assert = std.debug.assert;
4
4
  const math = std.math;
5
5
  const mem = std.mem;
6
6
 
7
- const config = @import("../config.zig");
7
+ const config = @import("../constants.zig");
8
8
  const vsr = @import("../vsr.zig");
9
9
 
10
10
  const GridType = @import("grid.zig").GridType;
@@ -3,10 +3,12 @@ const testing = std.testing;
3
3
  const allocator = testing.allocator;
4
4
  const assert = std.debug.assert;
5
5
 
6
- const config = @import("../config.zig");
6
+ const config = @import("../constants.zig");
7
7
  const fuzz = @import("../test/fuzz.zig");
8
8
  const vsr = @import("../vsr.zig");
9
+
9
10
  const log = std.log.scoped(.lsm_forest_fuzz);
11
+ const tracer = @import("../tracer.zig");
10
12
 
11
13
  const MessagePool = @import("../message_pool.zig").MessagePool;
12
14
  const Transfer = @import("../tigerbeetle.zig").Transfer;
@@ -23,6 +25,8 @@ const Forest = StateMachine.Forest;
23
25
  const Grid = GridType(Storage);
24
26
  const SuperBlock = vsr.SuperBlockType(Storage);
25
27
 
28
+ pub const tigerbeetle_config = @import("../config.zig").configs.test_min;
29
+
26
30
  const FuzzOp = union(enum) {
27
31
  // TODO Test secondary index lookups and range queries.
28
32
  compact: struct {
@@ -306,11 +310,7 @@ fn random_id(random: std.rand.Random, comptime Int: type) Int {
306
310
  return fuzz.random_int_exponential(random, Int, avg_int);
307
311
  }
308
312
 
309
- pub fn generate_fuzz_ops(random: std.rand.Random) ![]const FuzzOp {
310
- const fuzz_op_count = @minimum(
311
- @as(usize, 1E7),
312
- fuzz.random_int_exponential(random, usize, 1E6),
313
- );
313
+ pub fn generate_fuzz_ops(random: std.rand.Random, fuzz_op_count: usize) ![]const FuzzOp {
314
314
  log.info("fuzz_op_count = {}", .{fuzz_op_count});
315
315
 
316
316
  const fuzz_ops = try allocator.alloc(FuzzOp, fuzz_op_count);
@@ -395,11 +395,19 @@ pub fn generate_fuzz_ops(random: std.rand.Random) ![]const FuzzOp {
395
395
  }
396
396
 
397
397
  pub fn main() !void {
398
+ try tracer.init(allocator);
399
+ defer tracer.deinit(allocator);
400
+
398
401
  const fuzz_args = try fuzz.parse_fuzz_args(allocator);
399
402
  var rng = std.rand.DefaultPrng.init(fuzz_args.seed);
400
403
  const random = rng.random();
401
404
 
402
- const fuzz_ops = try generate_fuzz_ops(random);
405
+ const fuzz_op_count = @minimum(
406
+ fuzz_args.events_max orelse @as(usize, 1E7),
407
+ fuzz.random_int_exponential(random, usize, 1E6),
408
+ );
409
+
410
+ const fuzz_ops = try generate_fuzz_ops(random, fuzz_op_count);
403
411
  defer allocator.free(fuzz_ops);
404
412
 
405
413
  try run_fuzz_ops(Storage.Options{
@@ -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 config = @import("../constants.zig");
6
6
  const vsr = @import("../vsr.zig");
7
7
  const free_set = @import("../vsr/superblock_free_set.zig");
8
8
 
@@ -4,7 +4,7 @@ const assert = std.debug.assert;
4
4
  const math = std.math;
5
5
  const mem = std.mem;
6
6
 
7
- const config = @import("../config.zig");
7
+ const config = @import("../constants.zig");
8
8
 
9
9
  const TableType = @import("table.zig").TableType;
10
10
  const TreeType = @import("tree.zig").TreeType;
@@ -120,7 +120,7 @@ comptime {
120
120
  fn IndexTreeType(
121
121
  comptime Storage: type,
122
122
  comptime Field: type,
123
- comptime tree_name: []const u8,
123
+ comptime tree_name: [:0]const u8,
124
124
  ) type {
125
125
  const Key = CompositeKey(IndexCompositeKeyType(Field));
126
126
  const Table = TableType(
@@ -404,12 +404,8 @@ pub fn GrooveType(
404
404
  join_pending: usize = 0,
405
405
  join_callback: ?Callback = null,
406
406
 
407
- objects_cache: *ObjectTree.TableMutable.ValuesCache,
408
407
  objects: ObjectTree,
409
-
410
- ids_cache: *IdTree.TableMutable.ValuesCache,
411
408
  ids: IdTree,
412
-
413
409
  indexes: IndexTrees,
414
410
 
415
411
  /// Object IDs enqueued to be prefetched.
@@ -428,10 +424,6 @@ pub fn GrooveType(
428
424
  prefetch_snapshot: ?u64,
429
425
 
430
426
  pub const Options = struct {
431
- /// TODO Improve unit in this name to make more clear what should be passed.
432
- /// For example, is this a size in bytes or a count in objects? It's a count in objects,
433
- /// but the name poorly reflects this.
434
- cache_entries_max: u32,
435
427
  /// The maximum number of objects that might be prefetched by a batch.
436
428
  prefetch_entries_max: u32,
437
429
 
@@ -446,38 +438,19 @@ pub fn GrooveType(
446
438
  grid: *Grid,
447
439
  options: Options,
448
440
  ) !Groove {
449
- // Cache is heap-allocated to pass a pointer into the Object tree.
450
- const objects_cache = try allocator.create(ObjectTree.TableMutable.ValuesCache);
451
- errdefer allocator.destroy(objects_cache);
452
-
453
- objects_cache.* = try ObjectTree.TableMutable.ValuesCache.init(
454
- allocator,
455
- options.cache_entries_max,
456
- );
457
- errdefer objects_cache.deinit(allocator);
458
-
459
441
  // Intialize the object LSM tree.
460
442
  var object_tree = try ObjectTree.init(
461
443
  allocator,
462
444
  node_pool,
463
445
  grid,
464
- objects_cache,
465
446
  options.tree_options_object,
466
447
  );
467
448
  errdefer object_tree.deinit(allocator);
468
449
 
469
- // Cache is heap-allocated to pass a pointer into the ID tree.
470
- const ids_cache = try allocator.create(IdTree.TableMutable.ValuesCache);
471
- errdefer allocator.destroy(ids_cache);
472
-
473
- ids_cache.* = try IdTree.TableMutable.ValuesCache.init(allocator, options.cache_entries_max);
474
- errdefer ids_cache.deinit(allocator);
475
-
476
450
  var id_tree = try IdTree.init(
477
451
  allocator,
478
452
  node_pool,
479
453
  grid,
480
- ids_cache,
481
454
  options.tree_options_id,
482
455
  );
483
456
  errdefer id_tree.deinit(allocator);
@@ -494,11 +467,13 @@ pub fn GrooveType(
494
467
 
495
468
  // Initialize index LSM trees.
496
469
  inline for (std.meta.fields(IndexTrees)) |field| {
470
+ // No value cache for index trees, since they only do range queries.
471
+ assert(@field(options.tree_options_index, field.name).cache_entries_max == 0);
472
+
497
473
  @field(index_trees, field.name) = try field.field_type.init(
498
474
  allocator,
499
475
  node_pool,
500
476
  grid,
501
- null, // No value cache for index trees, since they only do range queries.
502
477
  @field(options.tree_options_index, field.name),
503
478
  );
504
479
  index_trees_initialized += 1;
@@ -513,12 +488,8 @@ pub fn GrooveType(
513
488
  errdefer prefetch_objects.deinit(allocator);
514
489
 
515
490
  return Groove{
516
- .objects_cache = objects_cache,
517
491
  .objects = object_tree,
518
-
519
- .ids_cache = ids_cache,
520
492
  .ids = id_tree,
521
-
522
493
  .indexes = index_trees,
523
494
 
524
495
  .prefetch_ids = prefetch_ids,
@@ -533,12 +504,7 @@ pub fn GrooveType(
533
504
  }
534
505
 
535
506
  groove.objects.deinit(allocator);
536
- groove.objects_cache.deinit(allocator);
537
- allocator.destroy(groove.objects_cache);
538
-
539
507
  groove.ids.deinit(allocator);
540
- groove.ids_cache.deinit(allocator);
541
- allocator.destroy(groove.ids_cache);
542
508
 
543
509
  groove.prefetch_ids.deinit(allocator);
544
510
  groove.prefetch_objects.deinit(allocator);
@@ -3,7 +3,7 @@ const mem = std.mem;
3
3
  const math = std.math;
4
4
  const assert = std.debug.assert;
5
5
 
6
- const config = @import("../config.zig");
6
+ const config = @import("../constants.zig");
7
7
 
8
8
  const Direction = @import("direction.zig").Direction;
9
9
  const TableIteratorType = @import("table_iterator.zig").TableIteratorType;
@@ -3,7 +3,7 @@ const mem = std.mem;
3
3
  const math = std.math;
4
4
  const assert = std.debug.assert;
5
5
 
6
- const config = @import("../config.zig");
6
+ const config = @import("../constants.zig");
7
7
  const growth_factor = config.lsm_growth_factor;
8
8
 
9
9
  const table_count_max = @import("tree.zig").table_count_max;
@@ -279,8 +279,6 @@ pub fn ManifestType(comptime Table: type, comptime Storage: type) type {
279
279
  key: Key,
280
280
  level: u8 = 0,
281
281
  inner: ?Level.Iterator = null,
282
- // Verifies that we never check a newer table after an older one.
283
- precedence: ?u64 = null,
284
282
 
285
283
  pub fn next(it: *LookupIterator) ?*const TableInfo {
286
284
  while (it.level < config.lsm_levels) : (it.level += 1) {
@@ -294,9 +292,6 @@ pub fn ManifestType(comptime Table: type, comptime Storage: type) type {
294
292
  );
295
293
 
296
294
  if (inner.next()) |table| {
297
- if (it.precedence) |p| assert(p > table.snapshot_min);
298
- it.precedence = table.snapshot_min;
299
-
300
295
  assert(table.visible(it.snapshot));
301
296
  assert(compare_keys(it.key, table.key_min) != .lt);
302
297
  assert(compare_keys(it.key, table.key_max) != .gt);
@@ -4,7 +4,7 @@ const math = std.math;
4
4
  const mem = std.mem;
5
5
  const meta = std.meta;
6
6
 
7
- const config = @import("../config.zig");
7
+ const config = @import("../constants.zig");
8
8
  const lsm = @import("tree.zig");
9
9
  const binary_search = @import("binary_search.zig");
10
10
 
@@ -26,7 +26,7 @@ const mem = std.mem;
26
26
 
27
27
  const log = std.log.scoped(.manifest_log);
28
28
 
29
- const config = @import("../config.zig");
29
+ const config = @import("../constants.zig");
30
30
  const vsr = @import("../vsr.zig");
31
31
  const util = @import("../util.zig");
32
32
 
@@ -16,7 +16,7 @@ const assert = std.debug.assert;
16
16
  const log = std.log.scoped(.fuzz_lsm_manifest_log);
17
17
 
18
18
  const vsr = @import("../vsr.zig");
19
- const config = @import("../config.zig");
19
+ const config = @import("../constants.zig");
20
20
  const RingBuffer = @import("../ring_buffer.zig").RingBuffer;
21
21
  const MessagePool = @import("../message_pool.zig").MessagePool;
22
22
  const SuperBlock = @import("../vsr/superblock.zig").SuperBlockType(Storage);
@@ -28,6 +28,8 @@ const BlockType = @import("grid.zig").BlockType;
28
28
  const ManifestLog = @import("manifest_log.zig").ManifestLogType(Storage, TableInfo);
29
29
  const fuzz = @import("../test/fuzz.zig");
30
30
 
31
+ pub const tigerbeetle_config = @import("../config.zig").configs.test_min;
32
+
31
33
  const storage_size_max = data_file_size_min + config.block_size * 1024;
32
34
 
33
35
  const entries_max_block = ManifestLog.Block.entry_count_max;
@@ -40,7 +42,12 @@ pub fn main() !void {
40
42
 
41
43
  var prng = std.rand.DefaultPrng.init(args.seed);
42
44
 
43
- const events = try generate_events(allocator, prng.random());
45
+ const events_count = std.math.min(
46
+ args.events_max orelse @as(usize, 2e5),
47
+ fuzz.random_int_exponential(prng.random(), usize, 1e4),
48
+ );
49
+
50
+ const events = try generate_events(allocator, prng.random(), events_count);
44
51
  defer allocator.free(events);
45
52
 
46
53
  try run_fuzz(allocator, prng.random(), events);
@@ -122,6 +129,7 @@ const ManifestEvent = union(enum) {
122
129
  fn generate_events(
123
130
  allocator: std.mem.Allocator,
124
131
  random: std.rand.Random,
132
+ events_count: usize,
125
133
  ) ![]const ManifestEvent {
126
134
  const EventType = enum {
127
135
  insert_new,
@@ -132,20 +140,17 @@ fn generate_events(
132
140
  checkpoint,
133
141
  };
134
142
 
135
- const events = try allocator.alloc(ManifestEvent, std.math.min(
136
- @as(usize, 1e6),
137
- fuzz.random_int_exponential(random, usize, 1e4),
138
- ));
143
+ const events = try allocator.alloc(ManifestEvent, events_count);
139
144
  errdefer allocator.free(events);
140
145
 
141
146
  var event_distribution = fuzz.random_enum_distribution(random, EventType);
142
147
  // Don't remove too often, so that there are plenty of tables accumulating.
143
- event_distribution.remove /= config.lsm_levels;
148
+ event_distribution.remove /= @intToFloat(f64, config.lsm_levels);
144
149
  // Don't compact or checkpoint too often, to approximate a real workload.
145
150
  // Additionally, checkpoint is slow because of the verification, so run it less
146
151
  // frequently.
147
- event_distribution.compact /= config.lsm_levels * config.lsm_batch_multiple;
148
- event_distribution.checkpoint /= config.lsm_levels * config.journal_slot_count;
152
+ event_distribution.compact /= @intToFloat(f64, config.lsm_levels * config.lsm_batch_multiple);
153
+ event_distribution.checkpoint /= @intToFloat(f64, config.lsm_levels * config.journal_slot_count);
149
154
 
150
155
  log.info("event_distribution = {d:.2}", .{event_distribution});
151
156
  log.info("event_count = {d}", .{events.len});
@@ -4,7 +4,7 @@ const assert = std.debug.assert;
4
4
  const math = std.math;
5
5
  const mem = std.mem;
6
6
 
7
- const config = @import("../config.zig");
7
+ const config = @import("../constants.zig");
8
8
 
9
9
  const TableType = @import("table.zig").TableType;
10
10
  const TreeType = @import("tree.zig").TreeType;
@@ -75,7 +75,6 @@ pub fn PostedGrooveType(comptime Storage: type) type {
75
75
  const PrefetchIDs = std.AutoHashMapUnmanaged(u128, void);
76
76
  const PrefetchObjects = std.AutoHashMapUnmanaged(u128, bool); // true:posted, false:voided
77
77
 
78
- cache: *Tree.TableMutable.ValuesCache,
79
78
  tree: Tree,
80
79
 
81
80
  /// Object IDs enqueued to be prefetched.
@@ -110,19 +109,12 @@ pub fn PostedGrooveType(comptime Storage: type) type {
110
109
  grid: *Grid,
111
110
  options: Options,
112
111
  ) !PostedGroove {
113
- // Cache is heap-allocated to pass a pointer into the Object tree.
114
- const cache = try allocator.create(Tree.TableMutable.ValuesCache);
115
- errdefer allocator.destroy(cache);
116
-
117
- cache.* = try Tree.TableMutable.ValuesCache.init(allocator, options.cache_entries_max);
118
- errdefer cache.deinit(allocator);
119
-
120
112
  var tree = try Tree.init(
121
113
  allocator,
122
114
  node_pool,
123
115
  grid,
124
- cache,
125
116
  .{
117
+ .cache_entries_max = options.cache_entries_max,
126
118
  .commit_entries_max = options.commit_entries_max,
127
119
  },
128
120
  );
@@ -137,7 +129,6 @@ pub fn PostedGrooveType(comptime Storage: type) type {
137
129
  errdefer prefetch_objects.deinit(allocator);
138
130
 
139
131
  return PostedGroove{
140
- .cache = cache,
141
132
  .tree = tree,
142
133
 
143
134
  .prefetch_ids = prefetch_ids,
@@ -148,8 +139,6 @@ pub fn PostedGrooveType(comptime Storage: type) type {
148
139
 
149
140
  pub fn deinit(groove: *PostedGroove, allocator: mem.Allocator) void {
150
141
  groove.tree.deinit(allocator);
151
- groove.cache.deinit(allocator);
152
- allocator.destroy(groove.cache);
153
142
 
154
143
  groove.prefetch_ids.deinit(allocator);
155
144
  groove.prefetch_objects.deinit(allocator);
@@ -1,7 +1,7 @@
1
1
  const std = @import("std");
2
2
  const assert = std.debug.assert;
3
3
 
4
- const config = @import("../config.zig");
4
+ const config = @import("../constants.zig");
5
5
  const NodePoolType = @import("node_pool.zig").NodePool;
6
6
  const table_count_max_for_level = @import("tree.zig").table_count_max_for_level;
7
7
  const table_count_max_for_tree = @import("tree.zig").table_count_max_for_tree;
@@ -7,7 +7,7 @@ const mem = std.mem;
7
7
  const meta = std.meta;
8
8
  const Vector = meta.Vector;
9
9
 
10
- const config = @import("../config.zig");
10
+ const config = @import("../constants.zig");
11
11
  const div_ceil = @import("../util.zig").div_ceil;
12
12
  const verify = config.verify;
13
13
 
@@ -3,7 +3,7 @@ const mem = std.mem;
3
3
  const math = std.math;
4
4
  const assert = std.debug.assert;
5
5
 
6
- const config = @import("../config.zig");
6
+ const config = @import("../constants.zig");
7
7
  const vsr = @import("../vsr.zig");
8
8
  const binary_search = @import("binary_search.zig");
9
9
  const bloom_filter = @import("bloom_filter.zig");
@@ -561,8 +561,9 @@ pub fn TableType(
561
561
  }
562
562
  }
563
563
 
564
- assert(@divExact(data.key_layout_size, key_size) == data.key_count + 1);
565
564
  if (data.key_count > 0) {
565
+ assert(@divExact(data.key_layout_size, key_size) == data.key_count + 1);
566
+
566
567
  const key_layout_bytes = @alignCast(
567
568
  @alignOf(Key),
568
569
  block[data.key_layout_offset..][0..data.key_layout_size],
@@ -638,6 +639,7 @@ pub fn TableType(
638
639
 
639
640
  pub fn filter_block_finish(builder: *Builder, options: FilterFinishOptions) void {
640
641
  assert(!builder.filter_block_empty());
642
+ assert(builder.data_block_empty());
641
643
  assert(options.address > 0);
642
644
 
643
645
  const header_bytes = builder.filter_block[0..@sizeOf(vsr.Header)];
@@ -680,6 +682,8 @@ pub fn TableType(
680
682
 
681
683
  pub fn index_block_finish(builder: *Builder, options: IndexFinishOptions) TableInfo {
682
684
  assert(options.address > 0);
685
+ assert(builder.filter_block_empty());
686
+ assert(builder.data_block_empty());
683
687
  assert(builder.data_block_count > 0);
684
688
  assert(builder.value == 0);
685
689
  assert(builder.data_blocks_in_filter == 0);
@@ -916,22 +920,26 @@ pub fn TableType(
916
920
  }
917
921
 
918
922
  pub fn data_block_search(data_block: BlockPtrConst, key: Key) ?*const Value {
919
- assert(@divExact(data.key_layout_size, key_size) == data.key_count + 1);
920
- const key_layout_bytes = @alignCast(
921
- @alignOf(Key),
922
- data_block[data.key_layout_offset..][0..data.key_layout_size],
923
- );
924
- const key_layout = mem.bytesAsValue([data.key_count + 1]Key, key_layout_bytes);
923
+ const values = blk: {
924
+ if (data.key_count == 0) break :blk data_block_values_used(data_block);
925
925
 
926
- const e = eytzinger(data.key_count, data.value_count_max);
927
- const values = e.search_values(
928
- Key,
929
- Value,
930
- compare_keys,
931
- key_layout,
932
- data_block_values_used(data_block),
933
- key,
934
- );
926
+ assert(@divExact(data.key_layout_size, key_size) == data.key_count + 1);
927
+ const key_layout_bytes = @alignCast(
928
+ @alignOf(Key),
929
+ data_block[data.key_layout_offset..][0..data.key_layout_size],
930
+ );
931
+ const key_layout = mem.bytesAsValue([data.key_count + 1]Key, key_layout_bytes);
932
+
933
+ const e = eytzinger(data.key_count, data.value_count_max);
934
+ break :blk e.search_values(
935
+ Key,
936
+ Value,
937
+ compare_keys,
938
+ key_layout,
939
+ data_block_values_used(data_block),
940
+ key,
941
+ );
942
+ };
935
943
 
936
944
  const result = binary_search.binary_search_values(
937
945
  Key,
@@ -3,7 +3,7 @@ const mem = std.mem;
3
3
  const math = std.math;
4
4
  const assert = std.debug.assert;
5
5
 
6
- const config = @import("../config.zig");
6
+ const config = @import("../constants.zig");
7
7
  const div_ceil = @import("../util.zig").div_ceil;
8
8
  const binary_search = @import("binary_search.zig");
9
9
  const snapshot_latest = @import("tree.zig").snapshot_latest;
@@ -3,7 +3,7 @@ const mem = std.mem;
3
3
  const math = std.math;
4
4
  const assert = std.debug.assert;
5
5
 
6
- const config = @import("../config.zig");
6
+ const config = @import("../constants.zig");
7
7
 
8
8
  const util = @import("../util.zig");
9
9
  const RingBuffer = @import("../ring_buffer.zig").RingBuffer;
@@ -3,7 +3,7 @@ const mem = std.mem;
3
3
  const math = std.math;
4
4
  const assert = std.debug.assert;
5
5
 
6
- const config = @import("../config.zig");
6
+ const config = @import("../constants.zig");
7
7
  const div_ceil = @import("../util.zig").div_ceil;
8
8
  const SetAssociativeCache = @import("set_associative_cache.zig").SetAssociativeCache;
9
9
 
@@ -4,7 +4,7 @@ const allocator = testing.allocator;
4
4
  const assert = std.debug.assert;
5
5
  const os = std.os;
6
6
 
7
- const config = @import("../config.zig");
7
+ const config = @import("../constants.zig");
8
8
  const vsr = @import("../vsr.zig");
9
9
  const log = std.log.scoped(.lsm_forest_test);
10
10