@elaraai/e3-rack 0.0.0-bootstrap.0 → 1.0.94
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 +407 -2
- package/dist/src/client/client.spec.d.ts +6 -0
- package/dist/src/client/client.spec.d.ts.map +1 -0
- package/dist/src/client/client.spec.js +150 -0
- package/dist/src/client/client.spec.js.map +1 -0
- package/dist/src/client/connect.d.ts +52 -0
- package/dist/src/client/connect.d.ts.map +1 -0
- package/dist/src/client/connect.js +112 -0
- package/dist/src/client/connect.js.map +1 -0
- package/dist/src/client/hub-client.d.ts +57 -0
- package/dist/src/client/hub-client.d.ts.map +1 -0
- package/dist/src/client/hub-client.js +87 -0
- package/dist/src/client/hub-client.js.map +1 -0
- package/dist/src/client/local-http.d.ts +78 -0
- package/dist/src/client/local-http.d.ts.map +1 -0
- package/dist/src/client/local-http.js +149 -0
- package/dist/src/client/local-http.js.map +1 -0
- package/dist/src/client/session-attempts.d.ts +20 -0
- package/dist/src/client/session-attempts.d.ts.map +1 -0
- package/dist/src/client/session-attempts.js +88 -0
- package/dist/src/client/session-attempts.js.map +1 -0
- package/dist/src/client/session-data-server.d.ts +37 -0
- package/dist/src/client/session-data-server.d.ts.map +1 -0
- package/dist/src/client/session-data-server.js +280 -0
- package/dist/src/client/session-data-server.js.map +1 -0
- package/dist/src/client/session-data-server.spec.d.ts +6 -0
- package/dist/src/client/session-data-server.spec.d.ts.map +1 -0
- package/dist/src/client/session-data-server.spec.js +192 -0
- package/dist/src/client/session-data-server.spec.js.map +1 -0
- package/dist/src/client/session.d.ts +119 -0
- package/dist/src/client/session.d.ts.map +1 -0
- package/dist/src/client/session.js +290 -0
- package/dist/src/client/session.js.map +1 -0
- package/dist/src/hub/config.d.ts +74 -0
- package/dist/src/hub/config.d.ts.map +1 -0
- package/dist/src/hub/config.js +159 -0
- package/dist/src/hub/config.js.map +1 -0
- package/dist/src/hub/fair-lease-store.d.ts +36 -0
- package/dist/src/hub/fair-lease-store.d.ts.map +1 -0
- package/dist/src/hub/fair-lease-store.js +73 -0
- package/dist/src/hub/fair-lease-store.js.map +1 -0
- package/dist/src/hub/hub.d.ts +91 -0
- package/dist/src/hub/hub.d.ts.map +1 -0
- package/dist/src/hub/hub.js +641 -0
- package/dist/src/hub/hub.js.map +1 -0
- package/dist/src/hub/hub.spec.d.ts +6 -0
- package/dist/src/hub/hub.spec.d.ts.map +1 -0
- package/dist/src/hub/hub.spec.js +363 -0
- package/dist/src/hub/hub.spec.js.map +1 -0
- package/dist/src/hub/infrastructure.spec.d.ts +6 -0
- package/dist/src/hub/infrastructure.spec.d.ts.map +1 -0
- package/dist/src/hub/infrastructure.spec.js +211 -0
- package/dist/src/hub/infrastructure.spec.js.map +1 -0
- package/dist/src/hub/lock.d.ts +62 -0
- package/dist/src/hub/lock.d.ts.map +1 -0
- package/dist/src/hub/lock.js +165 -0
- package/dist/src/hub/lock.js.map +1 -0
- package/dist/src/hub/main.d.ts +16 -0
- package/dist/src/hub/main.d.ts.map +1 -0
- package/dist/src/hub/main.js +56 -0
- package/dist/src/hub/main.js.map +1 -0
- package/dist/src/hub/session-bridge.d.ts +116 -0
- package/dist/src/hub/session-bridge.d.ts.map +1 -0
- package/dist/src/hub/session-bridge.js +336 -0
- package/dist/src/hub/session-bridge.js.map +1 -0
- package/dist/src/identity/file-identity-store.d.ts +18 -0
- package/dist/src/identity/file-identity-store.d.ts.map +1 -0
- package/dist/src/identity/file-identity-store.js +34 -0
- package/dist/src/identity/file-identity-store.js.map +1 -0
- package/dist/src/identity/file-identity-store.spec.d.ts +6 -0
- package/dist/src/identity/file-identity-store.spec.d.ts.map +1 -0
- package/dist/src/identity/file-identity-store.spec.js +59 -0
- package/dist/src/identity/file-identity-store.spec.js.map +1 -0
- package/dist/src/identity/in-memory-identity-store.d.ts +48 -0
- package/dist/src/identity/in-memory-identity-store.d.ts.map +1 -0
- package/dist/src/identity/in-memory-identity-store.js +102 -0
- package/dist/src/identity/in-memory-identity-store.js.map +1 -0
- package/dist/src/identity/machine-identity.d.ts +134 -0
- package/dist/src/identity/machine-identity.d.ts.map +1 -0
- package/dist/src/identity/machine-identity.js +65 -0
- package/dist/src/identity/machine-identity.js.map +1 -0
- package/dist/src/index.d.ts +34 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +34 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/lease/closure.d.ts +96 -0
- package/dist/src/lease/closure.d.ts.map +1 -0
- package/dist/src/lease/closure.js +192 -0
- package/dist/src/lease/closure.js.map +1 -0
- package/dist/src/lease/closure.spec.d.ts +6 -0
- package/dist/src/lease/closure.spec.d.ts.map +1 -0
- package/dist/src/lease/closure.spec.js +35 -0
- package/dist/src/lease/closure.spec.js.map +1 -0
- package/dist/src/lease/coordinator.d.ts +34 -0
- package/dist/src/lease/coordinator.d.ts.map +1 -0
- package/dist/src/lease/coordinator.js +42 -0
- package/dist/src/lease/coordinator.js.map +1 -0
- package/dist/src/lease/in-memory-lease-store.d.ts +58 -0
- package/dist/src/lease/in-memory-lease-store.d.ts.map +1 -0
- package/dist/src/lease/in-memory-lease-store.js +132 -0
- package/dist/src/lease/in-memory-lease-store.js.map +1 -0
- package/dist/src/lease/lease-store.d.ts +169 -0
- package/dist/src/lease/lease-store.d.ts.map +1 -0
- package/dist/src/lease/lease-store.js +94 -0
- package/dist/src/lease/lease-store.js.map +1 -0
- package/dist/src/lease/lease-store.spec.d.ts +6 -0
- package/dist/src/lease/lease-store.spec.d.ts.map +1 -0
- package/dist/src/lease/lease-store.spec.js +8 -0
- package/dist/src/lease/lease-store.spec.js.map +1 -0
- package/dist/src/lease/rack-dispatch.d.ts +105 -0
- package/dist/src/lease/rack-dispatch.d.ts.map +1 -0
- package/dist/src/lease/rack-dispatch.js +6 -0
- package/dist/src/lease/rack-dispatch.js.map +1 -0
- package/dist/src/mutation-queue.d.ts +13 -0
- package/dist/src/mutation-queue.d.ts.map +1 -0
- package/dist/src/mutation-queue.js +17 -0
- package/dist/src/mutation-queue.js.map +1 -0
- package/dist/src/paths.d.ts +56 -0
- package/dist/src/paths.d.ts.map +1 -0
- package/dist/src/paths.js +82 -0
- package/dist/src/paths.js.map +1 -0
- package/dist/src/protocol/control.d.ts +295 -0
- package/dist/src/protocol/control.d.ts.map +1 -0
- package/dist/src/protocol/control.js +74 -0
- package/dist/src/protocol/control.js.map +1 -0
- package/dist/src/protocol/index.d.ts +9 -0
- package/dist/src/protocol/index.d.ts.map +1 -0
- package/dist/src/protocol/index.js +9 -0
- package/dist/src/protocol/index.js.map +1 -0
- package/dist/src/protocol/rack-wire.d.ts +357 -0
- package/dist/src/protocol/rack-wire.d.ts.map +1 -0
- package/dist/src/protocol/rack-wire.js +262 -0
- package/dist/src/protocol/rack-wire.js.map +1 -0
- package/dist/src/protocol/rack-wire.spec.d.ts +6 -0
- package/dist/src/protocol/rack-wire.spec.d.ts.map +1 -0
- package/dist/src/protocol/rack-wire.spec.js +14 -0
- package/dist/src/protocol/rack-wire.spec.js.map +1 -0
- package/dist/src/protocol/registration.d.ts +70 -0
- package/dist/src/protocol/registration.d.ts.map +1 -0
- package/dist/src/protocol/registration.js +67 -0
- package/dist/src/protocol/registration.js.map +1 -0
- package/dist/src/protocol/session-data.d.ts +69 -0
- package/dist/src/protocol/session-data.d.ts.map +1 -0
- package/dist/src/protocol/session-data.js +26 -0
- package/dist/src/protocol/session-data.js.map +1 -0
- package/dist/src/protocol/task-envelope.d.ts +198 -0
- package/dist/src/protocol/task-envelope.d.ts.map +1 -0
- package/dist/src/protocol/task-envelope.js +93 -0
- package/dist/src/protocol/task-envelope.js.map +1 -0
- package/dist/src/protocol/wire-golden.d.ts +8 -0
- package/dist/src/protocol/wire-golden.d.ts.map +1 -0
- package/dist/src/protocol/wire-golden.js +34 -0
- package/dist/src/protocol/wire-golden.js.map +1 -0
- package/dist/src/protocol/wire-samples.d.ts +11 -0
- package/dist/src/protocol/wire-samples.d.ts.map +1 -0
- package/dist/src/protocol/wire-samples.js +52 -0
- package/dist/src/protocol/wire-samples.js.map +1 -0
- package/dist/src/registry/file-rack-registry.d.ts +68 -0
- package/dist/src/registry/file-rack-registry.d.ts.map +1 -0
- package/dist/src/registry/file-rack-registry.js +138 -0
- package/dist/src/registry/file-rack-registry.js.map +1 -0
- package/dist/src/registry/file-rack-registry.spec.d.ts +6 -0
- package/dist/src/registry/file-rack-registry.spec.d.ts.map +1 -0
- package/dist/src/registry/file-rack-registry.spec.js +50 -0
- package/dist/src/registry/file-rack-registry.spec.js.map +1 -0
- package/dist/src/registry/rack-registry.d.ts +64 -0
- package/dist/src/registry/rack-registry.d.ts.map +1 -0
- package/dist/src/registry/rack-registry.js +65 -0
- package/dist/src/registry/rack-registry.js.map +1 -0
- package/dist/src/registry/rack-registry.spec.d.ts +6 -0
- package/dist/src/registry/rack-registry.spec.d.ts.map +1 -0
- package/dist/src/registry/rack-registry.spec.js +8 -0
- package/dist/src/registry/rack-registry.spec.js.map +1 -0
- package/dist/src/routing/eligibility.d.ts +38 -0
- package/dist/src/routing/eligibility.d.ts.map +1 -0
- package/dist/src/routing/eligibility.js +78 -0
- package/dist/src/routing/eligibility.js.map +1 -0
- package/dist/src/routing/host-coupling.d.ts +26 -0
- package/dist/src/routing/host-coupling.d.ts.map +1 -0
- package/dist/src/routing/host-coupling.js +62 -0
- package/dist/src/routing/host-coupling.js.map +1 -0
- package/dist/src/routing/policy.d.ts +188 -0
- package/dist/src/routing/policy.d.ts.map +1 -0
- package/dist/src/routing/policy.js +212 -0
- package/dist/src/routing/policy.js.map +1 -0
- package/dist/src/routing/routing.spec.d.ts +6 -0
- package/dist/src/routing/routing.spec.d.ts.map +1 -0
- package/dist/src/routing/routing.spec.js +100 -0
- package/dist/src/routing/routing.spec.js.map +1 -0
- package/dist/src/routing/tiers.d.ts +22 -0
- package/dist/src/routing/tiers.d.ts.map +1 -0
- package/dist/src/routing/tiers.js +26 -0
- package/dist/src/routing/tiers.js.map +1 -0
- package/dist/src/runner/api-server.d.ts +45 -0
- package/dist/src/runner/api-server.d.ts.map +1 -0
- package/dist/src/runner/api-server.js +21 -0
- package/dist/src/runner/api-server.js.map +1 -0
- package/dist/src/runner/capacity.d.ts +13 -0
- package/dist/src/runner/capacity.d.ts.map +1 -0
- package/dist/src/runner/capacity.js +18 -0
- package/dist/src/runner/capacity.js.map +1 -0
- package/dist/src/runner/rack-body.d.ts +43 -0
- package/dist/src/runner/rack-body.d.ts.map +1 -0
- package/dist/src/runner/rack-body.js +208 -0
- package/dist/src/runner/rack-body.js.map +1 -0
- package/dist/src/runner/rack-runner.d.ts +62 -0
- package/dist/src/runner/rack-runner.d.ts.map +1 -0
- package/dist/src/runner/rack-runner.js +75 -0
- package/dist/src/runner/rack-runner.js.map +1 -0
- package/dist/src/runner/rack-runner.spec.d.ts +6 -0
- package/dist/src/runner/rack-runner.spec.d.ts.map +1 -0
- package/dist/src/runner/rack-runner.spec.js +302 -0
- package/dist/src/runner/rack-runner.spec.js.map +1 -0
- package/dist/src/runner/split.spec.d.ts +6 -0
- package/dist/src/runner/split.spec.d.ts.map +1 -0
- package/dist/src/runner/split.spec.js +188 -0
- package/dist/src/runner/split.spec.js.map +1 -0
- package/dist/src/runner-event.d.ts +261 -0
- package/dist/src/runner-event.d.ts.map +1 -0
- package/dist/src/runner-event.js +332 -0
- package/dist/src/runner-event.js.map +1 -0
- package/dist/src/server/beast2.d.ts +19 -0
- package/dist/src/server/beast2.d.ts.map +1 -0
- package/dist/src/server/beast2.js +18 -0
- package/dist/src/server/beast2.js.map +1 -0
- package/dist/src/server/body-limit.d.ts +16 -0
- package/dist/src/server/body-limit.d.ts.map +1 -0
- package/dist/src/server/body-limit.js +53 -0
- package/dist/src/server/body-limit.js.map +1 -0
- package/dist/src/server/body-limit.spec.d.ts +2 -0
- package/dist/src/server/body-limit.spec.d.ts.map +1 -0
- package/dist/src/server/body-limit.spec.js +32 -0
- package/dist/src/server/body-limit.spec.js.map +1 -0
- package/dist/src/server/bounded.d.ts +16 -0
- package/dist/src/server/bounded.d.ts.map +1 -0
- package/dist/src/server/bounded.js +39 -0
- package/dist/src/server/bounded.js.map +1 -0
- package/dist/src/server/dispatch.d.ts +137 -0
- package/dist/src/server/dispatch.d.ts.map +1 -0
- package/dist/src/server/dispatch.js +267 -0
- package/dist/src/server/dispatch.js.map +1 -0
- package/dist/src/server/env-publication.d.ts +45 -0
- package/dist/src/server/env-publication.d.ts.map +1 -0
- package/dist/src/server/env-publication.js +10 -0
- package/dist/src/server/env-publication.js.map +1 -0
- package/dist/src/server/index.d.ts +16 -0
- package/dist/src/server/index.d.ts.map +1 -0
- package/dist/src/server/index.js +17 -0
- package/dist/src/server/index.js.map +1 -0
- package/dist/src/server/protocol.spec.d.ts +6 -0
- package/dist/src/server/protocol.spec.d.ts.map +1 -0
- package/dist/src/server/protocol.spec.js +78 -0
- package/dist/src/server/protocol.spec.js.map +1 -0
- package/dist/src/server/rack-routes.d.ts +175 -0
- package/dist/src/server/rack-routes.d.ts.map +1 -0
- package/dist/src/server/rack-routes.js +755 -0
- package/dist/src/server/rack-routes.js.map +1 -0
- package/dist/src/server/rack-routes.spec.d.ts +6 -0
- package/dist/src/server/rack-routes.spec.d.ts.map +1 -0
- package/dist/src/server/rack-routes.spec.js +477 -0
- package/dist/src/server/rack-routes.spec.js.map +1 -0
- package/dist/src/server/storage-bridge.d.ts +140 -0
- package/dist/src/server/storage-bridge.d.ts.map +1 -0
- package/dist/src/server/storage-bridge.js +6 -0
- package/dist/src/server/storage-bridge.js.map +1 -0
- package/dist/src/state-file.d.ts +10 -0
- package/dist/src/state-file.d.ts.map +1 -0
- package/dist/src/state-file.js +38 -0
- package/dist/src/state-file.js.map +1 -0
- package/dist/src/testing/in-memory.d.ts +116 -0
- package/dist/src/testing/in-memory.d.ts.map +1 -0
- package/dist/src/testing/in-memory.js +193 -0
- package/dist/src/testing/in-memory.js.map +1 -0
- package/dist/src/testing/index.d.ts +14 -0
- package/dist/src/testing/index.d.ts.map +1 -0
- package/dist/src/testing/index.js +14 -0
- package/dist/src/testing/index.js.map +1 -0
- package/dist/src/testing/lease-store-contract.d.ts +14 -0
- package/dist/src/testing/lease-store-contract.d.ts.map +1 -0
- package/dist/src/testing/lease-store-contract.js +78 -0
- package/dist/src/testing/lease-store-contract.js.map +1 -0
- package/dist/src/testing/protocol-suite.d.ts +38 -0
- package/dist/src/testing/protocol-suite.d.ts.map +1 -0
- package/dist/src/testing/protocol-suite.js +207 -0
- package/dist/src/testing/protocol-suite.js.map +1 -0
- package/dist/src/testing/rack-registry-contract.d.ts +15 -0
- package/dist/src/testing/rack-registry-contract.d.ts.map +1 -0
- package/dist/src/testing/rack-registry-contract.js +106 -0
- package/dist/src/testing/rack-registry-contract.js.map +1 -0
- package/dist/src/testing/test-rack-agent.d.ts +121 -0
- package/dist/src/testing/test-rack-agent.d.ts.map +1 -0
- package/dist/src/testing/test-rack-agent.js +316 -0
- package/dist/src/testing/test-rack-agent.js.map +1 -0
- package/dist/src/tls/tls.d.ts +67 -0
- package/dist/src/tls/tls.d.ts.map +1 -0
- package/dist/src/tls/tls.js +200 -0
- package/dist/src/tls/tls.js.map +1 -0
- package/dist/src/tls/tls.spec.d.ts +6 -0
- package/dist/src/tls/tls.spec.d.ts.map +1 -0
- package/dist/src/tls/tls.spec.js +101 -0
- package/dist/src/tls/tls.spec.js.map +1 -0
- package/dist/src/version.d.ts +9 -0
- package/dist/src/version.d.ts.map +1 -0
- package/dist/src/version.js +10 -0
- package/dist/src/version.js.map +1 -0
- package/package.json +67 -7
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* A lease's closure (#214): every object its guest's execution reads, which
|
|
7
|
+
* the cloud computes when it grants the lease. The agent fetches exactly
|
|
8
|
+
* these into its cache and links them into the guest's scratch, and
|
|
9
|
+
* `/rack/storage` admits exactly these: a rack reaches no other object of the
|
|
10
|
+
* repository.
|
|
11
|
+
*
|
|
12
|
+
* What e3-core's execution reads over a staged store:
|
|
13
|
+
* - a task or a unit: its task object; its program, or its command IR; what
|
|
14
|
+
* its output kind folds with (a dict's merge, a fold's zero and combine);
|
|
15
|
+
* its environment's spec and the files that names; and each object it
|
|
16
|
+
* stages (a task's inputs, a piece's inputs, a merge's range and parts);
|
|
17
|
+
* - a function call: its program, its environment, and each stored dataset
|
|
18
|
+
* argument;
|
|
19
|
+
* - a staged dataset: the object, and, for a record state, its primary; for a
|
|
20
|
+
* manifest, its header and its segments.
|
|
21
|
+
*
|
|
22
|
+
* A closure larger than {@link INLINE_CLOSURE_MAX} hashes is recorded as an
|
|
23
|
+
* object in the repository's store, whose hash the lease carries.
|
|
24
|
+
*/
|
|
25
|
+
import { ArrayType, StringType, decodeBeast2For, encodeBeast2For } from '@elaraai/east';
|
|
26
|
+
import { openDatasetObject } from '@elaraai/e3-core';
|
|
27
|
+
import { EnvironmentSpecType, environmentSpecObjectHashes } from '@elaraai/e3-types';
|
|
28
|
+
/** The most hashes a lease's event carries inline: past it, the closure is an object. */
|
|
29
|
+
export const INLINE_CLOSURE_MAX = 512;
|
|
30
|
+
/** A closure object: the hashes, as a beast2 `Array<String>`. */
|
|
31
|
+
const ClosureListType = ArrayType(StringType);
|
|
32
|
+
const encodeList = encodeBeast2For(ClosureListType);
|
|
33
|
+
const decodeList = decodeBeast2For(ClosureListType);
|
|
34
|
+
const decodeEnvironmentSpec = decodeBeast2For(EnvironmentSpecType);
|
|
35
|
+
/**
|
|
36
|
+
* A closure object's bytes.
|
|
37
|
+
*
|
|
38
|
+
* @param hashes - The closure's hashes
|
|
39
|
+
* @returns The object's bytes
|
|
40
|
+
*/
|
|
41
|
+
export function encodeClosure(hashes) {
|
|
42
|
+
return encodeList([...hashes]);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The hashes a closure object lists.
|
|
46
|
+
*
|
|
47
|
+
* @param bytes - The object's bytes
|
|
48
|
+
* @returns The hashes
|
|
49
|
+
* @throws {Error} When the bytes are not a closure object
|
|
50
|
+
*/
|
|
51
|
+
export function decodeClosure(bytes) {
|
|
52
|
+
return decodeList(bytes);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* What a unit's execution stages: a piece's inputs, or a merge's key range
|
|
56
|
+
* and its parts (e3-core's `taskExecuteBody`).
|
|
57
|
+
*
|
|
58
|
+
* @param inputs - The unit's inputs, as its record names them
|
|
59
|
+
* @param merge - What a merge unit merges, or null for a piece
|
|
60
|
+
* @returns The staged objects' hashes
|
|
61
|
+
*/
|
|
62
|
+
export function stagedObjects(inputs, merge) {
|
|
63
|
+
return merge === null ? [...inputs] : [...(merge.range === null ? [] : [merge.range]), ...merge.parts];
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The closure of a task's or a unit's execution.
|
|
67
|
+
*
|
|
68
|
+
* @param storage - The repository's storage
|
|
69
|
+
* @param repo - Repository identifier
|
|
70
|
+
* @param taskHash - The task object's hash
|
|
71
|
+
* @param task - The task object
|
|
72
|
+
* @param staged - What the execution stages ({@link stagedObjects})
|
|
73
|
+
* @param parts - Collects the closure's collection parts (each staged
|
|
74
|
+
* manifest's entries): what a unit fetches only as it reads them
|
|
75
|
+
* @returns The objects it reads, sorted
|
|
76
|
+
* @throws {Error} When an object it names cannot be read
|
|
77
|
+
*/
|
|
78
|
+
export async function taskClosure(storage, repo, taskHash, task, staged, parts) {
|
|
79
|
+
const into = new Set([taskHash]);
|
|
80
|
+
into.add(task.body.type === 'east' ? task.body.value.program : task.body.value.commandIr);
|
|
81
|
+
const kind = task.output.kind;
|
|
82
|
+
if (kind.type === 'dict' && kind.value.merge.type === 'some')
|
|
83
|
+
into.add(kind.value.merge.value);
|
|
84
|
+
if (kind.type === 'fold') {
|
|
85
|
+
into.add(kind.value.zero);
|
|
86
|
+
into.add(kind.value.combine);
|
|
87
|
+
}
|
|
88
|
+
if (task.environment.type === 'some')
|
|
89
|
+
await addEnvironment(storage, repo, task.environment.value, into);
|
|
90
|
+
for (const hash of new Set(staged))
|
|
91
|
+
await addValue(storage, repo, hash, into, parts);
|
|
92
|
+
return [...into].sort();
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* The closure of a function call's execution.
|
|
96
|
+
*
|
|
97
|
+
* @param storage - The repository's storage
|
|
98
|
+
* @param repo - Repository identifier
|
|
99
|
+
* @param program - The program's object hash
|
|
100
|
+
* @param args - The call's arguments: a stored dataset's objects are staged
|
|
101
|
+
* @param environment - The environment the call declares
|
|
102
|
+
* @returns The objects it reads, sorted
|
|
103
|
+
* @throws {Error} When an object it names cannot be read
|
|
104
|
+
*/
|
|
105
|
+
export async function detachedClosure(storage, repo, program, args, environment) {
|
|
106
|
+
return [...new Set([program, ...await callClosure(storage, repo, args, environment)])].sort();
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* The closure of a function call whose program travels with it, not as an
|
|
110
|
+
* object: its environment, and each stored dataset argument (#225, a
|
|
111
|
+
* sandbox's call).
|
|
112
|
+
*
|
|
113
|
+
* @param storage - The repository's storage
|
|
114
|
+
* @param repo - Repository identifier
|
|
115
|
+
* @param args - The call's arguments: a stored dataset's objects are staged
|
|
116
|
+
* @param environment - The environment the call declares
|
|
117
|
+
* @param parts - Collects the closure's collection parts, as {@link taskClosure}'s
|
|
118
|
+
* @returns The objects it reads, sorted
|
|
119
|
+
* @throws {Error} When an object it names cannot be read
|
|
120
|
+
*/
|
|
121
|
+
export async function callClosure(storage, repo, args, environment, parts) {
|
|
122
|
+
const into = new Set();
|
|
123
|
+
if (environment !== undefined)
|
|
124
|
+
await addEnvironment(storage, repo, environment, into);
|
|
125
|
+
for (const arg of args) {
|
|
126
|
+
if (!(arg instanceof Uint8Array))
|
|
127
|
+
await addValue(storage, repo, arg.dataset, into, parts);
|
|
128
|
+
}
|
|
129
|
+
return [...into].sort();
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Records a closure on a lease: its hashes inline, or, when there are more
|
|
133
|
+
* than {@link INLINE_CLOSURE_MAX}, an object in the repository's store that
|
|
134
|
+
* lists them.
|
|
135
|
+
*
|
|
136
|
+
* @param storage - The repository's storage
|
|
137
|
+
* @param repo - Repository identifier
|
|
138
|
+
* @param hashes - The closure
|
|
139
|
+
* @returns What the lease's event carries
|
|
140
|
+
*/
|
|
141
|
+
export async function recordClosure(storage, repo, hashes) {
|
|
142
|
+
if (hashes.length <= INLINE_CLOSURE_MAX)
|
|
143
|
+
return { hashes: [...hashes] };
|
|
144
|
+
const object = await storage.objects.write(repo, encodeClosure(hashes));
|
|
145
|
+
return { object, count: hashes.length };
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Every object a lease may read, as its closure names them: the hashes, and,
|
|
149
|
+
* for a closure recorded as an object, that object too.
|
|
150
|
+
*
|
|
151
|
+
* @param closure - The lease's closure
|
|
152
|
+
* @param read - Reads the closure object, for one recorded as an object
|
|
153
|
+
* @returns The hashes
|
|
154
|
+
* @throws {Error} When the closure object cannot be read, or lists another
|
|
155
|
+
* number of hashes than the lease says
|
|
156
|
+
*/
|
|
157
|
+
export async function closureHashes(closure, read) {
|
|
158
|
+
if ('hashes' in closure)
|
|
159
|
+
return [...closure.hashes];
|
|
160
|
+
const hashes = decodeClosure(await read(closure.object));
|
|
161
|
+
if (hashes.length !== closure.count) {
|
|
162
|
+
throw new Error(`closure object ${closure.object} lists ${hashes.length} hashes, and its lease ${closure.count}`);
|
|
163
|
+
}
|
|
164
|
+
return [closure.object, ...hashes];
|
|
165
|
+
}
|
|
166
|
+
/** A staged dataset's objects: the object, a record state's primary, a manifest's header and segments (its parts). */
|
|
167
|
+
async function addValue(storage, repo, hash, into, parts) {
|
|
168
|
+
if (into.has(hash))
|
|
169
|
+
return;
|
|
170
|
+
into.add(hash);
|
|
171
|
+
const opened = await openDatasetObject(storage, repo, hash);
|
|
172
|
+
into.add(opened.hash);
|
|
173
|
+
if (opened.manifest === null)
|
|
174
|
+
return;
|
|
175
|
+
into.add(opened.manifest.header);
|
|
176
|
+
for (const entry of opened.manifest.entries) {
|
|
177
|
+
if (opened.manifest.level === 0n) {
|
|
178
|
+
into.add(entry.hash);
|
|
179
|
+
parts?.add(entry.hash);
|
|
180
|
+
}
|
|
181
|
+
else
|
|
182
|
+
await addValue(storage, repo, entry.hash, into, parts);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/** An environment's spec and the files it names. */
|
|
186
|
+
async function addEnvironment(storage, repo, hash, into) {
|
|
187
|
+
into.add(hash);
|
|
188
|
+
const spec = decodeEnvironmentSpec(await storage.objects.read(repo, hash));
|
|
189
|
+
for (const file of environmentSpecObjectHashes(spec))
|
|
190
|
+
into.add(file);
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=closure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"closure.js","sourceRoot":"","sources":["../../../src/lease/closure.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"closure.spec.d.ts","sourceRoot":"","sources":["../../../src/lease/closure.spec.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
import { afterEach, it } from 'node:test';
|
|
6
|
+
import assert from 'node:assert/strict';
|
|
7
|
+
import { mkdtemp, rm } from 'node:fs/promises';
|
|
8
|
+
import { tmpdir } from 'node:os';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { ArrayType, IntegerType, encodeCollectionManifest } from '@elaraai/east';
|
|
11
|
+
import { LocalStorage, datasetWrite, openDatasetObject, repoInit } from '@elaraai/e3-core';
|
|
12
|
+
import { callClosure, closureHashes, recordClosure } from './closure.js';
|
|
13
|
+
const homes = [];
|
|
14
|
+
afterEach(async () => { for (const home of homes.splice(0))
|
|
15
|
+
await rm(home, { recursive: true, force: true }); });
|
|
16
|
+
it('includes every descendant of a nested collection manifest and records large closures', async () => {
|
|
17
|
+
const repo = await mkdtemp(join(tmpdir(), 'e3-closure-'));
|
|
18
|
+
homes.push(repo);
|
|
19
|
+
assert(repoInit(repo).success);
|
|
20
|
+
const storage = new LocalStorage();
|
|
21
|
+
const leaf = await datasetWrite(storage, repo, [1n, 2n], ArrayType(IntegerType));
|
|
22
|
+
const opened = await openDatasetObject(storage, repo, leaf);
|
|
23
|
+
assert(opened.manifest);
|
|
24
|
+
const root = await storage.objects.write(repo, encodeCollectionManifest({ ...opened.manifest, level: 1n,
|
|
25
|
+
entries: [{ hash: leaf, count: 2n, bytes: BigInt((await storage.objects.stat(repo, leaf)).size), fence: new Uint8Array() }] }));
|
|
26
|
+
const parts = new Set();
|
|
27
|
+
const hashes = await callClosure(storage, repo, [{ dataset: root }], undefined, parts);
|
|
28
|
+
assert.deepEqual(hashes, [...new Set([root, leaf, opened.manifest.header, ...opened.manifest.entries.map((entry) => entry.hash)])].sort());
|
|
29
|
+
assert.deepEqual([...parts], opened.manifest.entries.map((entry) => entry.hash));
|
|
30
|
+
const large = Array.from({ length: 513 }, (_, n) => n.toString(16).padStart(64, '0'));
|
|
31
|
+
const closure = await recordClosure(storage, repo, large);
|
|
32
|
+
assert('object' in closure);
|
|
33
|
+
assert.deepEqual(await closureHashes(closure, (hash) => storage.objects.read(repo, hash)), [closure.object, ...large]);
|
|
34
|
+
});
|
|
35
|
+
//# sourceMappingURL=closure.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"closure.spec.js","sourceRoot":"","sources":["../../../src/lease/closure.spec.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC3F,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAEzE,MAAM,KAAK,GAAa,EAAE,CAAC;AAC3B,SAAS,CAAC,KAAK,IAAI,EAAE,GAAG,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IAAE,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAEjH,EAAE,CAAC,sFAAsF,EAAE,KAAK,IAAI,EAAE;IACpG,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,aAAa,CAAC,CAAC,CAAC;IAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5E,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC;IAC/B,MAAM,OAAO,GAAG,IAAI,YAAY,EAAE,CAAC;IACnC,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC;IACjF,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACrF,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,wBAAwB,CAAC,EAAE,GAAG,MAAM,CAAC,QAAQ,EAAE,KAAK,EAAE,EAAE;QACrG,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,UAAU,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAClI,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;IACvF,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC3I,MAAM,CAAC,SAAS,CAAC,CAAC,GAAG,KAAK,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IACjF,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;IACtF,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IAAC,MAAM,CAAC,QAAQ,IAAI,OAAO,CAAC,CAAC;IACvF,MAAM,CAAC,SAAS,CAAC,MAAM,aAAa,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC;AACzH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Serializes a lease transition together with its repository side effects.
|
|
7
|
+
* A host shares one coordinator between its routes and dispatcher. A
|
|
8
|
+
* distributed host supplies the equivalent fencing at its storage boundary.
|
|
9
|
+
*/
|
|
10
|
+
export interface LeaseCoordinator {
|
|
11
|
+
/** Runs a transition exclusively for one repository and lease. */
|
|
12
|
+
run<T>(repo: string, leaseId: string, operation: () => Promise<T>): Promise<T>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Serializes transitions in a single hub without blocking unrelated leases.
|
|
16
|
+
* Operations must not recursively acquire the same lease.
|
|
17
|
+
* @example
|
|
18
|
+
* const coordinator = new InMemoryLeaseCoordinator();
|
|
19
|
+
* await coordinator.run(repo, leaseId, () => completeAttempt());
|
|
20
|
+
*/
|
|
21
|
+
export declare class InMemoryLeaseCoordinator implements LeaseCoordinator {
|
|
22
|
+
private readonly tails;
|
|
23
|
+
/**
|
|
24
|
+
* Runs after prior transitions, even if a prior transition rejected.
|
|
25
|
+
* @param repo - Repository alias
|
|
26
|
+
* @param leaseId - Lease identity
|
|
27
|
+
* @param operation - Transition and its side effects
|
|
28
|
+
* @returns The operation's result
|
|
29
|
+
*/
|
|
30
|
+
run<T>(repo: string, leaseId: string, operation: () => Promise<T>): Promise<T>;
|
|
31
|
+
}
|
|
32
|
+
/** Runs unfenced operations for hosts whose backend supplies fencing. */
|
|
33
|
+
export declare const backendLeaseCoordinator: LeaseCoordinator;
|
|
34
|
+
//# sourceMappingURL=coordinator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coordinator.d.ts","sourceRoot":"","sources":["../../../src/lease/coordinator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,kEAAkE;IAClE,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAChF;AAED;;;;;;GAMG;AACH,qBAAa,wBAAyB,YAAW,gBAAgB;IAC/D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAoC;IAE1D;;;;;;OAMG;IACG,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;CAcrF;AAED,yEAAyE;AACzE,eAAO,MAAM,uBAAuB,EAAE,gBAErC,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Serializes transitions in a single hub without blocking unrelated leases.
|
|
7
|
+
* Operations must not recursively acquire the same lease.
|
|
8
|
+
* @example
|
|
9
|
+
* const coordinator = new InMemoryLeaseCoordinator();
|
|
10
|
+
* await coordinator.run(repo, leaseId, () => completeAttempt());
|
|
11
|
+
*/
|
|
12
|
+
export class InMemoryLeaseCoordinator {
|
|
13
|
+
tails = new Map();
|
|
14
|
+
/**
|
|
15
|
+
* Runs after prior transitions, even if a prior transition rejected.
|
|
16
|
+
* @param repo - Repository alias
|
|
17
|
+
* @param leaseId - Lease identity
|
|
18
|
+
* @param operation - Transition and its side effects
|
|
19
|
+
* @returns The operation's result
|
|
20
|
+
*/
|
|
21
|
+
async run(repo, leaseId, operation) {
|
|
22
|
+
const key = JSON.stringify([repo, leaseId]);
|
|
23
|
+
const before = this.tails.get(key) ?? Promise.resolve();
|
|
24
|
+
let release;
|
|
25
|
+
const after = new Promise((resolve) => { release = resolve; });
|
|
26
|
+
this.tails.set(key, after);
|
|
27
|
+
await before;
|
|
28
|
+
try {
|
|
29
|
+
return await operation();
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
release();
|
|
33
|
+
if (this.tails.get(key) === after)
|
|
34
|
+
this.tails.delete(key);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** Runs unfenced operations for hosts whose backend supplies fencing. */
|
|
39
|
+
export const backendLeaseCoordinator = {
|
|
40
|
+
run: (_repo, _leaseId, operation) => operation(),
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=coordinator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coordinator.js","sourceRoot":"","sources":["../../../src/lease/coordinator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAYH;;;;;;GAMG;AACH,MAAM,OAAO,wBAAwB;IAClB,KAAK,GAAG,IAAI,GAAG,EAAyB,CAAC;IAE1D;;;;;;OAMG;IACH,KAAK,CAAC,GAAG,CAAI,IAAY,EAAE,OAAe,EAAE,SAA2B;QACrE,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACxD,IAAI,OAAoB,CAAC;QACzB,MAAM,KAAK,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,GAAG,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QACrE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC3B,MAAM,MAAM,CAAC;QACb,IAAI,CAAC;YACH,OAAO,MAAM,SAAS,EAAE,CAAC;QAC3B,CAAC;gBAAS,CAAC;YACT,OAAO,EAAE,CAAC;YACV,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,KAAK;gBAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;CACF;AAED,yEAAyE;AACzE,MAAM,CAAC,MAAM,uBAAuB,GAAqB;IACvD,GAAG,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,CAAC,SAAS,EAAE;CACjD,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
import type { RackLeaseAttempt, RackLeaseResult } from '../protocol/task-envelope.js';
|
|
6
|
+
import { type CompleteDisposition, type RackLeaseRecord, type RackLeaseStore } from './lease-store.js';
|
|
7
|
+
/**
|
|
8
|
+
* Keeps leases in memory with the cloud store's conditional transitions.
|
|
9
|
+
* Each mutation completes synchronously before resolving its promise, so
|
|
10
|
+
* concurrent claims have one winner. Returned records are independent copies.
|
|
11
|
+
* @example
|
|
12
|
+
* const leases = new InMemoryRackLeaseStore();
|
|
13
|
+
* await leases.put(pending);
|
|
14
|
+
*/
|
|
15
|
+
export declare class InMemoryRackLeaseStore implements RackLeaseStore {
|
|
16
|
+
private readonly now;
|
|
17
|
+
private readonly records;
|
|
18
|
+
/** @param now - The clock for visibility and activity timestamps */
|
|
19
|
+
constructor(now?: () => number);
|
|
20
|
+
private key;
|
|
21
|
+
/** Forgets a terminal lease after its subscribers and retry window have ended. */
|
|
22
|
+
forget(repo: string, id: string): void;
|
|
23
|
+
put(record: RackLeaseRecord): Promise<void>;
|
|
24
|
+
get(repo: string, id: string): Promise<RackLeaseRecord | null>;
|
|
25
|
+
/**
|
|
26
|
+
* Reads a lease without copying it: for a count or a status check, never
|
|
27
|
+
* for a change, and not kept past the next transition. A copy per read is
|
|
28
|
+
* what {@link get} is for.
|
|
29
|
+
* @param repo - The lease's repository
|
|
30
|
+
* @param id - The lease
|
|
31
|
+
* @returns The store's own record, or null
|
|
32
|
+
* @example
|
|
33
|
+
* if (leases.peek(repo, id)?.status === 'claimed') busy++;
|
|
34
|
+
*/
|
|
35
|
+
peek(repo: string, id: string): Readonly<RackLeaseRecord> | null;
|
|
36
|
+
/**
|
|
37
|
+
* The leases an agent with these tiers could claim now, oldest first,
|
|
38
|
+
* without copying them: the same caution as {@link peek}.
|
|
39
|
+
* @param tiers - The tiers the agent runs
|
|
40
|
+
* @param now - The time, in ms since the epoch
|
|
41
|
+
* @returns The store's own records
|
|
42
|
+
* @example
|
|
43
|
+
* const queued = leases.peekClaimable(['node'], Date.now()).length;
|
|
44
|
+
*/
|
|
45
|
+
peekClaimable(tiers: readonly string[], now: number): ReadonlyArray<Readonly<RackLeaseRecord>>;
|
|
46
|
+
findByTask(repo: string, taskHash: string, inputsHash: string): Promise<RackLeaseRecord | null>;
|
|
47
|
+
listClaimable(tiers: string[], now: number, limit: number): Promise<RackLeaseRecord[]>;
|
|
48
|
+
claim(repo: string, id: string, rackId: string, deadline: number, attempt?: RackLeaseAttempt): Promise<RackLeaseRecord | null>;
|
|
49
|
+
recordTargets(repo: string, id: string, rackId: string, hashes: readonly string[]): Promise<boolean>;
|
|
50
|
+
extend(repo: string, id: string, rackId: string, deadline: number): Promise<boolean>;
|
|
51
|
+
complete(repo: string, id: string, rackId: string, result: RackLeaseResult): Promise<CompleteDisposition>;
|
|
52
|
+
listRecentByRack(rackId: string, limit: number): Promise<RackLeaseRecord[]>;
|
|
53
|
+
supersede(repo: string, id: string): Promise<RackLeaseRecord | null>;
|
|
54
|
+
cancel(repo: string, id: string): Promise<RackLeaseRecord | null>;
|
|
55
|
+
private terminal;
|
|
56
|
+
private held;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=in-memory-lease-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"in-memory-lease-store.d.ts","sourceRoot":"","sources":["../../../src/lease/in-memory-lease-store.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACtF,OAAO,EAA8B,KAAK,mBAAmB,EAAE,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEnI;;;;;;;GAOG;AACH,qBAAa,sBAAuB,YAAW,cAAc;IAI/C,OAAO,CAAC,QAAQ,CAAC,GAAG;IAHhC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsC;IAE9D,oEAAoE;gBACvC,GAAG,GAAE,MAAM,MAAiB;IAEzD,OAAO,CAAC,GAAG;IAEX,kFAAkF;IAClF,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAMtC,GAAG,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAK3C,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAI9D;;;;;;;;;OASG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,QAAQ,CAAC,eAAe,CAAC,GAAG,IAAI;IAIhE;;;;;;;;OAQG;IACH,aAAa,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,aAAa,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;IAK9F,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAQ/F,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAItF,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAW9H,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAOpG,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAOpF,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAUzG,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAK3E,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAIpE,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAIjE,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,IAAI;CAIb"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
import { isClaimable, leaseIdPrefix } from './lease-store.js';
|
|
6
|
+
/**
|
|
7
|
+
* Keeps leases in memory with the cloud store's conditional transitions.
|
|
8
|
+
* Each mutation completes synchronously before resolving its promise, so
|
|
9
|
+
* concurrent claims have one winner. Returned records are independent copies.
|
|
10
|
+
* @example
|
|
11
|
+
* const leases = new InMemoryRackLeaseStore();
|
|
12
|
+
* await leases.put(pending);
|
|
13
|
+
*/
|
|
14
|
+
export class InMemoryRackLeaseStore {
|
|
15
|
+
now;
|
|
16
|
+
records = new Map();
|
|
17
|
+
/** @param now - The clock for visibility and activity timestamps */
|
|
18
|
+
constructor(now = Date.now) {
|
|
19
|
+
this.now = now;
|
|
20
|
+
}
|
|
21
|
+
key(repo, id) { return JSON.stringify([repo, id]); }
|
|
22
|
+
/** Forgets a terminal lease after its subscribers and retry window have ended. */
|
|
23
|
+
forget(repo, id) {
|
|
24
|
+
const key = this.key(repo, id);
|
|
25
|
+
const record = this.records.get(key);
|
|
26
|
+
if (record !== undefined && record.status !== 'pending' && record.status !== 'claimed')
|
|
27
|
+
this.records.delete(key);
|
|
28
|
+
}
|
|
29
|
+
put(record) {
|
|
30
|
+
this.records.set(this.key(record.repo, record.leaseId), structuredClone(record));
|
|
31
|
+
return Promise.resolve();
|
|
32
|
+
}
|
|
33
|
+
get(repo, id) {
|
|
34
|
+
return Promise.resolve(structuredClone(this.records.get(this.key(repo, id)) ?? null));
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Reads a lease without copying it: for a count or a status check, never
|
|
38
|
+
* for a change, and not kept past the next transition. A copy per read is
|
|
39
|
+
* what {@link get} is for.
|
|
40
|
+
* @param repo - The lease's repository
|
|
41
|
+
* @param id - The lease
|
|
42
|
+
* @returns The store's own record, or null
|
|
43
|
+
* @example
|
|
44
|
+
* if (leases.peek(repo, id)?.status === 'claimed') busy++;
|
|
45
|
+
*/
|
|
46
|
+
peek(repo, id) {
|
|
47
|
+
return this.records.get(this.key(repo, id)) ?? null;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The leases an agent with these tiers could claim now, oldest first,
|
|
51
|
+
* without copying them: the same caution as {@link peek}.
|
|
52
|
+
* @param tiers - The tiers the agent runs
|
|
53
|
+
* @param now - The time, in ms since the epoch
|
|
54
|
+
* @returns The store's own records
|
|
55
|
+
* @example
|
|
56
|
+
* const queued = leases.peekClaimable(['node'], Date.now()).length;
|
|
57
|
+
*/
|
|
58
|
+
peekClaimable(tiers, now) {
|
|
59
|
+
return [...this.records.values()].filter((r) => tiers.includes(r.tier) && isClaimable(r, now))
|
|
60
|
+
.sort((a, b) => a.createdAtMs - b.createdAtMs || a.leaseId.localeCompare(b.leaseId));
|
|
61
|
+
}
|
|
62
|
+
findByTask(repo, taskHash, inputsHash) {
|
|
63
|
+
const prefix = leaseIdPrefix(taskHash, inputsHash);
|
|
64
|
+
const records = [...this.records.values()].filter((r) => r.repo === repo && r.leaseId.startsWith(prefix)
|
|
65
|
+
&& r.status !== 'superseded' && r.status !== 'cancelled');
|
|
66
|
+
records.sort((a, b) => b.createdAtMs - a.createdAtMs || b.leaseId.localeCompare(a.leaseId));
|
|
67
|
+
return Promise.resolve(structuredClone(records[0] ?? null));
|
|
68
|
+
}
|
|
69
|
+
listClaimable(tiers, now, limit) {
|
|
70
|
+
return Promise.resolve(this.peekClaimable(tiers, now).slice(0, limit).map((r) => structuredClone(r)));
|
|
71
|
+
}
|
|
72
|
+
claim(repo, id, rackId, deadline, attempt) {
|
|
73
|
+
const record = this.records.get(this.key(repo, id));
|
|
74
|
+
if (record === undefined || !isClaimable(record, this.now()))
|
|
75
|
+
return Promise.resolve(null);
|
|
76
|
+
record.status = 'claimed';
|
|
77
|
+
record.claimedBy = rackId;
|
|
78
|
+
record.claimedAtMs = this.now();
|
|
79
|
+
record.visibilityDeadlineMs = deadline;
|
|
80
|
+
if (attempt !== undefined)
|
|
81
|
+
record.attempt = structuredClone(attempt);
|
|
82
|
+
return Promise.resolve(structuredClone(record));
|
|
83
|
+
}
|
|
84
|
+
recordTargets(repo, id, rackId, hashes) {
|
|
85
|
+
const record = this.held(repo, id, rackId);
|
|
86
|
+
if (record === null)
|
|
87
|
+
return Promise.resolve(false);
|
|
88
|
+
record.targets = [...new Set([...(record.targets ?? []), ...hashes])];
|
|
89
|
+
return Promise.resolve(true);
|
|
90
|
+
}
|
|
91
|
+
extend(repo, id, rackId, deadline) {
|
|
92
|
+
const record = this.held(repo, id, rackId);
|
|
93
|
+
if (record === null)
|
|
94
|
+
return Promise.resolve(false);
|
|
95
|
+
record.visibilityDeadlineMs = deadline;
|
|
96
|
+
return Promise.resolve(true);
|
|
97
|
+
}
|
|
98
|
+
complete(repo, id, rackId, result) {
|
|
99
|
+
const record = this.records.get(this.key(repo, id));
|
|
100
|
+
if (record?.status === 'completed')
|
|
101
|
+
return Promise.resolve('idempotent');
|
|
102
|
+
if (record === undefined || record.status !== 'claimed' || record.claimedBy !== rackId)
|
|
103
|
+
return Promise.resolve('discarded');
|
|
104
|
+
record.status = 'completed';
|
|
105
|
+
record.result = structuredClone(result);
|
|
106
|
+
record.completedAtMs = this.now();
|
|
107
|
+
return Promise.resolve('recorded');
|
|
108
|
+
}
|
|
109
|
+
listRecentByRack(rackId, limit) {
|
|
110
|
+
return Promise.resolve([...this.records.values()].filter((r) => r.claimedBy === rackId && r.claimedAtMs !== undefined)
|
|
111
|
+
.sort((a, b) => b.claimedAtMs - a.claimedAtMs).slice(0, limit).map((r) => structuredClone(r)));
|
|
112
|
+
}
|
|
113
|
+
supersede(repo, id) {
|
|
114
|
+
return this.terminal(repo, id, 'superseded');
|
|
115
|
+
}
|
|
116
|
+
cancel(repo, id) {
|
|
117
|
+
return this.terminal(repo, id, 'cancelled');
|
|
118
|
+
}
|
|
119
|
+
terminal(repo, id, status) {
|
|
120
|
+
const record = this.records.get(this.key(repo, id));
|
|
121
|
+
if (record === undefined)
|
|
122
|
+
return Promise.resolve(null);
|
|
123
|
+
if (record.status === 'pending' || record.status === 'claimed')
|
|
124
|
+
record.status = status;
|
|
125
|
+
return Promise.resolve(structuredClone(record));
|
|
126
|
+
}
|
|
127
|
+
held(repo, id, rackId) {
|
|
128
|
+
const record = this.records.get(this.key(repo, id));
|
|
129
|
+
return record?.status === 'claimed' && record.claimedBy === rackId ? record : null;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=in-memory-lease-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"in-memory-lease-store.js","sourceRoot":"","sources":["../../../src/lease/in-memory-lease-store.ts"],"names":[],"mappings":"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"}
|