tigerbeetle-node 0.11.1 → 0.11.2

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.
@@ -0,0 +1 @@
1
+ 5e64232ef290c0ed5f8b48762a2f9d03683e4a2ac5d74fc06ea594c035ec4b8b dist/client.node
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tigerbeetle-node",
3
- "version": "0.11.1",
3
+ "version": "0.11.2",
4
4
  "description": "TigerBeetle Node.js client",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -13,6 +13,7 @@
13
13
  "LICENSE",
14
14
  "README.md",
15
15
  "dist",
16
+ "dist/.client.node.sha256",
16
17
  "!dist/client.node",
17
18
  "package.json",
18
19
  "package-lock.json",
@@ -1,16 +1,18 @@
1
1
  const std = @import("std");
2
2
  const assert = std.debug.assert;
3
3
  const fmt = std.fmt;
4
+ const math = std.math;
4
5
  const mem = std.mem;
5
6
  const meta = std.meta;
6
7
  const net = std.net;
7
8
  const os = std.os;
8
9
 
9
10
  const config = @import("config.zig");
11
+ const tigerbeetle = @import("tigerbeetle.zig");
10
12
  const vsr = @import("vsr.zig");
11
13
  const IO = @import("io.zig").IO;
12
14
 
13
- // TODO Document --memory
15
+ // TODO Document --cache-accounts, --cache-transfers, --cache-transfers-posted
14
16
  const usage = fmt.comptimePrint(
15
17
  \\Usage:
16
18
  \\
@@ -84,7 +86,9 @@ pub const Command = union(enum) {
84
86
  start: struct {
85
87
  args_allocated: std.ArrayList([:0]const u8),
86
88
  addresses: []net.Address,
87
- memory: u64,
89
+ cache_accounts: u32,
90
+ cache_transfers: u32,
91
+ cache_transfers_posted: u32,
88
92
  path: [:0]const u8,
89
93
  },
90
94
  version: struct {
@@ -110,7 +114,9 @@ pub fn parse_args(allocator: std.mem.Allocator) !Command {
110
114
  var cluster: ?[]const u8 = null;
111
115
  var replica: ?[]const u8 = null;
112
116
  var addresses: ?[]const u8 = null;
113
- var memory: ?[]const u8 = null;
117
+ var cache_accounts: ?[]const u8 = null;
118
+ var cache_transfers: ?[]const u8 = null;
119
+ var cache_transfers_posted: ?[]const u8 = null;
114
120
  var verbose: ?bool = null;
115
121
 
116
122
  var args = try std.process.argsWithAllocator(allocator);
@@ -140,14 +146,25 @@ pub fn parse_args(allocator: std.mem.Allocator) !Command {
140
146
  try args_allocated.append(arg);
141
147
 
142
148
  if (mem.startsWith(u8, arg, "--cluster")) {
149
+ if (command != .format) fatal("--cluster: supported only by 'format' command", .{});
143
150
  cluster = parse_flag("--cluster", arg);
144
151
  } else if (mem.startsWith(u8, arg, "--replica")) {
152
+ if (command != .format) fatal("--replica: supported only by 'format' command", .{});
145
153
  replica = parse_flag("--replica", arg);
146
154
  } else if (mem.startsWith(u8, arg, "--addresses")) {
155
+ if (command != .start) fatal("--addresses: supported only by 'start' command", .{});
147
156
  addresses = parse_flag("--addresses", arg);
148
- } else if (mem.startsWith(u8, arg, "--memory")) {
149
- memory = parse_flag("--memory", arg);
157
+ } else if (mem.startsWith(u8, arg, "--cache-accounts")) {
158
+ if (command != .start) fatal("--cache-accounts: supported only by 'start' command", .{});
159
+ cache_accounts = parse_flag("--cache-accounts", arg);
160
+ } else if (mem.startsWith(u8, arg, "--cache-transfers")) {
161
+ if (command != .start) fatal("--cache-transfers: supported only by 'start' command", .{});
162
+ cache_transfers = parse_flag("--cache-transfers", arg);
163
+ } else if (mem.startsWith(u8, arg, "--cache-transfers-posted")) {
164
+ if (command != .start) fatal("--cache-transfers-posted: supported only by 'start' command", .{});
165
+ cache_transfers_posted = parse_flag("--cache-transfers-posted", arg);
150
166
  } else if (mem.eql(u8, arg, "--verbose")) {
167
+ if (command != .version) fatal("--verbose: supported only by 'version' command", .{});
151
168
  verbose = true;
152
169
  } else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
153
170
  std.io.getStdOut().writeAll(usage) catch os.exit(1);
@@ -155,6 +172,7 @@ pub fn parse_args(allocator: std.mem.Allocator) !Command {
155
172
  } else if (mem.startsWith(u8, arg, "-")) {
156
173
  fatal("unexpected argument: '{s}'", .{arg});
157
174
  } else if (path == null) {
175
+ if (!(command == .format or command == .start)) fatal("unexpected path", .{});
158
176
  path = arg;
159
177
  } else {
160
178
  fatal("unexpected argument: '{s}' (must start with '--')", .{arg});
@@ -163,21 +181,11 @@ pub fn parse_args(allocator: std.mem.Allocator) !Command {
163
181
 
164
182
  switch (command) {
165
183
  .version => {
166
- if (addresses != null) fatal("--addresses: supported only by 'start' command", .{});
167
- if (memory != null) fatal("--memory: supported only by 'start' command", .{});
168
- if (cluster != null) fatal("--cluster: supported only by 'format' command", .{});
169
- if (replica != null) fatal("--replica: supported only by 'format' command", .{});
170
- if (path != null) fatal("unexpected path", .{});
171
-
172
184
  return Command{
173
185
  .version = .{ .verbose = verbose orelse false },
174
186
  };
175
187
  },
176
188
  .format => {
177
- if (addresses != null) fatal("--addresses: supported only by 'start' command", .{});
178
- if (memory != null) fatal("--memory: supported only by 'start' command", .{});
179
- if (verbose != null) fatal("--verbose: supported only by 'version' command", .{});
180
-
181
189
  return Command{
182
190
  .format = .{
183
191
  .args_allocated = args_allocated,
@@ -188,10 +196,6 @@ pub fn parse_args(allocator: std.mem.Allocator) !Command {
188
196
  };
189
197
  },
190
198
  .start => {
191
- if (cluster != null) fatal("--cluster: supported only by 'format' command", .{});
192
- if (replica != null) fatal("--replica: supported only by 'format' command", .{});
193
- if (verbose != null) fatal("--verbose: supported only by 'version' command", .{});
194
-
195
199
  return Command{
196
200
  .start = .{
197
201
  .args_allocated = args_allocated,
@@ -199,7 +203,21 @@ pub fn parse_args(allocator: std.mem.Allocator) !Command {
199
203
  allocator,
200
204
  addresses orelse fatal("required: --addresses", .{}),
201
205
  ),
202
- .memory = if (memory) |m| parse_size(m) else config.memory_size_max_default,
206
+ .cache_accounts = parse_size_to_count(
207
+ tigerbeetle.Account,
208
+ cache_accounts,
209
+ config.cache_accounts_max,
210
+ ),
211
+ .cache_transfers = parse_size_to_count(
212
+ tigerbeetle.Transfer,
213
+ cache_transfers,
214
+ config.cache_transfers_max,
215
+ ),
216
+ .cache_transfers_posted = parse_size_to_count(
217
+ u256, // TODO(#264): Use actual type here, once exposed.
218
+ cache_transfers_posted,
219
+ config.cache_transfers_posted_max,
220
+ ),
203
221
  .path = path orelse fatal("required: <path>", .{}),
204
222
  },
205
223
  };
@@ -323,6 +341,30 @@ test "parse_size" {
323
341
  try expectEqual(@as(u64, 1000 * kib), parse_size(" 1000 kb "));
324
342
  }
325
343
 
344
+ /// Given a limit like `10GiB`, return the maximum power-of-two count of `T`s
345
+ /// that can fit in the limit.
346
+ fn parse_size_to_count(comptime T: type, string_opt: ?[]const u8, comptime default: u32) u32 {
347
+ var result: u32 = default;
348
+ if (string_opt) |string| {
349
+ const byte_size = parse_size(string);
350
+ const count_u64 = math.floorPowerOfTwo(u64, @divFloor(byte_size, @sizeOf(T)));
351
+ const count = math.cast(u32, count_u64) catch |err| switch (err) {
352
+ error.Overflow => fatal("size value is too large: '{s}'", .{string}),
353
+ };
354
+ if (count < 2048) fatal("size value is too small: '{s}'", .{string});
355
+ assert(count * @sizeOf(T) <= byte_size);
356
+
357
+ result = count;
358
+ }
359
+
360
+ // SetAssociativeCache requires a power-of-two cardinality and a minimal
361
+ // size.
362
+ assert(result >= 2048);
363
+ assert(math.isPowerOfTwo(result));
364
+
365
+ return result;
366
+ }
367
+
326
368
  fn parse_replica(raw_replica: []const u8) u8 {
327
369
  comptime assert(config.replicas_max <= std.math.maxInt(u8));
328
370
  const replica = fmt.parseUnsigned(u8, raw_replica, 10) catch |err| switch (err) {
@@ -1,6 +1,5 @@
1
1
  const std = @import("std");
2
2
  const assert = std.debug.assert;
3
- const tigerbeetle = @import("tigerbeetle.zig");
4
3
  const vsr = @import("vsr.zig");
5
4
 
6
5
  const Environment = enum {
@@ -64,7 +63,7 @@ pub const cache_transfers_max = switch (deployment_environment) {
64
63
 
65
64
  /// The maximum number of two-phase transfers to store in memory:
66
65
  /// This impacts the amount of memory allocated at initialization by the server.
67
- pub const cache_transfers_pending_max = cache_transfers_max;
66
+ pub const cache_transfers_posted_max = cache_transfers_max;
68
67
 
69
68
  /// The maximum number of batch entries in the journal file:
70
69
  /// A batch entry may contain many transfers, so this is not a limit on the number of transfers.
@@ -383,7 +382,7 @@ comptime {
383
382
  // SetAssociativeCache requires a power-of-two cardinality.
384
383
  assert(std.math.isPowerOfTwo(cache_accounts_max));
385
384
  assert(std.math.isPowerOfTwo(cache_transfers_max));
386
- assert(std.math.isPowerOfTwo(cache_transfers_pending_max));
385
+ assert(std.math.isPowerOfTwo(cache_transfers_posted_max));
387
386
  }
388
387
 
389
388
  pub const is_32_bit = @sizeOf(usize) == 4; // TODO Return a compile error if we are not 32-bit.
@@ -172,9 +172,9 @@ pub fn GridType(comptime Storage: type) type {
172
172
  // Resolve reads that were seen in the cache during start_read()
173
173
  // but deferred to be asynchronously resolved on the next tick.
174
174
  //
175
- // Drain directly from the queue so that new cache reads (added upon completion of old
176
- // cache reads) that can be serviced immediately aren't deferred until the next tick
177
- // (which may be milliseconds later due to IO.run_for_ns). This is necessary to ensure
175
+ // Drain directly from the queue so that new cache reads (added upon completion of old
176
+ // cache reads) that can be serviced immediately aren't deferred until the next tick
177
+ // (which may be milliseconds later due to IO.run_for_ns). This is necessary to ensure
178
178
  // that groove prefetch completes promptly.
179
179
  //
180
180
  // Even still, we cap the reads processed to prevent going over
@@ -46,7 +46,18 @@ pub fn main() !void {
46
46
 
47
47
  switch (parse_args) {
48
48
  .format => |*args| try Command.format(allocator, args.cluster, args.replica, args.path),
49
- .start => |*args| try Command.start(&arena, args.addresses, args.memory, args.path),
49
+ .start => |*args| try Command.start(
50
+ &arena,
51
+ args.addresses,
52
+ .{
53
+ // TODO Tune lsm_forest_node_count better.
54
+ .lsm_forest_node_count = 4096,
55
+ .cache_entries_accounts = args.cache_accounts,
56
+ .cache_entries_transfers = args.cache_transfers,
57
+ .cache_entries_posted = args.cache_transfers_posted,
58
+ },
59
+ args.path,
60
+ ),
50
61
  .version => |*args| try Command.version(allocator, args.verbose),
51
62
  }
52
63
  }
@@ -114,11 +125,9 @@ const Command = struct {
114
125
  pub fn start(
115
126
  arena: *std.heap.ArenaAllocator,
116
127
  addresses: []std.net.Address,
117
- memory: u64,
128
+ options: StateMachine.Options,
118
129
  path: [:0]const u8,
119
130
  ) !void {
120
- _ = memory; // TODO
121
-
122
131
  const allocator = arena.allocator();
123
132
 
124
133
  var command: Command = undefined;
@@ -131,13 +140,7 @@ const Command = struct {
131
140
  .storage = &command.storage,
132
141
  .message_pool = &command.message_pool,
133
142
  .time = .{},
134
- .state_machine_options = .{
135
- // TODO Tune lsm_forest_node_count better.
136
- .lsm_forest_node_count = 4096,
137
- .cache_entries_accounts = config.cache_accounts_max,
138
- .cache_entries_transfers = config.cache_transfers_max,
139
- .cache_entries_posted = config.cache_transfers_pending_max,
140
- },
143
+ .state_machine_options = options,
141
144
  .message_bus_options = .{
142
145
  .configuration = addresses,
143
146
  .io = &command.io,
@@ -785,7 +785,7 @@ pub fn StateMachineType(comptime Storage: type, comptime constants_: struct {
785
785
  .ledger = p.ledger,
786
786
  .code = p.code,
787
787
  .pending_id = t.pending_id,
788
- .timeout = t.timeout,
788
+ .timeout = 0,
789
789
  .timestamp = t.timestamp,
790
790
  .flags = t.flags,
791
791
  .amount = amount,
@@ -16,6 +16,7 @@ test {
16
16
 
17
17
  _ = @import("io.zig");
18
18
 
19
+ _ = @import("cli.zig");
19
20
  _ = @import("ewah.zig");
20
21
  _ = @import("util.zig");
21
22