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.
- package/dist/.client.node.sha256 +1 -0
- package/package.json +2 -1
- package/src/tigerbeetle/src/cli.zig +62 -20
- package/src/tigerbeetle/src/config.zig +2 -3
- package/src/tigerbeetle/src/lsm/grid.zig +3 -3
- package/src/tigerbeetle/src/main.zig +14 -11
- package/src/tigerbeetle/src/state_machine.zig +1 -1
- package/src/tigerbeetle/src/unit_tests.zig +1 -0
|
@@ -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.
|
|
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 --
|
|
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
|
-
|
|
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
|
|
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, "--
|
|
149
|
-
|
|
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
|
-
.
|
|
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
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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 =
|
|
788
|
+
.timeout = 0,
|
|
789
789
|
.timestamp = t.timestamp,
|
|
790
790
|
.flags = t.flags,
|
|
791
791
|
.amount = amount,
|