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,474 +0,0 @@
|
|
|
1
|
-
const std = @import("std");
|
|
2
|
-
const assert = std.debug.assert;
|
|
3
|
-
const math = std.math;
|
|
4
|
-
const mem = std.mem;
|
|
5
|
-
|
|
6
|
-
const Direction = @import("direction.zig").Direction;
|
|
7
|
-
|
|
8
|
-
pub fn KWayMergeIterator(
|
|
9
|
-
comptime Context: type,
|
|
10
|
-
comptime Key: type,
|
|
11
|
-
comptime Value: type,
|
|
12
|
-
comptime key_from_value: fn (*const Value) callconv(.Inline) Key,
|
|
13
|
-
comptime compare_keys: fn (Key, Key) callconv(.Inline) math.Order,
|
|
14
|
-
comptime k_max: u32,
|
|
15
|
-
/// Peek the next key in the stream identified by stream_index.
|
|
16
|
-
/// For example, peek(stream_index=2) returns user_streams[2][0].
|
|
17
|
-
comptime stream_peek: fn (
|
|
18
|
-
context: *const Context,
|
|
19
|
-
stream_index: u32,
|
|
20
|
-
) error{ Empty, Drained }!Key,
|
|
21
|
-
comptime stream_pop: fn (context: *Context, stream_index: u32) Value,
|
|
22
|
-
/// Returns true if stream A has higher precedence than stream B.
|
|
23
|
-
/// This is used to deduplicate values across streams.
|
|
24
|
-
comptime stream_precedence: fn (context: *const Context, a: u32, b: u32) bool,
|
|
25
|
-
) type {
|
|
26
|
-
return struct {
|
|
27
|
-
const Self = @This();
|
|
28
|
-
|
|
29
|
-
context: *Context,
|
|
30
|
-
|
|
31
|
-
/// Array of keys, with each key representing the next key in each stream.
|
|
32
|
-
///
|
|
33
|
-
/// `keys` is *almost* structured as a binary heap — to become a heap, streams[0] must be
|
|
34
|
-
/// peeked and sifted (see pop_internal()).
|
|
35
|
-
///
|
|
36
|
-
/// * When `direction=ascending`, keys are ordered low-to-high.
|
|
37
|
-
/// * When `direction=descending`, keys are ordered high-to-low.
|
|
38
|
-
/// * Equivalent keys are ordered from high precedence to low.
|
|
39
|
-
keys: [k_max]Key,
|
|
40
|
-
|
|
41
|
-
/// For each key in keys above, the corresponding index of the stream containing that key.
|
|
42
|
-
/// This decouples the order and storage of streams, the user being responsible for storage.
|
|
43
|
-
/// The user's streams array is never reordered while keys are swapped, only this mapping.
|
|
44
|
-
streams: [k_max]u32,
|
|
45
|
-
|
|
46
|
-
/// The number of streams remaining in the iterator.
|
|
47
|
-
k: u32,
|
|
48
|
-
|
|
49
|
-
direction: Direction,
|
|
50
|
-
previous_key_popped: ?Key = null,
|
|
51
|
-
|
|
52
|
-
/// This function may create an Iterator with k being less than stream_count_max if
|
|
53
|
-
/// stream_peek() for one of the streams immediately returns null.
|
|
54
|
-
pub fn init(context: *Context, stream_count_max: u32, direction: Direction) Self {
|
|
55
|
-
// TODO Do we ever expect stream_count_max to be 0?
|
|
56
|
-
assert(stream_count_max <= k_max);
|
|
57
|
-
|
|
58
|
-
var it: Self = .{
|
|
59
|
-
.context = context,
|
|
60
|
-
.keys = undefined,
|
|
61
|
-
.streams = undefined,
|
|
62
|
-
.k = 0,
|
|
63
|
-
.direction = direction,
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
// We must loop on stream_index but assign at it.k, as k may be less than stream_index
|
|
67
|
-
// when there are empty streams.
|
|
68
|
-
// TODO Do we have test coverage for this edge case?
|
|
69
|
-
var stream_index: u32 = 0;
|
|
70
|
-
while (stream_index < stream_count_max) : (stream_index += 1) {
|
|
71
|
-
it.keys[it.k] = stream_peek(context, stream_index) catch |err| switch (err) {
|
|
72
|
-
// On initialization, the streams should either have data already
|
|
73
|
-
// buffered up to peek or be empty and have no more values to produce.
|
|
74
|
-
error.Drained => unreachable,
|
|
75
|
-
error.Empty => continue,
|
|
76
|
-
};
|
|
77
|
-
it.streams[it.k] = stream_index;
|
|
78
|
-
it.up_heap(it.k);
|
|
79
|
-
it.k += 1;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return it;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
pub fn empty(it: Self) bool {
|
|
86
|
-
return it.k == 0;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
pub fn pop(it: *Self) ?Value {
|
|
90
|
-
while (it.pop_internal()) |value| {
|
|
91
|
-
const key = key_from_value(&value);
|
|
92
|
-
if (it.previous_key_popped) |previous| {
|
|
93
|
-
switch (compare_keys(previous, key)) {
|
|
94
|
-
.lt => assert(it.direction == .ascending),
|
|
95
|
-
// Discard this value and pop the next one.
|
|
96
|
-
.eq => continue,
|
|
97
|
-
.gt => assert(it.direction == .descending),
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
it.previous_key_popped = key;
|
|
101
|
-
return value;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return null;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
fn pop_internal(it: *Self) ?Value {
|
|
108
|
-
if (it.k == 0) return null;
|
|
109
|
-
|
|
110
|
-
// We update the heap prior to removing the value from the stream. If we updated after
|
|
111
|
-
// stream_pop() instead, when stream_peek() returns Drained we would be unable to order
|
|
112
|
-
// the heap, and when the stream does buffer data it would be out of position.
|
|
113
|
-
if (stream_peek(it.context, it.streams[0])) |key| {
|
|
114
|
-
it.keys[0] = key;
|
|
115
|
-
it.down_heap();
|
|
116
|
-
} else |err| switch (err) {
|
|
117
|
-
error.Drained => return null,
|
|
118
|
-
error.Empty => {
|
|
119
|
-
it.swap(0, it.k - 1);
|
|
120
|
-
it.k -= 1;
|
|
121
|
-
it.down_heap();
|
|
122
|
-
},
|
|
123
|
-
}
|
|
124
|
-
if (it.k == 0) return null;
|
|
125
|
-
|
|
126
|
-
const root = it.streams[0];
|
|
127
|
-
const value = stream_pop(it.context, root);
|
|
128
|
-
|
|
129
|
-
return value;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
fn up_heap(it: *Self, start: u32) void {
|
|
133
|
-
var i = start;
|
|
134
|
-
while (parent(i)) |p| : (i = p) {
|
|
135
|
-
if (it.ordered(p, i)) break;
|
|
136
|
-
it.swap(p, i);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// Start at the root node.
|
|
141
|
-
// Compare the current node with its children, if the order is correct stop.
|
|
142
|
-
// If the order is incorrect, swap the current node with the appropriate child.
|
|
143
|
-
fn down_heap(it: *Self) void {
|
|
144
|
-
if (it.k == 0) return;
|
|
145
|
-
var i: u32 = 0;
|
|
146
|
-
// A maximum of height iterations are required. After height iterations we are
|
|
147
|
-
// guaranteed to have reached a leaf node, in which case we are always done.
|
|
148
|
-
var safety_count: u32 = 0;
|
|
149
|
-
const binary_tree_height = math.log2_int(u32, it.k) + 1;
|
|
150
|
-
while (safety_count < binary_tree_height) : (safety_count += 1) {
|
|
151
|
-
const left = left_child(i, it.k);
|
|
152
|
-
const right = right_child(i, it.k);
|
|
153
|
-
|
|
154
|
-
if (it.ordered(i, left)) {
|
|
155
|
-
if (it.ordered(i, right)) {
|
|
156
|
-
break;
|
|
157
|
-
} else {
|
|
158
|
-
it.swap(i, right.?);
|
|
159
|
-
i = right.?;
|
|
160
|
-
}
|
|
161
|
-
} else if (it.ordered(i, right)) {
|
|
162
|
-
it.swap(i, left.?);
|
|
163
|
-
i = left.?;
|
|
164
|
-
} else if (it.ordered(left.?, right.?)) {
|
|
165
|
-
it.swap(i, left.?);
|
|
166
|
-
i = left.?;
|
|
167
|
-
} else {
|
|
168
|
-
it.swap(i, right.?);
|
|
169
|
-
i = right.?;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
assert(safety_count < binary_tree_height);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
fn parent(node: u32) ?u32 {
|
|
176
|
-
if (node == 0) return null;
|
|
177
|
-
return (node - 1) / 2;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
fn left_child(node: u32, k: u32) ?u32 {
|
|
181
|
-
const child = 2 * node + 1;
|
|
182
|
-
return if (child < k) child else null;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
fn right_child(node: u32, k: u32) ?u32 {
|
|
186
|
-
const child = 2 * node + 2;
|
|
187
|
-
return if (child < k) child else null;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
fn swap(it: *Self, a: u32, b: u32) void {
|
|
191
|
-
mem.swap(Key, &it.keys[a], &it.keys[b]);
|
|
192
|
-
mem.swap(u32, &it.streams[a], &it.streams[b]);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
inline fn ordered(it: Self, a: u32, b: ?u32) bool {
|
|
196
|
-
return b == null or switch (compare_keys(it.keys[a], it.keys[b.?])) {
|
|
197
|
-
.lt => it.direction == .ascending,
|
|
198
|
-
.eq => stream_precedence(it.context, it.streams[a], it.streams[b.?]),
|
|
199
|
-
.gt => it.direction == .descending,
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
};
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
fn TestContext(comptime k_max: u32) type {
|
|
206
|
-
const testing = std.testing;
|
|
207
|
-
|
|
208
|
-
return struct {
|
|
209
|
-
const Self = @This();
|
|
210
|
-
|
|
211
|
-
const log = false;
|
|
212
|
-
|
|
213
|
-
const Value = struct {
|
|
214
|
-
key: u32,
|
|
215
|
-
version: u32,
|
|
216
|
-
|
|
217
|
-
inline fn to_key(v: *const Value) u32 {
|
|
218
|
-
return v.key;
|
|
219
|
-
}
|
|
220
|
-
};
|
|
221
|
-
|
|
222
|
-
streams: [k_max][]const Value,
|
|
223
|
-
|
|
224
|
-
inline fn compare_keys(a: u32, b: u32) math.Order {
|
|
225
|
-
return math.order(a, b);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
fn stream_peek(context: *const Self, stream_index: u32) error{ Empty, Drained }!u32 {
|
|
229
|
-
// TODO: test for Drained somehow as well
|
|
230
|
-
const stream = context.streams[stream_index];
|
|
231
|
-
if (stream.len == 0) return error.Empty;
|
|
232
|
-
return stream[0].key;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
fn stream_pop(context: *Self, stream_index: u32) Value {
|
|
236
|
-
const stream = context.streams[stream_index];
|
|
237
|
-
context.streams[stream_index] = stream[1..];
|
|
238
|
-
return stream[0];
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
fn stream_precedence(context: *const Self, a: u32, b: u32) bool {
|
|
242
|
-
_ = context;
|
|
243
|
-
|
|
244
|
-
// Higher streams have higher precedence
|
|
245
|
-
return a > b;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
fn merge(
|
|
249
|
-
direction: Direction,
|
|
250
|
-
streams_keys: []const []const u32,
|
|
251
|
-
expect: []const Value,
|
|
252
|
-
) !void {
|
|
253
|
-
const KWay = KWayMergeIterator(
|
|
254
|
-
Self,
|
|
255
|
-
u32,
|
|
256
|
-
Value,
|
|
257
|
-
Value.to_key,
|
|
258
|
-
compare_keys,
|
|
259
|
-
k_max,
|
|
260
|
-
stream_peek,
|
|
261
|
-
stream_pop,
|
|
262
|
-
stream_precedence,
|
|
263
|
-
);
|
|
264
|
-
var actual = std.ArrayList(Value).init(testing.allocator);
|
|
265
|
-
defer actual.deinit();
|
|
266
|
-
|
|
267
|
-
var streams: [k_max][]Value = undefined;
|
|
268
|
-
|
|
269
|
-
for (streams_keys) |stream_keys, i| {
|
|
270
|
-
errdefer for (streams[0..i]) |s| testing.allocator.free(s);
|
|
271
|
-
streams[i] = try testing.allocator.alloc(Value, stream_keys.len);
|
|
272
|
-
for (stream_keys) |key, j| {
|
|
273
|
-
streams[i][j] = .{
|
|
274
|
-
.key = key,
|
|
275
|
-
.version = @intCast(u32, i),
|
|
276
|
-
};
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
defer for (streams[0..streams_keys.len]) |s| testing.allocator.free(s);
|
|
280
|
-
|
|
281
|
-
var context: Self = .{ .streams = streams };
|
|
282
|
-
var kway = KWay.init(&context, @intCast(u32, streams_keys.len), direction);
|
|
283
|
-
|
|
284
|
-
while (kway.pop()) |value| {
|
|
285
|
-
try actual.append(value);
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
try testing.expectEqualSlices(Value, expect, actual.items);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
fn fuzz(random: std.rand.Random, stream_key_count_max: u32) !void {
|
|
292
|
-
if (log) std.debug.print("\n", .{});
|
|
293
|
-
const allocator = testing.allocator;
|
|
294
|
-
|
|
295
|
-
var streams: [k_max][]u32 = undefined;
|
|
296
|
-
|
|
297
|
-
const streams_buffer = try allocator.alloc(u32, k_max * stream_key_count_max);
|
|
298
|
-
defer allocator.free(streams_buffer);
|
|
299
|
-
|
|
300
|
-
const expect_buffer = try allocator.alloc(Value, k_max * stream_key_count_max);
|
|
301
|
-
defer allocator.free(expect_buffer);
|
|
302
|
-
|
|
303
|
-
var k: u32 = 0;
|
|
304
|
-
while (k < k_max) : (k += 1) {
|
|
305
|
-
if (log) std.debug.print("k = {}\n", .{k});
|
|
306
|
-
{
|
|
307
|
-
var i: u32 = 0;
|
|
308
|
-
while (i < k) : (i += 1) {
|
|
309
|
-
const len = fuzz_stream_len(random, stream_key_count_max);
|
|
310
|
-
streams[i] = streams_buffer[i * stream_key_count_max ..][0..len];
|
|
311
|
-
fuzz_stream_keys(random, streams[i]);
|
|
312
|
-
|
|
313
|
-
if (log) {
|
|
314
|
-
std.debug.print("stream {} = ", .{i});
|
|
315
|
-
for (streams[i]) |key| std.debug.print("{},", .{key});
|
|
316
|
-
std.debug.print("\n", .{});
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
var expect_buffer_len: usize = 0;
|
|
322
|
-
for (streams[0..k]) |stream, version| {
|
|
323
|
-
for (stream) |key| {
|
|
324
|
-
expect_buffer[expect_buffer_len] = .{
|
|
325
|
-
.key = key,
|
|
326
|
-
.version = @intCast(u32, version),
|
|
327
|
-
};
|
|
328
|
-
expect_buffer_len += 1;
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
const expect_with_duplicates = expect_buffer[0..expect_buffer_len];
|
|
332
|
-
std.sort.sort(Value, expect_with_duplicates, {}, value_less_than);
|
|
333
|
-
|
|
334
|
-
var target: usize = 0;
|
|
335
|
-
var previous_key: ?u32 = null;
|
|
336
|
-
for (expect_with_duplicates) |value| {
|
|
337
|
-
if (previous_key) |p| {
|
|
338
|
-
if (value.key == p) continue;
|
|
339
|
-
}
|
|
340
|
-
previous_key = value.key;
|
|
341
|
-
expect_with_duplicates[target] = value;
|
|
342
|
-
target += 1;
|
|
343
|
-
}
|
|
344
|
-
const expect = expect_with_duplicates[0..target];
|
|
345
|
-
|
|
346
|
-
if (log) {
|
|
347
|
-
std.debug.print("expect = ", .{});
|
|
348
|
-
for (expect) |value| std.debug.print("({},{}),", .{ value.key, value.version });
|
|
349
|
-
std.debug.print("\n", .{});
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
try merge(.ascending, streams[0..k], expect);
|
|
353
|
-
|
|
354
|
-
for (streams[0..k]) |stream| mem.reverse(u32, stream);
|
|
355
|
-
mem.reverse(Value, expect);
|
|
356
|
-
|
|
357
|
-
try merge(.descending, streams[0..k], expect);
|
|
358
|
-
|
|
359
|
-
if (log) std.debug.print("\n", .{});
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
fn fuzz_stream_len(random: std.rand.Random, stream_key_count_max: u32) u32 {
|
|
364
|
-
return switch (random.uintLessThanBiased(u8, 100)) {
|
|
365
|
-
0...4 => 0,
|
|
366
|
-
5...9 => stream_key_count_max,
|
|
367
|
-
else => random.uintAtMostBiased(u32, stream_key_count_max),
|
|
368
|
-
};
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
fn fuzz_stream_keys(random: std.rand.Random, stream: []u32) void {
|
|
372
|
-
const key_max = random.intRangeLessThanBiased(u32, 512, 1024);
|
|
373
|
-
switch (random.uintLessThanBiased(u8, 100)) {
|
|
374
|
-
0...4 => {
|
|
375
|
-
mem.set(u32, stream, random.int(u32));
|
|
376
|
-
},
|
|
377
|
-
else => {
|
|
378
|
-
random.bytes(mem.sliceAsBytes(stream));
|
|
379
|
-
},
|
|
380
|
-
}
|
|
381
|
-
for (stream) |*key| key.* = key.* % key_max;
|
|
382
|
-
std.sort.sort(u32, stream, {}, key_less_than);
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
fn key_less_than(_: void, a: u32, b: u32) bool {
|
|
386
|
-
return a < b;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
fn value_less_than(_: void, a: Value, b: Value) bool {
|
|
390
|
-
return switch (math.order(a.key, b.key)) {
|
|
391
|
-
.lt => true,
|
|
392
|
-
.eq => a.version > b.version,
|
|
393
|
-
.gt => false,
|
|
394
|
-
};
|
|
395
|
-
}
|
|
396
|
-
};
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
test "k_way_merge: unit" {
|
|
400
|
-
try TestContext(1).merge(
|
|
401
|
-
.ascending,
|
|
402
|
-
&[_][]const u32{
|
|
403
|
-
&[_]u32{ 0, 3, 4, 8 },
|
|
404
|
-
},
|
|
405
|
-
&[_]TestContext(1).Value{
|
|
406
|
-
.{ .key = 0, .version = 0 },
|
|
407
|
-
.{ .key = 3, .version = 0 },
|
|
408
|
-
.{ .key = 4, .version = 0 },
|
|
409
|
-
.{ .key = 8, .version = 0 },
|
|
410
|
-
},
|
|
411
|
-
);
|
|
412
|
-
try TestContext(1).merge(
|
|
413
|
-
.descending,
|
|
414
|
-
&[_][]const u32{
|
|
415
|
-
&[_]u32{ 8, 4, 3, 0 },
|
|
416
|
-
},
|
|
417
|
-
&[_]TestContext(1).Value{
|
|
418
|
-
.{ .key = 8, .version = 0 },
|
|
419
|
-
.{ .key = 4, .version = 0 },
|
|
420
|
-
.{ .key = 3, .version = 0 },
|
|
421
|
-
.{ .key = 0, .version = 0 },
|
|
422
|
-
},
|
|
423
|
-
);
|
|
424
|
-
try TestContext(3).merge(
|
|
425
|
-
.ascending,
|
|
426
|
-
&[_][]const u32{
|
|
427
|
-
&[_]u32{ 0, 3, 4, 8, 11 },
|
|
428
|
-
&[_]u32{ 2, 11, 12, 13, 15 },
|
|
429
|
-
&[_]u32{ 1, 2, 11 },
|
|
430
|
-
},
|
|
431
|
-
&[_]TestContext(3).Value{
|
|
432
|
-
.{ .key = 0, .version = 0 },
|
|
433
|
-
.{ .key = 1, .version = 2 },
|
|
434
|
-
.{ .key = 2, .version = 2 },
|
|
435
|
-
.{ .key = 3, .version = 0 },
|
|
436
|
-
.{ .key = 4, .version = 0 },
|
|
437
|
-
.{ .key = 8, .version = 0 },
|
|
438
|
-
.{ .key = 11, .version = 2 },
|
|
439
|
-
.{ .key = 12, .version = 1 },
|
|
440
|
-
.{ .key = 13, .version = 1 },
|
|
441
|
-
.{ .key = 15, .version = 1 },
|
|
442
|
-
},
|
|
443
|
-
);
|
|
444
|
-
try TestContext(3).merge(
|
|
445
|
-
.descending,
|
|
446
|
-
&[_][]const u32{
|
|
447
|
-
&[_]u32{ 11, 8, 4, 3, 0 },
|
|
448
|
-
&[_]u32{ 15, 13, 12, 11, 2 },
|
|
449
|
-
&[_]u32{ 11, 2, 1 },
|
|
450
|
-
},
|
|
451
|
-
&[_]TestContext(3).Value{
|
|
452
|
-
.{ .key = 15, .version = 1 },
|
|
453
|
-
.{ .key = 13, .version = 1 },
|
|
454
|
-
.{ .key = 12, .version = 1 },
|
|
455
|
-
.{ .key = 11, .version = 2 },
|
|
456
|
-
.{ .key = 8, .version = 0 },
|
|
457
|
-
.{ .key = 4, .version = 0 },
|
|
458
|
-
.{ .key = 3, .version = 0 },
|
|
459
|
-
.{ .key = 2, .version = 2 },
|
|
460
|
-
.{ .key = 1, .version = 2 },
|
|
461
|
-
.{ .key = 0, .version = 0 },
|
|
462
|
-
},
|
|
463
|
-
);
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
test "k_way_merge: fuzz" {
|
|
467
|
-
const seed = std.crypto.random.int(u64);
|
|
468
|
-
errdefer std.debug.print("\nTEST FAILED: seed = {}\n", .{seed});
|
|
469
|
-
|
|
470
|
-
var prng = std.rand.DefaultPrng.init(seed);
|
|
471
|
-
const random = prng.random();
|
|
472
|
-
|
|
473
|
-
try TestContext(32).fuzz(random, 256);
|
|
474
|
-
}
|