tigerbeetle-node 0.3.3 → 0.5.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 (71) hide show
  1. package/README.md +21 -7
  2. package/dist/benchmark.js +1 -1
  3. package/dist/benchmark.js.map +1 -1
  4. package/dist/index.d.ts +22 -20
  5. package/dist/index.js +40 -18
  6. package/dist/index.js.map +1 -1
  7. package/dist/test.js +13 -1
  8. package/dist/test.js.map +1 -1
  9. package/package.json +12 -12
  10. package/scripts/postinstall.sh +2 -2
  11. package/src/benchmark.ts +4 -4
  12. package/src/index.ts +35 -9
  13. package/src/node.zig +139 -28
  14. package/src/test.ts +19 -5
  15. package/src/tigerbeetle/scripts/benchmark.sh +10 -3
  16. package/src/tigerbeetle/scripts/install.sh +2 -2
  17. package/src/tigerbeetle/scripts/install_zig.bat +109 -0
  18. package/src/tigerbeetle/scripts/install_zig.sh +21 -4
  19. package/src/tigerbeetle/scripts/vopr.bat +48 -0
  20. package/src/tigerbeetle/scripts/vopr.sh +33 -0
  21. package/src/tigerbeetle/src/benchmark.zig +74 -42
  22. package/src/tigerbeetle/src/cli.zig +136 -83
  23. package/src/tigerbeetle/src/config.zig +80 -26
  24. package/src/tigerbeetle/src/demo.zig +101 -78
  25. package/src/tigerbeetle/src/demo_01_create_accounts.zig +2 -7
  26. package/src/tigerbeetle/src/demo_02_lookup_accounts.zig +2 -7
  27. package/src/tigerbeetle/src/demo_03_create_transfers.zig +2 -7
  28. package/src/tigerbeetle/src/demo_04_create_transfers_two_phase_commit.zig +2 -5
  29. package/src/tigerbeetle/src/demo_05_accept_transfers.zig +2 -7
  30. package/src/tigerbeetle/src/demo_06_reject_transfers.zig +2 -7
  31. package/src/tigerbeetle/src/demo_07_lookup_transfers.zig +8 -0
  32. package/src/tigerbeetle/src/fifo.zig +20 -11
  33. package/src/tigerbeetle/src/io.zig +35 -22
  34. package/src/tigerbeetle/src/io_darwin.zig +701 -0
  35. package/src/tigerbeetle/src/main.zig +72 -25
  36. package/src/tigerbeetle/src/message_bus.zig +379 -456
  37. package/src/tigerbeetle/src/message_pool.zig +3 -3
  38. package/src/tigerbeetle/src/ring_buffer.zig +192 -37
  39. package/src/tigerbeetle/src/simulator.zig +317 -0
  40. package/src/tigerbeetle/src/state_machine.zig +846 -38
  41. package/src/tigerbeetle/src/storage.zig +488 -90
  42. package/src/tigerbeetle/src/test/cluster.zig +221 -0
  43. package/src/tigerbeetle/src/test/message_bus.zig +92 -0
  44. package/src/tigerbeetle/src/test/network.zig +182 -0
  45. package/src/tigerbeetle/src/test/packet_simulator.zig +371 -0
  46. package/src/tigerbeetle/src/test/state_checker.zig +142 -0
  47. package/src/tigerbeetle/src/test/state_machine.zig +71 -0
  48. package/src/tigerbeetle/src/test/storage.zig +375 -0
  49. package/src/tigerbeetle/src/test/time.zig +84 -0
  50. package/src/tigerbeetle/src/tigerbeetle.zig +6 -3
  51. package/src/tigerbeetle/src/time.zig +65 -0
  52. package/src/tigerbeetle/src/unit_tests.zig +14 -0
  53. package/src/tigerbeetle/src/vsr/client.zig +519 -0
  54. package/src/tigerbeetle/src/vsr/clock.zig +829 -0
  55. package/src/tigerbeetle/src/vsr/journal.zig +1368 -0
  56. package/src/tigerbeetle/src/vsr/marzullo.zig +306 -0
  57. package/src/tigerbeetle/src/vsr/replica.zig +4248 -0
  58. package/src/tigerbeetle/src/vsr.zig +601 -0
  59. package/src/tigerbeetle/LICENSE +0 -177
  60. package/src/tigerbeetle/README.md +0 -116
  61. package/src/tigerbeetle/src/client.zig +0 -319
  62. package/src/tigerbeetle/src/concurrent_ranges.zig +0 -162
  63. package/src/tigerbeetle/src/fixed_array_list.zig +0 -53
  64. package/src/tigerbeetle/src/io_async.zig +0 -600
  65. package/src/tigerbeetle/src/journal.zig +0 -567
  66. package/src/tigerbeetle/src/test_client.zig +0 -41
  67. package/src/tigerbeetle/src/test_main.zig +0 -118
  68. package/src/tigerbeetle/src/test_message_bus.zig +0 -132
  69. package/src/tigerbeetle/src/vr/journal.zig +0 -672
  70. package/src/tigerbeetle/src/vr/replica.zig +0 -3061
  71. package/src/tigerbeetle/src/vr.zig +0 -374
