tigerbeetle-node 0.5.2 → 0.8.1
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 +97 -78
- package/dist/benchmark.js +96 -94
- package/dist/benchmark.js.map +1 -1
- package/dist/index.d.ts +82 -82
- package/dist/index.js +74 -93
- package/dist/index.js.map +1 -1
- package/dist/test.js +134 -111
- package/dist/test.js.map +1 -1
- package/package.json +3 -2
- package/scripts/download_node_headers.sh +3 -1
- package/src/benchmark.ts +114 -118
- package/src/index.ts +102 -111
- package/src/node.zig +55 -63
- package/src/test.ts +146 -125
- package/src/tigerbeetle/scripts/benchmark.bat +46 -0
- package/src/tigerbeetle/scripts/benchmark.sh +5 -0
- package/src/tigerbeetle/scripts/install_zig.bat +109 -109
- package/src/tigerbeetle/scripts/install_zig.sh +8 -4
- package/src/tigerbeetle/scripts/vopr.bat +47 -47
- package/src/tigerbeetle/scripts/vopr.sh +2 -2
- package/src/tigerbeetle/src/benchmark.zig +65 -102
- package/src/tigerbeetle/src/cli.zig +39 -18
- package/src/tigerbeetle/src/config.zig +44 -25
- package/src/tigerbeetle/src/demo.zig +2 -15
- package/src/tigerbeetle/src/demo_01_create_accounts.zig +10 -10
- package/src/tigerbeetle/src/demo_03_create_transfers.zig +5 -3
- package/src/tigerbeetle/src/{demo_04_create_transfers_two_phase_commit.zig → demo_04_create_pending_transfers.zig} +18 -12
- package/src/tigerbeetle/src/demo_05_post_pending_transfers.zig +37 -0
- package/src/tigerbeetle/src/demo_06_void_pending_transfers.zig +24 -0
- package/src/tigerbeetle/src/demo_07_lookup_transfers.zig +1 -1
- package/src/tigerbeetle/src/io/benchmark.zig +24 -49
- package/src/tigerbeetle/src/io/darwin.zig +175 -44
- package/src/tigerbeetle/src/io/linux.zig +177 -72
- package/src/tigerbeetle/src/io/test.zig +61 -39
- package/src/tigerbeetle/src/io/windows.zig +1161 -0
- package/src/tigerbeetle/src/io.zig +2 -0
- package/src/tigerbeetle/src/main.zig +31 -10
- package/src/tigerbeetle/src/message_bus.zig +49 -61
- package/src/tigerbeetle/src/message_pool.zig +66 -57
- package/src/tigerbeetle/src/ring_buffer.zig +55 -3
- package/src/tigerbeetle/src/simulator.zig +108 -12
- package/src/tigerbeetle/src/state_machine.zig +1813 -816
- package/src/tigerbeetle/src/storage.zig +0 -230
- package/src/tigerbeetle/src/test/cluster.zig +168 -38
- package/src/tigerbeetle/src/test/message_bus.zig +4 -3
- package/src/tigerbeetle/src/test/network.zig +13 -16
- package/src/tigerbeetle/src/test/packet_simulator.zig +14 -1
- package/src/tigerbeetle/src/test/state_checker.zig +6 -3
- package/src/tigerbeetle/src/test/state_machine.zig +8 -7
- package/src/tigerbeetle/src/test/storage.zig +99 -40
- package/src/tigerbeetle/src/tigerbeetle.zig +108 -101
- package/src/tigerbeetle/src/time.zig +58 -11
- package/src/tigerbeetle/src/vsr/client.zig +18 -32
- package/src/tigerbeetle/src/vsr/clock.zig +1 -1
- package/src/tigerbeetle/src/vsr/journal.zig +1388 -464
- package/src/tigerbeetle/src/vsr/replica.zig +1340 -576
- package/src/tigerbeetle/src/vsr.zig +452 -40
- package/src/translate.zig +10 -0
- package/src/tigerbeetle/src/demo_05_accept_transfers.zig +0 -23
- package/src/tigerbeetle/src/demo_06_reject_transfers.zig +0 -17
- package/src/tigerbeetle/src/format_test.zig +0 -69
package/README.md
CHANGED
|
@@ -10,29 +10,16 @@ The following steps will install the `tigerbeetle-node` module to your current w
|
|
|
10
10
|
|
|
11
11
|
> Your operating system should be Linux (kernel >= v5.6) or macOS. Windows support is not yet available but is in the works.
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
### YARN Package Manager
|
|
16
|
-
|
|
17
|
-
```sh
|
|
13
|
+
### YARN Package Manager Installation
|
|
14
|
+
```shell
|
|
18
15
|
yarn add tigerbeetle-node
|
|
19
16
|
```
|
|
20
17
|
or
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
```sh
|
|
18
|
+
### NPM Package Manager Installation
|
|
19
|
+
```shell
|
|
24
20
|
npm install tigerbeetle-node
|
|
25
21
|
```
|
|
26
22
|
|
|
27
|
-
**Development**
|
|
28
|
-
|
|
29
|
-
Follow these steps to get up and running when cloning the repo:
|
|
30
|
-
|
|
31
|
-
```sh
|
|
32
|
-
git clone --recurse-submodules https://github.com/coilhq/tigerbeetle-node.git
|
|
33
|
-
yarn
|
|
34
|
-
```
|
|
35
|
-
|
|
36
23
|
## Usage
|
|
37
24
|
A client needs to be configured with a `cluster_id` and `replica_addresses`.
|
|
38
25
|
This instantiates the client where memory is allocated to internally buffer events to be sent.
|
|
@@ -42,7 +29,7 @@ Future releases will allow multiple client instantiations.
|
|
|
42
29
|
import { createClient } from 'tigerbeetle-node'
|
|
43
30
|
|
|
44
31
|
const client = createClient({
|
|
45
|
-
cluster_id:
|
|
32
|
+
cluster_id: 0,
|
|
46
33
|
replica_addresses: ['3001', '3002', '3003']
|
|
47
34
|
})
|
|
48
35
|
```
|
|
@@ -55,15 +42,15 @@ This is reflected in the below function interfaces where each one takes in an ar
|
|
|
55
42
|
```js
|
|
56
43
|
const account = {
|
|
57
44
|
id: 137n, // u128
|
|
58
|
-
user_data: 0n, // u128, opaque third-party identifier to link this account
|
|
45
|
+
user_data: 0n, // u128, opaque third-party identifier to link this account to an external entity:
|
|
59
46
|
reserved: Buffer.alloc(48, 0), // [48]u8
|
|
60
|
-
|
|
47
|
+
ledger: 1, // u32, ledger value
|
|
61
48
|
code: 718, // u16, a chart of accounts code describing the type of account (e.g. clearing, settlement)
|
|
62
|
-
flags: 0, //
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
49
|
+
flags: 0, // u16
|
|
50
|
+
debits_pending: 0n, // u64
|
|
51
|
+
debits_posted: 0n, // u64
|
|
52
|
+
credits_pending: 0n, // u64
|
|
53
|
+
credits_posted: 0n, // u64
|
|
67
54
|
timestamp: 0n, // u64, Reserved: This will be set by the server.
|
|
68
55
|
}
|
|
69
56
|
|
|
@@ -88,7 +75,7 @@ The `flags` on an account provide a way for you to enforce policies by toggling
|
|
|
88
75
|
|----------|----------------------------------|-----------------------------------------|
|
|
89
76
|
| `linked` | `debits_must_not_exceed_credits` | `credits_must_not_exceed_debits` |
|
|
90
77
|
|
|
91
|
-
The creation of an account can be linked to the successful creation of another by setting the `linked` flag (see [linked events](#linked-events)). By setting `debits_must_not_exceed_credits`, then any transfer such that `
|
|
78
|
+
The creation of an account can be linked to the successful creation of another by setting the `linked` flag (see [linked events](#linked-events)). By setting `debits_must_not_exceed_credits`, then any transfer such that `debits_posted + debits_pending + amount > credits_posted` will fail. Similarly for `credits_must_not_exceed_debits`.
|
|
92
79
|
```js
|
|
93
80
|
enum CreateAccountFlags {
|
|
94
81
|
linked = (1 << 0),
|
|
@@ -100,7 +87,7 @@ The creation of an account can be linked to the successful creation of another b
|
|
|
100
87
|
flags |= CreateAccountFlags.debits_must_not_exceed_credits
|
|
101
88
|
```
|
|
102
89
|
|
|
103
|
-
### Account
|
|
90
|
+
### Account Lookup
|
|
104
91
|
|
|
105
92
|
The `id` of the account is used for lookups. Only matched accounts are returned.
|
|
106
93
|
```js
|
|
@@ -112,80 +99,78 @@ The `id` of the account is used for lookups. Only matched accounts are returned.
|
|
|
112
99
|
* id: 137n,
|
|
113
100
|
* user_data: 0n,
|
|
114
101
|
* reserved: Buffer,
|
|
115
|
-
*
|
|
102
|
+
* ledger: 1,
|
|
116
103
|
* code: 718,
|
|
117
104
|
* flags: 0,
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
105
|
+
* debits_pending: 0n,
|
|
106
|
+
* debits_posted: 0n,
|
|
107
|
+
* credits_pending: 0n,
|
|
108
|
+
* credits_posted: 0n,
|
|
122
109
|
* timestamp: 1623062009212508993n,
|
|
123
110
|
* }]
|
|
124
111
|
*/
|
|
125
112
|
```
|
|
126
113
|
|
|
127
|
-
### Creating a
|
|
114
|
+
### Creating a Transfer
|
|
128
115
|
|
|
129
116
|
This creates a journal entry between two accounts.
|
|
130
117
|
```js
|
|
131
118
|
const transfer = {
|
|
132
119
|
id: 1n, // u128
|
|
120
|
+
// Double-entry accounting:
|
|
133
121
|
debit_account_id: 1n, // u128
|
|
134
122
|
credit_account_id: 2n, // u128
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
123
|
+
// Opaque third-party identifier to link this transfer to an external entity:
|
|
124
|
+
user_data: 0n, // u128
|
|
125
|
+
reserved: 0n, // u128
|
|
126
|
+
// Timeout applicable for a pending/2-phase transfer:
|
|
127
|
+
timeout: 0n, // u64, in nano-seconds.
|
|
128
|
+
// Collection of accounts usually grouped by the currency:
|
|
129
|
+
// You can't transfer money between accounts with different ledgers:
|
|
130
|
+
ledger: 720, // u32, ledger for transfer (e.g. currency).
|
|
131
|
+
// Chart of accounts code describing the reason for the transfer:
|
|
132
|
+
code: 1, // u16, (e.g. deposit, settlement)
|
|
133
|
+
flags: 0, // u16
|
|
140
134
|
amount: 10n, // u64
|
|
141
135
|
timestamp: 0n, //u64, Reserved: This will be set by the server.
|
|
142
136
|
}
|
|
143
|
-
|
|
144
137
|
const errors = await client.createTransfers([transfer])
|
|
145
138
|
```
|
|
146
|
-
Two-phase transfers are supported natively by toggling the appropriate flag. TigerBeetle will then adjust the `
|
|
147
|
-
| bit 0 | bit 1 | bit 2 |
|
|
148
|
-
|----------|--------------------|------------------|
|
|
149
|
-
| `linked` | `two_phase_commit` | `condition` |
|
|
139
|
+
Two-phase transfers are supported natively by toggling the appropriate flag. TigerBeetle will then adjust the `credits_pending` and `debits_pending` fields of the appropriate accounts. A corresponding commit transfer then needs to be sent to accept or reject the transfer.
|
|
150
140
|
|
|
151
|
-
|
|
141
|
+
Transfers within a batch may also be linked (see [linked events](#linked-events)).
|
|
152
142
|
```js
|
|
153
|
-
enum
|
|
154
|
-
linked = (1 << 0
|
|
155
|
-
|
|
156
|
-
|
|
143
|
+
enum TransferFlags {
|
|
144
|
+
linked = (1 << 0),
|
|
145
|
+
pending = (1 << 1),
|
|
146
|
+
post_pending_transfer = (1 << 2),
|
|
147
|
+
void_pending_transfer = (1 << 3)
|
|
157
148
|
}
|
|
158
|
-
|
|
159
|
-
//
|
|
149
|
+
|
|
150
|
+
// Two-phase transfer (pending):
|
|
160
151
|
let flags = 0n
|
|
161
|
-
flags |= TransferFlags.
|
|
152
|
+
flags |= TransferFlags.pending
|
|
162
153
|
|
|
163
|
-
// two-phase transfer
|
|
154
|
+
// Linked two-phase transfer (pending):
|
|
164
155
|
let flags = 0n
|
|
165
|
-
flags |= TransferFlags.
|
|
166
|
-
flags |= TransferFlags.
|
|
156
|
+
flags |= TransferFlags.linked
|
|
157
|
+
flags |= TransferFlags.pending
|
|
167
158
|
```
|
|
168
159
|
|
|
169
|
-
###
|
|
170
|
-
|
|
171
|
-
This is used to commit a two-phase transfer.
|
|
172
|
-
| bit 0 | bit 1 | bit 2 |
|
|
173
|
-
|----------|----------|------------|
|
|
174
|
-
| `linked` | `reject` | `preimage` |
|
|
160
|
+
### Post a Pending Transfer (2-Phase)
|
|
175
161
|
|
|
176
|
-
|
|
162
|
+
With `flags = post_pending_transfer`, TigerBeetle will accept the transfer. TigerBeetle will atomically rollback the changes to `debits_pending` and `credits_pending` of the appropriate accounts and apply them to the `debits_posted` and `credits_posted` balances.
|
|
177
163
|
```js
|
|
178
|
-
const
|
|
179
|
-
id:
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
flags: 0, // u32
|
|
164
|
+
const post = {
|
|
165
|
+
id: 2n, // u128, must correspond to the transfer id
|
|
166
|
+
pending_id: 1n, // u128, id of the pending transfer
|
|
167
|
+
flags: TransferFlags.post_pending_transfer, // to void, use [void_pending_transfer]
|
|
183
168
|
timestamp: 0n, // u64, Reserved: This will be set by the server.
|
|
184
169
|
}
|
|
185
|
-
const errors = await client.
|
|
170
|
+
const errors = await client.createTransfers([post])
|
|
186
171
|
```
|
|
187
172
|
|
|
188
|
-
### Linked
|
|
173
|
+
### Linked Events
|
|
189
174
|
|
|
190
175
|
When the `linked` flag is specified for the `createAccount`, `createTransfer`, `commitTransfer` event, it links an event with the next event in the batch, to create a chain of events, of arbitrary length, which all succeed or fail together. The tail of a chain is denoted by the first event without this flag. The last event in a batch may therefore never have the `linked` flag set as this would leave a chain open-ended. Multiple chains or individual events may coexist within a batch to succeed or fail independently. Events within a chain are executed within order, or are rolled back on error, so that the effect of each event in the chain is visible to the next, and so that the chain is either visible or invisible as a unit to subsequent events after the chain. The event that was the first to break the chain will have a unique error result. Other events in the chain will have their error result set to `linked_event_failed`.
|
|
191
176
|
|
|
@@ -194,10 +179,10 @@ let batch = []
|
|
|
194
179
|
let linkedFlag = 0
|
|
195
180
|
linkedFlag |= CreateTransferFlags.linked
|
|
196
181
|
|
|
197
|
-
// An individual transfer (successful)
|
|
182
|
+
// An individual transfer (successful):
|
|
198
183
|
batch.push({ id: 1n, ... })
|
|
199
184
|
|
|
200
|
-
// A chain of 4 transfers (the last transfer in the chain closes the chain with linked=false)
|
|
185
|
+
// A chain of 4 transfers (the last transfer in the chain closes the chain with linked=false):
|
|
201
186
|
batch.push({ id: 2n, ..., flags: linkedFlag }) // Commit/rollback.
|
|
202
187
|
batch.push({ id: 3n, ..., flags: linkedFlag }) // Commit/rollback.
|
|
203
188
|
batch.push({ id: 2n, ..., flags: linkedFlag }) // Fail with exists
|
|
@@ -207,11 +192,11 @@ batch.push({ id: 4n, ..., flags: 0 }) // Fail without committing.
|
|
|
207
192
|
// This should not see any effect from the failed chain above.
|
|
208
193
|
batch.push({ id: 2n, ..., flags: 0 })
|
|
209
194
|
|
|
210
|
-
// A chain of 2 transfers (the first transfer fails the chain)
|
|
195
|
+
// A chain of 2 transfers (the first transfer fails the chain):
|
|
211
196
|
batch.push({ id: 2n, ..., flags: linkedFlag })
|
|
212
197
|
batch.push({ id: 3n, ..., flags: 0 })
|
|
213
198
|
|
|
214
|
-
// A chain of 2 transfers (successful)
|
|
199
|
+
// A chain of 2 transfers (successful):
|
|
215
200
|
batch.push({ id: 3n, ..., flags: linkedFlag })
|
|
216
201
|
batch.push({ id: 4n, ..., flags: 0 })
|
|
217
202
|
|
|
@@ -219,13 +204,47 @@ const errors = await client.createTransfers(batch)
|
|
|
219
204
|
|
|
220
205
|
/**
|
|
221
206
|
* [
|
|
222
|
-
* { index: 1, error: 1 },
|
|
223
|
-
* { index: 2, error: 1 },
|
|
224
|
-
* { index: 3, error:
|
|
225
|
-
* { index: 4, error: 1 },
|
|
207
|
+
* { index: 1, error: 1 }, // linked_event_failed
|
|
208
|
+
* { index: 2, error: 1 }, // linked_event_failed
|
|
209
|
+
* { index: 3, error: 25 }, // exists
|
|
210
|
+
* { index: 4, error: 1 }, // linked_event_failed
|
|
226
211
|
*
|
|
227
|
-
* { index: 6, error:
|
|
228
|
-
* { index: 7, error: 1 },
|
|
212
|
+
* { index: 6, error: 17 }, // exists_with_different_flags
|
|
213
|
+
* { index: 7, error: 1 }, // linked_event_failed
|
|
229
214
|
* ]
|
|
230
215
|
*/
|
|
231
216
|
```
|
|
217
|
+
|
|
218
|
+
### Development
|
|
219
|
+
|
|
220
|
+
Follow these steps to get up and running when cloning the repo:
|
|
221
|
+
```shell
|
|
222
|
+
git clone --recurse-submodules https://github.com/coilhq/tigerbeetle-node.git
|
|
223
|
+
cd tigerbeetle-node/
|
|
224
|
+
yarn install --immutable
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Build locally using `yarn`:
|
|
228
|
+
```shell
|
|
229
|
+
# Run the following from this directory:
|
|
230
|
+
yarn && yarn build
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
* **Please note: `yarn clean` will remove Zig and NodeAPI C headers, which mean you need to run:**
|
|
234
|
+
```shell
|
|
235
|
+
./scripts/postinstall.sh #Install Zig and NodeJS C Headers
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
***Yarn - Run Test***
|
|
239
|
+
Ensure TigerBeetle (`init` & `start`) is running on the port configured in `test.ts`, then run:
|
|
240
|
+
```shell
|
|
241
|
+
./tigerbeetle init --cluster=1 --replica=0 --directory=.
|
|
242
|
+
./tigerbeetle start --cluster=1 --replica=0 --directory=. --addresses=3001
|
|
243
|
+
yarn test
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
***Yarn - Run Benchmark***
|
|
247
|
+
Run the benchmark (The `benchmark` will automatically start TigerBeetle on port `3001` _(single replica)_:
|
|
248
|
+
```shell
|
|
249
|
+
yarn benchmark
|
|
250
|
+
```
|
package/dist/benchmark.js
CHANGED
|
@@ -5,46 +5,44 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const assert_1 = __importDefault(require("assert"));
|
|
7
7
|
const _1 = require(".");
|
|
8
|
-
const MAX_TRANSFERS =
|
|
9
|
-
const MAX_REQUEST_BATCH_SIZE =
|
|
10
|
-
const
|
|
8
|
+
const MAX_TRANSFERS = 51200;
|
|
9
|
+
const MAX_REQUEST_BATCH_SIZE = 5120;
|
|
10
|
+
const IS_TWO_PHASE_TRANSFER = false;
|
|
11
11
|
const IS_RAW_REQUEST = false;
|
|
12
|
-
const PREVIOUS_RAW_REQUEST_RESULT =
|
|
13
|
-
const PREVIOUS_RESULT =
|
|
12
|
+
const PREVIOUS_RAW_REQUEST_RESULT = IS_TWO_PHASE_TRANSFER ? 300000 : 620000;
|
|
13
|
+
const PREVIOUS_RESULT = IS_TWO_PHASE_TRANSFER ? 150000 : 310000;
|
|
14
14
|
const PREVIOUS_BENCHMARK = IS_RAW_REQUEST ? PREVIOUS_RAW_REQUEST_RESULT : PREVIOUS_RESULT;
|
|
15
15
|
const TOLERANCE = 10;
|
|
16
16
|
const client = _1.createClient({
|
|
17
|
-
cluster_id:
|
|
17
|
+
cluster_id: 0,
|
|
18
18
|
replica_addresses: ['3001']
|
|
19
19
|
});
|
|
20
20
|
const TRANSFER_SIZE = 128;
|
|
21
|
-
const COMMIT_SIZE = 64;
|
|
22
21
|
const Zeroed48Bytes = Buffer.alloc(48, 0);
|
|
23
|
-
const Zeroed32Bytes = Buffer.alloc(32, 0);
|
|
24
22
|
const accountA = {
|
|
25
23
|
id: 137n,
|
|
26
24
|
user_data: 0n,
|
|
27
25
|
reserved: Zeroed48Bytes,
|
|
28
|
-
|
|
26
|
+
ledger: 1,
|
|
27
|
+
code: 1,
|
|
29
28
|
flags: 0,
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
credits_reserved: 0n,
|
|
29
|
+
debits_pending: 0n,
|
|
30
|
+
debits_posted: 0n,
|
|
31
|
+
credits_pending: 0n,
|
|
32
|
+
credits_posted: 0n,
|
|
35
33
|
timestamp: 0n,
|
|
36
34
|
};
|
|
37
35
|
const accountB = {
|
|
38
36
|
id: 138n,
|
|
39
37
|
user_data: 0n,
|
|
40
38
|
reserved: Zeroed48Bytes,
|
|
41
|
-
|
|
39
|
+
ledger: 1,
|
|
40
|
+
code: 1,
|
|
42
41
|
flags: 0,
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
credits_reserved: 0n,
|
|
42
|
+
debits_pending: 0n,
|
|
43
|
+
debits_posted: 0n,
|
|
44
|
+
credits_pending: 0n,
|
|
45
|
+
credits_posted: 0n,
|
|
48
46
|
timestamp: 0n,
|
|
49
47
|
};
|
|
50
48
|
const rawCreateTransfers = async (batch) => {
|
|
@@ -63,46 +61,30 @@ const rawCreateTransfers = async (batch) => {
|
|
|
63
61
|
}
|
|
64
62
|
});
|
|
65
63
|
};
|
|
66
|
-
const rawCommitTransfers = async (batch) => {
|
|
67
|
-
return new Promise((resolve, reject) => {
|
|
68
|
-
const callback = (error, results) => {
|
|
69
|
-
if (error) {
|
|
70
|
-
reject(error);
|
|
71
|
-
}
|
|
72
|
-
resolve(results);
|
|
73
|
-
};
|
|
74
|
-
try {
|
|
75
|
-
client.rawRequest(_1.Operation.COMMIT_TRANSFER, batch, callback);
|
|
76
|
-
}
|
|
77
|
-
catch (error) {
|
|
78
|
-
reject(error);
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
};
|
|
82
64
|
const encodeTransfer = (transfer, offset, output) => {
|
|
83
|
-
assert_1.default(offset + TRANSFER_SIZE <= output.length);
|
|
65
|
+
assert_1.default(BigInt((offset + TRANSFER_SIZE)) <= BigInt(output.length), `Transfer ${transfer} exceeds buffer of ${output}!`);
|
|
84
66
|
output.writeBigUInt64LE(transfer.id, offset);
|
|
85
67
|
output.writeBigUInt64LE(transfer.debit_account_id, offset + 16);
|
|
86
68
|
output.writeBigUInt64LE(transfer.credit_account_id, offset + 32);
|
|
69
|
+
output.writeBigUInt64LE(transfer.user_data, offset + 48);
|
|
70
|
+
output.writeBigUInt64LE(transfer.reserved, offset + 64);
|
|
71
|
+
output.writeBigUInt64LE(transfer.pending_id, offset + 80);
|
|
87
72
|
output.writeBigUInt64LE(transfer.timeout, offset + 96);
|
|
88
|
-
output.writeUInt32LE(transfer.
|
|
89
|
-
output.writeUInt32LE(transfer.
|
|
73
|
+
output.writeUInt32LE(transfer.ledger, offset + 104);
|
|
74
|
+
output.writeUInt32LE(transfer.code, offset + 108);
|
|
75
|
+
output.writeUInt32LE(transfer.flags, offset + 110);
|
|
90
76
|
output.writeBigUInt64LE(transfer.amount, offset + 112);
|
|
91
77
|
output.writeBigUInt64LE(transfer.timestamp, offset + 120);
|
|
92
78
|
};
|
|
93
|
-
const
|
|
94
|
-
assert_1.default(offset + COMMIT_SIZE <= output.length);
|
|
95
|
-
output.writeBigUInt64LE(commit.id, offset);
|
|
96
|
-
};
|
|
97
|
-
const runBenchmarkRawReqeust = async () => {
|
|
79
|
+
const runBenchmarkRawRequest = async () => {
|
|
98
80
|
assert_1.default(MAX_TRANSFERS % MAX_REQUEST_BATCH_SIZE === 0, "The raw request benchmark requires MAX_TRANSFERS to be a multiple of MAX_REQUEST_BATCH_SIZE");
|
|
99
|
-
console.log(`pre-allocating ${MAX_TRANSFERS} transfers and
|
|
81
|
+
console.log(`pre-allocating ${MAX_TRANSFERS} transfers and posts...`);
|
|
100
82
|
const transfers = [];
|
|
101
|
-
const
|
|
83
|
+
const posts = [];
|
|
102
84
|
let count = 0;
|
|
103
85
|
while (count < MAX_TRANSFERS) {
|
|
104
86
|
const transferBatch = Buffer.alloc(MAX_REQUEST_BATCH_SIZE * TRANSFER_SIZE, 0);
|
|
105
|
-
const
|
|
87
|
+
const postTransferBatch = Buffer.alloc(MAX_REQUEST_BATCH_SIZE * TRANSFER_SIZE, 0);
|
|
106
88
|
for (let i = 0; i < MAX_REQUEST_BATCH_SIZE; i++) {
|
|
107
89
|
if (count === MAX_TRANSFERS)
|
|
108
90
|
break;
|
|
@@ -111,27 +93,38 @@ const runBenchmarkRawReqeust = async () => {
|
|
|
111
93
|
id: BigInt(count),
|
|
112
94
|
debit_account_id: accountA.id,
|
|
113
95
|
credit_account_id: accountB.id,
|
|
114
|
-
code: 0,
|
|
115
|
-
reserved: Zeroed32Bytes,
|
|
116
96
|
user_data: 0n,
|
|
117
|
-
|
|
97
|
+
reserved: 0n,
|
|
98
|
+
pending_id: 0n,
|
|
99
|
+
timeout: IS_TWO_PHASE_TRANSFER ? BigInt(2e9) : 0n,
|
|
100
|
+
ledger: 1,
|
|
101
|
+
code: 1,
|
|
102
|
+
flags: IS_TWO_PHASE_TRANSFER ? _1.TransferFlags.pending : 0,
|
|
118
103
|
amount: 1n,
|
|
119
|
-
timeout: IS_TWO_PHASE_COMMIT ? BigInt(2e9) : 0n,
|
|
120
104
|
timestamp: 0n,
|
|
121
105
|
}, i * TRANSFER_SIZE, transferBatch);
|
|
122
|
-
if (
|
|
123
|
-
|
|
124
|
-
id: BigInt(count),
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
106
|
+
if (IS_TWO_PHASE_TRANSFER) {
|
|
107
|
+
encodeTransfer({
|
|
108
|
+
id: BigInt((MAX_TRANSFERS + count)),
|
|
109
|
+
debit_account_id: accountA.id,
|
|
110
|
+
credit_account_id: accountB.id,
|
|
111
|
+
user_data: 0n,
|
|
112
|
+
reserved: 0n,
|
|
113
|
+
pending_id: BigInt(count),
|
|
114
|
+
timeout: 0n,
|
|
115
|
+
ledger: 1,
|
|
116
|
+
code: 1,
|
|
117
|
+
flags: _1.TransferFlags.post_pending_transfer,
|
|
118
|
+
amount: 1n,
|
|
128
119
|
timestamp: 0n,
|
|
129
|
-
}, i *
|
|
120
|
+
}, i * TRANSFER_SIZE, postTransferBatch);
|
|
130
121
|
}
|
|
131
122
|
}
|
|
132
123
|
transfers.push(transferBatch);
|
|
133
|
-
if (
|
|
134
|
-
|
|
124
|
+
if (IS_TWO_PHASE_TRANSFER)
|
|
125
|
+
posts.push(postTransferBatch);
|
|
126
|
+
if (count % 100)
|
|
127
|
+
console.log(`${Number((count / MAX_TRANSFERS) * 100).toFixed(1)}%`);
|
|
135
128
|
}
|
|
136
129
|
assert_1.default(count === MAX_TRANSFERS);
|
|
137
130
|
console.log(`starting benchmark. MAX_TRANSFERS=${MAX_TRANSFERS} REQUEST_BATCH_SIZE=${MAX_REQUEST_BATCH_SIZE} NUMBER_OF_BATCHES=${transfers.length}`);
|
|
@@ -140,16 +133,16 @@ const runBenchmarkRawReqeust = async () => {
|
|
|
140
133
|
const start = Date.now();
|
|
141
134
|
for (let i = 0; i < transfers.length; i++) {
|
|
142
135
|
const ms1 = Date.now();
|
|
143
|
-
const
|
|
144
|
-
assert_1.default(
|
|
136
|
+
const transferErrors = await rawCreateTransfers(transfers[i]);
|
|
137
|
+
assert_1.default(transferErrors.length === 0);
|
|
145
138
|
const ms2 = Date.now();
|
|
146
139
|
const createTransferLatency = ms2 - ms1;
|
|
147
140
|
if (createTransferLatency > maxCreateTransfersLatency) {
|
|
148
141
|
maxCreateTransfersLatency = createTransferLatency;
|
|
149
142
|
}
|
|
150
|
-
if (
|
|
151
|
-
const
|
|
152
|
-
assert_1.default(
|
|
143
|
+
if (IS_TWO_PHASE_TRANSFER) {
|
|
144
|
+
const commitErrors = await rawCreateTransfers(posts[i]);
|
|
145
|
+
assert_1.default(commitErrors.length === 0);
|
|
153
146
|
const ms3 = Date.now();
|
|
154
147
|
const commitTransferLatency = ms3 - ms2;
|
|
155
148
|
if (commitTransferLatency > maxCommitTransfersLatency) {
|
|
@@ -165,42 +158,51 @@ const runBenchmarkRawReqeust = async () => {
|
|
|
165
158
|
};
|
|
166
159
|
};
|
|
167
160
|
const runBenchmark = async () => {
|
|
168
|
-
console.log(`pre-allocating ${MAX_TRANSFERS} transfers and
|
|
161
|
+
console.log(`pre-allocating ${MAX_TRANSFERS} transfers and posts...`);
|
|
169
162
|
const transfers = [];
|
|
170
|
-
const
|
|
163
|
+
const posts = [];
|
|
171
164
|
let count = 0;
|
|
172
165
|
while (count < MAX_TRANSFERS) {
|
|
173
|
-
const
|
|
174
|
-
const
|
|
166
|
+
const pendingBatch = [];
|
|
167
|
+
const postBatch = [];
|
|
175
168
|
for (let i = 0; i < MAX_REQUEST_BATCH_SIZE; i++) {
|
|
176
169
|
if (count === MAX_TRANSFERS)
|
|
177
170
|
break;
|
|
178
171
|
count += 1;
|
|
179
|
-
|
|
172
|
+
pendingBatch.push({
|
|
180
173
|
id: BigInt(count),
|
|
181
174
|
debit_account_id: accountA.id,
|
|
182
175
|
credit_account_id: accountB.id,
|
|
183
|
-
|
|
184
|
-
|
|
176
|
+
pending_id: 0n,
|
|
177
|
+
code: 1,
|
|
178
|
+
ledger: 1,
|
|
179
|
+
reserved: 0n,
|
|
185
180
|
user_data: 0n,
|
|
186
|
-
flags:
|
|
181
|
+
flags: IS_TWO_PHASE_TRANSFER ? _1.TransferFlags.pending : 0,
|
|
187
182
|
amount: 1n,
|
|
188
|
-
timeout:
|
|
183
|
+
timeout: IS_TWO_PHASE_TRANSFER ? BigInt(2e9) : 0n,
|
|
189
184
|
timestamp: 0n,
|
|
190
185
|
});
|
|
191
|
-
if (
|
|
192
|
-
|
|
193
|
-
id: BigInt(count),
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
186
|
+
if (IS_TWO_PHASE_TRANSFER) {
|
|
187
|
+
postBatch.push({
|
|
188
|
+
id: BigInt(MAX_TRANSFERS + count),
|
|
189
|
+
debit_account_id: accountA.id,
|
|
190
|
+
credit_account_id: accountB.id,
|
|
191
|
+
pending_id: BigInt(count),
|
|
192
|
+
code: 1,
|
|
193
|
+
ledger: 1,
|
|
194
|
+
reserved: 0n,
|
|
195
|
+
user_data: 0n,
|
|
196
|
+
flags: IS_TWO_PHASE_TRANSFER ? _1.TransferFlags.post_pending_transfer : 0,
|
|
197
|
+
amount: 1n,
|
|
198
|
+
timeout: 0n,
|
|
197
199
|
timestamp: 0n,
|
|
198
200
|
});
|
|
199
201
|
}
|
|
200
202
|
}
|
|
201
|
-
transfers.push(
|
|
202
|
-
if (
|
|
203
|
-
|
|
203
|
+
transfers.push(pendingBatch);
|
|
204
|
+
if (IS_TWO_PHASE_TRANSFER)
|
|
205
|
+
posts.push(postBatch);
|
|
204
206
|
}
|
|
205
207
|
assert_1.default(count === MAX_TRANSFERS);
|
|
206
208
|
console.log(`starting benchmark. MAX_TRANSFERS=${MAX_TRANSFERS} REQUEST_BATCH_SIZE=${MAX_REQUEST_BATCH_SIZE} NUMBER_OF_BATCHES=${transfers.length}`);
|
|
@@ -209,16 +211,16 @@ const runBenchmark = async () => {
|
|
|
209
211
|
const start = Date.now();
|
|
210
212
|
for (let i = 0; i < transfers.length; i++) {
|
|
211
213
|
const ms1 = Date.now();
|
|
212
|
-
const
|
|
213
|
-
assert_1.default(
|
|
214
|
+
const transferErrors = await client.createTransfers(transfers[i]);
|
|
215
|
+
assert_1.default(transferErrors.length === 0);
|
|
214
216
|
const ms2 = Date.now();
|
|
215
217
|
const createTransferLatency = ms2 - ms1;
|
|
216
218
|
if (createTransferLatency > maxCreateTransfersLatency) {
|
|
217
219
|
maxCreateTransfersLatency = createTransferLatency;
|
|
218
220
|
}
|
|
219
|
-
if (
|
|
220
|
-
const
|
|
221
|
-
assert_1.default(
|
|
221
|
+
if (IS_TWO_PHASE_TRANSFER) {
|
|
222
|
+
const commitErrors = await client.createTransfers(posts[i]);
|
|
223
|
+
assert_1.default(commitErrors.length === 0);
|
|
222
224
|
const ms3 = Date.now();
|
|
223
225
|
const commitTransferLatency = ms3 - ms2;
|
|
224
226
|
if (commitTransferLatency > maxCommitTransfersLatency) {
|
|
@@ -238,18 +240,18 @@ const main = async () => {
|
|
|
238
240
|
await client.createAccounts([accountA, accountB]);
|
|
239
241
|
const accountResults = await client.lookupAccounts([accountA.id, accountB.id]);
|
|
240
242
|
assert_1.default(accountResults.length === 2);
|
|
241
|
-
assert_1.default(accountResults[0].
|
|
242
|
-
assert_1.default(accountResults[1].
|
|
243
|
-
const benchmark = IS_RAW_REQUEST ? await
|
|
243
|
+
assert_1.default(accountResults[0].debits_posted === 0n);
|
|
244
|
+
assert_1.default(accountResults[1].debits_posted === 0n);
|
|
245
|
+
const benchmark = IS_RAW_REQUEST ? await runBenchmarkRawRequest() : await runBenchmark();
|
|
244
246
|
const accounts = await client.lookupAccounts([accountA.id, accountB.id]);
|
|
245
247
|
const result = Math.floor((1000 * MAX_TRANSFERS) / benchmark.ms);
|
|
246
248
|
console.log("=============================");
|
|
247
|
-
console.log(`${
|
|
249
|
+
console.log(`${IS_TWO_PHASE_TRANSFER ? 'two-phase ' : ''}transfers per second: ${result}`);
|
|
248
250
|
console.log(`create transfers max p100 latency per 10 000 transfers = ${benchmark.maxCreateTransfersLatency}ms`);
|
|
249
251
|
console.log(`commit transfers max p100 latency per 10 000 transfers = ${benchmark.maxCommitTransfersLatency}ms`);
|
|
250
252
|
assert_1.default(accounts.length === 2);
|
|
251
|
-
assert_1.default(accounts[0].
|
|
252
|
-
assert_1.default(accounts[1].
|
|
253
|
+
assert_1.default(accounts[0].debits_posted === BigInt(MAX_TRANSFERS));
|
|
254
|
+
assert_1.default(accounts[1].credits_posted === BigInt(MAX_TRANSFERS));
|
|
253
255
|
if (result < PREVIOUS_BENCHMARK * (100 - TOLERANCE) / 100) {
|
|
254
256
|
console.warn(`There has been a performance regression. Previous benchmark=${PREVIOUS_BENCHMARK}`);
|
|
255
257
|
}
|