tigerbeetle-node 0.11.8 → 0.11.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.client.node.sha256 +1 -1
- package/package.json +4 -3
- package/scripts/build_lib.sh +41 -0
- package/src/node.zig +1 -1
- package/src/tigerbeetle/scripts/validate_docs.sh +7 -1
- package/src/tigerbeetle/src/benchmark.zig +3 -3
- package/src/tigerbeetle/src/config.zig +31 -16
- package/src/tigerbeetle/src/constants.zig +48 -9
- package/src/tigerbeetle/src/ewah.zig +5 -5
- package/src/tigerbeetle/src/ewah_fuzz.zig +1 -1
- package/src/tigerbeetle/src/lsm/binary_search.zig +1 -1
- package/src/tigerbeetle/src/lsm/bloom_filter.zig +1 -1
- package/src/tigerbeetle/src/lsm/compaction.zig +34 -21
- package/src/tigerbeetle/src/lsm/forest_fuzz.zig +84 -104
- package/src/tigerbeetle/src/lsm/grid.zig +19 -13
- package/src/tigerbeetle/src/lsm/manifest_log.zig +8 -10
- package/src/tigerbeetle/src/lsm/manifest_log_fuzz.zig +18 -13
- package/src/tigerbeetle/src/lsm/merge_iterator.zig +1 -1
- package/src/tigerbeetle/src/lsm/segmented_array.zig +17 -17
- package/src/tigerbeetle/src/lsm/segmented_array_fuzz.zig +1 -1
- package/src/tigerbeetle/src/lsm/set_associative_cache.zig +1 -1
- package/src/tigerbeetle/src/lsm/table.zig +8 -20
- package/src/tigerbeetle/src/lsm/table_immutable.zig +1 -1
- package/src/tigerbeetle/src/lsm/table_iterator.zig +3 -3
- package/src/tigerbeetle/src/lsm/table_mutable.zig +14 -2
- package/src/tigerbeetle/src/lsm/test.zig +5 -4
- package/src/tigerbeetle/src/lsm/tree.zig +1 -2
- package/src/tigerbeetle/src/lsm/tree_fuzz.zig +85 -115
- package/src/tigerbeetle/src/message_bus.zig +4 -4
- package/src/tigerbeetle/src/message_pool.zig +7 -10
- package/src/tigerbeetle/src/ring_buffer.zig +22 -12
- package/src/tigerbeetle/src/simulator.zig +366 -239
- package/src/tigerbeetle/src/state_machine/auditor.zig +5 -5
- package/src/tigerbeetle/src/state_machine/workload.zig +3 -3
- package/src/tigerbeetle/src/state_machine.zig +190 -178
- package/src/tigerbeetle/src/{util.zig → stdx.zig} +2 -0
- package/src/tigerbeetle/src/storage.zig +13 -6
- package/src/tigerbeetle/src/{test → testing/cluster}/message_bus.zig +3 -3
- package/src/tigerbeetle/src/{test → testing/cluster}/network.zig +46 -22
- package/src/tigerbeetle/src/testing/cluster/state_checker.zig +169 -0
- package/src/tigerbeetle/src/testing/cluster/storage_checker.zig +202 -0
- package/src/tigerbeetle/src/testing/cluster.zig +443 -0
- package/src/tigerbeetle/src/{test → testing}/fuzz.zig +0 -0
- package/src/tigerbeetle/src/testing/hash_log.zig +66 -0
- package/src/tigerbeetle/src/{test → testing}/id.zig +0 -0
- package/src/tigerbeetle/src/testing/packet_simulator.zig +365 -0
- package/src/tigerbeetle/src/{test → testing}/priority_queue.zig +1 -1
- package/src/tigerbeetle/src/testing/reply_sequence.zig +139 -0
- package/src/tigerbeetle/src/{test → testing}/state_machine.zig +3 -1
- package/src/tigerbeetle/src/testing/storage.zig +757 -0
- package/src/tigerbeetle/src/{test → testing}/table.zig +21 -0
- package/src/tigerbeetle/src/{test → testing}/time.zig +0 -0
- package/src/tigerbeetle/src/tigerbeetle.zig +2 -0
- package/src/tigerbeetle/src/tracer.zig +3 -3
- package/src/tigerbeetle/src/unit_tests.zig +4 -4
- package/src/tigerbeetle/src/vopr.zig +2 -2
- package/src/tigerbeetle/src/vsr/client.zig +5 -2
- package/src/tigerbeetle/src/vsr/clock.zig +93 -53
- package/src/tigerbeetle/src/vsr/journal.zig +109 -98
- package/src/tigerbeetle/src/vsr/journal_format_fuzz.zig +2 -2
- package/src/tigerbeetle/src/vsr/replica.zig +1983 -1430
- package/src/tigerbeetle/src/vsr/replica_format.zig +13 -13
- package/src/tigerbeetle/src/vsr/superblock.zig +240 -142
- package/src/tigerbeetle/src/vsr/superblock_client_table.zig +7 -7
- package/src/tigerbeetle/src/vsr/superblock_free_set.zig +1 -1
- package/src/tigerbeetle/src/vsr/superblock_free_set_fuzz.zig +1 -1
- package/src/tigerbeetle/src/vsr/superblock_fuzz.zig +49 -14
- package/src/tigerbeetle/src/vsr/superblock_manifest.zig +38 -19
- package/src/tigerbeetle/src/vsr/superblock_quorums.zig +48 -48
- package/src/tigerbeetle/src/vsr/superblock_quorums_fuzz.zig +51 -51
- package/src/tigerbeetle/src/vsr.zig +99 -33
- package/src/tigerbeetle/src/demo.zig +0 -132
- package/src/tigerbeetle/src/demo_01_create_accounts.zig +0 -35
- package/src/tigerbeetle/src/demo_02_lookup_accounts.zig +0 -7
- package/src/tigerbeetle/src/demo_03_create_transfers.zig +0 -37
- package/src/tigerbeetle/src/demo_04_create_pending_transfers.zig +0 -61
- package/src/tigerbeetle/src/demo_05_post_pending_transfers.zig +0 -37
- package/src/tigerbeetle/src/demo_06_void_pending_transfers.zig +0 -24
- package/src/tigerbeetle/src/demo_07_lookup_transfers.zig +0 -7
- package/src/tigerbeetle/src/test/cluster.zig +0 -352
- package/src/tigerbeetle/src/test/conductor.zig +0 -366
- package/src/tigerbeetle/src/test/packet_simulator.zig +0 -398
- package/src/tigerbeetle/src/test/state_checker.zig +0 -169
- package/src/tigerbeetle/src/test/storage.zig +0 -864
- package/src/tigerbeetle/src/test/storage_checker.zig +0 -204
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
//! * vsr_state
|
|
4
4
|
//! - vsr_state.commit_min is initially 0 (for a newly-formatted replica).
|
|
5
5
|
//! - vsr_state.commit_min ≤ vsr_state.commit_max
|
|
6
|
-
//! - vsr_state.
|
|
6
|
+
//! - vsr_state.log_view ≤ vsr_state.view
|
|
7
7
|
//! - checkpoint() must advance the superblock's vsr_state.commit_min.
|
|
8
8
|
//! - view_change() must not advance the superblock's vsr_state.commit_min.
|
|
9
9
|
//! - All fields of vsr_state except commit_min_checksum are monotonically increasing over
|
|
@@ -17,7 +17,7 @@ const meta = std.meta;
|
|
|
17
17
|
const os = std.os;
|
|
18
18
|
|
|
19
19
|
const constants = @import("../constants.zig");
|
|
20
|
-
const
|
|
20
|
+
const stdx = @import("../stdx.zig");
|
|
21
21
|
const vsr = @import("../vsr.zig");
|
|
22
22
|
const log = std.log.scoped(.superblock);
|
|
23
23
|
|
|
@@ -32,8 +32,11 @@ pub const Quorums = @import("superblock_quorums.zig").QuorumsType(.{
|
|
|
32
32
|
|
|
33
33
|
pub const SuperBlockVersion: u16 = 0;
|
|
34
34
|
|
|
35
|
+
const vsr_headers_reserved_size = constants.sector_size -
|
|
36
|
+
((constants.view_change_headers_max * @sizeOf(vsr.Header)) % constants.sector_size);
|
|
37
|
+
|
|
35
38
|
// Fields are aligned to work as an extern or packed struct.
|
|
36
|
-
pub const
|
|
39
|
+
pub const SuperBlockHeader = extern struct {
|
|
37
40
|
checksum: u128 = undefined,
|
|
38
41
|
|
|
39
42
|
/// Protects against misdirected reads at startup.
|
|
@@ -97,7 +100,19 @@ pub const SuperBlockSector = extern struct {
|
|
|
97
100
|
/// The size of the client table entries stored in the superblock trailer.
|
|
98
101
|
client_table_size: u32,
|
|
99
102
|
|
|
100
|
-
|
|
103
|
+
/// The number of headers in vsr_headers_all.
|
|
104
|
+
vsr_headers_count: u32,
|
|
105
|
+
|
|
106
|
+
reserved: [3144]u8 = [_]u8{0} ** 3144,
|
|
107
|
+
|
|
108
|
+
/// SV/DVC header suffix. Headers are ordered from high-to-low op.
|
|
109
|
+
/// Unoccupied headers (after vsr_headers_count) are zeroed.
|
|
110
|
+
///
|
|
111
|
+
/// When `vsr_state.log_view < vsr_state.view`, the headers are for a DVC.
|
|
112
|
+
/// When `vsr_state.log_view = vsr_state.view`, the headers are for a SV.
|
|
113
|
+
vsr_headers_all: [constants.view_change_headers_max]vsr.Header,
|
|
114
|
+
vsr_headers_reserved: [vsr_headers_reserved_size]u8 =
|
|
115
|
+
[_]u8{0} ** vsr_headers_reserved_size,
|
|
101
116
|
|
|
102
117
|
pub const VSRState = extern struct {
|
|
103
118
|
/// The vsr.Header.checksum of commit_min's message.
|
|
@@ -110,7 +125,7 @@ pub const SuperBlockSector = extern struct {
|
|
|
110
125
|
commit_max: u64,
|
|
111
126
|
|
|
112
127
|
/// The last view in which the replica's status was normal.
|
|
113
|
-
|
|
128
|
+
log_view: u32,
|
|
114
129
|
|
|
115
130
|
/// The view number of the replica.
|
|
116
131
|
view: u32,
|
|
@@ -128,25 +143,25 @@ pub const SuperBlockSector = extern struct {
|
|
|
128
143
|
.commit_min_checksum = vsr.Header.root_prepare(cluster).checksum,
|
|
129
144
|
.commit_min = 0,
|
|
130
145
|
.commit_max = 0,
|
|
131
|
-
.
|
|
146
|
+
.log_view = 0,
|
|
132
147
|
.view = 0,
|
|
133
148
|
};
|
|
134
149
|
}
|
|
135
150
|
|
|
136
151
|
pub fn internally_consistent(state: VSRState) bool {
|
|
137
|
-
return state.commit_max >= state.commit_min and state.view >= state.
|
|
152
|
+
return state.commit_max >= state.commit_min and state.view >= state.log_view;
|
|
138
153
|
}
|
|
139
154
|
|
|
140
155
|
pub fn monotonic(old: VSRState, new: VSRState) bool {
|
|
141
156
|
assert(old.internally_consistent());
|
|
142
157
|
assert(new.internally_consistent());
|
|
143
|
-
// The last case is for when checking monotonic() from the sequence=0
|
|
158
|
+
// The last case is for when checking monotonic() from the sequence=0 header.
|
|
144
159
|
assert(old.commit_min != new.commit_min or
|
|
145
160
|
old.commit_min_checksum == new.commit_min_checksum or
|
|
146
161
|
(old.commit_min_checksum == 0 and old.commit_min == 0));
|
|
147
162
|
|
|
148
163
|
if (old.view > new.view) return false;
|
|
149
|
-
if (old.
|
|
164
|
+
if (old.log_view > new.log_view) return false;
|
|
150
165
|
if (old.commit_min > new.commit_min) return false;
|
|
151
166
|
if (old.commit_max > new.commit_max) return false;
|
|
152
167
|
|
|
@@ -159,11 +174,6 @@ pub const SuperBlockSector = extern struct {
|
|
|
159
174
|
return !meta.eql(old, new);
|
|
160
175
|
}
|
|
161
176
|
|
|
162
|
-
pub fn update(state: *VSRState, new: VSRState) void {
|
|
163
|
-
assert(state.would_be_updated_by(new));
|
|
164
|
-
state.* = new;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
177
|
/// Compaction is one bar ahead of superblock's commit_min.
|
|
168
178
|
/// The commits from the bar following commit_min were in the mutable table, and
|
|
169
179
|
/// thus not preserved in the checkpoint.
|
|
@@ -205,14 +215,16 @@ pub const SuperBlockSector = extern struct {
|
|
|
205
215
|
};
|
|
206
216
|
|
|
207
217
|
comptime {
|
|
208
|
-
assert(@sizeOf(
|
|
218
|
+
assert(@sizeOf(SuperBlockHeader) % constants.sector_size == 0);
|
|
219
|
+
assert(@divExact(@sizeOf(SuperBlockHeader), constants.sector_size) >= 2);
|
|
220
|
+
assert(@offsetOf(SuperBlockHeader, "vsr_headers_all") == constants.sector_size);
|
|
209
221
|
// Assert that there is no implicit padding in the struct.
|
|
210
|
-
assert(@bitSizeOf(
|
|
222
|
+
assert(@bitSizeOf(SuperBlockHeader) == @sizeOf(SuperBlockHeader) * 8);
|
|
211
223
|
}
|
|
212
224
|
|
|
213
|
-
pub fn calculate_checksum(superblock: *const
|
|
214
|
-
comptime assert(meta.fieldIndex(
|
|
215
|
-
comptime assert(meta.fieldIndex(
|
|
225
|
+
pub fn calculate_checksum(superblock: *const SuperBlockHeader) u128 {
|
|
226
|
+
comptime assert(meta.fieldIndex(SuperBlockHeader, "checksum") == 0);
|
|
227
|
+
comptime assert(meta.fieldIndex(SuperBlockHeader, "copy") == 1);
|
|
216
228
|
|
|
217
229
|
const checksum_size = @sizeOf(@TypeOf(superblock.checksum));
|
|
218
230
|
comptime assert(checksum_size == @sizeOf(u128));
|
|
@@ -225,24 +237,33 @@ pub const SuperBlockSector = extern struct {
|
|
|
225
237
|
return vsr.checksum(std.mem.asBytes(superblock)[ignore_size..]);
|
|
226
238
|
}
|
|
227
239
|
|
|
228
|
-
pub fn set_checksum(superblock: *
|
|
240
|
+
pub fn set_checksum(superblock: *SuperBlockHeader) void {
|
|
229
241
|
assert(superblock.copy < constants.superblock_copies);
|
|
230
242
|
assert(superblock.version == SuperBlockVersion);
|
|
231
243
|
assert(superblock.flags == 0);
|
|
232
244
|
|
|
233
|
-
|
|
234
|
-
for (mem.bytesAsSlice(u64, superblock.reserved[4..])) |word| assert(word == 0);
|
|
245
|
+
for (mem.bytesAsSlice(u64, &superblock.reserved)) |word| assert(word == 0);
|
|
235
246
|
for (mem.bytesAsSlice(u64, &superblock.vsr_state.reserved)) |word| assert(word == 0);
|
|
247
|
+
for (mem.bytesAsSlice(u64, &superblock.vsr_headers_reserved)) |word| assert(word == 0);
|
|
236
248
|
|
|
237
249
|
superblock.checksum = superblock.calculate_checksum();
|
|
238
250
|
}
|
|
239
251
|
|
|
240
|
-
pub fn valid_checksum(superblock: *const
|
|
252
|
+
pub fn valid_checksum(superblock: *const SuperBlockHeader) bool {
|
|
241
253
|
return superblock.checksum == superblock.calculate_checksum();
|
|
242
254
|
}
|
|
243
255
|
|
|
244
256
|
/// Does not consider { checksum, copy } when comparing equality.
|
|
245
|
-
pub fn equal(a: *const
|
|
257
|
+
pub fn equal(a: *const SuperBlockHeader, b: *const SuperBlockHeader) bool {
|
|
258
|
+
for (mem.bytesAsSlice(u64, &a.reserved)) |word| assert(word == 0);
|
|
259
|
+
for (mem.bytesAsSlice(u64, &b.reserved)) |word| assert(word == 0);
|
|
260
|
+
|
|
261
|
+
for (mem.bytesAsSlice(u64, &a.vsr_state.reserved)) |word| assert(word == 0);
|
|
262
|
+
for (mem.bytesAsSlice(u64, &b.vsr_state.reserved)) |word| assert(word == 0);
|
|
263
|
+
|
|
264
|
+
for (mem.bytesAsSlice(u64, &a.vsr_headers_reserved)) |word| assert(word == 0);
|
|
265
|
+
for (mem.bytesAsSlice(u64, &b.vsr_headers_reserved)) |word| assert(word == 0);
|
|
266
|
+
|
|
246
267
|
if (a.version != b.version) return false;
|
|
247
268
|
if (a.replica != b.replica) return false;
|
|
248
269
|
if (a.cluster != b.cluster) return false;
|
|
@@ -258,17 +279,17 @@ pub const SuperBlockSector = extern struct {
|
|
|
258
279
|
if (!meta.eql(a.snapshots, b.snapshots)) return false;
|
|
259
280
|
if (a.manifest_size != b.manifest_size) return false;
|
|
260
281
|
if (a.free_set_size != b.free_set_size) return false;
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
assert(@bitCast(u32, b.reserved[0..4].*) == 0);
|
|
264
|
-
for (mem.bytesAsSlice(u64, a.reserved[4..])) |word| assert(word == 0);
|
|
265
|
-
for (mem.bytesAsSlice(u64, b.reserved[4..])) |word| assert(word == 0);
|
|
266
|
-
|
|
267
|
-
for (mem.bytesAsSlice(u64, &a.vsr_state.reserved)) |word| assert(word == 0);
|
|
268
|
-
for (mem.bytesAsSlice(u64, &b.vsr_state.reserved)) |word| assert(word == 0);
|
|
282
|
+
if (a.vsr_headers_count != b.vsr_headers_count) return false;
|
|
283
|
+
if (!meta.eql(a.vsr_headers_all, b.vsr_headers_all)) return false;
|
|
269
284
|
|
|
270
285
|
return true;
|
|
271
286
|
}
|
|
287
|
+
|
|
288
|
+
pub fn vsr_headers(superblock: *const SuperBlockHeader) vsr.ViewChangeHeaders {
|
|
289
|
+
return vsr.ViewChangeHeaders.init(
|
|
290
|
+
superblock.vsr_headers_all[0..superblock.vsr_headers_count],
|
|
291
|
+
);
|
|
292
|
+
}
|
|
272
293
|
};
|
|
273
294
|
|
|
274
295
|
comptime {
|
|
@@ -282,12 +303,12 @@ comptime {
|
|
|
282
303
|
pub const superblock_zone_size = superblock_copy_size * constants.superblock_copies;
|
|
283
304
|
|
|
284
305
|
/// The size of an individual superblock including trailer.
|
|
285
|
-
pub const superblock_copy_size = @sizeOf(
|
|
306
|
+
pub const superblock_copy_size = @sizeOf(SuperBlockHeader) + superblock_trailer_size_max;
|
|
286
307
|
comptime {
|
|
287
308
|
assert(superblock_copy_size % constants.sector_size == 0);
|
|
288
309
|
}
|
|
289
310
|
|
|
290
|
-
/// The maximum possible size of the superblock trailer, following the superblock
|
|
311
|
+
/// The maximum possible size of the superblock trailer, following the superblock header.
|
|
291
312
|
pub const superblock_trailer_size_max = blk: {
|
|
292
313
|
// To calculate the size of the superblock trailer we need to know:
|
|
293
314
|
// 1. the maximum number of manifest blocks that should be able to be referenced, and
|
|
@@ -312,7 +333,7 @@ pub const superblock_trailer_size_max = blk: {
|
|
|
312
333
|
|
|
313
334
|
// A manifest block reference of 40 bytes contains a tree hash, checksum, and address.
|
|
314
335
|
// These references are stored in struct-of-arrays layout in the trailer for the sake of alignment.
|
|
315
|
-
|
|
336
|
+
const superblock_trailer_manifest_size_max = blk: {
|
|
316
337
|
assert(SuperBlockManifest.BlockReferenceSize == 16 + 16 + 8);
|
|
317
338
|
|
|
318
339
|
// Use a multiple of sector * reference so that the size is exactly divisible without padding:
|
|
@@ -321,14 +342,14 @@ pub const superblock_trailer_manifest_size_max = blk: {
|
|
|
321
342
|
break :blk 16 * constants.sector_size * SuperBlockManifest.BlockReferenceSize;
|
|
322
343
|
};
|
|
323
344
|
|
|
324
|
-
|
|
345
|
+
const superblock_trailer_free_set_size_max = blk: {
|
|
325
346
|
const encode_size_max = SuperBlockFreeSet.encode_size_max(block_count_max);
|
|
326
347
|
assert(encode_size_max > 0);
|
|
327
348
|
|
|
328
349
|
break :blk vsr.sector_ceil(encode_size_max);
|
|
329
350
|
};
|
|
330
351
|
|
|
331
|
-
|
|
352
|
+
const superblock_trailer_client_table_size_max = blk: {
|
|
332
353
|
const encode_size_max = SuperBlockClientTable.encode_size_max;
|
|
333
354
|
assert(encode_size_max > 0);
|
|
334
355
|
|
|
@@ -342,7 +363,7 @@ pub const data_file_size_min = blk: {
|
|
|
342
363
|
/// The maximum number of blocks in the grid.
|
|
343
364
|
const block_count_max = blk: {
|
|
344
365
|
var size = constants.storage_size_max;
|
|
345
|
-
size -= constants.superblock_copies * @sizeOf(
|
|
366
|
+
size -= constants.superblock_copies * @sizeOf(SuperBlockHeader);
|
|
346
367
|
size -= constants.superblock_copies * superblock_trailer_client_table_size_max;
|
|
347
368
|
size -= constants.superblock_copies * superblock_trailer_manifest_size_max;
|
|
348
369
|
size -= constants.journal_size_max;
|
|
@@ -366,11 +387,11 @@ comptime {
|
|
|
366
387
|
assert(block_count_max * constants.block_size + data_file_size_min <= constants.storage_size_max);
|
|
367
388
|
}
|
|
368
389
|
|
|
369
|
-
/// This table shows the sequence number progression of the SuperBlock's
|
|
390
|
+
/// This table shows the sequence number progression of the SuperBlock's headers.
|
|
370
391
|
///
|
|
371
392
|
/// action working staging disk
|
|
372
393
|
/// format seq seq seq
|
|
373
|
-
/// 0 - Initially the file has no
|
|
394
|
+
/// 0 - Initially the file has no headers.
|
|
374
395
|
/// 0 1 -
|
|
375
396
|
/// 0 1 1 Write a copyset for the first sequence.
|
|
376
397
|
/// 1 1 1 Read quorum; verify 3/4 are valid.
|
|
@@ -418,7 +439,9 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
418
439
|
read_threshold: ?Quorums.Threshold = null,
|
|
419
440
|
copy: ?u8 = null,
|
|
420
441
|
/// Used by format(), checkpoint(), and view_change().
|
|
421
|
-
vsr_state: ?
|
|
442
|
+
vsr_state: ?SuperBlockHeader.VSRState = null,
|
|
443
|
+
/// Used by format() and view_change().
|
|
444
|
+
vsr_headers: ?vsr.ViewChangeHeaders.BoundedArray = null,
|
|
422
445
|
repairs: ?Quorums.RepairIterator = null, // Used by open().
|
|
423
446
|
};
|
|
424
447
|
|
|
@@ -431,15 +454,15 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
431
454
|
storage_size: u64 = superblock_zone_size,
|
|
432
455
|
|
|
433
456
|
/// The superblock that was recovered at startup after a crash or that was last written.
|
|
434
|
-
working: *align(constants.sector_size)
|
|
457
|
+
working: *align(constants.sector_size) SuperBlockHeader,
|
|
435
458
|
|
|
436
459
|
/// The superblock that will replace the current working superblock once written.
|
|
437
460
|
/// We cannot mutate any working state directly until it is safely on stable storage.
|
|
438
461
|
/// Otherwise, we may accidentally externalize guarantees that are not yet durable.
|
|
439
|
-
staging: *align(constants.sector_size)
|
|
462
|
+
staging: *align(constants.sector_size) SuperBlockHeader,
|
|
440
463
|
|
|
441
464
|
/// The copies that we read into at startup or when verifying the written superblock.
|
|
442
|
-
reading: []align(constants.sector_size)
|
|
465
|
+
reading: []align(constants.sector_size) SuperBlockHeader,
|
|
443
466
|
|
|
444
467
|
/// It might seem that, at startup, we simply install the copy with the highest sequence.
|
|
445
468
|
///
|
|
@@ -474,7 +497,7 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
474
497
|
/// other operations, only the following queue combinations are allowed:
|
|
475
498
|
/// 1. A view change may queue on a checkpoint.
|
|
476
499
|
/// 2. A checkpoint may queue on a view change.
|
|
477
|
-
///
|
|
500
|
+
///
|
|
478
501
|
/// There may only be a single caller queued at a time, to ensure that the VSR protocol is
|
|
479
502
|
/// careful to submit at most one view change at a time.
|
|
480
503
|
queue_head: ?*Context = null,
|
|
@@ -498,14 +521,14 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
498
521
|
const block_count_limit = shard_count_limit * FreeSet.shard_bits;
|
|
499
522
|
assert(block_count_limit <= block_count_max);
|
|
500
523
|
|
|
501
|
-
const a = try allocator.allocAdvanced(
|
|
524
|
+
const a = try allocator.allocAdvanced(SuperBlockHeader, constants.sector_size, 1, .exact);
|
|
502
525
|
errdefer allocator.free(a);
|
|
503
526
|
|
|
504
|
-
const b = try allocator.allocAdvanced(
|
|
527
|
+
const b = try allocator.allocAdvanced(SuperBlockHeader, constants.sector_size, 1, .exact);
|
|
505
528
|
errdefer allocator.free(b);
|
|
506
529
|
|
|
507
530
|
const reading = try allocator.allocAdvanced(
|
|
508
|
-
[constants.superblock_copies]
|
|
531
|
+
[constants.superblock_copies]SuperBlockHeader,
|
|
509
532
|
constants.sector_size,
|
|
510
533
|
1,
|
|
511
534
|
.exact,
|
|
@@ -615,16 +638,18 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
615
638
|
.commit_min_checksum = 0,
|
|
616
639
|
.commit_min = 0,
|
|
617
640
|
.commit_max = 0,
|
|
618
|
-
.
|
|
641
|
+
.log_view = 0,
|
|
619
642
|
.view = 0,
|
|
620
643
|
},
|
|
621
644
|
.snapshots = undefined,
|
|
622
645
|
.manifest_size = 0,
|
|
623
646
|
.free_set_size = 0,
|
|
624
647
|
.client_table_size = 0,
|
|
648
|
+
.vsr_headers_count = 0,
|
|
649
|
+
.vsr_headers_all = mem.zeroes([constants.view_change_headers_max]vsr.Header),
|
|
625
650
|
};
|
|
626
651
|
|
|
627
|
-
mem.set(
|
|
652
|
+
mem.set(SuperBlockHeader.Snapshot, &superblock.working.snapshots, .{
|
|
628
653
|
.created = 0,
|
|
629
654
|
.queried = 0,
|
|
630
655
|
.timeout = 0,
|
|
@@ -632,11 +657,15 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
632
657
|
|
|
633
658
|
superblock.working.set_checksum();
|
|
634
659
|
|
|
660
|
+
var vsr_headers = vsr.ViewChangeHeaders.BoundedArray{ .buffer = undefined };
|
|
661
|
+
vsr_headers.appendAssumeCapacity(vsr.Header.root_prepare(options.cluster));
|
|
662
|
+
|
|
635
663
|
context.* = .{
|
|
636
664
|
.superblock = superblock,
|
|
637
665
|
.callback = callback,
|
|
638
666
|
.caller = .format,
|
|
639
|
-
.vsr_state =
|
|
667
|
+
.vsr_state = SuperBlockHeader.VSRState.root(options.cluster),
|
|
668
|
+
.vsr_headers = vsr_headers,
|
|
640
669
|
};
|
|
641
670
|
|
|
642
671
|
// TODO At a higher layer, we must:
|
|
@@ -662,21 +691,33 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
662
691
|
superblock.acquire(context);
|
|
663
692
|
}
|
|
664
693
|
|
|
694
|
+
const UpdateCheckpoint = struct {
|
|
695
|
+
commit_min_checksum: u128,
|
|
696
|
+
commit_min: u64,
|
|
697
|
+
commit_max: u64,
|
|
698
|
+
};
|
|
699
|
+
|
|
665
700
|
/// The vsr_state must update the commit_min and commit_min_checksum.
|
|
666
|
-
|
|
667
|
-
// change? If not, forbid it.
|
|
701
|
+
/// The vsr_state must not update view/log_view.
|
|
668
702
|
pub fn checkpoint(
|
|
669
703
|
superblock: *SuperBlock,
|
|
670
704
|
callback: fn (context: *Context) void,
|
|
671
705
|
context: *Context,
|
|
672
|
-
|
|
706
|
+
update: UpdateCheckpoint,
|
|
673
707
|
) void {
|
|
674
708
|
assert(superblock.opened);
|
|
675
|
-
|
|
709
|
+
assert(superblock.staging.vsr_state.commit_min < update.commit_min);
|
|
710
|
+
assert(superblock.staging.vsr_state.commit_min_checksum != update.commit_min_checksum);
|
|
711
|
+
assert(update.commit_min <= update.commit_max);
|
|
712
|
+
|
|
713
|
+
const vsr_state = SuperBlockHeader.VSRState{
|
|
714
|
+
.commit_min_checksum = update.commit_min_checksum,
|
|
715
|
+
.commit_min = update.commit_min,
|
|
716
|
+
.commit_max = update.commit_max,
|
|
717
|
+
.log_view = superblock.staging.vsr_state.log_view,
|
|
718
|
+
.view = superblock.staging.vsr_state.view,
|
|
719
|
+
};
|
|
676
720
|
assert(superblock.staging.vsr_state.would_be_updated_by(vsr_state));
|
|
677
|
-
assert(superblock.staging.vsr_state.commit_min < vsr_state.commit_min);
|
|
678
|
-
assert(superblock.staging.vsr_state.commit_min_checksum !=
|
|
679
|
-
vsr_state.commit_min_checksum);
|
|
680
721
|
|
|
681
722
|
context.* = .{
|
|
682
723
|
.superblock = superblock,
|
|
@@ -688,59 +729,71 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
688
729
|
superblock.acquire(context);
|
|
689
730
|
}
|
|
690
731
|
|
|
691
|
-
|
|
732
|
+
const UpdateViewChange = struct {
|
|
733
|
+
commit_max: u64,
|
|
734
|
+
log_view: u32,
|
|
735
|
+
view: u32,
|
|
736
|
+
headers: vsr.ViewChangeHeaders.BoundedArray,
|
|
737
|
+
};
|
|
738
|
+
|
|
739
|
+
/// The replica calls view_change() to persist its view/log_view — it cannot
|
|
740
|
+
/// advertise either value until it is certain they will never backtrack.
|
|
741
|
+
///
|
|
742
|
+
/// The update must advance view/log_view (monotonically increasing).
|
|
692
743
|
pub fn view_change(
|
|
693
744
|
superblock: *SuperBlock,
|
|
694
745
|
callback: fn (context: *Context) void,
|
|
695
746
|
context: *Context,
|
|
696
|
-
|
|
747
|
+
update: UpdateViewChange,
|
|
697
748
|
) void {
|
|
698
749
|
assert(superblock.opened);
|
|
699
|
-
assert(vsr_state.commit_min
|
|
700
|
-
assert(vsr_state.
|
|
701
|
-
|
|
750
|
+
assert(superblock.staging.vsr_state.commit_min <= update.headers.get(0).op);
|
|
751
|
+
assert(superblock.staging.vsr_state.commit_max <= update.commit_max);
|
|
752
|
+
assert(superblock.staging.vsr_state.view <= update.view);
|
|
753
|
+
assert(superblock.staging.vsr_state.log_view <= update.log_view);
|
|
754
|
+
assert(superblock.staging.vsr_state.log_view < update.log_view or
|
|
755
|
+
superblock.staging.vsr_state.view < update.view);
|
|
756
|
+
|
|
757
|
+
vsr.ViewChangeHeaders.verify(update.headers.constSlice());
|
|
758
|
+
assert(update.view >= update.log_view);
|
|
759
|
+
|
|
760
|
+
const vsr_state = SuperBlockHeader.VSRState{
|
|
761
|
+
.commit_min_checksum = superblock.staging.vsr_state.commit_min_checksum,
|
|
762
|
+
.commit_min = superblock.staging.vsr_state.commit_min,
|
|
763
|
+
.commit_max = update.commit_max,
|
|
764
|
+
.log_view = update.log_view,
|
|
765
|
+
.view = update.view,
|
|
766
|
+
};
|
|
767
|
+
assert(vsr_state.internally_consistent());
|
|
768
|
+
assert(superblock.staging.vsr_state.would_be_updated_by(vsr_state));
|
|
702
769
|
assert(superblock.staging.vsr_state.monotonic(vsr_state));
|
|
703
770
|
|
|
704
|
-
log.debug(
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
.{
|
|
708
|
-
superblock.staging.vsr_state.commit_min_checksum,
|
|
709
|
-
vsr_state.commit_min_checksum,
|
|
710
|
-
|
|
711
|
-
superblock.staging.vsr_state.commit_min,
|
|
712
|
-
vsr_state.commit_min,
|
|
771
|
+
log.debug("view_change: commit_max={}..{} log_view={}..{} view={}..{} head={}..{}", .{
|
|
772
|
+
superblock.staging.vsr_state.commit_max,
|
|
773
|
+
update.commit_max,
|
|
713
774
|
|
|
714
|
-
|
|
715
|
-
|
|
775
|
+
superblock.staging.vsr_state.log_view,
|
|
776
|
+
update.log_view,
|
|
716
777
|
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
superblock.staging.vsr_state.view,
|
|
721
|
-
vsr_state.view,
|
|
722
|
-
},
|
|
723
|
-
);
|
|
778
|
+
superblock.staging.vsr_state.view,
|
|
779
|
+
update.view,
|
|
724
780
|
|
|
725
|
-
|
|
781
|
+
superblock.staging.vsr_headers().slice[0].checksum,
|
|
782
|
+
update.headers.get(0).checksum,
|
|
783
|
+
});
|
|
726
784
|
|
|
727
785
|
context.* = .{
|
|
728
786
|
.superblock = superblock,
|
|
729
787
|
.callback = callback,
|
|
730
788
|
.caller = .view_change,
|
|
731
789
|
.vsr_state = vsr_state,
|
|
790
|
+
.vsr_headers = update.headers,
|
|
732
791
|
};
|
|
733
792
|
|
|
734
|
-
if (!superblock.staging.vsr_state.would_be_updated_by(context.vsr_state.?)) {
|
|
735
|
-
log.debug("view_change: no change", .{});
|
|
736
|
-
callback(context);
|
|
737
|
-
return;
|
|
738
|
-
}
|
|
739
|
-
|
|
740
793
|
superblock.acquire(context);
|
|
741
794
|
}
|
|
742
795
|
|
|
743
|
-
pub fn view_change_in_progress(superblock: *SuperBlock) bool {
|
|
796
|
+
pub fn view_change_in_progress(superblock: *const SuperBlock) bool {
|
|
744
797
|
assert(superblock.opened);
|
|
745
798
|
|
|
746
799
|
if (superblock.queue_head) |head| {
|
|
@@ -768,7 +821,26 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
768
821
|
superblock.staging.* = superblock.working.*;
|
|
769
822
|
superblock.staging.sequence = superblock.staging.sequence + 1;
|
|
770
823
|
superblock.staging.parent = superblock.staging.checksum;
|
|
771
|
-
superblock.staging.vsr_state
|
|
824
|
+
superblock.staging.vsr_state = context.vsr_state.?;
|
|
825
|
+
|
|
826
|
+
if (context.vsr_headers) |headers| {
|
|
827
|
+
assert(context.caller == .format or context.caller == .view_change);
|
|
828
|
+
|
|
829
|
+
superblock.staging.vsr_headers_count = @intCast(u32, headers.len);
|
|
830
|
+
stdx.copy_disjoint(
|
|
831
|
+
.exact,
|
|
832
|
+
vsr.Header,
|
|
833
|
+
superblock.staging.vsr_headers_all[0..headers.len],
|
|
834
|
+
headers.constSlice(),
|
|
835
|
+
);
|
|
836
|
+
std.mem.set(
|
|
837
|
+
vsr.Header,
|
|
838
|
+
superblock.staging.vsr_headers_all[headers.len..],
|
|
839
|
+
std.mem.zeroes(vsr.Header),
|
|
840
|
+
);
|
|
841
|
+
} else {
|
|
842
|
+
assert(context.caller == .checkpoint);
|
|
843
|
+
}
|
|
772
844
|
|
|
773
845
|
if (context.caller != .view_change) {
|
|
774
846
|
superblock.write_staging_encode_manifest();
|
|
@@ -779,14 +851,14 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
779
851
|
|
|
780
852
|
context.copy = 0;
|
|
781
853
|
if (context.caller == .view_change) {
|
|
782
|
-
superblock.
|
|
854
|
+
superblock.write_header(context);
|
|
783
855
|
} else {
|
|
784
856
|
superblock.write_manifest(context);
|
|
785
857
|
}
|
|
786
858
|
}
|
|
787
859
|
|
|
788
860
|
fn write_staging_encode_manifest(superblock: *SuperBlock) void {
|
|
789
|
-
const staging: *
|
|
861
|
+
const staging: *SuperBlockHeader = superblock.staging;
|
|
790
862
|
const target = superblock.manifest_buffer;
|
|
791
863
|
|
|
792
864
|
staging.manifest_size = @intCast(u32, superblock.manifest.encode(target));
|
|
@@ -794,7 +866,7 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
794
866
|
}
|
|
795
867
|
|
|
796
868
|
fn write_staging_encode_free_set(superblock: *SuperBlock) void {
|
|
797
|
-
const staging: *
|
|
869
|
+
const staging: *SuperBlockHeader = superblock.staging;
|
|
798
870
|
const encode_size_max = FreeSet.encode_size_max(superblock.block_count_limit);
|
|
799
871
|
const target = superblock.free_set_buffer[0..encode_size_max];
|
|
800
872
|
|
|
@@ -824,7 +896,7 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
824
896
|
}
|
|
825
897
|
|
|
826
898
|
fn write_staging_encode_client_table(superblock: *SuperBlock) void {
|
|
827
|
-
const staging: *
|
|
899
|
+
const staging: *SuperBlockHeader = superblock.staging;
|
|
828
900
|
const target = superblock.client_table_buffer;
|
|
829
901
|
|
|
830
902
|
staging.client_table_size = @intCast(u32, superblock.client_table.encode(target));
|
|
@@ -838,7 +910,7 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
838
910
|
assert(size <= superblock_trailer_manifest_size_max);
|
|
839
911
|
|
|
840
912
|
const buffer = superblock.manifest_buffer[0..size];
|
|
841
|
-
const offset =
|
|
913
|
+
const offset = areas.manifest.offset(context.copy.?);
|
|
842
914
|
|
|
843
915
|
mem.set(u8, buffer[superblock.staging.manifest_size..], 0); // Zero sector padding.
|
|
844
916
|
|
|
@@ -881,7 +953,7 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
881
953
|
assert(size <= superblock_trailer_free_set_size_max);
|
|
882
954
|
|
|
883
955
|
const buffer = superblock.free_set_buffer[0..size];
|
|
884
|
-
const offset =
|
|
956
|
+
const offset = areas.free_set.offset(context.copy.?);
|
|
885
957
|
|
|
886
958
|
mem.set(u8, buffer[superblock.staging.free_set_size..], 0); // Zero sector padding.
|
|
887
959
|
|
|
@@ -924,7 +996,7 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
924
996
|
assert(size <= superblock_trailer_client_table_size_max);
|
|
925
997
|
|
|
926
998
|
const buffer = superblock.client_table_buffer[0..size];
|
|
927
|
-
const offset =
|
|
999
|
+
const offset = areas.client_table.offset(context.copy.?);
|
|
928
1000
|
|
|
929
1001
|
mem.set(u8, buffer[superblock.staging.client_table_size..], 0); // Zero sector padding.
|
|
930
1002
|
|
|
@@ -957,10 +1029,10 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
957
1029
|
|
|
958
1030
|
fn write_client_table_callback(write: *Storage.Write) void {
|
|
959
1031
|
const context = @fieldParentPtr(Context, "write", write);
|
|
960
|
-
context.superblock.
|
|
1032
|
+
context.superblock.write_header(context);
|
|
961
1033
|
}
|
|
962
1034
|
|
|
963
|
-
fn
|
|
1035
|
+
fn write_header(superblock: *SuperBlock, context: *Context) void {
|
|
964
1036
|
assert(superblock.queue_head == context);
|
|
965
1037
|
|
|
966
1038
|
// We update the working superblock for a checkpoint/format/view_change:
|
|
@@ -986,9 +1058,9 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
986
1058
|
assert(superblock.staging.valid_checksum());
|
|
987
1059
|
|
|
988
1060
|
const buffer = mem.asBytes(superblock.staging);
|
|
989
|
-
const offset =
|
|
1061
|
+
const offset = areas.header.offset(context.copy.?);
|
|
990
1062
|
|
|
991
|
-
log.debug("{}: {s}:
|
|
1063
|
+
log.debug("{}: {s}: write_header: checksum={x} sequence={} copy={} size={} offset={}", .{
|
|
992
1064
|
superblock.staging.replica,
|
|
993
1065
|
@tagName(context.caller),
|
|
994
1066
|
superblock.staging.checksum,
|
|
@@ -1001,7 +1073,7 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
1001
1073
|
superblock.assert_bounds(offset, buffer.len);
|
|
1002
1074
|
|
|
1003
1075
|
superblock.storage.write_sectors(
|
|
1004
|
-
|
|
1076
|
+
write_header_callback,
|
|
1005
1077
|
&context.write,
|
|
1006
1078
|
buffer,
|
|
1007
1079
|
.superblock,
|
|
@@ -1009,7 +1081,7 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
1009
1081
|
);
|
|
1010
1082
|
}
|
|
1011
1083
|
|
|
1012
|
-
fn
|
|
1084
|
+
fn write_header_callback(write: *Storage.Write) void {
|
|
1013
1085
|
const context = @fieldParentPtr(Context, "write", write);
|
|
1014
1086
|
const superblock = context.superblock;
|
|
1015
1087
|
const copy = context.copy.?;
|
|
@@ -1034,7 +1106,7 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
1034
1106
|
switch (context.caller) {
|
|
1035
1107
|
.open => unreachable,
|
|
1036
1108
|
.format, .checkpoint => superblock.write_manifest(context),
|
|
1037
|
-
.view_change => superblock.
|
|
1109
|
+
.view_change => superblock.write_header(context),
|
|
1038
1110
|
}
|
|
1039
1111
|
}
|
|
1040
1112
|
}
|
|
@@ -1056,18 +1128,18 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
1056
1128
|
context.copy = 0;
|
|
1057
1129
|
context.read_threshold = threshold;
|
|
1058
1130
|
for (superblock.reading) |*copy| copy.* = undefined;
|
|
1059
|
-
superblock.
|
|
1131
|
+
superblock.read_header(context);
|
|
1060
1132
|
}
|
|
1061
1133
|
|
|
1062
|
-
fn
|
|
1134
|
+
fn read_header(superblock: *SuperBlock, context: *Context) void {
|
|
1063
1135
|
assert(superblock.queue_head == context);
|
|
1064
1136
|
assert(context.copy.? < constants.superblock_copies);
|
|
1065
1137
|
assert(context.read_threshold != null);
|
|
1066
1138
|
|
|
1067
1139
|
const buffer = mem.asBytes(&superblock.reading[context.copy.?]);
|
|
1068
|
-
const offset =
|
|
1140
|
+
const offset = areas.header.offset(context.copy.?);
|
|
1069
1141
|
|
|
1070
|
-
log.debug("{s}:
|
|
1142
|
+
log.debug("{s}: read_header: copy={} size={} offset={}", .{
|
|
1071
1143
|
@tagName(context.caller),
|
|
1072
1144
|
context.copy.?,
|
|
1073
1145
|
buffer.len,
|
|
@@ -1077,7 +1149,7 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
1077
1149
|
superblock.assert_bounds(offset, buffer.len);
|
|
1078
1150
|
|
|
1079
1151
|
superblock.storage.read_sectors(
|
|
1080
|
-
|
|
1152
|
+
read_header_callback,
|
|
1081
1153
|
&context.read,
|
|
1082
1154
|
buffer,
|
|
1083
1155
|
.superblock,
|
|
@@ -1085,7 +1157,7 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
1085
1157
|
);
|
|
1086
1158
|
}
|
|
1087
1159
|
|
|
1088
|
-
fn
|
|
1160
|
+
fn read_header_callback(read: *Storage.Read) void {
|
|
1089
1161
|
const context = @fieldParentPtr(Context, "read", read);
|
|
1090
1162
|
const superblock = context.superblock;
|
|
1091
1163
|
const threshold = context.read_threshold.?;
|
|
@@ -1095,7 +1167,7 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
1095
1167
|
assert(context.copy.? < constants.superblock_copies);
|
|
1096
1168
|
if (context.copy.? + 1 != constants.superblock_copies) {
|
|
1097
1169
|
context.copy = context.copy.? + 1;
|
|
1098
|
-
superblock.
|
|
1170
|
+
superblock.read_header(context);
|
|
1099
1171
|
return;
|
|
1100
1172
|
}
|
|
1101
1173
|
|
|
@@ -1105,9 +1177,9 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
1105
1177
|
if (superblock.quorums.working(superblock.reading, threshold)) |quorum| {
|
|
1106
1178
|
assert(quorum.valid);
|
|
1107
1179
|
assert(quorum.copies.count() >= threshold.count());
|
|
1108
|
-
assert(quorum.
|
|
1180
|
+
assert(quorum.header.storage_size_max == constants.storage_size_max);
|
|
1109
1181
|
|
|
1110
|
-
const working = quorum.
|
|
1182
|
+
const working = quorum.header;
|
|
1111
1183
|
if (threshold == .verify) {
|
|
1112
1184
|
if (working.checksum != superblock.staging.checksum) {
|
|
1113
1185
|
@panic("superblock failed verification after writing");
|
|
@@ -1125,8 +1197,9 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
1125
1197
|
vsr.Header.root_prepare(working.cluster).checksum);
|
|
1126
1198
|
assert(working.vsr_state.commit_min == 0);
|
|
1127
1199
|
assert(working.vsr_state.commit_max == 0);
|
|
1128
|
-
assert(working.vsr_state.
|
|
1200
|
+
assert(working.vsr_state.log_view == 0);
|
|
1129
1201
|
assert(working.vsr_state.view == 0);
|
|
1202
|
+
assert(working.vsr_headers_count == 1);
|
|
1130
1203
|
} else if (context.caller == .checkpoint) {
|
|
1131
1204
|
superblock.free_set.checkpoint();
|
|
1132
1205
|
}
|
|
@@ -1137,7 +1210,7 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
1137
1210
|
"{s}: installed working superblock: checksum={x} sequence={} cluster={} " ++
|
|
1138
1211
|
"replica={} size={} " ++
|
|
1139
1212
|
"commit_min_checksum={} commit_min={} commit_max={} " ++
|
|
1140
|
-
"
|
|
1213
|
+
"log_view={} view={}",
|
|
1141
1214
|
.{
|
|
1142
1215
|
@tagName(context.caller),
|
|
1143
1216
|
superblock.working.checksum,
|
|
@@ -1148,10 +1221,17 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
1148
1221
|
superblock.working.vsr_state.commit_min_checksum,
|
|
1149
1222
|
superblock.working.vsr_state.commit_min,
|
|
1150
1223
|
superblock.working.vsr_state.commit_max,
|
|
1151
|
-
superblock.working.vsr_state.
|
|
1224
|
+
superblock.working.vsr_state.log_view,
|
|
1152
1225
|
superblock.working.vsr_state.view,
|
|
1153
1226
|
},
|
|
1154
1227
|
);
|
|
1228
|
+
for (superblock.working.vsr_headers().slice) |*header| {
|
|
1229
|
+
log.debug("{s}: vsr_header: op={} checksum={}", .{
|
|
1230
|
+
@tagName(context.caller),
|
|
1231
|
+
header.op,
|
|
1232
|
+
header.checksum,
|
|
1233
|
+
});
|
|
1234
|
+
}
|
|
1155
1235
|
|
|
1156
1236
|
if (context.caller == .open) {
|
|
1157
1237
|
if (context.repairs) |_| {
|
|
@@ -1187,7 +1267,7 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
1187
1267
|
assert(size <= superblock_trailer_manifest_size_max);
|
|
1188
1268
|
|
|
1189
1269
|
const buffer = superblock.manifest_buffer[0..size];
|
|
1190
|
-
const offset =
|
|
1270
|
+
const offset = areas.manifest.offset(context.copy.?);
|
|
1191
1271
|
|
|
1192
1272
|
log.debug("{s}: read_manifest: copy={} size={} offset={}", .{
|
|
1193
1273
|
@tagName(context.caller),
|
|
@@ -1236,12 +1316,14 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
1236
1316
|
// We do not repair padding.
|
|
1237
1317
|
context.copy = 0;
|
|
1238
1318
|
superblock.read_free_set(context);
|
|
1239
|
-
} else if (copy + 1 == constants.superblock_copies) {
|
|
1240
|
-
@panic("superblock manifest lost");
|
|
1241
1319
|
} else {
|
|
1242
1320
|
log.debug("open: read_manifest: corrupt copy={}", .{copy});
|
|
1243
|
-
|
|
1244
|
-
|
|
1321
|
+
if (copy + 1 == constants.superblock_copies) {
|
|
1322
|
+
@panic("superblock manifest lost");
|
|
1323
|
+
} else {
|
|
1324
|
+
context.copy = copy + 1;
|
|
1325
|
+
superblock.read_manifest(context);
|
|
1326
|
+
}
|
|
1245
1327
|
}
|
|
1246
1328
|
}
|
|
1247
1329
|
|
|
@@ -1254,7 +1336,7 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
1254
1336
|
assert(size <= superblock_trailer_free_set_size_max);
|
|
1255
1337
|
|
|
1256
1338
|
const buffer = superblock.free_set_buffer[0..size];
|
|
1257
|
-
const offset =
|
|
1339
|
+
const offset = areas.free_set.offset(context.copy.?);
|
|
1258
1340
|
|
|
1259
1341
|
log.debug("{s}: read_free_set: copy={} size={} offset={}", .{
|
|
1260
1342
|
@tagName(context.caller),
|
|
@@ -1328,7 +1410,7 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
1328
1410
|
assert(size <= superblock_trailer_client_table_size_max);
|
|
1329
1411
|
|
|
1330
1412
|
const buffer = superblock.client_table_buffer[0..size];
|
|
1331
|
-
const offset =
|
|
1413
|
+
const offset = areas.client_table.offset(context.copy.?);
|
|
1332
1414
|
|
|
1333
1415
|
log.debug("{s}: read_client_table: copy={} size={} offset={}", .{
|
|
1334
1416
|
@tagName(context.caller),
|
|
@@ -1497,32 +1579,48 @@ pub fn SuperBlockType(comptime Storage: type) type {
|
|
|
1497
1579
|
};
|
|
1498
1580
|
}
|
|
1499
1581
|
|
|
1500
|
-
pub const
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1582
|
+
pub const Area = enum {
|
|
1583
|
+
header,
|
|
1584
|
+
manifest,
|
|
1585
|
+
free_set,
|
|
1586
|
+
client_table,
|
|
1587
|
+
};
|
|
1505
1588
|
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1589
|
+
pub const areas = struct {
|
|
1590
|
+
pub const header = AreaRange{
|
|
1591
|
+
.base = 0,
|
|
1592
|
+
.size_max = @sizeOf(SuperBlockHeader),
|
|
1593
|
+
};
|
|
1510
1594
|
|
|
1511
|
-
pub
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
}
|
|
1595
|
+
pub const manifest = AreaRange{
|
|
1596
|
+
.base = header.base + header.size_max,
|
|
1597
|
+
.size_max = superblock_trailer_manifest_size_max, // TODO inline these constants?
|
|
1598
|
+
};
|
|
1515
1599
|
|
|
1516
|
-
pub
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
}
|
|
1600
|
+
pub const free_set = AreaRange{
|
|
1601
|
+
.base = manifest.base + manifest.size_max,
|
|
1602
|
+
.size_max = superblock_trailer_free_set_size_max,
|
|
1603
|
+
};
|
|
1604
|
+
|
|
1605
|
+
pub const client_table = AreaRange{
|
|
1606
|
+
.base = free_set.base + free_set.size_max,
|
|
1607
|
+
.size_max = superblock_trailer_client_table_size_max,
|
|
1608
|
+
};
|
|
1609
|
+
|
|
1610
|
+
const AreaRange = struct {
|
|
1611
|
+
base: u64,
|
|
1612
|
+
size_max: u64,
|
|
1613
|
+
|
|
1614
|
+
pub fn offset(area: AreaRange, copy: u8) u64 {
|
|
1615
|
+
return superblock_copy_size * @as(u64, copy) + area.base;
|
|
1616
|
+
}
|
|
1617
|
+
};
|
|
1520
1618
|
};
|
|
1521
1619
|
|
|
1522
|
-
test "
|
|
1620
|
+
test "SuperBlockHeader" {
|
|
1523
1621
|
const expect = std.testing.expect;
|
|
1524
1622
|
|
|
1525
|
-
var a = std.mem.
|
|
1623
|
+
var a = std.mem.zeroes(SuperBlockHeader);
|
|
1526
1624
|
a.set_checksum();
|
|
1527
1625
|
|
|
1528
1626
|
assert(a.copy == 0);
|