@@ -0,0 +1,109 @@
1
+ @echo off
2
+
3
+ set DEFAULT_RELEASE=0.8.1
4
+
5
+ :: Determine the Zig build:
6
+ if "%~1"=="" (
7
+ set ZIG_RELEASE=%DEFAULT_RELEASE%
8
+ ) else if "%~1"=="latest" (
9
+ set ZIG_RELEASE=builds
10
+ ) else (
11
+ set ZIG_RELEASE=%~1
12
+ )
13
+
14
+ :: Checks format of release version.
15
+ echo.%ZIG_RELEASE% | findstr /b /r /c:"builds" /c:"^[0-9][0-9]*.[0-9][0-9]*.[0-9][0-9]*">nul || (echo.Unexpected release format. && exit 1)
16
+
17
+ set ZIG_OS=windows
18
+ set ZIG_ARCH=x86_64
19
+
20
+ set ZIG_TARGET=zig-%ZIG_OS%-%ZIG_ARCH%
21
+
22
+ :: Determine the build, split the JSON line on whitespace and extract the 2nd field:
23
+ for /f "tokens=2" %%a in ('curl --silent https://ziglang.org/download/index.json ^| findstr %ZIG_TARGET% ^| findstr %ZIG_RELEASE%' ) do (
24
+ set ZIG_URL=%%a
25
+ )
26
+
27
+ :: Then remove quotes and commas:
28
+ for /f %%b in ("%ZIG_URL:,=%") do (
29
+ set ZIG_URL=%%~b
30
+ )
31
+
32
+ :: Checks the ZIG_URL variable follows the expected format.
33
+ echo.%ZIG_URL% | findstr /b /r /c:"https://ziglang.org/builds/" /c:"https://ziglang.org/download/%ZIG_RELEASE%">nul || (echo.Unexpected release URL format. && exit 1)
34
+
35
+ if "%ZIG_RELEASE%"=="builds" (
36
+ echo Installing Zig latest build...
37
+ ) else (
38
+ echo Installing Zig %ZIG_RELEASE% release build...
39
+ )
40
+
41
+ :: Using variable modifiers to determine the directory and filename from the URL:
42
+ :: %~ni Expands %i to a file name only and %~xi Expands %i to a file name extension only.
43
+ for /f %%i in ("%ZIG_URL%") do (
44
+ set ZIG_DIRECTORY=%%~ni
45
+ set ZIG_TARBALL=%%~nxi
46
+ )
47
+
48
+ :: Checks the ZIG_DIRECTORY variable follows the expected format.
49
+ echo.%ZIG_DIRECTORY% | findstr /b /r /c:"zig-win64-" /c:"zig-windows-x86_64-">nul || (echo.Unexpected zip directory name format. && exit 1)
50
+
51
+ :: Making sure we download to the same output document, without wget adding "-1" etc. if the file was previously partially downloaded:
52
+ if exist %ZIG_TARBALL% (
53
+ del /q %ZIG_TARBALL%
54
+ if exist %ZIG_TARBALL% (
55
+ echo Failed to delete %ZIG_TARBALL%.
56
+ exit 1
57
+ )
58
+ )
59
+
60
+ echo Downloading %ZIG_URL%...
61
+ curl --silent --progress-bar --output %ZIG_TARBALL% %ZIG_URL%
62
+ if not exist %ZIG_TARBALL% (
63
+ echo Failed to download Zig zip file.
64
+ exit 1
65
+ )
66
+
67
+ :: Replace any existing Zig installation so that we can install or upgrade:
68
+ echo Removing any existing 'zig' and %ZIG_DIRECTORY% folders before extracting.
69
+ if exist zig\ (
70
+ rd /s /q zig\
71
+ :: Ensure the directory has been deleted.
72
+ if exist zig\ (
73
+ echo The ‘zig’ directory could not be deleted.
74
+ exit 1
75
+ )
76
+ )
77
+
78
+ if exist %ZIG_DIRECTORY%\ (
79
+ rd /s /q %ZIG_DIRECTORY%
80
+ :: Ensure the directory has been deleted.
81
+ if exist %ZIG_DIRECTORY% (
82
+ echo The %ZIG_DIRECTORY% directory could not be deleted.
83
+ exit 1
84
+ )
85
+ )
86
+
87
+ :: Extract and then remove the downloaded tarball:
88
+ echo Extracting %ZIG_TARBALL%...
89
+ powershell -Command "Expand-Archive %ZIG_TARBALL% -DestinationPath ."
90
+ if not exist %ZIG_TARBALL% (
91
+ echo Failed to extract zip file.
92
+ exit 1
93
+ )
94
+
95
+ echo Installing %ZIG_DIRECTORY% to 'zig' in current working directory...
96
+ ren %ZIG_DIRECTORY% zig
97
+ if exist %ZIG_DIRECTORY% (
98
+ echo Failed to rename %ZIG_DIRECTORY% to zig.
99
+ exit 1
100
+ )
101
+
102
+ :: Removes the zip file
103
+ del /q %ZIG_TARBALL%
104
+ if exist %ZIG_TARBALL% (
105
+ echo Failed to delete %ZIG_TARBALL% file.
106
+ exit 1
107
+ )
108
+
109
+ echo "Congratulations, you have successfully installed Zig version %ZIG_RELEASE%. Enjoy!"
@@ -1,12 +1,23 @@
1
1
  #!/bin/bash
2
2
  set -e
3
3
 
4
- if [ "$1" == "0.8.0" ]; then
5
- ZIG_RELEASE="0.8.0"
6
- echo "Installing Zig $ZIG_RELEASE release build..."
7
- else
4
+ # Default to the 0.8.1 build, or allow the latest dev build, or an explicit release version:
5
+ if [ -z "$1" ]; then
6
+ ZIG_RELEASE="0.8.1"
7
+ elif [ "$1" == "latest" ]; then
8
8
  ZIG_RELEASE="builds"
9
+ else
10
+ ZIG_RELEASE=$1
11
+ fi
12
+
13
+ # Validate the release version explicitly:
14
+ if [[ $ZIG_RELEASE =~ ^builds$ ]]; then
9
15
  echo "Installing Zig latest build..."
16
+ elif [[ $ZIG_RELEASE =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
17
+ echo "Installing Zig $ZIG_RELEASE release build..."
18
+ else
19
+ echo "Release version invalid"
20
+ exit 1
10
21
  fi
11
22
 
12
23
  # Determine the architecture:
@@ -32,6 +43,12 @@ else
32
43
  ZIG_URL=`curl --silent https://ziglang.org/download/index.json | grep "$ZIG_TARGET" | grep "$ZIG_RELEASE" | awk '{print $2}' | sed 's/[",]//g'`
33
44
  fi
34
45
 
46
+ # Ensure that the release is actually hosted on the ziglang.org website:
47
+ if [ -z "$ZIG_URL" ]; then
48
+ echo "Release not found on ziglang.org"
49
+ exit 1
50
+ fi
51
+
35
52
  # Work out the filename from the URL, as well as the directory without the ".tar.xz" file extension:
36
53
  ZIG_TARBALL=`basename "$ZIG_URL"`
37
54
  ZIG_DIRECTORY=`basename "$ZIG_TARBALL" .tar.xz`
@@ -0,0 +1,48 @@
1
+ :: Installs Zig if needed and runs the VOPR
2
+ @echo off
3
+
4
+ :: Install Zig if a zig folder does not already exist:
5
+ if not exist zig\ (
6
+ :: Installs the latest version of Zig
7
+ call scripts\install_zig.bat
8
+ :: Checks that the Zig folder now exists
9
+ if not exist zig\ (
10
+ echo The Zig installation failed.
11
+ exit 1
12
+ )
13
+ echo Running the TigerBeetle VOPR for the first time...
14
+ echo Visit https://www.tigerbeetle.com
15
+ )
16
+
17
+ :: If a seed is provided as an argument then replay the seed, otherwise test 1,000 seeds:
18
+ if not "%~1"=="" (
19
+ :: Build in fast ReleaseSafe mode if required, useful where you don't need debug logging:
20
+ if "%~2"=="-OReleaseSafe" (
21
+ echo Replaying seed %~1 in ReleaseSafe mode...
22
+ call zig\zig run src\simulator.zig -OReleaseSafe -- %~1
23
+ if not %ERRORLEVEL%==0 (
24
+ echo Cannot replay the %~1 seed using the VOPR.
25
+ exit 1
26
+ )
27
+ ) else (
28
+ echo Replaying seed %~1 in Debug mode with full debug logging enabled...
29
+ call zig\zig run src\simulator.zig -ODebug -- %~1
30
+ if not %ERRORLEVEL%==0 (
31
+ echo Cannot run the VOPR.
32
+ exit 1
33
+ )
34
+ )
35
+ ) else (
36
+ call zig\zig build-exe src\simulator.zig -OReleaseSafe
37
+ if not %ERRORLEVEL%==0 (
38
+ echo Cannot run the VOPR.
39
+ exit 1
40
+ )
41
+ for %%i in (1,1,1000) do (
42
+ call simulator
43
+ if not %ERRORLEVEL%==0 (
44
+ echo Cannot run a seed using the VOPR.
45
+ exit 1
46
+ )
47
+ )
48
+ )
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env bash
2
+ set -e
3
+
4
+ # Install Zig 0.8.0 if it does not already exist:
5
+ if [ ! -d "zig" ]; then
6
+ scripts/install_zig.sh 0.8.0
7
+ echo ""
8
+ echo "Running the TigerBeetle VOPR for the first time..."
9
+ echo "Visit https://www.tigerbeetle.com"
10
+ sleep 2
11
+ fi
12
+
13
+ # If a seed is provided as an argument then replay the seed, otherwise test a 1,000 seeds:
14
+ if [ "$1" ]; then
15
+
16
+ # Build in fast ReleaseSafe mode if required, useful where you don't need debug logging:
17
+ if [ "$2" == "-OReleaseSafe" ]; then
18
+ echo "Replaying seed $1 in ReleaseSafe mode..."
19
+ BUILD_MODE="-OReleaseSafe"
20
+ else
21
+ echo "Replaying seed $1 in Debug mode with full debug logging enabled..."
22
+ BUILD_MODE="-ODebug"
23
+ fi
24
+ echo ""
25
+
26
+ zig/zig run src/simulator.zig $BUILD_MODE -- $1
27
+ else
28
+ zig/zig build-exe src/simulator.zig -OReleaseSafe
29
+ for I in {1..1000}
30
+ do
31
+ ./simulator
32
+ done
33
+ fi
@@ -4,20 +4,25 @@ const config = @import("config.zig");
4
4
 
5
5
  const cli = @import("cli.zig");
6
6
  const IO = @import("io.zig").IO;
7
- const Client = @import("client.zig").Client;
7
+
8
8
  const MessageBus = @import("message_bus.zig").MessageBusClient;
9
- const TigerBeetle = @import("tigerbeetle.zig");
10
- const Transfer = TigerBeetle.Transfer;
11
- const Commit = TigerBeetle.Commit;
12
- const Account = TigerBeetle.Account;
13
- const CreateAccountsResult = TigerBeetle.CreateAccountsResult;
14
- const CreateTransfersResult = TigerBeetle.CreateTransfersResult;
15
- const Operation = @import("state_machine.zig").Operation;
16
- const Header = @import("vr.zig").Header;
9
+ const StateMachine = @import("state_machine.zig").StateMachine;
10
+ const Operation = StateMachine.Operation;
17
11
  const RingBuffer = @import("ring_buffer.zig").RingBuffer;
18
12
 
13
+ const vsr = @import("vsr.zig");
14
+ const Header = vsr.Header;
15
+ const Client = vsr.Client(StateMachine, MessageBus);
16
+
17
+ const tb = @import("tigerbeetle.zig");
18
+ const Transfer = tb.Transfer;
19
+ const Commit = tb.Commit;
20
+ const Account = tb.Account;
21
+ const CreateAccountsResult = tb.CreateAccountsResult;
22
+ const CreateTransfersResult = tb.CreateTransfersResult;
23
+
19
24
  const MAX_TRANSFERS: u32 = 1_000_000;
20
- const BATCH_SIZE: u32 = 10_000;
25
+ const BATCH_SIZE: u32 = 5_000;
21
26
  const IS_TWO_PHASE_COMMIT = false;
22
27
  const BENCHMARK = if (IS_TWO_PHASE_COMMIT) 500_000 else 1_000_000;
23
28
  const RESULT_TOLERANCE = 10; // percent
@@ -25,7 +30,7 @@ const BATCHES: f32 = MAX_TRANSFERS / BATCH_SIZE;
25
30
  const TOTAL_BATCHES = @ceil(BATCHES);
26
31
 
27
32
  const log = std.log;
28
- pub const log_level: std.log.Level = .info;
33
+ pub const log_level: std.log.Level = .notice;
29
34
 
30
35
  var accounts = [_]Account{
31
36
  Account{
@@ -57,28 +62,32 @@ var max_create_transfers_latency: i64 = 0;
57
62
  var max_commit_transfers_latency: i64 = 0;
58
63
 
59
64
  pub fn main() !void {
60
- std.debug.print("builtin {o}\n", .{std.builtin.mode});
65
+ const stdout = std.io.getStdOut().writer();
66
+ const stderr = std.io.getStdErr().writer();
67
+
61
68
  if (std.builtin.mode != .ReleaseSafe and std.builtin.mode != .ReleaseFast) {
62
- log.warn("The client has not been built in ReleaseSafe or ReleaseFast mode.\n", .{});
69
+ try stderr.print("Benchmark must be built as ReleaseSafe for minimum performance.\n", .{});
63
70
  }
71
+
64
72
  var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
65
73
  defer arena.deinit();
66
74
  const allocator = &arena.allocator;
67
75
 
68
- const client_id: u128 = 123;
69
- const cluster_id: u128 = 746649394563965214; // a5ca1ab1ebee11e
76
+ const client_id = std.crypto.random.int(u128);
77
+ const cluster_id: u32 = 0;
70
78
  var address = [_]std.net.Address{try std.net.Address.parseIp4("127.0.0.1", config.port)};
71
79
  var io = try IO.init(32, 0);
72
80
  var message_bus = try MessageBus.init(allocator, cluster_id, address[0..], client_id, &io);
73
81
  defer message_bus.deinit();
74
82
  var client = try Client.init(
75
83
  allocator,
84
+ client_id,
76
85
  cluster_id,
77
- @intCast(u16, address.len),
86
+ @intCast(u8, address.len),
78
87
  &message_bus,
79
88
  );
80
89
  defer client.deinit();
81
- message_bus.process = .{ .client = &client };
90
+ message_bus.set_on_message(*Client, &client, Client.on_message);
82
91
 
83
92
  // Pre-allocate a million transfers:
84
93
  var transfers = try arena.allocator.alloc(Transfer, MAX_TRANSFERS);
@@ -111,7 +120,7 @@ pub fn main() !void {
111
120
 
112
121
  try wait_for_connect(&client, &io);
113
122
 
114
- std.debug.print("creating accounts...\n", .{});
123
+ try stdout.print("creating accounts...\n", .{});
115
124
  var queue = TimedQueue.init(&client, &io);
116
125
  try queue.push(.{
117
126
  .operation = Operation.create_accounts,
@@ -121,7 +130,7 @@ pub fn main() !void {
121
130
  assert(queue.end != null);
122
131
  assert(queue.batches.empty());
123
132
 
124
- log.info("batching transfers...", .{});
133
+ try stdout.print("batching transfers...\n", .{});
125
134
  var count: u64 = 0;
126
135
  queue.reset();
127
136
  while (count < transfers.len) {
@@ -141,29 +150,27 @@ pub fn main() !void {
141
150
  }
142
151
  assert(count == MAX_TRANSFERS);
143
152
 
144
- log.info("starting benchmark...", .{});
153
+ try stdout.print("starting benchmark...\n", .{});
145
154
  try queue.execute();
146
155
  assert(queue.end != null);
147
156
  assert(queue.batches.empty());
148
157
 
149
158
  var ms = queue.end.? - queue.start.?;
150
- const transfer_type = if (IS_TWO_PHASE_COMMIT) "two-phase commit" else "";
159
+ const transfer_type = if (IS_TWO_PHASE_COMMIT) "two-phase commit " else "";
151
160
  const result: i64 = @divFloor(@intCast(i64, transfers.len * 1000), ms);
152
- log.info("============================================", .{});
153
- log.info("{} {s} transfers per second\n", .{
161
+ try stdout.print("============================================\n", .{});
162
+ try stdout.print("{} {s}transfers per second\n\n", .{
154
163
  result,
155
164
  transfer_type,
156
165
  });
157
- log.info("create_transfers max p100 latency per 10,000 transfers = {}ms\n", .{
166
+ try stdout.print("create_transfers max p100 latency per {} transfers = {}ms\n", .{
167
+ BATCH_SIZE,
158
168
  queue.max_transfers_latency,
159
169
  });
160
- log.info("commit_transfers max p100 latency per 10,000 transfers = {}ms\n", .{
170
+ try stdout.print("commit_transfers max p100 latency per {} transfers = {}ms\n", .{
171
+ BATCH_SIZE,
161
172
  queue.max_commits_latency,
162
173
  });
163
-
164
- if (result < @divFloor(@intCast(i64, BENCHMARK * (100 - RESULT_TOLERANCE)), 100)) {
165
- log.warn("There has been a performance regression. previous benchmark={}\n", .{BENCHMARK});
166
- }
167
174
  }
168
175
 
169
176
  const Batch = struct {
@@ -214,17 +221,27 @@ const TimedQueue = struct {
214
221
  self.reset();
215
222
  log.debug("executing batches...", .{});
216
223
 
217
- var batch: ?Batch = self.batches.peek();
218
224
  const now = std.time.milliTimestamp();
219
225
  self.start = now;
220
- if (batch) |*starting_batch| {
226
+ if (self.batches.head_ptr()) |starting_batch| {
221
227
  log.debug("sending first batch...", .{});
222
228
  self.batch_start = now;
229
+ var message = self.client.get_message() orelse {
230
+ @panic("Client message pool has been exhausted. Cannot execute batch.");
231
+ };
232
+ defer self.client.unref(message);
233
+
234
+ std.mem.copy(
235
+ u8,
236
+ message.buffer[@sizeOf(Header)..],
237
+ std.mem.sliceAsBytes(starting_batch.data),
238
+ );
223
239
  self.client.request(
224
240
  @intCast(u128, @ptrToInt(self)),
225
241
  TimedQueue.lap,
226
242
  starting_batch.operation,
227
- starting_batch.data,
243
+ message,
244
+ starting_batch.data.len,
228
245
  );
229
246
  }
230
247
 
@@ -234,20 +251,24 @@ const TimedQueue = struct {
234
251
  }
235
252
  }
236
253
 
237
- pub fn lap(user_data: u128, operation: Operation, results: []const u8) void {
254
+ pub fn lap(user_data: u128, operation: Operation, results: Client.Error![]const u8) void {
238
255
  const now = std.time.milliTimestamp();
239
- assert(results.len == 0);
240
- if (log_level == .debug) {
241
- const response = std.mem.bytesAsSlice(CreateAccountsResult, results);
242
- log.debug("{o}", .{response});
243
- }
256
+ const value = results catch |err| {
257
+ log.emerg("Client returned error={o}", .{@errorName(err)});
258
+ @panic("Client returned error during benchmarking.");
259
+ };
260
+
261
+ log.debug("response={s}", .{std.mem.bytesAsSlice(CreateAccountsResult, value)});
244
262
 
245
263
  const self: *TimedQueue = @intToPtr(*TimedQueue, @intCast(usize, user_data));
246
264
  const completed_batch: ?Batch = self.batches.pop();
247
265
  assert(completed_batch != null);
248
266
  assert(completed_batch.?.operation == operation);
249
267
 
250
- log.debug("completed batch operation={} start={}", .{ completed_batch.?.operation, self.batch_start });
268
+ log.debug("completed batch operation={} start={}", .{
269
+ completed_batch.?.operation,
270
+ self.batch_start,
271
+ });
251
272
  const latency = now - self.batch_start.?;
252
273
  switch (operation) {
253
274
  .create_accounts => {},
@@ -264,14 +285,25 @@ const TimedQueue = struct {
264
285
  else => unreachable,
265
286
  }
266
287
 
267
- var batch: ?Batch = self.batches.peek();
268
- if (batch) |*next_batch| {
288
+ if (self.batches.head_ptr()) |next_batch| {
289
+ var message = self.client.get_message() orelse {
290
+ @panic("Client message pool has been exhausted.");
291
+ };
292
+ defer self.client.unref(message);
293
+
294
+ std.mem.copy(
295
+ u8,
296
+ message.buffer[@sizeOf(Header)..],
297
+ std.mem.sliceAsBytes(next_batch.data),
298
+ );
299
+
269
300
  self.batch_start = std.time.milliTimestamp();
270
301
  self.client.request(
271
302
  @intCast(u128, @ptrToInt(self)),
272
303
  TimedQueue.lap,
273
304
  next_batch.operation,
274
- next_batch.data,
305
+ message,
306
+ next_batch.data.len,
275
307
  );
276
308
  } else {
277
309
  log.debug("stopping timer...", .{});