@harperfast/harper 5.0.0-alpha.10 → 5.0.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/bin/BinObjects.js +17 -0
- package/bin/cliOperations.js +157 -0
- package/bin/copyDb.ts +280 -0
- package/bin/harper.js +156 -0
- package/bin/install.js +15 -0
- package/bin/lite.js +5 -0
- package/bin/restart.js +201 -0
- package/bin/run.js +409 -0
- package/bin/status.js +65 -0
- package/bin/stop.js +22 -0
- package/bin/upgrade.js +134 -0
- package/components/Application.ts +646 -0
- package/components/ApplicationScope.ts +49 -0
- package/components/Component.ts +53 -0
- package/components/ComponentV1.ts +342 -0
- package/components/DEFAULT_CONFIG.ts +18 -0
- package/components/EntryHandler.ts +227 -0
- package/components/Logger.ts +14 -0
- package/components/OptionsWatcher.ts +354 -0
- package/components/PluginModule.ts +6 -0
- package/components/Scope.ts +329 -0
- package/components/componentLoader.ts +529 -0
- package/components/deriveCommonPatternBase.ts +31 -0
- package/components/deriveGlobOptions.ts +44 -0
- package/components/deriveURLPath.ts +57 -0
- package/components/operations.js +658 -0
- package/components/operationsValidation.js +246 -0
- package/components/packageComponent.ts +39 -0
- package/components/requestRestart.ts +26 -0
- package/components/resolveBaseURLPath.ts +38 -0
- package/components/status/ComponentStatus.ts +110 -0
- package/components/status/ComponentStatusRegistry.ts +251 -0
- package/components/status/api.ts +153 -0
- package/components/status/crossThread.ts +405 -0
- package/components/status/errors.ts +152 -0
- package/components/status/index.ts +44 -0
- package/components/status/internal.ts +65 -0
- package/components/status/registry.ts +12 -0
- package/components/status/types.ts +96 -0
- package/config/RootConfigWatcher.ts +59 -0
- package/config/configHelpers.ts +11 -0
- package/config/configUtils.js +967 -0
- package/config/harperConfigEnvVars.ts +641 -0
- package/dataLayer/CreateAttributeObject.js +25 -0
- package/dataLayer/CreateTableObject.js +11 -0
- package/dataLayer/DataLayerObjects.js +43 -0
- package/dataLayer/DeleteBeforeObject.js +22 -0
- package/dataLayer/DeleteObject.js +25 -0
- package/dataLayer/DropAttributeObject.js +11 -0
- package/dataLayer/GetBackupObject.js +22 -0
- package/dataLayer/InsertObject.js +24 -0
- package/dataLayer/ReadAuditLogObject.js +24 -0
- package/dataLayer/SQLSearch.js +1335 -0
- package/dataLayer/SearchByConditionsObject.js +61 -0
- package/dataLayer/SearchByHashObject.js +21 -0
- package/dataLayer/SearchObject.js +45 -0
- package/dataLayer/SqlSearchObject.js +14 -0
- package/dataLayer/UpdateObject.js +23 -0
- package/dataLayer/UpsertObject.js +23 -0
- package/dataLayer/bulkLoad.js +813 -0
- package/dataLayer/dataObjects/BulkLoadObjects.js +27 -0
- package/dataLayer/dataObjects/UpsertObject.js +23 -0
- package/dataLayer/delete.js +164 -0
- package/dataLayer/export.js +381 -0
- package/dataLayer/getBackup.js +40 -0
- package/dataLayer/harperBridge/BridgeMethods.js +81 -0
- package/dataLayer/harperBridge/ResourceBridge.ts +633 -0
- package/dataLayer/harperBridge/bridgeUtility/insertUpdateReturnObj.js +28 -0
- package/dataLayer/harperBridge/bridgeUtility/insertUpdateValidate.js +88 -0
- package/dataLayer/harperBridge/harperBridge.js +21 -0
- package/dataLayer/harperBridge/lmdbBridge/LMDBBridge.js +119 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js +19 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateAttribute.js +112 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateRecords.js +67 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateSchema.js +31 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateTable.js +94 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDeleteAuditLogsBefore.js +98 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDeleteRecords.js +89 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDropAttribute.js +109 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDropSchema.js +107 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDropTable.js +137 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbFlush.js +35 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbGetBackup.js +111 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbGetDataByHash.js +28 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbGetDataByValue.js +29 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbReadAuditLog.js +207 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByConditions.js +156 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByHash.js +21 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByValue.js +30 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbTransaction.js +19 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbUpdateRecords.js +64 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbUpsertRecords.js +70 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBCreateAttributeObject.js +22 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBDeleteTransactionObject.js +23 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBInsertTransactionObject.js +22 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBTransactionObject.js +23 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBUpdateTransactionObject.js +24 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBUpsertTransactionObject.js +24 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/TableSizeObject.js +25 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializeHashSearch.js +21 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializePaths.js +157 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbCheckForNewAttributes.js +94 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbCreateTransactionsAuditEnvironment.js +39 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbGetTableSize.js +34 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbProcessRows.js +100 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbSearch.js +371 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbWriteTransaction.js +109 -0
- package/dataLayer/hdbInfoController.js +254 -0
- package/dataLayer/insert.js +266 -0
- package/dataLayer/readAuditLog.js +59 -0
- package/dataLayer/schema.js +366 -0
- package/dataLayer/schemaDescribe.js +289 -0
- package/dataLayer/search.js +60 -0
- package/dataLayer/transaction.js +17 -0
- package/dataLayer/update.js +124 -0
- package/dist/components/Logger.d.ts +12 -0
- package/dist/components/Logger.js +3 -0
- package/dist/components/Logger.js.map +1 -0
- package/dist/components/Scope.d.ts +14 -4
- package/dist/components/Scope.js +18 -10
- package/dist/components/Scope.js.map +1 -1
- package/dist/components/componentLoader.js +16 -9
- package/dist/components/componentLoader.js.map +1 -1
- package/dist/components/operations.js +2 -2
- package/dist/components/operations.js.map +1 -1
- package/dist/config/configUtils.d.ts +1 -1
- package/dist/config/configUtils.js +1 -1
- package/dist/config/configUtils.js.map +1 -1
- package/dist/dataLayer/CreateTableObject.d.ts +2 -2
- package/dist/dataLayer/CreateTableObject.js +2 -2
- package/dist/dataLayer/CreateTableObject.js.map +1 -1
- package/dist/dataLayer/delete.d.ts +1 -1
- package/dist/dataLayer/schema.js +6 -5
- package/dist/dataLayer/schema.js.map +1 -1
- package/dist/dataLayer/schemaDescribe.js +1 -1
- package/dist/dataLayer/schemaDescribe.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/resources/DatabaseTransaction.d.ts +1 -1
- package/dist/resources/IterableEventQueue.d.ts +1 -1
- package/dist/resources/LMDBTransaction.d.ts +5 -1
- package/dist/resources/Resource.d.ts +1 -1
- package/dist/resources/RocksIndexStore.d.ts +3 -3
- package/dist/resources/RocksTransactionLogStore.d.ts +6 -3
- package/dist/resources/Table.d.ts +15 -6
- package/dist/resources/Table.js +4 -1
- package/dist/resources/Table.js.map +1 -1
- package/dist/resources/analytics/read.js +32 -22
- package/dist/resources/analytics/read.js.map +1 -1
- package/dist/resources/analytics/write.js +3 -6
- package/dist/resources/analytics/write.js.map +1 -1
- package/dist/resources/auditStore.d.ts +3 -3
- package/dist/resources/blob.d.ts +25 -2
- package/dist/resources/databases.d.ts +12 -2
- package/dist/resources/databases.js +22 -19
- package/dist/resources/databases.js.map +1 -1
- package/dist/resources/search.js +11 -5
- package/dist/resources/search.js.map +1 -1
- package/dist/resources/transaction.d.ts +2 -1
- package/dist/security/auth.js +1 -1
- package/dist/security/auth.js.map +1 -1
- package/dist/security/cryptoHash.d.ts +2 -2
- package/dist/security/jsLoader.js +243 -66
- package/dist/security/jsLoader.js.map +1 -1
- package/dist/security/keys.js +4 -5
- package/dist/security/keys.js.map +1 -1
- package/dist/security/user.js +3 -3
- package/dist/security/user.js.map +1 -1
- package/dist/server/REST.js +16 -2
- package/dist/server/REST.js.map +1 -1
- package/dist/server/Server.d.ts +2 -1
- package/dist/server/Server.js.map +1 -1
- package/dist/server/fastifyRoutes/plugins/hdbCore.d.ts +6 -1
- package/dist/server/fastifyRoutes.js +2 -0
- package/dist/server/fastifyRoutes.js.map +1 -1
- package/dist/server/http.js +12 -6
- package/dist/server/http.js.map +1 -1
- package/dist/server/jobs/JobObject.d.ts +3 -3
- package/dist/server/loadRootComponents.js +1 -0
- package/dist/server/loadRootComponents.js.map +1 -1
- package/dist/server/operationsServer.js +3 -1
- package/dist/server/operationsServer.js.map +1 -1
- package/dist/server/serverHelpers/JSONStream.d.ts +3 -3
- package/dist/server/serverHelpers/Request.d.ts +5 -5
- package/dist/server/serverHelpers/requestTimePlugin.d.ts +1 -1
- package/dist/server/threads/manageThreads.d.ts +2 -2
- package/dist/server/threads/manageThreads.js +50 -35
- package/dist/server/threads/manageThreads.js.map +1 -1
- package/dist/server/threads/socketRouter.d.ts +1 -1
- package/dist/sqlTranslator/deleteTranslator.d.ts +1 -1
- package/dist/utility/AWS/AWSConnector.d.ts +3 -2
- package/dist/utility/common_utils.d.ts +3 -3
- package/dist/utility/environment/systemInformation.d.ts +1 -0
- package/dist/utility/functions/date/dateFunctions.d.ts +11 -11
- package/dist/utility/globalSchema.d.ts +1 -1
- package/dist/utility/hdbTerms.d.ts +3 -0
- package/dist/utility/hdbTerms.js +3 -0
- package/dist/utility/hdbTerms.js.map +1 -1
- package/dist/utility/installation.d.ts +2 -4
- package/dist/utility/installation.js.map +1 -1
- package/dist/utility/lmdb/commonUtility.d.ts +1 -0
- package/dist/utility/lmdb/deleteUtility.d.ts +1 -0
- package/dist/utility/lmdb/environmentUtility.d.ts +1 -0
- package/dist/utility/lmdb/searchUtility.d.ts +2 -1
- package/dist/utility/lmdb/writeUtility.d.ts +1 -0
- package/dist/utility/logging/harper_logger.d.ts +6 -6
- package/dist/utility/processManagement/processManagement.d.ts +1 -1
- package/dist/utility/processManagement/servicesConfig.d.ts +12 -6
- package/dist/validation/common_validators.d.ts +4 -3
- package/dist/validation/configValidator.d.ts +3 -2
- package/index.d.ts +56 -0
- package/index.js +41 -0
- package/json/systemSchema.json +373 -0
- package/launchServiceScripts/launchHarperDB.js +3 -0
- package/launchServiceScripts/utility/checkNodeVersion.js +15 -0
- package/package.json +21 -3
- package/resources/DatabaseTransaction.ts +378 -0
- package/resources/ErrorResource.ts +57 -0
- package/resources/IterableEventQueue.ts +94 -0
- package/resources/LMDBTransaction.ts +349 -0
- package/resources/RecordEncoder.ts +702 -0
- package/resources/RequestTarget.ts +134 -0
- package/resources/Resource.ts +789 -0
- package/resources/ResourceInterface.ts +221 -0
- package/resources/ResourceInterfaceV2.ts +53 -0
- package/resources/ResourceV2.ts +67 -0
- package/resources/Resources.ts +162 -0
- package/resources/RocksIndexStore.ts +70 -0
- package/resources/RocksTransactionLogStore.ts +352 -0
- package/resources/Table.ts +4527 -0
- package/resources/analytics/hostnames.ts +72 -0
- package/resources/analytics/metadata.ts +10 -0
- package/resources/analytics/read.ts +252 -0
- package/resources/analytics/write.ts +803 -0
- package/resources/auditStore.ts +556 -0
- package/resources/blob.ts +1268 -0
- package/resources/crdt.ts +125 -0
- package/resources/dataLoader.ts +527 -0
- package/resources/databases.ts +1290 -0
- package/resources/graphql.ts +221 -0
- package/resources/indexes/HierarchicalNavigableSmallWorld.ts +638 -0
- package/resources/indexes/customIndexes.ts +7 -0
- package/resources/indexes/vector.ts +38 -0
- package/resources/jsResource.ts +86 -0
- package/resources/loadEnv.ts +22 -0
- package/resources/login.ts +18 -0
- package/resources/openApi.ts +409 -0
- package/resources/registrationDeprecated.ts +8 -0
- package/resources/replayLogs.ts +136 -0
- package/resources/roles.ts +98 -0
- package/resources/search.ts +1301 -0
- package/resources/tracked.ts +584 -0
- package/resources/transaction.ts +89 -0
- package/resources/transactionBroadcast.ts +258 -0
- package/security/auth.ts +376 -0
- package/security/certificateVerification/certificateVerificationSource.ts +84 -0
- package/security/certificateVerification/configValidation.ts +107 -0
- package/security/certificateVerification/crlVerification.ts +623 -0
- package/security/certificateVerification/index.ts +121 -0
- package/security/certificateVerification/ocspVerification.ts +148 -0
- package/security/certificateVerification/pkijs-ed25519-patch.ts +188 -0
- package/security/certificateVerification/types.ts +128 -0
- package/security/certificateVerification/verificationConfig.ts +138 -0
- package/security/certificateVerification/verificationUtils.ts +447 -0
- package/security/cryptoHash.js +42 -0
- package/security/data_objects/PermissionAttributeResponseObject.js +15 -0
- package/security/data_objects/PermissionResponseObject.js +115 -0
- package/security/data_objects/PermissionTableResponseObject.js +20 -0
- package/security/fastifyAuth.js +169 -0
- package/security/impersonation.ts +160 -0
- package/security/jsLoader.ts +716 -0
- package/security/keys.js +948 -0
- package/security/permissionsTranslator.js +300 -0
- package/security/role.js +218 -0
- package/security/tokenAuthentication.ts +228 -0
- package/security/user.ts +449 -0
- package/server/DurableSubscriptionsSession.ts +503 -0
- package/server/REST.ts +407 -0
- package/server/Server.ts +89 -0
- package/server/fastifyRoutes/helpers/getCORSOptions.js +36 -0
- package/server/fastifyRoutes/helpers/getHeaderTimeoutConfig.js +15 -0
- package/server/fastifyRoutes/helpers/getServerOptions.js +33 -0
- package/server/fastifyRoutes/plugins/hdbCore.js +39 -0
- package/server/fastifyRoutes.ts +205 -0
- package/server/graphqlQuerying.ts +700 -0
- package/server/http.ts +640 -0
- package/server/itc/serverHandlers.js +161 -0
- package/server/itc/utility/ITCEventObject.js +10 -0
- package/server/jobs/JobObject.js +24 -0
- package/server/jobs/jobProcess.js +69 -0
- package/server/jobs/jobRunner.js +162 -0
- package/server/jobs/jobs.js +304 -0
- package/server/loadRootComponents.js +44 -0
- package/server/mqtt.ts +485 -0
- package/server/nodeName.ts +75 -0
- package/server/operationsServer.ts +313 -0
- package/server/serverHelpers/Headers.ts +108 -0
- package/server/serverHelpers/JSONStream.ts +269 -0
- package/server/serverHelpers/OperationFunctionObject.ts +13 -0
- package/server/serverHelpers/Request.ts +158 -0
- package/server/serverHelpers/contentTypes.ts +637 -0
- package/server/serverHelpers/requestTimePlugin.js +57 -0
- package/server/serverHelpers/serverHandlers.js +148 -0
- package/server/serverHelpers/serverUtilities.ts +473 -0
- package/server/serverRegistry.ts +8 -0
- package/server/static.ts +187 -0
- package/server/status/definitions.ts +37 -0
- package/server/status/index.ts +125 -0
- package/server/storageReclamation.ts +93 -0
- package/server/threads/itc.js +89 -0
- package/server/threads/manageThreads.js +594 -0
- package/server/threads/socketRouter.ts +360 -0
- package/server/threads/threadServer.js +279 -0
- package/server/throttle.ts +73 -0
- package/sqlTranslator/SelectValidator.js +330 -0
- package/sqlTranslator/alasqlFunctionImporter.js +62 -0
- package/sqlTranslator/deleteTranslator.js +67 -0
- package/sqlTranslator/index.js +242 -0
- package/sqlTranslator/sql_statement_bucket.js +472 -0
- package/static/defaultConfig.yaml +3 -0
- package/studio/web/HDBDogOnly.svg +78 -0
- package/studio/web/assets/PPRadioGrotesk-Bold-DDaUYG8E.woff +0 -0
- package/studio/web/assets/fa-brands-400-CEJbCg16.woff +0 -0
- package/studio/web/assets/fa-brands-400-CSYNqBb_.ttf +0 -0
- package/studio/web/assets/fa-brands-400-DnkPfk3o.eot +0 -0
- package/studio/web/assets/fa-brands-400-UxlILjvJ.woff2 +0 -0
- package/studio/web/assets/fa-brands-400-cH1MgKbP.svg +3717 -0
- package/studio/web/assets/fa-regular-400-BhTwtT8w.eot +0 -0
- package/studio/web/assets/fa-regular-400-D1vz6WBx.ttf +0 -0
- package/studio/web/assets/fa-regular-400-DFnMcJPd.woff +0 -0
- package/studio/web/assets/fa-regular-400-DGzu1beS.woff2 +0 -0
- package/studio/web/assets/fa-regular-400-gwj8Pxq-.svg +801 -0
- package/studio/web/assets/fa-solid-900-B4ZZ7kfP.svg +5034 -0
- package/studio/web/assets/fa-solid-900-B6Axprfb.eot +0 -0
- package/studio/web/assets/fa-solid-900-BUswJgRo.woff2 +0 -0
- package/studio/web/assets/fa-solid-900-DOXgCApm.woff +0 -0
- package/studio/web/assets/fa-solid-900-mxuxnBEa.ttf +0 -0
- package/studio/web/assets/index-BTgXJX9d.js +235 -0
- package/studio/web/assets/index-BTgXJX9d.js.map +1 -0
- package/studio/web/assets/index-C-GXfcup.js +37 -0
- package/studio/web/assets/index-C-GXfcup.js.map +1 -0
- package/studio/web/assets/index-PFlNdimM.js +2 -0
- package/studio/web/assets/index-PFlNdimM.js.map +1 -0
- package/studio/web/assets/index-Y2g_iFpU.css +1 -0
- package/studio/web/assets/index-jiPwkrsB.css +1 -0
- package/studio/web/assets/index.lazy-C3TJZJ4o.js +266 -0
- package/studio/web/assets/index.lazy-C3TJZJ4o.js.map +1 -0
- package/studio/web/assets/profiler-DotzgiCJ.js +2 -0
- package/studio/web/assets/profiler-DotzgiCJ.js.map +1 -0
- package/studio/web/assets/react-redux-VxUEx_mU.js +6 -0
- package/studio/web/assets/react-redux-VxUEx_mU.js.map +1 -0
- package/studio/web/assets/startRecording-B_9J9Csd.js +3 -0
- package/studio/web/assets/startRecording-B_9J9Csd.js.map +1 -0
- package/studio/web/fabric-signup-background.webp +0 -0
- package/studio/web/fabric-signup-text.png +0 -0
- package/studio/web/favicon_purple.png +0 -0
- package/studio/web/github-icon.svg +15 -0
- package/studio/web/harper-fabric_black.png +0 -0
- package/studio/web/harper-fabric_white.png +0 -0
- package/studio/web/harper-studio_white.png +0 -0
- package/studio/web/index.html +16 -0
- package/studio/web/running.css +148 -0
- package/studio/web/running.html +147 -0
- package/studio/web/running.js +111 -0
- package/upgrade/UpgradeObjects.js +13 -0
- package/upgrade/directives/directivesController.js +90 -0
- package/upgrade/directivesManager.js +139 -0
- package/upgrade/upgradePrompt.js +124 -0
- package/upgrade/upgradeUtilities.js +28 -0
- package/utility/AWS/AWSConnector.js +29 -0
- package/utility/OperationFunctionCaller.js +63 -0
- package/utility/assignCmdEnvVariables.js +62 -0
- package/utility/common_utils.js +867 -0
- package/utility/environment/environmentManager.js +208 -0
- package/utility/environment/systemInformation.js +355 -0
- package/utility/errors/commonErrors.js +267 -0
- package/utility/errors/hdbError.js +146 -0
- package/utility/functions/date/dateFunctions.js +65 -0
- package/utility/functions/geo.js +355 -0
- package/utility/functions/sql/alaSQLExtension.js +104 -0
- package/utility/globalSchema.js +35 -0
- package/utility/hdbTerms.ts +819 -0
- package/utility/install/checkJWTTokensExist.js +62 -0
- package/utility/install/harperdb.conf +15 -0
- package/utility/install/harperdb.service +14 -0
- package/utility/install/installer.js +635 -0
- package/utility/installation.ts +30 -0
- package/utility/lmdb/DBIDefinition.js +20 -0
- package/utility/lmdb/DeleteRecordsResponseObject.js +25 -0
- package/utility/lmdb/InsertRecordsResponseObject.js +22 -0
- package/utility/lmdb/OpenDBIObject.js +31 -0
- package/utility/lmdb/OpenEnvironmentObject.js +41 -0
- package/utility/lmdb/UpdateRecordsResponseObject.js +25 -0
- package/utility/lmdb/UpsertRecordsResponseObject.js +22 -0
- package/utility/lmdb/cleanLMDBMap.js +65 -0
- package/utility/lmdb/commonUtility.js +119 -0
- package/utility/lmdb/deleteUtility.js +128 -0
- package/utility/lmdb/environmentUtility.js +477 -0
- package/utility/lmdb/searchCursorFunctions.js +187 -0
- package/utility/lmdb/searchUtility.js +918 -0
- package/utility/lmdb/terms.js +57 -0
- package/utility/lmdb/writeUtility.js +407 -0
- package/utility/logging/harper_logger.js +876 -0
- package/utility/logging/logRotator.js +157 -0
- package/utility/logging/logger.ts +24 -0
- package/utility/logging/readLog.js +355 -0
- package/utility/logging/transactionLog.js +57 -0
- package/utility/mount_hdb.js +59 -0
- package/utility/npmUtilities.js +102 -0
- package/utility/operationPermissions.ts +112 -0
- package/utility/operation_authorization.js +836 -0
- package/utility/packageUtils.js +55 -0
- package/utility/password.ts +99 -0
- package/utility/processManagement/processManagement.js +187 -0
- package/utility/processManagement/servicesConfig.js +56 -0
- package/utility/scripts/restartHdb.js +24 -0
- package/utility/scripts/user_data.sh +13 -0
- package/utility/signalling.js +36 -0
- package/utility/terms/certificates.js +81 -0
- package/utility/when.ts +20 -0
- package/v1.d.ts +39 -0
- package/v1.js +41 -0
- package/v2.d.ts +39 -0
- package/v2.js +41 -0
- package/validation/bulkDeleteValidator.js +24 -0
- package/validation/check_permissions.js +19 -0
- package/validation/common_validators.js +95 -0
- package/validation/configValidator.js +331 -0
- package/validation/deleteValidator.js +15 -0
- package/validation/fileLoadValidator.js +153 -0
- package/validation/insertValidator.js +40 -0
- package/validation/installValidator.js +37 -0
- package/validation/readLogValidator.js +64 -0
- package/validation/role_validation.js +320 -0
- package/validation/schemaMetadataValidator.js +42 -0
- package/validation/searchValidator.js +166 -0
- package/validation/statusValidator.ts +66 -0
- package/validation/transactionLogValidator.js +33 -0
- package/validation/user_validation.js +55 -0
- package/validation/validationWrapper.js +105 -0
- package/dist/resources/analytics/profile.d.ts +0 -2
- package/dist/resources/analytics/profile.js +0 -144
- package/dist/resources/analytics/profile.js.map +0 -1
|
@@ -0,0 +1,803 @@
|
|
|
1
|
+
import { parentPort, threadId } from 'worker_threads';
|
|
2
|
+
import { onMessageByType } from '../../server/threads/manageThreads.js';
|
|
3
|
+
import { getDatabases, table } from '../databases.ts';
|
|
4
|
+
import type { Databases, Table, Tables } from '../databases.ts';
|
|
5
|
+
import harperLogger from '../../utility/logging/harper_logger.js';
|
|
6
|
+
import { stat } from 'node:fs/promises';
|
|
7
|
+
const { getLogFilePath, forComponent } = harperLogger;
|
|
8
|
+
import { dirname, join } from 'path';
|
|
9
|
+
import { open } from 'fs/promises';
|
|
10
|
+
import { getNextMonotonicTime } from '../../utility/lmdb/commonUtility.js';
|
|
11
|
+
import { get as envGet, initSync } from '../../utility/environment/environmentManager.js';
|
|
12
|
+
import { CONFIG_PARAMS } from '../../utility/hdbTerms.ts';
|
|
13
|
+
import { server } from '../../server/Server.ts';
|
|
14
|
+
import * as fs from 'node:fs';
|
|
15
|
+
import { getAnalyticsHostnameTable, nodeIds, stableNodeId } from './hostnames.ts';
|
|
16
|
+
import { METRIC } from './metadata.ts';
|
|
17
|
+
import { RocksDatabase } from '@harperfast/rocksdb-js';
|
|
18
|
+
|
|
19
|
+
const log = forComponent('analytics').conditional;
|
|
20
|
+
|
|
21
|
+
initSync();
|
|
22
|
+
|
|
23
|
+
type ActionCallback = (action: Action) => void;
|
|
24
|
+
export type Value = number | boolean | ActionCallback;
|
|
25
|
+
interface Action {
|
|
26
|
+
total?: number;
|
|
27
|
+
values?: Float32Array;
|
|
28
|
+
count?: number;
|
|
29
|
+
callback?: ActionCallback;
|
|
30
|
+
description?: {
|
|
31
|
+
metric: string;
|
|
32
|
+
path: string;
|
|
33
|
+
method: string;
|
|
34
|
+
type: string;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let activeActions = new Map<string, Action>();
|
|
39
|
+
let analyticsEnabled = envGet(CONFIG_PARAMS.ANALYTICS_AGGREGATEPERIOD) > -1;
|
|
40
|
+
let sendAnalyticsTimeout: NodeJS.Timeout;
|
|
41
|
+
|
|
42
|
+
export function setAnalyticsEnabled(enabled: boolean) {
|
|
43
|
+
analyticsEnabled = enabled;
|
|
44
|
+
clearTimeout(sendAnalyticsTimeout); // reset this
|
|
45
|
+
sendAnalyticsTimeout = null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function recordExistingAction(value: Value, action: Action) {
|
|
49
|
+
if (typeof value === 'number') {
|
|
50
|
+
let values: Float32Array = action.values;
|
|
51
|
+
const index = values.index++;
|
|
52
|
+
if (index >= values.length) {
|
|
53
|
+
const oldValues = values;
|
|
54
|
+
action.values = values = new Float32Array(index * 2);
|
|
55
|
+
values.set(oldValues);
|
|
56
|
+
values.index = index + 1;
|
|
57
|
+
}
|
|
58
|
+
values[index] = value;
|
|
59
|
+
action.total += value;
|
|
60
|
+
} else if (typeof value === 'boolean') {
|
|
61
|
+
if (value) action.total++;
|
|
62
|
+
action.count++;
|
|
63
|
+
} else if (typeof value === 'function') {
|
|
64
|
+
// nothing to do except wait for the callback
|
|
65
|
+
action.count++;
|
|
66
|
+
} else throw new TypeError('Invalid metric value type ' + typeof value);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function recordNewAction(key: string, value: Value, metric?: string, path?: string, method?: string, type?: string) {
|
|
70
|
+
const action: Action = {};
|
|
71
|
+
if (typeof value === 'number') {
|
|
72
|
+
action.total = value;
|
|
73
|
+
action.values = new Float32Array(4);
|
|
74
|
+
action.values.index = 1;
|
|
75
|
+
action.values[0] = value;
|
|
76
|
+
action.total = value;
|
|
77
|
+
} else if (typeof value === 'boolean') {
|
|
78
|
+
action.total = value ? 1 : 0;
|
|
79
|
+
action.count = 1;
|
|
80
|
+
} else if (typeof value === 'function') {
|
|
81
|
+
action.count = 1;
|
|
82
|
+
action.callback = value;
|
|
83
|
+
} else {
|
|
84
|
+
throw new TypeError('Invalid metric value type ' + typeof value);
|
|
85
|
+
}
|
|
86
|
+
action.description = {
|
|
87
|
+
metric,
|
|
88
|
+
path,
|
|
89
|
+
method,
|
|
90
|
+
type,
|
|
91
|
+
};
|
|
92
|
+
activeActions.set(key, action);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Record an action for analytics (like an HTTP request, replication, MQTT message)
|
|
97
|
+
* @param value
|
|
98
|
+
* @param metric
|
|
99
|
+
* @param path
|
|
100
|
+
* @param method
|
|
101
|
+
* @param type
|
|
102
|
+
*/
|
|
103
|
+
export function recordAction(value: Value, metric: string, path?: string, method?: string, type?: string) {
|
|
104
|
+
if (!analyticsEnabled) return;
|
|
105
|
+
// TODO: May want to consider nested paths, as they may yield faster hashing of (fixed) strings that hashing concatenated strings
|
|
106
|
+
let key = metric + (path ? '-' + path : '');
|
|
107
|
+
if (method !== undefined) key += '-' + method;
|
|
108
|
+
if (type !== undefined) key += '-' + type;
|
|
109
|
+
const action = activeActions.get(key);
|
|
110
|
+
if (action) {
|
|
111
|
+
recordExistingAction(value, action);
|
|
112
|
+
} else {
|
|
113
|
+
recordNewAction(key, value, metric, path, method, type);
|
|
114
|
+
}
|
|
115
|
+
if (!sendAnalyticsTimeout) sendAnalytics();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
server.recordAnalytics = recordAction;
|
|
119
|
+
|
|
120
|
+
export function recordActionBinary(value, metric, path?, method?, type?) {
|
|
121
|
+
recordAction(Boolean(value), metric, path, method, type);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
let analyticsStart = 0;
|
|
125
|
+
export const analyticsDelay = 1000;
|
|
126
|
+
const ANALYTICS_REPORT_TYPE = 'analytics-report';
|
|
127
|
+
const analyticsListeners = [];
|
|
128
|
+
const analyticsAggregateListeners = [];
|
|
129
|
+
|
|
130
|
+
export function addAnalyticsListener(callback) {
|
|
131
|
+
analyticsListeners.push(callback);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const IDEAL_PERCENTILES = [0.01, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95, 0.99, 0.999, 1];
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Periodically send analytics data back to the main thread for storage
|
|
138
|
+
*/
|
|
139
|
+
function sendAnalytics() {
|
|
140
|
+
analyticsStart ||= performance.now();
|
|
141
|
+
sendAnalyticsTimeout = setTimeout(async () => {
|
|
142
|
+
sendAnalyticsTimeout = null;
|
|
143
|
+
const period = performance.now() - analyticsStart;
|
|
144
|
+
analyticsStart = 0;
|
|
145
|
+
const metrics = [];
|
|
146
|
+
const report = {
|
|
147
|
+
time: Date.now(),
|
|
148
|
+
period,
|
|
149
|
+
threadId,
|
|
150
|
+
metrics,
|
|
151
|
+
};
|
|
152
|
+
for (const [_name, action] of activeActions) {
|
|
153
|
+
if (action.values) {
|
|
154
|
+
const values = action.values.subarray(0, action.values.index);
|
|
155
|
+
values.sort();
|
|
156
|
+
const count = values.length;
|
|
157
|
+
// compute the stats
|
|
158
|
+
let lastUpperBound = 0;
|
|
159
|
+
const distribution = [];
|
|
160
|
+
let lastValue;
|
|
161
|
+
for (const percentile of IDEAL_PERCENTILES) {
|
|
162
|
+
const upperBound = Math.floor(count * percentile);
|
|
163
|
+
const value = values[upperBound - 1];
|
|
164
|
+
if (upperBound > lastUpperBound) {
|
|
165
|
+
const count = upperBound - lastUpperBound;
|
|
166
|
+
if (value === lastValue) {
|
|
167
|
+
const entry = distribution[distribution.length - 1];
|
|
168
|
+
if (typeof entry === 'number') distribution[distribution.length - 1] = { value: entry, count: 1 + count };
|
|
169
|
+
else entry.count += count;
|
|
170
|
+
} else {
|
|
171
|
+
distribution.push(count > 1 ? { value, count } : value);
|
|
172
|
+
lastValue = value;
|
|
173
|
+
}
|
|
174
|
+
lastUpperBound = upperBound;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
metrics.push(
|
|
178
|
+
Object.assign(action.description, {
|
|
179
|
+
mean: action.total / count,
|
|
180
|
+
distribution,
|
|
181
|
+
count,
|
|
182
|
+
})
|
|
183
|
+
);
|
|
184
|
+
} else if (action.callback) {
|
|
185
|
+
metrics.push(Object.assign(action.description, action.callback(action)));
|
|
186
|
+
} else {
|
|
187
|
+
metrics.push(
|
|
188
|
+
Object.assign(action.description, {
|
|
189
|
+
total: action.total,
|
|
190
|
+
count: action.count,
|
|
191
|
+
})
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
await rest(); // sort's are expensive and we don't want to do two of them in the same event turn
|
|
195
|
+
}
|
|
196
|
+
const memoryUsage = process.memoryUsage();
|
|
197
|
+
metrics.push({
|
|
198
|
+
metric: 'memory',
|
|
199
|
+
threadId,
|
|
200
|
+
byThread: true,
|
|
201
|
+
...memoryUsage,
|
|
202
|
+
});
|
|
203
|
+
for (const listener of analyticsListeners) {
|
|
204
|
+
listener(metrics);
|
|
205
|
+
}
|
|
206
|
+
activeActions = new Map();
|
|
207
|
+
if (parentPort)
|
|
208
|
+
parentPort.postMessage({
|
|
209
|
+
type: ANALYTICS_REPORT_TYPE,
|
|
210
|
+
report,
|
|
211
|
+
});
|
|
212
|
+
else recordAnalytics({ report });
|
|
213
|
+
}, analyticsDelay).unref();
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export async function recordHostname() {
|
|
217
|
+
const hostname = server.hostname;
|
|
218
|
+
log.trace?.('recordHostname server.hostname:', hostname);
|
|
219
|
+
const nodeId = stableNodeId(hostname);
|
|
220
|
+
log.trace?.('recordHostname nodeId:', nodeId);
|
|
221
|
+
const hostnamesTable = getAnalyticsHostnameTable();
|
|
222
|
+
const record = await hostnamesTable.get(nodeId);
|
|
223
|
+
if (!record) {
|
|
224
|
+
const hostnameRecord = {
|
|
225
|
+
id: nodeId,
|
|
226
|
+
hostname,
|
|
227
|
+
};
|
|
228
|
+
log.trace?.(`recordHostname storing hostname: ${JSON.stringify(hostnameRecord)}`);
|
|
229
|
+
await hostnamesTable.put(hostnameRecord.id, hostnameRecord);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export interface Metric {
|
|
234
|
+
[key: string]: any;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function getHostNodeId(hostname: string) {
|
|
238
|
+
let nodeId = nodeIds.get(hostname);
|
|
239
|
+
if (nodeId) {
|
|
240
|
+
log.trace?.('storeMetric cached nodeId:', nodeId);
|
|
241
|
+
return nodeId;
|
|
242
|
+
}
|
|
243
|
+
nodeId = stableNodeId(hostname);
|
|
244
|
+
log.trace?.('storeMetric new nodeId:', nodeId);
|
|
245
|
+
nodeIds.set(hostname, nodeId);
|
|
246
|
+
return nodeId;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function storeMetric(table: Table, metric: Metric) {
|
|
250
|
+
const nodeId = getHostNodeId(server.hostname);
|
|
251
|
+
const metricValue = {
|
|
252
|
+
id: [getNextMonotonicTime(), nodeId],
|
|
253
|
+
...metric,
|
|
254
|
+
};
|
|
255
|
+
log.trace?.(`storing metric ${JSON.stringify(metricValue)}`);
|
|
256
|
+
table.put(metricValue.id, metricValue);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
interface ResourceUsage extends Partial<NodeJS.ResourceUsage> {
|
|
260
|
+
time?: number;
|
|
261
|
+
period?: number;
|
|
262
|
+
cpuUtilization?: number;
|
|
263
|
+
userCPUTime?: number;
|
|
264
|
+
systemCPUTime?: number;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/** calculateCPUUtilization takes a ResourceUsage with at least userCPUTime &
|
|
268
|
+
* systemCPUTime set with millisecond values and a time period in milliseconds
|
|
269
|
+
* and returns the percentage of that time the CPU was being utilized as a
|
|
270
|
+
* decimal value between 0 and 1. So for example, 50% utilization will be
|
|
271
|
+
* returned as 0.5.
|
|
272
|
+
*/
|
|
273
|
+
export function calculateCPUUtilization(resourceUsage: ResourceUsage, period: number): number {
|
|
274
|
+
const cpuTime = resourceUsage.userCPUTime + resourceUsage.systemCPUTime;
|
|
275
|
+
log.trace?.(`calculateCPUUtilization cpuTime: ${cpuTime} period: ${period}`);
|
|
276
|
+
return Math.round((cpuTime / period) * 100) / 100;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/** diffResourceUsage takes a ResourceUsage representing the last time we stored them and a new
|
|
280
|
+
* process.resourceUsage() return value and normalizes and diffs the two values to return the
|
|
281
|
+
* new values for this time period.
|
|
282
|
+
*/
|
|
283
|
+
export function diffResourceUsage(lastResourceUsage: ResourceUsage, resourceUsage: ResourceUsage): ResourceUsage {
|
|
284
|
+
return {
|
|
285
|
+
userCPUTime: resourceUsage.userCPUTime - (lastResourceUsage?.userCPUTime ?? 0),
|
|
286
|
+
systemCPUTime: resourceUsage.systemCPUTime - (lastResourceUsage?.systemCPUTime ?? 0),
|
|
287
|
+
minorPageFault: resourceUsage.minorPageFault - (lastResourceUsage?.minorPageFault ?? 0),
|
|
288
|
+
majorPageFault: resourceUsage.majorPageFault - (lastResourceUsage?.majorPageFault ?? 0),
|
|
289
|
+
fsRead: resourceUsage.fsRead - (lastResourceUsage?.fsRead ?? 0),
|
|
290
|
+
fsWrite: resourceUsage.fsWrite - (lastResourceUsage?.fsWrite ?? 0),
|
|
291
|
+
voluntaryContextSwitches:
|
|
292
|
+
resourceUsage.voluntaryContextSwitches - (lastResourceUsage?.voluntaryContextSwitches ?? 0),
|
|
293
|
+
involuntaryContextSwitches:
|
|
294
|
+
resourceUsage.involuntaryContextSwitches - (lastResourceUsage?.involuntaryContextSwitches ?? 0),
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/** storeTableSizeMetrics returns the cumulative size of the tables
|
|
299
|
+
*/
|
|
300
|
+
function storeTableSizeMetrics(analyticsTable: Table, dbName: string, tables: Tables): number {
|
|
301
|
+
let dbUsedSize = 0;
|
|
302
|
+
for (const [tableName, table] of Object.entries(tables)) {
|
|
303
|
+
const fullTableName = `${dbName}.${tableName}`;
|
|
304
|
+
const tableSize = table.getSize();
|
|
305
|
+
const metric = {
|
|
306
|
+
metric: METRIC.TABLE_SIZE,
|
|
307
|
+
database: dbName,
|
|
308
|
+
table: tableName,
|
|
309
|
+
size: tableSize,
|
|
310
|
+
};
|
|
311
|
+
log.trace?.(`table ${fullTableName} size metric: ${JSON.stringify(metric)}`);
|
|
312
|
+
storeMetric(analyticsTable, metric);
|
|
313
|
+
dbUsedSize += tableSize;
|
|
314
|
+
}
|
|
315
|
+
return dbUsedSize;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function storeDBSizeMetrics(analyticsTable: Table, databases: Databases) {
|
|
319
|
+
for (const [db, tables] of Object.entries(databases)) {
|
|
320
|
+
try {
|
|
321
|
+
const [firstTable] = Object.values(tables);
|
|
322
|
+
const dbAuditSize = firstTable?.getAuditSize();
|
|
323
|
+
if (!dbAuditSize) {
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
let metric;
|
|
327
|
+
if (firstTable.primaryStore instanceof RocksDatabase) {
|
|
328
|
+
const dbPath = firstTable.primaryStore.path;
|
|
329
|
+
let dbSize = 0;
|
|
330
|
+
for (const filename of fs.readdirSync(dbPath)) {
|
|
331
|
+
if (filename.endsWith('.sst')) {
|
|
332
|
+
dbSize += fs.statSync(join(dbPath, filename)).size;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
metric = {
|
|
336
|
+
metric: METRIC.DATABASE_SIZE,
|
|
337
|
+
database: db,
|
|
338
|
+
size: dbSize,
|
|
339
|
+
transactionLog: dbAuditSize,
|
|
340
|
+
};
|
|
341
|
+
storeMetric(analyticsTable, metric);
|
|
342
|
+
} else {
|
|
343
|
+
const dbTotalSize = fs.statSync(firstTable.primaryStore.path).size;
|
|
344
|
+
const dbUsedSize = storeTableSizeMetrics(analyticsTable, db, tables);
|
|
345
|
+
const dbFree = dbTotalSize - dbUsedSize;
|
|
346
|
+
metric = {
|
|
347
|
+
metric: METRIC.DATABASE_SIZE,
|
|
348
|
+
database: db,
|
|
349
|
+
size: dbTotalSize,
|
|
350
|
+
used: dbUsedSize,
|
|
351
|
+
free: dbFree,
|
|
352
|
+
audit: dbAuditSize,
|
|
353
|
+
};
|
|
354
|
+
storeMetric(analyticsTable, metric);
|
|
355
|
+
}
|
|
356
|
+
} catch (error) {
|
|
357
|
+
// a table or db was deleted, could get an error here
|
|
358
|
+
log.warn?.(`Error getting DB size metrics`, error);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function storeVolumeMetrics(analyticsTable: Table, databases: Databases) {
|
|
364
|
+
for (const [db, tables] of Object.entries(databases)) {
|
|
365
|
+
try {
|
|
366
|
+
const [firstTable] = Object.values(tables);
|
|
367
|
+
const storageStats = firstTable?.getStorageStats();
|
|
368
|
+
if (!storageStats) {
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
const metric = {
|
|
372
|
+
metric: METRIC.STORAGE_VOLUME,
|
|
373
|
+
database: db,
|
|
374
|
+
...storageStats,
|
|
375
|
+
};
|
|
376
|
+
storeMetric(analyticsTable, metric);
|
|
377
|
+
log.trace?.(`db ${db} storage volume metrics: ${JSON.stringify(metric)}`);
|
|
378
|
+
} catch (error) {
|
|
379
|
+
// a table or db was deleted, could get an error here
|
|
380
|
+
log.warn?.(`Error getting DB volume metrics`, error);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
async function aggregation(fromPeriod, toPeriod = 60000) {
|
|
386
|
+
const rawAnalyticsTable = getRawAnalyticsTable();
|
|
387
|
+
const analyticsTable = getAnalyticsTable();
|
|
388
|
+
const taskQueueLatency = (async () => {
|
|
389
|
+
const start = performance.now();
|
|
390
|
+
// measure how long it takes to enqueue and get a callback from a simple/fast task:
|
|
391
|
+
await stat(getLogFilePath());
|
|
392
|
+
const delay = performance.now() - start;
|
|
393
|
+
if (delay > 5000) {
|
|
394
|
+
log.warn?.('Unusually high task queue latency on the main thread of ' + Math.round(now - start) + 'ms');
|
|
395
|
+
}
|
|
396
|
+
return delay;
|
|
397
|
+
})();
|
|
398
|
+
let lastForPeriod;
|
|
399
|
+
const localNodeId = getHostNodeId(server.hostname);
|
|
400
|
+
// find the last entry for this period for the local node only
|
|
401
|
+
for (const entry of analyticsTable.primaryStore.getRange({
|
|
402
|
+
start: Infinity,
|
|
403
|
+
end: false,
|
|
404
|
+
reverse: true,
|
|
405
|
+
})) {
|
|
406
|
+
if (!entry.value?.time || entry.value?.id[1] !== localNodeId) continue;
|
|
407
|
+
lastForPeriod = entry.value.time;
|
|
408
|
+
break;
|
|
409
|
+
}
|
|
410
|
+
// was the last aggregation too recent to calculate a whole period?
|
|
411
|
+
if (Date.now() - toPeriod < lastForPeriod) return;
|
|
412
|
+
let firstForPeriod;
|
|
413
|
+
const aggregateActions = new Map();
|
|
414
|
+
const distributions = new Map();
|
|
415
|
+
const threadsToAverage = [];
|
|
416
|
+
let lastTime: number;
|
|
417
|
+
for (const { key, value } of rawAnalyticsTable.primaryStore.getRange({
|
|
418
|
+
start: lastForPeriod || false,
|
|
419
|
+
exclusiveStart: true,
|
|
420
|
+
end: Infinity,
|
|
421
|
+
})) {
|
|
422
|
+
if (!value) continue;
|
|
423
|
+
if (firstForPeriod) {
|
|
424
|
+
if (key > firstForPeriod + toPeriod) break; // outside the period of interest
|
|
425
|
+
} else firstForPeriod = key;
|
|
426
|
+
lastTime = key;
|
|
427
|
+
const { metrics, threadId } = value;
|
|
428
|
+
for (const entry of metrics || []) {
|
|
429
|
+
// eslint-disable-next-line no-unused-vars
|
|
430
|
+
let { path, method, type, metric, count, total, distribution, threads, ...measures } = entry;
|
|
431
|
+
if (!count) count = 1;
|
|
432
|
+
let key = metric + (path ? '-' + path : '');
|
|
433
|
+
if (method !== undefined) key += '-' + method;
|
|
434
|
+
if (type !== undefined) key += '-' + type;
|
|
435
|
+
let action = aggregateActions.get(key);
|
|
436
|
+
if (action) {
|
|
437
|
+
if (action.threads) {
|
|
438
|
+
const actionForThread = action.threads[threadId];
|
|
439
|
+
if (actionForThread) action = actionForThread;
|
|
440
|
+
else {
|
|
441
|
+
action.threads[threadId] = { ...measures };
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
if (!action.count) action.count = 1;
|
|
446
|
+
const previousCount = action.count;
|
|
447
|
+
for (const measureName in measures) {
|
|
448
|
+
const value = measures[measureName];
|
|
449
|
+
if (typeof value === 'number') {
|
|
450
|
+
action[measureName] = (action[measureName] * previousCount + value * count) / (previousCount + count);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
action.count += count;
|
|
454
|
+
if (total >= 0) {
|
|
455
|
+
action.total += total;
|
|
456
|
+
action.ratio = action.total / action.count;
|
|
457
|
+
}
|
|
458
|
+
} else {
|
|
459
|
+
action = { period: toPeriod, ...entry };
|
|
460
|
+
delete action.distribution;
|
|
461
|
+
aggregateActions.set(key, action);
|
|
462
|
+
if (action.byThread) {
|
|
463
|
+
action.threads = [];
|
|
464
|
+
action.threads[threadId] = { ...measures };
|
|
465
|
+
threadsToAverage.push(action);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
if (distribution) {
|
|
469
|
+
distribution = distribution.map((entry) => (typeof entry === 'number' ? { value: entry, count: 1 } : entry));
|
|
470
|
+
const existingDistribution = distributions.get(key);
|
|
471
|
+
if (!existingDistribution) distributions.set(key, distribution);
|
|
472
|
+
else {
|
|
473
|
+
existingDistribution.push(...distribution);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
await rest();
|
|
478
|
+
}
|
|
479
|
+
for (const entry of threadsToAverage) {
|
|
480
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars,prefer-const
|
|
481
|
+
let { path, method, type, metric, count, total, distribution, threads, ...measures } = entry;
|
|
482
|
+
threads = threads.filter((thread) => thread);
|
|
483
|
+
for (const measureName in measures) {
|
|
484
|
+
if (typeof entry[measureName] !== 'number') continue;
|
|
485
|
+
let total = 0;
|
|
486
|
+
for (const thread of threads) {
|
|
487
|
+
const value = thread[measureName];
|
|
488
|
+
if (typeof value === 'number') {
|
|
489
|
+
total += value;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
entry[measureName] = total;
|
|
493
|
+
}
|
|
494
|
+
entry.count = threads.length;
|
|
495
|
+
delete entry.threads;
|
|
496
|
+
delete entry.byThread;
|
|
497
|
+
}
|
|
498
|
+
for (const [key, distribution] of distributions) {
|
|
499
|
+
// now iterate through the distributions finding the close bin to each percentile and interpolating the position in that bin
|
|
500
|
+
const action = aggregateActions.get(key);
|
|
501
|
+
distribution.sort((a, b) => (a.value > b.value ? 1 : -1));
|
|
502
|
+
const count = action.count - 1;
|
|
503
|
+
const percentiles = [];
|
|
504
|
+
let countPosition = 0;
|
|
505
|
+
let index = 0;
|
|
506
|
+
let bin;
|
|
507
|
+
for (const percentile of IDEAL_PERCENTILES) {
|
|
508
|
+
const nextTargetCount = count * percentile;
|
|
509
|
+
while (countPosition < nextTargetCount) {
|
|
510
|
+
bin = distribution[index++];
|
|
511
|
+
countPosition += bin.count;
|
|
512
|
+
// we decrement these counts so we are skipping the minimum value in our interpolation
|
|
513
|
+
if (index === 1) countPosition--;
|
|
514
|
+
}
|
|
515
|
+
const previousBin = distribution[index > 1 ? index - 2 : 0];
|
|
516
|
+
if (!bin) bin = distribution[0];
|
|
517
|
+
percentiles.push(bin.value - ((bin.value - previousBin.value) * (countPosition - nextTargetCount)) / bin.count);
|
|
518
|
+
}
|
|
519
|
+
const [p1, p10, p25, median, p75, p90, p95, p99, p999] = percentiles;
|
|
520
|
+
Object.assign(action, { p1, p10, p25, median, p75, p90, p95, p99, p999 });
|
|
521
|
+
}
|
|
522
|
+
let hasUpdates;
|
|
523
|
+
for (const [, value] of aggregateActions) {
|
|
524
|
+
value.time = lastTime;
|
|
525
|
+
storeMetric(analyticsTable, value);
|
|
526
|
+
hasUpdates = true;
|
|
527
|
+
}
|
|
528
|
+
if (hasUpdates) {
|
|
529
|
+
for (const listener of analyticsAggregateListeners) {
|
|
530
|
+
listener(aggregateActions.values());
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
const now = Date.now();
|
|
534
|
+
const { idle, active } = performance.eventLoopUtilization();
|
|
535
|
+
// don't record boring entries
|
|
536
|
+
if (hasUpdates || active * 10 > idle) {
|
|
537
|
+
const value = {
|
|
538
|
+
metric: METRIC.MAIN_THREAD_UTILIZATION,
|
|
539
|
+
idle: idle - lastIdle,
|
|
540
|
+
active: active - lastActive,
|
|
541
|
+
taskQueueLatency: await taskQueueLatency,
|
|
542
|
+
time: now,
|
|
543
|
+
...process.memoryUsage(),
|
|
544
|
+
};
|
|
545
|
+
storeMetric(analyticsTable, value);
|
|
546
|
+
}
|
|
547
|
+
lastIdle = idle;
|
|
548
|
+
lastActive = active;
|
|
549
|
+
|
|
550
|
+
// resource-usage metrics
|
|
551
|
+
const resourceUsage = process.resourceUsage() as ResourceUsage;
|
|
552
|
+
resourceUsage.time = now;
|
|
553
|
+
// normalize to milliseconds
|
|
554
|
+
resourceUsage.userCPUTime = resourceUsage.userCPUTime / 1000;
|
|
555
|
+
resourceUsage.systemCPUTime = resourceUsage.systemCPUTime / 1000;
|
|
556
|
+
log.trace?.(`process.resourceUsage: ${JSON.stringify(resourceUsage)}`);
|
|
557
|
+
const currentResourceUsage = diffResourceUsage(lastResourceUsage, resourceUsage);
|
|
558
|
+
log.trace?.(`diffed resourceUsage: ${JSON.stringify(currentResourceUsage)}`);
|
|
559
|
+
currentResourceUsage.time = now;
|
|
560
|
+
currentResourceUsage.period = lastResourceUsage.time ? now - lastResourceUsage.time : toPeriod;
|
|
561
|
+
currentResourceUsage.cpuUtilization = calculateCPUUtilization(currentResourceUsage, currentResourceUsage.period);
|
|
562
|
+
const cruMetric = {
|
|
563
|
+
metric: METRIC.RESOURCE_USAGE,
|
|
564
|
+
...currentResourceUsage,
|
|
565
|
+
};
|
|
566
|
+
storeMetric(analyticsTable, cruMetric);
|
|
567
|
+
lastResourceUsage = resourceUsage;
|
|
568
|
+
|
|
569
|
+
// database-size & table-size metrics
|
|
570
|
+
const databases = getDatabases();
|
|
571
|
+
storeDBSizeMetrics(analyticsTable, databases);
|
|
572
|
+
storeDBSizeMetrics(analyticsTable, { system: databases.system });
|
|
573
|
+
|
|
574
|
+
// database storage volume metrics
|
|
575
|
+
storeVolumeMetrics(analyticsTable, databases);
|
|
576
|
+
storeVolumeMetrics(analyticsTable, { system: databases.system });
|
|
577
|
+
}
|
|
578
|
+
let lastIdle = 0;
|
|
579
|
+
let lastActive = 0;
|
|
580
|
+
let lastResourceUsage: ResourceUsage = {
|
|
581
|
+
userCPUTime: 0,
|
|
582
|
+
systemCPUTime: 0,
|
|
583
|
+
};
|
|
584
|
+
|
|
585
|
+
const rest = () => new Promise(setImmediate);
|
|
586
|
+
|
|
587
|
+
async function cleanup(AnalyticsTable, expiration) {
|
|
588
|
+
const end = Date.now() - expiration;
|
|
589
|
+
for (const key of AnalyticsTable.primaryStore.getKeys({ start: false, end })) {
|
|
590
|
+
AnalyticsTable.primaryStore.remove(key);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
const RAW_EXPIRATION = 3600000;
|
|
595
|
+
const AGGREGATE_EXPIRATION = 31536000000; // one year
|
|
596
|
+
|
|
597
|
+
let RawAnalyticsTable: Table;
|
|
598
|
+
function getRawAnalyticsTable() {
|
|
599
|
+
return (
|
|
600
|
+
RawAnalyticsTable ||
|
|
601
|
+
(RawAnalyticsTable = table({
|
|
602
|
+
table: 'hdb_raw_analytics',
|
|
603
|
+
database: 'system',
|
|
604
|
+
audit: false,
|
|
605
|
+
trackDeletes: false,
|
|
606
|
+
attributes: [
|
|
607
|
+
{
|
|
608
|
+
name: 'id',
|
|
609
|
+
isPrimaryKey: true,
|
|
610
|
+
},
|
|
611
|
+
{
|
|
612
|
+
name: 'action',
|
|
613
|
+
},
|
|
614
|
+
{
|
|
615
|
+
name: 'metrics',
|
|
616
|
+
},
|
|
617
|
+
],
|
|
618
|
+
}))
|
|
619
|
+
);
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
let AnalyticsTable: Table;
|
|
623
|
+
function getAnalyticsTable() {
|
|
624
|
+
return (
|
|
625
|
+
AnalyticsTable ||
|
|
626
|
+
(AnalyticsTable = table({
|
|
627
|
+
table: 'hdb_analytics',
|
|
628
|
+
database: 'system',
|
|
629
|
+
audit: true,
|
|
630
|
+
trackDeletes: false,
|
|
631
|
+
attributes: [
|
|
632
|
+
{
|
|
633
|
+
name: 'id',
|
|
634
|
+
isPrimaryKey: true,
|
|
635
|
+
},
|
|
636
|
+
{
|
|
637
|
+
name: 'metric',
|
|
638
|
+
},
|
|
639
|
+
{
|
|
640
|
+
name: 'path',
|
|
641
|
+
},
|
|
642
|
+
{
|
|
643
|
+
name: 'method',
|
|
644
|
+
},
|
|
645
|
+
{
|
|
646
|
+
name: 'type',
|
|
647
|
+
},
|
|
648
|
+
],
|
|
649
|
+
}))
|
|
650
|
+
);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
if (!parentPort) onMessageByType(ANALYTICS_REPORT_TYPE, recordAnalytics);
|
|
654
|
+
let scheduledTasksRunning;
|
|
655
|
+
function startScheduledTasks() {
|
|
656
|
+
scheduledTasksRunning = true;
|
|
657
|
+
const AGGREGATE_PERIOD = envGet(CONFIG_PARAMS.ANALYTICS_AGGREGATEPERIOD) * 1000;
|
|
658
|
+
if (AGGREGATE_PERIOD) {
|
|
659
|
+
setInterval(
|
|
660
|
+
async () => {
|
|
661
|
+
await aggregation(analyticsDelay, AGGREGATE_PERIOD);
|
|
662
|
+
await cleanup(getRawAnalyticsTable(), RAW_EXPIRATION);
|
|
663
|
+
await cleanup(getAnalyticsTable(), AGGREGATE_EXPIRATION);
|
|
664
|
+
},
|
|
665
|
+
Math.min(AGGREGATE_PERIOD / 2, 0x7fffffff)
|
|
666
|
+
).unref();
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
let totalBytesProcessed = 0;
|
|
671
|
+
const lastUtilizations = new Map();
|
|
672
|
+
const LOG_ANALYTICS = false; // TODO: Make this a config option if we really want this
|
|
673
|
+
function recordAnalytics(message, worker?) {
|
|
674
|
+
const report = message.report;
|
|
675
|
+
report.threadId = worker?.threadId || threadId;
|
|
676
|
+
// Add system information stats as well
|
|
677
|
+
for (const metric of report.metrics) {
|
|
678
|
+
if (metric.metric === 'bytes-sent') {
|
|
679
|
+
totalBytesProcessed += metric.mean * metric.count;
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
report.totalBytesProcessed = totalBytesProcessed;
|
|
683
|
+
if (worker) {
|
|
684
|
+
report.metrics.push({
|
|
685
|
+
metric: METRIC.UTILIZATION,
|
|
686
|
+
...worker.performance.eventLoopUtilization(lastUtilizations.get(worker)),
|
|
687
|
+
});
|
|
688
|
+
lastUtilizations.set(worker, worker.performance.eventLoopUtilization());
|
|
689
|
+
}
|
|
690
|
+
report.id = getNextMonotonicTime();
|
|
691
|
+
getRawAnalyticsTable().primaryStore.put(report.id, report);
|
|
692
|
+
if (!scheduledTasksRunning) startScheduledTasks();
|
|
693
|
+
if (LOG_ANALYTICS) lastAppend = logAnalytics(report);
|
|
694
|
+
}
|
|
695
|
+
let lastAppend;
|
|
696
|
+
let analyticsLog;
|
|
697
|
+
const MAX_ANALYTICS_SIZE = 1000000;
|
|
698
|
+
async function logAnalytics(report) {
|
|
699
|
+
await lastAppend;
|
|
700
|
+
if (!analyticsLog) {
|
|
701
|
+
const logDir = dirname(getLogFilePath());
|
|
702
|
+
try {
|
|
703
|
+
analyticsLog = await open(join(logDir, 'analytics.log'), 'r+');
|
|
704
|
+
} catch {
|
|
705
|
+
analyticsLog = await open(join(logDir, 'analytics.log'), 'w+');
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
let position = (await analyticsLog.stat()).size;
|
|
709
|
+
if (position > MAX_ANALYTICS_SIZE) {
|
|
710
|
+
let contents = Buffer.alloc(position);
|
|
711
|
+
await analyticsLog.read(contents, { position: 0 });
|
|
712
|
+
contents = contents.subarray(contents.indexOf(10, contents.length / 2) + 1); // find a carriage return to break on after the halfway point
|
|
713
|
+
await analyticsLog.write(contents, { position: 0 });
|
|
714
|
+
await analyticsLog.truncate(contents.length);
|
|
715
|
+
position = contents.length;
|
|
716
|
+
}
|
|
717
|
+
await analyticsLog.write(JSON.stringify(report) + '\n', position);
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
export function onAnalyticsAggregate(callback) {
|
|
721
|
+
if (callback) {
|
|
722
|
+
analyticsAggregateListeners.push(callback);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
/**
|
|
726
|
+
* This section contains a possible/experimental approach to bucketing values as they come instead of pushing all into an array and sorting.
|
|
727
|
+
*
|
|
728
|
+
const BUCKET_COUNT = 100;
|
|
729
|
+
function addToBucket(action, value) {
|
|
730
|
+
if (!action.buckets) {
|
|
731
|
+
action.buckets = newBuckets();
|
|
732
|
+
}
|
|
733
|
+
const { counts, values, totalCount } = action.buckets;
|
|
734
|
+
let jump = BUCKET_COUNT >> 1; // amount to jump with each iteration
|
|
735
|
+
let position = jump; // start at halfway point
|
|
736
|
+
while ((jump = jump >> 1) > 0) {
|
|
737
|
+
const bucketValue = values[position];
|
|
738
|
+
if (bucketValue === 0) {
|
|
739
|
+
// unused slot, immediately put our value in
|
|
740
|
+
counts[position] = 1;
|
|
741
|
+
values[position] = value;
|
|
742
|
+
}
|
|
743
|
+
if (value > bucketValue) {
|
|
744
|
+
position += jump;
|
|
745
|
+
} else {
|
|
746
|
+
position -= jump;
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
const count = counts[position] + 1;
|
|
750
|
+
if (position === BUCKET_COUNT) {
|
|
751
|
+
// if we go beyond the last item, increase the bucket (max) value
|
|
752
|
+
position--;
|
|
753
|
+
values[position] = value;
|
|
754
|
+
}
|
|
755
|
+
if (count > threshold) {
|
|
756
|
+
rebalance(action.buckets, false);
|
|
757
|
+
} else {
|
|
758
|
+
counts[position] = count;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
function newBuckets() {
|
|
763
|
+
const ab = new ArrayBuffer(8 * BUCKET_COUNT);
|
|
764
|
+
return {
|
|
765
|
+
values: new Float32Array(ab, 0, BUCKET_COUNT),
|
|
766
|
+
counts: new Uint32Array(ab, BUCKET_COUNT * 4, BUCKET_COUNT),
|
|
767
|
+
totalCount: 0,
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
let balancingBuckets;
|
|
772
|
+
|
|
773
|
+
/**
|
|
774
|
+
* Rebalance the buckets, we can reset the counts at the same time, if this occurred after a delivery
|
|
775
|
+
* @param param
|
|
776
|
+
* @param resetCounts
|
|
777
|
+
*
|
|
778
|
+
function rebalance({ counts, values, totalCount }, resetCounts: boolean) {
|
|
779
|
+
const countPerBucket = totalCount / BUCKET_COUNT;
|
|
780
|
+
let targetPosition = 0;
|
|
781
|
+
let targetCount = 0;
|
|
782
|
+
let lastTargetValue = 0;
|
|
783
|
+
const { values: targetValues, counts: targetCounts } = balancingBuckets || (balancingBuckets = newBuckets());
|
|
784
|
+
for (let i = 0; i < BUCKET_COUNT; i++) {
|
|
785
|
+
// iterate through the existing buckets, filling up the target buckets in a balanced way
|
|
786
|
+
let count = counts[i];
|
|
787
|
+
while ((countPerBucket - targetCount) < count) {
|
|
788
|
+
const value = values[i];
|
|
789
|
+
lastTargetValue = ((countPerBucket - targetCount) / count) * (value - lastTargetValue) + lastTargetValue;
|
|
790
|
+
targetValues[targetPosition] = lastTargetValue;
|
|
791
|
+
targetCounts[targetPosition] = countPerBucket;
|
|
792
|
+
count -= countPerBucket;
|
|
793
|
+
targetPosition++;
|
|
794
|
+
targetCount = 0;
|
|
795
|
+
}
|
|
796
|
+
targetCount += count;
|
|
797
|
+
}
|
|
798
|
+
// now copy the balanced buckets back into the original buckets
|
|
799
|
+
values.set(targetValues);
|
|
800
|
+
if (resetCounts) counts.fill(0);
|
|
801
|
+
else counts.set(targetCounts);
|
|
802
|
+
}
|
|
803
|
+
*/
|