@zlink-systems/framework 0.29.0 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/contracts/Configuration/Builders.d.ts +1 -2
- package/dist/contracts/Configuration/Configs.d.ts +0 -5
- package/dist/contracts/Configuration/RegistrationBuilders.js +6 -4
- package/dist/contracts/Configuration/RegistrationTypes.d.ts +1 -6
- package/dist/contracts/Configuration/RegistrationValidators.js +4 -4
- package/dist/contracts/Configuration/index.d.ts +1 -1
- package/dist/internal.d.ts +1 -0
- package/dist/internal.js +3 -1
- package/dist/runtime/actors/actor-handoff.d.ts +3 -2
- package/dist/runtime/actors/actor-handoff.js +9 -4
- package/dist/runtime/actors/actor-runtime-contracts.d.ts +1 -0
- package/dist/runtime/actors/index.d.ts +2 -0
- package/dist/runtime/actors/index.js +21 -6
- package/dist/runtime/application-jobs/application-ingress-record-owner.d.ts +3 -1
- package/dist/runtime/application-jobs/application-ingress-record-owner.js +6 -1
- package/dist/runtime/application-jobs/application-job-queue-scope.d.ts +3 -1
- package/dist/runtime/application-jobs/application-job-queue-scope.js +5 -0
- package/dist/runtime/application-jobs/contracts.d.ts +5 -1
- package/dist/runtime/backend/contracts/index.d.ts +10 -19
- package/dist/runtime/backend/mesh-completion-table.d.ts +6 -4
- package/dist/runtime/backend/mesh-completion-table.js +28 -18
- package/dist/runtime/backend/mesh-dispatch-pump.js +21 -25
- package/dist/runtime/backend/node/node-backend-adapter-factory.js +6 -1
- package/dist/runtime/backend/node/node-backend-adapter-support.d.ts +3 -3
- package/dist/runtime/backend/node/node-backend-adapter-support.js +24 -29
- package/dist/runtime/backend/node/node-mesh-backend-adapter.d.ts +1 -9
- package/dist/runtime/backend/node/node-mesh-backend-adapter.js +1 -1
- package/dist/runtime/backend/node/node-raw-binding-port.js +11 -6
- package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +10 -12
- package/dist/runtime/backend/node/node-raw-mesh-backend.js +64 -98
- package/dist/runtime/backend/node/node-socket-backend-adapter.js +10 -5
- package/dist/runtime/backend/raw-binding-port.d.ts +9 -2
- package/dist/runtime/channels/channel-receive-loops.js +3 -3
- package/dist/runtime/channels/channel-runtime-lifecycle.js +2 -1
- package/dist/runtime/channels/channel-socket-registry.d.ts +10 -3
- package/dist/runtime/channels/channel-socket-registry.js +59 -82
- package/dist/runtime/diagnostics/message-flow.d.ts +1 -0
- package/dist/runtime/diagnostics/message-flow.js +3 -3
- package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +15 -1
- package/dist/runtime/foundation/raw-service-mesh-runtime.js +193 -64
- package/dist/runtime/foundation/service-liveness-registry.d.ts +20 -8
- package/dist/runtime/foundation/service-liveness-registry.js +57 -44
- package/dist/runtime/foundation/service-mailbox.d.ts +3 -0
- package/dist/runtime/foundation/service-mailbox.js +2 -1
- package/dist/runtime/foundation/service-stateful-runtime.d.ts +7 -6
- package/dist/runtime/foundation/service-stateful-runtime.js +60 -41
- package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +5 -2
- package/dist/runtime/foundation/service-stateful-wire-codec.js +43 -61
- package/dist/runtime/foundation/service-topology-registry.d.ts +5 -3
- package/dist/runtime/foundation/service-topology-registry.js +9 -4
- package/dist/runtime/handlers/handler-instance-scope.js +1 -1
- package/dist/runtime/host/actor-packet-relay.js +7 -7
- package/dist/runtime/host/actor-placement-coordinator.d.ts +2 -1
- package/dist/runtime/host/actor-placement-coordinator.js +2 -1
- package/dist/runtime/host/actor-runtime-options-factory.d.ts +2 -1
- package/dist/runtime/host/actor-runtime-options-factory.js +2 -1
- package/dist/runtime/host/application-job-queue.d.ts +11 -4
- package/dist/runtime/host/application-job-queue.js +66 -10
- package/dist/runtime/host/entry-actor-runtime.js +1 -1
- package/dist/runtime/host/index.d.ts +1 -1
- package/dist/runtime/host/index.js +18 -13
- package/dist/runtime/host/instance-activation-authority.d.ts +2 -1
- package/dist/runtime/host/instance-activation-authority.js +89 -25
- package/dist/runtime/host/service-relocation-host-runtime.js +2 -2
- package/dist/runtime/host/spot-address-transport.d.ts +1 -0
- package/dist/runtime/host/spot-address-transport.js +25 -12
- package/dist/runtime/host/spot-runtime-options-factory.js +2 -2
- package/dist/runtime/host/user-spot-creation-coordinator.d.ts +1 -0
- package/dist/runtime/host/user-spot-creation-coordinator.js +1 -0
- package/dist/runtime/locations/domain-store-contract.d.ts +3 -2
- package/dist/runtime/locations/in-memory-authority-store.d.ts +5 -2
- package/dist/runtime/locations/in-memory-authority-store.js +107 -14
- package/dist/runtime/locations/in-memory-location-store.d.ts +3 -3
- package/dist/runtime/locations/in-memory-location-store.js +31 -13
- package/dist/runtime/locations/internal-location-contracts.d.ts +8 -0
- package/dist/runtime/locations/location-store-repository.d.ts +4 -2
- package/dist/runtime/locations/location-store-repository.js +209 -33
- package/dist/runtime/locations/resolvers.d.ts +2 -1
- package/dist/runtime/locations/resolvers.js +10 -1
- package/dist/runtime/messaging/submission-result.d.ts +1 -1
- package/dist/runtime/messaging/submission-result.js +2 -2
- package/dist/runtime/spots/formal-remote-actor-admission-registry.d.ts +2 -0
- package/dist/runtime/spots/index.d.ts +4 -3
- package/dist/runtime/spots/index.js +14 -14
- package/dist/runtime/spots/spot-activation.d.ts +2 -1
- package/dist/runtime/spots/spot-activation.js +4 -4
- package/dist/runtime/spots/spot-actor-admission-coordinator.d.ts +2 -1
- package/dist/runtime/spots/spot-actor-admission-coordinator.js +11 -10
- package/dist/runtime/spots/spot-actor-packet-dispatch.d.ts +4 -1
- package/dist/runtime/spots/spot-actor-packet-dispatch.js +7 -5
- package/dist/runtime/spots/spot-actor-packet-drain.js +2 -0
- package/dist/runtime/spots/spot-actor-packet-relay-dispatch.js +1 -0
- package/dist/runtime/spots/spot-entry-activation.d.ts +1 -0
- package/dist/runtime/spots/spot-entry-activation.js +6 -1
- package/dist/runtime/spots/spot-node-runtime-manager.d.ts +3 -1
- package/dist/runtime/spots/spot-node-runtime-manager.js +10 -11
- package/dist/runtime/spots/spot-routing-internal.d.ts +6 -0
- package/dist/runtime/spots/spot-runtime-ports.d.ts +2 -1
- package/dist/runtime/spots/spot-serial-executor.d.ts +1 -0
- package/dist/runtime/spots/spot-serial-executor.js +10 -1
- package/dist/runtime/streams/stream-session-runtime.js +1 -1
- package/package.json +3 -3
- package/src/contracts/Configuration/Builders.ts +1 -2
- package/src/contracts/Configuration/Configs.ts +0 -6
- package/src/contracts/Configuration/RegistrationBuilders.ts +8 -12
- package/src/contracts/Configuration/RegistrationTypes.ts +1 -6
- package/src/contracts/Configuration/RegistrationValidators.ts +9 -10
- package/src/contracts/Configuration/index.ts +1 -6
- package/src/internal.ts +1 -0
- package/src/runtime/actors/actor-handoff.ts +13 -4
- package/src/runtime/actors/actor-runtime-contracts.ts +4 -0
- package/src/runtime/actors/index.ts +77 -42
- package/src/runtime/application-jobs/application-ingress-record-owner.ts +12 -2
- package/src/runtime/application-jobs/application-job-queue-scope.ts +6 -1
- package/src/runtime/application-jobs/contracts.ts +14 -1
- package/src/runtime/backend/contracts/index.ts +10 -18
- package/src/runtime/backend/mesh-completion-table.ts +36 -19
- package/src/runtime/backend/mesh-dispatch-pump.ts +19 -22
- package/src/runtime/backend/node/node-backend-adapter-factory.ts +12 -5
- package/src/runtime/backend/node/node-backend-adapter-support.ts +31 -29
- package/src/runtime/backend/node/node-mesh-backend-adapter.ts +3 -10
- package/src/runtime/backend/node/node-raw-binding-port.ts +19 -10
- package/src/runtime/backend/node/node-raw-mesh-backend.ts +81 -111
- package/src/runtime/backend/node/node-socket-backend-adapter.ts +12 -8
- package/src/runtime/backend/raw-binding-port.ts +12 -2
- package/src/runtime/channels/channel-receive-loops.ts +3 -3
- package/src/runtime/channels/channel-runtime-lifecycle.ts +7 -1
- package/src/runtime/channels/channel-socket-registry.ts +84 -130
- package/src/runtime/diagnostics/message-flow.ts +1 -1
- package/src/runtime/foundation/raw-service-mesh-runtime.ts +268 -70
- package/src/runtime/foundation/service-liveness-registry.ts +68 -59
- package/src/runtime/foundation/service-mailbox.ts +7 -1
- package/src/runtime/foundation/service-stateful-runtime.ts +109 -77
- package/src/runtime/foundation/service-stateful-wire-codec.ts +55 -79
- package/src/runtime/foundation/service-topology-registry.ts +13 -7
- package/src/runtime/handlers/handler-instance-scope.ts +2 -1
- package/src/runtime/host/actor-packet-relay.ts +7 -0
- package/src/runtime/host/actor-placement-coordinator.ts +8 -2
- package/src/runtime/host/actor-runtime-options-factory.ts +7 -0
- package/src/runtime/host/application-job-queue.ts +77 -10
- package/src/runtime/host/entry-actor-runtime.ts +1 -0
- package/src/runtime/host/index.ts +30 -7
- package/src/runtime/host/instance-activation-authority.ts +132 -27
- package/src/runtime/host/service-relocation-host-runtime.ts +2 -0
- package/src/runtime/host/spot-address-transport.ts +45 -22
- package/src/runtime/host/spot-runtime-options-factory.ts +2 -0
- package/src/runtime/host/user-spot-creation-coordinator.ts +8 -0
- package/src/runtime/locations/domain-store-contract.ts +6 -2
- package/src/runtime/locations/in-memory-authority-store.ts +153 -12
- package/src/runtime/locations/in-memory-location-store.ts +39 -13
- package/src/runtime/locations/internal-location-contracts.ts +10 -0
- package/src/runtime/locations/location-store-repository.ts +295 -36
- package/src/runtime/locations/resolvers.ts +25 -2
- package/src/runtime/messaging/submission-result.ts +2 -2
- package/src/runtime/spots/formal-remote-actor-admission-registry.ts +2 -0
- package/src/runtime/spots/index.ts +16 -0
- package/src/runtime/spots/spot-activation.ts +5 -0
- package/src/runtime/spots/spot-actor-admission-coordinator.ts +13 -0
- package/src/runtime/spots/spot-actor-packet-dispatch.ts +10 -0
- package/src/runtime/spots/spot-actor-packet-drain.ts +2 -0
- package/src/runtime/spots/spot-actor-packet-relay-dispatch.ts +1 -0
- package/src/runtime/spots/spot-entry-activation.ts +7 -0
- package/src/runtime/spots/spot-node-runtime-manager.ts +14 -12
- package/src/runtime/spots/spot-routing-internal.ts +14 -0
- package/src/runtime/spots/spot-runtime-ports.ts +2 -0
- package/src/runtime/spots/spot-serial-executor.ts +10 -4
- package/src/runtime/streams/stream-session-runtime.ts +1 -1
|
@@ -7,6 +7,7 @@ import { UINT64_MAX } from '@zlink-systems/stream-wire';
|
|
|
7
7
|
import { ZLINK_MAX_ROUTING_ID_BYTES } from '../../contracts/Common/CoreTypes';
|
|
8
8
|
import { ZLINK_PROVIDER_MAX_PAGE_SIZE } from '../../contracts/Locations/Stores';
|
|
9
9
|
import { randomUUID } from 'node:crypto';
|
|
10
|
+
import { ZLinkFrameworkException, ZLinkFrameworkErrorKind } from '../../contracts';
|
|
10
11
|
import { SHA256_DIGEST_BYTES } from '../foundation/actor-join-recovery-codec';
|
|
11
12
|
import type {
|
|
12
13
|
ZLinkAggregateAbortResult,
|
|
@@ -31,6 +32,7 @@ import type {
|
|
|
31
32
|
ZLinkObjectCommitResult,
|
|
32
33
|
ZLinkObjectCreationCompleteRequest,
|
|
33
34
|
ZLinkObjectCreationCompleteResult,
|
|
35
|
+
ZLinkEndedOwnerReleaseIntent,
|
|
34
36
|
ZLinkObjectReserveRequest,
|
|
35
37
|
ZLinkObjectReserveResult,
|
|
36
38
|
ZLinkCreationOperationIdentity,
|
|
@@ -41,13 +43,22 @@ import type {
|
|
|
41
43
|
} from './internal-location-contracts';
|
|
42
44
|
import { encodeAuthorityKey } from './authority-key-codec';
|
|
43
45
|
import { creationTerminalPreimage } from './opaque-record-key';
|
|
46
|
+
import {
|
|
47
|
+
ServiceRelocationAuthorityPayloadCodec,
|
|
48
|
+
serviceRelocationAuthorityApplicationPayload
|
|
49
|
+
} from '../foundation/service-relocation-runtime';
|
|
50
|
+
import { decodeServiceReadySpotAuthority } from '../foundation/service-authority-payload-codec';
|
|
51
|
+
import { decodeActorAuthorityPayload } from '../actors/actor-authority-payload-codec';
|
|
52
|
+
import { ZLinkSpotKind } from '../../contracts';
|
|
44
53
|
|
|
45
54
|
const MAX_GENERATION = 0x7fff_ffff_ffff_ffffn;
|
|
46
55
|
|
|
47
56
|
const CREATION_TERMINAL_RETENTION_MS = 5 * 60 * 1000;
|
|
48
57
|
const MAX_U64 = UINT64_MAX;
|
|
58
|
+
const relocationAuthorityCodec = new ServiceRelocationAuthorityPayloadCodec();
|
|
49
59
|
|
|
50
60
|
export interface ZLinkInMemoryAuthorityValidation {
|
|
61
|
+
isOwnerLive(owner: ZLinkLocationOwnerToken): boolean;
|
|
51
62
|
isTargetLive(
|
|
52
63
|
descriptor: ZLinkMeshNodeDescriptorKey,
|
|
53
64
|
lifecycleGeneration: bigint,
|
|
@@ -60,6 +71,7 @@ export interface ZLinkInMemoryAuthorityValidation {
|
|
|
60
71
|
currentActive: ZLinkCapacityVector
|
|
61
72
|
): boolean;
|
|
62
73
|
identityClaimed?(authorityKey: string): boolean;
|
|
74
|
+
hasSpotMembers?(spotId: string, objectGeneration: bigint): boolean;
|
|
63
75
|
}
|
|
64
76
|
|
|
65
77
|
interface AuthorityRow {
|
|
@@ -199,6 +211,26 @@ export class ZLinkInMemoryAuthorityStore {
|
|
|
199
211
|
if (!this.isOwnerLive(row.snapshot)) {
|
|
200
212
|
return { kind: 'conflict', current: this.read(keyValue) };
|
|
201
213
|
}
|
|
214
|
+
const actor =
|
|
215
|
+
row.snapshot.allocation.objectKind === 'actor'
|
|
216
|
+
? decodeActorAuthorityPayload(
|
|
217
|
+
serviceRelocationAuthorityApplicationPayload(mutation.payload)
|
|
218
|
+
)
|
|
219
|
+
: undefined;
|
|
220
|
+
const previousActor =
|
|
221
|
+
actor === undefined
|
|
222
|
+
? undefined
|
|
223
|
+
: decodeActorAuthorityPayload(
|
|
224
|
+
serviceRelocationAuthorityApplicationPayload(row.snapshot.payload)
|
|
225
|
+
);
|
|
226
|
+
if (
|
|
227
|
+
actor?.currentSpotKind === ZLinkSpotKind.User &&
|
|
228
|
+
(previousActor?.currentSpotKind !== ZLinkSpotKind.User ||
|
|
229
|
+
previousActor.currentSpotId !== actor.currentSpotId ||
|
|
230
|
+
previousActor.currentSpotGeneration !== actor.currentSpotGeneration) &&
|
|
231
|
+
!this.acceptsUserSpotMembership(actor.currentSpotId, actor.currentSpotGeneration)
|
|
232
|
+
)
|
|
233
|
+
return { kind: 'conflict', current: this.read(keyValue) };
|
|
202
234
|
if (
|
|
203
235
|
mutation.generationTransition === 'reincarnate' &&
|
|
204
236
|
(this.objectGeneration >= MAX_GENERATION || this.ownerGeneration >= MAX_GENERATION)
|
|
@@ -279,22 +311,91 @@ export class ZLinkInMemoryAuthorityStore {
|
|
|
279
311
|
async releaseEndedReservation(
|
|
280
312
|
key: ZLinkAuthorityKey,
|
|
281
313
|
expectedStoreVersion: string,
|
|
282
|
-
signal?: AbortSignal
|
|
314
|
+
signal?: AbortSignal,
|
|
315
|
+
request?: ZLinkEndedOwnerReleaseIntent
|
|
283
316
|
): Promise<boolean> {
|
|
284
317
|
signal?.throwIfAborted();
|
|
285
|
-
return this.tryReleaseEndedReservation(key, expectedStoreVersion);
|
|
318
|
+
return this.tryReleaseEndedReservation(key, expectedStoreVersion, request);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
acceptsUserSpotMembership(spotId: string, objectGeneration: bigint): boolean {
|
|
322
|
+
const row = this.rows.get(encodeAuthorityKey('user_spot', spotId).value);
|
|
323
|
+
return (
|
|
324
|
+
row !== undefined &&
|
|
325
|
+
row.snapshot.allocation.objectKind === 'user_spot' &&
|
|
326
|
+
row.snapshot.allocation.state === 'active' &&
|
|
327
|
+
row.snapshot.objectGeneration === objectGeneration &&
|
|
328
|
+
decodeServiceReadySpotAuthority(row.snapshot.payload)?.kind === 'user_spot' &&
|
|
329
|
+
this.isOwnerLive(row.snapshot)
|
|
330
|
+
);
|
|
286
331
|
}
|
|
287
332
|
|
|
288
333
|
private tryReleaseEndedReservation(
|
|
289
334
|
key: ZLinkAuthorityKey,
|
|
290
|
-
expectedStoreVersion: string
|
|
335
|
+
expectedStoreVersion: string,
|
|
336
|
+
request?: ZLinkEndedOwnerReleaseIntent
|
|
291
337
|
): boolean {
|
|
292
338
|
const current = this.rows.get(key.value);
|
|
293
339
|
if (
|
|
294
340
|
current === undefined ||
|
|
295
341
|
current.snapshot.storeVersion.value !== expectedStoreVersion ||
|
|
296
|
-
current.snapshot.allocation.state
|
|
297
|
-
|
|
342
|
+
(current.snapshot.allocation.state === 'active'
|
|
343
|
+
? request === undefined
|
|
344
|
+
: current.creation === undefined)
|
|
345
|
+
)
|
|
346
|
+
return false;
|
|
347
|
+
if (current.snapshot.allocation.state === 'active') {
|
|
348
|
+
let unavailable = false;
|
|
349
|
+
for (const aggregate of this.aggregates.values()) {
|
|
350
|
+
if (
|
|
351
|
+
aggregate.state === 'prepared' &&
|
|
352
|
+
aggregate.request.participants.some(
|
|
353
|
+
(participant) => participant.authorityKey.value === key.value
|
|
354
|
+
)
|
|
355
|
+
)
|
|
356
|
+
unavailable = true;
|
|
357
|
+
}
|
|
358
|
+
unavailable ||= relocationAuthorityCodec.read(current.snapshot.payload) !== undefined;
|
|
359
|
+
if (
|
|
360
|
+
this.validation.isOwnerLive({
|
|
361
|
+
ownerId: current.snapshot.ownerId,
|
|
362
|
+
leaseGeneration: current.snapshot.ownerLeaseGeneration
|
|
363
|
+
})
|
|
364
|
+
)
|
|
365
|
+
return false;
|
|
366
|
+
const spot =
|
|
367
|
+
current.snapshot.allocation.objectKind === 'actor'
|
|
368
|
+
? undefined
|
|
369
|
+
: decodeServiceReadySpotAuthority(current.snapshot.payload);
|
|
370
|
+
if (current.snapshot.allocation.objectKind !== 'actor') {
|
|
371
|
+
unavailable ||=
|
|
372
|
+
spot === undefined ||
|
|
373
|
+
spot.kind !== request?.key.kind ||
|
|
374
|
+
spot.stableType !== request.intent.stableType ||
|
|
375
|
+
spot.spotId !== request.key.globalId ||
|
|
376
|
+
spot.activationRecovery !== undefined;
|
|
377
|
+
if (spot?.kind === 'user_spot') {
|
|
378
|
+
unavailable ||=
|
|
379
|
+
this.validation.hasSpotMembers?.(spot.spotId, current.snapshot.objectGeneration) ===
|
|
380
|
+
true;
|
|
381
|
+
for (const row of this.rows.values()) {
|
|
382
|
+
if (row.snapshot.allocation.objectKind !== 'actor') continue;
|
|
383
|
+
const actor = decodeActorAuthorityPayload(
|
|
384
|
+
serviceRelocationAuthorityApplicationPayload(row.snapshot.payload)
|
|
385
|
+
);
|
|
386
|
+
unavailable ||=
|
|
387
|
+
actor?.currentSpotKind === ZLinkSpotKind.User &&
|
|
388
|
+
actor.currentSpotId === spot.spotId &&
|
|
389
|
+
actor.currentSpotGeneration === current.snapshot.objectGeneration;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
if (unavailable || request?.actorRelocationPolicy !== 'disabled')
|
|
394
|
+
throw new ZLinkFrameworkException(
|
|
395
|
+
ZLinkFrameworkErrorKind.Unavailable,
|
|
396
|
+
'Object owner lease is unavailable.'
|
|
397
|
+
);
|
|
398
|
+
} else if (
|
|
298
399
|
this.validation.isTargetLive(
|
|
299
400
|
current.snapshot.allocation.descriptor,
|
|
300
401
|
current.snapshot.allocation.descriptorLifecycleGeneration,
|
|
@@ -305,9 +406,14 @@ export class ZLinkInMemoryAuthorityStore {
|
|
|
305
406
|
)
|
|
306
407
|
)
|
|
307
408
|
return false;
|
|
308
|
-
this.adjustCapacity(
|
|
409
|
+
this.adjustCapacity(
|
|
410
|
+
current.snapshot.allocation.state === 'active' ? this.activeCapacity : this.pendingCapacity,
|
|
411
|
+
current.snapshot.allocation,
|
|
412
|
+
-1
|
|
413
|
+
);
|
|
309
414
|
this.rows.delete(key.value);
|
|
310
|
-
|
|
415
|
+
if (current.snapshot.allocation.state === 'reserved' && current.creation !== undefined)
|
|
416
|
+
this.creationTerminals.set(current.creation.reservationId, 'aborted');
|
|
311
417
|
this.scanRevision++;
|
|
312
418
|
return true;
|
|
313
419
|
}
|
|
@@ -330,16 +436,16 @@ export class ZLinkInMemoryAuthorityStore {
|
|
|
330
436
|
) {
|
|
331
437
|
return { kind: 'typeMismatch', current: this.snapshot(current.snapshot) };
|
|
332
438
|
}
|
|
333
|
-
if (current.snapshot.allocation.state === 'active') {
|
|
334
|
-
return { kind: 'alreadyExists', current: this.snapshot(current.snapshot) };
|
|
335
|
-
}
|
|
336
439
|
if (
|
|
337
440
|
!this.tryReleaseEndedReservation(
|
|
338
441
|
encodeAuthorityKey(request.key.kind, request.key.globalId),
|
|
339
|
-
current.snapshot.storeVersion.value
|
|
442
|
+
current.snapshot.storeVersion.value,
|
|
443
|
+
request
|
|
340
444
|
)
|
|
341
445
|
)
|
|
342
|
-
return
|
|
446
|
+
return current.snapshot.allocation.state === 'active'
|
|
447
|
+
? { kind: 'alreadyExists', current: this.snapshot(current.snapshot) }
|
|
448
|
+
: { kind: 'conflict', current: this.read(key) };
|
|
343
449
|
}
|
|
344
450
|
const target = creationTarget(request);
|
|
345
451
|
if (
|
|
@@ -495,6 +601,17 @@ export class ZLinkInMemoryAuthorityStore {
|
|
|
495
601
|
if (!this.creationTerminalAvailable(terminalRecord)) {
|
|
496
602
|
return { kind: 'stale' };
|
|
497
603
|
}
|
|
604
|
+
const actor =
|
|
605
|
+
request.completion.kind === 'created'
|
|
606
|
+
? decodeActorAuthorityPayload(
|
|
607
|
+
serviceRelocationAuthorityApplicationPayload(request.completion.readyPayload)
|
|
608
|
+
)
|
|
609
|
+
: undefined;
|
|
610
|
+
if (
|
|
611
|
+
actor?.currentSpotKind === ZLinkSpotKind.User &&
|
|
612
|
+
!this.acceptsUserSpotMembership(actor.currentSpotId, actor.currentSpotGeneration)
|
|
613
|
+
)
|
|
614
|
+
return { kind: 'stale' };
|
|
498
615
|
const nextVersion = this.tryNextStoreVersion();
|
|
499
616
|
if (nextVersion === undefined) return { kind: 'generationExhausted' };
|
|
500
617
|
const pending = row.snapshot.allocation;
|
|
@@ -661,6 +778,30 @@ export class ZLinkInMemoryAuthorityStore {
|
|
|
661
778
|
) {
|
|
662
779
|
return { kind: 'stale' };
|
|
663
780
|
}
|
|
781
|
+
const actor =
|
|
782
|
+
row.snapshot.allocation.objectKind === 'actor'
|
|
783
|
+
? decodeActorAuthorityPayload(
|
|
784
|
+
serviceRelocationAuthorityApplicationPayload(participant.authorityPayload)
|
|
785
|
+
)
|
|
786
|
+
: undefined;
|
|
787
|
+
if (actor?.currentSpotKind === ZLinkSpotKind.User) {
|
|
788
|
+
const participantSpot = aggregate.request.participants.find(
|
|
789
|
+
(candidate) =>
|
|
790
|
+
candidate.authorityKey.value ===
|
|
791
|
+
encodeAuthorityKey('user_spot', actor.currentSpotId).value
|
|
792
|
+
);
|
|
793
|
+
if (participantSpot === undefined) {
|
|
794
|
+
if (!this.acceptsUserSpotMembership(actor.currentSpotId, actor.currentSpotGeneration))
|
|
795
|
+
return { kind: 'stale' };
|
|
796
|
+
} else {
|
|
797
|
+
const spot = this.rows.get(participantSpot.authorityKey.value);
|
|
798
|
+
if (
|
|
799
|
+
spot?.snapshot.allocation.objectKind !== 'user_spot' ||
|
|
800
|
+
spot.snapshot.objectGeneration !== actor.currentSpotGeneration
|
|
801
|
+
)
|
|
802
|
+
return { kind: 'stale' };
|
|
803
|
+
}
|
|
804
|
+
}
|
|
664
805
|
if (participant.ownerTransition === 'newOwner') {
|
|
665
806
|
if (
|
|
666
807
|
!this.validation.isTargetLive(
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { RoutingId } from '../../contracts/Common';
|
|
2
|
+
import { ZLinkSpotKind } from '../../contracts';
|
|
2
3
|
import { ZLINK_MAX_IDENTITY_TEXT_BYTES } from '../../contracts/Common/CoreTypes';
|
|
3
4
|
import {
|
|
4
5
|
isValidPublicWeight,
|
|
@@ -58,6 +59,7 @@ import {
|
|
|
58
59
|
type ZLinkObjectCommitResult,
|
|
59
60
|
type ZLinkObjectCreationCompleteRequest,
|
|
60
61
|
type ZLinkObjectCreationCompleteResult,
|
|
62
|
+
type ZLinkEndedOwnerReleaseIntent,
|
|
61
63
|
type ZLinkObjectReserveRequest,
|
|
62
64
|
type ZLinkObjectReserveResult,
|
|
63
65
|
type ZLinkOwnerLeaseClaimResult,
|
|
@@ -99,11 +101,14 @@ export class ZLinkInMemoryLocationStore
|
|
|
99
101
|
private readonly authority: ZLinkInMemoryAuthorityStore;
|
|
100
102
|
|
|
101
103
|
constructor(private readonly now: () => Date = () => new Date()) {
|
|
104
|
+
const isOwnerLive = (owner: ZLinkLocationOwnerToken): boolean =>
|
|
105
|
+
this.liveOwnerLease(owner.ownerId, this.now())?.token.leaseGeneration ===
|
|
106
|
+
owner.leaseGeneration;
|
|
102
107
|
this.authority = new ZLinkInMemoryAuthorityStore(
|
|
103
108
|
{
|
|
109
|
+
isOwnerLive,
|
|
104
110
|
isTargetLive: (key, lifecycleGeneration, owner) => {
|
|
105
111
|
const descriptor = this.meshNodes.rows.get(meshNodeKey(key.meshName, key.rid));
|
|
106
|
-
const lease = this.leases.get(owner.ownerId);
|
|
107
112
|
return (
|
|
108
113
|
descriptor !== undefined &&
|
|
109
114
|
descriptor.lifecycleGeneration === lifecycleGeneration &&
|
|
@@ -111,9 +116,7 @@ export class ZLinkInMemoryLocationStore
|
|
|
111
116
|
descriptor.leaseGeneration === owner.leaseGeneration &&
|
|
112
117
|
descriptor.objectRole === ZLinkObjectRole.Server &&
|
|
113
118
|
descriptor.state === ZLinkFrameworkRuntimeState.Serving &&
|
|
114
|
-
|
|
115
|
-
lease.token.leaseGeneration === owner.leaseGeneration &&
|
|
116
|
-
lease.leaseExpiresAt.getTime() > this.now().getTime()
|
|
119
|
+
isOwnerLive(owner)
|
|
117
120
|
);
|
|
118
121
|
},
|
|
119
122
|
placementCapacityAvailable: (key, requested, reserved, active) => {
|
|
@@ -142,7 +145,18 @@ export class ZLinkInMemoryLocationStore
|
|
|
142
145
|
typeCapacity.limit)))
|
|
143
146
|
);
|
|
144
147
|
},
|
|
145
|
-
identityClaimed: (authorityKey) => this.entrySpotClaims.has(authorityKey)
|
|
148
|
+
identityClaimed: (authorityKey) => this.entrySpotClaims.has(authorityKey),
|
|
149
|
+
hasSpotMembers: (spotId, objectGeneration) => {
|
|
150
|
+
for (const actor of this.actors.rows.values()) {
|
|
151
|
+
if (
|
|
152
|
+
actor.spotKind === ZLinkSpotKind.User &&
|
|
153
|
+
String(actor.spotId) === spotId &&
|
|
154
|
+
actor.spotGeneration === objectGeneration
|
|
155
|
+
)
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
146
160
|
},
|
|
147
161
|
now
|
|
148
162
|
);
|
|
@@ -204,9 +218,10 @@ export class ZLinkInMemoryLocationStore
|
|
|
204
218
|
async releaseEndedReservation(
|
|
205
219
|
key: ZLinkAuthorityKey,
|
|
206
220
|
expectedStoreVersion: string,
|
|
207
|
-
signal?: AbortSignal
|
|
221
|
+
signal?: AbortSignal,
|
|
222
|
+
request?: ZLinkEndedOwnerReleaseIntent
|
|
208
223
|
): Promise<boolean> {
|
|
209
|
-
return this.authority.releaseEndedReservation(key, expectedStoreVersion, signal);
|
|
224
|
+
return this.authority.releaseEndedReservation(key, expectedStoreVersion, signal, request);
|
|
210
225
|
}
|
|
211
226
|
|
|
212
227
|
async abort(
|
|
@@ -566,7 +581,8 @@ export class ZLinkInMemoryLocationStore
|
|
|
566
581
|
const storeNow = this.now();
|
|
567
582
|
return pageRows(
|
|
568
583
|
this.fanoutPublishers,
|
|
569
|
-
(row) =>
|
|
584
|
+
(row) =>
|
|
585
|
+
row.channelName === channelName && this.liveOwnerLease(row.ownerId, storeNow) !== undefined,
|
|
570
586
|
page
|
|
571
587
|
);
|
|
572
588
|
}
|
|
@@ -628,7 +644,7 @@ export class ZLinkInMemoryLocationStore
|
|
|
628
644
|
if (
|
|
629
645
|
intent === ZLinkLocationWriteIntent.NewClaim &&
|
|
630
646
|
current !== undefined &&
|
|
631
|
-
this.
|
|
647
|
+
this.liveOwnerLease(current.ownerId, updatedAt) !== undefined
|
|
632
648
|
) {
|
|
633
649
|
return rejectedConflict();
|
|
634
650
|
}
|
|
@@ -703,10 +719,18 @@ export class ZLinkInMemoryLocationStore
|
|
|
703
719
|
});
|
|
704
720
|
const updatedAt = this.now();
|
|
705
721
|
const current = this.actors.rows.get(key);
|
|
722
|
+
if (
|
|
723
|
+
actor.spotKind === ZLinkSpotKind.User &&
|
|
724
|
+
(current?.spotKind !== ZLinkSpotKind.User ||
|
|
725
|
+
String(current.spotId) !== String(actor.spotId) ||
|
|
726
|
+
current.spotGeneration !== actor.spotGeneration) &&
|
|
727
|
+
!this.authority.acceptsUserSpotMembership(String(actor.spotId), actor.spotGeneration)
|
|
728
|
+
)
|
|
729
|
+
return rejectedConflict();
|
|
706
730
|
if (
|
|
707
731
|
intent === ZLinkLocationWriteIntent.NewClaim &&
|
|
708
732
|
current !== undefined &&
|
|
709
|
-
this.
|
|
733
|
+
this.liveOwnerLease(current.ownerId, updatedAt) !== undefined
|
|
710
734
|
) {
|
|
711
735
|
return rejectedConflict();
|
|
712
736
|
}
|
|
@@ -1155,7 +1179,7 @@ export class ZLinkInMemoryLocationStore
|
|
|
1155
1179
|
if (
|
|
1156
1180
|
intent === ZLinkLocationWriteIntent.NewClaim &&
|
|
1157
1181
|
current !== undefined &&
|
|
1158
|
-
this.
|
|
1182
|
+
this.liveOwnerLease(ownerOf(current), updatedAt) !== undefined
|
|
1159
1183
|
) {
|
|
1160
1184
|
return rejectedConflict();
|
|
1161
1185
|
}
|
|
@@ -1252,9 +1276,11 @@ export class ZLinkInMemoryLocationStore
|
|
|
1252
1276
|
return removed;
|
|
1253
1277
|
}
|
|
1254
1278
|
|
|
1255
|
-
private
|
|
1279
|
+
private liveOwnerLease(ownerId: string, now: Date): InMemoryOwnerLease | undefined {
|
|
1256
1280
|
const lease = this.leases.get(ownerId);
|
|
1257
|
-
return lease !== undefined && lease.leaseExpiresAt.getTime() > now.getTime()
|
|
1281
|
+
return lease !== undefined && lease.leaseExpiresAt.getTime() > now.getTime()
|
|
1282
|
+
? lease
|
|
1283
|
+
: undefined;
|
|
1258
1284
|
}
|
|
1259
1285
|
|
|
1260
1286
|
private bump(kind: ZLinkLocationKind, meshName: string | undefined): void {
|
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
export * from '../../contracts/Locations';
|
|
2
|
+
import type { ZLinkObjectReserveRequest as ReserveRequest } from '../../contracts/Locations/Authority';
|
|
3
|
+
import type { ZLinkRelocationConfiguration } from '../../contracts/Configuration/RegistrationTypes';
|
|
4
|
+
|
|
5
|
+
export interface ZLinkObjectReserveRequest extends ReserveRequest {
|
|
6
|
+
readonly actorRelocationPolicy?: ZLinkRelocationConfiguration<unknown>['kind'];
|
|
7
|
+
}
|
|
8
|
+
export type ZLinkEndedOwnerReleaseIntent = Pick<
|
|
9
|
+
ZLinkObjectReserveRequest,
|
|
10
|
+
'key' | 'actorRelocationPolicy'
|
|
11
|
+
> & { readonly intent: Pick<ZLinkObjectReserveRequest['intent'], 'stableType'> };
|
|
2
12
|
export type * from '../../contracts/Locations/Authority';
|
|
3
13
|
export type {
|
|
4
14
|
ZLinkActorLocation,
|