@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.
Files changed (236) hide show
  1. package/README.md +7 -8
  2. package/dist/index.d.ts +3 -9
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +2 -7
  5. package/dist/index.js.map +1 -1
  6. package/dist/lock-stores/file-system/file-lock-store.d.ts +4 -9
  7. package/dist/lock-stores/file-system/file-lock-store.d.ts.map +1 -1
  8. package/dist/lock-stores/file-system/file-lock-store.js +21 -38
  9. package/dist/lock-stores/file-system/file-lock-store.js.map +1 -1
  10. package/dist/lock-stores/file-system/lock-file-store.d.ts +1 -1
  11. package/dist/lock-stores/file-system/lock-file-store.d.ts.map +1 -1
  12. package/dist/lock-stores/file-system/lock-file-store.js +15 -24
  13. package/dist/lock-stores/file-system/lock-file-store.js.map +1 -1
  14. package/dist/lock-stores/file-system/presence.d.ts +10 -17
  15. package/dist/lock-stores/file-system/presence.d.ts.map +1 -1
  16. package/dist/lock-stores/file-system/presence.js +30 -69
  17. package/dist/lock-stores/file-system/presence.js.map +1 -1
  18. package/dist/lock-stores/file-system/record-file.d.ts +10 -0
  19. package/dist/lock-stores/file-system/record-file.d.ts.map +1 -0
  20. package/dist/lock-stores/file-system/record-file.js +21 -0
  21. package/dist/lock-stores/file-system/record-file.js.map +1 -0
  22. package/dist/lock-stores/file-system/ticket-queue-file-store.d.ts +1 -1
  23. package/dist/lock-stores/file-system/ticket-queue-file-store.d.ts.map +1 -1
  24. package/dist/lock-stores/file-system/ticket-queue-file-store.js +25 -32
  25. package/dist/lock-stores/file-system/ticket-queue-file-store.js.map +1 -1
  26. package/dist/lock-stores/ipc/child-process-connection.d.ts +3 -4
  27. package/dist/lock-stores/ipc/child-process-connection.d.ts.map +1 -1
  28. package/dist/lock-stores/ipc/child-process-connection.js +11 -27
  29. package/dist/lock-stores/ipc/child-process-connection.js.map +1 -1
  30. package/dist/lock-stores/ipc/ipc-lock-coordinator.d.ts +3 -7
  31. package/dist/lock-stores/ipc/ipc-lock-coordinator.d.ts.map +1 -1
  32. package/dist/lock-stores/ipc/ipc-lock-coordinator.js +6 -12
  33. package/dist/lock-stores/ipc/ipc-lock-coordinator.js.map +1 -1
  34. package/dist/lock-stores/ipc/ipc-store.d.ts +2 -7
  35. package/dist/lock-stores/ipc/ipc-store.d.ts.map +1 -1
  36. package/dist/lock-stores/ipc/ipc-store.js +9 -15
  37. package/dist/lock-stores/ipc/ipc-store.js.map +1 -1
  38. package/dist/lock-stores/ipc/process-channel-connection.d.ts +4 -4
  39. package/dist/lock-stores/ipc/process-channel-connection.d.ts.map +1 -1
  40. package/dist/lock-stores/ipc/process-channel-connection.js +13 -25
  41. package/dist/lock-stores/ipc/process-channel-connection.js.map +1 -1
  42. package/dist/lock-stores/memory/memory-store.d.ts +1 -1
  43. package/dist/lock-stores/memory/memory-store.d.ts.map +1 -1
  44. package/dist/lock-stores/memory/memory-store.js +1 -1
  45. package/dist/lock-stores/memory/memory-store.js.map +1 -1
  46. package/dist/lock-stores/remote/connection-supervisor.d.ts +4 -4
  47. package/dist/lock-stores/remote/connection-supervisor.d.ts.map +1 -1
  48. package/dist/lock-stores/remote/connection-supervisor.js.map +1 -1
  49. package/dist/lock-stores/remote/connection.d.ts +4 -3
  50. package/dist/lock-stores/remote/connection.d.ts.map +1 -1
  51. package/dist/lock-stores/remote/connector.d.ts +5 -5
  52. package/dist/lock-stores/remote/connector.d.ts.map +1 -1
  53. package/dist/lock-stores/remote/delegating-lock-store.d.ts +14 -0
  54. package/dist/lock-stores/remote/delegating-lock-store.d.ts.map +1 -0
  55. package/dist/lock-stores/remote/delegating-lock-store.js +20 -0
  56. package/dist/lock-stores/remote/delegating-lock-store.js.map +1 -0
  57. package/dist/lock-stores/remote/lock-coordinator.d.ts +3 -4
  58. package/dist/lock-stores/remote/lock-coordinator.d.ts.map +1 -1
  59. package/dist/lock-stores/remote/lock-coordinator.js +23 -12
  60. package/dist/lock-stores/remote/lock-coordinator.js.map +1 -1
  61. package/dist/lock-stores/remote/protocol.d.ts +6 -2
  62. package/dist/lock-stores/remote/protocol.d.ts.map +1 -1
  63. package/dist/lock-stores/remote/protocol.js +14 -8
  64. package/dist/lock-stores/remote/protocol.js.map +1 -1
  65. package/dist/lock-stores/remote/queries.d.ts +2 -2
  66. package/dist/lock-stores/remote/queries.d.ts.map +1 -1
  67. package/dist/lock-stores/remote/queries.js.map +1 -1
  68. package/dist/lock-stores/remote/remote-lock-client.d.ts +2 -2
  69. package/dist/lock-stores/remote/remote-lock-client.d.ts.map +1 -1
  70. package/dist/lock-stores/remote/remote-lock-client.js +15 -8
  71. package/dist/lock-stores/remote/remote-lock-client.js.map +1 -1
  72. package/dist/lock-stores/remote/shared-channel-connection.d.ts +27 -0
  73. package/dist/lock-stores/remote/shared-channel-connection.d.ts.map +1 -0
  74. package/dist/lock-stores/remote/shared-channel-connection.js +41 -0
  75. package/dist/lock-stores/remote/shared-channel-connection.js.map +1 -0
  76. package/dist/lock-stores/socket/advertised-ops-connection.d.ts +3 -3
  77. package/dist/lock-stores/socket/advertised-ops-connection.d.ts.map +1 -1
  78. package/dist/lock-stores/socket/advertised-ops-connection.js +4 -1
  79. package/dist/lock-stores/socket/advertised-ops-connection.js.map +1 -1
  80. package/dist/lock-stores/socket/electing-connector.d.ts +4 -5
  81. package/dist/lock-stores/socket/electing-connector.d.ts.map +1 -1
  82. package/dist/lock-stores/socket/electing-connector.js +43 -50
  83. package/dist/lock-stores/socket/electing-connector.js.map +1 -1
  84. package/dist/lock-stores/socket/handshake.d.ts.map +1 -1
  85. package/dist/lock-stores/socket/handshake.js +6 -5
  86. package/dist/lock-stores/socket/handshake.js.map +1 -1
  87. package/dist/lock-stores/socket/json-line.d.ts +6 -0
  88. package/dist/lock-stores/socket/json-line.d.ts.map +1 -0
  89. package/dist/lock-stores/socket/json-line.js +8 -0
  90. package/dist/lock-stores/socket/json-line.js.map +1 -0
  91. package/dist/lock-stores/socket/leave-errors-to-close.d.ts +9 -0
  92. package/dist/lock-stores/socket/leave-errors-to-close.d.ts.map +1 -0
  93. package/dist/lock-stores/socket/leave-errors-to-close.js +10 -0
  94. package/dist/lock-stores/socket/leave-errors-to-close.js.map +1 -0
  95. package/dist/lock-stores/socket/local-directory-connector.d.ts.map +1 -1
  96. package/dist/lock-stores/socket/local-directory-connector.js +1 -1
  97. package/dist/lock-stores/socket/local-directory-connector.js.map +1 -1
  98. package/dist/lock-stores/socket/lock-server.d.ts +7 -4
  99. package/dist/lock-stores/socket/lock-server.d.ts.map +1 -1
  100. package/dist/lock-stores/socket/lock-server.js +29 -26
  101. package/dist/lock-stores/socket/lock-server.js.map +1 -1
  102. package/dist/lock-stores/socket/socket-connection.d.ts +5 -5
  103. package/dist/lock-stores/socket/socket-connection.d.ts.map +1 -1
  104. package/dist/lock-stores/socket/socket-connection.js +18 -23
  105. package/dist/lock-stores/socket/socket-connection.js.map +1 -1
  106. package/dist/lock-stores/socket/socket-election.d.ts +9 -0
  107. package/dist/lock-stores/socket/socket-election.d.ts.map +1 -0
  108. package/dist/lock-stores/socket/socket-election.js +16 -0
  109. package/dist/lock-stores/socket/socket-election.js.map +1 -0
  110. package/dist/lock-stores/socket/socket-store.d.ts +1 -1
  111. package/dist/lock-stores/socket/socket-store.d.ts.map +1 -1
  112. package/dist/lock-stores/socket/socket-store.js +6 -6
  113. package/dist/lock-stores/socket/socket-store.js.map +1 -1
  114. package/dist/lock-stores/sqlite/holder-record.d.ts.map +1 -1
  115. package/dist/lock-stores/sqlite/holder-record.js +9 -23
  116. package/dist/lock-stores/sqlite/holder-record.js.map +1 -1
  117. package/dist/lock-stores/sqlite/sqlite-store.d.ts +6 -7
  118. package/dist/lock-stores/sqlite/sqlite-store.d.ts.map +1 -1
  119. package/dist/lock-stores/sqlite/sqlite-store.js +31 -101
  120. package/dist/lock-stores/sqlite/sqlite-store.js.map +1 -1
  121. package/dist/lock-stores/thread/parent-port-connection.d.ts +3 -4
  122. package/dist/lock-stores/thread/parent-port-connection.d.ts.map +1 -1
  123. package/dist/lock-stores/thread/parent-port-connection.js +7 -13
  124. package/dist/lock-stores/thread/parent-port-connection.js.map +1 -1
  125. package/dist/lock-stores/thread/thread-lock-coordinator.d.ts +3 -7
  126. package/dist/lock-stores/thread/thread-lock-coordinator.d.ts.map +1 -1
  127. package/dist/lock-stores/thread/thread-lock-coordinator.js +6 -12
  128. package/dist/lock-stores/thread/thread-lock-coordinator.js.map +1 -1
  129. package/dist/lock-stores/thread/thread-store.d.ts +2 -7
  130. package/dist/lock-stores/thread/thread-store.d.ts.map +1 -1
  131. package/dist/lock-stores/thread/thread-store.js +3 -12
  132. package/dist/lock-stores/thread/thread-store.js.map +1 -1
  133. package/dist/lock-stores/thread/worker-connection.d.ts +3 -4
  134. package/dist/lock-stores/thread/worker-connection.d.ts.map +1 -1
  135. package/dist/lock-stores/thread/worker-connection.js +6 -18
  136. package/dist/lock-stores/thread/worker-connection.js.map +1 -1
  137. package/dist/mutex/key.d.ts +3 -3
  138. package/dist/mutex/key.d.ts.map +1 -1
  139. package/dist/mutex/key.js.map +1 -1
  140. package/dist/mutex/lease.d.ts +2 -9
  141. package/dist/mutex/lease.d.ts.map +1 -1
  142. package/dist/mutex/lease.js +17 -12
  143. package/dist/mutex/lease.js.map +1 -1
  144. package/dist/mutex/mutex.d.ts +3 -3
  145. package/dist/mutex/mutex.d.ts.map +1 -1
  146. package/dist/mutex/mutex.js +2 -2
  147. package/dist/mutex/mutex.js.map +1 -1
  148. package/package.json +6 -9
  149. package/dist/fencing/counter-token-source.d.ts +0 -11
  150. package/dist/fencing/counter-token-source.d.ts.map +0 -1
  151. package/dist/fencing/counter-token-source.js +0 -13
  152. package/dist/fencing/counter-token-source.js.map +0 -1
  153. package/dist/fencing/epoch-token-source.d.ts +0 -13
  154. package/dist/fencing/epoch-token-source.d.ts.map +0 -1
  155. package/dist/fencing/epoch-token-source.js +0 -27
  156. package/dist/fencing/epoch-token-source.js.map +0 -1
  157. package/dist/fencing/fencing-token.d.ts +0 -12
  158. package/dist/fencing/fencing-token.d.ts.map +0 -1
  159. package/dist/fencing/fencing-token.js +0 -18
  160. package/dist/fencing/fencing-token.js.map +0 -1
  161. package/dist/fencing/file-token-source.d.ts +0 -13
  162. package/dist/fencing/file-token-source.d.ts.map +0 -1
  163. package/dist/fencing/file-token-source.js +0 -36
  164. package/dist/fencing/file-token-source.js.map +0 -1
  165. package/dist/fencing/monotonic-clock-token-source.d.ts +0 -12
  166. package/dist/fencing/monotonic-clock-token-source.d.ts.map +0 -1
  167. package/dist/fencing/monotonic-clock-token-source.js +0 -15
  168. package/dist/fencing/monotonic-clock-token-source.js.map +0 -1
  169. package/dist/fencing/token-source.d.ts +0 -9
  170. package/dist/fencing/token-source.d.ts.map +0 -1
  171. package/dist/fencing/token-source.js +0 -2
  172. package/dist/fencing/token-source.js.map +0 -1
  173. package/dist/leader-election/index.d.ts +0 -4
  174. package/dist/leader-election/index.d.ts.map +0 -1
  175. package/dist/leader-election/index.js +0 -4
  176. package/dist/leader-election/index.js.map +0 -1
  177. package/dist/leader-election/leader-election.d.ts +0 -23
  178. package/dist/leader-election/leader-election.d.ts.map +0 -1
  179. package/dist/leader-election/leader-election.js +0 -79
  180. package/dist/leader-election/leader-election.js.map +0 -1
  181. package/dist/leader-election/leadership.d.ts +0 -14
  182. package/dist/leader-election/leadership.d.ts.map +0 -1
  183. package/dist/leader-election/leadership.js +0 -23
  184. package/dist/leader-election/leadership.js.map +0 -1
  185. package/dist/local-directory/local-directory.d.ts +0 -7
  186. package/dist/local-directory/local-directory.d.ts.map +0 -1
  187. package/dist/local-directory/local-directory.js +0 -75
  188. package/dist/local-directory/local-directory.js.map +0 -1
  189. package/dist/local-directory/network-directory-error.d.ts +0 -8
  190. package/dist/local-directory/network-directory-error.d.ts.map +0 -1
  191. package/dist/local-directory/network-directory-error.js +0 -13
  192. package/dist/local-directory/network-directory-error.js.map +0 -1
  193. package/dist/mutex/lock-lost-error.d.ts +0 -6
  194. package/dist/mutex/lock-lost-error.d.ts.map +0 -1
  195. package/dist/mutex/lock-lost-error.js +0 -10
  196. package/dist/mutex/lock-lost-error.js.map +0 -1
  197. package/dist/shared/fs/atomic-write.d.ts +0 -3
  198. package/dist/shared/fs/atomic-write.d.ts.map +0 -1
  199. package/dist/shared/fs/atomic-write.js +0 -10
  200. package/dist/shared/fs/atomic-write.js.map +0 -1
  201. package/dist/shared/fs/create-exclusive.d.ts +0 -6
  202. package/dist/shared/fs/create-exclusive.d.ts.map +0 -1
  203. package/dist/shared/fs/create-exclusive.js +0 -29
  204. package/dist/shared/fs/create-exclusive.js.map +0 -1
  205. package/dist/shared/fs/durable-write.d.ts +0 -9
  206. package/dist/shared/fs/durable-write.d.ts.map +0 -1
  207. package/dist/shared/fs/durable-write.js +0 -49
  208. package/dist/shared/fs/durable-write.js.map +0 -1
  209. package/dist/shared/fs/errno.d.ts +0 -2
  210. package/dist/shared/fs/errno.d.ts.map +0 -1
  211. package/dist/shared/fs/errno.js +0 -4
  212. package/dist/shared/fs/errno.js.map +0 -1
  213. package/dist/shared/fs/patiently.d.ts +0 -3
  214. package/dist/shared/fs/patiently.d.ts.map +0 -1
  215. package/dist/shared/fs/patiently.js +0 -30
  216. package/dist/shared/fs/patiently.js.map +0 -1
  217. package/dist/shared/fs/replace-file.d.ts +0 -8
  218. package/dist/shared/fs/replace-file.d.ts.map +0 -1
  219. package/dist/shared/fs/replace-file.js +0 -12
  220. package/dist/shared/fs/replace-file.js.map +0 -1
  221. package/dist/shared/fs/safe-file-name.d.ts +0 -16
  222. package/dist/shared/fs/safe-file-name.d.ts.map +0 -1
  223. package/dist/shared/fs/safe-file-name.js +0 -37
  224. package/dist/shared/fs/safe-file-name.js.map +0 -1
  225. package/dist/shared/sqlite/is-busy.d.ts +0 -3
  226. package/dist/shared/sqlite/is-busy.d.ts.map +0 -1
  227. package/dist/shared/sqlite/is-busy.js +0 -10
  228. package/dist/shared/sqlite/is-busy.js.map +0 -1
  229. package/dist/shared/sqlite/is-cant-open.d.ts +0 -3
  230. package/dist/shared/sqlite/is-cant-open.d.ts.map +0 -1
  231. package/dist/shared/sqlite/is-cant-open.js +0 -9
  232. package/dist/shared/sqlite/is-cant-open.js.map +0 -1
  233. package/dist/shared/sqlite/is-not-a-database.d.ts +0 -3
  234. package/dist/shared/sqlite/is-not-a-database.d.ts.map +0 -1
  235. package/dist/shared/sqlite/is-not-a-database.js +0 -9
  236. package/dist/shared/sqlite/is-not-a-database.js.map +0 -1
