tigerbeetle-node 0.5.1 → 0.8.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 (56) hide show
  1. package/README.md +88 -69
  2. package/dist/benchmark.js +96 -94
  3. package/dist/benchmark.js.map +1 -1
  4. package/dist/index.d.ts +82 -82
  5. package/dist/index.js +74 -93
  6. package/dist/index.js.map +1 -1
  7. package/dist/test.js +134 -111
  8. package/dist/test.js.map +1 -1
  9. package/package.json +3 -2
  10. package/src/benchmark.ts +114 -118
  11. package/src/index.ts +102 -111
  12. package/src/node.zig +54 -62
  13. package/src/test.ts +146 -125
  14. package/src/tigerbeetle/scripts/benchmark.bat +46 -0
  15. package/src/tigerbeetle/scripts/benchmark.sh +5 -0
  16. package/src/tigerbeetle/scripts/install_zig.bat +2 -2
  17. package/src/tigerbeetle/scripts/install_zig.sh +3 -3
  18. package/src/tigerbeetle/scripts/vopr.sh +2 -2
  19. package/src/tigerbeetle/src/benchmark.zig +65 -102
  20. package/src/tigerbeetle/src/cli.zig +39 -18
  21. package/src/tigerbeetle/src/config.zig +27 -12
  22. package/src/tigerbeetle/src/demo.zig +1 -14
  23. package/src/tigerbeetle/src/demo_01_create_accounts.zig +10 -10
  24. package/src/tigerbeetle/src/demo_03_create_transfers.zig +3 -1
  25. package/src/tigerbeetle/src/{demo_04_create_transfers_two_phase_commit.zig → demo_04_create_pending_transfers.zig} +12 -6
  26. package/src/tigerbeetle/src/demo_05_post_pending_transfers.zig +37 -0
  27. package/src/tigerbeetle/src/demo_06_void_pending_transfers.zig +24 -0
  28. package/src/tigerbeetle/src/demo_07_lookup_transfers.zig +1 -1
  29. package/src/tigerbeetle/src/io/benchmark.zig +24 -49
  30. package/src/tigerbeetle/src/io/darwin.zig +175 -44
  31. package/src/tigerbeetle/src/io/linux.zig +177 -72
  32. package/src/tigerbeetle/src/io/test.zig +61 -39
  33. package/src/tigerbeetle/src/io/windows.zig +1161 -0
  34. package/src/tigerbeetle/src/io.zig +2 -0
  35. package/src/tigerbeetle/src/main.zig +14 -9
  36. package/src/tigerbeetle/src/message_bus.zig +56 -74
  37. package/src/tigerbeetle/src/message_pool.zig +63 -57
  38. package/src/tigerbeetle/src/ring_buffer.zig +7 -0
  39. package/src/tigerbeetle/src/simulator.zig +4 -4
  40. package/src/tigerbeetle/src/state_machine.zig +1804 -797
  41. package/src/tigerbeetle/src/storage.zig +0 -230
  42. package/src/tigerbeetle/src/test/cluster.zig +3 -6
  43. package/src/tigerbeetle/src/test/message_bus.zig +4 -3
  44. package/src/tigerbeetle/src/test/network.zig +13 -16
  45. package/src/tigerbeetle/src/test/state_checker.zig +3 -2
  46. package/src/tigerbeetle/src/tigerbeetle.zig +108 -101
  47. package/src/tigerbeetle/src/time.zig +58 -11
  48. package/src/tigerbeetle/src/vsr/client.zig +18 -32
  49. package/src/tigerbeetle/src/vsr/clock.zig +1 -1
  50. package/src/tigerbeetle/src/vsr/journal.zig +2 -6
  51. package/src/tigerbeetle/src/vsr/replica.zig +152 -175
  52. package/src/tigerbeetle/src/vsr.zig +263 -5
  53. package/src/translate.zig +10 -0
  54. package/src/tigerbeetle/src/demo_05_accept_transfers.zig +0 -23
  55. package/src/tigerbeetle/src/demo_06_reject_transfers.zig +0 -17
  56. package/src/tigerbeetle/src/format_test.zig +0 -69
