@zukhruf/mutex 0.3.40 → 0.3.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/README.md +18 -10
  2. package/dist/lock-stores/docker/docker-engine-store.d.ts +37 -0
  3. package/dist/lock-stores/docker/docker-engine-store.d.ts.map +1 -0
  4. package/dist/lock-stores/docker/docker-engine-store.js +312 -0
  5. package/dist/lock-stores/docker/docker-engine-store.js.map +1 -0
  6. package/dist/lock-stores/docker/index.d.ts +2 -0
  7. package/dist/lock-stores/docker/index.d.ts.map +1 -0
  8. package/dist/lock-stores/docker/index.js +2 -0
  9. package/dist/lock-stores/docker/index.js.map +1 -0
  10. package/dist/lock-stores/mariadb/index.d.ts +2 -0
  11. package/dist/lock-stores/mariadb/index.d.ts.map +1 -0
  12. package/dist/lock-stores/mariadb/index.js +2 -0
  13. package/dist/lock-stores/mariadb/index.js.map +1 -0
  14. package/dist/lock-stores/mariadb/mariadb-store.d.ts +33 -0
  15. package/dist/lock-stores/mariadb/mariadb-store.d.ts.map +1 -0
  16. package/dist/lock-stores/mariadb/mariadb-store.js +36 -0
  17. package/dist/lock-stores/mariadb/mariadb-store.js.map +1 -0
  18. package/dist/lock-stores/mysql/get-lock-dialect.d.ts +46 -0
  19. package/dist/lock-stores/mysql/get-lock-dialect.d.ts.map +1 -0
  20. package/dist/lock-stores/mysql/get-lock-dialect.js +80 -0
  21. package/dist/lock-stores/mysql/get-lock-dialect.js.map +1 -0
  22. package/dist/lock-stores/mysql/index.d.ts +2 -0
  23. package/dist/lock-stores/mysql/index.d.ts.map +1 -0
  24. package/dist/lock-stores/mysql/index.js +2 -0
  25. package/dist/lock-stores/mysql/index.js.map +1 -0
  26. package/dist/lock-stores/mysql/mysql-store.d.ts +37 -0
  27. package/dist/lock-stores/mysql/mysql-store.d.ts.map +1 -0
  28. package/dist/lock-stores/mysql/mysql-store.js +35 -0
  29. package/dist/lock-stores/mysql/mysql-store.js.map +1 -0
  30. package/dist/lock-stores/postgres/postgres-store.d.ts +2 -8
  31. package/dist/lock-stores/postgres/postgres-store.d.ts.map +1 -1
  32. package/dist/lock-stores/postgres/postgres-store.js +55 -226
  33. package/dist/lock-stores/postgres/postgres-store.js.map +1 -1
  34. package/dist/lock-stores/session/session-lock-store.d.ts +72 -0
  35. package/dist/lock-stores/session/session-lock-store.d.ts.map +1 -0
  36. package/dist/lock-stores/session/session-lock-store.js +221 -0
  37. package/dist/lock-stores/session/session-lock-store.js.map +1 -0
  38. package/dist/lock-stores/sqlite/sqlite-store.d.ts.map +1 -1
  39. package/dist/lock-stores/sqlite/sqlite-store.js +6 -25
  40. package/dist/lock-stores/sqlite/sqlite-store.js.map +1 -1
  41. package/dist/lock-stores/sqlserver/index.d.ts +2 -0
  42. package/dist/lock-stores/sqlserver/index.d.ts.map +1 -0
  43. package/dist/lock-stores/sqlserver/index.js +2 -0
  44. package/dist/lock-stores/sqlserver/index.js.map +1 -0
  45. package/dist/lock-stores/sqlserver/sqlserver-store.d.ts +40 -0
  46. package/dist/lock-stores/sqlserver/sqlserver-store.d.ts.map +1 -0
  47. package/dist/lock-stores/sqlserver/sqlserver-store.js +104 -0
  48. package/dist/lock-stores/sqlserver/sqlserver-store.js.map +1 -0
  49. package/dist/shared/in-process-turns.d.ts +17 -0
  50. package/dist/shared/in-process-turns.d.ts.map +1 -0
  51. package/dist/shared/in-process-turns.js +39 -0
  52. package/dist/shared/in-process-turns.js.map +1 -0
  53. package/dist/shared/key-digest.d.ts +8 -0
  54. package/dist/shared/key-digest.d.ts.map +1 -0
  55. package/dist/shared/key-digest.js +11 -0
  56. package/dist/shared/key-digest.js.map +1 -0
  57. package/package.json +21 -8
