tigerbeetle-node 0.5.2 → 0.6.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/README.md +3 -4
- package/package.json +1 -1
- package/src/node.zig +2 -12
- package/src/tigerbeetle/scripts/benchmark.bat +46 -0
- package/src/tigerbeetle/scripts/install_zig.bat +2 -2
- package/src/tigerbeetle/scripts/install_zig.sh +1 -1
- package/src/tigerbeetle/scripts/vopr.sh +2 -2
- package/src/tigerbeetle/src/benchmark.zig +2 -6
- package/src/tigerbeetle/src/cli.zig +39 -18
- package/src/tigerbeetle/src/config.zig +24 -9
- package/src/tigerbeetle/src/demo.zig +1 -1
- package/src/tigerbeetle/src/io/benchmark.zig +24 -49
- package/src/tigerbeetle/src/io/darwin.zig +175 -44
- package/src/tigerbeetle/src/io/linux.zig +177 -72
- package/src/tigerbeetle/src/io/test.zig +61 -39
- package/src/tigerbeetle/src/io/windows.zig +1161 -0
- package/src/tigerbeetle/src/io.zig +2 -0
- package/src/tigerbeetle/src/main.zig +13 -8
- package/src/tigerbeetle/src/message_bus.zig +49 -61
- package/src/tigerbeetle/src/message_pool.zig +63 -57
- package/src/tigerbeetle/src/ring_buffer.zig +7 -0
- package/src/tigerbeetle/src/simulator.zig +4 -4
- package/src/tigerbeetle/src/storage.zig +0 -230
- package/src/tigerbeetle/src/test/cluster.zig +3 -6
- package/src/tigerbeetle/src/test/message_bus.zig +4 -3
- package/src/tigerbeetle/src/test/network.zig +13 -16
- package/src/tigerbeetle/src/test/state_checker.zig +3 -2
- package/src/tigerbeetle/src/tigerbeetle.zig +5 -3
- package/src/tigerbeetle/src/time.zig +58 -11
- package/src/tigerbeetle/src/vsr/client.zig +18 -32
- package/src/tigerbeetle/src/vsr/clock.zig +1 -1
- package/src/tigerbeetle/src/vsr/journal.zig +2 -6
- package/src/tigerbeetle/src/vsr/replica.zig +146 -169
- package/src/tigerbeetle/src/vsr.zig +263 -5
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const std = @import("std");
|
|
2
|
+
const builtin = @import("builtin");
|
|
2
3
|
const os = std.os;
|
|
3
4
|
const testing = std.testing;
|
|
4
5
|
const assert = std.debug.assert;
|
|
@@ -6,7 +7,7 @@ const assert = std.debug.assert;
|
|
|
6
7
|
const Time = @import("../time.zig").Time;
|
|
7
8
|
const IO = @import("../io.zig").IO;
|
|
8
9
|
|
|
9
|
-
test "write/
|
|
10
|
+
test "write/read/close" {
|
|
10
11
|
try struct {
|
|
11
12
|
const Context = @This();
|
|
12
13
|
|
|
@@ -18,11 +19,10 @@ test "write/fsync/read/close" {
|
|
|
18
19
|
read_buf: [20]u8 = [_]u8{98} ** 20,
|
|
19
20
|
|
|
20
21
|
written: usize = 0,
|
|
21
|
-
fsynced: bool = false,
|
|
22
22
|
read: usize = 0,
|
|
23
23
|
|
|
24
24
|
fn run_test() !void {
|
|
25
|
-
const path = "
|
|
25
|
+
const path = "test_io_write_read_close";
|
|
26
26
|
const file = try std.fs.cwd().createFile(path, .{ .read = true, .truncate = true });
|
|
27
27
|
defer std.fs.cwd().deleteFile(path) catch {};
|
|
28
28
|
|
|
@@ -46,7 +46,6 @@ test "write/fsync/read/close" {
|
|
|
46
46
|
while (!self.done) try self.io.tick();
|
|
47
47
|
|
|
48
48
|
try testing.expectEqual(self.write_buf.len, self.written);
|
|
49
|
-
try testing.expect(self.fsynced);
|
|
50
49
|
try testing.expectEqual(self.read_buf.len, self.read);
|
|
51
50
|
try testing.expectEqualSlices(u8, &self.write_buf, &self.read_buf);
|
|
52
51
|
}
|
|
@@ -57,17 +56,6 @@ test "write/fsync/read/close" {
|
|
|
57
56
|
result: IO.WriteError!usize,
|
|
58
57
|
) void {
|
|
59
58
|
self.written = result catch @panic("write error");
|
|
60
|
-
self.io.fsync(*Context, self, fsync_callback, completion, self.fd);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
fn fsync_callback(
|
|
64
|
-
self: *Context,
|
|
65
|
-
completion: *IO.Completion,
|
|
66
|
-
result: IO.FsyncError!void,
|
|
67
|
-
) void {
|
|
68
|
-
_ = result catch @panic("fsync error");
|
|
69
|
-
|
|
70
|
-
self.fsynced = true;
|
|
71
59
|
self.io.read(*Context, self, read_callback, completion, self.fd, &self.read_buf, 10);
|
|
72
60
|
}
|
|
73
61
|
|
|
@@ -97,7 +85,7 @@ test "accept/connect/send/receive" {
|
|
|
97
85
|
try struct {
|
|
98
86
|
const Context = @This();
|
|
99
87
|
|
|
100
|
-
io: IO,
|
|
88
|
+
io: *IO,
|
|
101
89
|
done: bool = false,
|
|
102
90
|
server: os.socket_t,
|
|
103
91
|
client: os.socket_t,
|
|
@@ -111,12 +99,15 @@ test "accept/connect/send/receive" {
|
|
|
111
99
|
received: usize = 0,
|
|
112
100
|
|
|
113
101
|
fn run_test() !void {
|
|
102
|
+
var io = try IO.init(32, 0);
|
|
103
|
+
defer io.deinit();
|
|
104
|
+
|
|
114
105
|
const address = try std.net.Address.parseIp4("127.0.0.1", 3131);
|
|
115
106
|
const kernel_backlog = 1;
|
|
116
|
-
const server = try
|
|
107
|
+
const server = try io.open_socket(address.any.family, os.SOCK.STREAM, os.IPPROTO.TCP);
|
|
117
108
|
defer os.closeSocket(server);
|
|
118
109
|
|
|
119
|
-
const client = try
|
|
110
|
+
const client = try io.open_socket(address.any.family, os.SOCK.STREAM, os.IPPROTO.TCP);
|
|
120
111
|
defer os.closeSocket(client);
|
|
121
112
|
|
|
122
113
|
try os.setsockopt(
|
|
@@ -129,11 +120,10 @@ test "accept/connect/send/receive" {
|
|
|
129
120
|
try os.listen(server, kernel_backlog);
|
|
130
121
|
|
|
131
122
|
var self: Context = .{
|
|
132
|
-
.io =
|
|
123
|
+
.io = &io,
|
|
133
124
|
.server = server,
|
|
134
125
|
.client = client,
|
|
135
126
|
};
|
|
136
|
-
defer self.io.deinit();
|
|
137
127
|
|
|
138
128
|
var client_completion: IO.Completion = undefined;
|
|
139
129
|
self.io.connect(
|
|
@@ -228,7 +218,6 @@ test "timeout" {
|
|
|
228
218
|
fn run_test() !void {
|
|
229
219
|
var timer = Time{};
|
|
230
220
|
const start_time = timer.monotonic();
|
|
231
|
-
|
|
232
221
|
var self: Context = .{
|
|
233
222
|
.timer = &timer,
|
|
234
223
|
.io = try IO.init(32, 0),
|
|
@@ -321,7 +310,7 @@ test "tick to wait" {
|
|
|
321
310
|
const Context = @This();
|
|
322
311
|
|
|
323
312
|
io: IO,
|
|
324
|
-
accepted: os.socket_t =
|
|
313
|
+
accepted: os.socket_t = IO.INVALID_SOCKET,
|
|
325
314
|
connected: bool = false,
|
|
326
315
|
received: bool = false,
|
|
327
316
|
|
|
@@ -332,7 +321,7 @@ test "tick to wait" {
|
|
|
332
321
|
const address = try std.net.Address.parseIp4("127.0.0.1", 3131);
|
|
333
322
|
const kernel_backlog = 1;
|
|
334
323
|
|
|
335
|
-
const server = try
|
|
324
|
+
const server = try self.io.open_socket(address.any.family, os.SOCK.STREAM, os.IPPROTO.TCP);
|
|
336
325
|
defer os.closeSocket(server);
|
|
337
326
|
|
|
338
327
|
try os.setsockopt(
|
|
@@ -344,7 +333,7 @@ test "tick to wait" {
|
|
|
344
333
|
try os.bind(server, &address.any, address.getOsSockLen());
|
|
345
334
|
try os.listen(server, kernel_backlog);
|
|
346
335
|
|
|
347
|
-
const client = try
|
|
336
|
+
const client = try self.io.open_socket(address.any.family, os.SOCK.STREAM, os.IPPROTO.TCP);
|
|
348
337
|
defer os.closeSocket(client);
|
|
349
338
|
|
|
350
339
|
// Start the accept
|
|
@@ -364,13 +353,13 @@ test "tick to wait" {
|
|
|
364
353
|
|
|
365
354
|
// Tick the IO to drain the accept & connect completions
|
|
366
355
|
assert(!self.connected);
|
|
367
|
-
assert(self.accepted ==
|
|
356
|
+
assert(self.accepted == IO.INVALID_SOCKET);
|
|
368
357
|
|
|
369
|
-
while (self.accepted ==
|
|
358
|
+
while (self.accepted == IO.INVALID_SOCKET or !self.connected)
|
|
370
359
|
try self.io.tick();
|
|
371
360
|
|
|
372
361
|
assert(self.connected);
|
|
373
|
-
assert(self.accepted !=
|
|
362
|
+
assert(self.accepted != IO.INVALID_SOCKET);
|
|
374
363
|
defer os.closeSocket(self.accepted);
|
|
375
364
|
|
|
376
365
|
// Start receiving on the client
|
|
@@ -395,7 +384,7 @@ test "tick to wait" {
|
|
|
395
384
|
// Other tests already check .tick() with IO based completions.
|
|
396
385
|
// This simulates IO being completed by an external system
|
|
397
386
|
var send_buf = std.mem.zeroes([64]u8);
|
|
398
|
-
const wrote = try
|
|
387
|
+
const wrote = try os_send(self.accepted, &send_buf, 0);
|
|
399
388
|
try testing.expectEqual(wrote, send_buf.len);
|
|
400
389
|
|
|
401
390
|
// Wait for the recv() to complete using only IO.tick().
|
|
@@ -417,7 +406,7 @@ test "tick to wait" {
|
|
|
417
406
|
) void {
|
|
418
407
|
_ = completion;
|
|
419
408
|
|
|
420
|
-
assert(self.accepted ==
|
|
409
|
+
assert(self.accepted == IO.INVALID_SOCKET);
|
|
421
410
|
self.accepted = result catch @panic("accept error");
|
|
422
411
|
}
|
|
423
412
|
|
|
@@ -444,6 +433,41 @@ test "tick to wait" {
|
|
|
444
433
|
assert(!self.received);
|
|
445
434
|
self.received = true;
|
|
446
435
|
}
|
|
436
|
+
|
|
437
|
+
// TODO: use os.send() instead when it gets fixed for windows
|
|
438
|
+
fn os_send(sock: os.socket_t, buf: []const u8, flags: u32) !usize {
|
|
439
|
+
if (builtin.target.os.tag != .windows) {
|
|
440
|
+
return os.send(sock, buf, flags);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
const rc = os.windows.sendto(sock, buf.ptr, buf.len, flags, null, 0);
|
|
444
|
+
if (rc == os.windows.ws2_32.SOCKET_ERROR) {
|
|
445
|
+
switch (os.windows.ws2_32.WSAGetLastError()) {
|
|
446
|
+
.WSAEACCES => return error.AccessDenied,
|
|
447
|
+
.WSAEADDRNOTAVAIL => return error.AddressNotAvailable,
|
|
448
|
+
.WSAECONNRESET => return error.ConnectionResetByPeer,
|
|
449
|
+
.WSAEMSGSIZE => return error.MessageTooBig,
|
|
450
|
+
.WSAENOBUFS => return error.SystemResources,
|
|
451
|
+
.WSAENOTSOCK => return error.FileDescriptorNotASocket,
|
|
452
|
+
.WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported,
|
|
453
|
+
.WSAEDESTADDRREQ => unreachable, // A destination address is required.
|
|
454
|
+
.WSAEFAULT => unreachable, // The lpBuffers, lpTo, lpOverlapped, lpNumberOfBytesSent, or lpCompletionRoutine parameters are not part of the user address space, or the lpTo parameter is too small.
|
|
455
|
+
.WSAEHOSTUNREACH => return error.NetworkUnreachable,
|
|
456
|
+
// TODO: WSAEINPROGRESS, WSAEINTR
|
|
457
|
+
.WSAEINVAL => unreachable,
|
|
458
|
+
.WSAENETDOWN => return error.NetworkSubsystemFailed,
|
|
459
|
+
.WSAENETRESET => return error.ConnectionResetByPeer,
|
|
460
|
+
.WSAENETUNREACH => return error.NetworkUnreachable,
|
|
461
|
+
.WSAENOTCONN => return error.SocketNotConnected,
|
|
462
|
+
.WSAESHUTDOWN => unreachable, // The socket has been shut down; it is not possible to WSASendTo on a socket after shutdown has been invoked with how set to SD_SEND or SD_BOTH.
|
|
463
|
+
.WSAEWOULDBLOCK => return error.WouldBlock,
|
|
464
|
+
.WSANOTINITIALISED => unreachable, // A successful WSAStartup call must occur before using this function.
|
|
465
|
+
else => |err| return os.windows.unexpectedWSAError(err),
|
|
466
|
+
}
|
|
467
|
+
} else {
|
|
468
|
+
return @intCast(usize, rc);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
447
471
|
}.run_test();
|
|
448
472
|
}
|
|
449
473
|
|
|
@@ -458,7 +482,7 @@ test "pipe data over socket" {
|
|
|
458
482
|
|
|
459
483
|
const Context = @This();
|
|
460
484
|
const Socket = struct {
|
|
461
|
-
fd: os.socket_t =
|
|
485
|
+
fd: os.socket_t = IO.INVALID_SOCKET,
|
|
462
486
|
completion: IO.Completion = undefined,
|
|
463
487
|
};
|
|
464
488
|
const Pipe = struct {
|
|
@@ -470,13 +494,11 @@ test "pipe data over socket" {
|
|
|
470
494
|
fn run() !void {
|
|
471
495
|
const tx_buf = try testing.allocator.alloc(u8, buffer_size);
|
|
472
496
|
defer testing.allocator.free(tx_buf);
|
|
473
|
-
|
|
474
497
|
const rx_buf = try testing.allocator.alloc(u8, buffer_size);
|
|
475
498
|
defer testing.allocator.free(rx_buf);
|
|
476
499
|
|
|
477
500
|
std.mem.set(u8, tx_buf, 1);
|
|
478
501
|
std.mem.set(u8, rx_buf, 0);
|
|
479
|
-
|
|
480
502
|
var self = Context{
|
|
481
503
|
.io = try IO.init(32, 0),
|
|
482
504
|
.tx = .{ .buffer = tx_buf },
|
|
@@ -484,7 +506,7 @@ test "pipe data over socket" {
|
|
|
484
506
|
};
|
|
485
507
|
defer self.io.deinit();
|
|
486
508
|
|
|
487
|
-
self.server.fd = try
|
|
509
|
+
self.server.fd = try self.io.open_socket(os.AF.INET, os.SOCK.STREAM, os.IPPROTO.TCP);
|
|
488
510
|
defer os.closeSocket(self.server.fd);
|
|
489
511
|
|
|
490
512
|
const address = try std.net.Address.parseIp4("127.0.0.1", 3131);
|
|
@@ -506,7 +528,7 @@ test "pipe data over socket" {
|
|
|
506
528
|
self.server.fd,
|
|
507
529
|
);
|
|
508
530
|
|
|
509
|
-
self.tx.socket.fd = try
|
|
531
|
+
self.tx.socket.fd = try self.io.open_socket(os.AF.INET, os.SOCK.STREAM, os.IPPROTO.TCP);
|
|
510
532
|
defer os.closeSocket(self.tx.socket.fd);
|
|
511
533
|
|
|
512
534
|
self.io.connect(
|
|
@@ -528,9 +550,9 @@ test "pipe data over socket" {
|
|
|
528
550
|
}
|
|
529
551
|
}
|
|
530
552
|
|
|
531
|
-
try testing.expect(self.server.fd !=
|
|
532
|
-
try testing.expect(self.tx.socket.fd !=
|
|
533
|
-
try testing.expect(self.rx.socket.fd !=
|
|
553
|
+
try testing.expect(self.server.fd != IO.INVALID_SOCKET);
|
|
554
|
+
try testing.expect(self.tx.socket.fd != IO.INVALID_SOCKET);
|
|
555
|
+
try testing.expect(self.rx.socket.fd != IO.INVALID_SOCKET);
|
|
534
556
|
os.closeSocket(self.rx.socket.fd);
|
|
535
557
|
|
|
536
558
|
try testing.expectEqual(self.tx.transferred, buffer_size);
|
|
@@ -543,7 +565,7 @@ test "pipe data over socket" {
|
|
|
543
565
|
completion: *IO.Completion,
|
|
544
566
|
result: IO.AcceptError!os.socket_t,
|
|
545
567
|
) void {
|
|
546
|
-
assert(self.rx.socket.fd ==
|
|
568
|
+
assert(self.rx.socket.fd == IO.INVALID_SOCKET);
|
|
547
569
|
assert(&self.server.completion == completion);
|
|
548
570
|
self.rx.socket.fd = result catch |err| std.debug.panic("accept error {}", .{err});
|
|
549
571
|
|
|
@@ -559,7 +581,7 @@ test "pipe data over socket" {
|
|
|
559
581
|
_ = completion;
|
|
560
582
|
_ = result catch unreachable;
|
|
561
583
|
|
|
562
|
-
assert(self.tx.socket.fd !=
|
|
584
|
+
assert(self.tx.socket.fd != IO.INVALID_SOCKET);
|
|
563
585
|
assert(&self.tx.socket.completion == completion);
|
|
564
586
|
|
|
565
587
|
assert(self.tx.transferred == 0);
|