Skip to content

Commit

Permalink
vsr: verify that FreeSet index is consistent
Browse files Browse the repository at this point in the history
None of our fuzzers actually checks that. In theory, the simulator can
discover inconsistencies when a replica restarts (decoding free set from
disk resets the index), but, given that the shard size is 4096, this is
quite unlikely.

With this change, injecting a bug in index computation gets discovered
by free set fuzzer at least.

See
#1309 (comment)
for an example of a bug this assert guards against.
  • Loading branch information
matklad committed Nov 23, 2023
1 parent 0cdf5de commit 076bc77
Showing 1 changed file with 10 additions and 2 deletions.
12 changes: 10 additions & 2 deletions src/vsr/superblock_free_set.zig
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,12 @@ pub const FreeSet = struct {
assert(set.staging.count() == 0);
}

fn verify_index(set: *const FreeSet) void {
for (0..set.index.bit_length) |shard| {
assert((set.find_free_block_in_shard(shard) == null) == set.index.isSet(shard));
}
}

/// Returns the number of active reservations.
pub fn count_reservations(set: FreeSet) usize {
return set.reservation_count;
Expand Down Expand Up @@ -339,6 +345,9 @@ pub const FreeSet = struct {
set.release_now(address);
}
assert(set.staging.count() == 0);
// Index verification is O(blocks.bit_length) so do it only at checkpoint, which is
// also linear.
set.verify_index();
}

/// Temporarily marks staged blocks as free.
Expand Down Expand Up @@ -375,8 +384,7 @@ pub const FreeSet = struct {
const words_decoded = ewah.decode(source, bit_set_masks(set.blocks));
assert(words_decoded * @bitSizeOf(MaskInt) <= set.blocks.bit_length);

var shard: usize = 0;
while (shard < set.index.bit_length) : (shard += 1) {
for (0..set.index.bit_length) |shard| {
if (set.find_free_block_in_shard(shard) == null) set.index.set(shard);
}
}
Expand Down

0 comments on commit 076bc77

Please sign in to comment.