Skip to content

Instantly share code, notes, and snippets.

@kprotty
Last active September 18, 2023 14:51
Show Gist options
  • Save kprotty/c5d7e95959508d27420a38bb159b8b55 to your computer and use it in GitHub Desktop.
Save kprotty/c5d7e95959508d27420a38bb159b8b55 to your computer and use it in GitHub Desktop.
const std = @import("std");
const assert = std.debug.assert;
const log = std.log.scoped(.lsm_manifest_fuzz);
const vsr = @import("../vsr.zig");
const constants = @import("../constants.zig");
const stdx = @import("../stdx.zig");
const fuzz = @import("../testing/fuzz.zig");
const allocator = fuzz.allocator;
const snapshot_latest = @import("tree.zig").snapshot_latest;
const table_count_max = @import("tree.zig").table_count_max;
const Key = u64;
const Value = extern struct { key: Key, is_tombstone: u64 };
inline fn compare_keys(a: Key, b: Key) std.math.Order {
return std.math.order(a, b);
}
inline fn key_from_value(value: *const Value) Key {
return value.key;
}
inline fn tombstone(value: *const Value) bool {
return value.is_tombstone != 0;
}
inline fn tombstone_from_key(key: Key) Value {
return .{ .key = key, .is_tombstone = 1 };
}
const Table = @import("table.zig").TableType(
Key,
Value,
compare_keys,
key_from_value,
std.math.maxInt(Key),
tombstone,
tombstone_from_key,
constants.state_machine_config.lsm_batch_multiple * 1024,
.secondary_index,
);
const ClusterFaultAtlas = @import("../testing/storage.zig").ClusterFaultAtlas;
const Storage = @import("../testing/storage.zig").Storage;
const Grid = @import("../vsr/grid.zig").GridType(Storage);
const SuperBlock = vsr.SuperBlockType(Storage);
const Direction = @import("direction.zig").Direction;
const TableInfo = @import("manifest.zig").TableInfoType(Table);
const NodePool = @import("node_pool.zig").NodePool(constants.lsm_manifest_node_size, 16);
const Manifest = @import("manifest.zig").ManifestType(Table, Storage);
pub const tigerbeetle_config = @import("../config.zig").configs.test_min;
pub fn main() !void {
var prng = std.rand.DefaultPrng.init(42);
const random = prng.random();
const storage_fault_atlas = ClusterFaultAtlas.init(3, random, .{
.faulty_superblock = false,
.faulty_wal_headers = false,
.faulty_wal_prepares = false,
.faulty_client_replies = false,
.faulty_grid = true,
});
const storage_options = .{
.seed = random.int(u64),
.replica_index = 0,
.read_latency_min = 0,
.read_latency_mean = 0 + fuzz.random_int_exponential(random, u64, 20),
.write_latency_min = 0,
.write_latency_mean = 0 + fuzz.random_int_exponential(random, u64, 20),
.read_fault_probability = random.uintLessThan(u8, 100),
.write_fault_probability = random.uintLessThan(u8, 100),
.fault_atlas = &storage_fault_atlas,
};
var storage = try Storage.init(allocator, constants.storage_size_max, storage_options);
defer storage.deinit(allocator);
var superblock = try SuperBlock.init(allocator, .{
.storage = &storage,
.storage_size_limit = constants.storage_size_max,
});
defer superblock.deinit(allocator);
const SuperBlockFormat = struct {
var formatted = false;
fn callback(_: *SuperBlock.Context) void {
assert(!@This().formatted);
@This().formatted = true;
}
};
var superblock_context: SuperBlock.Context = undefined;
superblock.format(SuperBlockFormat.callback, &superblock_context, .{
.cluster = 0,
.replica = 0,
.replica_count = 1,
});
while (!SuperBlockFormat.formatted) storage.tick();
const SuperBlockOpen = struct {
var opened = false;
fn callback(_: *SuperBlock.Context) void {
assert(!@This().opened);
@This().opened = true;
}
};
superblock.open(SuperBlockOpen.callback, &superblock_context);
while (!SuperBlockOpen.opened) storage.tick();
var grid = try Grid.init(allocator, .{ .superblock = &superblock });
defer grid.deinit(allocator);
const node_count = 16;
var node_pool = try NodePool.init(allocator, node_count);
errdefer node_pool.deinit(allocator);
const tree_name = "ManifestFuzzTree";
const tree_hash = blk: {
var hash: u256 = undefined;
std.crypto.hash.Blake3.hash(tree_name, std.mem.asBytes(&hash), .{});
break :blk @as(u128, @truncate(hash));
};
var manifest = try Manifest.init(allocator, &node_pool, &grid, tree_hash);
defer manifest.deinit(allocator);
const ManifestOpen = struct {
var opened = false;
fn callback(_: *Manifest) void {
assert(!@This().opened);
@This().opened = true;
}
};
manifest.open(ManifestOpen.callback);
while (!ManifestOpen.opened) storage.tick();
manifest.reserve();
manifest.insert_table(0, &.{
.checksum = 0,
.address = 0xdeadbeef,
.snapshot_min = 8,
.key_min = 42,
.key_max = 1337,
});
manifest.assert_level_table_counts();
manifest.assert_no_invisible_tables(6);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment