tigerbeetle-node 0.8.1 → 0.9.143

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 (83) hide show
  1. package/README.md +584 -184
  2. package/dist/benchmark.js +59 -51
  3. package/dist/benchmark.js.map +1 -1
  4. package/dist/bin/aarch64-linux-gnu/client.node +0 -0
  5. package/dist/bin/aarch64-linux-musl/client.node +0 -0
  6. package/dist/bin/aarch64-macos/client.node +0 -0
  7. package/dist/bin/x86_64-linux-gnu/client.node +0 -0
  8. package/dist/bin/x86_64-linux-musl/client.node +0 -0
  9. package/dist/bin/x86_64-macos/client.node +0 -0
  10. package/dist/bin/x86_64-windows/client.node +0 -0
  11. package/dist/bindings.d.ts +141 -0
  12. package/dist/bindings.js +112 -0
  13. package/dist/bindings.js.map +1 -0
  14. package/dist/index.d.ts +2 -125
  15. package/dist/index.js +51 -101
  16. package/dist/index.js.map +1 -1
  17. package/dist/test.js +69 -55
  18. package/dist/test.js.map +1 -1
  19. package/package-lock.json +26 -0
  20. package/package.json +17 -28
  21. package/src/benchmark.ts +58 -49
  22. package/src/bindings.ts +631 -0
  23. package/src/index.ts +71 -163
  24. package/src/node.zig +169 -148
  25. package/src/test.ts +71 -57
  26. package/src/translate.zig +19 -36
  27. package/.yarn/releases/yarn-berry.cjs +0 -55
  28. package/.yarnrc.yml +0 -1
  29. package/scripts/download_node_headers.sh +0 -25
  30. package/scripts/postinstall.sh +0 -6
  31. package/src/tigerbeetle/scripts/benchmark.bat +0 -46
  32. package/src/tigerbeetle/scripts/benchmark.sh +0 -55
  33. package/src/tigerbeetle/scripts/install.sh +0 -6
  34. package/src/tigerbeetle/scripts/install_zig.bat +0 -109
  35. package/src/tigerbeetle/scripts/install_zig.sh +0 -84
  36. package/src/tigerbeetle/scripts/lint.zig +0 -199
  37. package/src/tigerbeetle/scripts/upgrade_ubuntu_kernel.sh +0 -39
  38. package/src/tigerbeetle/scripts/vopr.bat +0 -48
  39. package/src/tigerbeetle/scripts/vopr.sh +0 -33
  40. package/src/tigerbeetle/scripts/vr_state_enumerate +0 -46
  41. package/src/tigerbeetle/src/benchmark.zig +0 -290
  42. package/src/tigerbeetle/src/cli.zig +0 -244
  43. package/src/tigerbeetle/src/config.zig +0 -239
  44. package/src/tigerbeetle/src/demo.zig +0 -125
  45. package/src/tigerbeetle/src/demo_01_create_accounts.zig +0 -35
  46. package/src/tigerbeetle/src/demo_02_lookup_accounts.zig +0 -7
  47. package/src/tigerbeetle/src/demo_03_create_transfers.zig +0 -24
  48. package/src/tigerbeetle/src/demo_04_create_pending_transfers.zig +0 -61
  49. package/src/tigerbeetle/src/demo_05_post_pending_transfers.zig +0 -37
  50. package/src/tigerbeetle/src/demo_06_void_pending_transfers.zig +0 -24
  51. package/src/tigerbeetle/src/demo_07_lookup_transfers.zig +0 -7
  52. package/src/tigerbeetle/src/fifo.zig +0 -104
  53. package/src/tigerbeetle/src/io/benchmark.zig +0 -213
  54. package/src/tigerbeetle/src/io/darwin.zig +0 -793
  55. package/src/tigerbeetle/src/io/linux.zig +0 -1038
  56. package/src/tigerbeetle/src/io/test.zig +0 -643
  57. package/src/tigerbeetle/src/io/windows.zig +0 -1161
  58. package/src/tigerbeetle/src/io.zig +0 -34
  59. package/src/tigerbeetle/src/main.zig +0 -144
  60. package/src/tigerbeetle/src/message_bus.zig +0 -1000
  61. package/src/tigerbeetle/src/message_pool.zig +0 -142
  62. package/src/tigerbeetle/src/ring_buffer.zig +0 -289
  63. package/src/tigerbeetle/src/simulator.zig +0 -417
  64. package/src/tigerbeetle/src/state_machine.zig +0 -2470
  65. package/src/tigerbeetle/src/storage.zig +0 -308
  66. package/src/tigerbeetle/src/test/cluster.zig +0 -351
  67. package/src/tigerbeetle/src/test/message_bus.zig +0 -93
  68. package/src/tigerbeetle/src/test/network.zig +0 -179
  69. package/src/tigerbeetle/src/test/packet_simulator.zig +0 -387
  70. package/src/tigerbeetle/src/test/state_checker.zig +0 -145
  71. package/src/tigerbeetle/src/test/state_machine.zig +0 -76
  72. package/src/tigerbeetle/src/test/storage.zig +0 -438
  73. package/src/tigerbeetle/src/test/time.zig +0 -84
  74. package/src/tigerbeetle/src/tigerbeetle.zig +0 -222
  75. package/src/tigerbeetle/src/time.zig +0 -113
  76. package/src/tigerbeetle/src/unit_tests.zig +0 -14
  77. package/src/tigerbeetle/src/vsr/client.zig +0 -505
  78. package/src/tigerbeetle/src/vsr/clock.zig +0 -812
  79. package/src/tigerbeetle/src/vsr/journal.zig +0 -2293
  80. package/src/tigerbeetle/src/vsr/marzullo.zig +0 -309
  81. package/src/tigerbeetle/src/vsr/replica.zig +0 -5015
  82. package/src/tigerbeetle/src/vsr.zig +0 -1017
  83. package/yarn.lock +0 -42
@@ -1,46 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- const messages = [
4
- 'prepare',
5
- 'prepare_ok',
6
- 'commit',
7
- 'request_state_transfer',
8
- 'state_transfer',
9
- 'start_view_change',
10
- 'do_view_change',
11
- 'start_view'
12
- ];
13
-
14
- const views = [
15
- 'old_view',
16
- 'same_view',
17
- 'new_view'
18
- ];
19
-
20
- const statuses = [
21
- 'normal',
22
- 'view_change',
23
- 'recovering'
24
- ];
25
-
26
- const tuples = {};
27
-
28
- statuses.forEach(
29
- function(status) {
30
- views.forEach(
31
- function(view) {
32
- messages.forEach(
33
- function(message) {
34
- tuples[`${message}, ${view}, ${status}`] = true;
35
- }
36
- );
37
- }
38
- );
39
- }
40
- );
41
-
42
- Object.keys(tuples).sort().forEach(
43
- function(key) {
44
- console.log(key);
45
- }
46
- );
@@ -1,290 +0,0 @@
1
- const std = @import("std");
2
- const builtin = @import("builtin");
3
- const assert = std.debug.assert;
4
- const config = @import("config.zig");
5
-
6
- const log = std.log;
7
- pub const log_level: std.log.Level = .err;
8
-
9
- const cli = @import("cli.zig");
10
- const IO = @import("io.zig").IO;
11
-
12
- const MessageBus = @import("message_bus.zig").MessageBusClient;
13
- const StateMachine = @import("state_machine.zig").StateMachine;
14
- const RingBuffer = @import("ring_buffer.zig").RingBuffer;
15
-
16
- const vsr = @import("vsr.zig");
17
- const Client = vsr.Client(StateMachine, MessageBus);
18
-
19
- const tb = @import("tigerbeetle.zig");
20
-
21
- const batches_count = 100;
22
-
23
- const transfers_per_batch: u32 = @divExact(
24
- config.message_size_max - @sizeOf(vsr.Header),
25
- @sizeOf(tb.Transfer),
26
- );
27
- comptime {
28
- assert(transfers_per_batch >= 2041);
29
- }
30
-
31
- const transfers_max: u32 = batches_count * transfers_per_batch;
32
-
33
- var accounts = [_]tb.Account{
34
- .{
35
- .id = 1,
36
- .user_data = 0,
37
- .reserved = [_]u8{0} ** 48,
38
- .ledger = 2,
39
- .code = 0,
40
- .flags = .{},
41
- .debits_pending = 0,
42
- .debits_posted = 0,
43
- .credits_pending = 0,
44
- .credits_posted = 0,
45
- },
46
- .{
47
- .id = 2,
48
- .user_data = 0,
49
- .reserved = [_]u8{0} ** 48,
50
- .ledger = 2,
51
- .code = 0,
52
- .flags = .{},
53
- .debits_pending = 0,
54
- .debits_posted = 0,
55
- .credits_pending = 0,
56
- .credits_posted = 0,
57
- },
58
- };
59
- var create_transfers_latency_max: i64 = 0;
60
-
61
- pub fn main() !void {
62
- const stdout = std.io.getStdOut().writer();
63
- const stderr = std.io.getStdErr().writer();
64
-
65
- if (builtin.mode != .ReleaseSafe and builtin.mode != .ReleaseFast) {
66
- try stderr.print("Benchmark must be built as ReleaseSafe for reasonable results.\n", .{});
67
- }
68
-
69
- var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
70
- defer arena.deinit();
71
-
72
- const allocator = arena.allocator();
73
-
74
- const client_id = std.crypto.random.int(u128);
75
- const cluster_id: u32 = 0;
76
- var address = [_]std.net.Address{try std.net.Address.parseIp4("127.0.0.1", config.port)};
77
-
78
- var io = try IO.init(32, 0);
79
- var message_bus = try MessageBus.init(allocator, cluster_id, address[0..], client_id, &io);
80
- defer message_bus.deinit();
81
-
82
- var client = try Client.init(
83
- allocator,
84
- client_id,
85
- cluster_id,
86
- @intCast(u8, address.len),
87
- &message_bus,
88
- );
89
- defer client.deinit();
90
-
91
- message_bus.set_on_message(*Client, &client, Client.on_message);
92
-
93
- // Pre-allocate a million transfers:
94
- const transfers = try arena.allocator().alloc(tb.Transfer, transfers_max);
95
- for (transfers) |*transfer, index| {
96
- transfer.* = .{
97
- .id = index,
98
- .debit_account_id = accounts[0].id,
99
- .credit_account_id = accounts[1].id,
100
- .pending_id = 0,
101
- .user_data = 0,
102
- .reserved = 0,
103
- .code = 0,
104
- .ledger = 2,
105
- .flags = .{},
106
- .amount = 1,
107
- .timeout = 0,
108
- };
109
- }
110
-
111
- try wait_for_connect(&client, &io);
112
-
113
- var queue = TimedQueue.init(&client, &io);
114
- try queue.push(.{
115
- .operation = StateMachine.Operation.create_accounts,
116
- .data = std.mem.sliceAsBytes(accounts[0..]),
117
- });
118
-
119
- try queue.execute();
120
- assert(queue.end != null);
121
- assert(queue.batches.empty());
122
-
123
- var count: u64 = 0;
124
- queue.reset();
125
- while (count < transfers.len) {
126
- try queue.push(.{
127
- .operation = .create_transfers,
128
- .data = std.mem.sliceAsBytes(transfers[count..][0..transfers_per_batch]),
129
- });
130
- count += transfers_per_batch;
131
- }
132
- assert(count == transfers_max);
133
-
134
- try queue.execute();
135
- assert(queue.end != null);
136
- assert(queue.batches.empty());
137
-
138
- var ms = queue.end.? - queue.start.?;
139
-
140
- const result: i64 = @divFloor(@intCast(i64, transfers.len * 1000), ms);
141
- try stdout.print("============================================\n", .{});
142
- try stdout.print("{} transfers per second\n\n", .{result});
143
- try stdout.print("max p100 latency per {} transfers = {}ms\n", .{
144
- transfers_per_batch,
145
- queue.transfers_latency_max,
146
- });
147
- }
148
-
149
- const Batch = struct {
150
- operation: StateMachine.Operation,
151
- data: []u8,
152
- };
153
-
154
- const TimedQueue = struct {
155
- batch_start: ?i64,
156
- start: ?i64,
157
- end: ?i64,
158
- transfers_latency_max: i64,
159
- client: *Client,
160
- io: *IO,
161
- batches: RingBuffer(Batch, batches_count),
162
-
163
- pub fn init(client: *Client, io: *IO) TimedQueue {
164
- var self = TimedQueue{
165
- .batch_start = null,
166
- .start = null,
167
- .end = null,
168
- .transfers_latency_max = 0,
169
- .client = client,
170
- .io = io,
171
- .batches = .{},
172
- };
173
-
174
- return self;
175
- }
176
-
177
- pub fn reset(self: *TimedQueue) void {
178
- self.batch_start = null;
179
- self.start = null;
180
- self.end = null;
181
- self.transfers_latency_max = 0;
182
- }
183
-
184
- pub fn push(self: *TimedQueue, batch: Batch) !void {
185
- try self.batches.push(batch);
186
- }
187
-
188
- pub fn execute(self: *TimedQueue) !void {
189
- assert(self.start == null);
190
- assert(!self.batches.empty());
191
- self.reset();
192
- log.debug("executing batches...", .{});
193
-
194
- const now = std.time.milliTimestamp();
195
- self.start = now;
196
- if (self.batches.head_ptr()) |starting_batch| {
197
- log.debug("sending first batch...", .{});
198
- self.batch_start = now;
199
- const message = self.client.get_message();
200
- defer self.client.unref(message);
201
-
202
- std.mem.copy(
203
- u8,
204
- message.buffer[@sizeOf(vsr.Header)..],
205
- std.mem.sliceAsBytes(starting_batch.data),
206
- );
207
- self.client.request(
208
- @intCast(u128, @ptrToInt(self)),
209
- TimedQueue.lap,
210
- starting_batch.operation,
211
- message,
212
- starting_batch.data.len,
213
- );
214
- }
215
-
216
- while (!self.batches.empty()) {
217
- self.client.tick();
218
- try self.io.run_for_ns(5 * std.time.ns_per_ms);
219
- }
220
- }
221
-
222
- pub fn lap(
223
- user_data: u128,
224
- operation: StateMachine.Operation,
225
- results: Client.Error![]const u8,
226
- ) void {
227
- const now = std.time.milliTimestamp();
228
- const value = results catch |err| {
229
- log.err("Client returned error={o}", .{@errorName(err)});
230
- @panic("Client returned error during benchmarking.");
231
- };
232
-
233
- log.debug("response={s}", .{std.mem.bytesAsSlice(tb.CreateAccountsResult, value)});
234
-
235
- const self: *TimedQueue = @intToPtr(*TimedQueue, @intCast(usize, user_data));
236
- const completed_batch: ?Batch = self.batches.pop();
237
- assert(completed_batch != null);
238
- assert(completed_batch.?.operation == operation);
239
-
240
- log.debug("completed batch operation={} start={}", .{
241
- completed_batch.?.operation,
242
- self.batch_start,
243
- });
244
- const latency = now - self.batch_start.?;
245
- switch (operation) {
246
- .create_accounts => {},
247
- .create_transfers => {
248
- if (latency > self.transfers_latency_max) {
249
- self.transfers_latency_max = latency;
250
- }
251
- },
252
- else => unreachable,
253
- }
254
-
255
- if (self.batches.head_ptr()) |next_batch| {
256
- const message = self.client.get_message();
257
- defer self.client.unref(message);
258
-
259
- std.mem.copy(
260
- u8,
261
- message.buffer[@sizeOf(vsr.Header)..],
262
- std.mem.sliceAsBytes(next_batch.data),
263
- );
264
-
265
- self.batch_start = std.time.milliTimestamp();
266
- self.client.request(
267
- @intCast(u128, @ptrToInt(self)),
268
- TimedQueue.lap,
269
- next_batch.operation,
270
- message,
271
- next_batch.data.len,
272
- );
273
- } else {
274
- log.debug("stopping timer...", .{});
275
- self.end = now;
276
- }
277
- }
278
- };
279
-
280
- fn wait_for_connect(client: *Client, io: *IO) !void {
281
- var ticks: u32 = 0;
282
- while (ticks < 20) : (ticks += 1) {
283
- client.tick();
284
- // We tick IO outside of client so that an IO instance can be shared by multiple clients:
285
- // Otherwise we will hit io_uring memory restrictions too quickly.
286
- try io.tick();
287
-
288
- std.time.sleep(10 * std.time.ns_per_ms);
289
- }
290
- }
@@ -1,244 +0,0 @@
1
- const std = @import("std");
2
- const assert = std.debug.assert;
3
- const fmt = std.fmt;
4
- const mem = std.mem;
5
- const meta = std.meta;
6
- const net = std.net;
7
- const os = std.os;
8
-
9
- const config = @import("config.zig");
10
- const vsr = @import("vsr.zig");
11
- const IO = @import("io.zig").IO;
12
-
13
- const usage = fmt.comptimePrint(
14
- \\Usage:
15
- \\
16
- \\ tigerbeetle [-h | --help]
17
- \\
18
- \\ tigerbeetle init [--directory=<path>] --cluster=<integer> --replica=<index>
19
- \\
20
- \\ tigerbeetle start [--directory=<path>] --cluster=<integer> --replica=<index> --addresses=<addresses>
21
- \\
22
- \\Commands:
23
- \\
24
- \\ init Create a new .tigerbeetle data file. Requires the --cluster and
25
- \\ --replica options. The file will be created in the path set by
26
- \\ the --directory option if provided. Otherwise, it will be created in
27
- \\ the default {[default_directory]s}.
28
- \\
29
- \\ start Run a TigerBeetle replica as part of the cluster specified by the
30
- \\ --cluster, --replica, and --addresses options. This requires an
31
- \\ existing .tigerbeetle data file, either in the default
32
- \\ {[default_directory]s} or the path set with --directory.
33
- \\
34
- \\Options:
35
- \\
36
- \\ -h, --help
37
- \\ Print this help message and exit.
38
- \\
39
- \\ --directory=<path>
40
- \\ Set the directory used to store .tigerbeetle data files. If this option is
41
- \\ omitted, the default {[default_directory]s} will be used.
42
- \\
43
- \\ --cluster=<integer>
44
- \\ Set the cluster ID to the provided 32-bit unsigned integer.
45
- \\
46
- \\ --replica=<index>
47
- \\ Set the zero-based index that will be used for this replica process.
48
- \\ The value of this option will be interpreted as an index into the --addresses array.
49
- \\
50
- \\ --addresses=<addresses>
51
- \\ Set the addresses of all replicas in the cluster. Accepts a
52
- \\ comma-separated list of IPv4 addresses with port numbers.
53
- \\ Either the IPv4 address or port number, but not both, may be
54
- \\ ommited in which case a default of {[default_address]s} or {[default_port]d}
55
- \\ will be used.
56
- \\
57
- \\Examples:
58
- \\
59
- \\ tigerbeetle init --cluster=0 --replica=0 --directory=/var/lib/tigerbeetle
60
- \\ tigerbeetle init --cluster=0 --replica=1 --directory=/var/lib/tigerbeetle
61
- \\ tigerbeetle init --cluster=0 --replica=2 --directory=/var/lib/tigerbeetle
62
- \\
63
- \\ tigerbeetle start --cluster=0 --replica=0 --addresses=127.0.0.1:3003,127.0.0.1:3001,127.0.0.1:3002
64
- \\ tigerbeetle start --cluster=0 --replica=1 --addresses=3003,3001,3002
65
- \\ tigerbeetle start --cluster=0 --replica=2 --addresses=3003,3001,3002
66
- \\
67
- \\ tigerbeetle start --cluster=1 --replica=0 --addresses=192.168.0.1,192.168.0.2,192.168.0.3
68
- \\
69
- , .{
70
- .default_directory = config.directory,
71
- .default_address = config.address,
72
- .default_port = config.port,
73
- });
74
-
75
- pub const Command = union(enum) {
76
- init: struct {
77
- cluster: u32,
78
- replica: u8,
79
- dir_fd: os.fd_t,
80
- },
81
- start: struct {
82
- cluster: u32,
83
- replica: u8,
84
- addresses: []net.Address,
85
- dir_fd: os.fd_t,
86
- },
87
- };
88
-
89
- /// Parse the command line arguments passed to the tigerbeetle binary.
90
- /// Exits the program with a non-zero exit code if an error is found.
91
- pub fn parse_args(allocator: std.mem.Allocator) !Command {
92
- var maybe_cluster: ?[]const u8 = null;
93
- var maybe_replica: ?[]const u8 = null;
94
- var maybe_addresses: ?[]const u8 = null;
95
- var maybe_directory: ?[:0]const u8 = null;
96
-
97
- var args = try std.process.argsWithAllocator(allocator);
98
- defer args.deinit();
99
-
100
- // Keep track of the args from the ArgIterator above that were allocated
101
- // then free them all at the end of the scope.
102
- var args_allocated = std.ArrayList([:0]const u8).init(allocator);
103
- defer {
104
- for (args_allocated.items) |arg| allocator.free(arg);
105
- args_allocated.deinit();
106
- }
107
-
108
- // Skip argv[0] which is the name of this executable
109
- const did_skip = args.skip();
110
- assert(did_skip);
111
-
112
- const raw_command = try (args.next(allocator) orelse
113
- fatal("no command provided, expected 'start' or 'init'", .{}));
114
- defer allocator.free(raw_command);
115
-
116
- if (mem.eql(u8, raw_command, "-h") or mem.eql(u8, raw_command, "--help")) {
117
- std.io.getStdOut().writeAll(usage) catch os.exit(1);
118
- os.exit(0);
119
- }
120
- const command = meta.stringToEnum(meta.Tag(Command), raw_command) orelse
121
- fatal("unknown command '{s}', expected 'start' or 'init'", .{raw_command});
122
-
123
- while (args.next(allocator)) |parsed_arg| {
124
- const arg = try parsed_arg;
125
- try args_allocated.append(arg);
126
-
127
- if (mem.startsWith(u8, arg, "--cluster")) {
128
- maybe_cluster = parse_flag("--cluster", arg);
129
- } else if (mem.startsWith(u8, arg, "--replica")) {
130
- maybe_replica = parse_flag("--replica", arg);
131
- } else if (mem.startsWith(u8, arg, "--addresses")) {
132
- maybe_addresses = parse_flag("--addresses", arg);
133
- } else if (mem.startsWith(u8, arg, "--directory")) {
134
- maybe_directory = parse_flag("--directory", arg);
135
- } else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
136
- std.io.getStdOut().writeAll(usage) catch os.exit(1);
137
- os.exit(0);
138
- } else if (mem.startsWith(u8, arg, "--")) {
139
- fatal("unexpected argument: '{s}'", .{arg});
140
- } else {
141
- fatal("unexpected argument: '{s}' (must start with '--')", .{arg});
142
- }
143
- }
144
-
145
- const raw_cluster = maybe_cluster orelse fatal("required argument: --cluster", .{});
146
- const raw_replica = maybe_replica orelse fatal("required argument: --replica", .{});
147
-
148
- const cluster = parse_cluster(raw_cluster);
149
- const replica = parse_replica(raw_replica);
150
-
151
- const dir_path = maybe_directory orelse config.directory;
152
- const dir_fd = IO.open_dir(dir_path) catch |err|
153
- fatal("failed to open directory '{s}': {}", .{ dir_path, err });
154
-
155
- switch (command) {
156
- .init => {
157
- if (maybe_addresses != null) {
158
- fatal("--addresses: supported only by 'start' command", .{});
159
- }
160
-
161
- return Command{
162
- .init = .{
163
- .cluster = cluster,
164
- .replica = replica,
165
- .dir_fd = dir_fd,
166
- },
167
- };
168
- },
169
- .start => {
170
- const raw_addresses = maybe_addresses orelse
171
- fatal("required argument: --addresses", .{});
172
- const addresses = parse_addresses(allocator, raw_addresses);
173
-
174
- if (replica >= addresses.len) {
175
- fatal("--replica: value greater than length of --addresses array", .{});
176
- }
177
-
178
- return Command{
179
- .start = .{
180
- .cluster = cluster,
181
- .replica = replica,
182
- .addresses = addresses,
183
- .dir_fd = dir_fd,
184
- },
185
- };
186
- },
187
- }
188
- }
189
-
190
- /// Format and print an error message followed by the usage string to stderr,
191
- /// then exit with an exit code of 1.
192
- fn fatal(comptime fmt_string: []const u8, args: anytype) noreturn {
193
- const stderr = std.io.getStdErr().writer();
194
- stderr.print("error: " ++ fmt_string ++ "\n", args) catch {};
195
- os.exit(1);
196
- }
197
-
198
- /// Parse e.g. `--cluster=1a2b3c` into `1a2b3c` with error handling.
199
- fn parse_flag(comptime flag: []const u8, arg: [:0]const u8) [:0]const u8 {
200
- const value = arg[flag.len..];
201
- if (value.len < 2) {
202
- fatal("{s} argument requires a value", .{flag});
203
- }
204
- if (value[0] != '=') {
205
- fatal("expected '=' after {s} but found '{c}'", .{ flag, value[0] });
206
- }
207
- return value[1..];
208
- }
209
-
210
- fn parse_cluster(raw_cluster: []const u8) u32 {
211
- const cluster = fmt.parseUnsigned(u32, raw_cluster, 10) catch |err| switch (err) {
212
- error.Overflow => fatal("--cluster: value exceeds a 32-bit unsigned integer", .{}),
213
- error.InvalidCharacter => fatal("--cluster: value contains an invalid character", .{}),
214
- };
215
- return cluster;
216
- }
217
-
218
- /// Parse and allocate the addresses returning a slice into that array.
219
- fn parse_addresses(allocator: std.mem.Allocator, raw_addresses: []const u8) []net.Address {
220
- return vsr.parse_addresses(allocator, raw_addresses) catch |err| switch (err) {
221
- error.AddressHasTrailingComma => fatal("--addresses: invalid trailing comma", .{}),
222
- error.AddressLimitExceeded => {
223
- fatal("--addresses: too many addresses, at most {d} are allowed", .{
224
- config.replicas_max,
225
- });
226
- },
227
- error.AddressHasMoreThanOneColon => {
228
- fatal("--addresses: invalid address with more than one colon", .{});
229
- },
230
- error.PortOverflow => fatal("--addresses: port exceeds 65535", .{}),
231
- error.PortInvalid => fatal("--addresses: invalid port", .{}),
232
- error.AddressInvalid => fatal("--addresses: invalid IPv4 address", .{}),
233
- error.OutOfMemory => fatal("--addresses: out of memory", .{}),
234
- };
235
- }
236
-
237
- fn parse_replica(raw_replica: []const u8) u8 {
238
- comptime assert(config.replicas_max <= std.math.maxInt(u8));
239
- const replica = fmt.parseUnsigned(u8, raw_replica, 10) catch |err| switch (err) {
240
- error.Overflow => fatal("--replica: value exceeds an 8-bit unsigned integer", .{}),
241
- error.InvalidCharacter => fatal("--replica: value contains an invalid character", .{}),
242
- };
243
- return replica;
244
- }