tigerbeetle-node 0.8.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.
Files changed (99) hide show
  1. package/README.md +47 -47
  2. package/dist/benchmark.js +15 -15
  3. package/dist/benchmark.js.map +1 -1
  4. package/dist/index.d.ts +66 -61
  5. package/dist/index.js +66 -61
  6. package/dist/index.js.map +1 -1
  7. package/dist/test.js +1 -1
  8. package/dist/test.js.map +1 -1
  9. package/package.json +14 -16
  10. package/scripts/download_node_headers.sh +3 -1
  11. package/src/index.ts +5 -0
  12. package/src/node.zig +18 -19
  13. package/src/tigerbeetle/scripts/benchmark.bat +47 -46
  14. package/src/tigerbeetle/scripts/benchmark.sh +25 -10
  15. package/src/tigerbeetle/scripts/install.sh +2 -1
  16. package/src/tigerbeetle/scripts/install_zig.bat +109 -109
  17. package/src/tigerbeetle/scripts/install_zig.sh +18 -18
  18. package/src/tigerbeetle/scripts/upgrade_ubuntu_kernel.sh +12 -3
  19. package/src/tigerbeetle/scripts/vopr.bat +47 -47
  20. package/src/tigerbeetle/scripts/vopr.sh +5 -5
  21. package/src/tigerbeetle/src/benchmark.zig +17 -9
  22. package/src/tigerbeetle/src/benchmark_array_search.zig +317 -0
  23. package/src/tigerbeetle/src/benchmarks/perf.zig +299 -0
  24. package/src/tigerbeetle/src/c/tb_client/context.zig +103 -0
  25. package/src/tigerbeetle/src/c/tb_client/packet.zig +80 -0
  26. package/src/tigerbeetle/src/c/tb_client/signal.zig +288 -0
  27. package/src/tigerbeetle/src/c/tb_client/thread.zig +329 -0
  28. package/src/tigerbeetle/src/c/tb_client.h +201 -0
  29. package/src/tigerbeetle/src/c/tb_client.zig +101 -0
  30. package/src/tigerbeetle/src/c/test.zig +1 -0
  31. package/src/tigerbeetle/src/cli.zig +142 -83
  32. package/src/tigerbeetle/src/config.zig +136 -23
  33. package/src/tigerbeetle/src/demo.zig +12 -8
  34. package/src/tigerbeetle/src/demo_03_create_transfers.zig +3 -3
  35. package/src/tigerbeetle/src/demo_04_create_pending_transfers.zig +10 -10
  36. package/src/tigerbeetle/src/demo_05_post_pending_transfers.zig +7 -7
  37. package/src/tigerbeetle/src/demo_06_void_pending_transfers.zig +3 -3
  38. package/src/tigerbeetle/src/demo_07_lookup_transfers.zig +1 -1
  39. package/src/tigerbeetle/src/ewah.zig +318 -0
  40. package/src/tigerbeetle/src/ewah_benchmark.zig +121 -0
  41. package/src/tigerbeetle/src/eytzinger_benchmark.zig +317 -0
  42. package/src/tigerbeetle/src/fifo.zig +17 -1
  43. package/src/tigerbeetle/src/io/darwin.zig +12 -10
  44. package/src/tigerbeetle/src/io/linux.zig +25 -9
  45. package/src/tigerbeetle/src/io/windows.zig +13 -9
  46. package/src/tigerbeetle/src/iops.zig +101 -0
  47. package/src/tigerbeetle/src/lsm/binary_search.zig +214 -0
  48. package/src/tigerbeetle/src/lsm/bloom_filter.zig +82 -0
  49. package/src/tigerbeetle/src/lsm/compaction.zig +603 -0
  50. package/src/tigerbeetle/src/lsm/composite_key.zig +75 -0
  51. package/src/tigerbeetle/src/lsm/direction.zig +11 -0
  52. package/src/tigerbeetle/src/lsm/eytzinger.zig +587 -0
  53. package/src/tigerbeetle/src/lsm/forest.zig +630 -0
  54. package/src/tigerbeetle/src/lsm/grid.zig +473 -0
  55. package/src/tigerbeetle/src/lsm/groove.zig +939 -0
  56. package/src/tigerbeetle/src/lsm/k_way_merge.zig +452 -0
  57. package/src/tigerbeetle/src/lsm/level_iterator.zig +296 -0
  58. package/src/tigerbeetle/src/lsm/manifest.zig +680 -0
  59. package/src/tigerbeetle/src/lsm/manifest_level.zig +1169 -0
  60. package/src/tigerbeetle/src/lsm/manifest_log.zig +904 -0
  61. package/src/tigerbeetle/src/lsm/node_pool.zig +231 -0
  62. package/src/tigerbeetle/src/lsm/posted_groove.zig +399 -0
  63. package/src/tigerbeetle/src/lsm/segmented_array.zig +998 -0
  64. package/src/tigerbeetle/src/lsm/set_associative_cache.zig +844 -0
  65. package/src/tigerbeetle/src/lsm/table.zig +932 -0
  66. package/src/tigerbeetle/src/lsm/table_immutable.zig +196 -0
  67. package/src/tigerbeetle/src/lsm/table_iterator.zig +295 -0
  68. package/src/tigerbeetle/src/lsm/table_mutable.zig +123 -0
  69. package/src/tigerbeetle/src/lsm/test.zig +429 -0
  70. package/src/tigerbeetle/src/lsm/tree.zig +1085 -0
  71. package/src/tigerbeetle/src/main.zig +121 -95
  72. package/src/tigerbeetle/src/message_bus.zig +49 -48
  73. package/src/tigerbeetle/src/message_pool.zig +19 -3
  74. package/src/tigerbeetle/src/ring_buffer.zig +172 -31
  75. package/src/tigerbeetle/src/simulator.zig +171 -43
  76. package/src/tigerbeetle/src/state_machine.zig +1026 -599
  77. package/src/tigerbeetle/src/storage.zig +46 -16
  78. package/src/tigerbeetle/src/test/cluster.zig +257 -78
  79. package/src/tigerbeetle/src/test/message_bus.zig +15 -24
  80. package/src/tigerbeetle/src/test/network.zig +26 -17
  81. package/src/tigerbeetle/src/test/packet_simulator.zig +14 -1
  82. package/src/tigerbeetle/src/test/state_checker.zig +10 -6
  83. package/src/tigerbeetle/src/test/state_machine.zig +159 -68
  84. package/src/tigerbeetle/src/test/storage.zig +137 -49
  85. package/src/tigerbeetle/src/tigerbeetle.zig +5 -0
  86. package/src/tigerbeetle/src/unit_tests.zig +8 -0
  87. package/src/tigerbeetle/src/util.zig +51 -0
  88. package/src/tigerbeetle/src/vsr/client.zig +21 -7
  89. package/src/tigerbeetle/src/vsr/journal.zig +1429 -514
  90. package/src/tigerbeetle/src/vsr/replica.zig +1855 -550
  91. package/src/tigerbeetle/src/vsr/superblock.zig +1743 -0
  92. package/src/tigerbeetle/src/vsr/superblock_client_table.zig +258 -0
  93. package/src/tigerbeetle/src/vsr/superblock_free_set.zig +644 -0
  94. package/src/tigerbeetle/src/vsr/superblock_manifest.zig +546 -0
  95. package/src/tigerbeetle/src/vsr.zig +134 -52
  96. package/.yarn/releases/yarn-berry.cjs +0 -55
  97. package/.yarnrc.yml +0 -1
  98. package/scripts/postinstall.sh +0 -6
  99. package/yarn.lock +0 -42
