@harperfast/harper 5.2.13 → 5.3.0-beta.1
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/agent/mcpTools.ts +1 -1
- package/agent/session.ts +25 -14
- package/bin/cliOperations.ts +58 -9
- package/bin/copyDb.ts +282 -59
- package/bin/deploySetup.ts +16 -5
- package/bin/harper.ts +1 -1
- package/bin/help.ts +4 -1
- package/bin/lite.ts +4 -1
- package/bin/restart.ts +120 -4
- package/bin/run.ts +6 -11
- package/bin/upgrade.js +7 -3
- package/bin/workloadIdentity.ts +119 -0
- package/components/Application.ts +3436 -242
- package/components/ApplicationScope.ts +8 -0
- package/components/EntryHandler.ts +59 -39
- package/components/OptionsWatcher.ts +440 -98
- package/components/RuntimeModuleTracker.ts +38 -7
- package/components/Scope.ts +56 -15
- package/components/awaitRestart.ts +84 -0
- package/components/componentLoader.ts +381 -32
- package/components/componentPreparationLock.ts +16 -5
- package/components/deploymentOperations.ts +4 -1
- package/components/deploymentRecorder.ts +9 -2
- package/components/mcp/adapters/harperHttp.ts +4 -0
- package/components/mcp/listChanged.ts +4 -0
- package/components/mcp/toolRegistry.ts +2 -0
- package/components/mcp/tools/operations.ts +9 -0
- package/components/mcp/tools/schemas/operationDescriptions.ts +2 -2
- package/components/operations.js +537 -113
- package/components/operationsValidation.js +98 -3
- package/components/packageComponent.ts +25 -1
- package/components/requestRestart.ts +11 -0
- package/components/status/ComponentStatusRegistry.ts +59 -0
- package/config/RootConfigWatcher.ts +240 -40
- package/config/configReadRetry.ts +62 -0
- package/config/configUtils.ts +357 -48
- package/config/harperConfigEnvVars.ts +170 -27
- package/config/parseConfigFile.ts +34 -0
- package/config/readConfigFileSync.ts +44 -0
- package/config/watcherArming.ts +59 -0
- package/config-root.schema.json +33 -0
- package/dataLayer/blobBackup.ts +160 -50
- package/dataLayer/delete.ts +6 -1
- package/dataLayer/harperBridge/ResourceBridge.ts +80 -10
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js +3 -1
- package/dataLayer/hdbInfoController.ts +34 -1
- package/dataLayer/insert.ts +44 -1
- package/dataLayer/rocksdbBackup.ts +53 -10
- package/dataLayer/schema.ts +11 -1
- package/dataLayer/schemaDescribe.ts +8 -1
- package/dist/agent/mcpTools.js +1 -1
- package/dist/agent/mcpTools.js.map +1 -1
- package/dist/agent/session.d.ts +22 -0
- package/dist/agent/session.js +26 -15
- package/dist/agent/session.js.map +1 -1
- package/dist/bin/cliOperations.js +61 -9
- package/dist/bin/cliOperations.js.map +1 -1
- package/dist/bin/copyDb.d.ts +12 -1
- package/dist/bin/copyDb.js +248 -60
- package/dist/bin/copyDb.js.map +1 -1
- package/dist/bin/deploySetup.d.ts +2 -0
- package/dist/bin/deploySetup.js +11 -3
- package/dist/bin/deploySetup.js.map +1 -1
- package/dist/bin/harper.js +1 -1
- package/dist/bin/harper.js.map +1 -1
- package/dist/bin/help.js +4 -1
- package/dist/bin/help.js.map +1 -1
- package/dist/bin/lite.js +4 -1
- package/dist/bin/lite.js.map +1 -1
- package/dist/bin/restart.js +91 -6
- package/dist/bin/restart.js.map +1 -1
- package/dist/bin/run.js +4 -10
- package/dist/bin/run.js.map +1 -1
- package/dist/bin/upgrade.js +4 -3
- package/dist/bin/upgrade.js.map +1 -1
- package/dist/bin/workloadIdentity.d.ts +18 -0
- package/dist/bin/workloadIdentity.js +100 -0
- package/dist/bin/workloadIdentity.js.map +1 -0
- package/dist/components/Application.d.ts +235 -17
- package/dist/components/Application.js +3038 -238
- package/dist/components/Application.js.map +1 -1
- package/dist/components/ApplicationScope.d.ts +8 -0
- package/dist/components/ApplicationScope.js +7 -0
- package/dist/components/ApplicationScope.js.map +1 -1
- package/dist/components/EntryHandler.js +26 -10
- package/dist/components/EntryHandler.js.map +1 -1
- package/dist/components/OptionsWatcher.d.ts +4 -0
- package/dist/components/OptionsWatcher.js +440 -99
- package/dist/components/OptionsWatcher.js.map +1 -1
- package/dist/components/RuntimeModuleTracker.js +40 -6
- package/dist/components/RuntimeModuleTracker.js.map +1 -1
- package/dist/components/Scope.js +52 -13
- package/dist/components/Scope.js.map +1 -1
- package/dist/components/awaitRestart.d.ts +33 -0
- package/dist/components/awaitRestart.js +61 -0
- package/dist/components/awaitRestart.js.map +1 -0
- package/dist/components/componentLoader.d.ts +38 -1
- package/dist/components/componentLoader.js +313 -24
- package/dist/components/componentLoader.js.map +1 -1
- package/dist/components/componentPreparationLock.d.ts +5 -0
- package/dist/components/componentPreparationLock.js +14 -6
- package/dist/components/componentPreparationLock.js.map +1 -1
- package/dist/components/deploymentOperations.js +4 -1
- package/dist/components/deploymentOperations.js.map +1 -1
- package/dist/components/deploymentRecorder.d.ts +4 -2
- package/dist/components/deploymentRecorder.js +1 -0
- package/dist/components/deploymentRecorder.js.map +1 -1
- package/dist/components/mcp/adapters/harperHttp.js +4 -0
- package/dist/components/mcp/adapters/harperHttp.js.map +1 -1
- package/dist/components/mcp/listChanged.js +5 -0
- package/dist/components/mcp/listChanged.js.map +1 -1
- package/dist/components/mcp/toolRegistry.d.ts +1 -0
- package/dist/components/mcp/toolRegistry.js.map +1 -1
- package/dist/components/mcp/tools/operations.d.ts +5 -0
- package/dist/components/mcp/tools/operations.js +9 -0
- package/dist/components/mcp/tools/operations.js.map +1 -1
- package/dist/components/mcp/tools/schemas/operationDescriptions.js +2 -2
- package/dist/components/mcp/tools/schemas/operationDescriptions.js.map +1 -1
- package/dist/components/operations.d.ts +28 -0
- package/dist/components/operations.js +476 -113
- package/dist/components/operations.js.map +1 -1
- package/dist/components/operationsValidation.js +97 -3
- package/dist/components/operationsValidation.js.map +1 -1
- package/dist/components/packageComponent.js +24 -0
- package/dist/components/packageComponent.js.map +1 -1
- package/dist/components/requestRestart.d.ts +1 -0
- package/dist/components/requestRestart.js +7 -0
- package/dist/components/requestRestart.js.map +1 -1
- package/dist/components/status/ComponentStatusRegistry.d.ts +0 -4
- package/dist/components/status/ComponentStatusRegistry.js +63 -0
- package/dist/components/status/ComponentStatusRegistry.js.map +1 -1
- package/dist/config/RootConfigWatcher.d.ts +9 -1
- package/dist/config/RootConfigWatcher.js +228 -37
- package/dist/config/RootConfigWatcher.js.map +1 -1
- package/dist/config/configReadRetry.d.ts +8 -0
- package/dist/config/configReadRetry.js +62 -0
- package/dist/config/configReadRetry.js.map +1 -0
- package/dist/config/configUtils.d.ts +11 -2
- package/dist/config/configUtils.js +304 -47
- package/dist/config/configUtils.js.map +1 -1
- package/dist/config/harperConfigEnvVars.d.ts +16 -0
- package/dist/config/harperConfigEnvVars.js +162 -25
- package/dist/config/harperConfigEnvVars.js.map +1 -1
- package/dist/config/parseConfigFile.d.ts +4 -0
- package/dist/config/parseConfigFile.js +35 -0
- package/dist/config/parseConfigFile.js.map +1 -0
- package/dist/config/readConfigFileSync.d.ts +1 -0
- package/dist/config/readConfigFileSync.js +47 -0
- package/dist/config/readConfigFileSync.js.map +1 -0
- package/dist/config/watcherArming.d.ts +15 -0
- package/dist/config/watcherArming.js +59 -0
- package/dist/config/watcherArming.js.map +1 -0
- package/dist/dataLayer/blobBackup.d.ts +49 -20
- package/dist/dataLayer/blobBackup.js +139 -50
- package/dist/dataLayer/blobBackup.js.map +1 -1
- package/dist/dataLayer/delete.js +1 -1
- package/dist/dataLayer/delete.js.map +1 -1
- package/dist/dataLayer/harperBridge/ResourceBridge.d.ts +14 -1
- package/dist/dataLayer/harperBridge/ResourceBridge.js +72 -12
- package/dist/dataLayer/harperBridge/ResourceBridge.js.map +1 -1
- package/dist/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.d.ts +3 -1
- package/dist/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js +3 -1
- package/dist/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js.map +1 -1
- package/dist/dataLayer/hdbInfoController.d.ts +10 -0
- package/dist/dataLayer/hdbInfoController.js +30 -1
- package/dist/dataLayer/hdbInfoController.js.map +1 -1
- package/dist/dataLayer/insert.d.ts +9 -1
- package/dist/dataLayer/insert.js +30 -0
- package/dist/dataLayer/insert.js.map +1 -1
- package/dist/dataLayer/rocksdbBackup.d.ts +2 -2
- package/dist/dataLayer/rocksdbBackup.js +45 -8
- package/dist/dataLayer/rocksdbBackup.js.map +1 -1
- package/dist/dataLayer/schema.js +8 -0
- package/dist/dataLayer/schema.js.map +1 -1
- package/dist/dataLayer/schemaDescribe.js +8 -1
- package/dist/dataLayer/schemaDescribe.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/json/systemSchema.json +55 -0
- package/dist/resources/DatabaseTransaction.d.ts +77 -0
- package/dist/resources/DatabaseTransaction.js +586 -54
- package/dist/resources/DatabaseTransaction.js.map +1 -1
- package/dist/resources/LMDBTransaction.d.ts +2 -1
- package/dist/resources/LMDBTransaction.js +43 -6
- package/dist/resources/LMDBTransaction.js.map +1 -1
- package/dist/resources/PrimaryRocksDatabase.d.ts +1 -0
- package/dist/resources/PrimaryRocksDatabase.js +49 -5
- package/dist/resources/PrimaryRocksDatabase.js.map +1 -1
- package/dist/resources/RecordEncoder.d.ts +20 -0
- package/dist/resources/RecordEncoder.js +110 -9
- package/dist/resources/RecordEncoder.js.map +1 -1
- package/dist/resources/RequestTarget.d.ts +2 -0
- package/dist/resources/RequestTarget.js.map +1 -1
- package/dist/resources/Resource.js +117 -24
- package/dist/resources/Resource.js.map +1 -1
- package/dist/resources/ResourceInterface.d.ts +28 -1
- package/dist/resources/ResourceInterface.js.map +1 -1
- package/dist/resources/RocksIndexStore.d.ts +6 -1
- package/dist/resources/RocksIndexStore.js +24 -9
- package/dist/resources/RocksIndexStore.js.map +1 -1
- package/dist/resources/RocksTransactionLogStore.d.ts +24 -1
- package/dist/resources/RocksTransactionLogStore.js +160 -49
- package/dist/resources/RocksTransactionLogStore.js.map +1 -1
- package/dist/resources/Table.d.ts +165 -10
- package/dist/resources/Table.js +1805 -303
- package/dist/resources/Table.js.map +1 -1
- package/dist/resources/analytics/write.js +10 -3
- package/dist/resources/analytics/write.js.map +1 -1
- package/dist/resources/auditStore.d.ts +181 -2
- package/dist/resources/auditStore.js +640 -29
- package/dist/resources/auditStore.js.map +1 -1
- package/dist/resources/blob.d.ts +129 -9
- package/dist/resources/blob.js +992 -114
- package/dist/resources/blob.js.map +1 -1
- package/dist/resources/branchDatabase.d.ts +48 -0
- package/dist/resources/branchDatabase.js +892 -0
- package/dist/resources/branchDatabase.js.map +1 -0
- package/dist/resources/crdt.js +50 -12
- package/dist/resources/crdt.js.map +1 -1
- package/dist/resources/dataLoader.js +3 -4
- package/dist/resources/dataLoader.js.map +1 -1
- package/dist/resources/databases.d.ts +157 -14
- package/dist/resources/databases.js +1462 -325
- package/dist/resources/databases.js.map +1 -1
- package/dist/resources/defineTable.d.ts +10 -2
- package/dist/resources/defineTable.js +9 -1
- package/dist/resources/defineTable.js.map +1 -1
- package/dist/resources/derivedIndexRegistry.d.ts +5 -0
- package/dist/resources/derivedIndexRegistry.js +68 -0
- package/dist/resources/derivedIndexRegistry.js.map +1 -0
- package/dist/resources/derivedIndexRuntime.d.ts +215 -0
- package/dist/resources/derivedIndexRuntime.js +2027 -0
- package/dist/resources/derivedIndexRuntime.js.map +1 -0
- package/dist/resources/graphql.d.ts +1 -1
- package/dist/resources/graphql.js +52 -16
- package/dist/resources/graphql.js.map +1 -1
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.d.ts +103 -9
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js +854 -41
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js.map +1 -1
- package/dist/resources/indexes/hnswDerivedIndex.d.ts +67 -0
- package/dist/resources/indexes/hnswDerivedIndex.js +464 -0
- package/dist/resources/indexes/hnswDerivedIndex.js.map +1 -0
- package/dist/resources/indexes/hnswPlaneBinding.d.ts +65 -0
- package/dist/resources/indexes/hnswPlaneBinding.js +91 -0
- package/dist/resources/indexes/hnswPlaneBinding.js.map +1 -0
- package/dist/resources/longLivedTransactions.d.ts +71 -0
- package/dist/resources/longLivedTransactions.js +358 -0
- package/dist/resources/longLivedTransactions.js.map +1 -0
- package/dist/resources/models/backendRegistry.d.ts +26 -0
- package/dist/resources/models/backendRegistry.js +60 -2
- package/dist/resources/models/backendRegistry.js.map +1 -1
- package/dist/resources/models/bootstrap.d.ts +33 -1
- package/dist/resources/models/bootstrap.js +416 -31
- package/dist/resources/models/bootstrap.js.map +1 -1
- package/dist/resources/nodeIdMapping.d.ts +5 -0
- package/dist/resources/nodeIdMapping.js +49 -0
- package/dist/resources/nodeIdMapping.js.map +1 -1
- package/dist/resources/recordLock.d.ts +123 -0
- package/dist/resources/recordLock.js +315 -0
- package/dist/resources/recordLock.js.map +1 -0
- package/dist/resources/recordLockCoordinator.d.ts +557 -0
- package/dist/resources/recordLockCoordinator.js +2565 -0
- package/dist/resources/recordLockCoordinator.js.map +1 -0
- package/dist/resources/replayLogs.d.ts +14 -1
- package/dist/resources/replayLogs.js +157 -24
- package/dist/resources/replayLogs.js.map +1 -1
- package/dist/resources/replayLogsGuards.d.ts +94 -7
- package/dist/resources/replayLogsGuards.js +111 -7
- package/dist/resources/replayLogsGuards.js.map +1 -1
- package/dist/resources/replicatedApplyFailure.d.ts +16 -0
- package/dist/resources/replicatedApplyFailure.js +63 -0
- package/dist/resources/replicatedApplyFailure.js.map +1 -0
- package/dist/resources/scheduler/scheduler.js +3 -3
- package/dist/resources/scheduler/scheduler.js.map +1 -1
- package/dist/resources/search.d.ts +10 -4
- package/dist/resources/search.js +283 -37
- package/dist/resources/search.js.map +1 -1
- package/dist/resources/tracked.d.ts +5 -1
- package/dist/resources/tracked.js +74 -23
- package/dist/resources/tracked.js.map +1 -1
- package/dist/resources/transactionBroadcast.d.ts +1 -1
- package/dist/resources/transactionBroadcast.js +2 -2
- package/dist/resources/transactionBroadcast.js.map +1 -1
- package/dist/security/auth.js +61 -30
- package/dist/security/auth.js.map +1 -1
- package/dist/security/authn/oidc/claims.d.ts +22 -0
- package/dist/security/authn/oidc/claims.js +71 -0
- package/dist/security/authn/oidc/claims.js.map +1 -0
- package/dist/security/authn/oidc/identityToken.d.ts +27 -0
- package/dist/security/authn/oidc/identityToken.js +111 -0
- package/dist/security/authn/oidc/identityToken.js.map +1 -0
- package/dist/security/authn/oidc/jwks.d.ts +25 -0
- package/dist/security/authn/oidc/jwks.js +261 -0
- package/dist/security/authn/oidc/jwks.js.map +1 -0
- package/dist/security/authn/oidc/providers/generic.d.ts +13 -0
- package/dist/security/authn/oidc/providers/generic.js +34 -0
- package/dist/security/authn/oidc/providers/generic.js.map +1 -0
- package/dist/security/authn/oidc/providers/githubActions.d.ts +11 -0
- package/dist/security/authn/oidc/providers/githubActions.js +129 -0
- package/dist/security/authn/oidc/providers/githubActions.js.map +1 -0
- package/dist/security/authn/oidc/providers/index.d.ts +37 -0
- package/dist/security/authn/oidc/providers/index.js +24 -0
- package/dist/security/authn/oidc/providers/index.js.map +1 -0
- package/dist/security/authn/oidc/tokenExchange.d.ts +12 -0
- package/dist/security/authn/oidc/tokenExchange.js +306 -0
- package/dist/security/authn/oidc/tokenExchange.js.map +1 -0
- package/dist/security/authn/oidc/trustPolicyOperations.d.ts +49 -0
- package/dist/security/authn/oidc/trustPolicyOperations.js +358 -0
- package/dist/security/authn/oidc/trustPolicyOperations.js.map +1 -0
- package/dist/security/authn/oidc/types.d.ts +38 -0
- package/dist/security/authn/oidc/types.js +6 -0
- package/dist/security/authn/oidc/types.js.map +1 -0
- package/dist/security/certificateVerification/index.js +40 -11
- package/dist/security/certificateVerification/index.js.map +1 -1
- package/dist/security/certificateVerification/trustedIssuers.d.ts +24 -0
- package/dist/security/certificateVerification/trustedIssuers.js +79 -0
- package/dist/security/certificateVerification/trustedIssuers.js.map +1 -0
- package/dist/security/certificateVerification/types.d.ts +1 -0
- package/dist/security/credentialProvenance.d.ts +35 -0
- package/dist/security/credentialProvenance.js +51 -0
- package/dist/security/credentialProvenance.js.map +1 -0
- package/dist/security/credentialRejection.d.ts +4 -0
- package/dist/security/credentialRejection.js +24 -0
- package/dist/security/credentialRejection.js.map +1 -0
- package/dist/security/deferredAuthentication.d.ts +36 -0
- package/dist/security/deferredAuthentication.js +70 -0
- package/dist/security/deferredAuthentication.js.map +1 -0
- package/dist/security/impersonation.d.ts +21 -0
- package/dist/security/impersonation.js +108 -9
- package/dist/security/impersonation.js.map +1 -1
- package/dist/security/jsLoader.d.ts +6 -0
- package/dist/security/jsLoader.js +77 -15
- package/dist/security/jsLoader.js.map +1 -1
- package/dist/security/keys.js +301 -71
- package/dist/security/keys.js.map +1 -1
- package/dist/security/operationScope.d.ts +21 -0
- package/dist/security/operationScope.js +36 -0
- package/dist/security/operationScope.js.map +1 -0
- package/dist/security/permissionsTranslator.js +21 -0
- package/dist/security/permissionsTranslator.js.map +1 -1
- package/dist/security/tokenAuthentication.d.ts +19 -1
- package/dist/security/tokenAuthentication.js +191 -10
- package/dist/security/tokenAuthentication.js.map +1 -1
- package/dist/security/user.js +4 -3
- package/dist/security/user.js.map +1 -1
- package/dist/server/DurableSubscriptionsSession.d.ts +2 -2
- package/dist/server/DurableSubscriptionsSession.js +67 -10
- package/dist/server/DurableSubscriptionsSession.js.map +1 -1
- package/dist/server/REST.js +106 -2
- package/dist/server/REST.js.map +1 -1
- package/dist/server/graphqlQuerying.js +4 -0
- package/dist/server/graphqlQuerying.js.map +1 -1
- package/dist/server/http.d.ts +16 -1
- package/dist/server/http.js +122 -17
- package/dist/server/http.js.map +1 -1
- package/dist/server/itc/serverHandlers.js +8 -1
- package/dist/server/itc/serverHandlers.js.map +1 -1
- package/dist/server/jobs/jobProcess.js +6 -2
- package/dist/server/jobs/jobProcess.js.map +1 -1
- package/dist/server/jobs/jobs.js +4 -1
- package/dist/server/jobs/jobs.js.map +1 -1
- package/dist/server/liveSubscriptionAuth.d.ts +26 -4
- package/dist/server/liveSubscriptionAuth.js +105 -39
- package/dist/server/liveSubscriptionAuth.js.map +1 -1
- package/dist/server/loadRootComponents.js +49 -10
- package/dist/server/loadRootComponents.js.map +1 -1
- package/dist/server/mqtt.d.ts +2 -0
- package/dist/server/mqtt.js +165 -30
- package/dist/server/mqtt.js.map +1 -1
- package/dist/server/nodeName.d.ts +2 -0
- package/dist/server/nodeName.js +107 -23
- package/dist/server/nodeName.js.map +1 -1
- package/dist/server/serverHelpers/Headers.d.ts +27 -0
- package/dist/server/serverHelpers/Headers.js +145 -1
- package/dist/server/serverHelpers/Headers.js.map +1 -1
- package/dist/server/serverHelpers/NodeAdapterResponse.d.ts +48 -0
- package/dist/server/serverHelpers/NodeAdapterResponse.js +220 -0
- package/dist/server/serverHelpers/NodeAdapterResponse.js.map +1 -0
- package/dist/server/serverHelpers/Request.d.ts +5 -10
- package/dist/server/serverHelpers/Request.js +38 -136
- package/dist/server/serverHelpers/Request.js.map +1 -1
- package/dist/server/serverHelpers/contentTypes.d.ts +11 -0
- package/dist/server/serverHelpers/contentTypes.js +221 -40
- package/dist/server/serverHelpers/contentTypes.js.map +1 -1
- package/dist/server/serverHelpers/deployValidationState.d.ts +3 -0
- package/dist/server/serverHelpers/deployValidationState.js +9 -19
- package/dist/server/serverHelpers/deployValidationState.js.map +1 -1
- package/dist/server/serverHelpers/operationAuthorizationState.d.ts +12 -0
- package/dist/server/serverHelpers/operationAuthorizationState.js +24 -2
- package/dist/server/serverHelpers/operationAuthorizationState.js.map +1 -1
- package/dist/server/serverHelpers/registeredOperations.d.ts +5 -4
- package/dist/server/serverHelpers/registeredOperations.js +74 -21
- package/dist/server/serverHelpers/registeredOperations.js.map +1 -1
- package/dist/server/serverHelpers/requestSanitization.d.ts +11 -0
- package/dist/server/serverHelpers/requestSanitization.js +20 -0
- package/dist/server/serverHelpers/requestSanitization.js.map +1 -0
- package/dist/server/serverHelpers/serverHandlers.js +6 -3
- package/dist/server/serverHelpers/serverHandlers.js.map +1 -1
- package/dist/server/serverHelpers/serverUtilities.d.ts +18 -0
- package/dist/server/serverHelpers/serverUtilities.js +178 -29
- package/dist/server/serverHelpers/serverUtilities.js.map +1 -1
- package/dist/server/serverHelpers/sharedMessageEncoding.d.ts +67 -0
- package/dist/server/serverHelpers/sharedMessageEncoding.js +280 -0
- package/dist/server/serverHelpers/sharedMessageEncoding.js.map +1 -0
- package/dist/server/serverHelpers/uwsServer.js +19 -1
- package/dist/server/serverHelpers/uwsServer.js.map +1 -1
- package/dist/server/static.js +24 -28
- package/dist/server/static.js.map +1 -1
- package/dist/server/storageReclamation.d.ts +5 -0
- package/dist/server/storageReclamation.js +17 -1
- package/dist/server/storageReclamation.js.map +1 -1
- package/dist/server/threads/isolatedApplications.d.ts +47 -0
- package/dist/server/threads/isolatedApplications.js +171 -0
- package/dist/server/threads/isolatedApplications.js.map +1 -0
- package/dist/server/threads/itc.d.ts +7 -2
- package/dist/server/threads/itc.js +5 -1
- package/dist/server/threads/itc.js.map +1 -1
- package/dist/server/threads/logRotationTransport.d.ts +1 -0
- package/dist/server/threads/logRotationTransport.js +33 -0
- package/dist/server/threads/logRotationTransport.js.map +1 -0
- package/dist/server/threads/manageThreads.d.ts +83 -3
- package/dist/server/threads/manageThreads.js +769 -75
- package/dist/server/threads/manageThreads.js.map +1 -1
- package/dist/server/threads/socketRouter.d.ts +1 -0
- package/dist/server/threads/socketRouter.js +277 -31
- package/dist/server/threads/socketRouter.js.map +1 -1
- package/dist/server/threads/threadHeapMemory.d.ts +2 -0
- package/dist/server/threads/threadHeapMemory.js +31 -0
- package/dist/server/threads/threadHeapMemory.js.map +1 -0
- package/dist/server/threads/threadServer.js +76 -22
- package/dist/server/threads/threadServer.js.map +1 -1
- package/dist/sqlEngine/config.d.ts +1 -3
- package/dist/sqlEngine/config.js +19 -16
- package/dist/sqlEngine/config.js.map +1 -1
- package/dist/sqlTranslator/index.d.ts +1 -1
- package/dist/sqlTranslator/index.js +30 -7
- package/dist/sqlTranslator/index.js.map +1 -1
- package/dist/upgrade/directives/5-3-0.d.ts +7 -0
- package/dist/upgrade/directives/5-3-0.js +148 -0
- package/dist/upgrade/directives/5-3-0.js.map +1 -0
- package/dist/upgrade/directives/directivesController.js +2 -1
- package/dist/upgrade/directives/directivesController.js.map +1 -1
- package/dist/utility/OperationFunctionCaller.js +2 -1
- package/dist/utility/OperationFunctionCaller.js.map +1 -1
- package/dist/utility/common_utils.d.ts +16 -0
- package/dist/utility/common_utils.js +32 -6
- package/dist/utility/common_utils.js.map +1 -1
- package/dist/utility/componentNames.d.ts +8 -0
- package/dist/utility/componentNames.js +12 -1
- package/dist/utility/componentNames.js.map +1 -1
- package/dist/utility/environment/environmentManager.js +3 -6
- package/dist/utility/environment/environmentManager.js.map +1 -1
- package/dist/utility/environment/systemInformation.d.ts +1 -0
- package/dist/utility/environment/systemInformation.js +1 -0
- package/dist/utility/environment/systemInformation.js.map +1 -1
- package/dist/utility/errors/commonErrors.d.ts +2 -0
- package/dist/utility/errors/commonErrors.js +2 -0
- package/dist/utility/errors/commonErrors.js.map +1 -1
- package/dist/utility/errors/hdbError.d.ts +33 -0
- package/dist/utility/errors/hdbError.js +58 -1
- package/dist/utility/errors/hdbError.js.map +1 -1
- package/dist/utility/globalSchema.d.ts +18 -0
- package/dist/utility/hdbTerms.d.ts +18 -0
- package/dist/utility/hdbTerms.js +20 -2
- package/dist/utility/hdbTerms.js.map +1 -1
- package/dist/utility/logging/harper_logger.d.ts +2 -0
- package/dist/utility/logging/harper_logger.js +286 -30
- package/dist/utility/logging/harper_logger.js.map +1 -1
- package/dist/utility/logging/logGenerationCoordinator.d.ts +35 -0
- package/dist/utility/logging/logGenerationCoordinator.js +184 -0
- package/dist/utility/logging/logGenerationCoordinator.js.map +1 -0
- package/dist/utility/logging/logRotation.d.ts +46 -0
- package/dist/utility/logging/logRotation.js +365 -0
- package/dist/utility/logging/logRotation.js.map +1 -0
- package/dist/utility/logging/logRotator.d.ts +1 -1
- package/dist/utility/logging/logRotator.js +192 -85
- package/dist/utility/logging/logRotator.js.map +1 -1
- package/dist/utility/nodeIdentity.d.ts +9 -0
- package/dist/utility/nodeIdentity.js +58 -0
- package/dist/utility/nodeIdentity.js.map +1 -0
- package/dist/utility/npmUtilities.js +11 -7
- package/dist/utility/npmUtilities.js.map +1 -1
- package/dist/utility/operationPermissions.d.ts +3 -1
- package/dist/utility/operationPermissions.js +16 -1
- package/dist/utility/operationPermissions.js.map +1 -1
- package/dist/utility/operation_authorization.d.ts +10 -7
- package/dist/utility/operation_authorization.js +212 -41
- package/dist/utility/operation_authorization.js.map +1 -1
- package/dist/utility/watchPath.d.ts +29 -0
- package/dist/utility/watchPath.js +68 -0
- package/dist/utility/watchPath.js.map +1 -0
- package/dist/utility/watcherFallback.d.ts +41 -0
- package/dist/utility/watcherFallback.js +153 -0
- package/dist/utility/watcherFallback.js.map +1 -1
- package/dist/validation/configValidator.d.ts +12 -0
- package/dist/validation/configValidator.js +205 -75
- package/dist/validation/configValidator.js.map +1 -1
- package/dist/validation/installValidator.js +12 -0
- package/dist/validation/installValidator.js.map +1 -1
- package/dist/validation/validationWrapper.d.ts +11 -0
- package/dist/validation/validationWrapper.js +16 -3
- package/dist/validation/validationWrapper.js.map +1 -1
- package/index.ts +8 -0
- package/json/systemSchema.json +55 -0
- package/npm-shrinkwrap.json +286 -194
- package/package.json +15 -7
- package/resources/DESIGN.md +219 -52
- package/resources/DatabaseTransaction.ts +657 -52
- package/resources/LMDBTransaction.ts +46 -6
- package/resources/PrimaryRocksDatabase.ts +46 -7
- package/resources/RecordEncoder.ts +124 -9
- package/resources/RequestTarget.ts +2 -0
- package/resources/Resource.ts +114 -22
- package/resources/ResourceInterface.ts +31 -0
- package/resources/RocksIndexStore.ts +30 -9
- package/resources/RocksTransactionLogStore.ts +188 -51
- package/resources/Table.ts +1960 -301
- package/resources/analytics/write.ts +10 -3
- package/resources/auditStore.ts +647 -32
- package/resources/blob.ts +1029 -110
- package/resources/branchDatabase.ts +941 -0
- package/resources/crdt.ts +76 -12
- package/resources/dataLoader.ts +3 -4
- package/resources/databases.ts +1584 -320
- package/resources/defineTable.ts +18 -2
- package/resources/derivedIndexRegistry.ts +56 -0
- package/resources/derivedIndexRuntime.ts +2292 -0
- package/resources/graphql.ts +72 -17
- package/resources/indexes/HierarchicalNavigableSmallWorld.ts +911 -48
- package/resources/indexes/hnswDerivedIndex.ts +531 -0
- package/resources/indexes/hnswPlaneBinding.ts +174 -0
- package/resources/longLivedTransactions.ts +360 -0
- package/resources/models/backendRegistry.ts +84 -2
- package/resources/models/bootstrap.ts +473 -28
- package/resources/nodeIdMapping.ts +50 -0
- package/resources/recordLock.ts +419 -0
- package/resources/recordLockCoordinator.ts +3043 -0
- package/resources/replayLogs.ts +152 -26
- package/resources/replayLogsGuards.ts +171 -8
- package/resources/replicatedApplyFailure.ts +77 -0
- package/resources/scheduler/scheduler.ts +4 -4
- package/resources/search.ts +288 -46
- package/resources/tracked.ts +73 -22
- package/resources/transactionBroadcast.ts +3 -3
- package/security/auth.ts +68 -29
- package/security/authn/oidc/claims.ts +72 -0
- package/security/authn/oidc/identityToken.ts +129 -0
- package/security/authn/oidc/jwks.ts +260 -0
- package/security/authn/oidc/providers/generic.ts +40 -0
- package/security/authn/oidc/providers/githubActions.ts +137 -0
- package/security/authn/oidc/providers/index.ts +52 -0
- package/security/authn/oidc/tokenExchange.ts +300 -0
- package/security/authn/oidc/trustPolicyOperations.ts +343 -0
- package/security/authn/oidc/types.ts +41 -0
- package/security/certificateVerification/index.ts +54 -13
- package/security/certificateVerification/trustedIssuers.ts +76 -0
- package/security/certificateVerification/types.ts +1 -0
- package/security/credentialProvenance.ts +47 -0
- package/security/credentialRejection.ts +22 -0
- package/security/deferredAuthentication.ts +71 -0
- package/security/impersonation.ts +117 -12
- package/security/jsLoader.ts +83 -18
- package/security/keys.ts +298 -72
- package/security/operationScope.ts +33 -0
- package/security/permissionsTranslator.js +23 -0
- package/security/tokenAuthentication.ts +233 -12
- package/security/user.ts +4 -3
- package/server/DESIGN.md +194 -16
- package/server/DurableSubscriptionsSession.ts +71 -11
- package/server/REST.ts +115 -4
- package/server/graphqlQuerying.ts +4 -0
- package/server/http.ts +133 -20
- package/server/itc/serverHandlers.js +8 -1
- package/server/jobs/jobProcess.ts +8 -2
- package/server/jobs/jobs.ts +4 -1
- package/server/liveSubscriptionAuth.ts +129 -46
- package/server/loadRootComponents.js +50 -8
- package/server/mqtt.ts +179 -38
- package/server/nodeName.ts +103 -21
- package/server/serverHelpers/Headers.ts +135 -0
- package/server/serverHelpers/NodeAdapterResponse.ts +221 -0
- package/server/serverHelpers/Request.ts +33 -131
- package/server/serverHelpers/contentTypes.ts +217 -36
- package/server/serverHelpers/deployValidationState.ts +24 -13
- package/server/serverHelpers/operationAuthorizationState.ts +34 -3
- package/server/serverHelpers/registeredOperations.ts +79 -22
- package/server/serverHelpers/requestSanitization.ts +15 -0
- package/server/serverHelpers/serverHandlers.js +6 -3
- package/server/serverHelpers/serverUtilities.ts +232 -40
- package/server/serverHelpers/sharedMessageEncoding.ts +307 -0
- package/server/serverHelpers/uwsServer.ts +17 -2
- package/server/static.ts +23 -29
- package/server/storageReclamation.ts +15 -2
- package/server/threads/isolatedApplications.ts +157 -0
- package/server/threads/itc.js +11 -1
- package/server/threads/logRotationTransport.ts +40 -0
- package/server/threads/manageThreads.js +771 -66
- package/server/threads/socketRouter.ts +291 -30
- package/server/threads/threadHeapMemory.ts +26 -0
- package/server/threads/threadServer.js +73 -22
- package/sqlTranslator/index.ts +31 -8
- package/studio/web/assets/{Chat-4RrB5134.js → Chat-D3j-1yY1.js} +1 -1
- package/studio/web/assets/{FloatingChat-omlNMDcJ.js → FloatingChat-BxJGYcfB.js} +3 -3
- package/studio/web/assets/{apiToken-Bke3wvfZ.js → apiToken-CT55oWOe.js} +1 -1
- package/studio/web/assets/{applications-DvFDYJgK.js → applications-D9Ct9_vm.js} +1 -1
- package/studio/web/assets/{cssMode-C1vRa7zh.js → cssMode-DV8H7VwA.js} +1 -1
- package/studio/web/assets/{editor-3XRWEDWX.js → editor-uatc0unt.js} +1 -1
- package/studio/web/assets/{html-CTY5tdMr.js → html-Bm6D6paN.js} +1 -1
- package/studio/web/assets/{htmlMode-CG1vSD9t.js → htmlMode-CEn7tpLG.js} +1 -1
- package/studio/web/assets/{index-Dfpeofdu.js → index-BIXW6Pu4.js} +5 -5
- package/studio/web/assets/{index.lazy-B1VOIv-t.js → index.lazy-UI7L-Vrk.js} +1 -1
- package/studio/web/assets/{javascript-CJeJzGnI.js → javascript-CJ0G3AFZ.js} +1 -1
- package/studio/web/assets/{jsonMode-CYPBwM82.js → jsonMode-DQADAYEa.js} +1 -1
- package/studio/web/assets/{languageServices-IKH4GUHl.js → languageServices-CAQJXWcI.js} +1 -1
- package/studio/web/assets/{lspLanguageFeatures-BC8_gxKG.js → lspLanguageFeatures-CCQ8P5sY.js} +1 -1
- package/studio/web/assets/{notifications-BfKBpYcq.js → notifications-BbxTU6Aw.js} +1 -1
- package/studio/web/assets/{notifications-DFbArTfC.js → notifications-Cvb3P1lB.js} +1 -1
- package/studio/web/assets/{profile-Q4-T6c-S.js → profile-Yyb7gsvL.js} +1 -1
- package/studio/web/assets/{regions-CtkV0xje.js → regions-OgjGHlU5.js} +1 -1
- package/studio/web/assets/{register-1ZZuMsiA.js → register-6qwNEOY3.js} +2 -2
- package/studio/web/assets/{setComponentFile-ZWLcWv5X.js → setComponentFile-BilDMtgB.js} +1 -1
- package/studio/web/assets/{setup-DWprJyJy.js → setup-J6qJ7OIU.js} +2 -2
- package/studio/web/assets/{status--aNm8isn.js → status-0RWGcfyD.js} +1 -1
- package/studio/web/assets/{toggleHighContrast-Cq_lt3XD.js → toggleHighContrast-BIn-vErT.js} +1 -1
- package/studio/web/assets/{tsMode-pjgytARx.js → tsMode-DgUXku4d.js} +1 -1
- package/studio/web/assets/{typescript-Cdg0mqUh.js → typescript-C9orXcsM.js} +1 -1
- package/studio/web/assets/{useEntityRestURL-RZhaY8Rn.js → useEntityRestURL-BEoXXbUB.js} +1 -1
- package/studio/web/assets/{workers-BgoXIqQe.js → workers-JVzSDmgx.js} +1 -1
- package/studio/web/assets/{xml-BwSeDMiP.js → xml-Cq-S8S4X.js} +1 -1
- package/studio/web/assets/{yaml-DotCUG5l.js → yaml-sfoRdh1M.js} +1 -1
- package/studio/web/index.html +1 -1
- package/upgrade/directives/5-3-0.ts +132 -0
- package/upgrade/directives/directivesController.ts +2 -1
- package/utility/OperationFunctionCaller.ts +2 -1
- package/utility/common_utils.ts +30 -5
- package/utility/componentNames.ts +12 -0
- package/utility/environment/environmentManager.ts +3 -7
- package/utility/environment/systemInformation.ts +7 -0
- package/utility/errors/commonErrors.ts +4 -0
- package/utility/errors/hdbError.ts +57 -0
- package/utility/hdbTerms.ts +19 -0
- package/utility/logging/harper_logger.ts +278 -26
- package/utility/logging/logGenerationCoordinator.ts +196 -0
- package/utility/logging/logRotation.ts +367 -0
- package/utility/logging/logRotator.ts +213 -81
- package/utility/nodeIdentity.ts +45 -0
- package/utility/npmUtilities.ts +12 -8
- package/utility/operationPermissions.ts +18 -1
- package/utility/operation_authorization.ts +231 -42
- package/utility/watchPath.ts +63 -0
- package/utility/watcherFallback.ts +148 -0
- package/validation/configValidator.ts +215 -75
- package/validation/installValidator.ts +15 -0
- package/validation/validationWrapper.ts +18 -4
package/resources/replayLogs.ts
CHANGED
|
@@ -40,13 +40,36 @@ export function structuresWouldShrink(existing: any, updated: any): boolean {
|
|
|
40
40
|
return false;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
/** The total wall-clock budget (ms) a replay may spend, as configured for this process. */
|
|
44
|
+
export function replayTimeBudgetMs(): number {
|
|
45
|
+
const configuredReplayTimeout = Number(envGet(CONFIG_PARAMS.REPLICATION_REPLAYTIMEOUT));
|
|
46
|
+
return configuredReplayTimeout > 0 ? configuredReplayTimeout : REPLAY_WALL_CLOCK_LIMIT_MS;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* `electedReplayer` marks a caller that has already won a cross-thread election for this store —
|
|
51
|
+
* the branch claim (branchDatabase.ts) — and so may replay off the main thread. It also makes the
|
|
52
|
+
* replay strict: the promise settles (never hangs), and a failure to apply the tail — a commit or
|
|
53
|
+
* write error, a stall or wall-clock abort — rejects instead of quietly serving a rewound store.
|
|
54
|
+
* Undecodable entries and a torn tail stay tolerated in both modes: a crash tears the last frame of
|
|
55
|
+
* a log by construction, and end-of-log is the designed reading of it (see replayLogsGuards.ts). A
|
|
56
|
+
* **mid-log** break is different — entries behind it were acknowledged and are now quarantined — so
|
|
57
|
+
* an elected replay rejects on one rather than publish a branch as a trustworthy point-in-time copy
|
|
58
|
+
* over known lost writes; boot replay still logs it and continues (harper#2016, harper#2063).
|
|
59
|
+
*/
|
|
60
|
+
export function replayLogs(rootStore: RocksDatabase, tables: any, electedReplayer?: boolean): Promise<void> {
|
|
61
|
+
if (!isMainThread && !electedReplayer) return Promise.resolve(); // ideally we don't do it like this, but for now this is predictable
|
|
62
|
+
return new Promise((resolve, reject) => {
|
|
46
63
|
const acquired = rootStore.tryLock('replayLogs', async () => {
|
|
47
64
|
resolve();
|
|
48
65
|
});
|
|
49
|
-
if (!acquired)
|
|
66
|
+
if (!acquired) {
|
|
67
|
+
// An elected replayer is the store's sole opener, so a held lock is a protocol violation;
|
|
68
|
+
// hanging its awaited promise would wedge the branch claim in CREATING. The boot-scan
|
|
69
|
+
// caller keeps the settle-on-unlock semantics (nothing awaits it).
|
|
70
|
+
if (electedReplayer) reject(new Error(`The replay lock for ${(rootStore as any).databaseName} is already held`));
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
50
73
|
// Shed transaction-log files already older than the audit retention window before
|
|
51
74
|
// replaying. A node that crash-loops during recovery never reaches the steady-state
|
|
52
75
|
// cleanup loop, so without this its aged backlog only grows and enlarges each subsequent
|
|
@@ -75,9 +98,13 @@ export function replayLogs(rootStore: RocksDatabase, tables: any): Promise<void>
|
|
|
75
98
|
tableById.set(table.tableId, table);
|
|
76
99
|
}
|
|
77
100
|
// replay all the logs
|
|
78
|
-
let transaction: DatabaseTransaction;
|
|
101
|
+
let transaction: DatabaseTransaction | undefined;
|
|
79
102
|
let lastTimestamp = 0;
|
|
80
103
|
let writes = 0;
|
|
104
|
+
// Writes staged on the currently-open transaction, so a discard can be taken back out of `writes`.
|
|
105
|
+
let stagedWrites = 0;
|
|
106
|
+
// Records dropped because a corrupt frame truncated the transaction they belong to.
|
|
107
|
+
let discardedWrites = 0;
|
|
81
108
|
let skipped = 0;
|
|
82
109
|
// Track forward progress so a backlog of unwritable entries can't grind the boot thread
|
|
83
110
|
// forever (harper#1266). `noProgressRun` counts every entry processed without a successful
|
|
@@ -89,13 +116,33 @@ export function replayLogs(rootStore: RocksDatabase, tables: any): Promise<void>
|
|
|
89
116
|
let lastProgressTime = replayStartTime;
|
|
90
117
|
// Total wall-clock budget (ms) for replay, configurable via `replication.replayTimeout`;
|
|
91
118
|
// falls back to the 10-minute default (harper#1316).
|
|
92
|
-
const
|
|
93
|
-
|
|
119
|
+
const replayTimeoutMs = replayTimeBudgetMs();
|
|
120
|
+
// Set on the first unrecoverable failure in elected mode; rejects below instead of publishing
|
|
121
|
+
// a store the replay knows is incomplete.
|
|
122
|
+
let strictFailure: Error | undefined;
|
|
123
|
+
const strictAbort = (error: Error, staged: DatabaseTransaction | undefined): void => {
|
|
124
|
+
try {
|
|
125
|
+
staged?.abort();
|
|
126
|
+
} catch (abortError) {
|
|
127
|
+
logger.warn('Error aborting a strict replay transaction', abortError);
|
|
128
|
+
}
|
|
129
|
+
strictFailure = error;
|
|
130
|
+
};
|
|
94
131
|
const txnLog: RocksTransactionLogStore = (rootStore as any).auditStore;
|
|
95
|
-
|
|
132
|
+
const entries = txnLog.getRange({
|
|
133
|
+
startFromLastFlushed: true,
|
|
134
|
+
readUncommitted: true,
|
|
135
|
+
trackCorruptTransactions: true,
|
|
136
|
+
});
|
|
137
|
+
for (const auditRecord of entries as any) {
|
|
96
138
|
if (noProgressRun > 0 && shouldAbortStalledReplay(noProgressRun, performance.now() - lastProgressTime)) {
|
|
139
|
+
const stallDiagnostic = `Aborting transaction-log replay in ${(rootStore as any).databaseName} database: ${noProgressRun} consecutive audit entries with no successful write (${skipped} skipped as unrecoverable, ${writes} replayed so far). This backlog is making no forward progress and was blocking startup (harper#1266) — typically a peer transaction log whose values reference unresolvable shared structures (harper#1163), or a backlog for a dropped table.`;
|
|
140
|
+
if (electedReplayer) {
|
|
141
|
+
strictAbort(new Error(stallDiagnostic), transaction);
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
97
144
|
logger.fatal(
|
|
98
|
-
|
|
145
|
+
`${stallDiagnostic} Continuing boot without replaying the remainder; shed or relocate the oversized/undecodable peer transaction log(s), or re-clone this node, to recover the unreplayed data.`
|
|
99
146
|
);
|
|
100
147
|
break;
|
|
101
148
|
}
|
|
@@ -105,6 +152,7 @@ export function replayLogs(rootStore: RocksDatabase, tables: any): Promise<void>
|
|
|
105
152
|
nodeId,
|
|
106
153
|
recordId,
|
|
107
154
|
version,
|
|
155
|
+
txnLogKey,
|
|
108
156
|
residencyId,
|
|
109
157
|
expiresAt,
|
|
110
158
|
originatingOperation,
|
|
@@ -117,6 +165,11 @@ export function replayLogs(rootStore: RocksDatabase, tables: any): Promise<void>
|
|
|
117
165
|
noProgressRun++;
|
|
118
166
|
continue;
|
|
119
167
|
}
|
|
168
|
+
if (type === 'evict') {
|
|
169
|
+
noProgressRun = 0;
|
|
170
|
+
lastProgressTime = performance.now();
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
120
173
|
const Table = tableById.get(tableId);
|
|
121
174
|
if (!Table) {
|
|
122
175
|
// Entry for a table this node no longer has (dropped/foreign). Not an
|
|
@@ -165,14 +218,35 @@ export function replayLogs(rootStore: RocksDatabase, tables: any): Promise<void>
|
|
|
165
218
|
warnedReplayHappening = true;
|
|
166
219
|
console.warn('Harper was not properly shutdown, replaying transaction logs to synchronize database');
|
|
167
220
|
}
|
|
168
|
-
|
|
169
|
-
|
|
221
|
+
// Transactions are delimited by the log key — which is also what `truncatedVersions` records —
|
|
222
|
+
// and each write is replayed at its own stored record version. The two differ for a source
|
|
223
|
+
// fill, and stamping such a record at the log key would move its version forward and make a
|
|
224
|
+
// later legitimate write in between look stale (harper#2411).
|
|
225
|
+
if (lastTimestamp !== txnLogKey) {
|
|
226
|
+
const torn = entries.corruptFrameStop.truncatedVersions.has(lastTimestamp);
|
|
227
|
+
lastTimestamp = txnLogKey;
|
|
170
228
|
try {
|
|
171
|
-
// commit the last transaction since we are starting a new one
|
|
172
|
-
transaction
|
|
229
|
+
// commit the last transaction since we are starting a new one, unless a corrupt
|
|
230
|
+
// frame swallowed the rest of it — half of a source transaction must never become
|
|
231
|
+
// durable, so it is dropped whole and stays in the log for a repaired retry
|
|
232
|
+
if (torn) {
|
|
233
|
+
writes -= stagedWrites;
|
|
234
|
+
discardedWrites += stagedWrites;
|
|
235
|
+
transaction?.abort();
|
|
236
|
+
} else transaction?.directCommitSync();
|
|
173
237
|
} catch (error) {
|
|
174
|
-
|
|
238
|
+
// directCommitSync aborts and detaches its transaction on failure; no cleanup here.
|
|
239
|
+
// The torn branch already backed stagedWrites out of writes before this try, so
|
|
240
|
+
// only a failed COMMIT (never applied) needs it backed out here too — otherwise a
|
|
241
|
+
// commit failure left `writes` counting records that never actually landed.
|
|
242
|
+
if (!torn) writes -= stagedWrites;
|
|
243
|
+
if (electedReplayer) {
|
|
244
|
+
strictFailure = error;
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
logger.error(`Error ${torn ? 'discarding a torn' : 'committing'} replay transaction`, error);
|
|
175
248
|
}
|
|
249
|
+
stagedWrites = 0;
|
|
176
250
|
// Abort if replay has exceeded the total wall-clock budget even while making progress
|
|
177
251
|
// (harper#1316, facet a). shouldAbortStalledReplay resets its counters on every write,
|
|
178
252
|
// so a slow-but-progressing replay (deep out-of-order audit chain walk per entry) can
|
|
@@ -181,15 +255,18 @@ export function replayLogs(rootStore: RocksDatabase, tables: any): Promise<void>
|
|
|
181
255
|
// is not yet staged, so aborting never tears a same-version (same source-transaction)
|
|
182
256
|
// write batch in half. Re-clone to recover the unreplayed remainder.
|
|
183
257
|
if (shouldAbortSlowReplay(performance.now() - replayStartTime, replayTimeoutMs)) {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
)
|
|
187
|
-
|
|
258
|
+
const slowMessage = `Aborting transaction-log replay in ${(rootStore as any).databaseName} database: replay has exceeded the wall-clock time limit (${writes} written, ${skipped} skipped). The transaction log contains a pathologically deep out-of-order write history that is too expensive to reconcile during boot (harper#1316). Re-clone this node from a healthy leader to recover the unreplayed data.`;
|
|
259
|
+
transaction = undefined; // already committed above; nothing staged for the new version
|
|
260
|
+
if (electedReplayer) {
|
|
261
|
+
strictFailure = new Error(slowMessage);
|
|
262
|
+
break;
|
|
263
|
+
}
|
|
264
|
+
logger.fatal(slowMessage);
|
|
188
265
|
break;
|
|
189
266
|
}
|
|
190
267
|
transaction = new DatabaseTransaction();
|
|
191
268
|
transaction.db = primaryStore;
|
|
192
|
-
transaction.timestamp =
|
|
269
|
+
transaction.timestamp = txnLogKey;
|
|
193
270
|
// retries=1 routes operation.commit() through its retry path (no duplicate audit staging)
|
|
194
271
|
transaction.retries = 1;
|
|
195
272
|
// Explicit replay marker: skips schema validation (harper#1316) and makes save() stamp
|
|
@@ -198,8 +275,9 @@ export function replayLogs(rootStore: RocksDatabase, tables: any): Promise<void>
|
|
|
198
275
|
transaction.isReplay = true;
|
|
199
276
|
}
|
|
200
277
|
context.transaction = transaction;
|
|
201
|
-
const options = { context, residencyId, nodeId, originatingOperation };
|
|
278
|
+
const options = { context, residencyId, nodeId, originatingOperation, version };
|
|
202
279
|
writes++;
|
|
280
|
+
stagedWrites++;
|
|
203
281
|
switch (type) {
|
|
204
282
|
case 'put':
|
|
205
283
|
tableInstance._writeUpdate(recordId, record, true, options);
|
|
@@ -274,6 +352,10 @@ export function replayLogs(rootStore: RocksDatabase, tables: any): Promise<void>
|
|
|
274
352
|
noProgressRun = 0;
|
|
275
353
|
lastProgressTime = performance.now();
|
|
276
354
|
} catch (err) {
|
|
355
|
+
if (electedReplayer) {
|
|
356
|
+
strictAbort(err, transaction);
|
|
357
|
+
break;
|
|
358
|
+
}
|
|
277
359
|
// A write that threw made no forward progress either — count it toward the stall
|
|
278
360
|
// bound so a continuous stream of throwing writes can't grind the boot thread
|
|
279
361
|
// indefinitely (and the per-entry error log below can't spam unboundedly). harper#1266
|
|
@@ -283,18 +365,62 @@ export function replayLogs(rootStore: RocksDatabase, tables: any): Promise<void>
|
|
|
283
365
|
});
|
|
284
366
|
}
|
|
285
367
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
368
|
+
const finalTorn = entries.corruptFrameStop.truncatedVersions.has(lastTimestamp);
|
|
369
|
+
if (!strictFailure) {
|
|
370
|
+
try {
|
|
371
|
+
if (finalTorn) {
|
|
372
|
+
writes -= stagedWrites;
|
|
373
|
+
discardedWrites += stagedWrites;
|
|
374
|
+
transaction?.abort();
|
|
375
|
+
} else transaction?.directCommitSync();
|
|
376
|
+
} catch (error) {
|
|
377
|
+
// directCommitSync aborts and detaches its transaction on failure; no cleanup here.
|
|
378
|
+
// Mirrors the interior version-boundary catch above: a failed commit never applied, so
|
|
379
|
+
// it must not stay counted in `writes`.
|
|
380
|
+
if (!finalTorn) writes -= stagedWrites;
|
|
381
|
+
if (electedReplayer) strictFailure = error;
|
|
382
|
+
logger.error(`Error ${finalTorn ? 'discarding a torn' : 'committing'} replay transaction`, error);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
// `breaks` also counts a torn tail — the designed, benign reading of a crash's last frame, and
|
|
386
|
+
// the reporter already logged it at `warn`. Only a mid-log break lost entries, so it alone earns
|
|
387
|
+
// this quarantine/repair summary; duplicating it for a torn tail would tell an operator to
|
|
388
|
+
// repair or re-clone the node on every ordinary unclean shutdown.
|
|
389
|
+
if (entries.corruptFrameStop.midLogBreak) {
|
|
390
|
+
logger.error(
|
|
391
|
+
`Transaction-log replay in ${(rootStore as any).databaseName} database stopped at a corrupt entry after replaying ${writes} records. Every entry after the break is quarantined — neither replayed nor replicated — and ${discardedWrites} record(s) of the transaction the break truncated were discarded rather than applied in part. Repair the transaction log or re-clone this node to recover them.`
|
|
392
|
+
);
|
|
393
|
+
// electedReplayer must not resolve past known loss — see the doc comment above. Only set
|
|
394
|
+
// strictFailure if nothing has already failed the replay for an unrelated reason, so this
|
|
395
|
+
// diagnostic never shadows a more specific commit/write error.
|
|
396
|
+
if (electedReplayer && !strictFailure) {
|
|
397
|
+
strictFailure = new Error(
|
|
398
|
+
`Elected replay in ${(rootStore as any).databaseName} database stopped at a mid-log corrupt transaction-log frame; entries behind the break were acknowledged and are now quarantined. Refusing to publish a branch over known lost writes — repair the transaction log or re-clone this node.`
|
|
399
|
+
);
|
|
400
|
+
}
|
|
290
401
|
}
|
|
291
402
|
if (writes > 0) logger.warn(`Replayed ${writes} records in ${(rootStore as any).databaseName} database`);
|
|
292
403
|
if (skipped > 0)
|
|
293
404
|
logger.warn(
|
|
294
405
|
`Skipped ${skipped} unrecoverable audit entries in ${(rootStore as any).databaseName} database during replay`
|
|
295
406
|
);
|
|
296
|
-
|
|
297
|
-
|
|
407
|
+
if (strictFailure) {
|
|
408
|
+
// A failed strict replay must be re-runnable: the branch claim resets for a retry, so the
|
|
409
|
+
// lock must not be what survives to wedge it. Only a COMPLETED replay keeps the lock
|
|
410
|
+
// forever (the once-per-boot guarantee). Reject BEFORE unlocking: unlock wakes tryLock
|
|
411
|
+
// callbacks — including this holder's own resolve() — and the first settle must be the
|
|
412
|
+
// rejection, or a failed replay reads as success.
|
|
413
|
+
reject(strictFailure);
|
|
414
|
+
try {
|
|
415
|
+
rootStore.unlock('replayLogs');
|
|
416
|
+
} catch (unlockError) {
|
|
417
|
+
logger.warn('Error releasing the replay lock after a failed replay', unlockError);
|
|
418
|
+
}
|
|
419
|
+
} else {
|
|
420
|
+
// we never actually release the lock because we only want to ever run one time
|
|
421
|
+
// rootStore.unlock('replayLogs');
|
|
422
|
+
resolve();
|
|
423
|
+
}
|
|
298
424
|
});
|
|
299
425
|
}
|
|
300
426
|
function asBinary(buffer) {
|
|
@@ -132,16 +132,66 @@ export function shouldAbortSlowReplay(totalElapsedMs: number, timeLimitMs = REPL
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
/**
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
135
|
+
* A corrupt transaction-log frame from rocksdb-js. `resyncPosition` is set only when intact entries
|
|
136
|
+
* follow the break, which is what distinguishes lost entries from a merely truncated tail; its
|
|
137
|
+
* absence is also all that any rocksdb-js predating that field can report.
|
|
138
|
+
*/
|
|
139
|
+
export type CorruptFrameError = RangeError & {
|
|
140
|
+
logId?: number | null;
|
|
141
|
+
position?: number | null;
|
|
142
|
+
resyncPosition?: number | null;
|
|
143
|
+
unreadableBytes?: number | null;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Corrupt frames hit by one `getRange` call, shared by its per-log iterators.
|
|
148
|
+
*
|
|
149
|
+
* `truncatedVersions` is what a consumer has to act on: a break destroys the framing after the last
|
|
150
|
+
* entry the broken log yielded, and whether the entries it swallowed continued that entry's version
|
|
151
|
+
* is exactly what can no longer be read — UNLESS that last entry's own `endTxn` already closed its
|
|
152
|
+
* transaction, in which case nothing of it was left open to swallow. That version's transaction is
|
|
153
|
+
* therefore incomplete only when it wasn't already known-closed, and replay must discard it rather
|
|
154
|
+
* than commit the part of it that was still readable. A log that broke before yielding anything
|
|
155
|
+
* truncates no transaction.
|
|
156
|
+
*
|
|
157
|
+
* `midLogBreak` is coarser: true once any break in this range left intact entries unreadable behind
|
|
158
|
+
* it (see {@link isMidLogBreak}), regardless of which version they belonged to. A consumer that must
|
|
159
|
+
* never serve a range with lost entries — an elected branch replay publishing itself as a trustworthy
|
|
160
|
+
* point-in-time copy — rejects on this rather than on `truncatedVersions`, since a mid-log break can
|
|
161
|
+
* strand entries whose version this range never even attributes to one log (harper#2016, #2063).
|
|
162
|
+
*/
|
|
163
|
+
export interface CorruptFrameStop {
|
|
164
|
+
breaks: number;
|
|
165
|
+
truncatedVersions: Set<number>;
|
|
166
|
+
midLogBreak: boolean;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Whether a corrupt frame is a mid-log break — intact entries followed it, so entries were lost
|
|
171
|
+
* rather than the log merely being torn at its tail. Shared by the reporter below and by
|
|
172
|
+
* `RocksTransactionLogStore.getRange`'s `CorruptFrameStop.midLogBreak`, so the two can't drift on
|
|
173
|
+
* what counts as a mid-log break.
|
|
174
|
+
*/
|
|
175
|
+
export function isMidLogBreak(error: CorruptFrameError): boolean {
|
|
176
|
+
return error.resyncPosition != null;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Wraps a transaction-log query iterator so a corrupt/torn frame ends that log's iteration cleanly
|
|
181
|
+
* instead of escaping as an uncaughtException.
|
|
182
|
+
*
|
|
183
|
+
* Iteration stops at the break whether or not intact entries follow it. Resuming past a mid-log
|
|
184
|
+
* break would recover those entries, but a transaction log carries no frame-level transaction
|
|
185
|
+
* boundaries: replay groups equal-version entries into one source transaction, so skipping a frame
|
|
186
|
+
* inside such a group applies and checkpoints the surviving subset of a transaction that never
|
|
187
|
+
* committed that way at the source. Availability loss is visible and recoverable; a silently torn
|
|
188
|
+
* transaction is neither. Recovery is deferred until the engine can resume at a proven boundary
|
|
189
|
+
* (harper#2016, harper#2063); `resyncPosition` is used only to report the break as lost entries
|
|
190
|
+
* rather than as a truncated tail.
|
|
141
191
|
*/
|
|
142
192
|
export function endIteratorOnCorruptFrame<T>(
|
|
143
193
|
iterator: Iterator<T>,
|
|
144
|
-
onCorruptFrame: (error:
|
|
194
|
+
onCorruptFrame: (error: CorruptFrameError) => void
|
|
145
195
|
): IterableIterator<T> {
|
|
146
196
|
let stopped = false;
|
|
147
197
|
return {
|
|
@@ -157,7 +207,7 @@ export function endIteratorOnCorruptFrame<T>(
|
|
|
157
207
|
// version-dependent (1.4.2 added hex offsets). Anything else re-throws.
|
|
158
208
|
if (!(error instanceof RangeError)) throw error;
|
|
159
209
|
stopped = true;
|
|
160
|
-
onCorruptFrame(error);
|
|
210
|
+
onCorruptFrame(error as CorruptFrameError);
|
|
161
211
|
return { done: true, value: undefined };
|
|
162
212
|
}
|
|
163
213
|
},
|
|
@@ -175,3 +225,116 @@ export function endIteratorOnCorruptFrame<T>(
|
|
|
175
225
|
},
|
|
176
226
|
};
|
|
177
227
|
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* A corrupt frame, accumulated for the life of the process. The same frame is re-encountered by
|
|
231
|
+
* every reader until each consumer's resume cursor has passed it, so this is deduplicated by
|
|
232
|
+
* location and the repeats become a count.
|
|
233
|
+
*/
|
|
234
|
+
export interface CorruptFrameReport {
|
|
235
|
+
log: string;
|
|
236
|
+
logId?: number;
|
|
237
|
+
position?: number;
|
|
238
|
+
/** Intact entries followed the break, so entries were lost rather than merely truncated. */
|
|
239
|
+
midLog: boolean;
|
|
240
|
+
/** Extent of the unreadable region, when the engine reports it; 0 when nothing valid follows it. */
|
|
241
|
+
unreadableBytes: number;
|
|
242
|
+
firstSeen: number;
|
|
243
|
+
lastSeen: number;
|
|
244
|
+
occurrences: number;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/** Distinct break sites retained. One physical corruption yields one site, so this is generous. */
|
|
248
|
+
export const MAX_CORRUPT_FRAME_REPORTS = 256;
|
|
249
|
+
|
|
250
|
+
// Re-encounters move a site to the end, so the first key is the least recently seen. Full means
|
|
251
|
+
// evicting that one rather than refusing a new site, which could not then be deduplicated.
|
|
252
|
+
const corruptFrameReports = new Map<string, CorruptFrameReport>();
|
|
253
|
+
let evictedCorruptFrameReports = 0;
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Every corrupt frame seen by this worker. This is not yet consumed by cluster/health status;
|
|
257
|
+
* callers must aggregate it across worker threads before exposing a node-wide signal.
|
|
258
|
+
*
|
|
259
|
+
* Mid-log breaks are immediately logged at error level even without that consumer.
|
|
260
|
+
*/
|
|
261
|
+
export function getCorruptFrameReports(): CorruptFrameReport[] {
|
|
262
|
+
return [...corruptFrameReports.values()];
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/** Break sites evicted because {@link MAX_CORRUPT_FRAME_REPORTS} was reached. */
|
|
266
|
+
export function getEvictedCorruptFrameReportCount(): number {
|
|
267
|
+
return evictedCorruptFrameReports;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
export function clearCorruptFrameReports() {
|
|
271
|
+
corruptFrameReports.clear();
|
|
272
|
+
evictedCorruptFrameReports = 0;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// `logId`/`position` are absent on any rocksdb-js predating the resync support, and every break on
|
|
276
|
+
// a stream would then collapse onto one key — folding genuinely different corruptions into a single
|
|
277
|
+
// count that only ever logs once. The message carries the offset and file in text, so it separates
|
|
278
|
+
// them when the fields can't.
|
|
279
|
+
function corruptFrameKey(logName: string, error: CorruptFrameError): string {
|
|
280
|
+
const { logId, position } = error;
|
|
281
|
+
return logId != null && position != null
|
|
282
|
+
? `${logName}\u0000${logId}:${position}`
|
|
283
|
+
: `${logName}\u0000${error.message}`;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Records a corrupt frame and logs it once per distinct break.
|
|
288
|
+
*
|
|
289
|
+
* A mid-log break is an `error`, not a `warn`: entries after it were acknowledged and are now
|
|
290
|
+
* quarantined behind it. Severity follows the break's own shape, never this pass's outcome — every
|
|
291
|
+
* pass stops, so keying on that would report the #2063 signature with the benign torn-tail `warn`.
|
|
292
|
+
* A site first seen as a torn tail can escalate later, since only a rocksdb-js that reports
|
|
293
|
+
* `resyncPosition` can tell the two apart.
|
|
294
|
+
*/
|
|
295
|
+
export function createCorruptFrameReporter(logger: {
|
|
296
|
+
warn: (message: string, error?: unknown) => void;
|
|
297
|
+
error: (message: string, error?: unknown) => void;
|
|
298
|
+
}) {
|
|
299
|
+
return (logName: string) => (error: CorruptFrameError) => {
|
|
300
|
+
const midLog = isMidLogBreak(error);
|
|
301
|
+
const unreadableBytes = error.unreadableBytes ?? 0;
|
|
302
|
+
const now = Date.now();
|
|
303
|
+
const key = corruptFrameKey(logName, error);
|
|
304
|
+
const existing = corruptFrameReports.get(key);
|
|
305
|
+
if (existing) {
|
|
306
|
+
corruptFrameReports.delete(key);
|
|
307
|
+
corruptFrameReports.set(key, existing);
|
|
308
|
+
existing.occurrences++;
|
|
309
|
+
existing.lastSeen = now;
|
|
310
|
+
if (!midLog || existing.midLog) return;
|
|
311
|
+
existing.midLog = true;
|
|
312
|
+
existing.unreadableBytes = unreadableBytes;
|
|
313
|
+
} else {
|
|
314
|
+
if (corruptFrameReports.size >= MAX_CORRUPT_FRAME_REPORTS) {
|
|
315
|
+
corruptFrameReports.delete(corruptFrameReports.keys().next().value);
|
|
316
|
+
evictedCorruptFrameReports++;
|
|
317
|
+
}
|
|
318
|
+
corruptFrameReports.set(key, {
|
|
319
|
+
log: logName,
|
|
320
|
+
logId: error.logId ?? undefined,
|
|
321
|
+
position: error.position ?? undefined,
|
|
322
|
+
midLog,
|
|
323
|
+
unreadableBytes,
|
|
324
|
+
firstSeen: now,
|
|
325
|
+
lastSeen: now,
|
|
326
|
+
occurrences: 1,
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
if (midLog) {
|
|
330
|
+
logger.error(
|
|
331
|
+
`Corrupt entry in transaction log "${logName}"; ${unreadableBytes} byte(s) are unreadable and the entries within them are lost. ` +
|
|
332
|
+
'Intact entries follow the break, but reading stops there rather than skipping the frame, which could tear a source transaction: ' +
|
|
333
|
+
'they are quarantined until the log is repaired or this node is re-cloned, and they are neither replayed nor replicated meanwhile.',
|
|
334
|
+
error
|
|
335
|
+
);
|
|
336
|
+
} else {
|
|
337
|
+
logger.warn(`Stopping transaction log "${logName}" at a corrupt entry during replay`, error);
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { onRemovedDB } from './databases.ts';
|
|
2
|
+
import { logger } from '../utility/logging/logger.ts';
|
|
3
|
+
import { contextStorage } from './transaction.ts';
|
|
4
|
+
|
|
5
|
+
export interface ReplicatedApplyFailure {
|
|
6
|
+
readonly database: string;
|
|
7
|
+
readonly table?: string;
|
|
8
|
+
readonly nodeId: number;
|
|
9
|
+
readonly position: number;
|
|
10
|
+
readonly localTime?: number;
|
|
11
|
+
readonly error: unknown;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type ReplicatedApplyFailureListener = (failure: ReplicatedApplyFailure) => void | Promise<void>;
|
|
15
|
+
|
|
16
|
+
const listenersByDatabase = new Map<string, Set<ReplicatedApplyFailureListener>>();
|
|
17
|
+
let watchingDatabaseRemoval = false;
|
|
18
|
+
|
|
19
|
+
export function registerReplicatedApplyFailureListener(
|
|
20
|
+
database: string,
|
|
21
|
+
listener: ReplicatedApplyFailureListener
|
|
22
|
+
): void {
|
|
23
|
+
if (!watchingDatabaseRemoval) {
|
|
24
|
+
onRemovedDB((database) => listenersByDatabase.delete(database));
|
|
25
|
+
watchingDatabaseRemoval = true;
|
|
26
|
+
}
|
|
27
|
+
let listeners = listenersByDatabase.get(database);
|
|
28
|
+
if (!listeners) listenersByDatabase.set(database, (listeners = new Set()));
|
|
29
|
+
listeners.add(listener);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function unregisterReplicatedApplyFailureListener(
|
|
33
|
+
database: string,
|
|
34
|
+
listener: ReplicatedApplyFailureListener
|
|
35
|
+
): void {
|
|
36
|
+
const listeners = listenersByDatabase.get(database);
|
|
37
|
+
listeners?.delete(listener);
|
|
38
|
+
if (listeners?.size === 0) listenersByDatabase.delete(database);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function notifyReplicatedApplyFailure(
|
|
42
|
+
database: string,
|
|
43
|
+
event: { table?: string; nodeId?: number; localTime?: number },
|
|
44
|
+
position: number | undefined,
|
|
45
|
+
error: unknown,
|
|
46
|
+
table?: string
|
|
47
|
+
): Promise<void> {
|
|
48
|
+
if (listenersByDatabase.size === 0) return;
|
|
49
|
+
try {
|
|
50
|
+
if (typeof event?.nodeId !== 'number' || typeof position !== 'number') return;
|
|
51
|
+
const listeners = listenersByDatabase.get(database);
|
|
52
|
+
if (!listeners) return;
|
|
53
|
+
const failure: ReplicatedApplyFailure = Object.freeze({
|
|
54
|
+
database,
|
|
55
|
+
table: event.table ?? table,
|
|
56
|
+
nodeId: event.nodeId,
|
|
57
|
+
position,
|
|
58
|
+
localTime: event.localTime,
|
|
59
|
+
error,
|
|
60
|
+
});
|
|
61
|
+
for (const listener of [...listeners]) {
|
|
62
|
+
try {
|
|
63
|
+
await contextStorage.exit(() => listener(failure));
|
|
64
|
+
} catch (error) {
|
|
65
|
+
logListenerFailure(database, error);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
} catch (error) {
|
|
69
|
+
logListenerFailure(database, error);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function logListenerFailure(database: string, error: unknown): void {
|
|
74
|
+
try {
|
|
75
|
+
logger.error?.('replicated apply failure listener failed', database, error);
|
|
76
|
+
} catch {}
|
|
77
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isAbsolute, join } from 'node:path';
|
|
2
|
-
import {
|
|
2
|
+
import { isApplicationPrimaryWorker } from '../../server/threads/manageThreads.js';
|
|
3
3
|
import { ClientError } from '../../utility/errors/hdbError.ts';
|
|
4
4
|
import { convertToMS } from '../../utility/common_utils.ts';
|
|
5
5
|
import harperLogger from '../../utility/logging/harper_logger.ts';
|
|
@@ -94,12 +94,12 @@ export async function handleApplication(scope): Promise<void> {
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
// Activation gates: one worker owns scheduling for the whole node
|
|
97
|
-
// (
|
|
97
|
+
// (the application's primary worker is correct in every threading mode, including
|
|
98
98
|
// threads:0 where the main thread acts as worker 0), and a deploy
|
|
99
99
|
// pre-flight validation scope must never touch the live engine — it can
|
|
100
100
|
// share a running component's identity, so registering from it would
|
|
101
|
-
// displace the real component's jobs
|
|
102
|
-
if (
|
|
101
|
+
// displace the real component's jobs.
|
|
102
|
+
if (!isApplicationPrimaryWorker(scope.applicationScope?.name)) {
|
|
103
103
|
schedulerLogger.debug?.('Scheduler config validated; activation skipped on non-primary worker');
|
|
104
104
|
return;
|
|
105
105
|
}
|