@fluidframework/container-runtime 2.0.0-dev.4.1.0.148229 → 2.0.0-dev.4.3.0.157531
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/CHANGELOG.md +58 -0
- package/README.md +69 -0
- package/dist/blobManager.d.ts +6 -14
- package/dist/blobManager.d.ts.map +1 -1
- package/dist/blobManager.js +50 -37
- package/dist/blobManager.js.map +1 -1
- package/dist/containerRuntime.d.ts +47 -4
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +203 -49
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStoreContext.d.ts +2 -1
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +3 -0
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStores.d.ts +5 -5
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/dataStores.js +3 -6
- package/dist/dataStores.js.map +1 -1
- package/dist/gc/garbageCollection.d.ts.map +1 -1
- package/dist/gc/garbageCollection.js +5 -5
- package/dist/gc/garbageCollection.js.map +1 -1
- package/dist/gc/gcConfigs.d.ts.map +1 -1
- package/dist/gc/gcConfigs.js +1 -3
- package/dist/gc/gcConfigs.js.map +1 -1
- package/dist/gc/gcDefinitions.js +1 -1
- package/dist/gc/gcDefinitions.js.map +1 -1
- package/dist/gc/gcHelpers.d.ts.map +1 -1
- package/dist/gc/gcHelpers.js +6 -6
- package/dist/gc/gcHelpers.js.map +1 -1
- package/dist/id-compressor/appendOnlySortedMap.d.ts +146 -0
- package/dist/id-compressor/appendOnlySortedMap.d.ts.map +1 -0
- package/dist/id-compressor/appendOnlySortedMap.js +360 -0
- package/dist/id-compressor/appendOnlySortedMap.js.map +1 -0
- package/dist/id-compressor/idCompressor.d.ts +279 -0
- package/dist/id-compressor/idCompressor.d.ts.map +1 -0
- package/dist/id-compressor/idCompressor.js +1258 -0
- package/dist/id-compressor/idCompressor.js.map +1 -0
- package/dist/id-compressor/idRange.d.ts +11 -0
- package/dist/id-compressor/idRange.d.ts.map +1 -0
- package/dist/id-compressor/idRange.js +29 -0
- package/dist/id-compressor/idRange.js.map +1 -0
- package/dist/id-compressor/index.d.ts +14 -0
- package/dist/id-compressor/index.d.ts.map +1 -0
- package/dist/id-compressor/index.js +38 -0
- package/dist/id-compressor/index.js.map +1 -0
- package/dist/id-compressor/numericUuid.d.ts +59 -0
- package/dist/id-compressor/numericUuid.d.ts.map +1 -0
- package/dist/id-compressor/numericUuid.js +325 -0
- package/dist/id-compressor/numericUuid.js.map +1 -0
- package/dist/id-compressor/sessionIdNormalizer.d.ts +138 -0
- package/dist/id-compressor/sessionIdNormalizer.d.ts.map +1 -0
- package/dist/id-compressor/sessionIdNormalizer.js +488 -0
- package/dist/id-compressor/sessionIdNormalizer.js.map +1 -0
- package/dist/id-compressor/utils.d.ts +57 -0
- package/dist/id-compressor/utils.d.ts.map +1 -0
- package/dist/id-compressor/utils.js +90 -0
- package/dist/id-compressor/utils.js.map +1 -0
- package/dist/id-compressor/uuidUtilities.d.ts +30 -0
- package/dist/id-compressor/uuidUtilities.d.ts.map +1 -0
- package/dist/id-compressor/uuidUtilities.js +106 -0
- package/dist/id-compressor/uuidUtilities.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/opLifecycle/batchManager.d.ts +9 -2
- package/dist/opLifecycle/batchManager.d.ts.map +1 -1
- package/dist/opLifecycle/batchManager.js +21 -2
- package/dist/opLifecycle/batchManager.js.map +1 -1
- package/dist/opLifecycle/index.d.ts +2 -1
- package/dist/opLifecycle/index.d.ts.map +1 -1
- package/dist/opLifecycle/index.js +3 -1
- package/dist/opLifecycle/index.js.map +1 -1
- package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opDecompressor.js +2 -1
- package/dist/opLifecycle/opDecompressor.js.map +1 -1
- package/dist/opLifecycle/opGroupingManager.d.ts +14 -0
- package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -0
- package/dist/opLifecycle/opGroupingManager.js +61 -0
- package/dist/opLifecycle/opGroupingManager.js.map +1 -0
- package/dist/opLifecycle/opSplitter.d.ts +1 -1
- package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
- package/dist/opLifecycle/opSplitter.js +5 -6
- package/dist/opLifecycle/opSplitter.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts +4 -2
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +37 -25
- package/dist/opLifecycle/outbox.js.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.d.ts +4 -2
- package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.js +30 -20
- package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/pendingStateManager.d.ts +1 -1
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +11 -3
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/summary/index.d.ts +2 -2
- package/dist/summary/index.d.ts.map +1 -1
- package/dist/summary/index.js +4 -1
- package/dist/summary/index.js.map +1 -1
- package/dist/summary/orderedClientElection.d.ts +1 -0
- package/dist/summary/orderedClientElection.d.ts.map +1 -1
- package/dist/summary/orderedClientElection.js +19 -0
- package/dist/summary/orderedClientElection.js.map +1 -1
- package/dist/summary/runningSummarizer.d.ts +4 -3
- package/dist/summary/runningSummarizer.d.ts.map +1 -1
- package/dist/summary/runningSummarizer.js +65 -66
- package/dist/summary/runningSummarizer.js.map +1 -1
- package/dist/summary/summarizer.d.ts.map +1 -1
- package/dist/summary/summarizer.js +1 -5
- package/dist/summary/summarizer.js.map +1 -1
- package/dist/summary/summarizerHeuristics.d.ts +1 -0
- package/dist/summary/summarizerHeuristics.d.ts.map +1 -1
- package/dist/summary/summarizerHeuristics.js +3 -0
- package/dist/summary/summarizerHeuristics.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.js +1 -1
- package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +128 -2
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js +4 -3
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/dist/summary/summarizerTypes.d.ts +14 -2
- package/dist/summary/summarizerTypes.d.ts.map +1 -1
- package/dist/summary/summarizerTypes.js.map +1 -1
- package/dist/summary/summaryFormat.d.ts +3 -0
- package/dist/summary/summaryFormat.d.ts.map +1 -1
- package/dist/summary/summaryFormat.js +3 -1
- package/dist/summary/summaryFormat.js.map +1 -1
- package/dist/summary/summaryGenerator.d.ts +28 -2
- package/dist/summary/summaryGenerator.d.ts.map +1 -1
- package/dist/summary/summaryGenerator.js +19 -16
- package/dist/summary/summaryGenerator.js.map +1 -1
- package/dist/summary/summaryManager.d.ts.map +1 -1
- package/dist/summary/summaryManager.js +2 -0
- package/dist/summary/summaryManager.js.map +1 -1
- package/lib/blobManager.d.ts +6 -14
- package/lib/blobManager.d.ts.map +1 -1
- package/lib/blobManager.js +50 -37
- package/lib/blobManager.js.map +1 -1
- package/lib/containerRuntime.d.ts +47 -4
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +187 -52
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStoreContext.d.ts +2 -1
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +3 -0
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStores.d.ts +5 -5
- package/lib/dataStores.d.ts.map +1 -1
- package/lib/dataStores.js +3 -6
- package/lib/dataStores.js.map +1 -1
- package/lib/gc/garbageCollection.d.ts.map +1 -1
- package/lib/gc/garbageCollection.js +5 -5
- package/lib/gc/garbageCollection.js.map +1 -1
- package/lib/gc/gcConfigs.d.ts.map +1 -1
- package/lib/gc/gcConfigs.js +1 -3
- package/lib/gc/gcConfigs.js.map +1 -1
- package/lib/gc/gcDefinitions.js +1 -1
- package/lib/gc/gcDefinitions.js.map +1 -1
- package/lib/gc/gcHelpers.d.ts.map +1 -1
- package/lib/gc/gcHelpers.js +6 -6
- package/lib/gc/gcHelpers.js.map +1 -1
- package/lib/id-compressor/appendOnlySortedMap.d.ts +146 -0
- package/lib/id-compressor/appendOnlySortedMap.d.ts.map +1 -0
- package/lib/id-compressor/appendOnlySortedMap.js +355 -0
- package/lib/id-compressor/appendOnlySortedMap.js.map +1 -0
- package/lib/id-compressor/idCompressor.d.ts +279 -0
- package/lib/id-compressor/idCompressor.d.ts.map +1 -0
- package/lib/id-compressor/idCompressor.js +1248 -0
- package/lib/id-compressor/idCompressor.js.map +1 -0
- package/lib/id-compressor/idRange.d.ts +11 -0
- package/lib/id-compressor/idRange.d.ts.map +1 -0
- package/lib/id-compressor/idRange.js +25 -0
- package/lib/id-compressor/idRange.js.map +1 -0
- package/lib/id-compressor/index.d.ts +14 -0
- package/lib/id-compressor/index.d.ts.map +1 -0
- package/lib/id-compressor/index.js +14 -0
- package/lib/id-compressor/index.js.map +1 -0
- package/lib/id-compressor/numericUuid.d.ts +59 -0
- package/lib/id-compressor/numericUuid.d.ts.map +1 -0
- package/lib/id-compressor/numericUuid.js +315 -0
- package/lib/id-compressor/numericUuid.js.map +1 -0
- package/lib/id-compressor/sessionIdNormalizer.d.ts +138 -0
- package/lib/id-compressor/sessionIdNormalizer.d.ts.map +1 -0
- package/lib/id-compressor/sessionIdNormalizer.js +484 -0
- package/lib/id-compressor/sessionIdNormalizer.js.map +1 -0
- package/lib/id-compressor/utils.d.ts +57 -0
- package/lib/id-compressor/utils.d.ts.map +1 -0
- package/lib/id-compressor/utils.js +79 -0
- package/lib/id-compressor/utils.js.map +1 -0
- package/lib/id-compressor/uuidUtilities.d.ts +30 -0
- package/lib/id-compressor/uuidUtilities.d.ts.map +1 -0
- package/lib/id-compressor/uuidUtilities.js +98 -0
- package/lib/id-compressor/uuidUtilities.js.map +1 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/opLifecycle/batchManager.d.ts +9 -2
- package/lib/opLifecycle/batchManager.d.ts.map +1 -1
- package/lib/opLifecycle/batchManager.js +19 -1
- package/lib/opLifecycle/batchManager.js.map +1 -1
- package/lib/opLifecycle/index.d.ts +2 -1
- package/lib/opLifecycle/index.d.ts.map +1 -1
- package/lib/opLifecycle/index.js +1 -0
- package/lib/opLifecycle/index.js.map +1 -1
- package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/lib/opLifecycle/opDecompressor.js +2 -1
- package/lib/opLifecycle/opDecompressor.js.map +1 -1
- package/lib/opLifecycle/opGroupingManager.d.ts +14 -0
- package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -0
- package/lib/opLifecycle/opGroupingManager.js +57 -0
- package/lib/opLifecycle/opGroupingManager.js.map +1 -0
- package/lib/opLifecycle/opSplitter.d.ts +1 -1
- package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
- package/lib/opLifecycle/opSplitter.js +5 -6
- package/lib/opLifecycle/opSplitter.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts +4 -2
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.js +38 -26
- package/lib/opLifecycle/outbox.js.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.d.ts +4 -2
- package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.js +30 -20
- package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/pendingStateManager.d.ts +1 -1
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +11 -3
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/summary/index.d.ts +2 -2
- package/lib/summary/index.d.ts.map +1 -1
- package/lib/summary/index.js +2 -1
- package/lib/summary/index.js.map +1 -1
- package/lib/summary/orderedClientElection.d.ts +1 -0
- package/lib/summary/orderedClientElection.d.ts.map +1 -1
- package/lib/summary/orderedClientElection.js +19 -0
- package/lib/summary/orderedClientElection.js.map +1 -1
- package/lib/summary/runningSummarizer.d.ts +4 -3
- package/lib/summary/runningSummarizer.d.ts.map +1 -1
- package/lib/summary/runningSummarizer.js +65 -66
- package/lib/summary/runningSummarizer.js.map +1 -1
- package/lib/summary/summarizer.d.ts.map +1 -1
- package/lib/summary/summarizer.js +1 -5
- package/lib/summary/summarizer.js.map +1 -1
- package/lib/summary/summarizerHeuristics.d.ts +1 -0
- package/lib/summary/summarizerHeuristics.d.ts.map +1 -1
- package/lib/summary/summarizerHeuristics.js +3 -0
- package/lib/summary/summarizerHeuristics.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.js +1 -1
- package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +128 -2
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js +3 -3
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/lib/summary/summarizerTypes.d.ts +14 -2
- package/lib/summary/summarizerTypes.d.ts.map +1 -1
- package/lib/summary/summarizerTypes.js.map +1 -1
- package/lib/summary/summaryFormat.d.ts +3 -0
- package/lib/summary/summaryFormat.d.ts.map +1 -1
- package/lib/summary/summaryFormat.js +2 -0
- package/lib/summary/summaryFormat.js.map +1 -1
- package/lib/summary/summaryGenerator.d.ts +28 -2
- package/lib/summary/summaryGenerator.d.ts.map +1 -1
- package/lib/summary/summaryGenerator.js +17 -15
- package/lib/summary/summaryGenerator.js.map +1 -1
- package/lib/summary/summaryManager.d.ts.map +1 -1
- package/lib/summary/summaryManager.js +2 -0
- package/lib/summary/summaryManager.js.map +1 -1
- package/package.json +29 -17
- package/src/blobManager.ts +64 -41
- package/src/containerRuntime.ts +294 -65
- package/src/dataStoreContext.ts +6 -0
- package/src/dataStores.ts +4 -7
- package/src/gc/garbageCollection.ts +7 -6
- package/src/gc/gcConfigs.ts +1 -3
- package/src/gc/gcDefinitions.ts +1 -1
- package/src/gc/gcHelpers.ts +9 -6
- package/src/id-compressor/README.md +3 -0
- package/src/id-compressor/appendOnlySortedMap.ts +427 -0
- package/src/id-compressor/idCompressor.ts +1854 -0
- package/src/id-compressor/idRange.ts +35 -0
- package/src/id-compressor/index.ts +35 -0
- package/src/id-compressor/numericUuid.ts +383 -0
- package/src/id-compressor/sessionIdNormalizer.ts +609 -0
- package/src/id-compressor/utils.ts +114 -0
- package/src/id-compressor/uuidUtilities.ts +123 -0
- package/src/index.ts +1 -0
- package/src/opLifecycle/README.md +119 -0
- package/src/opLifecycle/batchManager.ts +35 -2
- package/src/opLifecycle/index.ts +2 -1
- package/src/opLifecycle/opDecompressor.ts +1 -0
- package/src/opLifecycle/opGroupingManager.ts +82 -0
- package/src/opLifecycle/opSplitter.ts +1 -5
- package/src/opLifecycle/outbox.ts +64 -26
- package/src/opLifecycle/remoteMessageProcessor.ts +38 -22
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +21 -7
- package/src/summary/index.ts +2 -1
- package/src/summary/orderedClientElection.ts +17 -1
- package/src/summary/runningSummarizer.ts +78 -77
- package/src/summary/summarizer.ts +0 -8
- package/src/summary/summarizerHeuristics.ts +4 -0
- package/src/summary/summarizerNode/summarizerNode.ts +1 -1
- package/src/summary/summarizerNode/summarizerNodeWithGc.ts +3 -3
- package/src/summary/summarizerTypes.ts +20 -3
- package/src/summary/summaryFormat.ts +4 -0
- package/src/summary/summaryGenerator.ts +22 -16
- package/src/summary/summaryManager.ts +2 -0
package/dist/gc/gcHelpers.js
CHANGED
|
@@ -124,7 +124,7 @@ function concatGarbageCollectionStates(gcState1, gcState2) {
|
|
|
124
124
|
// Validate that same node doesn't have different unreferenced timestamp.
|
|
125
125
|
if (nodeData.unreferencedTimestampMs !== undefined &&
|
|
126
126
|
combineNodeData.unreferencedTimestampMs !== undefined) {
|
|
127
|
-
(0, common_utils_1.assert)(nodeData.unreferencedTimestampMs === combineNodeData.unreferencedTimestampMs,
|
|
127
|
+
(0, common_utils_1.assert)(nodeData.unreferencedTimestampMs === combineNodeData.unreferencedTimestampMs, 0x5d7 /* Two entries for the same GC node with different unreferenced timestamp */);
|
|
128
128
|
}
|
|
129
129
|
combineNodeData = {
|
|
130
130
|
outboundRoutes: [
|
|
@@ -198,7 +198,7 @@ async function getGCDataFromSnapshot(gcSnapshotTree, readAndParseBlob) {
|
|
|
198
198
|
continue;
|
|
199
199
|
}
|
|
200
200
|
const gcState = await readAndParseBlob(blobId);
|
|
201
|
-
(0, common_utils_1.assert)(gcState !== undefined,
|
|
201
|
+
(0, common_utils_1.assert)(gcState !== undefined, 0x5d8 /* GC blob missing from snapshot */);
|
|
202
202
|
// Merge the GC state of this blob into the root GC state.
|
|
203
203
|
rootGCState = concatGarbageCollectionStates(rootGCState, gcState);
|
|
204
204
|
}
|
|
@@ -222,7 +222,7 @@ function unpackChildNodesGCDetails(gcDetails) {
|
|
|
222
222
|
if (id === "/") {
|
|
223
223
|
continue;
|
|
224
224
|
}
|
|
225
|
-
(0, common_utils_1.assert)(id.startsWith("/"),
|
|
225
|
+
(0, common_utils_1.assert)(id.startsWith("/"), 0x5d9 /* node id should always be an absolute route */);
|
|
226
226
|
const childId = id.split("/")[1];
|
|
227
227
|
let childGCNodeId = id.slice(childId.length + 1);
|
|
228
228
|
// GC node id always begins with "/". Handle the special case where a child's id in the parent's GC nodes is
|
|
@@ -235,7 +235,7 @@ function unpackChildNodesGCDetails(gcDetails) {
|
|
|
235
235
|
childGCDetails = { gcData: { gcNodes: {} }, usedRoutes: [] };
|
|
236
236
|
}
|
|
237
237
|
// gcData should not undefined as its always at least initialized as empty above.
|
|
238
|
-
(0, common_utils_1.assert)(childGCDetails.gcData !== undefined,
|
|
238
|
+
(0, common_utils_1.assert)(childGCDetails.gcData !== undefined, 0x5da /* Child GC data should have been initialized */);
|
|
239
239
|
childGCDetails.gcData.gcNodes[childGCNodeId] = [...new Set(outboundRoutes)];
|
|
240
240
|
childGCDetailsMap.set(childId, childGCDetails);
|
|
241
241
|
}
|
|
@@ -245,11 +245,11 @@ function unpackChildNodesGCDetails(gcDetails) {
|
|
|
245
245
|
// Remove the node's self used route, if any, and generate the children used routes.
|
|
246
246
|
const usedRoutes = gcDetails.usedRoutes.filter((route) => route !== "" && route !== "/");
|
|
247
247
|
for (const route of usedRoutes) {
|
|
248
|
-
(0, common_utils_1.assert)(route.startsWith("/"),
|
|
248
|
+
(0, common_utils_1.assert)(route.startsWith("/"), 0x5db /* Used route should always be an absolute route */);
|
|
249
249
|
const childId = route.split("/")[1];
|
|
250
250
|
const childUsedRoute = route.slice(childId.length + 1);
|
|
251
251
|
const childGCDetails = childGCDetailsMap.get(childId);
|
|
252
|
-
(0, common_utils_1.assert)((childGCDetails === null || childGCDetails === void 0 ? void 0 : childGCDetails.usedRoutes) !== undefined,
|
|
252
|
+
(0, common_utils_1.assert)((childGCDetails === null || childGCDetails === void 0 ? void 0 : childGCDetails.usedRoutes) !== undefined, 0x5dc /* This should have be initialized when generate GC nodes above */);
|
|
253
253
|
childGCDetails.usedRoutes.push(childUsedRoute);
|
|
254
254
|
childGCDetailsMap.set(childId, childGCDetails);
|
|
255
255
|
}
|
package/dist/gc/gcHelpers.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gcHelpers.js","sourceRoot":"","sources":["../../src/gc/gcHelpers.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryGenericEvent } from \"@fluidframework/common-definitions\";\nimport { assert } from \"@fluidframework/common-utils\";\nimport { ISnapshotTree } from \"@fluidframework/protocol-definitions\";\nimport {\n\tgcBlobPrefix,\n\tgcDeletedBlobKey,\n\tgcTombstoneBlobKey,\n\tIGarbageCollectionData,\n\tIGarbageCollectionDetailsBase,\n} from \"@fluidframework/runtime-definitions\";\nimport { packagePathToTelemetryProperty } from \"@fluidframework/runtime-utils\";\nimport { MonitoringContext } from \"@fluidframework/telemetry-utils\";\nimport {\n\tdisableTombstoneKey,\n\tGCFeatureMatrix,\n\tGCVersion,\n\tIGCMetadata,\n\trunSweepKey,\n\tthrowOnTombstoneLoadKey,\n\tthrowOnTombstoneUsageKey,\n} from \"./gcDefinitions\";\nimport {\n\tIGarbageCollectionNodeData,\n\tIGarbageCollectionSnapshotData,\n\tIGarbageCollectionState,\n} from \"./gcSummaryDefinitions\";\n\nexport function getGCVersion(metadata?: IGCMetadata): GCVersion {\n\tif (!metadata) {\n\t\t// Force to 0/disallowed in prior versions\n\t\treturn 0;\n\t}\n\treturn metadata.gcFeature ?? 0;\n}\n\n/**\n * Consolidates info / logic for logging when we encounter unexpected usage of GC'd objects. For example, when a\n * tombstoned or deleted object is loaded.\n */\nexport function sendGCUnexpectedUsageEvent(\n\tmc: MonitoringContext,\n\tevent: ITelemetryGenericEvent & {\n\t\tcategory: \"error\" | \"generic\";\n\t\tgcTombstoneEnforcementAllowed: boolean | undefined;\n\t},\n\tpackagePath: readonly string[] | undefined,\n\terror?: unknown,\n) {\n\tevent.pkg = packagePathToTelemetryProperty(packagePath);\n\tevent.tombstoneFlags = JSON.stringify({\n\t\tDisableTombstone: mc.config.getBoolean(disableTombstoneKey),\n\t\tThrowOnTombstoneUsage: mc.config.getBoolean(throwOnTombstoneUsageKey),\n\t\tThrowOnTombstoneLoad: mc.config.getBoolean(throwOnTombstoneLoadKey),\n\t});\n\tevent.sweepFlags = JSON.stringify({\n\t\tEnableSweepFlag: mc.config.getBoolean(runSweepKey),\n\t});\n\n\tmc.logger.sendTelemetryEvent(event, error);\n}\n\n/**\n * Indicates whether Tombstone Enforcement is allowed for this document based on the current/persisted\n * TombstoneGeneration values\n *\n * In order to protect old documents that were created at a time when known bugs exist that violate GC's invariants\n * such that enforcing GC Tombstone (Failing on Tombstone load/usage) would cause legitimate data loss,\n * the container author may increment the generation value for Tombstone such that containers created\n * with a different value will not be subjected to GC enforcement.\n *\n * If no generation is provided at runtime, this defaults to return true to maintain expected default behavior\n *\n * @param persistedGeneration - The persisted tombstoneGeneration value\n * @param currentGeneration - The current app-provided tombstoneGeneration value\n * @returns true if GC Tombstone enforcement (Fail on Tombstone load/usage) should be allowed for this document\n */\nexport function shouldAllowGcTombstoneEnforcement(\n\tpersistedGeneration: number | undefined,\n\tcurrentGeneration: number | undefined,\n): boolean {\n\t// If no Generation value is provided for this session, then we should default to letting Tombstone feature behave as intended.\n\tif (currentGeneration === undefined) {\n\t\treturn true;\n\t}\n\treturn persistedGeneration === currentGeneration;\n}\n\n/**\n * Indicates whether Sweep is allowed for this document based on the GC Feature Matrix and current SweepGeneration\n *\n * In order to protect old documents that were created at a time when known bugs exist that violate GC's invariants\n * such that enforcing GC Sweep would cause legitimate data loss, the container author may increment the generation value for Sweep\n * such that containers created with a different value will not be subjected to GC Sweep.\n *\n * If no generation is provided, Sweep will be disabled.\n * Passing 0 is a special case: Sweep will be enabled for any document with gcSweepGeneration OR gcTombstoneGeneration as 0.\n *\n * @param persistedGenerations - The persisted sweep/tombstone generations from the GC Feature Matrix\n * @param currentGeneration - The current app-provided sweepGeneration value\n * @returns true if GC Sweep should be allowed for this document\n */\nexport function shouldAllowGcSweep(\n\tpersistedGenerations: Pick<GCFeatureMatrix, \"sweepGeneration\" | \"tombstoneGeneration\">,\n\tcurrentGeneration: number | undefined,\n): boolean {\n\t// If no Generation value is provided for this session, default to false\n\tif (currentGeneration === undefined) {\n\t\treturn false;\n\t}\n\n\t// 0 is a special case: It matches both SweepGeneration and TombstoneGeneration\n\t// This is an optimistic measure to maximize coverage of GC Sweep if no bumps to TombstoneGeneration are needed before enabling Sweep.\n\tif (currentGeneration === 0) {\n\t\treturn (\n\t\t\tpersistedGenerations.sweepGeneration === 0 ||\n\t\t\tpersistedGenerations.tombstoneGeneration === 0\n\t\t);\n\t}\n\n\treturn persistedGenerations.sweepGeneration === currentGeneration;\n}\n\n/**\n * Sorts the given GC state as per the id of the GC nodes. It also sorts the outbound routes array of each node.\n */\nexport function generateSortedGCState(gcState: IGarbageCollectionState): IGarbageCollectionState {\n\tconst sortableArray: [string, IGarbageCollectionNodeData][] = Object.entries(gcState.gcNodes);\n\tsortableArray.sort(([a], [b]) => a.localeCompare(b));\n\tconst sortedGCState: IGarbageCollectionState = { gcNodes: {} };\n\tfor (const [nodeId, nodeData] of sortableArray) {\n\t\tnodeData.outboundRoutes.sort();\n\t\tsortedGCState.gcNodes[nodeId] = nodeData;\n\t}\n\treturn sortedGCState;\n}\n\n/**\n * Concatenates the given GC states and returns the concatenated GC state.\n */\nexport function concatGarbageCollectionStates(\n\tgcState1: IGarbageCollectionState,\n\tgcState2: IGarbageCollectionState,\n): IGarbageCollectionState {\n\tconst combinedGCNodes: { [id: string]: IGarbageCollectionNodeData } = {};\n\tfor (const [nodeId, nodeData] of Object.entries(gcState1.gcNodes)) {\n\t\tcombinedGCNodes[nodeId] = {\n\t\t\toutboundRoutes: Array.from(nodeData.outboundRoutes),\n\t\t\tunreferencedTimestampMs: nodeData.unreferencedTimestampMs,\n\t\t};\n\t}\n\n\tfor (const [nodeId, nodeData] of Object.entries(gcState2.gcNodes)) {\n\t\tlet combineNodeData = combinedGCNodes[nodeId];\n\t\tif (combineNodeData === undefined) {\n\t\t\tcombineNodeData = {\n\t\t\t\toutboundRoutes: Array.from(nodeData.outboundRoutes),\n\t\t\t\tunreferencedTimestampMs: nodeData.unreferencedTimestampMs,\n\t\t\t};\n\t\t} else {\n\t\t\t// Validate that same node doesn't have different unreferenced timestamp.\n\t\t\tif (\n\t\t\t\tnodeData.unreferencedTimestampMs !== undefined &&\n\t\t\t\tcombineNodeData.unreferencedTimestampMs !== undefined\n\t\t\t) {\n\t\t\t\tassert(\n\t\t\t\t\tnodeData.unreferencedTimestampMs === combineNodeData.unreferencedTimestampMs,\n\t\t\t\t\t\"Two entries for the same GC node with different unreferenced timestamp\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tcombineNodeData = {\n\t\t\t\toutboundRoutes: [\n\t\t\t\t\t...new Set([...nodeData.outboundRoutes, ...combineNodeData.outboundRoutes]),\n\t\t\t\t],\n\t\t\t\tunreferencedTimestampMs:\n\t\t\t\t\tnodeData.unreferencedTimestampMs ?? combineNodeData.unreferencedTimestampMs,\n\t\t\t};\n\t\t}\n\t\tcombinedGCNodes[nodeId] = combineNodeData;\n\t}\n\treturn { gcNodes: combinedGCNodes };\n}\n\n/**\n * Helper function that clones the GC data.\n * @param gcData - The GC data to clone.\n * @returns a clone of the given GC data.\n */\nexport function cloneGCData(gcData: IGarbageCollectionData): IGarbageCollectionData {\n\tconst clonedGCNodes: { [id: string]: string[] } = {};\n\tfor (const [id, outboundRoutes] of Object.entries(gcData.gcNodes)) {\n\t\tclonedGCNodes[id] = Array.from(outboundRoutes);\n\t}\n\treturn {\n\t\tgcNodes: clonedGCNodes,\n\t};\n}\n\n/**\n * Concatenates the given GC data and returns the concatenated GC data.\n */\nexport function concatGarbageCollectionData(\n\tgcData1: IGarbageCollectionData,\n\tgcData2: IGarbageCollectionData,\n) {\n\tconst combinedGCData: IGarbageCollectionData = cloneGCData(gcData1);\n\tfor (const [id, routes] of Object.entries(gcData2.gcNodes)) {\n\t\tif (combinedGCData.gcNodes[id] === undefined) {\n\t\t\tcombinedGCData.gcNodes[id] = Array.from(routes);\n\t\t} else {\n\t\t\tconst combinedRoutes = [...routes, ...combinedGCData.gcNodes[id]];\n\t\t\tcombinedGCData.gcNodes[id] = [...new Set(combinedRoutes)];\n\t\t}\n\t}\n\treturn combinedGCData;\n}\n\n/**\n * Gets the base garbage collection state from the given snapshot tree. It contains GC state, deleted nodes and\n * tombstones. The GC state may be written into multiple blobs. Merge the GC state from all such blobs into one.\n */\nexport async function getGCDataFromSnapshot(\n\tgcSnapshotTree: ISnapshotTree,\n\treadAndParseBlob: <T>(id: string) => Promise<T>,\n): Promise<IGarbageCollectionSnapshotData> {\n\tlet rootGCState: IGarbageCollectionState = { gcNodes: {} };\n\tlet tombstones: string[] | undefined;\n\tlet deletedNodes: string[] | undefined;\n\tfor (const key of Object.keys(gcSnapshotTree.blobs)) {\n\t\t// Update deleted nodes blob.\n\t\tif (key === gcDeletedBlobKey) {\n\t\t\tdeletedNodes = await readAndParseBlob<string[]>(gcSnapshotTree.blobs[key]);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Update tombstone blob.\n\t\tif (key === gcTombstoneBlobKey) {\n\t\t\ttombstones = await readAndParseBlob<string[]>(gcSnapshotTree.blobs[key]);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Skip blobs that do not start with the GC prefix.\n\t\tif (!key.startsWith(gcBlobPrefix)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst blobId = gcSnapshotTree.blobs[key];\n\t\tif (blobId === undefined) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst gcState = await readAndParseBlob<IGarbageCollectionState>(blobId);\n\t\tassert(gcState !== undefined, \"GC blob missing from snapshot\");\n\t\t// Merge the GC state of this blob into the root GC state.\n\t\trootGCState = concatGarbageCollectionStates(rootGCState, gcState);\n\t}\n\treturn { gcState: rootGCState, tombstones, deletedNodes };\n}\n\n/**\n * Helper function that unpacks the GC details of the children from a given node's GC details.\n * @param gcDetails - The GC details of a node.\n * @returns A map of GC details of each children of the the given node.\n */\nexport function unpackChildNodesGCDetails(gcDetails: IGarbageCollectionDetailsBase) {\n\tconst childGCDetailsMap: Map<string, IGarbageCollectionDetailsBase> = new Map();\n\n\t// If GC data is not available, bail out.\n\tif (gcDetails.gcData === undefined) {\n\t\treturn childGCDetailsMap;\n\t}\n\n\tconst gcNodes = gcDetails.gcData.gcNodes;\n\tfor (const [id, outboundRoutes] of Object.entries(gcNodes)) {\n\t\t// Skip self-node since only children GC data is to be generated.\n\t\tif (id === \"/\") {\n\t\t\tcontinue;\n\t\t}\n\n\t\tassert(id.startsWith(\"/\"), \"node id should always be an absolute route\");\n\t\tconst childId = id.split(\"/\")[1];\n\t\tlet childGCNodeId = id.slice(childId.length + 1);\n\t\t// GC node id always begins with \"/\". Handle the special case where a child's id in the parent's GC nodes is\n\t\t// of format `/root`. In this case, the childId is root and childGCNodeId is \"\". Make childGCNodeId = \"/\".\n\t\tif (childGCNodeId === \"\") {\n\t\t\tchildGCNodeId = \"/\";\n\t\t}\n\n\t\tlet childGCDetails = childGCDetailsMap.get(childId);\n\t\tif (childGCDetails === undefined) {\n\t\t\tchildGCDetails = { gcData: { gcNodes: {} }, usedRoutes: [] };\n\t\t}\n\t\t// gcData should not undefined as its always at least initialized as empty above.\n\t\tassert(childGCDetails.gcData !== undefined, \"Child GC data should have been initialized\");\n\t\tchildGCDetails.gcData.gcNodes[childGCNodeId] = [...new Set(outboundRoutes)];\n\t\tchildGCDetailsMap.set(childId, childGCDetails);\n\t}\n\n\tif (gcDetails.usedRoutes === undefined) {\n\t\treturn childGCDetailsMap;\n\t}\n\n\t// Remove the node's self used route, if any, and generate the children used routes.\n\tconst usedRoutes = gcDetails.usedRoutes.filter((route) => route !== \"\" && route !== \"/\");\n\tfor (const route of usedRoutes) {\n\t\tassert(route.startsWith(\"/\"), \"Used route should always be an absolute route\");\n\t\tconst childId = route.split(\"/\")[1];\n\t\tconst childUsedRoute = route.slice(childId.length + 1);\n\n\t\tconst childGCDetails = childGCDetailsMap.get(childId);\n\t\tassert(\n\t\t\tchildGCDetails?.usedRoutes !== undefined,\n\t\t\t\"This should have be initialized when generate GC nodes above\",\n\t\t);\n\n\t\tchildGCDetails.usedRoutes.push(childUsedRoute);\n\t\tchildGCDetailsMap.set(childId, childGCDetails);\n\t}\n\treturn childGCDetailsMap;\n}\n\n/**\n * Trims the leading and trailing slashes from the given string.\n * @param str - A string that may contain leading and / or trailing slashes.\n * @returns A new string without leading and trailing slashes.\n */\nexport function trimLeadingAndTrailingSlashes(str: string) {\n\treturn str.replace(/^\\/+|\\/+$/g, \"\");\n}\n"]}
|
|
1
|
+
{"version":3,"file":"gcHelpers.js","sourceRoot":"","sources":["../../src/gc/gcHelpers.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryGenericEvent } from \"@fluidframework/common-definitions\";\nimport { assert } from \"@fluidframework/common-utils\";\nimport { ISnapshotTree } from \"@fluidframework/protocol-definitions\";\nimport {\n\tgcBlobPrefix,\n\tgcDeletedBlobKey,\n\tgcTombstoneBlobKey,\n\tIGarbageCollectionData,\n\tIGarbageCollectionDetailsBase,\n} from \"@fluidframework/runtime-definitions\";\nimport { packagePathToTelemetryProperty } from \"@fluidframework/runtime-utils\";\nimport { MonitoringContext } from \"@fluidframework/telemetry-utils\";\nimport {\n\tdisableTombstoneKey,\n\tGCFeatureMatrix,\n\tGCVersion,\n\tIGCMetadata,\n\trunSweepKey,\n\tthrowOnTombstoneLoadKey,\n\tthrowOnTombstoneUsageKey,\n} from \"./gcDefinitions\";\nimport {\n\tIGarbageCollectionNodeData,\n\tIGarbageCollectionSnapshotData,\n\tIGarbageCollectionState,\n} from \"./gcSummaryDefinitions\";\n\nexport function getGCVersion(metadata?: IGCMetadata): GCVersion {\n\tif (!metadata) {\n\t\t// Force to 0/disallowed in prior versions\n\t\treturn 0;\n\t}\n\treturn metadata.gcFeature ?? 0;\n}\n\n/**\n * Consolidates info / logic for logging when we encounter unexpected usage of GC'd objects. For example, when a\n * tombstoned or deleted object is loaded.\n */\nexport function sendGCUnexpectedUsageEvent(\n\tmc: MonitoringContext,\n\tevent: ITelemetryGenericEvent & {\n\t\tcategory: \"error\" | \"generic\";\n\t\tgcTombstoneEnforcementAllowed: boolean | undefined;\n\t},\n\tpackagePath: readonly string[] | undefined,\n\terror?: unknown,\n) {\n\tevent.pkg = packagePathToTelemetryProperty(packagePath);\n\tevent.tombstoneFlags = JSON.stringify({\n\t\tDisableTombstone: mc.config.getBoolean(disableTombstoneKey),\n\t\tThrowOnTombstoneUsage: mc.config.getBoolean(throwOnTombstoneUsageKey),\n\t\tThrowOnTombstoneLoad: mc.config.getBoolean(throwOnTombstoneLoadKey),\n\t});\n\tevent.sweepFlags = JSON.stringify({\n\t\tEnableSweepFlag: mc.config.getBoolean(runSweepKey),\n\t});\n\n\tmc.logger.sendTelemetryEvent(event, error);\n}\n\n/**\n * Indicates whether Tombstone Enforcement is allowed for this document based on the current/persisted\n * TombstoneGeneration values\n *\n * In order to protect old documents that were created at a time when known bugs exist that violate GC's invariants\n * such that enforcing GC Tombstone (Failing on Tombstone load/usage) would cause legitimate data loss,\n * the container author may increment the generation value for Tombstone such that containers created\n * with a different value will not be subjected to GC enforcement.\n *\n * If no generation is provided at runtime, this defaults to return true to maintain expected default behavior\n *\n * @param persistedGeneration - The persisted tombstoneGeneration value\n * @param currentGeneration - The current app-provided tombstoneGeneration value\n * @returns true if GC Tombstone enforcement (Fail on Tombstone load/usage) should be allowed for this document\n */\nexport function shouldAllowGcTombstoneEnforcement(\n\tpersistedGeneration: number | undefined,\n\tcurrentGeneration: number | undefined,\n): boolean {\n\t// If no Generation value is provided for this session, then we should default to letting Tombstone feature behave as intended.\n\tif (currentGeneration === undefined) {\n\t\treturn true;\n\t}\n\treturn persistedGeneration === currentGeneration;\n}\n\n/**\n * Indicates whether Sweep is allowed for this document based on the GC Feature Matrix and current SweepGeneration\n *\n * In order to protect old documents that were created at a time when known bugs exist that violate GC's invariants\n * such that enforcing GC Sweep would cause legitimate data loss, the container author may increment the generation value for Sweep\n * such that containers created with a different value will not be subjected to GC Sweep.\n *\n * If no generation is provided, Sweep will be disabled.\n * Passing 0 is a special case: Sweep will be enabled for any document with gcSweepGeneration OR gcTombstoneGeneration as 0.\n *\n * @param persistedGenerations - The persisted sweep/tombstone generations from the GC Feature Matrix\n * @param currentGeneration - The current app-provided sweepGeneration value\n * @returns true if GC Sweep should be allowed for this document\n */\nexport function shouldAllowGcSweep(\n\tpersistedGenerations: Pick<GCFeatureMatrix, \"sweepGeneration\" | \"tombstoneGeneration\">,\n\tcurrentGeneration: number | undefined,\n): boolean {\n\t// If no Generation value is provided for this session, default to false\n\tif (currentGeneration === undefined) {\n\t\treturn false;\n\t}\n\n\t// 0 is a special case: It matches both SweepGeneration and TombstoneGeneration\n\t// This is an optimistic measure to maximize coverage of GC Sweep if no bumps to TombstoneGeneration are needed before enabling Sweep.\n\tif (currentGeneration === 0) {\n\t\treturn (\n\t\t\tpersistedGenerations.sweepGeneration === 0 ||\n\t\t\tpersistedGenerations.tombstoneGeneration === 0\n\t\t);\n\t}\n\n\treturn persistedGenerations.sweepGeneration === currentGeneration;\n}\n\n/**\n * Sorts the given GC state as per the id of the GC nodes. It also sorts the outbound routes array of each node.\n */\nexport function generateSortedGCState(gcState: IGarbageCollectionState): IGarbageCollectionState {\n\tconst sortableArray: [string, IGarbageCollectionNodeData][] = Object.entries(gcState.gcNodes);\n\tsortableArray.sort(([a], [b]) => a.localeCompare(b));\n\tconst sortedGCState: IGarbageCollectionState = { gcNodes: {} };\n\tfor (const [nodeId, nodeData] of sortableArray) {\n\t\tnodeData.outboundRoutes.sort();\n\t\tsortedGCState.gcNodes[nodeId] = nodeData;\n\t}\n\treturn sortedGCState;\n}\n\n/**\n * Concatenates the given GC states and returns the concatenated GC state.\n */\nexport function concatGarbageCollectionStates(\n\tgcState1: IGarbageCollectionState,\n\tgcState2: IGarbageCollectionState,\n): IGarbageCollectionState {\n\tconst combinedGCNodes: { [id: string]: IGarbageCollectionNodeData } = {};\n\tfor (const [nodeId, nodeData] of Object.entries(gcState1.gcNodes)) {\n\t\tcombinedGCNodes[nodeId] = {\n\t\t\toutboundRoutes: Array.from(nodeData.outboundRoutes),\n\t\t\tunreferencedTimestampMs: nodeData.unreferencedTimestampMs,\n\t\t};\n\t}\n\n\tfor (const [nodeId, nodeData] of Object.entries(gcState2.gcNodes)) {\n\t\tlet combineNodeData = combinedGCNodes[nodeId];\n\t\tif (combineNodeData === undefined) {\n\t\t\tcombineNodeData = {\n\t\t\t\toutboundRoutes: Array.from(nodeData.outboundRoutes),\n\t\t\t\tunreferencedTimestampMs: nodeData.unreferencedTimestampMs,\n\t\t\t};\n\t\t} else {\n\t\t\t// Validate that same node doesn't have different unreferenced timestamp.\n\t\t\tif (\n\t\t\t\tnodeData.unreferencedTimestampMs !== undefined &&\n\t\t\t\tcombineNodeData.unreferencedTimestampMs !== undefined\n\t\t\t) {\n\t\t\t\tassert(\n\t\t\t\t\tnodeData.unreferencedTimestampMs === combineNodeData.unreferencedTimestampMs,\n\t\t\t\t\t0x5d7 /* Two entries for the same GC node with different unreferenced timestamp */,\n\t\t\t\t);\n\t\t\t}\n\t\t\tcombineNodeData = {\n\t\t\t\toutboundRoutes: [\n\t\t\t\t\t...new Set([...nodeData.outboundRoutes, ...combineNodeData.outboundRoutes]),\n\t\t\t\t],\n\t\t\t\tunreferencedTimestampMs:\n\t\t\t\t\tnodeData.unreferencedTimestampMs ?? combineNodeData.unreferencedTimestampMs,\n\t\t\t};\n\t\t}\n\t\tcombinedGCNodes[nodeId] = combineNodeData;\n\t}\n\treturn { gcNodes: combinedGCNodes };\n}\n\n/**\n * Helper function that clones the GC data.\n * @param gcData - The GC data to clone.\n * @returns a clone of the given GC data.\n */\nexport function cloneGCData(gcData: IGarbageCollectionData): IGarbageCollectionData {\n\tconst clonedGCNodes: { [id: string]: string[] } = {};\n\tfor (const [id, outboundRoutes] of Object.entries(gcData.gcNodes)) {\n\t\tclonedGCNodes[id] = Array.from(outboundRoutes);\n\t}\n\treturn {\n\t\tgcNodes: clonedGCNodes,\n\t};\n}\n\n/**\n * Concatenates the given GC data and returns the concatenated GC data.\n */\nexport function concatGarbageCollectionData(\n\tgcData1: IGarbageCollectionData,\n\tgcData2: IGarbageCollectionData,\n) {\n\tconst combinedGCData: IGarbageCollectionData = cloneGCData(gcData1);\n\tfor (const [id, routes] of Object.entries(gcData2.gcNodes)) {\n\t\tif (combinedGCData.gcNodes[id] === undefined) {\n\t\t\tcombinedGCData.gcNodes[id] = Array.from(routes);\n\t\t} else {\n\t\t\tconst combinedRoutes = [...routes, ...combinedGCData.gcNodes[id]];\n\t\t\tcombinedGCData.gcNodes[id] = [...new Set(combinedRoutes)];\n\t\t}\n\t}\n\treturn combinedGCData;\n}\n\n/**\n * Gets the base garbage collection state from the given snapshot tree. It contains GC state, deleted nodes and\n * tombstones. The GC state may be written into multiple blobs. Merge the GC state from all such blobs into one.\n */\nexport async function getGCDataFromSnapshot(\n\tgcSnapshotTree: ISnapshotTree,\n\treadAndParseBlob: <T>(id: string) => Promise<T>,\n): Promise<IGarbageCollectionSnapshotData> {\n\tlet rootGCState: IGarbageCollectionState = { gcNodes: {} };\n\tlet tombstones: string[] | undefined;\n\tlet deletedNodes: string[] | undefined;\n\tfor (const key of Object.keys(gcSnapshotTree.blobs)) {\n\t\t// Update deleted nodes blob.\n\t\tif (key === gcDeletedBlobKey) {\n\t\t\tdeletedNodes = await readAndParseBlob<string[]>(gcSnapshotTree.blobs[key]);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Update tombstone blob.\n\t\tif (key === gcTombstoneBlobKey) {\n\t\t\ttombstones = await readAndParseBlob<string[]>(gcSnapshotTree.blobs[key]);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Skip blobs that do not start with the GC prefix.\n\t\tif (!key.startsWith(gcBlobPrefix)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst blobId = gcSnapshotTree.blobs[key];\n\t\tif (blobId === undefined) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst gcState = await readAndParseBlob<IGarbageCollectionState>(blobId);\n\t\tassert(gcState !== undefined, 0x5d8 /* GC blob missing from snapshot */);\n\t\t// Merge the GC state of this blob into the root GC state.\n\t\trootGCState = concatGarbageCollectionStates(rootGCState, gcState);\n\t}\n\treturn { gcState: rootGCState, tombstones, deletedNodes };\n}\n\n/**\n * Helper function that unpacks the GC details of the children from a given node's GC details.\n * @param gcDetails - The GC details of a node.\n * @returns A map of GC details of each children of the the given node.\n */\nexport function unpackChildNodesGCDetails(gcDetails: IGarbageCollectionDetailsBase) {\n\tconst childGCDetailsMap: Map<string, IGarbageCollectionDetailsBase> = new Map();\n\n\t// If GC data is not available, bail out.\n\tif (gcDetails.gcData === undefined) {\n\t\treturn childGCDetailsMap;\n\t}\n\n\tconst gcNodes = gcDetails.gcData.gcNodes;\n\tfor (const [id, outboundRoutes] of Object.entries(gcNodes)) {\n\t\t// Skip self-node since only children GC data is to be generated.\n\t\tif (id === \"/\") {\n\t\t\tcontinue;\n\t\t}\n\n\t\tassert(id.startsWith(\"/\"), 0x5d9 /* node id should always be an absolute route */);\n\t\tconst childId = id.split(\"/\")[1];\n\t\tlet childGCNodeId = id.slice(childId.length + 1);\n\t\t// GC node id always begins with \"/\". Handle the special case where a child's id in the parent's GC nodes is\n\t\t// of format `/root`. In this case, the childId is root and childGCNodeId is \"\". Make childGCNodeId = \"/\".\n\t\tif (childGCNodeId === \"\") {\n\t\t\tchildGCNodeId = \"/\";\n\t\t}\n\n\t\tlet childGCDetails = childGCDetailsMap.get(childId);\n\t\tif (childGCDetails === undefined) {\n\t\t\tchildGCDetails = { gcData: { gcNodes: {} }, usedRoutes: [] };\n\t\t}\n\t\t// gcData should not undefined as its always at least initialized as empty above.\n\t\tassert(\n\t\t\tchildGCDetails.gcData !== undefined,\n\t\t\t0x5da /* Child GC data should have been initialized */,\n\t\t);\n\t\tchildGCDetails.gcData.gcNodes[childGCNodeId] = [...new Set(outboundRoutes)];\n\t\tchildGCDetailsMap.set(childId, childGCDetails);\n\t}\n\n\tif (gcDetails.usedRoutes === undefined) {\n\t\treturn childGCDetailsMap;\n\t}\n\n\t// Remove the node's self used route, if any, and generate the children used routes.\n\tconst usedRoutes = gcDetails.usedRoutes.filter((route) => route !== \"\" && route !== \"/\");\n\tfor (const route of usedRoutes) {\n\t\tassert(route.startsWith(\"/\"), 0x5db /* Used route should always be an absolute route */);\n\t\tconst childId = route.split(\"/\")[1];\n\t\tconst childUsedRoute = route.slice(childId.length + 1);\n\n\t\tconst childGCDetails = childGCDetailsMap.get(childId);\n\t\tassert(\n\t\t\tchildGCDetails?.usedRoutes !== undefined,\n\t\t\t0x5dc /* This should have be initialized when generate GC nodes above */,\n\t\t);\n\n\t\tchildGCDetails.usedRoutes.push(childUsedRoute);\n\t\tchildGCDetailsMap.set(childId, childGCDetails);\n\t}\n\treturn childGCDetailsMap;\n}\n\n/**\n * Trims the leading and trailing slashes from the given string.\n * @param str - A string that may contain leading and / or trailing slashes.\n * @returns A new string without leading and trailing slashes.\n */\nexport function trimLeadingAndTrailingSlashes(str: string) {\n\treturn str.replace(/^\\/+|\\/+$/g, \"\");\n}\n"]}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* A map in which entries are always added in key-sorted order.
|
|
7
|
+
* Supports appending and searching.
|
|
8
|
+
*/
|
|
9
|
+
export declare class AppendOnlySortedMap<K, V> {
|
|
10
|
+
protected readonly comparator: (a: K, b: K) => number;
|
|
11
|
+
protected readonly elements: (K | V)[];
|
|
12
|
+
/**
|
|
13
|
+
* @param comparator - a comparator for keys
|
|
14
|
+
*/
|
|
15
|
+
constructor(comparator: (a: K, b: K) => number);
|
|
16
|
+
/**
|
|
17
|
+
* @returns the number of entries in this map
|
|
18
|
+
*/
|
|
19
|
+
get size(): number;
|
|
20
|
+
/**
|
|
21
|
+
* @returns the min key in the map.
|
|
22
|
+
*/
|
|
23
|
+
minKey(): K | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* @returns the max key in the map.
|
|
26
|
+
*/
|
|
27
|
+
maxKey(): K | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* @returns the min value in the map.
|
|
30
|
+
*/
|
|
31
|
+
minValue(): V | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* @returns the min value in the map.
|
|
34
|
+
*/
|
|
35
|
+
maxValue(): V | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* @returns the min key in the map.
|
|
38
|
+
*/
|
|
39
|
+
first(): [K, V] | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* @returns the max key in the map.
|
|
42
|
+
*/
|
|
43
|
+
last(): [K, V] | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* Returns the element at the insertion index.
|
|
46
|
+
*/
|
|
47
|
+
getAtIndex(index: number): [K, V] | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* @returns an iterable of the entries in the map.
|
|
50
|
+
*/
|
|
51
|
+
entries(): IterableIterator<readonly [K, V]>;
|
|
52
|
+
/**
|
|
53
|
+
* @returns an iterable of the keys in the map.
|
|
54
|
+
*/
|
|
55
|
+
keys(): IterableIterator<K>;
|
|
56
|
+
/**
|
|
57
|
+
* @returns an iterable of the values in the map.
|
|
58
|
+
*/
|
|
59
|
+
values(): IterableIterator<V>;
|
|
60
|
+
/**
|
|
61
|
+
* @returns an iterable of the entries in the map, reversed.
|
|
62
|
+
*/
|
|
63
|
+
entriesReversed(): IterableIterator<readonly [K, V]>;
|
|
64
|
+
/**
|
|
65
|
+
* Adds a new key/value pair to the map. `key` must be \> to all keys in the map.
|
|
66
|
+
* @param key - the key to add.
|
|
67
|
+
* @param value - the value to add.
|
|
68
|
+
*/
|
|
69
|
+
append(key: K, value: V): void;
|
|
70
|
+
/**
|
|
71
|
+
* @param key - the key to lookup.
|
|
72
|
+
* @returns the value associated with `key` if such an entry exists, and undefined otherwise.
|
|
73
|
+
*/
|
|
74
|
+
get(key: K): V | undefined;
|
|
75
|
+
/**
|
|
76
|
+
* @param key - the key to lookup.
|
|
77
|
+
* @returns the entry associated with `key` if such an entry exists, the entry associated with the next lower key if such an entry
|
|
78
|
+
* exists, and undefined otherwise.
|
|
79
|
+
*/
|
|
80
|
+
getPairOrNextLower(key: K): readonly [K, V] | undefined;
|
|
81
|
+
/**
|
|
82
|
+
* @param key - the key to lookup.
|
|
83
|
+
* @returns the entry associated with `key` if such an entry exists, the entry associated with the next higher key if such an entry
|
|
84
|
+
* exists, and undefined otherwise.
|
|
85
|
+
*/
|
|
86
|
+
getPairOrNextHigher(key: K): readonly [K, V] | undefined;
|
|
87
|
+
/**
|
|
88
|
+
* Compares two `AppendOnlySortedMap`s.
|
|
89
|
+
*/
|
|
90
|
+
equals(other: AppendOnlySortedMap<K, V>, compareValues: (a: V, b: V) => boolean): boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Test-only expensive assertions to check the internal validity of the data structure.
|
|
93
|
+
*/
|
|
94
|
+
assertValid(): void;
|
|
95
|
+
/**
|
|
96
|
+
* Queries a range of entries.
|
|
97
|
+
* @param from - the key to start the range query at, inclusive.
|
|
98
|
+
* @param to - the key to end the range query at, inclusive.
|
|
99
|
+
* @returns the range of entries.
|
|
100
|
+
*/
|
|
101
|
+
getRange(from: K, to: K): IterableIterator<readonly [K, V]>;
|
|
102
|
+
protected getPairOrNextLowerBy<T>(search: T, comparator: (search: T, key: K, value: V) => number): readonly [K, V] | undefined;
|
|
103
|
+
private getKeyIndexOfOrNextLower;
|
|
104
|
+
protected getPairOrNextHigherBy<T>(search: T, comparator: (search: T, key: K, value: V) => number): readonly [K, V] | undefined;
|
|
105
|
+
private getKeyIndexOfOrNextHigher;
|
|
106
|
+
/**
|
|
107
|
+
* The value xor'd with the result index when a search fails.
|
|
108
|
+
*/
|
|
109
|
+
static readonly failureXor = -1;
|
|
110
|
+
/**
|
|
111
|
+
* Performs a binary search on the sorted array.
|
|
112
|
+
* @returns the index of the key for `search`, or (if not present) the index it would have been inserted into xor'd
|
|
113
|
+
* with `failureXor`. Note that negating is not an adequate solution as that could result in -0.
|
|
114
|
+
*/
|
|
115
|
+
static keyIndexOf<T, K, V>(elements: readonly (K | V)[], search: T, comparator: (search: T, key: K, value: V) => number): number;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* A map in which entries are always added in both key-sorted and value-sorted order.
|
|
119
|
+
* Supports appending and searching.
|
|
120
|
+
*/
|
|
121
|
+
export declare class AppendOnlyDoublySortedMap<K, V, S> extends AppendOnlySortedMap<K, V> {
|
|
122
|
+
private readonly extractSearchValue;
|
|
123
|
+
private readonly valueComparator;
|
|
124
|
+
constructor(keyComparator: (a: K, b: K) => number, extractSearchValue: (value: V) => S, valueComparator: (search: S, value: S) => number);
|
|
125
|
+
append(key: K, value: V): void;
|
|
126
|
+
private readonly compareValues;
|
|
127
|
+
/**
|
|
128
|
+
* @param searchValue - the search value to lookup.
|
|
129
|
+
* @returns the entry who's value, when run through the extractor provided to the constructor, matches
|
|
130
|
+
* `searchValue`. If no such entry exists, this method returns the next lower entry as determined by the value
|
|
131
|
+
* comparator provided to the constructor. If no such entry exists, this method returns undefined.
|
|
132
|
+
*/
|
|
133
|
+
getPairOrNextLowerByValue(searchValue: S): readonly [K, V] | undefined;
|
|
134
|
+
/**
|
|
135
|
+
* @param searchValue - the search value to lookup.
|
|
136
|
+
* @returns the entry who's value, when run through the extractor provided to the constructor, matches `searchValue`. If no such entry
|
|
137
|
+
* exists, this method returns the next higher entry as determined by the value comparator provided to the constructor. If no such entry
|
|
138
|
+
* exists, this method returns undefined.
|
|
139
|
+
*/
|
|
140
|
+
getPairOrNextHigherByValue(searchValue: S): readonly [K, V] | undefined;
|
|
141
|
+
/**
|
|
142
|
+
* Test-only expensive assertions to check the internal validity of the data structure.
|
|
143
|
+
*/
|
|
144
|
+
assertValid(): void;
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=appendOnlySortedMap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"appendOnlySortedMap.d.ts","sourceRoot":"","sources":["../../src/id-compressor/appendOnlySortedMap.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*!
|
|
3
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
4
|
+
* Licensed under the MIT License.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.AppendOnlyDoublySortedMap = exports.AppendOnlySortedMap = void 0;
|
|
8
|
+
/* eslint-disable no-bitwise */
|
|
9
|
+
const common_utils_1 = require("@fluidframework/common-utils");
|
|
10
|
+
const utils_1 = require("./utils");
|
|
11
|
+
/**
|
|
12
|
+
* A map in which entries are always added in key-sorted order.
|
|
13
|
+
* Supports appending and searching.
|
|
14
|
+
*/
|
|
15
|
+
class AppendOnlySortedMap {
|
|
16
|
+
/**
|
|
17
|
+
* @param comparator - a comparator for keys
|
|
18
|
+
*/
|
|
19
|
+
constructor(comparator) {
|
|
20
|
+
this.comparator = comparator;
|
|
21
|
+
this.elements = [];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* @returns the number of entries in this map
|
|
25
|
+
*/
|
|
26
|
+
get size() {
|
|
27
|
+
return this.elements.length / 2;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* @returns the min key in the map.
|
|
31
|
+
*/
|
|
32
|
+
minKey() {
|
|
33
|
+
return this.elements[0];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* @returns the max key in the map.
|
|
37
|
+
*/
|
|
38
|
+
maxKey() {
|
|
39
|
+
return this.elements[this.elements.length - 2];
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* @returns the min value in the map.
|
|
43
|
+
*/
|
|
44
|
+
minValue() {
|
|
45
|
+
return this.elements[1];
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* @returns the min value in the map.
|
|
49
|
+
*/
|
|
50
|
+
maxValue() {
|
|
51
|
+
return this.elements[this.elements.length - 1];
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* @returns the min key in the map.
|
|
55
|
+
*/
|
|
56
|
+
first() {
|
|
57
|
+
const { elements } = this;
|
|
58
|
+
const { length } = elements;
|
|
59
|
+
if (length === 0) {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
return [elements[0], elements[1]];
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* @returns the max key in the map.
|
|
66
|
+
*/
|
|
67
|
+
last() {
|
|
68
|
+
const { elements } = this;
|
|
69
|
+
const { length } = elements;
|
|
70
|
+
if (length === 0) {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
const lastKeyIndex = length - 2;
|
|
74
|
+
return [elements[lastKeyIndex], elements[lastKeyIndex + 1]];
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Returns the element at the insertion index.
|
|
78
|
+
*/
|
|
79
|
+
getAtIndex(index) {
|
|
80
|
+
const realIndex = index * 2;
|
|
81
|
+
const { elements } = this;
|
|
82
|
+
if (realIndex < 0 || realIndex > elements.length - 1) {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
return [elements[realIndex], elements[realIndex + 1]];
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* @returns an iterable of the entries in the map.
|
|
89
|
+
*/
|
|
90
|
+
*entries() {
|
|
91
|
+
const { elements } = this;
|
|
92
|
+
for (let i = 0; i < elements.length; i += 2) {
|
|
93
|
+
yield [elements[i], elements[i + 1]];
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* @returns an iterable of the keys in the map.
|
|
98
|
+
*/
|
|
99
|
+
*keys() {
|
|
100
|
+
const { elements } = this;
|
|
101
|
+
for (let i = 0; i < elements.length; i += 2) {
|
|
102
|
+
yield elements[i];
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* @returns an iterable of the values in the map.
|
|
107
|
+
*/
|
|
108
|
+
*values() {
|
|
109
|
+
const { elements } = this;
|
|
110
|
+
for (let i = 0; i < elements.length; i += 2) {
|
|
111
|
+
yield elements[i + 1];
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* @returns an iterable of the entries in the map, reversed.
|
|
116
|
+
*/
|
|
117
|
+
*entriesReversed() {
|
|
118
|
+
const { elements } = this;
|
|
119
|
+
for (let i = elements.length - 2; i >= 0; i -= 2) {
|
|
120
|
+
yield [elements[i], elements[i + 1]];
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Adds a new key/value pair to the map. `key` must be \> to all keys in the map.
|
|
125
|
+
* @param key - the key to add.
|
|
126
|
+
* @param value - the value to add.
|
|
127
|
+
*/
|
|
128
|
+
append(key, value) {
|
|
129
|
+
const { elements } = this;
|
|
130
|
+
const { length } = elements;
|
|
131
|
+
if (length !== 0 && this.comparator(key, this.maxKey()) <= 0) {
|
|
132
|
+
(0, utils_1.fail)("Inserted key must be > all others in the map.");
|
|
133
|
+
}
|
|
134
|
+
elements.push(key);
|
|
135
|
+
elements.push(value);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* @param key - the key to lookup.
|
|
139
|
+
* @returns the value associated with `key` if such an entry exists, and undefined otherwise.
|
|
140
|
+
*/
|
|
141
|
+
get(key) {
|
|
142
|
+
const index = AppendOnlySortedMap.keyIndexOf(this.elements, key, this.comparator);
|
|
143
|
+
if (index < 0) {
|
|
144
|
+
return undefined;
|
|
145
|
+
}
|
|
146
|
+
return this.elements[index + 1];
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* @param key - the key to lookup.
|
|
150
|
+
* @returns the entry associated with `key` if such an entry exists, the entry associated with the next lower key if such an entry
|
|
151
|
+
* exists, and undefined otherwise.
|
|
152
|
+
*/
|
|
153
|
+
getPairOrNextLower(key) {
|
|
154
|
+
return this.getPairOrNextLowerBy(key, this.comparator);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* @param key - the key to lookup.
|
|
158
|
+
* @returns the entry associated with `key` if such an entry exists, the entry associated with the next higher key if such an entry
|
|
159
|
+
* exists, and undefined otherwise.
|
|
160
|
+
*/
|
|
161
|
+
getPairOrNextHigher(key) {
|
|
162
|
+
return this.getPairOrNextHigherBy(key, this.comparator);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Compares two `AppendOnlySortedMap`s.
|
|
166
|
+
*/
|
|
167
|
+
equals(other, compareValues) {
|
|
168
|
+
if (other === this) {
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
if (this.elements.length !== other.elements.length) {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
for (let i = this.elements.length - 2; i >= 0; i -= 2) {
|
|
175
|
+
const keyThis = this.elements[i];
|
|
176
|
+
const valueThis = this.elements[i + 1];
|
|
177
|
+
const keyOther = other.elements[i];
|
|
178
|
+
const valueOther = other.elements[i + 1];
|
|
179
|
+
if (this.comparator(keyThis, keyOther) !== 0) {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
if (!compareValues(valueThis, valueOther)) {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Test-only expensive assertions to check the internal validity of the data structure.
|
|
190
|
+
*/
|
|
191
|
+
assertValid() {
|
|
192
|
+
let prev;
|
|
193
|
+
for (const kv of this.entries()) {
|
|
194
|
+
if (prev !== undefined) {
|
|
195
|
+
(0, common_utils_1.assert)(this.comparator(kv[0], prev[0]) > 0, 0x47f /* Keys in map must be sorted. */);
|
|
196
|
+
}
|
|
197
|
+
prev = kv;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Queries a range of entries.
|
|
202
|
+
* @param from - the key to start the range query at, inclusive.
|
|
203
|
+
* @param to - the key to end the range query at, inclusive.
|
|
204
|
+
* @returns the range of entries.
|
|
205
|
+
*/
|
|
206
|
+
*getRange(from, to) {
|
|
207
|
+
const keyIndexFrom = this.getKeyIndexOfOrNextHigher(from, this.comparator);
|
|
208
|
+
if (keyIndexFrom === undefined) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
const keyIndexTo = this.getKeyIndexOfOrNextLower(to, this.comparator);
|
|
212
|
+
if (keyIndexTo === undefined) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
for (let i = keyIndexFrom; i <= keyIndexTo; i += 2) {
|
|
216
|
+
yield [this.elements[i], this.elements[i + 1]];
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
getPairOrNextLowerBy(search, comparator) {
|
|
220
|
+
const keyIndex = this.getKeyIndexOfOrNextLower(search, comparator);
|
|
221
|
+
if (keyIndex === undefined) {
|
|
222
|
+
return undefined;
|
|
223
|
+
}
|
|
224
|
+
return [this.elements[keyIndex], this.elements[keyIndex + 1]];
|
|
225
|
+
}
|
|
226
|
+
getKeyIndexOfOrNextLower(search, comparator) {
|
|
227
|
+
const { elements } = this;
|
|
228
|
+
if (elements.length === 0) {
|
|
229
|
+
return undefined;
|
|
230
|
+
}
|
|
231
|
+
let keyIndex = AppendOnlySortedMap.keyIndexOf(elements, search, comparator);
|
|
232
|
+
if (keyIndex < 0) {
|
|
233
|
+
keyIndex ^= AppendOnlySortedMap.failureXor;
|
|
234
|
+
if (keyIndex > 0) {
|
|
235
|
+
return keyIndex - 2;
|
|
236
|
+
}
|
|
237
|
+
return undefined;
|
|
238
|
+
}
|
|
239
|
+
return keyIndex;
|
|
240
|
+
}
|
|
241
|
+
getPairOrNextHigherBy(search, comparator) {
|
|
242
|
+
const keyIndex = this.getKeyIndexOfOrNextHigher(search, comparator);
|
|
243
|
+
if (keyIndex === undefined) {
|
|
244
|
+
return undefined;
|
|
245
|
+
}
|
|
246
|
+
return [this.elements[keyIndex], this.elements[keyIndex + 1]];
|
|
247
|
+
}
|
|
248
|
+
getKeyIndexOfOrNextHigher(search, comparator) {
|
|
249
|
+
const { elements } = this;
|
|
250
|
+
const { length } = elements;
|
|
251
|
+
if (length === 0) {
|
|
252
|
+
return undefined;
|
|
253
|
+
}
|
|
254
|
+
let keyIndex = AppendOnlySortedMap.keyIndexOf(elements, search, comparator);
|
|
255
|
+
if (keyIndex < 0) {
|
|
256
|
+
keyIndex ^= AppendOnlySortedMap.failureXor;
|
|
257
|
+
if (keyIndex < length) {
|
|
258
|
+
return keyIndex;
|
|
259
|
+
}
|
|
260
|
+
return undefined;
|
|
261
|
+
}
|
|
262
|
+
return keyIndex;
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Performs a binary search on the sorted array.
|
|
266
|
+
* @returns the index of the key for `search`, or (if not present) the index it would have been inserted into xor'd
|
|
267
|
+
* with `failureXor`. Note that negating is not an adequate solution as that could result in -0.
|
|
268
|
+
*/
|
|
269
|
+
static keyIndexOf(elements, search, comparator) {
|
|
270
|
+
// Low, high, and mid are addresses of [K,V] pairs and *not* key indices
|
|
271
|
+
let low = 0;
|
|
272
|
+
let high = elements.length / 2;
|
|
273
|
+
let mid = high >> 1;
|
|
274
|
+
while (low < high) {
|
|
275
|
+
const keyIndex = mid * 2;
|
|
276
|
+
const c = comparator(search, elements[keyIndex], elements[keyIndex + 1]);
|
|
277
|
+
if (c > 0) {
|
|
278
|
+
low = mid + 1;
|
|
279
|
+
}
|
|
280
|
+
else if (c < 0) {
|
|
281
|
+
high = mid;
|
|
282
|
+
}
|
|
283
|
+
else if (c === 0) {
|
|
284
|
+
return keyIndex;
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
(0, utils_1.fail)("Invalid comparator.");
|
|
288
|
+
}
|
|
289
|
+
mid = (low + high) >> 1;
|
|
290
|
+
}
|
|
291
|
+
return (mid * 2) ^ AppendOnlySortedMap.failureXor;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
exports.AppendOnlySortedMap = AppendOnlySortedMap;
|
|
295
|
+
/**
|
|
296
|
+
* The value xor'd with the result index when a search fails.
|
|
297
|
+
*/
|
|
298
|
+
AppendOnlySortedMap.failureXor = -1;
|
|
299
|
+
/**
|
|
300
|
+
* A map in which entries are always added in both key-sorted and value-sorted order.
|
|
301
|
+
* Supports appending and searching.
|
|
302
|
+
*/
|
|
303
|
+
class AppendOnlyDoublySortedMap extends AppendOnlySortedMap {
|
|
304
|
+
constructor(keyComparator, extractSearchValue, valueComparator) {
|
|
305
|
+
super(keyComparator);
|
|
306
|
+
this.extractSearchValue = extractSearchValue;
|
|
307
|
+
this.valueComparator = valueComparator;
|
|
308
|
+
this.compareValues = (search, _, value) => {
|
|
309
|
+
return this.valueComparator(search, this.extractSearchValue(value));
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
append(key, value) {
|
|
313
|
+
if (this.elements.length !== 0 &&
|
|
314
|
+
this.valueComparator(this.extractSearchValue(value), this.extractSearchValue(this.maxValue())) <= 0) {
|
|
315
|
+
(0, utils_1.fail)("Inserted value must be > all others in the map.");
|
|
316
|
+
}
|
|
317
|
+
super.append(key, value);
|
|
318
|
+
}
|
|
319
|
+
// /**
|
|
320
|
+
// * @param value - the value to lookup.
|
|
321
|
+
// * @returns the key associated with `value` if such an entry exists, and undefined otherwise.
|
|
322
|
+
// */
|
|
323
|
+
// public getByValue(value: S): K | undefined {
|
|
324
|
+
// const index = AppendOnlySortedMap.keyIndexOf(this.elements, value, this.compareValues);
|
|
325
|
+
// return this.elements[index]?.[0];
|
|
326
|
+
// }
|
|
327
|
+
/**
|
|
328
|
+
* @param searchValue - the search value to lookup.
|
|
329
|
+
* @returns the entry who's value, when run through the extractor provided to the constructor, matches
|
|
330
|
+
* `searchValue`. If no such entry exists, this method returns the next lower entry as determined by the value
|
|
331
|
+
* comparator provided to the constructor. If no such entry exists, this method returns undefined.
|
|
332
|
+
*/
|
|
333
|
+
getPairOrNextLowerByValue(searchValue) {
|
|
334
|
+
return this.getPairOrNextLowerBy(searchValue, this.compareValues);
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* @param searchValue - the search value to lookup.
|
|
338
|
+
* @returns the entry who's value, when run through the extractor provided to the constructor, matches `searchValue`. If no such entry
|
|
339
|
+
* exists, this method returns the next higher entry as determined by the value comparator provided to the constructor. If no such entry
|
|
340
|
+
* exists, this method returns undefined.
|
|
341
|
+
*/
|
|
342
|
+
getPairOrNextHigherByValue(searchValue) {
|
|
343
|
+
return this.getPairOrNextHigherBy(searchValue, this.compareValues);
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Test-only expensive assertions to check the internal validity of the data structure.
|
|
347
|
+
*/
|
|
348
|
+
assertValid() {
|
|
349
|
+
super.assertValid();
|
|
350
|
+
let prev;
|
|
351
|
+
for (const kv of this.entries()) {
|
|
352
|
+
if (prev !== undefined) {
|
|
353
|
+
(0, common_utils_1.assert)(this.valueComparator(this.extractSearchValue(kv[1]), this.extractSearchValue(prev[1])) > 0, 0x480 /* Values in map must be sorted. */);
|
|
354
|
+
}
|
|
355
|
+
prev = kv;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
exports.AppendOnlyDoublySortedMap = AppendOnlyDoublySortedMap;
|
|
360
|
+
//# sourceMappingURL=appendOnlySortedMap.js.map
|