@fluidframework/container-runtime 2.0.0-dev-rc.5.0.0.271717 → 2.0.0-dev-rc.5.0.0.272889
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/api-extractor/api-extractor-lint-bundle.json +5 -0
- package/api-extractor/api-extractor-lint-legacy.cjs.json +5 -0
- package/api-extractor/api-extractor-lint-legacy.esm.json +5 -0
- package/api-extractor/api-extractor-lint-public.cjs.json +5 -0
- package/api-extractor/api-extractor-lint-public.esm.json +5 -0
- package/api-extractor.json +1 -1
- package/api-report/container-runtime.alpha.api.md +1 -1
- package/container-runtime.test-files.tar +0 -0
- package/dist/batchTracker.d.ts.map +1 -1
- package/dist/batchTracker.js.map +1 -1
- package/dist/blobManager.d.ts.map +1 -1
- package/dist/blobManager.js.map +1 -1
- package/dist/channelCollection.d.ts +12 -2
- package/dist/channelCollection.d.ts.map +1 -1
- package/dist/channelCollection.js +86 -90
- package/dist/channelCollection.js.map +1 -1
- package/dist/connectionTelemetry.d.ts.map +1 -1
- package/dist/connectionTelemetry.js.map +1 -1
- package/dist/containerRuntime.d.ts +2 -1
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +29 -9
- 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 +5 -3
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStoreContexts.d.ts.map +1 -1
- package/dist/dataStoreContexts.js.map +1 -1
- package/dist/deltaManagerProxies.d.ts.map +1 -1
- package/dist/deltaManagerProxies.js.map +1 -1
- package/dist/deltaScheduler.d.ts.map +1 -1
- package/dist/deltaScheduler.js +1 -3
- package/dist/deltaScheduler.js.map +1 -1
- package/dist/gc/garbageCollection.d.ts +4 -2
- package/dist/gc/garbageCollection.d.ts.map +1 -1
- package/dist/gc/garbageCollection.js +12 -8
- package/dist/gc/garbageCollection.js.map +1 -1
- package/dist/gc/gcConfigs.js +1 -1
- package/dist/gc/gcConfigs.js.map +1 -1
- package/dist/gc/gcDefinitions.d.ts +7 -4
- package/dist/gc/gcDefinitions.d.ts.map +1 -1
- package/dist/gc/gcDefinitions.js.map +1 -1
- package/dist/gc/gcHelpers.d.ts.map +1 -1
- package/dist/gc/gcHelpers.js.map +1 -1
- package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -1
- package/dist/gc/gcSummaryStateTracker.js.map +1 -1
- package/dist/gc/gcTelemetry.d.ts +1 -1
- package/dist/gc/gcTelemetry.d.ts.map +1 -1
- package/dist/gc/gcTelemetry.js +1 -7
- package/dist/gc/gcTelemetry.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/messageTypes.d.ts +5 -21
- package/dist/messageTypes.d.ts.map +1 -1
- package/dist/messageTypes.js.map +1 -1
- package/dist/opLifecycle/index.d.ts +1 -1
- package/dist/opLifecycle/index.d.ts.map +1 -1
- package/dist/opLifecycle/index.js.map +1 -1
- package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opDecompressor.js +1 -2
- package/dist/opLifecycle/opDecompressor.js.map +1 -1
- package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/dist/opLifecycle/opGroupingManager.js.map +1 -1
- package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
- package/dist/opLifecycle/opSplitter.js +1 -1
- package/dist/opLifecycle/opSplitter.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.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.map +1 -1
- package/dist/pendingStateManager.js +1 -1
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/summary/documentSchema.d.ts.map +1 -1
- package/dist/summary/documentSchema.js +1 -2
- package/dist/summary/documentSchema.js.map +1 -1
- package/dist/summary/index.d.ts +1 -1
- package/dist/summary/index.d.ts.map +1 -1
- package/dist/summary/index.js.map +1 -1
- package/dist/summary/orderedClientElection.d.ts.map +1 -1
- package/dist/summary/orderedClientElection.js.map +1 -1
- package/dist/summary/runningSummarizer.d.ts.map +1 -1
- package/dist/summary/runningSummarizer.js +1 -2
- package/dist/summary/runningSummarizer.js.map +1 -1
- package/dist/summary/summarizerClientElection.d.ts.map +1 -1
- package/dist/summary/summarizerClientElection.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js +4 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/dist/summary/summarizerTypes.d.ts.map +1 -1
- package/dist/summary/summarizerTypes.js.map +1 -1
- package/dist/summary/summaryCollection.d.ts.map +1 -1
- package/dist/summary/summaryCollection.js.map +1 -1
- package/dist/summary/summaryFormat.d.ts.map +1 -1
- package/dist/summary/summaryFormat.js.map +1 -1
- package/dist/summary/summaryGenerator.d.ts.map +1 -1
- package/dist/summary/summaryGenerator.js +1 -2
- package/dist/summary/summaryGenerator.js.map +1 -1
- package/dist/summary/summaryManager.d.ts.map +1 -1
- package/dist/summary/summaryManager.js +1 -2
- package/dist/summary/summaryManager.js.map +1 -1
- package/dist/throttler.d.ts.map +1 -1
- package/dist/throttler.js +3 -1
- package/dist/throttler.js.map +1 -1
- package/lib/batchTracker.d.ts.map +1 -1
- package/lib/batchTracker.js +1 -1
- package/lib/batchTracker.js.map +1 -1
- package/lib/blobManager.d.ts.map +1 -1
- package/lib/blobManager.js +1 -1
- package/lib/blobManager.js.map +1 -1
- package/lib/channelCollection.d.ts +12 -2
- package/lib/channelCollection.d.ts.map +1 -1
- package/lib/channelCollection.js +86 -90
- package/lib/channelCollection.js.map +1 -1
- package/lib/connectionTelemetry.d.ts.map +1 -1
- package/lib/connectionTelemetry.js.map +1 -1
- package/lib/containerRuntime.d.ts +2 -1
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +32 -12
- 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 +5 -3
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStoreContexts.d.ts.map +1 -1
- package/lib/dataStoreContexts.js +1 -1
- package/lib/dataStoreContexts.js.map +1 -1
- package/lib/deltaManagerProxies.d.ts.map +1 -1
- package/lib/deltaManagerProxies.js.map +1 -1
- package/lib/deltaScheduler.d.ts.map +1 -1
- package/lib/deltaScheduler.js +1 -3
- package/lib/deltaScheduler.js.map +1 -1
- package/lib/gc/garbageCollection.d.ts +4 -2
- package/lib/gc/garbageCollection.d.ts.map +1 -1
- package/lib/gc/garbageCollection.js +13 -9
- package/lib/gc/garbageCollection.js.map +1 -1
- package/lib/gc/gcConfigs.js +1 -1
- package/lib/gc/gcConfigs.js.map +1 -1
- package/lib/gc/gcDefinitions.d.ts +7 -4
- package/lib/gc/gcDefinitions.d.ts.map +1 -1
- package/lib/gc/gcDefinitions.js.map +1 -1
- package/lib/gc/gcHelpers.d.ts.map +1 -1
- package/lib/gc/gcHelpers.js.map +1 -1
- package/lib/gc/gcSummaryStateTracker.d.ts.map +1 -1
- package/lib/gc/gcSummaryStateTracker.js.map +1 -1
- package/lib/gc/gcTelemetry.d.ts +1 -1
- package/lib/gc/gcTelemetry.d.ts.map +1 -1
- package/lib/gc/gcTelemetry.js +1 -7
- package/lib/gc/gcTelemetry.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/messageTypes.d.ts +5 -21
- package/lib/messageTypes.d.ts.map +1 -1
- package/lib/messageTypes.js.map +1 -1
- package/lib/opLifecycle/index.d.ts +1 -1
- package/lib/opLifecycle/index.d.ts.map +1 -1
- package/lib/opLifecycle/index.js +1 -1
- package/lib/opLifecycle/index.js.map +1 -1
- package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/lib/opLifecycle/opDecompressor.js +1 -2
- package/lib/opLifecycle/opDecompressor.js.map +1 -1
- package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/lib/opLifecycle/opGroupingManager.js.map +1 -1
- package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
- package/lib/opLifecycle/opSplitter.js +1 -1
- package/lib/opLifecycle/opSplitter.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.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.map +1 -1
- package/lib/pendingStateManager.js +1 -1
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/summary/documentSchema.d.ts.map +1 -1
- package/lib/summary/documentSchema.js +1 -2
- package/lib/summary/documentSchema.js.map +1 -1
- package/lib/summary/index.d.ts +1 -1
- package/lib/summary/index.d.ts.map +1 -1
- package/lib/summary/index.js +1 -1
- package/lib/summary/index.js.map +1 -1
- package/lib/summary/orderedClientElection.d.ts.map +1 -1
- package/lib/summary/orderedClientElection.js.map +1 -1
- package/lib/summary/runningSummarizer.d.ts.map +1 -1
- package/lib/summary/runningSummarizer.js +1 -2
- package/lib/summary/runningSummarizer.js.map +1 -1
- package/lib/summary/summarizerClientElection.d.ts.map +1 -1
- package/lib/summary/summarizerClientElection.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js +4 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/lib/summary/summarizerTypes.d.ts.map +1 -1
- package/lib/summary/summarizerTypes.js.map +1 -1
- package/lib/summary/summaryCollection.d.ts.map +1 -1
- package/lib/summary/summaryCollection.js.map +1 -1
- package/lib/summary/summaryFormat.d.ts.map +1 -1
- package/lib/summary/summaryFormat.js.map +1 -1
- package/lib/summary/summaryGenerator.d.ts.map +1 -1
- package/lib/summary/summaryGenerator.js +1 -2
- package/lib/summary/summaryGenerator.js.map +1 -1
- package/lib/summary/summaryManager.d.ts.map +1 -1
- package/lib/summary/summaryManager.js +1 -2
- package/lib/summary/summaryManager.js.map +1 -1
- package/lib/throttler.d.ts.map +1 -1
- package/lib/throttler.js +3 -1
- package/lib/throttler.js.map +1 -1
- package/package.json +33 -20
- package/src/batchTracker.ts +4 -1
- package/src/blobManager.ts +14 -16
- package/src/channelCollection.ts +139 -132
- package/src/connectionTelemetry.ts +3 -8
- package/src/containerRuntime.ts +72 -44
- package/src/dataStoreContext.ts +34 -11
- package/src/dataStoreContexts.ts +7 -2
- package/src/deltaManagerProxies.ts +12 -3
- package/src/deltaScheduler.ts +1 -3
- package/src/gc/garbageCollection.ts +47 -31
- package/src/gc/gcConfigs.ts +7 -3
- package/src/gc/gcDefinitions.ts +16 -4
- package/src/gc/gcHelpers.ts +6 -2
- package/src/gc/gcSummaryStateTracker.ts +4 -1
- package/src/gc/gcTelemetry.ts +2 -9
- package/src/index.ts +0 -1
- package/src/messageTypes.ts +7 -23
- package/src/opLifecycle/index.ts +5 -1
- package/src/opLifecycle/opDecompressor.ts +2 -6
- package/src/opLifecycle/opGroupingManager.ts +1 -4
- package/src/opLifecycle/opSplitter.ts +9 -3
- package/src/opLifecycle/outbox.ts +1 -4
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +4 -2
- package/src/summary/documentSchema.ts +4 -7
- package/src/summary/index.ts +4 -1
- package/src/summary/orderedClientElection.ts +17 -10
- package/src/summary/runningSummarizer.ts +20 -9
- package/src/summary/summarizerClientElection.ts +2 -1
- package/src/summary/summarizerNode/summarizerNode.ts +6 -4
- package/src/summary/summarizerNode/summarizerNodeUtils.ts +7 -2
- package/src/summary/summarizerNode/summarizerNodeWithGc.ts +10 -6
- package/src/summary/summarizerTypes.ts +9 -2
- package/src/summary/summaryCollection.ts +4 -1
- package/src/summary/summaryFormat.ts +8 -3
- package/src/summary/summaryGenerator.ts +4 -9
- package/src/summary/summaryManager.ts +6 -9
- package/src/throttler.ts +3 -1
- package/tsdoc.json +4 -0
package/src/channelCollection.ts
CHANGED
|
@@ -397,11 +397,14 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
|
|
|
397
397
|
const attachMessage = message.contents as InboundAttachMessage;
|
|
398
398
|
|
|
399
399
|
// We need to process the GC Data for both local and remote attach messages
|
|
400
|
-
const foundGCData = processAttachMessageGCData(
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
400
|
+
const foundGCData = processAttachMessageGCData(
|
|
401
|
+
attachMessage.snapshot,
|
|
402
|
+
(nodeId, toPath) => {
|
|
403
|
+
// nodeId is the relative path under the node being attached. Always starts with "/", but no trailing "/" after an id
|
|
404
|
+
const fromPath = `/${attachMessage.id}${nodeId === "/" ? "" : nodeId}`;
|
|
405
|
+
this.parentContext.addedGCOutboundRoute(fromPath, toPath, message.timestamp);
|
|
406
|
+
},
|
|
407
|
+
);
|
|
405
408
|
|
|
406
409
|
// Only log once per container to avoid noise/cost.
|
|
407
410
|
// Allows longitudinal tracking of various state (e.g. foundGCData), and some sampled details
|
|
@@ -495,13 +498,18 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
|
|
|
495
498
|
const aliasResult = this.processAliasMessageCore(
|
|
496
499
|
aliasMessage.internalId,
|
|
497
500
|
aliasMessage.alias,
|
|
501
|
+
message.timestamp,
|
|
498
502
|
);
|
|
499
503
|
if (local) {
|
|
500
504
|
resolve(aliasResult);
|
|
501
505
|
}
|
|
502
506
|
}
|
|
503
507
|
|
|
504
|
-
public processAliasMessageCore(
|
|
508
|
+
public processAliasMessageCore(
|
|
509
|
+
internalId: string,
|
|
510
|
+
alias: string,
|
|
511
|
+
messageTimestampMs?: number,
|
|
512
|
+
): boolean {
|
|
505
513
|
if (this.alreadyProcessed(alias)) {
|
|
506
514
|
return false;
|
|
507
515
|
}
|
|
@@ -521,7 +529,11 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
|
|
|
521
529
|
return false;
|
|
522
530
|
}
|
|
523
531
|
|
|
524
|
-
this.
|
|
532
|
+
// If message timestamp doesn't exist, this is called in a detached container. Don't notify GC in that case
|
|
533
|
+
// because it doesn't run in detached container and doesn't need to know about this route.
|
|
534
|
+
if (messageTimestampMs) {
|
|
535
|
+
this.parentContext.addedGCOutboundRoute("/", `/${internalId}`, messageTimestampMs);
|
|
536
|
+
}
|
|
525
537
|
|
|
526
538
|
this.aliasMap.set(alias, context.id);
|
|
527
539
|
this.aliasedDataStores.add(context.id);
|
|
@@ -829,7 +841,7 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
|
|
|
829
841
|
envelope.address,
|
|
830
842
|
transformed.contents,
|
|
831
843
|
(fromPath: string, toPath: string) =>
|
|
832
|
-
this.parentContext.addedGCOutboundRoute(fromPath, toPath),
|
|
844
|
+
this.parentContext.addedGCOutboundRoute(fromPath, toPath, message.timestamp),
|
|
833
845
|
);
|
|
834
846
|
break;
|
|
835
847
|
}
|
|
@@ -966,9 +978,7 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
|
|
|
966
978
|
}
|
|
967
979
|
|
|
968
980
|
const idToLog =
|
|
969
|
-
originalRequest !== undefined
|
|
970
|
-
? urlToGCNodePath(originalRequest.url)
|
|
971
|
-
: dataStoreNodePath;
|
|
981
|
+
originalRequest !== undefined ? urlToGCNodePath(originalRequest.url) : dataStoreNodePath;
|
|
972
982
|
|
|
973
983
|
// Log the package details asynchronously since getInitialSnapshotDetails is async
|
|
974
984
|
const recentlyDeletedContext = this.contexts.getRecentlyDeletedContext(id);
|
|
@@ -1075,86 +1085,30 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
|
|
|
1075
1085
|
return this.contexts.size;
|
|
1076
1086
|
}
|
|
1077
1087
|
|
|
1078
|
-
public async summarize(
|
|
1079
|
-
fullTree: boolean,
|
|
1080
|
-
trackState: boolean,
|
|
1081
|
-
telemetryContext?: ITelemetryContext,
|
|
1082
|
-
): Promise<ISummaryTreeWithStats> {
|
|
1083
|
-
const summaryBuilder = new SummaryTreeBuilder();
|
|
1084
|
-
|
|
1085
|
-
// Iterate over each store and ask it to snapshot
|
|
1086
|
-
await Promise.all(
|
|
1087
|
-
Array.from(this.contexts)
|
|
1088
|
-
.filter(([_, context]) => {
|
|
1089
|
-
// Summarizer works only with clients with no local changes. A data store in attaching
|
|
1090
|
-
// state indicates an op was sent to attach a local data store, and the the attach op
|
|
1091
|
-
// had not yet round tripped back to the client.
|
|
1092
|
-
if (context.attachState === AttachState.Attaching) {
|
|
1093
|
-
// Formerly assert 0x588
|
|
1094
|
-
const error = DataProcessingError.create(
|
|
1095
|
-
"Local data store detected in attaching state during summarize",
|
|
1096
|
-
"summarize",
|
|
1097
|
-
);
|
|
1098
|
-
throw error;
|
|
1099
|
-
}
|
|
1100
|
-
return context.attachState === AttachState.Attached;
|
|
1101
|
-
})
|
|
1102
|
-
.map(async ([contextId, context]) => {
|
|
1103
|
-
const contextSummary = await context.summarize(
|
|
1104
|
-
fullTree,
|
|
1105
|
-
trackState,
|
|
1106
|
-
telemetryContext,
|
|
1107
|
-
);
|
|
1108
|
-
summaryBuilder.addWithStats(contextId, contextSummary);
|
|
1109
|
-
}),
|
|
1110
|
-
);
|
|
1111
|
-
|
|
1112
|
-
return summaryBuilder.getSummaryTree();
|
|
1113
|
-
}
|
|
1114
|
-
|
|
1115
1088
|
/**
|
|
1116
1089
|
* Create a summary. Used when attaching or serializing a detached container.
|
|
1117
1090
|
*/
|
|
1118
1091
|
public getAttachSummary(telemetryContext?: ITelemetryContext): ISummaryTreeWithStats {
|
|
1119
1092
|
const builder = new SummaryTreeBuilder();
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
.map(([key, value]) => {
|
|
1140
|
-
let dataStoreSummary: ISummarizeResult;
|
|
1141
|
-
if (value.isLoaded) {
|
|
1142
|
-
dataStoreSummary = value.getAttachSummary(telemetryContext);
|
|
1143
|
-
} else {
|
|
1144
|
-
// If this data store is not yet loaded, then there should be no changes in the snapshot from
|
|
1145
|
-
// which it was created as it is detached container. So just use the previous snapshot.
|
|
1146
|
-
assert(
|
|
1147
|
-
!!this.baseSnapshot,
|
|
1148
|
-
0x166 /* "BaseSnapshot should be there as detached container loaded from snapshot" */,
|
|
1149
|
-
);
|
|
1150
|
-
dataStoreSummary = convertSnapshotTreeToSummaryTree(
|
|
1151
|
-
getSnapshotTree(this.baseSnapshot).trees[key],
|
|
1152
|
-
);
|
|
1153
|
-
}
|
|
1154
|
-
builder.addWithStats(key, dataStoreSummary);
|
|
1155
|
-
});
|
|
1156
|
-
} while (notBoundContextsLength !== this.contexts.notBoundLength());
|
|
1157
|
-
|
|
1093
|
+
this.visitLocalBoundContextsDuringAttach(
|
|
1094
|
+
(contextId: string, context: FluidDataStoreContext) => {
|
|
1095
|
+
let dataStoreSummary: ISummarizeResult;
|
|
1096
|
+
if (context.isLoaded) {
|
|
1097
|
+
dataStoreSummary = context.getAttachSummary(telemetryContext);
|
|
1098
|
+
} else {
|
|
1099
|
+
// If this data store is not yet loaded, then there should be no changes in the snapshot from
|
|
1100
|
+
// which it was created as it is detached container. So just use the previous snapshot.
|
|
1101
|
+
assert(
|
|
1102
|
+
!!this.baseSnapshot,
|
|
1103
|
+
0x166 /* "BaseSnapshot should be there as detached container loaded from snapshot" */,
|
|
1104
|
+
);
|
|
1105
|
+
dataStoreSummary = convertSnapshotTreeToSummaryTree(
|
|
1106
|
+
getSnapshotTree(this.baseSnapshot).trees[contextId],
|
|
1107
|
+
);
|
|
1108
|
+
}
|
|
1109
|
+
builder.addWithStats(contextId, dataStoreSummary);
|
|
1110
|
+
},
|
|
1111
|
+
);
|
|
1158
1112
|
return builder.getSummaryTree();
|
|
1159
1113
|
}
|
|
1160
1114
|
|
|
@@ -1163,31 +1117,96 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
|
|
|
1163
1117
|
*/
|
|
1164
1118
|
public getAttachGCData(telemetryContext?: ITelemetryContext): IGarbageCollectionData {
|
|
1165
1119
|
const builder = new GCDataBuilder();
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
([key, _]) =>
|
|
1175
|
-
// Take GC data of bounded data stores only.
|
|
1176
|
-
!this.contexts.isNotBound(key),
|
|
1177
|
-
)
|
|
1178
|
-
.map(([key, value]) => {
|
|
1179
|
-
const contextGCData = value.getAttachGCData(telemetryContext);
|
|
1180
|
-
// Prefix the child's id to the ids of its GC nodes so they can be identified as belonging to the child.
|
|
1181
|
-
// This also gradually builds the id of each node to be a path from the root.
|
|
1182
|
-
builder.prefixAndAddNodes(key, contextGCData.gcNodes);
|
|
1183
|
-
});
|
|
1184
|
-
} while (notBoundContextsLength !== this.contexts.notBoundLength());
|
|
1185
|
-
|
|
1120
|
+
this.visitLocalBoundContextsDuringAttach(
|
|
1121
|
+
(contextId: string, context: FluidDataStoreContext) => {
|
|
1122
|
+
const contextGCData = context.getAttachGCData(telemetryContext);
|
|
1123
|
+
// Prefix the child's id to the ids of its GC nodes so they can be identified as belonging to the child.
|
|
1124
|
+
// This also gradually builds the id of each node to be a path from the root.
|
|
1125
|
+
builder.prefixAndAddNodes(contextId, contextGCData.gcNodes);
|
|
1126
|
+
},
|
|
1127
|
+
);
|
|
1186
1128
|
// Get the outbound routes (aliased data stores) and add a GC node for this channel.
|
|
1187
1129
|
builder.addNode("/", Array.from(this.aliasedDataStores));
|
|
1188
1130
|
return builder.getGCData();
|
|
1189
1131
|
}
|
|
1190
1132
|
|
|
1133
|
+
/**
|
|
1134
|
+
* Helper method for preparing to attach this channel.
|
|
1135
|
+
* Runs the callback for each bound context to incorporate its data however the caller specifies
|
|
1136
|
+
*/
|
|
1137
|
+
private visitLocalBoundContextsDuringAttach(
|
|
1138
|
+
visitor: (contextId: string, context: FluidDataStoreContext) => void,
|
|
1139
|
+
): void {
|
|
1140
|
+
const visitedContexts = new Set<string>();
|
|
1141
|
+
let visitedLength = -1;
|
|
1142
|
+
let notBoundContextsLength = -1;
|
|
1143
|
+
while (
|
|
1144
|
+
visitedLength !== visitedContexts.size &&
|
|
1145
|
+
notBoundContextsLength !== this.contexts.notBoundLength()
|
|
1146
|
+
) {
|
|
1147
|
+
// detect changes in the visitedContexts set, as on visiting a context
|
|
1148
|
+
// it could could make contexts available by removing other contexts
|
|
1149
|
+
// from the not bound context list, so we need to ensure those get processed as well.
|
|
1150
|
+
// only once the loop can run with no new contexts added to the visitedContexts set do we
|
|
1151
|
+
// know for sure all possible contexts have been visited.
|
|
1152
|
+
visitedLength = visitedContexts.size;
|
|
1153
|
+
notBoundContextsLength = this.contexts.notBoundLength();
|
|
1154
|
+
for (const [contextId, context] of this.contexts) {
|
|
1155
|
+
if (
|
|
1156
|
+
!(
|
|
1157
|
+
visitedContexts.has(contextId) ||
|
|
1158
|
+
this.contexts.isNotBound(contextId) ||
|
|
1159
|
+
this.attachOpFiredForDataStore.has(contextId)
|
|
1160
|
+
)
|
|
1161
|
+
) {
|
|
1162
|
+
visitor(contextId, context);
|
|
1163
|
+
visitedContexts.add(contextId);
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
/**
|
|
1170
|
+
* Helper method for preparing to summarize this channel.
|
|
1171
|
+
* Runs the callback for each bound context to incorporate its data however the caller specifies
|
|
1172
|
+
*/
|
|
1173
|
+
private async visitContextsDuringSummary(
|
|
1174
|
+
visitor: (contextId: string, context: FluidDataStoreContext) => Promise<void>,
|
|
1175
|
+
): Promise<void> {
|
|
1176
|
+
for (const [contextId, context] of this.contexts) {
|
|
1177
|
+
// Summarizer client and hence GC works only with clients with no local changes. A data store in
|
|
1178
|
+
// attaching state indicates an op was sent to attach a local data store, and the the attach op
|
|
1179
|
+
// had not yet round tripped back to the client.
|
|
1180
|
+
// Formerly assert 0x589
|
|
1181
|
+
if (context.attachState === AttachState.Attaching) {
|
|
1182
|
+
const error = DataProcessingError.create(
|
|
1183
|
+
"Local data store detected in attaching state",
|
|
1184
|
+
"summarize/getGCData",
|
|
1185
|
+
);
|
|
1186
|
+
throw error;
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
if (context.attachState === AttachState.Attached) {
|
|
1190
|
+
await visitor(contextId, context);
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
public async summarize(
|
|
1196
|
+
fullTree: boolean,
|
|
1197
|
+
trackState: boolean,
|
|
1198
|
+
telemetryContext?: ITelemetryContext,
|
|
1199
|
+
): Promise<ISummaryTreeWithStats> {
|
|
1200
|
+
const summaryBuilder = new SummaryTreeBuilder();
|
|
1201
|
+
await this.visitContextsDuringSummary(
|
|
1202
|
+
async (contextId: string, context: FluidDataStoreContext) => {
|
|
1203
|
+
const contextSummary = await context.summarize(fullTree, trackState, telemetryContext);
|
|
1204
|
+
summaryBuilder.addWithStats(contextId, contextSummary);
|
|
1205
|
+
},
|
|
1206
|
+
);
|
|
1207
|
+
return summaryBuilder.getSummaryTree();
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1191
1210
|
/**
|
|
1192
1211
|
* Generates data used for garbage collection. It does the following:
|
|
1193
1212
|
*
|
|
@@ -1203,30 +1222,13 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
|
|
|
1203
1222
|
*/
|
|
1204
1223
|
public async getGCData(fullGC: boolean = false): Promise<IGarbageCollectionData> {
|
|
1205
1224
|
const builder = new GCDataBuilder();
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
// Formerly assert 0x589
|
|
1214
|
-
if (context.attachState === AttachState.Attaching) {
|
|
1215
|
-
const error = DataProcessingError.create(
|
|
1216
|
-
"Local data store detected in attaching state while running GC",
|
|
1217
|
-
"getGCData",
|
|
1218
|
-
);
|
|
1219
|
-
throw error;
|
|
1220
|
-
}
|
|
1221
|
-
|
|
1222
|
-
return context.attachState === AttachState.Attached;
|
|
1223
|
-
})
|
|
1224
|
-
.map(async ([contextId, context]) => {
|
|
1225
|
-
const contextGCData = await context.getGCData(fullGC);
|
|
1226
|
-
// Prefix the child's id to the ids of its GC nodes so they can be identified as belonging to the child.
|
|
1227
|
-
// This also gradually builds the id of each node to be a path from the root.
|
|
1228
|
-
builder.prefixAndAddNodes(contextId, contextGCData.gcNodes);
|
|
1229
|
-
}),
|
|
1225
|
+
await this.visitContextsDuringSummary(
|
|
1226
|
+
async (contextId: string, context: FluidDataStoreContext) => {
|
|
1227
|
+
const contextGCData = await context.getGCData(fullGC);
|
|
1228
|
+
// Prefix the child's id to the ids of its GC nodes so they can be identified as belonging to the child.
|
|
1229
|
+
// This also gradually builds the id of each node to be a path from the root.
|
|
1230
|
+
builder.prefixAndAddNodes(contextId, contextGCData.gcNodes);
|
|
1231
|
+
},
|
|
1230
1232
|
);
|
|
1231
1233
|
|
|
1232
1234
|
// Get the outbound routes and add a GC node for this channel.
|
|
@@ -1283,7 +1285,9 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
|
|
|
1283
1285
|
* be deleted.
|
|
1284
1286
|
* @returns The routes of data stores and its objects that were deleted.
|
|
1285
1287
|
*/
|
|
1286
|
-
public deleteSweepReadyNodes(
|
|
1288
|
+
public deleteSweepReadyNodes(
|
|
1289
|
+
sweepReadyDataStoreRoutes: readonly string[],
|
|
1290
|
+
): readonly string[] {
|
|
1287
1291
|
for (const route of sweepReadyDataStoreRoutes) {
|
|
1288
1292
|
const pathParts = route.split("/");
|
|
1289
1293
|
const dataStoreId = pathParts[1];
|
|
@@ -1361,7 +1365,9 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
|
|
|
1361
1365
|
/**
|
|
1362
1366
|
* Called by GC to retrieve the package path of a data store node with the given path.
|
|
1363
1367
|
*/
|
|
1364
|
-
public async getDataStorePackagePath(
|
|
1368
|
+
public async getDataStorePackagePath(
|
|
1369
|
+
nodePath: string,
|
|
1370
|
+
): Promise<readonly string[] | undefined> {
|
|
1365
1371
|
// If the node belongs to a data store, return its package path. For DDSes, we return the package path of the
|
|
1366
1372
|
// data store that contains it.
|
|
1367
1373
|
const context = this.contexts.get(nodePath.split("/")[1]);
|
|
@@ -1432,6 +1438,7 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
|
|
|
1432
1438
|
packagePath: details.pkg,
|
|
1433
1439
|
request,
|
|
1434
1440
|
headerData,
|
|
1441
|
+
timestampMs: undefined, // This will be added by the parent context if needed.
|
|
1435
1442
|
});
|
|
1436
1443
|
|
|
1437
1444
|
const dataStore = await dataStoreContext.realize();
|
|
@@ -141,8 +141,7 @@ class OpPerfTelemetry {
|
|
|
141
141
|
return {
|
|
142
142
|
sample: () => {
|
|
143
143
|
eventCount++;
|
|
144
|
-
const shouldSample =
|
|
145
|
-
eventCount % OpPerfTelemetry.DELTA_LATENCY_SAMPLE_RATE === 0;
|
|
144
|
+
const shouldSample = eventCount % OpPerfTelemetry.DELTA_LATENCY_SAMPLE_RATE === 0;
|
|
146
145
|
if (shouldSample) {
|
|
147
146
|
eventCount = 0;
|
|
148
147
|
}
|
|
@@ -163,8 +162,7 @@ class OpPerfTelemetry {
|
|
|
163
162
|
return {
|
|
164
163
|
sample: () => {
|
|
165
164
|
eventCount++;
|
|
166
|
-
const shouldSample =
|
|
167
|
-
eventCount % OpPerfTelemetry.PROCESSED_OPS_SAMPLE_RATE === 0;
|
|
165
|
+
const shouldSample = eventCount % OpPerfTelemetry.PROCESSED_OPS_SAMPLE_RATE === 0;
|
|
168
166
|
if (shouldSample) {
|
|
169
167
|
eventCount = 0;
|
|
170
168
|
this.noOpCountForTelemetry = 0;
|
|
@@ -212,10 +210,7 @@ class OpPerfTelemetry {
|
|
|
212
210
|
) {
|
|
213
211
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
214
212
|
const latencyStats = this.latencyStatistics.get(msg.clientSequenceNumber)!;
|
|
215
|
-
assert(
|
|
216
|
-
latencyStats !== undefined,
|
|
217
|
-
0x7c2 /* Latency stats for op should exist */,
|
|
218
|
-
);
|
|
213
|
+
assert(latencyStats !== undefined, 0x7c2 /* Latency stats for op should exist */);
|
|
219
214
|
assert(
|
|
220
215
|
latencyStats.opProcessingTimes.outboundPushEventTime === undefined,
|
|
221
216
|
0x2c8 /* "outboundPushEventTime should be undefined" */,
|
package/src/containerRuntime.ts
CHANGED
|
@@ -121,17 +121,25 @@ import {
|
|
|
121
121
|
loggerToMonitoringContext,
|
|
122
122
|
raiseConnectedEvent,
|
|
123
123
|
wrapError,
|
|
124
|
+
tagCodeArtifacts,
|
|
124
125
|
} from "@fluidframework/telemetry-utils/internal";
|
|
125
126
|
import { v4 as uuid } from "uuid";
|
|
126
127
|
|
|
127
128
|
import { BindBatchTracker } from "./batchTracker.js";
|
|
128
129
|
import { BlobManager, IBlobManagerLoadInfo, IPendingBlobs } from "./blobManager.js";
|
|
129
|
-
import {
|
|
130
|
+
import {
|
|
131
|
+
ChannelCollection,
|
|
132
|
+
getSummaryForDatastores,
|
|
133
|
+
wrapContext,
|
|
134
|
+
} from "./channelCollection.js";
|
|
130
135
|
import { IPerfSignalReport, ReportOpPerfTelemetry } from "./connectionTelemetry.js";
|
|
131
136
|
import { ContainerFluidHandleContext } from "./containerHandleContext.js";
|
|
132
137
|
import { channelToDataStore } from "./dataStore.js";
|
|
133
138
|
import { FluidDataStoreRegistry } from "./dataStoreRegistry.js";
|
|
134
|
-
import {
|
|
139
|
+
import {
|
|
140
|
+
DeltaManagerPendingOpsProxy,
|
|
141
|
+
DeltaManagerSummarizerProxy,
|
|
142
|
+
} from "./deltaManagerProxies.js";
|
|
135
143
|
import {
|
|
136
144
|
GCNodeType,
|
|
137
145
|
GarbageCollector,
|
|
@@ -1135,10 +1143,7 @@ export class ContainerRuntime
|
|
|
1135
1143
|
// That's because any other usage will require immidiate loading of ID Compressor in next sessions in order
|
|
1136
1144
|
// to reason over such things as session ID space.
|
|
1137
1145
|
if (this.idCompressorMode === "on") {
|
|
1138
|
-
assert(
|
|
1139
|
-
this._idCompressor !== undefined,
|
|
1140
|
-
0x8ea /* compressor should have been loaded */,
|
|
1141
|
-
);
|
|
1146
|
+
assert(this._idCompressor !== undefined, 0x8ea /* compressor should have been loaded */);
|
|
1142
1147
|
return this._idCompressor;
|
|
1143
1148
|
}
|
|
1144
1149
|
}
|
|
@@ -1172,7 +1177,10 @@ export class ContainerRuntime
|
|
|
1172
1177
|
* should be sufficient. This should be used only if necessary. For example, for validating and propagating connected
|
|
1173
1178
|
* events which requires access to the actual real only info, this is needed.
|
|
1174
1179
|
*/
|
|
1175
|
-
private readonly innerDeltaManager: IDeltaManager<
|
|
1180
|
+
private readonly innerDeltaManager: IDeltaManager<
|
|
1181
|
+
ISequencedDocumentMessage,
|
|
1182
|
+
IDocumentMessage
|
|
1183
|
+
>;
|
|
1176
1184
|
|
|
1177
1185
|
// internal logger for ContainerRuntime. Use this.logger for stores, summaries, etc.
|
|
1178
1186
|
private readonly mc: MonitoringContext;
|
|
@@ -1537,7 +1545,9 @@ export class ContainerRuntime
|
|
|
1537
1545
|
const useDeltaManagerOpsProxy =
|
|
1538
1546
|
this.mc.config.getBoolean("Fluid.ContainerRuntime.DeltaManagerOpsProxy") !== false;
|
|
1539
1547
|
// The summarizerDeltaManager Proxy is used to lie to the summarizer to convince it is in the right state as a summarizer client.
|
|
1540
|
-
const summarizerDeltaManagerProxy = new DeltaManagerSummarizerProxy(
|
|
1548
|
+
const summarizerDeltaManagerProxy = new DeltaManagerSummarizerProxy(
|
|
1549
|
+
this.innerDeltaManager,
|
|
1550
|
+
);
|
|
1541
1551
|
outerDeltaManager = summarizerDeltaManagerProxy;
|
|
1542
1552
|
|
|
1543
1553
|
// The DeltaManagerPendingOpsProxy is used to control the minimum sequence number
|
|
@@ -1663,7 +1673,11 @@ export class ContainerRuntime
|
|
|
1663
1673
|
snapshot,
|
|
1664
1674
|
parentContext,
|
|
1665
1675
|
this.mc.logger,
|
|
1666
|
-
(props) =>
|
|
1676
|
+
(props) =>
|
|
1677
|
+
this.garbageCollector.nodeUpdated({
|
|
1678
|
+
...props,
|
|
1679
|
+
timestampMs: props.timestampMs ?? this.getCurrentReferenceTimestampMs(),
|
|
1680
|
+
}),
|
|
1667
1681
|
(path: string) => this.garbageCollector.isNodeDeleted(path),
|
|
1668
1682
|
new Map<string, string>(dataStoreAliasMap),
|
|
1669
1683
|
async (runtime: ChannelCollection) => provideEntryPoint,
|
|
@@ -1689,6 +1703,7 @@ export class ContainerRuntime
|
|
|
1689
1703
|
this.garbageCollector.nodeUpdated({
|
|
1690
1704
|
node: { type: "Blob", path: blobPath },
|
|
1691
1705
|
reason: "Loaded",
|
|
1706
|
+
timestampMs: this.getCurrentReferenceTimestampMs(),
|
|
1692
1707
|
}),
|
|
1693
1708
|
isBlobDeleted: (blobPath: string) => this.garbageCollector.isNodeDeleted(blobPath),
|
|
1694
1709
|
runtime: this,
|
|
@@ -1748,7 +1763,7 @@ export class ContainerRuntime
|
|
|
1748
1763
|
: ({
|
|
1749
1764
|
clientId,
|
|
1750
1765
|
client: audience.getMember(clientId),
|
|
1751
|
-
|
|
1766
|
+
} satisfies ISelf);
|
|
1752
1767
|
};
|
|
1753
1768
|
|
|
1754
1769
|
let oldClientId = this.clientId;
|
|
@@ -1767,7 +1782,8 @@ export class ContainerRuntime
|
|
|
1767
1782
|
const closeSummarizerDelayOverride = this.mc.config.getNumber(
|
|
1768
1783
|
"Fluid.ContainerRuntime.Test.CloseSummarizerDelayOverrideMs",
|
|
1769
1784
|
);
|
|
1770
|
-
this.closeSummarizerDelayMs =
|
|
1785
|
+
this.closeSummarizerDelayMs =
|
|
1786
|
+
closeSummarizerDelayOverride ?? defaultCloseSummarizerDelayMs;
|
|
1771
1787
|
this.summaryCollection = new SummaryCollection(this.deltaManager, this.logger);
|
|
1772
1788
|
|
|
1773
1789
|
this.dirtyContainer =
|
|
@@ -1934,7 +1950,10 @@ export class ContainerRuntime
|
|
|
1934
1950
|
}
|
|
1935
1951
|
}
|
|
1936
1952
|
|
|
1937
|
-
public getCreateChildSummarizerNodeFn(
|
|
1953
|
+
public getCreateChildSummarizerNodeFn(
|
|
1954
|
+
id: string,
|
|
1955
|
+
createParam: CreateChildSummarizerNodeParam,
|
|
1956
|
+
) {
|
|
1938
1957
|
return (
|
|
1939
1958
|
summarizeInternal: SummarizeInternalFn,
|
|
1940
1959
|
getGCDataFn: (fullGC?: boolean) => Promise<IGarbageCollectionData>,
|
|
@@ -2081,9 +2100,7 @@ export class ContainerRuntime
|
|
|
2081
2100
|
// the summarizer state is not up to date.
|
|
2082
2101
|
// This should be a recoverable scenario and shouldn't happen as we should process the ack first.
|
|
2083
2102
|
if (this.isSummarizerClient) {
|
|
2084
|
-
throw new Error(
|
|
2085
|
-
"Summarizer client behind, loaded newer snapshot with loadingGroupId",
|
|
2086
|
-
);
|
|
2103
|
+
throw new Error("Summarizer client behind, loaded newer snapshot with loadingGroupId");
|
|
2087
2104
|
}
|
|
2088
2105
|
|
|
2089
2106
|
// We want to catchup from sequenceNumber to targetSequenceNumber
|
|
@@ -2190,7 +2207,7 @@ export class ContainerRuntime
|
|
|
2190
2207
|
status: 200,
|
|
2191
2208
|
mimeType: "fluid/object",
|
|
2192
2209
|
value: blob,
|
|
2193
|
-
|
|
2210
|
+
}
|
|
2194
2211
|
: create404Response(request);
|
|
2195
2212
|
} else if (requestParser.pathParts.length > 0) {
|
|
2196
2213
|
return await this.channelCollection.request(request);
|
|
@@ -2591,13 +2608,13 @@ export class ContainerRuntime
|
|
|
2591
2608
|
message: message as InboundSequencedContainerRuntimeMessage,
|
|
2592
2609
|
local,
|
|
2593
2610
|
modernRuntimeMessage,
|
|
2594
|
-
|
|
2611
|
+
}
|
|
2595
2612
|
: // Unrecognized message will be ignored.
|
|
2596
|
-
|
|
2613
|
+
{
|
|
2597
2614
|
message,
|
|
2598
2615
|
local,
|
|
2599
2616
|
modernRuntimeMessage,
|
|
2600
|
-
|
|
2617
|
+
};
|
|
2601
2618
|
msg.savedOp = savedOp;
|
|
2602
2619
|
|
|
2603
2620
|
// ensure that we observe any re-entrancy, and if needed, rebase ops
|
|
@@ -2715,7 +2732,11 @@ export class ContainerRuntime
|
|
|
2715
2732
|
}
|
|
2716
2733
|
break;
|
|
2717
2734
|
case ContainerMessageType.GC:
|
|
2718
|
-
this.garbageCollector.processMessage(
|
|
2735
|
+
this.garbageCollector.processMessage(
|
|
2736
|
+
messageWithContext.message,
|
|
2737
|
+
messageWithContext.message.timestamp,
|
|
2738
|
+
local,
|
|
2739
|
+
);
|
|
2719
2740
|
break;
|
|
2720
2741
|
case ContainerMessageType.ChunkedOp:
|
|
2721
2742
|
// From observability POV, we should not exppse the rest of the system (including "op" events on object) to these messages.
|
|
@@ -2739,10 +2760,7 @@ export class ContainerRuntime
|
|
|
2739
2760
|
|
|
2740
2761
|
const compatBehavior = messageWithContext.message.compatDetails?.behavior;
|
|
2741
2762
|
if (
|
|
2742
|
-
!compatBehaviorAllowsMessageType(
|
|
2743
|
-
messageWithContext.message.type,
|
|
2744
|
-
compatBehavior,
|
|
2745
|
-
)
|
|
2763
|
+
!compatBehaviorAllowsMessageType(messageWithContext.message.type, compatBehavior)
|
|
2746
2764
|
) {
|
|
2747
2765
|
const { message } = messageWithContext;
|
|
2748
2766
|
const error = DataProcessingError.create(
|
|
@@ -2797,8 +2815,7 @@ export class ContainerRuntime
|
|
|
2797
2815
|
// Check to see if the signal was lost.
|
|
2798
2816
|
if (
|
|
2799
2817
|
this._perfSignalData.trackingSignalSequenceNumber !== undefined &&
|
|
2800
|
-
envelope.clientSignalSequenceNumber >
|
|
2801
|
-
this._perfSignalData.trackingSignalSequenceNumber
|
|
2818
|
+
envelope.clientSignalSequenceNumber > this._perfSignalData.trackingSignalSequenceNumber
|
|
2802
2819
|
) {
|
|
2803
2820
|
this._perfSignalData.signalsLost++;
|
|
2804
2821
|
this._perfSignalData.trackingSignalSequenceNumber = undefined;
|
|
@@ -2949,6 +2966,7 @@ export class ContainerRuntime
|
|
|
2949
2966
|
node: { type: "DataStore", path: `/${internalId}` },
|
|
2950
2967
|
reason: "Loaded",
|
|
2951
2968
|
packagePath: context.packagePath,
|
|
2969
|
+
timestampMs: this.getCurrentReferenceTimestampMs(),
|
|
2952
2970
|
});
|
|
2953
2971
|
return channel.entryPoint;
|
|
2954
2972
|
}
|
|
@@ -3402,9 +3420,25 @@ export class ContainerRuntime
|
|
|
3402
3420
|
* all references added in the system.
|
|
3403
3421
|
* @param fromPath - The absolute path of the node that added the reference.
|
|
3404
3422
|
* @param toPath - The absolute path of the outbound node that is referenced.
|
|
3423
|
+
* @param messageTimestampMs - The timestamp of the message that added the reference.
|
|
3405
3424
|
*/
|
|
3406
|
-
public addedGCOutboundRoute(fromPath: string, toPath: string) {
|
|
3407
|
-
|
|
3425
|
+
public addedGCOutboundRoute(fromPath: string, toPath: string, messageTimestampMs?: number) {
|
|
3426
|
+
// This is always called when processing an op so messageTimestampMs should exist. Due to back-compat
|
|
3427
|
+
// across the data store runtime / container runtime boundary, this may be undefined and if so, get
|
|
3428
|
+
// the timestamp from the last processed message which should exist.
|
|
3429
|
+
// If a timestamp doesn't exist, log so we can learn about these cases and return.
|
|
3430
|
+
const timestampMs = messageTimestampMs ?? this.getCurrentReferenceTimestampMs();
|
|
3431
|
+
if (timestampMs === undefined) {
|
|
3432
|
+
this.mc.logger.sendTelemetryEvent({
|
|
3433
|
+
eventName: "NoTimestampInGCOutboundRoute",
|
|
3434
|
+
...tagCodeArtifacts({
|
|
3435
|
+
id: toPath,
|
|
3436
|
+
fromId: fromPath,
|
|
3437
|
+
}),
|
|
3438
|
+
});
|
|
3439
|
+
return;
|
|
3440
|
+
}
|
|
3441
|
+
this.garbageCollector.addedOutboundReference(fromPath, toPath, timestampMs);
|
|
3408
3442
|
}
|
|
3409
3443
|
|
|
3410
3444
|
/**
|
|
@@ -3516,10 +3550,7 @@ export class ContainerRuntime
|
|
|
3516
3550
|
* Generally the validate sequence number comes from the running summarizer and the node sequence number comes from the
|
|
3517
3551
|
* summarizer nodes.
|
|
3518
3552
|
*/
|
|
3519
|
-
if (
|
|
3520
|
-
startSummaryResult.invalidNodes > 0 ||
|
|
3521
|
-
startSummaryResult.mismatchNumbers.size > 0
|
|
3522
|
-
) {
|
|
3553
|
+
if (startSummaryResult.invalidNodes > 0 || startSummaryResult.mismatchNumbers.size > 0) {
|
|
3523
3554
|
summaryLogger.sendTelemetryEvent({
|
|
3524
3555
|
eventName: "LatestSummaryRefSeqNumMismatch",
|
|
3525
3556
|
details: {
|
|
@@ -3687,12 +3718,12 @@ export class ContainerRuntime
|
|
|
3687
3718
|
proposalHandle: undefined,
|
|
3688
3719
|
ackHandle: this.loadedFromVersionId,
|
|
3689
3720
|
referenceSequenceNumber: summaryRefSeqNum,
|
|
3690
|
-
|
|
3721
|
+
}
|
|
3691
3722
|
: {
|
|
3692
3723
|
proposalHandle: lastAck.summaryOp.contents.handle,
|
|
3693
3724
|
ackHandle: lastAck.summaryAck.contents.handle,
|
|
3694
3725
|
referenceSequenceNumber: summaryRefSeqNum,
|
|
3695
|
-
|
|
3726
|
+
};
|
|
3696
3727
|
|
|
3697
3728
|
let handle: string;
|
|
3698
3729
|
try {
|
|
@@ -4240,10 +4271,7 @@ export class ContainerRuntime
|
|
|
4240
4271
|
"prefetchLatestSummaryBeforeClose",
|
|
4241
4272
|
FetchSource.noCache,
|
|
4242
4273
|
);
|
|
4243
|
-
assert(
|
|
4244
|
-
!!versions && !!versions[0],
|
|
4245
|
-
0x137 /* "Failed to get version from storage" */,
|
|
4246
|
-
);
|
|
4274
|
+
assert(!!versions && !!versions[0], 0x137 /* "Failed to get version from storage" */);
|
|
4247
4275
|
stats.getVersionDuration = trace.trace().duration;
|
|
4248
4276
|
|
|
4249
4277
|
const maybeSnapshot = await this.storage.getSnapshotTree(versions[0]);
|
|
@@ -4311,15 +4339,13 @@ export class ContainerRuntime
|
|
|
4311
4339
|
logAndReturnPendingState(
|
|
4312
4340
|
event,
|
|
4313
4341
|
getSyncState(
|
|
4314
|
-
await this.blobManager.attachAndGetPendingBlobs(
|
|
4315
|
-
props?.stopBlobAttachingSignal,
|
|
4316
|
-
),
|
|
4342
|
+
await this.blobManager.attachAndGetPendingBlobs(props?.stopBlobAttachingSignal),
|
|
4317
4343
|
),
|
|
4318
4344
|
),
|
|
4319
|
-
|
|
4345
|
+
)
|
|
4320
4346
|
: PerformanceEvent.timedExec(this.mc.logger, perfEvent, (event) =>
|
|
4321
4347
|
logAndReturnPendingState(event, getSyncState()),
|
|
4322
|
-
|
|
4348
|
+
);
|
|
4323
4349
|
}
|
|
4324
4350
|
|
|
4325
4351
|
public summarizeOnDemand(options: IOnDemandSummarizeOptions): ISummarizeResults {
|
|
@@ -4357,7 +4383,9 @@ export class ContainerRuntime
|
|
|
4357
4383
|
};
|
|
4358
4384
|
}
|
|
4359
4385
|
|
|
4360
|
-
private validateSummaryHeuristicConfiguration(
|
|
4386
|
+
private validateSummaryHeuristicConfiguration(
|
|
4387
|
+
configuration: ISummaryConfigurationHeuristics,
|
|
4388
|
+
) {
|
|
4361
4389
|
// eslint-disable-next-line no-restricted-syntax
|
|
4362
4390
|
for (const prop in configuration) {
|
|
4363
4391
|
if (typeof configuration[prop] === "number" && configuration[prop] < 0) {
|