@fluidframework/container-runtime 1.1.0 → 1.2.0-77818
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/dist/containerRuntime.d.ts +1 -1
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +8 -8
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStore.d.ts +2 -2
- package/dist/dataStore.d.ts.map +1 -1
- package/dist/dataStore.js +2 -2
- package/dist/dataStore.js.map +1 -1
- package/dist/dataStoreContext.d.ts +4 -4
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStores.d.ts +2 -2
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/dataStores.js +6 -5
- package/dist/dataStores.js.map +1 -1
- package/dist/garbageCollection.d.ts +12 -8
- package/dist/garbageCollection.d.ts.map +1 -1
- package/dist/garbageCollection.js +95 -68
- package/dist/garbageCollection.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.d.ts.map +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/summarizerTypes.d.ts +5 -2
- package/dist/summarizerTypes.d.ts.map +1 -1
- package/dist/summarizerTypes.js.map +1 -1
- package/dist/summaryGenerator.d.ts.map +1 -1
- package/dist/summaryGenerator.js +0 -1
- package/dist/summaryGenerator.js.map +1 -1
- package/garbageCollection.md +7 -7
- package/lib/containerRuntime.d.ts +1 -1
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +9 -9
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStore.d.ts +2 -2
- package/lib/dataStore.d.ts.map +1 -1
- package/lib/dataStore.js +2 -2
- package/lib/dataStore.js.map +1 -1
- package/lib/dataStoreContext.d.ts +4 -4
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStores.d.ts +2 -2
- package/lib/dataStores.d.ts.map +1 -1
- package/lib/dataStores.js +6 -5
- package/lib/dataStores.js.map +1 -1
- package/lib/garbageCollection.d.ts +12 -8
- package/lib/garbageCollection.d.ts.map +1 -1
- package/lib/garbageCollection.js +95 -68
- package/lib/garbageCollection.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.d.ts.map +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/summarizerTypes.d.ts +5 -2
- package/lib/summarizerTypes.d.ts.map +1 -1
- package/lib/summarizerTypes.js.map +1 -1
- package/lib/summaryGenerator.d.ts.map +1 -1
- package/lib/summaryGenerator.js +0 -1
- package/lib/summaryGenerator.js.map +1 -1
- package/package.json +16 -16
- package/src/containerRuntime.ts +60 -58
- package/src/dataStore.ts +4 -4
- package/src/dataStoreContext.ts +4 -4
- package/src/dataStores.ts +5 -5
- package/src/garbageCollection.ts +128 -95
- package/src/packageVersion.ts +1 -1
- package/src/summarizerTypes.ts +6 -3
- package/src/summaryGenerator.ts +0 -2
package/src/dataStoreContext.ts
CHANGED
|
@@ -704,7 +704,7 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
|
|
|
704
704
|
|
|
705
705
|
public abstract generateAttachMessage(): IAttachMessage;
|
|
706
706
|
|
|
707
|
-
|
|
707
|
+
public abstract getInitialSnapshotDetails(): Promise<ISnapshotDetails>;
|
|
708
708
|
|
|
709
709
|
/**
|
|
710
710
|
* @deprecated - Sets the datastore as root, for aliasing purposes: #7948
|
|
@@ -858,7 +858,7 @@ export class RemoteFluidDataStoreContext extends FluidDataStoreContext {
|
|
|
858
858
|
};
|
|
859
859
|
});
|
|
860
860
|
|
|
861
|
-
|
|
861
|
+
public async getInitialSnapshotDetails(): Promise<ISnapshotDetails> {
|
|
862
862
|
return this.initialSnapshotDetailsP;
|
|
863
863
|
}
|
|
864
864
|
|
|
@@ -947,7 +947,7 @@ export class LocalFluidDataStoreContextBase extends FluidDataStoreContext {
|
|
|
947
947
|
return message;
|
|
948
948
|
}
|
|
949
949
|
|
|
950
|
-
|
|
950
|
+
public async getInitialSnapshotDetails(): Promise<ISnapshotDetails> {
|
|
951
951
|
let snapshot = this.snapshotTree;
|
|
952
952
|
let attributes: ReadFluidDataStoreAttributes;
|
|
953
953
|
let isRootDataStore = false;
|
|
@@ -1050,7 +1050,7 @@ export class LocalDetachedFluidDataStoreContext
|
|
|
1050
1050
|
}
|
|
1051
1051
|
}
|
|
1052
1052
|
|
|
1053
|
-
|
|
1053
|
+
public async getInitialSnapshotDetails(): Promise<ISnapshotDetails> {
|
|
1054
1054
|
if (this.detachedRuntimeCreation) {
|
|
1055
1055
|
throw new Error("Detached Fluid Data Store context can't be realized! Please attach runtime first!");
|
|
1056
1056
|
}
|
package/src/dataStores.ts
CHANGED
|
@@ -647,13 +647,13 @@ export class DataStores implements IDisposable {
|
|
|
647
647
|
}
|
|
648
648
|
|
|
649
649
|
/**
|
|
650
|
-
* Called
|
|
650
|
+
* Called by GC to retrieve the package path of a data store node with the given path.
|
|
651
651
|
*/
|
|
652
|
-
public getDataStorePackagePath(nodePath: string): readonly string[] | undefined {
|
|
653
|
-
// If the node belongs to a data store, return its package path
|
|
654
|
-
//
|
|
652
|
+
public async getDataStorePackagePath(nodePath: string): Promise<readonly string[] | undefined> {
|
|
653
|
+
// If the node belongs to a data store, return its package path. For DDSes, we return the package path of the
|
|
654
|
+
// data store that contains it.
|
|
655
655
|
const context = this.contexts.get(nodePath.split("/")[1]);
|
|
656
|
-
return context?.
|
|
656
|
+
return (await context?.getInitialSnapshotDetails())?.pkg;
|
|
657
657
|
}
|
|
658
658
|
|
|
659
659
|
/**
|
package/src/garbageCollection.ts
CHANGED
|
@@ -115,12 +115,13 @@ export type GCNodeType = typeof GCNodeType[keyof typeof GCNodeType];
|
|
|
115
115
|
|
|
116
116
|
/** The event that is logged when unreferenced node is used after a certain time. */
|
|
117
117
|
interface IUnreferencedEvent {
|
|
118
|
-
|
|
118
|
+
usageType: "Changed" | "Loaded" | "Revived";
|
|
119
119
|
id: string;
|
|
120
120
|
type: GCNodeType;
|
|
121
121
|
age: number;
|
|
122
122
|
timeout: number;
|
|
123
123
|
completedGCRuns: number;
|
|
124
|
+
fromId?: string;
|
|
124
125
|
lastSummaryTime?: number;
|
|
125
126
|
externalRequest?: boolean;
|
|
126
127
|
viaHandle?: boolean;
|
|
@@ -191,7 +192,7 @@ export interface IGarbageCollectorCreateParams {
|
|
|
191
192
|
readonly metadata: IContainerRuntimeMetadata | undefined;
|
|
192
193
|
readonly baseSnapshot: ISnapshotTree | undefined;
|
|
193
194
|
readonly isSummarizerClient: boolean;
|
|
194
|
-
readonly getNodePackagePath: (nodePath: string) => readonly string[] | undefined
|
|
195
|
+
readonly getNodePackagePath: (nodePath: string) => Promise<readonly string[] | undefined>;
|
|
195
196
|
readonly getLastSummaryTimestampMs: () => number | undefined;
|
|
196
197
|
readonly readAndParseBlob: ReadAndParseBlob;
|
|
197
198
|
}
|
|
@@ -370,7 +371,7 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
370
371
|
// per event per node.
|
|
371
372
|
private readonly loggedUnreferencedEvents: Set<string> = new Set();
|
|
372
373
|
// Queue for unreferenced events that should be logged the next time GC runs.
|
|
373
|
-
private
|
|
374
|
+
private pendingEventsQueue: IUnreferencedEvent[] = [];
|
|
374
375
|
|
|
375
376
|
// The number of times GC has successfully completed on this instance of GarbageCollector.
|
|
376
377
|
private completedRuns = 0;
|
|
@@ -380,7 +381,7 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
380
381
|
private readonly isSummarizerClient: boolean;
|
|
381
382
|
|
|
382
383
|
/** For a given node path, returns the node's package path. */
|
|
383
|
-
private readonly getNodePackagePath: (nodePath: string) => readonly string[] | undefined
|
|
384
|
+
private readonly getNodePackagePath: (nodePath: string) => Promise<readonly string[] | undefined>;
|
|
384
385
|
/** Returns the timestamp of the last summary generated for this container. */
|
|
385
386
|
private readonly getLastSummaryTimestampMs: () => number | undefined;
|
|
386
387
|
|
|
@@ -678,7 +679,6 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
678
679
|
},
|
|
679
680
|
): Promise<IGCStats> {
|
|
680
681
|
const {
|
|
681
|
-
runSweep = this.shouldRunSweep,
|
|
682
682
|
fullGC = this.gcOptions.runFullGC === true || this.summaryStateNeedsReset,
|
|
683
683
|
} = options;
|
|
684
684
|
|
|
@@ -687,42 +687,52 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
687
687
|
: this.mc.logger;
|
|
688
688
|
|
|
689
689
|
return PerformanceEvent.timedExecAsync(logger, { eventName: "GarbageCollection" }, async (event) => {
|
|
690
|
-
await this.
|
|
691
|
-
|
|
692
|
-
// Let the runtime update its pending state before GC runs.
|
|
693
|
-
await this.runtime.updateStateBeforeGC();
|
|
690
|
+
await this.runPreGCSteps();
|
|
694
691
|
|
|
695
692
|
// Get the runtime's GC data and run GC on the reference graph in it.
|
|
696
693
|
const gcData = await this.runtime.getGCData(fullGC);
|
|
697
694
|
const gcResult = runGarbageCollection(gcData.gcNodes, ["/"]);
|
|
698
|
-
const gcStats = this.generateStatsAndLogEvents(gcResult, logger);
|
|
699
695
|
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
this.
|
|
696
|
+
const gcStats = await this.runPostGCSteps(gcData, gcResult, logger);
|
|
697
|
+
event.end({ ...gcStats });
|
|
698
|
+
this.completedRuns++;
|
|
699
|
+
return gcStats;
|
|
700
|
+
}, { end: true, cancel: "error" });
|
|
701
|
+
}
|
|
703
702
|
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
703
|
+
private async runPreGCSteps() {
|
|
704
|
+
// Ensure that base state has been initialized.
|
|
705
|
+
await this.initializeBaseStateP;
|
|
706
|
+
// Let the runtime update its pending state before GC runs.
|
|
707
|
+
await this.runtime.updateStateBeforeGC();
|
|
708
|
+
}
|
|
707
709
|
|
|
708
|
-
|
|
710
|
+
private async runPostGCSteps(gcData: IGarbageCollectionData, gcResult: IGCResult, logger: ITelemetryLogger) {
|
|
711
|
+
// Generate statistics from the current run. This is done before updating the current state because it
|
|
712
|
+
// generates some of its data based on previous state of the system.
|
|
713
|
+
const gcStats = this.generateStats(gcResult);
|
|
709
714
|
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
715
|
+
// Update the state since the last GC run. There can be nodes that were referenced between the last and
|
|
716
|
+
// the current run. We need to identify than and update their unreferenced state if needed.
|
|
717
|
+
this.updateStateSinceLastRun(gcData, logger);
|
|
713
718
|
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
}
|
|
719
|
+
// Update the current state and update the runtime of all routes or ids that used as per the GC run.
|
|
720
|
+
const currentReferenceTimestampMs = this.runtime.getCurrentReferenceTimestampMs();
|
|
721
|
+
this.updateCurrentState(gcData, gcResult, currentReferenceTimestampMs);
|
|
722
|
+
this.runtime.updateUsedRoutes(gcResult.referencedNodeIds, currentReferenceTimestampMs);
|
|
719
723
|
|
|
720
|
-
|
|
724
|
+
// If we are running in GC test mode, delete objects for unused routes. This enables testing scenarios
|
|
725
|
+
// involving access to deleted data.
|
|
726
|
+
if (this.testMode) {
|
|
727
|
+
this.runtime.deleteUnusedRoutes(gcResult.deletedNodeIds);
|
|
728
|
+
}
|
|
721
729
|
|
|
722
|
-
|
|
730
|
+
// Log pending unreferenced events such as a node being used after inactive. This is done after GC runs and
|
|
731
|
+
// updates its state so that we don't send false positives based on intermediate state. For example, we may get
|
|
732
|
+
// reference to an unreferenced node from another unreferenced node which means the node wasn't revived.
|
|
733
|
+
await this.logPendingEvents(logger);
|
|
723
734
|
|
|
724
|
-
|
|
725
|
-
}, { end: true, cancel: "error" });
|
|
735
|
+
return gcStats;
|
|
726
736
|
}
|
|
727
737
|
|
|
728
738
|
/**
|
|
@@ -863,13 +873,18 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
863
873
|
return;
|
|
864
874
|
}
|
|
865
875
|
|
|
866
|
-
this.
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
876
|
+
const unreferencedState = this.unreferencedNodesState.get(nodePath);
|
|
877
|
+
if (unreferencedState?.inactive) {
|
|
878
|
+
this.inactiveNodeUsed(
|
|
879
|
+
reason,
|
|
880
|
+
nodePath,
|
|
881
|
+
unreferencedState,
|
|
882
|
+
undefined /* fromNodeId */,
|
|
883
|
+
packagePath,
|
|
884
|
+
timestampMs,
|
|
885
|
+
requestHeaders,
|
|
886
|
+
);
|
|
887
|
+
}
|
|
873
888
|
}
|
|
874
889
|
|
|
875
890
|
/**
|
|
@@ -888,11 +903,10 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
888
903
|
outboundRoutes.push(toNodePath);
|
|
889
904
|
this.newReferencesSinceLastRun.set(fromNodePath, outboundRoutes);
|
|
890
905
|
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
"Revived",
|
|
894
|
-
|
|
895
|
-
);
|
|
906
|
+
const unreferencedState = this.unreferencedNodesState.get(toNodePath);
|
|
907
|
+
if (unreferencedState?.inactive) {
|
|
908
|
+
this.inactiveNodeUsed("Revived", toNodePath, unreferencedState, fromNodePath);
|
|
909
|
+
}
|
|
896
910
|
}
|
|
897
911
|
|
|
898
912
|
public dispose(): void {
|
|
@@ -1009,10 +1023,10 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
1009
1023
|
* references added new outbound references before getting deleted, we need to detect them.
|
|
1010
1024
|
* 2. We need new outbound references since last run because some of them may have been deleted later. If those
|
|
1011
1025
|
* references added new outbound references before getting deleted, we need to detect them.
|
|
1012
|
-
* 3. We need data from the current run because currently we may not detect when
|
|
1013
|
-
* - We don't require
|
|
1026
|
+
* 3. We need data from the current run because currently we may not detect when DDSes are referenced:
|
|
1027
|
+
* - We don't require DDSes handles to be stored in a referenced DDS. For this, we need GC at DDS level
|
|
1014
1028
|
* which is tracked by https://github.com/microsoft/FluidFramework/issues/8470.
|
|
1015
|
-
* - A new data store may have "root"
|
|
1029
|
+
* - A new data store may have "root" DDSes already created and we don't detect them today.
|
|
1016
1030
|
*/
|
|
1017
1031
|
const gcDataSuperSet = concatGarbageCollectionData(this.previousGCDataFromLastRun, currentGCData);
|
|
1018
1032
|
this.newReferencesSinceLastRun.forEach((outboundRoutes: string[], sourceNodeId: string) => {
|
|
@@ -1093,25 +1107,11 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
1093
1107
|
}
|
|
1094
1108
|
|
|
1095
1109
|
/**
|
|
1096
|
-
* Generates the stats of a garbage collection run from the given results of the run.
|
|
1097
|
-
* in the pendingEventsQueue. This should be called before updating the current state because it generates stats
|
|
1098
|
-
* based on previous state of the system.
|
|
1110
|
+
* Generates the stats of a garbage collection run from the given results of the run.
|
|
1099
1111
|
* @param gcResult - The result of a GC run.
|
|
1100
1112
|
* @returns the GC stats of the GC run.
|
|
1101
1113
|
*/
|
|
1102
|
-
private
|
|
1103
|
-
// Log pending events for unreferenced nodes after GC has run. We should have the package data available for
|
|
1104
|
-
// them now since the GC run should have loaded these nodes.
|
|
1105
|
-
let event = this.pendingEventsQueue.shift();
|
|
1106
|
-
while (event !== undefined) {
|
|
1107
|
-
const pkg = this.getNodePackagePath(event.id);
|
|
1108
|
-
logger.sendErrorEvent({
|
|
1109
|
-
...event,
|
|
1110
|
-
pkg: pkg ? { value: `/${pkg.join("/")}`, tag: TelemetryDataTag.PackageData } : undefined,
|
|
1111
|
-
});
|
|
1112
|
-
event = this.pendingEventsQueue.shift();
|
|
1113
|
-
}
|
|
1114
|
-
|
|
1114
|
+
private generateStats(gcResult: IGCResult): IGCStats {
|
|
1115
1115
|
const gcStats: IGCStats = {
|
|
1116
1116
|
nodeCount: 0,
|
|
1117
1117
|
dataStoreCount: 0,
|
|
@@ -1169,13 +1169,15 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
1169
1169
|
}
|
|
1170
1170
|
|
|
1171
1171
|
/**
|
|
1172
|
-
*
|
|
1172
|
+
* Called when a node is used. If the node is inactive, queue up an event that will be logged next time GC runs.
|
|
1173
1173
|
*/
|
|
1174
|
-
private
|
|
1175
|
-
|
|
1174
|
+
private inactiveNodeUsed(
|
|
1175
|
+
usageType: "Changed" | "Loaded" | "Revived",
|
|
1176
1176
|
nodeId: string,
|
|
1177
|
-
|
|
1177
|
+
unreferencedState: UnreferencedStateTracker,
|
|
1178
|
+
fromNodeId?: string,
|
|
1178
1179
|
packagePath?: readonly string[],
|
|
1180
|
+
currentReferenceTimestampMs = this.runtime.getCurrentReferenceTimestampMs(),
|
|
1179
1181
|
requestHeaders?: IRequestHeader,
|
|
1180
1182
|
) {
|
|
1181
1183
|
// If there is no reference timestamp to work with, no ops have been processed after creation. If so, skip
|
|
@@ -1184,6 +1186,12 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
1184
1186
|
return;
|
|
1185
1187
|
}
|
|
1186
1188
|
|
|
1189
|
+
// For non-summarizer clients, only log "Loaded" type events since these objects may not be loaded in the
|
|
1190
|
+
// summarizer clients if they are based off of user actions (such as scrolling to content for these objects).
|
|
1191
|
+
if (!this.isSummarizerClient && usageType !== "Loaded") {
|
|
1192
|
+
return;
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1187
1195
|
// We only care about data stores and attachment blobs for this telemetry since GC only marks these objects
|
|
1188
1196
|
// as unreferenced. Also, if an inactive DDS is used, the corresponding data store store will also be used.
|
|
1189
1197
|
const nodeType = this.runtime.getNodeType(nodeId);
|
|
@@ -1191,43 +1199,68 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
1191
1199
|
return;
|
|
1192
1200
|
}
|
|
1193
1201
|
|
|
1194
|
-
//
|
|
1195
|
-
|
|
1196
|
-
if (
|
|
1202
|
+
// A particular event is logged for a given node only once so that it is not too noisy.
|
|
1203
|
+
const uniqueEventId = `${nodeId}-${usageType}`;
|
|
1204
|
+
if (this.loggedUnreferencedEvents.has(uniqueEventId)) {
|
|
1197
1205
|
return;
|
|
1198
1206
|
}
|
|
1207
|
+
this.loggedUnreferencedEvents.add(uniqueEventId);
|
|
1208
|
+
|
|
1209
|
+
const event: IUnreferencedEvent = {
|
|
1210
|
+
usageType,
|
|
1211
|
+
id: nodeId,
|
|
1212
|
+
type: nodeType,
|
|
1213
|
+
age: currentReferenceTimestampMs - unreferencedState.unreferencedTimestampMs,
|
|
1214
|
+
timeout: this.inactiveTimeoutMs,
|
|
1215
|
+
completedGCRuns: this.completedRuns,
|
|
1216
|
+
lastSummaryTime: this.getLastSummaryTimestampMs(),
|
|
1217
|
+
externalRequest: requestHeaders?.[RuntimeHeaders.externalRequest],
|
|
1218
|
+
viaHandle: requestHeaders?.[RuntimeHeaders.viaHandle],
|
|
1219
|
+
fromId: fromNodeId,
|
|
1220
|
+
};
|
|
1199
1221
|
|
|
1200
|
-
|
|
1201
|
-
//
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
eventName
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
completedGCRuns: this.completedRuns,
|
|
1214
|
-
lastSummaryTime: this.getLastSummaryTimestampMs(),
|
|
1215
|
-
externalRequest: requestHeaders?.[RuntimeHeaders.externalRequest],
|
|
1216
|
-
viaHandle: requestHeaders?.[RuntimeHeaders.viaHandle],
|
|
1217
|
-
};
|
|
1222
|
+
// For summarizer client, queue the event so it is logged the next time GC runs if the event is still valid.
|
|
1223
|
+
// For non-summarizer client, log the event now since GC won't run on it. This may result in false positives
|
|
1224
|
+
// but it's a good signal nonetheless and we can consume it with a grain of salt.
|
|
1225
|
+
if (this.isSummarizerClient) {
|
|
1226
|
+
this.pendingEventsQueue.push(event);
|
|
1227
|
+
} else {
|
|
1228
|
+
this.mc.logger.sendErrorEvent({
|
|
1229
|
+
...event,
|
|
1230
|
+
eventName: `inactiveObject-${usageType}`,
|
|
1231
|
+
pkg: packagePath ? { value: packagePath.join("/"), tag: TelemetryDataTag.PackageData } : undefined,
|
|
1232
|
+
});
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1218
1235
|
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1236
|
+
/**
|
|
1237
|
+
* Logs pending unreferenced events if they are still valid.
|
|
1238
|
+
*/
|
|
1239
|
+
private async logPendingEvents(logger: ITelemetryLogger) {
|
|
1240
|
+
for (const event of this.pendingEventsQueue) {
|
|
1241
|
+
const unreferencedState = this.unreferencedNodesState.get(event.id);
|
|
1242
|
+
// Only log revived event if the node is not inactive anymore. If the node is still inactive, the
|
|
1243
|
+
// reference was from another unreferenced node and we don't care about logging this scenario.
|
|
1244
|
+
if (event.usageType === "Revived" && unreferencedState?.inactive) {
|
|
1245
|
+
continue;
|
|
1229
1246
|
}
|
|
1247
|
+
|
|
1248
|
+
// Only log loaded and changed event if the node is still inactive. If the node is not inactive, it was
|
|
1249
|
+
// revived and a revived event will be logged for it.
|
|
1250
|
+
if (event.usageType !== "Revived" && !unreferencedState?.inactive) {
|
|
1251
|
+
continue;
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
const pkg = await this.getNodePackagePath(event.id);
|
|
1255
|
+
const fromPkg = event.fromId ? await this.getNodePackagePath(event.fromId) : undefined;
|
|
1256
|
+
logger.sendErrorEvent({
|
|
1257
|
+
...event,
|
|
1258
|
+
eventName: `inactiveObject_${event.usageType}`,
|
|
1259
|
+
pkg: pkg ? { value: pkg.join("/"), tag: TelemetryDataTag.PackageData } : undefined,
|
|
1260
|
+
fromPkg: fromPkg ? { value: fromPkg.join("/"), tag: TelemetryDataTag.PackageData } : undefined,
|
|
1261
|
+
});
|
|
1230
1262
|
}
|
|
1263
|
+
this.pendingEventsQueue = [];
|
|
1231
1264
|
}
|
|
1232
1265
|
}
|
|
1233
1266
|
|
package/src/packageVersion.ts
CHANGED
package/src/summarizerTypes.ts
CHANGED
|
@@ -152,7 +152,7 @@ export interface IGeneratedSummaryStats extends ISummaryStats {
|
|
|
152
152
|
readonly gcBlobNodeCount?: number;
|
|
153
153
|
/** Sum of the sizes of all op contents since the last summary */
|
|
154
154
|
readonly opsSizesSinceLastSummary: number;
|
|
155
|
-
/** Number of non-system ops since the last summary @
|
|
155
|
+
/** Number of non-system ops since the last summary. See {@link @fluidframework/protocol-base#isSystemMessage} */
|
|
156
156
|
readonly nonSystemOpsSinceLastSummary: number;
|
|
157
157
|
/** The summary number for a container's summary. Incremented on summaries throughout its lifetime. */
|
|
158
158
|
readonly summaryNumber: number;
|
|
@@ -300,7 +300,7 @@ export interface ISummarizerEvents extends IEvent {
|
|
|
300
300
|
}
|
|
301
301
|
|
|
302
302
|
export interface ISummarizer extends
|
|
303
|
-
IEventProvider<ISummarizerEvents>, IFluidLoadable, Partial<IProvideSummarizer>{
|
|
303
|
+
IEventProvider<ISummarizerEvents>, IFluidLoadable, Partial<IProvideSummarizer> {
|
|
304
304
|
/*
|
|
305
305
|
* Asks summarizer to move to exit.
|
|
306
306
|
* Summarizer will finish current processes, which may take a while.
|
|
@@ -428,7 +428,10 @@ type SummaryGeneratorOptionalTelemetryProperties =
|
|
|
428
428
|
/** Delta in sum of op sizes between the current reference sequence number and the reference
|
|
429
429
|
* sequence number of the last summary */
|
|
430
430
|
"opsSizesSinceLastSummary" |
|
|
431
|
-
/**
|
|
431
|
+
/**
|
|
432
|
+
* Delta between the number of non-system ops since the last summary.
|
|
433
|
+
* See {@link @fluidframework/protocol-base#isSystemMessage}
|
|
434
|
+
*/
|
|
432
435
|
"nonSystemOpsSinceLastSummary" |
|
|
433
436
|
/** Time it took to generate the summary tree and stats. */
|
|
434
437
|
"generateDuration" |
|
package/src/summaryGenerator.ts
CHANGED
|
@@ -393,8 +393,6 @@ export class SummaryGenerator {
|
|
|
393
393
|
|
|
394
394
|
// pre-0.58 error message prefix: summaryNack
|
|
395
395
|
const error = new LoggingError(`Received summaryNack: ${message}`, { retryAfterSeconds });
|
|
396
|
-
logger.sendErrorEvent(
|
|
397
|
-
{ eventName: "SummaryNack", ...summarizeTelemetryProps, retryAfterSeconds }, error);
|
|
398
396
|
|
|
399
397
|
assert(getRetryDelaySecondsFromError(error) === retryAfterSeconds, 0x25f /* "retryAfterSeconds" */);
|
|
400
398
|
// This will only set resultsBuilder.receivedSummaryAckOrNack, as other promises are already set.
|