tigerbeetle-node 0.10.0 → 0.11.1
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/README.md +302 -101
- package/dist/index.d.ts +70 -72
- package/dist/index.js +70 -72
- package/dist/index.js.map +1 -1
- package/package.json +9 -8
- package/scripts/download_node_headers.sh +14 -7
- package/src/index.ts +6 -10
- package/src/node.zig +6 -3
- package/src/tigerbeetle/scripts/benchmark.sh +4 -4
- package/src/tigerbeetle/scripts/confirm_image.sh +44 -0
- package/src/tigerbeetle/scripts/fuzz_loop.sh +15 -0
- package/src/tigerbeetle/scripts/fuzz_unique_errors.sh +7 -0
- package/src/tigerbeetle/scripts/install.sh +19 -4
- package/src/tigerbeetle/scripts/install_zig.bat +5 -1
- package/src/tigerbeetle/scripts/install_zig.sh +24 -14
- package/src/tigerbeetle/scripts/pre-commit.sh +9 -0
- package/src/tigerbeetle/scripts/shellcheck.sh +5 -0
- package/src/tigerbeetle/scripts/tests_on_alpine.sh +10 -0
- package/src/tigerbeetle/scripts/tests_on_ubuntu.sh +14 -0
- package/src/tigerbeetle/scripts/validate_docs.sh +17 -0
- package/src/tigerbeetle/src/benchmark.zig +29 -13
- package/src/tigerbeetle/src/c/tb_client/context.zig +248 -47
- package/src/tigerbeetle/src/c/tb_client/echo_client.zig +108 -0
- package/src/tigerbeetle/src/c/tb_client/packet.zig +2 -2
- package/src/tigerbeetle/src/c/tb_client/signal.zig +2 -4
- package/src/tigerbeetle/src/c/tb_client/thread.zig +17 -257
- package/src/tigerbeetle/src/c/tb_client.h +118 -84
- package/src/tigerbeetle/src/c/tb_client.zig +88 -23
- package/src/tigerbeetle/src/c/tb_client_header_test.zig +135 -0
- package/src/tigerbeetle/src/c/test.zig +371 -1
- package/src/tigerbeetle/src/cli.zig +37 -7
- package/src/tigerbeetle/src/config.zig +58 -17
- package/src/tigerbeetle/src/demo.zig +5 -2
- package/src/tigerbeetle/src/demo_01_create_accounts.zig +1 -1
- package/src/tigerbeetle/src/demo_03_create_transfers.zig +13 -0
- package/src/tigerbeetle/src/ewah.zig +11 -33
- package/src/tigerbeetle/src/ewah_benchmark.zig +8 -9
- package/src/tigerbeetle/src/io/linux.zig +1 -1
- package/src/tigerbeetle/src/lsm/README.md +308 -0
- package/src/tigerbeetle/src/lsm/binary_search.zig +137 -10
- package/src/tigerbeetle/src/lsm/bloom_filter.zig +43 -0
- package/src/tigerbeetle/src/lsm/compaction.zig +376 -397
- package/src/tigerbeetle/src/lsm/composite_key.zig +2 -0
- package/src/tigerbeetle/src/lsm/eytzinger.zig +1 -1
- package/src/tigerbeetle/src/{eytzinger_benchmark.zig → lsm/eytzinger_benchmark.zig} +34 -21
- package/src/tigerbeetle/src/lsm/forest.zig +21 -447
- package/src/tigerbeetle/src/lsm/forest_fuzz.zig +414 -0
- package/src/tigerbeetle/src/lsm/grid.zig +170 -76
- package/src/tigerbeetle/src/lsm/groove.zig +197 -133
- package/src/tigerbeetle/src/lsm/k_way_merge.zig +40 -18
- package/src/tigerbeetle/src/lsm/level_iterator.zig +28 -9
- package/src/tigerbeetle/src/lsm/manifest.zig +93 -180
- package/src/tigerbeetle/src/lsm/manifest_level.zig +161 -454
- package/src/tigerbeetle/src/lsm/manifest_log.zig +243 -356
- package/src/tigerbeetle/src/lsm/manifest_log_fuzz.zig +665 -0
- package/src/tigerbeetle/src/lsm/node_pool.zig +4 -0
- package/src/tigerbeetle/src/lsm/posted_groove.zig +65 -76
- package/src/tigerbeetle/src/lsm/segmented_array.zig +580 -251
- package/src/tigerbeetle/src/lsm/segmented_array_benchmark.zig +148 -0
- package/src/tigerbeetle/src/lsm/segmented_array_fuzz.zig +9 -0
- package/src/tigerbeetle/src/lsm/set_associative_cache.zig +62 -12
- package/src/tigerbeetle/src/lsm/table.zig +115 -68
- package/src/tigerbeetle/src/lsm/table_immutable.zig +30 -23
- package/src/tigerbeetle/src/lsm/table_iterator.zig +27 -17
- package/src/tigerbeetle/src/lsm/table_mutable.zig +63 -12
- package/src/tigerbeetle/src/lsm/test.zig +61 -56
- package/src/tigerbeetle/src/lsm/tree.zig +450 -407
- package/src/tigerbeetle/src/lsm/tree_fuzz.zig +461 -0
- package/src/tigerbeetle/src/main.zig +83 -8
- package/src/tigerbeetle/src/message_bus.zig +20 -9
- package/src/tigerbeetle/src/message_pool.zig +22 -19
- package/src/tigerbeetle/src/ring_buffer.zig +7 -3
- package/src/tigerbeetle/src/simulator.zig +179 -119
- package/src/tigerbeetle/src/state_machine.zig +381 -246
- package/src/tigerbeetle/src/static_allocator.zig +65 -0
- package/src/tigerbeetle/src/storage.zig +3 -7
- package/src/tigerbeetle/src/test/accounting/auditor.zig +577 -0
- package/src/tigerbeetle/src/test/accounting/workload.zig +823 -0
- package/src/tigerbeetle/src/test/cluster.zig +33 -81
- package/src/tigerbeetle/src/test/conductor.zig +366 -0
- package/src/tigerbeetle/src/test/fuzz.zig +121 -0
- package/src/tigerbeetle/src/test/id.zig +89 -0
- package/src/tigerbeetle/src/test/network.zig +45 -19
- package/src/tigerbeetle/src/test/packet_simulator.zig +40 -29
- package/src/tigerbeetle/src/test/priority_queue.zig +645 -0
- package/src/tigerbeetle/src/test/state_checker.zig +91 -69
- package/src/tigerbeetle/src/test/state_machine.zig +11 -35
- package/src/tigerbeetle/src/test/storage.zig +470 -106
- package/src/tigerbeetle/src/test/storage_checker.zig +204 -0
- package/src/tigerbeetle/src/tigerbeetle.zig +15 -16
- package/src/tigerbeetle/src/unit_tests.zig +13 -1
- package/src/tigerbeetle/src/util.zig +97 -11
- package/src/tigerbeetle/src/vopr.zig +495 -0
- package/src/tigerbeetle/src/vsr/client.zig +21 -3
- package/src/tigerbeetle/src/vsr/journal.zig +293 -212
- package/src/tigerbeetle/src/vsr/replica.zig +1086 -515
- package/src/tigerbeetle/src/vsr/superblock.zig +382 -637
- package/src/tigerbeetle/src/vsr/superblock_client_table.zig +14 -16
- package/src/tigerbeetle/src/vsr/superblock_free_set.zig +416 -153
- package/src/tigerbeetle/src/vsr/superblock_free_set_fuzz.zig +332 -0
- package/src/tigerbeetle/src/vsr/superblock_fuzz.zig +349 -0
- package/src/tigerbeetle/src/vsr/superblock_manifest.zig +62 -12
- package/src/tigerbeetle/src/vsr/superblock_quorums.zig +394 -0
- package/src/tigerbeetle/src/vsr/superblock_quorums_fuzz.zig +312 -0
- package/src/tigerbeetle/src/vsr.zig +94 -60
- package/src/tigerbeetle/scripts/vopr.bat +0 -48
- package/src/tigerbeetle/scripts/vopr.sh +0 -33
- package/src/tigerbeetle/src/benchmark_array_search.zig +0 -317
- package/src/tigerbeetle/src/benchmarks/perf.zig +0 -299
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
const std = @import("std");
|
|
2
|
+
const assert = std.debug.assert;
|
|
3
|
+
const mem = std.mem;
|
|
4
|
+
|
|
5
|
+
const config = @import("../../config.zig");
|
|
6
|
+
const vsr = @import("../../vsr.zig");
|
|
7
|
+
const Header = vsr.Header;
|
|
8
|
+
|
|
9
|
+
const RingBuffer = @import("../../ring_buffer.zig").RingBuffer;
|
|
10
|
+
const MessagePool = @import("../../message_pool.zig").MessagePool;
|
|
11
|
+
const Message = @import("../../message_pool.zig").MessagePool.Message;
|
|
12
|
+
|
|
13
|
+
pub fn EchoClient(comptime StateMachine_: type, comptime MessageBus: type) type {
|
|
14
|
+
return struct {
|
|
15
|
+
const Self = @This();
|
|
16
|
+
|
|
17
|
+
// Exposing the same types the real client does:
|
|
18
|
+
pub usingnamespace blk: {
|
|
19
|
+
const Client = @import("../../vsr/client.zig").Client(StateMachine_, MessageBus);
|
|
20
|
+
break :blk struct {
|
|
21
|
+
pub const StateMachine = Client.StateMachine;
|
|
22
|
+
pub const Error = Client.Error;
|
|
23
|
+
pub const Request = Client.Request;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
request_queue: RingBuffer(Self.Request, config.client_request_queue_max, .array) = .{},
|
|
28
|
+
message_pool: *MessagePool,
|
|
29
|
+
|
|
30
|
+
pub fn init(
|
|
31
|
+
allocator: mem.Allocator,
|
|
32
|
+
id: u128,
|
|
33
|
+
cluster: u32,
|
|
34
|
+
replica_count: u8,
|
|
35
|
+
message_pool: *MessagePool,
|
|
36
|
+
message_bus_options: MessageBus.Options,
|
|
37
|
+
) !Self {
|
|
38
|
+
_ = allocator;
|
|
39
|
+
_ = id;
|
|
40
|
+
_ = cluster;
|
|
41
|
+
_ = replica_count;
|
|
42
|
+
_ = message_bus_options;
|
|
43
|
+
|
|
44
|
+
return Self{
|
|
45
|
+
.message_pool = message_pool,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
|
|
50
|
+
_ = allocator;
|
|
51
|
+
// Drains all pending requests before deiniting.
|
|
52
|
+
self.reply();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
pub fn tick(self: *Self) void {
|
|
56
|
+
self.reply();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
pub fn request(
|
|
60
|
+
self: *Self,
|
|
61
|
+
user_data: u128,
|
|
62
|
+
callback: Self.Request.Callback,
|
|
63
|
+
operation: Self.StateMachine.Operation,
|
|
64
|
+
message: *Message,
|
|
65
|
+
message_body_size: usize,
|
|
66
|
+
) void {
|
|
67
|
+
message.header.* = .{
|
|
68
|
+
.client = 0,
|
|
69
|
+
.request = 0,
|
|
70
|
+
.cluster = 0,
|
|
71
|
+
.command = .request,
|
|
72
|
+
.operation = vsr.Operation.from(Self.StateMachine, operation),
|
|
73
|
+
.size = @intCast(u32, @sizeOf(Header) + message_body_size),
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
if (self.request_queue.full()) {
|
|
77
|
+
callback(user_data, operation, error.TooManyOutstandingRequests);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
self.request_queue.push_assume_capacity(.{
|
|
82
|
+
.user_data = user_data,
|
|
83
|
+
.callback = callback,
|
|
84
|
+
.message = message.ref(),
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
pub fn get_message(self: *Self) *Message {
|
|
89
|
+
return self.message_pool.get_message();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
pub fn unref(self: *Self, message: *Message) void {
|
|
93
|
+
self.message_pool.unref(message);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
fn reply(self: *Self) void {
|
|
97
|
+
while (self.request_queue.pop()) |inflight| {
|
|
98
|
+
defer self.unref(inflight.message);
|
|
99
|
+
|
|
100
|
+
inflight.callback(
|
|
101
|
+
inflight.user_data,
|
|
102
|
+
inflight.message.header.operation.cast(Self.StateMachine),
|
|
103
|
+
inflight.message.body(),
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
}
|
|
@@ -4,11 +4,11 @@ const Atomic = std.atomic.Atomic;
|
|
|
4
4
|
|
|
5
5
|
pub const Packet = extern struct {
|
|
6
6
|
next: ?*Packet,
|
|
7
|
-
user_data:
|
|
7
|
+
user_data: ?*anyopaque,
|
|
8
8
|
operation: u8,
|
|
9
9
|
status: Status,
|
|
10
10
|
data_size: u32,
|
|
11
|
-
data:
|
|
11
|
+
data: ?*anyopaque,
|
|
12
12
|
|
|
13
13
|
pub const Status = enum(u8) {
|
|
14
14
|
ok,
|
|
@@ -8,12 +8,10 @@ const Atomic = std.atomic.Atomic;
|
|
|
8
8
|
|
|
9
9
|
const log = std.log.scoped(.tb_client_signal);
|
|
10
10
|
|
|
11
|
-
/// A Signal is a way to trigger a registered callback on a tigerbeetle IO
|
|
11
|
+
/// A Signal is a way to trigger a registered callback on a tigerbeetle IO instance
|
|
12
12
|
/// when notification occurs from another thread.
|
|
13
13
|
/// It does this by using OS sockets (which are thread safe)
|
|
14
14
|
/// to resolve IO.Completions on the tigerbeetle thread.
|
|
15
|
-
///
|
|
16
|
-
/// TODO: implement a simpler version of this eventually..
|
|
17
15
|
pub const Signal = struct {
|
|
18
16
|
io: *IO,
|
|
19
17
|
server_socket: os.socket_t,
|
|
@@ -50,7 +48,7 @@ pub const Signal = struct {
|
|
|
50
48
|
|
|
51
49
|
// Windows requires that the socket is bound before listening
|
|
52
50
|
if (builtin.target.os.tag == .windows) {
|
|
53
|
-
|
|
51
|
+
const addr = std.net.Address.initIp4(.{ 127, 0, 0, 1 }, 0); // zero port lets the OS choose
|
|
54
52
|
os.bind(self.server_socket, &addr.any, addr.getOsSockLen()) catch |err| {
|
|
55
53
|
log.err("failed to bind the server socket to a local random port: {}", .{err});
|
|
56
54
|
return switch (err) {
|
|
@@ -1,180 +1,44 @@
|
|
|
1
1
|
const std = @import("std");
|
|
2
|
-
const os = std.os;
|
|
3
2
|
const assert = std.debug.assert;
|
|
4
3
|
|
|
5
4
|
const config = @import("../../config.zig");
|
|
6
|
-
const log = std.log.scoped(.
|
|
7
|
-
|
|
8
|
-
const vsr = @import("../../vsr.zig");
|
|
9
|
-
const Header = vsr.Header;
|
|
10
|
-
|
|
11
|
-
const IO = @import("../../io.zig").IO;
|
|
12
|
-
const message_pool = @import("../../message_pool.zig");
|
|
13
|
-
|
|
14
|
-
const MessagePool = message_pool.MessagePool;
|
|
15
|
-
const Message = MessagePool.Message;
|
|
5
|
+
const log = std.log.scoped(.tb_client_thread);
|
|
16
6
|
|
|
17
7
|
const Packet = @import("packet.zig").Packet;
|
|
18
8
|
const Signal = @import("signal.zig").Signal;
|
|
19
9
|
|
|
20
10
|
pub fn ThreadType(
|
|
21
|
-
comptime
|
|
22
|
-
comptime MessageBus: type,
|
|
11
|
+
comptime Context: type,
|
|
23
12
|
) type {
|
|
24
13
|
return struct {
|
|
25
|
-
pub const Client = vsr.Client(StateMachine, MessageBus);
|
|
26
|
-
pub const Operation = StateMachine.Operation;
|
|
27
|
-
|
|
28
|
-
fn operation_size_of(op: u8) ?usize {
|
|
29
|
-
const allowed_operations = [_]Operation{
|
|
30
|
-
.create_accounts,
|
|
31
|
-
.create_transfers,
|
|
32
|
-
.lookup_accounts,
|
|
33
|
-
.lookup_transfers,
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
inline for (allowed_operations) |operation| {
|
|
37
|
-
if (op == @enumToInt(operation)) {
|
|
38
|
-
return @sizeOf(StateMachine.Event(operation));
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/////////////////////////////////////////////////////////////////////////
|
|
46
|
-
|
|
47
14
|
const Self = @This();
|
|
48
15
|
|
|
49
|
-
|
|
50
|
-
client_id: u128,
|
|
51
|
-
packets: []Packet,
|
|
52
|
-
|
|
53
|
-
addresses: []std.net.Address,
|
|
54
|
-
io: IO,
|
|
55
|
-
message_pool: MessagePool,
|
|
56
|
-
message_bus: MessageBus,
|
|
57
|
-
client: Client,
|
|
16
|
+
context: *Context,
|
|
58
17
|
|
|
59
18
|
retry: Packet.List,
|
|
60
19
|
submitted: Packet.Stack,
|
|
61
|
-
available_messages: usize,
|
|
62
|
-
on_completion_fn: CompletionFn,
|
|
63
20
|
|
|
64
21
|
signal: Signal,
|
|
65
22
|
thread: std.Thread,
|
|
66
23
|
|
|
67
|
-
pub const CompletionFn = fn (
|
|
68
|
-
client_thread: *Self,
|
|
69
|
-
packet: *Packet,
|
|
70
|
-
result: ?[]const u8,
|
|
71
|
-
) void;
|
|
72
|
-
|
|
73
|
-
pub const Error = error{
|
|
74
|
-
Unexpected,
|
|
75
|
-
OutOfMemory,
|
|
76
|
-
InvalidAddress,
|
|
77
|
-
SystemResources,
|
|
78
|
-
NetworkSubsystemFailed,
|
|
79
|
-
};
|
|
80
|
-
|
|
81
24
|
pub fn init(
|
|
82
25
|
self: *Self,
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
num_packets: u32,
|
|
87
|
-
on_completion_fn: CompletionFn,
|
|
88
|
-
) Error!void {
|
|
89
|
-
self.allocator = allocator;
|
|
90
|
-
self.client_id = std.crypto.random.int(u128);
|
|
91
|
-
log.debug("init: initializing client_id={}.", .{self.client_id});
|
|
92
|
-
|
|
93
|
-
log.debug("init: allocating tb_packets.", .{});
|
|
94
|
-
self.packets = self.allocator.alloc(Packet, num_packets) catch |err| {
|
|
95
|
-
log.err("failed to allocate tb_packets: {}", .{err});
|
|
96
|
-
return Error.OutOfMemory;
|
|
97
|
-
};
|
|
98
|
-
errdefer self.allocator.free(self.packets);
|
|
99
|
-
|
|
100
|
-
log.debug("init: parsing vsr addresses.", .{});
|
|
101
|
-
self.addresses = vsr.parse_addresses(self.allocator, addresses) catch |err| {
|
|
102
|
-
log.err("failed to parse addresses: {}.", .{err});
|
|
103
|
-
return Error.InvalidAddress;
|
|
104
|
-
};
|
|
105
|
-
errdefer self.allocator.free(self.addresses);
|
|
106
|
-
|
|
107
|
-
log.debug("init: initializing IO.", .{});
|
|
108
|
-
self.io = IO.init(32, 0) catch |err| {
|
|
109
|
-
log.err("failed to initialize IO: {}.", .{err});
|
|
110
|
-
return switch (err) {
|
|
111
|
-
error.ProcessFdQuotaExceeded => error.SystemResources,
|
|
112
|
-
error.Unexpected => error.Unexpected,
|
|
113
|
-
else => unreachable,
|
|
114
|
-
};
|
|
115
|
-
};
|
|
116
|
-
errdefer self.io.deinit();
|
|
117
|
-
|
|
118
|
-
log.debug("init: initializing MessagePool", .{});
|
|
119
|
-
self.message_pool = MessagePool.init(allocator, .client) catch |err| {
|
|
120
|
-
log.err("failed to initialize MessagePool: {}", .{err});
|
|
121
|
-
return err;
|
|
122
|
-
};
|
|
123
|
-
errdefer self.message_pool.deinit(self.allocator);
|
|
124
|
-
|
|
125
|
-
log.debug("init: initializing MessageBus.", .{});
|
|
126
|
-
self.message_bus = MessageBus.init(
|
|
127
|
-
self.allocator,
|
|
128
|
-
cluster_id,
|
|
129
|
-
.{ .client = self.client_id },
|
|
130
|
-
&self.message_pool,
|
|
131
|
-
Client.on_message,
|
|
132
|
-
.{
|
|
133
|
-
.configuration = self.addresses,
|
|
134
|
-
.io = &self.io,
|
|
135
|
-
},
|
|
136
|
-
) catch |err| {
|
|
137
|
-
log.err("failed to initialize message bus: {}.", .{err});
|
|
138
|
-
return err;
|
|
139
|
-
};
|
|
140
|
-
errdefer self.message_bus.deinit(self.allocator);
|
|
141
|
-
|
|
142
|
-
log.debug("init: Initializing client(cluster_id={d}, client_id={d}, addresses={o})", .{
|
|
143
|
-
cluster_id,
|
|
144
|
-
self.client_id,
|
|
145
|
-
self.addresses,
|
|
146
|
-
});
|
|
147
|
-
self.client = Client.init(
|
|
148
|
-
allocator,
|
|
149
|
-
self.client_id,
|
|
150
|
-
cluster_id,
|
|
151
|
-
@intCast(u8, self.addresses.len),
|
|
152
|
-
&self.message_pool,
|
|
153
|
-
.{
|
|
154
|
-
.configuration = self.addresses,
|
|
155
|
-
.io = &self.io,
|
|
156
|
-
},
|
|
157
|
-
) catch |err| {
|
|
158
|
-
log.err("failed to initalize client: {}", .{err});
|
|
159
|
-
return err;
|
|
160
|
-
};
|
|
161
|
-
errdefer self.client.deinit(self.allocator);
|
|
162
|
-
|
|
26
|
+
context: *Context,
|
|
27
|
+
) !void {
|
|
28
|
+
self.context = context;
|
|
163
29
|
self.retry = .{};
|
|
164
30
|
self.submitted = .{};
|
|
165
|
-
self.available_messages = message_pool.messages_max_client;
|
|
166
|
-
self.on_completion_fn = on_completion_fn;
|
|
167
31
|
|
|
168
|
-
log.debug("init: initializing
|
|
169
|
-
self.signal.init(&
|
|
170
|
-
log.err("failed to initialize Signal: {}.", .{err});
|
|
171
|
-
return err;
|
|
172
|
-
};
|
|
32
|
+
log.debug("{}: init: initializing signal", .{context.client_id});
|
|
33
|
+
try self.signal.init(&context.io, Self.on_signal);
|
|
173
34
|
errdefer self.signal.deinit();
|
|
174
35
|
|
|
175
|
-
log.debug("init: spawning
|
|
176
|
-
self.thread = std.Thread.spawn(.{},
|
|
177
|
-
log.err("failed to spawn
|
|
36
|
+
log.debug("{}: init: spawning thread", .{context.client_id});
|
|
37
|
+
self.thread = std.Thread.spawn(.{}, Context.run, .{context}) catch |err| {
|
|
38
|
+
log.err("{}: failed to spawn thread: {s}", .{
|
|
39
|
+
context.client_id,
|
|
40
|
+
@errorName(err),
|
|
41
|
+
});
|
|
178
42
|
return switch (err) {
|
|
179
43
|
error.Unexpected => error.Unexpected,
|
|
180
44
|
error.OutOfMemory => error.OutOfMemory,
|
|
@@ -188,13 +52,6 @@ pub fn ThreadType(
|
|
|
188
52
|
self.thread.join();
|
|
189
53
|
self.signal.deinit();
|
|
190
54
|
|
|
191
|
-
self.client.deinit(self.allocator);
|
|
192
|
-
self.message_bus.deinit(self.allocator);
|
|
193
|
-
self.message_pool.deinit(self.allocator);
|
|
194
|
-
self.io.deinit();
|
|
195
|
-
|
|
196
|
-
self.allocator.free(self.addresses);
|
|
197
|
-
self.allocator.free(self.packets);
|
|
198
55
|
self.* = undefined;
|
|
199
56
|
}
|
|
200
57
|
|
|
@@ -204,19 +61,9 @@ pub fn ThreadType(
|
|
|
204
61
|
self.signal.notify();
|
|
205
62
|
}
|
|
206
63
|
|
|
207
|
-
fn run(self: *Self) void {
|
|
208
|
-
while (!self.signal.is_shutdown()) {
|
|
209
|
-
self.client.tick();
|
|
210
|
-
self.io.run_for_ns(config.tick_ms * std.time.ns_per_ms) catch |err| {
|
|
211
|
-
log.err("IO.run() failed with {}", .{err});
|
|
212
|
-
return;
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
64
|
fn on_signal(signal: *Signal) void {
|
|
218
65
|
const self = @fieldParentPtr(Self, "signal", signal);
|
|
219
|
-
self.
|
|
66
|
+
self.context.tick();
|
|
220
67
|
|
|
221
68
|
// Consume all of retry here to avoid infinite loop
|
|
222
69
|
// if the code below pushes to self.retry while we're dequeueing.
|
|
@@ -233,97 +80,10 @@ pub fn ThreadType(
|
|
|
233
80
|
}
|
|
234
81
|
|
|
235
82
|
// Process packets from either pending or submitted as long as we have messages.
|
|
236
|
-
while (self.
|
|
83
|
+
while (self.context.messages_available > 0) {
|
|
237
84
|
const packet = pending.pop() orelse self.submitted.pop() orelse break;
|
|
238
|
-
|
|
239
|
-
self.available_messages -= 1;
|
|
240
|
-
self.request(packet, message);
|
|
85
|
+
self.context.request(packet);
|
|
241
86
|
}
|
|
242
87
|
}
|
|
243
|
-
|
|
244
|
-
fn request(self: *Self, packet: *Packet, message: *Message) void {
|
|
245
|
-
// Get the size of each request structure in the packet.data
|
|
246
|
-
const request_size: usize = operation_size_of(packet.operation) orelse {
|
|
247
|
-
return self.on_complete(packet, message, error.InvalidOperation);
|
|
248
|
-
};
|
|
249
|
-
|
|
250
|
-
// Make sure the packet.data size is correct.
|
|
251
|
-
const readable = packet.data[0..packet.data_size];
|
|
252
|
-
if (readable.len == 0 or readable.len % request_size != 0) {
|
|
253
|
-
return self.on_complete(packet, message, error.InvalidDataSize);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// Make sure the packet.data wouldn't overflow a message.
|
|
257
|
-
const writable = message.buffer[@sizeOf(Header)..];
|
|
258
|
-
if (readable.len > writable.len) {
|
|
259
|
-
return self.on_complete(packet, message, error.TooMuchData);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// Write the packet data to the message
|
|
263
|
-
std.mem.copy(u8, writable, readable);
|
|
264
|
-
const wrote = readable.len;
|
|
265
|
-
|
|
266
|
-
// .. and submit the message for processing
|
|
267
|
-
self.client.request(
|
|
268
|
-
@bitCast(u128, UserData{
|
|
269
|
-
.self = self,
|
|
270
|
-
.packet = packet,
|
|
271
|
-
}),
|
|
272
|
-
Self.on_result,
|
|
273
|
-
@intToEnum(Operation, packet.operation),
|
|
274
|
-
message,
|
|
275
|
-
wrote,
|
|
276
|
-
);
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
const UserData = packed struct {
|
|
280
|
-
self: *Self,
|
|
281
|
-
packet: *Packet,
|
|
282
|
-
};
|
|
283
|
-
|
|
284
|
-
fn on_result(raw_user_data: u128, op: Operation, results: Client.Error![]const u8) void {
|
|
285
|
-
const user_data = @bitCast(UserData, raw_user_data);
|
|
286
|
-
const self = user_data.self;
|
|
287
|
-
const packet = user_data.packet;
|
|
288
|
-
|
|
289
|
-
// Complete the packet without a message as it's already unref()'s by the Client.
|
|
290
|
-
assert(packet.operation == @enumToInt(op));
|
|
291
|
-
self.on_complete(packet, null, results);
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
const PacketError = Client.Error || error{
|
|
295
|
-
TooMuchData,
|
|
296
|
-
InvalidOperation,
|
|
297
|
-
InvalidDataSize,
|
|
298
|
-
};
|
|
299
|
-
|
|
300
|
-
fn on_complete(
|
|
301
|
-
self: *Self,
|
|
302
|
-
packet: *Packet,
|
|
303
|
-
message: ?*Message,
|
|
304
|
-
result: PacketError![]const u8,
|
|
305
|
-
) void {
|
|
306
|
-
// Mark the message as completed
|
|
307
|
-
if (message) |m| self.client.unref(m);
|
|
308
|
-
assert(self.available_messages < message_pool.messages_max_client);
|
|
309
|
-
self.available_messages += 1;
|
|
310
|
-
|
|
311
|
-
const bytes = result catch |err| {
|
|
312
|
-
packet.status = switch (err) {
|
|
313
|
-
// If there's too many requests, (re)try submitting the packet later
|
|
314
|
-
error.TooManyOutstandingRequests => {
|
|
315
|
-
return self.retry.push(Packet.List.from(packet));
|
|
316
|
-
},
|
|
317
|
-
error.TooMuchData => .too_much_data,
|
|
318
|
-
error.InvalidOperation => .invalid_operation,
|
|
319
|
-
error.InvalidDataSize => .invalid_data_size,
|
|
320
|
-
};
|
|
321
|
-
return self.on_completion_fn(self, packet, null);
|
|
322
|
-
};
|
|
323
|
-
|
|
324
|
-
// The packet completed normally
|
|
325
|
-
packet.status = .ok;
|
|
326
|
-
self.on_completion_fn(self, packet, bytes);
|
|
327
|
-
}
|
|
328
88
|
};
|
|
329
89
|
}
|