tigerbeetle-node 0.11.12 → 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.
Files changed (143) hide show
  1. package/README.md +212 -196
  2. package/dist/bin/aarch64-linux-gnu/client.node +0 -0
  3. package/dist/bin/aarch64-linux-musl/client.node +0 -0
  4. package/dist/bin/aarch64-macos/client.node +0 -0
  5. package/dist/bin/x86_64-linux-gnu/client.node +0 -0
  6. package/dist/bin/x86_64-linux-musl/client.node +0 -0
  7. package/dist/bin/x86_64-macos/client.node +0 -0
  8. package/dist/index.js +33 -1
  9. package/dist/index.js.map +1 -1
  10. package/package-lock.json +66 -0
  11. package/package.json +8 -17
  12. package/src/index.ts +56 -1
  13. package/src/node.zig +10 -9
  14. package/dist/.client.node.sha256 +0 -1
  15. package/scripts/build_lib.sh +0 -61
  16. package/scripts/download_node_headers.sh +0 -32
  17. package/src/tigerbeetle/scripts/benchmark.bat +0 -48
  18. package/src/tigerbeetle/scripts/benchmark.sh +0 -66
  19. package/src/tigerbeetle/scripts/confirm_image.sh +0 -44
  20. package/src/tigerbeetle/scripts/fuzz_loop.sh +0 -15
  21. package/src/tigerbeetle/scripts/fuzz_unique_errors.sh +0 -7
  22. package/src/tigerbeetle/scripts/install.bat +0 -7
  23. package/src/tigerbeetle/scripts/install.sh +0 -21
  24. package/src/tigerbeetle/scripts/install_zig.bat +0 -113
  25. package/src/tigerbeetle/scripts/install_zig.sh +0 -90
  26. package/src/tigerbeetle/scripts/lint.zig +0 -199
  27. package/src/tigerbeetle/scripts/pre-commit.sh +0 -9
  28. package/src/tigerbeetle/scripts/scripts/benchmark.bat +0 -48
  29. package/src/tigerbeetle/scripts/scripts/benchmark.sh +0 -66
  30. package/src/tigerbeetle/scripts/scripts/confirm_image.sh +0 -44
  31. package/src/tigerbeetle/scripts/scripts/fuzz_loop.sh +0 -15
  32. package/src/tigerbeetle/scripts/scripts/fuzz_unique_errors.sh +0 -7
  33. package/src/tigerbeetle/scripts/scripts/install.bat +0 -7
  34. package/src/tigerbeetle/scripts/scripts/install.sh +0 -21
  35. package/src/tigerbeetle/scripts/scripts/install_zig.bat +0 -113
  36. package/src/tigerbeetle/scripts/scripts/install_zig.sh +0 -90
  37. package/src/tigerbeetle/scripts/scripts/lint.zig +0 -199
  38. package/src/tigerbeetle/scripts/scripts/pre-commit.sh +0 -9
  39. package/src/tigerbeetle/scripts/scripts/shellcheck.sh +0 -5
  40. package/src/tigerbeetle/scripts/scripts/tests_on_alpine.sh +0 -10
  41. package/src/tigerbeetle/scripts/scripts/tests_on_ubuntu.sh +0 -14
  42. package/src/tigerbeetle/scripts/scripts/upgrade_ubuntu_kernel.sh +0 -48
  43. package/src/tigerbeetle/scripts/scripts/validate_docs.sh +0 -23
  44. package/src/tigerbeetle/scripts/scripts/vr_state_enumerate +0 -46
  45. package/src/tigerbeetle/scripts/shellcheck.sh +0 -5
  46. package/src/tigerbeetle/scripts/tests_on_alpine.sh +0 -10
  47. package/src/tigerbeetle/scripts/tests_on_ubuntu.sh +0 -14
  48. package/src/tigerbeetle/scripts/upgrade_ubuntu_kernel.sh +0 -48
  49. package/src/tigerbeetle/scripts/validate_docs.sh +0 -23
  50. package/src/tigerbeetle/scripts/vr_state_enumerate +0 -46
  51. package/src/tigerbeetle/src/benchmark.zig +0 -314
  52. package/src/tigerbeetle/src/config.zig +0 -234
  53. package/src/tigerbeetle/src/constants.zig +0 -436
  54. package/src/tigerbeetle/src/ewah.zig +0 -286
  55. package/src/tigerbeetle/src/ewah_benchmark.zig +0 -120
  56. package/src/tigerbeetle/src/ewah_fuzz.zig +0 -130
  57. package/src/tigerbeetle/src/fifo.zig +0 -120
  58. package/src/tigerbeetle/src/io/benchmark.zig +0 -213
  59. package/src/tigerbeetle/src/io/darwin.zig +0 -814
  60. package/src/tigerbeetle/src/io/linux.zig +0 -1062
  61. package/src/tigerbeetle/src/io/test.zig +0 -643
  62. package/src/tigerbeetle/src/io/windows.zig +0 -1183
  63. package/src/tigerbeetle/src/io.zig +0 -34
  64. package/src/tigerbeetle/src/iops.zig +0 -107
  65. package/src/tigerbeetle/src/lsm/README.md +0 -308
  66. package/src/tigerbeetle/src/lsm/binary_search.zig +0 -341
  67. package/src/tigerbeetle/src/lsm/bloom_filter.zig +0 -125
  68. package/src/tigerbeetle/src/lsm/compaction.zig +0 -603
  69. package/src/tigerbeetle/src/lsm/composite_key.zig +0 -77
  70. package/src/tigerbeetle/src/lsm/direction.zig +0 -11
  71. package/src/tigerbeetle/src/lsm/eytzinger.zig +0 -587
  72. package/src/tigerbeetle/src/lsm/eytzinger_benchmark.zig +0 -330
  73. package/src/tigerbeetle/src/lsm/forest.zig +0 -204
  74. package/src/tigerbeetle/src/lsm/forest_fuzz.zig +0 -401
  75. package/src/tigerbeetle/src/lsm/grid.zig +0 -573
  76. package/src/tigerbeetle/src/lsm/groove.zig +0 -972
  77. package/src/tigerbeetle/src/lsm/k_way_merge.zig +0 -474
  78. package/src/tigerbeetle/src/lsm/level_iterator.zig +0 -332
  79. package/src/tigerbeetle/src/lsm/manifest.zig +0 -617
  80. package/src/tigerbeetle/src/lsm/manifest_level.zig +0 -877
  81. package/src/tigerbeetle/src/lsm/manifest_log.zig +0 -789
  82. package/src/tigerbeetle/src/lsm/manifest_log_fuzz.zig +0 -691
  83. package/src/tigerbeetle/src/lsm/merge_iterator.zig +0 -106
  84. package/src/tigerbeetle/src/lsm/node_pool.zig +0 -235
  85. package/src/tigerbeetle/src/lsm/posted_groove.zig +0 -378
  86. package/src/tigerbeetle/src/lsm/segmented_array.zig +0 -1328
  87. package/src/tigerbeetle/src/lsm/segmented_array_benchmark.zig +0 -148
  88. package/src/tigerbeetle/src/lsm/segmented_array_fuzz.zig +0 -9
  89. package/src/tigerbeetle/src/lsm/set_associative_cache.zig +0 -850
  90. package/src/tigerbeetle/src/lsm/table.zig +0 -1031
  91. package/src/tigerbeetle/src/lsm/table_immutable.zig +0 -203
  92. package/src/tigerbeetle/src/lsm/table_iterator.zig +0 -340
  93. package/src/tigerbeetle/src/lsm/table_mutable.zig +0 -220
  94. package/src/tigerbeetle/src/lsm/test.zig +0 -438
  95. package/src/tigerbeetle/src/lsm/tree.zig +0 -1193
  96. package/src/tigerbeetle/src/lsm/tree_fuzz.zig +0 -474
  97. package/src/tigerbeetle/src/message_bus.zig +0 -1012
  98. package/src/tigerbeetle/src/message_pool.zig +0 -156
  99. package/src/tigerbeetle/src/ring_buffer.zig +0 -399
  100. package/src/tigerbeetle/src/simulator.zig +0 -569
  101. package/src/tigerbeetle/src/state_machine/auditor.zig +0 -577
  102. package/src/tigerbeetle/src/state_machine/workload.zig +0 -883
  103. package/src/tigerbeetle/src/state_machine.zig +0 -1881
  104. package/src/tigerbeetle/src/static_allocator.zig +0 -65
  105. package/src/tigerbeetle/src/stdx.zig +0 -162
  106. package/src/tigerbeetle/src/storage.zig +0 -393
  107. package/src/tigerbeetle/src/testing/cluster/message_bus.zig +0 -82
  108. package/src/tigerbeetle/src/testing/cluster/network.zig +0 -237
  109. package/src/tigerbeetle/src/testing/cluster/state_checker.zig +0 -169
  110. package/src/tigerbeetle/src/testing/cluster/storage_checker.zig +0 -202
  111. package/src/tigerbeetle/src/testing/cluster.zig +0 -443
  112. package/src/tigerbeetle/src/testing/fuzz.zig +0 -140
  113. package/src/tigerbeetle/src/testing/hash_log.zig +0 -66
  114. package/src/tigerbeetle/src/testing/id.zig +0 -99
  115. package/src/tigerbeetle/src/testing/packet_simulator.zig +0 -364
  116. package/src/tigerbeetle/src/testing/priority_queue.zig +0 -645
  117. package/src/tigerbeetle/src/testing/reply_sequence.zig +0 -139
  118. package/src/tigerbeetle/src/testing/state_machine.zig +0 -249
  119. package/src/tigerbeetle/src/testing/storage.zig +0 -757
  120. package/src/tigerbeetle/src/testing/table.zig +0 -247
  121. package/src/tigerbeetle/src/testing/time.zig +0 -84
  122. package/src/tigerbeetle/src/tigerbeetle.zig +0 -227
  123. package/src/tigerbeetle/src/time.zig +0 -112
  124. package/src/tigerbeetle/src/tracer.zig +0 -529
  125. package/src/tigerbeetle/src/unit_tests.zig +0 -42
  126. package/src/tigerbeetle/src/vopr.zig +0 -495
  127. package/src/tigerbeetle/src/vsr/README.md +0 -209
  128. package/src/tigerbeetle/src/vsr/client.zig +0 -544
  129. package/src/tigerbeetle/src/vsr/clock.zig +0 -853
  130. package/src/tigerbeetle/src/vsr/journal.zig +0 -2413
  131. package/src/tigerbeetle/src/vsr/journal_format_fuzz.zig +0 -111
  132. package/src/tigerbeetle/src/vsr/marzullo.zig +0 -309
  133. package/src/tigerbeetle/src/vsr/replica.zig +0 -6381
  134. package/src/tigerbeetle/src/vsr/replica_format.zig +0 -219
  135. package/src/tigerbeetle/src/vsr/superblock.zig +0 -1631
  136. package/src/tigerbeetle/src/vsr/superblock_client_table.zig +0 -256
  137. package/src/tigerbeetle/src/vsr/superblock_free_set.zig +0 -929
  138. package/src/tigerbeetle/src/vsr/superblock_free_set_fuzz.zig +0 -334
  139. package/src/tigerbeetle/src/vsr/superblock_fuzz.zig +0 -390
  140. package/src/tigerbeetle/src/vsr/superblock_manifest.zig +0 -615
  141. package/src/tigerbeetle/src/vsr/superblock_quorums.zig +0 -394
  142. package/src/tigerbeetle/src/vsr/superblock_quorums_fuzz.zig +0 -314
  143. package/src/tigerbeetle/src/vsr.zig +0 -1352
@@ -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
- }