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.
- package/README.md +584 -184
- package/dist/benchmark.js +59 -51
- package/dist/benchmark.js.map +1 -1
- package/dist/bin/aarch64-linux-gnu/client.node +0 -0
- package/dist/bin/aarch64-linux-musl/client.node +0 -0
- package/dist/bin/aarch64-macos/client.node +0 -0
- package/dist/bin/x86_64-linux-gnu/client.node +0 -0
- package/dist/bin/x86_64-linux-musl/client.node +0 -0
- package/dist/bin/x86_64-macos/client.node +0 -0
- package/dist/bin/x86_64-windows/client.node +0 -0
- package/dist/bindings.d.ts +141 -0
- package/dist/bindings.js +112 -0
- package/dist/bindings.js.map +1 -0
- package/dist/index.d.ts +2 -125
- package/dist/index.js +51 -101
- package/dist/index.js.map +1 -1
- package/dist/test.js +69 -55
- package/dist/test.js.map +1 -1
- package/package-lock.json +26 -0
- package/package.json +17 -28
- package/src/benchmark.ts +58 -49
- package/src/bindings.ts +631 -0
- package/src/index.ts +71 -163
- package/src/node.zig +169 -148
- package/src/test.ts +71 -57
- package/src/translate.zig +19 -36
- package/.yarn/releases/yarn-berry.cjs +0 -55
- package/.yarnrc.yml +0 -1
- package/scripts/download_node_headers.sh +0 -25
- package/scripts/postinstall.sh +0 -6
- package/src/tigerbeetle/scripts/benchmark.bat +0 -46
- package/src/tigerbeetle/scripts/benchmark.sh +0 -55
- package/src/tigerbeetle/scripts/install.sh +0 -6
- package/src/tigerbeetle/scripts/install_zig.bat +0 -109
- package/src/tigerbeetle/scripts/install_zig.sh +0 -84
- package/src/tigerbeetle/scripts/lint.zig +0 -199
- package/src/tigerbeetle/scripts/upgrade_ubuntu_kernel.sh +0 -39
- package/src/tigerbeetle/scripts/vopr.bat +0 -48
- package/src/tigerbeetle/scripts/vopr.sh +0 -33
- package/src/tigerbeetle/scripts/vr_state_enumerate +0 -46
- package/src/tigerbeetle/src/benchmark.zig +0 -290
- package/src/tigerbeetle/src/cli.zig +0 -244
- package/src/tigerbeetle/src/config.zig +0 -239
- package/src/tigerbeetle/src/demo.zig +0 -125
- package/src/tigerbeetle/src/demo_01_create_accounts.zig +0 -35
- package/src/tigerbeetle/src/demo_02_lookup_accounts.zig +0 -7
- package/src/tigerbeetle/src/demo_03_create_transfers.zig +0 -24
- package/src/tigerbeetle/src/demo_04_create_pending_transfers.zig +0 -61
- package/src/tigerbeetle/src/demo_05_post_pending_transfers.zig +0 -37
- package/src/tigerbeetle/src/demo_06_void_pending_transfers.zig +0 -24
- package/src/tigerbeetle/src/demo_07_lookup_transfers.zig +0 -7
- package/src/tigerbeetle/src/fifo.zig +0 -104
- package/src/tigerbeetle/src/io/benchmark.zig +0 -213
- package/src/tigerbeetle/src/io/darwin.zig +0 -793
- package/src/tigerbeetle/src/io/linux.zig +0 -1038
- package/src/tigerbeetle/src/io/test.zig +0 -643
- package/src/tigerbeetle/src/io/windows.zig +0 -1161
- package/src/tigerbeetle/src/io.zig +0 -34
- package/src/tigerbeetle/src/main.zig +0 -144
- package/src/tigerbeetle/src/message_bus.zig +0 -1000
- package/src/tigerbeetle/src/message_pool.zig +0 -142
- package/src/tigerbeetle/src/ring_buffer.zig +0 -289
- package/src/tigerbeetle/src/simulator.zig +0 -417
- package/src/tigerbeetle/src/state_machine.zig +0 -2470
- package/src/tigerbeetle/src/storage.zig +0 -308
- package/src/tigerbeetle/src/test/cluster.zig +0 -351
- package/src/tigerbeetle/src/test/message_bus.zig +0 -93
- package/src/tigerbeetle/src/test/network.zig +0 -179
- package/src/tigerbeetle/src/test/packet_simulator.zig +0 -387
- package/src/tigerbeetle/src/test/state_checker.zig +0 -145
- package/src/tigerbeetle/src/test/state_machine.zig +0 -76
- package/src/tigerbeetle/src/test/storage.zig +0 -438
- package/src/tigerbeetle/src/test/time.zig +0 -84
- package/src/tigerbeetle/src/tigerbeetle.zig +0 -222
- package/src/tigerbeetle/src/time.zig +0 -113
- package/src/tigerbeetle/src/unit_tests.zig +0 -14
- package/src/tigerbeetle/src/vsr/client.zig +0 -505
- package/src/tigerbeetle/src/vsr/clock.zig +0 -812
- package/src/tigerbeetle/src/vsr/journal.zig +0 -2293
- package/src/tigerbeetle/src/vsr/marzullo.zig +0 -309
- package/src/tigerbeetle/src/vsr/replica.zig +0 -5015
- package/src/tigerbeetle/src/vsr.zig +0 -1017
- package/yarn.lock +0 -42
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
const std = @import("std");
|
|
2
|
-
const assert = std.debug.assert;
|
|
3
|
-
|
|
4
|
-
/// Whether development or production:
|
|
5
|
-
pub const deployment_environment = .development;
|
|
6
|
-
|
|
7
|
-
/// The maximum log level in increasing order of verbosity (emergency=0, debug=3):
|
|
8
|
-
pub const log_level = 2;
|
|
9
|
-
|
|
10
|
-
/// The maximum number of replicas allowed in a cluster.
|
|
11
|
-
pub const replicas_max = 6;
|
|
12
|
-
|
|
13
|
-
/// The maximum number of clients allowed per cluster, where each client has a unique 128-bit ID.
|
|
14
|
-
/// This impacts the amount of memory allocated at initialization by the server.
|
|
15
|
-
/// This determines the size of the VR client table used to cache replies to clients by client ID.
|
|
16
|
-
/// Each client has one entry in the VR client table to store the latest `message_size_max` reply.
|
|
17
|
-
pub const clients_max = 32;
|
|
18
|
-
|
|
19
|
-
/// The minimum number of nodes required to form a quorum for replication:
|
|
20
|
-
/// Majority quorums are only required across view change and replication phases (not within).
|
|
21
|
-
/// As per Flexible Paxos, provided `quorum_replication + quorum_view_change > replicas`:
|
|
22
|
-
/// 1. you may increase `quorum_view_change` above a majority, so that
|
|
23
|
-
/// 2. you can decrease `quorum_replication` below a majority, to optimize the common case.
|
|
24
|
-
/// This improves latency by reducing the number of nodes required for synchronous replication.
|
|
25
|
-
/// This reduces redundancy only in the short term, asynchronous replication will still continue.
|
|
26
|
-
/// The size of the replication quorum is limited to the minimum of this value and actual majority.
|
|
27
|
-
/// The size of the view change quorum will then be automatically inferred from quorum_replication.
|
|
28
|
-
pub const quorum_replication_max = 3;
|
|
29
|
-
|
|
30
|
-
/// The default server port to listen on if not specified in `--addresses`:
|
|
31
|
-
pub const port = 3001;
|
|
32
|
-
|
|
33
|
-
/// The default network interface address to listen on if not specified in `--addresses`:
|
|
34
|
-
/// WARNING: Binding to all interfaces with "0.0.0.0" is dangerous and opens the server to anyone.
|
|
35
|
-
/// Bind to the "127.0.0.1" loopback address to accept local connections as a safe default only.
|
|
36
|
-
pub const address = "127.0.0.1";
|
|
37
|
-
|
|
38
|
-
/// Where data files should be persisted by default:
|
|
39
|
-
pub const directory = "/var/lib/tigerbeetle";
|
|
40
|
-
|
|
41
|
-
/// The maximum number of accounts to store in memory:
|
|
42
|
-
/// This impacts the amount of memory allocated at initialization by the server.
|
|
43
|
-
pub const accounts_max = switch (deployment_environment) {
|
|
44
|
-
.production => 1_000_000,
|
|
45
|
-
else => 100_000,
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
/// The maximum number of transfers to store in memory:
|
|
49
|
-
/// This impacts the amount of memory allocated at initialization by the server.
|
|
50
|
-
/// We allocate more capacity than the number of transfers for a safe hash table load factor.
|
|
51
|
-
pub const transfers_max = switch (deployment_environment) {
|
|
52
|
-
.production => 100_000_000,
|
|
53
|
-
else => 1_000_000,
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
/// The maximum number of two-phase transfers to store in memory:
|
|
57
|
-
/// This impacts the amount of memory allocated at initialization by the server.
|
|
58
|
-
pub const transfers_pending_max = transfers_max;
|
|
59
|
-
|
|
60
|
-
/// The maximum number of batch entries in the journal file:
|
|
61
|
-
/// A batch entry may contain many transfers, so this is not a limit on the number of transfers.
|
|
62
|
-
/// We need this limit to allocate space for copies of batch headers at the start of the journal.
|
|
63
|
-
/// These header copies enable us to disentangle corruption from crashes and recover accordingly.
|
|
64
|
-
pub const journal_slot_count = switch (deployment_environment) {
|
|
65
|
-
.production => 1024,
|
|
66
|
-
else => 128,
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
/// The maximum size of the journal file:
|
|
70
|
-
/// This is pre-allocated and zeroed for performance when initialized.
|
|
71
|
-
/// Writes within this file never extend the filesystem inode size reducing the cost of fdatasync().
|
|
72
|
-
/// This enables static allocation of disk space so that appends cannot fail with ENOSPC.
|
|
73
|
-
/// This also enables us to detect filesystem inode corruption that would change the journal size.
|
|
74
|
-
// TODO remove this; just allocate a part of the total storage for the journal
|
|
75
|
-
pub const journal_size_max = journal_slot_count * (128 + message_size_max);
|
|
76
|
-
|
|
77
|
-
/// The maximum number of connections that can be held open by the server at any time:
|
|
78
|
-
pub const connections_max = replicas_max + clients_max;
|
|
79
|
-
|
|
80
|
-
/// The maximum size of a message in bytes:
|
|
81
|
-
/// This is also the limit of all inflight data across multiple pipelined requests per connection.
|
|
82
|
-
/// We may have one request of up to 2 MiB inflight or 2 pipelined requests of up to 1 MiB inflight.
|
|
83
|
-
/// This impacts sequential disk write throughput, the larger the buffer the better.
|
|
84
|
-
/// 2 MiB is 16,384 transfers, and a reasonable choice for sequential disk write throughput.
|
|
85
|
-
/// However, this impacts bufferbloat and head-of-line blocking latency for pipelined requests.
|
|
86
|
-
/// For a 1 Gbps NIC = 125 MiB/s throughput: 2 MiB / 125 * 1000ms = 16ms for the next request.
|
|
87
|
-
/// This impacts the amount of memory allocated at initialization by the server.
|
|
88
|
-
pub const message_size_max = 1 * 1024 * 1024;
|
|
89
|
-
|
|
90
|
-
/// The maximum number of Viewstamped Replication prepare messages that can be inflight at a time.
|
|
91
|
-
/// This is immutable once assigned per cluster, as replicas need to know how many operations might
|
|
92
|
-
/// possibly be uncommitted during a view change, and this must be constant for all replicas.
|
|
93
|
-
pub const pipeline_max = clients_max;
|
|
94
|
-
|
|
95
|
-
/// The minimum and maximum amount of time in milliseconds to wait before initiating a connection.
|
|
96
|
-
/// Exponential backoff and jitter are applied within this range.
|
|
97
|
-
pub const connection_delay_min_ms = 50;
|
|
98
|
-
pub const connection_delay_max_ms = 1000;
|
|
99
|
-
|
|
100
|
-
/// The maximum number of outgoing messages that may be queued on a replica connection.
|
|
101
|
-
pub const connection_send_queue_max_replica = std.math.max(std.math.min(clients_max, 4), 2);
|
|
102
|
-
|
|
103
|
-
/// The maximum number of outgoing messages that may be queued on a client connection.
|
|
104
|
-
/// The client has one in-flight request, and occasionally a ping.
|
|
105
|
-
pub const connection_send_queue_max_client = 2;
|
|
106
|
-
|
|
107
|
-
/// The maximum number of outgoing requests that may be queued on a client (including the in-flight request).
|
|
108
|
-
pub const client_request_queue_max = 32;
|
|
109
|
-
|
|
110
|
-
/// The maximum number of connections in the kernel's complete connection queue pending an accept():
|
|
111
|
-
/// If the backlog argument is greater than the value in `/proc/sys/net/core/somaxconn`, then it is
|
|
112
|
-
/// silently truncated to that value. Since Linux 5.4, the default in this file is 4096.
|
|
113
|
-
pub const tcp_backlog = 64;
|
|
114
|
-
|
|
115
|
-
/// The maximum size of a kernel socket receive buffer in bytes (or 0 to use the system default):
|
|
116
|
-
/// This sets SO_RCVBUF as an alternative to the auto-tuning range in /proc/sys/net/ipv4/tcp_rmem.
|
|
117
|
-
/// The value is limited by /proc/sys/net/core/rmem_max, unless the CAP_NET_ADMIN privilege exists.
|
|
118
|
-
/// The kernel doubles this value to allow space for packet bookkeeping overhead.
|
|
119
|
-
/// The receive buffer should ideally exceed the Bandwidth-Delay Product for maximum throughput.
|
|
120
|
-
/// At the same time, be careful going beyond 4 MiB as the kernel may merge many small TCP packets,
|
|
121
|
-
/// causing considerable latency spikes for large buffer sizes:
|
|
122
|
-
/// https://blog.cloudflare.com/the-story-of-one-latency-spike/
|
|
123
|
-
pub const tcp_rcvbuf = 4 * 1024 * 1024;
|
|
124
|
-
|
|
125
|
-
/// The maximum size of a kernel socket send buffer in bytes (or 0 to use the system default):
|
|
126
|
-
/// This sets SO_SNDBUF as an alternative to the auto-tuning range in /proc/sys/net/ipv4/tcp_wmem.
|
|
127
|
-
/// The value is limited by /proc/sys/net/core/wmem_max, unless the CAP_NET_ADMIN privilege exists.
|
|
128
|
-
/// The kernel doubles this value to allow space for packet bookkeeping overhead.
|
|
129
|
-
pub const tcp_sndbuf_replica = connection_send_queue_max_replica * message_size_max;
|
|
130
|
-
pub const tcp_sndbuf_client = connection_send_queue_max_client * message_size_max;
|
|
131
|
-
|
|
132
|
-
/// Whether to enable TCP keepalive:
|
|
133
|
-
pub const tcp_keepalive = true;
|
|
134
|
-
|
|
135
|
-
/// The time (in seconds) the connection needs to be idle before sending TCP keepalive probes:
|
|
136
|
-
/// Probes are not sent when the send buffer has data or the congestion window size is zero,
|
|
137
|
-
/// for these cases we also need tcp_user_timeout below.
|
|
138
|
-
pub const tcp_keepidle = 5;
|
|
139
|
-
|
|
140
|
-
/// The time (in seconds) between individual keepalive probes:
|
|
141
|
-
pub const tcp_keepintvl = 4;
|
|
142
|
-
|
|
143
|
-
/// The maximum number of keepalive probes to send before dropping the connection:
|
|
144
|
-
pub const tcp_keepcnt = 3;
|
|
145
|
-
|
|
146
|
-
/// The time (in milliseconds) to timeout an idle connection or unacknowledged send:
|
|
147
|
-
/// This timer rides on the granularity of the keepalive or retransmission timers.
|
|
148
|
-
/// For example, if keepalive will only send a probe after 10s then this becomes the lower bound
|
|
149
|
-
/// for tcp_user_timeout to fire, even if tcp_user_timeout is 2s. Nevertheless, this would timeout
|
|
150
|
-
/// the connection at 10s rather than wait for tcp_keepcnt probes to be sent. At the same time, if
|
|
151
|
-
/// tcp_user_timeout is larger than the max keepalive time then tcp_keepcnt will be ignored and
|
|
152
|
-
/// more keepalive probes will be sent until tcp_user_timeout fires.
|
|
153
|
-
/// For a thorough overview of how these settings interact:
|
|
154
|
-
/// https://blog.cloudflare.com/when-tcp-sockets-refuse-to-die/
|
|
155
|
-
pub const tcp_user_timeout = (tcp_keepidle + tcp_keepintvl * tcp_keepcnt) * 1000;
|
|
156
|
-
|
|
157
|
-
/// Whether to disable Nagle's algorithm to eliminate send buffering delays:
|
|
158
|
-
pub const tcp_nodelay = true;
|
|
159
|
-
|
|
160
|
-
/// The minimum size of an aligned kernel page and an Advanced Format disk sector:
|
|
161
|
-
/// This is necessary for direct I/O without the kernel having to fix unaligned pages with a copy.
|
|
162
|
-
/// The new Advanced Format sector size is backwards compatible with the old 512 byte sector size.
|
|
163
|
-
/// This should therefore never be less than 4 KiB to be future-proof when server disks are swapped.
|
|
164
|
-
pub const sector_size = 4096;
|
|
165
|
-
|
|
166
|
-
/// Whether to perform direct I/O to the underlying disk device:
|
|
167
|
-
/// This enables several performance optimizations:
|
|
168
|
-
/// * A memory copy to the kernel's page cache can be eliminated for reduced CPU utilization.
|
|
169
|
-
/// * I/O can be issued immediately to the disk device without buffering delay for improved latency.
|
|
170
|
-
/// This also enables several safety features:
|
|
171
|
-
/// * Disk data can be scrubbed to repair latent sector errors and checksum errors proactively.
|
|
172
|
-
/// * Fsync failures can be recovered from correctly.
|
|
173
|
-
/// WARNING: Disabling direct I/O is unsafe; the page cache cannot be trusted after an fsync error,
|
|
174
|
-
/// even after an application panic, since the kernel will mark dirty pages as clean, even
|
|
175
|
-
/// when they were never written to disk.
|
|
176
|
-
pub const direct_io = true;
|
|
177
|
-
|
|
178
|
-
/// The maximum number of concurrent read I/O operations to allow at once.
|
|
179
|
-
pub const io_depth_read = 8;
|
|
180
|
-
/// The maximum number of concurrent write I/O operations to allow at once.
|
|
181
|
-
pub const io_depth_write = 8;
|
|
182
|
-
|
|
183
|
-
/// The number of milliseconds between each replica tick, the basic unit of time in TigerBeetle.
|
|
184
|
-
/// Used to regulate heartbeats, retries and timeouts, all specified as multiples of a tick.
|
|
185
|
-
pub const tick_ms = 10;
|
|
186
|
-
|
|
187
|
-
/// The conservative round-trip time at startup when there is no network knowledge.
|
|
188
|
-
/// Adjusted dynamically thereafter for RTT-sensitive timeouts according to network congestion.
|
|
189
|
-
/// This should be set higher rather than lower to avoid flooding the network at startup.
|
|
190
|
-
pub const rtt_ticks = 300 / tick_ms;
|
|
191
|
-
|
|
192
|
-
/// The multiple of round-trip time for RTT-sensitive timeouts.
|
|
193
|
-
pub const rtt_multiple = 2;
|
|
194
|
-
|
|
195
|
-
/// The min/max bounds of exponential backoff (and jitter) to add to RTT-sensitive timeouts.
|
|
196
|
-
pub const backoff_min_ticks = 100 / tick_ms;
|
|
197
|
-
pub const backoff_max_ticks = 10000 / tick_ms;
|
|
198
|
-
|
|
199
|
-
/// The maximum skew between two clocks to allow when considering them to be in agreement.
|
|
200
|
-
/// The principle is that no two clocks tick exactly alike but some clocks more or less agree.
|
|
201
|
-
/// The maximum skew across the cluster as a whole is this value times the total number of clocks.
|
|
202
|
-
/// The cluster will be unavailable if the majority of clocks are all further than this value apart.
|
|
203
|
-
/// Decreasing this reduces the probability of reaching agreement on synchronized time.
|
|
204
|
-
/// Increasing this reduces the accuracy of synchronized time.
|
|
205
|
-
pub const clock_offset_tolerance_max_ms = 10000;
|
|
206
|
-
|
|
207
|
-
/// The amount of time before the clock's synchronized epoch is expired.
|
|
208
|
-
/// If the epoch is expired before it can be replaced with a new synchronized epoch, then this most
|
|
209
|
-
/// likely indicates either a network partition or else too many clock faults across the cluster.
|
|
210
|
-
/// A new synchronized epoch will be installed as soon as these conditions resolve.
|
|
211
|
-
pub const clock_epoch_max_ms = 60000;
|
|
212
|
-
|
|
213
|
-
/// The amount of time to wait for enough accurate samples before synchronizing the clock.
|
|
214
|
-
/// The more samples we can take per remote clock source, the more accurate our estimation becomes.
|
|
215
|
-
/// This impacts cluster startup time as the leader must first wait for synchronization to complete.
|
|
216
|
-
pub const clock_synchronization_window_min_ms = 2000;
|
|
217
|
-
|
|
218
|
-
/// The amount of time without agreement before the clock window is expired and a new window opened.
|
|
219
|
-
/// This happens where some samples have been collected but not enough to reach agreement.
|
|
220
|
-
/// The quality of samples degrades as they age so at some point we throw them away and start over.
|
|
221
|
-
/// This eliminates the impact of gradual clock drift on our clock offset (clock skew) measurements.
|
|
222
|
-
/// If a window expires because of this then it is likely that the clock epoch will also be expired.
|
|
223
|
-
pub const clock_synchronization_window_max_ms = 20000;
|
|
224
|
-
|
|
225
|
-
// TODO Move these to a separate "internal computed constants" file.
|
|
226
|
-
pub const journal_size_headers = journal_slot_count * 128; // 128 == @sizeOf(Header)
|
|
227
|
-
pub const journal_size_prepares = journal_slot_count * message_size_max;
|
|
228
|
-
|
|
229
|
-
comptime {
|
|
230
|
-
// vsr.parse_address assumes that config.address/config.port are valid.
|
|
231
|
-
_ = std.net.Address.parseIp4(address, 0) catch unreachable;
|
|
232
|
-
_ = @as(u16, port);
|
|
233
|
-
|
|
234
|
-
// Avoid latency issues from setting sndbuf too high:
|
|
235
|
-
assert(tcp_sndbuf_replica <= 16 * 1024 * 1024);
|
|
236
|
-
assert(tcp_sndbuf_client <= 16 * 1024 * 1024);
|
|
237
|
-
|
|
238
|
-
assert(journal_size_max == journal_size_headers + journal_size_prepares);
|
|
239
|
-
}
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
const std = @import("std");
|
|
2
|
-
const assert = std.debug.assert;
|
|
3
|
-
|
|
4
|
-
const config = @import("config.zig");
|
|
5
|
-
|
|
6
|
-
const tb = @import("tigerbeetle.zig");
|
|
7
|
-
const Account = tb.Account;
|
|
8
|
-
const Transfer = tb.Transfer;
|
|
9
|
-
|
|
10
|
-
const CreateAccountsResult = tb.CreateAccountsResult;
|
|
11
|
-
const CreateTransfersResult = tb.CreateTransfersResult;
|
|
12
|
-
|
|
13
|
-
const IO = @import("io.zig").IO;
|
|
14
|
-
const MessageBus = @import("message_bus.zig").MessageBusClient;
|
|
15
|
-
const StateMachine = @import("state_machine.zig").StateMachine;
|
|
16
|
-
|
|
17
|
-
const vsr = @import("vsr.zig");
|
|
18
|
-
const Header = vsr.Header;
|
|
19
|
-
const Client = vsr.Client(StateMachine, MessageBus);
|
|
20
|
-
|
|
21
|
-
pub const log_level: std.log.Level = .alert;
|
|
22
|
-
|
|
23
|
-
pub fn request(
|
|
24
|
-
operation: StateMachine.Operation,
|
|
25
|
-
batch: anytype,
|
|
26
|
-
on_reply: fn (
|
|
27
|
-
user_data: u128,
|
|
28
|
-
operation: StateMachine.Operation,
|
|
29
|
-
results: Client.Error![]const u8,
|
|
30
|
-
) void,
|
|
31
|
-
) !void {
|
|
32
|
-
const allocator = std.heap.page_allocator;
|
|
33
|
-
const client_id = std.crypto.random.int(u128);
|
|
34
|
-
const cluster_id: u32 = 1;
|
|
35
|
-
var addresses = [_]std.net.Address{try std.net.Address.parseIp4("127.0.0.1", config.port)};
|
|
36
|
-
|
|
37
|
-
var io = try IO.init(32, 0);
|
|
38
|
-
defer io.deinit();
|
|
39
|
-
|
|
40
|
-
var message_bus = try MessageBus.init(allocator, cluster_id, &addresses, client_id, &io);
|
|
41
|
-
defer message_bus.deinit();
|
|
42
|
-
|
|
43
|
-
var client = try Client.init(
|
|
44
|
-
allocator,
|
|
45
|
-
client_id,
|
|
46
|
-
cluster_id,
|
|
47
|
-
@intCast(u8, addresses.len),
|
|
48
|
-
&message_bus,
|
|
49
|
-
);
|
|
50
|
-
defer client.deinit();
|
|
51
|
-
|
|
52
|
-
message_bus.set_on_message(*Client, &client, Client.on_message);
|
|
53
|
-
|
|
54
|
-
const message = client.get_message();
|
|
55
|
-
defer client.unref(message);
|
|
56
|
-
|
|
57
|
-
const body = std.mem.asBytes(&batch);
|
|
58
|
-
std.mem.copy(u8, message.buffer[@sizeOf(Header)..], body);
|
|
59
|
-
|
|
60
|
-
client.request(
|
|
61
|
-
0,
|
|
62
|
-
on_reply,
|
|
63
|
-
operation,
|
|
64
|
-
message,
|
|
65
|
-
body.len,
|
|
66
|
-
);
|
|
67
|
-
|
|
68
|
-
while (client.request_queue.count > 0) {
|
|
69
|
-
client.tick();
|
|
70
|
-
try io.run_for_ns(config.tick_ms * std.time.ns_per_ms);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
pub fn on_create_accounts(
|
|
75
|
-
user_data: u128,
|
|
76
|
-
operation: StateMachine.Operation,
|
|
77
|
-
results: Client.Error![]const u8,
|
|
78
|
-
) void {
|
|
79
|
-
_ = user_data;
|
|
80
|
-
_ = operation;
|
|
81
|
-
|
|
82
|
-
print_results(CreateAccountsResult, results);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
pub fn on_lookup_accounts(
|
|
86
|
-
user_data: u128,
|
|
87
|
-
operation: StateMachine.Operation,
|
|
88
|
-
results: Client.Error![]const u8,
|
|
89
|
-
) void {
|
|
90
|
-
_ = user_data;
|
|
91
|
-
_ = operation;
|
|
92
|
-
|
|
93
|
-
print_results(Account, results);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
pub fn on_lookup_transfers(
|
|
97
|
-
user_data: u128,
|
|
98
|
-
operation: StateMachine.Operation,
|
|
99
|
-
results: Client.Error![]const u8,
|
|
100
|
-
) void {
|
|
101
|
-
_ = user_data;
|
|
102
|
-
_ = operation;
|
|
103
|
-
|
|
104
|
-
print_results(Transfer, results);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
pub fn on_create_transfers(
|
|
108
|
-
user_data: u128,
|
|
109
|
-
operation: StateMachine.Operation,
|
|
110
|
-
results: Client.Error![]const u8,
|
|
111
|
-
) void {
|
|
112
|
-
_ = user_data;
|
|
113
|
-
_ = operation;
|
|
114
|
-
|
|
115
|
-
print_results(CreateTransfersResult, results);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
fn print_results(comptime Results: type, results: Client.Error![]const u8) void {
|
|
119
|
-
const body = results catch unreachable;
|
|
120
|
-
const slice = std.mem.bytesAsSlice(Results, body);
|
|
121
|
-
for (slice) |result| {
|
|
122
|
-
std.debug.print("{}\n", .{result});
|
|
123
|
-
}
|
|
124
|
-
if (slice.len == 0) std.debug.print("OK\n", .{});
|
|
125
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
const tb = @import("tigerbeetle.zig");
|
|
2
|
-
const demo = @import("demo.zig");
|
|
3
|
-
|
|
4
|
-
const Account = tb.Account;
|
|
5
|
-
|
|
6
|
-
pub fn main() !void {
|
|
7
|
-
const accounts = [_]Account{
|
|
8
|
-
Account{
|
|
9
|
-
.id = 1,
|
|
10
|
-
.user_data = 0,
|
|
11
|
-
.reserved = [_]u8{0} ** 48,
|
|
12
|
-
.ledger = 710, // Let's use the ISO-4217 Code Number for ZAR
|
|
13
|
-
.code = 1000, // A chart of accounts code to describe this as a clearing account.
|
|
14
|
-
.flags = .{ .debits_must_not_exceed_credits = true },
|
|
15
|
-
.debits_pending = 0,
|
|
16
|
-
.debits_posted = 0,
|
|
17
|
-
.credits_pending = 0,
|
|
18
|
-
.credits_posted = 10000, // Let's start with some liquidity.
|
|
19
|
-
},
|
|
20
|
-
Account{
|
|
21
|
-
.id = 2,
|
|
22
|
-
.user_data = 0,
|
|
23
|
-
.reserved = [_]u8{0} ** 48,
|
|
24
|
-
.ledger = 710, // Let's use the ISO-4217 Code Number for ZAR
|
|
25
|
-
.code = 2000, // A chart of accounts code to describe this as a payable account.
|
|
26
|
-
.flags = .{},
|
|
27
|
-
.debits_pending = 0,
|
|
28
|
-
.debits_posted = 0,
|
|
29
|
-
.credits_pending = 0,
|
|
30
|
-
.credits_posted = 0,
|
|
31
|
-
},
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
try demo.request(.create_accounts, accounts, demo.on_create_accounts);
|
|
35
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
const tb = @import("tigerbeetle.zig");
|
|
2
|
-
const demo = @import("demo.zig");
|
|
3
|
-
|
|
4
|
-
const Transfer = tb.Transfer;
|
|
5
|
-
|
|
6
|
-
pub fn main() !void {
|
|
7
|
-
const transfers = [_]Transfer{
|
|
8
|
-
Transfer{
|
|
9
|
-
.id = 1,
|
|
10
|
-
.debit_account_id = 1,
|
|
11
|
-
.credit_account_id = 2,
|
|
12
|
-
.user_data = 0,
|
|
13
|
-
.reserved = 0,
|
|
14
|
-
.pending_id = 0,
|
|
15
|
-
.timeout = 0,
|
|
16
|
-
.ledger = 710, // Let's use the ISO-4217 Code Number for ZAR
|
|
17
|
-
.code = 1,
|
|
18
|
-
.flags = .{},
|
|
19
|
-
.amount = 1000,
|
|
20
|
-
},
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
try demo.request(.create_transfers, transfers, demo.on_create_transfers);
|
|
24
|
-
}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
const std = @import("std");
|
|
2
|
-
|
|
3
|
-
const tb = @import("tigerbeetle.zig");
|
|
4
|
-
const demo = @import("demo.zig");
|
|
5
|
-
|
|
6
|
-
const Transfer = tb.Transfer;
|
|
7
|
-
|
|
8
|
-
pub fn main() !void {
|
|
9
|
-
const transfers = [_]Transfer{
|
|
10
|
-
Transfer{
|
|
11
|
-
.id = 1001,
|
|
12
|
-
.debit_account_id = 1,
|
|
13
|
-
.credit_account_id = 2,
|
|
14
|
-
.user_data = 0,
|
|
15
|
-
.reserved = 0,
|
|
16
|
-
.pending_id = 0,
|
|
17
|
-
.timeout = std.time.ns_per_hour,
|
|
18
|
-
.ledger = 710,
|
|
19
|
-
.code = 1,
|
|
20
|
-
.flags = .{
|
|
21
|
-
.pending = true, // Set this transfer to be two-phase.
|
|
22
|
-
},
|
|
23
|
-
.amount = 8000,
|
|
24
|
-
},
|
|
25
|
-
Transfer{
|
|
26
|
-
.id = 1002,
|
|
27
|
-
.debit_account_id = 1,
|
|
28
|
-
.credit_account_id = 2,
|
|
29
|
-
.user_data = 0,
|
|
30
|
-
.reserved = 0,
|
|
31
|
-
.pending_id = 0,
|
|
32
|
-
.timeout = std.time.ns_per_hour,
|
|
33
|
-
.ledger = 710,
|
|
34
|
-
.code = 1,
|
|
35
|
-
.flags = .{
|
|
36
|
-
.pending = true, // Set this transfer to be two-phase.
|
|
37
|
-
.linked = true, // Link this transfer with the next transfer 1003.
|
|
38
|
-
},
|
|
39
|
-
.amount = 500,
|
|
40
|
-
},
|
|
41
|
-
Transfer{
|
|
42
|
-
.id = 1003,
|
|
43
|
-
.debit_account_id = 1,
|
|
44
|
-
.credit_account_id = 2,
|
|
45
|
-
.user_data = 0,
|
|
46
|
-
.reserved = 0,
|
|
47
|
-
.pending_id = 0,
|
|
48
|
-
.timeout = std.time.ns_per_hour,
|
|
49
|
-
.ledger = 710,
|
|
50
|
-
.code = 1,
|
|
51
|
-
.flags = .{
|
|
52
|
-
.pending = true, // Set this transfer to be two-phase.
|
|
53
|
-
// The last transfer in a linked chain has .linked set to false to close the chain.
|
|
54
|
-
// This transfer will succeed or fail together with transfer 1002 above.
|
|
55
|
-
},
|
|
56
|
-
.amount = 500,
|
|
57
|
-
},
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
try demo.request(.create_transfers, transfers, demo.on_create_transfers);
|
|
61
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
const tb = @import("tigerbeetle.zig");
|
|
2
|
-
const demo = @import("demo.zig");
|
|
3
|
-
|
|
4
|
-
const Transfer = tb.Transfer;
|
|
5
|
-
|
|
6
|
-
pub fn main() !void {
|
|
7
|
-
const commits = [_]Transfer{
|
|
8
|
-
Transfer{
|
|
9
|
-
.id = 2001,
|
|
10
|
-
.debit_account_id = 1,
|
|
11
|
-
.credit_account_id = 2,
|
|
12
|
-
.user_data = 0,
|
|
13
|
-
.reserved = 0,
|
|
14
|
-
.pending_id = 1001,
|
|
15
|
-
.timeout = 0,
|
|
16
|
-
.ledger = 0,// Honor original Transfer ledger.
|
|
17
|
-
.code = 0,// Honor original Transfer code.
|
|
18
|
-
.flags = .{ .post_pending_transfer = true }, // Post the pending two-phase transfer.
|
|
19
|
-
.amount = 0, // Inherit the amount from the pending transfer.
|
|
20
|
-
},
|
|
21
|
-
Transfer{
|
|
22
|
-
.id = 2002,
|
|
23
|
-
.debit_account_id = 1,
|
|
24
|
-
.credit_account_id = 2,
|
|
25
|
-
.user_data = 0,
|
|
26
|
-
.reserved = 0,
|
|
27
|
-
.pending_id = 1002,
|
|
28
|
-
.timeout = 0,
|
|
29
|
-
.ledger = 0,
|
|
30
|
-
.code = 0,
|
|
31
|
-
.flags = .{ .post_pending_transfer = true }, // Post the pending two-phase transfer.
|
|
32
|
-
.amount = 0, // Inherit the amount from the pending transfer.
|
|
33
|
-
},
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
try demo.request(.create_transfers, commits, demo.on_create_transfers);
|
|
37
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
const tb = @import("tigerbeetle.zig");
|
|
2
|
-
const demo = @import("demo.zig");
|
|
3
|
-
|
|
4
|
-
const Transfer = tb.Transfer;
|
|
5
|
-
|
|
6
|
-
pub fn main() !void {
|
|
7
|
-
const commits = [_]Transfer{
|
|
8
|
-
Transfer{
|
|
9
|
-
.id = 2003,
|
|
10
|
-
.debit_account_id = 1,
|
|
11
|
-
.credit_account_id = 2,
|
|
12
|
-
.user_data = 0,
|
|
13
|
-
.reserved = 0,
|
|
14
|
-
.pending_id = 1003,
|
|
15
|
-
.timeout = 0,
|
|
16
|
-
.ledger = 0,
|
|
17
|
-
.code = 0,
|
|
18
|
-
.flags = .{ .void_pending_transfer = true },
|
|
19
|
-
.amount = 0,
|
|
20
|
-
},
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
try demo.request(.create_transfers, commits, demo.on_create_transfers);
|
|
24
|
-
}
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
const std = @import("std");
|
|
2
|
-
const assert = std.debug.assert;
|
|
3
|
-
|
|
4
|
-
/// An intrusive first in/first out linked list.
|
|
5
|
-
/// The element type T must have a field called "next" of type ?*T
|
|
6
|
-
pub fn FIFO(comptime T: type) type {
|
|
7
|
-
return struct {
|
|
8
|
-
const Self = @This();
|
|
9
|
-
|
|
10
|
-
in: ?*T = null,
|
|
11
|
-
out: ?*T = null,
|
|
12
|
-
|
|
13
|
-
pub fn push(self: *Self, elem: *T) void {
|
|
14
|
-
assert(elem.next == null);
|
|
15
|
-
if (self.in) |in| {
|
|
16
|
-
in.next = elem;
|
|
17
|
-
self.in = elem;
|
|
18
|
-
} else {
|
|
19
|
-
assert(self.out == null);
|
|
20
|
-
self.in = elem;
|
|
21
|
-
self.out = elem;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
pub fn pop(self: *Self) ?*T {
|
|
26
|
-
const ret = self.out orelse return null;
|
|
27
|
-
self.out = ret.next;
|
|
28
|
-
ret.next = null;
|
|
29
|
-
if (self.in == ret) self.in = null;
|
|
30
|
-
return ret;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
pub fn peek(self: Self) ?*T {
|
|
34
|
-
return self.out;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/// Remove an element from the FIFO. Asserts that the element is
|
|
38
|
-
/// in the FIFO. This operation is O(N), if this is done often you
|
|
39
|
-
/// probably want a different data structure.
|
|
40
|
-
pub fn remove(self: *Self, to_remove: *T) void {
|
|
41
|
-
if (to_remove == self.out) {
|
|
42
|
-
_ = self.pop();
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
var it = self.out;
|
|
46
|
-
while (it) |elem| : (it = elem.next) {
|
|
47
|
-
if (to_remove == elem.next) {
|
|
48
|
-
if (to_remove == self.in) self.in = elem;
|
|
49
|
-
elem.next = to_remove.next;
|
|
50
|
-
to_remove.next = null;
|
|
51
|
-
break;
|
|
52
|
-
}
|
|
53
|
-
} else unreachable;
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
test "push/pop/peek/remove" {
|
|
59
|
-
const testing = @import("std").testing;
|
|
60
|
-
|
|
61
|
-
const Foo = struct { next: ?*@This() = null };
|
|
62
|
-
|
|
63
|
-
var one: Foo = .{};
|
|
64
|
-
var two: Foo = .{};
|
|
65
|
-
var three: Foo = .{};
|
|
66
|
-
|
|
67
|
-
var fifo: FIFO(Foo) = .{};
|
|
68
|
-
|
|
69
|
-
fifo.push(&one);
|
|
70
|
-
try testing.expectEqual(@as(?*Foo, &one), fifo.peek());
|
|
71
|
-
|
|
72
|
-
fifo.push(&two);
|
|
73
|
-
fifo.push(&three);
|
|
74
|
-
try testing.expectEqual(@as(?*Foo, &one), fifo.peek());
|
|
75
|
-
|
|
76
|
-
fifo.remove(&one);
|
|
77
|
-
try testing.expectEqual(@as(?*Foo, &two), fifo.pop());
|
|
78
|
-
try testing.expectEqual(@as(?*Foo, &three), fifo.pop());
|
|
79
|
-
try testing.expectEqual(@as(?*Foo, null), fifo.pop());
|
|
80
|
-
|
|
81
|
-
fifo.push(&one);
|
|
82
|
-
fifo.push(&two);
|
|
83
|
-
fifo.push(&three);
|
|
84
|
-
fifo.remove(&two);
|
|
85
|
-
try testing.expectEqual(@as(?*Foo, &one), fifo.pop());
|
|
86
|
-
try testing.expectEqual(@as(?*Foo, &three), fifo.pop());
|
|
87
|
-
try testing.expectEqual(@as(?*Foo, null), fifo.pop());
|
|
88
|
-
|
|
89
|
-
fifo.push(&one);
|
|
90
|
-
fifo.push(&two);
|
|
91
|
-
fifo.push(&three);
|
|
92
|
-
fifo.remove(&three);
|
|
93
|
-
try testing.expectEqual(@as(?*Foo, &one), fifo.pop());
|
|
94
|
-
try testing.expectEqual(@as(?*Foo, &two), fifo.pop());
|
|
95
|
-
try testing.expectEqual(@as(?*Foo, null), fifo.pop());
|
|
96
|
-
|
|
97
|
-
fifo.push(&one);
|
|
98
|
-
fifo.push(&two);
|
|
99
|
-
fifo.remove(&two);
|
|
100
|
-
fifo.push(&three);
|
|
101
|
-
try testing.expectEqual(@as(?*Foo, &one), fifo.pop());
|
|
102
|
-
try testing.expectEqual(@as(?*Foo, &three), fifo.pop());
|
|
103
|
-
try testing.expectEqual(@as(?*Foo, null), fifo.pop());
|
|
104
|
-
}
|