@harperfast/harper 5.2.0 → 5.2.2
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/copyDb.ts +40 -11
- package/bin/harper.ts +20 -51
- package/bin/help.ts +216 -0
- package/components/Application.ts +236 -46
- package/components/ApplicationScope.ts +26 -0
- package/components/EntryHandler.ts +410 -105
- package/components/RuntimeModuleTracker.ts +189 -0
- package/components/Scope.ts +68 -24
- package/components/componentLoader.ts +70 -16
- package/components/deployLifecycle.ts +119 -33
- package/components/deploymentRecorder.ts +102 -11
- package/components/mcp/tools/operations.ts +6 -0
- package/components/operations.js +8 -6
- package/config/configUtils.ts +78 -20
- package/config/harperConfigEnvVars.ts +114 -17
- package/config-root.schema.json +10 -0
- package/dataLayer/harperBridge/ResourceBridge.ts +26 -5
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializePaths.js +4 -4
- package/dataLayer/hdbInfoController.ts +8 -0
- package/dataLayer/schemaDescribe.ts +2 -1
- package/dist/bin/copyDb.js +33 -9
- package/dist/bin/copyDb.js.map +1 -1
- package/dist/bin/harper.d.ts +6 -0
- package/dist/bin/harper.js +18 -50
- package/dist/bin/harper.js.map +1 -1
- package/dist/bin/help.d.ts +8 -0
- package/dist/bin/help.js +192 -0
- package/dist/bin/help.js.map +1 -0
- package/dist/components/Application.d.ts +16 -1
- package/dist/components/Application.js +210 -38
- package/dist/components/Application.js.map +1 -1
- package/dist/components/ApplicationScope.d.ts +7 -0
- package/dist/components/ApplicationScope.js +22 -0
- package/dist/components/ApplicationScope.js.map +1 -1
- package/dist/components/EntryHandler.d.ts +4 -4
- package/dist/components/EntryHandler.js +386 -95
- package/dist/components/EntryHandler.js.map +1 -1
- package/dist/components/RuntimeModuleTracker.d.ts +11 -0
- package/dist/components/RuntimeModuleTracker.js +189 -0
- package/dist/components/RuntimeModuleTracker.js.map +1 -0
- package/dist/components/Scope.d.ts +1 -0
- package/dist/components/Scope.js +69 -22
- package/dist/components/Scope.js.map +1 -1
- package/dist/components/componentLoader.js +69 -10
- package/dist/components/componentLoader.js.map +1 -1
- package/dist/components/deployLifecycle.d.ts +6 -2
- package/dist/components/deployLifecycle.js +109 -31
- package/dist/components/deployLifecycle.js.map +1 -1
- package/dist/components/deploymentRecorder.d.ts +6 -0
- package/dist/components/deploymentRecorder.js +94 -12
- package/dist/components/deploymentRecorder.js.map +1 -1
- package/dist/components/mcp/tools/operations.js +6 -0
- package/dist/components/mcp/tools/operations.js.map +1 -1
- package/dist/components/operations.js +8 -6
- package/dist/components/operations.js.map +1 -1
- package/dist/config/configUtils.d.ts +6 -0
- package/dist/config/configUtils.js +78 -18
- package/dist/config/configUtils.js.map +1 -1
- package/dist/config/harperConfigEnvVars.js +108 -16
- package/dist/config/harperConfigEnvVars.js.map +1 -1
- package/dist/dataLayer/harperBridge/ResourceBridge.js +12 -5
- package/dist/dataLayer/harperBridge/ResourceBridge.js.map +1 -1
- package/dist/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializePaths.js +4 -4
- package/dist/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializePaths.js.map +1 -1
- package/dist/dataLayer/hdbInfoController.js +4 -0
- package/dist/dataLayer/hdbInfoController.js.map +1 -1
- package/dist/dataLayer/schemaDescribe.js +2 -1
- package/dist/dataLayer/schemaDescribe.js.map +1 -1
- package/dist/resources/DatabaseTransaction.d.ts +57 -0
- package/dist/resources/DatabaseTransaction.js +284 -104
- package/dist/resources/DatabaseTransaction.js.map +1 -1
- package/dist/resources/ResourceInterface.d.ts +8 -2
- package/dist/resources/ResourceInterface.js.map +1 -1
- package/dist/resources/Resources.js +22 -4
- package/dist/resources/Resources.js.map +1 -1
- package/dist/resources/Table.d.ts +8 -6
- package/dist/resources/Table.js +158 -31
- package/dist/resources/Table.js.map +1 -1
- package/dist/resources/analytics/write.js +6 -6
- package/dist/resources/analytics/write.js.map +1 -1
- package/dist/resources/auditStore.js +27 -1
- package/dist/resources/auditStore.js.map +1 -1
- package/dist/resources/blob.d.ts +0 -1
- package/dist/resources/blob.js +15 -7
- package/dist/resources/blob.js.map +1 -1
- package/dist/resources/databases.d.ts +22 -5
- package/dist/resources/databases.js +118 -9
- package/dist/resources/databases.js.map +1 -1
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.d.ts +15 -2
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js +128 -39
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js.map +1 -1
- package/dist/resources/jsResource.d.ts +4 -26
- package/dist/resources/jsResource.js +5 -59
- package/dist/resources/jsResource.js.map +1 -1
- package/dist/resources/models/Models.d.ts +11 -1
- package/dist/resources/models/Models.js +10 -1
- package/dist/resources/models/Models.js.map +1 -1
- package/dist/resources/models/backendRegistry.d.ts +9 -0
- package/dist/resources/models/backendRegistry.js +10 -0
- package/dist/resources/models/backendRegistry.js.map +1 -1
- package/dist/resources/models/openaiStream.d.ts +16 -1
- package/dist/resources/models/openaiStream.js +113 -21
- package/dist/resources/models/openaiStream.js.map +1 -1
- package/dist/resources/models/v1/chatCompletions.d.ts +54 -0
- package/dist/resources/models/v1/chatCompletions.js +115 -0
- package/dist/resources/models/v1/chatCompletions.js.map +1 -0
- package/dist/resources/models/v1/embeddings.d.ts +11 -0
- package/dist/resources/models/v1/embeddings.js +71 -0
- package/dist/resources/models/v1/embeddings.js.map +1 -0
- package/dist/resources/models/v1/errors.d.ts +54 -0
- package/dist/resources/models/v1/errors.js +130 -0
- package/dist/resources/models/v1/errors.js.map +1 -0
- package/dist/resources/models/v1/index.d.ts +36 -0
- package/dist/resources/models/v1/index.js +75 -0
- package/dist/resources/models/v1/index.js.map +1 -0
- package/dist/resources/models/v1/models.d.ts +26 -0
- package/dist/resources/models/v1/models.js +44 -0
- package/dist/resources/models/v1/models.js.map +1 -0
- package/dist/resources/models/v1/translation.d.ts +133 -0
- package/dist/resources/models/v1/translation.js +298 -0
- package/dist/resources/models/v1/translation.js.map +1 -0
- package/dist/resources/roles.d.ts +1 -1
- package/dist/resources/roles.js +54 -7
- package/dist/resources/roles.js.map +1 -1
- package/dist/resources/search.d.ts +1 -1
- package/dist/resources/search.js +7 -3
- package/dist/resources/search.js.map +1 -1
- package/dist/security/jsLoader.js +84 -33
- package/dist/security/jsLoader.js.map +1 -1
- package/dist/security/role.js +4 -0
- package/dist/security/role.js.map +1 -1
- package/dist/security/superUserGuard.d.ts +7 -0
- package/dist/security/superUserGuard.js +23 -0
- package/dist/security/superUserGuard.js.map +1 -0
- package/dist/security/tokenAuthentication.d.ts +0 -1
- package/dist/security/tokenAuthentication.js +6 -2
- package/dist/security/tokenAuthentication.js.map +1 -1
- package/dist/security/user.d.ts +6 -1
- package/dist/security/user.js +23 -1
- package/dist/security/user.js.map +1 -1
- package/dist/server/http.d.ts +23 -2
- package/dist/server/http.js +99 -12
- package/dist/server/http.js.map +1 -1
- package/dist/server/operationsServer.d.ts +0 -2
- package/dist/server/operationsServer.js.map +1 -1
- package/dist/server/serverHelpers/multipartParser.js +9 -0
- package/dist/server/serverHelpers/multipartParser.js.map +1 -1
- package/dist/server/serverHelpers/operationAuthorizationState.d.ts +2 -0
- package/dist/server/serverHelpers/operationAuthorizationState.js +13 -0
- package/dist/server/serverHelpers/operationAuthorizationState.js.map +1 -0
- package/dist/server/serverHelpers/registeredOperations.d.ts +3 -2
- package/dist/server/serverHelpers/registeredOperations.js +14 -13
- package/dist/server/serverHelpers/registeredOperations.js.map +1 -1
- package/dist/server/serverHelpers/serverHandlers.js +19 -3
- package/dist/server/serverHelpers/serverHandlers.js.map +1 -1
- package/dist/server/serverHelpers/serverUtilities.d.ts +1 -1
- package/dist/server/serverHelpers/serverUtilities.js +10 -7
- package/dist/server/serverHelpers/serverUtilities.js.map +1 -1
- package/dist/server/static.js +57 -18
- package/dist/server/static.js.map +1 -1
- package/dist/server/storageReclamation.d.ts +17 -0
- package/dist/server/storageReclamation.js +90 -6
- package/dist/server/storageReclamation.js.map +1 -1
- package/dist/server/threads/manageThreads.js +8 -0
- package/dist/server/threads/manageThreads.js.map +1 -1
- package/dist/server/threads/socketRouter.js +20 -0
- package/dist/server/threads/socketRouter.js.map +1 -1
- package/dist/server/threads/threadServer.js +12 -0
- package/dist/server/threads/threadServer.js.map +1 -1
- package/dist/sqlEngine/diff/differential.js +7 -3
- package/dist/sqlEngine/diff/differential.js.map +1 -1
- package/dist/sqlEngine/parser/normalizer.js +37 -9
- package/dist/sqlEngine/parser/normalizer.js.map +1 -1
- package/dist/sqlTranslator/index.js +6 -1
- package/dist/sqlTranslator/index.js.map +1 -1
- package/dist/upgrade/upgradePrompt.d.ts +2 -2
- package/dist/upgrade/upgradePrompt.js +22 -3
- package/dist/upgrade/upgradePrompt.js.map +1 -1
- package/dist/utility/environment/environmentManager.d.ts +11 -0
- package/dist/utility/environment/environmentManager.js +154 -0
- package/dist/utility/environment/environmentManager.js.map +1 -1
- package/dist/utility/errors/commonErrors.d.ts +1 -0
- package/dist/utility/errors/commonErrors.js +1 -0
- package/dist/utility/errors/commonErrors.js.map +1 -1
- package/dist/utility/hdbTerms.d.ts +2 -0
- package/dist/utility/hdbTerms.js +2 -0
- package/dist/utility/hdbTerms.js.map +1 -1
- package/dist/utility/install/installer.js +32 -0
- package/dist/utility/install/installer.js.map +1 -1
- package/dist/utility/lmdb/environmentUtility.js +2 -1
- package/dist/utility/lmdb/environmentUtility.js.map +1 -1
- package/dist/utility/logging/harper_logger.d.ts +7 -0
- package/dist/utility/logging/harper_logger.js +57 -24
- package/dist/utility/logging/harper_logger.js.map +1 -1
- package/npm-shrinkwrap.json +208 -198
- package/package.json +10 -8
- package/resources/DESIGN.md +1 -0
- package/resources/DatabaseTransaction.ts +313 -102
- package/resources/ResourceInterface.ts +8 -2
- package/resources/Resources.ts +22 -4
- package/resources/Table.ts +398 -259
- package/resources/analytics/write.ts +22 -20
- package/resources/auditStore.ts +32 -1
- package/resources/blob.ts +15 -8
- package/resources/databases.ts +123 -12
- package/resources/indexes/HierarchicalNavigableSmallWorld.ts +119 -45
- package/resources/jsResource.ts +5 -62
- package/resources/models/Models.ts +14 -1
- package/resources/models/backendRegistry.ts +10 -0
- package/resources/models/openaiStream.ts +131 -19
- package/resources/models/v1/chatCompletions.ts +128 -0
- package/resources/models/v1/embeddings.ts +70 -0
- package/resources/models/v1/errors.ts +141 -0
- package/resources/models/v1/index.ts +72 -0
- package/resources/models/v1/models.ts +53 -0
- package/resources/models/v1/translation.ts +362 -0
- package/resources/roles.ts +67 -7
- package/resources/search.ts +8 -3
- package/security/jsLoader.ts +84 -30
- package/security/role.ts +7 -0
- package/security/superUserGuard.ts +20 -0
- package/security/tokenAuthentication.ts +6 -3
- package/security/user.ts +26 -1
- package/server/DESIGN.md +45 -34
- package/server/http.ts +100 -13
- package/server/operationsServer.ts +0 -2
- package/server/serverHelpers/multipartParser.ts +9 -0
- package/server/serverHelpers/operationAuthorizationState.ts +11 -0
- package/server/serverHelpers/registeredOperations.ts +19 -15
- package/server/serverHelpers/serverHandlers.js +20 -3
- package/server/serverHelpers/serverUtilities.ts +10 -7
- package/server/static.ts +75 -20
- package/server/storageReclamation.ts +104 -8
- package/server/threads/manageThreads.js +8 -0
- package/server/threads/socketRouter.ts +20 -0
- package/server/threads/threadServer.js +11 -0
- package/sqlTranslator/index.ts +6 -1
- package/static/defaultConfig.yaml +2 -0
- package/studio/web/assets/{Chat-DoVWScmq.js → Chat-BMUjPklt.js} +5 -5
- package/studio/web/assets/{Chat-DoVWScmq.js.map → Chat-BMUjPklt.js.map} +1 -1
- package/studio/web/assets/{FloatingChat-UZ2NsUOZ.js → FloatingChat-Cbghuxe5.js} +5 -5
- package/studio/web/assets/{FloatingChat-UZ2NsUOZ.js.map → FloatingChat-Cbghuxe5.js.map} +1 -1
- package/studio/web/assets/{apiToken-BUI_04o7.js → apiToken-CkgTQAqc.js} +2 -2
- package/studio/web/assets/{apiToken-BUI_04o7.js.map → apiToken-CkgTQAqc.js.map} +1 -1
- package/studio/web/assets/{applications-D03NA7wW.js → applications-WvF4NOTN.js} +13 -13
- package/studio/web/assets/applications-WvF4NOTN.js.map +1 -0
- package/studio/web/assets/chevron-right-anDJCGlp.js +2 -0
- package/studio/web/assets/chevron-right-anDJCGlp.js.map +1 -0
- package/studio/web/assets/index-CDeqVx71.css +1 -0
- package/studio/web/assets/index-Sevt3MVx.js +819 -0
- package/studio/web/assets/index-Sevt3MVx.js.map +1 -0
- package/studio/web/assets/index.lazy-Dg5YYPGg.js +14 -0
- package/studio/web/assets/{index.lazy-Dx3MpyDC.js.map → index.lazy-Dg5YYPGg.js.map} +1 -1
- package/studio/web/assets/{jsonMode-Cjj7dtlr.js → jsonMode-CBSEleE7.js} +2 -2
- package/studio/web/assets/{jsonMode-Cjj7dtlr.js.map → jsonMode-CBSEleE7.js.map} +1 -1
- package/studio/web/assets/languageServices-gxedeeTo.js +2 -0
- package/studio/web/assets/languageServices-gxedeeTo.js.map +1 -0
- package/studio/web/assets/{notifications-0edoFTsb.js → notifications-Ap84YyQp.js} +2 -2
- package/studio/web/assets/{notifications-0edoFTsb.js.map → notifications-Ap84YyQp.js.map} +1 -1
- package/studio/web/assets/notifications-vehqyOLM.js +2 -0
- package/studio/web/assets/{notifications-CwKhipK7.js.map → notifications-vehqyOLM.js.map} +1 -1
- package/studio/web/assets/{pollUnlessForbidden-HHdQZW1N.js → pollUnlessForbidden-BhzefVRn.js} +2 -2
- package/studio/web/assets/pollUnlessForbidden-BhzefVRn.js.map +1 -0
- package/studio/web/assets/{profile-DUfEPQtx.js → profile-DzDpRLHY.js} +2 -2
- package/studio/web/assets/{profile-DUfEPQtx.js.map → profile-DzDpRLHY.js.map} +1 -1
- package/studio/web/assets/queryClient-CgtkoiCY.js +2 -0
- package/studio/web/assets/queryClient-CgtkoiCY.js.map +1 -0
- package/studio/web/assets/regions-DpJ8s7iN.js +2 -0
- package/studio/web/assets/regions-DpJ8s7iN.js.map +1 -0
- package/studio/web/assets/register-BDy01-q3.js +3 -0
- package/studio/web/assets/register-BDy01-q3.js.map +1 -0
- package/studio/web/assets/register-CQHRwNP4.js +3 -0
- package/studio/web/assets/register-CQHRwNP4.js.map +1 -0
- package/studio/web/assets/{setComponentFile-DMPo4UjC.js → setComponentFile-D0aPcI3W.js} +2 -2
- package/studio/web/assets/{setComponentFile-DMPo4UjC.js.map → setComponentFile-D0aPcI3W.js.map} +1 -1
- package/studio/web/assets/setup-I15FAF9H.js +3 -0
- package/studio/web/assets/{setup-B56Oz1_u.js.map → setup-I15FAF9H.js.map} +1 -1
- package/studio/web/assets/status-BF1eJshJ.js +62 -0
- package/studio/web/assets/status-BF1eJshJ.js.map +1 -0
- package/studio/web/assets/{swagger-ui-react-lQrBxfwM.js → swagger-ui-react-DwSPXXhl.js} +2 -2
- package/studio/web/assets/{swagger-ui-react-lQrBxfwM.js.map → swagger-ui-react-DwSPXXhl.js.map} +1 -1
- package/studio/web/assets/{textarea-DhLMZ3PA.js → table-DpOjNQHt.js} +2 -10
- package/studio/web/assets/table-DpOjNQHt.js.map +1 -0
- package/studio/web/assets/{tsMode-CrHCRjTK.js → tsMode-Bu51A-VG.js} +2 -2
- package/studio/web/assets/{tsMode-CrHCRjTK.js.map → tsMode-Bu51A-VG.js.map} +1 -1
- package/studio/web/assets/{useEntityRestURL-DoaBMEvU.js → useEntityRestURL-DrV1zMrN.js} +2 -2
- package/studio/web/assets/{useEntityRestURL-DoaBMEvU.js.map → useEntityRestURL-DrV1zMrN.js.map} +1 -1
- package/studio/web/index.html +6 -7
- package/upgrade/upgradePrompt.ts +22 -3
- package/utility/environment/environmentManager.ts +152 -0
- package/utility/errors/commonErrors.ts +2 -0
- package/utility/hdbTerms.ts +2 -0
- package/utility/install/installer.ts +37 -0
- package/utility/lmdb/environmentUtility.ts +2 -1
- package/utility/logging/harper_logger.ts +57 -26
- package/studio/web/assets/applications-D03NA7wW.js.map +0 -1
- package/studio/web/assets/index-Bh_CNAHr.js +0 -809
- package/studio/web/assets/index-Bh_CNAHr.js.map +0 -1
- package/studio/web/assets/index-C8Mv9kHV.css +0 -1
- package/studio/web/assets/index.lazy-Dx3MpyDC.js +0 -14
- package/studio/web/assets/notifications-CwKhipK7.js +0 -2
- package/studio/web/assets/pollUnlessForbidden-HHdQZW1N.js.map +0 -1
- package/studio/web/assets/queryClient-CbA8wM7J.js +0 -2
- package/studio/web/assets/queryClient-CbA8wM7J.js.map +0 -1
- package/studio/web/assets/setup-B56Oz1_u.js +0 -3
- package/studio/web/assets/status-BAod7p3o.js +0 -62
- package/studio/web/assets/status-BAod7p3o.js.map +0 -1
- package/studio/web/assets/textarea-DhLMZ3PA.js.map +0 -1
package/dist/resources/Table.js
CHANGED
|
@@ -341,10 +341,20 @@ function makeTable(options) {
|
|
|
341
341
|
if (!properties)
|
|
342
342
|
properties = (0, jsonSchemaTypes_ts_1.projectAttributesToProperties)(attributes);
|
|
343
343
|
const updateRecord = (0, RecordEncoder_ts_1.recordUpdater)(primaryStore, tableId, auditStore);
|
|
344
|
+
let warnedNullSourcePut = false; // latched: one warn per table per worker (see _writeUpdate)
|
|
344
345
|
let sourceLoad; // if a source has a load function (replicator), record it here
|
|
345
346
|
let hasSourceGet;
|
|
346
347
|
let primaryKeyAttribute;
|
|
347
348
|
let lastEvictionCompletion = Promise.resolve();
|
|
349
|
+
// getFromSource() intentionally resolves its caller before the resolved record's cache
|
|
350
|
+
// write has committed (see there) so GET latency doesn't pay for the write. dropTable()
|
|
351
|
+
// must not drop this table's column families while one of those writes is still landing —
|
|
352
|
+
// racing a drop against an in-flight write is what corrupts the column family handle and
|
|
353
|
+
// produces "Invalid column family specified in write batch" (harper#1381). Track the
|
|
354
|
+
// in-flight commit promises here so dropTable() can drain them first, and stop admitting
|
|
355
|
+
// new ones (droppingTable) once a drop has actually started.
|
|
356
|
+
const pendingSourceCommits = new Set();
|
|
357
|
+
let droppingTable = false;
|
|
348
358
|
let createdTimeProperty, updatedTimeProperty, expiresAtProperty;
|
|
349
359
|
for (const attribute of attributes) {
|
|
350
360
|
if (attribute.assignCreatedTime || attribute.name === '__createdtime__')
|
|
@@ -1317,12 +1327,52 @@ function makeTable(options) {
|
|
|
1317
1327
|
await tombstoneWrite;
|
|
1318
1328
|
}
|
|
1319
1329
|
}
|
|
1330
|
+
// A get() against a sourcedFrom table resolves to its caller before the resolved
|
|
1331
|
+
// record's cache write has committed (see getFromSource) - the write lands "in the
|
|
1332
|
+
// background" for latency reasons. Flip this BEFORE removing the table from the
|
|
1333
|
+
// schema below: getFromSource() checks it and skips caching (treats the load as
|
|
1334
|
+
// noCacheStore) for any call it admits from here on, including one that slipped in
|
|
1335
|
+
// through a stale reference to this Table between the two steps.
|
|
1336
|
+
droppingTable = true;
|
|
1320
1337
|
// Remove the table from the in-memory schema immediately so concurrent
|
|
1321
1338
|
// requests get "table does not exist" instead of racing the column
|
|
1322
1339
|
// family drops below. If a drop fails past this point the table stays
|
|
1323
1340
|
// invisible, and the tombstone guarantees the drop completes on the
|
|
1324
1341
|
// next startup (or on a same-name create).
|
|
1325
1342
|
delete databases_ts_1.databases[databaseName][tableName];
|
|
1343
|
+
// The above stops new source-fill writes from starting, but a write from a get()
|
|
1344
|
+
// that already returned to its caller may still be in flight. Dropping the column
|
|
1345
|
+
// families out from under that write is a genuine invariant violation, not just a
|
|
1346
|
+
// benign race: RocksDB rejects the still-open write batch with "Invalid column
|
|
1347
|
+
// family specified in write batch" (or "Could not access column family N"), which
|
|
1348
|
+
// can also abort this drop before it removes the tombstoned catalog rows - leaving
|
|
1349
|
+
// the table stuck "dropping" for completeInterruptedDrop to retry (and fail
|
|
1350
|
+
// identically) on every subsequent load (harper#1381). Drain any in-flight commits
|
|
1351
|
+
// before the blob sweep below (so it observes every row a drain-caught write just
|
|
1352
|
+
// committed) and before touching a single column family.
|
|
1353
|
+
//
|
|
1354
|
+
// Bounded, and fails CLOSED: the tracked promise covers the whole source round-trip
|
|
1355
|
+
// plus the local commit (see getFromSource), so a hung/slow source or a slow commit
|
|
1356
|
+
// (e.g. a large blob write) could otherwise wedge this drop forever. Rather than
|
|
1357
|
+
// give up and drop anyway - which would reopen exactly the race this drain exists to
|
|
1358
|
+
// close, just less often - a timeout FAILS the drop. The tombstone written above is
|
|
1359
|
+
// already durable, so completeInterruptedDrop picks the drop back up on the next
|
|
1360
|
+
// load, once the stuck write has had time to finish.
|
|
1361
|
+
if (pendingSourceCommits.size) {
|
|
1362
|
+
const pending = [...pendingSourceCommits];
|
|
1363
|
+
let timer;
|
|
1364
|
+
const timedOut = Symbol('timedOut');
|
|
1365
|
+
const result = await Promise.race([
|
|
1366
|
+
Promise.allSettled(pending),
|
|
1367
|
+
new Promise((resolve) => {
|
|
1368
|
+
timer = setTimeout(() => resolve(timedOut), LOCK_TIMEOUT);
|
|
1369
|
+
}),
|
|
1370
|
+
]);
|
|
1371
|
+
clearTimeout(timer);
|
|
1372
|
+
if (result === timedOut) {
|
|
1373
|
+
throw new Error(`dropTable() timed out after ${LOCK_TIMEOUT}ms waiting for ${pending.length} in-flight source-populated cache write(s) on ${tableName} to settle; refusing to drop the column families out from under a write that may still be staged. The drop tombstone is durable, so this will be retried on the next load.`);
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1326
1376
|
for (const entry of primaryStore.getRange({ versions: true, snapshot: false, lazy: true })) {
|
|
1327
1377
|
if (entry.metadataFlags & auditStore_ts_1.HAS_BLOBS && entry.value) {
|
|
1328
1378
|
(0, blob_ts_1.deleteBlobsInObject)(entry.value);
|
|
@@ -2108,6 +2158,19 @@ function makeTable(options) {
|
|
|
2108
2158
|
const context = this.getContext();
|
|
2109
2159
|
const transaction = txnForContext(context);
|
|
2110
2160
|
checkValidId(id);
|
|
2161
|
+
if (fullUpdate && recordUpdate == null && options?.isNotification) {
|
|
2162
|
+
// A source/replication-applied put must carry the record; these applies skip record
|
|
2163
|
+
// validation, so this is the one path a nullish full update reaches (isNotification scopes
|
|
2164
|
+
// this to the apply dispatcher, not instance flows that fill from #changes). Applying it
|
|
2165
|
+
// stores nothing and mints an audit-only entry misrepresenting the write (#2153) — skip it;
|
|
2166
|
+
// a redelivery re-skips and a later real write supersedes.
|
|
2167
|
+
logger_ts_1.logger.trace?.('Skipped valueless source put', tableName, id, options?.nodeId);
|
|
2168
|
+
if (!warnedNullSourcePut) {
|
|
2169
|
+
warnedNullSourcePut = true;
|
|
2170
|
+
logger_ts_1.logger.warn?.(`Skipping a source-applied put with no record content for ${tableName} id ${id} from node ${options?.nodeId}`, new Error('valueless source put'));
|
|
2171
|
+
}
|
|
2172
|
+
return;
|
|
2173
|
+
}
|
|
2111
2174
|
const entry = this.#entry ?? primaryStore.getEntry(id, { transaction: transaction.getReadTxn() });
|
|
2112
2175
|
const writeToSource = () => {
|
|
2113
2176
|
if (!this.constructor.source || context?.source)
|
|
@@ -3137,6 +3200,13 @@ function makeTable(options) {
|
|
|
3137
3200
|
if (conditions.length > 0 || operator)
|
|
3138
3201
|
conditions = prepareConditions(conditions, operator);
|
|
3139
3202
|
const sort = typeof target.sort === 'object' && target.sort;
|
|
3203
|
+
for (let order = sort; order; order = order.next) {
|
|
3204
|
+
if (typeof order.attribute !== 'string')
|
|
3205
|
+
continue;
|
|
3206
|
+
const customIndex = indices[order.attribute]?.customIndex;
|
|
3207
|
+
if (customIndex?.exactDistance)
|
|
3208
|
+
customIndex.exactDistance(order, null);
|
|
3209
|
+
}
|
|
3140
3210
|
let postOrdering;
|
|
3141
3211
|
if (sort) {
|
|
3142
3212
|
// TODO: Support index-assisted sorts of unions, which will require potentially recursively adding/modifying an order aligned condition and be able to recursively undo it if necessary
|
|
@@ -3174,9 +3244,12 @@ function makeTable(options) {
|
|
|
3174
3244
|
if (sort.next) {
|
|
3175
3245
|
postOrdering = {
|
|
3176
3246
|
dbOrderedAttribute: sort.attribute,
|
|
3247
|
+
dbOrderedSort: sort,
|
|
3177
3248
|
attribute: sort.next.attribute,
|
|
3178
3249
|
descending: sort.next.descending,
|
|
3179
3250
|
next: sort.next.next,
|
|
3251
|
+
target: sort.next.target,
|
|
3252
|
+
distance: sort.next.distance,
|
|
3180
3253
|
};
|
|
3181
3254
|
}
|
|
3182
3255
|
}
|
|
@@ -3241,7 +3314,7 @@ function makeTable(options) {
|
|
|
3241
3314
|
// since those never run the ensureLoaded-gated freshness check this transform
|
|
3242
3315
|
// otherwise applies unconditionally to every read.
|
|
3243
3316
|
const includeExpired = target.includeExpired === true;
|
|
3244
|
-
const transformToRecord = TableResource.transformEntryForSelect(select, context, readTxn, filtered, ensure_loaded, true, boundRowFilter, includeExpired);
|
|
3317
|
+
const transformToRecord = TableResource.transformEntryForSelect(select, context, readTxn, filtered, ensure_loaded, true, boundRowFilter, includeExpired, postOrdering);
|
|
3245
3318
|
let results = TableResource.transformToOrderedSelect(entries, select, postOrdering, context, readTxn, transformToRecord);
|
|
3246
3319
|
// apply any offset/limit after all the sorting and filtering
|
|
3247
3320
|
if (target.offset || target.limit !== undefined)
|
|
@@ -3283,10 +3356,9 @@ function makeTable(options) {
|
|
|
3283
3356
|
function createComparator(order) {
|
|
3284
3357
|
const nextComparator = order.next && createComparator(order.next);
|
|
3285
3358
|
const descending = order.descending;
|
|
3286
|
-
context.sort = order; // make sure this is set to the current sort order
|
|
3287
3359
|
return (entryA, entryB) => {
|
|
3288
|
-
const a = getAttributeValue(entryA, order.attribute, context);
|
|
3289
|
-
const b = getAttributeValue(entryB, order.attribute, context);
|
|
3360
|
+
const a = getAttributeValue(entryA, order.attribute, context, order);
|
|
3361
|
+
const b = getAttributeValue(entryB, order.attribute, context, order);
|
|
3290
3362
|
const diff = descending
|
|
3291
3363
|
? (0, ordered_binary_1.compareKeys)(convertToComparableKeys(b), convertToComparableKeys(a))
|
|
3292
3364
|
: (0, ordered_binary_1.compareKeys)(convertToComparableKeys(a), convertToComparableKeys(b));
|
|
@@ -3336,7 +3408,7 @@ function makeTable(options) {
|
|
|
3336
3408
|
// if the index has already provided the first order of sorting, we only need to sort
|
|
3337
3409
|
// within each grouping
|
|
3338
3410
|
if (dbOrderedAttribute) {
|
|
3339
|
-
const groupingValue = getAttributeValue(entry, dbOrderedAttribute, context);
|
|
3411
|
+
const groupingValue = getAttributeValue(entry, dbOrderedAttribute, context, sort.dbOrderedSort);
|
|
3340
3412
|
if (firstEntry) {
|
|
3341
3413
|
firstEntry = false;
|
|
3342
3414
|
lastGroupingValue = groupingValue;
|
|
@@ -3446,9 +3518,10 @@ function makeTable(options) {
|
|
|
3446
3518
|
* authorization verdict can't be made on bytes that differ from what the caller receives.
|
|
3447
3519
|
* @param includeExpired when true, a row past its TTL but not yet swept is treated as a live
|
|
3448
3520
|
* match rather than gone (used by the SQL engine's UPDATE/DELETE row-finder).
|
|
3521
|
+
* @param sort post-ordering owned by this selection
|
|
3449
3522
|
* @returns
|
|
3450
3523
|
*/
|
|
3451
|
-
static transformEntryForSelect(select, context, readTxn, filtered, ensure_loaded, canSkip, rowFilter, includeExpired) {
|
|
3524
|
+
static transformEntryForSelect(select, context, readTxn, filtered, ensure_loaded, canSkip, rowFilter, includeExpired, sort) {
|
|
3452
3525
|
let checkLoaded;
|
|
3453
3526
|
if (ensure_loaded &&
|
|
3454
3527
|
hasSourceGet &&
|
|
@@ -3517,7 +3590,7 @@ function makeTable(options) {
|
|
|
3517
3590
|
swrResource.setRecord(record);
|
|
3518
3591
|
const loadingFromSource = ensureLoadedFromSource(source, entry.key ?? entry, entry, context, swrResource);
|
|
3519
3592
|
if (loadingFromSource?.then) {
|
|
3520
|
-
return loadingFromSource.then(transform);
|
|
3593
|
+
return loadingFromSource.then(transform.bind(this));
|
|
3521
3594
|
}
|
|
3522
3595
|
}
|
|
3523
3596
|
}
|
|
@@ -3554,7 +3627,7 @@ function makeTable(options) {
|
|
|
3554
3627
|
}
|
|
3555
3628
|
}
|
|
3556
3629
|
else {
|
|
3557
|
-
value = resolver(record, context, entry, true);
|
|
3630
|
+
value = resolver(record, context, entry, true, sort);
|
|
3558
3631
|
}
|
|
3559
3632
|
const handleResolvedValue = (value) => {
|
|
3560
3633
|
if (resolver.directReturn)
|
|
@@ -3572,7 +3645,7 @@ function makeTable(options) {
|
|
|
3572
3645
|
// otherwise pass along the nested selected
|
|
3573
3646
|
attribute_name === attribute
|
|
3574
3647
|
? null
|
|
3575
|
-
: attribute.select || (Array.isArray(attribute) ? attribute : null), context, targetReadTxn, filterMap, ensure_loaded));
|
|
3648
|
+
: attribute.select || (Array.isArray(attribute) ? attribute : null), context, targetReadTxn, filterMap, ensure_loaded, undefined, undefined, undefined, typeof attribute.sort === 'object' && attribute.sort));
|
|
3576
3649
|
if (Array.isArray(value)) {
|
|
3577
3650
|
const results = [];
|
|
3578
3651
|
const iterator = targetTable
|
|
@@ -4510,13 +4583,13 @@ function makeTable(options) {
|
|
|
4510
4583
|
(stats.totalSize ??
|
|
4511
4584
|
(stats.treeBranchPageCount + stats.treeLeafPageCount + stats.overflowPages) * stats.pageSize));
|
|
4512
4585
|
}
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4586
|
+
/**
|
|
4587
|
+
* Get available/free/size storage stats for the table's underlying volume. Async because
|
|
4588
|
+
* this may need to read quota-status.json (#1976); getSize/getAuditSize stay sync because
|
|
4589
|
+
* they only read in-memory store stats.
|
|
4590
|
+
*/
|
|
4591
|
+
static async getStorageStats() {
|
|
4592
|
+
return (0, storageReclamation_ts_1.getStorageSpaceStats)(primaryStore.path);
|
|
4520
4593
|
}
|
|
4521
4594
|
static async getRecordCount(options) {
|
|
4522
4595
|
// iterate through the metadata entries to exclude their count and exclude the deletion counts
|
|
@@ -4630,8 +4703,26 @@ function makeTable(options) {
|
|
|
4630
4703
|
$updatedTime: (object, context, entry) => entry.version,
|
|
4631
4704
|
$expiresAt: (object, context, entry) => entry.expiresAt,
|
|
4632
4705
|
$record: (object, context, entry) => (entry ? { value: object } : object),
|
|
4633
|
-
$distance: (object, context, entry) => {
|
|
4634
|
-
|
|
4706
|
+
$distance: (object, context, entry, returnEntry, sort) => {
|
|
4707
|
+
if (!entry)
|
|
4708
|
+
return;
|
|
4709
|
+
if (entry.distance !== undefined)
|
|
4710
|
+
return entry.distance;
|
|
4711
|
+
let distanceSort = sort;
|
|
4712
|
+
while (distanceSort &&
|
|
4713
|
+
(typeof distanceSort.attribute !== 'string' ||
|
|
4714
|
+
!Array.isArray(distanceSort.target) ||
|
|
4715
|
+
!indices[distanceSort.attribute]?.customIndex?.propertyResolver))
|
|
4716
|
+
distanceSort = distanceSort.next;
|
|
4717
|
+
if (!distanceSort)
|
|
4718
|
+
return;
|
|
4719
|
+
const customIndex = indices[distanceSort.attribute].customIndex;
|
|
4720
|
+
const vector = object[distanceSort.attribute];
|
|
4721
|
+
const distanceCache = context?.vectorDistanceCaches?.get(distanceSort);
|
|
4722
|
+
const cachedDistance = distanceCache?.get(entry) ?? distanceCache?.get(vector);
|
|
4723
|
+
if (cachedDistance !== undefined)
|
|
4724
|
+
return cachedDistance;
|
|
4725
|
+
return customIndex.propertyResolver(vector, context, entry, distanceSort);
|
|
4635
4726
|
},
|
|
4636
4727
|
};
|
|
4637
4728
|
for (const attribute of this.attributes) {
|
|
@@ -4771,9 +4862,13 @@ function makeTable(options) {
|
|
|
4771
4862
|
}
|
|
4772
4863
|
else if (indices[attribute.name]?.customIndex?.propertyResolver) {
|
|
4773
4864
|
const customIndex = indices[attribute.name].customIndex;
|
|
4774
|
-
propertyResolvers[attribute.name] = (object, context, entry) => {
|
|
4865
|
+
propertyResolvers[attribute.name] = (object, context, entry, returnEntry, sort, comparing) => {
|
|
4775
4866
|
const value = object[attribute.name];
|
|
4776
|
-
|
|
4867
|
+
const sortAttribute = sort?.attribute;
|
|
4868
|
+
const resolvesSort = comparing === true &&
|
|
4869
|
+
(sortAttribute === attribute.name ||
|
|
4870
|
+
(Array.isArray(sortAttribute) && sortAttribute[sortAttribute.length - 1] === attribute.name));
|
|
4871
|
+
return customIndex.propertyResolver(value, context, entry, resolvesSort ? sort : undefined);
|
|
4777
4872
|
};
|
|
4778
4873
|
propertyResolvers[attribute.name].directReturn = true;
|
|
4779
4874
|
}
|
|
@@ -5337,14 +5432,16 @@ function makeTable(options) {
|
|
|
5337
5432
|
// Inherit never-drop-on-conflict so a source-applied multi-store transaction doesn't
|
|
5338
5433
|
// drop the canonical write when a secondary store hits a transient conflict.
|
|
5339
5434
|
transaction.next.sourceApply = transaction.sourceApply;
|
|
5435
|
+
transaction.next.timeoutBudget = transaction.timeoutBudget;
|
|
5340
5436
|
// Inherit the replay marker so a multi-table replay transaction skips validation on
|
|
5341
5437
|
// every store, not just the first (harper#1316).
|
|
5342
5438
|
transaction.next.isReplay = transaction.isReplay;
|
|
5343
5439
|
// Inherit which resource/method started this logical operation, so a chained (second
|
|
5344
5440
|
// table) transaction's long-transaction-abort log (DatabaseTransaction.ts) can still
|
|
5345
|
-
// identify the request that caused it instead of leaving that field blank.
|
|
5346
|
-
// checkOverloaded() stuck-commit log reads this too
|
|
5347
|
-
//
|
|
5441
|
+
// identify the request that caused it instead of leaving that field blank. The
|
|
5442
|
+
// checkOverloaded() stuck-commit log reads this too — every chained link's own native
|
|
5443
|
+
// commit is tracked with its own identity (DatabaseTransaction.ts's trackOutstandingCommit),
|
|
5444
|
+
// so a wedged second-store commit is named just as precisely as a wedged first one.
|
|
5348
5445
|
transaction.next.startedFrom = transaction.startedFrom;
|
|
5349
5446
|
if (transaction.open === DatabaseTransaction_ts_1.TRANSACTION_STATE.CLOSED) {
|
|
5350
5447
|
// if the current transaction is already closed, we need to retain that state on new databases we work with
|
|
@@ -5367,7 +5464,7 @@ function makeTable(options) {
|
|
|
5367
5464
|
return transaction;
|
|
5368
5465
|
}
|
|
5369
5466
|
}
|
|
5370
|
-
function getAttributeValue(entry, attribute_name, context) {
|
|
5467
|
+
function getAttributeValue(entry, attribute_name, context, sort) {
|
|
5371
5468
|
if (!entry) {
|
|
5372
5469
|
return;
|
|
5373
5470
|
}
|
|
@@ -5379,14 +5476,17 @@ function makeTable(options) {
|
|
|
5379
5476
|
for (let i = 0, l = attribute_name.length; i < l; i++) {
|
|
5380
5477
|
const attribute = attribute_name[i];
|
|
5381
5478
|
const resolver = resolvers?.[attribute];
|
|
5382
|
-
value =
|
|
5479
|
+
value =
|
|
5480
|
+
resolver && value
|
|
5481
|
+
? resolver(value, context, entry, false, i === l - 1 ? sort : undefined, true)
|
|
5482
|
+
: value?.[attribute];
|
|
5383
5483
|
entry = null; // can't use this in the nested object
|
|
5384
5484
|
resolvers = resolver?.definition?.tableClass?.propertyResolvers;
|
|
5385
5485
|
}
|
|
5386
5486
|
return value;
|
|
5387
5487
|
}
|
|
5388
5488
|
const resolver = propertyResolvers[attribute_name];
|
|
5389
|
-
return resolver ? resolver(record, context, entry) : record[attribute_name];
|
|
5489
|
+
return resolver ? resolver(record, context, entry, false, sort, true) : record[attribute_name];
|
|
5390
5490
|
}
|
|
5391
5491
|
function transformToEntries(ids, select, context, readTxn, filters) {
|
|
5392
5492
|
// TODO: Test and ensure that we break out of these loops when a connection is lost
|
|
@@ -5527,7 +5627,10 @@ function makeTable(options) {
|
|
|
5527
5627
|
replacingRecord: existingRecord,
|
|
5528
5628
|
replacingEntry: existingEntry,
|
|
5529
5629
|
replacingVersion: existingVersion,
|
|
5530
|
-
|
|
5630
|
+
// Once dropTable() has started, no new source-fill write may begin (dropTable()
|
|
5631
|
+
// only drains writes already in flight - see there); still resolve the caller's
|
|
5632
|
+
// read with fresh source data, just don't cache it into a table that's going away.
|
|
5633
|
+
noCacheStore: droppingTable,
|
|
5531
5634
|
source: null,
|
|
5532
5635
|
transaction: undefined,
|
|
5533
5636
|
expiresAt: undefined,
|
|
@@ -5538,7 +5641,18 @@ function makeTable(options) {
|
|
|
5538
5641
|
// we don't want to wait for the transaction because we want to return as fast as possible
|
|
5539
5642
|
// and let the transaction commit in the background
|
|
5540
5643
|
let resolved;
|
|
5541
|
-
|
|
5644
|
+
// Tracked in pendingSourceCommits (below) for the full lifetime of this transaction -
|
|
5645
|
+
// including the source round-trip, not just from the point it's actually staged -
|
|
5646
|
+
// so dropTable() can wait for it before dropping the table's column families (see the
|
|
5647
|
+
// comment there). Registering only once a write reaches staging would track less (no
|
|
5648
|
+
// Set churn for a plain cache miss, and a slow/hung source couldn't delay a drop) and
|
|
5649
|
+
// is safe on its own given the live droppingTable re-checks in this function - but it
|
|
5650
|
+
// would make dropTable()'s correctness depend on every future early-return path in
|
|
5651
|
+
// this function remembering to check droppingTable, rather than on dropTable() simply
|
|
5652
|
+
// waiting for whatever this function is doing. Tracking the whole lifetime is the
|
|
5653
|
+
// belt to that suspenders, at the cost of a bounded wait on a merely slow source
|
|
5654
|
+
// before the drain's fail-closed timeout below.
|
|
5655
|
+
const commitPromise = (0, transaction_ts_1.transaction)(sourceContext, async (_txn) => {
|
|
5542
5656
|
const start = performance.now();
|
|
5543
5657
|
let updatedRecord;
|
|
5544
5658
|
let hasChanges, invalidated;
|
|
@@ -5663,8 +5777,11 @@ function makeTable(options) {
|
|
|
5663
5777
|
sourceContext.transaction.abort();
|
|
5664
5778
|
return;
|
|
5665
5779
|
}
|
|
5666
|
-
if (context?.noCacheStore || sourceContext.noCacheStore) {
|
|
5667
|
-
// abort before we write any change
|
|
5780
|
+
if (context?.noCacheStore || sourceContext.noCacheStore || droppingTable) {
|
|
5781
|
+
// abort before we write any change. droppingTable is re-checked live (not just
|
|
5782
|
+
// the noCacheStore snapshot taken at call start) because a call admitted before
|
|
5783
|
+
// dropTable() began can still be sitting here after it started - the await above
|
|
5784
|
+
// waited on the source, which may take arbitrarily long.
|
|
5668
5785
|
sourceContext.transaction.abort();
|
|
5669
5786
|
return;
|
|
5670
5787
|
}
|
|
@@ -5773,11 +5890,21 @@ function makeTable(options) {
|
|
|
5773
5890
|
const embedBefore = (0, embedHook_ts_1.buildEmbedBefore)(updatedRecord, sourceContext, undefined, TableResource.embedAttributes, TableResource.userEmbedders);
|
|
5774
5891
|
if (embedBefore)
|
|
5775
5892
|
await embedBefore();
|
|
5893
|
+
if (droppingTable) {
|
|
5894
|
+
// Re-check right before staging the write: dropTable() may have started
|
|
5895
|
+
// while we were awaiting the embed step above (harper#1381).
|
|
5896
|
+
sourceContext.transaction.abort();
|
|
5897
|
+
return;
|
|
5898
|
+
}
|
|
5776
5899
|
sourceWrite.before = preCommitBlobsForRecordBefore(sourceWrite, updatedRecord);
|
|
5777
5900
|
dbTxn.addWrite(sourceWrite);
|
|
5778
|
-
})
|
|
5901
|
+
});
|
|
5902
|
+
pendingSourceCommits.add(commitPromise);
|
|
5903
|
+
(0, when_ts_1.when)(commitPromise, () => {
|
|
5904
|
+
pendingSourceCommits.delete(commitPromise);
|
|
5779
5905
|
primaryStore.unlock(id);
|
|
5780
5906
|
}, (error) => {
|
|
5907
|
+
pendingSourceCommits.delete(commitPromise);
|
|
5781
5908
|
primaryStore.unlock(id);
|
|
5782
5909
|
if (resolved)
|
|
5783
5910
|
logger_ts_1.logger.error?.('Error committing cache update', error);
|