tigerbeetle-node 0.11.13 → 0.12.0
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/bin/aarch64-linux-gnu/client.node +0 -0
- package/dist/bin/aarch64-linux-musl/client.node +0 -0
- package/dist/bin/aarch64-macos/client.node +0 -0
- package/dist/bin/x86_64-linux-gnu/client.node +0 -0
- package/dist/bin/x86_64-linux-musl/client.node +0 -0
- package/dist/bin/x86_64-macos/client.node +0 -0
- package/dist/index.js +33 -1
- package/dist/index.js.map +1 -1
- package/package-lock.json +66 -0
- package/package.json +6 -16
- package/src/index.ts +56 -1
- package/src/node.zig +9 -9
- package/dist/.client.node.sha256 +0 -1
- package/scripts/build_lib.sh +0 -61
- package/scripts/download_node_headers.sh +0 -32
- package/src/tigerbeetle/scripts/benchmark.bat +0 -55
- package/src/tigerbeetle/scripts/benchmark.sh +0 -66
- package/src/tigerbeetle/scripts/confirm_image.sh +0 -44
- package/src/tigerbeetle/scripts/fail_on_diff.sh +0 -9
- package/src/tigerbeetle/scripts/fuzz_loop.sh +0 -15
- package/src/tigerbeetle/scripts/fuzz_loop_hash_log.sh +0 -12
- package/src/tigerbeetle/scripts/fuzz_unique_errors.sh +0 -7
- package/src/tigerbeetle/scripts/install.bat +0 -7
- package/src/tigerbeetle/scripts/install.sh +0 -21
- package/src/tigerbeetle/scripts/install_zig.bat +0 -113
- package/src/tigerbeetle/scripts/install_zig.sh +0 -90
- package/src/tigerbeetle/scripts/lint.zig +0 -199
- package/src/tigerbeetle/scripts/pre-commit.sh +0 -9
- package/src/tigerbeetle/scripts/scripts/benchmark.bat +0 -55
- package/src/tigerbeetle/scripts/scripts/benchmark.sh +0 -66
- package/src/tigerbeetle/scripts/scripts/confirm_image.sh +0 -44
- package/src/tigerbeetle/scripts/scripts/fail_on_diff.sh +0 -9
- package/src/tigerbeetle/scripts/scripts/fuzz_loop.sh +0 -15
- package/src/tigerbeetle/scripts/scripts/fuzz_loop_hash_log.sh +0 -12
- package/src/tigerbeetle/scripts/scripts/fuzz_unique_errors.sh +0 -7
- package/src/tigerbeetle/scripts/scripts/install.bat +0 -7
- package/src/tigerbeetle/scripts/scripts/install.sh +0 -21
- package/src/tigerbeetle/scripts/scripts/install_zig.bat +0 -113
- package/src/tigerbeetle/scripts/scripts/install_zig.sh +0 -90
- package/src/tigerbeetle/scripts/scripts/lint.zig +0 -199
- package/src/tigerbeetle/scripts/scripts/pre-commit.sh +0 -9
- package/src/tigerbeetle/scripts/scripts/shellcheck.sh +0 -5
- package/src/tigerbeetle/scripts/scripts/tests_on_alpine.sh +0 -10
- package/src/tigerbeetle/scripts/scripts/tests_on_ubuntu.sh +0 -14
- package/src/tigerbeetle/scripts/scripts/upgrade_ubuntu_kernel.sh +0 -48
- package/src/tigerbeetle/scripts/scripts/validate_docs.sh +0 -23
- package/src/tigerbeetle/scripts/scripts/vr_state_enumerate +0 -46
- package/src/tigerbeetle/scripts/shellcheck.sh +0 -5
- package/src/tigerbeetle/scripts/tests_on_alpine.sh +0 -10
- package/src/tigerbeetle/scripts/tests_on_ubuntu.sh +0 -14
- package/src/tigerbeetle/scripts/upgrade_ubuntu_kernel.sh +0 -48
- package/src/tigerbeetle/scripts/validate_docs.sh +0 -23
- package/src/tigerbeetle/scripts/vr_state_enumerate +0 -46
- package/src/tigerbeetle/src/benchmark.zig +0 -336
- package/src/tigerbeetle/src/config.zig +0 -233
- package/src/tigerbeetle/src/constants.zig +0 -428
- package/src/tigerbeetle/src/ewah.zig +0 -286
- package/src/tigerbeetle/src/ewah_benchmark.zig +0 -120
- package/src/tigerbeetle/src/ewah_fuzz.zig +0 -130
- package/src/tigerbeetle/src/fifo.zig +0 -120
- package/src/tigerbeetle/src/io/benchmark.zig +0 -213
- package/src/tigerbeetle/src/io/darwin.zig +0 -814
- package/src/tigerbeetle/src/io/linux.zig +0 -1071
- package/src/tigerbeetle/src/io/test.zig +0 -643
- package/src/tigerbeetle/src/io/windows.zig +0 -1183
- package/src/tigerbeetle/src/io.zig +0 -34
- package/src/tigerbeetle/src/iops.zig +0 -107
- package/src/tigerbeetle/src/lsm/README.md +0 -308
- package/src/tigerbeetle/src/lsm/binary_search.zig +0 -341
- package/src/tigerbeetle/src/lsm/bloom_filter.zig +0 -125
- package/src/tigerbeetle/src/lsm/compaction.zig +0 -603
- package/src/tigerbeetle/src/lsm/composite_key.zig +0 -77
- package/src/tigerbeetle/src/lsm/direction.zig +0 -11
- package/src/tigerbeetle/src/lsm/eytzinger.zig +0 -587
- package/src/tigerbeetle/src/lsm/eytzinger_benchmark.zig +0 -330
- package/src/tigerbeetle/src/lsm/forest.zig +0 -205
- package/src/tigerbeetle/src/lsm/forest_fuzz.zig +0 -450
- package/src/tigerbeetle/src/lsm/grid.zig +0 -573
- package/src/tigerbeetle/src/lsm/groove.zig +0 -1036
- package/src/tigerbeetle/src/lsm/k_way_merge.zig +0 -474
- package/src/tigerbeetle/src/lsm/level_iterator.zig +0 -332
- package/src/tigerbeetle/src/lsm/manifest.zig +0 -617
- package/src/tigerbeetle/src/lsm/manifest_level.zig +0 -878
- package/src/tigerbeetle/src/lsm/manifest_log.zig +0 -789
- package/src/tigerbeetle/src/lsm/manifest_log_fuzz.zig +0 -691
- package/src/tigerbeetle/src/lsm/merge_iterator.zig +0 -106
- package/src/tigerbeetle/src/lsm/node_pool.zig +0 -235
- package/src/tigerbeetle/src/lsm/posted_groove.zig +0 -381
- package/src/tigerbeetle/src/lsm/segmented_array.zig +0 -1329
- package/src/tigerbeetle/src/lsm/segmented_array_benchmark.zig +0 -148
- package/src/tigerbeetle/src/lsm/segmented_array_fuzz.zig +0 -9
- package/src/tigerbeetle/src/lsm/set_associative_cache.zig +0 -850
- package/src/tigerbeetle/src/lsm/table.zig +0 -1009
- package/src/tigerbeetle/src/lsm/table_immutable.zig +0 -192
- package/src/tigerbeetle/src/lsm/table_iterator.zig +0 -340
- package/src/tigerbeetle/src/lsm/table_mutable.zig +0 -203
- package/src/tigerbeetle/src/lsm/test.zig +0 -439
- package/src/tigerbeetle/src/lsm/tree.zig +0 -1169
- package/src/tigerbeetle/src/lsm/tree_fuzz.zig +0 -479
- package/src/tigerbeetle/src/message_bus.zig +0 -1013
- package/src/tigerbeetle/src/message_pool.zig +0 -156
- package/src/tigerbeetle/src/ring_buffer.zig +0 -399
- package/src/tigerbeetle/src/simulator.zig +0 -580
- package/src/tigerbeetle/src/state_machine/auditor.zig +0 -578
- package/src/tigerbeetle/src/state_machine/workload.zig +0 -883
- package/src/tigerbeetle/src/state_machine.zig +0 -2099
- package/src/tigerbeetle/src/static_allocator.zig +0 -65
- package/src/tigerbeetle/src/stdx.zig +0 -171
- package/src/tigerbeetle/src/storage.zig +0 -393
- package/src/tigerbeetle/src/testing/cluster/message_bus.zig +0 -82
- package/src/tigerbeetle/src/testing/cluster/network.zig +0 -237
- package/src/tigerbeetle/src/testing/cluster/state_checker.zig +0 -169
- package/src/tigerbeetle/src/testing/cluster/storage_checker.zig +0 -202
- package/src/tigerbeetle/src/testing/cluster.zig +0 -444
- package/src/tigerbeetle/src/testing/fuzz.zig +0 -140
- package/src/tigerbeetle/src/testing/hash_log.zig +0 -66
- package/src/tigerbeetle/src/testing/id.zig +0 -99
- package/src/tigerbeetle/src/testing/packet_simulator.zig +0 -374
- package/src/tigerbeetle/src/testing/priority_queue.zig +0 -645
- package/src/tigerbeetle/src/testing/reply_sequence.zig +0 -139
- package/src/tigerbeetle/src/testing/state_machine.zig +0 -250
- package/src/tigerbeetle/src/testing/storage.zig +0 -757
- package/src/tigerbeetle/src/testing/table.zig +0 -247
- package/src/tigerbeetle/src/testing/time.zig +0 -84
- package/src/tigerbeetle/src/tigerbeetle.zig +0 -227
- package/src/tigerbeetle/src/time.zig +0 -112
- package/src/tigerbeetle/src/tracer.zig +0 -529
- package/src/tigerbeetle/src/unit_tests.zig +0 -40
- package/src/tigerbeetle/src/vopr.zig +0 -495
- package/src/tigerbeetle/src/vsr/README.md +0 -209
- package/src/tigerbeetle/src/vsr/client.zig +0 -544
- package/src/tigerbeetle/src/vsr/clock.zig +0 -855
- package/src/tigerbeetle/src/vsr/journal.zig +0 -2415
- package/src/tigerbeetle/src/vsr/journal_format_fuzz.zig +0 -111
- package/src/tigerbeetle/src/vsr/marzullo.zig +0 -309
- package/src/tigerbeetle/src/vsr/replica.zig +0 -6616
- package/src/tigerbeetle/src/vsr/replica_format.zig +0 -219
- package/src/tigerbeetle/src/vsr/superblock.zig +0 -1631
- package/src/tigerbeetle/src/vsr/superblock_client_table.zig +0 -256
- package/src/tigerbeetle/src/vsr/superblock_free_set.zig +0 -929
- package/src/tigerbeetle/src/vsr/superblock_free_set_fuzz.zig +0 -334
- package/src/tigerbeetle/src/vsr/superblock_fuzz.zig +0 -390
- package/src/tigerbeetle/src/vsr/superblock_manifest.zig +0 -615
- package/src/tigerbeetle/src/vsr/superblock_quorums.zig +0 -394
- package/src/tigerbeetle/src/vsr/superblock_quorums_fuzz.zig +0 -314
- package/src/tigerbeetle/src/vsr.zig +0 -1425
|
@@ -1,691 +0,0 @@
|
|
|
1
|
-
//! Fuzz ManifestLog open()/insert()/remove()/compact()/checkpoint().
|
|
2
|
-
//!
|
|
3
|
-
//! Invariants checked:
|
|
4
|
-
//!
|
|
5
|
-
//! - Checkpoint flushes all buffered log blocks (including partial blocks).
|
|
6
|
-
//! - The state of the ManifestLog/SuperBlock.Manifest immediately after recovery matches
|
|
7
|
-
//! the state of the ManifestLog/SuperBlock.Manifest immediately after the latest checkpoint.
|
|
8
|
-
//! - SuperBlock.Manifest.open() only returns the latest version of each table.
|
|
9
|
-
//! - SuperBlock.Manifest's compaction queue contains any blocks which:
|
|
10
|
-
//! - contain fewer than entry_count_max entries, or
|
|
11
|
-
//! - contain a "remove" entry, or
|
|
12
|
-
//! - contain an overridden entry.
|
|
13
|
-
//!
|
|
14
|
-
const std = @import("std");
|
|
15
|
-
const assert = std.debug.assert;
|
|
16
|
-
const log = std.log.scoped(.fuzz_lsm_manifest_log);
|
|
17
|
-
|
|
18
|
-
const vsr = @import("../vsr.zig");
|
|
19
|
-
const constants = @import("../constants.zig");
|
|
20
|
-
const RingBuffer = @import("../ring_buffer.zig").RingBuffer;
|
|
21
|
-
const MessagePool = @import("../message_pool.zig").MessagePool;
|
|
22
|
-
const SuperBlock = @import("../vsr/superblock.zig").SuperBlockType(Storage);
|
|
23
|
-
const data_file_size_min = @import("../vsr/superblock.zig").data_file_size_min;
|
|
24
|
-
const TableExtent = @import("../vsr/superblock_manifest.zig").Manifest.TableExtent;
|
|
25
|
-
const Storage = @import("../testing/storage.zig").Storage;
|
|
26
|
-
const Grid = @import("grid.zig").GridType(Storage);
|
|
27
|
-
const BlockType = @import("grid.zig").BlockType;
|
|
28
|
-
const ManifestLog = @import("manifest_log.zig").ManifestLogType(Storage, TableInfo);
|
|
29
|
-
const fuzz = @import("../testing/fuzz.zig");
|
|
30
|
-
|
|
31
|
-
pub const tigerbeetle_config = @import("../config.zig").configs.test_min;
|
|
32
|
-
|
|
33
|
-
const entries_max_block = ManifestLog.Block.entry_count_max;
|
|
34
|
-
const entries_max_buffered = entries_max_block *
|
|
35
|
-
std.meta.fieldInfo(ManifestLog, .blocks).field_type.count_max;
|
|
36
|
-
|
|
37
|
-
pub fn main() !void {
|
|
38
|
-
const allocator = std.testing.allocator;
|
|
39
|
-
const args = try fuzz.parse_fuzz_args(allocator);
|
|
40
|
-
|
|
41
|
-
var prng = std.rand.DefaultPrng.init(args.seed);
|
|
42
|
-
|
|
43
|
-
const events_count = std.math.min(
|
|
44
|
-
args.events_max orelse @as(usize, 2e5),
|
|
45
|
-
fuzz.random_int_exponential(prng.random(), usize, 1e4),
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
const events = try generate_events(allocator, prng.random(), events_count);
|
|
49
|
-
defer allocator.free(events);
|
|
50
|
-
|
|
51
|
-
try run_fuzz(allocator, prng.random(), events);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
fn run_fuzz(
|
|
55
|
-
allocator: std.mem.Allocator,
|
|
56
|
-
random: std.rand.Random,
|
|
57
|
-
events: []const ManifestEvent,
|
|
58
|
-
) !void {
|
|
59
|
-
const storage_options = .{
|
|
60
|
-
.seed = random.int(u64),
|
|
61
|
-
.read_latency_min = 1,
|
|
62
|
-
.read_latency_mean = 1 + random.uintLessThan(u64, 40),
|
|
63
|
-
.write_latency_min = 1,
|
|
64
|
-
.write_latency_mean = 1 + random.uintLessThan(u64, 40),
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
var storage = try Storage.init(allocator, constants.storage_size_max, storage_options);
|
|
68
|
-
defer storage.deinit(allocator);
|
|
69
|
-
|
|
70
|
-
var storage_verify = try Storage.init(allocator, constants.storage_size_max, storage_options);
|
|
71
|
-
defer storage_verify.deinit(allocator);
|
|
72
|
-
|
|
73
|
-
// The MessagePool is shared by both superblocks because they will not use it.
|
|
74
|
-
var message_pool = try MessagePool.init(allocator, .replica);
|
|
75
|
-
defer message_pool.deinit(allocator);
|
|
76
|
-
|
|
77
|
-
var superblock = try SuperBlock.init(allocator, .{
|
|
78
|
-
.storage = &storage,
|
|
79
|
-
.storage_size_limit = constants.storage_size_max,
|
|
80
|
-
.message_pool = &message_pool,
|
|
81
|
-
});
|
|
82
|
-
defer superblock.deinit(allocator);
|
|
83
|
-
|
|
84
|
-
var superblock_verify = try SuperBlock.init(allocator, .{
|
|
85
|
-
.storage = &storage_verify,
|
|
86
|
-
.storage_size_limit = constants.storage_size_max,
|
|
87
|
-
.message_pool = &message_pool,
|
|
88
|
-
});
|
|
89
|
-
defer superblock_verify.deinit(allocator);
|
|
90
|
-
|
|
91
|
-
var grid = try Grid.init(allocator, &superblock);
|
|
92
|
-
defer grid.deinit(allocator);
|
|
93
|
-
|
|
94
|
-
var grid_verify = try Grid.init(allocator, &superblock_verify);
|
|
95
|
-
defer grid_verify.deinit(allocator);
|
|
96
|
-
|
|
97
|
-
var env = try Environment.init(allocator, .{
|
|
98
|
-
.grid = &grid,
|
|
99
|
-
.grid_verify = &grid_verify,
|
|
100
|
-
});
|
|
101
|
-
defer env.deinit(allocator);
|
|
102
|
-
|
|
103
|
-
{
|
|
104
|
-
env.format_superblock();
|
|
105
|
-
env.wait(&env.manifest_log);
|
|
106
|
-
|
|
107
|
-
env.open_superblock();
|
|
108
|
-
env.wait(&env.manifest_log);
|
|
109
|
-
|
|
110
|
-
env.open();
|
|
111
|
-
env.wait(&env.manifest_log);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
for (events) |event| {
|
|
115
|
-
log.debug("event={}", .{event});
|
|
116
|
-
switch (event) {
|
|
117
|
-
.insert => |e| try env.insert(e.level, &e.table),
|
|
118
|
-
.remove => |e| try env.remove(e.level, &e.table),
|
|
119
|
-
.compact => try env.compact(),
|
|
120
|
-
.checkpoint => try env.checkpoint(),
|
|
121
|
-
.noop => {},
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const ManifestEvent = union(enum) {
|
|
127
|
-
insert: struct { level: u7, table: TableInfo },
|
|
128
|
-
remove: struct { level: u7, table: TableInfo },
|
|
129
|
-
compact: void,
|
|
130
|
-
checkpoint: void,
|
|
131
|
-
/// The random EventType could not be generated — this simplifies event generation.
|
|
132
|
-
noop: void,
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
fn generate_events(
|
|
136
|
-
allocator: std.mem.Allocator,
|
|
137
|
-
random: std.rand.Random,
|
|
138
|
-
events_count: usize,
|
|
139
|
-
) ![]const ManifestEvent {
|
|
140
|
-
const EventType = enum {
|
|
141
|
-
insert_new,
|
|
142
|
-
insert_change_level,
|
|
143
|
-
insert_change_snapshot,
|
|
144
|
-
remove,
|
|
145
|
-
compact,
|
|
146
|
-
checkpoint,
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
const events = try allocator.alloc(ManifestEvent, events_count);
|
|
150
|
-
errdefer allocator.free(events);
|
|
151
|
-
|
|
152
|
-
var event_distribution = fuzz.random_enum_distribution(random, EventType);
|
|
153
|
-
// Don't remove too often, so that there are plenty of tables accumulating.
|
|
154
|
-
event_distribution.remove /= @intToFloat(f64, constants.lsm_levels);
|
|
155
|
-
// Don't compact or checkpoint too often, to approximate a real workload.
|
|
156
|
-
// Additionally, checkpoint is slow because of the verification, so run it less
|
|
157
|
-
// frequently.
|
|
158
|
-
event_distribution.compact /= @intToFloat(
|
|
159
|
-
f64,
|
|
160
|
-
constants.lsm_levels * constants.lsm_batch_multiple,
|
|
161
|
-
);
|
|
162
|
-
event_distribution.checkpoint /= @intToFloat(
|
|
163
|
-
f64,
|
|
164
|
-
constants.lsm_levels * constants.journal_slot_count,
|
|
165
|
-
);
|
|
166
|
-
|
|
167
|
-
log.info("event_distribution = {d:.2}", .{event_distribution});
|
|
168
|
-
log.info("event_count = {d}", .{events.len});
|
|
169
|
-
|
|
170
|
-
var tables = std.ArrayList(struct {
|
|
171
|
-
level: u7,
|
|
172
|
-
table: TableInfo,
|
|
173
|
-
}).init(allocator);
|
|
174
|
-
defer tables.deinit();
|
|
175
|
-
|
|
176
|
-
// The number of appends since the last flush (compact or checkpoint).
|
|
177
|
-
var append_count: usize = 0;
|
|
178
|
-
for (events) |*event, i| {
|
|
179
|
-
const event_type = blk: {
|
|
180
|
-
if (append_count == ManifestLog.compaction_appends_max) {
|
|
181
|
-
// We must compact or checkpoint periodically to avoid overfilling the ManifestLog.
|
|
182
|
-
break :blk if (random.boolean()) EventType.compact else EventType.checkpoint;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
const event_type_random = fuzz.random_enum(random, EventType, event_distribution);
|
|
186
|
-
if (tables.items.len == 0) {
|
|
187
|
-
if (event_type_random == .insert_change_level or
|
|
188
|
-
event_type_random == .insert_change_snapshot or
|
|
189
|
-
event_type_random == .remove)
|
|
190
|
-
{
|
|
191
|
-
break :blk .insert_new;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
break :blk event_type_random;
|
|
196
|
-
};
|
|
197
|
-
|
|
198
|
-
event.* = switch (event_type) {
|
|
199
|
-
.insert_new => insert: {
|
|
200
|
-
const level = random.uintLessThan(u7, constants.lsm_levels);
|
|
201
|
-
const table = TableInfo{
|
|
202
|
-
.checksum = 0,
|
|
203
|
-
.address = i + 1,
|
|
204
|
-
.snapshot_min = 1,
|
|
205
|
-
.snapshot_max = 2,
|
|
206
|
-
.key_min = 0,
|
|
207
|
-
.key_max = 0,
|
|
208
|
-
};
|
|
209
|
-
try tables.append(.{
|
|
210
|
-
.level = level,
|
|
211
|
-
.table = table,
|
|
212
|
-
});
|
|
213
|
-
const insert = ManifestEvent{ .insert = .{
|
|
214
|
-
.level = level,
|
|
215
|
-
.table = table,
|
|
216
|
-
} };
|
|
217
|
-
break :insert insert;
|
|
218
|
-
},
|
|
219
|
-
|
|
220
|
-
.insert_change_level => insert: {
|
|
221
|
-
const table = &tables.items[random.uintLessThan(usize, tables.items.len)];
|
|
222
|
-
if (table.level == constants.lsm_levels - 1) {
|
|
223
|
-
break :insert ManifestEvent{ .noop = {} };
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
table.level += 1;
|
|
227
|
-
const insert = ManifestEvent{ .insert = .{
|
|
228
|
-
.level = table.level,
|
|
229
|
-
.table = table.table,
|
|
230
|
-
} };
|
|
231
|
-
break :insert insert;
|
|
232
|
-
},
|
|
233
|
-
|
|
234
|
-
.insert_change_snapshot => insert: {
|
|
235
|
-
const table = &tables.items[random.uintLessThan(usize, tables.items.len)];
|
|
236
|
-
table.table.snapshot_max += 1;
|
|
237
|
-
const insert = ManifestEvent{ .insert = .{
|
|
238
|
-
.level = table.level,
|
|
239
|
-
.table = table.table,
|
|
240
|
-
} };
|
|
241
|
-
break :insert insert;
|
|
242
|
-
},
|
|
243
|
-
|
|
244
|
-
.remove => remove: {
|
|
245
|
-
const table = tables.swapRemove(random.uintLessThan(usize, tables.items.len));
|
|
246
|
-
const remove = ManifestEvent{ .remove = .{
|
|
247
|
-
.level = table.level,
|
|
248
|
-
.table = table.table,
|
|
249
|
-
} };
|
|
250
|
-
break :remove remove;
|
|
251
|
-
},
|
|
252
|
-
|
|
253
|
-
.compact => ManifestEvent{ .compact = {} },
|
|
254
|
-
.checkpoint => ManifestEvent{ .checkpoint = {} },
|
|
255
|
-
};
|
|
256
|
-
|
|
257
|
-
switch (event.*) {
|
|
258
|
-
.compact, .checkpoint => append_count = 0,
|
|
259
|
-
.noop => {},
|
|
260
|
-
else => append_count += 1,
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
return events;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
const TableInfo = extern struct {
|
|
267
|
-
checksum: u128,
|
|
268
|
-
address: u64,
|
|
269
|
-
flags: u64 = 0,
|
|
270
|
-
snapshot_min: u64,
|
|
271
|
-
snapshot_max: u64 = std.math.maxInt(u64),
|
|
272
|
-
key_min: u128,
|
|
273
|
-
key_max: u128,
|
|
274
|
-
|
|
275
|
-
comptime {
|
|
276
|
-
assert(@sizeOf(TableInfo) == 48 + 16 * 2);
|
|
277
|
-
assert(@alignOf(TableInfo) == 16);
|
|
278
|
-
assert(@bitSizeOf(TableInfo) == @sizeOf(TableInfo) * 8);
|
|
279
|
-
}
|
|
280
|
-
};
|
|
281
|
-
|
|
282
|
-
const Environment = struct {
|
|
283
|
-
allocator: std.mem.Allocator,
|
|
284
|
-
superblock_context: SuperBlock.Context = undefined,
|
|
285
|
-
manifest_log: ManifestLog,
|
|
286
|
-
manifest_log_verify: ManifestLog,
|
|
287
|
-
manifest_log_model: ManifestLogModel,
|
|
288
|
-
manifest_log_opening: ?ManifestLogModel.TableMap = null,
|
|
289
|
-
manifest_log_reserved: bool = false,
|
|
290
|
-
pending: usize = 0,
|
|
291
|
-
|
|
292
|
-
fn init(
|
|
293
|
-
allocator: std.mem.Allocator,
|
|
294
|
-
options: struct {
|
|
295
|
-
grid: *Grid,
|
|
296
|
-
grid_verify: *Grid,
|
|
297
|
-
},
|
|
298
|
-
) !Environment {
|
|
299
|
-
var manifest_log_model = try ManifestLogModel.init(allocator);
|
|
300
|
-
errdefer manifest_log_model.deinit();
|
|
301
|
-
|
|
302
|
-
const tree_hash = std.math.maxInt(u128);
|
|
303
|
-
var manifest_log = try ManifestLog.init(allocator, options.grid, tree_hash);
|
|
304
|
-
errdefer manifest_log.deinit(allocator);
|
|
305
|
-
|
|
306
|
-
var manifest_log_verify = try ManifestLog.init(allocator, options.grid_verify, tree_hash);
|
|
307
|
-
errdefer manifest_log_verify.deinit(allocator);
|
|
308
|
-
|
|
309
|
-
return Environment{
|
|
310
|
-
.allocator = allocator,
|
|
311
|
-
.manifest_log = manifest_log,
|
|
312
|
-
.manifest_log_verify = manifest_log_verify,
|
|
313
|
-
.manifest_log_model = manifest_log_model,
|
|
314
|
-
};
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
fn deinit(env: *Environment, allocator: std.mem.Allocator) void {
|
|
318
|
-
env.manifest_log.deinit(allocator);
|
|
319
|
-
env.manifest_log_verify.deinit(env.allocator);
|
|
320
|
-
env.manifest_log_model.deinit();
|
|
321
|
-
assert(env.manifest_log_opening == null);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
fn wait(env: *Environment, manifest_log: *ManifestLog) void {
|
|
325
|
-
while (env.pending > 0) {
|
|
326
|
-
// manifest_log.grid.tick();
|
|
327
|
-
manifest_log.superblock.storage.tick();
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
fn format_superblock(env: *Environment) void {
|
|
332
|
-
assert(env.pending == 0);
|
|
333
|
-
env.pending += 1;
|
|
334
|
-
env.manifest_log.superblock.format(format_superblock_callback, &env.superblock_context, .{
|
|
335
|
-
.cluster = 0,
|
|
336
|
-
.replica = 0,
|
|
337
|
-
});
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
fn format_superblock_callback(context: *SuperBlock.Context) void {
|
|
341
|
-
const env = @fieldParentPtr(Environment, "superblock_context", context);
|
|
342
|
-
env.pending -= 1;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
fn open_superblock(env: *Environment) void {
|
|
346
|
-
assert(env.pending == 0);
|
|
347
|
-
env.pending += 1;
|
|
348
|
-
env.manifest_log.superblock.open(open_superblock_callback, &env.superblock_context);
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
fn open_superblock_callback(context: *SuperBlock.Context) void {
|
|
352
|
-
const env = @fieldParentPtr(Environment, "superblock_context", context);
|
|
353
|
-
env.pending -= 1;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
fn open(env: *Environment) void {
|
|
357
|
-
assert(env.pending == 0);
|
|
358
|
-
assert(!env.manifest_log_reserved);
|
|
359
|
-
|
|
360
|
-
env.pending += 1;
|
|
361
|
-
env.manifest_log.open(open_event, open_callback);
|
|
362
|
-
env.manifest_log.reserve();
|
|
363
|
-
env.manifest_log_reserved = true;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
fn open_event(manifest_log: *ManifestLog, level: u7, table: *const TableInfo) void {
|
|
367
|
-
_ = manifest_log;
|
|
368
|
-
_ = level;
|
|
369
|
-
_ = table;
|
|
370
|
-
|
|
371
|
-
// This ManifestLog is only opened during setup, when it has no blocks.
|
|
372
|
-
unreachable;
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
fn open_callback(manifest_log: *ManifestLog) void {
|
|
376
|
-
const env = @fieldParentPtr(Environment, "manifest_log", manifest_log);
|
|
377
|
-
env.pending -= 1;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
fn insert(env: *Environment, level: u7, table: *const TableInfo) !void {
|
|
381
|
-
if (!env.manifest_log_reserved) env.manifest_log.reserve();
|
|
382
|
-
env.manifest_log_reserved = true;
|
|
383
|
-
|
|
384
|
-
try env.manifest_log_model.insert(level, table);
|
|
385
|
-
env.manifest_log.insert(level, table);
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
fn remove(env: *Environment, level: u7, table: *const TableInfo) !void {
|
|
389
|
-
if (!env.manifest_log_reserved) env.manifest_log.reserve();
|
|
390
|
-
env.manifest_log_reserved = true;
|
|
391
|
-
|
|
392
|
-
try env.manifest_log_model.remove(level, table);
|
|
393
|
-
env.manifest_log.remove(level, table);
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
fn compact(env: *Environment) !void {
|
|
397
|
-
if (!env.manifest_log_reserved) env.manifest_log.reserve();
|
|
398
|
-
env.manifest_log_reserved = true;
|
|
399
|
-
|
|
400
|
-
env.pending += 1;
|
|
401
|
-
env.manifest_log.compact(compact_callback);
|
|
402
|
-
env.wait(&env.manifest_log);
|
|
403
|
-
|
|
404
|
-
env.manifest_log_reserved = false;
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
fn compact_callback(manifest_log: *ManifestLog) void {
|
|
408
|
-
const env = @fieldParentPtr(Environment, "manifest_log", manifest_log);
|
|
409
|
-
env.pending -= 1;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
fn checkpoint(env: *Environment) !void {
|
|
413
|
-
// Checkpoint always follows compaction.
|
|
414
|
-
try env.compact();
|
|
415
|
-
|
|
416
|
-
try env.manifest_log_model.checkpoint();
|
|
417
|
-
|
|
418
|
-
env.pending += 1;
|
|
419
|
-
env.manifest_log.checkpoint(checkpoint_callback);
|
|
420
|
-
env.wait(&env.manifest_log);
|
|
421
|
-
|
|
422
|
-
const vsr_state = &env.manifest_log.superblock.working.vsr_state;
|
|
423
|
-
|
|
424
|
-
env.pending += 1;
|
|
425
|
-
env.manifest_log.superblock.checkpoint(
|
|
426
|
-
checkpoint_superblock_callback,
|
|
427
|
-
&env.superblock_context,
|
|
428
|
-
.{
|
|
429
|
-
.commit_min_checksum = vsr_state.commit_min_checksum + 1,
|
|
430
|
-
.commit_min = vsr_state.commit_min + 1,
|
|
431
|
-
.commit_max = vsr_state.commit_max + 1,
|
|
432
|
-
},
|
|
433
|
-
);
|
|
434
|
-
env.wait(&env.manifest_log);
|
|
435
|
-
|
|
436
|
-
try env.verify();
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
fn checkpoint_callback(manifest_log: *ManifestLog) void {
|
|
440
|
-
const env = @fieldParentPtr(Environment, "manifest_log", manifest_log);
|
|
441
|
-
env.pending -= 1;
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
fn checkpoint_superblock_callback(context: *SuperBlock.Context) void {
|
|
445
|
-
const env = @fieldParentPtr(Environment, "superblock_context", context);
|
|
446
|
-
env.pending -= 1;
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
/// Verify that the state of a ManifestLog restored from checkpoint matches the state
|
|
450
|
-
/// immediately after the checkpoint was created.
|
|
451
|
-
fn verify(env: *Environment) !void {
|
|
452
|
-
const test_superblock = env.manifest_log_verify.superblock;
|
|
453
|
-
const test_storage = test_superblock.storage;
|
|
454
|
-
const test_grid = env.manifest_log_verify.grid;
|
|
455
|
-
const test_manifest_log = &env.manifest_log_verify;
|
|
456
|
-
|
|
457
|
-
{
|
|
458
|
-
test_storage.copy(env.manifest_log.superblock.storage);
|
|
459
|
-
test_storage.reset();
|
|
460
|
-
|
|
461
|
-
// Reset the state so that the manifest log (and dependencies) can be reused.
|
|
462
|
-
// Do not "defer deinit()" because these are cleaned up by Env.deinit().
|
|
463
|
-
test_superblock.deinit(env.allocator);
|
|
464
|
-
test_superblock.* = try SuperBlock.init(
|
|
465
|
-
env.allocator,
|
|
466
|
-
.{
|
|
467
|
-
.storage = test_storage,
|
|
468
|
-
.storage_size_limit = constants.storage_size_max,
|
|
469
|
-
.message_pool = env.manifest_log.superblock.client_table.message_pool,
|
|
470
|
-
},
|
|
471
|
-
);
|
|
472
|
-
|
|
473
|
-
test_grid.deinit(env.allocator);
|
|
474
|
-
test_grid.* = try Grid.init(env.allocator, test_superblock);
|
|
475
|
-
|
|
476
|
-
test_manifest_log.deinit(env.allocator);
|
|
477
|
-
test_manifest_log.* = try ManifestLog.init(
|
|
478
|
-
env.allocator,
|
|
479
|
-
test_grid,
|
|
480
|
-
env.manifest_log.tree_hash,
|
|
481
|
-
);
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
env.pending += 1;
|
|
485
|
-
test_superblock.open(verify_superblock_open_callback, &env.superblock_context);
|
|
486
|
-
env.wait(test_manifest_log);
|
|
487
|
-
|
|
488
|
-
assert(env.manifest_log_opening == null);
|
|
489
|
-
env.manifest_log_opening = try env.manifest_log_model.tables.clone();
|
|
490
|
-
defer {
|
|
491
|
-
assert(env.manifest_log_opening.?.count() == 0);
|
|
492
|
-
env.manifest_log_opening.?.deinit();
|
|
493
|
-
env.manifest_log_opening = null;
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
env.pending += 1;
|
|
497
|
-
test_manifest_log.open(verify_manifest_open_event, verify_manifest_open_callback);
|
|
498
|
-
env.wait(test_manifest_log);
|
|
499
|
-
|
|
500
|
-
try verify_manifest(&test_superblock.manifest, &env.manifest_log.superblock.manifest);
|
|
501
|
-
try verify_manifest_compaction_set(test_superblock, &env.manifest_log_model);
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
fn verify_superblock_open_callback(superblock_context: *SuperBlock.Context) void {
|
|
505
|
-
const env = @fieldParentPtr(Environment, "superblock_context", superblock_context);
|
|
506
|
-
env.pending -= 1;
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
fn verify_manifest_open_event(
|
|
510
|
-
manifest_log_verify: *ManifestLog,
|
|
511
|
-
level: u7,
|
|
512
|
-
table: *const TableInfo,
|
|
513
|
-
) void {
|
|
514
|
-
const env = @fieldParentPtr(Environment, "manifest_log_verify", manifest_log_verify);
|
|
515
|
-
assert(env.pending > 0);
|
|
516
|
-
|
|
517
|
-
const expect = env.manifest_log_opening.?.get(table.address).?;
|
|
518
|
-
assert(expect.level == level);
|
|
519
|
-
assert(std.meta.eql(expect.table, table.*));
|
|
520
|
-
assert(env.manifest_log_opening.?.remove(table.address));
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
fn verify_manifest_open_callback(manifest_log_verify: *ManifestLog) void {
|
|
524
|
-
const env = @fieldParentPtr(Environment, "manifest_log_verify", manifest_log_verify);
|
|
525
|
-
env.pending -= 1;
|
|
526
|
-
}
|
|
527
|
-
};
|
|
528
|
-
|
|
529
|
-
const ManifestLogModel = struct {
|
|
530
|
-
/// Stores the latest checkpointed version of every table.
|
|
531
|
-
/// Indexed by table address.
|
|
532
|
-
const TableMap = std.AutoHashMap(u64, TableEntry);
|
|
533
|
-
|
|
534
|
-
const TableEntry = struct {
|
|
535
|
-
level: u7,
|
|
536
|
-
table: TableInfo,
|
|
537
|
-
};
|
|
538
|
-
|
|
539
|
-
/// Stores table updates that are not yet checkpointed.
|
|
540
|
-
const AppendList = std.ArrayList(struct {
|
|
541
|
-
event: enum { insert, remove },
|
|
542
|
-
level: u7,
|
|
543
|
-
table: TableInfo,
|
|
544
|
-
});
|
|
545
|
-
|
|
546
|
-
tables: TableMap,
|
|
547
|
-
appends: AppendList,
|
|
548
|
-
|
|
549
|
-
fn init(allocator: std.mem.Allocator) !ManifestLogModel {
|
|
550
|
-
const tables = TableMap.init(allocator);
|
|
551
|
-
errdefer tables.deinit(allocator);
|
|
552
|
-
|
|
553
|
-
const appends = AppendList.init(allocator);
|
|
554
|
-
errdefer appends.deinit(allocator);
|
|
555
|
-
|
|
556
|
-
return ManifestLogModel{
|
|
557
|
-
.tables = tables,
|
|
558
|
-
.appends = appends,
|
|
559
|
-
};
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
fn deinit(model: *ManifestLogModel) void {
|
|
563
|
-
model.tables.deinit();
|
|
564
|
-
model.appends.deinit();
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
fn current(model: ManifestLogModel, table_address: u64) ?TableEntry {
|
|
568
|
-
assert(model.appends.items.len == 0);
|
|
569
|
-
|
|
570
|
-
return model.tables.get(table_address);
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
fn insert(model: *ManifestLogModel, level: u7, table: *const TableInfo) !void {
|
|
574
|
-
try model.appends.append(.{
|
|
575
|
-
.event = .insert,
|
|
576
|
-
.level = level,
|
|
577
|
-
.table = table.*,
|
|
578
|
-
});
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
fn remove(model: *ManifestLogModel, level: u7, table: *const TableInfo) !void {
|
|
582
|
-
try model.appends.append(.{
|
|
583
|
-
.event = .remove,
|
|
584
|
-
.level = level,
|
|
585
|
-
.table = table.*,
|
|
586
|
-
});
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
fn checkpoint(model: *ManifestLogModel) !void {
|
|
590
|
-
for (model.appends.items) |append| {
|
|
591
|
-
switch (append.event) {
|
|
592
|
-
.insert => {
|
|
593
|
-
try model.tables.put(append.table.address, .{
|
|
594
|
-
.level = append.level,
|
|
595
|
-
.table = append.table,
|
|
596
|
-
});
|
|
597
|
-
},
|
|
598
|
-
.remove => {
|
|
599
|
-
const removed = model.tables.get(append.table.address).?;
|
|
600
|
-
assert(removed.level == append.level);
|
|
601
|
-
assert(std.meta.eql(removed.table, append.table));
|
|
602
|
-
assert(model.tables.remove(append.table.address));
|
|
603
|
-
},
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
model.appends.clearRetainingCapacity();
|
|
607
|
-
}
|
|
608
|
-
};
|
|
609
|
-
|
|
610
|
-
fn verify_manifest(
|
|
611
|
-
expect: *const SuperBlock.Manifest,
|
|
612
|
-
actual: *const SuperBlock.Manifest,
|
|
613
|
-
) !void {
|
|
614
|
-
try std.testing.expectEqual(expect.count, actual.count);
|
|
615
|
-
try std.testing.expectEqual(expect.count_max, actual.count_max);
|
|
616
|
-
|
|
617
|
-
const c = expect.count;
|
|
618
|
-
try std.testing.expect(std.mem.eql(u128, expect.trees[0..c], actual.trees[0..c]));
|
|
619
|
-
try std.testing.expect(std.mem.eql(u128, expect.checksums[0..c], actual.checksums[0..c]));
|
|
620
|
-
try std.testing.expect(std.mem.eql(u64, expect.addresses[0..c], actual.addresses[0..c]));
|
|
621
|
-
|
|
622
|
-
try std.testing.expect(hash_map_equals(
|
|
623
|
-
SuperBlock.Manifest.TableExtentKey,
|
|
624
|
-
SuperBlock.Manifest.TableExtent,
|
|
625
|
-
&expect.tables,
|
|
626
|
-
&actual.tables,
|
|
627
|
-
));
|
|
628
|
-
try std.testing.expect(hash_map_equals(
|
|
629
|
-
u64,
|
|
630
|
-
void,
|
|
631
|
-
&expect.compaction_set,
|
|
632
|
-
&actual.compaction_set,
|
|
633
|
-
));
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
fn verify_manifest_compaction_set(
|
|
637
|
-
superblock: *const SuperBlock,
|
|
638
|
-
manifest_log_model: *const ManifestLogModel,
|
|
639
|
-
) !void {
|
|
640
|
-
var compact_blocks_checked: u32 = 0;
|
|
641
|
-
|
|
642
|
-
// This test doesn't include any actual table blocks, so all blocks are manifest blocks.
|
|
643
|
-
var blocks = superblock.free_set.blocks.iterator(.{ .kind = .set });
|
|
644
|
-
while (blocks.next()) |block_index| {
|
|
645
|
-
const block_address = block_index + 1;
|
|
646
|
-
const block = superblock.storage.grid_block(block_address);
|
|
647
|
-
const block_header = std.mem.bytesToValue(vsr.Header, block[0..@sizeOf(vsr.Header)]);
|
|
648
|
-
try std.testing.expectEqual(BlockType.manifest.operation(), block_header.operation);
|
|
649
|
-
|
|
650
|
-
const entry_count = ManifestLog.Block.entry_count(block);
|
|
651
|
-
var compact_soon: bool = entry_count < ManifestLog.Block.entry_count_max;
|
|
652
|
-
for (ManifestLog.Block.labels_const(block)[0..entry_count]) |label, i| {
|
|
653
|
-
const table = &ManifestLog.Block.tables_const(block)[i];
|
|
654
|
-
compact_soon = compact_soon or switch (label.event) {
|
|
655
|
-
.remove => true,
|
|
656
|
-
.insert => blk: {
|
|
657
|
-
const table_current = manifest_log_model.current(table.address);
|
|
658
|
-
break :blk table_current == null or
|
|
659
|
-
table_current.?.level != label.level or
|
|
660
|
-
table_current.?.table.snapshot_min != table.snapshot_min or
|
|
661
|
-
table_current.?.table.snapshot_max != table.snapshot_max;
|
|
662
|
-
},
|
|
663
|
-
};
|
|
664
|
-
}
|
|
665
|
-
try std.testing.expectEqual(
|
|
666
|
-
compact_soon,
|
|
667
|
-
superblock.manifest.compaction_set.contains(block_address),
|
|
668
|
-
);
|
|
669
|
-
compact_blocks_checked += @boolToInt(compact_soon);
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
// There are no blocks queued for compaction which were not allocated in the FreeSet.
|
|
673
|
-
try std.testing.expectEqual(superblock.manifest.compaction_set.count(), compact_blocks_checked);
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
fn hash_map_equals(
|
|
677
|
-
comptime K: type,
|
|
678
|
-
comptime V: type,
|
|
679
|
-
a: *const std.AutoHashMapUnmanaged(K, V),
|
|
680
|
-
b: *const std.AutoHashMapUnmanaged(K, V),
|
|
681
|
-
) bool {
|
|
682
|
-
if (a.count() != b.count()) return false;
|
|
683
|
-
|
|
684
|
-
var a_iterator = a.iterator();
|
|
685
|
-
while (a_iterator.next()) |a_entry| {
|
|
686
|
-
const a_value = a_entry.value_ptr.*;
|
|
687
|
-
const b_value = b.get(a_entry.key_ptr.*) orelse return false;
|
|
688
|
-
if (!std.meta.eql(a_value, b_value)) return false;
|
|
689
|
-
}
|
|
690
|
-
return true;
|
|
691
|
-
}
|