package/README.md CHANGED
@@ -38,22 +38,30 @@ The full program is in the recipe [Stop two requests from selling the last item]
38
38
 
39
39
  First find who writes to the resource. Then select the lock store with that [reach](./docs/concepts/reach.md). Each family of lock stores has its own import path. The root `@zukhruf/mutex` gives only `Mutex` and the acquire modes ([ADR 0020](./docs/adr/0020-each-store-family-has-its-own-import-path.md)).
40
40
 
41
- | Lock store | Import | Reach | Order | A holder stops | Needs |
42
- | ---------------------------------------------------------------- | ---------------------------- | --------------------------------------- | --------------------------------------- | --------------------------------------------- | -------------------------------------------- |
43
- | [MemoryStore](./docs/stores/memory-store.md) | `@zukhruf/mutex/memory` | One object | First come, first served | The locks stop with the process | Nothing |
44
- | [ThreadStore](./docs/stores/thread-store.md) | `@zukhruf/mutex/thread` | One process (threads) | First come, first served | Released when the worker exits | `adopt(worker)` |
45
- | [IpcStore](./docs/stores/ipc-store.md) | `@zukhruf/mutex/ipc` | Parent and its children | First come, first served | Released in approximately 2 ms | `fork()` and `adopt(child)` |
46
- | [TicketQueueFileStore](./docs/stores/ticket-queue-file-store.md) | `@zukhruf/mutex/file-system` | One host | First come, first served | Released after a waiter finds that it stopped | A shared directory |
47
- | [LockFileStore](./docs/stores/lock-file-store.md) | `@zukhruf/mutex/file-system` | One host | No order | Released after a waiter finds that it stopped | A shared directory |
48
- | [SqliteStore](./docs/stores/sqlite-store.md) | `@zukhruf/mutex/sqlite` | One host | First come, first served in one process | Released by the kernel | A shared directory |
49
- | [SocketStore](./docs/stores/socket-store.md) | `@zukhruf/mutex/socket` | One host | First come, first served | Released in approximately 2 ms | A shared directory |
50
- | [PostgresStore](./docs/stores/postgres-store.md) | `@zukhruf/mutex/postgres` | Every machine that reaches the database | Postgres' lock queue | Released when its session ends | A Postgres database and a `connect` function |
41
+ | Lock store | Import | Reach | Order | A holder stops | Needs |
42
+ | ---------------------------------------------------------------- | ---------------------------- | -------------------------------------------- | --------------------------------------- | --------------------------------------------- | ----------------------------------------------------------- |
43
+ | [MemoryStore](./docs/stores/memory-store.md) | `@zukhruf/mutex/memory` | One object | First come, first served | The locks stop with the process | Nothing |
44
+ | [ThreadStore](./docs/stores/thread-store.md) | `@zukhruf/mutex/thread` | One process (threads) | First come, first served | Released when the worker exits | `adopt(worker)` |
45
+ | [IpcStore](./docs/stores/ipc-store.md) | `@zukhruf/mutex/ipc` | Parent and its children | First come, first served | Released in approximately 2 ms | `fork()` and `adopt(child)` |
46
+ | [TicketQueueFileStore](./docs/stores/ticket-queue-file-store.md) | `@zukhruf/mutex/file-system` | One host | First come, first served | Released after a waiter finds that it stopped | A shared directory |
47
+ | [LockFileStore](./docs/stores/lock-file-store.md) | `@zukhruf/mutex/file-system` | One host | No order | Released after a waiter finds that it stopped | A shared directory |
48
+ | [SqliteStore](./docs/stores/sqlite-store.md) | `@zukhruf/mutex/sqlite` | One host | First come, first served in one process | Released by the kernel | A shared directory |
49
+ | [SocketStore](./docs/stores/socket-store.md) | `@zukhruf/mutex/socket` | One host | First come, first served | Released in approximately 2 ms | A shared directory |
50
+ | [PostgresStore](./docs/stores/postgres-store.md) | `@zukhruf/mutex/postgres` | Every machine that reaches the database | Postgres' lock queue | Released when its session ends | A Postgres database and a `connect` function |
51
+ | [SqlServerStore](./docs/stores/sqlserver-store.md) | `@zukhruf/mutex/sqlserver` | Every machine that reaches the database | SQL Server's lock queue | Released when its session ends | A SQL Server database and a `connect` function |
52
+ | [MysqlStore](./docs/stores/mysql-store.md) | `@zukhruf/mutex/mysql` | Every machine that reaches the database | MySQL's lock queue | Released when its session ends | A MySQL database and a `connect` function |
53
+ | [MariadbStore](./docs/stores/mariadb-store.md) | `@zukhruf/mutex/mariadb` | Every machine that reaches the database | MariaDB's lock queue | Released when its session ends | A MariaDB database and a `connect` function |
54
+ | [DockerEngineStore](./docs/stores/docker-engine-store.md) | `@zukhruf/mutex/docker` | Every machine that reaches the Docker engine | No order between processes | Released when its attach ends | A Docker engine, an image with `cat`, and `@zukhruf/docker` |
51
55
 
