tigerbeetle-node 0.11.13 → 0.12.0
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/bin/aarch64-linux-gnu/client.node +0 -0
- package/dist/bin/aarch64-linux-musl/client.node +0 -0
- package/dist/bin/aarch64-macos/client.node +0 -0
- package/dist/bin/x86_64-linux-gnu/client.node +0 -0
- package/dist/bin/x86_64-linux-musl/client.node +0 -0
- package/dist/bin/x86_64-macos/client.node +0 -0
- package/dist/index.js +33 -1
- package/dist/index.js.map +1 -1
- package/package-lock.json +66 -0
- package/package.json +6 -16
- package/src/index.ts +56 -1
- package/src/node.zig +9 -9
- package/dist/.client.node.sha256 +0 -1
- package/scripts/build_lib.sh +0 -61
- package/scripts/download_node_headers.sh +0 -32
- package/src/tigerbeetle/scripts/benchmark.bat +0 -55
- package/src/tigerbeetle/scripts/benchmark.sh +0 -66
- package/src/tigerbeetle/scripts/confirm_image.sh +0 -44
- package/src/tigerbeetle/scripts/fail_on_diff.sh +0 -9
- package/src/tigerbeetle/scripts/fuzz_loop.sh +0 -15
- package/src/tigerbeetle/scripts/fuzz_loop_hash_log.sh +0 -12
- package/src/tigerbeetle/scripts/fuzz_unique_errors.sh +0 -7
- package/src/tigerbeetle/scripts/install.bat +0 -7
- package/src/tigerbeetle/scripts/install.sh +0 -21
- package/src/tigerbeetle/scripts/install_zig.bat +0 -113
- package/src/tigerbeetle/scripts/install_zig.sh +0 -90
- package/src/tigerbeetle/scripts/lint.zig +0 -199
- package/src/tigerbeetle/scripts/pre-commit.sh +0 -9
- package/src/tigerbeetle/scripts/scripts/benchmark.bat +0 -55
- package/src/tigerbeetle/scripts/scripts/benchmark.sh +0 -66
- package/src/tigerbeetle/scripts/scripts/confirm_image.sh +0 -44
- package/src/tigerbeetle/scripts/scripts/fail_on_diff.sh +0 -9
- package/src/tigerbeetle/scripts/scripts/fuzz_loop.sh +0 -15
- package/src/tigerbeetle/scripts/scripts/fuzz_loop_hash_log.sh +0 -12
- package/src/tigerbeetle/scripts/scripts/fuzz_unique_errors.sh +0 -7
- package/src/tigerbeetle/scripts/scripts/install.bat +0 -7
- package/src/tigerbeetle/scripts/scripts/install.sh +0 -21
- package/src/tigerbeetle/scripts/scripts/install_zig.bat +0 -113
- package/src/tigerbeetle/scripts/scripts/install_zig.sh +0 -90
- package/src/tigerbeetle/scripts/scripts/lint.zig +0 -199
- package/src/tigerbeetle/scripts/scripts/pre-commit.sh +0 -9
- package/src/tigerbeetle/scripts/scripts/shellcheck.sh +0 -5
- package/src/tigerbeetle/scripts/scripts/tests_on_alpine.sh +0 -10
- package/src/tigerbeetle/scripts/scripts/tests_on_ubuntu.sh +0 -14
- package/src/tigerbeetle/scripts/scripts/upgrade_ubuntu_kernel.sh +0 -48
- package/src/tigerbeetle/scripts/scripts/validate_docs.sh +0 -23
- package/src/tigerbeetle/scripts/scripts/vr_state_enumerate +0 -46
- package/src/tigerbeetle/scripts/shellcheck.sh +0 -5
- package/src/tigerbeetle/scripts/tests_on_alpine.sh +0 -10
- package/src/tigerbeetle/scripts/tests_on_ubuntu.sh +0 -14
- package/src/tigerbeetle/scripts/upgrade_ubuntu_kernel.sh +0 -48
- package/src/tigerbeetle/scripts/validate_docs.sh +0 -23
- package/src/tigerbeetle/scripts/vr_state_enumerate +0 -46
- package/src/tigerbeetle/src/benchmark.zig +0 -336
- package/src/tigerbeetle/src/config.zig +0 -233
- package/src/tigerbeetle/src/constants.zig +0 -428
- package/src/tigerbeetle/src/ewah.zig +0 -286
- package/src/tigerbeetle/src/ewah_benchmark.zig +0 -120
- package/src/tigerbeetle/src/ewah_fuzz.zig +0 -130
- package/src/tigerbeetle/src/fifo.zig +0 -120
- package/src/tigerbeetle/src/io/benchmark.zig +0 -213
- package/src/tigerbeetle/src/io/darwin.zig +0 -814
- package/src/tigerbeetle/src/io/linux.zig +0 -1071
- package/src/tigerbeetle/src/io/test.zig +0 -643
- package/src/tigerbeetle/src/io/windows.zig +0 -1183
- package/src/tigerbeetle/src/io.zig +0 -34
- package/src/tigerbeetle/src/iops.zig +0 -107
- package/src/tigerbeetle/src/lsm/README.md +0 -308
- package/src/tigerbeetle/src/lsm/binary_search.zig +0 -341
- package/src/tigerbeetle/src/lsm/bloom_filter.zig +0 -125
- package/src/tigerbeetle/src/lsm/compaction.zig +0 -603
- package/src/tigerbeetle/src/lsm/composite_key.zig +0 -77
- package/src/tigerbeetle/src/lsm/direction.zig +0 -11
- package/src/tigerbeetle/src/lsm/eytzinger.zig +0 -587
- package/src/tigerbeetle/src/lsm/eytzinger_benchmark.zig +0 -330
- package/src/tigerbeetle/src/lsm/forest.zig +0 -205
- package/src/tigerbeetle/src/lsm/forest_fuzz.zig +0 -450
- package/src/tigerbeetle/src/lsm/grid.zig +0 -573
- package/src/tigerbeetle/src/lsm/groove.zig +0 -1036
- package/src/tigerbeetle/src/lsm/k_way_merge.zig +0 -474
- package/src/tigerbeetle/src/lsm/level_iterator.zig +0 -332
- package/src/tigerbeetle/src/lsm/manifest.zig +0 -617
- package/src/tigerbeetle/src/lsm/manifest_level.zig +0 -878
- package/src/tigerbeetle/src/lsm/manifest_log.zig +0 -789
- package/src/tigerbeetle/src/lsm/manifest_log_fuzz.zig +0 -691
- package/src/tigerbeetle/src/lsm/merge_iterator.zig +0 -106
- package/src/tigerbeetle/src/lsm/node_pool.zig +0 -235
- package/src/tigerbeetle/src/lsm/posted_groove.zig +0 -381
- package/src/tigerbeetle/src/lsm/segmented_array.zig +0 -1329
- package/src/tigerbeetle/src/lsm/segmented_array_benchmark.zig +0 -148
- package/src/tigerbeetle/src/lsm/segmented_array_fuzz.zig +0 -9
- package/src/tigerbeetle/src/lsm/set_associative_cache.zig +0 -850
- package/src/tigerbeetle/src/lsm/table.zig +0 -1009
- package/src/tigerbeetle/src/lsm/table_immutable.zig +0 -192
- package/src/tigerbeetle/src/lsm/table_iterator.zig +0 -340
- package/src/tigerbeetle/src/lsm/table_mutable.zig +0 -203
- package/src/tigerbeetle/src/lsm/test.zig +0 -439
- package/src/tigerbeetle/src/lsm/tree.zig +0 -1169
- package/src/tigerbeetle/src/lsm/tree_fuzz.zig +0 -479
- package/src/tigerbeetle/src/message_bus.zig +0 -1013
- package/src/tigerbeetle/src/message_pool.zig +0 -156
- package/src/tigerbeetle/src/ring_buffer.zig +0 -399
- package/src/tigerbeetle/src/simulator.zig +0 -580
- package/src/tigerbeetle/src/state_machine/auditor.zig +0 -578
- package/src/tigerbeetle/src/state_machine/workload.zig +0 -883
- package/src/tigerbeetle/src/state_machine.zig +0 -2099
- package/src/tigerbeetle/src/static_allocator.zig +0 -65
- package/src/tigerbeetle/src/stdx.zig +0 -171
- package/src/tigerbeetle/src/storage.zig +0 -393
- package/src/tigerbeetle/src/testing/cluster/message_bus.zig +0 -82
- package/src/tigerbeetle/src/testing/cluster/network.zig +0 -237
- package/src/tigerbeetle/src/testing/cluster/state_checker.zig +0 -169
- package/src/tigerbeetle/src/testing/cluster/storage_checker.zig +0 -202
- package/src/tigerbeetle/src/testing/cluster.zig +0 -444
- package/src/tigerbeetle/src/testing/fuzz.zig +0 -140
- package/src/tigerbeetle/src/testing/hash_log.zig +0 -66
- package/src/tigerbeetle/src/testing/id.zig +0 -99
- package/src/tigerbeetle/src/testing/packet_simulator.zig +0 -374
- package/src/tigerbeetle/src/testing/priority_queue.zig +0 -645
- package/src/tigerbeetle/src/testing/reply_sequence.zig +0 -139
- package/src/tigerbeetle/src/testing/state_machine.zig +0 -250
- package/src/tigerbeetle/src/testing/storage.zig +0 -757
- package/src/tigerbeetle/src/testing/table.zig +0 -247
- package/src/tigerbeetle/src/testing/time.zig +0 -84
- package/src/tigerbeetle/src/tigerbeetle.zig +0 -227
- package/src/tigerbeetle/src/time.zig +0 -112
- package/src/tigerbeetle/src/tracer.zig +0 -529
- package/src/tigerbeetle/src/unit_tests.zig +0 -40
- package/src/tigerbeetle/src/vopr.zig +0 -495
- package/src/tigerbeetle/src/vsr/README.md +0 -209
- package/src/tigerbeetle/src/vsr/client.zig +0 -544
- package/src/tigerbeetle/src/vsr/clock.zig +0 -855
- package/src/tigerbeetle/src/vsr/journal.zig +0 -2415
- package/src/tigerbeetle/src/vsr/journal_format_fuzz.zig +0 -111
- package/src/tigerbeetle/src/vsr/marzullo.zig +0 -309
- package/src/tigerbeetle/src/vsr/replica.zig +0 -6616
- package/src/tigerbeetle/src/vsr/replica_format.zig +0 -219
- package/src/tigerbeetle/src/vsr/superblock.zig +0 -1631
- package/src/tigerbeetle/src/vsr/superblock_client_table.zig +0 -256
- package/src/tigerbeetle/src/vsr/superblock_free_set.zig +0 -929
- package/src/tigerbeetle/src/vsr/superblock_free_set_fuzz.zig +0 -334
- package/src/tigerbeetle/src/vsr/superblock_fuzz.zig +0 -390
- package/src/tigerbeetle/src/vsr/superblock_manifest.zig +0 -615
- package/src/tigerbeetle/src/vsr/superblock_quorums.zig +0 -394
- package/src/tigerbeetle/src/vsr/superblock_quorums_fuzz.zig +0 -314
- package/src/tigerbeetle/src/vsr.zig +0 -1425
|
@@ -1,479 +0,0 @@
|
|
|
1
|
-
const std = @import("std");
|
|
2
|
-
const testing = std.testing;
|
|
3
|
-
const allocator = testing.allocator;
|
|
4
|
-
const assert = std.debug.assert;
|
|
5
|
-
|
|
6
|
-
const constants = @import("../constants.zig");
|
|
7
|
-
const fuzz = @import("../testing/fuzz.zig");
|
|
8
|
-
const vsr = @import("../vsr.zig");
|
|
9
|
-
|
|
10
|
-
const log = std.log.scoped(.lsm_tree_fuzz);
|
|
11
|
-
const tracer = @import("../tracer.zig");
|
|
12
|
-
|
|
13
|
-
const MessagePool = @import("../message_pool.zig").MessagePool;
|
|
14
|
-
const Transfer = @import("../tigerbeetle.zig").Transfer;
|
|
15
|
-
const Account = @import("../tigerbeetle.zig").Account;
|
|
16
|
-
const Storage = @import("../testing/storage.zig").Storage;
|
|
17
|
-
const StateMachine = @import("../state_machine.zig").StateMachineType(Storage, .{
|
|
18
|
-
.message_body_size_max = constants.message_body_size_max,
|
|
19
|
-
.lsm_batch_multiple = constants.lsm_batch_multiple,
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
const GridType = @import("grid.zig").GridType;
|
|
23
|
-
const NodePool = @import("node_pool.zig").NodePool(constants.lsm_manifest_node_size, 16);
|
|
24
|
-
const TableUsage = @import("table.zig").TableUsage;
|
|
25
|
-
const TableType = @import("table.zig").TableType;
|
|
26
|
-
|
|
27
|
-
const Grid = GridType(Storage);
|
|
28
|
-
const SuperBlock = vsr.SuperBlockType(Storage);
|
|
29
|
-
|
|
30
|
-
pub const tigerbeetle_config = @import("../config.zig").configs.test_min;
|
|
31
|
-
|
|
32
|
-
const Key = packed struct {
|
|
33
|
-
id: u64 align(@alignOf(u64)),
|
|
34
|
-
|
|
35
|
-
const Value = packed struct {
|
|
36
|
-
id: u64,
|
|
37
|
-
value: u63,
|
|
38
|
-
tombstone: u1 = 0,
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
inline fn compare_keys(a: Key, b: Key) std.math.Order {
|
|
42
|
-
return std.math.order(a.id, b.id);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
inline fn key_from_value(value: *const Key.Value) Key {
|
|
46
|
-
return Key{ .id = value.id };
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const sentinel_key = Key{
|
|
50
|
-
.id = std.math.maxInt(u64),
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
inline fn tombstone(value: *const Key.Value) bool {
|
|
54
|
-
return value.tombstone != 0;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
inline fn tombstone_from_key(key: Key) Key.Value {
|
|
58
|
-
return Key.Value{
|
|
59
|
-
.id = key.id,
|
|
60
|
-
.value = 0,
|
|
61
|
-
.tombstone = 1,
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
const FuzzOpTag = std.meta.Tag(FuzzOp);
|
|
67
|
-
const FuzzOp = union(enum) {
|
|
68
|
-
// TODO Test range queries.
|
|
69
|
-
compact: struct {
|
|
70
|
-
op: u64,
|
|
71
|
-
checkpoint: bool,
|
|
72
|
-
},
|
|
73
|
-
put: Key.Value,
|
|
74
|
-
remove: Key.Value,
|
|
75
|
-
get: Key,
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
const batch_size_max = constants.message_size_max - @sizeOf(vsr.Header);
|
|
79
|
-
const commit_entries_max = @divFloor(batch_size_max, @sizeOf(Key.Value));
|
|
80
|
-
const value_count_max = constants.lsm_batch_multiple * commit_entries_max;
|
|
81
|
-
|
|
82
|
-
const cluster = 32;
|
|
83
|
-
const replica = 4;
|
|
84
|
-
const node_count = 1024;
|
|
85
|
-
const tree_options = .{
|
|
86
|
-
// This is the smallest size that set_associative_cache will allow us.
|
|
87
|
-
.cache_entries_max = 2048,
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
// We must call compact after every 'batch'.
|
|
91
|
-
// Every `lsm_batch_multiple` batches may put/remove `value_count_max` values.
|
|
92
|
-
// Every `FuzzOp.put` issues one remove and one put.
|
|
93
|
-
const puts_since_compact_max = @divTrunc(commit_entries_max, 2);
|
|
94
|
-
const compacts_per_checkpoint = std.math.divCeil(
|
|
95
|
-
usize,
|
|
96
|
-
constants.journal_slot_count,
|
|
97
|
-
constants.lsm_batch_multiple,
|
|
98
|
-
) catch unreachable;
|
|
99
|
-
|
|
100
|
-
fn EnvironmentType(comptime table_usage: TableUsage) type {
|
|
101
|
-
return struct {
|
|
102
|
-
const Environment = @This();
|
|
103
|
-
|
|
104
|
-
const Tree = @import("tree.zig").TreeType(Table, Storage, "Key.Value");
|
|
105
|
-
const Table = TableType(
|
|
106
|
-
Key,
|
|
107
|
-
Key.Value,
|
|
108
|
-
Key.compare_keys,
|
|
109
|
-
Key.key_from_value,
|
|
110
|
-
Key.sentinel_key,
|
|
111
|
-
Key.tombstone,
|
|
112
|
-
Key.tombstone_from_key,
|
|
113
|
-
value_count_max,
|
|
114
|
-
table_usage,
|
|
115
|
-
);
|
|
116
|
-
|
|
117
|
-
const State = enum {
|
|
118
|
-
init,
|
|
119
|
-
superblock_format,
|
|
120
|
-
superblock_open,
|
|
121
|
-
tree_init,
|
|
122
|
-
tree_open,
|
|
123
|
-
fuzzing,
|
|
124
|
-
tree_compact,
|
|
125
|
-
tree_checkpoint,
|
|
126
|
-
superblock_checkpoint,
|
|
127
|
-
tree_lookup,
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
state: State,
|
|
131
|
-
storage: *Storage,
|
|
132
|
-
message_pool: MessagePool,
|
|
133
|
-
superblock: SuperBlock,
|
|
134
|
-
superblock_context: SuperBlock.Context,
|
|
135
|
-
grid: Grid,
|
|
136
|
-
node_pool: NodePool,
|
|
137
|
-
tree: Tree,
|
|
138
|
-
lookup_context: Tree.LookupContext,
|
|
139
|
-
lookup_value: ?*const Key.Value,
|
|
140
|
-
checkpoint_op: ?u64,
|
|
141
|
-
|
|
142
|
-
pub fn run(storage: *Storage, fuzz_ops: []const FuzzOp) !void {
|
|
143
|
-
var env: Environment = undefined;
|
|
144
|
-
env.state = .init;
|
|
145
|
-
env.storage = storage;
|
|
146
|
-
|
|
147
|
-
env.message_pool = try MessagePool.init(allocator, .replica);
|
|
148
|
-
defer env.message_pool.deinit(allocator);
|
|
149
|
-
|
|
150
|
-
env.superblock = try SuperBlock.init(allocator, .{
|
|
151
|
-
.storage = env.storage,
|
|
152
|
-
.storage_size_limit = constants.storage_size_max,
|
|
153
|
-
.message_pool = &env.message_pool,
|
|
154
|
-
});
|
|
155
|
-
defer env.superblock.deinit(allocator);
|
|
156
|
-
|
|
157
|
-
env.grid = try Grid.init(allocator, &env.superblock);
|
|
158
|
-
defer env.grid.deinit(allocator);
|
|
159
|
-
|
|
160
|
-
env.node_pool = try NodePool.init(allocator, node_count);
|
|
161
|
-
defer env.node_pool.deinit(allocator);
|
|
162
|
-
|
|
163
|
-
env.tree = undefined;
|
|
164
|
-
env.lookup_value = null;
|
|
165
|
-
env.checkpoint_op = null;
|
|
166
|
-
|
|
167
|
-
try env.open_then_apply(fuzz_ops);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
fn change_state(env: *Environment, current_state: State, next_state: State) void {
|
|
171
|
-
assert(env.state == current_state);
|
|
172
|
-
env.state = next_state;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
fn tick_until_state_change(env: *Environment, current_state: State, next_state: State) void {
|
|
176
|
-
// Sometimes operations complete synchronously so we might already be in next_state before ticking.
|
|
177
|
-
//assert(env.state == current_state or env.state == next_state);
|
|
178
|
-
while (env.state == current_state) env.storage.tick();
|
|
179
|
-
assert(env.state == next_state);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
pub fn open_then_apply(env: *Environment, fuzz_ops: []const FuzzOp) !void {
|
|
183
|
-
env.change_state(.init, .superblock_format);
|
|
184
|
-
env.superblock.format(superblock_format_callback, &env.superblock_context, .{
|
|
185
|
-
.cluster = cluster,
|
|
186
|
-
.replica = replica,
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
env.tick_until_state_change(.superblock_format, .superblock_open);
|
|
190
|
-
env.superblock.open(superblock_open_callback, &env.superblock_context);
|
|
191
|
-
|
|
192
|
-
env.tick_until_state_change(.superblock_open, .tree_init);
|
|
193
|
-
env.tree = try Tree.init(allocator, &env.node_pool, &env.grid, tree_options);
|
|
194
|
-
defer env.tree.deinit(allocator);
|
|
195
|
-
|
|
196
|
-
env.change_state(.tree_init, .tree_open);
|
|
197
|
-
env.tree.open(tree_open_callback);
|
|
198
|
-
|
|
199
|
-
env.tick_until_state_change(.tree_open, .fuzzing);
|
|
200
|
-
try env.apply(fuzz_ops);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
fn superblock_format_callback(superblock_context: *SuperBlock.Context) void {
|
|
204
|
-
const env = @fieldParentPtr(@This(), "superblock_context", superblock_context);
|
|
205
|
-
env.change_state(.superblock_format, .superblock_open);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
fn superblock_open_callback(superblock_context: *SuperBlock.Context) void {
|
|
209
|
-
const env = @fieldParentPtr(@This(), "superblock_context", superblock_context);
|
|
210
|
-
env.change_state(.superblock_open, .tree_init);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
fn tree_open_callback(tree: *Tree) void {
|
|
214
|
-
const env = @fieldParentPtr(@This(), "tree", tree);
|
|
215
|
-
env.change_state(.tree_open, .fuzzing);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
pub fn compact(env: *Environment, op: u64) void {
|
|
219
|
-
env.change_state(.fuzzing, .tree_compact);
|
|
220
|
-
env.tree.compact(tree_compact_callback, op);
|
|
221
|
-
env.tick_until_state_change(.tree_compact, .fuzzing);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
fn tree_compact_callback(tree: *Tree) void {
|
|
225
|
-
const env = @fieldParentPtr(@This(), "tree", tree);
|
|
226
|
-
env.change_state(.tree_compact, .fuzzing);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
pub fn checkpoint(env: *Environment, op: u64) void {
|
|
230
|
-
assert(env.checkpoint_op == null);
|
|
231
|
-
env.checkpoint_op = op - constants.lsm_batch_multiple;
|
|
232
|
-
|
|
233
|
-
env.change_state(.fuzzing, .tree_checkpoint);
|
|
234
|
-
env.tree.checkpoint(tree_checkpoint_callback);
|
|
235
|
-
env.tick_until_state_change(.tree_checkpoint, .superblock_checkpoint);
|
|
236
|
-
env.tick_until_state_change(.superblock_checkpoint, .fuzzing);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
fn tree_checkpoint_callback(tree: *Tree) void {
|
|
240
|
-
const env = @fieldParentPtr(@This(), "tree", tree);
|
|
241
|
-
const op = env.checkpoint_op.?;
|
|
242
|
-
env.checkpoint_op = null;
|
|
243
|
-
|
|
244
|
-
env.change_state(.tree_checkpoint, .superblock_checkpoint);
|
|
245
|
-
env.superblock.checkpoint(superblock_checkpoint_callback, &env.superblock_context, .{
|
|
246
|
-
.commit_min_checksum = env.superblock.working.vsr_state.commit_min_checksum + 1,
|
|
247
|
-
.commit_min = op,
|
|
248
|
-
.commit_max = op + 1,
|
|
249
|
-
});
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
fn superblock_checkpoint_callback(superblock_context: *SuperBlock.Context) void {
|
|
253
|
-
const env = @fieldParentPtr(@This(), "superblock_context", superblock_context);
|
|
254
|
-
env.change_state(.superblock_checkpoint, .fuzzing);
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
pub fn get(env: *Environment, key: Key) ?*const Key.Value {
|
|
258
|
-
env.change_state(.fuzzing, .tree_lookup);
|
|
259
|
-
|
|
260
|
-
if (env.tree.lookup_from_memory(env.tree.lookup_snapshot_max, key)) |value| {
|
|
261
|
-
env.change_state(.tree_lookup, .fuzzing);
|
|
262
|
-
return Tree.unwrap_tombstone(value);
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
env.lookup_value = null;
|
|
266
|
-
env.tree.lookup_from_levels(get_callback, &env.lookup_context, env.tree.lookup_snapshot_max, key);
|
|
267
|
-
env.tick_until_state_change(.tree_lookup, .fuzzing);
|
|
268
|
-
return env.lookup_value;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
fn get_callback(lookup_context: *Tree.LookupContext, value: ?*const Key.Value) void {
|
|
272
|
-
const env = @fieldParentPtr(Environment, "lookup_context", lookup_context);
|
|
273
|
-
assert(env.lookup_value == null);
|
|
274
|
-
env.lookup_value = value;
|
|
275
|
-
env.change_state(.tree_lookup, .fuzzing);
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
pub fn apply(env: *Environment, fuzz_ops: []const FuzzOp) !void {
|
|
279
|
-
// The tree should behave like a simple key-value data-structure.
|
|
280
|
-
// We'll compare it to a hash map.
|
|
281
|
-
var model = std.hash_map.AutoHashMap(Key, Key.Value).init(allocator);
|
|
282
|
-
defer model.deinit();
|
|
283
|
-
|
|
284
|
-
for (fuzz_ops) |fuzz_op, fuzz_op_index| {
|
|
285
|
-
assert(env.state == .fuzzing);
|
|
286
|
-
log.debug("Running fuzz_ops[{}/{}] == {}", .{ fuzz_op_index, fuzz_ops.len, fuzz_op });
|
|
287
|
-
|
|
288
|
-
const storage_size_used = env.storage.size_used();
|
|
289
|
-
log.debug("storage.size_used = {}/{}", .{ storage_size_used, env.storage.size });
|
|
290
|
-
|
|
291
|
-
const model_size = model.count() * @sizeOf(Key.Value);
|
|
292
|
-
log.debug("space_amplification = {d:.2}", .{
|
|
293
|
-
@intToFloat(f64, storage_size_used) / @intToFloat(f64, model_size),
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
// Apply fuzz_op to the tree and the model.
|
|
297
|
-
switch (fuzz_op) {
|
|
298
|
-
.compact => |compact| {
|
|
299
|
-
env.compact(compact.op);
|
|
300
|
-
if (compact.checkpoint) env.checkpoint(compact.op);
|
|
301
|
-
},
|
|
302
|
-
.put => |value| {
|
|
303
|
-
if (table_usage == .secondary_index) {
|
|
304
|
-
if (model.get(Key.key_from_value(&value))) |old_value| {
|
|
305
|
-
// Not allowed to put a present key without removing the old value first.
|
|
306
|
-
env.tree.remove(&old_value);
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
env.tree.put(&value);
|
|
310
|
-
try model.put(Key.key_from_value(&value), value);
|
|
311
|
-
},
|
|
312
|
-
.remove => |value| {
|
|
313
|
-
if (table_usage == .secondary_index and !model.contains((Key.key_from_value(&value)))) {
|
|
314
|
-
// Not allowed to remove non-present keys
|
|
315
|
-
} else {
|
|
316
|
-
env.tree.remove(&value);
|
|
317
|
-
}
|
|
318
|
-
_ = model.remove(Key.key_from_value(&value));
|
|
319
|
-
},
|
|
320
|
-
.get => |key| {
|
|
321
|
-
// Get account from lsm.
|
|
322
|
-
const tree_value = env.get(key);
|
|
323
|
-
|
|
324
|
-
// Compare result to model.
|
|
325
|
-
const model_value = model.get(key);
|
|
326
|
-
if (model_value == null) {
|
|
327
|
-
assert(tree_value == null);
|
|
328
|
-
} else {
|
|
329
|
-
switch (table_usage) {
|
|
330
|
-
.general => {
|
|
331
|
-
assert(std.mem.eql(
|
|
332
|
-
u8,
|
|
333
|
-
std.mem.asBytes(&model_value.?),
|
|
334
|
-
std.mem.asBytes(tree_value.?),
|
|
335
|
-
));
|
|
336
|
-
},
|
|
337
|
-
.secondary_index => {
|
|
338
|
-
// secondary_index only preserves keys - may return old values
|
|
339
|
-
assert(std.mem.eql(
|
|
340
|
-
u8,
|
|
341
|
-
std.mem.asBytes(&Key.key_from_value(&model_value.?)),
|
|
342
|
-
std.mem.asBytes(&Key.key_from_value(tree_value.?)),
|
|
343
|
-
));
|
|
344
|
-
},
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
},
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
};
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
fn random_id(random: std.rand.Random, comptime Int: type) Int {
|
|
355
|
-
// We have two opposing desires for random ids:
|
|
356
|
-
const avg_int: Int = if (random.boolean())
|
|
357
|
-
// 1. We want to cause many collisions.
|
|
358
|
-
//8
|
|
359
|
-
100 * constants.lsm_growth_factor * tree_options.cache_entries_max
|
|
360
|
-
else
|
|
361
|
-
// 2. We want to generate enough ids that the cache can't hold them all.
|
|
362
|
-
constants.lsm_growth_factor * tree_options.cache_entries_max;
|
|
363
|
-
return fuzz.random_int_exponential(random, Int, avg_int);
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
pub fn generate_fuzz_ops(random: std.rand.Random, fuzz_op_count: usize) ![]const FuzzOp {
|
|
367
|
-
log.info("fuzz_op_count = {}", .{fuzz_op_count});
|
|
368
|
-
|
|
369
|
-
const fuzz_ops = try allocator.alloc(FuzzOp, fuzz_op_count);
|
|
370
|
-
errdefer allocator.free(fuzz_ops);
|
|
371
|
-
|
|
372
|
-
var fuzz_op_distribution = fuzz.Distribution(FuzzOpTag){
|
|
373
|
-
// Maybe compact more often than forced to by `puts_since_compact`.
|
|
374
|
-
.compact = if (random.boolean()) 0 else 1,
|
|
375
|
-
// Always do puts, and always more puts than removes.
|
|
376
|
-
.put = constants.lsm_batch_multiple * 2,
|
|
377
|
-
// Maybe do some removes.
|
|
378
|
-
.remove = if (random.boolean()) 0 else constants.lsm_batch_multiple,
|
|
379
|
-
// Maybe do some gets.
|
|
380
|
-
.get = if (random.boolean()) 0 else constants.lsm_batch_multiple,
|
|
381
|
-
};
|
|
382
|
-
log.info("fuzz_op_distribution = {d:.2}", .{fuzz_op_distribution});
|
|
383
|
-
|
|
384
|
-
log.info("puts_since_compact_max = {}", .{puts_since_compact_max});
|
|
385
|
-
log.info("compacts_per_checkpoint = {}", .{compacts_per_checkpoint});
|
|
386
|
-
|
|
387
|
-
var op: u64 = 1;
|
|
388
|
-
var puts_since_compact: usize = 0;
|
|
389
|
-
for (fuzz_ops) |*fuzz_op| {
|
|
390
|
-
const fuzz_op_tag = if (puts_since_compact >= puts_since_compact_max)
|
|
391
|
-
// We have to compact before doing any other operations.
|
|
392
|
-
FuzzOpTag.compact
|
|
393
|
-
else
|
|
394
|
-
// Otherwise pick a random FuzzOp.
|
|
395
|
-
fuzz.random_enum(random, FuzzOpTag, fuzz_op_distribution);
|
|
396
|
-
fuzz_op.* = switch (fuzz_op_tag) {
|
|
397
|
-
.compact => compact: {
|
|
398
|
-
const compact_op = op;
|
|
399
|
-
op += 1;
|
|
400
|
-
const is_checkpoint =
|
|
401
|
-
// Can only checkpoint on the last beat of the bar.
|
|
402
|
-
compact_op % constants.lsm_batch_multiple == constants.lsm_batch_multiple - 1 and
|
|
403
|
-
compact_op > constants.lsm_batch_multiple and
|
|
404
|
-
// Checkpoint at roughly the same rate as log wraparound.
|
|
405
|
-
random.uintLessThan(usize, compacts_per_checkpoint) == 0;
|
|
406
|
-
break :compact FuzzOp{
|
|
407
|
-
.compact = .{
|
|
408
|
-
.op = compact_op,
|
|
409
|
-
.checkpoint = is_checkpoint,
|
|
410
|
-
},
|
|
411
|
-
};
|
|
412
|
-
},
|
|
413
|
-
.put => FuzzOp{ .put = .{
|
|
414
|
-
.id = random_id(random, u64),
|
|
415
|
-
.value = random.int(u63),
|
|
416
|
-
} },
|
|
417
|
-
.remove => FuzzOp{ .remove = .{
|
|
418
|
-
.id = random_id(random, u64),
|
|
419
|
-
.value = random.int(u63),
|
|
420
|
-
} },
|
|
421
|
-
.get => FuzzOp{ .get = .{
|
|
422
|
-
.id = random_id(random, u64),
|
|
423
|
-
} },
|
|
424
|
-
};
|
|
425
|
-
switch (fuzz_op.*) {
|
|
426
|
-
.compact => puts_since_compact = 0,
|
|
427
|
-
// Tree.remove() works by inserting a tombstone, so it counts as a put.
|
|
428
|
-
.put, .remove => puts_since_compact += 1,
|
|
429
|
-
.get => {},
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
return fuzz_ops;
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
pub fn main() !void {
|
|
437
|
-
try tracer.init(allocator);
|
|
438
|
-
defer tracer.deinit(allocator);
|
|
439
|
-
|
|
440
|
-
const fuzz_args = try fuzz.parse_fuzz_args(allocator);
|
|
441
|
-
|
|
442
|
-
var rng = std.rand.DefaultPrng.init(fuzz_args.seed);
|
|
443
|
-
const random = rng.random();
|
|
444
|
-
|
|
445
|
-
const table_usage = random.enumValue(TableUsage);
|
|
446
|
-
log.info("table_usage={}", .{table_usage});
|
|
447
|
-
|
|
448
|
-
const storage_options = .{
|
|
449
|
-
.seed = random.int(u64),
|
|
450
|
-
.read_latency_min = 0,
|
|
451
|
-
.read_latency_mean = 0 + fuzz.random_int_exponential(random, u64, 20),
|
|
452
|
-
.write_latency_min = 0,
|
|
453
|
-
.write_latency_mean = 0 + fuzz.random_int_exponential(random, u64, 20),
|
|
454
|
-
};
|
|
455
|
-
|
|
456
|
-
const fuzz_op_count = @minimum(
|
|
457
|
-
fuzz_args.events_max orelse @as(usize, 1E7),
|
|
458
|
-
fuzz.random_int_exponential(random, usize, 1E6),
|
|
459
|
-
);
|
|
460
|
-
|
|
461
|
-
const fuzz_ops = try generate_fuzz_ops(random, fuzz_op_count);
|
|
462
|
-
defer allocator.free(fuzz_ops);
|
|
463
|
-
|
|
464
|
-
// Init mocked storage.
|
|
465
|
-
var storage = try Storage.init(allocator, constants.storage_size_max, storage_options);
|
|
466
|
-
defer storage.deinit(allocator);
|
|
467
|
-
|
|
468
|
-
// TODO Use inline switch after upgrading to zig 0.10
|
|
469
|
-
switch (table_usage) {
|
|
470
|
-
.general => {
|
|
471
|
-
try EnvironmentType(.general).run(&storage, fuzz_ops);
|
|
472
|
-
},
|
|
473
|
-
.secondary_index => {
|
|
474
|
-
try EnvironmentType(.secondary_index).run(&storage, fuzz_ops);
|
|
475
|
-
},
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
log.info("Passed!", .{});
|
|
479
|
-
}
|