@@ -0,0 +1,258 @@
1
+ const std = @import("std");
2
+ const assert = std.debug.assert;
3
+ const mem = std.mem;
4
+
5
+ const config = @import("../config.zig");
6
+ const vsr = @import("../vsr.zig");
7
+
8
+ const MessagePool = @import("../message_pool.zig").MessagePool;
9
+
10
+ pub const ClientTable = struct {
11
+ /// We found two bugs in the VRR paper relating to the client table:
12
+ ///
13
+ /// 1. a correctness bug, where successive client crashes may cause request numbers to collide for
14
+ /// different request payloads, resulting in requests receiving the wrong reply, and
15
+ ///
16
+ /// 2. a liveness bug, where if the client table is updated for request and prepare messages with
17
+ /// the client's latest request number, then the client may be locked out from the cluster if the
18
+ /// request is ever reordered through a view change.
19
+ ///
20
+ /// We therefore take a different approach with the implementation of our client table, to:
21
+ ///
22
+ /// 1. register client sessions explicitly through the state machine to ensure that client session
23
+ /// numbers always increase, and
24
+ ///
25
+ /// 2. make a more careful distinction between uncommitted and committed request numbers,
26
+ /// considering that uncommitted requests may not survive a view change.
27
+ pub const Entry = struct {
28
+ /// The client's session number as committed to the cluster by a register request.
29
+ session: u64,
30
+
31
+ /// The reply sent to the client's latest committed request.
32
+ reply: *MessagePool.Message,
33
+ };
34
+
35
+ const Entries = std.AutoHashMapUnmanaged(u128, Entry);
36
+
37
+ entries: Entries,
38
+ sorted: []*const Entry,
39
+ message_pool: *MessagePool,
40
+
41
+ pub fn init(allocator: mem.Allocator, message_pool: *MessagePool) !ClientTable {
42
+ var entries: Entries = .{};
43
+ errdefer entries.deinit(allocator);
44
+
45
+ try entries.ensureTotalCapacity(allocator, @intCast(u32, config.clients_max));
46
+ assert(entries.capacity() >= config.clients_max);
47
+
48
+ const sorted = try allocator.alloc(*const Entry, entries.capacity());
49
+ errdefer allocator.free(sorted);
50
+
51
+ return ClientTable{
52
+ .entries = entries,
53
+ .sorted = sorted,
54
+ .message_pool = message_pool,
55
+ };
56
+ }
57
+
58
+ pub fn deinit(client_table: *ClientTable, allocator: mem.Allocator) void {
59
+ {
60
+ var it = client_table.iterator();
61
+ while (it.next()) |entry| {
62
+ client_table.message_pool.unref(entry.reply);
63
+ }
64
+ }
65
+
66
+ client_table.entries.deinit(allocator);
67
+ allocator.free(client_table.sorted);
68
+ }
69
+
70
+ fn sort_entries_less_than(context: void, a: *const Entry, b: *const Entry) bool {
71
+ _ = context;
72
+ assert(a.reply.header.client != b.reply.header.client);
73
+ return std.math.order(
74
+ a.reply.header.client,
75
+ b.reply.header.client,
76
+ ) == .lt;
77
+ }
78
+
79
+ /// Maximum size of the buffer needed to encode the client table on disk.
80
+ pub const encode_size_max = blk: {
81
+ var size_max: usize = 0;
82
+
83
+ // First goes the vsr headers for the entries.
84
+ // This takes advantage of the buffer alignment to avoid adding padding for the headers.
85
+ size_max = std.mem.alignForward(size_max, @alignOf(vsr.Header));
86
+ size_max += @sizeOf(vsr.Header) * config.clients_max;
87
+
88
+ // Then follows the session values for the entries.
89
+ size_max = std.mem.alignForward(size_max, @alignOf(u64));
90
+ size_max += @sizeOf(u64) * config.clients_max;
91
+
92
+ // Followed by the message bodies for the entries.
93
+ size_max = std.mem.alignForward(size_max, @alignOf(u8));
94
+ size_max += config.message_size_max * config.clients_max;
95
+
96
+ // Finally the entry count at the end
97
+ size_max = std.mem.alignForward(size_max, @alignOf(u32));
98
+ size_max += @sizeOf(u32);
99
+
100
+ break :blk size_max;
101
+ };
102
+
103
+ pub fn encode(client_table: *const ClientTable, target: []align(@alignOf(vsr.Header)) u8) u64 {
104
+ // The entries must be collected and sorted into a separate buffer first before iteration.
105
+ // This avoids relying on iteration order of AutoHashMapUnmanaged which may change between
106
+ // zig versions.
107
+ var entries_count: u32 = 0;
108
+ {
109
+ var it = client_table.entries.valueIterator();
110
+ while (it.next()) |entry| : (entries_count += 1) {
111
+ assert(entries_count < client_table.sorted.len);
112
+ assert(entry.reply.header.command == .reply);
113
+ client_table.sorted[entries_count] = entry;
114
+ entries_count += 1;
115
+ }
116
+ }
117
+
118
+ assert(entries_count <= client_table.sorted.len);
119
+ const entries = client_table.sorted[0..entries_count];
120
+ std.sort.sort(*const Entry, entries, {}, sort_entries_less_than);
121
+
122
+ var size: u64 = 0;
123
+ assert(target.len >= encode_size_max);
124
+
125
+ // Write all headers:
126
+ var new_size = std.mem.alignForward(size, @alignOf(vsr.Header));
127
+ std.mem.set(u8, target[size..new_size], 0);
128
+ size = new_size;
129
+
130
+ for (entries) |entry| {
131
+ mem.copy(u8, target[size..], mem.asBytes(entry.reply.header));
132
+ size += @sizeOf(vsr.Header);
133
+ }
134
+
135
+ // Write all sessions:
136
+ new_size = std.mem.alignForward(size, @alignOf(u64));
137
+ std.mem.set(u8, target[size..new_size], 0);
138
+ size = new_size;
139
+
140
+ for (entries) |entry| {
141
+ mem.copy(u8, target[size..], mem.asBytes(&entry.session));
142
+ size += @sizeOf(u64);
143
+ }
144
+
145
+ // Write all messages:
146
+ new_size = std.mem.alignForward(size, @alignOf(u8));
147
+ std.mem.set(u8, target[size..new_size], 0);
148
+ size = new_size;
149
+
150
+ for (entries) |entry| {
151
+ const body = entry.reply.body();
152
+ assert(body.len == (entry.reply.header.size - @sizeOf(vsr.Header)));
153
+ mem.copy(u8, target[size..], body);
154
+ size += body.len;
155
+ }
156
+
157
+ // Finally write the entry count:
158
+ new_size = std.mem.alignForward(size, @alignOf(u32));
159
+ std.mem.set(u8, target[size..new_size], 0);
160
+ size = new_size;
161
+
162
+ mem.copy(u8, target[size..], mem.asBytes(&entries_count));
163
+ size += @sizeOf(u32);
164
+
165
+ assert(size <= encode_size_max);
166
+ return size;
167
+ }
168
+
169
+ pub fn decode(client_table: *ClientTable, source: []align(@alignOf(vsr.Header)) const u8) void {
170
+ // Read the entry count at the end of the buffer to determine how many there are.
171
+ var entries_count: u32 = undefined;
172
+ mem.copy(u8, mem.asBytes(&entries_count), source[source.len - @sizeOf(u32) ..]);
173
+ assert(entries_count <= client_table.sorted.len);
174
+
175
+ assert(client_table.count() == 0);
176
+ defer assert(client_table.count() == entries_count);
177
+
178
+ // Skip decoding if there aren't any entries.
179
+ if (entries_count == 0) return;
180
+
181
+ var size: u64 = 0;
182
+ assert(source.len > 0);
183
+ assert(source.len <= encode_size_max);
184
+
185
+ size = std.mem.alignForward(size, @alignOf(vsr.Header));
186
+ const headers = mem.bytesAsSlice(
187
+ vsr.Header,
188
+ source[size .. entries_count * @sizeOf(vsr.Header)],
189
+ );
190
+ size += mem.sliceAsBytes(headers).len;
191
+
192
+ size = std.mem.alignForward(size, @alignOf(u64));
193
+ const sessions = mem.bytesAsSlice(u64, source[size .. entries_count * @sizeOf(u64)]);
194
+ size += mem.sliceAsBytes(sessions).len;
195
+
196
+ size = std.mem.alignForward(size, @alignOf(u8));
197
+ var bodies = source[size..];
198
+ assert(bodies.len > 0);
199
+
200
+ var i: u32 = 0;
201
+ while (i < entries_count) : (i += 1) {
202
+ // Prepare the entry with a message.
203
+ var entry: Entry = undefined;
204
+ entry.reply = client_table.message_pool.get_message();
205
+
206
+ // Read the header and session for the entry.
207
+ entry.session = sessions[i];
208
+ entry.reply.header.* = headers[i];
209
+ assert(entry.reply.header.valid_checksum());
210
+ assert(entry.reply.header.command == .reply);
211
+ assert(entry.reply.header.commit >= entry.session);
212
+
213
+ // Get the message body buffer for the entry.
214
+ const body_size = entry.reply.header.size - @sizeOf(vsr.Header);
215
+ const body = entry.reply.body()[0..body_size];
216
+
217
+ // Read the message body for the entry.
218
+ assert(bodies.len >= body_size);
219
+ mem.copy(u8, body, bodies[0..body_size]);
220
+ bodies = bodies[body_size..];
221
+ assert(entry.reply.header.valid_checksum_body(body));
222
+
223
+ // Insert into the client table
224
+ client_table.put(&entry);
225
+ }
226
+ }
227
+
228
+ pub fn count(client_table: *const ClientTable) usize {
229
+ return client_table.entries.count();
230
+ }
231
+
232
+ pub fn capacity(client_table: *const ClientTable) usize {
233
+ return client_table.entries.capacity();
234
+ }
235
+
236
+ pub fn get(client_table: *ClientTable, client: u128) ?*Entry {
237
+ return client_table.entries.getPtr(client);
238
+ }
239
+
240
+ pub fn put(client_table: *ClientTable, entry: *const Entry) void {
241
+ const client = entry.reply.header.client;
242
+ client_table.entries.putAssumeCapacityNoClobber(client, entry.*);
243
+
244
+ if (config.verify) assert(client_table.entries.contains(client));
245
+ }
246
+
247
+ pub fn remove(client_table: *ClientTable, client: u128) void {
248
+ assert(client_table.entries.remove(client));
249
+
250
+ if (config.verify) assert(!client_table.entries.contains(client));
251
+ }
252
+
253
+ pub const Iterator = Entries.ValueIterator;
254
+
255
+ pub fn iterator(client_table: *ClientTable) Iterator {
256
+ return client_table.entries.valueIterator();
257
+ }
258
+ };