52
56
  If you are not sure:
53
57
 
54
58
  - **One process:** use `MemoryStore`.
55
59
  - **Several processes on one host:** use `SqliteStore`.
56
60
  - **Many machines that already use Postgres:** use `PostgresStore`.
61
+ - **Many machines that already use SQL Server:** use `SqlServerStore`.
62
+ - **Many machines that already use MySQL:** use `MysqlStore`.
63
+ - **Many machines that already use MariaDB:** use `MariadbStore`.
64
+ - **Many machines that already use one Docker engine, with no database:** use `DockerEngineStore`.
57
65
 
58
66
  ## Acquire modes
59
67
 
@@ -0,0 +1,37 @@
1
+ import { type Docker } from '@zukhruf/docker';
2
+ import type { LockHandle } from '../../mutex/lease.ts';
3
+ import type { AcquireOptions, LockStore } from '../../mutex/lock-store.ts';
4
+ export interface DockerEngineStoreOptions {
5
+ /** The client of the engine. The caller owns it; its disposal ends each attach, so each held key is lost. */
6
+ docker: Docker;
7
+ /** The image of each claim. It must be on the engine and have `cat` on its `PATH`; the store never pulls it. */
8
+ image: string;
9
+ /** The first part of each name and the value of the label `zukhruf.mutex.namespace`. Stores with one namespace on one engine share their locks. */
10
+ namespace: string;
11
+ /**
12
+ * Milliseconds between two heartbeats of a holder, and the time limit of
13
+ * each heartbeat: the longest time that a holder can work after its claim
14
+ * ended, before its signal aborts. It is also the time that a waiter gives
15
+ * a `created` claim before it removes it, and the time between two looks of
16
+ * a waiter at the claim.
17
+ */
18
+ heartbeatInterval: number;
19
+ }
20
+ /**
21
+ * Holds a key as a named container on one Docker engine: the claim. The claim
22
+ * runs `cat` on the standard input of the attach of its holder, so it ends
23
+ * and the engine removes it when the attach ends. Every process on every
24
+ * machine that reaches the engine shares the locks.
25
+ *
26
+ * Callers in this process first line up in a queue in memory, so one process
27
+ * makes at most one claim attempt for each key, in the order of the calls.
28
+ */
29
+ export declare class DockerEngineStore implements LockStore {
30
+ #private;
31
+ constructor(options: DockerEngineStoreOptions);
32
+ acquire(key: string, options?: AcquireOptions): Promise<LockHandle>;
33
+ tryAcquire(key: string): Promise<LockHandle | undefined>;
34
+ /** Reads the state of the claim, and never creates a container or mints a token. */
35
+ isHeld(key: string): Promise<boolean>;
36
+ }
37
+ //# sourceMappingURL=docker-engine-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docker-engine-store.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/docker/docker-engine-store.ts"],"names":[],"mappings":"AAEA,OAAO,EAML,KAAK,MAAM,EAEZ,MAAM,iBAAiB,CAAC;AAIzB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAI3E,MAAM,WAAW,wBAAwB;IACvC,6GAA6G;IAC7G,MAAM,EAAE,MAAM,CAAC;IACf,gHAAgH;IAChH,KAAK,EAAE,MAAM,CAAC;IACd,mJAAmJ;IACnJ,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;;OAMG;IACH,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAYD;;;;;;;;GAQG;AACH,qBAAa,iBAAkB,YAAW,SAAS;;gBAIrC,OAAO,EAAE,wBAAwB;IAI7C,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC;IAkBnE,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAOxD,oFAAoF;IAC9E,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAO5C"}
@@ -0,0 +1,312 @@
1
+ import { setTimeout as delay } from 'node:timers/promises';
2
+ import { ContainerNotFoundError, ContainerRunningError, NameConflictError, } from '@zukhruf/docker';
3
+ import { FencingToken } from '@zukhruf/fencing';
4
+ import { LeaseController } from '@zukhruf/lease';
5
+ import { InProcessTurns } from "../../shared/in-process-turns.js";
6
+ import { keyDigest } from "../../shared/key-digest.js";
7
+ const namespaceLabel = 'zukhruf.mutex.namespace';
8
+ const keyLabel = 'zukhruf.mutex.key';
9
+ const tokenLabel = 'zukhruf.mutex.token';
10
+ /** The states of a claim that no other caller can take the key from. */
11
+ const holdingStates = new Set(['created', 'running', 'paused', 'restarting']);
12
+ /** The states of a claim that ended: no holder can have it, and only a removal makes its name free. */
13
+ const endedStates = new Set(['exited', 'dead']);
14
+ /**
15
+ * Holds a key as a named container on one Docker engine: the claim. The claim
16
+ * runs `cat` on the standard input of the attach of its holder, so it ends
17
+ * and the engine removes it when the attach ends. Every process on every
18
+ * machine that reaches the engine shares the locks.
19
+ *
20
+ * Callers in this process first line up in a queue in memory, so one process
21
+ * makes at most one claim attempt for each key, in the order of the calls.
22
+ */
23
+ export class DockerEngineStore {
24
+ #turns = new InProcessTurns();
25
+ #options;
26
+ constructor(options) {
27
+ this.#options = options;
28
+ }
29
+ acquire(key, options) {
30
+ return this.#turns.acquire(key, options, async () => {
31
+ const signal = options?.signal;
32
+ const claims = new Claims(key, this.#options);
33
+ const cancel = signal === undefined ? {} : { signal };
34
+ for (;;) {
35
+ signal?.throwIfAborted();
36
+ const claim = await claims.create(signal);
37
+ if (claim === undefined) {
38
+ await claims.waitForRelease(cancel);
39
+ continue;
40
+ }
41
+ const handle = await claim.hold();
42
+ if (handle !== undefined)
43
+ return handle;
44
+ }
45
+ });
46
+ }
47
+ tryAcquire(key) {
48
+ return this.#turns.tryAcquire(key, async () => {
49
+ const claim = await new Claims(key, this.#options).create(undefined);
50
+ return claim?.hold();
51
+ });
52
+ }
53
+ /** Reads the state of the claim, and never creates a container or mints a token. */
54
+ async isHeld(key) {
55
+ const claim = await this.#options.docker.containers.find(claimName(key, this.#options.namespace));
56
+ if (claim === undefined)
57
+ return false;
58
+ return holdingStates.has((await stateOf(claim)) ?? '');
59
+ }
60
+ }
61
+ /** The key digest in hexadecimal. */
62
+ function digestOf(key) {
63
+ return keyDigest(key).toString('hex');
64
+ }
65
+ function claimName(key, namespace) {
66
+ return `${namespace}-${digestOf(key)}`;
67
+ }
68
+ /** The state of the container, or undefined when it is gone. */
69
+ async function stateOf(container, cancel = {}) {
70
+ try {
71
+ return (await container.inspect(cancel)).State?.Status;
72
+ }
73
+ catch (error) {
74
+ if (error instanceof ContainerNotFoundError)
75
+ return undefined;
76
+ throw error;
77
+ }
78
+ }
79
+ /** The claims of one key: their create, and the wait of a caller that did not get the name. */
80
+ class Claims {
81
+ #key;
82
+ #options;
83
+ #name;
84
+ constructor(key, options) {
85
+ this.#key = key;
86
+ this.#options = options;
87
+ this.#name = claimName(key, options.namespace);
88
+ }
89
+ /** The new claim, or undefined when another caller has the name. A cancel after the create removes the new claim. */
90
+ async create(signal) {
91
+ const { docker, image, namespace } = this.#options;
92
+ let container;
93
+ try {
94
+ container = await docker.containers.create({
95
+ Image: image,
96
+ Entrypoint: ['cat'],
97
+ Cmd: [],
98
+ OpenStdin: true,
99
+ StdinOnce: true,
100
+ AttachStdin: true,
101
+ Labels: { [namespaceLabel]: namespace, [keyLabel]: this.#key },
102
+ HostConfig: { AutoRemove: true },
103
+ }, { name: this.#name });
104
+ }
105
+ catch (error) {
106
+ if (error instanceof NameConflictError)
107
+ return undefined;
108
+ throw error;
109
+ }
110
+ if (signal?.aborted) {
111
+ await container.remove({ force: true });
112
+ throw signal.reason;
113
+ }
114
+ return new Claim(container, this.#key, this.#options);
115
+ }
116
+ /**
117
+ * Waits by ID for the claim that has the name, so that a release before the
118
+ * wait is never lost. Each wait lasts at most `heartbeatInterval`, and then
119
+ * the waiter looks at the claim again:
120
+ *
121
+ * - An `exited` or `dead` claim has no holder. Its removal failed, so the
122
+ * waiter removes it.
123
+ * - A claim that stays `created` gets a removal without force: the engine
124
+ * lets only one of that removal and the start of its caller succeed.
125
+ * - A `running`, `paused` or `restarting` claim can have a live holder, so
126
+ * the waiter never removes it, and waits again.
127
+ */
128
+ async waitForRelease(cancel) {
129
+ const claim = await this.#options.docker.containers.find(this.#name, cancel);
130
+ if (claim === undefined)
131
+ return;
132
+ let state = await stateOf(claim, cancel);
133
+ for (;;) {
134
+ if (state === undefined)
135
+ return;
136
+ if (endedStates.has(state)) {
137
+ await removeUnlessRunning(claim, cancel);
138
+ return;
139
+ }
140
+ const seen = state;
141
+ if (await this.#removedWithin(claim, cancel))
142
+ return;
143
+ state = await stateOf(claim, cancel);
144
+ if (seen === 'created' && state === 'created') {
145
+ await removeUnlessRunning(claim, cancel);
146
+ return;
147
+ }
148
+ }
149
+ }
150
+ /** True when the claim is gone within `heartbeatInterval`, false when it is still there. */
151
+ async #removedWithin(claim, { signal }) {
152
+ const patience = AbortSignal.timeout(this.#options.heartbeatInterval);
153
+ try {
154
+ await claim.wait({
155
+ condition: 'removed',
156
+ signal: signal === undefined ? patience : AbortSignal.any([signal, patience]),
157
+ });
158
+ return true;
159
+ }
160
+ catch (error) {
161
+ if (error instanceof ContainerNotFoundError)
162
+ return true;
163
+ if (signal?.aborted || !patience.aborted)
164
+ throw error;
165
+ return false;
166
+ }
167
+ }
168
+ }
169
+ /**
170
+ * Removes the claim by its ID without force, so that a claim of a later
171
+ * holder with the same name is never removed. The engine lets only one of
172
+ * this removal and the start of a `created` claim succeed.
173
+ */
174
+ async function removeUnlessRunning(claim, cancel) {
175
+ try {
176
+ await claim.remove({ force: false, ...cancel });
177
+ }
178
+ catch (error) {
179
+ if (!(error instanceof ContainerRunningError))
180
+ throw error;
181
+ }
182
+ }
183
+ /** A claim that this caller created: it attaches, starts, mints and confirms, then holds with a heartbeat. */
184
+ class Claim {
185
+ #container;
186
+ #key;
187
+ #options;
188
+ #lease;
189
+ /** Aborts when the store stops holding: a release, or a lost claim. */
190
+ #done = new AbortController();
191
+ constructor(container, key, options) {
192
+ this.#container = container;
193
+ this.#key = key;
194
+ this.#options = options;
195
+ this.#lease = new LeaseController(key);
196
+ }
197
+ /** The handle of the key, or undefined when a waiter removed the claim before its start, or the claim ended during the mint. */
198
+ async hold() {
199
+ let attach;
200
+ let token;
201
+ try {
202
+ // The attach comes before the start, so the claim never runs without it.
203
+ attach = await this.#container.attach({ stdin: true });
204
+ const ended = attach.exitCode;
205
+ ended.catch(() => { });
206
+ await this.#container.start();
207
+ token = await this.#mint();
208
+ if ((await stateOf(this.#container)) === undefined)
209
+ return undefined;
210
+ ended.then((code) => this.#lose(new Error(`The claim exited with the code ${code}.`)), (cause) => this.#lose(cause));
211
+ }
212
+ catch (error) {
213
+ if (error instanceof ContainerNotFoundError)
214
+ return undefined;
215
+ await this.#container.remove({ force: true });
216
+ throw error;
217
+ }
218
+ void this.#beat();
219
+ return {
220
+ token,
221
+ signal: this.#lease.signal,
222
+ [Symbol.asyncDispose]: () => this.#release(),
223
+ };
224
+ }
225
+ /**
226
+ * Creates the rung above the highest rung of the ladder of the key, climbs
227
+ * on a taken name, then removes the rungs that it read. A rung goes only
228
+ * after a higher one exists, so a list always finds the highest rung.
229
+ */
230
+ async #mint() {
231
+ const { docker, namespace } = this.#options;
232
+ const digest = digestOf(this.#key);
233
+ const prefix = `${namespace}-${digest}-token-`;
234
+ const rungs = await docker.volumes.list({
235
+ filters: {
236
+ label: [`${namespaceLabel}=${namespace}`, `${tokenLabel}=${digest}`],
237
+ },
238
+ });
239
+ let rung = 0;
240
+ for (const { Name } of rungs) {
241
+ if (!Name.startsWith(prefix))
242
+ continue;
243
+ const number = Number(Name.slice(prefix.length));
244
+ if (Number.isSafeInteger(number) && number > rung)
245
+ rung = number;
246
+ }
247
+ for (;;) {
248
+ rung += 1;
249
+ try {
250
+ await docker.volumes.create({
251
+ Name: `${prefix}${rung}`,
252
+ Labels: { [namespaceLabel]: namespace, [tokenLabel]: digest },
253
+ });
254
+ break;
255
+ }
256
+ catch (error) {
257
+ if (!(error instanceof NameConflictError))
258
+ throw error;
259
+ }
260
+ }
261
+ for (const { Name } of rungs) {
262
+ await (await docker.volumes.find(Name))?.remove();
263
+ }
264
+ return new FencingToken(BigInt(rung));
265
+ }
266
+ /** Inspects the claim each interval. A claim that is gone or does not run, or a failed or late answer, loses the lease. */
267
+ async #beat() {
268
+ const interval = this.#options.heartbeatInterval;
269
+ const done = this.#done.signal;
270
+ try {
271
+ for (;;) {
272
+ await delay(interval, undefined, { signal: done });
273
+ const state = await stateOf(this.#container, {
274
+ signal: AbortSignal.any([done, AbortSignal.timeout(interval)]),
275
+ });
276
+ if (state !== 'running') {
277
+ throw new Error(state === undefined
278
+ ? 'The claim is gone.'
279
+ : `The claim is ${state}.`);
280
+ }
281
+ }
282
+ }
283
+ catch (cause) {
284
+ if (!done.aborted)
285
+ this.#lose(cause);
286
+ }
287
+ }
288
+ /** Another caller can have the key now. A claim that still runs is removed, so that waiters do not wait for it. */
289
+ #lose(cause) {
290
+ if (this.#done.signal.aborted)
291
+ return;
292
+ this.#done.abort();
293
+ this.#lease.lose(cause);
294
+ // Nobody waits for this removal; a failed one leaves the claim to the end of its attach.
295
+ this.#container.remove({ force: true }).catch(() => { });
296
+ }
297
+ /** Removes the claim by its ID, so that a release never removes the claim of a later holder. */
298
+ async #release() {
299
+ if (this.#done.signal.aborted)
300
+ return;
301
+ this.#done.abort();
302
+ try {
303
+ await this.#container.remove({ force: true });
304
+ }
305
+ catch (cause) {
306
+ this.#lease.lose(cause);
307
+ return;
308
+ }
309
+ this.#lease.end();
310
+ }
311
+ }
312
+ //# sourceMappingURL=docker-engine-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docker-engine-store.js","sourceRoot":"","sources":["../../../src/lock-stores/docker/docker-engine-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export { DockerEngineStore, type DockerEngineStoreOptions, } from './docker-engine-store.ts';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/docker/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,KAAK,wBAAwB,GAC9B,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { DockerEngineStore, } from "./docker-engine-store.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lock-stores/docker/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,GAElB,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { MariadbStore, type MariadbSession, type MariadbStoreOptions, } from './mariadb-store.ts';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/mariadb/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,KAAK,cAAc,EACnB,KAAK,mBAAmB,GACzB,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { MariadbStore, } from "./mariadb-store.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lock-stores/mariadb/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,GAGb,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,33 @@
1
+ import { type GetLockSession } from '../mysql/get-lock-dialect.ts';
2
+ import { SessionLockStore } from '../session/session-lock-store.ts';
3
+ /**
4
+ * One connection to the MariaDB server: only the methods that the store
5
+ * calls. A `PoolConnection` of `mariadb` (MariaDB Connector/Node.js) fits it.
6
+ */
7
+ export interface MariadbSession extends GetLockSession {
8
+ query(sql: string, values: unknown[]): Promise<unknown>;
9
+ /** Gives the session back to its pool. It never rejects. */
10
+ release(): Promise<void>;
11
+ }
12
+ export interface MariadbStoreOptions {
13
+ /** Gives a new session. The store owns each session that it gets. */
14
+ connect(): Promise<MariadbSession>;
15
+ /** The name of an existing sequence in the database of the session, for the fencing tokens. The store runs no DDL. */
16
+ sequence: string;
17
+ /**
18
+ * Milliseconds between two heartbeats of a holder, and the time limit of
19
+ * each heartbeat: the longest time that a holder can work after its session
20
+ * ended, before its signal aborts.
21
+ */
22
+ heartbeatInterval: number;
23
+ }
24
+ /**
25
+ * Holds a MariaDB user lock (`GET_LOCK`) for each key, on a session of its
26
+ * own. The server releases the lock when the session ends, so a holder that
27
+ * stops never leaves a key locked. Every process on every machine that
28
+ * reaches one MariaDB database shares the locks.
29
+ */
30
+ export declare class MariadbStore extends SessionLockStore<MariadbSession> {
31
+ constructor({ connect, sequence, heartbeatInterval }: MariadbStoreOptions);
32
+ }
33
+ //# sourceMappingURL=mariadb-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mariadb-store.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/mariadb/mariadb-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EAIpB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAEpE;;;GAGG;AACH,MAAM,WAAW,cAAe,SAAQ,cAAc;IACpD,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACxD,4DAA4D;IAC5D,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,MAAM,WAAW,mBAAmB;IAClC,qEAAqE;IACrE,OAAO,IAAI,OAAO,CAAC,cAAc,CAAC,CAAC;IACnC,sHAAsH;IACtH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AASD;;;;;GAKG;AACH,qBAAa,YAAa,SAAQ,gBAAgB,CAAC,cAAc,CAAC;gBACpD,EAAE,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,EAAE,mBAAmB;CAM1E"}
@@ -0,0 +1,36 @@
1
+ import { getLockDialect, lockName, quoteName, } from "../mysql/get-lock-dialect.js";
2
+ import { SessionLockStore } from "../session/session-lock-store.js";
3
+ /**
4
+ * MariaDB's longest `GET_LOCK` timeout that the store uses: one year, in
5
+ * seconds. A negative timeout gives NULL, and a timeout that ends after
6
+ * 2^64 nanoseconds since 1970 gives 0 at once.
7
+ */
8
+ const oneYear = 31_536_000;
9
+ /**
10
+ * Holds a MariaDB user lock (`GET_LOCK`) for each key, on a session of its
11
+ * own. The server releases the lock when the session ends, so a holder that
12
+ * stops never leaves a key locked. Every process on every machine that
13
+ * reaches one MariaDB database shares the locks.
14
+ */
15
+ export class MariadbStore extends SessionLockStore {
16
+ constructor({ connect, sequence, heartbeatInterval }) {
17
+ super({ connect, heartbeatInterval }, getLockDialect(mariadbServer(quoteName(sequence))));
18
+ }
19
+ }
20
+ function mariadbServer(sequence) {
21
+ return {
22
+ server: 'MariaDB',
23
+ // The session's max_statement_time makes a waiting GET_LOCK give NULL.
24
+ waitStatement: `SET STATEMENT max_statement_time = 0 FOR SELECT GET_LOCK(${lockName}, ${oneYear}) AS locked`,
25
+ run: (session, sql, values) => session.query(sql, values),
26
+ giveBack: (session) => void session.release(),
27
+ mint: async (run) => {
28
+ const row = await run(`SELECT CAST(NEXTVAL(${sequence}) AS CHAR) AS token`, []);
29
+ if (typeof row?.['token'] !== 'string') {
30
+ throw new Error(`NEXTVAL of sequence ${sequence} gave no number.`);
31
+ }
32
+ return BigInt(row['token']);
33
+ },
34
+ };
35
+ }
36
+ //# sourceMappingURL=mariadb-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mariadb-store.js","sourceRoot":"","sources":["../../../src/lock-stores/mariadb/mariadb-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,cAAc,EACd,QAAQ,EACR,SAAS,GACV,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAyBpE;;;;GAIG;AACH,MAAM,OAAO,GAAG,UAAU,CAAC;AAE3B;;;;;GAKG;AACH,MAAM,OAAO,YAAa,SAAQ,gBAAgC;IAChE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAuB;QACvE,KAAK,CACH,EAAE,OAAO,EAAE,iBAAiB,EAAE,EAC9B,cAAc,CAAC,aAAa,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,CACnD,CAAC;IACJ,CAAC;CACF;AAED,SAAS,aAAa,CAAC,QAAgB;IACrC,OAAO;QACL,MAAM,EAAE,SAAS;QACjB,uEAAuE;QACvE,aAAa,EAAE,4DAA4D,QAAQ,KAAK,OAAO,aAAa;QAC5G,GAAG,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC;QACzD,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,OAAO,CAAC,OAAO,EAAE;QAC7C,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YAClB,MAAM,GAAG,GAAG,MAAM,GAAG,CACnB,uBAAuB,QAAQ,qBAAqB,EACpD,EAAE,CACH,CAAC;YACF,IAAI,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;gBACvC,MAAM,IAAI,KAAK,CAAC,uBAAuB,QAAQ,kBAAkB,CAAC,CAAC;YACrE,CAAC;YACD,OAAO,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;QAC9B,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,46 @@
1
+ import type { SessionLockDialect } from '../session/session-lock-store.ts';
2
+ /** The events and the close of one connection to a server of the MySQL family: the parts that both drivers share. */
3
+ export interface GetLockSession {
4
+ on(event: 'error', listener: (error: Error) => void): unknown;
5
+ on(event: 'end', listener: () => void): unknown;
6
+ off(event: 'error' | 'end', listener: (error: Error) => void): unknown;
7
+ /** Closes the connection; the server then releases each user lock of the session. */
8
+ destroy(): void;
9
+ }
10
+ export type Row = Record<string, unknown>;
11
+ /** Runs one statement on the session and gives its first row, if it gives rows. */
12
+ export type RunStatement = (sql: string, values: unknown[]) => Promise<Row | undefined>;
13
+ /** What differs between MySQL and MariaDB, and between their drivers. */
14
+ export interface GetLockServer<Session extends GetLockSession> {
15
+ /** The name of the server in error messages. */
16
+ readonly server: string;
17
+ /**
18
+ * `SELECT GET_LOCK(${lockName}, <timeout>) AS locked`, with the longest timeout of
19
+ * the server, and free of the time limit of a statement of the session.
20
+ */
21
+ readonly waitStatement: string;
22
+ /** Runs a statement with the driver, and gives the result: the rows of a SELECT. */
23
+ run(session: Session, sql: string, values: unknown[]): Promise<unknown>;
24
+ /** Gives a session that holds nothing back to its pool. */
25
+ giveBack(session: Session): void;
26
+ /** Gives the next fencing token from the object that the caller created. */
27
+ mint(run: RunStatement): Promise<bigint>;
28
+ }
29
+ /**
30
+ * The name of the user lock, made on the server from the database of the
31
+ * session and the digest of the key (the one `?`). A user lock belongs to
32
+ * the whole server, but the token source belongs to one database, so the
33
+ * lock belongs to one database too. SHA-256 gives 64 lowercase hex
34
+ * characters: the limit of MySQL, and the same under a comparison with or
35
+ * without case. With no database, the name is NULL, and the statement fails.
36
+ */
37
+ export declare const lockName = "SHA2(CONCAT(DATABASE(), ':', ?), 256)";
38
+ /**
39
+ * The dialect of a user lock (`GET_LOCK`) for each key. The name of each lock
40
+ * includes the database of the session, so the locks belong to one database.
41
+ * The client sends the key digest as 64 lowercase hex characters.
42
+ */
43
+ export declare function getLockDialect<Session extends GetLockSession>(server: GetLockServer<Session>): SessionLockDialect<Session>;
44
+ /** Quotes one identifier for MySQL and MariaDB. */
45
+ export declare function quoteName(name: string): string;
46
+ //# sourceMappingURL=get-lock-dialect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-lock-dialect.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/mysql/get-lock-dialect.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAE3E,qHAAqH;AACrH,MAAM,WAAW,cAAc;IAC7B,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,OAAO,CAAC;IAC9D,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC;IAChD,GAAG,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,OAAO,CAAC;IACvE,qFAAqF;IACrF,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE1C,mFAAmF;AACnF,MAAM,MAAM,YAAY,GAAG,CACzB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,OAAO,EAAE,KACd,OAAO,CAAC,GAAG,GAAG,SAAS,CAAC,CAAC;AAE9B,yEAAyE;AACzE,MAAM,WAAW,aAAa,CAAC,OAAO,SAAS,cAAc;IAC3D,gDAAgD;IAChD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,oFAAoF;IACpF,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACxE,2DAA2D;IAC3D,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACjC,4EAA4E;IAC5E,IAAI,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC1C;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,QAAQ,0CAA0C,CAAC;AAehE;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,SAAS,cAAc,EAC3D,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC,GAC7B,kBAAkB,CAAC,OAAO,CAAC,CA+D7B;AAED,mDAAmD;AACnD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C"}