package/README.md CHANGED
@@ -98,7 +98,7 @@ await mutex.acquire('product:42', async (lease) => {
98
98
  });
99
99
  ```
100
100
 
101
- Sometimes the lock store sees the loss, for example after a failover of `SocketStore`. Then the signal of the lease aborts with `LockLostError`, and the task can stop before its next write. When the task ends, the call rejects with `LockLostError`:
101
+ Sometimes the lock store sees the loss, for example after a failover of `SocketStore`. Then the signal of the lease aborts with `LeaseLostError`, and the task can stop before its next write. When the task ends, the call rejects with `LeaseLostError`:
102
102
 
103
103
  ```ts
104
104
  await mutex.acquire('product:42', async (lease) => {
@@ -111,6 +111,8 @@ await mutex.acquire('product:42', async (lease) => {
111
111
 
112
112
  The signal is a warning. A frozen holder can write before its lock store sees the loss, so the fencing token is still the protection.
113
113
 
114
+ The lease is a `FencedLease` of [`@zukhruf/fencing`](../fencing/README.md). Import `FencingToken` and the token sources from `@zukhruf/fencing`. `LeaseLostError` is from [`@zukhruf/lease`](../lease/README.md), and this package also exports it, because its calls reject with it.
115
+
114
116
  See [Fencing tokens](./docs/concepts/fencing-tokens.md) and the recipe [Protect a database from stale holders](./docs/recipes/fence-a-database.md).
115
117
 
116
118
  ## Documentation
@@ -120,7 +122,7 @@ See [Fencing tokens](./docs/concepts/fencing-tokens.md) and the recipe [Protect
120
122
  - [Reach](./docs/concepts/reach.md): who can share a lock, and how to select it.
121
123
  - [Acquire modes](./docs/concepts/acquire-modes.md): wait or skip while a key is busy, and cancel a wait.
122
124
  - [Fencing tokens](./docs/concepts/fencing-tokens.md): how a resource refuses a stale holder.
123
- - [Leader election](./docs/concepts/leader-election.md): how `SocketStore` selects its coordinator.
125
+ - [Leader election](../election/docs/concepts/leader-election.md): how `SocketStore` selects its coordinator, with `SqliteElection` of `@zukhruf/election`.
124
126
  - [Failure modes](./docs/concepts/failure-modes.md): what each lock store does when something stops.
125
127
 
126
128
  **Lock stores**: one page for each lock store, with What, Why, When, When not, How it works, Acquire modes, Failure modes, Options, and Evidence. See the table above.
@@ -133,7 +135,7 @@ See [Fencing tokens](./docs/concepts/fencing-tokens.md) and the recipe [Protect
133
135
  4. [Worker threads that share a lock](./docs/recipes/worker-threads.md)
134
136
  5. [Protect a database from stale holders](./docs/recipes/fence-a-database.md)
135
137
  6. [Survive a crashed holder](./docs/recipes/survive-a-crashed-holder.md)
136
- 7. [Run a job in only one process](./docs/recipes/singleton-job-with-leader-election.md)
138
+ 7. [Run a job in only one process](../election/docs/recipes/singleton-job-with-leader-election.md), with `@zukhruf/election`
137
139
  8. [Write your own lock store](./docs/recipes/write-your-own-lock-store.md)
138
140
  9. [Skip a job that is already running](./docs/recipes/skip-a-job-that-is-already-running.md)
139
141
  10. [Compute a value once and share it](./docs/recipes/compute-once-and-share-it.md)
@@ -150,7 +152,6 @@ npm install @zukhruf/mutex
150
152
 
151
153
  ```ts
152
154
  import { Mutex, SqliteStore } from '@zukhruf/mutex';
153
- import { LeaderElection } from '@zukhruf/mutex/leader-election';
154
155
  ```
155
156
 
156
157
  ## Development
@@ -169,12 +170,10 @@ The tests run from `src/`, not from `dist/`: they start workers and child proces
169
170
 
170
171
  ```
171
172
  src/
172
- mutex/ Mutex, Key, acquire modes, Lease, LockHandle, LockStore, LockLostError
173
- fencing/ fencing tokens and token sources
173
+ mutex/ Mutex, Key, acquire modes, LockHandle, LockStore
174
174
  lock-stores/ one folder for each lock store
175
175
  remote/ the coordinator and client that ThreadStore, IpcStore and SocketStore share
176
- leader-election/ leader election (separate entry point, not part of the mutex)
177
- shared/ small file system and SQLite helpers
176
+ shared/ a record check (key file names, file writes and file locks are in @zukhruf/fs)
178
177
  testing/ test helpers and the matrix of lock stores (not published)
179
178
  docs/
180
179
  concepts/ stores/ recipes/ adr/
package/dist/index.d.ts CHANGED
@@ -1,18 +1,12 @@
1
1
  export { Mutex } from './mutex/mutex.ts';
2
2
  export { Key } from './mutex/key.ts';
3
- export { leaseFor, type Lease, type LockHandle } from './mutex/lease.ts';
3
+ export { leaseFor, type LockHandle } from './mutex/lease.ts';
4
4
  export type { AcquireOptions, LockStore } from './mutex/lock-store.ts';
5
- export { LockLostError } from './mutex/lock-lost-error.ts';
5
+ export { LeaseLostError } from '@zukhruf/lease';
6
6
  export type { Acquired, AcquireMode, ModeResult, NotAcquired, Outcome, OutcomeResults, } from './mutex/acquire-mode.ts';
7
7
  export { Modes } from './mutex/acquire-modes/modes.ts';
8
8
  export { WaitMode } from './mutex/acquire-modes/wait-mode.ts';
9
9
  export { SkipIfBusyMode, type SkipIfBusyOptions, } from './mutex/acquire-modes/skip-if-busy-mode.ts';
10
- export { FencingToken } from './fencing/fencing-token.ts';
11
- export type { TokenSource } from './fencing/token-source.ts';
12
- export { CounterTokenSource } from './fencing/counter-token-source.ts';
13
- export { FileTokenSource } from './fencing/file-token-source.ts';
14
- export { MonotonicClockTokenSource } from './fencing/monotonic-clock-token-source.ts';
15
- export { EpochTokenSource } from './fencing/epoch-token-source.ts';
16
10
  export { MemoryStore, type MemoryStoreOptions, } from './lock-stores/memory/memory-store.ts';
17
11
  export { ThreadLockCoordinator, type ThreadLockCoordinatorOptions, } from './lock-stores/thread/thread-lock-coordinator.ts';
18
12
  export { ThreadStore } from './lock-stores/thread/thread-store.ts';
@@ -20,7 +14,7 @@ export { IpcLockCoordinator, type IpcLockCoordinatorOptions, } from './lock-stor
20
14
  export { IpcStore } from './lock-stores/ipc/ipc-store.ts';
21
15
  export { CoordinatorUnavailableError } from './lock-stores/remote/coordinator-unavailable-error.ts';
22
16
  export { UnsupportedRequestError } from './lock-stores/remote/unsupported-request-error.ts';
23
- export { NetworkDirectoryError } from './local-directory/network-directory-error.ts';
17
+ export { NetworkDirectoryError } from '@zukhruf/fs';
24
18
  export { FileLockStore, type FileLockStoreOptions, } from './lock-stores/file-system/file-lock-store.ts';
25
19
  export { TicketQueueFileStore } from './lock-stores/file-system/ticket-queue-file-store.ts';
26
20
  export { LockFileStore } from './lock-stores/file-system/lock-file-store.ts';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,KAAK,KAAK,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACzE,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,YAAY,EACV,QAAQ,EACR,WAAW,EACX,UAAU,EACV,WAAW,EACX,OAAO,EACP,cAAc,GACf,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAC;AAC9D,OAAO,EACL,cAAc,EACd,KAAK,iBAAiB,GACvB,MAAM,4CAA4C,CAAC;AAEpD,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,YAAY,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,yBAAyB,EAAE,MAAM,2CAA2C,CAAC;AACtF,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAEnE,OAAO,EACL,WAAW,EACX,KAAK,kBAAkB,GACxB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACL,qBAAqB,EACrB,KAAK,4BAA4B,GAClC,MAAM,iDAAiD,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACnE,OAAO,EACL,kBAAkB,EAClB,KAAK,yBAAyB,GAC/B,MAAM,2CAA2C,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAC1D,OAAO,EAAE,2BAA2B,EAAE,MAAM,uDAAuD,CAAC;AACpG,OAAO,EAAE,uBAAuB,EAAE,MAAM,mDAAmD,CAAC;AAC5F,OAAO,EAAE,qBAAqB,EAAE,MAAM,8CAA8C,CAAC;AACrF,OAAO,EACL,aAAa,EACb,KAAK,oBAAoB,GAC1B,MAAM,8CAA8C,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,sDAAsD,CAAC;AAC5F,OAAO,EAAE,aAAa,EAAE,MAAM,8CAA8C,CAAC;AAC7E,OAAO,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,gDAAgD,CAAC;AACtF,OAAO,EACL,WAAW,EACX,KAAK,UAAU,EACf,KAAK,kBAAkB,GACxB,MAAM,sCAAsC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC7D,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,YAAY,EACV,QAAQ,EACR,WAAW,EACX,UAAU,EACV,WAAW,EACX,OAAO,EACP,cAAc,GACf,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAC;AAC9D,OAAO,EACL,cAAc,EACd,KAAK,iBAAiB,GACvB,MAAM,4CAA4C,CAAC;AAEpD,OAAO,EACL,WAAW,EACX,KAAK,kBAAkB,GACxB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACL,qBAAqB,EACrB,KAAK,4BAA4B,GAClC,MAAM,iDAAiD,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACnE,OAAO,EACL,kBAAkB,EAClB,KAAK,yBAAyB,GAC/B,MAAM,2CAA2C,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAC1D,OAAO,EAAE,2BAA2B,EAAE,MAAM,uDAAuD,CAAC;AACpG,OAAO,EAAE,uBAAuB,EAAE,MAAM,mDAAmD,CAAC;AAC5F,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EACL,aAAa,EACb,KAAK,oBAAoB,GAC1B,MAAM,8CAA8C,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,sDAAsD,CAAC;AAC5F,OAAO,EAAE,aAAa,EAAE,MAAM,8CAA8C,CAAC;AAC7E,OAAO,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,gDAAgD,CAAC;AACtF,OAAO,EACL,WAAW,EACX,KAAK,UAAU,EACf,KAAK,kBAAkB,GACxB,MAAM,sCAAsC,CAAC"}
package/dist/index.js CHANGED
@@ -1,15 +1,10 @@
1
1
  export { Mutex } from "./mutex/mutex.js";
2
2
  export { Key } from "./mutex/key.js";
3
3
  export { leaseFor } from "./mutex/lease.js";
4
- export { LockLostError } from "./mutex/lock-lost-error.js";
4
+ export { LeaseLostError } from '@zukhruf/lease';
5
5
  export { Modes } from "./mutex/acquire-modes/modes.js";
6
6
  export { WaitMode } from "./mutex/acquire-modes/wait-mode.js";
7
7
  export { SkipIfBusyMode, } from "./mutex/acquire-modes/skip-if-busy-mode.js";
8
- export { FencingToken } from "./fencing/fencing-token.js";
9
- export { CounterTokenSource } from "./fencing/counter-token-source.js";
10
- export { FileTokenSource } from "./fencing/file-token-source.js";
11
- export { MonotonicClockTokenSource } from "./fencing/monotonic-clock-token-source.js";
12
- export { EpochTokenSource } from "./fencing/epoch-token-source.js";
13
8
  export { MemoryStore, } from "./lock-stores/memory/memory-store.js";
14
9
  export { ThreadLockCoordinator, } from "./lock-stores/thread/thread-lock-coordinator.js";
15
10
  export { ThreadStore } from "./lock-stores/thread/thread-store.js";
@@ -17,7 +12,7 @@ export { IpcLockCoordinator, } from "./lock-stores/ipc/ipc-lock-coordinator.js";
17
12
  export { IpcStore } from "./lock-stores/ipc/ipc-store.js";
18
13
  export { CoordinatorUnavailableError } from "./lock-stores/remote/coordinator-unavailable-error.js";
19
14
  export { UnsupportedRequestError } from "./lock-stores/remote/unsupported-request-error.js";
20
- export { NetworkDirectoryError } from "./local-directory/network-directory-error.js";
15
+ export { NetworkDirectoryError } from '@zukhruf/fs';
21
16
  export { FileLockStore, } from "./lock-stores/file-system/file-lock-store.js";
22
17
  export { TicketQueueFileStore } from "./lock-stores/file-system/ticket-queue-file-store.js";
23
18
  export { LockFileStore } from "./lock-stores/file-system/lock-file-store.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,EAAE,QAAQ,EAA+B,MAAM,kBAAkB,CAAC;AAEzE,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAS3D,OAAO,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAC;AAC9D,OAAO,EACL,cAAc,GAEf,MAAM,4CAA4C,CAAC;AAEpD,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,yBAAyB,EAAE,MAAM,2CAA2C,CAAC;AACtF,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAEnE,OAAO,EACL,WAAW,GAEZ,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACL,qBAAqB,GAEtB,MAAM,iDAAiD,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACnE,OAAO,EACL,kBAAkB,GAEnB,MAAM,2CAA2C,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAC1D,OAAO,EAAE,2BAA2B,EAAE,MAAM,uDAAuD,CAAC;AACpG,OAAO,EAAE,uBAAuB,EAAE,MAAM,mDAAmD,CAAC;AAC5F,OAAO,EAAE,qBAAqB,EAAE,MAAM,8CAA8C,CAAC;AACrF,OAAO,EACL,aAAa,GAEd,MAAM,8CAA8C,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,sDAAsD,CAAC;AAC5F,OAAO,EAAE,aAAa,EAAE,MAAM,8CAA8C,CAAC;AAC7E,OAAO,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,gDAAgD,CAAC;AACtF,OAAO,EACL,WAAW,GAGZ,MAAM,sCAAsC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAmB,MAAM,kBAAkB,CAAC;AAE7D,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAShD,OAAO,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAC;AAC9D,OAAO,EACL,cAAc,GAEf,MAAM,4CAA4C,CAAC;AAEpD,OAAO,EACL,WAAW,GAEZ,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACL,qBAAqB,GAEtB,MAAM,iDAAiD,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACnE,OAAO,EACL,kBAAkB,GAEnB,MAAM,2CAA2C,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAC1D,OAAO,EAAE,2BAA2B,EAAE,MAAM,uDAAuD,CAAC;AACpG,OAAO,EAAE,uBAAuB,EAAE,MAAM,mDAAmD,CAAC;AAC5F,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EACL,aAAa,GAEd,MAAM,8CAA8C,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,sDAAsD,CAAC;AAC5F,OAAO,EAAE,aAAa,EAAE,MAAM,8CAA8C,CAAC;AAC7E,OAAO,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,gDAAgD,CAAC;AACtF,OAAO,EACL,WAAW,GAGZ,MAAM,sCAAsC,CAAC"}
@@ -1,4 +1,4 @@
1
- import type { TokenSource } from '../../fencing/token-source.ts';
1
+ import { type TokenSource } from '@zukhruf/fencing';
2
2
  import { type LockHandle } from '../../mutex/lease.ts';
3
3
  import type { AcquireOptions, LockStore } from '../../mutex/lock-store.ts';
4
4
  export interface FileLockStoreOptions {
@@ -7,10 +7,6 @@ export interface FileLockStoreOptions {
7
7
  /** Defaults to durable per-key counter files beside the locks. */
8
8
  tokens?: TokenSource;
9
9
  }
10
- export interface PollOptions {
11
- /** Stops between attempts when it aborts; the poll then rejects with `signal.reason`. */
12
- signal?: AbortSignal | undefined;
13
- }
14
10
  /** Shares one lock directory between processes: each key maps to `<directory>/<key>.lock`. */
15
11
  export declare abstract class FileLockStore implements LockStore {
16
12
  #private;
@@ -31,15 +27,14 @@ export declare abstract class FileLockStore implements LockStore {
31
27
  protected abstract tryLock(path: string): Promise<AsyncDisposable | undefined>;
32
28
  /** Whether the lock at `path` has a holder now, learned without a lock that a caller of `lock` or `tryLock` needs. */
33
29
  protected abstract isHeldAt(path: string): Promise<boolean>;
34
- protected poll<T>(attempt: () => Promise<T | undefined>, { signal }?: PollOptions): Promise<T>;
30
+ /** Stops between attempts once `signal` aborts, and then rejects with `signal.reason`. */
31
+ protected poll<T>(attempt: () => Promise<T | undefined>, signal: AbortSignal | undefined): Promise<T>;
35
32
  /**
36
33
  * Serializes evicting a dead holder. Without it, two waiters that saw the
37
34
  * same dead holder could each remove a lock the other had just taken. The
38
35
  * kernel holds this lock, so a waiter that dies while it evicts frees it at
39
36
  * once. Its file stays for the next eviction: deleting it while waiters use
40
- * it would let two of them lock two different files. Nothing may open that
41
- * file except through SQLite: closing any other handle to it drops this
42
- * process's lock without a word.
37
+ * it would let two of them lock two different files.
43
38
  */
44
39
  protected withReclaimLock(path: string, task: () => Promise<void>): Promise<void>;
45
40
  }
@@ -1 +1 @@
1
- {"version":3,"file":"file-lock-store.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/file-system/file-lock-store.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAEjE,OAAO,EAAE,KAAK,UAAU,EAAY,MAAM,sBAAsB,CAAC;AACjE,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAK3E,MAAM,WAAW,oBAAoB;IACnC,qDAAqD;IACrD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kEAAkE;IAClE,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,yFAAyF;IACzF,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CAClC;AAED,8FAA8F;AAC9F,8BAAsB,aAAc,YAAW,SAAS;;gBAMpD,SAAS,EAAE,MAAM,EACjB,EACE,YAAiB,EACjB,MAAuC,GACxC,GAAE,oBAAyB;IAOxB,OAAO,CACX,GAAG,EAAE,MAAM,EACX,EAAE,MAAM,EAAE,GAAE,cAAmB,GAC9B,OAAO,CAAC,UAAU,CAAC;IAMhB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAK9D,kFAAkF;IAC5E,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAK3C;;;;OAIG;IACH,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAElD,kFAAkF;IAClF,SAAS,CAAC,QAAQ,CAAC,IAAI,CACrB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,WAAW,GAAG,SAAS,GAC9B,OAAO,CAAC,eAAe,CAAC;IAE3B,mEAAmE;IACnE,SAAS,CAAC,QAAQ,CAAC,OAAO,CACxB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC;IAEvC,sHAAsH;IACtH,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;cAE3C,IAAI,CAAC,CAAC,EACpB,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,EACrC,EAAE,MAAM,EAAE,GAAE,WAAgB,GAC3B,OAAO,CAAC,CAAC,CAAC;IAab;;;;;;;;OAQG;cACa,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC;CAyBxE"}
1
+ {"version":3,"file":"file-lock-store.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/file-system/file-lock-store.ts"],"names":[],"mappings":"AAKA,OAAO,EAAmB,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGrE,OAAO,EAAE,KAAK,UAAU,EAAY,MAAM,sBAAsB,CAAC;AACjE,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAE3E,MAAM,WAAW,oBAAoB;IACnC,qDAAqD;IACrD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kEAAkE;IAClE,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,8FAA8F;AAC9F,8BAAsB,aAAc,YAAW,SAAS;;gBAMpD,SAAS,EAAE,MAAM,EACjB,EACE,YAAiB,EACjB,MAAuC,GACxC,GAAE,oBAAyB;IAOxB,OAAO,CACX,GAAG,EAAE,MAAM,EACX,EAAE,MAAM,EAAE,GAAE,cAAmB,GAC9B,OAAO,CAAC,UAAU,CAAC;IAMhB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAK9D,kFAAkF;IAC5E,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAK3C;;;;OAIG;IACH,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAElD,kFAAkF;IAClF,SAAS,CAAC,QAAQ,CAAC,IAAI,CACrB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,WAAW,GAAG,SAAS,GAC9B,OAAO,CAAC,eAAe,CAAC;IAE3B,mEAAmE;IACnE,SAAS,CAAC,QAAQ,CAAC,OAAO,CACxB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC;IAEvC,sHAAsH;IACtH,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAE3D,0FAA0F;cAC1E,IAAI,CAAC,CAAC,EACpB,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,EACrC,MAAM,EAAE,WAAW,GAAG,SAAS,GAC9B,OAAO,CAAC,CAAC,CAAC;IAWb;;;;;;OAMG;cACa,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC;CAiBxE"}
@@ -1,13 +1,10 @@
1
1
  import { mkdir } from 'node:fs/promises';
2
2
  import { join } from 'node:path';
3
- import { DatabaseSync } from 'node:sqlite';
4
3
  import { setTimeout as delay } from 'node:timers/promises';
5
- import { FileTokenSource } from "../../fencing/file-token-source.js";
6
- import { assertLocalDirectory } from "../../local-directory/local-directory.js";
4
+ import { untilAborted } from '@zukhruf/async';
5
+ import { FileTokenSource } from '@zukhruf/fencing';
6
+ import { FileLock, assertLocalDirectory, safeFileName } from '@zukhruf/fs';
7
7
  import { leaseFor } from "../../mutex/lease.js";
8
- import { safeFileName } from "../../shared/fs/safe-file-name.js";
9
- import { isBusy } from "../../shared/sqlite/is-busy.js";
10
- import { isNotADatabase } from "../../shared/sqlite/is-not-a-database.js";
11
8
  /** Shares one lock directory between processes: each key maps to `<directory>/<key>.lock`. */
12
9
  export class FileLockStore {
13
10
  #directory;
@@ -32,18 +29,13 @@ export class FileLockStore {
32
29
  await assertLocalDirectory(this.#directory);
33
30
  return this.isHeldAt(this.#pathFor(key));
34
31
  }
35
- async poll(attempt, { signal } = {}) {
32
+ /** Stops between attempts once `signal` aborts, and then rejects with `signal.reason`. */
33
+ async poll(attempt, signal) {
36
34
  for (;;) {
37
35
  const result = await attempt();
38
36
  if (result !== undefined)
39
37
  return result;
40
- try {
41
- await delay(this.#pollInterval, undefined, { signal });
42
- }
43
- catch (error) {
44
- signal?.throwIfAborted();
45
- throw error;
46
- }
38
+ await untilAborted(delay(this.#pollInterval, undefined, { signal }), signal);
47
39
  }
48
40
  }
49
41
  /**
@@ -51,26 +43,14 @@ export class FileLockStore {
51
43
  * same dead holder could each remove a lock the other had just taken. The
52
44
  * kernel holds this lock, so a waiter that dies while it evicts frees it at
53
45
  * once. Its file stays for the next eviction: deleting it while waiters use
54
- * it would let two of them lock two different files. Nothing may open that
55
- * file except through SQLite: closing any other handle to it drops this
56
- * process's lock without a word.
46
+ * it would let two of them lock two different files.
57
47
  */
58
48
  async withReclaimLock(path, task) {
59
49
  const reclaimPath = `${path}.reclaim`;
60
- const reclaim = new DatabaseSync(reclaimPath, { timeout: 0 });
61
- try {
62
- if (!claim(reclaim, reclaimPath))
63
- return;
64
- try {
65
- await task();
66
- }
67
- finally {
68
- reclaim.exec('ROLLBACK');
69
- }
70
- }
71
- finally {
72
- reclaim.close();
73
- }
50
+ using reclaim = FileLock.open(reclaimPath);
51
+ if (!claim(reclaim, reclaimPath))
52
+ return;
53
+ await task();
74
54
  }
75
55
  async #prepare(key) {
76
56
  await assertLocalDirectory(this.#directory);
@@ -82,21 +62,24 @@ export class FileLockStore {
82
62
  return join(this.#directory, `${name}.lock`);
83
63
  }
84
64
  }
85
- /** Whether this connection now holds the reclaim lock; another waiter is evicting if not. */
65
+ /** Whether this handle now holds the reclaim lock; another waiter is evicting if not. */
86
66
  function claim(reclaim, path) {
87
67
  try {
88
- // A journal on disk would outlive a waiter that dies while it holds the lock.
89
- reclaim.exec('PRAGMA journal_mode = MEMORY');
90
- reclaim.exec('BEGIN EXCLUSIVE');
91
- return true;
68
+ return reclaim.tryLock();
92
69
  }
93
70
  catch (error) {
94
- if (isBusy(error))
95
- return false;
96
71
  if (isNotADatabase(error)) {
97
72
  throw new Error(`The reclaim file ${JSON.stringify(path)} was left by an older version of @zukhruf/mutex. Stop the processes that run that version, then delete the file.`, { cause: error });
98
73
  }
99
74
  throw error;
100
75
  }
101
76
  }
77
+ const SQLITE_NOTADB = 26;
78
+ /** Whether `error` means the file is not a SQLite database, for example a file that an older version wrote. */
79
+ function isNotADatabase(error) {
80
+ return (error instanceof Error &&
81
+ 'errcode' in error &&
82
+ typeof error.errcode === 'number' &&
83
+ (error.errcode & 0xff) === SQLITE_NOTADB);
84
+ }
102
85
  //# sourceMappingURL=file-lock-store.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-lock-store.js","sourceRoot":"","sources":["../../../src/lock-stores/file-system/file-lock-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"file-lock-store.js","sourceRoot":"","sources":["../../../src/lock-stores/file-system/file-lock-store.ts"],"names":[],"mappings":"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"}
@@ -5,7 +5,7 @@ import { FileLockStore } from './file-lock-store.ts';
5
5
  */
6
6
  export declare class LockFileStore extends FileLockStore {
7
7
  #private;
8
- /** A presence file has the longest name this store makes for a key. */
8
+ /** The longer of a presence file and the draft that `createExclusive` writes beside the record. */
9
9
  protected readonly longestSuffix: number;
10
10
  protected lock(path: string, signal: AbortSignal | undefined): Promise<AsyncDisposable>;
11
11
  protected tryLock(path: string): Promise<AsyncDisposable | undefined>;
@@ -1 +1 @@
1
- {"version":3,"file":"lock-file-store.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/file-system/lock-file-store.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrD;;;GAGG;AACH,qBAAa,aAAc,SAAQ,aAAa;;IAC9C,uEAAuE;IACvE,SAAS,CAAC,QAAQ,CAAC,aAAa,SAAyB;IAEzD,SAAS,CAAC,IAAI,CACZ,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,WAAW,GAAG,SAAS,GAC9B,OAAO,CAAC,eAAe,CAAC;cAKX,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC;IAkC3E,kEAAkE;IAClE,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAiBnD"}
1
+ {"version":3,"file":"lock-file-store.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/file-system/lock-file-store.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIrD;;;GAGG;AACH,qBAAa,aAAc,SAAQ,aAAa;;IAC9C,mGAAmG;IACnG,SAAS,CAAC,QAAQ,CAAC,aAAa,SAG9B;IAEF,SAAS,CAAC,IAAI,CACZ,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,WAAW,GAAG,SAAS,GAC9B,OAAO,CAAC,eAAe,CAAC;cAKX,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC;IA6B3E,kEAAkE;IAClE,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAanD"}
@@ -1,20 +1,19 @@
1
- import { readFile, unlink } from 'node:fs/promises';
2
- import { createExclusive } from "../../shared/fs/create-exclusive.js";
3
- import { isErrno } from "../../shared/fs/errno.js";
4
- import { patiently } from "../../shared/fs/patiently.js";
1
+ import { unlink } from 'node:fs/promises';
2
+ import { createExclusive, draftSuffixLength, patiently } from '@zukhruf/fs';
5
3
  import { Caller } from "./caller.js";
6
4
  import { FileLockStore } from "./file-lock-store.js";
7
5
  import { Presence } from "./presence.js";
6
+ import { readRecord } from "./record-file.js";
8
7
  /**
9
8
  * Whoever creates the lock file holds the key; releasing deletes it. Waiters
10
9
  * retry in no particular order, so this store is not FIFO.
11
10
  */
12
11
  export class LockFileStore extends FileLockStore {
13
- /** A presence file has the longest name this store makes for a key. */
14
- longestSuffix = Presence.suffixLength;
12
+ /** The longer of a presence file and the draft that `createExclusive` writes beside the record. */
13
+ longestSuffix = Math.max(Presence.suffixLength, draftSuffixLength);
15
14
  lock(path, signal) {
16
15
  const me = Caller.current();
17
- return this.poll(() => this.#attempt(path, me), { signal });
16
+ return this.poll(() => this.#attempt(path, me), signal);
18
17
  }
19
18
  async tryLock(path) {
20
19
  const me = Caller.current();
@@ -28,15 +27,11 @@ export class LockFileStore extends FileLockStore {
28
27
  await this.#evictIfGone(path, holder);
29
28
  return undefined;
30
29
  }
31
- const presence = Presence.claim(Presence.pathOf(path, me));
32
- const created = await createExclusive(path, me.serialize()).catch(async (error) => {
33
- await presence.withdraw();
34
- throw error;
35
- });
36
- if (!created) {
37
- await presence.withdraw();
30
+ await using claiming = new AsyncDisposableStack();
31
+ const presence = claiming.adopt(Presence.claim(path, me), (claimed) => claimed.withdraw());
32
+ if (!(await createExclusive(path, me.serialize())))
38
33
  return undefined;
39
- }
34
+ claiming.move();
40
35
  return {
41
36
  [Symbol.asyncDispose]: () => presence.releaseAfter(() => removeLockFile(path)),
42
37
  };
@@ -46,7 +41,7 @@ export class LockFileStore extends FileLockStore {
46
41
  return Presence.isNamedCallerPresent(path, () => readHolder(path));
47
42
  }
48
43
  async #evictIfGone(path, holder) {
49
- const state = await Presence.judge(path, holder, async () => (await readHolder(path))?.id === holder.id);
44
+ const state = await Presence.judge(path, holder, () => readHolder(path));
50
45
  if (state !== 'gone')
51
46
  return;
52
47
  await this.withReclaimLock(path, async () => {
@@ -61,13 +56,9 @@ function removeLockFile(path) {
61
56
  return patiently(() => unlink(path));
62
57
  }
63
58
  async function readHolder(path) {
64
- try {
65
- return Caller.parse(await patiently(() => readFile(path, 'utf8')));
66
- }
67
- catch (error) {
68
- if (isErrno(error, 'ENOENT'))
69
- return undefined;
70
- throw error;
71
- }
59
+ const content = await readRecord(path);
60
+ if (content === undefined)
61
+ return undefined;
62
+ return Caller.parse(content);
72
63
  }
73
64
  //# sourceMappingURL=lock-file-store.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"lock-file-store.js","sourceRoot":"","sources":["../../../src/lock-stores/file-system/lock-file-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"lock-file-store.js","sourceRoot":"","sources":["../../../src/lock-stores/file-system/lock-file-store.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,10 @@
1
1
  import { Caller } from './caller.ts';
2
2
  /**
3
- * A caller's presence: an exclusive SQLite transaction on a file of its own,
4
- * held from before the caller's record (a lock file, a ticket, or the holder
5
- * record of `SqliteStore`) appears until after it is gone. The kernel ends it
6
- * when the caller's process or thread stops, however it stops, so a waiter
7
- * that can read the file knows the caller is gone. Nothing may open the file
8
- * except through SQLite: closing any other handle to it drops this process's
9
- * lock without a word.
3
+ * A caller's presence: the file lock of a file of its own, held from before
4
+ * the caller's record (a lock file, a ticket, or the holder record of
5
+ * `SqliteStore`) appears until after it is gone. The kernel ends it when the
6
+ * caller's process or thread stops, however it stops, so a waiter that can
7
+ * check the file knows the caller is gone.
10
8
  */
11
9
  export declare class Presence {
12
10
  #private;
@@ -15,20 +13,15 @@ export declare class Presence {
15
13
  static readonly suffixLength: number;
16
14
  /** The presence file of `caller`, whose record is at `record`. */
17
15
  static pathOf(record: string, caller: Caller): string;
18
- static claim(path: string): Presence;
19
- /**
20
- * Whether the caller behind `path` still runs. Reading needs a lock that the
21
- * caller's exclusive transaction refuses, and opening read-only never creates
22
- * the file.
23
- */
24
- static check(path: string): 'present' | 'gone' | 'missing';
16
+ /** Claims the presence of `caller`, whose record is at `record`. */
17
+ static claim(record: string, caller: Caller): Presence;
25
18
  /**
26
19
  * Whether `caller`, whom the record at `record` named, still runs. A caller's
27
20
  * record goes before its presence file, so a missing presence file is a
28
- * fault while `stillNamed` says the record names the caller, and means the
29
- * caller `moved` on when it does not.
21
+ * fault while `readNamed` still reads the caller from the record, and means
22
+ * the caller `moved` on when it does not.
30
23
  */
31
- static judge(record: string, caller: Caller, stillNamed: () => Promise<boolean>): Promise<'present' | 'gone' | 'moved'>;
24
+ static judge(record: string, caller: Caller, readNamed: () => Promise<Caller | undefined>): Promise<'present' | 'gone' | 'moved'>;
32
25
  /** Whether the caller that `readNamed` reads from the record at `record` still runs. Writes nothing. */
33
26
  static isNamedCallerPresent(record: string, readNamed: () => Promise<Caller | undefined>): Promise<boolean>;
34
27
  /** Deletes the file of a presence that has ended. */
@@ -1 +1 @@
1
- {"version":3,"file":"presence.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/file-system/presence.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAKrC;;;;;;;;GAQG;AACH,qBAAa,QAAQ;;IAInB,OAAO;IAKP,2DAA2D;IAC3D,MAAM,CAAC,QAAQ,CAAC,YAAY,SAAgD;IAE5E,kEAAkE;IAClE,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM;IAIrD,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ;IAcpC;;;;OAIG;IACH,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS;IAoB1D;;;;;OAKG;WACU,KAAK,CAChB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GACjC,OAAO,CAAC,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;IAQxC,wGAAwG;WAC3F,oBAAoB,CAC/B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,GAC3C,OAAO,CAAC,OAAO,CAAC;IAanB,qDAAqD;WACxC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWhD,sGAAsG;IACtG,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,KAAK;IAMnD,uFAAuF;IACvF,GAAG,IAAI,IAAI;IAMX;;;;OAIG;IACG,YAAY,CAAC,YAAY,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAWpE,uEAAuE;IACjE,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAIhC"}
1
+ {"version":3,"file":"presence.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/file-system/presence.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;;;;;GAMG;AACH,qBAAa,QAAQ;;IAInB,OAAO;IAKP,2DAA2D;IAC3D,MAAM,CAAC,QAAQ,CAAC,YAAY,SAAgD;IAE5E,kEAAkE;IAClE,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM;IAIrD,oEAAoE;IACpE,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,QAAQ;IAatD;;;;;OAKG;WACU,KAAK,CAChB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,GAC3C,OAAO,CAAC,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;IAWxC,wGAAwG;WAC3F,oBAAoB,CAC/B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,GAC3C,OAAO,CAAC,OAAO,CAAC;IASnB,qDAAqD;WACxC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWhD,sGAAsG;IACtG,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,KAAK;IAMnD,uFAAuF;IACvF,GAAG,IAAI,IAAI;IAIX;;;;OAIG;IACG,YAAY,CAAC,YAAY,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAWpE,uEAAuE;IACjE,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAIhC"}
@@ -1,27 +1,19 @@
1
- import { existsSync } from 'node:fs';
2
1
  import { unlink } from 'node:fs/promises';
3
- import { DatabaseSync } from 'node:sqlite';
4
- import { patiently } from "../../shared/fs/patiently.js";
5
- import { isBusy } from "../../shared/sqlite/is-busy.js";
6
- import { isCantOpen } from "../../shared/sqlite/is-cant-open.js";
2
+ import { FileLock, patiently } from '@zukhruf/fs';
7
3
  import { Caller } from "./caller.js";
8
- /** Garbage collection closes a connection nobody references, which would end a presence its caller still holds. */
9
- const open = new Set();
10
4
  /**
11
- * A caller's presence: an exclusive SQLite transaction on a file of its own,
12
- * held from before the caller's record (a lock file, a ticket, or the holder
13
- * record of `SqliteStore`) appears until after it is gone. The kernel ends it
14
- * when the caller's process or thread stops, however it stops, so a waiter
15
- * that can read the file knows the caller is gone. Nothing may open the file
16
- * except through SQLite: closing any other handle to it drops this process's
17
- * lock without a word.
5
+ * A caller's presence: the file lock of a file of its own, held from before
6
+ * the caller's record (a lock file, a ticket, or the holder record of
7
+ * `SqliteStore`) appears until after it is gone. The kernel ends it when the
8
+ * caller's process or thread stops, however it stops, so a waiter that can
9
+ * check the file knows the caller is gone.
18
10
  */
19
11
  export class Presence {
20
12
  #path;
21
- #database;
22
- constructor(path, database) {
13
+ #lock;
14
+ constructor(path, lock) {
23
15
  this.#path = path;
24
- this.#database = database;
16
+ this.#lock = lock;
25
17
  }
26
18
  /** The length of what `pathOf` adds to a record's path. */
27
19
  static suffixLength = Presence.pathOf('', Caller.current()).length;
@@ -29,62 +21,33 @@ export class Presence {
29
21
  static pathOf(record, caller) {
30
22
  return `${record}.${caller.id}.presence`;
31
23
  }
32
- static claim(path) {
33
- const database = new DatabaseSync(path, { timeout: 0 });
34
- try {
35
- // A journal on disk would outlive a caller that dies while present.
36
- database.exec('PRAGMA journal_mode = MEMORY');
37
- database.exec('BEGIN EXCLUSIVE');
38
- }
39
- catch (error) {
40
- database.close();
41
- throw error;
42
- }
43
- open.add(database);
44
- return new Presence(path, database);
45
- }
46
- /**
47
- * Whether the caller behind `path` still runs. Reading needs a lock that the
48
- * caller's exclusive transaction refuses, and opening read-only never creates
49
- * the file.
50
- */
51
- static check(path) {
52
- let database;
53
- try {
54
- database = new DatabaseSync(path, { readOnly: true, timeout: 0 });
55
- }
56
- catch (error) {
57
- // A file that exists but cannot be opened is a fault, not a missing presence.
58
- if (isCantOpen(error) && !existsSync(path))
59
- return 'missing';
60
- throw error;
61
- }
62
- try {
63
- database.prepare('SELECT count(*) FROM sqlite_schema').get();
64
- return 'gone';
65
- }
66
- catch (error) {
67
- if (isBusy(error))
68
- return 'present';
69
- throw error;
70
- }
71
- finally {
72
- database.close();
24
+ /** Claims the presence of `caller`, whose record is at `record`. */
25
+ static claim(record, caller) {
26
+ const path = Presence.pathOf(record, caller);
27
+ using opened = new DisposableStack();
28
+ const lock = opened.use(FileLock.open(path));
29
+ if (!lock.tryLock()) {
30
+ throw new Error(`The presence file ${JSON.stringify(path)} is locked already, but it belongs to one caller only. Another program opened it.`);
73
31
  }
32
+ opened.move();
33
+ return new Presence(path, lock);
74
34
  }
75
35
  /**
76
36
  * Whether `caller`, whom the record at `record` named, still runs. A caller's
77
37
  * record goes before its presence file, so a missing presence file is a
78
- * fault while `stillNamed` says the record names the caller, and means the
79
- * caller `moved` on when it does not.
38
+ * fault while `readNamed` still reads the caller from the record, and means
39
+ * the caller `moved` on when it does not.
80
40
  */
81
- static async judge(record, caller, stillNamed) {
41
+ static async judge(record, caller, readNamed) {
82
42
  const path = Presence.pathOf(record, caller);
83
- const state = Presence.check(path);
84
- if (state !== 'missing')
85
- return state;
86
- if (await stillNamed())
43
+ const state = FileLock.check(path);
44
+ if (state === 'locked')
45
+ return 'present';
46
+ if (state === 'unlocked')
47
+ return 'gone';
48
+ if ((await readNamed())?.id === caller.id) {
87
49
  throw Presence.missing(record, path);
50
+ }
88
51
  return 'moved';
89
52
  }
90
53
  /** Whether the caller that `readNamed` reads from the record at `record` still runs. Writes nothing. */
@@ -93,7 +56,7 @@ export class Presence {
93
56
  const caller = await readNamed();
94
57
  if (!caller)
95
58
  return false;
96
- const state = await Presence.judge(record, caller, async () => (await readNamed())?.id === caller.id);
59
+ const state = await Presence.judge(record, caller, readNamed);
97
60
  if (state !== 'moved')
98
61
  return state === 'present';
99
62
  }
@@ -113,9 +76,7 @@ export class Presence {
113
76
  }
114
77
  /** Lets the kernel lock go. The file stays for whoever removes the caller's record. */
115
78
  end() {
116
- open.delete(this.#database);
117
- this.#database.exec('ROLLBACK');
118
- this.#database.close();
79
+ this.#lock[Symbol.dispose]();
119
80
  }
120
81
  /**
121
82
  * Removes the caller's record, then ends this presence and deletes its file.