@harperfast/harper 5.3.0 → 5.3.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/copyDb.ts +5 -1
- package/bin/deployRenderer.ts +3 -0
- package/components/Application.ts +66 -22
- package/components/DESIGN.md +89 -36
- package/components/componentLoader.ts +2 -0
- package/components/deploymentRecorder.ts +18 -1
- package/components/installFingerprint.ts +123 -0
- package/components/mcp/DESIGN.md +4 -4
- package/components/operations.js +29 -0
- package/config/DESIGN.md +5 -5
- package/dataLayer/DESIGN.md +37 -22
- package/dataLayer/backupRepository.ts +248 -0
- package/dataLayer/restoreMarker.ts +30 -75
- package/dataLayer/rocksdbBackup.ts +253 -110
- package/dist/bin/copyDb.js +3 -0
- package/dist/bin/copyDb.js.map +1 -1
- package/dist/bin/deployRenderer.js +3 -0
- package/dist/bin/deployRenderer.js.map +1 -1
- package/dist/components/Application.d.ts +5 -0
- package/dist/components/Application.js +51 -19
- package/dist/components/Application.js.map +1 -1
- package/dist/components/componentLoader.js +2 -0
- package/dist/components/componentLoader.js.map +1 -1
- package/dist/components/deploymentRecorder.js +18 -1
- package/dist/components/deploymentRecorder.js.map +1 -1
- package/dist/components/installFingerprint.d.ts +39 -0
- package/dist/components/installFingerprint.js +113 -0
- package/dist/components/installFingerprint.js.map +1 -0
- package/dist/components/operations.d.ts +2 -0
- package/dist/components/operations.js +31 -0
- package/dist/components/operations.js.map +1 -1
- package/dist/dataLayer/backupRepository.d.ts +33 -0
- package/dist/dataLayer/backupRepository.js +232 -0
- package/dist/dataLayer/backupRepository.js.map +1 -0
- package/dist/dataLayer/restoreMarker.d.ts +4 -1
- package/dist/dataLayer/restoreMarker.js +29 -68
- package/dist/dataLayer/restoreMarker.js.map +1 -1
- package/dist/dataLayer/rocksdbBackup.js +221 -112
- package/dist/dataLayer/rocksdbBackup.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js.map +1 -1
- package/dist/json/systemSchema.json +14 -0
- package/dist/resources/DatabaseTransaction.d.ts +140 -11
- package/dist/resources/DatabaseTransaction.js +1055 -464
- package/dist/resources/DatabaseTransaction.js.map +1 -1
- package/dist/resources/IterableEventQueue.d.ts +2 -1
- package/dist/resources/IterableEventQueue.js +16 -8
- package/dist/resources/IterableEventQueue.js.map +1 -1
- package/dist/resources/LMDBTransaction.d.ts +13 -2
- package/dist/resources/LMDBTransaction.js +219 -93
- package/dist/resources/LMDBTransaction.js.map +1 -1
- package/dist/resources/RecordEncoder.js +2 -3
- package/dist/resources/RecordEncoder.js.map +1 -1
- package/dist/resources/Resource.js +5 -6
- package/dist/resources/Resource.js.map +1 -1
- package/dist/resources/ResourceInterface.d.ts +3 -1
- package/dist/resources/ResourceInterface.js.map +1 -1
- package/dist/resources/RocksIndexStore.d.ts +2 -1
- package/dist/resources/RocksIndexStore.js +3 -0
- package/dist/resources/RocksIndexStore.js.map +1 -1
- package/dist/resources/Table.js +116 -12
- package/dist/resources/Table.js.map +1 -1
- package/dist/resources/analytics/write.js +6 -2
- package/dist/resources/analytics/write.js.map +1 -1
- package/dist/resources/auditStore.d.ts +71 -17
- package/dist/resources/auditStore.js +248 -64
- package/dist/resources/auditStore.js.map +1 -1
- package/dist/resources/branchDatabase.js +2 -0
- package/dist/resources/branchDatabase.js.map +1 -1
- package/dist/resources/databases.js +8 -2
- package/dist/resources/databases.js.map +1 -1
- package/dist/resources/indexes/fullTextNativeBinding.d.ts +6 -2
- package/dist/resources/indexes/fullTextNativeBinding.js +12 -2
- package/dist/resources/indexes/fullTextNativeBinding.js.map +1 -1
- package/dist/resources/indexes/fullTextQueryIndex.d.ts +4 -0
- package/dist/resources/indexes/fullTextQueryIndex.js +207 -10
- package/dist/resources/indexes/fullTextQueryIndex.js.map +1 -1
- package/dist/resources/models/Models.d.ts +11 -0
- package/dist/resources/models/Models.js +95 -4
- package/dist/resources/models/Models.js.map +1 -1
- package/dist/resources/models/backendRegistry.d.ts +8 -0
- package/dist/resources/models/backendRegistry.js +15 -1
- package/dist/resources/models/backendRegistry.js.map +1 -1
- package/dist/resources/models/bootstrap.d.ts +2 -0
- package/dist/resources/models/bootstrap.js +6 -0
- package/dist/resources/models/bootstrap.js.map +1 -1
- package/dist/resources/models/calibration.d.ts +88 -0
- package/dist/resources/models/calibration.js +244 -0
- package/dist/resources/models/calibration.js.map +1 -0
- package/dist/resources/models/calibrationStore.d.ts +163 -0
- package/dist/resources/models/calibrationStore.js +986 -0
- package/dist/resources/models/calibrationStore.js.map +1 -0
- package/dist/resources/models/decisionStore.d.ts +24 -0
- package/dist/resources/models/decisionStore.js +45 -0
- package/dist/resources/models/decisionStore.js.map +1 -1
- package/dist/resources/models/generativeDecision.js +44 -15
- package/dist/resources/models/generativeDecision.js.map +1 -1
- package/dist/resources/models/types.d.ts +7 -0
- package/dist/resources/recordLock.d.ts +8 -5
- package/dist/resources/recordLock.js +6 -4
- package/dist/resources/recordLock.js.map +1 -1
- package/dist/resources/replayLogs.js +8 -1
- package/dist/resources/replayLogs.js.map +1 -1
- package/dist/resources/scheduler/engine.d.ts +4 -0
- package/dist/resources/scheduler/engine.js +30 -2
- package/dist/resources/scheduler/engine.js.map +1 -1
- package/dist/resources/search.d.ts +16 -4
- package/dist/resources/search.js +117 -13
- package/dist/resources/search.js.map +1 -1
- package/dist/resources/transaction.js +85 -5
- package/dist/resources/transaction.js.map +1 -1
- package/dist/resources/transactionBroadcast.d.ts +8 -0
- package/dist/resources/transactionBroadcast.js +65 -0
- package/dist/resources/transactionBroadcast.js.map +1 -1
- package/dist/security/keys.d.ts +1 -1
- package/dist/security/keys.js +170 -120
- package/dist/security/keys.js.map +1 -1
- package/dist/server/http.js +10 -0
- package/dist/server/http.js.map +1 -1
- package/dist/server/serverHelpers/Request.js +11 -2
- package/dist/server/serverHelpers/Request.js.map +1 -1
- package/dist/server/serverHelpers/contentTypes.js +8 -3
- package/dist/server/serverHelpers/contentTypes.js.map +1 -1
- package/dist/server/serverHelpers/uwsServer.js +38 -7
- package/dist/server/serverHelpers/uwsServer.js.map +1 -1
- package/dist/server/threads/manageThreads.d.ts +3 -3
- package/dist/server/threads/manageThreads.js +15 -13
- package/dist/server/threads/manageThreads.js.map +1 -1
- package/dist/server/threads/threadServer.d.ts +3 -0
- package/dist/server/threads/threadServer.js +24 -6
- package/dist/server/threads/threadServer.js.map +1 -1
- package/dist/upgrade/directives/5-3-0.js +9 -3
- package/dist/upgrade/directives/5-3-0.js.map +1 -1
- package/dist/utility/durableFile.d.ts +36 -0
- package/dist/utility/durableFile.js +106 -0
- package/dist/utility/durableFile.js.map +1 -0
- package/dist/utility/errors/hdbError.d.ts +4 -0
- package/dist/utility/errors/hdbError.js +10 -1
- package/dist/utility/errors/hdbError.js.map +1 -1
- package/dist/utility/globalSchema.d.ts +9 -0
- package/dist/utility/hdbTerms.d.ts +1 -0
- package/dist/utility/hdbTerms.js +1 -0
- package/dist/utility/hdbTerms.js.map +1 -1
- package/dist/validation/configValidator.js +29 -0
- package/dist/validation/configValidator.js.map +1 -1
- package/index.ts +7 -0
- package/json/systemSchema.json +14 -0
- package/npm-shrinkwrap.json +22 -22
- package/package.json +2 -2
- package/resources/DESIGN.md +57 -272
- package/resources/DatabaseTransaction.ts +708 -87
- package/resources/FULL_TEXT.md +6 -2
- package/resources/IterableEventQueue.ts +14 -7
- package/resources/LMDBTransaction.ts +212 -84
- package/resources/RecordEncoder.ts +2 -3
- package/resources/Resource.ts +5 -6
- package/resources/ResourceInterface.ts +3 -1
- package/resources/RocksIndexStore.ts +5 -0
- package/resources/Table.ts +118 -15
- package/resources/analytics/write.ts +6 -2
- package/resources/audit-retention.md +203 -0
- package/resources/auditStore.ts +306 -84
- package/resources/branchDatabase.ts +2 -0
- package/resources/databases.ts +6 -2
- package/resources/indexes/DESIGN.md +120 -177
- package/resources/indexes/fullTextNativeBinding.ts +22 -3
- package/resources/indexes/fullTextQueryIndex.ts +274 -11
- package/resources/models/DESIGN.md +11 -3
- package/resources/models/Models.ts +127 -4
- package/resources/models/backendRegistry.ts +17 -0
- package/resources/models/bootstrap.ts +9 -1
- package/resources/models/calibration.ts +298 -0
- package/resources/models/calibrationStore.ts +1167 -0
- package/resources/models/decisionStore.ts +57 -0
- package/resources/models/generativeDecision.ts +54 -16
- package/resources/models/types.ts +6 -0
- package/resources/record-locks.md +155 -141
- package/resources/recordLock.ts +12 -6
- package/resources/replayLogs.ts +9 -2
- package/resources/scheduler/DESIGN.md +4 -3
- package/resources/scheduler/engine.ts +35 -2
- package/resources/search.ts +154 -16
- package/resources/transaction.ts +50 -5
- package/resources/transactionBroadcast.ts +69 -0
- package/security/DESIGN.md +9 -30
- package/security/keys.ts +175 -127
- package/server/DESIGN.md +70 -36
- package/server/http.ts +10 -0
- package/server/serverHelpers/Request.ts +10 -2
- package/server/serverHelpers/contentTypes.ts +5 -3
- package/server/serverHelpers/uwsServer.ts +34 -7
- package/server/threads/manageThreads.js +16 -14
- package/server/threads/threadServer.js +24 -6
- package/studio/web/assets/{Chat-CNEKMllJ.js → Chat-4LMxI0yB.js} +1 -1
- package/studio/web/assets/{FloatingChat-CEnWhHeR.js → FloatingChat-kWHApEtF.js} +3 -3
- package/studio/web/assets/{SearchDialog-CwhJdEdY.js → SearchDialog-B7ymna97.js} +1 -1
- package/studio/web/assets/{apiToken-DC5vsaaO.js → apiToken-CE3AAt9f.js} +1 -1
- package/studio/web/assets/{applications-DQZxDy0x.js → applications-DdN7CqsB.js} +1 -1
- package/studio/web/assets/{cssMode-Dz2DxF4e.js → cssMode-BpySZUSt.js} +1 -1
- package/studio/web/assets/{editor-B3mjd3tz.js → editor-myLCVv9C.js} +1 -1
- package/studio/web/assets/{html-BsRGM7tp.js → html-DGNYO55O.js} +1 -1
- package/studio/web/assets/{htmlMode-tUKJaA3o.js → htmlMode-BUgpQr41.js} +1 -1
- package/studio/web/assets/{index-BuqFjN5K.js → index-FN4KC9va.js} +39 -39
- package/studio/web/assets/index-QLZw6xrU.css +1 -0
- package/studio/web/assets/{index.lazy-CcpfQFY_.js → index.lazy-DZFuaumG.js} +1 -1
- package/studio/web/assets/{javascript-BZ_uRGHl.js → javascript-DiBzh4pj.js} +1 -1
- package/studio/web/assets/{jsonMode-DgB-aFMj.js → jsonMode-Bm312nmu.js} +1 -1
- package/studio/web/assets/{languageServices-BleuBw17.js → languageServices-Dz2K9rZN.js} +1 -1
- package/studio/web/assets/{lspLanguageFeatures-ByVYLSsQ.js → lspLanguageFeatures-CNu1L5xn.js} +1 -1
- package/studio/web/assets/{notifications-TuzN0IMi.js → notifications--nwFLGmM.js} +1 -1
- package/studio/web/assets/{notifications-D1Nf-Edn.js → notifications-BelKw5bR.js} +1 -1
- package/studio/web/assets/{profile-D7C7Lupz.js → profile-AU5FjOBx.js} +1 -1
- package/studio/web/assets/{regions-nGQCm-v8.js → regions-C0sTSEHH.js} +1 -1
- package/studio/web/assets/{register-C3x9Ze6P.js → register-DyNR2rGk.js} +2 -2
- package/studio/web/assets/{setComponentFile-DpjrRqeG.js → setComponentFile-BkWx8AN3.js} +1 -1
- package/studio/web/assets/{setup-CGiKLZ9e.js → setup-D6LZS78d.js} +2 -2
- package/studio/web/assets/{status-CGJwrNPH.js → status-BCWnn70o.js} +1 -1
- package/studio/web/assets/{toggleHighContrast-C-Ne6P7T.js → toggleHighContrast-pyeGJ6W1.js} +1 -1
- package/studio/web/assets/{tsMode-CSreYTys.js → tsMode-CGV3iaWC.js} +1 -1
- package/studio/web/assets/{typescript-MnxBk89W.js → typescript-Ci7Khvwo.js} +1 -1
- package/studio/web/assets/{useEntityRestURL-TNrh77-s.js → useEntityRestURL-DNiz3aZ0.js} +1 -1
- package/studio/web/assets/{workers-BfZlUNVI.js → workers-byzxjbqy.js} +1 -1
- package/studio/web/assets/{xml-BHd6qGH7.js → xml-DGnHQ3CX.js} +1 -1
- package/studio/web/assets/{yaml-C53R8OQq.js → yaml-BUoTnPWb.js} +1 -1
- package/studio/web/index.html +2 -2
- package/upgrade/directives/5-3-0.ts +10 -3
- package/utility/durableFile.ts +96 -0
- package/utility/errors/hdbError.ts +9 -0
- package/utility/hdbTerms.ts +1 -0
- package/validation/configValidator.ts +31 -0
- package/studio/web/assets/index-72cEH474.css +0 -1
|
@@ -41,7 +41,6 @@ export type NativeFullTextSearchRequest = {
|
|
|
41
41
|
mode?: NativeFullTextSearchMode;
|
|
42
42
|
operator?: 'any' | 'all';
|
|
43
43
|
fields?: string[];
|
|
44
|
-
candidateIds?: string[];
|
|
45
44
|
offset?: number;
|
|
46
45
|
limit?: number;
|
|
47
46
|
exactTotal?: boolean;
|
|
@@ -109,15 +108,20 @@ export type NativeFullTextRuntimeInfo = {
|
|
|
109
108
|
storageBackends: ReadonlyArray<'native'>;
|
|
110
109
|
limits: {
|
|
111
110
|
maxCommitPayloadBytes: number;
|
|
111
|
+
maxRecordIdBytes: number;
|
|
112
|
+
maxRecordVersionBytes: number;
|
|
113
|
+
maxCandidateIds: number;
|
|
114
|
+
maxCandidateBytes: number;
|
|
112
115
|
maxSearchWindow: number;
|
|
113
116
|
maxAutocompleteResults: number;
|
|
117
|
+
maxSearchResponseBytes: number;
|
|
114
118
|
maxSearchBudgetMilliseconds: number;
|
|
115
119
|
maxTraceRecords: number;
|
|
116
120
|
maxTraceSourceBytes: number;
|
|
117
121
|
};
|
|
118
122
|
};
|
|
119
123
|
export type NativeFullTextQueryRuntimeInfo = Pick<NativeFullTextRuntimeInfo, 'queryClassIsolationMinimumSearchThreads'> & {
|
|
120
|
-
limits: Pick<NativeFullTextRuntimeInfo['limits'], 'maxSearchWindow' | 'maxAutocompleteResults' | 'maxSearchBudgetMilliseconds' | 'maxTraceRecords' | 'maxTraceSourceBytes'>;
|
|
124
|
+
limits: Pick<NativeFullTextRuntimeInfo['limits'], 'maxSearchWindow' | 'maxAutocompleteResults' | 'maxRecordIdBytes' | 'maxRecordVersionBytes' | 'maxCandidateIds' | 'maxCandidateBytes' | 'maxSearchResponseBytes' | 'maxSearchBudgetMilliseconds' | 'maxTraceRecords' | 'maxTraceSourceBytes'>;
|
|
121
125
|
};
|
|
122
126
|
export interface NativeFullTextModule {
|
|
123
127
|
NativeFullTextIndex: {
|
|
@@ -15,8 +15,8 @@ exports.nativeFullTextSearchThreads = nativeFullTextSearchThreads;
|
|
|
15
15
|
exports.validateFullTextQueryRuntimeInfo = validateFullTextQueryRuntimeInfo;
|
|
16
16
|
const logger_ts_1 = require("../../utility/logging/logger.js");
|
|
17
17
|
const FULLTEXT_LIFECYCLE_API_VERSION = 1;
|
|
18
|
-
const FULLTEXT_MUTATION_BATCH_API_VERSION =
|
|
19
|
-
const FULLTEXT_QUERY_API_VERSION =
|
|
18
|
+
const FULLTEXT_MUTATION_BATCH_API_VERSION = 5;
|
|
19
|
+
const FULLTEXT_QUERY_API_VERSION = 3;
|
|
20
20
|
const logger = (0, logger_ts_1.loggerWithTag)('fulltext-derived-index');
|
|
21
21
|
let bindingPromise;
|
|
22
22
|
let bindingWarningLogged = false;
|
|
@@ -102,11 +102,21 @@ function validateFullTextQueryRuntimeInfo(info) {
|
|
|
102
102
|
!Number.isSafeInteger(runtime.queryClassIsolationMinimumSearchThreads) ||
|
|
103
103
|
runtime.queryClassIsolationMinimumSearchThreads <= 0 ||
|
|
104
104
|
!runtime.limits ||
|
|
105
|
+
!Number.isSafeInteger(runtime.limits.maxRecordIdBytes) ||
|
|
106
|
+
runtime.limits.maxRecordIdBytes <= 0 ||
|
|
107
|
+
!Number.isSafeInteger(runtime.limits.maxRecordVersionBytes) ||
|
|
108
|
+
runtime.limits.maxRecordVersionBytes <= 0 ||
|
|
109
|
+
!Number.isSafeInteger(runtime.limits.maxCandidateIds) ||
|
|
110
|
+
runtime.limits.maxCandidateIds <= 0 ||
|
|
111
|
+
!Number.isSafeInteger(runtime.limits.maxCandidateBytes) ||
|
|
112
|
+
runtime.limits.maxCandidateBytes <= 0 ||
|
|
105
113
|
!Number.isSafeInteger(runtime.limits.maxSearchWindow) ||
|
|
106
114
|
runtime.limits.maxSearchWindow <= 0 ||
|
|
107
115
|
!Number.isSafeInteger(runtime.limits.maxAutocompleteResults) ||
|
|
108
116
|
runtime.limits.maxAutocompleteResults <= 0 ||
|
|
109
117
|
runtime.limits.maxAutocompleteResults > runtime.limits.maxSearchWindow ||
|
|
118
|
+
!Number.isSafeInteger(runtime.limits.maxSearchResponseBytes) ||
|
|
119
|
+
runtime.limits.maxSearchResponseBytes <= 0 ||
|
|
110
120
|
!Number.isSafeInteger(runtime.limits.maxSearchBudgetMilliseconds) ||
|
|
111
121
|
runtime.limits.maxSearchBudgetMilliseconds <= 0 ||
|
|
112
122
|
!Number.isSafeInteger(runtime.limits.maxTraceRecords) ||
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fullTextNativeBinding.js","sourceRoot":"","sources":["../../../resources/indexes/fullTextNativeBinding.ts"],"names":[],"mappings":";;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"fullTextNativeBinding.js","sourceRoot":"","sources":["../../../resources/indexes/fullTextNativeBinding.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,7 @@ import type { RocksTransactionLogStore } from '../RocksTransactionLogStore.ts';
|
|
|
3
3
|
import { type NativeFullTextIndexConfiguration, type NativeFullTextModule, type NativeFullTextSearchExpression, type NativeFullTextSearchMode } from './fullTextNativeBinding.ts';
|
|
4
4
|
export { FULL_TEXT_QUERY_PAUSE_OPERATION, FULL_TEXT_QUERY_RESUME_OPERATION, fullTextComparatorMode, } from './fullTextQueryProtocol.ts';
|
|
5
5
|
import { type DerivedNativeIndexHost } from './hnswDerivedIndex.ts';
|
|
6
|
+
import type { CandidateKeyPlan } from '../search.ts';
|
|
6
7
|
export type FullTextCondition = {
|
|
7
8
|
attribute?: string;
|
|
8
9
|
value?: string;
|
|
@@ -34,6 +35,8 @@ export type FullTextQueryIndexOptions = {
|
|
|
34
35
|
export declare class FullTextQueryIndex {
|
|
35
36
|
#private;
|
|
36
37
|
readonly filteredSearch = true;
|
|
38
|
+
readonly candidateKeyFilter = true;
|
|
39
|
+
readonly candidateKeyProbe = true;
|
|
37
40
|
readonly filePrimary = true;
|
|
38
41
|
constructor(options: FullTextQueryIndexOptions);
|
|
39
42
|
updateDefinition(definition: FullTextDefinition): void;
|
|
@@ -43,6 +46,7 @@ export declare class FullTextQueryIndex {
|
|
|
43
46
|
minResults?: number;
|
|
44
47
|
resultOffset?: number;
|
|
45
48
|
assertTransactionActive?: () => void;
|
|
49
|
+
candidateKeys?: CandidateKeyPlan;
|
|
46
50
|
}): Promise<Array<{
|
|
47
51
|
key: unknown;
|
|
48
52
|
$score: number;
|
|
@@ -18,8 +18,20 @@ Object.defineProperty(exports, "fullTextComparatorMode", { enumerable: true, get
|
|
|
18
18
|
const hnswDerivedIndex_ts_1 = require("./hnswDerivedIndex.js");
|
|
19
19
|
const logger_ts_1 = require("../../utility/logging/logger.js");
|
|
20
20
|
const RAW_PAGE_SIZE = 256;
|
|
21
|
+
const MAX_FILTERED_RAW_PAGE_SIZE = 4_096;
|
|
21
22
|
const MIN_RAW_PAGE_SIZE = 32;
|
|
22
23
|
const RAW_PAGE_OVERFETCH_FACTOR = 2;
|
|
24
|
+
const RAW_PAGE_ZERO_YIELD_GROWTH_FACTOR = 4;
|
|
25
|
+
const RAW_PAGE_YIELD_INTERVAL = 256;
|
|
26
|
+
const CANDIDATE_KEYS_PER_SOURCE_READ = 8;
|
|
27
|
+
const MAX_CANDIDATE_KEYS = 4_096;
|
|
28
|
+
// Four key-only reads remain cheaper than loading and decoding the authoritative record they replace.
|
|
29
|
+
const MAX_POINT_PROBE_READS_PER_CANDIDATE = 4;
|
|
30
|
+
const REJECTED_GATE_SAMPLE_SIZE = 8;
|
|
31
|
+
const CANDIDATE_GATE_FAILURE_RETRY_MILLISECONDS = 1_000;
|
|
32
|
+
// Fulltext 0.5.0 Query API v3 uses a 13-byte response header and 13 bytes per versioned hit before string data.
|
|
33
|
+
const NATIVE_SEARCH_RESPONSE_HEADER_BYTES = 13;
|
|
34
|
+
const NATIVE_SEARCH_HIT_OVERHEAD_BYTES = 13;
|
|
23
35
|
const MAX_RELOAD_FAILURES_BEFORE_REOPEN = 3;
|
|
24
36
|
const HIGHLIGHT_BLOB_READ_TIMEOUT_MILLISECONDS = 5_000;
|
|
25
37
|
const READER_DRAIN_GRACE_MILLISECONDS = 1_000;
|
|
@@ -33,6 +45,8 @@ const retiredReadinessIdsByPath = new Map();
|
|
|
33
45
|
const MAX_RETIRED_READINESS_IDS_PER_PATH = 64;
|
|
34
46
|
class FullTextQueryIndex {
|
|
35
47
|
filteredSearch = true;
|
|
48
|
+
candidateKeyFilter = true;
|
|
49
|
+
candidateKeyProbe = true;
|
|
36
50
|
filePrimary = true;
|
|
37
51
|
#options;
|
|
38
52
|
#nativeOptions;
|
|
@@ -44,6 +58,7 @@ class FullTextQueryIndex {
|
|
|
44
58
|
#readerOperation;
|
|
45
59
|
#retiredReaderSlots = new Set();
|
|
46
60
|
#maxSearchWindow;
|
|
61
|
+
#maxFilteredRawPageSize;
|
|
47
62
|
#maxAutocompleteResults;
|
|
48
63
|
#maxSearchBudgetMilliseconds;
|
|
49
64
|
#maxTraceRecords;
|
|
@@ -57,6 +72,13 @@ class FullTextQueryIndex {
|
|
|
57
72
|
#publicationRebuildRequested = false;
|
|
58
73
|
#refreshFailureWarned = false;
|
|
59
74
|
#unexpectedSearchFailureWarned = false;
|
|
75
|
+
#incompletePageFailureLogged = false;
|
|
76
|
+
#candidateCollectionFailureWarned = false;
|
|
77
|
+
#candidateProbeFailureWarned = false;
|
|
78
|
+
#candidateCollectionRetryAfter = 0;
|
|
79
|
+
#candidateProbeRetryAfter = 0;
|
|
80
|
+
#candidateCollectionFailureEpoch = 0;
|
|
81
|
+
#candidateProbeFailureEpoch = 0;
|
|
60
82
|
constructor(options) {
|
|
61
83
|
this.#options = options;
|
|
62
84
|
this.#definition = options.definition;
|
|
@@ -140,11 +162,13 @@ class FullTextQueryIndex {
|
|
|
140
162
|
context?.signal?.throwIfAborted();
|
|
141
163
|
const result = await this.#search(condition, context, options);
|
|
142
164
|
this.#unexpectedSearchFailureWarned = false;
|
|
165
|
+
this.#incompletePageFailureLogged = false;
|
|
143
166
|
return result;
|
|
144
167
|
}
|
|
145
168
|
coverage = this.#queryCoverage(maxIndexLagMilliseconds);
|
|
146
169
|
const result = await this.#search(condition, context, options);
|
|
147
170
|
this.#unexpectedSearchFailureWarned = false;
|
|
171
|
+
this.#incompletePageFailureLogged = false;
|
|
148
172
|
return result;
|
|
149
173
|
};
|
|
150
174
|
const operation = execute().catch((error) => {
|
|
@@ -271,14 +295,22 @@ class FullTextQueryIndex {
|
|
|
271
295
|
let moreMayExist = false;
|
|
272
296
|
let staleVersionHits = 0;
|
|
273
297
|
let expiredHits = 0;
|
|
298
|
+
let rejectedGateSampleCount = 0;
|
|
299
|
+
let rejectedGateKeys;
|
|
300
|
+
let rejectedGateVersions;
|
|
301
|
+
let rawPageSize = bounded
|
|
302
|
+
? Math.min(this.#maxFilteredRawPageSize, RAW_PAGE_SIZE, Math.max(MIN_RAW_PAGE_SIZE, target * RAW_PAGE_OVERFETCH_FACTOR))
|
|
303
|
+
: Math.min(this.#maxFilteredRawPageSize, RAW_PAGE_SIZE);
|
|
274
304
|
const transaction = context && this.#options.Table._readTxnForContext(context);
|
|
305
|
+
const candidatePlan = options.filter ? options.candidateKeys : undefined;
|
|
306
|
+
let candidateGate;
|
|
307
|
+
let candidateGatePlanned = false;
|
|
308
|
+
let candidateProbeFailureEpoch = 0;
|
|
275
309
|
while (accepted.length < target && offset < searchWindow) {
|
|
276
310
|
if (context?.signal?.aborted)
|
|
277
311
|
throw context.signal.reason ?? new Error('Full-text search aborted');
|
|
278
|
-
const
|
|
279
|
-
|
|
280
|
-
: RAW_PAGE_SIZE;
|
|
281
|
-
const limit = autocomplete ? searchWindow : Math.min(RAW_PAGE_SIZE, desiredPageSize, searchWindow - offset);
|
|
312
|
+
const limit = autocomplete ? searchWindow : Math.min(rawPageSize, searchWindow - offset);
|
|
313
|
+
const acceptedBeforePage = accepted.length;
|
|
282
314
|
const result = await reader.search({
|
|
283
315
|
query,
|
|
284
316
|
offset,
|
|
@@ -287,16 +319,98 @@ class FullTextQueryIndex {
|
|
|
287
319
|
}, { remainingBudgetMilliseconds: remainingSearchBudget(deadline) });
|
|
288
320
|
if (!bounded && !autocomplete && result.totalRelation === 'exact' && result.total > searchWindow)
|
|
289
321
|
throw new hdbError_ts_1.ClientError(`Full-text query exceeds the ${searchWindow}-result search window; add a limit`, 400);
|
|
322
|
+
// Fulltext 0.5.0 Query API v3 only reports lower-bound while a full requested page remains retrievable.
|
|
323
|
+
if (result.totalRelation === 'lower-bound' &&
|
|
324
|
+
result.hits.length < limit &&
|
|
325
|
+
offset + result.hits.length < result.total) {
|
|
326
|
+
if (!this.#incompletePageFailureLogged) {
|
|
327
|
+
this.#incompletePageFailureLogged = true;
|
|
328
|
+
logger.error?.(`Full-text index '${this.#definition.name}' returned ${result.hits.length} of ${limit} hits at offset ${offset} with lower-bound total ${result.total}`);
|
|
329
|
+
}
|
|
330
|
+
throw new hdbError_ts_1.ServerError('Full-text index returned an incomplete result page', 500);
|
|
331
|
+
}
|
|
332
|
+
// An exact total can safely continue from the returned offset; only a short lower-bound page breaks the v3 contract.
|
|
290
333
|
moreMayExist =
|
|
291
334
|
result.totalRelation === 'exact' ? offset + result.hits.length < result.total : result.hits.length === limit;
|
|
292
335
|
if (result.hits.length === 0)
|
|
293
336
|
break;
|
|
294
|
-
|
|
337
|
+
if (!candidateGatePlanned) {
|
|
338
|
+
candidateGatePlanned = true;
|
|
339
|
+
if (candidatePlan) {
|
|
340
|
+
const assertSearchActive = () => {
|
|
341
|
+
if (context?.signal?.aborted)
|
|
342
|
+
throw context.signal.reason ?? new Error('Full-text search aborted');
|
|
343
|
+
options.assertTransactionActive?.();
|
|
344
|
+
remainingSearchBudget(deadline);
|
|
345
|
+
};
|
|
346
|
+
assertSearchActive();
|
|
347
|
+
const nativeHitCount = Math.min(searchWindow, Math.max(result.hits.length, result.total));
|
|
348
|
+
candidateGate = await this.#candidateGate(candidatePlan, target, nativeHitCount, async () => {
|
|
349
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
350
|
+
assertSearchActive();
|
|
351
|
+
}, assertSearchActive);
|
|
352
|
+
candidateProbeFailureEpoch = this.#candidateProbeFailureEpoch;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
const pointReadsPerCandidate = candidateGate?.maxReadsPerCandidate ?? 0;
|
|
356
|
+
const workYieldInterval = Math.min(limit, pointReadsPerCandidate === 0
|
|
357
|
+
? RAW_PAGE_YIELD_INTERVAL
|
|
358
|
+
: Math.max(1, Math.floor(RAW_PAGE_YIELD_INTERVAL / (pointReadsPerCandidate + 1))));
|
|
359
|
+
let nextYieldIndex = workYieldInterval;
|
|
360
|
+
for (let hitIndex = 0; hitIndex < result.hits.length; hitIndex++) {
|
|
361
|
+
if (hitIndex === nextYieldIndex) {
|
|
362
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
363
|
+
if (context?.signal?.aborted)
|
|
364
|
+
throw context.signal.reason ?? new Error('Full-text search aborted');
|
|
365
|
+
remainingSearchBudget(deadline);
|
|
366
|
+
nextYieldIndex += workYieldInterval;
|
|
367
|
+
}
|
|
368
|
+
const hit = result.hits[hitIndex];
|
|
295
369
|
const key = decodeNativeId(hit.id, this.#options.Table.tableId);
|
|
296
|
-
options.assertTransactionActive?.();
|
|
297
|
-
const entry = this.#options.Table.primaryStore.getEntry(key, { transaction });
|
|
298
370
|
if (typeof hit.version !== 'string')
|
|
299
371
|
throw new hdbError_ts_1.ServerError('Full-text index returned a hit without a source version', 500);
|
|
372
|
+
options.assertTransactionActive?.();
|
|
373
|
+
let candidateDecides = false;
|
|
374
|
+
if (candidateGate) {
|
|
375
|
+
try {
|
|
376
|
+
const admitted = candidateGate.has(key);
|
|
377
|
+
if (candidateGate.maxReadsPerCandidate > 0 &&
|
|
378
|
+
candidateProbeFailureEpoch === this.#candidateProbeFailureEpoch) {
|
|
379
|
+
this.#candidateProbeFailureWarned = false;
|
|
380
|
+
this.#candidateProbeRetryAfter = 0;
|
|
381
|
+
}
|
|
382
|
+
if (!admitted) {
|
|
383
|
+
if (rejectedGateSampleCount < REJECTED_GATE_SAMPLE_SIZE) {
|
|
384
|
+
(rejectedGateKeys ??= [])[rejectedGateSampleCount] = key;
|
|
385
|
+
(rejectedGateVersions ??= [])[rejectedGateSampleCount] = hit.version;
|
|
386
|
+
rejectedGateSampleCount++;
|
|
387
|
+
}
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
candidateDecides = candidateGate.complete;
|
|
391
|
+
}
|
|
392
|
+
catch (error) {
|
|
393
|
+
const usedPointProbe = candidateGate.maxReadsPerCandidate > 0;
|
|
394
|
+
candidateGate = undefined;
|
|
395
|
+
if (usedPointProbe) {
|
|
396
|
+
this.#candidateProbeFailureEpoch++;
|
|
397
|
+
this.#candidateProbeRetryAfter = Date.now() + CANDIDATE_GATE_FAILURE_RETRY_MILLISECONDS;
|
|
398
|
+
if (!this.#candidateProbeFailureWarned) {
|
|
399
|
+
this.#candidateProbeFailureWarned = true;
|
|
400
|
+
logger.warn?.('could not probe the full-text companion index; using the record predicate', error);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
else {
|
|
404
|
+
this.#candidateCollectionFailureEpoch++;
|
|
405
|
+
this.#candidateCollectionRetryAfter = Date.now() + CANDIDATE_GATE_FAILURE_RETRY_MILLISECONDS;
|
|
406
|
+
if (!this.#candidateCollectionFailureWarned) {
|
|
407
|
+
this.#candidateCollectionFailureWarned = true;
|
|
408
|
+
logger.warn?.('could not apply the full-text candidate-key set; using the record predicate; point probes may resume on later requests', error);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
const entry = this.#options.Table.primaryStore.getEntry(key, { transaction });
|
|
300
414
|
if (!entry?.value || hit.version !== String(entry.version)) {
|
|
301
415
|
staleVersionHits++;
|
|
302
416
|
continue;
|
|
@@ -309,7 +423,7 @@ class FullTextQueryIndex {
|
|
|
309
423
|
expiredHits++;
|
|
310
424
|
continue;
|
|
311
425
|
}
|
|
312
|
-
if (options.filter && !options.filter(key, entry))
|
|
426
|
+
if (options.filter && !candidateDecides && !options.filter(key, entry))
|
|
313
427
|
continue;
|
|
314
428
|
accepted.push({ key, $score: hit.score, nativeId: hit.id, record: entry.value, recordEntry: entry });
|
|
315
429
|
if (accepted.length >= target)
|
|
@@ -320,11 +434,34 @@ class FullTextQueryIndex {
|
|
|
320
434
|
break;
|
|
321
435
|
if (!moreMayExist)
|
|
322
436
|
break;
|
|
323
|
-
if (accepted.length < target)
|
|
437
|
+
if (accepted.length < target) {
|
|
438
|
+
if (bounded) {
|
|
439
|
+
const acceptedThisPage = accepted.length - acceptedBeforePage;
|
|
440
|
+
rawPageSize = nextFilteredRawPageSize(limit, result.hits.length, acceptedThisPage, target - accepted.length, this.#maxFilteredRawPageSize);
|
|
441
|
+
}
|
|
324
442
|
await new Promise((resolve) => setImmediate(resolve));
|
|
443
|
+
}
|
|
325
444
|
}
|
|
326
445
|
if (!bounded && moreMayExist)
|
|
327
446
|
throw new hdbError_ts_1.ClientError(`Full-text query exceeds the ${searchWindow}-result search window; add a limit`, 400);
|
|
447
|
+
if (bounded &&
|
|
448
|
+
accepted.length < target &&
|
|
449
|
+
moreMayExist &&
|
|
450
|
+
staleVersionHits === 0 &&
|
|
451
|
+
rejectedGateSampleCount > 0) {
|
|
452
|
+
options.assertTransactionActive?.();
|
|
453
|
+
for (let sampleIndex = 0; sampleIndex < rejectedGateSampleCount; sampleIndex++) {
|
|
454
|
+
const entry = this.#options.Table.primaryStore.getEntry(rejectedGateKeys[sampleIndex], { transaction });
|
|
455
|
+
if (!entry?.value ||
|
|
456
|
+
rejectedGateVersions[sampleIndex] !== String(entry.version) ||
|
|
457
|
+
this.#options.Table.isFullTextSearchEntryCurrent?.(entry) === false) {
|
|
458
|
+
staleVersionHits++;
|
|
459
|
+
break;
|
|
460
|
+
}
|
|
461
|
+
if (entry.expiresAt !== undefined && entry.expiresAt < Date.now())
|
|
462
|
+
expiredHits++;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
328
465
|
if (bounded && accepted.length < target && moreMayExist && staleVersionHits > 0)
|
|
329
466
|
throw new hdbError_ts_1.DerivedIndexLagError(`Full-text index '${this.#definition.name}' changed while searching; retry this query`);
|
|
330
467
|
if (bounded && accepted.length < target && moreMayExist)
|
|
@@ -344,6 +481,52 @@ class FullTextQueryIndex {
|
|
|
344
481
|
await lease.release();
|
|
345
482
|
}
|
|
346
483
|
}
|
|
484
|
+
async #candidateGate(plan, target, maxSourceReads, cooperate, assertActive) {
|
|
485
|
+
const store = this.#options.Table.primaryStore;
|
|
486
|
+
const estimatedRecords = typeof store.getEstimatedKeyCount === 'function' ? store.getEstimatedKeyCount() : store.getStats?.().entryCount;
|
|
487
|
+
const recordCount = Math.max(1, Number.isFinite(estimatedRecords) ? estimatedRecords : target);
|
|
488
|
+
const selectivity = Math.min(1, Math.max(1, plan.estimatedCount) / recordCount);
|
|
489
|
+
const expectedSourceReads = Math.min(maxSourceReads, Math.ceil(target / selectivity));
|
|
490
|
+
const expectedRejectedReads = Math.ceil(expectedSourceReads * (1 - selectivity));
|
|
491
|
+
const maxKeys = Math.min(MAX_CANDIDATE_KEYS, Math.ceil(expectedRejectedReads * CANDIDATE_KEYS_PER_SOURCE_READ));
|
|
492
|
+
const now = Date.now();
|
|
493
|
+
if (plan.estimatedCount <= maxKeys && now >= this.#candidateCollectionRetryAfter) {
|
|
494
|
+
const collectionFailureEpoch = this.#candidateCollectionFailureEpoch;
|
|
495
|
+
try {
|
|
496
|
+
const collected = await plan.collect(maxKeys, cooperate);
|
|
497
|
+
assertActive();
|
|
498
|
+
if (collectionFailureEpoch === this.#candidateCollectionFailureEpoch) {
|
|
499
|
+
this.#candidateCollectionFailureWarned = false;
|
|
500
|
+
this.#candidateCollectionRetryAfter = 0;
|
|
501
|
+
}
|
|
502
|
+
if (collected)
|
|
503
|
+
return {
|
|
504
|
+
complete: collected.complete,
|
|
505
|
+
maxReadsPerCandidate: 0,
|
|
506
|
+
has: (primaryKey) => collected.keys.has(primaryKey),
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
catch (error) {
|
|
510
|
+
assertActive();
|
|
511
|
+
this.#candidateCollectionFailureEpoch++;
|
|
512
|
+
this.#candidateCollectionRetryAfter = Date.now() + CANDIDATE_GATE_FAILURE_RETRY_MILLISECONDS;
|
|
513
|
+
if (!this.#candidateCollectionFailureWarned) {
|
|
514
|
+
this.#candidateCollectionFailureWarned = true;
|
|
515
|
+
logger.warn?.('could not build the full-text candidate-key set; using point probes or the record predicate', error);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
const probe = plan.probe;
|
|
520
|
+
if (!probe ||
|
|
521
|
+
now < this.#candidateProbeRetryAfter ||
|
|
522
|
+
probe.maxReadsPerCandidate > MAX_POINT_PROBE_READS_PER_CANDIDATE)
|
|
523
|
+
return;
|
|
524
|
+
const probeSelectivity = Math.min(1, Math.max(1, probe.estimatedCount) / recordCount);
|
|
525
|
+
const expectedAvoidedSourceReadsPerCandidate = 1 - probeSelectivity;
|
|
526
|
+
return probe.maxReadsPerCandidate <= expectedAvoidedSourceReadsPerCandidate * CANDIDATE_KEYS_PER_SOURCE_READ
|
|
527
|
+
? probe
|
|
528
|
+
: undefined;
|
|
529
|
+
}
|
|
347
530
|
async #addHighlights(reader, definition, condition, entries, deadline) {
|
|
348
531
|
const highlighting = definition.highlighting;
|
|
349
532
|
if (!highlighting)
|
|
@@ -685,7 +868,14 @@ class FullTextQueryIndex {
|
|
|
685
868
|
const info = (0, fullTextNativeBinding_ts_1.validateFullTextQueryRuntimeInfo)(await binding.runtimeInfo());
|
|
686
869
|
this.#nativeOptions.limits.searchThreads = (0, fullTextNativeBinding_ts_1.nativeFullTextSearchThreads)(info, this.#nativeOptions.limits.searchThreads);
|
|
687
870
|
this.#maxSearchWindow = info.limits.maxSearchWindow;
|
|
688
|
-
|
|
871
|
+
const responseHitCapacity = Math.floor((info.limits.maxSearchResponseBytes - NATIVE_SEARCH_RESPONSE_HEADER_BYTES) /
|
|
872
|
+
(NATIVE_SEARCH_HIT_OVERHEAD_BYTES + info.limits.maxRecordIdBytes + info.limits.maxRecordVersionBytes));
|
|
873
|
+
if (responseHitCapacity < 1)
|
|
874
|
+
throw new TypeError('@harperfast/fulltext/native search response limit cannot hold one maximum-size hit');
|
|
875
|
+
if (responseHitCapacity < info.limits.maxAutocompleteResults)
|
|
876
|
+
logger.warn?.(`Full-text index '${this.#definition.name}' limits autocomplete to ${responseHitCapacity} results because the native response envelope cannot hold its advertised maximum`);
|
|
877
|
+
this.#maxFilteredRawPageSize = Math.min(MAX_FILTERED_RAW_PAGE_SIZE, info.limits.maxSearchWindow, responseHitCapacity);
|
|
878
|
+
this.#maxAutocompleteResults = Math.min(info.limits.maxAutocompleteResults, responseHitCapacity);
|
|
689
879
|
this.#maxSearchBudgetMilliseconds = info.limits.maxSearchBudgetMilliseconds;
|
|
690
880
|
this.#maxTraceRecords = info.limits.maxTraceRecords;
|
|
691
881
|
this.#maxTraceSourceBytes = info.limits.maxTraceSourceBytes;
|
|
@@ -707,6 +897,13 @@ class FullTextQueryIndex {
|
|
|
707
897
|
}
|
|
708
898
|
}
|
|
709
899
|
exports.FullTextQueryIndex = FullTextQueryIndex;
|
|
900
|
+
function nextFilteredRawPageSize(currentPageSize, rawHits, acceptedHits, remainingResults, maxPageSize) {
|
|
901
|
+
const projected = acceptedHits === 0
|
|
902
|
+
? // With no selectivity signal, grow independently of the remaining target to minimize native round trips.
|
|
903
|
+
currentPageSize * RAW_PAGE_ZERO_YIELD_GROWTH_FACTOR
|
|
904
|
+
: Math.ceil((remainingResults * rawHits * RAW_PAGE_OVERFETCH_FACTOR) / acceptedHits);
|
|
905
|
+
return Math.min(maxPageSize, Math.max(MIN_RAW_PAGE_SIZE, projected));
|
|
906
|
+
}
|
|
710
907
|
async function pauseNativeFullTextQueryReaders(path, readinessId, ownerEpoch, allowUnregisteredReadiness = false) {
|
|
711
908
|
const indexes = queryIndexesByPath.get(path);
|
|
712
909
|
if (!indexes || indexes.size === 0)
|