@harperfast/harper-pro 5.0.25 → 5.1.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/analytics/profile.ts +4 -0
- package/core/AGENTS.md +92 -6
- package/core/DESIGN.md +24 -0
- package/core/README.md +11 -10
- package/core/agent/agent.ts +203 -0
- package/core/agent/loop.ts +205 -0
- package/core/agent/operations.ts +148 -0
- package/core/agent/session.ts +187 -0
- package/core/agent/tools/fsTools.ts +276 -0
- package/core/agent/tools/httpFetchTool.ts +112 -0
- package/core/agent/tools/scheduleTool.ts +68 -0
- package/core/agent/toolset.ts +43 -0
- package/core/agent/types.ts +85 -0
- package/core/benchmarks/hnsw-search.js +157 -0
- package/core/benchmarks/ycsb/README.md +144 -0
- package/core/benchmarks/ycsb/analyze-profile.mts +120 -0
- package/core/benchmarks/ycsb/app/config.yaml +3 -0
- package/core/benchmarks/ycsb/app/schema.graphql +17 -0
- package/core/benchmarks/ycsb/harness.mts +328 -0
- package/core/benchmarks/ycsb/restClient.mts +120 -0
- package/core/benchmarks/ycsb/run-single-node.mts +97 -0
- package/core/benchmarks/ycsb/to-benchmark-json.mts +58 -0
- package/core/benchmarks/ycsb/workload.mts +499 -0
- package/core/benchmarks/ycsb/workload.test.mts +174 -0
- package/core/bin/{BinObjects.js → BinObjects.ts} +4 -5
- package/core/bin/cliCredentials.ts +133 -0
- package/core/bin/cliOperations.ts +339 -0
- package/core/bin/copyDb.ts +10 -10
- package/core/bin/deployRenderer.ts +196 -0
- package/core/bin/{harper.js → harper.ts} +48 -24
- package/core/bin/{install.js → install.ts} +3 -3
- package/core/bin/lite.ts +2 -0
- package/core/bin/login.ts +168 -0
- package/core/bin/logout.ts +11 -0
- package/core/bin/mcp/client.ts +407 -0
- package/core/bin/mcp/doctor.ts +189 -0
- package/core/bin/mcp/index.ts +80 -0
- package/core/bin/mcp/options.ts +122 -0
- package/core/bin/mcp/printConfig.ts +89 -0
- package/core/bin/multipartBuilder.ts +74 -0
- package/core/bin/{restart.js → restart.ts} +31 -32
- package/core/bin/{run.js → run.ts} +57 -46
- package/core/bin/sseConsumer.ts +126 -0
- package/core/bin/{status.js → status.ts} +10 -10
- package/core/bin/stop.ts +21 -0
- package/core/bin/upgrade.js +6 -6
- package/core/components/Application.ts +144 -18
- package/core/components/ApplicationScope.ts +2 -2
- package/core/components/ComponentV1.ts +2 -2
- package/core/components/EntryHandler.ts +159 -9
- package/core/components/OptionsWatcher.ts +75 -11
- package/core/components/Scope.ts +125 -15
- package/core/components/anthropic/index.ts +547 -0
- package/core/components/bedrock/index.ts +823 -0
- package/core/components/componentLoader.ts +63 -32
- package/core/components/deployLifecycle.ts +161 -0
- package/core/components/deploymentOperations.ts +173 -0
- package/core/components/deploymentRecorder.ts +402 -0
- package/core/components/deriveURLPath.ts +4 -4
- package/core/components/mcp/adapters/fastify.ts +87 -0
- package/core/components/mcp/adapters/harperHttp.ts +103 -0
- package/core/components/mcp/audit.ts +75 -0
- package/core/components/mcp/index.ts +134 -0
- package/core/components/mcp/jsonrpc.ts +134 -0
- package/core/components/mcp/lifecycle.ts +105 -0
- package/core/components/mcp/listChanged.ts +270 -0
- package/core/components/mcp/rateLimit.ts +217 -0
- package/core/components/mcp/resources.ts +593 -0
- package/core/components/mcp/session.ts +151 -0
- package/core/components/mcp/sessionRegistry.ts +140 -0
- package/core/components/mcp/toolRegistry.ts +292 -0
- package/core/components/mcp/tools/application.ts +603 -0
- package/core/components/mcp/tools/operations.ts +283 -0
- package/core/components/mcp/tools/schemas/derive.ts +256 -0
- package/core/components/mcp/tools/schemas/operations.ts +245 -0
- package/core/components/mcp/transport.ts +517 -0
- package/core/components/ollama/index.ts +316 -0
- package/core/components/openai/index.ts +563 -0
- package/core/components/operations.js +211 -60
- package/core/components/operationsValidation.js +3 -3
- package/core/components/packageComponent.ts +97 -29
- package/core/components/requestRestart.ts +17 -2
- package/core/components/status/crossThread.ts +14 -5
- package/core/components/status/errors.ts +1 -1
- package/core/config/RootConfigWatcher.ts +56 -2
- package/core/config/configUtils.js +29 -8
- package/core/config/harperConfigEnvVars.ts +1 -1
- package/core/dataLayer/{CreateAttributeObject.js → CreateAttributeObject.ts} +4 -3
- package/core/dataLayer/{CreateTableObject.js → CreateTableObject.ts} +2 -1
- package/core/dataLayer/{DataLayerObjects.js → DataLayerObjects.ts} +17 -9
- package/core/dataLayer/{DeleteBeforeObject.js → DeleteBeforeObject.ts} +2 -1
- package/core/dataLayer/{DeleteObject.js → DeleteObject.ts} +3 -2
- package/core/dataLayer/{DropAttributeObject.js → DropAttributeObject.ts} +2 -1
- package/core/dataLayer/{GetBackupObject.js → GetBackupObject.ts} +3 -2
- package/core/dataLayer/{InsertObject.js → InsertObject.ts} +3 -2
- package/core/dataLayer/{ReadAuditLogObject.js → ReadAuditLogObject.ts} +3 -2
- package/core/dataLayer/{SQLSearch.js → SQLSearch.ts} +97 -43
- package/core/dataLayer/{SearchByConditionsObject.js → SearchByConditionsObject.ts} +5 -6
- package/core/dataLayer/{SearchByHashObject.js → SearchByHashObject.ts} +2 -1
- package/core/dataLayer/{SearchObject.js → SearchObject.ts} +2 -1
- package/core/dataLayer/{SqlSearchObject.js → SqlSearchObject.ts} +2 -1
- package/core/dataLayer/{UpdateObject.js → UpdateObject.ts} +3 -2
- package/core/dataLayer/{UpsertObject.js → UpsertObject.ts} +3 -2
- package/core/dataLayer/{bulkLoad.js → bulkLoad.ts} +40 -49
- package/core/dataLayer/{delete.js → delete.ts} +21 -26
- package/core/dataLayer/{export.js → export.ts} +22 -26
- package/core/dataLayer/{getBackup.js → getBackup.ts} +7 -9
- package/core/dataLayer/harperBridge/BridgeMethods.ts +102 -0
- package/core/dataLayer/harperBridge/ResourceBridge.ts +27 -26
- package/core/dataLayer/harperBridge/TableSizeObject.ts +1 -0
- package/core/dataLayer/harperBridge/bridgeUtility/insertUpdateValidate.js +4 -4
- package/core/dataLayer/harperBridge/{harperBridge.js → harperBridge.ts} +3 -3
- package/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateAttribute.js +8 -6
- package/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateRecords.js +4 -4
- package/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateSchema.js +1 -1
- package/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateTable.js +6 -4
- package/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDeleteAuditLogsBefore.js +5 -4
- package/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDeleteRecords.js +4 -4
- package/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDropAttribute.js +6 -5
- package/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDropSchema.js +5 -4
- package/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDropTable.js +5 -5
- package/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbFlush.js +1 -1
- package/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbGetBackup.js +3 -3
- package/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbGetDataByHash.js +1 -1
- package/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbGetDataByValue.js +3 -2
- package/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbReadAuditLog.js +5 -5
- package/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByConditions.js +10 -8
- package/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByHash.js +1 -1
- package/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByValue.js +4 -3
- package/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbUpdateRecords.js +3 -3
- package/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbUpsertRecords.js +6 -5
- package/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBCreateAttributeObject.js +2 -1
- package/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializeHashSearch.js +3 -2
- package/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializePaths.js +2 -2
- package/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbCheckForNewAttributes.js +5 -4
- package/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbCreateTransactionsAuditEnvironment.js +6 -3
- package/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbGetTableSize.ts +1 -1
- package/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbProcessRows.js +4 -4
- package/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbSearch.js +5 -5
- package/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbWriteTransaction.js +4 -4
- package/core/dataLayer/{hdbInfoController.js → hdbInfoController.ts} +20 -26
- package/core/dataLayer/{insert.js → insert.ts} +24 -24
- package/core/dataLayer/{readAuditLog.js → readAuditLog.ts} +8 -10
- package/core/dataLayer/{schema.js → schema.ts} +32 -44
- package/core/dataLayer/{schemaDescribe.js → schemaDescribe.ts} +23 -26
- package/core/dataLayer/{search.js → search.ts} +9 -15
- package/core/dataLayer/{transaction.js → transaction.ts} +2 -5
- package/core/dataLayer/{update.js → update.ts} +19 -22
- package/core/index.ts +5 -0
- package/core/json/systemSchema.json +65 -0
- package/core/launchServiceScripts/utility/checkNodeVersion.js +2 -0
- package/core/package-lock.json +9051 -4318
- package/core/resources/DESIGN.md +98 -0
- package/core/resources/DatabaseTransaction.ts +58 -30
- package/core/resources/ErrorResource.ts +2 -1
- package/core/resources/LMDBTransaction.ts +38 -29
- package/core/resources/RecordEncoder.ts +12 -4
- package/core/resources/RequestTarget.ts +2 -0
- package/core/resources/Resource.ts +89 -56
- package/core/resources/ResourceInterface.ts +44 -21
- package/core/resources/Resources.ts +8 -8
- package/core/resources/RocksIndexStore.ts +3 -0
- package/core/resources/RocksTransactionLogStore.ts +47 -28
- package/core/resources/Table.ts +386 -214
- package/core/resources/analytics/metadata.ts +1 -0
- package/core/resources/analytics/read.ts +24 -6
- package/core/resources/analytics/write.ts +240 -17
- package/core/resources/auditStore.ts +28 -19
- package/core/resources/blob.ts +53 -53
- package/core/resources/dataLoader.ts +4 -4
- package/core/resources/databases.ts +190 -71
- package/core/resources/graphql.ts +227 -164
- package/core/resources/indexes/HierarchicalNavigableSmallWorld.ts +294 -65
- package/core/resources/indexes/vector.ts +17 -0
- package/core/resources/loadEnv.ts +21 -17
- package/core/resources/login.ts +5 -3
- package/core/resources/models/Models.ts +304 -0
- package/core/resources/models/TestBackend.ts +83 -0
- package/core/resources/models/agentLoop.ts +895 -0
- package/core/resources/models/analyticsTable.ts +199 -0
- package/core/resources/models/backendHelpers.ts +116 -0
- package/core/resources/models/backendRegistry.ts +66 -0
- package/core/resources/models/bootstrap.ts +135 -0
- package/core/resources/models/embedHook.ts +138 -0
- package/core/resources/models/types.ts +296 -0
- package/core/resources/replayLogs.ts +15 -7
- package/core/resources/roles.ts +62 -67
- package/core/resources/search.ts +355 -135
- package/core/resources/tracked.ts +8 -8
- package/core/resources/transaction.ts +8 -8
- package/core/resources/transactionBroadcast.ts +3 -3
- package/core/security/auth.ts +35 -26
- package/core/security/certificateVerification/crlVerification.ts +11 -4
- package/core/security/{cryptoHash.js → cryptoHash.ts} +3 -8
- package/core/security/data_objects/{PermissionAttributeResponseObject.js → PermissionAttributeResponseObject.ts} +4 -4
- package/core/security/data_objects/{PermissionResponseObject.js → PermissionResponseObject.ts} +12 -11
- package/core/security/data_objects/{PermissionTableResponseObject.js → PermissionTableResponseObject.ts} +6 -4
- package/core/security/{fastifyAuth.js → fastifyAuth.ts} +93 -20
- package/core/security/impersonation.ts +3 -3
- package/core/security/jsLoader.ts +22 -8
- package/core/security/{keys.js → keys.ts} +113 -121
- package/core/security/permissionsTranslator.js +2 -2
- package/core/security/{role.js → role.ts} +26 -33
- package/core/security/tokenAuthentication.ts +34 -7
- package/core/security/user.ts +26 -22
- package/core/server/DESIGN.md +139 -0
- package/core/server/DurableSubscriptionsSession.ts +67 -50
- package/core/server/REST.ts +120 -107
- package/core/server/Server.ts +31 -12
- package/core/server/fastifyRoutes/helpers/getCORSOptions.js +1 -1
- package/core/server/fastifyRoutes/helpers/getHeaderTimeoutConfig.js +1 -1
- package/core/server/fastifyRoutes/helpers/getServerOptions.js +1 -1
- package/core/server/fastifyRoutes.ts +37 -33
- package/core/server/graphqlQuerying.ts +6 -5
- package/core/server/http.ts +517 -26
- package/core/server/itc/serverHandlers.js +75 -14
- package/core/server/jobs/{JobObject.js → JobObject.ts} +13 -6
- package/core/server/jobs/{jobProcess.js → jobProcess.ts} +20 -16
- package/core/server/jobs/{jobRunner.js → jobRunner.ts} +20 -21
- package/core/server/jobs/{jobs.js → jobs.ts} +41 -44
- package/core/server/loadRootComponents.js +1 -1
- package/core/server/middlewareChain.ts +270 -0
- package/core/server/mqtt.ts +35 -26
- package/core/server/nodeName.ts +2 -1
- package/core/server/operationsServer.ts +85 -10
- package/core/server/serverHelpers/Headers.ts +10 -8
- package/core/server/serverHelpers/JSONStream.ts +15 -5
- package/core/server/serverHelpers/Request.ts +370 -13
- package/core/server/serverHelpers/contentTypes.ts +42 -11
- package/core/server/serverHelpers/multipartParser.ts +152 -0
- package/core/server/serverHelpers/progressEmitter.ts +110 -0
- package/core/server/serverHelpers/serverHandlers.js +43 -7
- package/core/server/serverHelpers/serverUtilities.ts +40 -30
- package/core/server/static.ts +9 -6
- package/core/server/status/index.ts +2 -2
- package/core/server/storageReclamation.ts +39 -2
- package/core/server/threads/itc.js +7 -4
- package/core/server/threads/manageThreads.js +100 -26
- package/core/server/threads/socketRouter.ts +12 -275
- package/core/server/threads/threadServer.js +345 -105
- package/core/server/threads/workerProcessGuard.ts +93 -0
- package/core/server/throttle.ts +18 -0
- package/core/sqlTranslator/{SelectValidator.js → SelectValidator.ts} +41 -49
- package/core/sqlTranslator/{alasqlFunctionImporter.js → alasqlFunctionImporter.ts} +5 -5
- package/core/sqlTranslator/{deleteTranslator.js → deleteTranslator.ts} +13 -18
- package/core/sqlTranslator/{index.js → index.ts} +30 -33
- package/core/sqlTranslator/{sql_statement_bucket.js → sql_statement_bucket.ts} +49 -20
- package/core/static/README.md +10 -9
- package/core/system/000004.log +0 -0
- package/core/system/CURRENT +1 -0
- package/core/system/IDENTITY +1 -0
- package/core/system/LOCK +0 -0
- package/core/system/LOG +1351 -0
- package/core/system/MANIFEST-000005 +0 -0
- package/core/system/OPTIONS-000013 +607 -0
- package/core/system/OPTIONS-000015 +734 -0
- package/core/upgrade/{UpgradeObjects.js → UpgradeObjects.ts} +3 -6
- package/core/upgrade/directives/5-2-0.ts +49 -0
- package/core/upgrade/directives/{directivesController.js → directivesController.ts} +16 -16
- package/core/upgrade/{directivesManager.js → directivesManager.ts} +7 -11
- package/core/upgrade/{upgradePrompt.js → upgradePrompt.ts} +8 -14
- package/core/upgrade/{upgradeUtilities.js → upgradeUtilities.ts} +3 -7
- package/core/utility/{OperationFunctionCaller.js → OperationFunctionCaller.ts} +7 -7
- package/core/utility/{assignCmdEnvVariables.js → assignCmdEnvVariables.ts} +6 -8
- package/core/utility/{common_utils.js → common_utils.ts} +113 -139
- package/core/utility/environment/{environmentManager.js → environmentManager.ts} +34 -33
- package/core/utility/environment/systemInformation.ts +18 -4
- package/core/utility/errors/{commonErrors.js → commonErrors.ts} +9 -9
- package/core/utility/errors/{hdbError.js → hdbError.ts} +39 -45
- package/core/utility/expandEnvVar.ts +110 -0
- package/core/utility/functions/geo.js +2 -2
- package/core/utility/functions/sql/alaSQLExtension.js +1 -1
- package/core/utility/globalSchema.ts +30 -0
- package/core/utility/hdbTerms.ts +56 -0
- package/core/utility/install/checkJWTTokensExist.js +1 -1
- package/core/utility/install/{installer.js → installer.ts} +58 -59
- package/core/utility/installation.ts +2 -2
- package/core/utility/lmdb/{DBIDefinition.js → DBIDefinition.ts} +4 -1
- package/core/utility/lmdb/{DeleteRecordsResponseObject.js → DeleteRecordsResponseObject.ts} +2 -1
- package/core/utility/lmdb/{InsertRecordsResponseObject.js → InsertRecordsResponseObject.ts} +2 -1
- package/core/utility/lmdb/OpenDBIObject.ts +43 -0
- package/core/utility/lmdb/{OpenEnvironmentObject.js → OpenEnvironmentObject.ts} +19 -6
- package/core/utility/lmdb/{UpdateRecordsResponseObject.js → UpdateRecordsResponseObject.ts} +2 -1
- package/core/utility/lmdb/{UpsertRecordsResponseObject.js → UpsertRecordsResponseObject.ts} +2 -1
- package/core/utility/lmdb/{cleanLMDBMap.js → cleanLMDBMap.ts} +5 -5
- package/core/utility/lmdb/{commonUtility.js → commonUtility.ts} +13 -21
- package/core/utility/lmdb/{deleteUtility.js → deleteUtility.ts} +8 -12
- package/core/utility/lmdb/{environmentUtility.js → environmentUtility.ts} +43 -52
- package/core/utility/lmdb/{searchCursorFunctions.js → searchCursorFunctions.ts} +12 -26
- package/core/utility/lmdb/{searchUtility.js → searchUtility.ts} +75 -64
- package/core/utility/lmdb/{terms.js → terms.ts} +10 -23
- package/core/utility/lmdb/{writeUtility.js → writeUtility.ts} +37 -22
- package/core/utility/logging/{harper_logger.js → harper_logger.ts} +136 -89
- package/core/utility/logging/{logRotator.js → logRotator.ts} +13 -13
- package/core/utility/logging/logger.ts +1 -1
- package/core/utility/logging/{readLog.js → readLog.ts} +19 -19
- package/core/utility/logging/{transactionLog.js → transactionLog.ts} +10 -14
- package/core/utility/{mount_hdb.js → mount_hdb.ts} +15 -16
- package/core/utility/{npmUtilities.js → npmUtilities.ts} +14 -17
- package/core/utility/{operation_authorization.js → operation_authorization.ts} +173 -124
- package/core/utility/packageUtils.js +7 -16
- package/core/utility/password.ts +1 -1
- package/core/utility/processManagement/processManagement.js +2 -2
- package/core/utility/processManagement/servicesConfig.js +1 -1
- package/core/utility/{signalling.js → signalling.ts} +6 -11
- package/core/utility/watcherFallback.ts +74 -0
- package/core/validation/analyticsValidator.ts +43 -0
- package/core/validation/{bulkDeleteValidator.js → bulkDeleteValidator.ts} +5 -5
- package/core/validation/{check_permissions.js → check_permissions.ts} +3 -3
- package/core/validation/{common_validators.js → common_validators.ts} +12 -24
- package/core/validation/{configValidator.js → configValidator.ts} +114 -18
- package/core/validation/{deleteValidator.js → deleteValidator.ts} +5 -5
- package/core/validation/{fileLoadValidator.js → fileLoadValidator.ts} +12 -19
- package/core/validation/{insertValidator.js → insertValidator.ts} +5 -5
- package/core/validation/{installValidator.js → installValidator.ts} +8 -8
- package/core/validation/{readLogValidator.js → readLogValidator.ts} +10 -10
- package/core/validation/{role_validation.js → role_validation.ts} +26 -32
- package/core/validation/{schemaMetadataValidator.js → schemaMetadataValidator.ts} +5 -11
- package/core/validation/{searchValidator.js → searchValidator.ts} +12 -11
- package/core/validation/statusValidator.ts +1 -1
- package/core/validation/{transactionLogValidator.js → transactionLogValidator.ts} +4 -9
- package/core/validation/{user_validation.js → user_validation.ts} +4 -10
- package/core/validation/{validationWrapper.js → validationWrapper.ts} +3 -9
- package/dist/analytics/profile.js +4 -0
- package/dist/analytics/profile.js.map +1 -1
- package/dist/cloneNode/cloneNode.js +224 -12
- package/dist/cloneNode/cloneNode.js.map +1 -1
- package/dist/core/agent/agent.js +175 -0
- package/dist/core/agent/agent.js.map +1 -0
- package/dist/core/agent/loop.js +176 -0
- package/dist/core/agent/loop.js.map +1 -0
- package/dist/core/agent/operations.js +137 -0
- package/dist/core/agent/operations.js.map +1 -0
- package/dist/core/agent/session.js +182 -0
- package/dist/core/agent/session.js.map +1 -0
- package/dist/core/agent/tools/fsTools.js +286 -0
- package/dist/core/agent/tools/fsTools.js.map +1 -0
- package/dist/core/agent/tools/httpFetchTool.js +116 -0
- package/dist/core/agent/tools/httpFetchTool.js.map +1 -0
- package/dist/core/agent/tools/scheduleTool.js +54 -0
- package/dist/core/agent/tools/scheduleTool.js.map +1 -0
- package/dist/core/agent/toolset.js +33 -0
- package/dist/core/agent/toolset.js.map +1 -0
- package/dist/core/agent/types.js +10 -0
- package/dist/core/agent/types.js.map +1 -0
- package/dist/core/bin/BinObjects.js +6 -3
- package/dist/core/bin/BinObjects.js.map +1 -1
- package/dist/core/bin/cliCredentials.js +130 -0
- package/dist/core/bin/cliCredentials.js.map +1 -0
- package/dist/core/bin/cliOperations.js +254 -40
- package/dist/core/bin/cliOperations.js.map +1 -1
- package/dist/core/bin/copyDb.js +16 -16
- package/dist/core/bin/copyDb.js.map +1 -1
- package/dist/core/bin/deployRenderer.js +185 -0
- package/dist/core/bin/deployRenderer.js.map +1 -0
- package/dist/core/bin/harper.js +92 -31
- package/dist/core/bin/harper.js.map +1 -1
- package/dist/core/bin/install.js +41 -4
- package/dist/core/bin/install.js.map +1 -1
- package/dist/core/bin/lite.js +3 -4
- package/dist/core/bin/lite.js.map +1 -1
- package/dist/core/bin/login.js +158 -0
- package/dist/core/bin/login.js.map +1 -0
- package/dist/core/bin/logout.js +16 -0
- package/dist/core/bin/logout.js.map +1 -0
- package/dist/core/bin/mcp/client.js +395 -0
- package/dist/core/bin/mcp/client.js.map +1 -0
- package/dist/core/bin/mcp/doctor.js +193 -0
- package/dist/core/bin/mcp/doctor.js.map +1 -0
- package/dist/core/bin/mcp/index.js +81 -0
- package/dist/core/bin/mcp/index.js.map +1 -0
- package/dist/core/bin/mcp/options.js +113 -0
- package/dist/core/bin/mcp/options.js.map +1 -0
- package/dist/core/bin/mcp/printConfig.js +85 -0
- package/dist/core/bin/mcp/printConfig.js.map +1 -0
- package/dist/core/bin/multipartBuilder.js +55 -0
- package/dist/core/bin/multipartBuilder.js.map +1 -0
- package/dist/core/bin/restart.js +85 -48
- package/dist/core/bin/restart.js.map +1 -1
- package/dist/core/bin/run.js +123 -77
- package/dist/core/bin/run.js.map +1 -1
- package/dist/core/bin/sseConsumer.js +127 -0
- package/dist/core/bin/sseConsumer.js.map +1 -0
- package/dist/core/bin/status.js +48 -11
- package/dist/core/bin/status.js.map +1 -1
- package/dist/core/bin/stop.js +44 -7
- package/dist/core/bin/stop.js.map +1 -1
- package/dist/core/bin/upgrade.js +6 -6
- package/dist/core/components/Application.js +134 -28
- package/dist/core/components/Application.js.map +1 -1
- package/dist/core/components/ApplicationScope.js +2 -2
- package/dist/core/components/ComponentV1.js +5 -5
- package/dist/core/components/ComponentV1.js.map +1 -1
- package/dist/core/components/EntryHandler.js +153 -13
- package/dist/core/components/EntryHandler.js.map +1 -1
- package/dist/core/components/OptionsWatcher.js +72 -10
- package/dist/core/components/OptionsWatcher.js.map +1 -1
- package/dist/core/components/Scope.js +105 -9
- package/dist/core/components/Scope.js.map +1 -1
- package/dist/core/components/anthropic/index.js +428 -0
- package/dist/core/components/anthropic/index.js.map +1 -0
- package/dist/core/components/bedrock/index.js +734 -0
- package/dist/core/components/bedrock/index.js.map +1 -0
- package/dist/core/components/componentLoader.js +63 -38
- package/dist/core/components/componentLoader.js.map +1 -1
- package/dist/core/components/deployLifecycle.js +156 -0
- package/dist/core/components/deployLifecycle.js.map +1 -0
- package/dist/core/components/deploymentOperations.js +185 -0
- package/dist/core/components/deploymentOperations.js.map +1 -0
- package/dist/core/components/deploymentRecorder.js +401 -0
- package/dist/core/components/deploymentRecorder.js.map +1 -0
- package/dist/core/components/deriveURLPath.js +2 -2
- package/dist/core/components/deriveURLPath.js.map +1 -1
- package/dist/core/components/mcp/adapters/fastify.js +66 -0
- package/dist/core/components/mcp/adapters/fastify.js.map +1 -0
- package/dist/core/components/mcp/adapters/harperHttp.js +78 -0
- package/dist/core/components/mcp/adapters/harperHttp.js.map +1 -0
- package/dist/core/components/mcp/audit.js +73 -0
- package/dist/core/components/mcp/audit.js.map +1 -0
- package/dist/core/components/mcp/index.js +109 -0
- package/dist/core/components/mcp/index.js.map +1 -0
- package/dist/core/components/mcp/jsonrpc.js +93 -0
- package/dist/core/components/mcp/jsonrpc.js.map +1 -0
- package/dist/core/components/mcp/lifecycle.js +79 -0
- package/dist/core/components/mcp/lifecycle.js.map +1 -0
- package/dist/core/components/mcp/listChanged.js +257 -0
- package/dist/core/components/mcp/listChanged.js.map +1 -0
- package/dist/core/components/mcp/rateLimit.js +226 -0
- package/dist/core/components/mcp/rateLimit.js.map +1 -0
- package/dist/core/components/mcp/resources.js +515 -0
- package/dist/core/components/mcp/resources.js.map +1 -0
- package/dist/core/components/mcp/session.js +170 -0
- package/dist/core/components/mcp/session.js.map +1 -0
- package/dist/core/components/mcp/sessionRegistry.js +124 -0
- package/dist/core/components/mcp/sessionRegistry.js.map +1 -0
- package/dist/core/components/mcp/toolRegistry.js +176 -0
- package/dist/core/components/mcp/toolRegistry.js.map +1 -0
- package/dist/core/components/mcp/tools/application.js +549 -0
- package/dist/core/components/mcp/tools/application.js.map +1 -0
- package/dist/core/components/mcp/tools/operations.js +303 -0
- package/dist/core/components/mcp/tools/operations.js.map +1 -0
- package/dist/core/components/mcp/tools/schemas/derive.js +216 -0
- package/dist/core/components/mcp/tools/schemas/derive.js.map +1 -0
- package/dist/core/components/mcp/tools/schemas/operations.js +243 -0
- package/dist/core/components/mcp/tools/schemas/operations.js.map +1 -0
- package/dist/core/components/mcp/transport.js +467 -0
- package/dist/core/components/mcp/transport.js.map +1 -0
- package/dist/core/components/ollama/index.js +239 -0
- package/dist/core/components/ollama/index.js.map +1 -0
- package/dist/core/components/openai/index.js +475 -0
- package/dist/core/components/openai/index.js.map +1 -0
- package/dist/core/components/operations.js +198 -52
- package/dist/core/components/operations.js.map +1 -1
- package/dist/core/components/operationsValidation.js +3 -3
- package/dist/core/components/packageComponent.js +87 -26
- package/dist/core/components/packageComponent.js.map +1 -1
- package/dist/core/components/requestRestart.js +12 -1
- package/dist/core/components/requestRestart.js.map +1 -1
- package/dist/core/components/status/crossThread.js +12 -5
- package/dist/core/components/status/crossThread.js.map +1 -1
- package/dist/core/components/status/errors.js +7 -7
- package/dist/core/config/RootConfigWatcher.js +52 -1
- package/dist/core/config/RootConfigWatcher.js.map +1 -1
- package/dist/core/config/configUtils.js +31 -8
- package/dist/core/config/configUtils.js.map +1 -1
- package/dist/core/config/harperConfigEnvVars.js +1 -1
- package/dist/core/config/harperConfigEnvVars.js.map +1 -1
- package/dist/core/dataLayer/CreateAttributeObject.js +4 -3
- package/dist/core/dataLayer/CreateAttributeObject.js.map +1 -1
- package/dist/core/dataLayer/CreateTableObject.js +2 -1
- package/dist/core/dataLayer/CreateTableObject.js.map +1 -1
- package/dist/core/dataLayer/DataLayerObjects.js +19 -5
- package/dist/core/dataLayer/DataLayerObjects.js.map +1 -1
- package/dist/core/dataLayer/DeleteBeforeObject.js +2 -1
- package/dist/core/dataLayer/DeleteBeforeObject.js.map +1 -1
- package/dist/core/dataLayer/DeleteObject.js +4 -3
- package/dist/core/dataLayer/DeleteObject.js.map +1 -1
- package/dist/core/dataLayer/DropAttributeObject.js +2 -1
- package/dist/core/dataLayer/DropAttributeObject.js.map +1 -1
- package/dist/core/dataLayer/GetBackupObject.js +4 -3
- package/dist/core/dataLayer/GetBackupObject.js.map +1 -1
- package/dist/core/dataLayer/InsertObject.js +4 -3
- package/dist/core/dataLayer/InsertObject.js.map +1 -1
- package/dist/core/dataLayer/ReadAuditLogObject.js +4 -3
- package/dist/core/dataLayer/ReadAuditLogObject.js.map +1 -1
- package/dist/core/dataLayer/SQLSearch.js +140 -78
- package/dist/core/dataLayer/SQLSearch.js.map +1 -1
- package/dist/core/dataLayer/SearchByConditionsObject.js +5 -7
- package/dist/core/dataLayer/SearchByConditionsObject.js.map +1 -1
- package/dist/core/dataLayer/SearchByHashObject.js +2 -1
- package/dist/core/dataLayer/SearchByHashObject.js.map +1 -1
- package/dist/core/dataLayer/SearchObject.js +2 -1
- package/dist/core/dataLayer/SearchObject.js.map +1 -1
- package/dist/core/dataLayer/SqlSearchObject.js +2 -1
- package/dist/core/dataLayer/SqlSearchObject.js.map +1 -1
- package/dist/core/dataLayer/UpdateObject.js +4 -3
- package/dist/core/dataLayer/UpdateObject.js.map +1 -1
- package/dist/core/dataLayer/UpsertObject.js +4 -3
- package/dist/core/dataLayer/UpsertObject.js.map +1 -1
- package/dist/core/dataLayer/bulkLoad.js +122 -88
- package/dist/core/dataLayer/bulkLoad.js.map +1 -1
- package/dist/core/dataLayer/delete.js +74 -39
- package/dist/core/dataLayer/delete.js.map +1 -1
- package/dist/core/dataLayer/export.js +90 -55
- package/dist/core/dataLayer/export.js.map +1 -1
- package/dist/core/dataLayer/getBackup.js +43 -11
- package/dist/core/dataLayer/getBackup.js.map +1 -1
- package/dist/core/dataLayer/harperBridge/BridgeMethods.js +41 -20
- package/dist/core/dataLayer/harperBridge/BridgeMethods.js.map +1 -1
- package/dist/core/dataLayer/harperBridge/ResourceBridge.js +26 -25
- package/dist/core/dataLayer/harperBridge/ResourceBridge.js.map +1 -1
- package/dist/core/dataLayer/harperBridge/TableSizeObject.js.map +1 -1
- package/dist/core/dataLayer/harperBridge/bridgeUtility/insertUpdateValidate.js +4 -4
- package/dist/core/dataLayer/harperBridge/harperBridge.js +38 -4
- package/dist/core/dataLayer/harperBridge/harperBridge.js.map +1 -1
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateAttribute.js +7 -6
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateAttribute.js.map +1 -1
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateRecords.js +4 -4
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateRecords.js.map +1 -1
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateSchema.js +1 -1
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateSchema.js.map +1 -1
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateTable.js +5 -4
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateTable.js.map +1 -1
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDeleteAuditLogsBefore.js +4 -4
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDeleteAuditLogsBefore.js.map +1 -1
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDeleteRecords.js +4 -4
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDropAttribute.js +5 -5
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDropAttribute.js.map +1 -1
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDropSchema.js +4 -4
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDropSchema.js.map +1 -1
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDropTable.js +5 -5
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDropTable.js.map +1 -1
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbFlush.js +1 -1
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbGetBackup.js +3 -3
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbGetDataByHash.js +1 -1
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbGetDataByValue.js +2 -2
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbGetDataByValue.js.map +1 -1
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbReadAuditLog.js +5 -5
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByConditions.js +8 -8
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByConditions.js.map +1 -1
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByHash.js +1 -1
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByValue.js +3 -3
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByValue.js.map +1 -1
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbUpdateRecords.js +3 -3
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbUpsertRecords.js +5 -5
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbUpsertRecords.js.map +1 -1
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBCreateAttributeObject.js +1 -1
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBCreateAttributeObject.js.map +1 -1
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializeHashSearch.js +2 -2
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializeHashSearch.js.map +1 -1
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializePaths.js +2 -2
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbCheckForNewAttributes.js +4 -4
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbCheckForNewAttributes.js.map +1 -1
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbCreateTransactionsAuditEnvironment.js +5 -3
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbCreateTransactionsAuditEnvironment.js.map +1 -1
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbGetTableSize.js +2 -2
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbProcessRows.js +4 -4
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbProcessRows.js.map +1 -1
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbSearch.js +5 -5
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbWriteTransaction.js +4 -4
- package/dist/core/dataLayer/hdbInfoController.js +66 -31
- package/dist/core/dataLayer/hdbInfoController.js.map +1 -1
- package/dist/core/dataLayer/insert.js +63 -28
- package/dist/core/dataLayer/insert.js.map +1 -1
- package/dist/core/dataLayer/readAuditLog.js +45 -13
- package/dist/core/dataLayer/readAuditLog.js.map +1 -1
- package/dist/core/dataLayer/schema.js +124 -89
- package/dist/core/dataLayer/schema.js.map +1 -1
- package/dist/core/dataLayer/schemaDescribe.js +78 -41
- package/dist/core/dataLayer/schemaDescribe.js.map +1 -1
- package/dist/core/dataLayer/search.js +12 -13
- package/dist/core/dataLayer/search.js.map +1 -1
- package/dist/core/dataLayer/transaction.js +3 -4
- package/dist/core/dataLayer/transaction.js.map +1 -1
- package/dist/core/dataLayer/update.js +53 -18
- package/dist/core/dataLayer/update.js.map +1 -1
- package/dist/core/globals.js +1 -0
- package/dist/core/globals.js.map +1 -1
- package/dist/core/index.js +4 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/json/systemSchema.json +65 -0
- package/dist/core/launchServiceScripts/utility/checkNodeVersion.js +3 -0
- package/dist/core/launchServiceScripts/utility/checkNodeVersion.js.map +1 -1
- package/dist/core/resources/DatabaseTransaction.js +39 -15
- package/dist/core/resources/DatabaseTransaction.js.map +1 -1
- package/dist/core/resources/ErrorResource.js +3 -1
- package/dist/core/resources/ErrorResource.js.map +1 -1
- package/dist/core/resources/LMDBTransaction.js +18 -7
- package/dist/core/resources/LMDBTransaction.js.map +1 -1
- package/dist/core/resources/RecordEncoder.js +5 -2
- package/dist/core/resources/RecordEncoder.js.map +1 -1
- package/dist/core/resources/RequestTarget.js.map +1 -1
- package/dist/core/resources/Resource.js +37 -10
- package/dist/core/resources/Resource.js.map +1 -1
- package/dist/core/resources/ResourceInterface.js +20 -0
- package/dist/core/resources/ResourceInterface.js.map +1 -1
- package/dist/core/resources/Resources.js +7 -6
- package/dist/core/resources/Resources.js.map +1 -1
- package/dist/core/resources/RocksIndexStore.js +3 -0
- package/dist/core/resources/RocksIndexStore.js.map +1 -1
- package/dist/core/resources/RocksTransactionLogStore.js +46 -27
- package/dist/core/resources/RocksTransactionLogStore.js.map +1 -1
- package/dist/core/resources/Table.js +267 -107
- package/dist/core/resources/Table.js.map +1 -1
- package/dist/core/resources/analytics/metadata.js +1 -0
- package/dist/core/resources/analytics/metadata.js.map +1 -1
- package/dist/core/resources/analytics/read.js +16 -5
- package/dist/core/resources/analytics/read.js.map +1 -1
- package/dist/core/resources/analytics/write.js +232 -20
- package/dist/core/resources/analytics/write.js.map +1 -1
- package/dist/core/resources/auditStore.js +13 -8
- package/dist/core/resources/auditStore.js.map +1 -1
- package/dist/core/resources/blob.js +8 -8
- package/dist/core/resources/blob.js.map +1 -1
- package/dist/core/resources/dataLoader.js +13 -13
- package/dist/core/resources/databases.js +160 -52
- package/dist/core/resources/databases.js.map +1 -1
- package/dist/core/resources/graphql.js +224 -174
- package/dist/core/resources/graphql.js.map +1 -1
- package/dist/core/resources/indexes/HierarchicalNavigableSmallWorld.js +308 -59
- package/dist/core/resources/indexes/HierarchicalNavigableSmallWorld.js.map +1 -1
- package/dist/core/resources/indexes/vector.js +14 -0
- package/dist/core/resources/indexes/vector.js.map +1 -1
- package/dist/core/resources/loadEnv.js +21 -18
- package/dist/core/resources/loadEnv.js.map +1 -1
- package/dist/core/resources/login.js +5 -4
- package/dist/core/resources/login.js.map +1 -1
- package/dist/core/resources/models/Models.js +265 -0
- package/dist/core/resources/models/Models.js.map +1 -0
- package/dist/core/resources/models/TestBackend.js +71 -0
- package/dist/core/resources/models/TestBackend.js.map +1 -0
- package/dist/core/resources/models/agentLoop.js +746 -0
- package/dist/core/resources/models/agentLoop.js.map +1 -0
- package/dist/core/resources/models/analyticsTable.js +166 -0
- package/dist/core/resources/models/analyticsTable.js.map +1 -0
- package/dist/core/resources/models/backendHelpers.js +109 -0
- package/dist/core/resources/models/backendHelpers.js.map +1 -0
- package/dist/core/resources/models/backendRegistry.js +54 -0
- package/dist/core/resources/models/backendRegistry.js.map +1 -0
- package/dist/core/resources/models/bootstrap.js +112 -0
- package/dist/core/resources/models/bootstrap.js.map +1 -0
- package/dist/core/resources/models/embedHook.js +127 -0
- package/dist/core/resources/models/embedHook.js.map +1 -0
- package/dist/core/resources/models/types.js +11 -0
- package/dist/core/resources/models/types.js.map +1 -0
- package/dist/core/resources/replayLogs.js +7 -1
- package/dist/core/resources/replayLogs.js.map +1 -1
- package/dist/core/resources/roles.js +67 -71
- package/dist/core/resources/roles.js.map +1 -1
- package/dist/core/resources/search.js +349 -140
- package/dist/core/resources/search.js.map +1 -1
- package/dist/core/resources/tracked.js +14 -14
- package/dist/core/resources/tracked.js.map +1 -1
- package/dist/core/resources/transaction.js +1 -1
- package/dist/core/resources/transaction.js.map +1 -1
- package/dist/core/resources/transactionBroadcast.js.map +1 -1
- package/dist/core/security/auth.js +34 -25
- package/dist/core/security/auth.js.map +1 -1
- package/dist/core/security/certificateVerification/crlVerification.js +7 -1
- package/dist/core/security/certificateVerification/crlVerification.js.map +1 -1
- package/dist/core/security/cryptoHash.js +37 -5
- package/dist/core/security/cryptoHash.js.map +1 -1
- package/dist/core/security/data_objects/PermissionAttributeResponseObject.js +4 -1
- package/dist/core/security/data_objects/PermissionAttributeResponseObject.js.map +1 -1
- package/dist/core/security/data_objects/PermissionResponseObject.js +15 -8
- package/dist/core/security/data_objects/PermissionResponseObject.js.map +1 -1
- package/dist/core/security/data_objects/PermissionTableResponseObject.js +6 -1
- package/dist/core/security/data_objects/PermissionTableResponseObject.js.map +1 -1
- package/dist/core/security/fastifyAuth.js +131 -22
- package/dist/core/security/fastifyAuth.js.map +1 -1
- package/dist/core/security/impersonation.js +15 -15
- package/dist/core/security/jsLoader.js +18 -5
- package/dist/core/security/jsLoader.js.map +1 -1
- package/dist/core/security/keys.js +160 -114
- package/dist/core/security/keys.js.map +1 -1
- package/dist/core/security/permissionsTranslator.js +2 -2
- package/dist/core/security/role.js +70 -35
- package/dist/core/security/role.js.map +1 -1
- package/dist/core/security/tokenAuthentication.js +57 -27
- package/dist/core/security/tokenAuthentication.js.map +1 -1
- package/dist/core/security/user.js +74 -38
- package/dist/core/security/user.js.map +1 -1
- package/dist/core/server/DurableSubscriptionsSession.js +71 -55
- package/dist/core/server/DurableSubscriptionsSession.js.map +1 -1
- package/dist/core/server/REST.js +17 -16
- package/dist/core/server/REST.js.map +1 -1
- package/dist/core/server/Server.js +1 -1
- package/dist/core/server/Server.js.map +1 -1
- package/dist/core/server/fastifyRoutes/helpers/getCORSOptions.js +1 -1
- package/dist/core/server/fastifyRoutes/helpers/getHeaderTimeoutConfig.js +1 -1
- package/dist/core/server/fastifyRoutes/helpers/getServerOptions.js +1 -1
- package/dist/core/server/fastifyRoutes.js +34 -30
- package/dist/core/server/fastifyRoutes.js.map +1 -1
- package/dist/core/server/graphqlQuerying.js +8 -7
- package/dist/core/server/graphqlQuerying.js.map +1 -1
- package/dist/core/server/http.js +523 -47
- package/dist/core/server/http.js.map +1 -1
- package/dist/core/server/itc/serverHandlers.js +66 -15
- package/dist/core/server/itc/serverHandlers.js.map +1 -1
- package/dist/core/server/jobs/JobObject.js +53 -7
- package/dist/core/server/jobs/JobObject.js.map +1 -1
- package/dist/core/server/jobs/jobProcess.js +64 -24
- package/dist/core/server/jobs/jobProcess.js.map +1 -1
- package/dist/core/server/jobs/jobRunner.js +68 -30
- package/dist/core/server/jobs/jobRunner.js.map +1 -1
- package/dist/core/server/jobs/jobs.js +93 -61
- package/dist/core/server/jobs/jobs.js.map +1 -1
- package/dist/core/server/loadRootComponents.js +1 -1
- package/dist/core/server/middlewareChain.js +252 -0
- package/dist/core/server/middlewareChain.js.map +1 -0
- package/dist/core/server/mqtt.js +22 -17
- package/dist/core/server/mqtt.js.map +1 -1
- package/dist/core/server/nodeName.js +44 -13
- package/dist/core/server/nodeName.js.map +1 -1
- package/dist/core/server/operationsServer.js +106 -33
- package/dist/core/server/operationsServer.js.map +1 -1
- package/dist/core/server/serverHelpers/Headers.js +2 -0
- package/dist/core/server/serverHelpers/Headers.js.map +1 -1
- package/dist/core/server/serverHelpers/JSONStream.js +12 -3
- package/dist/core/server/serverHelpers/JSONStream.js.map +1 -1
- package/dist/core/server/serverHelpers/Request.js +370 -9
- package/dist/core/server/serverHelpers/Request.js.map +1 -1
- package/dist/core/server/serverHelpers/contentTypes.js +36 -7
- package/dist/core/server/serverHelpers/contentTypes.js.map +1 -1
- package/dist/core/server/serverHelpers/multipartParser.js +142 -0
- package/dist/core/server/serverHelpers/multipartParser.js.map +1 -0
- package/dist/core/server/serverHelpers/progressEmitter.js +103 -0
- package/dist/core/server/serverHelpers/progressEmitter.js.map +1 -0
- package/dist/core/server/serverHelpers/serverHandlers.js +38 -7
- package/dist/core/server/serverHelpers/serverHandlers.js.map +1 -1
- package/dist/core/server/serverHelpers/serverUtilities.js +97 -93
- package/dist/core/server/serverHelpers/serverUtilities.js.map +1 -1
- package/dist/core/server/static.js +8 -5
- package/dist/core/server/static.js.map +1 -1
- package/dist/core/server/status/index.js +3 -3
- package/dist/core/server/storageReclamation.js +68 -9
- package/dist/core/server/storageReclamation.js.map +1 -1
- package/dist/core/server/threads/itc.js +7 -4
- package/dist/core/server/threads/itc.js.map +1 -1
- package/dist/core/server/threads/manageThreads.js +110 -26
- package/dist/core/server/threads/manageThreads.js.map +1 -1
- package/dist/core/server/threads/socketRouter.js +8 -271
- package/dist/core/server/threads/socketRouter.js.map +1 -1
- package/dist/core/server/threads/threadServer.js +360 -118
- package/dist/core/server/threads/threadServer.js.map +1 -1
- package/dist/core/server/threads/workerProcessGuard.js +114 -0
- package/dist/core/server/threads/workerProcessGuard.js.map +1 -0
- package/dist/core/server/throttle.js +17 -0
- package/dist/core/server/throttle.js.map +1 -1
- package/dist/core/sqlTranslator/SelectValidator.js +86 -47
- package/dist/core/sqlTranslator/SelectValidator.js.map +1 -1
- package/dist/core/sqlTranslator/alasqlFunctionImporter.js +40 -3
- package/dist/core/sqlTranslator/alasqlFunctionImporter.js.map +1 -1
- package/dist/core/sqlTranslator/deleteTranslator.js +48 -14
- package/dist/core/sqlTranslator/deleteTranslator.js.map +1 -1
- package/dist/core/sqlTranslator/index.js +69 -30
- package/dist/core/sqlTranslator/index.js.map +1 -1
- package/dist/core/sqlTranslator/sql_statement_bucket.js +55 -13
- package/dist/core/sqlTranslator/sql_statement_bucket.js.map +1 -1
- package/dist/core/upgrade/UpgradeObjects.js +37 -4
- package/dist/core/upgrade/UpgradeObjects.js.map +1 -1
- package/dist/core/upgrade/directives/5-2-0.js +77 -0
- package/dist/core/upgrade/directives/5-2-0.js.map +1 -0
- package/dist/core/upgrade/directives/directivesController.js +52 -11
- package/dist/core/upgrade/directives/directivesController.js.map +1 -1
- package/dist/core/upgrade/directivesManager.js +53 -18
- package/dist/core/upgrade/directivesManager.js.map +1 -1
- package/dist/core/upgrade/upgradePrompt.js +65 -30
- package/dist/core/upgrade/upgradePrompt.js.map +1 -1
- package/dist/core/upgrade/upgradeUtilities.js +37 -5
- package/dist/core/upgrade/upgradeUtilities.js.map +1 -1
- package/dist/core/utility/OperationFunctionCaller.js +45 -10
- package/dist/core/utility/OperationFunctionCaller.js.map +1 -1
- package/dist/core/utility/assignCmdEnvVariables.js +8 -4
- package/dist/core/utility/assignCmdEnvVariables.js.map +1 -1
- package/dist/core/utility/common_utils.js +140 -79
- package/dist/core/utility/common_utils.js.map +1 -1
- package/dist/core/utility/environment/environmentManager.js +75 -29
- package/dist/core/utility/environment/environmentManager.js.map +1 -1
- package/dist/core/utility/environment/systemInformation.js +27 -16
- package/dist/core/utility/environment/systemInformation.js.map +1 -1
- package/dist/core/utility/errors/commonErrors.js +49 -18
- package/dist/core/utility/errors/commonErrors.js.map +1 -1
- package/dist/core/utility/errors/hdbError.js +65 -26
- package/dist/core/utility/errors/hdbError.js.map +1 -1
- package/dist/core/utility/expandEnvVar.js +113 -0
- package/dist/core/utility/expandEnvVar.js.map +1 -0
- package/dist/core/utility/functions/geo.js +2 -2
- package/dist/core/utility/functions/sql/alaSQLExtension.js +1 -1
- package/dist/core/utility/globalSchema.js +14 -11
- package/dist/core/utility/globalSchema.js.map +1 -1
- package/dist/core/utility/hdbTerms.js +56 -0
- package/dist/core/utility/hdbTerms.js.map +1 -1
- package/dist/core/utility/install/checkJWTTokensExist.js +1 -1
- package/dist/core/utility/install/installer.js +106 -70
- package/dist/core/utility/install/installer.js.map +1 -1
- package/dist/core/utility/installation.js +3 -3
- package/dist/core/utility/lmdb/DBIDefinition.js +5 -1
- package/dist/core/utility/lmdb/DBIDefinition.js.map +1 -1
- package/dist/core/utility/lmdb/DeleteRecordsResponseObject.js +2 -1
- package/dist/core/utility/lmdb/DeleteRecordsResponseObject.js.map +1 -1
- package/dist/core/utility/lmdb/InsertRecordsResponseObject.js +2 -1
- package/dist/core/utility/lmdb/InsertRecordsResponseObject.js.map +1 -1
- package/dist/core/utility/lmdb/OpenDBIObject.js +54 -6
- package/dist/core/utility/lmdb/OpenDBIObject.js.map +1 -1
- package/dist/core/utility/lmdb/OpenEnvironmentObject.js +52 -4
- package/dist/core/utility/lmdb/OpenEnvironmentObject.js.map +1 -1
- package/dist/core/utility/lmdb/UpdateRecordsResponseObject.js +2 -1
- package/dist/core/utility/lmdb/UpdateRecordsResponseObject.js.map +1 -1
- package/dist/core/utility/lmdb/UpsertRecordsResponseObject.js +2 -1
- package/dist/core/utility/lmdb/UpsertRecordsResponseObject.js.map +1 -1
- package/dist/core/utility/lmdb/cleanLMDBMap.js +44 -7
- package/dist/core/utility/lmdb/cleanLMDBMap.js.map +1 -1
- package/dist/core/utility/lmdb/commonUtility.js +46 -17
- package/dist/core/utility/lmdb/commonUtility.js.map +1 -1
- package/dist/core/utility/lmdb/deleteUtility.js +51 -16
- package/dist/core/utility/lmdb/deleteUtility.js.map +1 -1
- package/dist/core/utility/lmdb/environmentUtility.js +91 -51
- package/dist/core/utility/lmdb/environmentUtility.js.map +1 -1
- package/dist/core/utility/lmdb/searchCursorFunctions.js +46 -14
- package/dist/core/utility/lmdb/searchCursorFunctions.js.map +1 -1
- package/dist/core/utility/lmdb/searchUtility.js +91 -55
- package/dist/core/utility/lmdb/searchUtility.js.map +1 -1
- package/dist/core/utility/lmdb/terms.js +12 -22
- package/dist/core/utility/lmdb/terms.js.map +1 -1
- package/dist/core/utility/lmdb/writeUtility.js +61 -28
- package/dist/core/utility/lmdb/writeUtility.js.map +1 -1
- package/dist/core/utility/logging/harper_logger.js +176 -81
- package/dist/core/utility/logging/harper_logger.js.map +1 -1
- package/dist/core/utility/logging/logRotator.js +65 -28
- package/dist/core/utility/logging/logRotator.js.map +1 -1
- package/dist/core/utility/logging/logger.js +4 -4
- package/dist/core/utility/logging/readLog.js +54 -17
- package/dist/core/utility/logging/readLog.js.map +1 -1
- package/dist/core/utility/logging/transactionLog.js +51 -16
- package/dist/core/utility/logging/transactionLog.js.map +1 -1
- package/dist/core/utility/mount_hdb.js +54 -17
- package/dist/core/utility/mount_hdb.js.map +1 -1
- package/dist/core/utility/npmUtilities.js +54 -19
- package/dist/core/utility/npmUtilities.js.map +1 -1
- package/dist/core/utility/operation_authorization.js +135 -86
- package/dist/core/utility/operation_authorization.js.map +1 -1
- package/dist/core/utility/packageUtils.js +7 -17
- package/dist/core/utility/packageUtils.js.map +1 -1
- package/dist/core/utility/password.js +2 -2
- package/dist/core/utility/processManagement/processManagement.js +2 -2
- package/dist/core/utility/processManagement/servicesConfig.js +1 -1
- package/dist/core/utility/signalling.js +51 -16
- package/dist/core/utility/signalling.js.map +1 -1
- package/dist/core/utility/watcherFallback.js +73 -0
- package/dist/core/utility/watcherFallback.js.map +1 -0
- package/dist/core/validation/analyticsValidator.js +79 -0
- package/dist/core/validation/analyticsValidator.js.map +1 -0
- package/dist/core/validation/bulkDeleteValidator.js +49 -11
- package/dist/core/validation/bulkDeleteValidator.js.map +1 -1
- package/dist/core/validation/check_permissions.js +38 -3
- package/dist/core/validation/check_permissions.js.map +1 -1
- package/dist/core/validation/common_validators.js +62 -31
- package/dist/core/validation/common_validators.js.map +1 -1
- package/dist/core/validation/configValidator.js +189 -54
- package/dist/core/validation/configValidator.js.map +1 -1
- package/dist/core/validation/deleteValidator.js +49 -11
- package/dist/core/validation/deleteValidator.js.map +1 -1
- package/dist/core/validation/fileLoadValidator.js +67 -32
- package/dist/core/validation/fileLoadValidator.js.map +1 -1
- package/dist/core/validation/insertValidator.js +48 -10
- package/dist/core/validation/insertValidator.js.map +1 -1
- package/dist/core/validation/installValidator.js +47 -10
- package/dist/core/validation/installValidator.js.map +1 -1
- package/dist/core/validation/readLogValidator.js +60 -22
- package/dist/core/validation/readLogValidator.js.map +1 -1
- package/dist/core/validation/role_validation.js +55 -19
- package/dist/core/validation/role_validation.js.map +1 -1
- package/dist/core/validation/schemaMetadataValidator.js +11 -12
- package/dist/core/validation/schemaMetadataValidator.js.map +1 -1
- package/dist/core/validation/searchValidator.js +82 -43
- package/dist/core/validation/searchValidator.js.map +1 -1
- package/dist/core/validation/transactionLogValidator.js +52 -17
- package/dist/core/validation/transactionLogValidator.js.map +1 -1
- package/dist/core/validation/user_validation.js +38 -6
- package/dist/core/validation/user_validation.js.map +1 -1
- package/dist/core/validation/validationWrapper.js +4 -5
- package/dist/core/validation/validationWrapper.js.map +1 -1
- package/dist/licensing/usageLicensing.js +30 -21
- package/dist/licensing/usageLicensing.js.map +1 -1
- package/dist/replication/knownNodes.js +173 -39
- package/dist/replication/knownNodes.js.map +1 -1
- package/dist/replication/replicationConnection.js +441 -85
- package/dist/replication/replicationConnection.js.map +1 -1
- package/dist/replication/replicator.js +44 -26
- package/dist/replication/replicator.js.map +1 -1
- package/dist/replication/setNode.js +22 -2
- package/dist/replication/setNode.js.map +1 -1
- package/dist/replication/subscriptionManager.js +121 -9
- package/dist/replication/subscriptionManager.js.map +1 -1
- package/dist/security/certificate.js +41 -6
- package/dist/security/certificate.js.map +1 -1
- package/dist/security/sshKeyOperations.js +35 -2
- package/dist/security/sshKeyOperations.js.map +1 -1
- package/licensing/usageLicensing.ts +32 -37
- package/npm-shrinkwrap.json +8994 -4305
- package/package.json +16 -11
- package/replication/DESIGN.md +139 -0
- package/replication/knownNodes.ts +166 -43
- package/replication/replicationConnection.ts +475 -92
- package/replication/replicator.ts +42 -25
- package/replication/setNode.ts +28 -9
- package/replication/subscriptionManager.ts +138 -14
- package/security/certificate.ts +8 -4
- package/security/sshKeyOperations.ts +1 -1
- package/static/defaultConfig.yaml +1 -0
- package/studio/web/assets/{index-CmtPP0YO.js → index-COfIkCT-.js} +5 -5
- package/studio/web/assets/index-COfIkCT-.js.map +1 -0
- package/studio/web/assets/{index.lazy-C8jvGtlu.js → index.lazy-CIvl7Fj9.js} +2 -2
- package/studio/web/assets/{index.lazy-C8jvGtlu.js.map → index.lazy-CIvl7Fj9.js.map} +1 -1
- package/studio/web/assets/{profile-O0DYlJUv.js → profile-B2ZVB--r.js} +2 -2
- package/studio/web/assets/{profile-O0DYlJUv.js.map → profile-B2ZVB--r.js.map} +1 -1
- package/studio/web/assets/{status-BIlJkJby.js → status-Db6WBmhf.js} +2 -2
- package/studio/web/assets/{status-BIlJkJby.js.map → status-Db6WBmhf.js.map} +1 -1
- package/studio/web/index.html +1 -1
- package/core/bin/cliOperations.js +0 -159
- package/core/bin/lite.js +0 -5
- package/core/bin/stop.js +0 -21
- package/core/dataLayer/harperBridge/BridgeMethods.js +0 -85
- package/core/utility/globalSchema.js +0 -35
- package/core/utility/lmdb/OpenDBIObject.js +0 -31
- package/studio/web/assets/index-CmtPP0YO.js.map +0 -1
|
@@ -37,6 +37,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.NodeReplicationConnection = exports.databaseSubscriptions = exports.tableUpdateListeners = exports.RECEIVING_STATUS_RECEIVING = exports.RECEIVING_STATUS_WAITING = exports.BACK_PRESSURE_RATIO_POSITION = exports.RECEIVING_STATUS_POSITION = exports.LATENCY_POSITION = exports.SENDING_TIME_POSITION = exports.RECEIVED_TIME_POSITION = exports.RECEIVED_VERSION_POSITION = exports.CONFIRMATION_STATUS_POSITION = exports.OPERATION_REQUEST = void 0;
|
|
40
|
+
exports.shouldTerminateIdlePing = shouldTerminateIdlePing;
|
|
41
|
+
exports.createReceiveWatchdog = createReceiveWatchdog;
|
|
40
42
|
exports.createWebSocket = createWebSocket;
|
|
41
43
|
exports.replicateOverWS = replicateOverWS;
|
|
42
44
|
const databases_ts_1 = require("../core/resources/databases.js");
|
|
@@ -45,10 +47,11 @@ const nodeIdMapping_ts_1 = require("../core/resources/nodeIdMapping.js");
|
|
|
45
47
|
const transactionBroadcast_ts_1 = require("../core/resources/transactionBroadcast.js");
|
|
46
48
|
const replicator_ts_1 = require("./replicator.js");
|
|
47
49
|
const nodeName_ts_1 = require("../core/server/nodeName.js");
|
|
48
|
-
const
|
|
50
|
+
const env = __importStar(require("../core/utility/environment/environmentManager.js"));
|
|
49
51
|
const hdbTerms_ts_1 = require("../core/utility/hdbTerms.js");
|
|
50
52
|
const RecordEncoder_ts_1 = require("../core/resources/RecordEncoder.js");
|
|
51
53
|
const msgpackr_1 = require("msgpackr");
|
|
54
|
+
const structon_1 = require("structon");
|
|
52
55
|
const ws_1 = require("ws");
|
|
53
56
|
const worker_threads_1 = require("worker_threads");
|
|
54
57
|
const harper_logger_js_1 = __importDefault(require("../core/utility/logging/harper_logger.js"));
|
|
@@ -65,6 +68,13 @@ const blob_ts_1 = require("../core/resources/blob.js");
|
|
|
65
68
|
const node_stream_1 = require("node:stream");
|
|
66
69
|
const lmdb_1 = require("lmdb");
|
|
67
70
|
const logger = forComponent('replication').conditional;
|
|
71
|
+
// msgpackr v2 removed the built-in `randomAccessStructure` option; that random-access
|
|
72
|
+
// struct support now lives in the `structon` package (the same wrapper core's
|
|
73
|
+
// RecordEncoder uses). Replication decoders must be structon-wrapped so they install
|
|
74
|
+
// the `_readStruct` hook and can decode typed-struct records — without it, struct
|
|
75
|
+
// marker bytes (0x20–0x3f) decode as plain integers and the decode aborts with
|
|
76
|
+
// "Data read, but end of buffer not reached".
|
|
77
|
+
const StructonPackr = (0, structon_1.createStructon)(msgpackr_1.Packr);
|
|
68
78
|
// these are the codes we use for the different commands
|
|
69
79
|
const SUBSCRIPTION_REQUEST = 129;
|
|
70
80
|
const NODE_NAME = 140;
|
|
@@ -81,6 +91,8 @@ const COMMITTED_UPDATE = 144;
|
|
|
81
91
|
const DB_SCHEMA = 145;
|
|
82
92
|
const BLOB_CHUNK = 146;
|
|
83
93
|
const SUBSCRIPTION_UPDATE = 147;
|
|
94
|
+
const COPY_START = 148; // leader -> follower: a bulk table copy is starting; carries copyStartTime
|
|
95
|
+
const COPY_COMPLETE = 149; // leader -> follower: the bulk table copy finished; follower clears its resume cursor
|
|
84
96
|
exports.CONFIRMATION_STATUS_POSITION = 0;
|
|
85
97
|
exports.RECEIVED_VERSION_POSITION = 1;
|
|
86
98
|
exports.RECEIVED_TIME_POSITION = 2;
|
|
@@ -90,12 +102,22 @@ exports.RECEIVING_STATUS_POSITION = 5;
|
|
|
90
102
|
exports.BACK_PRESSURE_RATIO_POSITION = 6;
|
|
91
103
|
exports.RECEIVING_STATUS_WAITING = 0;
|
|
92
104
|
exports.RECEIVING_STATUS_RECEIVING = 1;
|
|
93
|
-
const MAX_PAYLOAD =
|
|
105
|
+
const MAX_PAYLOAD = env.get('replication_maxPayload') ?? 100_000_000;
|
|
94
106
|
// When receiving a replication message, we apply per-record backpressure to keep a single
|
|
95
107
|
// large batch from synchronously decoding thousands of records and ballooning the worker
|
|
96
108
|
// heap past its limit. If the local replicator queue grows beyond this threshold we pause
|
|
97
109
|
// the WS connection and wait for it to drain before continuing the decode loop.
|
|
98
|
-
const RECEIVE_EVENT_HIGH_WATER_MARK =
|
|
110
|
+
const RECEIVE_EVENT_HIGH_WATER_MARK = env.get('replication_receiveEventHighWaterMark') ?? 100;
|
|
111
|
+
// Even when the consumer keeps up (queue below the high-water mark), a single large inbound message
|
|
112
|
+
// would otherwise decode thousands of records in one synchronous turn — pegging the worker, blocking
|
|
113
|
+
// replication ping responses, and tripping core's "JavaScript execution has taken too long" monitor
|
|
114
|
+
// (MAX_EVENT_DELAY_TIME = 3 s). Yield the event loop at least this often (ms) while decoding so the
|
|
115
|
+
// worker stays responsive during a bulk copy/clone.
|
|
116
|
+
const RECEIVE_YIELD_INTERVAL = env.get('replication_receiveYieldInterval') ?? 100;
|
|
117
|
+
// During a bulk clone copy the leader flushes a checkpoint transaction every this many records so the
|
|
118
|
+
// follower commits incrementally and persists a resume cursor. On reconnect the copy resumes from that
|
|
119
|
+
// cursor instead of restarting from zero. Larger = less overhead but coarser resume granularity.
|
|
120
|
+
const COPY_CHECKPOINT_RECORDS = env.get('replication_copyCheckpointRecords') ?? 1000;
|
|
99
121
|
exports.tableUpdateListeners = new Map();
|
|
100
122
|
// This a map of the database name to the subscription object, for the subscriptions from our tables to the replication module
|
|
101
123
|
// when we receive messages from other nodes, we then forward them on to as a notification on these subscriptions
|
|
@@ -108,7 +130,91 @@ const SKIPPED_MESSAGE_SEQUENCE_UPDATE_DELAY = 300;
|
|
|
108
130
|
// We want it be fairly quick so we can let the sending node know that we have received and committed the update.
|
|
109
131
|
// (but still allow for batching so we aren't sending out a message for every update under load)
|
|
110
132
|
const COMMITTED_UPDATE_DELAY = 2;
|
|
111
|
-
const PING_INTERVAL = 30000;
|
|
133
|
+
const PING_INTERVAL = env.get(hdbTerms_ts_1.CONFIG_PARAMS.REPLICATION_PINGINTERVAL) ?? 30000;
|
|
134
|
+
// Time (ms) without any socket activity before a connection is treated as dead.
|
|
135
|
+
const PING_TIMEOUT = env.get(hdbTerms_ts_1.CONFIG_PARAMS.REPLICATION_PINGTIMEOUT) ?? PING_INTERVAL * 2;
|
|
136
|
+
// The receive-side watchdog fires after this much silence on a replication WS. Both client and
|
|
137
|
+
// server arm it: the client also runs an active 30s sendPing tick that should normally catch a
|
|
138
|
+
// silent peer first, but if that tick is missed (event-loop stall, ws.terminate() not propagating
|
|
139
|
+
// to 'close', etc.) this timer-based watchdog is the belt-and-suspenders that forces the
|
|
140
|
+
// reconnect — see harper-pro#233.
|
|
141
|
+
const RECEIVE_SILENCE_THRESHOLD_MS = PING_TIMEOUT;
|
|
142
|
+
/**
|
|
143
|
+
* Decide whether an idle replication connection should be terminated as dead.
|
|
144
|
+
*
|
|
145
|
+
* Liveness is measured from the last observed socket byte movement (in either direction), not from a
|
|
146
|
+
* single ping interval. A bulk transfer — notably the initial clone copy of a large table — makes
|
|
147
|
+
* slow but real progress: the sender's socket buffer drains in bursts as the peer consumes, so bytes
|
|
148
|
+
* keep moving within the timeout window even while it is otherwise stalled. A genuinely dead or
|
|
149
|
+
* unreachable peer moves no bytes at all, so it still trips the timeout. We deliberately do NOT exempt
|
|
150
|
+
* the sender's `isPausedForBackPressure` drain-wait here: if the peer dies after we have filled our
|
|
151
|
+
* socket buffer, the drain event never fires, and exempting it would hang the connection forever.
|
|
152
|
+
*
|
|
153
|
+
* The one exemption is `pauseReasons > 0`: the receiver has intentionally stopped reading to drain its
|
|
154
|
+
* own queue. That stall is local and self-clearing (it does not depend on the peer), so it is never a
|
|
155
|
+
* death signal; the caller keeps liveness fresh while paused and resumes normal detection afterward.
|
|
156
|
+
*/
|
|
157
|
+
function shouldTerminateIdlePing(idleMs, pingTimeout, pauseReasons) {
|
|
158
|
+
return pauseReasons === 0 && idleMs >= pingTimeout;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Receive-side silence watchdog. Arm with `reset()` whenever incoming activity is observed
|
|
162
|
+
* (peer ping, pong, message). If `intervalMs` elapses with the underlying socket's `bytesRead`
|
|
163
|
+
* unchanged, `onSilence` is invoked exactly once.
|
|
164
|
+
*
|
|
165
|
+
* Only `bytesRead` is checked — `bytesWritten` reflects our own outbound traffic (pings, blob
|
|
166
|
+
* sends) and is not proof that the peer is alive. Including it would let our own keepalive
|
|
167
|
+
* pings suppress the watchdog in the exact missed-sendPing scenario this is meant to recover.
|
|
168
|
+
*
|
|
169
|
+
* Callers should suspend the watchdog (via `stop()`) when the underlying WS is intentionally
|
|
170
|
+
* paused for backpressure: `bytesRead` is frozen by design while paused and would otherwise
|
|
171
|
+
* cause a spurious termination of a healthy connection.
|
|
172
|
+
*
|
|
173
|
+
* Exported so the timer logic can be exercised in isolation by `unitTests/replication/
|
|
174
|
+
* receiveWatchdog.test.mjs` — production callers go through `replicateOverWS`.
|
|
175
|
+
*/
|
|
176
|
+
function createReceiveWatchdog(opts) {
|
|
177
|
+
let timer;
|
|
178
|
+
let bytesReadAtArm = 0;
|
|
179
|
+
let lastResetAt = 0;
|
|
180
|
+
// Coalesce rapid reset() calls (e.g. message frames arriving thousands of times per second
|
|
181
|
+
// during a large copy) so we do not churn setTimeout/clearTimeout per frame. Granularity loss
|
|
182
|
+
// is small relative to intervalMs — at worst the watchdog fires this much earlier or later.
|
|
183
|
+
const throttleMs = Math.min(1000, Math.max(100, opts.intervalMs / 30));
|
|
184
|
+
function check() {
|
|
185
|
+
const current = opts.getBytesRead();
|
|
186
|
+
if (current === bytesReadAtArm) {
|
|
187
|
+
timer = undefined;
|
|
188
|
+
opts.onSilence();
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
// Bytes advanced since the last arm — but the activity may have been swallowed by the
|
|
192
|
+
// reset() throttle, so we cannot rely on an external caller to re-arm us. Re-arm from
|
|
193
|
+
// the new baseline; otherwise a throttled-reset-then-silence sequence would leave the
|
|
194
|
+
// watchdog permanently inactive (see PR #234 review).
|
|
195
|
+
bytesReadAtArm = current;
|
|
196
|
+
lastResetAt = Date.now();
|
|
197
|
+
timer = setTimeout(check, opts.intervalMs).unref();
|
|
198
|
+
}
|
|
199
|
+
return {
|
|
200
|
+
reset() {
|
|
201
|
+
const now = Date.now();
|
|
202
|
+
if (timer && now - lastResetAt < throttleMs)
|
|
203
|
+
return;
|
|
204
|
+
lastResetAt = now;
|
|
205
|
+
if (timer)
|
|
206
|
+
clearTimeout(timer);
|
|
207
|
+
bytesReadAtArm = opts.getBytesRead();
|
|
208
|
+
timer = setTimeout(check, opts.intervalMs).unref();
|
|
209
|
+
},
|
|
210
|
+
stop() {
|
|
211
|
+
if (timer) {
|
|
212
|
+
clearTimeout(timer);
|
|
213
|
+
timer = undefined;
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
};
|
|
217
|
+
}
|
|
112
218
|
let secureContexts;
|
|
113
219
|
let replicationSecureContext;
|
|
114
220
|
async function createWebSocket(url, options) {
|
|
@@ -196,6 +302,7 @@ class NodeReplicationConnection extends events_1.EventEmitter {
|
|
|
196
302
|
databaseName;
|
|
197
303
|
nodeName;
|
|
198
304
|
authorization;
|
|
305
|
+
tentativeNode;
|
|
199
306
|
constructor(url, subscription, databaseName, nodeName, authorization) {
|
|
200
307
|
super();
|
|
201
308
|
this.url = url;
|
|
@@ -205,6 +312,8 @@ class NodeReplicationConnection extends events_1.EventEmitter {
|
|
|
205
312
|
this.nodeName = this.nodeName ?? (0, replicator_ts_1.urlToNodeName)(url);
|
|
206
313
|
}
|
|
207
314
|
async connect() {
|
|
315
|
+
if (this.intentionallyUnsubscribed)
|
|
316
|
+
return;
|
|
208
317
|
if (!this.session)
|
|
209
318
|
this.resetSession();
|
|
210
319
|
// TODO: Need to do this specifically for each node
|
|
@@ -318,7 +427,7 @@ class NodeReplicationConnection extends events_1.EventEmitter {
|
|
|
318
427
|
}
|
|
319
428
|
unsubscribe() {
|
|
320
429
|
this.intentionallyUnsubscribed = true;
|
|
321
|
-
this.socket
|
|
430
|
+
this.socket?.close(1008, 'No longer subscribed');
|
|
322
431
|
}
|
|
323
432
|
getRecord(request) {
|
|
324
433
|
return this.session.then((session) => {
|
|
@@ -366,7 +475,33 @@ function replicateOverWS(ws, options, authorization) {
|
|
|
366
475
|
if (remoteNodeName && options.connection)
|
|
367
476
|
options.connection.nodeName = remoteNodeName;
|
|
368
477
|
let lastSequenceIdReceived, lastSequenceIdCommitted;
|
|
369
|
-
|
|
478
|
+
// Bulk-copy resume state (receiver side). While inCopyMode, each committed batch persists a cursor
|
|
479
|
+
// (copyStartTime + last committed table/key) so an interrupted copy can resume instead of restarting.
|
|
480
|
+
let inCopyMode = false;
|
|
481
|
+
let copyModeStartTime = 0;
|
|
482
|
+
let copyFromNodeId; // local id of the node we are copying from — the key for the persisted cursor
|
|
483
|
+
let copyCompleteReceived = false;
|
|
484
|
+
// Finish the copy — leave copy mode and remove the resume cursor — only once COPY_COMPLETE has been
|
|
485
|
+
// received AND every copied batch has committed (outstandingCommits drained, which includes the final
|
|
486
|
+
// end_txn that advances the resume seqId to copyStartTime). We deliberately stay in copy mode until
|
|
487
|
+
// then so batches still committing keep advancing the cursor (onCommit). Finishing earlier — e.g.
|
|
488
|
+
// synchronously when COPY_COMPLETE is decoded while batches are still queued — would freeze the cursor
|
|
489
|
+
// and risk a crash that loses both the cursor and the not-yet-durable rows, leaving the next start to
|
|
490
|
+
// resume from seqId with gaps.
|
|
491
|
+
function maybeFinishCopy() {
|
|
492
|
+
if (copyCompleteReceived && outstandingCommits === 0) {
|
|
493
|
+
// guard only the cursor removal on a known node id; ALWAYS exit copy mode, otherwise a
|
|
494
|
+
// COPY_START whose getIdOfRemoteNode returned undefined would strand the node in copy mode
|
|
495
|
+
// (received-version watermark suppressed) and it could never reach Available.
|
|
496
|
+
if (copyFromNodeId !== undefined)
|
|
497
|
+
tableSubscriptionToReplicator?.dbisDB?.remove([Symbol.for('copyCursor'), copyFromNodeId]);
|
|
498
|
+
inCopyMode = false;
|
|
499
|
+
copyCompleteReceived = false;
|
|
500
|
+
copyFromNodeId = undefined;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
let sendPingInterval, lastPingTime, skippedMessageSequenceUpdateTimer;
|
|
504
|
+
let receiveWatchdog;
|
|
370
505
|
let blobsTimer;
|
|
371
506
|
const DELAY_CLOSE_TIME = 60000; // amount of time to wait before closing the connection if we haven't any activity and there are no subscriptions
|
|
372
507
|
let delayedClose;
|
|
@@ -374,42 +509,77 @@ function replicateOverWS(ws, options, authorization) {
|
|
|
374
509
|
// track bytes read and written so we can verify if a connection is really dead on pings
|
|
375
510
|
let bytesRead = 0;
|
|
376
511
|
let bytesWritten = 0;
|
|
377
|
-
|
|
512
|
+
// wall-clock time of the last observed socket activity (bytes moved in either direction); the
|
|
513
|
+
// keep-alive timeout is measured from this so a legitimately slow-but-progressing transfer stays
|
|
514
|
+
// alive while a truly idle/dead peer is still terminated.
|
|
515
|
+
let lastByteActivity = performance.now();
|
|
516
|
+
// Multiple independent conditions can ask to pause receive on this WS (commit backlog, consumer
|
|
517
|
+
// queue full, blob write backpressure). We refcount the reasons so that resuming one does not race
|
|
518
|
+
// ahead of another that still wants the WS paused. Declared before the ping setup below because the
|
|
519
|
+
// immediate sendPing() reads it.
|
|
520
|
+
let pauseReasons = 0;
|
|
521
|
+
const blobTimeout = env.get(hdbTerms_ts_1.CONFIG_PARAMS.REPLICATION_BLOBTIMEOUT) ?? 120000;
|
|
378
522
|
const blobsInFlight = new Map();
|
|
379
523
|
const outstandingBlobsToFinish = [];
|
|
380
524
|
let outstandingBlobsBeingSent = 0;
|
|
381
525
|
let blobSentCallback;
|
|
526
|
+
// Refresh the keep-alive liveness clock from observed socket byte movement. If the underlying
|
|
527
|
+
// _socket isn't observable (test mocks, pre-connect, or a change in the ws library internals),
|
|
528
|
+
// bytesRead/bytesWritten read as undefined; we can't measure activity, so treat the connection as
|
|
529
|
+
// live rather than let the keep-alive falsely terminate a healthy peer.
|
|
530
|
+
function noteByteActivity() {
|
|
531
|
+
const read = ws._socket?.bytesRead;
|
|
532
|
+
const written = ws._socket?.bytesWritten;
|
|
533
|
+
if (read === undefined || written === undefined || read !== bytesRead || written !== bytesWritten) {
|
|
534
|
+
lastByteActivity = performance.now();
|
|
535
|
+
}
|
|
536
|
+
}
|
|
382
537
|
if (options.url) {
|
|
383
538
|
const sendPing = () => {
|
|
384
|
-
//
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
bytesRead = ws._socket?.bytesRead;
|
|
391
|
-
bytesWritten = ws._socket?.bytesWritten;
|
|
539
|
+
// Note any socket activity since the last interval (incoming pong/data or our send buffer
|
|
540
|
+
// draining as the peer consumes) — either proves the peer is still alive.
|
|
541
|
+
noteByteActivity();
|
|
542
|
+
if (shouldTerminateIdlePing(performance.now() - lastByteActivity, PING_TIMEOUT, pauseReasons)) {
|
|
543
|
+
ws.terminate(); // no socket activity within the timeout — peer is gone
|
|
544
|
+
return;
|
|
392
545
|
}
|
|
546
|
+
// While paused for receiver backpressure, keep our own liveness fresh: the stall is local and
|
|
547
|
+
// self-clearing (it doesn't depend on the peer), so we must not time the peer out for it.
|
|
548
|
+
if (pauseReasons > 0)
|
|
549
|
+
lastByteActivity = performance.now();
|
|
550
|
+
// Always send the keep-alive ping. ws.pause() only stops reads, not writes, and the accepted
|
|
551
|
+
// peer relies on our pings to keep its own receive timer alive even when it has no data to send
|
|
552
|
+
// us. Record byte counts AFTER the ping so the ping's own bytes aren't later mistaken for peer
|
|
553
|
+
// activity.
|
|
554
|
+
lastPingTime = performance.now();
|
|
555
|
+
ws.ping();
|
|
556
|
+
bytesRead = ws._socket?.bytesRead;
|
|
557
|
+
bytesWritten = ws._socket?.bytesWritten;
|
|
393
558
|
};
|
|
394
559
|
sendPingInterval = setInterval(sendPing, PING_INTERVAL).unref();
|
|
395
560
|
sendPing(); // send the first ping immediately so we can measure latency
|
|
396
561
|
}
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
562
|
+
// Both client and server arm the receive watchdog. On the client this is independent of the
|
|
563
|
+
// sendPing tick above: if that tick is missed or its ws.terminate() does not propagate a
|
|
564
|
+
// 'close' event, the watchdog forces the reconnect path. See harper-pro#233 for the failure
|
|
565
|
+
// modes observed in the field.
|
|
566
|
+
receiveWatchdog = createReceiveWatchdog({
|
|
567
|
+
intervalMs: RECEIVE_SILENCE_THRESHOLD_MS,
|
|
568
|
+
getBytesRead: () => ws._socket?.bytesRead ?? 0,
|
|
569
|
+
onSilence: () => {
|
|
570
|
+
// Warn-level: if the active sendPing was healthy this watchdog should not have fired,
|
|
571
|
+
// so it is a signal that something is wrong upstream (event-loop stall, keepalive timer
|
|
572
|
+
// misbehaving, peer accepting bytes but not progressing the protocol). Surface it so
|
|
573
|
+
// operators have something to grep for.
|
|
574
|
+
const dbContext = databaseName ? ` (db: "${databaseName}")` : '';
|
|
575
|
+
const direction = options.url ? 'no activity from' : 'no ping from';
|
|
576
|
+
logger.warn?.(`Receive watchdog: ${direction} ${remoteNodeName}${dbContext} for ${RECEIVE_SILENCE_THRESHOLD_MS}ms — terminating connection and reconnecting`);
|
|
577
|
+
ws.terminate();
|
|
578
|
+
},
|
|
579
|
+
});
|
|
580
|
+
const resetPingTimer = receiveWatchdog.reset;
|
|
581
|
+
resetPingTimer();
|
|
400
582
|
ws._socket?.setMaxListeners(200); // we should allow a lot of drain listeners for concurrent blob streams
|
|
401
|
-
function resetPingTimer() {
|
|
402
|
-
clearTimeout(receivePingTimer);
|
|
403
|
-
bytesRead = ws._socket?.bytesRead;
|
|
404
|
-
bytesWritten = ws._socket?.bytesWritten;
|
|
405
|
-
receivePingTimer = setTimeout(() => {
|
|
406
|
-
// double check to make sure we aren't just waiting for other data to flow
|
|
407
|
-
if (bytesRead === ws._socket?.bytesRead && bytesWritten === ws._socket?.bytesWritten) {
|
|
408
|
-
logger.warn?.(`Timeout waiting for ping from ${remoteNodeName}, terminating connection and reconnecting`);
|
|
409
|
-
ws.terminate();
|
|
410
|
-
}
|
|
411
|
-
}, PING_INTERVAL * 2).unref();
|
|
412
|
-
}
|
|
413
583
|
let ratioOfBackPressureTime = 0;
|
|
414
584
|
let lastBackPressureCheck = 0;
|
|
415
585
|
let isPausedForBackPressure = false;
|
|
@@ -448,30 +618,37 @@ function replicateOverWS(ws, options, authorization) {
|
|
|
448
618
|
const residencyMap = [];
|
|
449
619
|
const sentResidencyLists = [];
|
|
450
620
|
const receivedResidencyLists = [];
|
|
451
|
-
const MAX_OUTSTANDING_COMMITS =
|
|
452
|
-
const MAX_OUTSTANDING_BLOBS_BEING_SENT =
|
|
621
|
+
const MAX_OUTSTANDING_COMMITS = env.get(hdbTerms_ts_1.CONFIG_PARAMS.REPLICATION_RECORDCONCURRENCY) ?? 150; // maximum before requesting that other nodes pause
|
|
622
|
+
const MAX_OUTSTANDING_BLOBS_BEING_SENT = env.get(hdbTerms_ts_1.CONFIG_PARAMS.REPLICATION_BLOBCONCURRENCY) ?? 5;
|
|
453
623
|
let outstandingCommits = 0;
|
|
454
624
|
let lastStructureLength = 0;
|
|
455
|
-
// Multiple independent conditions can ask to pause receive on this WS (commit backlog,
|
|
456
|
-
// consumer queue full, blob write backpressure). We refcount the reasons so that resuming
|
|
457
|
-
// one does not race ahead of another that still wants the WS paused.
|
|
458
|
-
let pauseReasons = 0;
|
|
459
625
|
let commitBacklogPaused = false;
|
|
460
626
|
function addPauseReason() {
|
|
461
|
-
if (pauseReasons === 0)
|
|
627
|
+
if (pauseReasons === 0) {
|
|
462
628
|
ws.pause();
|
|
629
|
+
// Suspend the receive watchdog while the socket is intentionally paused — `bytesRead`
|
|
630
|
+
// is frozen by `ws.pause()` so the byte check cannot tell legitimate backpressure
|
|
631
|
+
// from peer silence, and firing here would terminate a healthy mid-ingest connection.
|
|
632
|
+
receiveWatchdog?.stop();
|
|
633
|
+
}
|
|
463
634
|
pauseReasons++;
|
|
464
635
|
}
|
|
465
636
|
function removePauseReason() {
|
|
466
637
|
if (pauseReasons === 0)
|
|
467
638
|
return;
|
|
468
639
|
pauseReasons--;
|
|
469
|
-
if (pauseReasons === 0)
|
|
640
|
+
if (pauseReasons === 0) {
|
|
470
641
|
ws.resume();
|
|
642
|
+
// Restart the silence window from the resume point — we deliberately do not penalize
|
|
643
|
+
// the connection for the time it spent paused.
|
|
644
|
+
receiveWatchdog?.reset();
|
|
645
|
+
}
|
|
471
646
|
}
|
|
472
647
|
let subscriptionRequest, auditSubscription;
|
|
473
648
|
let nodeSubscriptions;
|
|
474
649
|
let excludedNodes; // list of nodes to exclude from this subscription
|
|
650
|
+
// undefined = not yet computed; null = computed, no exclusions; Set = tables to drop on receive
|
|
651
|
+
let receiveExcludedTables;
|
|
475
652
|
let remoteShortIdToLocalId;
|
|
476
653
|
let subscribedNodeIds; // map of node IDs to their subscription time ranges
|
|
477
654
|
// Serialize message handling so that async backpressure inside onWSMessage doesn't allow
|
|
@@ -481,6 +658,9 @@ function replicateOverWS(ws, options, authorization) {
|
|
|
481
658
|
let messageProcessing = Promise.resolve();
|
|
482
659
|
let wsClosed = false;
|
|
483
660
|
ws.on('message', (body) => {
|
|
661
|
+
// Reset the receive watchdog synchronously on every frame — async processing below may
|
|
662
|
+
// take a long time and we want a single late frame to count as proof of life immediately.
|
|
663
|
+
resetPingTimer();
|
|
484
664
|
messageProcessing = messageProcessing.then(() => (wsClosed ? undefined : onWSMessage(body)), () => (wsClosed ? undefined : onWSMessage(body)));
|
|
485
665
|
});
|
|
486
666
|
let authorizationFinished = false;
|
|
@@ -683,9 +863,8 @@ function replicateOverWS(ws, options, authorization) {
|
|
|
683
863
|
// of the table id to the decoder so we can decode the binary data for each table.
|
|
684
864
|
tableDecoders[tableId] = {
|
|
685
865
|
name: tableName,
|
|
686
|
-
decoder: new
|
|
866
|
+
decoder: new StructonPackr({
|
|
687
867
|
useBigIntExtension: true,
|
|
688
|
-
randomAccessStructure: true,
|
|
689
868
|
freezeData: true,
|
|
690
869
|
typedStructs: data.typedStructs,
|
|
691
870
|
structures: data.structures,
|
|
@@ -714,6 +893,20 @@ function replicateOverWS(ws, options, authorization) {
|
|
|
714
893
|
(0, write_ts_1.recordAction)(body.length, 'bytes-received', `${remoteNodeName}.${databaseName}`, 'replication', 'committed-update');
|
|
715
894
|
getSharedStatus().buffer.notify();
|
|
716
895
|
break;
|
|
896
|
+
case COPY_START:
|
|
897
|
+
// the leader is (re)starting a bulk copy; track a resume cursor for it
|
|
898
|
+
inCopyMode = true;
|
|
899
|
+
copyModeStartTime = data; // copyStartTime anchor chosen by the leader
|
|
900
|
+
copyFromNodeId = (0, nodeIdMapping_ts_1.getIdOfRemoteNode)(remoteNodeName, auditStore);
|
|
901
|
+
logger.debug?.(connectionId, 'bulk copy starting from', remoteNodeName, new Date(copyModeStartTime));
|
|
902
|
+
break;
|
|
903
|
+
case COPY_COMPLETE:
|
|
904
|
+
// Copy signalled complete. Stay in copy mode so batches still committing keep advancing the
|
|
905
|
+
// cursor; maybeFinishCopy exits copy mode and clears the cursor once those commits drain.
|
|
906
|
+
copyCompleteReceived = true;
|
|
907
|
+
maybeFinishCopy();
|
|
908
|
+
logger.debug?.(connectionId, 'bulk copy complete from', remoteNodeName);
|
|
909
|
+
break;
|
|
717
910
|
case SEQUENCE_ID_UPDATE:
|
|
718
911
|
// we need to record the sequence number that the remote node has received
|
|
719
912
|
lastSequenceIdReceived = data;
|
|
@@ -759,20 +952,38 @@ function replicateOverWS(ws, options, authorization) {
|
|
|
759
952
|
if (stream.connectedToBlob)
|
|
760
953
|
blobsInFlight.delete(fileId);
|
|
761
954
|
}
|
|
955
|
+
else if (stream.destroyed || stream.writableEnded) {
|
|
956
|
+
// The stream was already torn down before this mid-blob chunk arrived —
|
|
957
|
+
// typically because saveBlob's pipeline failed (e.g. ENOENT on
|
|
958
|
+
// createWriteStream) and destroyed the PassThrough source, firing 'close'.
|
|
959
|
+
// We must NOT fall into the backpressure branch below: writing to a dead
|
|
960
|
+
// stream returns false, and pausing to wait for a 'drain'/'close' that has
|
|
961
|
+
// already fired strands the pause reason forever, wedging the entire
|
|
962
|
+
// receive loop (observed in prod: receiver goes silent, sender stuck
|
|
963
|
+
// reconnecting, replication never recovers). Drop the orphaned chunk and
|
|
964
|
+
// forget the stream instead.
|
|
965
|
+
blobsInFlight.delete(fileId);
|
|
966
|
+
}
|
|
762
967
|
else if (!stream.write(blobBody)) {
|
|
763
968
|
// The PassThrough's internal queue is over its HWM, meaning the downstream
|
|
764
969
|
// file write (via pipeline in saveBlob) can't keep up. Pause the WS until the
|
|
765
970
|
// stream drains so blob chunks don't accumulate in memory faster than they
|
|
766
|
-
// can be flushed to disk.
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
971
|
+
// can be flushed to disk.
|
|
972
|
+
if (stream.destroyed || stream.writableEnded) {
|
|
973
|
+
// write() itself may have torn the stream down (e.g. a late error). If so,
|
|
974
|
+
// 'drain'/'close' won't arrive — skip pausing rather than strand the reason.
|
|
975
|
+
blobsInFlight.delete(fileId);
|
|
976
|
+
}
|
|
977
|
+
else {
|
|
978
|
+
addPauseReason();
|
|
979
|
+
const release = () => {
|
|
980
|
+
stream.off('drain', release);
|
|
981
|
+
stream.off('close', release);
|
|
982
|
+
removePauseReason();
|
|
983
|
+
};
|
|
984
|
+
stream.on('drain', release);
|
|
985
|
+
stream.on('close', release);
|
|
986
|
+
}
|
|
776
987
|
}
|
|
777
988
|
}
|
|
778
989
|
catch (error) {
|
|
@@ -994,6 +1205,10 @@ function replicateOverWS(ws, options, authorization) {
|
|
|
994
1205
|
let tableById;
|
|
995
1206
|
let currentSequenceId = Infinity; // the last sequence number in the audit log that we have processed, set this with a finite number from the subscriptions
|
|
996
1207
|
let sentSequenceId; // the last sequence number we have sent
|
|
1208
|
+
// Tables excluded from outgoing replication to this peer+database (from sendsTo config)
|
|
1209
|
+
const sendExcludedTables = authorization?.replicates && typeof authorization.replicates === 'object'
|
|
1210
|
+
? (0, knownNodes_ts_1.getExcludedTablesForRouteEntries)(authorization.replicates.sendsTo, remoteNodeName, databaseName)
|
|
1211
|
+
: null;
|
|
997
1212
|
const sendAuditRecord = (auditRecord, localTime) => {
|
|
998
1213
|
if (auditRecord.type === 'end_txn') {
|
|
999
1214
|
if (currentTransaction.txnTime) {
|
|
@@ -1019,6 +1234,9 @@ function replicateOverWS(ws, options, authorization) {
|
|
|
1019
1234
|
}
|
|
1020
1235
|
}
|
|
1021
1236
|
const table = tableEntry.table;
|
|
1237
|
+
if (sendExcludedTables?.has(table.tableName)) {
|
|
1238
|
+
return skipAuditRecord();
|
|
1239
|
+
}
|
|
1022
1240
|
const primaryStore = table.primaryStore;
|
|
1023
1241
|
const encoder = primaryStore.encoder;
|
|
1024
1242
|
// Force a reload the first time this connection touches each table:
|
|
@@ -1044,7 +1262,9 @@ function replicateOverWS(ws, options, authorization) {
|
|
|
1044
1262
|
// in the subscribedNodeIds list, than it matches the subscription
|
|
1045
1263
|
const matchesSubscription = (excludedNodes && timeRange === undefined) ||
|
|
1046
1264
|
// if it is in the list, we check the timestamps to verify it matches
|
|
1047
|
-
(timeRange &&
|
|
1265
|
+
(timeRange &&
|
|
1266
|
+
timeRange.startTime < localTime &&
|
|
1267
|
+
(!timeRange.endTime || timeRange.endTime > localTime));
|
|
1048
1268
|
if (!matchesSubscription) {
|
|
1049
1269
|
if (DEBUG_MODE)
|
|
1050
1270
|
logger.trace?.(connectionId, 'skipping replication update', auditRecord.recordId, 'to:', remoteNodeName, 'from:', nodeId, 'subscribed:', subscribedNodeIds);
|
|
@@ -1232,9 +1452,13 @@ function replicateOverWS(ws, options, authorization) {
|
|
|
1232
1452
|
subscriptionToHdbNodes?.end();
|
|
1233
1453
|
});
|
|
1234
1454
|
// find the earliest start time of the subscriptions
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1455
|
+
let copyResume;
|
|
1456
|
+
for (const subscription of nodeSubscriptions) {
|
|
1457
|
+
if (subscription.startTime < currentSequenceId)
|
|
1458
|
+
currentSequenceId = subscription.startTime;
|
|
1459
|
+
// a follower resuming an interrupted bulk copy sends back where it left off
|
|
1460
|
+
if (subscription.copyResume)
|
|
1461
|
+
copyResume = subscription.copyResume;
|
|
1238
1462
|
}
|
|
1239
1463
|
// wait for internal subscription, might be waiting for a table to be registered
|
|
1240
1464
|
(whenSubscribedToHdbNodes || Promise.resolve())
|
|
@@ -1301,21 +1525,53 @@ function replicateOverWS(ws, options, authorization) {
|
|
|
1301
1525
|
isFirst = false;
|
|
1302
1526
|
if (currentSequenceId === 0) {
|
|
1303
1527
|
logger.info?.('Replicating all tables to', remoteNodeName);
|
|
1304
|
-
|
|
1528
|
+
// Capture the resume point BEFORE iterating. The bulk copy walks the primary store in
|
|
1529
|
+
// key order (snapshot: false), but the follower resumes replication from the audit log in
|
|
1530
|
+
// time order. Using copyStartTime — not max(localTime) of the copied records — guarantees
|
|
1531
|
+
// the post-copy audit replay re-delivers every write committed during the copy, including
|
|
1532
|
+
// ones to keys we already passed; resuming from max(localTime) would skip those (data loss).
|
|
1533
|
+
// When the follower is resuming an interrupted copy, keep the original copy start time so
|
|
1534
|
+
// the post-copy resume point stays anchored to when the copy first began (see safety note).
|
|
1535
|
+
const copyStartTime = copyResume?.copyStartTime ?? Date.now();
|
|
1305
1536
|
const nodeId = (0, nodeIdMapping_ts_1.getThisNodeId)(auditStore);
|
|
1537
|
+
// Tell the follower a bulk copy is starting and its anchor time, so it tracks a resume cursor.
|
|
1538
|
+
ws.send((0, msgpackr_1.encode)([COPY_START, copyStartTime]));
|
|
1539
|
+
let recordsSinceCheckpoint = 0;
|
|
1540
|
+
// If resuming, the follower already committed every table before currentTable (records commit
|
|
1541
|
+
// in stable iteration order), so skip to currentTable and continue after its last committed key.
|
|
1542
|
+
let reachedResumeTable = !copyResume;
|
|
1543
|
+
// currentTable must be one the loop below will actually visit (present in `tables` AND passing
|
|
1544
|
+
// the same replication filter); otherwise the skip loop never reaches it and would omit every
|
|
1545
|
+
// later table. Mirror the loop's own check so a dropped/unreplicated cursor table forces a restart.
|
|
1546
|
+
if (copyResume && !tableToTableEntry(tables[copyResume.currentTable])) {
|
|
1547
|
+
// cursor table is gone or no longer replicated — the skip loop would never reach it and
|
|
1548
|
+
// would omit every later table, so recopy from scratch (idempotent puts, copyStartTime reset)
|
|
1549
|
+
logger.warn?.('Copy-resume table missing or unreplicated, restarting full copy', copyResume.currentTable);
|
|
1550
|
+
copyResume = undefined;
|
|
1551
|
+
reachedResumeTable = true;
|
|
1552
|
+
}
|
|
1553
|
+
const resumeCurrentTable = copyResume?.currentTable;
|
|
1554
|
+
const resumeAfterKey = copyResume?.afterKey;
|
|
1306
1555
|
for (const tableName in tables) {
|
|
1307
|
-
if (!tableToTableEntry(tableName))
|
|
1308
|
-
continue; // if we aren't replicating this table, skip it
|
|
1309
1556
|
const table = tables[tableName];
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1557
|
+
if (!tableToTableEntry(table))
|
|
1558
|
+
continue; // if we aren't replicating this table, skip it
|
|
1559
|
+
if (!reachedResumeTable) {
|
|
1560
|
+
if (tableName !== resumeCurrentTable)
|
|
1561
|
+
continue; // already committed on the follower
|
|
1562
|
+
reachedResumeTable = true;
|
|
1563
|
+
}
|
|
1564
|
+
const rangeOptions = { snapshot: false, versions: true };
|
|
1565
|
+
// values: false, // TODO: eventually, we don't want to decode, we want to use fast binary transfer
|
|
1566
|
+
if (tableName === resumeCurrentTable) {
|
|
1567
|
+
// resume this table after the last key the follower committed
|
|
1568
|
+
rangeOptions.start = resumeAfterKey;
|
|
1569
|
+
rangeOptions.exclusiveStart = true;
|
|
1570
|
+
}
|
|
1571
|
+
for (const entry of table.primaryStore.getRange(rangeOptions)) {
|
|
1315
1572
|
if (closed)
|
|
1316
1573
|
return;
|
|
1317
1574
|
logger.trace?.(connectionId, 'Copying record from', databaseName, tableName, entry.key, entry.localTime);
|
|
1318
|
-
lastSequenceId = Math.max(entry.localTime ?? 1, lastSequenceId);
|
|
1319
1575
|
getSharedStatus()[exports.SENDING_TIME_POSITION] = 1;
|
|
1320
1576
|
const encoded = (0, auditStore_ts_1.createAuditEntry)({
|
|
1321
1577
|
version: entry.version,
|
|
@@ -1348,23 +1604,43 @@ function replicateOverWS(ws, options, authorization) {
|
|
|
1348
1604
|
extendedType: entry.metadataFlags,
|
|
1349
1605
|
}, entry.localTime);
|
|
1350
1606
|
logger.debug?.('sent record from table', entry.key, 'length:', encoded.length, encoded.slice(0, 10));
|
|
1607
|
+
// Periodically flush the accumulated records as a message so the follower commits this
|
|
1608
|
+
// batch and advances its resume cursor. This is a plain flush with NO sequence update:
|
|
1609
|
+
// emitting an end_txn here would advance the follower's received-version watermark to
|
|
1610
|
+
// copyStartTime mid-copy, which monitorSync could read as "caught up" and mark the clone
|
|
1611
|
+
// Available/cloned with rows still uncopied. (Records with differing versions already flush
|
|
1612
|
+
// naturally above; this also bounds same-version bulk data into committable batches.) The
|
|
1613
|
+
// watermark is only advanced to copyStartTime by the single end_txn after the whole copy.
|
|
1614
|
+
if (++recordsSinceCheckpoint >= COPY_CHECKPOINT_RECORDS && position - encodingStart > 8) {
|
|
1615
|
+
recordsSinceCheckpoint = 0;
|
|
1616
|
+
sendQueuedData();
|
|
1617
|
+
encodingStart = position;
|
|
1618
|
+
currentTransaction.txnTime = 0;
|
|
1619
|
+
}
|
|
1351
1620
|
}
|
|
1352
1621
|
logger.info?.('Finished copy table', tableName, remoteNodeName);
|
|
1353
1622
|
}
|
|
1354
|
-
currentSequenceId =
|
|
1623
|
+
currentSequenceId = copyStartTime;
|
|
1355
1624
|
if (!currentTransaction.txnTime) {
|
|
1356
|
-
//
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
// if we have any queued transactions to send, send them now
|
|
1362
|
-
sendAuditRecord({
|
|
1363
|
-
type: 'end_txn',
|
|
1364
|
-
}, currentSequenceId);
|
|
1625
|
+
// no records pending (none sent, or the last batch landed on a checkpoint flush):
|
|
1626
|
+
// force a txn so the end_txn below still carries the sequence update
|
|
1627
|
+
currentTransaction.txnTime = copyStartTime;
|
|
1628
|
+
encodingStart = position;
|
|
1629
|
+
writeFloat64(copyStartTime);
|
|
1365
1630
|
}
|
|
1631
|
+
// ALWAYS emit the final end_txn at copyStartTime. It carries the REMOTE_SEQUENCE_UPDATE
|
|
1632
|
+
// that advances the follower's seqId and received-version watermark to copyStartTime —
|
|
1633
|
+
// the sole signal that the copy is synced (per-record watermark advance is suppressed
|
|
1634
|
+
// during the copy). Skipping it when the last rows landed exactly on a checkpoint flush
|
|
1635
|
+
// would leave the clone unable to ever reach Available.
|
|
1636
|
+
sendAuditRecord({
|
|
1637
|
+
type: 'end_txn',
|
|
1638
|
+
}, currentSequenceId);
|
|
1639
|
+
// The full copy is done — tell the follower to clear its resume cursor and fall back to
|
|
1640
|
+
// normal audit-log replication from the persisted seqId (which is copyStartTime).
|
|
1641
|
+
ws.send((0, msgpackr_1.encode)([COPY_COMPLETE]));
|
|
1366
1642
|
getSharedStatus()[exports.SENDING_TIME_POSITION] = 0;
|
|
1367
|
-
currentSequenceId =
|
|
1643
|
+
currentSequenceId = copyStartTime;
|
|
1368
1644
|
}
|
|
1369
1645
|
}
|
|
1370
1646
|
const logName = subscribedNodeName === (0, nodeName_ts_1.getThisNodeName)() ? 'local' : subscribedNodeName;
|
|
@@ -1415,6 +1691,7 @@ function replicateOverWS(ws, options, authorization) {
|
|
|
1415
1691
|
let beginTxn = true;
|
|
1416
1692
|
let event; // could also get txnTime from decoder.getFloat64(0);
|
|
1417
1693
|
let sequenceIdReceived;
|
|
1694
|
+
let lastYieldTime = performance.now();
|
|
1418
1695
|
do {
|
|
1419
1696
|
getSharedStatus();
|
|
1420
1697
|
const eventLength = decoder.readInt();
|
|
@@ -1441,6 +1718,23 @@ function replicateOverWS(ws, options, authorization) {
|
|
|
1441
1718
|
if (!tableDecoder) {
|
|
1442
1719
|
logger.error?.(`No table found with an id of ${auditRecord.tableId}`);
|
|
1443
1720
|
}
|
|
1721
|
+
// Lazily compute receive-side exclusions once remoteNodeName is known.
|
|
1722
|
+
// Prefer routeReplicates from the subscriber-side connection; fall back to
|
|
1723
|
+
// authorization.replicates when this is the server-side handler.
|
|
1724
|
+
if (receiveExcludedTables === undefined) {
|
|
1725
|
+
const firstNode = options.connection?.nodeSubscriptions?.[0];
|
|
1726
|
+
const receivesFromEntries = firstNode?.routeReplicates?.receivesFrom ??
|
|
1727
|
+
(authorization?.replicates && typeof authorization.replicates === 'object'
|
|
1728
|
+
? authorization.replicates.receivesFrom
|
|
1729
|
+
: undefined);
|
|
1730
|
+
receiveExcludedTables =
|
|
1731
|
+
(0, knownNodes_ts_1.getExcludedTablesForRouteEntries)(receivesFromEntries, remoteNodeName, databaseName) ?? null;
|
|
1732
|
+
}
|
|
1733
|
+
if (tableDecoder && receiveExcludedTables?.has(tableDecoder.name)) {
|
|
1734
|
+
logger.trace?.(connectionId, 'dropping incoming replication for excluded table', databaseName + '.' + tableDecoder.name, 'from', remoteNodeName);
|
|
1735
|
+
decoder.position = start + eventLength;
|
|
1736
|
+
continue;
|
|
1737
|
+
}
|
|
1444
1738
|
let residencyList;
|
|
1445
1739
|
if (auditRecord.residencyId) {
|
|
1446
1740
|
residencyList = receivedResidencyLists[auditRecord.residencyId];
|
|
@@ -1448,6 +1742,7 @@ function replicateOverWS(ws, options, authorization) {
|
|
|
1448
1742
|
}
|
|
1449
1743
|
const id = auditRecord.recordId;
|
|
1450
1744
|
event = undefined; // reset before each decode attempt
|
|
1745
|
+
let receivedBlobs;
|
|
1451
1746
|
try {
|
|
1452
1747
|
(0, blob_ts_1.decodeBlobsWithWrites)(() => {
|
|
1453
1748
|
event = {
|
|
@@ -1463,14 +1758,30 @@ function replicateOverWS(ws, options, authorization) {
|
|
|
1463
1758
|
beginTxn,
|
|
1464
1759
|
expiresAt: auditRecord.expiresAt,
|
|
1465
1760
|
};
|
|
1466
|
-
}, auditStore?.rootStore, (blob) =>
|
|
1761
|
+
}, auditStore?.rootStore, (blob) => {
|
|
1762
|
+
const localBlob = receiveBlobs(blob, id);
|
|
1763
|
+
(receivedBlobs ??= []).push(localBlob);
|
|
1764
|
+
return localBlob;
|
|
1765
|
+
});
|
|
1467
1766
|
}
|
|
1468
1767
|
catch (error) {
|
|
1469
1768
|
logger.error?.('Error decoding replication message, record id: ' + id, ' typed structures for current decoder' + JSON.stringify(tableDecoder.decoder.typedStructs), ' structures for current decoder' + JSON.stringify(tableDecoder.decoder.structures), 'encoded message', auditRecord.encoded.subarray(0, 1000), auditRecord, error);
|
|
1470
1769
|
}
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1770
|
+
if (!event && receivedBlobs) {
|
|
1771
|
+
// decode failed mid-message; the blobs that were already accepted will never be referenced. Give in-flight reads
|
|
1772
|
+
// a window to complete, then unlink the files. (mirrors the pattern at the relocate path above.)
|
|
1773
|
+
setTimeout(() => receivedBlobs.forEach(blob_ts_1.deleteBlob), 60000).unref();
|
|
1774
|
+
}
|
|
1775
|
+
// During a bulk copy, do NOT advance the received-version watermark per copied record:
|
|
1776
|
+
// records arrive in primary-key order carrying their original (possibly newest) versions, so a
|
|
1777
|
+
// single record at the leader's latest timestamp would otherwise let checkSyncStatus mark the
|
|
1778
|
+
// clone Available with rows still uncopied. The watermark is advanced to copyStartTime by the
|
|
1779
|
+
// single end_txn after the whole copy (the REMOTE_SEQUENCE_UPDATE branch above).
|
|
1780
|
+
if (!inCopyMode) {
|
|
1781
|
+
replicationSharedStatus[exports.RECEIVED_VERSION_POSITION] = Math.max(
|
|
1782
|
+
// ensure monotonicity
|
|
1783
|
+
auditRecord.version, replicationSharedStatus[exports.RECEIVED_VERSION_POSITION]);
|
|
1784
|
+
}
|
|
1474
1785
|
replicationSharedStatus[exports.RECEIVED_TIME_POSITION] = Date.now();
|
|
1475
1786
|
replicationSharedStatus[exports.RECEIVING_STATUS_POSITION] = exports.RECEIVING_STATUS_RECEIVING;
|
|
1476
1787
|
if (event) {
|
|
@@ -1491,6 +1802,14 @@ function replicateOverWS(ws, options, authorization) {
|
|
|
1491
1802
|
finally {
|
|
1492
1803
|
removePauseReason();
|
|
1493
1804
|
}
|
|
1805
|
+
lastYieldTime = performance.now();
|
|
1806
|
+
}
|
|
1807
|
+
else if (performance.now() - lastYieldTime >= RECEIVE_YIELD_INTERVAL) {
|
|
1808
|
+
// The high-water-mark pause only fires under heap pressure. When the consumer keeps
|
|
1809
|
+
// up, yield on a time budget anyway so a large message doesn't decode in one
|
|
1810
|
+
// synchronous turn and stall ping responses (see RECEIVE_YIELD_INTERVAL).
|
|
1811
|
+
await new Promise(setImmediate);
|
|
1812
|
+
lastYieldTime = performance.now();
|
|
1494
1813
|
}
|
|
1495
1814
|
}
|
|
1496
1815
|
decoder.position = start + eventLength;
|
|
@@ -1504,6 +1823,9 @@ function replicateOverWS(ws, options, authorization) {
|
|
|
1504
1823
|
addPauseReason();
|
|
1505
1824
|
logger.debug?.(`Commit backlog causing replication back-pressure, requesting that ${remoteNodeName} pause replication`);
|
|
1506
1825
|
}
|
|
1826
|
+
// Is this a bulk-copy frame? Only frames received before COPY_COMPLETE are part of the
|
|
1827
|
+
// primary-key copy; later audit-replay frames must not be recorded as the resume cursor.
|
|
1828
|
+
const isCopyFrame = inCopyMode && !copyCompleteReceived;
|
|
1507
1829
|
tableSubscriptionToReplicator.send({
|
|
1508
1830
|
type: 'end_txn',
|
|
1509
1831
|
localTime: lastSequenceIdReceived,
|
|
@@ -1526,6 +1848,18 @@ function replicateOverWS(ws, options, authorization) {
|
|
|
1526
1848
|
if (outstandingBlobsToFinish.length > 0)
|
|
1527
1849
|
await Promise.all(outstandingBlobsToFinish);
|
|
1528
1850
|
logger.trace?.('All blobs finished');
|
|
1851
|
+
// Persist/clear the resume cursor only AFTER this batch's blobs are durable too. The cursor
|
|
1852
|
+
// means "fully copied through this key"; advancing it before blob writes finish would let a
|
|
1853
|
+
// crash skip re-requesting an unfinished blob, leaving the record pointing at missing data.
|
|
1854
|
+
if (isCopyFrame && event && copyFromNodeId !== undefined) {
|
|
1855
|
+
tableSubscriptionToReplicator?.dbisDB?.put([Symbol.for('copyCursor'), copyFromNodeId], {
|
|
1856
|
+
copyStartTime: copyModeStartTime,
|
|
1857
|
+
currentTable: event.table,
|
|
1858
|
+
afterKey: event.id,
|
|
1859
|
+
});
|
|
1860
|
+
}
|
|
1861
|
+
// once the last copied batch (incl. its blobs) is durable, it's safe to drop the cursor
|
|
1862
|
+
maybeFinishCopy();
|
|
1529
1863
|
if (!lastSequenceIdCommitted && sequenceIdReceived) {
|
|
1530
1864
|
logger.trace?.(connectionId, 'queuing confirmation of a commit at', sequenceIdReceived);
|
|
1531
1865
|
setTimeout(() => {
|
|
@@ -1546,6 +1880,7 @@ function replicateOverWS(ws, options, authorization) {
|
|
|
1546
1880
|
}
|
|
1547
1881
|
}
|
|
1548
1882
|
ws.on('ping', resetPingTimer);
|
|
1883
|
+
ws.on('pong', resetPingTimer);
|
|
1549
1884
|
ws.on('pong', () => {
|
|
1550
1885
|
if (options.connection) {
|
|
1551
1886
|
// every pong we can use to update our connection information (and latency)
|
|
@@ -1570,7 +1905,7 @@ function replicateOverWS(ws, options, authorization) {
|
|
|
1570
1905
|
// cleanup
|
|
1571
1906
|
wsClosed = true;
|
|
1572
1907
|
clearInterval(sendPingInterval);
|
|
1573
|
-
|
|
1908
|
+
receiveWatchdog?.stop();
|
|
1574
1909
|
clearInterval(blobsTimer);
|
|
1575
1910
|
if (auditSubscription)
|
|
1576
1911
|
auditSubscription.emit('close');
|
|
@@ -1690,7 +2025,7 @@ function replicateOverWS(ws, options, authorization) {
|
|
|
1690
2025
|
stream.recordId = id;
|
|
1691
2026
|
if (remoteBlob.size === undefined && stream.expectedSize)
|
|
1692
2027
|
remoteBlob.size = stream.expectedSize;
|
|
1693
|
-
const localBlob = stream.blob ?? createBlob(stream, remoteBlob);
|
|
2028
|
+
const localBlob = stream.blob ?? (0, blob_ts_1.createBlob)(stream, remoteBlob);
|
|
1694
2029
|
stream.blob = localBlob; // record the blob so we can reuse it if another request uses the same blob
|
|
1695
2030
|
// start the save immediately. TODO: If we could add support for blobs to directly pass on a stream to the consumer
|
|
1696
2031
|
// we would skip this
|
|
@@ -1798,14 +2133,16 @@ function replicateOverWS(ws, options, authorization) {
|
|
|
1798
2133
|
const nodeSubscriptions = options.connection?.nodeSubscriptions.map((node) => {
|
|
1799
2134
|
const tableSubs = [];
|
|
1800
2135
|
let { replicateByDefault } = node;
|
|
2136
|
+
// Tables excluded by this node's receivesFrom config for this peer+database
|
|
2137
|
+
const receiverExcludedTables = (0, knownNodes_ts_1.getExcludedTablesForRouteEntries)(node.routeReplicates?.receivesFrom, node.name, databaseName);
|
|
1801
2138
|
if (node.subscriptions) {
|
|
1802
2139
|
// if the node has explicit subscriptions, we need to use that to determine subscriptions
|
|
1803
2140
|
for (const subscription of node.subscriptions) {
|
|
1804
2141
|
// if there is an explicit subscription listed
|
|
1805
2142
|
if (subscription.subscribe && (subscription.schema || subscription.database) === databaseName) {
|
|
1806
2143
|
const tableName = subscription.table;
|
|
1807
|
-
if (tables?.[tableName]?.replicate !== false)
|
|
1808
|
-
// if replication is enabled for this table
|
|
2144
|
+
if (tables?.[tableName]?.replicate !== false && !receiverExcludedTables?.has(tableName))
|
|
2145
|
+
// if replication is enabled for this table and not excluded
|
|
1809
2146
|
tableSubs.push(tableName);
|
|
1810
2147
|
}
|
|
1811
2148
|
}
|
|
@@ -1814,14 +2151,22 @@ function replicateOverWS(ws, options, authorization) {
|
|
|
1814
2151
|
else {
|
|
1815
2152
|
// note that if replicateByDefault is enabled, we are listing the *excluded* tables
|
|
1816
2153
|
for (const tableName in tables) {
|
|
1817
|
-
if (replicateByDefault
|
|
2154
|
+
if (replicateByDefault
|
|
2155
|
+
? tables[tableName].replicate === false || receiverExcludedTables?.has(tableName)
|
|
2156
|
+
: tables[tableName].replicate && !receiverExcludedTables?.has(tableName)) {
|
|
1818
2157
|
tableSubs.push(tableName);
|
|
1819
2158
|
}
|
|
1820
2159
|
}
|
|
1821
2160
|
}
|
|
1822
2161
|
const nodeId = auditStore && (0, nodeIdMapping_ts_1.getIdOfRemoteNode)(node.name, auditStore);
|
|
1823
|
-
auditStore
|
|
2162
|
+
auditStore?.ensureLogExists?.(node.name);
|
|
1824
2163
|
const sequenceEntry = tableSubscriptionToReplicator?.dbisDB?.get([Symbol.for('seq'), nodeId]) ?? 1;
|
|
2164
|
+
// A persisted copy cursor means a bulk copy from this node was interrupted mid-stream. We must
|
|
2165
|
+
// resume that copy (not treat the persisted seqId as a normal start point — the un-copied table
|
|
2166
|
+
// data predates copyStartTime and would never be delivered by an audit-log resume).
|
|
2167
|
+
const copyCursor = nodeId === undefined
|
|
2168
|
+
? undefined
|
|
2169
|
+
: tableSubscriptionToReplicator?.dbisDB?.get([Symbol.for('copyCursor'), nodeId]);
|
|
1825
2170
|
// if we are connected directly to the node, we start from the last sequence number we received at the top level
|
|
1826
2171
|
let startTime = Math.max(sequenceEntry?.seqId ?? 1, (typeof node.startTime === 'string' ? new Date(node.startTime).getTime() : node.startTime) ?? 1);
|
|
1827
2172
|
logger.debug?.('Starting time recorded in db', node.name, nodeId, databaseName, sequenceEntry?.seqId, 'start time:', startTime, new Date(startTime));
|
|
@@ -1859,6 +2204,16 @@ function replicateOverWS(ws, options, authorization) {
|
|
|
1859
2204
|
startTime = Date.now() - 60000;
|
|
1860
2205
|
}
|
|
1861
2206
|
}
|
|
2207
|
+
let copyResume;
|
|
2208
|
+
if (copyCursor) {
|
|
2209
|
+
startTime = 0; // request a copy; the cursor tells the leader where to resume
|
|
2210
|
+
copyResume = {
|
|
2211
|
+
copyStartTime: copyCursor.copyStartTime,
|
|
2212
|
+
currentTable: copyCursor.currentTable,
|
|
2213
|
+
afterKey: copyCursor.afterKey,
|
|
2214
|
+
};
|
|
2215
|
+
logger.warn?.(`Resuming interrupted copy of database ${databaseName} from ${(0, knownNodes_ts_1.getNodeURL)(node)} at table ${copyCursor.currentTable}`);
|
|
2216
|
+
}
|
|
1862
2217
|
logger.trace?.(connectionId, 'defining subscription request', node.name, databaseName, new Date(startTime));
|
|
1863
2218
|
return {
|
|
1864
2219
|
name: node.name,
|
|
@@ -1867,6 +2222,7 @@ function replicateOverWS(ws, options, authorization) {
|
|
|
1867
2222
|
startTime,
|
|
1868
2223
|
isLeader: node.isLeader,
|
|
1869
2224
|
endTime: node.endTime,
|
|
2225
|
+
copyResume, // present only when resuming an interrupted bulk copy
|
|
1870
2226
|
};
|
|
1871
2227
|
});
|
|
1872
2228
|
let excluded;
|
|
@@ -1953,7 +2309,7 @@ function replicateOverWS(ws, options, authorization) {
|
|
|
1953
2309
|
if (!thisNodeName)
|
|
1954
2310
|
throw new Error('Node name not defined');
|
|
1955
2311
|
else
|
|
1956
|
-
throw new Error('Should not connect to self'
|
|
2312
|
+
throw new Error('Should not connect to self: ' + thisNodeName);
|
|
1957
2313
|
}
|
|
1958
2314
|
sendNodeDBName(thisNodeName, databaseName);
|
|
1959
2315
|
return true;
|