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.
Files changed (34) hide show
  1. package/README.md +3 -4
  2. package/package.json +1 -1
  3. package/src/node.zig +2 -12
  4. package/src/tigerbeetle/scripts/benchmark.bat +46 -0
  5. package/src/tigerbeetle/scripts/install_zig.bat +2 -2
  6. package/src/tigerbeetle/scripts/install_zig.sh +1 -1
  7. package/src/tigerbeetle/scripts/vopr.sh +2 -2
  8. package/src/tigerbeetle/src/benchmark.zig +2 -6
  9. package/src/tigerbeetle/src/cli.zig +39 -18
  10. package/src/tigerbeetle/src/config.zig +24 -9
  11. package/src/tigerbeetle/src/demo.zig +1 -1
  12. package/src/tigerbeetle/src/io/benchmark.zig +24 -49
  13. package/src/tigerbeetle/src/io/darwin.zig +175 -44
  14. package/src/tigerbeetle/src/io/linux.zig +177 -72
  15. package/src/tigerbeetle/src/io/test.zig +61 -39
  16. package/src/tigerbeetle/src/io/windows.zig +1161 -0
  17. package/src/tigerbeetle/src/io.zig +2 -0
  18. package/src/tigerbeetle/src/main.zig +13 -8
  19. package/src/tigerbeetle/src/message_bus.zig +49 -61
  20. package/src/tigerbeetle/src/message_pool.zig +63 -57
  21. package/src/tigerbeetle/src/ring_buffer.zig +7 -0
  22. package/src/tigerbeetle/src/simulator.zig +4 -4
  23. package/src/tigerbeetle/src/storage.zig +0 -230
  24. package/src/tigerbeetle/src/test/cluster.zig +3 -6
  25. package/src/tigerbeetle/src/test/message_bus.zig +4 -3
  26. package/src/tigerbeetle/src/test/network.zig +13 -16
  27. package/src/tigerbeetle/src/test/state_checker.zig +3 -2
  28. package/src/tigerbeetle/src/tigerbeetle.zig +5 -3
  29. package/src/tigerbeetle/src/time.zig +58 -11
  30. package/src/tigerbeetle/src/vsr/client.zig +18 -32
  31. package/src/tigerbeetle/src/vsr/clock.zig +1 -1
  32. package/src/tigerbeetle/src/vsr/journal.zig +2 -6
  33. package/src/tigerbeetle/src/vsr/replica.zig +146 -169
  34. 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/fsync/read/close" {
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 = "test_io_write_fsync_read";
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 IO.openSocket(address.any.family, os.SOCK.STREAM, os.IPPROTO.TCP);
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 IO.openSocket(address.any.family, os.SOCK.STREAM, os.IPPROTO.TCP);
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 = try IO.init(32, 0),
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 = -1,
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 IO.openSocket(address.any.family, os.SOCK.STREAM, os.IPPROTO.TCP);
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 IO.openSocket(address.any.family, os.SOCK.STREAM, os.IPPROTO.TCP);
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 == -1);
356
+ assert(self.accepted == IO.INVALID_SOCKET);
368
357
 
369
- while (self.accepted == -1 or !self.connected)
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 != -1);
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 os.write(self.accepted, &send_buf);
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 == -1);
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 = -1,
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 IO.openSocket(os.AF.INET, os.SOCK.STREAM, os.IPPROTO.TCP);
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 IO.openSocket(os.AF.INET, os.SOCK.STREAM, os.IPPROTO.TCP);
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 != -1);
532
- try testing.expect(self.tx.socket.fd != -1);
533
- try testing.expect(self.rx.socket.fd != -1);
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 == -1);
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 != -1);
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);