package/src/benchmark.ts CHANGED
@@ -1,44 +1,40 @@
1
1
  import assert from 'assert'
2
2
  import {
3
- Commit,
4
3
  Account,
5
4
  createClient,
6
5
  Transfer,
7
6
  TransferFlags,
8
7
  CreateTransfersError,
9
- CommitTransfersError,
10
8
  Operation
11
9
  } from '.'
12
10
 
13
- const MAX_TRANSFERS = 1000000
14
- const MAX_REQUEST_BATCH_SIZE = 10000
15
- const IS_TWO_PHASE_COMMIT = false
11
+ const MAX_TRANSFERS = 51200
12
+ const MAX_REQUEST_BATCH_SIZE = 5120
13
+ const IS_TWO_PHASE_TRANSFER = false
16
14
  const IS_RAW_REQUEST = false
17
- const PREVIOUS_RAW_REQUEST_RESULT = IS_TWO_PHASE_COMMIT ? 300000 : 620000
18
- const PREVIOUS_RESULT = IS_TWO_PHASE_COMMIT ? 150000 : 310000
15
+ const PREVIOUS_RAW_REQUEST_RESULT = IS_TWO_PHASE_TRANSFER ? 300000 : 620000
16
+ const PREVIOUS_RESULT = IS_TWO_PHASE_TRANSFER ? 150000 : 310000
19
17
  const PREVIOUS_BENCHMARK = IS_RAW_REQUEST ? PREVIOUS_RAW_REQUEST_RESULT : PREVIOUS_RESULT
20
18
  const TOLERANCE = 10 // percent that the benchmark is allowed to deviate from the previous benchmark
21
19
 
22
20
  const client = createClient({
23
- cluster_id: 1,
21
+ cluster_id: 0,
24
22
  replica_addresses: ['3001']
25
23
  })
26
24
 
27
25
  const TRANSFER_SIZE = 128
28
- const COMMIT_SIZE = 64
29
26
  const Zeroed48Bytes = Buffer.alloc(48, 0)
30
- const Zeroed32Bytes = Buffer.alloc(32, 0)
31
27
  const accountA: Account = {
32
28
  id: 137n,
33
29
  user_data: 0n,
34
30
  reserved: Zeroed48Bytes,
35
- code: 0,
31
+ ledger: 1,
32
+ code: 1,
36
33
  flags: 0,
37
- unit: 1,
38
- debits_accepted: 0n,
39
- debits_reserved: 0n,
40
- credits_accepted: 0n,
41
- credits_reserved: 0n,
34
+ debits_pending: 0n,
35
+ debits_posted: 0n,
36
+ credits_pending: 0n,
37
+ credits_posted: 0n,
42
38
  timestamp: 0n,
43
39
  }
44
40
 
@@ -46,17 +42,17 @@ const accountB: Account = {
46
42
  id: 138n,
47
43
  user_data: 0n,
48
44
  reserved: Zeroed48Bytes,
49
- code: 0,
45
+ ledger: 1,
46
+ code: 1,
50
47
  flags: 0,
51
- unit: 1,
52
- debits_accepted: 0n,
53
- debits_reserved: 0n,
54
- credits_accepted: 0n,
55
- credits_reserved: 0n,
48
+ debits_pending: 0n,
49
+ debits_posted: 0n,
50
+ credits_pending: 0n,
51
+ credits_posted: 0n,
56
52
  timestamp: 0n,
57
53
  }
58
54
 
