@zukhruf/mutex 0.3.16 → 0.3.17
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 +7 -8
- package/dist/index.d.ts +3 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -7
- package/dist/index.js.map +1 -1
- package/dist/lock-stores/file-system/file-lock-store.d.ts +4 -9
- package/dist/lock-stores/file-system/file-lock-store.d.ts.map +1 -1
- package/dist/lock-stores/file-system/file-lock-store.js +21 -38
- package/dist/lock-stores/file-system/file-lock-store.js.map +1 -1
- package/dist/lock-stores/file-system/lock-file-store.d.ts +1 -1
- package/dist/lock-stores/file-system/lock-file-store.d.ts.map +1 -1
- package/dist/lock-stores/file-system/lock-file-store.js +15 -24
- package/dist/lock-stores/file-system/lock-file-store.js.map +1 -1
- package/dist/lock-stores/file-system/presence.d.ts +10 -17
- package/dist/lock-stores/file-system/presence.d.ts.map +1 -1
- package/dist/lock-stores/file-system/presence.js +30 -69
- package/dist/lock-stores/file-system/presence.js.map +1 -1
- package/dist/lock-stores/file-system/record-file.d.ts +10 -0
- package/dist/lock-stores/file-system/record-file.d.ts.map +1 -0
- package/dist/lock-stores/file-system/record-file.js +21 -0
- package/dist/lock-stores/file-system/record-file.js.map +1 -0
- package/dist/lock-stores/file-system/ticket-queue-file-store.d.ts +1 -1
- package/dist/lock-stores/file-system/ticket-queue-file-store.d.ts.map +1 -1
- package/dist/lock-stores/file-system/ticket-queue-file-store.js +25 -32
- package/dist/lock-stores/file-system/ticket-queue-file-store.js.map +1 -1
- package/dist/lock-stores/ipc/child-process-connection.d.ts +3 -4
- package/dist/lock-stores/ipc/child-process-connection.d.ts.map +1 -1
- package/dist/lock-stores/ipc/child-process-connection.js +11 -27
- package/dist/lock-stores/ipc/child-process-connection.js.map +1 -1
- package/dist/lock-stores/ipc/ipc-lock-coordinator.d.ts +3 -7
- package/dist/lock-stores/ipc/ipc-lock-coordinator.d.ts.map +1 -1
- package/dist/lock-stores/ipc/ipc-lock-coordinator.js +6 -12
- package/dist/lock-stores/ipc/ipc-lock-coordinator.js.map +1 -1
- package/dist/lock-stores/ipc/ipc-store.d.ts +2 -7
- package/dist/lock-stores/ipc/ipc-store.d.ts.map +1 -1
- package/dist/lock-stores/ipc/ipc-store.js +9 -15
- package/dist/lock-stores/ipc/ipc-store.js.map +1 -1
- package/dist/lock-stores/ipc/process-channel-connection.d.ts +4 -4
- package/dist/lock-stores/ipc/process-channel-connection.d.ts.map +1 -1
- package/dist/lock-stores/ipc/process-channel-connection.js +13 -25
- package/dist/lock-stores/ipc/process-channel-connection.js.map +1 -1
- package/dist/lock-stores/memory/memory-store.d.ts +1 -1
- package/dist/lock-stores/memory/memory-store.d.ts.map +1 -1
- package/dist/lock-stores/memory/memory-store.js +1 -1
- package/dist/lock-stores/memory/memory-store.js.map +1 -1
- package/dist/lock-stores/remote/connection-supervisor.d.ts +4 -4
- package/dist/lock-stores/remote/connection-supervisor.d.ts.map +1 -1
- package/dist/lock-stores/remote/connection-supervisor.js.map +1 -1
- package/dist/lock-stores/remote/connection.d.ts +4 -3
- package/dist/lock-stores/remote/connection.d.ts.map +1 -1
- package/dist/lock-stores/remote/connector.d.ts +5 -5
- package/dist/lock-stores/remote/connector.d.ts.map +1 -1
- package/dist/lock-stores/remote/delegating-lock-store.d.ts +14 -0
- package/dist/lock-stores/remote/delegating-lock-store.d.ts.map +1 -0
- package/dist/lock-stores/remote/delegating-lock-store.js +20 -0
- package/dist/lock-stores/remote/delegating-lock-store.js.map +1 -0
- package/dist/lock-stores/remote/lock-coordinator.d.ts +3 -4
- package/dist/lock-stores/remote/lock-coordinator.d.ts.map +1 -1
- package/dist/lock-stores/remote/lock-coordinator.js +23 -12
- package/dist/lock-stores/remote/lock-coordinator.js.map +1 -1
- package/dist/lock-stores/remote/protocol.d.ts +6 -2
- package/dist/lock-stores/remote/protocol.d.ts.map +1 -1
- package/dist/lock-stores/remote/protocol.js +14 -8
- package/dist/lock-stores/remote/protocol.js.map +1 -1
- package/dist/lock-stores/remote/queries.d.ts +2 -2
- package/dist/lock-stores/remote/queries.d.ts.map +1 -1
- package/dist/lock-stores/remote/queries.js.map +1 -1
- package/dist/lock-stores/remote/remote-lock-client.d.ts +2 -2
- package/dist/lock-stores/remote/remote-lock-client.d.ts.map +1 -1
- package/dist/lock-stores/remote/remote-lock-client.js +15 -8
- package/dist/lock-stores/remote/remote-lock-client.js.map +1 -1
- package/dist/lock-stores/remote/shared-channel-connection.d.ts +27 -0
- package/dist/lock-stores/remote/shared-channel-connection.d.ts.map +1 -0
- package/dist/lock-stores/remote/shared-channel-connection.js +41 -0
- package/dist/lock-stores/remote/shared-channel-connection.js.map +1 -0
- package/dist/lock-stores/socket/advertised-ops-connection.d.ts +3 -3
- package/dist/lock-stores/socket/advertised-ops-connection.d.ts.map +1 -1
- package/dist/lock-stores/socket/advertised-ops-connection.js +4 -1
- package/dist/lock-stores/socket/advertised-ops-connection.js.map +1 -1
- package/dist/lock-stores/socket/electing-connector.d.ts +4 -5
- package/dist/lock-stores/socket/electing-connector.d.ts.map +1 -1
- package/dist/lock-stores/socket/electing-connector.js +43 -50
- package/dist/lock-stores/socket/electing-connector.js.map +1 -1
- package/dist/lock-stores/socket/handshake.d.ts.map +1 -1
- package/dist/lock-stores/socket/handshake.js +6 -5
- package/dist/lock-stores/socket/handshake.js.map +1 -1
- package/dist/lock-stores/socket/json-line.d.ts +6 -0
- package/dist/lock-stores/socket/json-line.d.ts.map +1 -0
- package/dist/lock-stores/socket/json-line.js +8 -0
- package/dist/lock-stores/socket/json-line.js.map +1 -0
- package/dist/lock-stores/socket/leave-errors-to-close.d.ts +9 -0
- package/dist/lock-stores/socket/leave-errors-to-close.d.ts.map +1 -0
- package/dist/lock-stores/socket/leave-errors-to-close.js +10 -0
- package/dist/lock-stores/socket/leave-errors-to-close.js.map +1 -0
- package/dist/lock-stores/socket/local-directory-connector.d.ts.map +1 -1
- package/dist/lock-stores/socket/local-directory-connector.js +1 -1
- package/dist/lock-stores/socket/local-directory-connector.js.map +1 -1
- package/dist/lock-stores/socket/lock-server.d.ts +7 -4
- package/dist/lock-stores/socket/lock-server.d.ts.map +1 -1
- package/dist/lock-stores/socket/lock-server.js +29 -26
- package/dist/lock-stores/socket/lock-server.js.map +1 -1
- package/dist/lock-stores/socket/socket-connection.d.ts +5 -5
- package/dist/lock-stores/socket/socket-connection.d.ts.map +1 -1
- package/dist/lock-stores/socket/socket-connection.js +18 -23
- package/dist/lock-stores/socket/socket-connection.js.map +1 -1
- package/dist/lock-stores/socket/socket-election.d.ts +9 -0
- package/dist/lock-stores/socket/socket-election.d.ts.map +1 -0
- package/dist/lock-stores/socket/socket-election.js +16 -0
- package/dist/lock-stores/socket/socket-election.js.map +1 -0
- package/dist/lock-stores/socket/socket-store.d.ts +1 -1
- package/dist/lock-stores/socket/socket-store.d.ts.map +1 -1
- package/dist/lock-stores/socket/socket-store.js +6 -6
- package/dist/lock-stores/socket/socket-store.js.map +1 -1
- package/dist/lock-stores/sqlite/holder-record.d.ts.map +1 -1
- package/dist/lock-stores/sqlite/holder-record.js +9 -23
- package/dist/lock-stores/sqlite/holder-record.js.map +1 -1
- package/dist/lock-stores/sqlite/sqlite-store.d.ts +6 -7
- package/dist/lock-stores/sqlite/sqlite-store.d.ts.map +1 -1
- package/dist/lock-stores/sqlite/sqlite-store.js +31 -101
- package/dist/lock-stores/sqlite/sqlite-store.js.map +1 -1
- package/dist/lock-stores/thread/parent-port-connection.d.ts +3 -4
- package/dist/lock-stores/thread/parent-port-connection.d.ts.map +1 -1
- package/dist/lock-stores/thread/parent-port-connection.js +7 -13
- package/dist/lock-stores/thread/parent-port-connection.js.map +1 -1
- package/dist/lock-stores/thread/thread-lock-coordinator.d.ts +3 -7
- package/dist/lock-stores/thread/thread-lock-coordinator.d.ts.map +1 -1
- package/dist/lock-stores/thread/thread-lock-coordinator.js +6 -12
- package/dist/lock-stores/thread/thread-lock-coordinator.js.map +1 -1
- package/dist/lock-stores/thread/thread-store.d.ts +2 -7
- package/dist/lock-stores/thread/thread-store.d.ts.map +1 -1
- package/dist/lock-stores/thread/thread-store.js +3 -12
- package/dist/lock-stores/thread/thread-store.js.map +1 -1
- package/dist/lock-stores/thread/worker-connection.d.ts +3 -4
- package/dist/lock-stores/thread/worker-connection.d.ts.map +1 -1
- package/dist/lock-stores/thread/worker-connection.js +6 -18
- package/dist/lock-stores/thread/worker-connection.js.map +1 -1
- package/dist/mutex/key.d.ts +3 -3
- package/dist/mutex/key.d.ts.map +1 -1
- package/dist/mutex/key.js.map +1 -1
- package/dist/mutex/lease.d.ts +2 -9
- package/dist/mutex/lease.d.ts.map +1 -1
- package/dist/mutex/lease.js +17 -12
- package/dist/mutex/lease.js.map +1 -1
- package/dist/mutex/mutex.d.ts +3 -3
- package/dist/mutex/mutex.d.ts.map +1 -1
- package/dist/mutex/mutex.js +2 -2
- package/dist/mutex/mutex.js.map +1 -1
- package/package.json +6 -9
- package/dist/fencing/counter-token-source.d.ts +0 -11
- package/dist/fencing/counter-token-source.d.ts.map +0 -1
- package/dist/fencing/counter-token-source.js +0 -13
- package/dist/fencing/counter-token-source.js.map +0 -1
- package/dist/fencing/epoch-token-source.d.ts +0 -13
- package/dist/fencing/epoch-token-source.d.ts.map +0 -1
- package/dist/fencing/epoch-token-source.js +0 -27
- package/dist/fencing/epoch-token-source.js.map +0 -1
- package/dist/fencing/fencing-token.d.ts +0 -12
- package/dist/fencing/fencing-token.d.ts.map +0 -1
- package/dist/fencing/fencing-token.js +0 -18
- package/dist/fencing/fencing-token.js.map +0 -1
- package/dist/fencing/file-token-source.d.ts +0 -13
- package/dist/fencing/file-token-source.d.ts.map +0 -1
- package/dist/fencing/file-token-source.js +0 -36
- package/dist/fencing/file-token-source.js.map +0 -1
- package/dist/fencing/monotonic-clock-token-source.d.ts +0 -12
- package/dist/fencing/monotonic-clock-token-source.d.ts.map +0 -1
- package/dist/fencing/monotonic-clock-token-source.js +0 -15
- package/dist/fencing/monotonic-clock-token-source.js.map +0 -1
- package/dist/fencing/token-source.d.ts +0 -9
- package/dist/fencing/token-source.d.ts.map +0 -1
- package/dist/fencing/token-source.js +0 -2
- package/dist/fencing/token-source.js.map +0 -1
- package/dist/leader-election/index.d.ts +0 -4
- package/dist/leader-election/index.d.ts.map +0 -1
- package/dist/leader-election/index.js +0 -4
- package/dist/leader-election/index.js.map +0 -1
- package/dist/leader-election/leader-election.d.ts +0 -23
- package/dist/leader-election/leader-election.d.ts.map +0 -1
- package/dist/leader-election/leader-election.js +0 -79
- package/dist/leader-election/leader-election.js.map +0 -1
- package/dist/leader-election/leadership.d.ts +0 -14
- package/dist/leader-election/leadership.d.ts.map +0 -1
- package/dist/leader-election/leadership.js +0 -23
- package/dist/leader-election/leadership.js.map +0 -1
- package/dist/local-directory/local-directory.d.ts +0 -7
- package/dist/local-directory/local-directory.d.ts.map +0 -1
- package/dist/local-directory/local-directory.js +0 -75
- package/dist/local-directory/local-directory.js.map +0 -1
- package/dist/local-directory/network-directory-error.d.ts +0 -8
- package/dist/local-directory/network-directory-error.d.ts.map +0 -1
- package/dist/local-directory/network-directory-error.js +0 -13
- package/dist/local-directory/network-directory-error.js.map +0 -1
- package/dist/mutex/lock-lost-error.d.ts +0 -6
- package/dist/mutex/lock-lost-error.d.ts.map +0 -1
- package/dist/mutex/lock-lost-error.js +0 -10
- package/dist/mutex/lock-lost-error.js.map +0 -1
- package/dist/shared/fs/atomic-write.d.ts +0 -3
- package/dist/shared/fs/atomic-write.d.ts.map +0 -1
- package/dist/shared/fs/atomic-write.js +0 -10
- package/dist/shared/fs/atomic-write.js.map +0 -1
- package/dist/shared/fs/create-exclusive.d.ts +0 -6
- package/dist/shared/fs/create-exclusive.d.ts.map +0 -1
- package/dist/shared/fs/create-exclusive.js +0 -29
- package/dist/shared/fs/create-exclusive.js.map +0 -1
- package/dist/shared/fs/durable-write.d.ts +0 -9
- package/dist/shared/fs/durable-write.d.ts.map +0 -1
- package/dist/shared/fs/durable-write.js +0 -49
- package/dist/shared/fs/durable-write.js.map +0 -1
- package/dist/shared/fs/errno.d.ts +0 -2
- package/dist/shared/fs/errno.d.ts.map +0 -1
- package/dist/shared/fs/errno.js +0 -4
- package/dist/shared/fs/errno.js.map +0 -1
- package/dist/shared/fs/patiently.d.ts +0 -3
- package/dist/shared/fs/patiently.d.ts.map +0 -1
- package/dist/shared/fs/patiently.js +0 -30
- package/dist/shared/fs/patiently.js.map +0 -1
- package/dist/shared/fs/replace-file.d.ts +0 -8
- package/dist/shared/fs/replace-file.d.ts.map +0 -1
- package/dist/shared/fs/replace-file.js +0 -12
- package/dist/shared/fs/replace-file.js.map +0 -1
- package/dist/shared/fs/safe-file-name.d.ts +0 -16
- package/dist/shared/fs/safe-file-name.d.ts.map +0 -1
- package/dist/shared/fs/safe-file-name.js +0 -37
- package/dist/shared/fs/safe-file-name.js.map +0 -1
- package/dist/shared/sqlite/is-busy.d.ts +0 -3
- package/dist/shared/sqlite/is-busy.d.ts.map +0 -1
- package/dist/shared/sqlite/is-busy.js +0 -10
- package/dist/shared/sqlite/is-busy.js.map +0 -1
- package/dist/shared/sqlite/is-cant-open.d.ts +0 -3
- package/dist/shared/sqlite/is-cant-open.d.ts.map +0 -1
- package/dist/shared/sqlite/is-cant-open.js +0 -9
- package/dist/shared/sqlite/is-cant-open.js.map +0 -1
- package/dist/shared/sqlite/is-not-a-database.d.ts +0 -3
- package/dist/shared/sqlite/is-not-a-database.d.ts.map +0 -1
- package/dist/shared/sqlite/is-not-a-database.js +0 -9
- package/dist/shared/sqlite/is-not-a-database.js.map +0 -1
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import { unwrap } from "./envelope.js";
|
|
3
|
+
/**
|
|
4
|
+
* A connection over a message channel that the application uses too: an IPC
|
|
5
|
+
* channel or a worker port. Lock messages travel in an envelope, so the
|
|
6
|
+
* application's own messages, which have none, are dropped (ADR 0017). Each
|
|
7
|
+
* subclass decides when it listens, because the listeners can keep the
|
|
8
|
+
* process alive.
|
|
9
|
+
*/
|
|
10
|
+
export class SharedChannelConnection extends EventEmitter {
|
|
11
|
+
#channel;
|
|
12
|
+
/** The events of the channel that tell that the peer is gone. */
|
|
13
|
+
#goneEvents;
|
|
14
|
+
#onMessage = (envelope) => {
|
|
15
|
+
const message = unwrap(envelope);
|
|
16
|
+
if (message !== undefined)
|
|
17
|
+
this.emit('message', message);
|
|
18
|
+
};
|
|
19
|
+
#onGone = () => {
|
|
20
|
+
this.stopListening();
|
|
21
|
+
this.emit('close');
|
|
22
|
+
};
|
|
23
|
+
constructor(channel, goneEvents) {
|
|
24
|
+
super();
|
|
25
|
+
this.#channel = channel;
|
|
26
|
+
this.#goneEvents = goneEvents;
|
|
27
|
+
}
|
|
28
|
+
listen() {
|
|
29
|
+
this.#channel.on('message', this.#onMessage);
|
|
30
|
+
for (const event of this.#goneEvents) {
|
|
31
|
+
this.#channel.once(event, this.#onGone);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
stopListening() {
|
|
35
|
+
this.#channel.off('message', this.#onMessage);
|
|
36
|
+
for (const event of this.#goneEvents) {
|
|
37
|
+
this.#channel.off(event, this.#onGone);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=shared-channel-connection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared-channel-connection.js","sourceRoot":"","sources":["../../../src/lock-stores/remote/shared-channel-connection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AASvC;;;;;;GAMG;AACH,MAAM,OAAgB,uBACpB,SAAQ,YAA8B;IAG7B,QAAQ,CAAa;IAC9B,iEAAiE;IACxD,WAAW,CAAoB;IAE/B,UAAU,GAAG,CAAC,QAAiB,EAAE,EAAE;QAC1C,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;QACjC,IAAI,OAAO,KAAK,SAAS;YAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAC3D,CAAC,CAAC;IAEO,OAAO,GAAG,GAAG,EAAE;QACtB,IAAI,CAAC,aAAa,EAAE,CAAC;QACrB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrB,CAAC,CAAC;IAEF,YAAsB,OAAmB,EAAE,UAA6B;QACtE,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;QACxB,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC;IAChC,CAAC;IAUS,MAAM;QACd,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QAC7C,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC;IAES,aAAa;QACrB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QAC9C,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;CACF"}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { EventEmitter } from 'node:events';
|
|
2
2
|
import type { Connection, ConnectionEvents } from '../remote/connection.ts';
|
|
3
|
-
import { type LockRequest
|
|
3
|
+
import { type LockRequest } from '../remote/protocol.ts';
|
|
4
4
|
/**
|
|
5
5
|
* A follower's connection to a leader, which sends an added request only if
|
|
6
6
|
* the leader listed it in its welcome. A leader of 0.3.x closes a connection
|
|
7
7
|
* that sends a request it does not know, and the follower would lose every key
|
|
8
8
|
* it holds; such a request is answered `unsupported` here instead.
|
|
9
9
|
*/
|
|
10
|
-
export declare class AdvertisedOpsConnection extends EventEmitter<ConnectionEvents
|
|
10
|
+
export declare class AdvertisedOpsConnection extends EventEmitter<ConnectionEvents> implements Connection<LockRequest> {
|
|
11
11
|
#private;
|
|
12
|
-
constructor(leader: Connection<LockRequest
|
|
12
|
+
constructor(leader: Connection<LockRequest>, listed: ReadonlySet<string>);
|
|
13
13
|
send(request: LockRequest): Promise<void>;
|
|
14
14
|
ref(): void;
|
|
15
15
|
unref(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"advertised-ops-connection.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/socket/advertised-ops-connection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC5E,OAAO,EAEL,KAAK,WAAW,
|
|
1
|
+
{"version":3,"file":"advertised-ops-connection.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/socket/advertised-ops-connection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC5E,OAAO,EAEL,KAAK,WAAW,EAEjB,MAAM,uBAAuB,CAAC;AAE/B;;;;;GAKG;AACH,qBAAa,uBACX,SAAQ,YAAY,CAAC,gBAAgB,CACrC,YAAW,UAAU,CAAC,WAAW,CAAC;;gBAKtB,MAAM,EAAE,UAAU,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC;IAQlE,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAc/C,GAAG;IAIH,KAAK;IAIL,KAAK;CAGN"}
|
|
@@ -19,7 +19,10 @@ export class AdvertisedOpsConnection extends EventEmitter {
|
|
|
19
19
|
async send(request) {
|
|
20
20
|
if (ADDED_OPS.has(request.op) && !this.#listed.has(request.op)) {
|
|
21
21
|
// Answered after the send returns, as an answer from the leader would be.
|
|
22
|
-
queueMicrotask(() => this.emit('message', {
|
|
22
|
+
queueMicrotask(() => this.emit('message', {
|
|
23
|
+
op: 'unsupported',
|
|
24
|
+
id: request.id,
|
|
25
|
+
}));
|
|
23
26
|
return;
|
|
24
27
|
}
|
|
25
28
|
await this.#leader.send(request);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"advertised-ops-connection.js","sourceRoot":"","sources":["../../../src/lock-stores/socket/advertised-ops-connection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,EACL,SAAS,GAGV,MAAM,uBAAuB,CAAC;AAE/B;;;;;GAKG;AACH,MAAM,OAAO,uBACX,SAAQ,
|
|
1
|
+
{"version":3,"file":"advertised-ops-connection.js","sourceRoot":"","sources":["../../../src/lock-stores/socket/advertised-ops-connection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,EACL,SAAS,GAGV,MAAM,uBAAuB,CAAC;AAE/B;;;;;GAKG;AACH,MAAM,OAAO,uBACX,SAAQ,YAA8B;IAG7B,OAAO,CAA0B;IACjC,OAAO,CAAsB;IAEtC,YAAY,MAA+B,EAAE,MAA2B;QACtE,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC;QACnE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,OAAoB;QAC7B,IAAI,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC;YAC/D,0EAA0E;YAC1E,cAAc,CAAC,GAAG,EAAE,CAClB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;gBACnB,EAAE,EAAE,aAAa;gBACjB,EAAE,EAAE,OAAO,CAAC,EAAE;aACQ,CAAC,CAC1B,CAAC;YACF,OAAO;QACT,CAAC;QACD,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACnC,CAAC;IAED,GAAG;QACD,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;IACrB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;CACF"}
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import type { LeaderElection } from '
|
|
2
|
-
import type { Leadership } from '../../leader-election/leadership.ts';
|
|
1
|
+
import type { LeaderElection, Term } from '@zukhruf/election';
|
|
3
2
|
import type { ClientConnection, ClientConnector } from '../remote/connector.ts';
|
|
4
3
|
export interface ElectingConnectorOptions {
|
|
5
4
|
socketPath: string;
|
|
6
|
-
/**
|
|
7
|
-
election: Pick<LeaderElection
|
|
5
|
+
/** Only `campaign`: the connector never runs a backend's own steps, so an election of any backend fits. */
|
|
6
|
+
election: Pick<LeaderElection<unknown>, 'campaign'>;
|
|
8
7
|
pollInterval: number;
|
|
9
8
|
/** Starts serving for a term this process just won. */
|
|
10
|
-
serve(
|
|
9
|
+
serve(term: Term): Promise<void>;
|
|
11
10
|
/** Reached the server of another process, so this process follows it. */
|
|
12
11
|
connected(): void;
|
|
13
12
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"electing-connector.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/socket/electing-connector.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,
|
|
1
|
+
{"version":3,"file":"electing-connector.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/socket/electing-connector.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAE9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAahF,MAAM,WAAW,wBAAwB;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,2GAA2G;IAC3G,QAAQ,EAAE,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,UAAU,CAAC,CAAC;IACpD,YAAY,EAAE,MAAM,CAAC;IACrB,uDAAuD;IACvD,KAAK,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,yEAAyE;IACzE,SAAS,IAAI,IAAI,CAAC;CACnB;AAED;;;;GAIG;AACH,qBAAa,iBAAkB,YAAW,eAAe;;gBAG3C,OAAO,EAAE,wBAAwB;IAIvC,OAAO,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAoG9D"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { once } from 'node:events';
|
|
1
2
|
import { connect } from 'node:net';
|
|
2
3
|
import { setTimeout as delay } from 'node:timers/promises';
|
|
3
4
|
import { untilAborted } from '@zukhruf/async';
|
|
4
|
-
import { isLockResponse, } from "../remote/protocol.js";
|
|
5
5
|
import { AdvertisedOpsConnection } from "./advertised-ops-connection.js";
|
|
6
6
|
import { PROTOCOL_VERSION, greet } from "./handshake.js";
|
|
7
7
|
import { ProtocolVersionError } from "./protocol-version-error.js";
|
|
@@ -31,14 +31,14 @@ export class ElectingConnector {
|
|
|
31
31
|
if (connection)
|
|
32
32
|
return connection;
|
|
33
33
|
}
|
|
34
|
-
const
|
|
35
|
-
if (
|
|
36
|
-
const own = await this.#lead(
|
|
34
|
+
const term = await this.#campaign(pollInterval, signal);
|
|
35
|
+
if (term) {
|
|
36
|
+
const own = await this.#lead(term, signal);
|
|
37
37
|
if (own)
|
|
38
38
|
return own;
|
|
39
39
|
}
|
|
40
40
|
else {
|
|
41
|
-
await delay(pollInterval, undefined, { signal });
|
|
41
|
+
await untilAborted(delay(pollInterval, undefined, { signal }), signal);
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
}
|
|
@@ -54,9 +54,9 @@ export class ElectingConnector {
|
|
|
54
54
|
const { socketPath, pollInterval } = this.#options;
|
|
55
55
|
const deadline = performance.now() + HANDSHAKE_PATIENCE;
|
|
56
56
|
for (;;) {
|
|
57
|
-
const
|
|
58
|
-
if (
|
|
59
|
-
return this.#lead(
|
|
57
|
+
const term = await this.#campaign(0, signal);
|
|
58
|
+
if (term)
|
|
59
|
+
return this.#lead(term, signal);
|
|
60
60
|
const again = await reachUnlessAborted(socketPath, signal);
|
|
61
61
|
if (!again)
|
|
62
62
|
return undefined;
|
|
@@ -66,27 +66,28 @@ export class ElectingConnector {
|
|
|
66
66
|
if (performance.now() >= deadline) {
|
|
67
67
|
throw new ProtocolVersionError(PROTOCOL_VERSION, undefined);
|
|
68
68
|
}
|
|
69
|
-
await delay(pollInterval, undefined, { signal });
|
|
69
|
+
await untilAborted(delay(pollInterval, undefined, { signal }), signal);
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
|
-
/**
|
|
72
|
+
/**
|
|
73
|
+
* Campaigns until `timeout`; a term won after `signal` aborted is resigned.
|
|
74
|
+
* The election gives up a term that it wins after the abort, but the abort
|
|
75
|
+
* can also land after the campaign resolved, before this step continues.
|
|
76
|
+
*/
|
|
73
77
|
async #campaign(timeout, signal) {
|
|
74
|
-
const
|
|
78
|
+
const term = await this.#options.election.campaign({ timeout, signal });
|
|
75
79
|
if (signal.aborted)
|
|
76
|
-
await
|
|
80
|
+
await term?.resign();
|
|
77
81
|
signal.throwIfAborted();
|
|
78
|
-
return
|
|
82
|
+
return term;
|
|
79
83
|
}
|
|
80
84
|
/** Serves the term this process just won, and reaches its own server without following anyone. */
|
|
81
|
-
async #lead(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
await leadership.resign();
|
|
88
|
-
throw error;
|
|
89
|
-
}
|
|
85
|
+
async #lead(term, signal) {
|
|
86
|
+
await using serving = new AsyncDisposableStack();
|
|
87
|
+
// A term that nothing serves would stop every other candidate from leading.
|
|
88
|
+
serving.defer(() => term.resign());
|
|
89
|
+
await this.#options.serve(term);
|
|
90
|
+
serving.move();
|
|
90
91
|
const own = await reachUnlessAborted(this.#options.socketPath, signal);
|
|
91
92
|
if (!own)
|
|
92
93
|
return undefined;
|
|
@@ -106,19 +107,16 @@ export class ElectingConnector {
|
|
|
106
107
|
}
|
|
107
108
|
return undefined;
|
|
108
109
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
socket.destroy();
|
|
115
|
-
throw error;
|
|
116
|
-
}
|
|
110
|
+
using following = new DisposableStack();
|
|
111
|
+
// Nobody will use this socket, and an open one would keep the process alive.
|
|
112
|
+
following.defer(() => socket.destroy());
|
|
113
|
+
this.#options.connected();
|
|
114
|
+
following.move();
|
|
117
115
|
return leaderConnection(socket, greeting.ops);
|
|
118
116
|
}
|
|
119
117
|
}
|
|
120
118
|
function leaderConnection(socket, listed) {
|
|
121
|
-
return new AdvertisedOpsConnection(new SocketConnection(socket
|
|
119
|
+
return new AdvertisedOpsConnection(new SocketConnection(socket), listed);
|
|
122
120
|
}
|
|
123
121
|
/** Like `reach`, but a socket reached after `signal` aborted is destroyed, not returned. */
|
|
124
122
|
async function reachUnlessAborted(socketPath, signal) {
|
|
@@ -130,28 +128,23 @@ async function reachUnlessAborted(socketPath, signal) {
|
|
|
130
128
|
return socket;
|
|
131
129
|
}
|
|
132
130
|
/** Resolves `undefined` when nothing listens yet (no file, or a dead leader's file). */
|
|
133
|
-
function reach(socketPath) {
|
|
134
|
-
|
|
135
|
-
const socket = connect(socketPath);
|
|
136
|
-
const fail = () => {
|
|
137
|
-
socket.destroy();
|
|
138
|
-
resolve(undefined);
|
|
139
|
-
};
|
|
140
|
-
socket.once('error', fail);
|
|
141
|
-
socket.once('connect', () => {
|
|
142
|
-
socket.off('error', fail);
|
|
143
|
-
resolve(socket);
|
|
144
|
-
});
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
/** Greets the leader on `socket`; a store that closes meanwhile gives the socket up. */
|
|
148
|
-
async function greetUnlessAborted(socket, signal) {
|
|
131
|
+
async function reach(socketPath) {
|
|
132
|
+
const socket = connect(socketPath);
|
|
149
133
|
try {
|
|
150
|
-
|
|
134
|
+
await once(socket, 'connect');
|
|
135
|
+
return socket;
|
|
151
136
|
}
|
|
152
|
-
catch
|
|
137
|
+
catch {
|
|
153
138
|
socket.destroy();
|
|
154
|
-
|
|
139
|
+
return undefined;
|
|
155
140
|
}
|
|
156
141
|
}
|
|
142
|
+
/** Greets the leader on `socket`; a store that closes meanwhile gives the socket up. */
|
|
143
|
+
async function greetUnlessAborted(socket, signal) {
|
|
144
|
+
using greeting = new DisposableStack();
|
|
145
|
+
greeting.defer(() => socket.destroy());
|
|
146
|
+
const greeted = await untilAborted(greet(socket), signal);
|
|
147
|
+
greeting.move();
|
|
148
|
+
return greeted;
|
|
149
|
+
}
|
|
157
150
|
//# sourceMappingURL=electing-connector.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"electing-connector.js","sourceRoot":"","sources":["../../../src/lock-stores/socket/electing-connector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,OAAO,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EAAE,UAAU,IAAI,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAK9C,OAAO,
|
|
1
|
+
{"version":3,"file":"electing-connector.js","sourceRoot":"","sources":["../../../src/lock-stores/socket/electing-connector.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handshake.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/socket/handshake.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"handshake.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/socket/handshake.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAOvC;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC,wDAAwD;AACxD,MAAM,MAAM,QAAQ;AAClB,kFAAkF;AAChF;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,GAAG,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE;AACtC,kGAAkG;GAChG;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEvB,8EAA8E;AAC9E,wBAAsB,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAc7D;AAED;;;;;;;GAOG;AACH,wBAAsB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAiB9D"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { isRecord } from "../../shared/is-record.js";
|
|
2
2
|
import { ADDED_OPS } from "../remote/protocol.js";
|
|
3
|
+
import { jsonLine } from "./json-line.js";
|
|
4
|
+
import { leaveErrorsToClose } from "./leave-errors-to-close.js";
|
|
3
5
|
/**
|
|
4
6
|
* The version of the messages a socket store's processes exchange. It changes
|
|
5
7
|
* only when they change, so processes that run different package versions
|
|
@@ -11,7 +13,7 @@ import { ADDED_OPS } from "../remote/protocol.js";
|
|
|
11
13
|
export const PROTOCOL_VERSION = 1;
|
|
12
14
|
/** Says which protocol this process speaks, and reads the leader's answer. */
|
|
13
15
|
export async function greet(socket) {
|
|
14
|
-
socket.write(
|
|
16
|
+
socket.write(jsonLine({ op: 'hello', version: PROTOCOL_VERSION }));
|
|
15
17
|
const answer = parse(await readLine(socket));
|
|
16
18
|
if (isRecord(answer) && answer.op === 'welcome') {
|
|
17
19
|
return { kind: 'welcome', ops: listedOps(answer.ops) };
|
|
@@ -40,11 +42,11 @@ export async function welcome(socket) {
|
|
|
40
42
|
}
|
|
41
43
|
if (hello.version === PROTOCOL_VERSION) {
|
|
42
44
|
// A follower of 0.3.x reads only `op`, so the list is new to followers only.
|
|
43
|
-
socket.write(
|
|
45
|
+
socket.write(jsonLine({ op: 'welcome', ops: [...ADDED_OPS] }));
|
|
44
46
|
return true;
|
|
45
47
|
}
|
|
46
48
|
// Destroyed once the answer is written: a paused socket would never see a silent process hang up.
|
|
47
|
-
socket.end(
|
|
49
|
+
socket.end(jsonLine({ op: 'refused', version: PROTOCOL_VERSION }), () => socket.destroy());
|
|
48
50
|
return false;
|
|
49
51
|
}
|
|
50
52
|
function listedOps(ops) {
|
|
@@ -102,8 +104,7 @@ function readLine(socket) {
|
|
|
102
104
|
socket.off('data', onData);
|
|
103
105
|
resolve(undefined);
|
|
104
106
|
};
|
|
105
|
-
|
|
106
|
-
socket.on('error', () => { });
|
|
107
|
+
leaveErrorsToClose(socket);
|
|
107
108
|
socket.on('data', onData);
|
|
108
109
|
socket.once('close', onClose);
|
|
109
110
|
return promise;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handshake.js","sourceRoot":"","sources":["../../../src/lock-stores/socket/handshake.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"handshake.js","sourceRoot":"","sources":["../../../src/lock-stores/socket/handshake.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-line.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/socket/json-line.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAEjD"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One message as one line of the socket's newline-delimited JSON. JSON escapes
|
|
3
|
+
* newlines inside strings, so one line is always one message.
|
|
4
|
+
*/
|
|
5
|
+
export function jsonLine(message) {
|
|
6
|
+
return `${JSON.stringify(message)}\n`;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=json-line.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-line.js","sourceRoot":"","sources":["../../../src/lock-stores/socket/json-line.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,OAAgB;IACvC,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC;AACxC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { EventEmitter } from 'node:events';
|
|
2
|
+
/**
|
|
3
|
+
* Keeps the errors of a socket, or of a stream reading it, from stopping the
|
|
4
|
+
* process: an `error` with no listener does that. Every such error is followed
|
|
5
|
+
* by the socket's `close`, which is where the lost connection is reported, so
|
|
6
|
+
* this listener does nothing.
|
|
7
|
+
*/
|
|
8
|
+
export declare function leaveErrorsToClose(emitter: EventEmitter): void;
|
|
9
|
+
//# sourceMappingURL=leave-errors-to-close.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"leave-errors-to-close.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/socket/leave-errors-to-close.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAE9D"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keeps the errors of a socket, or of a stream reading it, from stopping the
|
|
3
|
+
* process: an `error` with no listener does that. Every such error is followed
|
|
4
|
+
* by the socket's `close`, which is where the lost connection is reported, so
|
|
5
|
+
* this listener does nothing.
|
|
6
|
+
*/
|
|
7
|
+
export function leaveErrorsToClose(emitter) {
|
|
8
|
+
emitter.on('error', () => { });
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=leave-errors-to-close.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"leave-errors-to-close.js","sourceRoot":"","sources":["../../../src/lock-stores/socket/leave-errors-to-close.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAqB;IACtD,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;AAChC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-directory-connector.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/socket/local-directory-connector.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"local-directory-connector.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/socket/local-directory-connector.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEhF;;;;;;GAMG;AACH,qBAAa,uBAAwB,YAAW,eAAe;;gBAIjD,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,eAAe;IAKnD,OAAO,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC;CAM1E"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { assertLocalDirectory } from
|
|
1
|
+
import { assertLocalDirectory } from '@zukhruf/fs';
|
|
2
2
|
/**
|
|
3
3
|
* Refuses a lock directory on a network file system before the first
|
|
4
4
|
* connection exists. Every connect asks, but a directory that passed once is
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-directory-connector.js","sourceRoot":"","sources":["../../../src/lock-stores/socket/local-directory-connector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"local-directory-connector.js","sourceRoot":"","sources":["../../../src/lock-stores/socket/local-directory-connector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAInD;;;;;;GAMG;AACH,MAAM,OAAO,uBAAuB;IACzB,UAAU,CAAS;IACnB,UAAU,CAAkB;IAErC,YAAY,SAAiB,EAAE,SAA0B;QACvD,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QAC5B,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,MAAmB;QAC/B,MAAM,CAAC,cAAc,EAAE,CAAC;QACxB,MAAM,oBAAoB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC5C,MAAM,CAAC,cAAc,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,CAAC;CACF"}
|
|
@@ -1,22 +1,25 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Term } from '@zukhruf/election';
|
|
2
2
|
export interface LockServerOptions {
|
|
3
3
|
/** Milliseconds the new term grants nothing, so holders from the last term can reassert. */
|
|
4
4
|
graceWindow: number;
|
|
5
5
|
}
|
|
6
6
|
/**
|
|
7
7
|
* Serves a `LockCoordinator` on a Unix socket for one leadership term. Tokens
|
|
8
|
-
* carry the term's epoch, so they outrank every token of earlier terms.
|
|
8
|
+
* carry the term's epoch, so they outrank every token of earlier terms. A
|
|
9
|
+
* term that is lost may already be another process's, so the server closes
|
|
10
|
+
* itself when the term's signal aborts.
|
|
9
11
|
*/
|
|
10
12
|
export declare class LockServer {
|
|
11
13
|
#private;
|
|
12
14
|
private constructor();
|
|
13
|
-
static start(socketPath: string,
|
|
15
|
+
static start(socketPath: string, term: Term, { graceWindow }: LockServerOptions): Promise<LockServer>;
|
|
14
16
|
/**
|
|
15
17
|
* Hands leadership over. Dropping every connection tells followers to elect
|
|
16
18
|
* a successor and reassert their keys during its grace window; `close` alone
|
|
17
19
|
* would wait for followers that never disconnect on their own. The term ends
|
|
18
20
|
* only after the socket is gone: in the other order, this close could remove
|
|
19
|
-
* a successor's socket file.
|
|
21
|
+
* a successor's socket file. The first call removes the file at once, so a
|
|
22
|
+
* second caller finds it gone, and it too resolves only once the term ended.
|
|
20
23
|
*/
|
|
21
24
|
close(): Promise<void>;
|
|
22
25
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lock-server.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/socket/lock-server.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"lock-server.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/socket/lock-server.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAQ9C,MAAM,WAAW,iBAAiB;IAChC,4FAA4F;IAC5F,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,qBAAa,UAAU;;IAMrB,OAAO;WAOM,KAAK,CAChB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,IAAI,EACV,EAAE,WAAW,EAAE,EAAE,iBAAiB,GACjC,OAAO,CAAC,UAAU,CAAC;IAkCtB;;;;;;;OAOG;IACG,KAAK;CAOZ"}
|
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { addAbortListener, once } from 'node:events';
|
|
2
|
+
import { rm } from 'node:fs/promises';
|
|
2
3
|
import { createServer } from 'node:net';
|
|
3
|
-
import { EpochTokenSource } from
|
|
4
|
-
import { isErrno } from "../../shared/fs/errno.js";
|
|
4
|
+
import { EpochTokenSource } from '@zukhruf/fencing';
|
|
5
5
|
import { LockCoordinator } from "../remote/lock-coordinator.js";
|
|
6
|
-
import { isRequestEnvelope, } from "../remote/protocol.js";
|
|
7
6
|
import { welcome } from "./handshake.js";
|
|
8
7
|
import { SocketConnection } from "./socket-connection.js";
|
|
9
8
|
/**
|
|
10
9
|
* Serves a `LockCoordinator` on a Unix socket for one leadership term. Tokens
|
|
11
|
-
* carry the term's epoch, so they outrank every token of earlier terms.
|
|
10
|
+
* carry the term's epoch, so they outrank every token of earlier terms. A
|
|
11
|
+
* term that is lost may already be another process's, so the server closes
|
|
12
|
+
* itself when the term's signal aborts.
|
|
12
13
|
*/
|
|
13
14
|
export class LockServer {
|
|
14
15
|
#server;
|
|
15
16
|
#connections;
|
|
16
|
-
#
|
|
17
|
-
|
|
17
|
+
#term;
|
|
18
|
+
#closeOnLoss;
|
|
19
|
+
constructor(server, connections, term) {
|
|
18
20
|
this.#server = server;
|
|
19
21
|
this.#connections = connections;
|
|
20
|
-
this.#
|
|
22
|
+
this.#term = term;
|
|
23
|
+
this.#closeOnLoss = addAbortListener(term.signal, () => void this.close());
|
|
21
24
|
}
|
|
22
|
-
static async start(socketPath,
|
|
25
|
+
static async start(socketPath, term, { graceWindow }) {
|
|
23
26
|
// Only the leader gets here, so removing a dead leader's socket file cannot race another server.
|
|
24
27
|
// Windows removes a named pipe when its process stops, so there is no file to remove.
|
|
25
28
|
if (process.platform !== 'win32') {
|
|
26
|
-
await
|
|
27
|
-
if (!isErrno(error, 'ENOENT'))
|
|
28
|
-
throw error;
|
|
29
|
-
});
|
|
29
|
+
await rm(socketPath, { force: true });
|
|
30
30
|
}
|
|
31
31
|
const coordinator = new LockCoordinator({
|
|
32
|
-
tokens: new EpochTokenSource(
|
|
32
|
+
tokens: new EpochTokenSource(term.epoch),
|
|
33
33
|
graceWindow,
|
|
34
34
|
});
|
|
35
35
|
const connections = new Set();
|
|
@@ -42,32 +42,35 @@ export class LockServer {
|
|
|
42
42
|
void welcome(socket).then((speaksOurs) => {
|
|
43
43
|
if (!speaksOurs)
|
|
44
44
|
return;
|
|
45
|
-
coordinator.serve(new SocketConnection(socket
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
await new Promise((resolve, reject) => {
|
|
49
|
-
server.once('error', reject);
|
|
50
|
-
server.listen(socketPath, () => {
|
|
51
|
-
server.off('error', reject);
|
|
52
|
-
resolve();
|
|
45
|
+
coordinator.serve(new SocketConnection(socket));
|
|
53
46
|
});
|
|
54
47
|
});
|
|
48
|
+
server.listen(socketPath);
|
|
49
|
+
await once(server, 'listening');
|
|
55
50
|
server.unref();
|
|
56
|
-
|
|
51
|
+
const started = new LockServer(server, connections, term);
|
|
52
|
+
// The term may have been lost while the server started.
|
|
53
|
+
if (term.signal.aborted) {
|
|
54
|
+
await started.close();
|
|
55
|
+
term.signal.throwIfAborted();
|
|
56
|
+
}
|
|
57
|
+
return started;
|
|
57
58
|
}
|
|
58
59
|
/**
|
|
59
60
|
* Hands leadership over. Dropping every connection tells followers to elect
|
|
60
61
|
* a successor and reassert their keys during its grace window; `close` alone
|
|
61
62
|
* would wait for followers that never disconnect on their own. The term ends
|
|
62
63
|
* only after the socket is gone: in the other order, this close could remove
|
|
63
|
-
* a successor's socket file.
|
|
64
|
+
* a successor's socket file. The first call removes the file at once, so a
|
|
65
|
+
* second caller finds it gone, and it too resolves only once the term ended.
|
|
64
66
|
*/
|
|
65
67
|
async close() {
|
|
66
|
-
|
|
68
|
+
this.#closeOnLoss[Symbol.dispose]();
|
|
69
|
+
const closed = this.#server[Symbol.asyncDispose]();
|
|
67
70
|
for (const socket of this.#connections)
|
|
68
71
|
socket.destroy();
|
|
69
72
|
await closed;
|
|
70
|
-
await this.#
|
|
73
|
+
await this.#term.resign();
|
|
71
74
|
}
|
|
72
75
|
}
|
|
73
76
|
//# sourceMappingURL=lock-server.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lock-server.js","sourceRoot":"","sources":["../../../src/lock-stores/socket/lock-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"lock-server.js","sourceRoot":"","sources":["../../../src/lock-stores/socket/lock-server.ts"],"names":[],"mappings":"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"}
|