tigerbeetle-node 0.11.5 → 0.11.7
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/dist/index.d.ts +41 -42
- package/dist/index.js +41 -42
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +0 -1
- package/src/tigerbeetle/scripts/benchmark.bat +7 -3
- package/src/tigerbeetle/scripts/benchmark.sh +2 -3
- package/src/tigerbeetle/scripts/install.bat +7 -0
- package/src/tigerbeetle/scripts/install.sh +2 -3
- package/src/tigerbeetle/src/benchmark.zig +3 -3
- package/src/tigerbeetle/src/config.zig +24 -3
- package/src/tigerbeetle/src/constants.zig +8 -5
- package/src/tigerbeetle/src/ewah.zig +6 -5
- package/src/tigerbeetle/src/ewah_fuzz.zig +1 -1
- package/src/tigerbeetle/src/io/darwin.zig +19 -0
- package/src/tigerbeetle/src/io/linux.zig +8 -0
- package/src/tigerbeetle/src/io/windows.zig +20 -2
- package/src/tigerbeetle/src/iops.zig +7 -1
- package/src/tigerbeetle/src/lsm/compaction.zig +27 -72
- package/src/tigerbeetle/src/lsm/forest_fuzz.zig +10 -11
- package/src/tigerbeetle/src/lsm/grid.zig +267 -267
- package/src/tigerbeetle/src/lsm/groove.zig +3 -0
- package/src/tigerbeetle/src/lsm/level_iterator.zig +18 -1
- package/src/tigerbeetle/src/lsm/manifest.zig +29 -1
- package/src/tigerbeetle/src/lsm/manifest_level.zig +1 -0
- package/src/tigerbeetle/src/lsm/manifest_log.zig +5 -5
- package/src/tigerbeetle/src/lsm/manifest_log_fuzz.zig +19 -11
- package/src/tigerbeetle/src/lsm/merge_iterator.zig +106 -0
- package/src/tigerbeetle/src/lsm/posted_groove.zig +1 -0
- package/src/tigerbeetle/src/lsm/segmented_array.zig +1 -0
- package/src/tigerbeetle/src/lsm/set_associative_cache.zig +26 -70
- package/src/tigerbeetle/src/lsm/table.zig +56 -0
- package/src/tigerbeetle/src/lsm/table_iterator.zig +29 -2
- package/src/tigerbeetle/src/lsm/table_mutable.zig +49 -15
- package/src/tigerbeetle/src/lsm/test.zig +10 -7
- package/src/tigerbeetle/src/lsm/tree.zig +27 -6
- package/src/tigerbeetle/src/lsm/tree_fuzz.zig +302 -263
- package/src/tigerbeetle/src/message_pool.zig +2 -1
- package/src/tigerbeetle/src/simulator.zig +22 -84
- package/src/tigerbeetle/src/{test/accounting → state_machine}/auditor.zig +8 -8
- package/src/tigerbeetle/src/{test/accounting → state_machine}/workload.zig +108 -48
- package/src/tigerbeetle/src/state_machine.zig +20 -14
- package/src/tigerbeetle/src/storage.zig +58 -6
- package/src/tigerbeetle/src/test/cluster.zig +14 -11
- package/src/tigerbeetle/src/test/conductor.zig +2 -3
- package/src/tigerbeetle/src/test/id.zig +10 -0
- package/src/tigerbeetle/src/test/state_checker.zig +1 -1
- package/src/tigerbeetle/src/test/state_machine.zig +151 -46
- package/src/tigerbeetle/src/test/storage.zig +22 -1
- package/src/tigerbeetle/src/tigerbeetle.zig +0 -1
- package/src/tigerbeetle/src/tracer.zig +50 -28
- package/src/tigerbeetle/src/unit_tests.zig +11 -6
- package/src/tigerbeetle/src/vopr.zig +4 -4
- package/src/tigerbeetle/src/vsr/client.zig +5 -5
- package/src/tigerbeetle/src/vsr/clock.zig +2 -2
- package/src/tigerbeetle/src/vsr/journal.zig +647 -537
- package/src/tigerbeetle/src/vsr/replica.zig +333 -333
- package/src/tigerbeetle/src/vsr/replica_format.zig +7 -4
- package/src/tigerbeetle/src/vsr/superblock.zig +87 -39
- package/src/tigerbeetle/src/vsr/superblock_free_set.zig +114 -93
- package/src/tigerbeetle/src/vsr/superblock_free_set_fuzz.zig +1 -1
- package/src/tigerbeetle/src/vsr/superblock_fuzz.zig +11 -8
- package/src/tigerbeetle/src/vsr/superblock_quorums_fuzz.zig +3 -3
- package/src/tigerbeetle/src/vsr.zig +60 -13
- package/src/tigerbeetle/src/c/tb_client/context.zig +0 -304
- package/src/tigerbeetle/src/c/tb_client/echo_client.zig +0 -108
- package/src/tigerbeetle/src/c/tb_client/packet.zig +0 -80
- package/src/tigerbeetle/src/c/tb_client/signal.zig +0 -286
- package/src/tigerbeetle/src/c/tb_client/thread.zig +0 -88
- package/src/tigerbeetle/src/c/tb_client.h +0 -221
- package/src/tigerbeetle/src/c/tb_client.zig +0 -177
- package/src/tigerbeetle/src/c/tb_client_header.zig +0 -218
- package/src/tigerbeetle/src/c/tb_client_header_test.zig +0 -135
- package/src/tigerbeetle/src/c/test.zig +0 -371
- package/src/tigerbeetle/src/cli.zig +0 -375
- package/src/tigerbeetle/src/main.zig +0 -245
|
@@ -62,7 +62,7 @@ pub const IO = struct {
|
|
|
62
62
|
};
|
|
63
63
|
|
|
64
64
|
fn flush(self: *IO, mode: FlushMode) !void {
|
|
65
|
-
if (self.completed.
|
|
65
|
+
if (self.completed.empty()) {
|
|
66
66
|
// Compute how long to poll by flushing timeout completions.
|
|
67
67
|
// NOTE: this may push to completed queue
|
|
68
68
|
var timeout_ms: ?os.windows.DWORD = null;
|
|
@@ -78,7 +78,7 @@ pub const IO = struct {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
// Poll for IO iff theres IO pending and flush_timeouts() found no ready completions
|
|
81
|
-
if (self.io_pending > 0 and self.completed.
|
|
81
|
+
if (self.io_pending > 0 and self.completed.empty()) {
|
|
82
82
|
// In blocking mode, we're always waiting at least until the timeout by run_for_ns.
|
|
83
83
|
// In non-blocking mode, we shouldn't wait at all.
|
|
84
84
|
const io_timeout = switch (mode) {
|
|
@@ -868,6 +868,24 @@ pub const IO = struct {
|
|
|
868
868
|
completion: *Completion,
|
|
869
869
|
nanoseconds: u63,
|
|
870
870
|
) void {
|
|
871
|
+
// Special case a zero timeout as a yield.
|
|
872
|
+
if (nanoseconds == 0) {
|
|
873
|
+
completion.* = .{
|
|
874
|
+
.next = null,
|
|
875
|
+
.context = @ptrCast(?*anyopaque, context),
|
|
876
|
+
.operation = undefined,
|
|
877
|
+
.callback = struct {
|
|
878
|
+
fn on_complete(ctx: Completion.Context) void {
|
|
879
|
+
const _context = @intToPtr(Context, @ptrToInt(ctx.completion.context));
|
|
880
|
+
callback(_context, ctx.completion, {});
|
|
881
|
+
}
|
|
882
|
+
}.on_complete,
|
|
883
|
+
};
|
|
884
|
+
|
|
885
|
+
self.completed.push(completion);
|
|
886
|
+
return;
|
|
887
|
+
}
|
|
888
|
+
|
|
871
889
|
self.submit(
|
|
872
890
|
context,
|
|
873
891
|
callback,
|
|
@@ -19,11 +19,17 @@ pub fn IOPS(comptime T: type, comptime size: u6) type {
|
|
|
19
19
|
|
|
20
20
|
pub fn release(self: *Self, item: *T) void {
|
|
21
21
|
item.* = undefined;
|
|
22
|
-
const i =
|
|
22
|
+
const i = self.index(item);
|
|
23
23
|
assert(!self.free.isSet(i));
|
|
24
24
|
self.free.set(i);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
pub fn index(self: *Self, item: *T) usize {
|
|
28
|
+
const i = (@ptrToInt(item) - @ptrToInt(&self.items)) / @sizeOf(T);
|
|
29
|
+
assert(i < size);
|
|
30
|
+
return i;
|
|
31
|
+
}
|
|
32
|
+
|
|
27
33
|
/// Returns the count of IOPs available.
|
|
28
34
|
pub fn available(self: *const Self) usize {
|
|
29
35
|
return self.free.count();
|
|
@@ -42,7 +42,7 @@ const constants = @import("../constants.zig");
|
|
|
42
42
|
|
|
43
43
|
const GridType = @import("grid.zig").GridType;
|
|
44
44
|
const ManifestType = @import("manifest.zig").ManifestType;
|
|
45
|
-
const
|
|
45
|
+
const MergeIteratorType = @import("merge_iterator.zig").MergeIteratorType;
|
|
46
46
|
const TableIteratorType = @import("table_iterator.zig").TableIteratorType;
|
|
47
47
|
const LevelIteratorType = @import("level_iterator.zig").LevelIteratorType;
|
|
48
48
|
|
|
@@ -51,8 +51,6 @@ pub fn CompactionType(
|
|
|
51
51
|
comptime Storage: type,
|
|
52
52
|
comptime IteratorAType: anytype,
|
|
53
53
|
) type {
|
|
54
|
-
const Key = Table.Key;
|
|
55
|
-
const Value = Table.Value;
|
|
56
54
|
const tombstone = Table.tombstone;
|
|
57
55
|
|
|
58
56
|
return struct {
|
|
@@ -63,7 +61,7 @@ pub fn CompactionType(
|
|
|
63
61
|
const BlockPtrConst = Grid.BlockPtrConst;
|
|
64
62
|
const BlockWrite = struct {
|
|
65
63
|
write: Grid.Write = undefined,
|
|
66
|
-
block: BlockPtr = undefined,
|
|
64
|
+
block: *BlockPtr = undefined,
|
|
67
65
|
writable: bool = false,
|
|
68
66
|
};
|
|
69
67
|
|
|
@@ -73,47 +71,12 @@ pub fn CompactionType(
|
|
|
73
71
|
const IteratorA = IteratorAType(Table, Storage);
|
|
74
72
|
const IteratorB = LevelIteratorType(Table, Storage);
|
|
75
73
|
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
Table.Value,
|
|
81
|
-
Table.key_from_value,
|
|
82
|
-
Table.compare_keys,
|
|
83
|
-
k,
|
|
84
|
-
MergeStreamSelector.peek,
|
|
85
|
-
MergeStreamSelector.pop,
|
|
86
|
-
MergeStreamSelector.precedence,
|
|
74
|
+
const MergeIterator = MergeIteratorType(
|
|
75
|
+
Table,
|
|
76
|
+
IteratorA,
|
|
77
|
+
IteratorB,
|
|
87
78
|
);
|
|
88
79
|
|
|
89
|
-
const MergeStreamSelector = struct {
|
|
90
|
-
fn peek(compaction: *const Compaction, stream_id: u32) error{ Empty, Drained }!Key {
|
|
91
|
-
return switch (stream_id) {
|
|
92
|
-
0 => compaction.iterator_a.peek(),
|
|
93
|
-
1 => compaction.iterator_b.peek(),
|
|
94
|
-
else => unreachable,
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
fn pop(compaction: *Compaction, stream_id: u32) Value {
|
|
99
|
-
return switch (stream_id) {
|
|
100
|
-
0 => compaction.iterator_a.pop(),
|
|
101
|
-
1 => compaction.iterator_b.pop(),
|
|
102
|
-
else => unreachable,
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/// Returns true if stream A has higher precedence than stream B.
|
|
107
|
-
/// This is used to deduplicate values across streams.
|
|
108
|
-
fn precedence(compaction: *const Compaction, stream_a: u32, stream_b: u32) bool {
|
|
109
|
-
_ = compaction;
|
|
110
|
-
assert(stream_a + stream_b == 1);
|
|
111
|
-
|
|
112
|
-
// All tables in iterator_a (stream=0) have a higher precedence.
|
|
113
|
-
return stream_a == 0;
|
|
114
|
-
}
|
|
115
|
-
};
|
|
116
|
-
|
|
117
80
|
pub const Callback = fn (it: *Compaction) void;
|
|
118
81
|
|
|
119
82
|
const Status = enum {
|
|
@@ -122,7 +85,8 @@ pub fn CompactionType(
|
|
|
122
85
|
done,
|
|
123
86
|
};
|
|
124
87
|
|
|
125
|
-
|
|
88
|
+
/// Used only for debugging/tracing.
|
|
89
|
+
name: [:0]const u8,
|
|
126
90
|
|
|
127
91
|
grid: *Grid,
|
|
128
92
|
grid_reservation: Grid.Reservation,
|
|
@@ -161,7 +125,7 @@ pub fn CompactionType(
|
|
|
161
125
|
|
|
162
126
|
tracer_slot: ?tracer.SpanStart = null,
|
|
163
127
|
|
|
164
|
-
pub fn init(allocator: mem.Allocator,
|
|
128
|
+
pub fn init(allocator: mem.Allocator, name: [:0]const u8) !Compaction {
|
|
165
129
|
var iterator_a = try IteratorA.init(allocator);
|
|
166
130
|
errdefer iterator_a.deinit(allocator);
|
|
167
131
|
|
|
@@ -172,7 +136,7 @@ pub fn CompactionType(
|
|
|
172
136
|
errdefer table_builder.deinit(allocator);
|
|
173
137
|
|
|
174
138
|
return Compaction{
|
|
175
|
-
.
|
|
139
|
+
.name = name,
|
|
176
140
|
|
|
177
141
|
// Assigned by start()
|
|
178
142
|
.grid = undefined,
|
|
@@ -239,7 +203,7 @@ pub fn CompactionType(
|
|
|
239
203
|
assert(drop_tombstones or level_b < constants.lsm_levels - 1);
|
|
240
204
|
|
|
241
205
|
compaction.* = .{
|
|
242
|
-
.
|
|
206
|
+
.name = compaction.name,
|
|
243
207
|
|
|
244
208
|
.grid = grid,
|
|
245
209
|
// Reserve enough blocks to write our output tables in the worst case, where:
|
|
@@ -350,11 +314,8 @@ pub fn CompactionType(
|
|
|
350
314
|
|
|
351
315
|
tracer.start(
|
|
352
316
|
&compaction.tracer_slot,
|
|
353
|
-
.{ .
|
|
354
|
-
.{ .tree_compaction_tick = .{
|
|
355
|
-
.tree_name = compaction.tree_name,
|
|
356
|
-
.level_b = compaction.level_b,
|
|
357
|
-
} },
|
|
317
|
+
.{ .tree_compaction = .{ .compaction_name = compaction.name } },
|
|
318
|
+
.{ .tree_compaction_tick = .{ .level_b = compaction.level_b } },
|
|
358
319
|
@src(),
|
|
359
320
|
);
|
|
360
321
|
|
|
@@ -397,7 +358,7 @@ pub fn CompactionType(
|
|
|
397
358
|
write_callback,
|
|
398
359
|
&block_write.write,
|
|
399
360
|
block_write.block,
|
|
400
|
-
Table.block_address(block_write.block),
|
|
361
|
+
Table.block_address(block_write.block.*),
|
|
401
362
|
);
|
|
402
363
|
}
|
|
403
364
|
}
|
|
@@ -429,18 +390,18 @@ pub fn CompactionType(
|
|
|
429
390
|
var tracer_slot: ?tracer.SpanStart = null;
|
|
430
391
|
tracer.start(
|
|
431
392
|
&tracer_slot,
|
|
432
|
-
.{ .
|
|
433
|
-
.{ .tree_compaction_merge = .{
|
|
434
|
-
.tree_name = compaction.tree_name,
|
|
435
|
-
.level_b = compaction.level_b,
|
|
436
|
-
} },
|
|
393
|
+
.{ .tree_compaction = .{ .compaction_name = compaction.name } },
|
|
394
|
+
.{ .tree_compaction_merge = .{ .level_b = compaction.level_b } },
|
|
437
395
|
@src(),
|
|
438
396
|
);
|
|
439
397
|
|
|
440
398
|
// Create the merge iterator only when we can peek() from the read iterators.
|
|
441
399
|
// This happens after IO for the first reads complete.
|
|
442
400
|
if (compaction.merge_iterator == null) {
|
|
443
|
-
compaction.merge_iterator = MergeIterator.init(
|
|
401
|
+
compaction.merge_iterator = MergeIterator.init(
|
|
402
|
+
&compaction.iterator_a,
|
|
403
|
+
&compaction.iterator_b,
|
|
404
|
+
);
|
|
444
405
|
assert(!compaction.merge_iterator.?.empty());
|
|
445
406
|
}
|
|
446
407
|
|
|
@@ -456,19 +417,13 @@ pub fn CompactionType(
|
|
|
456
417
|
|
|
457
418
|
tracer.end(
|
|
458
419
|
&tracer_slot,
|
|
459
|
-
.{ .
|
|
460
|
-
.{ .tree_compaction_merge = .{
|
|
461
|
-
.tree_name = compaction.tree_name,
|
|
462
|
-
.level_b = compaction.level_b,
|
|
463
|
-
} },
|
|
420
|
+
.{ .tree_compaction = .{ .compaction_name = compaction.name } },
|
|
421
|
+
.{ .tree_compaction_merge = .{ .level_b = compaction.level_b } },
|
|
464
422
|
);
|
|
465
423
|
tracer.end(
|
|
466
424
|
&compaction.tracer_slot,
|
|
467
|
-
.{ .
|
|
468
|
-
.{ .tree_compaction_tick = .{
|
|
469
|
-
.tree_name = compaction.tree_name,
|
|
470
|
-
.level_b = compaction.level_b,
|
|
471
|
-
} },
|
|
425
|
+
.{ .tree_compaction = .{ .compaction_name = compaction.name } },
|
|
426
|
+
.{ .tree_compaction_tick = .{ .level_b = compaction.level_b } },
|
|
472
427
|
);
|
|
473
428
|
|
|
474
429
|
// TODO Implement pacing here by deciding if we should do another compact_tick()
|
|
@@ -514,7 +469,7 @@ pub fn CompactionType(
|
|
|
514
469
|
});
|
|
515
470
|
|
|
516
471
|
// Mark the finished data block as writable for the next compact_tick() call.
|
|
517
|
-
compaction.data.block = compaction.table_builder.data_block;
|
|
472
|
+
compaction.data.block = &compaction.table_builder.data_block;
|
|
518
473
|
assert(!compaction.data.writable);
|
|
519
474
|
compaction.data.writable = true;
|
|
520
475
|
}
|
|
@@ -531,7 +486,7 @@ pub fn CompactionType(
|
|
|
531
486
|
});
|
|
532
487
|
|
|
533
488
|
// Mark the finished filter block as writable for the next compact_tick() call.
|
|
534
|
-
compaction.filter.block = compaction.table_builder.filter_block;
|
|
489
|
+
compaction.filter.block = &compaction.table_builder.filter_block;
|
|
535
490
|
assert(!compaction.filter.writable);
|
|
536
491
|
compaction.filter.writable = true;
|
|
537
492
|
}
|
|
@@ -551,7 +506,7 @@ pub fn CompactionType(
|
|
|
551
506
|
compaction.manifest.insert_table(compaction.level_b, &table);
|
|
552
507
|
|
|
553
508
|
// Mark the finished index block as writable for the next compact_tick() call.
|
|
554
|
-
compaction.index.block = compaction.table_builder.index_block;
|
|
509
|
+
compaction.index.block = &compaction.table_builder.index_block;
|
|
555
510
|
assert(!compaction.index.writable);
|
|
556
511
|
compaction.index.writable = true;
|
|
557
512
|
|
|
@@ -41,18 +41,12 @@ const FuzzOpTag = std.meta.Tag(FuzzOp);
|
|
|
41
41
|
const Environment = struct {
|
|
42
42
|
const cluster = 32;
|
|
43
43
|
const replica = 4;
|
|
44
|
-
// TODO Is this appropriate for the number of fuzz_ops we want to run?
|
|
45
|
-
const size_max = vsr.Zone.superblock.size().? +
|
|
46
|
-
vsr.Zone.wal_headers.size().? +
|
|
47
|
-
vsr.Zone.wal_prepares.size().? +
|
|
48
|
-
1024 * 1024 * 1024;
|
|
49
44
|
|
|
50
45
|
const node_count = 1024;
|
|
51
46
|
// This is the smallest size that set_associative_cache will allow us.
|
|
52
47
|
const cache_entries_max = 2048;
|
|
53
48
|
const forest_options = StateMachine.forest_options(.{
|
|
54
|
-
|
|
55
|
-
.lsm_forest_node_count = undefined,
|
|
49
|
+
.lsm_forest_node_count = node_count,
|
|
56
50
|
.cache_entries_accounts = cache_entries_max,
|
|
57
51
|
.cache_entries_transfers = cache_entries_max,
|
|
58
52
|
.cache_entries_posted = cache_entries_max,
|
|
@@ -98,7 +92,11 @@ const Environment = struct {
|
|
|
98
92
|
env.message_pool = try MessagePool.init(allocator, .replica);
|
|
99
93
|
errdefer env.message_pool.deinit(allocator);
|
|
100
94
|
|
|
101
|
-
env.superblock = try SuperBlock.init(allocator,
|
|
95
|
+
env.superblock = try SuperBlock.init(allocator, .{
|
|
96
|
+
.storage = env.storage,
|
|
97
|
+
.storage_size_limit = constants.storage_size_max,
|
|
98
|
+
.message_pool = &env.message_pool,
|
|
99
|
+
});
|
|
102
100
|
errdefer env.superblock.deinit(allocator);
|
|
103
101
|
|
|
104
102
|
env.grid = try Grid.init(allocator, &env.superblock);
|
|
@@ -126,7 +124,7 @@ const Environment = struct {
|
|
|
126
124
|
}
|
|
127
125
|
|
|
128
126
|
fn tick(env: *Environment) void {
|
|
129
|
-
env.grid.tick();
|
|
127
|
+
// env.grid.tick();
|
|
130
128
|
env.storage.tick();
|
|
131
129
|
}
|
|
132
130
|
|
|
@@ -152,7 +150,6 @@ const Environment = struct {
|
|
|
152
150
|
env.superblock.format(superblock_format_callback, &env.superblock_context, .{
|
|
153
151
|
.cluster = cluster,
|
|
154
152
|
.replica = replica,
|
|
155
|
-
.size_max = size_max,
|
|
156
153
|
});
|
|
157
154
|
env.tick_until_state_change(.init, .formatted);
|
|
158
155
|
}
|
|
@@ -265,6 +262,8 @@ const Environment = struct {
|
|
|
265
262
|
if (compact.checkpoint) env.checkpoint(compact.op);
|
|
266
263
|
},
|
|
267
264
|
.put_account => |account| {
|
|
265
|
+
// The forest requires prefetch before put.
|
|
266
|
+
env.prefetch_account(account.id);
|
|
268
267
|
env.forest.grooves.accounts.put(&account);
|
|
269
268
|
try model.put(account.id, account);
|
|
270
269
|
},
|
|
@@ -292,7 +291,7 @@ const Environment = struct {
|
|
|
292
291
|
|
|
293
292
|
pub fn run_fuzz_ops(storage_options: Storage.Options, fuzz_ops: []const FuzzOp) !void {
|
|
294
293
|
// Init mocked storage.
|
|
295
|
-
var storage = try Storage.init(allocator,
|
|
294
|
+
var storage = try Storage.init(allocator, constants.storage_size_max, storage_options);
|
|
296
295
|
defer storage.deinit(allocator);
|
|
297
296
|
|
|
298
297
|
try Environment.format(&storage);
|