@fluidframework/container-runtime 2.0.0-dev-rc.1.0.0.225277 → 2.0.0-dev-rc.1.0.0.232845
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 +34 -0
- package/README.md +0 -6
- package/api-report/container-runtime.api.md +14 -3
- package/dist/{batchTracker.cjs → batchTracker.js} +1 -1
- package/dist/batchTracker.js.map +1 -0
- package/dist/blobManager.d.ts.map +1 -1
- package/dist/{blobManager.cjs → blobManager.js} +9 -3
- package/dist/blobManager.js.map +1 -0
- package/dist/{connectionTelemetry.cjs → connectionTelemetry.js} +1 -1
- package/dist/connectionTelemetry.js.map +1 -0
- package/dist/container-runtime-alpha.d.ts +13 -3
- package/dist/container-runtime-beta.d.ts +7 -0
- package/dist/container-runtime-public.d.ts +7 -0
- package/dist/container-runtime-untrimmed.d.ts +30 -3
- package/dist/{containerHandleContext.cjs → containerHandleContext.js} +1 -1
- package/dist/containerHandleContext.js.map +1 -0
- package/dist/containerRuntime.d.ts +5 -2
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/{containerRuntime.cjs → containerRuntime.js} +78 -85
- package/dist/containerRuntime.js.map +1 -0
- package/dist/{dataStore.cjs → dataStore.js} +1 -1
- package/dist/dataStore.js.map +1 -0
- package/dist/dataStoreContext.d.ts +7 -1
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/{dataStoreContext.cjs → dataStoreContext.js} +13 -7
- package/dist/dataStoreContext.js.map +1 -0
- package/dist/{dataStoreContexts.cjs → dataStoreContexts.js} +1 -1
- package/dist/dataStoreContexts.js.map +1 -0
- package/dist/{dataStoreRegistry.cjs → dataStoreRegistry.js} +1 -1
- package/dist/dataStoreRegistry.js.map +1 -0
- package/dist/dataStores.d.ts +9 -3
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/{dataStores.cjs → dataStores.js} +62 -16
- package/dist/dataStores.js.map +1 -0
- package/dist/{deltaManagerProxyBase.cjs → deltaManagerProxyBase.js} +1 -1
- package/dist/deltaManagerProxyBase.js.map +1 -0
- package/dist/{deltaManagerSummarizerProxy.cjs → deltaManagerSummarizerProxy.js} +3 -3
- package/dist/deltaManagerSummarizerProxy.js.map +1 -0
- package/dist/{deltaScheduler.cjs → deltaScheduler.js} +1 -1
- package/dist/deltaScheduler.js.map +1 -0
- package/dist/{error.cjs → error.js} +1 -1
- package/dist/error.js.map +1 -0
- package/dist/gc/garbageCollection.d.ts +17 -1
- package/dist/gc/garbageCollection.d.ts.map +1 -1
- package/dist/gc/{garbageCollection.cjs → garbageCollection.js} +111 -42
- package/dist/gc/garbageCollection.js.map +1 -0
- package/dist/gc/{gcConfigs.cjs → gcConfigs.js} +3 -3
- package/dist/gc/gcConfigs.js.map +1 -0
- package/dist/gc/gcDefinitions.d.ts +20 -2
- package/dist/gc/gcDefinitions.d.ts.map +1 -1
- package/dist/gc/{gcDefinitions.cjs → gcDefinitions.js} +8 -2
- package/dist/gc/gcDefinitions.js.map +1 -0
- package/dist/gc/{gcHelpers.cjs → gcHelpers.js} +1 -1
- package/dist/gc/gcHelpers.js.map +1 -0
- package/dist/gc/{gcReferenceGraphAlgorithm.cjs → gcReferenceGraphAlgorithm.js} +1 -1
- package/dist/gc/gcReferenceGraphAlgorithm.js.map +1 -0
- package/dist/gc/{gcSummaryDefinitions.cjs → gcSummaryDefinitions.js} +1 -1
- package/dist/gc/gcSummaryDefinitions.js.map +1 -0
- package/dist/gc/{gcSummaryStateTracker.cjs → gcSummaryStateTracker.js} +2 -2
- package/dist/gc/gcSummaryStateTracker.js.map +1 -0
- package/dist/gc/gcTelemetry.d.ts +1 -0
- package/dist/gc/gcTelemetry.d.ts.map +1 -1
- package/dist/gc/{gcTelemetry.cjs → gcTelemetry.js} +2 -4
- package/dist/gc/gcTelemetry.js.map +1 -0
- package/dist/gc/gcUnreferencedStateTracker.d.ts +5 -0
- package/dist/gc/gcUnreferencedStateTracker.d.ts.map +1 -1
- package/dist/gc/{gcUnreferencedStateTracker.cjs → gcUnreferencedStateTracker.js} +14 -3
- package/dist/gc/{gcUnreferencedStateTracker.cjs.map → gcUnreferencedStateTracker.js.map} +1 -1
- package/dist/gc/index.d.ts +1 -1
- package/dist/gc/index.d.ts.map +1 -1
- package/dist/gc/{index.cjs → index.js} +11 -9
- package/dist/gc/index.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/{index.cjs → index.js} +10 -8
- package/dist/index.js.map +1 -0
- package/dist/messageTypes.d.ts +1 -1
- package/dist/{messageTypes.cjs → messageTypes.js} +1 -1
- package/dist/messageTypes.js.map +1 -0
- package/dist/{metadata.cjs → metadata.js} +1 -1
- package/dist/metadata.js.map +1 -0
- package/dist/opLifecycle/{batchManager.cjs → batchManager.js} +1 -1
- package/dist/opLifecycle/batchManager.js.map +1 -0
- package/dist/opLifecycle/{definitions.cjs → definitions.js} +1 -1
- package/dist/opLifecycle/definitions.js.map +1 -0
- package/dist/opLifecycle/{index.cjs → index.js} +8 -8
- package/dist/opLifecycle/index.js.map +1 -0
- package/dist/opLifecycle/{opCompressor.cjs → opCompressor.js} +3 -3
- package/dist/opLifecycle/opCompressor.js.map +1 -0
- package/dist/opLifecycle/{opDecompressor.cjs → opDecompressor.js} +2 -2
- package/dist/opLifecycle/opDecompressor.js.map +1 -0
- package/dist/opLifecycle/{opGroupingManager.cjs → opGroupingManager.js} +1 -1
- package/dist/opLifecycle/opGroupingManager.js.map +1 -0
- package/dist/opLifecycle/{opSplitter.cjs → opSplitter.js} +3 -3
- package/dist/opLifecycle/opSplitter.js.map +1 -0
- package/dist/opLifecycle/{outbox.cjs → outbox.js} +2 -2
- package/dist/opLifecycle/outbox.js.map +1 -0
- package/dist/opLifecycle/{remoteMessageProcessor.cjs → remoteMessageProcessor.js} +2 -2
- package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -0
- package/dist/{opProperties.cjs → opProperties.js} +1 -1
- package/dist/opProperties.js.map +1 -0
- package/dist/packageVersion.d.ts +1 -1
- package/dist/{packageVersion.cjs → packageVersion.js} +2 -2
- package/dist/packageVersion.js.map +1 -0
- package/dist/{pendingStateManager.cjs → pendingStateManager.js} +2 -2
- package/dist/pendingStateManager.js.map +1 -0
- package/dist/{scheduleManager.cjs → scheduleManager.js} +3 -3
- package/dist/scheduleManager.js.map +1 -0
- package/dist/{storageServiceWithAttachBlobs.cjs → storageServiceWithAttachBlobs.js} +1 -1
- package/dist/storageServiceWithAttachBlobs.js.map +1 -0
- package/dist/summary/{index.cjs → index.js} +12 -12
- package/dist/summary/index.js.map +1 -0
- package/dist/summary/{orderedClientElection.cjs → orderedClientElection.js} +2 -2
- package/dist/summary/orderedClientElection.js.map +1 -0
- package/dist/summary/{runWhileConnectedCoordinator.cjs → runWhileConnectedCoordinator.js} +1 -1
- package/dist/summary/runWhileConnectedCoordinator.js.map +1 -0
- package/dist/summary/runningSummarizer.d.ts +11 -6
- package/dist/summary/runningSummarizer.d.ts.map +1 -1
- package/dist/summary/{runningSummarizer.cjs → runningSummarizer.js} +140 -93
- package/dist/summary/runningSummarizer.js.map +1 -0
- package/dist/summary/{summarizer.cjs → summarizer.js} +4 -4
- package/dist/summary/summarizer.js.map +1 -0
- package/dist/summary/{summarizerClientElection.cjs → summarizerClientElection.js} +1 -1
- package/dist/summary/summarizerClientElection.js.map +1 -0
- package/dist/summary/{summarizerHeuristics.cjs → summarizerHeuristics.js} +1 -1
- package/dist/summary/summarizerHeuristics.js.map +1 -0
- package/dist/summary/summarizerNode/{index.cjs → index.js} +3 -3
- package/dist/summary/summarizerNode/index.js.map +1 -0
- package/dist/summary/summarizerNode/summarizerNode.d.ts +2 -3
- package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/dist/summary/summarizerNode/{summarizerNode.cjs → summarizerNode.js} +8 -50
- package/dist/summary/summarizerNode/summarizerNode.js.map +1 -0
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +1 -18
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/dist/summary/summarizerNode/{summarizerNodeUtils.cjs → summarizerNodeUtils.js} +2 -22
- package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -0
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +3 -3
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/dist/summary/summarizerNode/{summarizerNodeWithGc.cjs → summarizerNodeWithGc.js} +9 -9
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -0
- package/dist/summary/summarizerTypes.d.ts +3 -1
- package/dist/summary/summarizerTypes.d.ts.map +1 -1
- package/dist/summary/{summarizerTypes.cjs → summarizerTypes.js} +1 -1
- package/dist/summary/summarizerTypes.js.map +1 -0
- package/dist/summary/{summaryCollection.cjs → summaryCollection.js} +1 -1
- package/dist/summary/summaryCollection.js.map +1 -0
- package/dist/summary/{summaryFormat.cjs → summaryFormat.js} +1 -1
- package/dist/summary/summaryFormat.js.map +1 -0
- package/dist/summary/{summaryGenerator.cjs → summaryGenerator.js} +1 -1
- package/dist/summary/summaryGenerator.js.map +1 -0
- package/dist/summary/{summaryManager.cjs → summaryManager.js} +2 -2
- package/dist/summary/summaryManager.js.map +1 -0
- package/dist/{throttler.cjs → throttler.js} +1 -1
- package/dist/throttler.js.map +1 -0
- package/dist/tsdoc-metadata.json +1 -1
- package/lib/blobManager.d.mts.map +1 -1
- package/lib/blobManager.mjs +7 -1
- package/lib/blobManager.mjs.map +1 -1
- package/lib/container-runtime-alpha.d.mts +13 -3
- package/lib/container-runtime-beta.d.mts +7 -0
- package/lib/container-runtime-public.d.mts +7 -0
- package/lib/container-runtime-untrimmed.d.mts +30 -3
- package/lib/containerRuntime.d.mts +5 -2
- package/lib/containerRuntime.d.mts.map +1 -1
- package/lib/containerRuntime.mjs +62 -69
- package/lib/containerRuntime.mjs.map +1 -1
- package/lib/dataStoreContext.d.mts +7 -1
- package/lib/dataStoreContext.d.mts.map +1 -1
- package/lib/dataStoreContext.mjs +11 -5
- package/lib/dataStoreContext.mjs.map +1 -1
- package/lib/dataStores.d.mts +9 -3
- package/lib/dataStores.d.mts.map +1 -1
- package/lib/dataStores.mjs +54 -9
- package/lib/dataStores.mjs.map +1 -1
- package/lib/gc/garbageCollection.d.mts +17 -1
- package/lib/gc/garbageCollection.d.mts.map +1 -1
- package/lib/gc/garbageCollection.mjs +103 -34
- package/lib/gc/garbageCollection.mjs.map +1 -1
- package/lib/gc/gcDefinitions.d.mts +20 -2
- package/lib/gc/gcDefinitions.d.mts.map +1 -1
- package/lib/gc/gcDefinitions.mjs +6 -0
- package/lib/gc/gcDefinitions.mjs.map +1 -1
- package/lib/gc/gcTelemetry.d.mts +1 -0
- package/lib/gc/gcTelemetry.d.mts.map +1 -1
- package/lib/gc/gcTelemetry.mjs +0 -2
- package/lib/gc/gcTelemetry.mjs.map +1 -1
- package/lib/gc/gcUnreferencedStateTracker.d.mts +5 -0
- package/lib/gc/gcUnreferencedStateTracker.d.mts.map +1 -1
- package/lib/gc/gcUnreferencedStateTracker.mjs +10 -0
- package/lib/gc/gcUnreferencedStateTracker.mjs.map +1 -1
- package/lib/gc/index.d.mts +1 -1
- package/lib/gc/index.d.mts.map +1 -1
- package/lib/gc/index.mjs +1 -1
- package/lib/gc/index.mjs.map +1 -1
- package/lib/index.d.mts +2 -1
- package/lib/index.d.mts.map +1 -1
- package/lib/index.mjs +1 -0
- package/lib/index.mjs.map +1 -1
- package/lib/messageTypes.d.mts +1 -1
- package/lib/messageTypes.mjs.map +1 -1
- package/lib/packageVersion.d.mts +1 -1
- package/lib/packageVersion.mjs +1 -1
- package/lib/packageVersion.mjs.map +1 -1
- package/lib/summary/runningSummarizer.d.mts +11 -6
- package/lib/summary/runningSummarizer.d.mts.map +1 -1
- package/lib/summary/runningSummarizer.mjs +136 -89
- package/lib/summary/runningSummarizer.mjs.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.d.mts +2 -3
- package/lib/summary/summarizerNode/summarizerNode.d.mts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.mjs +8 -50
- package/lib/summary/summarizerNode/summarizerNode.mjs.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.mts +1 -18
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.mts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.mjs +0 -19
- package/lib/summary/summarizerNode/summarizerNodeUtils.mjs.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.mts +3 -3
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.mts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.mjs +5 -5
- package/lib/summary/summarizerNode/summarizerNodeWithGc.mjs.map +1 -1
- package/lib/summary/summarizerTypes.d.mts +3 -1
- package/lib/summary/summarizerTypes.d.mts.map +1 -1
- package/lib/summary/summarizerTypes.mjs.map +1 -1
- package/package.json +48 -38
- package/src/blobManager.ts +7 -1
- package/src/containerRuntime.ts +103 -85
- package/src/dataStoreContext.ts +15 -6
- package/src/dataStores.ts +64 -6
- package/src/gc/garbageCollection.ts +118 -32
- package/src/gc/gcDefinitions.ts +21 -3
- package/src/gc/gcTelemetry.ts +1 -2
- package/src/gc/gcUnreferencedStateTracker.ts +11 -0
- package/src/gc/index.ts +3 -0
- package/src/index.ts +2 -0
- package/src/messageTypes.ts +1 -1
- package/src/packageVersion.ts +1 -1
- package/src/summary/runningSummarizer.ts +174 -113
- package/src/summary/summarizerNode/summarizerNode.ts +4 -64
- package/src/summary/summarizerNode/summarizerNodeUtils.ts +2 -33
- package/src/summary/summarizerNode/summarizerNodeWithGc.ts +0 -6
- package/src/summary/summarizerTypes.ts +3 -1
- package/dist/batchTracker.cjs.map +0 -1
- package/dist/blobManager.cjs.map +0 -1
- package/dist/connectionTelemetry.cjs.map +0 -1
- package/dist/containerHandleContext.cjs.map +0 -1
- package/dist/containerRuntime.cjs.map +0 -1
- package/dist/dataStore.cjs.map +0 -1
- package/dist/dataStoreContext.cjs.map +0 -1
- package/dist/dataStoreContexts.cjs.map +0 -1
- package/dist/dataStoreRegistry.cjs.map +0 -1
- package/dist/dataStores.cjs.map +0 -1
- package/dist/deltaManagerProxyBase.cjs.map +0 -1
- package/dist/deltaManagerSummarizerProxy.cjs.map +0 -1
- package/dist/deltaScheduler.cjs.map +0 -1
- package/dist/error.cjs.map +0 -1
- package/dist/gc/garbageCollection.cjs.map +0 -1
- package/dist/gc/gcConfigs.cjs.map +0 -1
- package/dist/gc/gcDefinitions.cjs.map +0 -1
- package/dist/gc/gcHelpers.cjs.map +0 -1
- package/dist/gc/gcReferenceGraphAlgorithm.cjs.map +0 -1
- package/dist/gc/gcSummaryDefinitions.cjs.map +0 -1
- package/dist/gc/gcSummaryStateTracker.cjs.map +0 -1
- package/dist/gc/gcTelemetry.cjs.map +0 -1
- package/dist/gc/index.cjs.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/messageTypes.cjs.map +0 -1
- package/dist/metadata.cjs.map +0 -1
- package/dist/opLifecycle/batchManager.cjs.map +0 -1
- package/dist/opLifecycle/definitions.cjs.map +0 -1
- package/dist/opLifecycle/index.cjs.map +0 -1
- package/dist/opLifecycle/opCompressor.cjs.map +0 -1
- package/dist/opLifecycle/opDecompressor.cjs.map +0 -1
- package/dist/opLifecycle/opGroupingManager.cjs.map +0 -1
- package/dist/opLifecycle/opSplitter.cjs.map +0 -1
- package/dist/opLifecycle/outbox.cjs.map +0 -1
- package/dist/opLifecycle/remoteMessageProcessor.cjs.map +0 -1
- package/dist/opProperties.cjs.map +0 -1
- package/dist/packageVersion.cjs.map +0 -1
- package/dist/pendingStateManager.cjs.map +0 -1
- package/dist/scheduleManager.cjs.map +0 -1
- package/dist/storageServiceWithAttachBlobs.cjs.map +0 -1
- package/dist/summary/index.cjs.map +0 -1
- package/dist/summary/orderedClientElection.cjs.map +0 -1
- package/dist/summary/runWhileConnectedCoordinator.cjs.map +0 -1
- package/dist/summary/runningSummarizer.cjs.map +0 -1
- package/dist/summary/summarizer.cjs.map +0 -1
- package/dist/summary/summarizerClientElection.cjs.map +0 -1
- package/dist/summary/summarizerHeuristics.cjs.map +0 -1
- package/dist/summary/summarizerNode/index.cjs.map +0 -1
- package/dist/summary/summarizerNode/summarizerNode.cjs.map +0 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.cjs.map +0 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.cjs.map +0 -1
- package/dist/summary/summarizerTypes.cjs.map +0 -1
- package/dist/summary/summaryCollection.cjs.map +0 -1
- package/dist/summary/summaryFormat.cjs.map +0 -1
- package/dist/summary/summaryGenerator.cjs.map +0 -1
- package/dist/summary/summaryManager.cjs.map +0 -1
- package/dist/throttler.cjs.map +0 -1
- package/tsc-multi.test.json +0 -4
- /package/{.eslintrc.js → .eslintrc.cjs} +0 -0
package/src/containerRuntime.ts
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
IRequest,
|
|
12
12
|
IResponse,
|
|
13
13
|
IProvideFluidHandleContext,
|
|
14
|
+
ISignalEnvelope,
|
|
14
15
|
} from "@fluidframework/core-interfaces";
|
|
15
16
|
import {
|
|
16
17
|
IAudience,
|
|
@@ -46,12 +47,13 @@ import {
|
|
|
46
47
|
ITelemetryLoggerExt,
|
|
47
48
|
UsageError,
|
|
48
49
|
LoggingError,
|
|
50
|
+
createSampledLogger,
|
|
51
|
+
IEventSampler,
|
|
49
52
|
} from "@fluidframework/telemetry-utils";
|
|
50
53
|
import {
|
|
51
54
|
DriverHeader,
|
|
52
55
|
FetchSource,
|
|
53
56
|
IDocumentStorageService,
|
|
54
|
-
ISummaryContext,
|
|
55
57
|
} from "@fluidframework/driver-definitions";
|
|
56
58
|
import { readAndParse } from "@fluidframework/driver-utils";
|
|
57
59
|
import {
|
|
@@ -77,7 +79,6 @@ import {
|
|
|
77
79
|
IGarbageCollectionData,
|
|
78
80
|
IEnvelope,
|
|
79
81
|
IInboundSignalMessage,
|
|
80
|
-
ISignalEnvelope,
|
|
81
82
|
NamedFluidDataStoreRegistryEntries,
|
|
82
83
|
ISummaryTreeWithStats,
|
|
83
84
|
ISummarizeInternalResult,
|
|
@@ -862,14 +863,34 @@ export class ContainerRuntime
|
|
|
862
863
|
"@fluidframework/id-compressor"
|
|
863
864
|
);
|
|
864
865
|
|
|
865
|
-
|
|
866
|
+
/**
|
|
867
|
+
* Because the IdCompressor emits so much telemetry, this function is used to sample
|
|
868
|
+
* approximately 5% of all clients. Only the given percentage of sessions will emit telemetry.
|
|
869
|
+
*/
|
|
870
|
+
const idCompressorEventSampler: IEventSampler = (() => {
|
|
871
|
+
const isIdCompressorTelemetryEnabled = Math.random() < 0.05;
|
|
872
|
+
return {
|
|
873
|
+
sample: () => {
|
|
874
|
+
return isIdCompressorTelemetryEnabled;
|
|
875
|
+
},
|
|
876
|
+
};
|
|
877
|
+
})();
|
|
866
878
|
|
|
879
|
+
const compressorLogger = createSampledLogger(logger, idCompressorEventSampler);
|
|
880
|
+
const pendingLocalState = context.pendingLocalState as IPendingRuntimeState;
|
|
867
881
|
if (pendingLocalState?.pendingIdCompressorState !== undefined) {
|
|
868
|
-
idCompressor = deserializeIdCompressor(
|
|
882
|
+
idCompressor = deserializeIdCompressor(
|
|
883
|
+
pendingLocalState.pendingIdCompressorState,
|
|
884
|
+
compressorLogger,
|
|
885
|
+
);
|
|
869
886
|
} else if (serializedIdCompressor !== undefined) {
|
|
870
|
-
idCompressor = deserializeIdCompressor(
|
|
887
|
+
idCompressor = deserializeIdCompressor(
|
|
888
|
+
serializedIdCompressor,
|
|
889
|
+
createSessionId(),
|
|
890
|
+
compressorLogger,
|
|
891
|
+
);
|
|
871
892
|
} else {
|
|
872
|
-
idCompressor = createIdCompressor(
|
|
893
|
+
idCompressor = createIdCompressor(compressorLogger);
|
|
873
894
|
}
|
|
874
895
|
}
|
|
875
896
|
|
|
@@ -1371,15 +1392,17 @@ export class ContainerRuntime
|
|
|
1371
1392
|
|
|
1372
1393
|
const pendingRuntimeState = pendingLocalState as IPendingRuntimeState | undefined;
|
|
1373
1394
|
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1395
|
+
if (context.attachState === AttachState.Attached) {
|
|
1396
|
+
const maxSnapshotCacheDurationMs = this._storage?.policies?.maximumCacheDurationMs;
|
|
1397
|
+
if (
|
|
1398
|
+
maxSnapshotCacheDurationMs !== undefined &&
|
|
1399
|
+
maxSnapshotCacheDurationMs > 5 * 24 * 60 * 60 * 1000
|
|
1400
|
+
) {
|
|
1401
|
+
// This is a runtime enforcement of what's already explicit in the policy's type itself,
|
|
1402
|
+
// which dictates the value is either undefined or exactly 5 days in ms.
|
|
1403
|
+
// As long as the actual value is less than 5 days, the assumptions GC makes here are valid.
|
|
1404
|
+
throw new UsageError("Driver's maximumCacheDurationMs policy cannot exceed 5 days");
|
|
1405
|
+
}
|
|
1383
1406
|
}
|
|
1384
1407
|
|
|
1385
1408
|
this.garbageCollector = GarbageCollector.create({
|
|
@@ -1411,9 +1434,6 @@ export class ContainerRuntime
|
|
|
1411
1434
|
// Must set to false to prevent sending summary handle which would be pointing to
|
|
1412
1435
|
// a summary with an older protocol state.
|
|
1413
1436
|
canReuseHandle: false,
|
|
1414
|
-
// Must set to true to throw on any data stores failure that was too severe to be handled.
|
|
1415
|
-
// We also are not decoding the base summaries at the root.
|
|
1416
|
-
throwOnFailure: true,
|
|
1417
1437
|
// If GC should not run, let the summarizer node know so that it does not track GC state.
|
|
1418
1438
|
gcDisabled: !this.garbageCollector.shouldRunGC,
|
|
1419
1439
|
},
|
|
@@ -2054,6 +2074,8 @@ export class ContainerRuntime
|
|
|
2054
2074
|
this.closeFn(error);
|
|
2055
2075
|
throw error;
|
|
2056
2076
|
}
|
|
2077
|
+
// Note: Even if its compat behavior allows it, we don't know how to apply this stashed op.
|
|
2078
|
+
// All we can do is ignore it (similar to on process).
|
|
2057
2079
|
}
|
|
2058
2080
|
}
|
|
2059
2081
|
}
|
|
@@ -2268,6 +2290,7 @@ export class ContainerRuntime
|
|
|
2268
2290
|
messageWithContext.message,
|
|
2269
2291
|
local,
|
|
2270
2292
|
localOpMetadata,
|
|
2293
|
+
(from, to) => this.garbageCollector.addedOutboundReference(from, to),
|
|
2271
2294
|
);
|
|
2272
2295
|
break;
|
|
2273
2296
|
case ContainerMessageType.BlobAttach:
|
|
@@ -2407,6 +2430,9 @@ export class ContainerRuntime
|
|
|
2407
2430
|
assert(this.outbox.isEmpty, 0x3cf /* reentrancy */);
|
|
2408
2431
|
}
|
|
2409
2432
|
|
|
2433
|
+
/**
|
|
2434
|
+
* {@inheritDoc @fluidframework/runtime-definitions#IContainerRuntimeBase.orderSequentially}
|
|
2435
|
+
*/
|
|
2410
2436
|
public orderSequentially<T>(callback: () => T): T {
|
|
2411
2437
|
let checkpoint: IBatchCheckpoint | undefined;
|
|
2412
2438
|
let result: T;
|
|
@@ -2438,9 +2464,21 @@ export class ContainerRuntime
|
|
|
2438
2464
|
throw error2;
|
|
2439
2465
|
}
|
|
2440
2466
|
} else {
|
|
2441
|
-
|
|
2442
|
-
|
|
2467
|
+
this.closeFn(
|
|
2468
|
+
wrapError(
|
|
2469
|
+
error,
|
|
2470
|
+
(errorMessage) =>
|
|
2471
|
+
new GenericError(
|
|
2472
|
+
`orderSequentially callback exception: ${errorMessage}`,
|
|
2473
|
+
error,
|
|
2474
|
+
{
|
|
2475
|
+
orderSequentiallyCalls: this._orderSequentiallyCalls,
|
|
2476
|
+
},
|
|
2477
|
+
),
|
|
2478
|
+
),
|
|
2479
|
+
);
|
|
2443
2480
|
}
|
|
2481
|
+
|
|
2444
2482
|
throw error; // throw the original error for the consumer of the runtime
|
|
2445
2483
|
} finally {
|
|
2446
2484
|
this._orderSequentiallyCalls--;
|
|
@@ -2495,15 +2533,23 @@ export class ContainerRuntime
|
|
|
2495
2533
|
return this.dataStores.createDetachedDataStoreCore(pkg, true, rootDataStoreId);
|
|
2496
2534
|
}
|
|
2497
2535
|
|
|
2498
|
-
public createDetachedDataStore(
|
|
2499
|
-
|
|
2536
|
+
public createDetachedDataStore(
|
|
2537
|
+
pkg: Readonly<string[]>,
|
|
2538
|
+
groupId?: string,
|
|
2539
|
+
): IFluidDataStoreContextDetached {
|
|
2540
|
+
return this.dataStores.createDetachedDataStoreCore(pkg, false, undefined, groupId);
|
|
2500
2541
|
}
|
|
2501
2542
|
|
|
2502
|
-
public async createDataStore(pkg: string | string[]): Promise<IDataStore> {
|
|
2543
|
+
public async createDataStore(pkg: string | string[], groupId?: string): Promise<IDataStore> {
|
|
2503
2544
|
const id = uuid();
|
|
2504
2545
|
return channelToDataStore(
|
|
2505
2546
|
await this.dataStores
|
|
2506
|
-
._createFluidDataStoreContext(
|
|
2547
|
+
._createFluidDataStoreContext(
|
|
2548
|
+
Array.isArray(pkg) ? pkg : [pkg],
|
|
2549
|
+
id,
|
|
2550
|
+
undefined,
|
|
2551
|
+
groupId,
|
|
2552
|
+
)
|
|
2507
2553
|
.realize(),
|
|
2508
2554
|
id,
|
|
2509
2555
|
this,
|
|
@@ -2679,6 +2725,12 @@ export class ContainerRuntime
|
|
|
2679
2725
|
this.blobManager.setRedirectTable(blobRedirectTable);
|
|
2680
2726
|
}
|
|
2681
2727
|
|
|
2728
|
+
// We can finalize any allocated IDs since we're the only client
|
|
2729
|
+
const idRange = this.idCompressor?.takeNextCreationRange();
|
|
2730
|
+
if (idRange !== undefined) {
|
|
2731
|
+
this.idCompressor?.finalizeCreationRange(idRange);
|
|
2732
|
+
}
|
|
2733
|
+
|
|
2682
2734
|
const summarizeResult = this.dataStores.createSummary(telemetryContext);
|
|
2683
2735
|
// Wrap data store summaries in .channels subtree.
|
|
2684
2736
|
wrapSummaryInChannelsTree(summarizeResult);
|
|
@@ -2898,6 +2950,12 @@ export class ContainerRuntime
|
|
|
2898
2950
|
* data store or an attachment blob.
|
|
2899
2951
|
*/
|
|
2900
2952
|
public async getGCNodePackagePath(nodePath: string): Promise<readonly string[] | undefined> {
|
|
2953
|
+
// GC uses "/" when adding "root" references, e.g. for Aliasing or as part of Tombstone Auto-Recovery.
|
|
2954
|
+
// These have no package path so return a special value.
|
|
2955
|
+
if (nodePath === "/") {
|
|
2956
|
+
return ["<GCROOT>"];
|
|
2957
|
+
}
|
|
2958
|
+
|
|
2901
2959
|
switch (this.getNodeType(nodePath)) {
|
|
2902
2960
|
case GCNodeType.Blob:
|
|
2903
2961
|
return [BlobManager.basePath];
|
|
@@ -2993,7 +3051,6 @@ export class ContainerRuntime
|
|
|
2993
3051
|
assert(this.outbox.isEmpty, 0x3d1 /* Can't trigger summary in the middle of a batch */);
|
|
2994
3052
|
|
|
2995
3053
|
// We close the summarizer and download a new snapshot and reload the container
|
|
2996
|
-
let latestSnapshotVersionId: string | undefined;
|
|
2997
3054
|
if (refreshLatestAck === true) {
|
|
2998
3055
|
return this.prefetchLatestSummaryThenClose(
|
|
2999
3056
|
createChildLogger({
|
|
@@ -3209,34 +3266,18 @@ export class ContainerRuntime
|
|
|
3209
3266
|
return { stage: "generate", ...generateSummaryData, error: continueResult.error };
|
|
3210
3267
|
}
|
|
3211
3268
|
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
ackHandle: latestSnapshotVersionId,
|
|
3225
|
-
referenceSequenceNumber: summaryRefSeqNum,
|
|
3226
|
-
};
|
|
3227
|
-
} else if (lastAck === undefined) {
|
|
3228
|
-
summaryContext = {
|
|
3229
|
-
proposalHandle: undefined,
|
|
3230
|
-
ackHandle: this.loadedFromVersionId,
|
|
3231
|
-
referenceSequenceNumber: summaryRefSeqNum,
|
|
3232
|
-
};
|
|
3233
|
-
} else {
|
|
3234
|
-
summaryContext = {
|
|
3235
|
-
proposalHandle: lastAck.summaryOp.contents.handle,
|
|
3236
|
-
ackHandle: lastAck.summaryAck.contents.handle,
|
|
3237
|
-
referenceSequenceNumber: summaryRefSeqNum,
|
|
3238
|
-
};
|
|
3239
|
-
}
|
|
3269
|
+
const summaryContext =
|
|
3270
|
+
lastAck === undefined
|
|
3271
|
+
? {
|
|
3272
|
+
proposalHandle: undefined,
|
|
3273
|
+
ackHandle: this.loadedFromVersionId,
|
|
3274
|
+
referenceSequenceNumber: summaryRefSeqNum,
|
|
3275
|
+
}
|
|
3276
|
+
: {
|
|
3277
|
+
proposalHandle: lastAck.summaryOp.contents.handle,
|
|
3278
|
+
ackHandle: lastAck.summaryAck.contents.handle,
|
|
3279
|
+
referenceSequenceNumber: summaryRefSeqNum,
|
|
3280
|
+
};
|
|
3240
3281
|
|
|
3241
3282
|
let handle: string;
|
|
3242
3283
|
try {
|
|
@@ -3680,6 +3721,7 @@ export class ContainerRuntime
|
|
|
3680
3721
|
localOpMetadata: unknown,
|
|
3681
3722
|
opMetadata: Record<string, unknown> | undefined,
|
|
3682
3723
|
) {
|
|
3724
|
+
assert(!this.isSummarizerClient, "Summarizer never reconnects so should never resubmit");
|
|
3683
3725
|
switch (message.type) {
|
|
3684
3726
|
case ContainerMessageType.FluidDataStoreOp:
|
|
3685
3727
|
// For Operations, call resubmitDataStoreOp which will find the right store
|
|
@@ -3701,13 +3743,14 @@ export class ContainerRuntime
|
|
|
3701
3743
|
this.submit(message);
|
|
3702
3744
|
break;
|
|
3703
3745
|
case ContainerMessageType.GC:
|
|
3704
|
-
|
|
3705
|
-
|
|
3746
|
+
this.submit(message);
|
|
3747
|
+
break;
|
|
3706
3748
|
default: {
|
|
3707
3749
|
// This case should be very rare - it would imply an op was stashed from a
|
|
3708
|
-
// future version of runtime code and now is being applied on an older version
|
|
3750
|
+
// future version of runtime code and now is being applied on an older version.
|
|
3709
3751
|
const compatBehavior = message.compatDetails?.behavior;
|
|
3710
3752
|
if (compatBehaviorAllowsMessageType(message.type, compatBehavior)) {
|
|
3753
|
+
// We do not ultimately resubmit it, to be consistent with this version of the code.
|
|
3711
3754
|
this.logger.sendTelemetryEvent({
|
|
3712
3755
|
eventName: "resubmitUnrecognizedMessageTypeAllowed",
|
|
3713
3756
|
messageDetails: { type: message.type, compatBehavior },
|
|
@@ -3764,7 +3807,7 @@ export class ContainerRuntime
|
|
|
3764
3807
|
* and then close as the current main client is likely to be re-elected as the parent summarizer again.
|
|
3765
3808
|
*/
|
|
3766
3809
|
if (!result.isSummaryTracked && result.isSummaryNewer) {
|
|
3767
|
-
|
|
3810
|
+
await this.fetchLatestSnapshotFromStorage(
|
|
3768
3811
|
summaryLogger,
|
|
3769
3812
|
{
|
|
3770
3813
|
eventName: "RefreshLatestSummaryAckFetch",
|
|
@@ -3774,32 +3817,7 @@ export class ContainerRuntime
|
|
|
3774
3817
|
readAndParseBlob,
|
|
3775
3818
|
);
|
|
3776
3819
|
|
|
3777
|
-
|
|
3778
|
-
* If the fetched snapshot is older than the one for which the ack was received, close the container.
|
|
3779
|
-
* This should never happen because an ack should be sent after the latest summary is updated in the server.
|
|
3780
|
-
* However, there are couple of scenarios where it's possible:
|
|
3781
|
-
* 1. A file was modified externally resulting in modifying the snapshot's sequence number. This can lead to
|
|
3782
|
-
* the document being unusable and we should not proceed.
|
|
3783
|
-
* 2. The server DB failed after the ack was sent which may delete the corresponding snapshot. Ideally, in
|
|
3784
|
-
* such cases, the file will be rolled back along with the ack and we will eventually reach a consistent
|
|
3785
|
-
* state.
|
|
3786
|
-
*/
|
|
3787
|
-
if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
|
|
3788
|
-
const error = DataProcessingError.create(
|
|
3789
|
-
"Fetched snapshot is older than the received ack",
|
|
3790
|
-
"RefreshLatestSummaryAck",
|
|
3791
|
-
undefined /* sequencedMessage */,
|
|
3792
|
-
{
|
|
3793
|
-
ackHandle,
|
|
3794
|
-
summaryRefSeq,
|
|
3795
|
-
fetchedSnapshotRefSeq: fetchResult.latestSnapshotRefSeq,
|
|
3796
|
-
},
|
|
3797
|
-
);
|
|
3798
|
-
this.disposeFn(error);
|
|
3799
|
-
throw error;
|
|
3800
|
-
}
|
|
3801
|
-
|
|
3802
|
-
await this.closeStaleSummarizer("RefreshLatestSummaryAckFetch");
|
|
3820
|
+
await this.closeStaleSummarizer();
|
|
3803
3821
|
return;
|
|
3804
3822
|
}
|
|
3805
3823
|
|
|
@@ -3828,7 +3846,7 @@ export class ContainerRuntime
|
|
|
3828
3846
|
readAndParseBlob,
|
|
3829
3847
|
);
|
|
3830
3848
|
|
|
3831
|
-
await this.closeStaleSummarizer(
|
|
3849
|
+
await this.closeStaleSummarizer();
|
|
3832
3850
|
|
|
3833
3851
|
return {
|
|
3834
3852
|
stage: "base",
|
|
@@ -3838,7 +3856,7 @@ export class ContainerRuntime
|
|
|
3838
3856
|
};
|
|
3839
3857
|
}
|
|
3840
3858
|
|
|
3841
|
-
private async closeStaleSummarizer(
|
|
3859
|
+
private async closeStaleSummarizer(): Promise<void> {
|
|
3842
3860
|
// Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
|
|
3843
3861
|
await delay(this.closeSummarizerDelayMs);
|
|
3844
3862
|
this._summarizer?.stop("latestSummaryStateStale");
|
package/src/dataStoreContext.ts
CHANGED
|
@@ -50,8 +50,6 @@ import {
|
|
|
50
50
|
ISummarizerNodeWithGC,
|
|
51
51
|
SummarizeInternalFn,
|
|
52
52
|
ITelemetryContext,
|
|
53
|
-
IIdCompressor,
|
|
54
|
-
IIdCompressorCore,
|
|
55
53
|
VisibilityState,
|
|
56
54
|
} from "@fluidframework/runtime-definitions";
|
|
57
55
|
import { addBlobToSummary, convertSummaryTreeToITree } from "@fluidframework/runtime-utils";
|
|
@@ -67,6 +65,7 @@ import {
|
|
|
67
65
|
tagCodeArtifacts,
|
|
68
66
|
ThresholdCounter,
|
|
69
67
|
} from "@fluidframework/telemetry-utils";
|
|
68
|
+
import { IIdCompressor, IIdCompressorCore } from "@fluidframework/id-compressor";
|
|
70
69
|
import {
|
|
71
70
|
dataStoreAttributesBlobName,
|
|
72
71
|
hasIsolatedChannels,
|
|
@@ -78,7 +77,7 @@ import {
|
|
|
78
77
|
summarizerClientType,
|
|
79
78
|
} from "./summary";
|
|
80
79
|
import { ContainerRuntime } from "./containerRuntime";
|
|
81
|
-
import { sendGCUnexpectedUsageEvent } from "./gc";
|
|
80
|
+
import { detectOutboundRoutesViaDDSKey, sendGCUnexpectedUsageEvent } from "./gc";
|
|
82
81
|
|
|
83
82
|
function createAttributes(
|
|
84
83
|
pkg: readonly string[],
|
|
@@ -115,6 +114,7 @@ export interface IFluidDataStoreContextProps {
|
|
|
115
114
|
readonly scope: FluidObject;
|
|
116
115
|
readonly createSummarizerNodeFn: CreateChildSummarizerNodeFn;
|
|
117
116
|
readonly pkg?: Readonly<string[]>;
|
|
117
|
+
readonly groupId?: string;
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
/** Properties necessary for creating a local FluidDataStoreContext */
|
|
@@ -272,6 +272,8 @@ export abstract class FluidDataStoreContext
|
|
|
272
272
|
private readonly _containerRuntime: ContainerRuntime;
|
|
273
273
|
public readonly storage: IDocumentStorageService;
|
|
274
274
|
public readonly scope: FluidObject;
|
|
275
|
+
// Represents the group to which the data store belongs too.
|
|
276
|
+
public readonly groupId: string | undefined;
|
|
275
277
|
protected pkg?: readonly string[];
|
|
276
278
|
|
|
277
279
|
constructor(
|
|
@@ -287,6 +289,7 @@ export abstract class FluidDataStoreContext
|
|
|
287
289
|
this.storage = props.storage;
|
|
288
290
|
this.scope = props.scope;
|
|
289
291
|
this.pkg = props.pkg;
|
|
292
|
+
this.groupId = props.groupId;
|
|
290
293
|
|
|
291
294
|
// URIs use slashes as delimiters. Handles use URIs.
|
|
292
295
|
// Thus having slashes in types almost guarantees trouble down the road!
|
|
@@ -650,13 +653,20 @@ export abstract class FluidDataStoreContext
|
|
|
650
653
|
}
|
|
651
654
|
|
|
652
655
|
/**
|
|
656
|
+
* @deprecated There is no replacement for this, its functionality is no longer needed.
|
|
657
|
+
* It will be removed in a future release, sometime after 2.0.0-internal.8.0.0
|
|
658
|
+
*
|
|
653
659
|
* Called when a new outbound reference is added to another node. This is used by garbage collection to identify
|
|
654
660
|
* all references added in the system.
|
|
655
661
|
* @param srcHandle - The handle of the node that added the reference.
|
|
656
662
|
* @param outboundHandle - The handle of the outbound node that is referenced.
|
|
657
663
|
*/
|
|
658
664
|
public addedGCOutboundReference(srcHandle: IFluidHandle, outboundHandle: IFluidHandle) {
|
|
659
|
-
this.
|
|
665
|
+
// By default, skip this call since the ContainerRuntime will detect the outbound route directly.
|
|
666
|
+
if (this.mc.config.getBoolean(detectOutboundRoutesViaDDSKey) === true) {
|
|
667
|
+
// Note: The ContainerRuntime code will check this same setting to avoid double counting.
|
|
668
|
+
this._containerRuntime.addedGCOutboundReference(srcHandle, outboundHandle);
|
|
669
|
+
}
|
|
660
670
|
}
|
|
661
671
|
|
|
662
672
|
/**
|
|
@@ -941,8 +951,7 @@ export abstract class FluidDataStoreContext
|
|
|
941
951
|
summarizeInternal,
|
|
942
952
|
id,
|
|
943
953
|
createParam,
|
|
944
|
-
|
|
945
|
-
{ throwOnFailure: true },
|
|
954
|
+
undefined /* config */,
|
|
946
955
|
getGCDataFn,
|
|
947
956
|
);
|
|
948
957
|
}
|
package/src/dataStores.ts
CHANGED
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
create404Response,
|
|
34
34
|
createResponseError,
|
|
35
35
|
GCDataBuilder,
|
|
36
|
+
isSerializedHandle,
|
|
36
37
|
responseToException,
|
|
37
38
|
SummaryTreeBuilder,
|
|
38
39
|
unpackChildNodesUsedRoutes,
|
|
@@ -61,7 +62,7 @@ import {
|
|
|
61
62
|
} from "./dataStoreContext";
|
|
62
63
|
import { StorageServiceWithAttachBlobs } from "./storageServiceWithAttachBlobs";
|
|
63
64
|
import { IDataStoreAliasMessage, isDataStoreAliasMessage } from "./dataStore";
|
|
64
|
-
import { GCNodeType, disableDatastoreSweepKey } from "./gc";
|
|
65
|
+
import { GCNodeType, detectOutboundRoutesViaDDSKey, disableDatastoreSweepKey } from "./gc";
|
|
65
66
|
import { IContainerRuntimeMetadata, nonDataStorePaths, rootHasIsolatedChannels } from "./summary";
|
|
66
67
|
|
|
67
68
|
type PendingAliasResolve = (success: boolean) => void;
|
|
@@ -152,6 +153,7 @@ export class DataStores implements IDisposable {
|
|
|
152
153
|
createSummarizerNodeFn: this.getCreateChildSummarizerNodeFn(key, {
|
|
153
154
|
type: CreateSummarizerNodeSource.FromSummary,
|
|
154
155
|
}),
|
|
156
|
+
groupId: value.groupId,
|
|
155
157
|
});
|
|
156
158
|
} else {
|
|
157
159
|
if (typeof value !== "object") {
|
|
@@ -238,6 +240,7 @@ export class DataStores implements IDisposable {
|
|
|
238
240
|
runtime: this.runtime,
|
|
239
241
|
storage: new StorageServiceWithAttachBlobs(this.runtime.storage, flatAttachBlobs),
|
|
240
242
|
scope: this.runtime.scope,
|
|
243
|
+
groupId: snapshotTree?.groupId,
|
|
241
244
|
createSummarizerNodeFn: this.getCreateChildSummarizerNodeFn(attachMessage.id, {
|
|
242
245
|
type: CreateSummarizerNodeSource.FromAttach,
|
|
243
246
|
sequenceNumber: message.sequenceNumber,
|
|
@@ -343,6 +346,7 @@ export class DataStores implements IDisposable {
|
|
|
343
346
|
pkg: Readonly<string[]>,
|
|
344
347
|
isRoot: boolean,
|
|
345
348
|
id = uuid(),
|
|
349
|
+
groupId?: string,
|
|
346
350
|
): IFluidDataStoreContextDetached {
|
|
347
351
|
assert(!id.includes("/"), 0x30c /* Id cannot contain slashes */);
|
|
348
352
|
|
|
@@ -358,12 +362,13 @@ export class DataStores implements IDisposable {
|
|
|
358
362
|
makeLocallyVisibleFn: () => this.makeDataStoreLocallyVisible(id),
|
|
359
363
|
snapshotTree: undefined,
|
|
360
364
|
isRootDataStore: isRoot,
|
|
365
|
+
groupId,
|
|
361
366
|
});
|
|
362
367
|
this.contexts.addUnbound(context);
|
|
363
368
|
return context;
|
|
364
369
|
}
|
|
365
370
|
|
|
366
|
-
public _createFluidDataStoreContext(pkg: string[], id: string, props?: any) {
|
|
371
|
+
public _createFluidDataStoreContext(pkg: string[], id: string, props?: any, groupId?: string) {
|
|
367
372
|
assert(!id.includes("/"), 0x30d /* Id cannot contain slashes */);
|
|
368
373
|
const context = new LocalFluidDataStoreContext({
|
|
369
374
|
id,
|
|
@@ -378,6 +383,7 @@ export class DataStores implements IDisposable {
|
|
|
378
383
|
snapshotTree: undefined,
|
|
379
384
|
isRootDataStore: false,
|
|
380
385
|
createProps: props,
|
|
386
|
+
groupId,
|
|
381
387
|
});
|
|
382
388
|
this.contexts.addUnbound(context);
|
|
383
389
|
return context;
|
|
@@ -441,6 +447,7 @@ export class DataStores implements IDisposable {
|
|
|
441
447
|
message: ISequencedDocumentMessage,
|
|
442
448
|
local: boolean,
|
|
443
449
|
localMessageMetadata: unknown,
|
|
450
|
+
addedOutboundReference: (fromNodePath: string, toNodePath: string) => void,
|
|
444
451
|
) {
|
|
445
452
|
const envelope = message.contents as IEnvelope;
|
|
446
453
|
const transformed = { ...message, contents: envelope.contents };
|
|
@@ -462,6 +469,13 @@ export class DataStores implements IDisposable {
|
|
|
462
469
|
assert(!!context, 0x162 /* "There should be a store context for the op" */);
|
|
463
470
|
context.process(transformed, local, localMessageMetadata);
|
|
464
471
|
|
|
472
|
+
// By default, we use the new behavior of detecting outbound routes here.
|
|
473
|
+
// If this setting is true, then DataStoreContext would be notifying GC instead.
|
|
474
|
+
if (this.mc.config.getBoolean(detectOutboundRoutesViaDDSKey) !== true) {
|
|
475
|
+
// Notify GC of any outbound references that were added by this op.
|
|
476
|
+
detectOutboundReferences(envelope, addedOutboundReference);
|
|
477
|
+
}
|
|
478
|
+
|
|
465
479
|
// Notify that a GC node for the data store changed. This is used to detect if a deleted data store is
|
|
466
480
|
// being used.
|
|
467
481
|
this.gcNodeUpdated(
|
|
@@ -830,12 +844,15 @@ export class DataStores implements IDisposable {
|
|
|
830
844
|
|
|
831
845
|
const dataStoreContext = this.contexts.get(dataStoreId);
|
|
832
846
|
if (dataStoreContext === undefined) {
|
|
833
|
-
this.
|
|
847
|
+
// If the data store hasn't already been deleted, log an error because this should never happen.
|
|
848
|
+
// If the data store has already been deleted, log a telemetry event. This can happen because multiple GC
|
|
849
|
+
// sweep ops can contain the same data store. It would be interesting to track how often this happens.
|
|
850
|
+
const alreadyDeleted = this.isDataStoreDeleted(`/${dataStoreId}`);
|
|
851
|
+
this.mc.logger.sendTelemetryEvent({
|
|
834
852
|
eventName: "DeletedDataStoreNotFound",
|
|
853
|
+
category: alreadyDeleted ? "generic" : "error",
|
|
835
854
|
...tagCodeArtifacts({ id: dataStoreId }),
|
|
836
|
-
details: {
|
|
837
|
-
alreadyDeleted: this.isDataStoreDeleted(dataStoreId),
|
|
838
|
-
},
|
|
855
|
+
details: { alreadyDeleted },
|
|
839
856
|
});
|
|
840
857
|
continue;
|
|
841
858
|
}
|
|
@@ -947,3 +964,44 @@ export function getSummaryForDatastores(
|
|
|
947
964
|
};
|
|
948
965
|
}
|
|
949
966
|
}
|
|
967
|
+
|
|
968
|
+
/**
|
|
969
|
+
* Traverse this op's contents and detect any outbound routes that were added by this op.
|
|
970
|
+
*
|
|
971
|
+
* @internal
|
|
972
|
+
*/
|
|
973
|
+
export function detectOutboundReferences(
|
|
974
|
+
envelope: IEnvelope,
|
|
975
|
+
addedOutboundReference: (fromNodePath: string, toNodePath: string) => void,
|
|
976
|
+
): void {
|
|
977
|
+
// These will be built up as we traverse the envelope contents
|
|
978
|
+
const outboundPaths: string[] = [];
|
|
979
|
+
let ddsAddress: string | undefined;
|
|
980
|
+
|
|
981
|
+
function recursivelyFindHandles(obj: unknown) {
|
|
982
|
+
if (typeof obj === "object" && obj !== null) {
|
|
983
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
984
|
+
// If 'value' is a serialized IFluidHandle, it represents a new outbound route.
|
|
985
|
+
if (isSerializedHandle(value)) {
|
|
986
|
+
outboundPaths.push(value.url);
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
// NOTE: This is taking a hard dependency on the fact that in our DataStore implementation,
|
|
990
|
+
// the address of the DDS is stored in a property called "address". This is not ideal.
|
|
991
|
+
// An alternative would be for the op envelope to include the absolute path (built up as it is submitted)
|
|
992
|
+
if (key === "address" && ddsAddress === undefined) {
|
|
993
|
+
ddsAddress = value;
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
recursivelyFindHandles(value);
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
recursivelyFindHandles(envelope.contents);
|
|
1002
|
+
|
|
1003
|
+
// GC node paths are all absolute paths, hence the "" prefix.
|
|
1004
|
+
// e.g. this will yield "/dataStoreId/ddsId"
|
|
1005
|
+
const fromPath = ["", envelope.address, ddsAddress].join("/");
|
|
1006
|
+
outboundPaths.forEach((toPath) => addedOutboundReference(fromPath, toPath));
|
|
1007
|
+
}
|