@harperfast/harper 5.3.0-alpha.1 → 5.3.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cliOperations.ts +12 -0
- package/bin/restart.ts +66 -6
- package/components/Application.ts +1134 -112
- package/components/OptionsWatcher.ts +368 -102
- package/components/Scope.ts +20 -1
- package/components/componentLoader.ts +43 -4
- package/components/deploymentOperations.ts +4 -1
- package/components/deploymentRecorder.ts +9 -2
- package/components/operations.js +284 -52
- package/components/operationsValidation.js +49 -2
- package/components/packageComponent.ts +25 -1
- package/components/requestRestart.ts +11 -0
- package/config/RootConfigWatcher.ts +191 -37
- package/config/configReadRetry.ts +62 -0
- package/config/configUtils.ts +78 -26
- package/config/parseConfigFile.ts +34 -0
- package/config/readConfigFileSync.ts +44 -0
- package/config/watcherArming.ts +59 -0
- package/config-root.schema.json +4 -0
- package/dataLayer/harperBridge/ResourceBridge.ts +28 -2
- package/dist/bin/cliOperations.js +13 -0
- package/dist/bin/cliOperations.js.map +1 -1
- package/dist/bin/restart.js +42 -6
- package/dist/bin/restart.js.map +1 -1
- package/dist/components/Application.d.ts +104 -9
- package/dist/components/Application.js +954 -102
- package/dist/components/Application.js.map +1 -1
- package/dist/components/OptionsWatcher.d.ts +4 -1
- package/dist/components/OptionsWatcher.js +378 -104
- package/dist/components/OptionsWatcher.js.map +1 -1
- package/dist/components/Scope.js +15 -1
- package/dist/components/Scope.js.map +1 -1
- package/dist/components/componentLoader.js +35 -3
- package/dist/components/componentLoader.js.map +1 -1
- package/dist/components/deploymentOperations.js +4 -1
- package/dist/components/deploymentOperations.js.map +1 -1
- package/dist/components/deploymentRecorder.d.ts +4 -2
- package/dist/components/deploymentRecorder.js +1 -0
- package/dist/components/deploymentRecorder.js.map +1 -1
- package/dist/components/operations.d.ts +28 -0
- package/dist/components/operations.js +263 -54
- package/dist/components/operations.js.map +1 -1
- package/dist/components/operationsValidation.js +48 -2
- package/dist/components/operationsValidation.js.map +1 -1
- package/dist/components/packageComponent.js +24 -0
- package/dist/components/packageComponent.js.map +1 -1
- package/dist/components/requestRestart.d.ts +1 -0
- package/dist/components/requestRestart.js +7 -0
- package/dist/components/requestRestart.js.map +1 -1
- package/dist/config/RootConfigWatcher.d.ts +2 -0
- package/dist/config/RootConfigWatcher.js +189 -35
- package/dist/config/RootConfigWatcher.js.map +1 -1
- package/dist/config/configReadRetry.d.ts +8 -0
- package/dist/config/configReadRetry.js +62 -0
- package/dist/config/configReadRetry.js.map +1 -0
- package/dist/config/configUtils.d.ts +10 -9
- package/dist/config/configUtils.js +63 -27
- package/dist/config/configUtils.js.map +1 -1
- package/dist/config/parseConfigFile.d.ts +4 -0
- package/dist/config/parseConfigFile.js +35 -0
- package/dist/config/parseConfigFile.js.map +1 -0
- package/dist/config/readConfigFileSync.d.ts +1 -0
- package/dist/config/readConfigFileSync.js +47 -0
- package/dist/config/readConfigFileSync.js.map +1 -0
- package/dist/config/watcherArming.d.ts +15 -0
- package/dist/config/watcherArming.js +59 -0
- package/dist/config/watcherArming.js.map +1 -0
- package/dist/dataLayer/harperBridge/ResourceBridge.js +21 -2
- package/dist/dataLayer/harperBridge/ResourceBridge.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/json/systemSchema.json +3 -0
- package/dist/resources/DatabaseTransaction.d.ts +25 -0
- package/dist/resources/DatabaseTransaction.js +224 -18
- package/dist/resources/DatabaseTransaction.js.map +1 -1
- package/dist/resources/LMDBTransaction.d.ts +2 -1
- package/dist/resources/LMDBTransaction.js +22 -3
- package/dist/resources/LMDBTransaction.js.map +1 -1
- package/dist/resources/PrimaryRocksDatabase.js +22 -6
- package/dist/resources/PrimaryRocksDatabase.js.map +1 -1
- package/dist/resources/RecordEncoder.d.ts +1 -1
- package/dist/resources/RecordEncoder.js +21 -5
- package/dist/resources/RecordEncoder.js.map +1 -1
- package/dist/resources/Resource.js +97 -13
- package/dist/resources/Resource.js.map +1 -1
- package/dist/resources/ResourceInterface.d.ts +8 -0
- package/dist/resources/RocksIndexStore.js +2 -1
- package/dist/resources/RocksIndexStore.js.map +1 -1
- package/dist/resources/RocksTransactionLogStore.d.ts +10 -0
- package/dist/resources/RocksTransactionLogStore.js +104 -33
- package/dist/resources/RocksTransactionLogStore.js.map +1 -1
- package/dist/resources/Table.d.ts +58 -7
- package/dist/resources/Table.js +1095 -346
- package/dist/resources/Table.js.map +1 -1
- package/dist/resources/analytics/write.js +10 -3
- package/dist/resources/analytics/write.js.map +1 -1
- package/dist/resources/auditStore.d.ts +170 -0
- package/dist/resources/auditStore.js +457 -11
- package/dist/resources/auditStore.js.map +1 -1
- package/dist/resources/dataLoader.js +3 -4
- package/dist/resources/dataLoader.js.map +1 -1
- package/dist/resources/databases.d.ts +16 -13
- package/dist/resources/databases.js +624 -176
- package/dist/resources/databases.js.map +1 -1
- package/dist/resources/derivedIndexRegistry.d.ts +5 -0
- package/dist/resources/derivedIndexRegistry.js +68 -0
- package/dist/resources/derivedIndexRegistry.js.map +1 -0
- package/dist/resources/derivedIndexRuntime.d.ts +215 -0
- package/dist/resources/derivedIndexRuntime.js +2027 -0
- package/dist/resources/derivedIndexRuntime.js.map +1 -0
- package/dist/resources/graphql.js +3 -2
- package/dist/resources/graphql.js.map +1 -1
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.d.ts +102 -9
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js +848 -39
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js.map +1 -1
- package/dist/resources/indexes/hnswDerivedIndex.d.ts +67 -0
- package/dist/resources/indexes/hnswDerivedIndex.js +464 -0
- package/dist/resources/indexes/hnswDerivedIndex.js.map +1 -0
- package/dist/resources/indexes/hnswPlaneBinding.d.ts +65 -0
- package/dist/resources/indexes/hnswPlaneBinding.js +91 -0
- package/dist/resources/indexes/hnswPlaneBinding.js.map +1 -0
- package/dist/resources/nodeIdMapping.d.ts +5 -0
- package/dist/resources/nodeIdMapping.js +49 -0
- package/dist/resources/nodeIdMapping.js.map +1 -1
- package/dist/resources/recordLock.d.ts +47 -4
- package/dist/resources/recordLock.js +138 -7
- package/dist/resources/recordLock.js.map +1 -1
- package/dist/resources/recordLockCoordinator.d.ts +557 -0
- package/dist/resources/recordLockCoordinator.js +2565 -0
- package/dist/resources/recordLockCoordinator.js.map +1 -0
- package/dist/resources/replayLogs.js +5 -0
- package/dist/resources/replayLogs.js.map +1 -1
- package/dist/resources/replicatedApplyFailure.d.ts +16 -0
- package/dist/resources/replicatedApplyFailure.js +63 -0
- package/dist/resources/replicatedApplyFailure.js.map +1 -0
- package/dist/resources/scheduler/scheduler.js +3 -3
- package/dist/resources/scheduler/scheduler.js.map +1 -1
- package/dist/resources/search.d.ts +10 -4
- package/dist/resources/search.js +160 -40
- package/dist/resources/search.js.map +1 -1
- package/dist/resources/tracked.d.ts +5 -1
- package/dist/resources/tracked.js +74 -23
- package/dist/resources/tracked.js.map +1 -1
- package/dist/security/jsLoader.js +6 -4
- package/dist/security/jsLoader.js.map +1 -1
- package/dist/server/REST.js +33 -2
- package/dist/server/REST.js.map +1 -1
- package/dist/server/http.d.ts +5 -1
- package/dist/server/http.js +34 -2
- package/dist/server/http.js.map +1 -1
- package/dist/server/serverHelpers/Headers.d.ts +2 -0
- package/dist/server/serverHelpers/Headers.js +6 -0
- package/dist/server/serverHelpers/Headers.js.map +1 -1
- package/dist/server/serverHelpers/NodeAdapterResponse.d.ts +48 -0
- package/dist/server/serverHelpers/NodeAdapterResponse.js +220 -0
- package/dist/server/serverHelpers/NodeAdapterResponse.js.map +1 -0
- package/dist/server/serverHelpers/Request.d.ts +5 -10
- package/dist/server/serverHelpers/Request.js +38 -136
- package/dist/server/serverHelpers/Request.js.map +1 -1
- package/dist/server/serverHelpers/contentTypes.d.ts +2 -0
- package/dist/server/serverHelpers/contentTypes.js +189 -15
- package/dist/server/serverHelpers/contentTypes.js.map +1 -1
- package/dist/server/serverHelpers/serverUtilities.js +96 -17
- package/dist/server/serverHelpers/serverUtilities.js.map +1 -1
- package/dist/server/storageReclamation.js +1 -1
- package/dist/server/storageReclamation.js.map +1 -1
- package/dist/server/threads/isolatedApplications.d.ts +47 -0
- package/dist/server/threads/isolatedApplications.js +171 -0
- package/dist/server/threads/isolatedApplications.js.map +1 -0
- package/dist/server/threads/logRotationTransport.d.ts +1 -0
- package/dist/server/threads/logRotationTransport.js +33 -0
- package/dist/server/threads/logRotationTransport.js.map +1 -0
- package/dist/server/threads/manageThreads.d.ts +64 -6
- package/dist/server/threads/manageThreads.js +261 -12
- package/dist/server/threads/manageThreads.js.map +1 -1
- package/dist/server/threads/socketRouter.d.ts +1 -0
- package/dist/server/threads/socketRouter.js +196 -13
- package/dist/server/threads/socketRouter.js.map +1 -1
- package/dist/server/threads/threadServer.js +30 -7
- package/dist/server/threads/threadServer.js.map +1 -1
- package/dist/utility/errors/hdbError.d.ts +24 -0
- package/dist/utility/errors/hdbError.js +58 -1
- package/dist/utility/errors/hdbError.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/logging/harper_logger.js +217 -38
- package/dist/utility/logging/harper_logger.js.map +1 -1
- package/dist/utility/logging/logGenerationCoordinator.d.ts +35 -0
- package/dist/utility/logging/logGenerationCoordinator.js +184 -0
- package/dist/utility/logging/logGenerationCoordinator.js.map +1 -0
- package/dist/utility/logging/logRotation.d.ts +46 -0
- package/dist/utility/logging/logRotation.js +365 -0
- package/dist/utility/logging/logRotation.js.map +1 -0
- package/dist/utility/logging/logRotator.d.ts +1 -1
- package/dist/utility/logging/logRotator.js +172 -92
- package/dist/utility/logging/logRotator.js.map +1 -1
- package/dist/utility/npmUtilities.js +6 -4
- package/dist/utility/npmUtilities.js.map +1 -1
- package/dist/utility/watcherFallback.d.ts +0 -45
- package/dist/utility/watcherFallback.js +1 -125
- package/dist/utility/watcherFallback.js.map +1 -1
- package/dist/validation/configValidator.js +6 -3
- package/dist/validation/configValidator.js.map +1 -1
- package/index.ts +6 -0
- package/json/systemSchema.json +3 -0
- package/npm-shrinkwrap.json +131 -41
- package/package.json +10 -3
- package/resources/DESIGN.md +124 -19
- package/resources/DatabaseTransaction.ts +230 -17
- package/resources/LMDBTransaction.ts +21 -3
- package/resources/PrimaryRocksDatabase.ts +20 -7
- package/resources/RecordEncoder.ts +25 -5
- package/resources/Resource.ts +97 -13
- package/resources/ResourceInterface.ts +8 -0
- package/resources/RocksIndexStore.ts +2 -1
- package/resources/RocksTransactionLogStore.ts +111 -31
- package/resources/Table.ts +1224 -393
- package/resources/analytics/write.ts +10 -3
- package/resources/auditStore.ts +460 -11
- package/resources/dataLoader.ts +3 -4
- package/resources/databases.ts +610 -146
- package/resources/derivedIndexRegistry.ts +56 -0
- package/resources/derivedIndexRuntime.ts +2292 -0
- package/resources/graphql.ts +3 -2
- package/resources/indexes/HierarchicalNavigableSmallWorld.ts +905 -46
- package/resources/indexes/hnswDerivedIndex.ts +531 -0
- package/resources/indexes/hnswPlaneBinding.ts +174 -0
- package/resources/nodeIdMapping.ts +50 -0
- package/resources/recordLock.ts +173 -7
- package/resources/recordLockCoordinator.ts +3043 -0
- package/resources/replayLogs.ts +5 -0
- package/resources/replicatedApplyFailure.ts +77 -0
- package/resources/scheduler/scheduler.ts +4 -4
- package/resources/search.ts +169 -49
- package/resources/tracked.ts +73 -22
- package/security/jsLoader.ts +6 -4
- package/server/DESIGN.md +11 -0
- package/server/REST.ts +36 -3
- package/server/http.ts +34 -2
- package/server/serverHelpers/Headers.ts +5 -1
- package/server/serverHelpers/NodeAdapterResponse.ts +221 -0
- package/server/serverHelpers/Request.ts +33 -131
- package/server/serverHelpers/contentTypes.ts +188 -15
- package/server/serverHelpers/serverUtilities.ts +143 -24
- package/server/storageReclamation.ts +2 -2
- package/server/threads/isolatedApplications.ts +157 -0
- package/server/threads/logRotationTransport.ts +40 -0
- package/server/threads/manageThreads.js +254 -12
- package/server/threads/socketRouter.ts +217 -11
- package/server/threads/threadServer.js +30 -7
- package/studio/web/assets/{Chat-BnCBegQz.js → Chat-D3j-1yY1.js} +1 -1
- package/studio/web/assets/{FloatingChat-CoDW1ySS.js → FloatingChat-BxJGYcfB.js} +3 -3
- package/studio/web/assets/{apiToken-Bwk5BLXW.js → apiToken-CT55oWOe.js} +1 -1
- package/studio/web/assets/{applications-DHxGi7JH.js → applications-D9Ct9_vm.js} +1 -1
- package/studio/web/assets/{cssMode-s0cWI-_M.js → cssMode-DV8H7VwA.js} +1 -1
- package/studio/web/assets/{editor-DNcRHK54.js → editor-uatc0unt.js} +1 -1
- package/studio/web/assets/{html-Bdssedlg.js → html-Bm6D6paN.js} +1 -1
- package/studio/web/assets/{htmlMode-CoDlJ3fw.js → htmlMode-CEn7tpLG.js} +1 -1
- package/studio/web/assets/{index-D6sxmFLR.js → index-BIXW6Pu4.js} +5 -5
- package/studio/web/assets/{index.lazy-tmU5BS8s.js → index.lazy-UI7L-Vrk.js} +1 -1
- package/studio/web/assets/{javascript-B8meVSTH.js → javascript-CJ0G3AFZ.js} +1 -1
- package/studio/web/assets/{jsonMode-DpIPd35T.js → jsonMode-DQADAYEa.js} +1 -1
- package/studio/web/assets/{languageServices-C_5FMJzQ.js → languageServices-CAQJXWcI.js} +1 -1
- package/studio/web/assets/{lspLanguageFeatures-BIzNBzPK.js → lspLanguageFeatures-CCQ8P5sY.js} +1 -1
- package/studio/web/assets/{notifications-CQf18QKb.js → notifications-BbxTU6Aw.js} +1 -1
- package/studio/web/assets/{notifications-CvZivSbh.js → notifications-Cvb3P1lB.js} +1 -1
- package/studio/web/assets/{profile-DdOwtntb.js → profile-Yyb7gsvL.js} +1 -1
- package/studio/web/assets/{regions-n69fwagr.js → regions-OgjGHlU5.js} +1 -1
- package/studio/web/assets/{register-PfWTCXWB.js → register-6qwNEOY3.js} +2 -2
- package/studio/web/assets/{setComponentFile-Bg6O7X0S.js → setComponentFile-BilDMtgB.js} +1 -1
- package/studio/web/assets/{setup-CUx_aUDl.js → setup-J6qJ7OIU.js} +2 -2
- package/studio/web/assets/{status-D7BVKqX9.js → status-0RWGcfyD.js} +1 -1
- package/studio/web/assets/{toggleHighContrast-DBSyXzMr.js → toggleHighContrast-BIn-vErT.js} +1 -1
- package/studio/web/assets/{tsMode-BByKCjBS.js → tsMode-DgUXku4d.js} +1 -1
- package/studio/web/assets/{typescript-DDLnLpw9.js → typescript-C9orXcsM.js} +1 -1
- package/studio/web/assets/{useEntityRestURL-31CHGaHk.js → useEntityRestURL-BEoXXbUB.js} +1 -1
- package/studio/web/assets/{workers-pR3jRY9D.js → workers-JVzSDmgx.js} +1 -1
- package/studio/web/assets/{xml-2iRnMhQO.js → xml-Cq-S8S4X.js} +1 -1
- package/studio/web/assets/{yaml-Bf92gJpd.js → yaml-sfoRdh1M.js} +1 -1
- package/studio/web/index.html +1 -1
- package/utility/errors/hdbError.ts +54 -0
- package/utility/hdbTerms.ts +2 -0
- package/utility/logging/harper_logger.ts +209 -30
- package/utility/logging/logGenerationCoordinator.ts +196 -0
- package/utility/logging/logRotation.ts +367 -0
- package/utility/logging/logRotator.ts +196 -91
- package/utility/npmUtilities.ts +6 -4
- package/utility/watcherFallback.ts +0 -122
- package/validation/configValidator.ts +6 -3
|
@@ -48,6 +48,8 @@ declare class StartedTransaction extends Error {
|
|
|
48
48
|
* transactions, while core keeps the consistency guarantee.
|
|
49
49
|
*/
|
|
50
50
|
export declare function transactionOpenTooLongError(): ServerError;
|
|
51
|
+
export declare function getReadTransactionGuard(transaction: ReadTransaction): (() => void) | undefined;
|
|
52
|
+
export declare function trackReadRange(transaction: ReadTransaction, createRange: () => any): any;
|
|
51
53
|
type MaybePromise<T> = T | Promise<T>;
|
|
52
54
|
export type CommitOptions = {
|
|
53
55
|
doneWriting?: boolean;
|
|
@@ -62,6 +64,10 @@ type ReadTransaction = (LMDBTransaction | RocksTransaction) & {
|
|
|
62
64
|
isDone?: boolean;
|
|
63
65
|
isCommitted?: boolean;
|
|
64
66
|
};
|
|
67
|
+
export type WriteGeneration = {
|
|
68
|
+
closed: boolean;
|
|
69
|
+
internalWrites: number;
|
|
70
|
+
};
|
|
65
71
|
export type TransactionWrite = {
|
|
66
72
|
key: Id;
|
|
67
73
|
store: any;
|
|
@@ -96,7 +102,12 @@ export type TransactionWrite = {
|
|
|
96
102
|
trackRecordVersion?: boolean;
|
|
97
103
|
recordVersionApplied?: boolean;
|
|
98
104
|
innerCommit?: MaybePromise<CommitResolution>;
|
|
105
|
+
reloadCommitBase?: boolean;
|
|
106
|
+
writeGeneration?: WriteGeneration;
|
|
107
|
+
instanceClosed?: boolean;
|
|
99
108
|
};
|
|
109
|
+
export declare function closeWriteInstance(operation: TransactionWrite | null | undefined): void;
|
|
110
|
+
export declare function validateWrite(operation: TransactionWrite, txnTime: number, transaction: DatabaseTransaction): any;
|
|
100
111
|
export declare function getAppliedWriteVersion(recordVersion: number | undefined, txnLogKey: number): number;
|
|
101
112
|
/**
|
|
102
113
|
* The state a preceding write in this transaction left for `operation`'s key, or undefined if this
|
|
@@ -128,6 +139,7 @@ export declare class DatabaseTransaction implements Transaction {
|
|
|
128
139
|
scopeOwned?: boolean;
|
|
129
140
|
});
|
|
130
141
|
writes: TransactionWrite[];
|
|
142
|
+
ownedWrites?: WeakSet<TransactionWrite>;
|
|
131
143
|
writesByKey?: Map<any, Map<unknown, TransactionWrite>>;
|
|
132
144
|
completions: Promise<void>[];
|
|
133
145
|
db: RootDatabaseKind;
|
|
@@ -169,8 +181,21 @@ export declare class DatabaseTransaction implements Transaction {
|
|
|
169
181
|
commitPhaseTicks: number;
|
|
170
182
|
commitChainHead?: DatabaseTransaction;
|
|
171
183
|
recordLocks?: Map<any, Map<unknown, RecordLockHandle>>;
|
|
184
|
+
/**
|
|
185
|
+
* Whether any staged write was made through a record lock handle. The commit-time lease fence
|
|
186
|
+
* below is skipped entirely when this is false, which is every transaction in a core-only
|
|
187
|
+
* deployment: without it a bulk transaction of 100,000 plain writes pays 100,000 property checks
|
|
188
|
+
* before submission, on a path that is supposed to be untouched when no lock is involved. It
|
|
189
|
+
* latches rather than tracking a count, because a write whose handle was released or expired after
|
|
190
|
+
* staging is exactly what the fence exists to catch.
|
|
191
|
+
*/
|
|
192
|
+
hasLeaseProtectedWrite?: boolean;
|
|
172
193
|
pendingLocks?: Map<any, Map<unknown, Promise<RecordLockHandle>>>;
|
|
173
194
|
setCommitPhase(committing: boolean): void;
|
|
195
|
+
rangeReadActive: boolean;
|
|
196
|
+
renewReadTimeout(): void;
|
|
197
|
+
renewIdleTimeout(): void;
|
|
198
|
+
renewChainForNativeCommit(): void;
|
|
174
199
|
getReadTxn(disableSnapshot?: boolean): ReadTransaction;
|
|
175
200
|
private attachOwnedTransaction;
|
|
176
201
|
/**
|
|
@@ -40,6 +40,10 @@ exports.setCommitLatencyRecorder = setCommitLatencyRecorder;
|
|
|
40
40
|
exports.getTransactionQueueDepths = getTransactionQueueDepths;
|
|
41
41
|
exports.replicationConfirmation = replicationConfirmation;
|
|
42
42
|
exports.transactionOpenTooLongError = transactionOpenTooLongError;
|
|
43
|
+
exports.getReadTransactionGuard = getReadTransactionGuard;
|
|
44
|
+
exports.trackReadRange = trackReadRange;
|
|
45
|
+
exports.closeWriteInstance = closeWriteInstance;
|
|
46
|
+
exports.validateWrite = validateWrite;
|
|
43
47
|
exports.getAppliedWriteVersion = getAppliedWriteVersion;
|
|
44
48
|
exports.priorStagedWrite = priorStagedWrite;
|
|
45
49
|
exports.writeKeyId = writeKeyId;
|
|
@@ -65,6 +69,7 @@ const RETRY_NOW_VALUE = rocksdb_js_1.constants.RETRY_NOW_VALUE;
|
|
|
65
69
|
const ordered_binary_1 = require("ordered-binary");
|
|
66
70
|
const longLivedTransactions_ts_1 = require("./longLivedTransactions.js");
|
|
67
71
|
const trackedTxns = new Set();
|
|
72
|
+
const readTransactionOwners = new WeakMap();
|
|
68
73
|
// Read options for a rotated generation's native transactions; shared because they never vary.
|
|
69
74
|
const SNAPSHOT_FREE = Object.freeze({ disableSnapshot: true });
|
|
70
75
|
// Logical transactions the monitor supervises for their WRITES, kept apart from trackedTxns because the
|
|
@@ -297,6 +302,104 @@ function transactionOpenTooLongError() {
|
|
|
297
302
|
// 422 signals the request itself must change (split the work), which is the actionable response.
|
|
298
303
|
return new hdbError_ts_1.ServerError('Transaction was aborted after exceeding the maximum open-transaction time; split long-running work into smaller transactions', 422);
|
|
299
304
|
}
|
|
305
|
+
class ReadSnapshotExpiredError extends hdbError_ts_1.ServerError {
|
|
306
|
+
constructor() {
|
|
307
|
+
super('Read scan snapshot expired; retry the read without replaying previously committed writes', 503);
|
|
308
|
+
this.name = 'ReadSnapshotExpiredError';
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
function getReadTransactionGuard(transaction) {
|
|
312
|
+
const owner = readTransactionOwners.get(transaction);
|
|
313
|
+
if (!owner)
|
|
314
|
+
return;
|
|
315
|
+
return function checkActive() {
|
|
316
|
+
if (owner.timedOut)
|
|
317
|
+
throw transactionOpenTooLongError();
|
|
318
|
+
if (owner.transaction !== transaction) {
|
|
319
|
+
throw new ReadSnapshotExpiredError();
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
function trackReadRange(transaction, createRange) {
|
|
324
|
+
const owner = readTransactionOwners.get(transaction);
|
|
325
|
+
if (!owner)
|
|
326
|
+
return createRange();
|
|
327
|
+
const checkActive = getReadTransactionGuard(transaction);
|
|
328
|
+
checkActive();
|
|
329
|
+
const range = createRange();
|
|
330
|
+
const iterate = range.iterate;
|
|
331
|
+
range.iterate = function (options) {
|
|
332
|
+
const iterator = iterate.call(this, options);
|
|
333
|
+
let done = false;
|
|
334
|
+
// Closing the underlying iterator is the one step here that can throw for a reason the caller
|
|
335
|
+
// must not see: `next()` only reaches it once the snapshot is already gone, which is the
|
|
336
|
+
// likeliest moment for the native layer to object, and an error from cleanup would replace the
|
|
337
|
+
// named 503 with exactly the raw iterator error this wrapper exists to stop surfacing. The
|
|
338
|
+
// closure reference rather than `this` so a destructured `next` still cleans up.
|
|
339
|
+
const wrapper = {
|
|
340
|
+
[Symbol.iterator]() {
|
|
341
|
+
return this;
|
|
342
|
+
},
|
|
343
|
+
next() {
|
|
344
|
+
if (done)
|
|
345
|
+
return { done: true, value: undefined };
|
|
346
|
+
try {
|
|
347
|
+
checkActive();
|
|
348
|
+
owner.rangeReadActive = true;
|
|
349
|
+
const result = iterator.next();
|
|
350
|
+
done = result.done === true;
|
|
351
|
+
return result;
|
|
352
|
+
}
|
|
353
|
+
catch (error) {
|
|
354
|
+
closeQuietly();
|
|
355
|
+
throw error;
|
|
356
|
+
}
|
|
357
|
+
},
|
|
358
|
+
return(value) {
|
|
359
|
+
if (!done) {
|
|
360
|
+
done = true;
|
|
361
|
+
iterator.return?.(value);
|
|
362
|
+
}
|
|
363
|
+
return { done: true, value };
|
|
364
|
+
},
|
|
365
|
+
throw(error) {
|
|
366
|
+
// Not delegated to `iterator.throw`: it closes and rethrows the same error anyway, and
|
|
367
|
+
// delegating after the close below would run it against an iterator already closed.
|
|
368
|
+
closeQuietly();
|
|
369
|
+
throw error;
|
|
370
|
+
},
|
|
371
|
+
};
|
|
372
|
+
function closeQuietly() {
|
|
373
|
+
try {
|
|
374
|
+
wrapper.return();
|
|
375
|
+
}
|
|
376
|
+
catch {
|
|
377
|
+
// the error being propagated is the actionable one
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
return wrapper;
|
|
381
|
+
};
|
|
382
|
+
return range;
|
|
383
|
+
}
|
|
384
|
+
function closeWriteInstance(operation) {
|
|
385
|
+
if (operation && !operation.instanceClosed) {
|
|
386
|
+
operation.instanceClosed = true;
|
|
387
|
+
if (operation.writeGeneration)
|
|
388
|
+
operation.writeGeneration.closed = true;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
function validateWrite(operation, txnTime, transaction) {
|
|
392
|
+
const generation = operation.writeGeneration;
|
|
393
|
+
if (generation)
|
|
394
|
+
generation.internalWrites++;
|
|
395
|
+
try {
|
|
396
|
+
return operation.validate?.(txnTime, transaction);
|
|
397
|
+
}
|
|
398
|
+
finally {
|
|
399
|
+
if (generation)
|
|
400
|
+
generation.internalWrites--;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
300
403
|
function getAppliedWriteVersion(recordVersion, txnLogKey) {
|
|
301
404
|
return recordVersion == null ? txnLogKey : Math.min(recordVersion, txnLogKey);
|
|
302
405
|
}
|
|
@@ -342,6 +445,7 @@ class DatabaseTransaction {
|
|
|
342
445
|
this.#scopeOwned = options?.scopeOwned === true;
|
|
343
446
|
}
|
|
344
447
|
writes = []; // the set of writes to commit if the conditions are met
|
|
448
|
+
ownedWrites;
|
|
345
449
|
completions = []; // the set of outstanding async operations to complete
|
|
346
450
|
db;
|
|
347
451
|
transaction;
|
|
@@ -388,8 +492,8 @@ class DatabaseTransaction {
|
|
|
388
492
|
txn.commitPhaseTicks = 0;
|
|
389
493
|
}
|
|
390
494
|
}
|
|
391
|
-
|
|
392
|
-
|
|
495
|
+
rangeReadActive = false;
|
|
496
|
+
renewReadTimeout() {
|
|
393
497
|
// The limit is an IDLE limit. Writes always re-arm it (see addWrite), but reads only do so
|
|
394
498
|
// while no uncommitted writes are held: staged writes hold write intents that other writers'
|
|
395
499
|
// coordinated-retry commits park on, so a handler that wrote once and then only reads — an
|
|
@@ -402,6 +506,23 @@ class DatabaseTransaction {
|
|
|
402
506
|
if ((this.writes.length === 0 && !this.next) || this.open !== exports.TRANSACTION_STATE.OPEN || !this.hasPendingWrites()) {
|
|
403
507
|
this.timeout = Math.max(txnExpiration, this.timeoutBudget);
|
|
404
508
|
}
|
|
509
|
+
}
|
|
510
|
+
// Each engine keeps its own expiration; LMDBTransaction overrides this with its own.
|
|
511
|
+
renewIdleTimeout() {
|
|
512
|
+
this.timeout = Math.max(txnExpiration, this.timeoutBudget ?? 0);
|
|
513
|
+
}
|
|
514
|
+
// The links after this one wait for its native commit before their own commit() is entered; each
|
|
515
|
+
// hop starts with a full idle window and a stalled native commit is still bounded by one.
|
|
516
|
+
renewChainForNativeCommit() {
|
|
517
|
+
for (let txn = this; txn; txn = txn.next) {
|
|
518
|
+
if (txn.timedOut || txn.open === exports.TRANSACTION_STATE.CLOSED)
|
|
519
|
+
continue;
|
|
520
|
+
txn.renewIdleTimeout();
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
getReadTxn(disableSnapshot) {
|
|
524
|
+
this.readTxnRefCount = (this.readTxnRefCount || 0) + 1;
|
|
525
|
+
this.renewReadTimeout();
|
|
405
526
|
if (this.transaction) {
|
|
406
527
|
if (this.transaction.openTimer)
|
|
407
528
|
this.transaction.openTimer = 0;
|
|
@@ -434,6 +555,8 @@ class DatabaseTransaction {
|
|
|
434
555
|
// Monitor state is not ownership state: it stays with `trackedTxns.add` in getReadTxn().
|
|
435
556
|
attachOwnedTransaction(transaction) {
|
|
436
557
|
this.transaction = transaction;
|
|
558
|
+
readTransactionOwners.set(transaction, this);
|
|
559
|
+
this.rangeReadActive = false;
|
|
437
560
|
this.readTxnsUsed = 1;
|
|
438
561
|
this.baseReadRefConsumed = false;
|
|
439
562
|
this.handleOpenedAt = performance.now();
|
|
@@ -475,6 +598,7 @@ class DatabaseTransaction {
|
|
|
475
598
|
trackedTxns.delete(this);
|
|
476
599
|
this.endWriteSupervision();
|
|
477
600
|
this.transaction = null;
|
|
601
|
+
this.rangeReadActive = false;
|
|
478
602
|
this.readTxnsUsed = 0;
|
|
479
603
|
this.readTxnRefCount = 0;
|
|
480
604
|
this.handleOpenedAt = 0;
|
|
@@ -576,6 +700,7 @@ class DatabaseTransaction {
|
|
|
576
700
|
const index = this.writes.indexOf(operation);
|
|
577
701
|
if (index > -1)
|
|
578
702
|
this.writes[index] = null;
|
|
703
|
+
this.ownedWrites?.delete(operation);
|
|
579
704
|
if (operation.key === undefined)
|
|
580
705
|
return;
|
|
581
706
|
const writesForStore = this.writesByKey?.get(operation.store);
|
|
@@ -585,7 +710,7 @@ class DatabaseTransaction {
|
|
|
585
710
|
// Membership, not `stagedIn`, which every commit handler clears and so cannot tell a takeover from a
|
|
586
711
|
// write done in place; a prior already taken over must not become this transaction's basis again.
|
|
587
712
|
let prior = operation.priorWrite;
|
|
588
|
-
while (prior && !this.
|
|
713
|
+
while (prior && !this.ownedWrites?.has(prior))
|
|
589
714
|
prior = prior.priorWrite;
|
|
590
715
|
const tail = writesForStore.get(keyId);
|
|
591
716
|
if (tail === operation) {
|
|
@@ -619,10 +744,10 @@ class DatabaseTransaction {
|
|
|
619
744
|
const h = storeMap.get(keyId);
|
|
620
745
|
if (!h)
|
|
621
746
|
return undefined;
|
|
622
|
-
if (!h.
|
|
747
|
+
if (!h.isExpired())
|
|
623
748
|
return h;
|
|
624
|
-
// Prune released handles so they don't accumulate;
|
|
625
|
-
// would otherwise be seen as the holder and incorrectly granted access.
|
|
749
|
+
// Prune released/expired handles so they don't accumulate; a handle past its deadline checking
|
|
750
|
+
// re-entrancy would otherwise be seen as the holder and incorrectly granted access.
|
|
626
751
|
storeMap.delete(keyId);
|
|
627
752
|
return undefined;
|
|
628
753
|
}
|
|
@@ -684,11 +809,19 @@ class DatabaseTransaction {
|
|
|
684
809
|
// fire after a commit or abort, and routing it back here would revive a write this transaction
|
|
685
810
|
// already rolled back — whose blobs abort() has reclaimed. Cleared here, save() resolves the
|
|
686
811
|
// context's current transaction as it did before `stagedIn` existed.
|
|
687
|
-
for (const write of this.writes)
|
|
812
|
+
for (const write of this.writes) {
|
|
688
813
|
if (write?.stagedIn === this)
|
|
689
814
|
write.stagedIn = undefined;
|
|
815
|
+
if (write)
|
|
816
|
+
this.ownedWrites?.delete(write);
|
|
817
|
+
}
|
|
690
818
|
this.writes = [];
|
|
691
819
|
this.writesByKey = undefined;
|
|
820
|
+
// The commit-fence latch belongs to the discarded batch. A reused transaction that once staged
|
|
821
|
+
// a locked write would otherwise re-scan every write of every later unlocked batch. Assigned
|
|
822
|
+
// only when it was set, so an ordinary transaction never gains the property at all.
|
|
823
|
+
if (this.hasLeaseProtectedWrite)
|
|
824
|
+
this.hasLeaseProtectedWrite = false;
|
|
692
825
|
}
|
|
693
826
|
/**
|
|
694
827
|
* Drop this transaction's back-reference from its context once completed (commit or abort),
|
|
@@ -811,6 +944,7 @@ class DatabaseTransaction {
|
|
|
811
944
|
this.writeTick = monitorTick;
|
|
812
945
|
this.linkWrite(operation);
|
|
813
946
|
this.writes.push(operation);
|
|
947
|
+
(this.ownedWrites ??= new WeakSet()).add(operation);
|
|
814
948
|
operation.stagedIn = this;
|
|
815
949
|
// Hold this write back while any earlier same-key write has not run — out of staging order both
|
|
816
950
|
// diff against the pre-transaction record (harper#2211, DESIGN.md). The whole chain, not just the
|
|
@@ -841,16 +975,26 @@ class DatabaseTransaction {
|
|
|
841
975
|
const lockHandle = operation.lockHandle;
|
|
842
976
|
// Guard: a write staged through an expired or released lock handle must not land.
|
|
843
977
|
// The handle's lease timer already unlocked the native key; another holder may have taken it.
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
978
|
+
// isExpired() re-evaluates the deadline here rather than trusting the timer to have run: a
|
|
979
|
+
// holder whose event loop stalled past its lease would otherwise commit in the window between
|
|
980
|
+
// the deadline and its own timer callback, after peers had already granted the key onward.
|
|
981
|
+
//
|
|
982
|
+
// A RE-save is judged by the lease alone. `released` belongs to the first stage — a caller that
|
|
983
|
+
// unlocked and then saved is writing through a handle it gave back — but an operation already
|
|
984
|
+
// staged was staged while the lock was held, and an `unlock()` inside the lease leaves it valid
|
|
985
|
+
// (the same rule the pre-submit fence applies below). Without the distinction,
|
|
986
|
+
// `lock(); save(); unlock(); commit()` succeeded normally and threw 409 only when a conflict
|
|
987
|
+
// retry or an open read iterator forced the replay to re-save it.
|
|
988
|
+
if (operation.saved ? lockHandle?.isLeaseExpired() : lockHandle?.isExpired()) {
|
|
989
|
+
// Through `detachWrite`, which also repairs the per-key chain: dropping it from `writes` alone
|
|
990
|
+
// leaves `writesByKey` pointing at a write that was refused, so a caller that catches this 409
|
|
991
|
+
// and stages the same key again would take the rejected operation as its merge basis.
|
|
992
|
+
this.detachWrite(operation);
|
|
850
993
|
throw (0, recordLock_ts_1.lockNotHeldError)(lockHandle);
|
|
851
994
|
}
|
|
852
995
|
// Lock-write timestamp rules.
|
|
853
996
|
if (lockHandle) {
|
|
997
|
+
this.hasLeaseProtectedWrite = true;
|
|
854
998
|
if (this.open === exports.TRANSACTION_STATE.CLOSED || this.saveCommits) {
|
|
855
999
|
// CLOSED path (second+ write per ImmediateTransaction cycle) OR the first write in
|
|
856
1000
|
// an ImmediateTransaction (open=OPEN until commit sets it CLOSED, but saveCommits
|
|
@@ -910,21 +1054,44 @@ class DatabaseTransaction {
|
|
|
910
1054
|
}
|
|
911
1055
|
if (!txnTime)
|
|
912
1056
|
txnTime = this.timestamp = transaction.getTimestamp();
|
|
1057
|
+
if (!operation.saved && operation.pendingPriorWrite) {
|
|
1058
|
+
const pendingWrites = [];
|
|
1059
|
+
for (let pending = operation.pendingPriorWrite; pending;) {
|
|
1060
|
+
if (!pending.saved && this.ownedWrites?.has(pending))
|
|
1061
|
+
pendingWrites.push(pending);
|
|
1062
|
+
pending = pending.pendingPriorWrite !== undefined ? pending.pendingPriorWrite : pending.priorWrite;
|
|
1063
|
+
}
|
|
1064
|
+
for (let index = pendingWrites.length - 1; index >= 0; index--)
|
|
1065
|
+
this.save(pendingWrites[index], transaction, false, options);
|
|
1066
|
+
operation.pendingPriorWrite = null;
|
|
1067
|
+
}
|
|
913
1068
|
// `txnTime` is this transaction's timestamp — the key its entries take in the per-origin log.
|
|
914
1069
|
// A write applied from elsewhere carries the origin's record version too, and that is what the
|
|
915
1070
|
// record is stored at; the two coincide for every locally-originated write. Gated on the apply
|
|
916
1071
|
// flags so an ordinary write never reads the property (harper#2412).
|
|
917
1072
|
const writeVersion = this.sourceApply || this.isReplay ? getAppliedWriteVersion(operation.recordVersion, txnTime) : txnTime;
|
|
918
|
-
|
|
919
|
-
|
|
1073
|
+
// A base that feeds stored state must come from this transaction's snapshot, never the
|
|
1074
|
+
// cross-worker cache vouch (stale when a resequenced write reused a version). That closes the
|
|
1075
|
+
// lost-update window only when this transaction holds a snapshot to validate the later Put
|
|
1076
|
+
// against; a snapshot-free transaction (this.snapshotFree, after a mid-scope-commit rotation)
|
|
1077
|
+
// has no snapshot for rocksdb-js to validate the Put against, so it only narrows the window to
|
|
1078
|
+
// the read-to-put span rather than closing it (open follow-up, tracked in the PR description).
|
|
1079
|
+
// Replays keep their pre-read base — their convergence contract is the replay pass itself.
|
|
1080
|
+
const reloadsCommitBase = operation.reloadCommitBase && !operation.saved && !this.isReplay;
|
|
1081
|
+
if (reloadEntry || operation.entry === undefined || reloadsCommitBase) {
|
|
1082
|
+
const uncachedRead = (!!operation.reloadCommitBase && !this.isReplay) || reloadEntry;
|
|
1083
|
+
operation.entry = operation.store.getEntry(operation.key, { transaction, uncachedRead });
|
|
920
1084
|
}
|
|
921
1085
|
if (!operation.saved) {
|
|
922
|
-
operation.saved = true;
|
|
923
1086
|
// immediately execute in this transaction
|
|
924
|
-
|
|
1087
|
+
const validated = validateWrite(operation, writeVersion, this);
|
|
1088
|
+
if (validated === false) {
|
|
1089
|
+
operation.saved = true;
|
|
925
1090
|
operation.commit = () => { }; // noop if we try again
|
|
1091
|
+
closeWriteInstance(operation);
|
|
926
1092
|
return;
|
|
927
1093
|
}
|
|
1094
|
+
operation.saved = true;
|
|
928
1095
|
let result = operation.before?.();
|
|
929
1096
|
if (result?.then)
|
|
930
1097
|
this.stageCompletion(result);
|
|
@@ -936,7 +1103,13 @@ class DatabaseTransaction {
|
|
|
936
1103
|
operation.trackRecordVersion = true;
|
|
937
1104
|
if (operation.trackRecordVersion)
|
|
938
1105
|
operation.recordVersionApplied = false;
|
|
939
|
-
|
|
1106
|
+
let completion;
|
|
1107
|
+
try {
|
|
1108
|
+
completion = operation.commit(writeVersion, operation.entry, this.retries > 0, transaction);
|
|
1109
|
+
}
|
|
1110
|
+
finally {
|
|
1111
|
+
closeWriteInstance(operation);
|
|
1112
|
+
}
|
|
940
1113
|
if (operation.trackRecordVersion)
|
|
941
1114
|
operation.appliedRecordVersion = operation.recordVersionApplied ? writeVersion : undefined;
|
|
942
1115
|
if (typeof completion?.then === 'function')
|
|
@@ -1013,6 +1186,8 @@ class DatabaseTransaction {
|
|
|
1013
1186
|
// and replay branches below deliberately commit a handle other than this.transaction.
|
|
1014
1187
|
if (!transaction)
|
|
1015
1188
|
transaction = this.transaction;
|
|
1189
|
+
if (!options.transaction && this.writes.some((write) => write))
|
|
1190
|
+
this.renewChainForNativeCommit();
|
|
1016
1191
|
this.open = exports.TRANSACTION_STATE.CLOSED;
|
|
1017
1192
|
// RocksTransaction.commit() resolves with RETRY_NOW_VALUE (a number) under
|
|
1018
1193
|
// coordinatedRetry, or void on a normal commit/abort.
|
|
@@ -1096,6 +1271,33 @@ class DatabaseTransaction {
|
|
|
1096
1271
|
if (transaction) {
|
|
1097
1272
|
this.writes = this.writes.filter((write) => write); // filter out removed entries
|
|
1098
1273
|
if (this.writes.length > 0) {
|
|
1274
|
+
// Commit retries can construct fresh ranges on this live handle after read ownership ends.
|
|
1275
|
+
readTransactionOwners.delete(transaction);
|
|
1276
|
+
// Re-fence before submitting: the loop above skips operations already marked saved, so
|
|
1277
|
+
// save()'s own check cannot see a holder that stalled between staging and commit. The
|
|
1278
|
+
// retry/replay path re-saves every operation and is fenced there instead. Lease expiry
|
|
1279
|
+
// only: an unlock() inside the lease leaves the staged write valid, an elapsed lease
|
|
1280
|
+
// does not, whether or not the caller also unlocked.
|
|
1281
|
+
for (let i = 0; this.hasLeaseProtectedWrite && i < this.writes.length; i++) {
|
|
1282
|
+
const lapsed = this.writes[i].lockHandle;
|
|
1283
|
+
if (!lapsed?.isLeaseExpired())
|
|
1284
|
+
continue;
|
|
1285
|
+
try {
|
|
1286
|
+
transaction.abort();
|
|
1287
|
+
}
|
|
1288
|
+
catch { }
|
|
1289
|
+
// Every other terminal exit from commit() runs the logical cleanup too. Throwing
|
|
1290
|
+
// straight out would strand the OTHER locks this transaction holds, its staged
|
|
1291
|
+
// blobs, and the context's back-reference to a CLOSED transaction — and
|
|
1292
|
+
// transaction()'s onComplete has no rejection path to run it later.
|
|
1293
|
+
try {
|
|
1294
|
+
this.abort();
|
|
1295
|
+
}
|
|
1296
|
+
catch (error) {
|
|
1297
|
+
harperLogger.debug?.('cleaning up a transaction whose record lock lapsed', error);
|
|
1298
|
+
}
|
|
1299
|
+
throw (0, recordLock_ts_1.lockNotHeldError)(lapsed);
|
|
1300
|
+
}
|
|
1099
1301
|
// The transaction was created with coordinatedRetry:true (see
|
|
1100
1302
|
// getReadTxn), so commit() can resolve to RETRY_NOW_VALUE. That
|
|
1101
1303
|
// sentinel (a number) is why commitResolution is typed
|
|
@@ -1855,6 +2057,10 @@ function startMonitoringTxns() {
|
|
|
1855
2057
|
(0, longLivedTransactions_ts_1.finishLongLivedHolderReports)(reportBudget);
|
|
1856
2058
|
}, txnExpiration).unref();
|
|
1857
2059
|
function monitorTransaction(txn, checkedCommitPhaseChains, reportThresholdMs, reportNow, reportBudget) {
|
|
2060
|
+
if (txn.rangeReadActive) {
|
|
2061
|
+
txn.rangeReadActive = false;
|
|
2062
|
+
txn.renewReadTimeout();
|
|
2063
|
+
}
|
|
1858
2064
|
reportIfLongLived(txn, reportThresholdMs, reportNow, reportBudget);
|
|
1859
2065
|
{
|
|
1860
2066
|
const commitChainHead = txn.commitChainHead ?? txn;
|