camusdb 0.5.0 → 0.7.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 +207 -5
- package/dist/client.d.ts +42 -37
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +117 -166
- 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/json.d.ts +4 -3
- package/dist/json.d.ts.map +1 -1
- package/dist/json.js +10 -4
- package/dist/json.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 +126 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +363 -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 +4 -1
- package/dist/query-stream.d.ts.map +1 -1
- package/dist/query-stream.js +13 -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/statements.d.ts.map +1 -1
- package/dist/statements.js +37 -4
- 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 +422 -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/ndjson-row-source.d.ts +2 -0
- package/dist/transport/ndjson-row-source.d.ts.map +1 -1
- package/dist/transport/ndjson-row-source.js +7 -4
- package/dist/transport/ndjson-row-source.js.map +1 -1
- package/dist/transport/rest-decode.d.ts +14 -4
- package/dist/transport/rest-decode.d.ts.map +1 -1
- package/dist/transport/rest-decode.js +56 -17
- package/dist/transport/rest-decode.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/dist/values/encode.js +13 -5
- package/dist/values/encode.js.map +1 -1
- package/package.json +10 -4
- package/proto/camus_sql.proto +114 -0
package/README.md
CHANGED
|
@@ -12,6 +12,9 @@ The gRPC transport needs two more packages. Install them only if you use it:
|
|
|
12
12
|
npm install @grpc/grpc-js @grpc/proto-loader
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
+
Traces and metrics need `@opentelemetry/api`. Install it only if you collect them. See
|
|
16
|
+
[OpenTelemetry](#opentelemetry).
|
|
17
|
+
|
|
15
18
|
**Requirements**: Node.js 20.19 or later, or 22.12 or later. The package ships as ECMAScript
|
|
16
19
|
modules with TypeScript declarations.
|
|
17
20
|
|
|
@@ -36,8 +39,10 @@ modules with TypeScript declarations.
|
|
|
36
39
|
- [Databases and branches](#databases-and-branches)
|
|
37
40
|
- [The query result cache](#the-query-result-cache)
|
|
38
41
|
- [Backups](#backups)
|
|
42
|
+
- [Node stats](#node-stats)
|
|
39
43
|
- [Errors](#errors)
|
|
40
44
|
- [Cancellation and deadlines](#cancellation-and-deadlines)
|
|
45
|
+
- [OpenTelemetry](#opentelemetry)
|
|
41
46
|
- [What a client shares](#what-a-client-shares)
|
|
42
47
|
- [Security notes](#security-notes)
|
|
43
48
|
- [Development](#development)
|
|
@@ -119,6 +124,7 @@ const b = CamusClient.fromConnectionString('Endpoint=http://localhost:8082;Datab
|
|
|
119
124
|
| `coalescingDelayMs` | `CoalescingDelay` | No | gRPC only: milliseconds. Default `0`, which is off. |
|
|
120
125
|
| `requestFrames` | `RequestFrames` | No | gRPC only: pack the operations that wait together into one stream message. Default `true`. |
|
|
121
126
|
| `streamDrainTimeoutMs` | `StreamDrainTimeout` | No | gRPC only: milliseconds a rotated-out stream stays open for its transactions. Default `300000`. |
|
|
127
|
+
| `httpVersion` | `HttpVersion` | No | The highest HTTP version for REST calls. Only `1.1` (the default) is accepted. See the note below. |
|
|
122
128
|
| `backupEndpoint` | `BackupEndpoint` | No | The HTTP endpoint for the backup admin API. Required with `grpc`. |
|
|
123
129
|
| `backupTimeoutSeconds` | `BackupTimeout` | No | The backup request timeout in seconds. Default `300`. |
|
|
124
130
|
| `allowInsecureCredentials` | `AllowInsecureCredentials` | No | Waives the refusal to send credentials to a remote plaintext endpoint. |
|
|
@@ -127,6 +133,13 @@ const b = CamusClient.fromConnectionString('Endpoint=http://localhost:8082;Datab
|
|
|
127
133
|
| `routingMaxHintAgeMs` | `RoutingMaxHintAge` | No | The ceiling on how long a learned route is reused. Default `5000`. |
|
|
128
134
|
| `defaultTransactionOptions` | `IsolationLevel`, `TransactionMode`, `Locking` | No | Concurrency defaults for every transaction and autocommit statement. |
|
|
129
135
|
| `int64` | `Int64` | No | `auto` (the default), `number`, or `bigint`. See [Types](#types). |
|
|
136
|
+
| `traceQueryText` | `TraceQueryText` | No | Put the SQL text on the driver's spans as `db.query.text`. Default `false`. See [OpenTelemetry](#opentelemetry). |
|
|
137
|
+
|
|
138
|
+
**`HttpVersion`.** The .NET driver reads `HttpVersion=1.1|2|3` and can send REST calls over HTTP/2
|
|
139
|
+
or HTTP/3. Node's `fetch` sends HTTP/1.1 only. So this driver accepts `1.1`, and it refuses `2` and
|
|
140
|
+
`3` (also `2.0` and `3.0`) with a `CamusError` when the client is built. Remove the key, or set it
|
|
141
|
+
to `1.1`, in a connection string that you share with a .NET service. Any other value reads as `1.1`,
|
|
142
|
+
as in .NET. The key does not apply to `protocol: 'grpc'`, which always uses HTTP/2.
|
|
130
143
|
|
|
131
144
|
### How a connection string is parsed
|
|
132
145
|
|
|
@@ -223,15 +236,15 @@ change what the statement means.
|
|
|
223
236
|
| --- | --- |
|
|
224
237
|
| `null`, `undefined` | `Null` |
|
|
225
238
|
| `boolean` | `Bool` |
|
|
226
|
-
| `number` that is an integer | `Integer64` |
|
|
227
|
-
| `number` that is not | `Float64` |
|
|
239
|
+
| `number` that is an integer, other than `-0` | `Integer64` |
|
|
240
|
+
| `number` that is not, and `-0` | `Float64` |
|
|
228
241
|
| `bigint` | `Integer64` |
|
|
229
242
|
| `string` | `String` |
|
|
230
243
|
| `Date` | `DateTime` |
|
|
231
244
|
| `Uint8Array`, `Buffer`, `ArrayBuffer` | `Bytes` |
|
|
232
245
|
| `Float32Array` | `Bytes`, packed as a vector |
|
|
233
246
|
| `CamusObjectId` | `Id` |
|
|
234
|
-
| an array | `Array`, with the element type read from the first element that is not null. When that element is a whole `number` and another `number` element is not whole
|
|
247
|
+
| an array | `Array`, with the element type read from the first element that is not null. When that element is a whole `number` and another `number` element is not whole or is `-0`, the element type is `Float64`. |
|
|
235
248
|
|
|
236
249
|
A UUID-shaped string is **not** read as a `uuid`. A 36-character string that happens to look like
|
|
237
250
|
one would otherwise change type silently.
|
|
@@ -297,6 +310,15 @@ against an `OID` column. `camus.array(uuids, ColumnType.Id)` therefore sends a `
|
|
|
297
310
|
| `Numeric` | `string`, the exact decimal text — see [NUMERIC](#numeric) |
|
|
298
311
|
| `Array` | an array of the values above |
|
|
299
312
|
|
|
313
|
+
A `Float32` value is the single-precision number the server stored, on both transports. A negative
|
|
314
|
+
zero keeps its sign in both directions.
|
|
315
|
+
|
|
316
|
+
An array element reads as its element type on both transports. Over REST the driver reads that type
|
|
317
|
+
from the `elementType` field of the result's `columns`. An older server does not send the field. A
|
|
318
|
+
`Date`, `DateTime`, or `Bytes` element then reads as its wire value: the tick count as a number or
|
|
319
|
+
a `bigint`, and the bytes as base64 text. A `Float64` array whose numbers are all whole reads them
|
|
320
|
+
as integers. Use gRPC, or a newer server, when you read such arrays.
|
|
321
|
+
|
|
300
322
|
### 64-bit integers
|
|
301
323
|
|
|
302
324
|
CamusDB is a 64-bit database, and a JavaScript number stops being able to name every integer above
|
|
@@ -564,8 +586,8 @@ A server from 0.13.2 on has sequences. A sequence stores `int64` values only, ha
|
|
|
564
586
|
increment, and never cycles. The server refuses `CYCLE` with `CADB0533`, because a counter that
|
|
565
587
|
wraps would issue again the values that committed rows already hold.
|
|
566
588
|
|
|
567
|
-
`CREATE SEQUENCE`, `ALTER SEQUENCE`, and `
|
|
568
|
-
the create and the drop statements:
|
|
589
|
+
`CREATE SEQUENCE`, `ALTER SEQUENCE`, `DROP SEQUENCE`, and `COMMENT ON SEQUENCE` go to the DDL
|
|
590
|
+
route. Two helpers compose the create and the drop statements:
|
|
569
591
|
|
|
570
592
|
```ts
|
|
571
593
|
import { createSequenceStatement, dropSequenceStatement, nextValueExpression } from 'camusdb';
|
|
@@ -684,6 +706,10 @@ await client.transaction(work, {
|
|
|
684
706
|
- **`locking`** — `Pessimistic` (the default) takes locks up front. `Optimistic` stages the writes
|
|
685
707
|
and detects a conflict only at commit; a losing transaction fails its commit and must be retried.
|
|
686
708
|
It does not protect against phantoms.
|
|
709
|
+
- **`deferBegin`** — `true` sends `BEGIN` with the first statement, and not from
|
|
710
|
+
`beginTransaction`. When that first statement is a pipeline send, `BEGIN` travels inside the same
|
|
711
|
+
exchange. With learned routing on, `BEGIN` is deferred already. The transaction identity reads as
|
|
712
|
+
zero until the first statement, and a failure to begin comes from that statement.
|
|
687
713
|
|
|
688
714
|
Every knob is optional. A knob left unset falls back to the client's `defaultTransactionOptions`,
|
|
689
715
|
then to the connection-string defaults, then to the server default.
|
|
@@ -697,6 +723,63 @@ dead, so the driver re-issues the **same** commit on the **same** handle, backin
|
|
|
697
723
|
times. It never replays the work from the start, because that could apply an already-durable commit
|
|
698
724
|
a second time. This is handled inside the driver; you do not write it.
|
|
699
725
|
|
|
726
|
+
### Pipelined transactions
|
|
727
|
+
|
|
728
|
+
A transaction that awaits each statement pays one round trip for each statement: six for a bank
|
|
729
|
+
transfer (`BEGIN`, two reads, two writes, `COMMIT`). At high concurrency, those round trips set the
|
|
730
|
+
latency, and the statements do not. A pipeline sends the statements whose inputs are known as one
|
|
731
|
+
stream message, and it settles the promise of each statement from its own answer.
|
|
732
|
+
|
|
733
|
+
```ts
|
|
734
|
+
const txn = await client.beginTransaction({
|
|
735
|
+
locking: CamusLocking.Optimistic,
|
|
736
|
+
deferBegin: true, // BEGIN travels inside the first send
|
|
737
|
+
});
|
|
738
|
+
|
|
739
|
+
const pipeline = txn.pipeline();
|
|
740
|
+
|
|
741
|
+
// Exchange 1: [BEGIN, SELECT a, SELECT b]
|
|
742
|
+
const readA = pipeline.query<{ balance: number }>('SELECT balance FROM accounts WHERE id = @id', { id: a });
|
|
743
|
+
const readB = pipeline.query<{ balance: number }>('SELECT balance FROM accounts WHERE id = @id', { id: b });
|
|
744
|
+
await pipeline.send();
|
|
745
|
+
|
|
746
|
+
const fromBalance = (await readA).rows[0]!.balance;
|
|
747
|
+
const toBalance = (await readB).rows[0]!.balance;
|
|
748
|
+
|
|
749
|
+
// Exchange 2: [UPDATE a, UPDATE b, COMMIT]. The commit happens only if both updates succeed.
|
|
750
|
+
pipeline.execute('UPDATE accounts SET balance = @v WHERE id = @id', { v: fromBalance - amount, id: a });
|
|
751
|
+
pipeline.execute('UPDATE accounts SET balance = @v WHERE id = @id', { v: toBalance + amount, id: b });
|
|
752
|
+
await pipeline.commit();
|
|
753
|
+
|
|
754
|
+
console.log(`${pipeline.exchanges} round trips`); // 2 over gRPC
|
|
755
|
+
```
|
|
756
|
+
|
|
757
|
+
- **Results.** `query` returns the promise of a `QueryResult`, and `execute` returns the promise of
|
|
758
|
+
an `ExecuteResult`, as the client methods do. A write with `RETURNING` in `query` gives its rows
|
|
759
|
+
and `affectedRows`. `send` and `commit` also reject with the first failure, so a caller that awaits
|
|
760
|
+
only the send still learns of it. A queued promise that nobody awaits is never reported as an
|
|
761
|
+
unhandled rejection.
|
|
762
|
+
- **Failure.** The statements after a failed one in the same exchange still get an answer. The
|
|
763
|
+
transaction has ended, so they fail too, and `commit` rejects with the first failure and does not
|
|
764
|
+
commit. The server rolled the transaction back, so `rollback` is then a harmless call. To retry,
|
|
765
|
+
run the whole transaction again from `BEGIN`, as for any failed statement.
|
|
766
|
+
- **Commit.** After a successful `pipeline.commit()`, the transaction is committed. A later
|
|
767
|
+
`txn.rollback()` does nothing, and a later `txn.commit()` throws. Inside `client.transaction`, the
|
|
768
|
+
helper sees the pipeline commit and does not commit a second time.
|
|
769
|
+
- **Order.** The queued statements run in queue order, after every statement of the transaction
|
|
770
|
+
sent before them. A pipeline can be sent more than once on one transaction, and an ordinary
|
|
771
|
+
statement can run between two sends. One send at a time for each pipeline.
|
|
772
|
+
- **Exchanges.** `pipeline.exchanges` gives the round trips used. Over gRPC, to a server that
|
|
773
|
+
announces frame contract version 2 or higher, it is one for each send. Over REST, with
|
|
774
|
+
`requestFrames: false`, or against an older server, the driver runs the same statements one
|
|
775
|
+
exchange per step, with the same results, and the count shows it. The driver never sends an
|
|
776
|
+
older server something that it could misread.
|
|
777
|
+
- **Routing.** With learned routing on, a pipelined statement asks for routing advice, and the
|
|
778
|
+
driver learns the route from its reply, as for a lone statement. So the next deferred transaction
|
|
779
|
+
begins on the node that the advice names.
|
|
780
|
+
- **What cannot be queued.** DDL, which does not run inside the transaction, and `TRUNCATE`. These
|
|
781
|
+
throw a `CamusError` at queue time, and the pipeline stays usable.
|
|
782
|
+
|
|
700
783
|
---
|
|
701
784
|
|
|
702
785
|
## Retries
|
|
@@ -836,6 +919,10 @@ frame, and the fixed cost of a message is paid once instead of six times. A fram
|
|
|
836
919
|
more statements. A lone statement stays a plain single message, and a server that does not announce
|
|
837
920
|
frames never receives one. Set `requestFrames` to `false` to turn frames off.
|
|
838
921
|
|
|
922
|
+
A whole transaction can travel as one frame too: a pipeline puts the `BEGIN`, the statements, and a
|
|
923
|
+
conditional commit in one stream message. That needs a server that announces frame contract version
|
|
924
|
+
2. See [Pipelined transactions](#pipelined-transactions).
|
|
925
|
+
|
|
839
926
|
A stream carries its bearer token once, in the metadata it opens with, and gRPC gives no way to
|
|
840
927
|
change it later. The token provider renews the token every few minutes, so a long-lived stream
|
|
841
928
|
outlives the token it presented. Whether a server tolerates that is the server's decision. The
|
|
@@ -1057,6 +1144,39 @@ HTTP endpoint; the driver refuses to guess rather than send HTTP at a gRPC port.
|
|
|
1057
1144
|
|
|
1058
1145
|
---
|
|
1059
1146
|
|
|
1147
|
+
## Node stats
|
|
1148
|
+
|
|
1149
|
+
`client.nodeStats()` returns the disk, CPU, and memory of one node. It works over REST
|
|
1150
|
+
(`GET /v1/admin/stats`) and gRPC (`GetNodeStats`).
|
|
1151
|
+
|
|
1152
|
+
```ts
|
|
1153
|
+
const stats = await client.nodeStats(); // the next endpoint in the rotation
|
|
1154
|
+
const data = stats.dataVolume!; // the volume that holds data_dir
|
|
1155
|
+
|
|
1156
|
+
console.log(`${data.availableBytes} bytes free of ${data.totalBytes}`);
|
|
1157
|
+
console.log(`writes refused (below min_free_disk_bytes): ${data.belowWatermark}`);
|
|
1158
|
+
|
|
1159
|
+
for (const endpoint of client.endpoints) {
|
|
1160
|
+
const node = await client.nodeStats(endpoint); // one call for each node of a cluster
|
|
1161
|
+
console.log(`${node.address}: ${node.cpu.processCpuPercent}% CPU, ${node.memory.hostAvailableBytes} bytes free`);
|
|
1162
|
+
}
|
|
1163
|
+
```
|
|
1164
|
+
|
|
1165
|
+
- **Each node answers for itself.** `address` names the configured endpoint that answered.
|
|
1166
|
+
`nodeStats(endpoint)` accepts only an endpoint from `client.endpoints`, so the client's credentials
|
|
1167
|
+
never go to another address. Any other endpoint throws a `TypeError`.
|
|
1168
|
+
- **`-1` means unknown.** A value that the node could not read is `-1`, and `errors` names the field
|
|
1169
|
+
and the reason. One failed probe never fails the call. A value that an older server does not send
|
|
1170
|
+
is `-1` too.
|
|
1171
|
+
- **`belowWatermark` is the answer of the write gate.** While it is `true`, writes on that node fail
|
|
1172
|
+
with `CADB0536`.
|
|
1173
|
+
- **`MONITOR`, not superuser.** With authentication on, the account needs the superuser attribute or
|
|
1174
|
+
the `MONITOR` privilege: `GRANT MONITOR ON *.* TO monitoring;`. Other accounts get `CADB0517`.
|
|
1175
|
+
- **Cheap enough to poll.** The server answers from caches and a background sampler, so one call
|
|
1176
|
+
each minute from several monitors costs nothing measurable.
|
|
1177
|
+
|
|
1178
|
+
---
|
|
1179
|
+
|
|
1060
1180
|
## Errors
|
|
1061
1181
|
|
|
1062
1182
|
Every database-level failure is a `CamusError` carrying the server's `CADBxxxx` code.
|
|
@@ -1108,6 +1228,88 @@ not marked unreachable.
|
|
|
1108
1228
|
|
|
1109
1229
|
---
|
|
1110
1230
|
|
|
1231
|
+
## OpenTelemetry
|
|
1232
|
+
|
|
1233
|
+
The driver reports traces and metrics through `@opentelemetry/api`, which is an optional peer
|
|
1234
|
+
dependency. Install it, and register an OpenTelemetry SDK as usual. The driver needs no plugin and
|
|
1235
|
+
no extra setting:
|
|
1236
|
+
|
|
1237
|
+
```shell
|
|
1238
|
+
npm install @opentelemetry/api @opentelemetry/sdk-node
|
|
1239
|
+
```
|
|
1240
|
+
|
|
1241
|
+
```ts
|
|
1242
|
+
import { NodeSDK } from '@opentelemetry/sdk-node';
|
|
1243
|
+
|
|
1244
|
+
new NodeSDK({ /* exporters */ }).start();
|
|
1245
|
+
|
|
1246
|
+
// Every client reports from now on, under the instrumentation scope 'camusdb' (CAMUS_TELEMETRY_NAME).
|
|
1247
|
+
```
|
|
1248
|
+
|
|
1249
|
+
Without the package, the driver reports nothing and loads nothing for telemetry. The driver loads
|
|
1250
|
+
the package with `require` on the first operation, so the first operation is reported too. Register
|
|
1251
|
+
the SDK before the first database call.
|
|
1252
|
+
|
|
1253
|
+
**Spans.** The driver records one client span for each of these operations:
|
|
1254
|
+
|
|
1255
|
+
- A statement: `query` (and so `queryOne`, `scalar`, and `nextSequenceValue`), `queryStream`,
|
|
1256
|
+
`execute`, `executeDdl`, `evictCache`, and `evictAllCache`.
|
|
1257
|
+
- A typed insert (`insert`).
|
|
1258
|
+
- `BEGIN`, `COMMIT`, and `ROLLBACK`. One `COMMIT` span covers all the retries of an unresolved
|
|
1259
|
+
commit (`CADB0509`), with one `camusdb.retry` event for each retry.
|
|
1260
|
+
- A pipeline exchange, as one `BATCH` span with `db.operation.batch.size` and
|
|
1261
|
+
`camusdb.pipeline.commit`.
|
|
1262
|
+
|
|
1263
|
+
The span name is `{operation} {target}`, for example `SELECT shop`. The target is the table for a
|
|
1264
|
+
typed insert, and the database for all other operations. The span has these attributes from the
|
|
1265
|
+
[OpenTelemetry database conventions](https://opentelemetry.io/docs/specs/semconv/database/):
|
|
1266
|
+
|
|
1267
|
+
| Attribute | Value |
|
|
1268
|
+
| --- | --- |
|
|
1269
|
+
| `db.system.name` | `camusdb` |
|
|
1270
|
+
| `db.namespace` | The database of the client. |
|
|
1271
|
+
| `db.operation.name` | The first keyword of the SQL text, if it is a known verb (`SELECT`, `INSERT`, `UPDATE`, `DELETE`, `CREATE`, `ALTER`, `DROP`, `TRUNCATE`, and others), or `BEGIN`, `COMMIT`, `ROLLBACK`, `BATCH`. |
|
|
1272
|
+
| `db.collection.name` | The table of a typed insert. |
|
|
1273
|
+
| `server.address`, `server.port` | The endpoint that received the operation, after routing. |
|
|
1274
|
+
| `db.query.text` | The SQL text. Only with `traceQueryText: true`. |
|
|
1275
|
+
| `error.type`, `db.response.status_code` | The `CADBxxxx` code of a failed operation, or the error name when there is no code. |
|
|
1276
|
+
| `camusdb.transport` | `rest` or `grpc`. |
|
|
1277
|
+
|
|
1278
|
+
The span is a child of the active span. While the operation runs, the driver span is the active
|
|
1279
|
+
span, so the HTTP or gRPC spans of the transport are its children. This needs a context manager,
|
|
1280
|
+
which `NodeSDK` registers.
|
|
1281
|
+
|
|
1282
|
+
**Duration metric.** The driver records the `db.client.operation.duration` histogram, in seconds,
|
|
1283
|
+
for the same operations. Its attributes are `db.system.name`, `db.namespace`, `db.operation.name`,
|
|
1284
|
+
`server.address`, `server.port`, `error.type`, and `db.response.status_code`. The SQL text is never
|
|
1285
|
+
an attribute.
|
|
1286
|
+
|
|
1287
|
+
**Driver metrics.** The same meter also has these metrics:
|
|
1288
|
+
|
|
1289
|
+
| Metric | Type | Attributes | What it counts |
|
|
1290
|
+
| --- | --- | --- | --- |
|
|
1291
|
+
| `camusdb.client.operation.retries` | Counter | `camusdb.retry.kind`, `error.type`, and `db.namespace` and `db.operation.name` when known | Each time the driver sends an operation again. The kinds are `finalize` (a `COMMIT` or `ROLLBACK` after `CADB0509`), `autocommit` (`withRetry`), `transaction` (`client.transaction` from `BEGIN`), `token_renewal` (a call sent again with a new token after `CADB0516`), and `create_database`. When a driver span is active, the retry is also a `camusdb.retry` event on it. |
|
|
1292
|
+
| `camusdb.client.endpoint.quarantines` | Counter | `server.address`, `server.port` | Each time an endpoint fails at the transport level and the driver sets it aside for 30 seconds. |
|
|
1293
|
+
| `camusdb.client.endpoint.quarantined` | Gauge | `server.address`, `server.port` | `1` while the endpoint is set aside, `0` while it takes traffic. |
|
|
1294
|
+
| `camusdb.client.prepared_statement.lookups` | Counter | `db.namespace`, `camusdb.prepared_statement.result` | Each execution of a preparable statement: `hit` (already prepared), `registered` (prepared by this execution), or `miss` (sent as SQL text). |
|
|
1295
|
+
| `camusdb.client.prepared_statement.registrations` | Counter | `db.namespace`, `camusdb.prepared_statement.result`, `error.type` | Each request to prepare a statement that got an answer: `success`, `refused` (the statement runs as SQL text from then on), or `unsupported` (the server has no prepared statements, so automatic preparation stops). |
|
|
1296
|
+
| `camusdb.client.prepared_statement.evictions` | Counter | `db.namespace` | Each prepared statement released to make room for one used more recently. See `maxAutoPrepare`. |
|
|
1297
|
+
| `camusdb.client.prepared_statement.count` | UpDownCounter | `db.namespace` | The statements kept prepared now. |
|
|
1298
|
+
|
|
1299
|
+
If `count` stays at `maxAutoPrepare` and `evictions` keeps growing, `maxAutoPrepare` is too small
|
|
1300
|
+
for the workload.
|
|
1301
|
+
|
|
1302
|
+
- **The SQL text is opt-in.** SQL text with literal values can contain sensitive data, so set
|
|
1303
|
+
`traceQueryText: true` (or `TraceQueryText=true`) to record it. The driver never records
|
|
1304
|
+
parameter values.
|
|
1305
|
+
- **A stream ends its span at the last row.** For `queryStream`, the span ends when the iteration
|
|
1306
|
+
reaches the last row, when a read fails, or when the stream is closed.
|
|
1307
|
+
- **A provider registered later.** The metrics API has no proxy provider, so the driver makes its
|
|
1308
|
+
instruments again when the global meter provider changes. Spans go through the proxy tracer of the
|
|
1309
|
+
API, so a tracer provider registered later gets them too.
|
|
1310
|
+
|
|
1311
|
+
---
|
|
1312
|
+
|
|
1111
1313
|
## What a client shares
|
|
1112
1314
|
|
|
1113
1315
|
A client holds no socket of its own. Four kinds of state are shared process-wide, keyed by what
|
package/dist/client.d.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { CamusBackupClient } from './backup.js';
|
|
8
8
|
import type { CamusCacheMetadata } from './cache.js';
|
|
9
9
|
import type { CamusClientOptions, CamusProtocol, ResolvedConfig } from './config.js';
|
|
10
|
+
import type { CamusNodeStats } from './node-stats.js';
|
|
10
11
|
import type { CamusTransactionOptions } from './options.js';
|
|
11
12
|
import { CamusQueryStream } from './query-stream.js';
|
|
12
13
|
import type { CamusColumn } from './result-set.js';
|
|
@@ -171,6 +172,7 @@ export declare class CamusClient implements AsyncDisposable {
|
|
|
171
172
|
* a large result, such as an `INSERT … SELECT … RETURNING` or an `UPDATE` of many rows.
|
|
172
173
|
*/
|
|
173
174
|
query<T = Record<string, unknown>>(sql: string, parameters?: Parameters, options?: AutocommitStatementOptions): Promise<QueryResult<T>>;
|
|
175
|
+
private runQuery;
|
|
174
176
|
/**
|
|
175
177
|
* Runs a `SELECT` and reads its first row, or `undefined` when it returned none. It accepts an
|
|
176
178
|
* `INSERT`, `UPDATE`, or `DELETE` with `RETURNING` as `query` does.
|
|
@@ -220,6 +222,7 @@ export declare class CamusClient implements AsyncDisposable {
|
|
|
220
222
|
* for it. The stream reports no written-row count, so count the rows as you read them.
|
|
221
223
|
*/
|
|
222
224
|
queryStream<T = Record<string, unknown>>(sql: string, parameters?: Parameters, options?: AutocommitStatementOptions): Promise<CamusQueryStream<T>>;
|
|
225
|
+
private openQueryStream;
|
|
223
226
|
/**
|
|
224
227
|
* Runs an `INSERT`, `UPDATE`, or `DELETE` and reports how many rows it changed.
|
|
225
228
|
*
|
|
@@ -246,6 +249,7 @@ export declare class CamusClient implements AsyncDisposable {
|
|
|
246
249
|
* deliver, and the driver refuses it before the round trip.
|
|
247
250
|
*/
|
|
248
251
|
executeDdl(sql: string, options?: AutocommitStatementOptions): Promise<boolean>;
|
|
252
|
+
private runDdl;
|
|
249
253
|
/**
|
|
250
254
|
* Inserts one row through the server's typed row-level route, naming a table and a column-to-value
|
|
251
255
|
* map instead of composing SQL.
|
|
@@ -258,6 +262,38 @@ export declare class CamusClient implements AsyncDisposable {
|
|
|
258
262
|
* health, and error translation. Use it to avoid building statement text for a hot write path.
|
|
259
263
|
*/
|
|
260
264
|
insert(table: string, values: Parameters, options?: StatementOptions): Promise<number>;
|
|
265
|
+
/** The endpoints that this client is configured with, in configuration order. */
|
|
266
|
+
get endpoints(): readonly string[];
|
|
267
|
+
/**
|
|
268
|
+
* The disk, CPU, and memory of one node. See `CamusNodeStats` for every field.
|
|
269
|
+
*
|
|
270
|
+
* ```ts
|
|
271
|
+
* const stats = await client.nodeStats();
|
|
272
|
+
* const data = stats.dataVolume!;
|
|
273
|
+
*
|
|
274
|
+
* console.log(`${data.availableBytes} bytes free of ${data.totalBytes}`);
|
|
275
|
+
*
|
|
276
|
+
* for (const endpoint of client.endpoints) {
|
|
277
|
+
* const node = await client.nodeStats(endpoint);
|
|
278
|
+
* console.log(`${node.address}: ${node.cpu.processCpuPercent}% CPU`);
|
|
279
|
+
* }
|
|
280
|
+
* ```
|
|
281
|
+
*
|
|
282
|
+
* Without `endpoint`, it asks the next node in the rotation. Each node answers only for itself.
|
|
283
|
+
* An `endpoint` must be one of `endpoints`, so the client's credentials go only to the addresses
|
|
284
|
+
* it was configured with.
|
|
285
|
+
*
|
|
286
|
+
* It is server-level, not scoped to this client's database, and it works over REST
|
|
287
|
+
* (`GET /v1/admin/stats`) and gRPC (`GetNodeStats`). With authentication on, the account needs
|
|
288
|
+
* the superuser attribute or the `MONITOR` privilege (`GRANT MONITOR ON *.* TO <user>`). Any
|
|
289
|
+
* other account gets `CADB0517`.
|
|
290
|
+
*
|
|
291
|
+
* @throws {TypeError} when `endpoint` is not one of `endpoints`.
|
|
292
|
+
*/
|
|
293
|
+
nodeStats(endpoint?: string, options?: {
|
|
294
|
+
signal?: AbortSignal;
|
|
295
|
+
timeoutSeconds?: number;
|
|
296
|
+
}): Promise<CamusNodeStats>;
|
|
261
297
|
/** Reports whether the server answers. */
|
|
262
298
|
ping(options?: {
|
|
263
299
|
signal?: AbortSignal;
|
|
@@ -280,6 +316,9 @@ export declare class CamusClient implements AsyncDisposable {
|
|
|
280
316
|
*
|
|
281
317
|
* With `await using`, a transaction that is left without a commit is rolled back as the block
|
|
282
318
|
* unwinds.
|
|
319
|
+
*
|
|
320
|
+
* With `deferBegin`, or with learned routing on, `BEGIN` is not sent here. The first statement,
|
|
321
|
+
* or the first `CamusPipeline` send, sends it.
|
|
283
322
|
*/
|
|
284
323
|
beginTransaction(options?: CamusTransactionOptions, signal?: AbortSignal): Promise<CamusTransaction>;
|
|
285
324
|
/**
|
|
@@ -299,6 +338,9 @@ export declare class CamusClient implements AsyncDisposable {
|
|
|
299
338
|
* an exponential back-off. So the function must be safe to run more than once — it must not send
|
|
300
339
|
* an email, charge a card, or mutate state outside the database on a path that could repeat.
|
|
301
340
|
*
|
|
341
|
+
* The work can commit the transaction itself with `CamusPipeline.commit`. The transaction is
|
|
342
|
+
* then not committed a second time.
|
|
343
|
+
*
|
|
302
344
|
* A commit that reports an unresolved outcome is **not** retried this way. That case is resolved
|
|
303
345
|
* inside `CamusTransaction`, by re-issuing the same commit on the same handle, because replaying
|
|
304
346
|
* the work could apply an already-durable commit twice.
|
|
@@ -467,43 +509,6 @@ export declare class CamusClient implements AsyncDisposable {
|
|
|
467
509
|
*/
|
|
468
510
|
private route;
|
|
469
511
|
private buildRequest;
|
|
470
|
-
/**
|
|
471
|
-
* Whether this execution should name a prepared statement instead of carrying its SQL,
|
|
472
|
-
* registering it first when this is the execution that tips it over the threshold.
|
|
473
|
-
*
|
|
474
|
-
* The registration is awaited rather than started in the background, because the whole point is
|
|
475
|
-
* that this execution and the ones after it are cheap. Firing it off and running inline anyway
|
|
476
|
-
* would leave a busy statement racing its own warm-up. It costs one extra round trip, once per
|
|
477
|
-
* statement per endpoint.
|
|
478
|
-
*
|
|
479
|
-
* The caller passes the endpoint it already resolved. A REST handle is node-local and the pool
|
|
480
|
-
* rotates, so registering against a freshly drawn endpoint would routinely prepare on one node
|
|
481
|
-
* and execute on another — correct, because the transport re-registers where it lands, but a
|
|
482
|
-
* wasted round trip every single time.
|
|
483
|
-
*/
|
|
484
|
-
private shouldPrepare;
|
|
485
|
-
/**
|
|
486
|
-
* Registers a statement and records what happened, reporting whether it may now run prepared.
|
|
487
|
-
*
|
|
488
|
-
* A registration failure never reaches the caller: preparing is an optimization, and the
|
|
489
|
-
* statement runs inline exactly as it would have if the driver had not tried. What the failure
|
|
490
|
-
* does decide is whether to ask again. A refusal specific to this statement stops asking for that
|
|
491
|
-
* statement; anything that says the node has no prepared-statement support at all stops asking
|
|
492
|
-
* for every statement, because one round trip per distinct SQL to relearn that is worse than not
|
|
493
|
-
* trying. A failure that never reached a verdict — a timeout, an unreachable node — drops the
|
|
494
|
-
* entry instead, so one network blip does not cost this statement its registration for the life
|
|
495
|
-
* of the process.
|
|
496
|
-
*/
|
|
497
|
-
private register;
|
|
498
|
-
/**
|
|
499
|
-
* Releases a statement the policy evicted, so the server stops holding a handle this client has
|
|
500
|
-
* stopped using.
|
|
501
|
-
*
|
|
502
|
-
* It is best effort and off the caller's path: it is bookkeeping, not part of the statement being
|
|
503
|
-
* run. It takes the endpoint the caller already resolved rather than drawing a new one, which
|
|
504
|
-
* would rotate the pool as a side effect of housekeeping.
|
|
505
|
-
*/
|
|
506
|
-
private release;
|
|
507
512
|
/**
|
|
508
513
|
* The effective options for a transaction or an autocommit statement: the caller's explicit knobs
|
|
509
514
|
* win, then this client's defaults, then the server default for any knob still unset.
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAGrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|