Last active
September 18, 2023 14:51
-
-
Save kprotty/c5d7e95959508d27420a38bb159b8b55 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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