@harperfast/harper 5.3.0-beta.3 → 5.3.0-beta.4
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/bin/cliOperations.ts +25 -3
- package/bin/run.ts +18 -0
- package/components/Application.ts +52 -78
- package/components/DESIGN.md +76 -3
- package/components/Scope.ts +10 -4
- package/components/anthropic/index.ts +10 -1
- package/components/bedrock/index.ts +10 -1
- package/components/componentLoader.ts +23 -14
- package/components/mcp/tools/operations.ts +3 -1
- package/components/ollama/index.ts +10 -1
- package/components/openai/index.ts +265 -18
- package/components/operations.js +40 -1
- package/config/configUtils.ts +3 -19
- package/dataLayer/DESIGN.md +29 -5
- package/dataLayer/harperBridge/ResourceBridge.ts +39 -3
- package/dataLayer/restoreMarker.ts +250 -14
- package/dataLayer/schema.ts +2 -7
- package/dataLayer/schemaDescribe.ts +10 -0
- package/dist/bin/cliOperations.js +28 -3
- package/dist/bin/cliOperations.js.map +1 -1
- package/dist/bin/run.js +19 -0
- package/dist/bin/run.js.map +1 -1
- package/dist/components/Application.d.ts +8 -2
- package/dist/components/Application.js +43 -69
- package/dist/components/Application.js.map +1 -1
- package/dist/components/Scope.d.ts +1 -1
- package/dist/components/Scope.js +9 -4
- package/dist/components/Scope.js.map +1 -1
- package/dist/components/anthropic/index.d.ts +0 -10
- package/dist/components/anthropic/index.js +9 -1
- package/dist/components/anthropic/index.js.map +1 -1
- package/dist/components/bedrock/index.d.ts +0 -12
- package/dist/components/bedrock/index.js +9 -1
- package/dist/components/bedrock/index.js.map +1 -1
- package/dist/components/componentLoader.js +23 -14
- package/dist/components/componentLoader.js.map +1 -1
- package/dist/components/mcp/tools/operations.js +1 -1
- package/dist/components/mcp/tools/operations.js.map +1 -1
- package/dist/components/ollama/index.d.ts +0 -13
- package/dist/components/ollama/index.js +9 -1
- package/dist/components/ollama/index.js.map +1 -1
- package/dist/components/openai/index.d.ts +11 -15
- package/dist/components/openai/index.js +224 -12
- package/dist/components/openai/index.js.map +1 -1
- package/dist/components/operations.d.ts +9 -0
- package/dist/components/operations.js +32 -2
- package/dist/components/operations.js.map +1 -1
- package/dist/config/configUtils.d.ts +1 -2
- package/dist/config/configUtils.js +7 -22
- package/dist/config/configUtils.js.map +1 -1
- package/dist/dataLayer/harperBridge/ResourceBridge.js +29 -2
- package/dist/dataLayer/harperBridge/ResourceBridge.js.map +1 -1
- package/dist/dataLayer/restoreMarker.d.ts +25 -3
- package/dist/dataLayer/restoreMarker.js +213 -13
- package/dist/dataLayer/restoreMarker.js.map +1 -1
- package/dist/dataLayer/schema.js +1 -4
- package/dist/dataLayer/schema.js.map +1 -1
- package/dist/dataLayer/schemaDescribe.js +10 -0
- package/dist/dataLayer/schemaDescribe.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/json/systemSchema.json +28 -0
- package/dist/resources/DatabaseTransaction.d.ts +21 -1
- package/dist/resources/DatabaseTransaction.js +147 -8
- package/dist/resources/DatabaseTransaction.js.map +1 -1
- package/dist/resources/PrimaryRocksDatabase.js +1 -1
- package/dist/resources/PrimaryRocksDatabase.js.map +1 -1
- package/dist/resources/Table.d.ts +31 -3
- package/dist/resources/Table.js +397 -79
- package/dist/resources/Table.js.map +1 -1
- package/dist/resources/auditStore.js +16 -10
- package/dist/resources/auditStore.js.map +1 -1
- package/dist/resources/blob.d.ts +1 -0
- package/dist/resources/blob.js +14 -5
- package/dist/resources/blob.js.map +1 -1
- package/dist/resources/branchDatabase.js +3 -3
- package/dist/resources/branchDatabase.js.map +1 -1
- package/dist/resources/databaseDropPreparation.d.ts +20 -0
- package/dist/resources/databaseDropPreparation.js +106 -0
- package/dist/resources/databaseDropPreparation.js.map +1 -0
- package/dist/resources/databases.d.ts +26 -21
- package/dist/resources/databases.js +1040 -204
- package/dist/resources/databases.js.map +1 -1
- package/dist/resources/derivedIndexRegistry.d.ts +23 -0
- package/dist/resources/derivedIndexRegistry.js +92 -0
- package/dist/resources/derivedIndexRegistry.js.map +1 -1
- package/dist/resources/derivedIndexRuntime.d.ts +10 -0
- package/dist/resources/derivedIndexRuntime.js +136 -25
- package/dist/resources/derivedIndexRuntime.js.map +1 -1
- package/dist/resources/derivedIndexes.d.ts +39 -0
- package/dist/resources/derivedIndexes.js +733 -0
- package/dist/resources/derivedIndexes.js.map +1 -0
- package/dist/resources/fullTextSchema.d.ts +8 -0
- package/dist/resources/fullTextSchema.js +42 -0
- package/dist/resources/fullTextSchema.js.map +1 -1
- package/dist/resources/fullTextSchemaLifecycle.d.ts +0 -5
- package/dist/resources/fullTextSchemaLifecycle.js +0 -9
- package/dist/resources/fullTextSchemaLifecycle.js.map +1 -1
- package/dist/resources/graphql.js +101 -9
- package/dist/resources/graphql.js.map +1 -1
- package/dist/resources/indexes/hnswDerivedIndex.d.ts +0 -10
- package/dist/resources/indexes/hnswDerivedIndex.js +0 -230
- package/dist/resources/indexes/hnswDerivedIndex.js.map +1 -1
- package/dist/resources/indexes/nativeFullTextDerivedIndexLifecycle.d.ts +3 -0
- package/dist/resources/indexes/nativeFullTextDerivedIndexLifecycle.js +57 -8
- package/dist/resources/indexes/nativeFullTextDerivedIndexLifecycle.js.map +1 -1
- package/dist/resources/models/Models.d.ts +26 -3
- package/dist/resources/models/Models.js +256 -13
- package/dist/resources/models/Models.js.map +1 -1
- package/dist/resources/models/TestBackend.d.ts +3 -1
- package/dist/resources/models/TestBackend.js +35 -1
- package/dist/resources/models/TestBackend.js.map +1 -1
- package/dist/resources/models/analyticsTable.d.ts +2 -2
- package/dist/resources/models/analyticsTable.js +4 -2
- package/dist/resources/models/analyticsTable.js.map +1 -1
- package/dist/resources/models/backendHelpers.d.ts +24 -0
- package/dist/resources/models/backendHelpers.js +18 -1
- package/dist/resources/models/backendHelpers.js.map +1 -1
- package/dist/resources/models/backendRegistry.d.ts +10 -21
- package/dist/resources/models/backendRegistry.js +74 -18
- package/dist/resources/models/backendRegistry.js.map +1 -1
- package/dist/resources/models/bootstrap.d.ts +7 -0
- package/dist/resources/models/bootstrap.js +36 -4
- package/dist/resources/models/bootstrap.js.map +1 -1
- package/dist/resources/models/decideHook.d.ts +33 -0
- package/dist/resources/models/decideHook.js +105 -0
- package/dist/resources/models/decideHook.js.map +1 -0
- package/dist/resources/models/decision.d.ts +64 -0
- package/dist/resources/models/decision.js +507 -0
- package/dist/resources/models/decision.js.map +1 -0
- package/dist/resources/models/decisionStore.d.ts +134 -0
- package/dist/resources/models/decisionStore.js +350 -0
- package/dist/resources/models/decisionStore.js.map +1 -0
- package/dist/resources/models/embedHook.d.ts +66 -8
- package/dist/resources/models/embedHook.js +228 -61
- package/dist/resources/models/embedHook.js.map +1 -1
- package/dist/resources/models/generativeDecision.d.ts +58 -0
- package/dist/resources/models/generativeDecision.js +315 -0
- package/dist/resources/models/generativeDecision.js.map +1 -0
- package/dist/resources/models/types.d.ts +232 -4
- package/dist/security/authn/oidc/tokenExchange.js +3 -33
- package/dist/security/authn/oidc/tokenExchange.js.map +1 -1
- package/dist/security/authn/oidc/tokenUseTable.d.ts +9 -0
- package/dist/security/authn/oidc/tokenUseTable.js +28 -0
- package/dist/security/authn/oidc/tokenUseTable.js.map +1 -0
- package/dist/security/certificateVerification/certificateVerificationSource.d.ts +0 -1
- package/dist/security/certificateVerification/certificateVerificationSource.js +3 -3
- package/dist/security/certificateVerification/certificateVerificationSource.js.map +1 -1
- package/dist/security/certificateVerification/crlVerification.js +77 -165
- package/dist/security/certificateVerification/crlVerification.js.map +1 -1
- package/dist/security/certificateVerification/types.d.ts +0 -3
- package/dist/security/certificateVerification/verificationTables.d.ts +19 -0
- package/dist/security/certificateVerification/verificationTables.js +125 -0
- package/dist/security/certificateVerification/verificationTables.js.map +1 -0
- package/dist/security/certificateVerification/verificationUtils.d.ts +1 -1
- package/dist/security/certificateVerification/verificationUtils.js +6 -31
- package/dist/security/certificateVerification/verificationUtils.js.map +1 -1
- package/dist/security/jsLoader.d.ts +5 -0
- package/dist/security/jsLoader.js +8 -0
- package/dist/security/jsLoader.js.map +1 -1
- package/dist/server/Server.d.ts +1 -0
- package/dist/server/Server.js.map +1 -1
- package/dist/server/http.js +2 -2
- package/dist/server/http.js.map +1 -1
- package/dist/server/itc/serverHandlers.js +21 -2
- package/dist/server/itc/serverHandlers.js.map +1 -1
- package/dist/server/jobs/jobOwnership.d.ts +25 -0
- package/dist/server/jobs/jobOwnership.js +127 -0
- package/dist/server/jobs/jobOwnership.js.map +1 -0
- package/dist/server/jobs/jobProcess.js +9 -2
- package/dist/server/jobs/jobProcess.js.map +1 -1
- package/dist/server/jobs/jobs.js +18 -5
- package/dist/server/jobs/jobs.js.map +1 -1
- package/dist/server/loadRootComponents.js +10 -0
- package/dist/server/loadRootComponents.js.map +1 -1
- package/dist/server/serverHelpers/contentTypes.js +11 -1
- package/dist/server/serverHelpers/contentTypes.js.map +1 -1
- package/dist/server/serverHelpers/serverHandlers.js +12 -2
- package/dist/server/serverHelpers/serverHandlers.js.map +1 -1
- package/dist/server/threads/itc.d.ts +4 -1
- package/dist/server/threads/itc.js +29 -6
- package/dist/server/threads/itc.js.map +1 -1
- package/dist/server/threads/manageThreads.d.ts +12 -4
- package/dist/server/threads/manageThreads.js +241 -119
- package/dist/server/threads/manageThreads.js.map +1 -1
- package/dist/server/threads/threadServer.d.ts +1 -0
- package/dist/server/threads/threadServer.js +15 -1
- package/dist/server/threads/threadServer.js.map +1 -1
- package/dist/server/threads/windowsProcessTree.d.ts +91 -0
- package/dist/server/threads/windowsProcessTree.js +361 -0
- package/dist/server/threads/windowsProcessTree.js.map +1 -0
- package/dist/server/throttle.d.ts +1 -1
- package/dist/server/throttle.js +8 -1
- package/dist/server/throttle.js.map +1 -1
- package/dist/upgrade/directives/5-3-0.js +53 -46
- package/dist/upgrade/directives/5-3-0.js.map +1 -1
- package/dist/utility/errors/hdbError.d.ts +10 -1
- package/dist/utility/errors/hdbError.js +55 -11
- package/dist/utility/errors/hdbError.js.map +1 -1
- package/dist/utility/fsync.d.ts +2 -0
- package/dist/utility/fsync.js +20 -0
- package/dist/utility/fsync.js.map +1 -0
- package/dist/utility/globalSchema.d.ts +18 -0
- package/dist/utility/hdbTerms.d.ts +3 -0
- package/dist/utility/hdbTerms.js +3 -0
- package/dist/utility/hdbTerms.js.map +1 -1
- package/dist/utility/signalling.d.ts +7 -1
- package/dist/utility/signalling.js +27 -3
- package/dist/utility/signalling.js.map +1 -1
- package/dist/utility/when.d.ts +1 -0
- package/dist/utility/when.js +21 -0
- package/dist/utility/when.js.map +1 -1
- package/dist/validation/configValidator.js +30 -3
- package/dist/validation/configValidator.js.map +1 -1
- package/index.ts +13 -0
- package/json/systemSchema.json +28 -0
- package/npm-shrinkwrap.json +151 -55
- package/package.json +14 -13
- package/resources/DESIGN.md +80 -100
- package/resources/DatabaseTransaction.ts +157 -10
- package/resources/PrimaryRocksDatabase.ts +2 -2
- package/resources/Table.ts +494 -101
- package/resources/auditStore.ts +18 -10
- package/resources/blob.ts +13 -6
- package/resources/branchDatabase.ts +3 -3
- package/resources/databaseDropPreparation.ts +120 -0
- package/resources/databases.ts +1155 -205
- package/resources/derivedIndexRegistry.ts +122 -0
- package/resources/derivedIndexRuntime.ts +157 -30
- package/resources/derivedIndexes.ts +856 -0
- package/resources/fullTextSchema.ts +55 -0
- package/resources/fullTextSchemaLifecycle.ts +0 -15
- package/resources/graphql.ts +107 -12
- package/resources/indexes/DESIGN.md +7 -0
- package/resources/indexes/hnswDerivedIndex.ts +0 -260
- package/resources/indexes/nativeFullTextDerivedIndexLifecycle.ts +72 -9
- package/resources/models/DESIGN.md +39 -0
- package/resources/models/Models.ts +361 -18
- package/resources/models/TestBackend.ts +56 -1
- package/resources/models/analyticsTable.ts +6 -4
- package/resources/models/backendHelpers.ts +17 -0
- package/resources/models/backendRegistry.ts +76 -21
- package/resources/models/bootstrap.ts +57 -7
- package/resources/models/decideHook.ts +135 -0
- package/resources/models/decision.ts +505 -0
- package/resources/models/decisionStore.ts +419 -0
- package/resources/models/embedHook.ts +272 -55
- package/resources/models/generativeDecision.ts +459 -0
- package/resources/models/types.ts +231 -4
- package/security/DESIGN.md +22 -2
- package/security/authn/oidc/tokenExchange.ts +6 -34
- package/security/authn/oidc/tokenUseTable.ts +27 -0
- package/security/certificateVerification/certificateVerificationSource.ts +2 -3
- package/security/certificateVerification/crlVerification.ts +96 -174
- package/security/certificateVerification/types.ts +0 -3
- package/security/certificateVerification/verificationTables.ts +124 -0
- package/security/certificateVerification/verificationUtils.ts +8 -32
- package/security/jsLoader.ts +9 -1
- package/server/DESIGN.md +27 -1
- package/server/Server.ts +2 -1
- package/server/http.ts +4 -2
- package/server/itc/serverHandlers.js +29 -1
- package/server/jobs/jobOwnership.ts +89 -0
- package/server/jobs/jobProcess.ts +8 -2
- package/server/jobs/jobs.ts +15 -4
- package/server/loadRootComponents.js +11 -0
- package/server/serverHelpers/contentTypes.ts +13 -1
- package/server/serverHelpers/serverHandlers.js +11 -2
- package/server/threads/itc.js +32 -6
- package/server/threads/manageThreads.js +268 -122
- package/server/threads/threadServer.js +13 -1
- package/server/threads/windowsProcessTree.ts +409 -0
- package/server/throttle.ts +11 -1
- package/studio/web/assets/{Chat-CveGbxe6.js → Chat-Bq60AO-g.js} +1 -1
- package/studio/web/assets/{FloatingChat-IpCFgYWL.js → FloatingChat-D4560T0p.js} +3 -3
- package/studio/web/assets/{apiToken-CS8fFTgL.js → apiToken-BEvbFPMc.js} +1 -1
- package/studio/web/assets/{applications-D7F4Jopl.js → applications-CSUVTH4E.js} +1 -1
- package/studio/web/assets/{cssMode-Daw_oLPq.js → cssMode-DJyc9mHj.js} +1 -1
- package/studio/web/assets/{editor-B3Bs1zWX.js → editor-DDIsQfj6.js} +1 -1
- package/studio/web/assets/{html-CDaQwWiE.js → html-g1BJHxLy.js} +1 -1
- package/studio/web/assets/{htmlMode-Cb6emO4U.js → htmlMode-Vh5IglCQ.js} +1 -1
- package/studio/web/assets/{index-B4g2Fu_2.js → index-DGRAzvO4.js} +5 -5
- package/studio/web/assets/{index.lazy-NwhvF1q1.js → index.lazy-vgSic7et.js} +1 -1
- package/studio/web/assets/{javascript-2_86gB9Q.js → javascript-5VIolqf7.js} +1 -1
- package/studio/web/assets/{jsonMode-DX-i86uQ.js → jsonMode-DG4zQraI.js} +1 -1
- package/studio/web/assets/{languageServices-B85WN-Ej.js → languageServices-t5FBpX-i.js} +1 -1
- package/studio/web/assets/{lspLanguageFeatures-JCWHIsKg.js → lspLanguageFeatures-DgVnNPh-.js} +1 -1
- package/studio/web/assets/{notifications-D9ejzt52.js → notifications-BeWcX04m.js} +1 -1
- package/studio/web/assets/{notifications-B7hjKhai.js → notifications-DUGWrWoO.js} +1 -1
- package/studio/web/assets/{profile-D8B6No3F.js → profile-BvUEDBzW.js} +1 -1
- package/studio/web/assets/{regions-DFazIfTK.js → regions-CB-_2m7M.js} +1 -1
- package/studio/web/assets/{register-CwFLviLF.js → register-1w1Zr3b2.js} +2 -2
- package/studio/web/assets/{setComponentFile-VnJ80SSJ.js → setComponentFile-z4-qJCbA.js} +1 -1
- package/studio/web/assets/{setup-BYQxFy-C.js → setup-CS50uJ4x.js} +2 -2
- package/studio/web/assets/{status-Cn5XjmsL.js → status-CI0wOdOE.js} +1 -1
- package/studio/web/assets/{toggleHighContrast-g9xIh6TX.js → toggleHighContrast-BsAE4jPe.js} +1 -1
- package/studio/web/assets/{tsMode-EC-n0Wqc.js → tsMode-D83Gg3cq.js} +1 -1
- package/studio/web/assets/{typescript-DHmM9JCO.js → typescript-Dfp-GrNq.js} +1 -1
- package/studio/web/assets/{useEntityRestURL-BUdnVSVv.js → useEntityRestURL-BKetlINf.js} +1 -1
- package/studio/web/assets/{workers-BVl9bBB-.js → workers-CCvmDLH3.js} +1 -1
- package/studio/web/assets/{xml-C4_sqOkX.js → xml-06pZp00U.js} +1 -1
- package/studio/web/assets/{yaml-CVkbDqtW.js → yaml-iSnWMVlV.js} +1 -1
- package/studio/web/index.html +1 -1
- package/upgrade/directives/5-3-0.ts +61 -54
- package/utility/DESIGN.md +5 -1
- package/utility/errors/hdbError.ts +56 -8
- package/utility/fsync.ts +16 -0
- package/utility/hdbTerms.ts +3 -0
- package/utility/signalling.ts +33 -4
- package/utility/when.ts +22 -0
- package/validation/configValidator.ts +36 -7
|
@@ -1,5 +1,28 @@
|
|
|
1
|
+
type LockStore = {
|
|
2
|
+
status?: string;
|
|
3
|
+
tryLock(key: string): boolean;
|
|
4
|
+
unlock(key: string): void;
|
|
5
|
+
};
|
|
6
|
+
type FenceWaitOptions = {
|
|
7
|
+
shouldContinue?: () => boolean;
|
|
8
|
+
timeoutMilliseconds?: number;
|
|
9
|
+
};
|
|
10
|
+
/** Hold this node-wide fence for the full duration of an asynchronous table clear. */
|
|
11
|
+
export declare function acquireFullTextClearFence(rootStore: LockStore, tableId: number): (() => void) | undefined;
|
|
12
|
+
/** Probe without waiting; callers hold the schema lock so a clear cannot start between this and persistence. */
|
|
13
|
+
export declare function fullTextClearInProgress(rootStore: LockStore, tableId: number): boolean;
|
|
14
|
+
/** Wait until the current clear releases its fence; callers retry admission afterwards. */
|
|
15
|
+
export declare function waitForFullTextClear(rootStore: LockStore, tableId: number, options?: FenceWaitOptions): Promise<boolean>;
|
|
16
|
+
/** Fence same-name recreation while a dropped table's native directories are being retired. */
|
|
17
|
+
export declare function acquireFullTextRetirementFence(rootStore: LockStore, tableName: string): (() => void) | undefined;
|
|
18
|
+
/** Probe under the schema lock so recreation cannot pass between the probe and catalog persistence. */
|
|
19
|
+
export declare function fullTextRetirementInProgress(rootStore: LockStore, tableName: string): boolean;
|
|
20
|
+
/** Wait until the current retirement releases its fence; the caller must recheck its generation afterwards. */
|
|
21
|
+
export declare function waitForFullTextRetirement(rootStore: LockStore, tableName: string, options?: FenceWaitOptions): Promise<boolean>;
|
|
22
|
+
export declare function waitForFullTextRetirementLease(rootStore: LockStore, tableName: string, options?: FenceWaitOptions): Promise<(() => void) | undefined>;
|
|
1
23
|
/** `admission` returns a reason while writes to these tables must be rejected. */
|
|
2
24
|
export declare function registerDerivedIndexTables(auditStore: object, tableIds: Iterable<number>, admission?: () => string | undefined): () => void;
|
|
3
25
|
export declare function hasDerivedIndexRegistration(auditStore: object, tableId: number): boolean;
|
|
4
26
|
/** The reason a write to this table must currently be rejected, or undefined when writes are admitted. */
|
|
5
27
|
export declare function derivedIndexWriteRejection(auditStore: object, tableId: number): string | undefined;
|
|
28
|
+
export {};
|
|
@@ -1,10 +1,102 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.acquireFullTextClearFence = acquireFullTextClearFence;
|
|
4
|
+
exports.fullTextClearInProgress = fullTextClearInProgress;
|
|
5
|
+
exports.waitForFullTextClear = waitForFullTextClear;
|
|
6
|
+
exports.acquireFullTextRetirementFence = acquireFullTextRetirementFence;
|
|
7
|
+
exports.fullTextRetirementInProgress = fullTextRetirementInProgress;
|
|
8
|
+
exports.waitForFullTextRetirement = waitForFullTextRetirement;
|
|
9
|
+
exports.waitForFullTextRetirementLease = waitForFullTextRetirementLease;
|
|
3
10
|
exports.registerDerivedIndexTables = registerDerivedIndexTables;
|
|
4
11
|
exports.hasDerivedIndexRegistration = hasDerivedIndexRegistration;
|
|
5
12
|
exports.derivedIndexWriteRejection = derivedIndexWriteRejection;
|
|
13
|
+
const hdbError_ts_1 = require("../utility/errors/hdbError.js");
|
|
6
14
|
const registrations = new WeakMap();
|
|
7
15
|
const admissions = new WeakMap();
|
|
16
|
+
const DEFAULT_FENCE_WAIT_MILLISECONDS = 70_000;
|
|
17
|
+
function fullTextClearLockKey(tableId) {
|
|
18
|
+
return `derived-index:fulltext:${tableId}:table-clear`;
|
|
19
|
+
}
|
|
20
|
+
function fullTextRetirementLockKey(tableName) {
|
|
21
|
+
return `derived-index:fulltext:${tableName}:retirement`;
|
|
22
|
+
}
|
|
23
|
+
/** Hold this node-wide fence for the full duration of an asynchronous table clear. */
|
|
24
|
+
function acquireFullTextClearFence(rootStore, tableId) {
|
|
25
|
+
const key = fullTextClearLockKey(tableId);
|
|
26
|
+
if (!rootStore.tryLock(key))
|
|
27
|
+
return;
|
|
28
|
+
let held = true;
|
|
29
|
+
return () => {
|
|
30
|
+
if (!held)
|
|
31
|
+
return;
|
|
32
|
+
held = false;
|
|
33
|
+
rootStore.unlock(key);
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/** Probe without waiting; callers hold the schema lock so a clear cannot start between this and persistence. */
|
|
37
|
+
function fullTextClearInProgress(rootStore, tableId) {
|
|
38
|
+
const release = acquireFullTextClearFence(rootStore, tableId);
|
|
39
|
+
if (!release)
|
|
40
|
+
return true;
|
|
41
|
+
release();
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
/** Wait until the current clear releases its fence; callers retry admission afterwards. */
|
|
45
|
+
function waitForFullTextClear(rootStore, tableId, options) {
|
|
46
|
+
return waitForFence(rootStore, () => acquireFullTextClearFence(rootStore, tableId), 'table clear', options);
|
|
47
|
+
}
|
|
48
|
+
/** Fence same-name recreation while a dropped table's native directories are being retired. */
|
|
49
|
+
function acquireFullTextRetirementFence(rootStore, tableName) {
|
|
50
|
+
const key = fullTextRetirementLockKey(tableName);
|
|
51
|
+
if (!rootStore.tryLock(key))
|
|
52
|
+
return;
|
|
53
|
+
let held = true;
|
|
54
|
+
return () => {
|
|
55
|
+
if (!held)
|
|
56
|
+
return;
|
|
57
|
+
held = false;
|
|
58
|
+
rootStore.unlock(key);
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/** Probe under the schema lock so recreation cannot pass between the probe and catalog persistence. */
|
|
62
|
+
function fullTextRetirementInProgress(rootStore, tableName) {
|
|
63
|
+
const release = acquireFullTextRetirementFence(rootStore, tableName);
|
|
64
|
+
if (!release)
|
|
65
|
+
return true;
|
|
66
|
+
release();
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
/** Wait until the current retirement releases its fence; the caller must recheck its generation afterwards. */
|
|
70
|
+
function waitForFullTextRetirement(rootStore, tableName, options) {
|
|
71
|
+
return waitForFence(rootStore, () => acquireFullTextRetirementFence(rootStore, tableName), `retirement of full-text storage for '${tableName}'`, options);
|
|
72
|
+
}
|
|
73
|
+
function waitForFullTextRetirementLease(rootStore, tableName, options) {
|
|
74
|
+
return waitForFenceLease(rootStore, () => acquireFullTextRetirementFence(rootStore, tableName), `retirement of full-text storage for '${tableName}'`, options);
|
|
75
|
+
}
|
|
76
|
+
async function waitForFence(rootStore, acquire, description, options = {}) {
|
|
77
|
+
const release = await waitForFenceLease(rootStore, acquire, description, options);
|
|
78
|
+
if (!release)
|
|
79
|
+
return false;
|
|
80
|
+
release();
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
async function waitForFenceLease(rootStore, acquire, description, options = {}) {
|
|
84
|
+
const deadline = Date.now() + (options.timeoutMilliseconds ?? DEFAULT_FENCE_WAIT_MILLISECONDS);
|
|
85
|
+
let retryDelayMilliseconds = 1;
|
|
86
|
+
for (;;) {
|
|
87
|
+
if (options.shouldContinue && !options.shouldContinue())
|
|
88
|
+
return;
|
|
89
|
+
if (rootStore.status !== undefined && rootStore.status !== 'open')
|
|
90
|
+
throw new Error(`Cannot wait for ${description} on a ${rootStore.status} store`);
|
|
91
|
+
const release = acquire();
|
|
92
|
+
if (release)
|
|
93
|
+
return release;
|
|
94
|
+
if (Date.now() >= deadline)
|
|
95
|
+
throw new hdbError_ts_1.DerivedIndexLagError(`Timed out waiting for ${description}; retry the operation`);
|
|
96
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelayMilliseconds));
|
|
97
|
+
retryDelayMilliseconds = Math.min(retryDelayMilliseconds * 2, 50);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
8
100
|
/** `admission` returns a reason while writes to these tables must be rejected. */
|
|
9
101
|
function registerDerivedIndexTables(auditStore, tableIds, admission) {
|
|
10
102
|
const registeredTableIds = new Set(tableIds);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"derivedIndexRegistry.js","sourceRoot":"","sources":["../../resources/derivedIndexRegistry.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"derivedIndexRegistry.js","sourceRoot":"","sources":["../../resources/derivedIndexRegistry.ts"],"names":[],"mappings":"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"}
|
|
@@ -144,6 +144,10 @@ export type DerivedIndexRegistration = {
|
|
|
144
144
|
backend: DerivedIndexBackend;
|
|
145
145
|
projections: ReadonlyMap<number, (record: unknown) => unknown>;
|
|
146
146
|
options?: DerivedIndexRunnerOptions;
|
|
147
|
+
/** Shared readiness identity when it must be narrower than the stable backend/lock identity. */
|
|
148
|
+
readinessId?: string;
|
|
149
|
+
/** False once this table generation has been superseded. Must be synchronous and allocation-free. */
|
|
150
|
+
isCurrent?: () => boolean;
|
|
147
151
|
};
|
|
148
152
|
/**
|
|
149
153
|
* `size` is the stored byte size of the record when known; it bounds the projection's size without
|
|
@@ -211,5 +215,11 @@ export declare class DerivedIndexRuntime {
|
|
|
211
215
|
}
|
|
212
216
|
/** Read an index's shared readiness on any worker, without a registered runtime. */
|
|
213
217
|
export declare function readDerivedIndexReadiness(logStore: RocksTransactionLogStore, backendId: string): DerivedIndexReadiness;
|
|
218
|
+
/** Publish setup-time state before a backend runner exists. */
|
|
219
|
+
export declare function publishDerivedIndexReadiness(logStore: RocksTransactionLogStore, backendId: string, state: DerivedIndexReadinessState, reason?: DerivedIndexReadinessReason): void;
|
|
220
|
+
/** Publish a setup failure only while no elected runner has published a stronger state. */
|
|
221
|
+
export declare function publishDerivedIndexUnavailableIfUnknown(logStore: RocksTransactionLogStore, backendId: string): boolean;
|
|
222
|
+
/** Rearm setup only while no peer has replaced the unavailable state. */
|
|
223
|
+
export declare function retryDerivedIndexUnavailable(logStore: RocksTransactionLogStore, backendId: string): boolean;
|
|
214
224
|
export declare function sameDerivedIndexPositions(left: DerivedIndexPositions, right: DerivedIndexPositions): boolean;
|
|
215
225
|
export declare function readDerivedIndexCoverage(logStore: RocksTransactionLogStore, backendId: string, loadCursor: () => DerivedIndexCursor | undefined, maxLagMilliseconds: number): DerivedIndexCoverage;
|
|
@@ -3,6 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.DerivedIndexRuntime = exports.READINESS_BYTES = exports.DERIVED_INDEX_FAILED = exports.DERIVED_INDEX_DEFERRED = exports.DERIVED_INDEX_ACCEPTED = void 0;
|
|
4
4
|
exports.derivedIndexTime = derivedIndexTime;
|
|
5
5
|
exports.readDerivedIndexReadiness = readDerivedIndexReadiness;
|
|
6
|
+
exports.publishDerivedIndexReadiness = publishDerivedIndexReadiness;
|
|
7
|
+
exports.publishDerivedIndexUnavailableIfUnknown = publishDerivedIndexUnavailableIfUnknown;
|
|
8
|
+
exports.retryDerivedIndexUnavailable = retryDerivedIndexUnavailable;
|
|
6
9
|
exports.sameDerivedIndexPositions = sameDerivedIndexPositions;
|
|
7
10
|
exports.readDerivedIndexCoverage = readDerivedIndexCoverage;
|
|
8
11
|
const DatabaseTransaction_ts_1 = require("./DatabaseTransaction.js");
|
|
@@ -33,6 +36,8 @@ const READINESS_STATES = [
|
|
|
33
36
|
'needs-rebuild',
|
|
34
37
|
'unavailable',
|
|
35
38
|
];
|
|
39
|
+
const READINESS_BACKEND_FAILED = READINESS_STATES.length;
|
|
40
|
+
const READINESS_RETRYING = READINESS_BACKEND_FAILED + 1;
|
|
36
41
|
const READINESS_REASONS = [
|
|
37
42
|
'none',
|
|
38
43
|
'cursor-missing',
|
|
@@ -114,6 +119,7 @@ class DerivedIndexRuntime {
|
|
|
114
119
|
this.#listening = true;
|
|
115
120
|
}
|
|
116
121
|
runner.wake(true);
|
|
122
|
+
let releaseStarted = false;
|
|
117
123
|
return () => {
|
|
118
124
|
if (this.#runners.get(registration.backend.id) === runner) {
|
|
119
125
|
this.#runners.delete(registration.backend.id);
|
|
@@ -124,6 +130,9 @@ class DerivedIndexRuntime {
|
|
|
124
130
|
}
|
|
125
131
|
this.#stopListeningIfIdle();
|
|
126
132
|
}
|
|
133
|
+
if (releaseStarted)
|
|
134
|
+
return this.#retryRunnerRelease(registration.backend.id, runner);
|
|
135
|
+
releaseStarted = true;
|
|
127
136
|
return this.#track(runner, runner.stop());
|
|
128
137
|
};
|
|
129
138
|
}
|
|
@@ -197,7 +206,7 @@ class DerivedIndexRuntime {
|
|
|
197
206
|
}
|
|
198
207
|
#pollCoverage(backendId, group) {
|
|
199
208
|
try {
|
|
200
|
-
const views = getReadinessViews(this.#logStore, backendId);
|
|
209
|
+
const views = getReadinessViews(this.#logStore, this.#runners.get(backendId)?.readinessId ?? backendId);
|
|
201
210
|
const before = readReadiness(views);
|
|
202
211
|
const time = Atomics.load(views.coverage, 0);
|
|
203
212
|
const after = readReadiness(views);
|
|
@@ -224,21 +233,32 @@ class DerivedIndexRuntime {
|
|
|
224
233
|
/** Force a rebuild (or retry one that became `unavailable`). Returns false when the backend cannot be rebuilt by the runtime. */
|
|
225
234
|
requestRebuild(backendId) {
|
|
226
235
|
const held = this.#heldRunners.get(backendId);
|
|
227
|
-
if (held)
|
|
228
|
-
|
|
229
|
-
this.#pendingStops.add(released);
|
|
230
|
-
released.then(() => {
|
|
231
|
-
this.#pendingStops.delete(released);
|
|
232
|
-
this.#pendingStops.delete(held.stopped);
|
|
233
|
-
if (this.#heldRunners.get(backendId) === held)
|
|
234
|
-
this.#heldRunners.delete(backendId);
|
|
235
|
-
}, () => { });
|
|
236
|
-
}
|
|
236
|
+
if (held)
|
|
237
|
+
void this.#retryRunnerRelease(backendId, held.runner);
|
|
237
238
|
const runner = this.#runners.get(backendId);
|
|
238
239
|
if (runner)
|
|
239
240
|
return runner.requestRebuild();
|
|
240
241
|
return held !== undefined;
|
|
241
242
|
}
|
|
243
|
+
#retryRunnerRelease(backendId, runner) {
|
|
244
|
+
const held = this.#heldRunners.get(backendId);
|
|
245
|
+
const released = runner.retryRelease();
|
|
246
|
+
this.#pendingStops.add(released);
|
|
247
|
+
released.then(() => {
|
|
248
|
+
this.#pendingStops.delete(released);
|
|
249
|
+
if (held?.runner === runner)
|
|
250
|
+
this.#pendingStops.delete(held.stopped);
|
|
251
|
+
if (this.#heldRunners.get(backendId)?.runner === runner)
|
|
252
|
+
this.#heldRunners.delete(backendId);
|
|
253
|
+
}, () => {
|
|
254
|
+
if (held?.runner === runner && held.stopped !== released)
|
|
255
|
+
this.#pendingStops.delete(held.stopped);
|
|
256
|
+
const current = this.#heldRunners.get(backendId);
|
|
257
|
+
if (!current || current.runner === runner)
|
|
258
|
+
this.#heldRunners.set(backendId, { runner, stopped: released });
|
|
259
|
+
});
|
|
260
|
+
return released;
|
|
261
|
+
}
|
|
242
262
|
/** Resolves once every runner has released ownership and its backend shutdown has settled. */
|
|
243
263
|
stop() {
|
|
244
264
|
if (this.#stopping)
|
|
@@ -269,8 +289,18 @@ class DerivedIndexRuntime {
|
|
|
269
289
|
#stopListening() {
|
|
270
290
|
if (!this.#listening)
|
|
271
291
|
return;
|
|
272
|
-
|
|
273
|
-
|
|
292
|
+
try {
|
|
293
|
+
this.#logStore.rootStore.off?.('committed', this.#onCommit);
|
|
294
|
+
}
|
|
295
|
+
catch (error) {
|
|
296
|
+
// An already-closed store cannot emit again and some native stores reject listener access
|
|
297
|
+
// after close. Preserve errors from a live store, where losing the listener would be unsafe.
|
|
298
|
+
if (this.#logStore.rootStore.status === 'open')
|
|
299
|
+
throw error;
|
|
300
|
+
}
|
|
301
|
+
finally {
|
|
302
|
+
this.#listening = false;
|
|
303
|
+
}
|
|
274
304
|
}
|
|
275
305
|
}
|
|
276
306
|
exports.DerivedIndexRuntime = DerivedIndexRuntime;
|
|
@@ -379,12 +409,16 @@ class DerivedIndexRunner {
|
|
|
379
409
|
#unregisterTables;
|
|
380
410
|
#ownerEpoch;
|
|
381
411
|
#readinessBuffer;
|
|
412
|
+
#wakeBuffer;
|
|
382
413
|
#sharedViews;
|
|
383
414
|
#resetting;
|
|
384
415
|
status = { state: 'idle' };
|
|
385
416
|
get id() {
|
|
386
417
|
return this.#registration.backend.id;
|
|
387
418
|
}
|
|
419
|
+
get readinessId() {
|
|
420
|
+
return this.#registration.readinessId ?? this.id;
|
|
421
|
+
}
|
|
388
422
|
retryRelease() {
|
|
389
423
|
if (!this.#heldLock)
|
|
390
424
|
return this.#stopResult ?? Promise.resolve();
|
|
@@ -414,7 +448,9 @@ class DerivedIndexRunner {
|
|
|
414
448
|
typeof root?.getSync === 'function' &&
|
|
415
449
|
typeof root?.removeSync === 'function';
|
|
416
450
|
this.#lagBudget = effectiveLagBudget(options);
|
|
417
|
-
|
|
451
|
+
const notified = () => this.#notified();
|
|
452
|
+
this.#readinessBuffer = readinessBuffer(logStore, this.readinessId, this.readinessId === this.id ? notified : undefined);
|
|
453
|
+
this.#wakeBuffer = this.readinessId === this.id ? this.#readinessBuffer : wakeBuffer(logStore, this.id, notified);
|
|
418
454
|
this.#sharedViews = sharedViewsOf(this.#readinessBuffer);
|
|
419
455
|
try {
|
|
420
456
|
registration.backend.attach({
|
|
@@ -425,6 +461,8 @@ class DerivedIndexRunner {
|
|
|
425
461
|
}
|
|
426
462
|
catch (error) {
|
|
427
463
|
this.#readinessBuffer.cancel?.();
|
|
464
|
+
if (this.#wakeBuffer !== this.#readinessBuffer)
|
|
465
|
+
this.#wakeBuffer.cancel?.();
|
|
428
466
|
throw error;
|
|
429
467
|
}
|
|
430
468
|
this.#unregisterTables = (0, derivedIndexRegistry_ts_1.registerDerivedIndexTables)(logStore, registration.projections.keys(), this.#lagBudget > 0 ? () => this.#writeRejection() : undefined);
|
|
@@ -443,8 +481,7 @@ class DerivedIndexRunner {
|
|
|
443
481
|
if (!fromBackend && !forCoverage && this.#lagBudget > 0)
|
|
444
482
|
this.#unreadSince ??= this.#options.now();
|
|
445
483
|
if (this.status.state === 'unavailable') {
|
|
446
|
-
if (this.#heldLock ||
|
|
447
|
-
Atomics.load(this.#shared().words, READINESS_STATE) === READINESS_STATES.indexOf('unavailable'))
|
|
484
|
+
if (this.#heldLock || isUnavailableReadinessState(Atomics.load(this.#shared().words, READINESS_STATE)))
|
|
448
485
|
return;
|
|
449
486
|
this.status = { state: 'idle' };
|
|
450
487
|
}
|
|
@@ -492,6 +529,8 @@ class DerivedIndexRunner {
|
|
|
492
529
|
try {
|
|
493
530
|
this.#unsubscribeBackend?.();
|
|
494
531
|
this.#readinessBuffer.cancel?.();
|
|
532
|
+
if (this.#wakeBuffer !== this.#readinessBuffer)
|
|
533
|
+
this.#wakeBuffer.cancel?.();
|
|
495
534
|
}
|
|
496
535
|
catch (error) {
|
|
497
536
|
logger.warn?.(`Derived index '${this.id}' cleanup hook threw`, error);
|
|
@@ -630,9 +669,9 @@ class DerivedIndexRunner {
|
|
|
630
669
|
return true;
|
|
631
670
|
}
|
|
632
671
|
// The owner may be another worker that never idles: leave the request where every runner looks,
|
|
633
|
-
// and notify
|
|
672
|
+
// and notify every generation sharing the stable runner lock.
|
|
634
673
|
Atomics.store(this.#shared().words, READINESS_REBUILD_REQUEST, 1);
|
|
635
|
-
this.#
|
|
674
|
+
this.#wakeBuffer.notify?.();
|
|
636
675
|
this.wake(true);
|
|
637
676
|
return true;
|
|
638
677
|
}
|
|
@@ -672,13 +711,16 @@ class DerivedIndexRunner {
|
|
|
672
711
|
* The lock is taken without an unlock callback. rocksdb-js queues such a callback as a
|
|
673
712
|
* thread-safe function of the caller's env, and on Node 22 a callback left behind by a worker that
|
|
674
713
|
* was terminated aborts the process when another thread unlocks (HarperFast/rocksdb-js, pending).
|
|
675
|
-
* A successor is woken by the releasing owner's `notify()` on the
|
|
676
|
-
* tolerates a dead listener's env — and by the retry timer below.
|
|
714
|
+
* A successor is woken by the releasing owner's `notify()` on the stable-id wake buffer — which
|
|
715
|
+
* tolerates a dead listener's env — and by the retry timer below. Registrations without a
|
|
716
|
+
* generation-specific readiness id keep using the readiness buffer itself.
|
|
677
717
|
*/
|
|
678
718
|
#acquire() {
|
|
679
719
|
// Commit wakes are frequent; neither a parked nor a backing-off runner may re-probe on each one.
|
|
680
720
|
if (this.#waitingForLock || this.#lockBackoff)
|
|
681
721
|
return;
|
|
722
|
+
if (this.#registration.isCurrent && !this.#registration.isCurrent())
|
|
723
|
+
return;
|
|
682
724
|
if (this.#releasing) {
|
|
683
725
|
this.#releasing.then(() => this.wake(true));
|
|
684
726
|
return;
|
|
@@ -729,6 +771,10 @@ class DerivedIndexRunner {
|
|
|
729
771
|
try {
|
|
730
772
|
if (!reviving)
|
|
731
773
|
this.#ownerEpoch = this.#mintEpoch();
|
|
774
|
+
// A worker that could not construct this generation may have published a setup-only
|
|
775
|
+
// failure before this healthy backend acquired the stable runner lock. Ownership is
|
|
776
|
+
// stronger evidence: clear only that sentinel, never a runner-published unavailable state.
|
|
777
|
+
Atomics.compareExchange(this.#shared().words, READINESS_STATE, READINESS_BACKEND_FAILED, READINESS_STATES.indexOf('unknown'));
|
|
732
778
|
this.status = { state: 'running', ownerEpoch: this.#ownerEpoch };
|
|
733
779
|
const condemned = this.#readCondemnation();
|
|
734
780
|
const shared = this.getReadiness();
|
|
@@ -849,6 +895,10 @@ class DerivedIndexRunner {
|
|
|
849
895
|
#drain() {
|
|
850
896
|
if (!this.#owned || this.#stopped || this.#rebuilding)
|
|
851
897
|
return;
|
|
898
|
+
if (this.#registration.isCurrent && !this.#registration.isCurrent()) {
|
|
899
|
+
this.#release();
|
|
900
|
+
return;
|
|
901
|
+
}
|
|
852
902
|
if (this.#canRebuild() && this.#takeSharedRebuildRequest()) {
|
|
853
903
|
if (this.#rebuildTimer) {
|
|
854
904
|
clearTimeout(this.#rebuildTimer);
|
|
@@ -1844,10 +1894,10 @@ class DerivedIndexRunner {
|
|
|
1844
1894
|
logger.error(`Failed to release derived index runner '${backend.id}'`, error);
|
|
1845
1895
|
}
|
|
1846
1896
|
// A skip left standing by an absent or throwing `notify` swallows a peer's release instead.
|
|
1847
|
-
if (this.#
|
|
1897
|
+
if (this.#wakeBuffer.notify) {
|
|
1848
1898
|
this.#skipNextNotify = !this.#stopped;
|
|
1849
1899
|
try {
|
|
1850
|
-
this.#
|
|
1900
|
+
this.#wakeBuffer.notify();
|
|
1851
1901
|
}
|
|
1852
1902
|
catch (error) {
|
|
1853
1903
|
this.#skipNextNotify = false;
|
|
@@ -1884,6 +1934,11 @@ function lastOpen(collected) {
|
|
|
1884
1934
|
function readinessBuffer(logStore, backendId, callback) {
|
|
1885
1935
|
return logStore.getUserSharedBuffer(`derived-index:${backendId}:readiness`, new ArrayBuffer(exports.READINESS_BYTES), callback ? { callback } : undefined);
|
|
1886
1936
|
}
|
|
1937
|
+
function wakeBuffer(logStore, backendId, callback) {
|
|
1938
|
+
return logStore.getUserSharedBuffer(`derived-index:${backendId}:wake`, new ArrayBuffer(1), {
|
|
1939
|
+
callback,
|
|
1940
|
+
});
|
|
1941
|
+
}
|
|
1887
1942
|
function sharedViewsOf(buffer) {
|
|
1888
1943
|
return {
|
|
1889
1944
|
words: new Int32Array(buffer, 0, READINESS_WORDS),
|
|
@@ -1893,12 +1948,19 @@ function sharedViewsOf(buffer) {
|
|
|
1893
1948
|
}
|
|
1894
1949
|
const readinessViews = new WeakMap();
|
|
1895
1950
|
function readReadiness({ words, epoch }) {
|
|
1896
|
-
const
|
|
1897
|
-
const
|
|
1951
|
+
const stateIndex = Atomics.load(words, READINESS_STATE);
|
|
1952
|
+
const setupFailed = stateIndex === READINESS_BACKEND_FAILED;
|
|
1953
|
+
const retrying = stateIndex === READINESS_RETRYING;
|
|
1954
|
+
const state = setupFailed ? 'unavailable' : retrying ? 'unknown' : (READINESS_STATES[stateIndex] ?? 'unknown');
|
|
1955
|
+
const reason = setupFailed
|
|
1956
|
+
? 'backend-failed'
|
|
1957
|
+
: retrying
|
|
1958
|
+
? 'none'
|
|
1959
|
+
: (READINESS_REASONS[Atomics.load(words, READINESS_REASON)] ?? 'none');
|
|
1898
1960
|
const readiness = {
|
|
1899
1961
|
state,
|
|
1900
1962
|
ownerEpoch: Atomics.load(epoch, 0),
|
|
1901
|
-
rebuildAttempts: Atomics.load(words, READINESS_ATTEMPTS),
|
|
1963
|
+
rebuildAttempts: retrying || setupFailed ? 0 : Atomics.load(words, READINESS_ATTEMPTS),
|
|
1902
1964
|
};
|
|
1903
1965
|
if (reason !== 'none')
|
|
1904
1966
|
readiness.reason = reason;
|
|
@@ -1908,6 +1970,55 @@ function readReadiness({ words, epoch }) {
|
|
|
1908
1970
|
function readDerivedIndexReadiness(logStore, backendId) {
|
|
1909
1971
|
return readReadiness(getReadinessViews(logStore, backendId));
|
|
1910
1972
|
}
|
|
1973
|
+
/** Publish setup-time state before a backend runner exists. */
|
|
1974
|
+
function publishDerivedIndexReadiness(logStore, backendId, state, reason = 'none') {
|
|
1975
|
+
const views = getReadinessViews(logStore, backendId);
|
|
1976
|
+
if (state === 'unknown')
|
|
1977
|
+
Atomics.store(views.words, READINESS_ATTEMPTS, 0);
|
|
1978
|
+
Atomics.store(views.words, READINESS_REASON, READINESS_REASONS.indexOf(reason));
|
|
1979
|
+
Atomics.store(views.words, READINESS_STATE, READINESS_STATES.indexOf(state));
|
|
1980
|
+
}
|
|
1981
|
+
/** Publish a setup failure only while no elected runner has published a stronger state. */
|
|
1982
|
+
function publishDerivedIndexUnavailableIfUnknown(logStore, backendId) {
|
|
1983
|
+
const { words, epoch } = getReadinessViews(logStore, backendId);
|
|
1984
|
+
// RETRYING is an explicit setup retry. Epochs are monotonic, so a prior
|
|
1985
|
+
// owner must not prevent that retry from returning to an observable failure.
|
|
1986
|
+
const retryEpoch = Atomics.load(epoch, 0);
|
|
1987
|
+
if (Atomics.compareExchange(words, READINESS_STATE, READINESS_RETRYING, READINESS_BACKEND_FAILED) === READINESS_RETRYING) {
|
|
1988
|
+
// Close the same owner-election race as the unknown-state path below. A
|
|
1989
|
+
// runner that acquired this epoch owns readiness, even if its worker has
|
|
1990
|
+
// not published ready yet.
|
|
1991
|
+
if (Atomics.load(epoch, 0) !== retryEpoch) {
|
|
1992
|
+
Atomics.compareExchange(words, READINESS_STATE, READINESS_BACKEND_FAILED, READINESS_STATES.indexOf('unknown'));
|
|
1993
|
+
return false;
|
|
1994
|
+
}
|
|
1995
|
+
return true;
|
|
1996
|
+
}
|
|
1997
|
+
if (Atomics.load(epoch, 0) !== 0n)
|
|
1998
|
+
return false;
|
|
1999
|
+
const published = Atomics.compareExchange(words, READINESS_STATE, READINESS_STATES.indexOf('unknown'), READINESS_BACKEND_FAILED) ===
|
|
2000
|
+
READINESS_STATES.indexOf('unknown');
|
|
2001
|
+
if (!published)
|
|
2002
|
+
return false;
|
|
2003
|
+
// Close the race with an owner acquiring between the epoch probe and the state CAS.
|
|
2004
|
+
if (Atomics.load(epoch, 0) !== 0n) {
|
|
2005
|
+
Atomics.compareExchange(words, READINESS_STATE, READINESS_BACKEND_FAILED, READINESS_STATES.indexOf('unknown'));
|
|
2006
|
+
return false;
|
|
2007
|
+
}
|
|
2008
|
+
return true;
|
|
2009
|
+
}
|
|
2010
|
+
/** Rearm setup only while no peer has replaced the unavailable state. */
|
|
2011
|
+
function retryDerivedIndexUnavailable(logStore, backendId) {
|
|
2012
|
+
const { words } = getReadinessViews(logStore, backendId);
|
|
2013
|
+
const unavailable = READINESS_STATES.indexOf('unavailable');
|
|
2014
|
+
if (Atomics.compareExchange(words, READINESS_STATE, unavailable, READINESS_RETRYING) === unavailable)
|
|
2015
|
+
return true;
|
|
2016
|
+
return (Atomics.compareExchange(words, READINESS_STATE, READINESS_BACKEND_FAILED, READINESS_RETRYING) ===
|
|
2017
|
+
READINESS_BACKEND_FAILED);
|
|
2018
|
+
}
|
|
2019
|
+
function isUnavailableReadinessState(stateIndex) {
|
|
2020
|
+
return stateIndex === READINESS_STATES.indexOf('unavailable') || stateIndex === READINESS_BACKEND_FAILED;
|
|
2021
|
+
}
|
|
1911
2022
|
function getReadinessViews(logStore, backendId) {
|
|
1912
2023
|
let byBackend = readinessViews.get(logStore);
|
|
1913
2024
|
if (!byBackend)
|