@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/src/dataStores.ts
CHANGED
|
@@ -116,7 +116,7 @@ export class DataStores implements IDisposable {
|
|
|
116
116
|
constructor(
|
|
117
117
|
private readonly baseSnapshot: ISnapshotTree | undefined,
|
|
118
118
|
private readonly runtime: ContainerRuntime,
|
|
119
|
-
private readonly submitAttachFn: (attachContent:
|
|
119
|
+
private readonly submitAttachFn: (attachContent: IAttachMessage) => void,
|
|
120
120
|
private readonly getCreateChildSummarizerNodeFn: (
|
|
121
121
|
id: string,
|
|
122
122
|
createParam: CreateChildSummarizerNodeParam,
|
|
@@ -399,22 +399,19 @@ export class DataStores implements IDisposable {
|
|
|
399
399
|
}
|
|
400
400
|
public readonly dispose = () => this.disposeOnce.value;
|
|
401
401
|
|
|
402
|
-
public resubmitDataStoreOp(
|
|
403
|
-
const envelope = content as IEnvelope;
|
|
402
|
+
public resubmitDataStoreOp(envelope: IEnvelope, localOpMetadata: unknown) {
|
|
404
403
|
const context = this.contexts.get(envelope.address);
|
|
405
404
|
assert(!!context, 0x160 /* "There should be a store context for the op" */);
|
|
406
405
|
context.reSubmit(envelope.contents, localOpMetadata);
|
|
407
406
|
}
|
|
408
407
|
|
|
409
|
-
public rollbackDataStoreOp(
|
|
410
|
-
const envelope = content as IEnvelope;
|
|
408
|
+
public rollbackDataStoreOp(envelope: IEnvelope, localOpMetadata: unknown) {
|
|
411
409
|
const context = this.contexts.get(envelope.address);
|
|
412
410
|
assert(!!context, 0x2e8 /* "There should be a store context for the op" */);
|
|
413
411
|
context.rollback(envelope.contents, localOpMetadata);
|
|
414
412
|
}
|
|
415
413
|
|
|
416
|
-
public async applyStashedOp(
|
|
417
|
-
const envelope = content as IEnvelope;
|
|
414
|
+
public async applyStashedOp(envelope: IEnvelope): Promise<unknown> {
|
|
418
415
|
const context = this.contexts.get(envelope.address);
|
|
419
416
|
assert(!!context, 0x161 /* "There should be a store context for the op" */);
|
|
420
417
|
return context.applyStashedOp(envelope.contents);
|
|
@@ -465,6 +465,13 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
465
465
|
const fullGC =
|
|
466
466
|
options.fullGC ??
|
|
467
467
|
(this.configs.runFullGC === true || this.summaryStateTracker.doesSummaryStateNeedReset);
|
|
468
|
+
|
|
469
|
+
// Add the options that are used to run GC to the telemetry context.
|
|
470
|
+
telemetryContext?.setMultiple("fluid_GC", "Options", {
|
|
471
|
+
fullGC,
|
|
472
|
+
runSweep: options.runSweep,
|
|
473
|
+
});
|
|
474
|
+
|
|
468
475
|
const logger = options.logger
|
|
469
476
|
? ChildLogger.create(options.logger, undefined, {
|
|
470
477
|
all: { completedGCRuns: () => this.completedRuns },
|
|
@@ -489,12 +496,6 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
489
496
|
return undefined;
|
|
490
497
|
}
|
|
491
498
|
|
|
492
|
-
// Add the options that are used to run GC to the telemetry context.
|
|
493
|
-
telemetryContext?.setMultiple("fluid_GC", "Options", {
|
|
494
|
-
fullGC,
|
|
495
|
-
runSweep: options.runSweep,
|
|
496
|
-
});
|
|
497
|
-
|
|
498
499
|
return PerformanceEvent.timedExecAsync(
|
|
499
500
|
logger,
|
|
500
501
|
{ eventName: "GarbageCollection" },
|
package/src/gc/gcConfigs.ts
CHANGED
|
@@ -158,9 +158,7 @@ export function generateGCConfigs(
|
|
|
158
158
|
|
|
159
159
|
// If version upgrade is not enabled, fall back to the stable GC version.
|
|
160
160
|
const gcVersionInEffect =
|
|
161
|
-
mc.config.getBoolean(gcVersionUpgradeToV3Key) ===
|
|
162
|
-
? stableGCVersion
|
|
163
|
-
: currentGCVersion;
|
|
161
|
+
mc.config.getBoolean(gcVersionUpgradeToV3Key) === true ? currentGCVersion : stableGCVersion;
|
|
164
162
|
|
|
165
163
|
return {
|
|
166
164
|
gcEnabled,
|
package/src/gc/gcDefinitions.ts
CHANGED
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
export type GCVersion = number;
|
|
24
24
|
|
|
25
25
|
/** The stable version of garbage collection in production. */
|
|
26
|
-
export const stableGCVersion: GCVersion =
|
|
26
|
+
export const stableGCVersion: GCVersion = 2;
|
|
27
27
|
/** The current version of garbage collection. */
|
|
28
28
|
export const currentGCVersion: GCVersion = 3;
|
|
29
29
|
|
package/src/gc/gcHelpers.ts
CHANGED
|
@@ -169,7 +169,7 @@ export function concatGarbageCollectionStates(
|
|
|
169
169
|
) {
|
|
170
170
|
assert(
|
|
171
171
|
nodeData.unreferencedTimestampMs === combineNodeData.unreferencedTimestampMs,
|
|
172
|
-
|
|
172
|
+
0x5d7 /* Two entries for the same GC node with different unreferenced timestamp */,
|
|
173
173
|
);
|
|
174
174
|
}
|
|
175
175
|
combineNodeData = {
|
|
@@ -253,7 +253,7 @@ export async function getGCDataFromSnapshot(
|
|
|
253
253
|
continue;
|
|
254
254
|
}
|
|
255
255
|
const gcState = await readAndParseBlob<IGarbageCollectionState>(blobId);
|
|
256
|
-
assert(gcState !== undefined,
|
|
256
|
+
assert(gcState !== undefined, 0x5d8 /* GC blob missing from snapshot */);
|
|
257
257
|
// Merge the GC state of this blob into the root GC state.
|
|
258
258
|
rootGCState = concatGarbageCollectionStates(rootGCState, gcState);
|
|
259
259
|
}
|
|
@@ -280,7 +280,7 @@ export function unpackChildNodesGCDetails(gcDetails: IGarbageCollectionDetailsBa
|
|
|
280
280
|
continue;
|
|
281
281
|
}
|
|
282
282
|
|
|
283
|
-
assert(id.startsWith("/"),
|
|
283
|
+
assert(id.startsWith("/"), 0x5d9 /* node id should always be an absolute route */);
|
|
284
284
|
const childId = id.split("/")[1];
|
|
285
285
|
let childGCNodeId = id.slice(childId.length + 1);
|
|
286
286
|
// GC node id always begins with "/". Handle the special case where a child's id in the parent's GC nodes is
|
|
@@ -294,7 +294,10 @@ export function unpackChildNodesGCDetails(gcDetails: IGarbageCollectionDetailsBa
|
|
|
294
294
|
childGCDetails = { gcData: { gcNodes: {} }, usedRoutes: [] };
|
|
295
295
|
}
|
|
296
296
|
// gcData should not undefined as its always at least initialized as empty above.
|
|
297
|
-
assert(
|
|
297
|
+
assert(
|
|
298
|
+
childGCDetails.gcData !== undefined,
|
|
299
|
+
0x5da /* Child GC data should have been initialized */,
|
|
300
|
+
);
|
|
298
301
|
childGCDetails.gcData.gcNodes[childGCNodeId] = [...new Set(outboundRoutes)];
|
|
299
302
|
childGCDetailsMap.set(childId, childGCDetails);
|
|
300
303
|
}
|
|
@@ -306,14 +309,14 @@ export function unpackChildNodesGCDetails(gcDetails: IGarbageCollectionDetailsBa
|
|
|
306
309
|
// Remove the node's self used route, if any, and generate the children used routes.
|
|
307
310
|
const usedRoutes = gcDetails.usedRoutes.filter((route) => route !== "" && route !== "/");
|
|
308
311
|
for (const route of usedRoutes) {
|
|
309
|
-
assert(route.startsWith("/"),
|
|
312
|
+
assert(route.startsWith("/"), 0x5db /* Used route should always be an absolute route */);
|
|
310
313
|
const childId = route.split("/")[1];
|
|
311
314
|
const childUsedRoute = route.slice(childId.length + 1);
|
|
312
315
|
|
|
313
316
|
const childGCDetails = childGCDetailsMap.get(childId);
|
|
314
317
|
assert(
|
|
315
318
|
childGCDetails?.usedRoutes !== undefined,
|
|
316
|
-
|
|
319
|
+
0x5dc /* This should have be initialized when generate GC nodes above */,
|
|
317
320
|
);
|
|
318
321
|
|
|
319
322
|
childGCDetails.usedRoutes.push(childUsedRoute);
|
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/* eslint-disable no-bitwise */
|
|
7
|
+
|
|
8
|
+
import { assert } from "@fluidframework/common-utils";
|
|
9
|
+
import { fail } from "./utils";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* A map in which entries are always added in key-sorted order.
|
|
13
|
+
* Supports appending and searching.
|
|
14
|
+
*/
|
|
15
|
+
export class AppendOnlySortedMap<K, V> {
|
|
16
|
+
protected readonly elements: (K | V)[] = [];
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param comparator - a comparator for keys
|
|
20
|
+
*/
|
|
21
|
+
public constructor(protected readonly comparator: (a: K, b: K) => number) {}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @returns the number of entries in this map
|
|
25
|
+
*/
|
|
26
|
+
public get size(): number {
|
|
27
|
+
return this.elements.length / 2;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @returns the min key in the map.
|
|
32
|
+
*/
|
|
33
|
+
public minKey(): K | undefined {
|
|
34
|
+
return this.elements[0] as K | undefined;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @returns the max key in the map.
|
|
39
|
+
*/
|
|
40
|
+
public maxKey(): K | undefined {
|
|
41
|
+
return this.elements[this.elements.length - 2] as K | undefined;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @returns the min value in the map.
|
|
46
|
+
*/
|
|
47
|
+
public minValue(): V | undefined {
|
|
48
|
+
return this.elements[1] as V | undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @returns the min value in the map.
|
|
53
|
+
*/
|
|
54
|
+
public maxValue(): V | undefined {
|
|
55
|
+
return this.elements[this.elements.length - 1] as V | undefined;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @returns the min key in the map.
|
|
60
|
+
*/
|
|
61
|
+
public first(): [K, V] | undefined {
|
|
62
|
+
const { elements } = this;
|
|
63
|
+
const { length } = elements;
|
|
64
|
+
if (length === 0) {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
return [elements[0] as K, elements[1] as V];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @returns the max key in the map.
|
|
72
|
+
*/
|
|
73
|
+
public last(): [K, V] | undefined {
|
|
74
|
+
const { elements } = this;
|
|
75
|
+
const { length } = elements;
|
|
76
|
+
if (length === 0) {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
const lastKeyIndex = length - 2;
|
|
80
|
+
return [elements[lastKeyIndex] as K, elements[lastKeyIndex + 1] as V];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Returns the element at the insertion index.
|
|
85
|
+
*/
|
|
86
|
+
public getAtIndex(index: number): [K, V] | undefined {
|
|
87
|
+
const realIndex = index * 2;
|
|
88
|
+
const { elements } = this;
|
|
89
|
+
if (realIndex < 0 || realIndex > elements.length - 1) {
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
return [elements[realIndex] as K, elements[realIndex + 1] as V];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* @returns an iterable of the entries in the map.
|
|
97
|
+
*/
|
|
98
|
+
public *entries(): IterableIterator<readonly [K, V]> {
|
|
99
|
+
const { elements } = this;
|
|
100
|
+
for (let i = 0; i < elements.length; i += 2) {
|
|
101
|
+
yield [elements[i] as K, elements[i + 1] as V];
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* @returns an iterable of the keys in the map.
|
|
107
|
+
*/
|
|
108
|
+
public *keys(): IterableIterator<K> {
|
|
109
|
+
const { elements } = this;
|
|
110
|
+
for (let i = 0; i < elements.length; i += 2) {
|
|
111
|
+
yield elements[i] as K;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* @returns an iterable of the values in the map.
|
|
117
|
+
*/
|
|
118
|
+
public *values(): IterableIterator<V> {
|
|
119
|
+
const { elements } = this;
|
|
120
|
+
for (let i = 0; i < elements.length; i += 2) {
|
|
121
|
+
yield elements[i + 1] as V;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* @returns an iterable of the entries in the map, reversed.
|
|
127
|
+
*/
|
|
128
|
+
public *entriesReversed(): IterableIterator<readonly [K, V]> {
|
|
129
|
+
const { elements } = this;
|
|
130
|
+
for (let i = elements.length - 2; i >= 0; i -= 2) {
|
|
131
|
+
yield [elements[i] as K, elements[i + 1] as V];
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Adds a new key/value pair to the map. `key` must be \> to all keys in the map.
|
|
137
|
+
* @param key - the key to add.
|
|
138
|
+
* @param value - the value to add.
|
|
139
|
+
*/
|
|
140
|
+
public append(key: K, value: V): void {
|
|
141
|
+
const { elements } = this;
|
|
142
|
+
const { length } = elements;
|
|
143
|
+
if (length !== 0 && this.comparator(key, this.maxKey() as K) <= 0) {
|
|
144
|
+
fail("Inserted key must be > all others in the map.");
|
|
145
|
+
}
|
|
146
|
+
elements.push(key);
|
|
147
|
+
elements.push(value);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* @param key - the key to lookup.
|
|
152
|
+
* @returns the value associated with `key` if such an entry exists, and undefined otherwise.
|
|
153
|
+
*/
|
|
154
|
+
public get(key: K): V | undefined {
|
|
155
|
+
const index = AppendOnlySortedMap.keyIndexOf(this.elements, key, this.comparator);
|
|
156
|
+
if (index < 0) {
|
|
157
|
+
return undefined;
|
|
158
|
+
}
|
|
159
|
+
return this.elements[index + 1] as V;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* @param key - the key to lookup.
|
|
164
|
+
* @returns the entry associated with `key` if such an entry exists, the entry associated with the next lower key if such an entry
|
|
165
|
+
* exists, and undefined otherwise.
|
|
166
|
+
*/
|
|
167
|
+
public getPairOrNextLower(key: K): readonly [K, V] | undefined {
|
|
168
|
+
return this.getPairOrNextLowerBy(key, this.comparator);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* @param key - the key to lookup.
|
|
173
|
+
* @returns the entry associated with `key` if such an entry exists, the entry associated with the next higher key if such an entry
|
|
174
|
+
* exists, and undefined otherwise.
|
|
175
|
+
*/
|
|
176
|
+
public getPairOrNextHigher(key: K): readonly [K, V] | undefined {
|
|
177
|
+
return this.getPairOrNextHigherBy(key, this.comparator);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Compares two `AppendOnlySortedMap`s.
|
|
182
|
+
*/
|
|
183
|
+
public equals(
|
|
184
|
+
other: AppendOnlySortedMap<K, V>,
|
|
185
|
+
compareValues: (a: V, b: V) => boolean,
|
|
186
|
+
): boolean {
|
|
187
|
+
if (other === this) {
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (this.elements.length !== other.elements.length) {
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
for (let i = this.elements.length - 2; i >= 0; i -= 2) {
|
|
196
|
+
const keyThis = this.elements[i] as K;
|
|
197
|
+
const valueThis = this.elements[i + 1] as V;
|
|
198
|
+
const keyOther = other.elements[i] as K;
|
|
199
|
+
const valueOther = other.elements[i + 1] as V;
|
|
200
|
+
if (this.comparator(keyThis, keyOther) !== 0) {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
if (!compareValues(valueThis, valueOther)) {
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Test-only expensive assertions to check the internal validity of the data structure.
|
|
213
|
+
*/
|
|
214
|
+
public assertValid(): void {
|
|
215
|
+
let prev: readonly [K, unknown] | undefined;
|
|
216
|
+
for (const kv of this.entries()) {
|
|
217
|
+
if (prev !== undefined) {
|
|
218
|
+
assert(
|
|
219
|
+
this.comparator(kv[0], prev[0]) > 0,
|
|
220
|
+
0x47f /* Keys in map must be sorted. */,
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
prev = kv;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Queries a range of entries.
|
|
229
|
+
* @param from - the key to start the range query at, inclusive.
|
|
230
|
+
* @param to - the key to end the range query at, inclusive.
|
|
231
|
+
* @returns the range of entries.
|
|
232
|
+
*/
|
|
233
|
+
public *getRange(from: K, to: K): IterableIterator<readonly [K, V]> {
|
|
234
|
+
const keyIndexFrom = this.getKeyIndexOfOrNextHigher(from, this.comparator);
|
|
235
|
+
if (keyIndexFrom === undefined) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const keyIndexTo = this.getKeyIndexOfOrNextLower(to, this.comparator);
|
|
240
|
+
if (keyIndexTo === undefined) {
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
for (let i = keyIndexFrom; i <= keyIndexTo; i += 2) {
|
|
245
|
+
yield [this.elements[i] as K, this.elements[i + 1] as V];
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
protected getPairOrNextLowerBy<T>(
|
|
250
|
+
search: T,
|
|
251
|
+
comparator: (search: T, key: K, value: V) => number,
|
|
252
|
+
): readonly [K, V] | undefined {
|
|
253
|
+
const keyIndex = this.getKeyIndexOfOrNextLower(search, comparator);
|
|
254
|
+
if (keyIndex === undefined) {
|
|
255
|
+
return undefined;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return [this.elements[keyIndex] as K, this.elements[keyIndex + 1] as V];
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
private getKeyIndexOfOrNextLower<T>(
|
|
262
|
+
search: T,
|
|
263
|
+
comparator: (search: T, key: K, value: V) => number,
|
|
264
|
+
): number | undefined {
|
|
265
|
+
const { elements } = this;
|
|
266
|
+
if (elements.length === 0) {
|
|
267
|
+
return undefined;
|
|
268
|
+
}
|
|
269
|
+
let keyIndex = AppendOnlySortedMap.keyIndexOf(elements, search, comparator);
|
|
270
|
+
if (keyIndex < 0) {
|
|
271
|
+
keyIndex ^= AppendOnlySortedMap.failureXor;
|
|
272
|
+
if (keyIndex > 0) {
|
|
273
|
+
return keyIndex - 2;
|
|
274
|
+
}
|
|
275
|
+
return undefined;
|
|
276
|
+
}
|
|
277
|
+
return keyIndex;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
protected getPairOrNextHigherBy<T>(
|
|
281
|
+
search: T,
|
|
282
|
+
comparator: (search: T, key: K, value: V) => number,
|
|
283
|
+
): readonly [K, V] | undefined {
|
|
284
|
+
const keyIndex = this.getKeyIndexOfOrNextHigher(search, comparator);
|
|
285
|
+
if (keyIndex === undefined) {
|
|
286
|
+
return undefined;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return [this.elements[keyIndex] as K, this.elements[keyIndex + 1] as V];
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
private getKeyIndexOfOrNextHigher<T>(
|
|
293
|
+
search: T,
|
|
294
|
+
comparator: (search: T, key: K, value: V) => number,
|
|
295
|
+
): number | undefined {
|
|
296
|
+
const { elements } = this;
|
|
297
|
+
const { length } = elements;
|
|
298
|
+
if (length === 0) {
|
|
299
|
+
return undefined;
|
|
300
|
+
}
|
|
301
|
+
let keyIndex = AppendOnlySortedMap.keyIndexOf(elements, search, comparator);
|
|
302
|
+
if (keyIndex < 0) {
|
|
303
|
+
keyIndex ^= AppendOnlySortedMap.failureXor;
|
|
304
|
+
if (keyIndex < length) {
|
|
305
|
+
return keyIndex;
|
|
306
|
+
}
|
|
307
|
+
return undefined;
|
|
308
|
+
}
|
|
309
|
+
return keyIndex;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* The value xor'd with the result index when a search fails.
|
|
314
|
+
*/
|
|
315
|
+
public static readonly failureXor = -1;
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Performs a binary search on the sorted array.
|
|
319
|
+
* @returns the index of the key for `search`, or (if not present) the index it would have been inserted into xor'd
|
|
320
|
+
* with `failureXor`. Note that negating is not an adequate solution as that could result in -0.
|
|
321
|
+
*/
|
|
322
|
+
public static keyIndexOf<T, K, V>(
|
|
323
|
+
elements: readonly (K | V)[],
|
|
324
|
+
search: T,
|
|
325
|
+
comparator: (search: T, key: K, value: V) => number,
|
|
326
|
+
): number {
|
|
327
|
+
// Low, high, and mid are addresses of [K,V] pairs and *not* key indices
|
|
328
|
+
let low = 0;
|
|
329
|
+
let high = elements.length / 2;
|
|
330
|
+
let mid = high >> 1;
|
|
331
|
+
while (low < high) {
|
|
332
|
+
const keyIndex = mid * 2;
|
|
333
|
+
const c = comparator(search, elements[keyIndex] as K, elements[keyIndex + 1] as V);
|
|
334
|
+
if (c > 0) {
|
|
335
|
+
low = mid + 1;
|
|
336
|
+
} else if (c < 0) {
|
|
337
|
+
high = mid;
|
|
338
|
+
} else if (c === 0) {
|
|
339
|
+
return keyIndex;
|
|
340
|
+
} else {
|
|
341
|
+
fail("Invalid comparator.");
|
|
342
|
+
}
|
|
343
|
+
mid = (low + high) >> 1;
|
|
344
|
+
}
|
|
345
|
+
return (mid * 2) ^ AppendOnlySortedMap.failureXor;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* A map in which entries are always added in both key-sorted and value-sorted order.
|
|
351
|
+
* Supports appending and searching.
|
|
352
|
+
*/
|
|
353
|
+
export class AppendOnlyDoublySortedMap<K, V, S> extends AppendOnlySortedMap<K, V> {
|
|
354
|
+
public constructor(
|
|
355
|
+
keyComparator: (a: K, b: K) => number,
|
|
356
|
+
private readonly extractSearchValue: (value: V) => S,
|
|
357
|
+
private readonly valueComparator: (search: S, value: S) => number,
|
|
358
|
+
) {
|
|
359
|
+
super(keyComparator);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
public override append(key: K, value: V): void {
|
|
363
|
+
if (
|
|
364
|
+
this.elements.length !== 0 &&
|
|
365
|
+
this.valueComparator(
|
|
366
|
+
this.extractSearchValue(value),
|
|
367
|
+
this.extractSearchValue(this.maxValue() as V),
|
|
368
|
+
) <= 0
|
|
369
|
+
) {
|
|
370
|
+
fail("Inserted value must be > all others in the map.");
|
|
371
|
+
}
|
|
372
|
+
super.append(key, value);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
private readonly compareValues = (search: S, _: K, value: V): number => {
|
|
376
|
+
return this.valueComparator(search, this.extractSearchValue(value));
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
// /**
|
|
380
|
+
// * @param value - the value to lookup.
|
|
381
|
+
// * @returns the key associated with `value` if such an entry exists, and undefined otherwise.
|
|
382
|
+
// */
|
|
383
|
+
// public getByValue(value: S): K | undefined {
|
|
384
|
+
// const index = AppendOnlySortedMap.keyIndexOf(this.elements, value, this.compareValues);
|
|
385
|
+
// return this.elements[index]?.[0];
|
|
386
|
+
// }
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* @param searchValue - the search value to lookup.
|
|
390
|
+
* @returns the entry who's value, when run through the extractor provided to the constructor, matches
|
|
391
|
+
* `searchValue`. If no such entry exists, this method returns the next lower entry as determined by the value
|
|
392
|
+
* comparator provided to the constructor. If no such entry exists, this method returns undefined.
|
|
393
|
+
*/
|
|
394
|
+
public getPairOrNextLowerByValue(searchValue: S): readonly [K, V] | undefined {
|
|
395
|
+
return this.getPairOrNextLowerBy(searchValue, this.compareValues);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* @param searchValue - the search value to lookup.
|
|
400
|
+
* @returns the entry who's value, when run through the extractor provided to the constructor, matches `searchValue`. If no such entry
|
|
401
|
+
* exists, this method returns the next higher entry as determined by the value comparator provided to the constructor. If no such entry
|
|
402
|
+
* exists, this method returns undefined.
|
|
403
|
+
*/
|
|
404
|
+
public getPairOrNextHigherByValue(searchValue: S): readonly [K, V] | undefined {
|
|
405
|
+
return this.getPairOrNextHigherBy(searchValue, this.compareValues);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Test-only expensive assertions to check the internal validity of the data structure.
|
|
410
|
+
*/
|
|
411
|
+
public override assertValid(): void {
|
|
412
|
+
super.assertValid();
|
|
413
|
+
let prev: readonly [unknown, V] | undefined;
|
|
414
|
+
for (const kv of this.entries()) {
|
|
415
|
+
if (prev !== undefined) {
|
|
416
|
+
assert(
|
|
417
|
+
this.valueComparator(
|
|
418
|
+
this.extractSearchValue(kv[1]),
|
|
419
|
+
this.extractSearchValue(prev[1]),
|
|
420
|
+
) > 0,
|
|
421
|
+
0x480 /* Values in map must be sorted. */,
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
prev = kv;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|