tigerbeetle-node 0.11.7 → 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.
- package/dist/.client.node.sha256 +1 -1
- package/package.json +4 -3
- package/scripts/build_lib.sh +29 -0
- package/src/node.zig +1 -1
- package/src/tigerbeetle/scripts/validate_docs.sh +7 -1
- package/src/tigerbeetle/src/benchmark.zig +3 -3
- package/src/tigerbeetle/src/config.zig +29 -16
- package/src/tigerbeetle/src/constants.zig +30 -9
- package/src/tigerbeetle/src/ewah.zig +5 -5
- package/src/tigerbeetle/src/ewah_fuzz.zig +1 -1
- package/src/tigerbeetle/src/lsm/binary_search.zig +1 -1
- package/src/tigerbeetle/src/lsm/bloom_filter.zig +1 -1
- package/src/tigerbeetle/src/lsm/compaction.zig +34 -21
- package/src/tigerbeetle/src/lsm/forest_fuzz.zig +85 -103
- package/src/tigerbeetle/src/lsm/grid.zig +19 -13
- package/src/tigerbeetle/src/lsm/manifest_log.zig +8 -10
- package/src/tigerbeetle/src/lsm/manifest_log_fuzz.zig +12 -8
- package/src/tigerbeetle/src/lsm/merge_iterator.zig +1 -1
- package/src/tigerbeetle/src/lsm/segmented_array.zig +17 -17
- package/src/tigerbeetle/src/lsm/segmented_array_fuzz.zig +1 -1
- package/src/tigerbeetle/src/lsm/set_associative_cache.zig +1 -1
- package/src/tigerbeetle/src/lsm/table.zig +8 -20
- package/src/tigerbeetle/src/lsm/table_immutable.zig +1 -1
- package/src/tigerbeetle/src/lsm/table_iterator.zig +3 -3
- package/src/tigerbeetle/src/lsm/table_mutable.zig +14 -2
- package/src/tigerbeetle/src/lsm/tree.zig +31 -5
- package/src/tigerbeetle/src/lsm/tree_fuzz.zig +86 -114
- package/src/tigerbeetle/src/message_bus.zig +4 -4
- package/src/tigerbeetle/src/message_pool.zig +7 -10
- package/src/tigerbeetle/src/ring_buffer.zig +22 -12
- package/src/tigerbeetle/src/simulator.zig +360 -214
- package/src/tigerbeetle/src/state_machine/auditor.zig +5 -5
- package/src/tigerbeetle/src/state_machine/workload.zig +3 -3
- package/src/tigerbeetle/src/state_machine.zig +190 -178
- package/src/tigerbeetle/src/{util.zig → stdx.zig} +2 -0
- package/src/tigerbeetle/src/storage.zig +13 -6
- package/src/tigerbeetle/src/{test → testing/cluster}/message_bus.zig +3 -3
- package/src/tigerbeetle/src/{test → testing/cluster}/network.zig +46 -22
- package/src/tigerbeetle/src/testing/cluster/state_checker.zig +169 -0
- package/src/tigerbeetle/src/testing/cluster/storage_checker.zig +202 -0
- package/src/tigerbeetle/src/testing/cluster.zig +537 -0
- package/src/tigerbeetle/src/{test → testing}/fuzz.zig +0 -0
- package/src/tigerbeetle/src/testing/hash_log.zig +66 -0
- package/src/tigerbeetle/src/{test → testing}/id.zig +0 -0
- package/src/tigerbeetle/src/testing/packet_simulator.zig +365 -0
- package/src/tigerbeetle/src/{test → testing}/priority_queue.zig +1 -1
- package/src/tigerbeetle/src/testing/reply_sequence.zig +139 -0
- package/src/tigerbeetle/src/{test → testing}/state_machine.zig +3 -1
- package/src/tigerbeetle/src/testing/storage.zig +754 -0
- package/src/tigerbeetle/src/{test → testing}/table.zig +21 -0
- package/src/tigerbeetle/src/{test → testing}/time.zig +0 -0
- package/src/tigerbeetle/src/tigerbeetle.zig +2 -0
- package/src/tigerbeetle/src/tracer.zig +3 -3
- package/src/tigerbeetle/src/unit_tests.zig +4 -4
- package/src/tigerbeetle/src/vopr.zig +2 -2
- package/src/tigerbeetle/src/vsr/client.zig +16 -9
- package/src/tigerbeetle/src/vsr/clock.zig +93 -53
- package/src/tigerbeetle/src/vsr/journal.zig +29 -14
- package/src/tigerbeetle/src/vsr/journal_format_fuzz.zig +2 -2
- package/src/tigerbeetle/src/vsr/replica.zig +1383 -774
- package/src/tigerbeetle/src/vsr/replica_format.zig +2 -2
- package/src/tigerbeetle/src/vsr/superblock.zig +59 -43
- package/src/tigerbeetle/src/vsr/superblock_client_table.zig +7 -7
- package/src/tigerbeetle/src/vsr/superblock_free_set.zig +1 -1
- package/src/tigerbeetle/src/vsr/superblock_free_set_fuzz.zig +1 -1
- package/src/tigerbeetle/src/vsr/superblock_fuzz.zig +15 -7
- package/src/tigerbeetle/src/vsr/superblock_manifest.zig +38 -19
- package/src/tigerbeetle/src/vsr/superblock_quorums_fuzz.zig +1 -1
- package/src/tigerbeetle/src/vsr.zig +6 -4
- package/src/tigerbeetle/src/demo.zig +0 -132
- package/src/tigerbeetle/src/demo_01_create_accounts.zig +0 -35
- package/src/tigerbeetle/src/demo_02_lookup_accounts.zig +0 -7
- package/src/tigerbeetle/src/demo_03_create_transfers.zig +0 -37
- package/src/tigerbeetle/src/demo_04_create_pending_transfers.zig +0 -61
- package/src/tigerbeetle/src/demo_05_post_pending_transfers.zig +0 -37
- package/src/tigerbeetle/src/demo_06_void_pending_transfers.zig +0 -24
- package/src/tigerbeetle/src/demo_07_lookup_transfers.zig +0 -7
- package/src/tigerbeetle/src/test/cluster.zig +0 -352
- package/src/tigerbeetle/src/test/conductor.zig +0 -366
- package/src/tigerbeetle/src/test/packet_simulator.zig +0 -398
- package/src/tigerbeetle/src/test/state_checker.zig +0 -169
- package/src/tigerbeetle/src/test/storage.zig +0 -864
- package/src/tigerbeetle/src/test/storage_checker.zig +0 -204
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
//! Verify deterministic storage.
|
|
2
|
-
//!
|
|
3
|
-
//! At each replica compact and checkpoint, check that storage is byte-for-byte identical across
|
|
4
|
-
//! replicas.
|
|
5
|
-
//!
|
|
6
|
-
//! Areas verified at compaction (half-measure):
|
|
7
|
-
//! - Acquired Grid blocks (ignores skipped recovery compactions)
|
|
8
|
-
//! TODO Because ManifestLog acquires blocks potentially several beats prior to actually writing
|
|
9
|
-
//! the block, this check will need to be removed or use a different strategy.
|
|
10
|
-
//!
|
|
11
|
-
//! Areas verified at checkpoint:
|
|
12
|
-
//! - WAL prepares
|
|
13
|
-
//! - SuperBlock Manifest, FreeSet, ClientTable
|
|
14
|
-
//! - Acquired Grid blocks
|
|
15
|
-
//!
|
|
16
|
-
//! Areas not verified:
|
|
17
|
-
//! - SuperBlock sectors, which hold replica-specific state.
|
|
18
|
-
//! - WAL headers, which may differ because the WAL writes deliberately corrupt redundant headers
|
|
19
|
-
//! to faulty slots to ensure recovery is consistent.
|
|
20
|
-
//! - Non-allocated Grid blocks, which may differ due to state transfer.
|
|
21
|
-
const std = @import("std");
|
|
22
|
-
const assert = std.debug.assert;
|
|
23
|
-
const log = std.log.scoped(.storage_checker);
|
|
24
|
-
|
|
25
|
-
const constants = @import("../constants.zig");
|
|
26
|
-
const vsr = @import("../vsr.zig");
|
|
27
|
-
const SuperBlockLayout = @import("../vsr/superblock.zig").Layout;
|
|
28
|
-
const SuperBlockSector = @import("../vsr/superblock.zig").SuperBlockSector;
|
|
29
|
-
const Replica = @import("cluster.zig").Replica;
|
|
30
|
-
const Storage = @import("storage.zig").Storage;
|
|
31
|
-
|
|
32
|
-
/// After each compaction half measure, save the cumulative hash of all acquired grid blocks.
|
|
33
|
-
///
|
|
34
|
-
/// (Track half-measures instead of beats because the on-disk state mid-compaction is
|
|
35
|
-
/// nondeterministic; it depends on IO progress.)
|
|
36
|
-
const Compactions = std.ArrayList(u128);
|
|
37
|
-
|
|
38
|
-
/// Maps from op_checkpoint to cumulative storage checksum.
|
|
39
|
-
///
|
|
40
|
-
/// Not every checkpoint is necessarily recorded — a replica calls on_checkpoint *at most* once.
|
|
41
|
-
/// For example, a replica will not call on_checkpoint if it crashes (during a checkpoint) after
|
|
42
|
-
/// writing 2 superblock copies. (This could be repeated by other replicas, causing a checkpoint
|
|
43
|
-
/// op to be skipped in Checkpoints).
|
|
44
|
-
const Checkpoints = std.AutoHashMap(u64, Checkpoint);
|
|
45
|
-
|
|
46
|
-
const Checkpoint = struct {
|
|
47
|
-
// The superblock trailers are an XOR of all copies of all respective trailers, not the
|
|
48
|
-
// `SuperBlockSector.{trailer}_checksum`.
|
|
49
|
-
checksum_superblock_manifest: u128,
|
|
50
|
-
checksum_superblock_free_set: u128,
|
|
51
|
-
checksum_superblock_client_table: u128,
|
|
52
|
-
checksum_wal_prepares: u128,
|
|
53
|
-
checksum_grid: u128,
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
pub const StorageChecker = struct {
|
|
57
|
-
allocator: std.mem.Allocator,
|
|
58
|
-
compactions: Compactions,
|
|
59
|
-
checkpoints: Checkpoints,
|
|
60
|
-
|
|
61
|
-
pub fn init(allocator: std.mem.Allocator) StorageChecker {
|
|
62
|
-
var compactions = Compactions.init(allocator);
|
|
63
|
-
errdefer compactions.deinit();
|
|
64
|
-
|
|
65
|
-
var checkpoints = Checkpoints.init(allocator);
|
|
66
|
-
errdefer checkpoints.deinit();
|
|
67
|
-
|
|
68
|
-
return StorageChecker{
|
|
69
|
-
.allocator = allocator,
|
|
70
|
-
.compactions = compactions,
|
|
71
|
-
.checkpoints = checkpoints,
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
pub fn deinit(checker: *StorageChecker) void {
|
|
76
|
-
checker.compactions.deinit();
|
|
77
|
-
checker.checkpoints.deinit();
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
pub fn replica_compact(checker: *StorageChecker, replica: *const Replica) !void {
|
|
81
|
-
// TODO(Beat Compaction) Remove when deterministic beat compaction is fixed.
|
|
82
|
-
// Until then this is too noisy.
|
|
83
|
-
if (1 == 1) return;
|
|
84
|
-
|
|
85
|
-
// If we are recovering from a crash, don't test the checksum until we are caught up.
|
|
86
|
-
// Until then our grid's checksum is too far ahead.
|
|
87
|
-
if (replica.superblock.working.vsr_state.op_compacted(replica.commit_min)) return;
|
|
88
|
-
|
|
89
|
-
// TODO(Beat Compaction) Remove when deterministic beat compaction is implemented.
|
|
90
|
-
const half_measure_beat_count = @divExact(constants.lsm_batch_multiple, 2);
|
|
91
|
-
if ((replica.commit_min + 1) % half_measure_beat_count != 0) return;
|
|
92
|
-
|
|
93
|
-
const checksum = checksum_grid(replica);
|
|
94
|
-
log.debug("{}: replica_compact: op={} area=grid checksum={}", .{
|
|
95
|
-
replica.replica,
|
|
96
|
-
replica.commit_min,
|
|
97
|
-
checksum,
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
// -1 since we never compact op=1.
|
|
101
|
-
const compactions_index = @divExact(replica.commit_min + 1, half_measure_beat_count) - 1;
|
|
102
|
-
if (compactions_index == checker.compactions.items.len) {
|
|
103
|
-
try checker.compactions.append(checksum);
|
|
104
|
-
} else {
|
|
105
|
-
const checksum_expect = checker.compactions.items[compactions_index];
|
|
106
|
-
if (checksum_expect != checksum) {
|
|
107
|
-
log.err("{}: replica_compact: mismatch area=grid expect={} actual={}", .{
|
|
108
|
-
replica.replica,
|
|
109
|
-
checksum_expect,
|
|
110
|
-
checksum,
|
|
111
|
-
});
|
|
112
|
-
return error.StorageMismatch;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
pub fn replica_checkpoint(checker: *StorageChecker, replica: *const Replica) !void {
|
|
118
|
-
const storage = replica.superblock.storage;
|
|
119
|
-
const working = replica.superblock.working;
|
|
120
|
-
|
|
121
|
-
// TODO(Beat Compaction) Remove when deterministic storage is fixed.
|
|
122
|
-
// Until then this is too noisy.
|
|
123
|
-
if (1 == 1) return;
|
|
124
|
-
|
|
125
|
-
var checkpoint = Checkpoint{
|
|
126
|
-
.checksum_superblock_manifest = 0,
|
|
127
|
-
.checksum_superblock_free_set = 0,
|
|
128
|
-
.checksum_superblock_client_table = 0,
|
|
129
|
-
.checksum_wal_prepares = checksum_wal_prepares(storage),
|
|
130
|
-
.checksum_grid = checksum_grid(replica),
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
inline for (.{
|
|
134
|
-
.{ .field = .manifest, .offset = SuperBlockLayout.offset_manifest },
|
|
135
|
-
.{ .field = .free_set, .offset = SuperBlockLayout.offset_free_set },
|
|
136
|
-
.{ .field = .client_table, .offset = SuperBlockLayout.offset_client_table },
|
|
137
|
-
}) |trailer| {
|
|
138
|
-
const trailer_size = @field(working, @tagName(trailer.field) ++ "_size");
|
|
139
|
-
|
|
140
|
-
var copy: u8 = 0;
|
|
141
|
-
while (copy < constants.superblock_copies) : (copy += 1) {
|
|
142
|
-
const offset_in_storage = vsr.Zone.superblock.offset(trailer.offset(copy));
|
|
143
|
-
@field(checkpoint, "checksum_superblock_" ++ @tagName(trailer.field)) |=
|
|
144
|
-
vsr.checksum(storage.memory[offset_in_storage..][0..trailer_size]);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
inline for (std.meta.fields(Checkpoint)) |field| {
|
|
149
|
-
log.debug("{}: replica_checkpoint: checkpoint={} area={s} value={}", .{
|
|
150
|
-
replica.replica,
|
|
151
|
-
replica.op_checkpoint,
|
|
152
|
-
field.name,
|
|
153
|
-
@field(checkpoint, field.name),
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const checkpoint_expect = checker.checkpoints.get(replica.op_checkpoint) orelse {
|
|
158
|
-
// This replica is the first to reach op_checkpoint.
|
|
159
|
-
try checker.checkpoints.putNoClobber(replica.op_checkpoint, checkpoint);
|
|
160
|
-
return;
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
var fail: bool = false;
|
|
164
|
-
inline for (std.meta.fields(Checkpoint)) |field| {
|
|
165
|
-
const field_actual = @field(checkpoint, field.name);
|
|
166
|
-
const field_expect = @field(checkpoint_expect, field.name);
|
|
167
|
-
if (!std.meta.eql(field_expect, field_actual)) {
|
|
168
|
-
fail = true;
|
|
169
|
-
log.debug("{}: replica_checkpoint: mismatch area={s} expect={} actual={}", .{
|
|
170
|
-
replica.replica,
|
|
171
|
-
field.name,
|
|
172
|
-
@field(checkpoint_expect, field.name),
|
|
173
|
-
@field(checkpoint, field.name),
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
if (fail) return error.StorageMismatch;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
fn checksum_wal_prepares(storage: *const Storage) u128 {
|
|
181
|
-
var checksum: u128 = 0;
|
|
182
|
-
for (storage.wal_prepares()) |*prepare| {
|
|
183
|
-
assert(prepare.header.valid_checksum());
|
|
184
|
-
assert(prepare.header.command == .prepare);
|
|
185
|
-
|
|
186
|
-
// Only checksum the actual message header+body. Any leftover space is nondeterministic,
|
|
187
|
-
// because the current prepare may have overwritten a longer message.
|
|
188
|
-
checksum ^= vsr.checksum(std.mem.asBytes(prepare)[0..prepare.header.size]);
|
|
189
|
-
}
|
|
190
|
-
return checksum;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
fn checksum_grid(replica: *const Replica) u128 {
|
|
194
|
-
const storage = replica.superblock.storage;
|
|
195
|
-
var acquired = replica.superblock.free_set.blocks.iterator(.{ .kind = .unset });
|
|
196
|
-
var checksum: u128 = 0;
|
|
197
|
-
while (acquired.next()) |address_index| {
|
|
198
|
-
const block = storage.grid_block(address_index + 1);
|
|
199
|
-
const block_header = std.mem.bytesToValue(vsr.Header, block[0..@sizeOf(vsr.Header)]);
|
|
200
|
-
checksum ^= vsr.checksum(block[0..block_header.size]);
|
|
201
|
-
}
|
|
202
|
-
return checksum;
|
|
203
|
-
}
|
|
204
|
-
};
|