camusdb 0.6.0 → 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.
- package/README.md +250 -0
- package/dist/client.d.ts +73 -39
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +158 -169
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +22 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +19 -0
- package/dist/config.js.map +1 -1
- package/dist/endpoint-pool.d.ts +8 -0
- package/dist/endpoint-pool.d.ts.map +1 -1
- package/dist/endpoint-pool.js +25 -0
- package/dist/endpoint-pool.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/node-stats.d.ts +113 -0
- package/dist/node-stats.d.ts.map +1 -0
- package/dist/node-stats.js +90 -0
- package/dist/node-stats.js.map +1 -0
- package/dist/options.d.ts +10 -0
- package/dist/options.d.ts.map +1 -1
- package/dist/options.js +1 -0
- package/dist/options.js.map +1 -1
- package/dist/pipeline.d.ts +136 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +375 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/prepared/auto-prepare.d.ts +51 -0
- package/dist/prepared/auto-prepare.d.ts.map +1 -0
- package/dist/prepared/auto-prepare.js +150 -0
- package/dist/prepared/auto-prepare.js.map +1 -0
- package/dist/prepared/policy.d.ts +7 -0
- package/dist/prepared/policy.d.ts.map +1 -1
- package/dist/prepared/policy.js +16 -0
- package/dist/prepared/policy.js.map +1 -1
- package/dist/query-stream.d.ts +9 -1
- package/dist/query-stream.d.ts.map +1 -1
- package/dist/query-stream.js +20 -2
- package/dist/query-stream.js.map +1 -1
- package/dist/retry.d.ts +8 -0
- package/dist/retry.d.ts.map +1 -1
- package/dist/retry.js +12 -1
- package/dist/retry.js.map +1 -1
- package/dist/sql-syntax.d.ts +6 -0
- package/dist/sql-syntax.d.ts.map +1 -1
- package/dist/sql-syntax.js +8 -0
- package/dist/sql-syntax.js.map +1 -1
- package/dist/statements.d.ts +14 -0
- package/dist/statements.d.ts.map +1 -1
- package/dist/statements.js +45 -3
- package/dist/statements.js.map +1 -1
- package/dist/telemetry.d.ts +199 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +423 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/transaction.d.ts +60 -5
- package/dist/transaction.d.ts.map +1 -1
- package/dist/transaction.js +124 -24
- package/dist/transaction.js.map +1 -1
- package/dist/transport/authenticating-transport.d.ts +9 -1
- package/dist/transport/authenticating-transport.d.ts.map +1 -1
- package/dist/transport/authenticating-transport.js +13 -0
- package/dist/transport/authenticating-transport.js.map +1 -1
- package/dist/transport/grpc/batch-frames.d.ts +23 -5
- package/dist/transport/grpc/batch-frames.d.ts.map +1 -1
- package/dist/transport/grpc/batch-frames.js +29 -8
- package/dist/transport/grpc/batch-frames.js.map +1 -1
- package/dist/transport/grpc/batcher.d.ts +69 -5
- package/dist/transport/grpc/batcher.d.ts.map +1 -1
- package/dist/transport/grpc/batcher.js +217 -10
- package/dist/transport/grpc/batcher.js.map +1 -1
- package/dist/transport/grpc/grpc-transport.d.ts +35 -1
- package/dist/transport/grpc/grpc-transport.d.ts.map +1 -1
- package/dist/transport/grpc/grpc-transport.js +193 -7
- package/dist/transport/grpc/grpc-transport.js.map +1 -1
- package/dist/transport/grpc/messages.d.ts +15 -0
- package/dist/transport/grpc/messages.d.ts.map +1 -1
- package/dist/transport/grpc/messages.js +9 -0
- package/dist/transport/grpc/messages.js.map +1 -1
- package/dist/transport/rest-transport.d.ts +9 -1
- package/dist/transport/rest-transport.d.ts.map +1 -1
- package/dist/transport/rest-transport.js +24 -0
- package/dist/transport/rest-transport.js.map +1 -1
- package/dist/transport/sequential-pipeline.d.ts +21 -0
- package/dist/transport/sequential-pipeline.d.ts.map +1 -0
- package/dist/transport/sequential-pipeline.js +119 -0
- package/dist/transport/sequential-pipeline.js.map +1 -0
- package/dist/transport/transport.d.ts +94 -0
- package/dist/transport/transport.d.ts.map +1 -1
- package/dist/transport/transport.js +10 -0
- package/dist/transport/transport.js.map +1 -1
- package/package.json +10 -4
- package/proto/camus_sql.proto +114 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of CamusDB
|
|
3
|
+
*
|
|
4
|
+
* For the full copyright and license information, please view the LICENSE.txt
|
|
5
|
+
* file that was distributed with this source code.
|
|
6
|
+
*/
|
|
7
|
+
import type { ExecuteResult, QueryResult } from './client.js';
|
|
8
|
+
import type { ClientRuntime } from './runtime.js';
|
|
9
|
+
import type { CamusTransaction } from './transaction.js';
|
|
10
|
+
import type { Int64Mode } from './values/decode.js';
|
|
11
|
+
import type { Parameters } from './values/encode.js';
|
|
12
|
+
/** What one queued read may override for itself. */
|
|
13
|
+
export interface PipelineQueryOptions {
|
|
14
|
+
/** How an `int64` column reaches the caller, for this statement alone. */
|
|
15
|
+
readonly int64?: Int64Mode | undefined;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Several statements of one `CamusTransaction`, sent together as one exchange and answered
|
|
19
|
+
* together.
|
|
20
|
+
*
|
|
21
|
+
* A transaction that awaits each statement pays one round trip per statement: six for a bank
|
|
22
|
+
* transfer (`BEGIN`, two reads, two writes, `COMMIT`). At high concurrency those round trips, and
|
|
23
|
+
* not the statements, set its latency. A pipeline queues the statements whose inputs are known,
|
|
24
|
+
* sends them as one stream message, and settles each statement's promise from its own answer.
|
|
25
|
+
*
|
|
26
|
+
* ```ts
|
|
27
|
+
* const txn = await client.beginTransaction({ deferBegin: true });
|
|
28
|
+
* const pipeline = txn.pipeline();
|
|
29
|
+
*
|
|
30
|
+
* // Exchange 1: [BEGIN, SELECT a, SELECT b]
|
|
31
|
+
* const readA = pipeline.query<{ balance: number }>('SELECT balance FROM accounts WHERE id = @id', { id: a });
|
|
32
|
+
* const readB = pipeline.query<{ balance: number }>('SELECT balance FROM accounts WHERE id = @id', { id: b });
|
|
33
|
+
* await pipeline.send();
|
|
34
|
+
*
|
|
35
|
+
* const from = (await readA).rows[0]!.balance;
|
|
36
|
+
* const to = (await readB).rows[0]!.balance;
|
|
37
|
+
*
|
|
38
|
+
* // Exchange 2: [UPDATE a, UPDATE b, COMMIT]. The commit happens only if both updates succeed.
|
|
39
|
+
* pipeline.execute('UPDATE accounts SET balance = @v WHERE id = @id', { v: from - amount, id: a });
|
|
40
|
+
* pipeline.execute('UPDATE accounts SET balance = @v WHERE id = @id', { v: to + amount, id: b });
|
|
41
|
+
* await pipeline.commit();
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* **Shape.** Queue with `query` and `execute`. Each returns the promise for that statement's result.
|
|
45
|
+
* Then call `send` to run what is queued, or `commit` to run it and commit the transaction in the
|
|
46
|
+
* same exchange. That commit happens only when every statement of the transaction succeeded. A
|
|
47
|
+
* transaction begun with `deferBegin`, or with learned routing on, sends its `BEGIN` inside the
|
|
48
|
+
* first exchange too.
|
|
49
|
+
*
|
|
50
|
+
* **Failure.** Every queued promise settles with its own result or its own `CamusError`, as a lone
|
|
51
|
+
* statement does. The statements after a failed one in the same exchange still get an answer. The
|
|
52
|
+
* transaction has ended, so they fail too. The send itself rejects with the first failure, so a
|
|
53
|
+
* caller that awaits only the send still learns of it. A queued promise that nobody awaits is never
|
|
54
|
+
* reported as an unhandled rejection. After a failed `commit`, the server has rolled the
|
|
55
|
+
* transaction back, and `rollback` is a harmless call. To retry, run the whole transaction again
|
|
56
|
+
* from `BEGIN`.
|
|
57
|
+
*
|
|
58
|
+
* **Order and reuse.** The queued statements run in queue order, after every statement of the
|
|
59
|
+
* transaction sent before them. So a pipeline can be sent more than once on one transaction, and an
|
|
60
|
+
* ordinary statement can run between two sends. One send at a time per pipeline. `exchanges`
|
|
61
|
+
* reports the round trips used. It is one per send over gRPC to a server that reads the pipeline
|
|
62
|
+
* contract. Over REST, with `requestFrames` off, or against an older server, it is one per
|
|
63
|
+
* statement, with the same results.
|
|
64
|
+
*/
|
|
65
|
+
export declare class CamusPipeline {
|
|
66
|
+
private readonly transactionValue;
|
|
67
|
+
private readonly runtime;
|
|
68
|
+
private readonly queued;
|
|
69
|
+
private exchangesValue;
|
|
70
|
+
private sending;
|
|
71
|
+
/** @internal Use `CamusTransaction.pipeline`. */
|
|
72
|
+
constructor(transaction: CamusTransaction, runtime: ClientRuntime);
|
|
73
|
+
/** The transaction that every queued statement runs in. */
|
|
74
|
+
get transaction(): CamusTransaction;
|
|
75
|
+
/** How many statements are queued and not sent yet. */
|
|
76
|
+
get size(): number;
|
|
77
|
+
/**
|
|
78
|
+
* The round trips this pipeline has cost so far. A send that travelled as one stream message
|
|
79
|
+
* costs one. A send that did not costs one for each step: the `BEGIN`, each statement, and the
|
|
80
|
+
* commit.
|
|
81
|
+
*/
|
|
82
|
+
get exchanges(): number;
|
|
83
|
+
/**
|
|
84
|
+
* Queues a statement that returns rows, and reports the promise for them. That is a `SELECT`, or
|
|
85
|
+
* an `INSERT`, `UPDATE`, or `DELETE` with a `RETURNING` list. A write reports its written-row
|
|
86
|
+
* count in `affectedRows`. A `CALL` is also accepted: it has no rows, and it reports in
|
|
87
|
+
* `affectedRows` the number of rows that the procedure's SQL changed. The promise settles when the pipeline is sent and the statement is
|
|
88
|
+
* answered.
|
|
89
|
+
*
|
|
90
|
+
* @throws {CamusError} at once, for a statement that cannot run inside the transaction (DDL and
|
|
91
|
+
* `TRUNCATE`), and while a send is in progress.
|
|
92
|
+
*/
|
|
93
|
+
query<T = Record<string, unknown>>(sql: string, parameters?: Parameters, options?: PipelineQueryOptions): Promise<QueryResult<T>>;
|
|
94
|
+
/**
|
|
95
|
+
* Queues a write, and reports the promise for its affected-row count. For a write with
|
|
96
|
+
* `RETURNING`, the server sends the count only. The promise settles when the pipeline is sent
|
|
97
|
+
* and the statement is answered.
|
|
98
|
+
*
|
|
99
|
+
* @throws {CamusError} at once, for a statement that cannot run inside the transaction (DDL and
|
|
100
|
+
* `TRUNCATE`), and while a send is in progress.
|
|
101
|
+
*/
|
|
102
|
+
execute(sql: string, parameters?: Parameters): Promise<ExecuteResult>;
|
|
103
|
+
/**
|
|
104
|
+
* Queues `CALL procedure(@a, @b, ...)` for a procedure that a C# extension on the server defines,
|
|
105
|
+
* and reports the promise for the number of rows that the procedure's SQL changed. The arguments
|
|
106
|
+
* follow the order of the parameter object's keys, as in `CamusClient.call`.
|
|
107
|
+
*
|
|
108
|
+
* @throws {TypeError} at once, when `procedure` is not a plain identifier.
|
|
109
|
+
* @throws {CamusError} at once, while a send is in progress.
|
|
110
|
+
*/
|
|
111
|
+
call(procedure: string, parameters?: Parameters): Promise<ExecuteResult>;
|
|
112
|
+
/**
|
|
113
|
+
* Sends the queued statements as one exchange, and waits for every answer. It rejects with the
|
|
114
|
+
* first failure, if any. Each statement's own promise carries its own outcome.
|
|
115
|
+
*/
|
|
116
|
+
send(signal?: AbortSignal): Promise<void>;
|
|
117
|
+
/**
|
|
118
|
+
* Sends the queued statements and the transaction's commit as one exchange.
|
|
119
|
+
*
|
|
120
|
+
* The commit happens only when every statement of the transaction succeeded, in this send and
|
|
121
|
+
* before it. If not, the server rolls the transaction back, and this rejects with the first
|
|
122
|
+
* failure. After a success the transaction is committed, and `CamusTransaction.commit` must not
|
|
123
|
+
* be called again.
|
|
124
|
+
*/
|
|
125
|
+
commit(signal?: AbortSignal): Promise<void>;
|
|
126
|
+
private add;
|
|
127
|
+
private flush;
|
|
128
|
+
private exchange;
|
|
129
|
+
/**
|
|
130
|
+
* Where a transaction that has not begun yet begins: the first statement's learned route when
|
|
131
|
+
* the client routes, and the pool's rotation if not. That is the choice a lone first statement
|
|
132
|
+
* makes.
|
|
133
|
+
*/
|
|
134
|
+
private chooseEndpoint;
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=pipeline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAQ9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAIlD,OAAO,KAAK,EAAE,gBAAgB,EAAc,MAAM,kBAAkB,CAAC;AAOrE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGrD,oDAAoD;AACpD,MAAM,WAAW,oBAAoB;IACnC,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;CACxC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;IAEpD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;IAExC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAyB;IAEhD,OAAO,CAAC,cAAc,CAAK;IAE3B,OAAO,CAAC,OAAO,CAAS;IAExB,iDAAiD;gBACrC,WAAW,EAAE,gBAAgB,EAAE,OAAO,EAAE,aAAa;IAKjE,2DAA2D;IAC3D,IAAI,WAAW,IAAI,gBAAgB,CAElC;IAED,uDAAuD;IACvD,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;;;OAIG;IACH,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,GAAG,EAAE,MAAM,EACX,UAAU,CAAC,EAAE,UAAU,EACvB,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAM1B;;;;;;;OAOG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC;IAMrE;;;;;;;OAOG;IACH,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC;IAIxE;;;OAGG;IACH,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzC;;;;;;;OAOG;IACH,MAAM,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3C,OAAO,CAAC,GAAG;YA2CG,KAAK;YAwBL,QAAQ;IAuHtB;;;;OAIG;IACH,OAAO,CAAC,cAAc;CAYvB"}
|
package/dist/pipeline.js
ADDED
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of CamusDB
|
|
3
|
+
*
|
|
4
|
+
* For the full copyright and license information, please view the LICENSE.txt
|
|
5
|
+
* file that was distributed with this source code.
|
|
6
|
+
*/
|
|
7
|
+
import { CamusError } from './errors.js';
|
|
8
|
+
import { CamusErrorCode } from './error-codes.js';
|
|
9
|
+
import { shouldPrepare } from './prepared/auto-prepare.js';
|
|
10
|
+
import { CamusResultSet, RowMapper } from './result-set.js';
|
|
11
|
+
import { ROUTING_ACCEPT_VERSION } from './routing/advice.js';
|
|
12
|
+
import { CamusRouteOpKind } from './routing/route-cache.js';
|
|
13
|
+
import { callStatement, isDdlStatement, isDmlStatement, runsInOwnTransaction } from './statements.js';
|
|
14
|
+
import { traced } from './telemetry.js';
|
|
15
|
+
import { firstPipelineFailure } from './transport/transport.js';
|
|
16
|
+
import { encodeParameters } from './values/encode.js';
|
|
17
|
+
/**
|
|
18
|
+
* Several statements of one `CamusTransaction`, sent together as one exchange and answered
|
|
19
|
+
* together.
|
|
20
|
+
*
|
|
21
|
+
* A transaction that awaits each statement pays one round trip per statement: six for a bank
|
|
22
|
+
* transfer (`BEGIN`, two reads, two writes, `COMMIT`). At high concurrency those round trips, and
|
|
23
|
+
* not the statements, set its latency. A pipeline queues the statements whose inputs are known,
|
|
24
|
+
* sends them as one stream message, and settles each statement's promise from its own answer.
|
|
25
|
+
*
|
|
26
|
+
* ```ts
|
|
27
|
+
* const txn = await client.beginTransaction({ deferBegin: true });
|
|
28
|
+
* const pipeline = txn.pipeline();
|
|
29
|
+
*
|
|
30
|
+
* // Exchange 1: [BEGIN, SELECT a, SELECT b]
|
|
31
|
+
* const readA = pipeline.query<{ balance: number }>('SELECT balance FROM accounts WHERE id = @id', { id: a });
|
|
32
|
+
* const readB = pipeline.query<{ balance: number }>('SELECT balance FROM accounts WHERE id = @id', { id: b });
|
|
33
|
+
* await pipeline.send();
|
|
34
|
+
*
|
|
35
|
+
* const from = (await readA).rows[0]!.balance;
|
|
36
|
+
* const to = (await readB).rows[0]!.balance;
|
|
37
|
+
*
|
|
38
|
+
* // Exchange 2: [UPDATE a, UPDATE b, COMMIT]. The commit happens only if both updates succeed.
|
|
39
|
+
* pipeline.execute('UPDATE accounts SET balance = @v WHERE id = @id', { v: from - amount, id: a });
|
|
40
|
+
* pipeline.execute('UPDATE accounts SET balance = @v WHERE id = @id', { v: to + amount, id: b });
|
|
41
|
+
* await pipeline.commit();
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* **Shape.** Queue with `query` and `execute`. Each returns the promise for that statement's result.
|
|
45
|
+
* Then call `send` to run what is queued, or `commit` to run it and commit the transaction in the
|
|
46
|
+
* same exchange. That commit happens only when every statement of the transaction succeeded. A
|
|
47
|
+
* transaction begun with `deferBegin`, or with learned routing on, sends its `BEGIN` inside the
|
|
48
|
+
* first exchange too.
|
|
49
|
+
*
|
|
50
|
+
* **Failure.** Every queued promise settles with its own result or its own `CamusError`, as a lone
|
|
51
|
+
* statement does. The statements after a failed one in the same exchange still get an answer. The
|
|
52
|
+
* transaction has ended, so they fail too. The send itself rejects with the first failure, so a
|
|
53
|
+
* caller that awaits only the send still learns of it. A queued promise that nobody awaits is never
|
|
54
|
+
* reported as an unhandled rejection. After a failed `commit`, the server has rolled the
|
|
55
|
+
* transaction back, and `rollback` is a harmless call. To retry, run the whole transaction again
|
|
56
|
+
* from `BEGIN`.
|
|
57
|
+
*
|
|
58
|
+
* **Order and reuse.** The queued statements run in queue order, after every statement of the
|
|
59
|
+
* transaction sent before them. So a pipeline can be sent more than once on one transaction, and an
|
|
60
|
+
* ordinary statement can run between two sends. One send at a time per pipeline. `exchanges`
|
|
61
|
+
* reports the round trips used. It is one per send over gRPC to a server that reads the pipeline
|
|
62
|
+
* contract. Over REST, with `requestFrames` off, or against an older server, it is one per
|
|
63
|
+
* statement, with the same results.
|
|
64
|
+
*/
|
|
65
|
+
export class CamusPipeline {
|
|
66
|
+
transactionValue;
|
|
67
|
+
runtime;
|
|
68
|
+
queued = [];
|
|
69
|
+
exchangesValue = 0;
|
|
70
|
+
sending = false;
|
|
71
|
+
/** @internal Use `CamusTransaction.pipeline`. */
|
|
72
|
+
constructor(transaction, runtime) {
|
|
73
|
+
this.transactionValue = transaction;
|
|
74
|
+
this.runtime = runtime;
|
|
75
|
+
}
|
|
76
|
+
/** The transaction that every queued statement runs in. */
|
|
77
|
+
get transaction() {
|
|
78
|
+
return this.transactionValue;
|
|
79
|
+
}
|
|
80
|
+
/** How many statements are queued and not sent yet. */
|
|
81
|
+
get size() {
|
|
82
|
+
return this.queued.length;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* The round trips this pipeline has cost so far. A send that travelled as one stream message
|
|
86
|
+
* costs one. A send that did not costs one for each step: the `BEGIN`, each statement, and the
|
|
87
|
+
* commit.
|
|
88
|
+
*/
|
|
89
|
+
get exchanges() {
|
|
90
|
+
return this.exchangesValue;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Queues a statement that returns rows, and reports the promise for them. That is a `SELECT`, or
|
|
94
|
+
* an `INSERT`, `UPDATE`, or `DELETE` with a `RETURNING` list. A write reports its written-row
|
|
95
|
+
* count in `affectedRows`. A `CALL` is also accepted: it has no rows, and it reports in
|
|
96
|
+
* `affectedRows` the number of rows that the procedure's SQL changed. The promise settles when the pipeline is sent and the statement is
|
|
97
|
+
* answered.
|
|
98
|
+
*
|
|
99
|
+
* @throws {CamusError} at once, for a statement that cannot run inside the transaction (DDL and
|
|
100
|
+
* `TRUNCATE`), and while a send is in progress.
|
|
101
|
+
*/
|
|
102
|
+
query(sql, parameters, options = {}) {
|
|
103
|
+
const statement = this.add(sql, parameters, true, options.int64);
|
|
104
|
+
return statement.promise;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Queues a write, and reports the promise for its affected-row count. For a write with
|
|
108
|
+
* `RETURNING`, the server sends the count only. The promise settles when the pipeline is sent
|
|
109
|
+
* and the statement is answered.
|
|
110
|
+
*
|
|
111
|
+
* @throws {CamusError} at once, for a statement that cannot run inside the transaction (DDL and
|
|
112
|
+
* `TRUNCATE`), and while a send is in progress.
|
|
113
|
+
*/
|
|
114
|
+
execute(sql, parameters) {
|
|
115
|
+
const statement = this.add(sql, parameters, false, undefined);
|
|
116
|
+
return statement.promise;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Queues `CALL procedure(@a, @b, ...)` for a procedure that a C# extension on the server defines,
|
|
120
|
+
* and reports the promise for the number of rows that the procedure's SQL changed. The arguments
|
|
121
|
+
* follow the order of the parameter object's keys, as in `CamusClient.call`.
|
|
122
|
+
*
|
|
123
|
+
* @throws {TypeError} at once, when `procedure` is not a plain identifier.
|
|
124
|
+
* @throws {CamusError} at once, while a send is in progress.
|
|
125
|
+
*/
|
|
126
|
+
call(procedure, parameters) {
|
|
127
|
+
return this.execute(callStatement(procedure, parameters), parameters);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Sends the queued statements as one exchange, and waits for every answer. It rejects with the
|
|
131
|
+
* first failure, if any. Each statement's own promise carries its own outcome.
|
|
132
|
+
*/
|
|
133
|
+
send(signal) {
|
|
134
|
+
return this.flush(false, signal);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Sends the queued statements and the transaction's commit as one exchange.
|
|
138
|
+
*
|
|
139
|
+
* The commit happens only when every statement of the transaction succeeded, in this send and
|
|
140
|
+
* before it. If not, the server rolls the transaction back, and this rejects with the first
|
|
141
|
+
* failure. After a success the transaction is committed, and `CamusTransaction.commit` must not
|
|
142
|
+
* be called again.
|
|
143
|
+
*/
|
|
144
|
+
commit(signal) {
|
|
145
|
+
return this.flush(true, signal);
|
|
146
|
+
}
|
|
147
|
+
add(sql, parameters, asReader, int64) {
|
|
148
|
+
if (this.sending) {
|
|
149
|
+
throw new CamusError(CamusErrorCode.Generic, 'A send is in progress on this pipeline. Queue the statement after it completes.');
|
|
150
|
+
}
|
|
151
|
+
if (runsInOwnTransaction(sql)) {
|
|
152
|
+
throw new CamusError(CamusErrorCode.StatementNotAllowedInTransaction, 'This statement runs in its own transaction and cannot be pipelined.');
|
|
153
|
+
}
|
|
154
|
+
if (isDdlStatement(sql)) {
|
|
155
|
+
throw new CamusError(CamusErrorCode.Generic, 'A DDL statement cannot be pipelined, because it does not run inside the transaction.');
|
|
156
|
+
}
|
|
157
|
+
const dml = isDmlStatement(sql);
|
|
158
|
+
const statement = new QueuedStatement(sql, encodeParameters(parameters), asReader, asReader && !dml ? 'query' : 'nonQuery', asReader && !dml ? CamusRouteOpKind.Query : CamusRouteOpKind.NonQuery, int64 ?? this.runtime.config.decode.int64);
|
|
159
|
+
this.queued.push(statement);
|
|
160
|
+
return statement;
|
|
161
|
+
}
|
|
162
|
+
async flush(commit, signal) {
|
|
163
|
+
if (this.sending) {
|
|
164
|
+
throw new CamusError(CamusErrorCode.Generic, 'A send is already in progress on this pipeline.');
|
|
165
|
+
}
|
|
166
|
+
if (this.queued.length === 0 && !commit)
|
|
167
|
+
return;
|
|
168
|
+
const batch = this.queued.splice(0);
|
|
169
|
+
this.sending = true;
|
|
170
|
+
try {
|
|
171
|
+
// One span for the exchange. Its statements get no spans of their own: they travel together,
|
|
172
|
+
// and the server answers them together.
|
|
173
|
+
await traced(this.runtime, { operationName: 'BATCH', batchSize: batch.length }, (operation) => {
|
|
174
|
+
operation?.setAttribute('camusdb.pipeline.commit', commit);
|
|
175
|
+
return this.exchange(batch, commit, signal, operation);
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
finally {
|
|
179
|
+
this.sending = false;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
async exchange(batch, commit, signal, operation) {
|
|
183
|
+
const transaction = this.transactionValue;
|
|
184
|
+
const runtime = this.runtime;
|
|
185
|
+
let claim;
|
|
186
|
+
try {
|
|
187
|
+
if (transaction.isFinalized) {
|
|
188
|
+
throw new CamusError(CamusErrorCode.Generic, 'This transaction was already committed or rolled back.');
|
|
189
|
+
}
|
|
190
|
+
// The `BEGIN` rides this exchange when nothing has begun the transaction yet. When a
|
|
191
|
+
// statement is beginning it at this moment, wait for that instead: one `BEGIN` per
|
|
192
|
+
// transaction.
|
|
193
|
+
if (!transaction.isStarted) {
|
|
194
|
+
const start = transaction.claimStart();
|
|
195
|
+
claim = start.claim;
|
|
196
|
+
if (start.pending !== undefined)
|
|
197
|
+
await start.pending;
|
|
198
|
+
}
|
|
199
|
+
const endpoint = transaction.endpoint ?? this.chooseEndpoint(batch);
|
|
200
|
+
const database = runtime.database;
|
|
201
|
+
operation?.setEndpoint(endpoint);
|
|
202
|
+
const router = runtime.router;
|
|
203
|
+
// Each statement's route entry is read before the exchange, pinned or not, for the reason a
|
|
204
|
+
// lone statement reads it: the reply's advice refreshes the route only if the entry has not
|
|
205
|
+
// moved since, so a late reply never overwrites what a faster one learned.
|
|
206
|
+
const observed = [];
|
|
207
|
+
const statements = [];
|
|
208
|
+
for (const statement of batch) {
|
|
209
|
+
statements.push({
|
|
210
|
+
kind: statement.kind,
|
|
211
|
+
sql: statement.sql,
|
|
212
|
+
parameters: statement.parameters,
|
|
213
|
+
prepared: await shouldPrepare(runtime, statement.sql, endpoint, { signal }),
|
|
214
|
+
routingAcceptVersion: router !== undefined ? ROUTING_ACCEPT_VERSION : 0,
|
|
215
|
+
...(statement.kind === 'nonQuery' && !statement.asReader ? { discardReturningRows: true } : {}),
|
|
216
|
+
});
|
|
217
|
+
observed.push(router?.selectEndpoint(database, statement.sql, statement.routeKind).revision ?? 0);
|
|
218
|
+
}
|
|
219
|
+
const result = await runtime.transport.executePipeline({
|
|
220
|
+
endpoint,
|
|
221
|
+
database,
|
|
222
|
+
start: claim !== undefined ? transaction.options : undefined,
|
|
223
|
+
...(claim === undefined
|
|
224
|
+
? {
|
|
225
|
+
txnIdPT: transaction.txnIdPT,
|
|
226
|
+
txnIdCounter: transaction.txnIdCounter,
|
|
227
|
+
streamSlot: transaction.streamSlot,
|
|
228
|
+
}
|
|
229
|
+
: {}),
|
|
230
|
+
statements,
|
|
231
|
+
commit,
|
|
232
|
+
timeoutSeconds: runtime.timeoutSeconds,
|
|
233
|
+
signal,
|
|
234
|
+
});
|
|
235
|
+
this.exchangesValue += result.exchanges;
|
|
236
|
+
if (claim !== undefined) {
|
|
237
|
+
if (result.started !== undefined) {
|
|
238
|
+
claim.resolve(result.started, endpoint);
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
claim.reject(result.startFailure ?? new CamusError(CamusErrorCode.Generic, 'The transaction did not begin.'));
|
|
242
|
+
}
|
|
243
|
+
claim = undefined;
|
|
244
|
+
}
|
|
245
|
+
batch.forEach((statement, i) => {
|
|
246
|
+
const outcome = result.statements[i] ?? {};
|
|
247
|
+
statement.settle(outcome);
|
|
248
|
+
// A pipelined statement teaches the router what a lone one would. Without this, the first
|
|
249
|
+
// exchange of every deferred transaction starts on the pool's rotation, most of them on a
|
|
250
|
+
// follower, and every statement of the transaction is forwarded from there.
|
|
251
|
+
const advice = outcome.query?.routing ?? outcome.nonQuery?.routing;
|
|
252
|
+
if (advice !== undefined) {
|
|
253
|
+
router?.learn(database, statement.sql, statement.routeKind, advice, observed[i]);
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
if (commit && result.committed)
|
|
257
|
+
transaction.markCommittedByPipeline();
|
|
258
|
+
const first = firstPipelineFailure(result);
|
|
259
|
+
if (first !== undefined)
|
|
260
|
+
throw first;
|
|
261
|
+
}
|
|
262
|
+
catch (error) {
|
|
263
|
+
const failure = error instanceof Error ? error : new Error(String(error));
|
|
264
|
+
// A failure before the exchange, or of the exchange itself: nothing was settled. So settle it
|
|
265
|
+
// all with the one failure, the claim included, so that no caller waits forever.
|
|
266
|
+
claim?.reject(failure);
|
|
267
|
+
for (const statement of batch)
|
|
268
|
+
statement.fail(failure);
|
|
269
|
+
throw error;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Where a transaction that has not begun yet begins: the first statement's learned route when
|
|
274
|
+
* the client routes, and the pool's rotation if not. That is the choice a lone first statement
|
|
275
|
+
* makes.
|
|
276
|
+
*/
|
|
277
|
+
chooseEndpoint(batch) {
|
|
278
|
+
const router = this.runtime.router;
|
|
279
|
+
const first = batch[0];
|
|
280
|
+
if (router !== undefined && first !== undefined) {
|
|
281
|
+
const learned = router.selectEndpoint(this.runtime.database, first.sql, first.routeKind);
|
|
282
|
+
if (learned.endpoint !== undefined)
|
|
283
|
+
return learned.endpoint;
|
|
284
|
+
}
|
|
285
|
+
return this.runtime.nextEndpoint();
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
/** One queued statement, and the promise its caller holds. */
|
|
289
|
+
class QueuedStatement {
|
|
290
|
+
sql;
|
|
291
|
+
parameters;
|
|
292
|
+
asReader;
|
|
293
|
+
kind;
|
|
294
|
+
routeKind;
|
|
295
|
+
int64;
|
|
296
|
+
promise;
|
|
297
|
+
resolve;
|
|
298
|
+
reject;
|
|
299
|
+
settled = false;
|
|
300
|
+
constructor(sql, parameters, asReader, kind, routeKind, int64) {
|
|
301
|
+
this.sql = sql;
|
|
302
|
+
this.parameters = parameters;
|
|
303
|
+
this.asReader = asReader;
|
|
304
|
+
this.kind = kind;
|
|
305
|
+
this.routeKind = routeKind;
|
|
306
|
+
this.int64 = int64;
|
|
307
|
+
this.promise = new Promise((resolve, reject) => {
|
|
308
|
+
this.resolve = resolve;
|
|
309
|
+
this.reject = reject;
|
|
310
|
+
});
|
|
311
|
+
// A caller that awaits only the send, which rejects with the same failure, must not be charged
|
|
312
|
+
// with an unhandled rejection. A caller that awaits this promise still sees the failure.
|
|
313
|
+
this.promise.catch(() => undefined);
|
|
314
|
+
}
|
|
315
|
+
settle(outcome) {
|
|
316
|
+
if (outcome.failure !== undefined) {
|
|
317
|
+
this.fail(outcome.failure);
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
if (this.asReader) {
|
|
321
|
+
if (outcome.query !== undefined) {
|
|
322
|
+
const { resultSet, cacheMetadata, routing } = outcome.query;
|
|
323
|
+
this.succeed({
|
|
324
|
+
...this.mapRows(resultSet),
|
|
325
|
+
cacheMetadata,
|
|
326
|
+
routingAdvice: routing,
|
|
327
|
+
});
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
if (outcome.nonQuery !== undefined) {
|
|
331
|
+
const { returning, affectedRows, routing } = outcome.nonQuery;
|
|
332
|
+
this.succeed({
|
|
333
|
+
...this.mapRows(returning ?? CamusResultSet.EMPTY),
|
|
334
|
+
affectedRows,
|
|
335
|
+
routingAdvice: routing,
|
|
336
|
+
});
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
if (outcome.nonQuery !== undefined) {
|
|
342
|
+
this.succeed({
|
|
343
|
+
affectedRows: outcome.nonQuery.affectedRows,
|
|
344
|
+
routingAdvice: outcome.nonQuery.routing,
|
|
345
|
+
});
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
if (outcome.query !== undefined) {
|
|
349
|
+
this.succeed({
|
|
350
|
+
affectedRows: outcome.query.resultSet.rowCount,
|
|
351
|
+
routingAdvice: outcome.query.routing,
|
|
352
|
+
});
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
this.fail(new CamusError(CamusErrorCode.Generic, 'The statement was not answered.'));
|
|
357
|
+
}
|
|
358
|
+
fail(error) {
|
|
359
|
+
if (this.settled)
|
|
360
|
+
return;
|
|
361
|
+
this.settled = true;
|
|
362
|
+
this.reject(error);
|
|
363
|
+
}
|
|
364
|
+
succeed(value) {
|
|
365
|
+
if (this.settled)
|
|
366
|
+
return;
|
|
367
|
+
this.settled = true;
|
|
368
|
+
this.resolve(value);
|
|
369
|
+
}
|
|
370
|
+
mapRows(resultSet) {
|
|
371
|
+
const mapper = new RowMapper(resultSet.columnNames, { int64: this.int64 });
|
|
372
|
+
return { rows: mapper.mapAll(resultSet), columns: resultSet.columns, rowCount: resultSet.rowCount };
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
//# sourceMappingURL=pipeline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of CamusDB
|
|
3
|
+
*
|
|
4
|
+
* For the full copyright and license information, please view the LICENSE.txt
|
|
5
|
+
* file that was distributed with this source code.
|
|
6
|
+
*/
|
|
7
|
+
import type { ClientRuntime } from '../runtime.js';
|
|
8
|
+
import type { EvictedStatement } from './policy.js';
|
|
9
|
+
/** What one statement's prepare step reads from its caller. */
|
|
10
|
+
export interface PrepareCallOptions {
|
|
11
|
+
readonly signal?: AbortSignal | undefined;
|
|
12
|
+
readonly timeoutSeconds?: number | undefined;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Whether this execution should name a prepared statement instead of carrying its SQL,
|
|
16
|
+
* registering it first when this is the execution that tips it over the threshold.
|
|
17
|
+
*
|
|
18
|
+
* The registration is awaited rather than started in the background, because the whole point is
|
|
19
|
+
* that this execution and the ones after it are cheap. Firing it off and running inline anyway
|
|
20
|
+
* would leave a busy statement racing its own warm-up. It costs one extra round trip, once per
|
|
21
|
+
* statement per endpoint.
|
|
22
|
+
*
|
|
23
|
+
* The caller passes the endpoint it already resolved. A REST handle is node-local and the pool
|
|
24
|
+
* rotates, so registering against a freshly drawn endpoint would routinely prepare on one node
|
|
25
|
+
* and execute on another — correct, because the transport re-registers where it lands, but a
|
|
26
|
+
* wasted round trip every single time.
|
|
27
|
+
*/
|
|
28
|
+
export declare function shouldPrepare(runtime: ClientRuntime, sql: string, endpoint: string, options: PrepareCallOptions): Promise<boolean>;
|
|
29
|
+
/**
|
|
30
|
+
* Registers a statement and records what happened, reporting whether it may now run prepared.
|
|
31
|
+
*
|
|
32
|
+
* A registration failure never reaches the caller: preparing is an optimization, and the
|
|
33
|
+
* statement runs inline exactly as it would have if the driver had not tried. What the failure
|
|
34
|
+
* does decide is whether to ask again. A refusal specific to this statement stops asking for that
|
|
35
|
+
* statement; anything that says the node has no prepared-statement support at all stops asking
|
|
36
|
+
* for every statement, because one round trip per distinct SQL to relearn that is worse than not
|
|
37
|
+
* trying. A failure that never reached a verdict — a timeout, an unreachable node — drops the
|
|
38
|
+
* entry instead, so one network blip does not cost this statement its registration for the life
|
|
39
|
+
* of the process.
|
|
40
|
+
*/
|
|
41
|
+
export declare function registerStatement(runtime: ClientRuntime, endpoint: string, database: string, sql: string, options: PrepareCallOptions): Promise<boolean>;
|
|
42
|
+
/**
|
|
43
|
+
* Releases a statement the policy evicted, so the server stops holding a handle this client has
|
|
44
|
+
* stopped using.
|
|
45
|
+
*
|
|
46
|
+
* It is best effort and off the caller's path: it is bookkeeping, not part of the statement being
|
|
47
|
+
* run. It takes the endpoint the caller already resolved rather than drawing a new one, which
|
|
48
|
+
* would rotate the pool as a side effect of housekeeping.
|
|
49
|
+
*/
|
|
50
|
+
export declare function releaseEvicted(runtime: ClientRuntime, endpoint: string, evicted: EvictedStatement | undefined): void;
|
|
51
|
+
//# sourceMappingURL=auto-prepare.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-prepare.d.ts","sourceRoot":"","sources":["../../src/prepared/auto-prepare.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AASnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,+DAA+D;AAC/D,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC9C;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,aAAa,EACtB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,OAAO,CAAC,CAyBlB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,aAAa,EACtB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,OAAO,CAAC,CAyClB;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,aAAa,EACtB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,gBAAgB,GAAG,SAAS,GACpC,IAAI,CAMN"}
|