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,394 +0,0 @@
1
- const std = @import("std");
2
- const assert = std.debug.assert;
3
- const log = std.log.scoped(.superblock_quorums);
4
-
5
- const superblock = @import("./superblock.zig");
6
- const SuperBlockHeader = superblock.SuperBlockHeader;
7
- const SuperBlockVersion = superblock.SuperBlockVersion;
8
- const fuzz = @import("./superblock_quorums_fuzz.zig");
9
-
10
- pub const Options = struct {
11
- superblock_copies: u8,
12
- };
13
-
14
- pub fn QuorumsType(comptime options: Options) type {
15
- return struct {
16
- const Quorums = @This();
17
-
18
- const Quorum = struct {
19
- header: *const SuperBlockHeader,
20
- valid: bool = false,
21
- /// Track which copies are a member of the quorum.
22
- /// Used to ignore duplicate copies of a header when determining a quorum.
23
- copies: QuorumCount = QuorumCount.initEmpty(),
24
- /// An integer value indicates the copy index found in the corresponding slot.
25
- /// A `null` value indicates that the copy is invalid or not a member of the working
26
- /// quorum. All copies belong to the same (valid, working) quorum.
27
- slots: [options.superblock_copies]?u8 = [_]?u8{null} ** options.superblock_copies,
28
-
29
- pub fn repairs(quorum: Quorum) RepairIterator {
30
- assert(quorum.valid);
31
- return .{ .slots = quorum.slots };
32
- }
33
- };
34
-
35
- pub const QuorumCount = std.StaticBitSet(options.superblock_copies);
36
-
37
- pub const Error = error{
38
- Fork,
39
- NotFound,
40
- QuorumLost,
41
- ParentNotConnected,
42
- ParentSkipped,
43
- VSRStateNotMonotonic,
44
- };
45
-
46
- /// We use flexible quorums for even quorums with write quorum > read quorum, for example:
47
- /// * When writing, we must verify that at least 3/4 copies were written.
48
- /// * At startup, we must verify that at least 2/4 copies were read.
49
- ///
50
- /// This ensures that our read and write quorums will intersect.
51
- /// Using flexible quorums in this way increases resiliency of the superblock.
52
- pub const Threshold = enum {
53
- verify,
54
- open,
55
- // Working these threshold out by formula is easy to get wrong, so enumerate them:
56
- // The rule is that the write quorum plus the read quorum must be exactly copies + 1.
57
-
58
- pub fn count(threshold: Threshold) u8 {
59
- return switch (threshold) {
60
- .verify => switch (options.superblock_copies) {
61
- 4 => 3,
62
- 6 => 4,
63
- 8 => 5,
64
- else => unreachable,
65
- },
66
- // The open quorum must allow for at least two copy faults, because we update
67
- // copies in place, temporarily impairing one copy.
68
- .open => switch (options.superblock_copies) {
69
- 4 => 2,
70
- 6 => 3,
71
- 8 => 4,
72
- else => unreachable,
73
- },
74
- };
75
- }
76
- };
77
-
78
- array: [options.superblock_copies]Quorum = undefined,
79
- count: u8 = 0,
80
-
81
- /// Returns the working superblock according to the quorum with the highest sequence number.
82
- ///
83
- /// * When a member of the parent quorum is still present, verify that the highest quorum is
84
- /// connected.
85
- /// * When there are 2 quorums: 1/4 new and 3/4 old, favor the 3/4 old since the 1/4's
86
- /// trailers may be damaged.
87
- pub fn working(
88
- quorums: *Quorums,
89
- copies: []SuperBlockHeader,
90
- threshold: Threshold,
91
- ) Error!Quorum {
92
- assert(copies.len == options.superblock_copies);
93
- assert(threshold.count() >= 2 and threshold.count() <= 5);
94
-
95
- quorums.array = undefined;
96
- quorums.count = 0;
97
-
98
- for (copies) |*copy, index| quorums.count_copy(copy, index, threshold);
99
-
100
- std.sort.sort(Quorum, quorums.slice(), {}, sort_priority_descending);
101
-
102
- for (quorums.slice()) |quorum| {
103
- if (quorum.copies.count() == options.superblock_copies) {
104
- log.debug("quorum: checksum={x} parent={x} sequence={} count={} valid={}", .{
105
- quorum.header.checksum,
106
- quorum.header.parent,
107
- quorum.header.sequence,
108
- quorum.copies.count(),
109
- quorum.valid,
110
- });
111
- } else {
112
- log.warn("quorum: checksum={x} parent={x} sequence={} count={} valid={}", .{
113
- quorum.header.checksum,
114
- quorum.header.parent,
115
- quorum.header.sequence,
116
- quorum.copies.count(),
117
- quorum.valid,
118
- });
119
- }
120
- }
121
-
122
- // No working copies of any sequence number exist in the superblock storage zone at all.
123
- if (quorums.slice().len == 0) return error.NotFound;
124
-
125
- // At least one copy or quorum exists.
126
- const b = quorums.slice()[0];
127
-
128
- // Verify that the remaining quorums are correctly sorted:
129
- for (quorums.slice()[1..]) |a| {
130
- assert(sort_priority_descending({}, b, a));
131
- assert(a.header.valid_checksum());
132
- }
133
-
134
- // Even the best copy with the most quorum still has inadequate quorum.
135
- if (!b.valid) return error.QuorumLost;
136
-
137
- // If a parent quorum is present (either complete or incomplete) it must be connected to the
138
- // new working quorum. The parent quorum can exist due to:
139
- // - a crash during checkpoint()/view_change() before writing all copies
140
- // - a lost or misdirected write
141
- // - a latent sector error that prevented a write
142
- for (quorums.slice()[1..]) |a| {
143
- if (a.header.cluster != b.header.cluster) {
144
- log.warn("superblock copy={} has cluster={} instead of {}", .{
145
- a.header.copy,
146
- a.header.cluster,
147
- b.header.cluster,
148
- });
149
- continue;
150
- }
151
-
152
- if (a.header.replica != b.header.replica) {
153
- log.warn("superblock copy={} has replica={} instead of {}", .{
154
- a.header.copy,
155
- a.header.replica,
156
- b.header.replica,
157
- });
158
- continue;
159
- }
160
-
161
- if (a.header.sequence == b.header.sequence) {
162
- // Two quorums, same cluster+replica+sequence, but different checksums.
163
- // This shouldn't ever happen — but if it does, we can't safely repair.
164
- assert(a.header.checksum != b.header.checksum);
165
- return error.Fork;
166
- }
167
-
168
- if (a.header.sequence > b.header.sequence + 1) {
169
- // We read sequences such as (2,2,2,4) — 2 isn't safe to use, but there isn't a
170
- // valid quorum for 4 either.
171
- return error.ParentSkipped;
172
- }
173
-
174
- if (a.header.sequence + 1 == b.header.sequence) {
175
- assert(a.header.checksum != b.header.checksum);
176
- assert(a.header.cluster == b.header.cluster);
177
- assert(a.header.replica == b.header.replica);
178
-
179
- if (a.header.checksum != b.header.parent) {
180
- return error.ParentNotConnected;
181
- } else if (!a.header.vsr_state.monotonic(b.header.vsr_state)) {
182
- return error.VSRStateNotMonotonic;
183
- } else {
184
- assert(b.header.valid_checksum());
185
-
186
- return b;
187
- }
188
- }
189
- }
190
-
191
- assert(b.header.valid_checksum());
192
- return b;
193
- }
194
-
195
- fn count_copy(
196
- quorums: *Quorums,
197
- copy: *const SuperBlockHeader,
198
- slot: usize,
199
- threshold: Threshold,
200
- ) void {
201
- assert(slot < options.superblock_copies);
202
- assert(threshold.count() >= 2 and threshold.count() <= 5);
203
-
204
- if (!copy.valid_checksum()) {
205
- log.debug("copy: {}/{}: invalid checksum", .{ slot, options.superblock_copies });
206
- return;
207
- }
208
-
209
- if (copy.copy == slot) {
210
- log.debug("copy: {}/{}: checksum={x} parent={x} sequence={}", .{
211
- slot,
212
- options.superblock_copies,
213
- copy.checksum,
214
- copy.parent,
215
- copy.sequence,
216
- });
217
- } else if (copy.copy >= options.superblock_copies) {
218
- log.warn("copy: {}/{}: checksum={x} parent={x} sequence={} corrupt copy={}", .{
219
- slot,
220
- options.superblock_copies,
221
- copy.checksum,
222
- copy.parent,
223
- copy.sequence,
224
- copy.copy,
225
- });
226
- } else {
227
- // If our read was misdirected, we definitely still want to count the copy.
228
- // We must just be careful to count it idempotently.
229
- log.warn(
230
- "copy: {}/{}: checksum={x} parent={x} sequence={} misdirected from copy={}",
231
- .{
232
- slot,
233
- options.superblock_copies,
234
- copy.checksum,
235
- copy.parent,
236
- copy.sequence,
237
- copy.copy,
238
- },
239
- );
240
- }
241
-
242
- var quorum = quorums.find_or_insert_quorum_for_copy(copy);
243
- assert(quorum.header.checksum == copy.checksum);
244
- assert(quorum.header.equal(copy));
245
-
246
- if (copy.copy >= options.superblock_copies) {
247
- // This header is a valid member of the quorum, but with an unexpected copy number.
248
- // The "SuperBlockHeader.copy" field is not protected by the checksum, so if that byte
249
- // (and only that byte) is corrupted, the superblock is still valid — but we don't know
250
- // for certain which copy this was supposed to be.
251
- // We make the assumption that this was not a double-fault (corrupt + misdirect) —
252
- // that is, the copy is in the correct slot, and its copy index is simply corrupt.
253
- quorum.slots[slot] = @intCast(u8, slot);
254
- quorum.copies.set(slot);
255
- } else if (quorum.copies.isSet(copy.copy)) {
256
- // Ignore the duplicate copy.
257
- } else {
258
- quorum.slots[slot] = copy.copy;
259
- quorum.copies.set(copy.copy);
260
- }
261
-
262
- quorum.valid = quorum.copies.count() >= threshold.count();
263
- }
264
-
265
- fn find_or_insert_quorum_for_copy(quorums: *Quorums, copy: *const SuperBlockHeader) *Quorum {
266
- assert(copy.valid_checksum());
267
-
268
- for (quorums.array[0..quorums.count]) |*quorum| {
269
- if (copy.checksum == quorum.header.checksum) return quorum;
270
- } else {
271
- quorums.array[quorums.count] = Quorum{ .header = copy };
272
- quorums.count += 1;
273
-
274
- return &quorums.array[quorums.count - 1];
275
- }
276
- }
277
-
278
- fn slice(quorums: *Quorums) []Quorum {
279
- return quorums.array[0..quorums.count];
280
- }
281
-
282
- fn sort_priority_descending(_: void, a: Quorum, b: Quorum) bool {
283
- assert(a.header.checksum != b.header.checksum);
284
-
285
- if (a.valid and !b.valid) return true;
286
- if (b.valid and !a.valid) return false;
287
-
288
- if (a.header.sequence > b.header.sequence) return true;
289
- if (b.header.sequence > a.header.sequence) return false;
290
-
291
- if (a.copies.count() > b.copies.count()) return true;
292
- if (b.copies.count() > a.copies.count()) return false;
293
-
294
- // The sort order must be stable and deterministic:
295
- return a.header.checksum > b.header.checksum;
296
- }
297
-
298
- /// Repair a quorum's copies in the safest known order.
299
- /// Repair is complete when every copy is on-disk (not necessarily in its home slot).
300
- ///
301
- /// We must be careful when repairing superblock headers to avoid endangering our quorum if
302
- /// an additional fault occurs. We primarily guard against torn header writes — preventing a
303
- /// misdirected write from derailing repair is far more expensive and complex — but they are
304
- /// likewise far less likely to occur.
305
- ///
306
- /// For example, consider this case:
307
- /// 0. Sequence is initially A.
308
- /// 1. Checkpoint sequence B.
309
- /// 2. Write B₀ — ok.
310
- /// 3. Write B₁ — misdirected to B₂'s slot.
311
- /// 4. Crash.
312
- /// 5. Recover with quorum B[B₀,A₁,B₁,A₃].
313
- /// If we repair the superblock quorum while only considering the valid copies (and not slots)
314
- /// the following scenario could occur:
315
- /// 6. We already have a valid B₀ and B₁, so begin writing B₂.
316
- /// 7. Crash, tearing the B₂ write.
317
- /// 8. Recover with quorum A[B₀,A₁,_,A₂].
318
- /// The working quorum backtracked from B to A!
319
- pub const RepairIterator = struct {
320
- /// An integer value indicates the copy index found in the corresponding slot.
321
- /// A `null` value indicates that the copy is invalid or not a member of the working quorum.
322
- /// All copies belong to the same (valid, working) quorum.
323
- slots: [options.superblock_copies]?u8,
324
-
325
- /// Returns the slot/copy to repair next.
326
- /// We never (deliberately) write a copy to a slot other than its own. This is simpler to
327
- /// implement, and also reduces risk when one of open()'s reads was misdirected.
328
- pub fn next(iterator: *RepairIterator) ?u8 {
329
- // Corrupt copy indices have already been normalized.
330
- for (iterator.slots) |slot| assert(slot == null or slot.? < options.superblock_copies);
331
-
332
- // Set bits indicate that the corresponding copy was found at least once.
333
- var copies_any = QuorumCount.initEmpty();
334
- // Set bits indicate that the corresponding copy was found more than once.
335
- var copies_duplicate = QuorumCount.initEmpty();
336
-
337
- for (iterator.slots) |slot| {
338
- if (slot) |copy| {
339
- if (copies_any.isSet(copy)) copies_duplicate.set(copy);
340
- copies_any.set(copy);
341
- }
342
- }
343
-
344
- // In descending order, our priorities for repair are:
345
- // 1. The slot holds no header, and the copy was not found anywhere.
346
- // 2. The slot holds no header, but its copy was found elsewhere.
347
- // 3. The slot holds a misdirected header, but that copy is in another slot as well.
348
- var a: ?u8 = null;
349
- var b: ?u8 = null;
350
- var c: ?u8 = null;
351
- for (iterator.slots) |slot, i| {
352
- if (slot == null and !copies_any.isSet(i)) a = @intCast(u8, i);
353
- if (slot == null and copies_any.isSet(i)) b = @intCast(u8, i);
354
- if (slot) |slot_copy| {
355
- if (slot_copy != i and copies_duplicate.isSet(slot_copy)) c = @intCast(u8, i);
356
- }
357
- }
358
-
359
- const repair = a orelse b orelse c orelse {
360
- for (iterator.slots) |slot| assert(slot != null);
361
- return null;
362
- };
363
-
364
- iterator.slots[repair] = repair;
365
- return repair;
366
- }
367
- };
368
- };
369
- }
370
-
371
- test "Quorums.working" {
372
- var prng = std.rand.DefaultPrng.init(123);
373
-
374
- // Don't print warnings from the Quorums.
375
- var level = std.log.Level.err;
376
- std.testing.log_level = std.log.Level.err;
377
- defer std.testing.log_level = level;
378
-
379
- try fuzz.fuzz_quorums_working(prng.random());
380
- }
381
-
382
- test "Quorum.repairs" {
383
- var prng = std.rand.DefaultPrng.init(123);
384
-
385
- // Don't print warnings from the Quorums.
386
- var level = std.log.Level.err;
387
- std.testing.log_level = std.log.Level.err;
388
- defer std.testing.log_level = level;
389
-
390
- try fuzz.fuzz_quorum_repairs(prng.random(), .{ .superblock_copies = 4 });
391
- // TODO: Enable these once SuperBlockHeader is generic over its Constants.
392
- // try fuzz.fuzz_quorum_repairs(prng.random(), .{ .superblock_copies = 6 });
393
- // try fuzz.fuzz_quorum_repairs(prng.random(), .{ .superblock_copies = 8 });
394
- }