59
- // helper function to promisify the raw_request
55
+ // Helper function to promisify the raw_request:
60
56
  const rawCreateTransfers = async (batch: Buffer): Promise<CreateTransfersError[]> => {
61
57
  return new Promise((resolve, reject) => {
62
58
  const callback = (error: undefined | Error, results: CreateTransfersError[]) => {
@@ -74,71 +70,52 @@ const rawCreateTransfers = async (batch: Buffer): Promise<CreateTransfersError[]
74
70
  })
75
71
  }
76
72
 
77
- // helper function to promisify the raw_request
78
- const rawCommitTransfers = async (batch: Buffer): Promise<CommitTransfersError[]> => {
79
- return new Promise((resolve, reject) => {
80
- const callback = (error: undefined | Error, results: CommitTransfersError[]) => {
81
- if (error) {
82
- reject(error)
83
- }
84
- resolve(results)
85
- }
86
-
87
- try {
88
- client.rawRequest(Operation.COMMIT_TRANSFER, batch, callback)
89
- } catch (error) {
90
- reject(error)
91
- }
92
- })
93
- }
94
-
95
73
  /**
96
74
  * This encoding function is only for this benchmark script.
97
75
  *
98
- * ID_OFFSET = 0
99
- * DEBIT_ACCOUNT_ID_OFFSET = 0 + 16 = 16
100
- * CREDIT_ACCOUNT_ID_OFFSET = 16 + 16 = 32
101
- * USER_DATA_OFFSET = 32 + 16 = 48
102
- * RESERVED_OFFSET = 48 + 16 = 64
103
- * TIMEOUT_OFFSET = 64 + 32 = 96
104
- * CODE_OFFSET = 96 + 8 = 104
105
- * FLAGS_OFFSET = 104 + 4 = 108
106
- * AMOUNT_OFFSET = 108 + 4 = 112
107
- * TIMESTAMP_OFFSET = 112 + 8 = 120
76
+ * ID_OFFSET = 0 (0 -> 16)
77
+ * DEBIT_ACCOUNT_ID_OFFSET = 0 + 16 = 16 (16 -> 32)
78
+ * CREDIT_ACCOUNT_ID_OFFSET = 16 + 16 = 32 (32 -> 48)
79
+ * USER_DATA_OFFSET = 32 + 16 = 48 (48 -> 64)
80
+ * RESERVED_OFFSET = 48 + 16 = 64 (64 -> 80)
81
+ * PENDING_ID_OFFSET = 64 + 16 = 80 (80 -> 96)
82
+ * TIMEOUT_OFFSET = 96 + 8 = 104 (96 -> 104)
83
+ * LEDGER_OFFSET = 104 + 4 = 108 (104 -> 108)
84
+ * CODE_OFFSET = 108 + 2 = 110 (108 -> 110)
85
+ * FLAGS_OFFSET = 110 + 2 = 112 (110 -> 112)
86
+ * AMOUNT_OFFSET = 112 + 8 = 120 (112 -> 120)
87
+ * TIMESTAMP = 120 + 8 = 128 (120 -> 128)
108
88
  */
109
89
  const encodeTransfer = (transfer: Transfer, offset: number, output: Buffer): void => {
110
- assert(offset + TRANSFER_SIZE <= output.length)
111
-
112
- output.writeBigUInt64LE(transfer.id, offset)
113
- output.writeBigUInt64LE(transfer.debit_account_id, offset + 16)
114
- output.writeBigUInt64LE(transfer.credit_account_id, offset + 32)
115
- output.writeBigUInt64LE(transfer.timeout, offset + 96)
116
- output.writeUInt32LE(transfer.code, offset + 104)
117
- output.writeUInt32LE(transfer.flags, offset + 108)
118
- output.writeBigUInt64LE(transfer.amount, offset + 112)
119
- output.writeBigUInt64LE(transfer.timestamp, offset + 120)
120
- }
121
-
122
- // This encoding function is only for this benchmark script.
123
- const encodeCommit = (commit: Commit, offset: number, output: Buffer): void => {
124
- assert(offset + COMMIT_SIZE <= output.length)
125
-
126
- output.writeBigUInt64LE(commit.id, offset)
90
+ assert(BigInt((offset + TRANSFER_SIZE)) <= BigInt(output.length), `Transfer ${transfer} exceeds buffer of ${output}!`)
91
+
92
+ output.writeBigUInt64LE(transfer.id, offset)
93
+ output.writeBigUInt64LE(transfer.debit_account_id, offset + 16)
94
+ output.writeBigUInt64LE(transfer.credit_account_id, offset + 32)
95
+ output.writeBigUInt64LE(transfer.user_data, offset + 48)
96
+ output.writeBigUInt64LE(transfer.reserved, offset + 64)
97
+ output.writeBigUInt64LE(transfer.pending_id, offset + 80)
98
+ output.writeBigUInt64LE(transfer.timeout, offset + 96)
99
+ output.writeUInt32LE(transfer.ledger, offset + 104)
100
+ output.writeUInt32LE(transfer.code, offset + 108)
101
+ output.writeUInt32LE(transfer.flags, offset + 110)
102
+ output.writeBigUInt64LE(transfer.amount, offset + 112)
103
+ output.writeBigUInt64LE(transfer.timestamp, offset + 120)
127
104
  }
128
105
 
129
- const runBenchmarkRawReqeust = async () => {
106
+ const runBenchmarkRawRequest = async () => {
130
107
  assert(
131
108
  MAX_TRANSFERS % MAX_REQUEST_BATCH_SIZE === 0,
132
109
  "The raw request benchmark requires MAX_TRANSFERS to be a multiple of MAX_REQUEST_BATCH_SIZE"
133
110
  )
134
- console.log(`pre-allocating ${MAX_TRANSFERS} transfers and commits...`)
111
+ console.log(`pre-allocating ${MAX_TRANSFERS} transfers and posts...`)
135
112
  const transfers: Buffer[] = []
136
- const commits: Buffer[] = []
113
+ const posts: Buffer[] = []
137
114
 
138
115
  let count = 0
139
116
  while (count < MAX_TRANSFERS) {
140
117
  const transferBatch = Buffer.alloc(MAX_REQUEST_BATCH_SIZE * TRANSFER_SIZE, 0)
141
- const commitBatch = Buffer.alloc(MAX_REQUEST_BATCH_SIZE * COMMIT_SIZE, 0)
118
+ const postTransferBatch = Buffer.alloc(MAX_REQUEST_BATCH_SIZE * TRANSFER_SIZE, 0)
142
119
  for (let i = 0; i < MAX_REQUEST_BATCH_SIZE; i++) {
143
120
  if (count === MAX_TRANSFERS) break
144
121
 
@@ -148,35 +125,45 @@ const runBenchmarkRawReqeust = async () => {
148
125
  id: BigInt(count),
149
126
  debit_account_id: accountA.id,
150
127
  credit_account_id: accountB.id,
151
- code: 0,
152
- reserved: Zeroed32Bytes,
153
128
  user_data: 0n,
154
- flags: IS_TWO_PHASE_COMMIT ? TransferFlags.two_phase_commit : 0,
129
+ reserved: 0n,
130
+ pending_id: 0n,
131
+ timeout: IS_TWO_PHASE_TRANSFER ? BigInt(2e9) : 0n,
132
+ ledger: 1,
133
+ code: 1,
134
+ flags: IS_TWO_PHASE_TRANSFER ? TransferFlags.pending : 0,
155
135
  amount: 1n,
156
- timeout: IS_TWO_PHASE_COMMIT ? BigInt(2e9) : 0n,
157
136
  timestamp: 0n,
158
137
  },
159
138
  i * TRANSFER_SIZE,
160
139
  transferBatch
161
140
  )
162
141
 
163
- if (IS_TWO_PHASE_COMMIT) {
164
- encodeCommit(
142
+ if (IS_TWO_PHASE_TRANSFER) {
143
+ encodeTransfer(
165
144
  {
166
- id: BigInt(count),
167
- reserved: Buffer.alloc(32, 0),
168
- code: 0,
169
- flags: 0,
145
+ id: BigInt((MAX_TRANSFERS + count)),
146
+ debit_account_id: accountA.id,
147
+ credit_account_id: accountB.id,
148
+ user_data: 0n,
149
+ reserved: 0n,
150
+ pending_id: BigInt(count),
151
+ timeout: 0n,
152
+ ledger: 1,
153
+ code: 1,
154
+ flags: TransferFlags.post_pending_transfer,
155
+ amount: 1n,
170
156
  timestamp: 0n,
171
157
  },
172
- i * COMMIT_SIZE,
173
- commitBatch
158
+ i * TRANSFER_SIZE,
159
+ postTransferBatch
174
160
  )
175
161
  }
176
162
  }
177
163
 
178
164
  transfers.push(transferBatch)
179
- if (IS_TWO_PHASE_COMMIT) commits.push(commitBatch)
165
+ if (IS_TWO_PHASE_TRANSFER) posts.push(postTransferBatch)
166
+ if (count % 100) console.log(`${Number((count / MAX_TRANSFERS) * 100).toFixed(1)}%`)
180
167
  }
181
168
  assert(count === MAX_TRANSFERS)
182
169
 
@@ -188,8 +175,8 @@ const runBenchmarkRawReqeust = async () => {
188
175
  for (let i = 0; i < transfers.length; i++) {
189
176
  const ms1 = Date.now()
190
177
 
191
- const transferResults = await rawCreateTransfers(transfers[i])
192
- assert(transferResults.length === 0)
178
+ const transferErrors = await rawCreateTransfers(transfers[i])
179
+ assert(transferErrors.length === 0)
193
180
 
194
181
  const ms2 = Date.now()
195
182
  const createTransferLatency = ms2 - ms1
@@ -197,9 +184,9 @@ const runBenchmarkRawReqeust = async () => {
197
184
  maxCreateTransfersLatency = createTransferLatency
198
185
  }
199
186
 
200
- if (IS_TWO_PHASE_COMMIT) {
201
- const commitResults = await rawCommitTransfers(commits[i])
202
- assert(commitResults.length === 0)
187
+ if (IS_TWO_PHASE_TRANSFER) {
188
+ const commitErrors = await rawCreateTransfers(posts[i])
189
+ assert(commitErrors.length === 0)
203
190
 
204
191
  const ms3 = Date.now()
205
192
  const commitTransferLatency = ms3 - ms2
@@ -219,44 +206,53 @@ const runBenchmarkRawReqeust = async () => {
219
206
  }
220
207
 
221
208
  const runBenchmark = async () => {
222
- console.log(`pre-allocating ${MAX_TRANSFERS} transfers and commits...`)
209
+ console.log(`pre-allocating ${MAX_TRANSFERS} transfers and posts...`)
223
210
  const transfers: Transfer[][] = []
224
- const commits: Commit[][] = []
211
+ const posts: Transfer[][] = []
225
212
 
226
213
  let count = 0
227
214
  while (count < MAX_TRANSFERS) {
228
- const transferBatch: Transfer[] = []
229
- const commitBatch: Commit[] = []
215
+ const pendingBatch: Transfer[] = []
216
+ const postBatch: Transfer[] = []
230
217
  for (let i = 0; i < MAX_REQUEST_BATCH_SIZE; i++) {
231
218
  if (count === MAX_TRANSFERS) break
232
219
 
233
220
  count += 1
234
- transferBatch.push({
221
+ pendingBatch.push({
235
222
  id: BigInt(count),
236
223
  debit_account_id: accountA.id,
237
224
  credit_account_id: accountB.id,
238
- code: 0,
239
- reserved: Zeroed32Bytes,
225
+ pending_id: 0n,
226
+ code: 1,
227
+ ledger: 1,
228
+ reserved: 0n,
240
229
  user_data: 0n,
241
- flags: IS_TWO_PHASE_COMMIT ? TransferFlags.two_phase_commit : 0,
230
+ flags: IS_TWO_PHASE_TRANSFER ? TransferFlags.pending : 0,
242
231
  amount: 1n,
243
- timeout: IS_TWO_PHASE_COMMIT ? BigInt(2e9) : 0n,
232
+ timeout: IS_TWO_PHASE_TRANSFER ? BigInt(2e9) : 0n,
244
233
  timestamp: 0n,
245
234
  })
246
235
 
247
- if (IS_TWO_PHASE_COMMIT) {
248
- commitBatch.push({
249
- id: BigInt(count),
250
- reserved: Buffer.alloc(32, 0),
251
- code: 0,
252
- flags: 0,
236
+ if (IS_TWO_PHASE_TRANSFER) {
237
+ postBatch.push({
238
+ id: BigInt(MAX_TRANSFERS + count),
239
+ debit_account_id: accountA.id,
240
+ credit_account_id: accountB.id,
241
+ pending_id: BigInt(count),
242
+ code: 1,
243
+ ledger: 1,
244
+ reserved: 0n,
245
+ user_data: 0n,
246
+ flags: IS_TWO_PHASE_TRANSFER ? TransferFlags.post_pending_transfer : 0,
247
+ amount: 1n,
248
+ timeout: 0n,
253
249
  timestamp: 0n,
254
250
  })
255
251
  }
256
252
  }
257
253
 
258
- transfers.push(transferBatch)
259
- if (IS_TWO_PHASE_COMMIT) commits.push(commitBatch)
254
+ transfers.push(pendingBatch)
255
+ if (IS_TWO_PHASE_TRANSFER) posts.push(postBatch)
260
256
  }
261
257
  assert(count === MAX_TRANSFERS)
262
258
 
@@ -268,8 +264,8 @@ const runBenchmark = async () => {
268
264
  for (let i = 0; i < transfers.length; i++) {
269
265
  const ms1 = Date.now()
270
266
 
271
- const transferResults = await client.createTransfers(transfers[i])
272
- assert(transferResults.length === 0)
267
+ const transferErrors = await client.createTransfers(transfers[i])
268
+ assert(transferErrors.length === 0)
273
269
 
274
270
  const ms2 = Date.now()
275
271
  const createTransferLatency = ms2 - ms1
@@ -277,9 +273,9 @@ const runBenchmark = async () => {
277
273
  maxCreateTransfersLatency = createTransferLatency
278
274
  }
279
275
 
280
- if (IS_TWO_PHASE_COMMIT) {
281
- const commitResults = await client.commitTransfers(commits[i])
282
- assert(commitResults.length === 0)
276
+ if (IS_TWO_PHASE_TRANSFER) {
277
+ const commitErrors = await client.createTransfers(posts[i])
278
+ assert(commitErrors.length === 0)
283
279
 
284
280
  const ms3 = Date.now()
285
281
  const commitTransferLatency = ms3 - ms2
@@ -303,20 +299,20 @@ const main = async () => {
303
299
  await client.createAccounts([accountA, accountB])
304
300
  const accountResults = await client.lookupAccounts([accountA.id, accountB.id])
305
301
  assert(accountResults.length === 2)
306
- assert(accountResults[0].debits_accepted === 0n)
307
- assert(accountResults[1].debits_accepted === 0n)
302
+ assert(accountResults[0].debits_posted === 0n)
303
+ assert(accountResults[1].debits_posted === 0n)
308
304
 
309
- const benchmark = IS_RAW_REQUEST ? await runBenchmarkRawReqeust() : await runBenchmark()
305
+ const benchmark = IS_RAW_REQUEST ? await runBenchmarkRawRequest() : await runBenchmark()
310
306
 
311
307
  const accounts = await client.lookupAccounts([accountA.id, accountB.id])
312
308
  const result = Math.floor((1000 * MAX_TRANSFERS)/benchmark.ms)
313
309
  console.log("=============================")
314
- console.log(`${IS_TWO_PHASE_COMMIT ? 'two-phase ' : ''}transfers per second: ${result}`)
310
+ console.log(`${IS_TWO_PHASE_TRANSFER ? 'two-phase ' : ''}transfers per second: ${result}`)
315
311
  console.log(`create transfers max p100 latency per 10 000 transfers = ${benchmark.maxCreateTransfersLatency}ms`)
316
312
  console.log(`commit transfers max p100 latency per 10 000 transfers = ${benchmark.maxCommitTransfersLatency}ms`)
317
313
  assert(accounts.length === 2)
318
- assert(accounts[0].debits_accepted === BigInt(MAX_TRANSFERS))
319
- assert(accounts[1].credits_accepted === BigInt(MAX_TRANSFERS))
314
+ assert(accounts[0].debits_posted === BigInt(MAX_TRANSFERS))
315
+ assert(accounts[1].credits_posted === BigInt(MAX_TRANSFERS))
320
316
 
321
317
  if (result < PREVIOUS_BENCHMARK * (100 - TOLERANCE)/100) {
322
318
  console.warn(`There has been a performance regression. Previous benchmark=${PREVIOUS_BENCHMARK}`)