tigerbeetle-node 0.9.0 → 0.10.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.
- package/README.md +3 -2
- package/dist/index.d.ts +66 -61
- package/dist/index.js +66 -61
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +5 -0
- package/src/node.zig +17 -18
- package/src/tigerbeetle/scripts/benchmark.bat +4 -3
- package/src/tigerbeetle/scripts/benchmark.sh +25 -10
- package/src/tigerbeetle/scripts/install.sh +2 -1
- package/src/tigerbeetle/scripts/install_zig.sh +14 -18
- package/src/tigerbeetle/scripts/upgrade_ubuntu_kernel.sh +12 -3
- package/src/tigerbeetle/scripts/vopr.sh +5 -5
- package/src/tigerbeetle/src/benchmark.zig +17 -9
- package/src/tigerbeetle/src/benchmark_array_search.zig +317 -0
- package/src/tigerbeetle/src/benchmarks/perf.zig +299 -0
- package/src/tigerbeetle/src/c/tb_client/context.zig +103 -0
- package/src/tigerbeetle/src/c/tb_client/packet.zig +80 -0
- package/src/tigerbeetle/src/c/tb_client/signal.zig +288 -0
- package/src/tigerbeetle/src/c/tb_client/thread.zig +329 -0
- package/src/tigerbeetle/src/c/tb_client.h +201 -0
- package/src/tigerbeetle/src/c/tb_client.zig +101 -0
- package/src/tigerbeetle/src/c/test.zig +1 -0
- package/src/tigerbeetle/src/cli.zig +142 -83
- package/src/tigerbeetle/src/config.zig +119 -10
- package/src/tigerbeetle/src/demo.zig +12 -8
- package/src/tigerbeetle/src/demo_05_post_pending_transfers.zig +2 -2
- package/src/tigerbeetle/src/ewah.zig +318 -0
- package/src/tigerbeetle/src/ewah_benchmark.zig +121 -0
- package/src/tigerbeetle/src/eytzinger_benchmark.zig +317 -0
- package/src/tigerbeetle/src/fifo.zig +17 -1
- package/src/tigerbeetle/src/io/darwin.zig +12 -10
- package/src/tigerbeetle/src/io/linux.zig +25 -9
- package/src/tigerbeetle/src/io/windows.zig +13 -9
- package/src/tigerbeetle/src/iops.zig +101 -0
- package/src/tigerbeetle/src/lsm/binary_search.zig +214 -0
- package/src/tigerbeetle/src/lsm/bloom_filter.zig +82 -0
- package/src/tigerbeetle/src/lsm/compaction.zig +603 -0
- package/src/tigerbeetle/src/lsm/composite_key.zig +75 -0
- package/src/tigerbeetle/src/lsm/direction.zig +11 -0
- package/src/tigerbeetle/src/lsm/eytzinger.zig +587 -0
- package/src/tigerbeetle/src/lsm/forest.zig +630 -0
- package/src/tigerbeetle/src/lsm/grid.zig +473 -0
- package/src/tigerbeetle/src/lsm/groove.zig +939 -0
- package/src/tigerbeetle/src/lsm/k_way_merge.zig +452 -0
- package/src/tigerbeetle/src/lsm/level_iterator.zig +296 -0
- package/src/tigerbeetle/src/lsm/manifest.zig +680 -0
- package/src/tigerbeetle/src/lsm/manifest_level.zig +1169 -0
- package/src/tigerbeetle/src/lsm/manifest_log.zig +904 -0
- package/src/tigerbeetle/src/lsm/node_pool.zig +231 -0
- package/src/tigerbeetle/src/lsm/posted_groove.zig +399 -0
- package/src/tigerbeetle/src/lsm/segmented_array.zig +998 -0
- package/src/tigerbeetle/src/lsm/set_associative_cache.zig +844 -0
- package/src/tigerbeetle/src/lsm/table.zig +932 -0
- package/src/tigerbeetle/src/lsm/table_immutable.zig +196 -0
- package/src/tigerbeetle/src/lsm/table_iterator.zig +295 -0
- package/src/tigerbeetle/src/lsm/table_mutable.zig +123 -0
- package/src/tigerbeetle/src/lsm/test.zig +429 -0
- package/src/tigerbeetle/src/lsm/tree.zig +1085 -0
- package/src/tigerbeetle/src/main.zig +119 -109
- package/src/tigerbeetle/src/message_bus.zig +49 -48
- package/src/tigerbeetle/src/message_pool.zig +15 -2
- package/src/tigerbeetle/src/ring_buffer.zig +126 -30
- package/src/tigerbeetle/src/simulator.zig +76 -44
- package/src/tigerbeetle/src/state_machine.zig +1022 -585
- package/src/tigerbeetle/src/storage.zig +46 -16
- package/src/tigerbeetle/src/test/cluster.zig +109 -63
- package/src/tigerbeetle/src/test/message_bus.zig +15 -24
- package/src/tigerbeetle/src/test/network.zig +26 -17
- package/src/tigerbeetle/src/test/state_checker.zig +7 -5
- package/src/tigerbeetle/src/test/state_machine.zig +159 -69
- package/src/tigerbeetle/src/test/storage.zig +57 -28
- package/src/tigerbeetle/src/tigerbeetle.zig +5 -0
- package/src/tigerbeetle/src/unit_tests.zig +8 -0
- package/src/tigerbeetle/src/util.zig +51 -0
- package/src/tigerbeetle/src/vsr/client.zig +21 -7
- package/src/tigerbeetle/src/vsr/journal.zig +154 -167
- package/src/tigerbeetle/src/vsr/replica.zig +744 -226
- package/src/tigerbeetle/src/vsr/superblock.zig +1743 -0
- package/src/tigerbeetle/src/vsr/superblock_client_table.zig +258 -0
- package/src/tigerbeetle/src/vsr/superblock_free_set.zig +644 -0
- package/src/tigerbeetle/src/vsr/superblock_manifest.zig +546 -0
- package/src/tigerbeetle/src/vsr.zig +43 -115
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
#ifndef TB_CLIENT_C
|
|
2
|
+
#define TB_CLIENT_C
|
|
3
|
+
|
|
4
|
+
#include <stddef.h>
|
|
5
|
+
#include <stdint.h>
|
|
6
|
+
#include <stdbool.h>
|
|
7
|
+
|
|
8
|
+
typedef __uint128_t tb_uint128_t;
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
typedef enum TB_ACCOUNT_FLAGS {
|
|
12
|
+
TB_ACCOUNT_LINKED = 1 << 0,
|
|
13
|
+
TB_ACCOUNT_DEBITS_MUST_NOT_EXCEED_CREDITS = 1 << 1,
|
|
14
|
+
TB_ACCOUNT_CREDITS_MUST_NOT_EXCEED_DEBITS = 1 << 2,
|
|
15
|
+
} TB_ACCOUNT_FLAGS;
|
|
16
|
+
|
|
17
|
+
typedef struct tb_account_t {
|
|
18
|
+
tb_uint128_t id;
|
|
19
|
+
tb_uint128_t user_data;
|
|
20
|
+
uint8_t reserved[48];
|
|
21
|
+
uint16_t unit;
|
|
22
|
+
uint16_t code;
|
|
23
|
+
uint32_t flags;
|
|
24
|
+
uint64_t debits_reserved;
|
|
25
|
+
uint64_t debits_accepted;
|
|
26
|
+
uint64_t credits_reserved;
|
|
27
|
+
uint64_t credits_accepted;
|
|
28
|
+
uint64_t timestamp;
|
|
29
|
+
} tb_account_t;
|
|
30
|
+
|
|
31
|
+
typedef enum TB_TRANSFER_FLAGS {
|
|
32
|
+
TB_TRANSFER_LINKED = 1 << 0,
|
|
33
|
+
TB_TRANSFER_TWO_PHASE_COMMIT = 1 << 1,
|
|
34
|
+
TB_TRANSFER_CONDITION = 1 << 2,
|
|
35
|
+
} TB_TRANSFER_FLAGS;
|
|
36
|
+
|
|
37
|
+
typedef struct tb_transfer_t {
|
|
38
|
+
tb_uint128_t id;
|
|
39
|
+
tb_uint128_t debit_account_id;
|
|
40
|
+
tb_uint128_t credit_account_id;
|
|
41
|
+
tb_uint128_t user_data;
|
|
42
|
+
uint8_t reserved[32];
|
|
43
|
+
uint64_t timeout;
|
|
44
|
+
uint32_t code;
|
|
45
|
+
uint32_t flags;
|
|
46
|
+
uint64_t amount;
|
|
47
|
+
uint64_t timestamp;
|
|
48
|
+
} tb_transfer_t;
|
|
49
|
+
|
|
50
|
+
typedef enum TB_COMMIT_FLAGS {
|
|
51
|
+
TB_COMMIT_LINKED = 1 << 0,
|
|
52
|
+
TB_COMMIT_REJECT = 1 << 1,
|
|
53
|
+
TB_COMMIT_PREIMAGE = 1 << 2,
|
|
54
|
+
} TB_COMMIT_FLAGS;
|
|
55
|
+
|
|
56
|
+
typedef struct tb_commit_t {
|
|
57
|
+
tb_uint128_t id;
|
|
58
|
+
uint8_t reserved[32];
|
|
59
|
+
uint32_t code;
|
|
60
|
+
uint32_t flags;
|
|
61
|
+
uint64_t timestamp;
|
|
62
|
+
} tb_commit_t;
|
|
63
|
+
|
|
64
|
+
typedef enum TB_CREATE_ACCOUNT_RESULT {
|
|
65
|
+
TB_CREATE_ACCOUNT_OK,
|
|
66
|
+
TB_CREATE_ACCOUNT_LINKED_EVENT_FAILED,
|
|
67
|
+
TB_CREATE_ACCOUNT_EXISTS,
|
|
68
|
+
TB_CREATE_ACCOUNT_EXISTS_WITH_DIFFERENT_USER_DATA,
|
|
69
|
+
TB_CREATE_ACCOUNT_EXISTS_WITH_DIFFERENT_RESERVED_FIELD,
|
|
70
|
+
TB_CREATE_ACCOUNT_EXISTS_WITH_DIFFERENT_UNIT,
|
|
71
|
+
TB_CREATE_ACCOUNT_EXISTS_WITH_DIFFERENT_CODE,
|
|
72
|
+
TB_CREATE_ACCOUNT_EXISTS_WITH_DIFFERENT_FLAGS,
|
|
73
|
+
TB_CREATE_ACCOUNT_EXCEEDS_CREDITS,
|
|
74
|
+
TB_CREATE_ACCOUNT_EXCEEDS_DEBITS,
|
|
75
|
+
TB_CREATE_ACCOUNT_RESERVE_FAILED,
|
|
76
|
+
TB_CREATE_ACCOUNT_RESERVE_FLAG_PADDING
|
|
77
|
+
} TB_CREATE_ACCOUNT_RESULT;
|
|
78
|
+
|
|
79
|
+
typedef enum TB_CREATE_TRANSFER_RESULT {
|
|
80
|
+
TB_CREATE_TRANSFER_OK,
|
|
81
|
+
TB_CREATE_TRANSFER_LINKED_EVENT_FAILED,
|
|
82
|
+
TB_CREATE_TRANSFER_EXISTS,
|
|
83
|
+
TB_CREATE_TRANSFER_EXISTS_WITH_DIFFERENT_DEBIT_ACCOUNT_ID,
|
|
84
|
+
TB_CREATE_TRANSFER_EXISTS_WITH_DIFFERENT_CREDIT_ACCOUNT_ID,
|
|
85
|
+
TB_CREATE_TRANSFER_EXISTS_WITH_DIFFERENT_USER_DATA,
|
|
86
|
+
TB_CREATE_TRANSFER_EXISTS_WITH_DIFFERENT_RESERVED_FIELD,
|
|
87
|
+
TB_CREATE_TRANSFER_EXISTS_WITH_DIFFERENT_CODE,
|
|
88
|
+
TB_CREATE_TRANSFER_EXISTS_WITH_DIFFERENT_AMOUNT,
|
|
89
|
+
TB_CREATE_TRANSFER_EXISTS_WITH_DIFFERENT_TIMEOUT,
|
|
90
|
+
TB_CREATE_TRANSFER_EXISTS_WITH_DIFFERENT_FLAGS,
|
|
91
|
+
TB_CREATE_TRANSFER_EXISTS_AND_ALREADY_COMMITTED_AND_ACCEPTED,
|
|
92
|
+
TB_CREATE_TRANSFER_EXISTS_AND_ALREADY_COMMITTED_AND_REJECTED,
|
|
93
|
+
TB_CREATE_TRANSFER_RESERVED_FIELD,
|
|
94
|
+
TB_CREATE_TRANSFER_RESERVED_FLAG_PADDING,
|
|
95
|
+
TB_CREATE_TRANSFER_DEBIT_ACCOUNT_NOT_FOUND,
|
|
96
|
+
TB_CREATE_TRANSFER_CREDIT_ACCOUNT_NOT_FOUND,
|
|
97
|
+
TB_CREATE_TRANSFER_ACCOUNTS_ARE_THE_SAME,
|
|
98
|
+
TB_CREATE_TRANSFER_ACCOUNTS_HAVE_DIFFERENT_UNITS,
|
|
99
|
+
TB_CREATE_TRANSFER_AMOUNT_IS_ZERO,
|
|
100
|
+
TB_CREATE_TRANSFER_EXCEEDS_CREDITS,
|
|
101
|
+
TB_CREATE_TRANSFER_EXCEEDS_DEBITS,
|
|
102
|
+
TB_CREATE_TRANSFER_TWO_PHASE_COMMIT_MUST_TIMEOUT,
|
|
103
|
+
TB_CREATE_TRANSFER_TIMEOUT_RESERVED_FOR_TWO_PHASE_COMMIT
|
|
104
|
+
} TB_CREATE_TRANSFER_RESULT;
|
|
105
|
+
|
|
106
|
+
typedef enum TB_COMMIT_TRANSFER_RESULT {
|
|
107
|
+
TB_COMMIT_TRANSFER_OK,
|
|
108
|
+
TB_COMMIT_TRANSFER_LINKED_EVENT_FAILED,
|
|
109
|
+
TB_COMMIT_TRANSFER_RESERVE_FAILED,
|
|
110
|
+
TB_COMMIT_TRANSFER_RESERVE_FLAG_PADDING,
|
|
111
|
+
TB_COMMIT_TRANSFER_NOT_FOUND,
|
|
112
|
+
TB_COMMIT_TRANSFER_NOT_TWO_PHASE_COMMIT,
|
|
113
|
+
TB_COMMIT_TRANSFER_EXPIRED,
|
|
114
|
+
TB_COMMIT_TRANSFER_ALREADY_COMMITTED,
|
|
115
|
+
TB_COMMIT_TRANSFER_ALREADY_COMMITTED_BUT_ACCEPTED,
|
|
116
|
+
TB_COMMIT_TRANSFER_ALREADY_COMMITTED_BUT_REJECTED,
|
|
117
|
+
TB_COMMIT_TRANSFER_DEBIT_ACCOUNT_NOT_FOUND,
|
|
118
|
+
TB_COMMIT_TRANSFER_CREDIT_ACCOUNT_NOT_FOUND,
|
|
119
|
+
TB_COMMIT_TRANSFER_EXCEEDS_CREDITS,
|
|
120
|
+
TB_COMMIT_TRANSFER_EXCEEDS_DEBITS,
|
|
121
|
+
TB_COMMIT_TRANSFER_CONDITION_REQUIRES_PREIMAGE,
|
|
122
|
+
TB_COMMIT_TRANSFER_PREIMAGE_REQUIRES_CONDITION,
|
|
123
|
+
TB_COMMIT_TRANSFER_PREIMAGE_INVALID
|
|
124
|
+
} TB_COMMIT_TRANSFER_RESULT;
|
|
125
|
+
|
|
126
|
+
typedef struct tb_create_accounts_result_t {
|
|
127
|
+
uint32_t index;
|
|
128
|
+
TB_CREATE_ACCOUNT_RESULT result;
|
|
129
|
+
} tb_create_accounts_result_t;
|
|
130
|
+
|
|
131
|
+
typedef struct tb_create_transfers_result_t {
|
|
132
|
+
uint32_t index;
|
|
133
|
+
TB_CREATE_TRANSFER_RESULT result;
|
|
134
|
+
} tb_create_transfers_result_t;
|
|
135
|
+
|
|
136
|
+
typedef struct tb_commit_transfers_result_t {
|
|
137
|
+
uint32_t index;
|
|
138
|
+
TB_COMMIT_TRANSFER_RESULT result;
|
|
139
|
+
} tb_commit_transfers_result_t;
|
|
140
|
+
|
|
141
|
+
typedef enum TB_OPERATION {
|
|
142
|
+
TB_OP_CREATE_ACCOUNTS = 3,
|
|
143
|
+
TB_OP_CREATE_TRANSFERS = 4,
|
|
144
|
+
TB_OP_COMMIT_TRANSFERS = 5,
|
|
145
|
+
TB_OP_LOOKUP_ACCOUNTS = 6,
|
|
146
|
+
TB_OP_LOOKUP_TRANSFERS = 7
|
|
147
|
+
} TB_OPERATION;
|
|
148
|
+
|
|
149
|
+
typedef enum TB_PACKET_STATUS {
|
|
150
|
+
TB_PACKET_OK,
|
|
151
|
+
TB_PACKET_TOO_MUCH_DATA,
|
|
152
|
+
TB_PACKET_INVALID_OPERATION,
|
|
153
|
+
TB_PACKET_INVALID_DATA_SIZE
|
|
154
|
+
} TB_PACKET_STATUS;
|
|
155
|
+
|
|
156
|
+
typedef struct tb_packet_t {
|
|
157
|
+
struct tb_packet_t* next;
|
|
158
|
+
void* user_data;
|
|
159
|
+
uint8_t operation;
|
|
160
|
+
uint8_t status;
|
|
161
|
+
uint32_t data_size;
|
|
162
|
+
void* data;
|
|
163
|
+
} tb_packet_t;
|
|
164
|
+
|
|
165
|
+
typedef struct tb_packet_list_t {
|
|
166
|
+
struct tb_packet_t* head;
|
|
167
|
+
struct tb_packet_t* tail;
|
|
168
|
+
} tb_packet_list_t;
|
|
169
|
+
|
|
170
|
+
typedef void* tb_client_t;
|
|
171
|
+
|
|
172
|
+
typedef enum TB_STATUS {
|
|
173
|
+
TB_STATUS_SUCCESS = 0,
|
|
174
|
+
TB_STATUS_UNEXPECTED = 1,
|
|
175
|
+
TB_STATUS_OUT_OF_MEMORY = 2,
|
|
176
|
+
TB_STATUS_INVALID_ADDRESS = 3,
|
|
177
|
+
TB_STATUS_SYSTEM_RESOURCES = 4,
|
|
178
|
+
TB_STATUS_NETWORK_SUBSYSTEM = 5,
|
|
179
|
+
} TB_STATUS;
|
|
180
|
+
|
|
181
|
+
TB_STATUS tb_client_init(
|
|
182
|
+
tb_client_t* out_client,
|
|
183
|
+
tb_packet_list_t* out_packets,
|
|
184
|
+
uint32_t cluster_id,
|
|
185
|
+
const char* address_ptr,
|
|
186
|
+
uint32_t address_len,
|
|
187
|
+
uint32_t num_packets,
|
|
188
|
+
uintptr_t on_completion_ctx,
|
|
189
|
+
void (*on_completion_fn)(uintptr_t, tb_client_t, tb_packet_t*, const uint8_t*, uint32_t)
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
void tb_client_submit(
|
|
193
|
+
tb_client_t client,
|
|
194
|
+
tb_packet_list_t* packets
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
void tb_client_deinit(
|
|
198
|
+
tb_client_t client
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
#endif // TB_CLIENT_C
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
const std = @import("std");
|
|
2
|
+
const builtin = @import("builtin");
|
|
3
|
+
|
|
4
|
+
pub const tb_packet_t = @import("tb_client/packet.zig").Packet;
|
|
5
|
+
pub const tb_packet_list_t = tb_packet_t.List;
|
|
6
|
+
pub const tb_packet_status_t = tb_packet_t.Status;
|
|
7
|
+
|
|
8
|
+
pub const tb_client_t = *anyopaque;
|
|
9
|
+
pub const tb_status_t = enum(c_int) {
|
|
10
|
+
success = 0,
|
|
11
|
+
unexpected,
|
|
12
|
+
out_of_memory,
|
|
13
|
+
invalid_address,
|
|
14
|
+
system_resources,
|
|
15
|
+
network_subsystem,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
pub const tb_completion_t = fn (
|
|
19
|
+
context: usize,
|
|
20
|
+
client: tb_client_t,
|
|
21
|
+
packet: *tb_packet_t,
|
|
22
|
+
result_ptr: ?[*]const u8,
|
|
23
|
+
result_len: u32,
|
|
24
|
+
) callconv(.C) void;
|
|
25
|
+
|
|
26
|
+
const ContextType = @import("tb_client/context.zig").ContextType;
|
|
27
|
+
const ContextImplementation = @import("tb_client/context.zig").ContextImplementation;
|
|
28
|
+
|
|
29
|
+
pub fn context_to_client(implementation: *ContextImplementation) tb_client_t {
|
|
30
|
+
return @ptrCast(tb_client_t, implementation);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
fn client_to_context(tb_client: tb_client_t) *ContextImplementation {
|
|
34
|
+
return @ptrCast(*ContextImplementation, @alignCast(@alignOf(ContextImplementation), tb_client));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const DefaultContext = blk: {
|
|
38
|
+
const Storage = @import("../storage.zig").Storage;
|
|
39
|
+
const MessageBus = @import("../message_bus.zig").MessageBusClient;
|
|
40
|
+
const StateMachine = @import("../state_machine.zig").StateMachineType(Storage);
|
|
41
|
+
break :blk ContextType(StateMachine, MessageBus);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// const TestingContext = blk: {
|
|
45
|
+
// const MessageBus = @import("test_message_bus.zig").MessageBusClient;
|
|
46
|
+
// const StateMachine = @import("../state_machine.zig").StateMachine;
|
|
47
|
+
// break :blk ContextType(StateMachine, MessageBus);
|
|
48
|
+
// };
|
|
49
|
+
|
|
50
|
+
// Pick the most suitable allocator
|
|
51
|
+
const global_allocator = if (builtin.link_libc)
|
|
52
|
+
std.heap.c_allocator
|
|
53
|
+
else if (builtin.target.os.tag == .windows)
|
|
54
|
+
(struct {
|
|
55
|
+
var gpa = std.heap.HeapAllocator.init();
|
|
56
|
+
}).gpa.allocator()
|
|
57
|
+
else
|
|
58
|
+
@compileError("tb_client must be built with libc");
|
|
59
|
+
|
|
60
|
+
pub export fn tb_client_init(
|
|
61
|
+
out_client: *tb_client_t,
|
|
62
|
+
out_packets: *tb_packet_list_t,
|
|
63
|
+
cluster_id: u32,
|
|
64
|
+
addresses_ptr: [*:0]const u8,
|
|
65
|
+
addresses_len: u32,
|
|
66
|
+
num_packets: u32,
|
|
67
|
+
on_completion_ctx: usize,
|
|
68
|
+
on_completion_fn: tb_completion_t,
|
|
69
|
+
) tb_status_t {
|
|
70
|
+
var init_fn = DefaultContext.init;
|
|
71
|
+
// if (addresses_len == 0) {
|
|
72
|
+
// init_fn = TestingContext.init;
|
|
73
|
+
// }
|
|
74
|
+
|
|
75
|
+
return (init_fn)(
|
|
76
|
+
global_allocator,
|
|
77
|
+
out_client,
|
|
78
|
+
out_packets,
|
|
79
|
+
cluster_id,
|
|
80
|
+
addresses_ptr,
|
|
81
|
+
addresses_len,
|
|
82
|
+
num_packets,
|
|
83
|
+
on_completion_ctx,
|
|
84
|
+
on_completion_fn,
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
pub export fn tb_client_submit(
|
|
89
|
+
client: tb_client_t,
|
|
90
|
+
packets: *tb_packet_list_t,
|
|
91
|
+
) void {
|
|
92
|
+
const context = client_to_context(client);
|
|
93
|
+
(context.submit_fn)(context, packets);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
pub export fn tb_client_deinit(
|
|
97
|
+
client: tb_client_t,
|
|
98
|
+
) void {
|
|
99
|
+
const context = client_to_context(client);
|
|
100
|
+
(context.deinit_fn)(context);
|
|
101
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// TODO
|
|
@@ -10,89 +10,93 @@ const config = @import("config.zig");
|
|
|
10
10
|
const vsr = @import("vsr.zig");
|
|
11
11
|
const IO = @import("io.zig").IO;
|
|
12
12
|
|
|
13
|
+
// TODO Document --memory
|
|
13
14
|
const usage = fmt.comptimePrint(
|
|
14
15
|
\\Usage:
|
|
15
16
|
\\
|
|
16
17
|
\\ tigerbeetle [-h | --help]
|
|
17
18
|
\\
|
|
18
|
-
\\ tigerbeetle
|
|
19
|
+
\\ tigerbeetle format --cluster=<integer> --replica=<index> <path>
|
|
19
20
|
\\
|
|
20
|
-
\\ tigerbeetle start
|
|
21
|
+
\\ tigerbeetle start --addresses=<addresses> <path>
|
|
21
22
|
\\
|
|
22
23
|
\\Commands:
|
|
23
24
|
\\
|
|
24
|
-
\\
|
|
25
|
-
\\
|
|
26
|
-
\\
|
|
27
|
-
\\ the default {[default_directory]s}.
|
|
25
|
+
\\ format Create a TigerBeetle replica data file at <path>.
|
|
26
|
+
\\ The --cluster and --replica arguments are required.
|
|
27
|
+
\\ Each TigerBeetle replica must have its own data file.
|
|
28
28
|
\\
|
|
29
|
-
\\ start
|
|
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.
|
|
29
|
+
\\ start Run a TigerBeetle replica from the data file at <path>.
|
|
33
30
|
\\
|
|
34
31
|
\\Options:
|
|
35
32
|
\\
|
|
36
33
|
\\ -h, --help
|
|
37
34
|
\\ Print this help message and exit.
|
|
38
35
|
\\
|
|
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
36
|
\\ --cluster=<integer>
|
|
44
37
|
\\ Set the cluster ID to the provided 32-bit unsigned integer.
|
|
45
38
|
\\
|
|
46
39
|
\\ --replica=<index>
|
|
47
|
-
\\ Set the zero-based index that will be used for
|
|
48
|
-
\\ The value of this
|
|
40
|
+
\\ Set the zero-based index that will be used for the replica process.
|
|
41
|
+
\\ The value of this argument will be interpreted as an index into the --addresses array.
|
|
49
42
|
\\
|
|
50
43
|
\\ --addresses=<addresses>
|
|
51
|
-
\\ Set the addresses of all replicas in the cluster.
|
|
52
|
-
\\ comma-separated list of IPv4 addresses with port numbers.
|
|
53
|
-
\\ Either the IPv4 address or port number
|
|
54
|
-
\\
|
|
44
|
+
\\ Set the addresses of all replicas in the cluster.
|
|
45
|
+
\\ Accepts a comma-separated list of IPv4 addresses with port numbers.
|
|
46
|
+
\\ Either the IPv4 address or port number (but not both) may be omitted,
|
|
47
|
+
\\ in which case a default of {[default_address]s} or {[default_port]d}
|
|
55
48
|
\\ will be used.
|
|
56
49
|
\\
|
|
57
50
|
\\Examples:
|
|
58
51
|
\\
|
|
59
|
-
\\ tigerbeetle
|
|
60
|
-
\\ tigerbeetle
|
|
61
|
-
\\ tigerbeetle
|
|
52
|
+
\\ tigerbeetle format --cluster=7 --replica=0 7_0.tigerbeetle
|
|
53
|
+
\\ tigerbeetle format --cluster=7 --replica=1 7_1.tigerbeetle
|
|
54
|
+
\\ tigerbeetle format --cluster=7 --replica=2 7_2.tigerbeetle
|
|
62
55
|
\\
|
|
63
|
-
\\ tigerbeetle start --
|
|
64
|
-
\\ tigerbeetle start --
|
|
65
|
-
\\ tigerbeetle start --
|
|
56
|
+
\\ tigerbeetle start --addresses=127.0.0.1:3003,127.0.0.1:3001,127.0.0.1:3002 7_0.tigerbeetle
|
|
57
|
+
\\ tigerbeetle start --addresses=3003,3001,3002 7_1.tigerbeetle
|
|
58
|
+
\\ tigerbeetle start --addresses=3003,3001,3002 7_2.tigerbeetle
|
|
66
59
|
\\
|
|
67
|
-
\\ tigerbeetle start --
|
|
60
|
+
\\ tigerbeetle start --addresses=192.168.0.1,192.168.0.2,192.168.0.3 7_0.tigerbeetle
|
|
68
61
|
\\
|
|
69
62
|
, .{
|
|
70
|
-
.default_directory = config.directory,
|
|
71
63
|
.default_address = config.address,
|
|
72
64
|
.default_port = config.port,
|
|
73
65
|
});
|
|
74
66
|
|
|
75
67
|
pub const Command = union(enum) {
|
|
76
|
-
|
|
68
|
+
format: struct {
|
|
69
|
+
args_allocated: std.ArrayList([:0]const u8),
|
|
77
70
|
cluster: u32,
|
|
78
71
|
replica: u8,
|
|
79
|
-
|
|
72
|
+
path: [:0]const u8,
|
|
80
73
|
},
|
|
81
74
|
start: struct {
|
|
82
|
-
|
|
83
|
-
replica: u8,
|
|
75
|
+
args_allocated: std.ArrayList([:0]const u8),
|
|
84
76
|
addresses: []net.Address,
|
|
85
|
-
|
|
77
|
+
memory: u64,
|
|
78
|
+
path: [:0]const u8,
|
|
86
79
|
},
|
|
80
|
+
|
|
81
|
+
pub fn deinit(command: Command, allocator: std.mem.Allocator) void {
|
|
82
|
+
var args_allocated = switch (command) {
|
|
83
|
+
.format => |cmd| cmd.args_allocated,
|
|
84
|
+
.start => |cmd| cmd.args_allocated,
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
for (args_allocated.items) |arg| allocator.free(arg);
|
|
88
|
+
args_allocated.deinit();
|
|
89
|
+
}
|
|
87
90
|
};
|
|
88
91
|
|
|
89
|
-
/// Parse the command line arguments passed to the tigerbeetle binary.
|
|
92
|
+
/// Parse the command line arguments passed to the `tigerbeetle` binary.
|
|
90
93
|
/// Exits the program with a non-zero exit code if an error is found.
|
|
91
94
|
pub fn parse_args(allocator: std.mem.Allocator) !Command {
|
|
92
|
-
var
|
|
93
|
-
var
|
|
94
|
-
var
|
|
95
|
-
var
|
|
95
|
+
var path: ?[:0]const u8 = null;
|
|
96
|
+
var cluster: ?[]const u8 = null;
|
|
97
|
+
var replica: ?[]const u8 = null;
|
|
98
|
+
var addresses: ?[]const u8 = null;
|
|
99
|
+
var memory: ?[]const u8 = null;
|
|
96
100
|
|
|
97
101
|
var args = try std.process.argsWithAllocator(allocator);
|
|
98
102
|
defer args.deinit();
|
|
@@ -100,17 +104,13 @@ pub fn parse_args(allocator: std.mem.Allocator) !Command {
|
|
|
100
104
|
// Keep track of the args from the ArgIterator above that were allocated
|
|
101
105
|
// then free them all at the end of the scope.
|
|
102
106
|
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
107
|
|
|
108
108
|
// Skip argv[0] which is the name of this executable
|
|
109
109
|
const did_skip = args.skip();
|
|
110
110
|
assert(did_skip);
|
|
111
111
|
|
|
112
112
|
const raw_command = try (args.next(allocator) orelse
|
|
113
|
-
fatal("no command provided, expected 'start' or '
|
|
113
|
+
fatal("no command provided, expected 'start' or 'format'", .{}));
|
|
114
114
|
defer allocator.free(raw_command);
|
|
115
115
|
|
|
116
116
|
if (mem.eql(u8, raw_command, "-h") or mem.eql(u8, raw_command, "--help")) {
|
|
@@ -118,69 +118,59 @@ pub fn parse_args(allocator: std.mem.Allocator) !Command {
|
|
|
118
118
|
os.exit(0);
|
|
119
119
|
}
|
|
120
120
|
const command = meta.stringToEnum(meta.Tag(Command), raw_command) orelse
|
|
121
|
-
fatal("unknown command '{s}', expected 'start' or '
|
|
121
|
+
fatal("unknown command '{s}', expected 'start' or 'format'", .{raw_command});
|
|
122
122
|
|
|
123
123
|
while (args.next(allocator)) |parsed_arg| {
|
|
124
124
|
const arg = try parsed_arg;
|
|
125
125
|
try args_allocated.append(arg);
|
|
126
126
|
|
|
127
127
|
if (mem.startsWith(u8, arg, "--cluster")) {
|
|
128
|
-
|
|
128
|
+
cluster = parse_flag("--cluster", arg);
|
|
129
129
|
} else if (mem.startsWith(u8, arg, "--replica")) {
|
|
130
|
-
|
|
130
|
+
replica = parse_flag("--replica", arg);
|
|
131
131
|
} else if (mem.startsWith(u8, arg, "--addresses")) {
|
|
132
|
-
|
|
133
|
-
} else if (mem.startsWith(u8, arg, "--
|
|
134
|
-
|
|
132
|
+
addresses = parse_flag("--addresses", arg);
|
|
133
|
+
} else if (mem.startsWith(u8, arg, "--memory")) {
|
|
134
|
+
memory = parse_flag("--memory", arg);
|
|
135
135
|
} else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
|
|
136
136
|
std.io.getStdOut().writeAll(usage) catch os.exit(1);
|
|
137
137
|
os.exit(0);
|
|
138
|
-
} else if (mem.startsWith(u8, arg, "
|
|
138
|
+
} else if (mem.startsWith(u8, arg, "-")) {
|
|
139
139
|
fatal("unexpected argument: '{s}'", .{arg});
|
|
140
|
+
} else if (path == null) {
|
|
141
|
+
path = arg;
|
|
140
142
|
} else {
|
|
141
143
|
fatal("unexpected argument: '{s}' (must start with '--')", .{arg});
|
|
142
144
|
}
|
|
143
145
|
}
|
|
144
146
|
|
|
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
147
|
switch (command) {
|
|
156
|
-
.
|
|
157
|
-
if (
|
|
158
|
-
|
|
159
|
-
}
|
|
148
|
+
.format => {
|
|
149
|
+
if (addresses != null) fatal("--addresses: supported only by 'start' command", .{});
|
|
150
|
+
if (memory != null) fatal("--memory: supported only by 'start' command", .{});
|
|
160
151
|
|
|
161
152
|
return Command{
|
|
162
|
-
.
|
|
163
|
-
.
|
|
164
|
-
.
|
|
165
|
-
.
|
|
153
|
+
.format = .{
|
|
154
|
+
.args_allocated = args_allocated,
|
|
155
|
+
.cluster = parse_cluster(cluster orelse fatal("required: --cluster", .{})),
|
|
156
|
+
.replica = parse_replica(replica orelse fatal("required: --replica", .{})),
|
|
157
|
+
.path = path orelse fatal("required: <path>", .{}),
|
|
166
158
|
},
|
|
167
159
|
};
|
|
168
160
|
},
|
|
169
161
|
.start => {
|
|
170
|
-
|
|
171
|
-
|
|
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
|
-
}
|
|
162
|
+
if (cluster != null) fatal("--cluster: supported only by 'format' command", .{});
|
|
163
|
+
if (replica != null) fatal("--replica: supported only by 'format' command", .{});
|
|
177
164
|
|
|
178
165
|
return Command{
|
|
179
166
|
.start = .{
|
|
180
|
-
.
|
|
181
|
-
.
|
|
182
|
-
|
|
183
|
-
|
|
167
|
+
.args_allocated = args_allocated,
|
|
168
|
+
.addresses = parse_addresses(
|
|
169
|
+
allocator,
|
|
170
|
+
addresses orelse fatal("required: --addresses", .{}),
|
|
171
|
+
),
|
|
172
|
+
.memory = if (memory) |m| parse_size(m) else config.memory_size_max_default,
|
|
173
|
+
.path = path orelse fatal("required: <path>", .{}),
|
|
184
174
|
},
|
|
185
175
|
};
|
|
186
176
|
},
|
|
@@ -189,20 +179,20 @@ pub fn parse_args(allocator: std.mem.Allocator) !Command {
|
|
|
189
179
|
|
|
190
180
|
/// Format and print an error message followed by the usage string to stderr,
|
|
191
181
|
/// then exit with an exit code of 1.
|
|
192
|
-
fn fatal(comptime fmt_string: []const u8, args: anytype) noreturn {
|
|
182
|
+
pub fn fatal(comptime fmt_string: []const u8, args: anytype) noreturn {
|
|
193
183
|
const stderr = std.io.getStdErr().writer();
|
|
194
184
|
stderr.print("error: " ++ fmt_string ++ "\n", args) catch {};
|
|
195
185
|
os.exit(1);
|
|
196
186
|
}
|
|
197
187
|
|
|
198
|
-
/// Parse e.g. `--cluster=
|
|
188
|
+
/// Parse e.g. `--cluster=123` into `123` with error handling.
|
|
199
189
|
fn parse_flag(comptime flag: []const u8, arg: [:0]const u8) [:0]const u8 {
|
|
200
190
|
const value = arg[flag.len..];
|
|
201
191
|
if (value.len < 2) {
|
|
202
192
|
fatal("{s} argument requires a value", .{flag});
|
|
203
193
|
}
|
|
204
194
|
if (value[0] != '=') {
|
|
205
|
-
fatal("expected '=' after {s} but found '{c}'", .{ flag, value[0] });
|
|
195
|
+
fatal("expected '=' after '{s}' but found '{c}'", .{ flag, value[0] });
|
|
206
196
|
}
|
|
207
197
|
return value[1..];
|
|
208
198
|
}
|
|
@@ -230,8 +220,77 @@ fn parse_addresses(allocator: std.mem.Allocator, raw_addresses: []const u8) []ne
|
|
|
230
220
|
error.PortOverflow => fatal("--addresses: port exceeds 65535", .{}),
|
|
231
221
|
error.PortInvalid => fatal("--addresses: invalid port", .{}),
|
|
232
222
|
error.AddressInvalid => fatal("--addresses: invalid IPv4 address", .{}),
|
|
233
|
-
error.OutOfMemory => fatal("
|
|
223
|
+
error.OutOfMemory => fatal("out of memory", .{}),
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
fn parse_size(string: []const u8) u64 {
|
|
228
|
+
var value = mem.trim(u8, string, " ");
|
|
229
|
+
|
|
230
|
+
const unit: u64 = blk: {
|
|
231
|
+
if (parse_size_unit(&value, &[_][]const u8{ "TiB", "tib", "TB", "tb" })) {
|
|
232
|
+
break :blk 1024 * 1024 * 1024 * 1024;
|
|
233
|
+
} else if (parse_size_unit(&value, &[_][]const u8{ "GiB", "gib", "GB", "gb" })) {
|
|
234
|
+
break :blk 1024 * 1024 * 1024;
|
|
235
|
+
} else if (parse_size_unit(&value, &[_][]const u8{ "MiB", "mib", "MB", "mb" })) {
|
|
236
|
+
break :blk 1024 * 1024;
|
|
237
|
+
} else if (parse_size_unit(&value, &[_][]const u8{ "KiB", "kib", "KB", "kb" })) {
|
|
238
|
+
break :blk 1024;
|
|
239
|
+
} else {
|
|
240
|
+
break :blk 1;
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
const size = fmt.parseUnsigned(u64, value, 10) catch |err| switch (err) {
|
|
245
|
+
error.Overflow => fatal("size value exceeds a 64-bit unsigned integer", .{}),
|
|
246
|
+
error.InvalidCharacter => fatal("size value contains an invalid character", .{}),
|
|
234
247
|
};
|
|
248
|
+
|
|
249
|
+
return size * unit;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
fn parse_size_unit(value: *[]const u8, suffixes: []const []const u8) bool {
|
|
253
|
+
for (suffixes) |suffix| {
|
|
254
|
+
if (mem.endsWith(u8, value.*, suffix)) {
|
|
255
|
+
value.* = mem.trim(u8, value.*[0 .. value.*.len - suffix.len], " ");
|
|
256
|
+
return true;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
test "parse_size" {
|
|
263
|
+
const expectEqual = std.testing.expectEqual;
|
|
264
|
+
|
|
265
|
+
const tib = 1024 * 1024 * 1024 * 1024;
|
|
266
|
+
const gib = 1024 * 1024 * 1024;
|
|
267
|
+
const mib = 1024 * 1024;
|
|
268
|
+
const kib = 1024;
|
|
269
|
+
|
|
270
|
+
try expectEqual(@as(u64, 0), parse_size("0"));
|
|
271
|
+
try expectEqual(@as(u64, 1), parse_size(" 1 "));
|
|
272
|
+
try expectEqual(@as(u64, 140737488355328), parse_size(" 140737488355328 "));
|
|
273
|
+
try expectEqual(@as(u64, 140737488355328), parse_size(" 128TiB "));
|
|
274
|
+
|
|
275
|
+
try expectEqual(@as(u64, 1 * tib), parse_size(" 1TiB "));
|
|
276
|
+
try expectEqual(@as(u64, 10 * tib), parse_size(" 10 tib "));
|
|
277
|
+
try expectEqual(@as(u64, 100 * tib), parse_size(" 100 TB "));
|
|
278
|
+
try expectEqual(@as(u64, 1000 * tib), parse_size(" 1000 tb "));
|
|
279
|
+
|
|
280
|
+
try expectEqual(@as(u64, 1 * gib), parse_size(" 1GiB "));
|
|
281
|
+
try expectEqual(@as(u64, 10 * gib), parse_size(" 10 gib "));
|
|
282
|
+
try expectEqual(@as(u64, 100 * gib), parse_size(" 100 GB "));
|
|
283
|
+
try expectEqual(@as(u64, 1000 * gib), parse_size(" 1000 gb "));
|
|
284
|
+
|
|
285
|
+
try expectEqual(@as(u64, 1 * mib), parse_size(" 1MiB "));
|
|
286
|
+
try expectEqual(@as(u64, 10 * mib), parse_size(" 10 mib "));
|
|
287
|
+
try expectEqual(@as(u64, 100 * mib), parse_size(" 100 MB "));
|
|
288
|
+
try expectEqual(@as(u64, 1000 * mib), parse_size(" 1000 mb "));
|
|
289
|
+
|
|
290
|
+
try expectEqual(@as(u64, 1 * kib), parse_size(" 1KiB "));
|
|
291
|
+
try expectEqual(@as(u64, 10 * kib), parse_size(" 10 kib "));
|
|
292
|
+
try expectEqual(@as(u64, 100 * kib), parse_size(" 100 KB "));
|
|
293
|
+
try expectEqual(@as(u64, 1000 * kib), parse_size(" 1000 kb "));
|
|
235
294
|
}
|
|
236
295
|
|
|
237
296
|
fn parse_replica(raw_replica: []const u8) u8 {
|