tigerbeetle-node 0.11.4 → 0.11.5
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 +1 -1
- package/src/node.zig +5 -5
- package/src/tigerbeetle/src/benchmark.zig +4 -4
- package/src/tigerbeetle/src/c/tb_client/context.zig +6 -6
- package/src/tigerbeetle/src/c/tb_client/echo_client.zig +2 -2
- package/src/tigerbeetle/src/c/tb_client/thread.zig +0 -1
- package/src/tigerbeetle/src/c/tb_client.zig +2 -2
- package/src/tigerbeetle/src/c/test.zig +8 -8
- package/src/tigerbeetle/src/cli.zig +9 -9
- package/src/tigerbeetle/src/demo.zig +4 -4
- package/src/tigerbeetle/src/io/darwin.zig +4 -4
- package/src/tigerbeetle/src/io/linux.zig +6 -6
- package/src/tigerbeetle/src/io/windows.zig +4 -4
- package/src/tigerbeetle/src/lsm/compaction.zig +8 -8
- package/src/tigerbeetle/src/lsm/forest.zig +2 -2
- package/src/tigerbeetle/src/lsm/forest_fuzz.zig +9 -9
- package/src/tigerbeetle/src/lsm/grid.zig +5 -5
- package/src/tigerbeetle/src/lsm/groove.zig +4 -4
- package/src/tigerbeetle/src/lsm/level_iterator.zig +2 -2
- package/src/tigerbeetle/src/lsm/manifest.zig +19 -18
- package/src/tigerbeetle/src/lsm/manifest_level.zig +2 -2
- package/src/tigerbeetle/src/lsm/manifest_log.zig +8 -8
- package/src/tigerbeetle/src/lsm/manifest_log_fuzz.zig +15 -7
- package/src/tigerbeetle/src/lsm/posted_groove.zig +3 -3
- package/src/tigerbeetle/src/lsm/segmented_array_benchmark.zig +13 -13
- package/src/tigerbeetle/src/lsm/set_associative_cache.zig +2 -2
- package/src/tigerbeetle/src/lsm/table.zig +19 -19
- package/src/tigerbeetle/src/lsm/table_immutable.zig +4 -4
- package/src/tigerbeetle/src/lsm/table_iterator.zig +17 -9
- package/src/tigerbeetle/src/lsm/table_mutable.zig +3 -3
- package/src/tigerbeetle/src/lsm/test.zig +6 -6
- package/src/tigerbeetle/src/lsm/tree.zig +48 -45
- package/src/tigerbeetle/src/lsm/tree_fuzz.zig +14 -14
- package/src/tigerbeetle/src/main.zig +18 -11
- package/src/tigerbeetle/src/message_bus.zig +25 -25
- package/src/tigerbeetle/src/message_pool.zig +17 -17
- package/src/tigerbeetle/src/simulator.zig +6 -4
- package/src/tigerbeetle/src/storage.zig +12 -12
- package/src/tigerbeetle/src/test/accounting/auditor.zig +2 -2
- package/src/tigerbeetle/src/test/accounting/workload.zig +5 -5
- package/src/tigerbeetle/src/test/cluster.zig +8 -8
- package/src/tigerbeetle/src/test/conductor.zig +6 -5
- package/src/tigerbeetle/src/test/message_bus.zig +0 -2
- package/src/tigerbeetle/src/test/network.zig +5 -5
- package/src/tigerbeetle/src/test/state_checker.zig +2 -2
- package/src/tigerbeetle/src/test/storage.zig +54 -51
- package/src/tigerbeetle/src/test/storage_checker.zig +3 -3
- package/src/tigerbeetle/src/time.zig +0 -1
- package/src/tigerbeetle/src/tracer.zig +4 -4
- package/src/tigerbeetle/src/vsr/client.zig +5 -5
- package/src/tigerbeetle/src/vsr/clock.zig +9 -8
- package/src/tigerbeetle/src/vsr/journal.zig +47 -47
- package/src/tigerbeetle/src/vsr/journal_format_fuzz.zig +11 -11
- package/src/tigerbeetle/src/vsr/replica.zig +53 -53
- package/src/tigerbeetle/src/vsr/replica_format.zig +8 -8
- package/src/tigerbeetle/src/vsr/superblock.zig +55 -55
- package/src/tigerbeetle/src/vsr/superblock_client_table.zig +9 -9
- package/src/tigerbeetle/src/vsr/superblock_free_set.zig +4 -4
- package/src/tigerbeetle/src/vsr/superblock_fuzz.zig +2 -2
- package/src/tigerbeetle/src/vsr/superblock_manifest.zig +5 -5
- package/src/tigerbeetle/src/vsr.zig +20 -20
|
@@ -2,7 +2,7 @@ const std = @import("std");
|
|
|
2
2
|
const Allocator = std.mem.Allocator;
|
|
3
3
|
const assert = std.debug.assert;
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const constants = @import("../constants.zig");
|
|
6
6
|
|
|
7
7
|
const StaticAllocator = @import("../static_allocator.zig");
|
|
8
8
|
const GridType = @import("../lsm/grid.zig").GridType;
|
|
@@ -58,10 +58,10 @@ const Prepare = struct {
|
|
|
58
58
|
ok_quorum_received: bool = false,
|
|
59
59
|
};
|
|
60
60
|
|
|
61
|
-
const QuorumMessages = [
|
|
62
|
-
const quorum_messages_null = [_]?*Message{null} **
|
|
61
|
+
const QuorumMessages = [constants.replicas_max]?*Message;
|
|
62
|
+
const quorum_messages_null = [_]?*Message{null} ** constants.replicas_max;
|
|
63
63
|
|
|
64
|
-
const QuorumCounter = std.StaticBitSet(
|
|
64
|
+
const QuorumCounter = std.StaticBitSet(constants.replicas_max);
|
|
65
65
|
const quorum_counter_null = QuorumCounter.initEmpty();
|
|
66
66
|
|
|
67
67
|
// CRITICAL: The number of prepare headers to include in the body:
|
|
@@ -70,13 +70,13 @@ const quorum_counter_null = QuorumCounter.initEmpty();
|
|
|
70
70
|
// that cannot be repaired because they are gaps, and this must be relative to the
|
|
71
71
|
// cluster as a whole (not relative to the difference between our op and commit number)
|
|
72
72
|
// as otherwise we would break correctness.
|
|
73
|
-
const view_change_headers_count =
|
|
73
|
+
const view_change_headers_count = constants.pipeline_max;
|
|
74
74
|
|
|
75
75
|
comptime {
|
|
76
76
|
assert(view_change_headers_count > 0);
|
|
77
|
-
assert(view_change_headers_count >=
|
|
77
|
+
assert(view_change_headers_count >= constants.pipeline_max);
|
|
78
78
|
assert(view_change_headers_count <=
|
|
79
|
-
@divFloor(
|
|
79
|
+
@divFloor(constants.message_size_max - @sizeOf(Header), @sizeOf(Header)));
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
pub fn ReplicaType(
|
|
@@ -197,7 +197,7 @@ pub fn ReplicaType(
|
|
|
197
197
|
///
|
|
198
198
|
/// After a view change, the old leader's pipeline is left untouched so that it is able to
|
|
199
199
|
/// help the new leader repair, even in the face of local storage faults.
|
|
200
|
-
pipeline: RingBuffer(Prepare,
|
|
200
|
+
pipeline: RingBuffer(Prepare, constants.pipeline_max, .array) = .{},
|
|
201
201
|
|
|
202
202
|
/// In some cases, a replica may send a message to itself. We do not submit these messages
|
|
203
203
|
/// to the message bus but rather queue them here for guaranteed immediate delivery, which
|
|
@@ -392,8 +392,8 @@ pub fn ReplicaType(
|
|
|
392
392
|
const majority = (replica_count / 2) + 1;
|
|
393
393
|
assert(majority <= replica_count);
|
|
394
394
|
|
|
395
|
-
assert(
|
|
396
|
-
const quorum_replication = std.math.min(
|
|
395
|
+
assert(constants.quorum_replication_max >= 2);
|
|
396
|
+
const quorum_replication = std.math.min(constants.quorum_replication_max, majority);
|
|
397
397
|
assert(quorum_replication >= 2 or quorum_replication == replica_count);
|
|
398
398
|
|
|
399
399
|
const quorum_view_change = std.math.max(
|
|
@@ -534,10 +534,10 @@ pub fn ReplicaType(
|
|
|
534
534
|
|
|
535
535
|
// To reduce the probability of clustering, for efficient linear probing, the hash map will
|
|
536
536
|
// always overallocate capacity by a factor of two.
|
|
537
|
-
log.debug("{}: init: client_table.capacity()={} for
|
|
537
|
+
log.debug("{}: init: client_table.capacity()={} for constants.clients_max={} entries", .{
|
|
538
538
|
self.replica,
|
|
539
539
|
self.client_table().capacity(),
|
|
540
|
-
|
|
540
|
+
constants.clients_max,
|
|
541
541
|
});
|
|
542
542
|
|
|
543
543
|
assert(self.status == .recovering);
|
|
@@ -1005,7 +1005,7 @@ pub fn ReplicaType(
|
|
|
1005
1005
|
// TODO: When Block recover & state transfer are implemented, this can be removed.
|
|
1006
1006
|
const threshold =
|
|
1007
1007
|
if (prepare.message.header.op == self.op_checkpoint_trigger() or
|
|
1008
|
-
prepare.message.header.op == self.op_checkpoint +
|
|
1008
|
+
prepare.message.header.op == self.op_checkpoint + constants.lsm_batch_multiple + 1)
|
|
1009
1009
|
self.replica_count
|
|
1010
1010
|
else
|
|
1011
1011
|
self.quorum_replication;
|
|
@@ -1598,7 +1598,7 @@ pub fn ReplicaType(
|
|
|
1598
1598
|
// more useful (i.e. older) headers.
|
|
1599
1599
|
self.replace_headers(leader_headers);
|
|
1600
1600
|
|
|
1601
|
-
if (self.op <
|
|
1601
|
+
if (self.op < constants.journal_slot_count) {
|
|
1602
1602
|
if (self.journal.header_with_op(0)) |header| {
|
|
1603
1603
|
assert(header.command == .prepare);
|
|
1604
1604
|
assert(header.operation == .root);
|
|
@@ -1983,7 +1983,7 @@ pub fn ReplicaType(
|
|
|
1983
1983
|
}
|
|
1984
1984
|
|
|
1985
1985
|
// The list of remote replicas yet to send a prepare_ok:
|
|
1986
|
-
var waiting: [
|
|
1986
|
+
var waiting: [constants.replicas_max]u8 = undefined;
|
|
1987
1987
|
var waiting_len: usize = 0;
|
|
1988
1988
|
var ok_from_all_replicas_iterator = prepare.ok_from_all_replicas.iterator(.{
|
|
1989
1989
|
.kind = .unset,
|
|
@@ -1993,7 +1993,7 @@ pub fn ReplicaType(
|
|
|
1993
1993
|
// The bits between `replica_count` and `replicas_max` are always unset,
|
|
1994
1994
|
// since they don't actually represent replicas.
|
|
1995
1995
|
if (replica == self.replica_count) {
|
|
1996
|
-
assert(self.replica_count <
|
|
1996
|
+
assert(self.replica_count < constants.replicas_max);
|
|
1997
1997
|
break;
|
|
1998
1998
|
}
|
|
1999
1999
|
assert(replica < self.replica_count);
|
|
@@ -2003,7 +2003,7 @@ pub fn ReplicaType(
|
|
|
2003
2003
|
waiting_len += 1;
|
|
2004
2004
|
}
|
|
2005
2005
|
} else {
|
|
2006
|
-
assert(self.replica_count ==
|
|
2006
|
+
assert(self.replica_count == constants.replicas_max);
|
|
2007
2007
|
}
|
|
2008
2008
|
|
|
2009
2009
|
if (waiting_len == 0) {
|
|
@@ -2015,7 +2015,7 @@ pub fn ReplicaType(
|
|
|
2015
2015
|
// We may be slow and waiting for the write to complete.
|
|
2016
2016
|
//
|
|
2017
2017
|
// We may even have maxed out our IO depth and been unable to initiate the write,
|
|
2018
|
-
// which can happen if `
|
|
2018
|
+
// which can happen if `constants.pipeline_max` exceeds `constants.journal_iops_write_max`.
|
|
2019
2019
|
// This can lead to deadlock for a cluster of one or two (if we do not retry here),
|
|
2020
2020
|
// since there is no other way for the leader to repair the dirty op because no
|
|
2021
2021
|
// other replica has it.
|
|
@@ -2121,7 +2121,7 @@ pub fn ReplicaType(
|
|
|
2121
2121
|
assert(threshold >= 1);
|
|
2122
2122
|
assert(threshold <= self.replica_count);
|
|
2123
2123
|
|
|
2124
|
-
assert(messages.len ==
|
|
2124
|
+
assert(messages.len == constants.replicas_max);
|
|
2125
2125
|
assert(message.header.cluster == self.cluster);
|
|
2126
2126
|
assert(message.header.replica < self.replica_count);
|
|
2127
2127
|
assert(message.header.view == self.view);
|
|
@@ -2222,7 +2222,7 @@ pub fn ReplicaType(
|
|
|
2222
2222
|
assert(threshold >= 1);
|
|
2223
2223
|
assert(threshold <= self.replica_count);
|
|
2224
2224
|
|
|
2225
|
-
assert(QuorumCounter.bit_length ==
|
|
2225
|
+
assert(QuorumCounter.bit_length == constants.replicas_max);
|
|
2226
2226
|
assert(message.header.cluster == self.cluster);
|
|
2227
2227
|
assert(message.header.replica < self.replica_count);
|
|
2228
2228
|
assert(message.header.view == self.view);
|
|
@@ -2597,7 +2597,7 @@ pub fn ReplicaType(
|
|
|
2597
2597
|
|
|
2598
2598
|
if (op == self.op_checkpoint_trigger()) {
|
|
2599
2599
|
assert(op == self.op);
|
|
2600
|
-
assert((op + 1) %
|
|
2600
|
+
assert((op + 1) % constants.lsm_batch_multiple == 0);
|
|
2601
2601
|
log.debug("{}: commit_op_compact_callback: checkpoint start " ++
|
|
2602
2602
|
"(op={} current_checkpoint={} next_checkpoint={})", .{
|
|
2603
2603
|
self.replica,
|
|
@@ -2660,7 +2660,7 @@ pub fn ReplicaType(
|
|
|
2660
2660
|
assert(self.commit_prepare.?.header.op == self.commit_min);
|
|
2661
2661
|
|
|
2662
2662
|
self.op_checkpoint = self.op_checkpoint_next();
|
|
2663
|
-
assert(self.op_checkpoint == self.commit_min -
|
|
2663
|
+
assert(self.op_checkpoint == self.commit_min - constants.lsm_batch_multiple);
|
|
2664
2664
|
assert(self.op_checkpoint == self.superblock.staging.vsr_state.commit_min);
|
|
2665
2665
|
assert(self.op_checkpoint == self.superblock.working.vsr_state.commit_min);
|
|
2666
2666
|
|
|
@@ -2921,7 +2921,7 @@ pub fn ReplicaType(
|
|
|
2921
2921
|
command: Command,
|
|
2922
2922
|
context: u128,
|
|
2923
2923
|
) usize {
|
|
2924
|
-
assert(messages.len ==
|
|
2924
|
+
assert(messages.len == constants.replicas_max);
|
|
2925
2925
|
var count: usize = 0;
|
|
2926
2926
|
for (messages) |received, replica| {
|
|
2927
2927
|
if (received) |m| {
|
|
@@ -2962,16 +2962,16 @@ pub fn ReplicaType(
|
|
|
2962
2962
|
|
|
2963
2963
|
// For correctness, it's critical that all replicas evict deterministically:
|
|
2964
2964
|
// We cannot depend on `HashMap.capacity()` since `HashMap.ensureTotalCapacity()` may
|
|
2965
|
-
// change across versions of the Zig std lib. We therefore rely on
|
|
2966
|
-
// which must be the same across all replicas, and must not
|
|
2967
|
-
// cluster.
|
|
2965
|
+
// change across versions of the Zig std lib. We therefore rely on
|
|
2966
|
+
// `constants.clients_max`, which must be the same across all replicas, and must not
|
|
2967
|
+
// change after initializing a cluster.
|
|
2968
2968
|
// We also do not depend on `HashMap.valueIterator()` being deterministic here. However,
|
|
2969
2969
|
// we do require that all entries have different commit numbers and are iterated.
|
|
2970
2970
|
// This ensures that we will always pick the entry with the oldest commit number.
|
|
2971
2971
|
// We also check that a client has only one entry in the hash map (or it's buggy).
|
|
2972
2972
|
const clients = self.client_table().count();
|
|
2973
|
-
assert(clients <=
|
|
2974
|
-
if (clients ==
|
|
2973
|
+
assert(clients <= constants.clients_max);
|
|
2974
|
+
if (clients == constants.clients_max) {
|
|
2975
2975
|
var evictee: ?*Message = null;
|
|
2976
2976
|
var iterated: usize = 0;
|
|
2977
2977
|
var iterator = self.client_table().iterator();
|
|
@@ -2996,7 +2996,7 @@ pub fn ReplicaType(
|
|
|
2996
2996
|
log.err("{}: create_client_table_entry: clients={}/{} evicting client={}", .{
|
|
2997
2997
|
self.replica,
|
|
2998
2998
|
clients,
|
|
2999
|
-
|
|
2999
|
+
constants.clients_max,
|
|
3000
3000
|
evictee.?.header.client,
|
|
3001
3001
|
});
|
|
3002
3002
|
self.client_table().remove(evictee.?.header.client);
|
|
@@ -3016,7 +3016,7 @@ pub fn ReplicaType(
|
|
|
3016
3016
|
.session = session,
|
|
3017
3017
|
.reply = reply.ref(),
|
|
3018
3018
|
});
|
|
3019
|
-
assert(self.client_table().count() <=
|
|
3019
|
+
assert(self.client_table().count() <= constants.clients_max);
|
|
3020
3020
|
}
|
|
3021
3021
|
|
|
3022
3022
|
/// The caller owns the returned message, if any, which has exactly 1 reference.
|
|
@@ -3114,16 +3114,16 @@ pub fn ReplicaType(
|
|
|
3114
3114
|
self.op - self.commit_min,
|
|
3115
3115
|
// The number of uncommitted ops cannot be more than the length of the pipeline.
|
|
3116
3116
|
// Do not reset any ops that we did not include in our do_view_change message.
|
|
3117
|
-
|
|
3117
|
+
constants.pipeline_max,
|
|
3118
3118
|
);
|
|
3119
3119
|
|
|
3120
|
-
assert(uncanonical_op_count <=
|
|
3120
|
+
assert(uncanonical_op_count <= constants.pipeline_max);
|
|
3121
3121
|
if (uncanonical_op_count == 0) return self.op;
|
|
3122
3122
|
|
|
3123
3123
|
// * When uncanonical_op_count = self.op - self.commit_min,
|
|
3124
3124
|
// self.op - uncanonical_op_count = self.commit_min.
|
|
3125
|
-
// * When uncanonical_op_count =
|
|
3126
|
-
//
|
|
3125
|
+
// * When uncanonical_op_count = constants.pipeline_max,
|
|
3126
|
+
// constants.pipeline_max < self.op - self.commit_min holds.
|
|
3127
3127
|
const canonical_op_max = self.op - uncanonical_op_count;
|
|
3128
3128
|
|
|
3129
3129
|
log.debug("{}: on_do_view_change: not canonical ops={}..{}", .{
|
|
@@ -3134,7 +3134,7 @@ pub fn ReplicaType(
|
|
|
3134
3134
|
|
|
3135
3135
|
assert(canonical_op_max <= self.op);
|
|
3136
3136
|
assert(canonical_op_max >= self.commit_min);
|
|
3137
|
-
assert(canonical_op_max +
|
|
3137
|
+
assert(canonical_op_max + constants.pipeline_max >= self.op);
|
|
3138
3138
|
return canonical_op_max;
|
|
3139
3139
|
}
|
|
3140
3140
|
|
|
@@ -3724,16 +3724,16 @@ pub fn ReplicaType(
|
|
|
3724
3724
|
assert(self.op_checkpoint <= self.commit_min);
|
|
3725
3725
|
assert(self.op_checkpoint <= self.op);
|
|
3726
3726
|
assert(self.op_checkpoint == 0 or
|
|
3727
|
-
(self.op_checkpoint + 1) %
|
|
3727
|
+
(self.op_checkpoint + 1) % constants.lsm_batch_multiple == 0);
|
|
3728
3728
|
|
|
3729
3729
|
const op = if (self.op_checkpoint == 0)
|
|
3730
3730
|
// First wrap: op_checkpoint_next = 8-2-1 = 5
|
|
3731
|
-
|
|
3731
|
+
constants.journal_slot_count - constants.lsm_batch_multiple - 1
|
|
3732
3732
|
else
|
|
3733
3733
|
// Second wrap: op_checkpoint_next = 5+8-2 = 11
|
|
3734
3734
|
// Third wrap: op_checkpoint_next = 11+8-2 = 17
|
|
3735
|
-
self.op_checkpoint +
|
|
3736
|
-
assert((op + 1) %
|
|
3735
|
+
self.op_checkpoint + constants.journal_slot_count - constants.lsm_batch_multiple;
|
|
3736
|
+
assert((op + 1) % constants.lsm_batch_multiple == 0);
|
|
3737
3737
|
// The checkpoint always advances.
|
|
3738
3738
|
assert(op > self.op_checkpoint);
|
|
3739
3739
|
|
|
@@ -3748,7 +3748,7 @@ pub fn ReplicaType(
|
|
|
3748
3748
|
///
|
|
3749
3749
|
/// See `op_checkpoint_next` for more detail.
|
|
3750
3750
|
fn op_checkpoint_trigger(self: *const Self) u64 {
|
|
3751
|
-
return self.op_checkpoint_next() +
|
|
3751
|
+
return self.op_checkpoint_next() + constants.lsm_batch_multiple;
|
|
3752
3752
|
}
|
|
3753
3753
|
|
|
3754
3754
|
/// Finds the header with the highest op number in a slice of headers from a replica.
|
|
@@ -3834,7 +3834,7 @@ pub fn ReplicaType(
|
|
|
3834
3834
|
op += 1;
|
|
3835
3835
|
}
|
|
3836
3836
|
|
|
3837
|
-
assert(self.pipeline.count <=
|
|
3837
|
+
assert(self.pipeline.count <= constants.pipeline_max);
|
|
3838
3838
|
assert(self.commit_max + self.pipeline.count == op - 1);
|
|
3839
3839
|
assert(self.commit_max + self.pipeline.count == self.op);
|
|
3840
3840
|
|
|
@@ -4376,7 +4376,7 @@ pub fn ReplicaType(
|
|
|
4376
4376
|
assert(self.repairs_allowed());
|
|
4377
4377
|
assert(self.journal.dirty.count > 0);
|
|
4378
4378
|
assert(self.op >= self.commit_min);
|
|
4379
|
-
assert(self.op - self.commit_min + 1 <=
|
|
4379
|
+
assert(self.op - self.commit_min + 1 <= constants.journal_slot_count);
|
|
4380
4380
|
|
|
4381
4381
|
// Request enough prepares to utilize our max IO depth:
|
|
4382
4382
|
var budget = self.journal.writes.available();
|
|
@@ -4385,12 +4385,12 @@ pub fn ReplicaType(
|
|
|
4385
4385
|
return;
|
|
4386
4386
|
}
|
|
4387
4387
|
|
|
4388
|
-
if (self.op <
|
|
4388
|
+
if (self.op < constants.journal_slot_count) {
|
|
4389
4389
|
// The op is known, and this is the first WAL cycle.
|
|
4390
4390
|
// Therefore, any faulty ops to the right of `replica.op` are corrupt reserved
|
|
4391
4391
|
// entries from the initial format, or corrupt prepares which were since truncated.
|
|
4392
4392
|
var op: usize = self.op + 1;
|
|
4393
|
-
while (op <
|
|
4393
|
+
while (op < constants.journal_slot_count) : (op += 1) {
|
|
4394
4394
|
const slot = self.journal.slot_for_op(op);
|
|
4395
4395
|
assert(slot.index == op);
|
|
4396
4396
|
|
|
@@ -4411,7 +4411,7 @@ pub fn ReplicaType(
|
|
|
4411
4411
|
var op = self.op + 1;
|
|
4412
4412
|
// To maximize durability, repair all prepares for which we have a header (not only
|
|
4413
4413
|
// uncommitted headers). This in turn enables the replica to help repair other replicas.
|
|
4414
|
-
const op_min = op -|
|
|
4414
|
+
const op_min = op -| constants.journal_slot_count;
|
|
4415
4415
|
while (op > op_min) {
|
|
4416
4416
|
op -= 1;
|
|
4417
4417
|
|
|
@@ -4713,7 +4713,7 @@ pub fn ReplicaType(
|
|
|
4713
4713
|
}
|
|
4714
4714
|
|
|
4715
4715
|
fn reset_quorum_messages(self: *Self, messages: *QuorumMessages, command: Command) void {
|
|
4716
|
-
assert(messages.len ==
|
|
4716
|
+
assert(messages.len == constants.replicas_max);
|
|
4717
4717
|
var view: ?u32 = null;
|
|
4718
4718
|
var count: usize = 0;
|
|
4719
4719
|
for (messages) |*received, replica| {
|
|
@@ -5158,7 +5158,7 @@ pub fn ReplicaType(
|
|
|
5158
5158
|
}
|
|
5159
5159
|
|
|
5160
5160
|
assert(commit_max >=
|
|
5161
|
-
self.commit_max - std.math.min(
|
|
5161
|
+
self.commit_max - std.math.min(constants.pipeline_max, self.commit_max));
|
|
5162
5162
|
|
|
5163
5163
|
assert(self.commit_min <= self.commit_max);
|
|
5164
5164
|
assert(self.op >= self.commit_max or self.op < self.commit_max);
|
|
@@ -5240,7 +5240,7 @@ pub fn ReplicaType(
|
|
|
5240
5240
|
// headers to become dirty.
|
|
5241
5241
|
const op_canonical = self.op_canonical_max(view_normal_canonical);
|
|
5242
5242
|
assert(op_canonical <= self.op);
|
|
5243
|
-
assert(op_canonical >= self.op -|
|
|
5243
|
+
assert(op_canonical >= self.op -| constants.pipeline_max);
|
|
5244
5244
|
assert(op_canonical >= self.commit_min);
|
|
5245
5245
|
|
|
5246
5246
|
if (do_view_change_head.op > self.op_checkpoint_trigger()) {
|
|
@@ -5373,7 +5373,7 @@ pub fn ReplicaType(
|
|
|
5373
5373
|
assert(message.header.replica == replica);
|
|
5374
5374
|
assert(message.header.view == self.view);
|
|
5375
5375
|
assert(message.header.op >= message.header.commit);
|
|
5376
|
-
assert(message.header.op - message.header.commit <=
|
|
5376
|
+
assert(message.header.op - message.header.commit <= constants.journal_slot_count);
|
|
5377
5377
|
|
|
5378
5378
|
// The view when this replica was last in normal status, which:
|
|
5379
5379
|
// * may be higher than the view in any of the prepare headers.
|
|
@@ -5484,8 +5484,8 @@ pub fn ReplicaType(
|
|
|
5484
5484
|
assert(self.op >= self.commit_max);
|
|
5485
5485
|
// At least one replica in the new quorum committed in the new replica.op's WAL wrap —
|
|
5486
5486
|
// wrapping implies a checkpoint (which implies a commit).
|
|
5487
|
-
assert(self.op - self.commit_max <=
|
|
5488
|
-
assert(self.op - self.commit_min <=
|
|
5487
|
+
assert(self.op - self.commit_max <= constants.journal_slot_count);
|
|
5488
|
+
assert(self.op - self.commit_min <= constants.journal_slot_count);
|
|
5489
5489
|
|
|
5490
5490
|
assert(op_canonical <= self.op);
|
|
5491
5491
|
assert(op_canonical >= self.commit_min);
|
|
@@ -5518,7 +5518,7 @@ pub fn ReplicaType(
|
|
|
5518
5518
|
// if it was committed it would have survived into the new view as a header not a gap.
|
|
5519
5519
|
const op_before_gap = blk: {
|
|
5520
5520
|
// An op cannot be uncommitted if it is definitely outside the pipeline.
|
|
5521
|
-
const op_committed = std.math.max(self.commit_max, self.op -|
|
|
5521
|
+
const op_committed = std.math.max(self.commit_max, self.op -| constants.pipeline_max);
|
|
5522
5522
|
assert(op_committed <= self.op);
|
|
5523
5523
|
|
|
5524
5524
|
var op = op_committed;
|
|
@@ -5864,7 +5864,7 @@ pub fn ReplicaType(
|
|
|
5864
5864
|
parent = prepare.message.header.checksum;
|
|
5865
5865
|
op += 1;
|
|
5866
5866
|
}
|
|
5867
|
-
assert(self.pipeline.count <=
|
|
5867
|
+
assert(self.pipeline.count <= constants.pipeline_max);
|
|
5868
5868
|
assert(self.commit_max + self.pipeline.count == op - 1);
|
|
5869
5869
|
}
|
|
5870
5870
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const std = @import("std");
|
|
2
2
|
const assert = std.debug.assert;
|
|
3
3
|
|
|
4
|
-
const
|
|
4
|
+
const constants = @import("../constants.zig");
|
|
5
5
|
const vsr = @import("../vsr.zig");
|
|
6
6
|
const Header = vsr.Header;
|
|
7
7
|
const format_wal_headers = @import("./journal.zig").format_wal_headers;
|
|
@@ -29,7 +29,7 @@ pub fn format(
|
|
|
29
29
|
.cluster = cluster,
|
|
30
30
|
.replica = replica,
|
|
31
31
|
// TODO Convert this to a runtime arg, to cap storage.
|
|
32
|
-
.size_max =
|
|
32
|
+
.size_max = constants.size_max,
|
|
33
33
|
},
|
|
34
34
|
);
|
|
35
35
|
|
|
@@ -54,12 +54,12 @@ fn ReplicaFormatType(comptime Storage: type) type {
|
|
|
54
54
|
) !void {
|
|
55
55
|
const header_zeroes = [_]u8{0} ** @sizeOf(Header);
|
|
56
56
|
const wal_write_size_max = 4 * 1024 * 1024;
|
|
57
|
-
assert(wal_write_size_max %
|
|
57
|
+
assert(wal_write_size_max % constants.sector_size == 0);
|
|
58
58
|
|
|
59
59
|
// Direct I/O requires the buffer to be sector-aligned.
|
|
60
60
|
var wal_buffer = try allocator.allocAdvanced(
|
|
61
61
|
u8,
|
|
62
|
-
|
|
62
|
+
constants.sector_size,
|
|
63
63
|
wal_write_size_max,
|
|
64
64
|
.exact,
|
|
65
65
|
);
|
|
@@ -70,7 +70,7 @@ fn ReplicaFormatType(comptime Storage: type) type {
|
|
|
70
70
|
// first. This allows the test Storage to check the invariant "never write the redundant
|
|
71
71
|
// header before the prepare".
|
|
72
72
|
var wal_offset: u64 = 0;
|
|
73
|
-
while (wal_offset <
|
|
73
|
+
while (wal_offset < constants.journal_size_prepares) {
|
|
74
74
|
const size = format_wal_prepares(cluster, wal_offset, wal_buffer);
|
|
75
75
|
assert(size > 0);
|
|
76
76
|
|
|
@@ -105,7 +105,7 @@ fn ReplicaFormatType(comptime Storage: type) type {
|
|
|
105
105
|
assert(format_wal_prepares(cluster, wal_offset, wal_buffer) == 0);
|
|
106
106
|
|
|
107
107
|
wal_offset = 0;
|
|
108
|
-
while (wal_offset <
|
|
108
|
+
while (wal_offset < constants.journal_size_headers) {
|
|
109
109
|
const size = format_wal_headers(cluster, wal_offset, wal_buffer);
|
|
110
110
|
assert(size > 0);
|
|
111
111
|
|
|
@@ -160,7 +160,7 @@ test "format" {
|
|
|
160
160
|
|
|
161
161
|
var storage = try Storage.init(
|
|
162
162
|
allocator,
|
|
163
|
-
superblock_zone_size +
|
|
163
|
+
superblock_zone_size + constants.journal_size_headers + constants.journal_size_prepares,
|
|
164
164
|
.{
|
|
165
165
|
.read_latency_min = 0,
|
|
166
166
|
.read_latency_mean = 0,
|
|
@@ -180,7 +180,7 @@ test "format" {
|
|
|
180
180
|
|
|
181
181
|
// Verify the superblock sectors.
|
|
182
182
|
var copy: u8 = 0;
|
|
183
|
-
while (copy <
|
|
183
|
+
while (copy < constants.superblock_copies) : (copy += 1) {
|
|
184
184
|
const sector = storage.superblock_sector(copy);
|
|
185
185
|
|
|
186
186
|
try std.testing.expectEqual(sector.copy, copy);
|