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,156 +0,0 @@
|
|
|
1
|
-
const std = @import("std");
|
|
2
|
-
const builtin = @import("builtin");
|
|
3
|
-
const assert = std.debug.assert;
|
|
4
|
-
const mem = std.mem;
|
|
5
|
-
|
|
6
|
-
const constants = @import("constants.zig");
|
|
7
|
-
|
|
8
|
-
const vsr = @import("vsr.zig");
|
|
9
|
-
const Header = vsr.Header;
|
|
10
|
-
|
|
11
|
-
comptime {
|
|
12
|
-
// message_size_max must be a multiple of sector_size for Direct I/O
|
|
13
|
-
assert(constants.message_size_max % constants.sector_size == 0);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/// The number of full-sized messages allocated at initialization by the replica message pool.
|
|
17
|
-
/// There must be enough messages to ensure that the replica can always progress, to avoid deadlock.
|
|
18
|
-
pub const messages_max_replica = messages_max: {
|
|
19
|
-
var sum: usize = 0;
|
|
20
|
-
|
|
21
|
-
sum += constants.journal_iops_read_max; // Journal reads
|
|
22
|
-
sum += constants.journal_iops_write_max; // Journal writes
|
|
23
|
-
sum += constants.clients_max; // SuperBlock.client_table
|
|
24
|
-
sum += 1; // Replica.loopback_queue
|
|
25
|
-
sum += constants.pipeline_prepare_queue_max; // Replica.Pipeline{Queue|Cache}
|
|
26
|
-
sum += constants.pipeline_request_queue_max; // Replica.Pipeline{Queue|Cache}
|
|
27
|
-
sum += 1; // Replica.commit_prepare
|
|
28
|
-
// Replica.do_view_change_from_all_replicas quorum:
|
|
29
|
-
// Replica.recovery_response_quorum is only used for recovery and does not increase the limit.
|
|
30
|
-
// All other quorums are bitsets.
|
|
31
|
-
sum += constants.replicas_max;
|
|
32
|
-
sum += constants.connections_max; // Connection.recv_message
|
|
33
|
-
sum += constants.connections_max * constants.connection_send_queue_max_replica; // Connection.send_queue
|
|
34
|
-
sum += 1; // Handle bursts (e.g. Connection.parse_message)
|
|
35
|
-
// Handle Replica.commit_op's reply:
|
|
36
|
-
// (This is separate from the burst +1 because they may occur concurrently).
|
|
37
|
-
sum += 1;
|
|
38
|
-
|
|
39
|
-
break :messages_max sum;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
/// The number of full-sized messages allocated at initialization by the client message pool.
|
|
43
|
-
pub const messages_max_client = messages_max: {
|
|
44
|
-
var sum: usize = 0;
|
|
45
|
-
|
|
46
|
-
sum += constants.replicas_max; // Connection.recv_message
|
|
47
|
-
sum += constants.replicas_max * constants.connection_send_queue_max_client; // Connection.send_queue
|
|
48
|
-
sum += constants.client_request_queue_max; // Client.request_queue
|
|
49
|
-
// Handle bursts (e.g. Connection.parse_message, or sending a ping when the send queue is full).
|
|
50
|
-
sum += 1;
|
|
51
|
-
|
|
52
|
-
break :messages_max sum;
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
comptime {
|
|
56
|
-
// These conditions are necessary (but not sufficient) to prevent deadlocks.
|
|
57
|
-
assert(messages_max_replica > constants.replicas_max);
|
|
58
|
-
assert(messages_max_client > constants.client_request_queue_max);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/// A pool of reference-counted Messages, memory for which is allocated only once during
|
|
62
|
-
/// initialization and reused thereafter. The messages_max values determine the size of this pool.
|
|
63
|
-
pub const MessagePool = struct {
|
|
64
|
-
pub const Message = struct {
|
|
65
|
-
// TODO: replace this with a header() function to save memory
|
|
66
|
-
header: *Header,
|
|
67
|
-
buffer: *align(constants.sector_size) [constants.message_size_max]u8,
|
|
68
|
-
references: u32 = 0,
|
|
69
|
-
next: ?*Message,
|
|
70
|
-
|
|
71
|
-
/// Increment the reference count of the message and return the same pointer passed.
|
|
72
|
-
pub fn ref(message: *Message) *Message {
|
|
73
|
-
message.references += 1;
|
|
74
|
-
return message;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
pub fn body(message: *const Message) []align(@sizeOf(Header)) u8 {
|
|
78
|
-
return message.buffer[@sizeOf(Header)..message.header.size];
|
|
79
|
-
}
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
/// List of currently unused messages.
|
|
83
|
-
free_list: ?*Message,
|
|
84
|
-
|
|
85
|
-
messages_max: usize,
|
|
86
|
-
|
|
87
|
-
pub fn init(allocator: mem.Allocator, process_type: vsr.ProcessType) error{OutOfMemory}!MessagePool {
|
|
88
|
-
return MessagePool.init_capacity(allocator, switch (process_type) {
|
|
89
|
-
.replica => messages_max_replica,
|
|
90
|
-
.client => messages_max_client,
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
pub fn init_capacity(allocator: mem.Allocator, messages_max: usize) error{OutOfMemory}!MessagePool {
|
|
95
|
-
var pool: MessagePool = .{
|
|
96
|
-
.free_list = null,
|
|
97
|
-
.messages_max = messages_max,
|
|
98
|
-
};
|
|
99
|
-
{
|
|
100
|
-
var i: usize = 0;
|
|
101
|
-
while (i < messages_max) : (i += 1) {
|
|
102
|
-
const buffer = try allocator.allocAdvanced(
|
|
103
|
-
u8,
|
|
104
|
-
constants.sector_size,
|
|
105
|
-
constants.message_size_max,
|
|
106
|
-
.exact,
|
|
107
|
-
);
|
|
108
|
-
const message = try allocator.create(Message);
|
|
109
|
-
message.* = .{
|
|
110
|
-
.header = mem.bytesAsValue(Header, buffer[0..@sizeOf(Header)]),
|
|
111
|
-
.buffer = buffer[0..constants.message_size_max],
|
|
112
|
-
.next = pool.free_list,
|
|
113
|
-
};
|
|
114
|
-
pool.free_list = message;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
return pool;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/// Frees all messages that were unused or returned to the pool via unref().
|
|
122
|
-
pub fn deinit(pool: *MessagePool, allocator: mem.Allocator) void {
|
|
123
|
-
var free_count: usize = 0;
|
|
124
|
-
while (pool.free_list) |message| {
|
|
125
|
-
pool.free_list = message.next;
|
|
126
|
-
allocator.free(@as([]const u8, message.buffer));
|
|
127
|
-
allocator.destroy(message);
|
|
128
|
-
free_count += 1;
|
|
129
|
-
}
|
|
130
|
-
// If the MessagePool is being deinitialized, all messages should have already been
|
|
131
|
-
// released to the pool.
|
|
132
|
-
assert(free_count == pool.messages_max);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/// Get an unused message with a buffer of constants.message_size_max.
|
|
136
|
-
/// The returned message has exactly one reference.
|
|
137
|
-
pub fn get_message(pool: *MessagePool) *Message {
|
|
138
|
-
const message = pool.free_list.?;
|
|
139
|
-
pool.free_list = message.next;
|
|
140
|
-
message.next = null;
|
|
141
|
-
assert(message.references == 0);
|
|
142
|
-
|
|
143
|
-
message.references = 1;
|
|
144
|
-
return message;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/// Decrement the reference count of the message, possibly freeing it.
|
|
148
|
-
pub fn unref(pool: *MessagePool, message: *Message) void {
|
|
149
|
-
message.references -= 1;
|
|
150
|
-
if (message.references == 0) {
|
|
151
|
-
mem.set(u8, message.buffer, 0);
|
|
152
|
-
message.next = pool.free_list;
|
|
153
|
-
pool.free_list = message;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
};
|
|
@@ -1,399 +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 stdx = @import("stdx.zig");
|
|
7
|
-
|
|
8
|
-
/// A First In, First Out ring buffer holding at most `count_max` elements.
|
|
9
|
-
pub fn RingBuffer(
|
|
10
|
-
comptime T: type,
|
|
11
|
-
comptime count_max_: usize,
|
|
12
|
-
comptime buffer_type: enum { array, pointer },
|
|
13
|
-
) type {
|
|
14
|
-
return struct {
|
|
15
|
-
const Self = @This();
|
|
16
|
-
|
|
17
|
-
pub const count_max = count_max_;
|
|
18
|
-
|
|
19
|
-
buffer: switch (buffer_type) {
|
|
20
|
-
.array => [count_max]T,
|
|
21
|
-
.pointer => *[count_max]T,
|
|
22
|
-
} = switch (buffer_type) {
|
|
23
|
-
.array => undefined,
|
|
24
|
-
.pointer => @compileError("init() must be used if buffer_type is .pointer!"),
|
|
25
|
-
},
|
|
26
|
-
|
|
27
|
-
/// The index of the slot with the first item, if any.
|
|
28
|
-
index: usize = 0,
|
|
29
|
-
|
|
30
|
-
/// The number of items in the buffer.
|
|
31
|
-
count: usize = 0,
|
|
32
|
-
|
|
33
|
-
pub usingnamespace switch (buffer_type) {
|
|
34
|
-
.array => struct {},
|
|
35
|
-
.pointer => struct {
|
|
36
|
-
pub fn init(allocator: mem.Allocator) !Self {
|
|
37
|
-
const buffer = try allocator.create([count_max]T);
|
|
38
|
-
errdefer allocator.destroy(buffer);
|
|
39
|
-
return Self{ .buffer = buffer };
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
pub fn deinit(self: *Self, allocator: mem.Allocator) void {
|
|
43
|
-
allocator.destroy(self.buffer);
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
// TODO Add doc comments to these functions:
|
|
49
|
-
pub inline fn head(self: Self) ?T {
|
|
50
|
-
if (count_max == 0 or self.empty()) return null;
|
|
51
|
-
return self.buffer[self.index];
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
pub inline fn head_ptr(self: *Self) ?*T {
|
|
55
|
-
if (count_max == 0 or self.empty()) return null;
|
|
56
|
-
return &self.buffer[self.index];
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
pub inline fn head_ptr_const(self: *const Self) ?*const T {
|
|
60
|
-
if (count_max == 0 or self.empty()) return null;
|
|
61
|
-
return &self.buffer[self.index];
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
pub inline fn tail(self: Self) ?T {
|
|
65
|
-
if (count_max == 0 or self.empty()) return null;
|
|
66
|
-
return self.buffer[(self.index + self.count - 1) % self.buffer.len];
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
pub inline fn tail_ptr(self: *Self) ?*T {
|
|
70
|
-
if (count_max == 0 or self.empty()) return null;
|
|
71
|
-
return &self.buffer[(self.index + self.count - 1) % self.buffer.len];
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
pub inline fn tail_ptr_const(self: *const Self) ?*const T {
|
|
75
|
-
if (count_max == 0 or self.empty()) return null;
|
|
76
|
-
return &self.buffer[(self.index + self.count - 1) % self.buffer.len];
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
pub inline fn get_ptr(self: *Self, index: usize) ?*T {
|
|
80
|
-
if (count_max == 0) unreachable;
|
|
81
|
-
|
|
82
|
-
if (index < self.count) {
|
|
83
|
-
return &self.buffer[(self.index + index) % self.buffer.len];
|
|
84
|
-
} else {
|
|
85
|
-
assert(index < count_max);
|
|
86
|
-
return null;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
pub inline fn next_tail(self: Self) ?T {
|
|
91
|
-
if (count_max == 0 or self.full()) return null;
|
|
92
|
-
return self.buffer[(self.index + self.count) % self.buffer.len];
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
pub inline fn next_tail_ptr(self: *Self) ?*T {
|
|
96
|
-
if (count_max == 0 or self.full()) return null;
|
|
97
|
-
return &self.buffer[(self.index + self.count) % self.buffer.len];
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
pub inline fn next_tail_ptr_const(self: *const Self) ?*const T {
|
|
101
|
-
if (count_max == 0 or self.full()) return null;
|
|
102
|
-
return &self.buffer[(self.index + self.count) % self.buffer.len];
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
pub inline fn advance_head(self: *Self) void {
|
|
106
|
-
self.index += 1;
|
|
107
|
-
self.index %= self.buffer.len;
|
|
108
|
-
self.count -= 1;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
pub inline fn advance_tail(self: *Self) void {
|
|
112
|
-
assert(self.count < self.buffer.len);
|
|
113
|
-
self.count += 1;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
pub inline fn retreat_tail(self: *Self) void {
|
|
117
|
-
self.count -= 1;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/// Returns whether the ring buffer is completely full.
|
|
121
|
-
pub inline fn full(self: Self) bool {
|
|
122
|
-
return self.count == self.buffer.len;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/// Returns whether the ring buffer is completely empty.
|
|
126
|
-
pub inline fn empty(self: Self) bool {
|
|
127
|
-
return self.count == 0;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// Higher level, less error-prone wrappers:
|
|
131
|
-
|
|
132
|
-
/// Add an element to the RingBuffer. Returns an error if the buffer
|
|
133
|
-
/// is already full and the element could not be added.
|
|
134
|
-
pub fn push(self: *Self, item: T) error{NoSpaceLeft}!void {
|
|
135
|
-
const ptr = self.next_tail_ptr() orelse return error.NoSpaceLeft;
|
|
136
|
-
ptr.* = item;
|
|
137
|
-
self.advance_tail();
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/// Add an element to a RingBuffer, and assert that the capacity is sufficient.
|
|
141
|
-
pub fn push_assume_capacity(self: *Self, item: T) void {
|
|
142
|
-
self.push(item) catch |err| switch (err) {
|
|
143
|
-
error.NoSpaceLeft => unreachable,
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
pub fn push_slice(self: *Self, items: []const T) error{NoSpaceLeft}!void {
|
|
148
|
-
if (count_max == 0) return error.NoSpaceLeft;
|
|
149
|
-
if (self.count + items.len > self.buffer.len) return error.NoSpaceLeft;
|
|
150
|
-
|
|
151
|
-
const pre_wrap_start = (self.index + self.count) % self.buffer.len;
|
|
152
|
-
const pre_wrap_count = math.min(items.len, self.buffer.len - pre_wrap_start);
|
|
153
|
-
const post_wrap_count = items.len - pre_wrap_count;
|
|
154
|
-
|
|
155
|
-
stdx.copy_disjoint(.inexact, T, self.buffer[pre_wrap_start..], items[0..pre_wrap_count]);
|
|
156
|
-
stdx.copy_disjoint(.exact, T, self.buffer[0..post_wrap_count], items[pre_wrap_count..]);
|
|
157
|
-
|
|
158
|
-
self.count += items.len;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/// Remove and return the next item, if any.
|
|
162
|
-
pub fn pop(self: *Self) ?T {
|
|
163
|
-
const result = self.head() orelse return null;
|
|
164
|
-
self.advance_head();
|
|
165
|
-
return result;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/// Remove and return the last item, if any.
|
|
169
|
-
pub fn pop_tail(self: *Self) ?T {
|
|
170
|
-
const result = self.tail() orelse return null;
|
|
171
|
-
self.retreat_tail();
|
|
172
|
-
return result;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
pub const Iterator = struct {
|
|
176
|
-
ring: *const Self,
|
|
177
|
-
count: usize = 0,
|
|
178
|
-
|
|
179
|
-
pub fn next(it: *Iterator) ?T {
|
|
180
|
-
if (count_max == 0) return null;
|
|
181
|
-
// TODO Use next_ptr() internally to avoid duplicating this code.
|
|
182
|
-
assert(it.count <= it.ring.count);
|
|
183
|
-
if (it.count == it.ring.count) return null;
|
|
184
|
-
defer it.count += 1;
|
|
185
|
-
return it.ring.buffer[(it.ring.index + it.count) % it.ring.buffer.len];
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
pub fn next_ptr(it: *Iterator) ?*const T {
|
|
189
|
-
assert(it.count <= it.ring.count);
|
|
190
|
-
if (count_max == 0) return null;
|
|
191
|
-
if (it.count == it.ring.count) return null;
|
|
192
|
-
defer it.count += 1;
|
|
193
|
-
return &it.ring.buffer[(it.ring.index + it.count) % it.ring.buffer.len];
|
|
194
|
-
}
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
/// Returns an iterator to iterate through all `count` items in the ring buffer.
|
|
198
|
-
/// The iterator is invalidated if the ring buffer is advanced.
|
|
199
|
-
pub fn iterator(self: *const Self) Iterator {
|
|
200
|
-
return .{ .ring = self };
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
pub const IteratorMutable = struct {
|
|
204
|
-
ring: *Self,
|
|
205
|
-
count: usize = 0,
|
|
206
|
-
|
|
207
|
-
pub fn next_ptr(it: *IteratorMutable) ?*T {
|
|
208
|
-
assert(it.count <= it.ring.count);
|
|
209
|
-
if (count_max == 0) return null;
|
|
210
|
-
if (it.count == it.ring.count) return null;
|
|
211
|
-
defer it.count += 1;
|
|
212
|
-
return &it.ring.buffer[(it.ring.index + it.count) % it.ring.buffer.len];
|
|
213
|
-
}
|
|
214
|
-
};
|
|
215
|
-
|
|
216
|
-
// TODO Add to tests.
|
|
217
|
-
pub fn iterator_mutable(self: *Self) IteratorMutable {
|
|
218
|
-
return .{ .ring = self };
|
|
219
|
-
}
|
|
220
|
-
};
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
const testing = std.testing;
|
|
224
|
-
|
|
225
|
-
fn test_iterator(comptime T: type, ring: *T, values: []const u32) !void {
|
|
226
|
-
const ring_index = ring.index;
|
|
227
|
-
|
|
228
|
-
var loops: usize = 0;
|
|
229
|
-
while (loops < 2) : (loops += 1) {
|
|
230
|
-
var iterator = ring.iterator();
|
|
231
|
-
var index: usize = 0;
|
|
232
|
-
while (iterator.next()) |item| {
|
|
233
|
-
try testing.expectEqual(values[index], item);
|
|
234
|
-
index += 1;
|
|
235
|
-
}
|
|
236
|
-
try testing.expectEqual(values.len, index);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
try testing.expectEqual(ring_index, ring.index);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
fn test_low_level_interface(comptime Ring: type, ring: *Ring) !void {
|
|
243
|
-
try ring.push_slice(&[_]u32{});
|
|
244
|
-
try test_iterator(Ring, ring, &[_]u32{});
|
|
245
|
-
|
|
246
|
-
try testing.expectError(error.NoSpaceLeft, ring.push_slice(&[_]u32{ 1, 2, 3 }));
|
|
247
|
-
|
|
248
|
-
try ring.push_slice(&[_]u32{1});
|
|
249
|
-
try testing.expectEqual(@as(?u32, 1), ring.tail());
|
|
250
|
-
try testing.expectEqual(@as(u32, 1), ring.tail_ptr().?.*);
|
|
251
|
-
ring.advance_head();
|
|
252
|
-
|
|
253
|
-
try testing.expectEqual(@as(usize, 1), ring.index);
|
|
254
|
-
try testing.expectEqual(@as(usize, 0), ring.count);
|
|
255
|
-
try ring.push_slice(&[_]u32{ 1, 2 });
|
|
256
|
-
try test_iterator(Ring, ring, &[_]u32{ 1, 2 });
|
|
257
|
-
ring.advance_head();
|
|
258
|
-
ring.advance_head();
|
|
259
|
-
|
|
260
|
-
try testing.expectEqual(@as(usize, 1), ring.index);
|
|
261
|
-
try testing.expectEqual(@as(usize, 0), ring.count);
|
|
262
|
-
try ring.push_slice(&[_]u32{1});
|
|
263
|
-
try testing.expectEqual(@as(?u32, 1), ring.tail());
|
|
264
|
-
try testing.expectEqual(@as(u32, 1), ring.tail_ptr().?.*);
|
|
265
|
-
ring.advance_head();
|
|
266
|
-
|
|
267
|
-
try testing.expectEqual(@as(?u32, null), ring.head());
|
|
268
|
-
try testing.expectEqual(@as(?*u32, null), ring.head_ptr());
|
|
269
|
-
try testing.expectEqual(@as(?u32, null), ring.tail());
|
|
270
|
-
try testing.expectEqual(@as(?*u32, null), ring.tail_ptr());
|
|
271
|
-
|
|
272
|
-
ring.next_tail_ptr().?.* = 0;
|
|
273
|
-
ring.advance_tail();
|
|
274
|
-
try testing.expectEqual(@as(?u32, 0), ring.tail());
|
|
275
|
-
try testing.expectEqual(@as(u32, 0), ring.tail_ptr().?.*);
|
|
276
|
-
try test_iterator(Ring, ring, &[_]u32{0});
|
|
277
|
-
|
|
278
|
-
ring.next_tail_ptr().?.* = 1;
|
|
279
|
-
ring.advance_tail();
|
|
280
|
-
try testing.expectEqual(@as(?u32, 1), ring.tail());
|
|
281
|
-
try testing.expectEqual(@as(u32, 1), ring.tail_ptr().?.*);
|
|
282
|
-
try test_iterator(Ring, ring, &[_]u32{ 0, 1 });
|
|
283
|
-
|
|
284
|
-
try testing.expectEqual(@as(?u32, null), ring.next_tail());
|
|
285
|
-
try testing.expectEqual(@as(?*u32, null), ring.next_tail_ptr());
|
|
286
|
-
|
|
287
|
-
try testing.expectEqual(@as(?u32, 0), ring.head());
|
|
288
|
-
try testing.expectEqual(@as(u32, 0), ring.head_ptr().?.*);
|
|
289
|
-
ring.advance_head();
|
|
290
|
-
try test_iterator(Ring, ring, &[_]u32{1});
|
|
291
|
-
|
|
292
|
-
ring.next_tail_ptr().?.* = 2;
|
|
293
|
-
ring.advance_tail();
|
|
294
|
-
try testing.expectEqual(@as(?u32, 2), ring.tail());
|
|
295
|
-
try testing.expectEqual(@as(u32, 2), ring.tail_ptr().?.*);
|
|
296
|
-
try test_iterator(Ring, ring, &[_]u32{ 1, 2 });
|
|
297
|
-
|
|
298
|
-
ring.advance_head();
|
|
299
|
-
try test_iterator(Ring, ring, &[_]u32{2});
|
|
300
|
-
|
|
301
|
-
ring.next_tail_ptr().?.* = 3;
|
|
302
|
-
ring.advance_tail();
|
|
303
|
-
try testing.expectEqual(@as(?u32, 3), ring.tail());
|
|
304
|
-
try testing.expectEqual(@as(u32, 3), ring.tail_ptr().?.*);
|
|
305
|
-
try test_iterator(Ring, ring, &[_]u32{ 2, 3 });
|
|
306
|
-
|
|
307
|
-
try testing.expectEqual(@as(?u32, 2), ring.head());
|
|
308
|
-
try testing.expectEqual(@as(u32, 2), ring.head_ptr().?.*);
|
|
309
|
-
ring.advance_head();
|
|
310
|
-
try test_iterator(Ring, ring, &[_]u32{3});
|
|
311
|
-
|
|
312
|
-
try testing.expectEqual(@as(?u32, 3), ring.head());
|
|
313
|
-
try testing.expectEqual(@as(u32, 3), ring.head_ptr().?.*);
|
|
314
|
-
ring.advance_head();
|
|
315
|
-
try test_iterator(Ring, ring, &[_]u32{});
|
|
316
|
-
|
|
317
|
-
try testing.expectEqual(@as(?u32, null), ring.head());
|
|
318
|
-
try testing.expectEqual(@as(?*u32, null), ring.head_ptr());
|
|
319
|
-
try testing.expectEqual(@as(?u32, null), ring.tail());
|
|
320
|
-
try testing.expectEqual(@as(?*u32, null), ring.tail_ptr());
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
test "RingBuffer: low level interface" {
|
|
324
|
-
const ArrayRing = RingBuffer(u32, 2, .array);
|
|
325
|
-
var array_ring: ArrayRing = .{};
|
|
326
|
-
try test_low_level_interface(ArrayRing, &array_ring);
|
|
327
|
-
|
|
328
|
-
const PointerRing = RingBuffer(u32, 2, .pointer);
|
|
329
|
-
var pointer_ring = try PointerRing.init(testing.allocator);
|
|
330
|
-
defer pointer_ring.deinit(testing.allocator);
|
|
331
|
-
try test_low_level_interface(PointerRing, &pointer_ring);
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
test "RingBuffer: push/pop high level interface" {
|
|
335
|
-
var fifo = RingBuffer(u32, 3, .array){};
|
|
336
|
-
|
|
337
|
-
try testing.expect(!fifo.full());
|
|
338
|
-
try testing.expect(fifo.empty());
|
|
339
|
-
try testing.expectEqual(@as(?*u32, null), fifo.get_ptr(0));
|
|
340
|
-
try testing.expectEqual(@as(?*u32, null), fifo.get_ptr(1));
|
|
341
|
-
try testing.expectEqual(@as(?*u32, null), fifo.get_ptr(2));
|
|
342
|
-
|
|
343
|
-
try fifo.push(1);
|
|
344
|
-
try testing.expectEqual(@as(?u32, 1), fifo.head());
|
|
345
|
-
try testing.expectEqual(@as(u32, 1), fifo.get_ptr(0).?.*);
|
|
346
|
-
try testing.expectEqual(@as(?*u32, null), fifo.get_ptr(1));
|
|
347
|
-
|
|
348
|
-
try testing.expect(!fifo.full());
|
|
349
|
-
try testing.expect(!fifo.empty());
|
|
350
|
-
|
|
351
|
-
try fifo.push(2);
|
|
352
|
-
try testing.expectEqual(@as(?u32, 1), fifo.head());
|
|
353
|
-
try testing.expectEqual(@as(u32, 2), fifo.get_ptr(1).?.*);
|
|
354
|
-
|
|
355
|
-
try fifo.push(3);
|
|
356
|
-
try testing.expectError(error.NoSpaceLeft, fifo.push(4));
|
|
357
|
-
|
|
358
|
-
try testing.expect(fifo.full());
|
|
359
|
-
try testing.expect(!fifo.empty());
|
|
360
|
-
|
|
361
|
-
try testing.expectEqual(@as(?u32, 1), fifo.head());
|
|
362
|
-
try testing.expectEqual(@as(?u32, 1), fifo.pop());
|
|
363
|
-
try testing.expectEqual(@as(u32, 2), fifo.get_ptr(0).?.*);
|
|
364
|
-
try testing.expectEqual(@as(u32, 3), fifo.get_ptr(1).?.*);
|
|
365
|
-
try testing.expectEqual(@as(?*u32, null), fifo.get_ptr(2));
|
|
366
|
-
|
|
367
|
-
try testing.expect(!fifo.full());
|
|
368
|
-
try testing.expect(!fifo.empty());
|
|
369
|
-
|
|
370
|
-
try fifo.push(4);
|
|
371
|
-
|
|
372
|
-
try testing.expectEqual(@as(?u32, 2), fifo.pop());
|
|
373
|
-
try testing.expectEqual(@as(?u32, 3), fifo.pop());
|
|
374
|
-
try testing.expectEqual(@as(?u32, 4), fifo.pop());
|
|
375
|
-
try testing.expectEqual(@as(?u32, null), fifo.pop());
|
|
376
|
-
|
|
377
|
-
try testing.expect(!fifo.full());
|
|
378
|
-
try testing.expect(fifo.empty());
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
test "RingBuffer: pop_tail" {
|
|
382
|
-
var lifo = RingBuffer(u32, 3, .array){};
|
|
383
|
-
try lifo.push(1);
|
|
384
|
-
try lifo.push(2);
|
|
385
|
-
try lifo.push(3);
|
|
386
|
-
try testing.expect(lifo.full());
|
|
387
|
-
|
|
388
|
-
try testing.expectEqual(@as(?u32, 3), lifo.pop_tail());
|
|
389
|
-
try testing.expectEqual(@as(?u32, 1), lifo.head());
|
|
390
|
-
try testing.expectEqual(@as(?u32, 2), lifo.pop_tail());
|
|
391
|
-
try testing.expectEqual(@as(?u32, 1), lifo.head());
|
|
392
|
-
try testing.expectEqual(@as(?u32, 1), lifo.pop_tail());
|
|
393
|
-
try testing.expectEqual(@as(?u32, null), lifo.pop_tail());
|
|
394
|
-
try testing.expect(lifo.empty());
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
test "RingBuffer: count_max=0" {
|
|
398
|
-
std.testing.refAllDecls(RingBuffer(u32, 0, .array));
|
|
399
|
-
}
|