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.
- package/dist/.client.node.sha256 +1 -1
- package/package.json +1 -1
- package/src/node.zig +6 -1
- package/src/tigerbeetle/src/benchmark.zig +1 -1
- package/src/tigerbeetle/src/c/tb_client/context.zig +1 -1
- package/src/tigerbeetle/src/c/tb_client/echo_client.zig +1 -1
- package/src/tigerbeetle/src/c/tb_client/thread.zig +1 -1
- package/src/tigerbeetle/src/c/tb_client.h +97 -111
- package/src/tigerbeetle/src/c/tb_client.zig +29 -18
- package/src/tigerbeetle/src/c/tb_client_header.zig +218 -0
- package/src/tigerbeetle/src/c/test.zig +7 -7
- package/src/tigerbeetle/src/cli.zig +4 -4
- package/src/tigerbeetle/src/config.zig +184 -374
- package/src/tigerbeetle/src/constants.zig +394 -0
- package/src/tigerbeetle/src/demo.zig +1 -1
- package/src/tigerbeetle/src/ewah.zig +18 -29
- package/src/tigerbeetle/src/ewah_fuzz.zig +130 -0
- package/src/tigerbeetle/src/io/darwin.zig +1 -1
- package/src/tigerbeetle/src/io/linux.zig +2 -2
- package/src/tigerbeetle/src/io/windows.zig +1 -1
- package/src/tigerbeetle/src/lsm/bloom_filter.zig +1 -1
- package/src/tigerbeetle/src/lsm/compaction.zig +55 -2
- package/src/tigerbeetle/src/lsm/forest.zig +1 -1
- package/src/tigerbeetle/src/lsm/forest_fuzz.zig +15 -7
- package/src/tigerbeetle/src/lsm/grid.zig +1 -1
- package/src/tigerbeetle/src/lsm/groove.zig +5 -39
- package/src/tigerbeetle/src/lsm/level_iterator.zig +1 -1
- package/src/tigerbeetle/src/lsm/manifest.zig +1 -6
- package/src/tigerbeetle/src/lsm/manifest_level.zig +1 -1
- package/src/tigerbeetle/src/lsm/manifest_log.zig +1 -1
- package/src/tigerbeetle/src/lsm/manifest_log_fuzz.zig +14 -9
- package/src/tigerbeetle/src/lsm/posted_groove.zig +2 -13
- package/src/tigerbeetle/src/lsm/segmented_array_benchmark.zig +1 -1
- package/src/tigerbeetle/src/lsm/set_associative_cache.zig +1 -1
- package/src/tigerbeetle/src/lsm/table.zig +25 -17
- package/src/tigerbeetle/src/lsm/table_immutable.zig +1 -1
- package/src/tigerbeetle/src/lsm/table_iterator.zig +1 -1
- package/src/tigerbeetle/src/lsm/table_mutable.zig +1 -1
- package/src/tigerbeetle/src/lsm/test.zig +1 -1
- package/src/tigerbeetle/src/lsm/tree.zig +47 -5
- package/src/tigerbeetle/src/lsm/tree_fuzz.zig +22 -18
- package/src/tigerbeetle/src/main.zig +22 -16
- package/src/tigerbeetle/src/message_bus.zig +1 -1
- package/src/tigerbeetle/src/message_pool.zig +2 -2
- package/src/tigerbeetle/src/simulator.zig +3 -10
- package/src/tigerbeetle/src/state_machine.zig +627 -1806
- package/src/tigerbeetle/src/storage.zig +1 -1
- package/src/tigerbeetle/src/test/accounting/auditor.zig +1 -1
- package/src/tigerbeetle/src/test/accounting/workload.zig +1 -1
- package/src/tigerbeetle/src/test/cluster.zig +1 -1
- package/src/tigerbeetle/src/test/conductor.zig +1 -1
- package/src/tigerbeetle/src/test/fuzz.zig +19 -0
- package/src/tigerbeetle/src/test/message_bus.zig +1 -1
- package/src/tigerbeetle/src/test/network.zig +1 -1
- package/src/tigerbeetle/src/test/state_checker.zig +2 -2
- package/src/tigerbeetle/src/test/storage.zig +14 -5
- package/src/tigerbeetle/src/test/storage_checker.zig +1 -1
- package/src/tigerbeetle/src/test/table.zig +226 -0
- package/src/tigerbeetle/src/time.zig +1 -1
- package/src/tigerbeetle/src/tracer.zig +507 -0
- package/src/tigerbeetle/src/unit_tests.zig +2 -0
- package/src/tigerbeetle/src/vsr/client.zig +1 -1
- package/src/tigerbeetle/src/vsr/clock.zig +1 -1
- package/src/tigerbeetle/src/vsr/journal.zig +46 -115
- package/src/tigerbeetle/src/vsr/journal_format_fuzz.zig +111 -0
- package/src/tigerbeetle/src/vsr/replica.zig +50 -159
- package/src/tigerbeetle/src/vsr/replica_format.zig +216 -0
- package/src/tigerbeetle/src/vsr/superblock.zig +1 -1
- package/src/tigerbeetle/src/vsr/superblock_client_table.zig +1 -1
- package/src/tigerbeetle/src/vsr/superblock_free_set.zig +3 -2
- package/src/tigerbeetle/src/vsr/superblock_free_set_fuzz.zig +2 -0
- package/src/tigerbeetle/src/vsr/superblock_fuzz.zig +8 -5
- package/src/tigerbeetle/src/vsr/superblock_manifest.zig +1 -1
- package/src/tigerbeetle/src/vsr/superblock_quorums_fuzz.zig +2 -0
- 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
|
|
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
|
-
|
|
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.
|
|
@@ -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("../
|
|
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
|
|
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("../
|
|
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("../
|
|
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("../
|
|
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("../
|
|
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);
|
|
@@ -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("../
|
|
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
|
|
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,
|
|
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("../
|
|
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("../
|
|
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;
|
|
@@ -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("../
|
|
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
|
-
|
|
920
|
-
|
|
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
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
key_layout,
|
|
932
|
-
|
|
933
|
-
|
|
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("../
|
|
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("../
|
|
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("../
|
|
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("../
|
|
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
|
|