@fluidframework/container-runtime 2.0.0-dev-rc.1.0.0.228517 → 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/README.md +1 -1
- package/api-report/container-runtime.api.md +13 -3
- package/dist/container-runtime-alpha.d.ts +11 -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 +28 -3
- package/dist/containerRuntime.d.ts +5 -2
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +55 -67
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStoreContext.d.ts +4 -1
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +2 -3
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStores.d.ts +4 -2
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/dataStores.js +8 -2
- package/dist/dataStores.js.map +1 -1
- package/dist/gc/garbageCollection.d.ts +17 -1
- package/dist/gc/garbageCollection.d.ts.map +1 -1
- package/dist/gc/garbageCollection.js +72 -29
- package/dist/gc/garbageCollection.js.map +1 -1
- package/dist/gc/gcDefinitions.d.ts +18 -2
- package/dist/gc/gcDefinitions.d.ts.map +1 -1
- package/dist/gc/gcDefinitions.js +5 -1
- package/dist/gc/gcDefinitions.js.map +1 -1
- package/dist/gc/gcTelemetry.d.ts +1 -0
- package/dist/gc/gcTelemetry.d.ts.map +1 -1
- package/dist/gc/gcTelemetry.js +0 -2
- package/dist/gc/gcTelemetry.js.map +1 -1
- package/dist/gc/gcUnreferencedStateTracker.d.ts +5 -0
- package/dist/gc/gcUnreferencedStateTracker.d.ts.map +1 -1
- package/dist/gc/gcUnreferencedStateTracker.js +12 -1
- package/dist/gc/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.js +2 -1
- package/dist/gc/index.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/messageTypes.d.ts +1 -1
- package/dist/messageTypes.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/summary/runningSummarizer.d.ts +6 -6
- package/dist/summary/runningSummarizer.d.ts.map +1 -1
- package/dist/summary/runningSummarizer.js +90 -72
- package/dist/summary/runningSummarizer.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.d.ts +2 -3
- package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.js +6 -48
- package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +1 -18
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.js +1 -21
- package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +3 -3
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js +5 -5
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/dist/summary/summarizerTypes.d.ts +1 -1
- package/dist/summary/summarizerTypes.d.ts.map +1 -1
- package/dist/summary/summarizerTypes.js.map +1 -1
- package/dist/tsdoc-metadata.json +1 -1
- package/lib/container-runtime-alpha.d.mts +11 -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 +28 -3
- package/lib/containerRuntime.d.mts +5 -2
- package/lib/containerRuntime.d.mts.map +1 -1
- package/lib/containerRuntime.mjs +56 -68
- package/lib/containerRuntime.mjs.map +1 -1
- package/lib/dataStoreContext.d.mts +4 -1
- package/lib/dataStoreContext.d.mts.map +1 -1
- package/lib/dataStoreContext.mjs +2 -3
- package/lib/dataStoreContext.mjs.map +1 -1
- package/lib/dataStores.d.mts +4 -2
- package/lib/dataStores.d.mts.map +1 -1
- package/lib/dataStores.mjs +8 -2
- 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 +74 -31
- package/lib/gc/garbageCollection.mjs.map +1 -1
- package/lib/gc/gcDefinitions.d.mts +18 -2
- package/lib/gc/gcDefinitions.d.mts.map +1 -1
- package/lib/gc/gcDefinitions.mjs +4 -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 +6 -6
- package/lib/summary/runningSummarizer.d.mts.map +1 -1
- package/lib/summary/runningSummarizer.mjs +90 -72
- 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 +1 -1
- package/lib/summary/summarizerTypes.d.mts.map +1 -1
- package/lib/summary/summarizerTypes.mjs.map +1 -1
- package/package.json +27 -21
- package/src/containerRuntime.ts +96 -85
- package/src/dataStoreContext.ts +6 -4
- package/src/dataStores.ts +8 -1
- package/src/gc/garbageCollection.ts +86 -30
- package/src/gc/gcDefinitions.ts +19 -3
- package/src/gc/gcTelemetry.ts +1 -2
- package/src/gc/gcUnreferencedStateTracker.ts +11 -0
- package/src/gc/index.ts +1 -0
- package/src/index.ts +2 -0
- package/src/messageTypes.ts +1 -1
- package/src/packageVersion.ts +1 -1
- package/src/summary/runningSummarizer.ts +116 -88
- 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 +1 -1
- /package/{.eslintrc.js → .eslintrc.cjs} +0 -0
package/src/gc/gcDefinitions.ts
CHANGED
|
@@ -76,6 +76,8 @@ export const disableDatastoreSweepKey = "Fluid.GarbageCollection.DisableDataStor
|
|
|
76
76
|
export const disableAttachmentBlobSweepKey = "Fluid.GarbageCollection.DisableAttachmentBlobSweep";
|
|
77
77
|
/** Config key to revert new paradigm of detecting outbound routes in ContainerRuntime layer (use true) */
|
|
78
78
|
export const detectOutboundRoutesViaDDSKey = "Fluid.GarbageCollection.DetectOutboundRoutesViaDDS";
|
|
79
|
+
/** Config key to disable auto-recovery mechanism that protects Tombstones that are loaded from being swept (use true) */
|
|
80
|
+
export const disableAutoRecoveryKey = "Fluid.GarbageCollection.DisableAutoRecovery";
|
|
79
81
|
|
|
80
82
|
// One day in milliseconds.
|
|
81
83
|
export const oneDayMs = 1 * 24 * 60 * 60 * 1000;
|
|
@@ -253,6 +255,8 @@ export type GCNodeType = (typeof GCNodeType)[keyof typeof GCNodeType];
|
|
|
253
255
|
export const GarbageCollectionMessageType = {
|
|
254
256
|
/** Message sent directing GC to delete the given nodes */
|
|
255
257
|
Sweep: "Sweep",
|
|
258
|
+
/** Message sent notifying GC that a Tombstoned object was Loaded */
|
|
259
|
+
TombstoneLoaded: "TombstoneLoaded",
|
|
256
260
|
} as const;
|
|
257
261
|
|
|
258
262
|
/**
|
|
@@ -266,16 +270,28 @@ export type GarbageCollectionMessageType =
|
|
|
266
270
|
* @internal
|
|
267
271
|
*/
|
|
268
272
|
export interface ISweepMessage {
|
|
269
|
-
|
|
270
|
-
|
|
273
|
+
/** @see GarbageCollectionMessageType.Sweep */
|
|
274
|
+
type: typeof GarbageCollectionMessageType.Sweep;
|
|
275
|
+
/** The ids of nodes that are deleted. */
|
|
271
276
|
deletedNodeIds: string[];
|
|
272
277
|
}
|
|
273
278
|
|
|
279
|
+
/**
|
|
280
|
+
* The GC TombstoneLoaded message.
|
|
281
|
+
* @internal
|
|
282
|
+
*/
|
|
283
|
+
export interface ITombstoneLoadedMessage {
|
|
284
|
+
/** @see GarbageCollectionMessageType.TombstoneLoaded */
|
|
285
|
+
type: typeof GarbageCollectionMessageType.TombstoneLoaded;
|
|
286
|
+
/** The id of Tombstoned node that was loaded. */
|
|
287
|
+
nodePath: string;
|
|
288
|
+
}
|
|
289
|
+
|
|
274
290
|
/**
|
|
275
291
|
* Type for a message to be used for sending / received garbage collection messages.
|
|
276
292
|
* @internal
|
|
277
293
|
*/
|
|
278
|
-
export type GarbageCollectionMessage = ISweepMessage;
|
|
294
|
+
export type GarbageCollectionMessage = ISweepMessage | ITombstoneLoadedMessage;
|
|
279
295
|
|
|
280
296
|
/**
|
|
281
297
|
* Defines the APIs for the runtime object to be passed to the garbage collector.
|
package/src/gc/gcTelemetry.ts
CHANGED
|
@@ -63,6 +63,7 @@ interface INodeUsageProps extends ICommonProps {
|
|
|
63
63
|
currentReferenceTimestampMs: number | undefined;
|
|
64
64
|
packagePath: readonly string[] | undefined;
|
|
65
65
|
fromId?: string;
|
|
66
|
+
autorecovery?: true;
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
/**
|
|
@@ -189,8 +190,6 @@ export class GCTelemetryTracker {
|
|
|
189
190
|
};
|
|
190
191
|
|
|
191
192
|
// If the node that is used is tombstoned, log a tombstone telemetry.
|
|
192
|
-
// Note that this is done before checking if "nodeStateTracker" is undefined below because unreferenced
|
|
193
|
-
// tracking may not have yet been enabled. That happens only after the client transitions to write mode.
|
|
194
193
|
if (nodeUsageProps.isTombstoned) {
|
|
195
194
|
this.logTombstoneUsageTelemetry(nodeUsageProps, unrefEventProps, nodeType, usageType);
|
|
196
195
|
}
|
|
@@ -25,6 +25,17 @@ class TimerWithNoDefaultTimeout extends Timer {
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
/** The collection of UnreferencedStateTrackers for all unreferenced nodes. Ensures stopTracking is called when deleting */
|
|
29
|
+
export class UnreferencedStateTrackerMap extends Map<string, UnreferencedStateTracker> {
|
|
30
|
+
/** Delete the given key, and stop tracking if that node was actually unreferenced */
|
|
31
|
+
delete(key: string): boolean {
|
|
32
|
+
// Stop tracking so as to clear out any running timers.
|
|
33
|
+
this.get(key)?.stopTracking();
|
|
34
|
+
// Delete the node as we don't need to track it any more.
|
|
35
|
+
return super.delete(key);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
28
39
|
/**
|
|
29
40
|
* Helper class that tracks the state of an unreferenced node such as the time it was unreferenced and if it can
|
|
30
41
|
* be tombstoned or deleted by the sweep phase.
|
package/src/gc/index.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -30,9 +30,11 @@ export {
|
|
|
30
30
|
IContainerRuntimeMessageCompatDetails,
|
|
31
31
|
CompatModeBehavior,
|
|
32
32
|
RecentlyAddedContainerRuntimeMessageDetails,
|
|
33
|
+
UnknownContainerRuntimeMessage,
|
|
33
34
|
} from "./messageTypes";
|
|
34
35
|
export { IBlobManagerLoadInfo } from "./blobManager";
|
|
35
36
|
export { FluidDataStoreRegistry } from "./dataStoreRegistry";
|
|
37
|
+
export { detectOutboundReferences } from "./dataStores";
|
|
36
38
|
export {
|
|
37
39
|
GCNodeType,
|
|
38
40
|
IGCMetadata,
|
package/src/messageTypes.ts
CHANGED
|
@@ -133,7 +133,7 @@ export type ContainerRuntimeGCMessage = TypedContainerRuntimeMessage<
|
|
|
133
133
|
>;
|
|
134
134
|
|
|
135
135
|
/**
|
|
136
|
-
* Represents an unrecognized
|
|
136
|
+
* Represents an unrecognized TypedContainerRuntimeMessage, e.g. a message from a future version of the container runtime.
|
|
137
137
|
* @internal
|
|
138
138
|
*/
|
|
139
139
|
export interface UnknownContainerRuntimeMessage
|
package/src/packageVersion.ts
CHANGED
|
@@ -91,15 +91,26 @@ export class RunningSummarizer extends TypedEventEmitter<ISummarizerEvents> impl
|
|
|
91
91
|
runtime,
|
|
92
92
|
);
|
|
93
93
|
|
|
94
|
-
//
|
|
95
|
-
//
|
|
96
|
-
|
|
94
|
+
// If there have been any acks newer that the one this client loaded from until now, process them before
|
|
95
|
+
// starting the running summarizer which will trigger summary heuristics.
|
|
96
|
+
// This is done primarily to handle scenarios where the summarizer loads from a cached snapshot and there
|
|
97
|
+
// is newer one available. The ack for the newer summary is processed before summarizing because otherwise
|
|
98
|
+
// that summary would fail as it has an older parent.
|
|
99
|
+
let nextReferenceSequenceNumber = runtime.deltaManager.initialSequenceNumber + 1;
|
|
100
|
+
const latestAck = summaryCollection.latestAck;
|
|
101
|
+
if (
|
|
102
|
+
latestAck !== undefined &&
|
|
103
|
+
latestAck.summaryOp.referenceSequenceNumber >= nextReferenceSequenceNumber
|
|
104
|
+
) {
|
|
105
|
+
await summarizer.handleSummaryAck(latestAck);
|
|
106
|
+
nextReferenceSequenceNumber = latestAck.summaryOp.referenceSequenceNumber + 1;
|
|
107
|
+
}
|
|
97
108
|
|
|
98
109
|
await summarizer.waitStart();
|
|
99
110
|
|
|
100
|
-
//
|
|
111
|
+
// Process summary acks asynchronously
|
|
101
112
|
// Note: no exceptions are thrown from processIncomingSummaryAcks handler as it handles all exceptions
|
|
102
|
-
summarizer.processIncomingSummaryAcks(
|
|
113
|
+
summarizer.processIncomingSummaryAcks(nextReferenceSequenceNumber).catch((error) => {
|
|
103
114
|
createChildLogger({ logger }).sendErrorEvent(
|
|
104
115
|
{ eventName: "HandleSummaryAckFatalError" },
|
|
105
116
|
error,
|
|
@@ -272,94 +283,77 @@ export class RunningSummarizer extends TypedEventEmitter<ISummarizerEvents> impl
|
|
|
272
283
|
: defaultMaxAttemptsForSubmitFailures;
|
|
273
284
|
}
|
|
274
285
|
|
|
275
|
-
private async handleSummaryAck(
|
|
276
|
-
const
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
286
|
+
private async handleSummaryAck(ack: IAckedSummary) {
|
|
287
|
+
const refSequenceNumber = ack.summaryOp.referenceSequenceNumber;
|
|
288
|
+
const summaryLogger = this.tryGetCorrelatedLogger(refSequenceNumber) ?? this.mc.logger;
|
|
289
|
+
const summaryOpHandle = ack.summaryOp.contents.handle;
|
|
290
|
+
const summaryAckHandle = ack.summaryAck.contents.handle;
|
|
291
|
+
while (this.summarizingLock !== undefined) {
|
|
292
|
+
summaryLogger.sendTelemetryEvent({
|
|
293
|
+
eventName: "RefreshAttemptWithSummarizerRunning",
|
|
294
|
+
referenceSequenceNumber: refSequenceNumber,
|
|
295
|
+
proposalHandle: summaryOpHandle,
|
|
296
|
+
ackHandle: summaryAckHandle,
|
|
297
|
+
});
|
|
298
|
+
await this.summarizingLock;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Make sure we block any summarizer from being executed/enqueued while
|
|
302
|
+
// executing the refreshLatestSummaryAck.
|
|
303
|
+
// https://dev.azure.com/fluidframework/internal/_workitems/edit/779
|
|
304
|
+
await this.lockedSummaryAction(
|
|
305
|
+
() => {},
|
|
306
|
+
async () =>
|
|
307
|
+
this.refreshLatestSummaryAckCallback({
|
|
288
308
|
proposalHandle: summaryOpHandle,
|
|
289
309
|
ackHandle: summaryAckHandle,
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
{
|
|
319
|
-
eventName: isIgnoredError
|
|
320
|
-
? "HandleSummaryAckErrorIgnored"
|
|
321
|
-
: "HandleLastSummaryAckError",
|
|
322
|
-
referenceSequenceNumber: refSequenceNumber,
|
|
323
|
-
proposalHandle: summaryOpHandle,
|
|
324
|
-
ackHandle: summaryAckHandle,
|
|
325
|
-
},
|
|
326
|
-
error,
|
|
327
|
-
);
|
|
328
|
-
}),
|
|
329
|
-
() => {},
|
|
330
|
-
);
|
|
331
|
-
refSequenceNumber++;
|
|
332
|
-
}
|
|
333
|
-
return refSequenceNumber;
|
|
310
|
+
summaryRefSeq: refSequenceNumber,
|
|
311
|
+
summaryLogger,
|
|
312
|
+
}).catch(async (error) => {
|
|
313
|
+
// If the error is 404, so maybe the fetched version no longer exists on server. We just
|
|
314
|
+
// ignore this error in that case, as that means we will have another summaryAck for the
|
|
315
|
+
// latest version with which we will refresh the state. However in case of single commit
|
|
316
|
+
// summary, we might me missing a summary ack, so in that case we are still fine as the
|
|
317
|
+
// code in `submitSummary` function in container runtime, will refresh the latest state
|
|
318
|
+
// by calling `prefetchLatestSummaryThenClose`. We will load the next summarizer from the
|
|
319
|
+
// updated state and be fine.
|
|
320
|
+
const isIgnoredError =
|
|
321
|
+
isFluidError(error) &&
|
|
322
|
+
error.errorType === DriverErrorTypes.fileNotFoundOrAccessDeniedError;
|
|
323
|
+
|
|
324
|
+
summaryLogger.sendTelemetryEvent(
|
|
325
|
+
{
|
|
326
|
+
eventName: isIgnoredError
|
|
327
|
+
? "HandleSummaryAckErrorIgnored"
|
|
328
|
+
: "HandleLastSummaryAckError",
|
|
329
|
+
referenceSequenceNumber: refSequenceNumber,
|
|
330
|
+
proposalHandle: summaryOpHandle,
|
|
331
|
+
ackHandle: summaryAckHandle,
|
|
332
|
+
},
|
|
333
|
+
error,
|
|
334
|
+
);
|
|
335
|
+
}),
|
|
336
|
+
() => {},
|
|
337
|
+
);
|
|
334
338
|
}
|
|
335
339
|
|
|
336
340
|
/**
|
|
337
|
-
* Responsible for receiving and processing all the
|
|
338
|
-
*
|
|
339
|
-
*
|
|
340
|
-
*
|
|
341
|
-
*
|
|
342
|
-
*
|
|
341
|
+
* Responsible for receiving and processing all the summary acks.
|
|
342
|
+
* It starts processing ACKs after the one for the summary this client loaded from (initialSequenceNumber). Any
|
|
343
|
+
* ACK before that is not interesting as it will simply be ignored.
|
|
344
|
+
*
|
|
345
|
+
* @param referenceSequenceNumber - The referenceSequenceNumber of the summary from which to start processing
|
|
346
|
+
* acks.
|
|
343
347
|
*/
|
|
344
|
-
private async processIncomingSummaryAcks(
|
|
345
|
-
|
|
346
|
-
|
|
348
|
+
private async processIncomingSummaryAcks(referenceSequenceNumber: number) {
|
|
349
|
+
// Start waiting for acks that are for summaries newer that the one this client loaded from.
|
|
350
|
+
let nextReferenceSequenceNumber = referenceSequenceNumber;
|
|
347
351
|
while (!this.disposed) {
|
|
348
|
-
const
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
summaryLogger.sendTelemetryEvent({
|
|
355
|
-
eventName: "processIncomingSummaryAcks",
|
|
356
|
-
referenceSequenceNumber: refSequenceNumber,
|
|
357
|
-
lastAckRefSeq,
|
|
358
|
-
});
|
|
359
|
-
|
|
360
|
-
refSequenceNumber = await this.handleSummaryAck();
|
|
361
|
-
// A valid Summary Ack must have been processed.
|
|
362
|
-
assert(refSequenceNumber >= 0, 0x58f /* Invalid ref sequence number */);
|
|
352
|
+
const ackedSummary = await this.summaryCollection.waitSummaryAck(
|
|
353
|
+
nextReferenceSequenceNumber,
|
|
354
|
+
);
|
|
355
|
+
await this.handleSummaryAck(ackedSummary);
|
|
356
|
+
nextReferenceSequenceNumber = ackedSummary.summaryOp.referenceSequenceNumber + 1;
|
|
363
357
|
}
|
|
364
358
|
}
|
|
365
359
|
|
|
@@ -574,7 +568,17 @@ export class RunningSummarizer extends TypedEventEmitter<ISummarizerEvents> impl
|
|
|
574
568
|
};
|
|
575
569
|
const summarizeResult = this.generator.summarize(summaryOptions, resultsBuilder);
|
|
576
570
|
// ensure we wait till the end of the process
|
|
577
|
-
|
|
571
|
+
const result = await summarizeResult.receivedSummaryAckOrNack;
|
|
572
|
+
if (!result.success) {
|
|
573
|
+
this.mc.logger.sendErrorEvent(
|
|
574
|
+
{
|
|
575
|
+
eventName: "SummarizeFailed",
|
|
576
|
+
maxAttempts: 1,
|
|
577
|
+
summaryAttempts: 1,
|
|
578
|
+
},
|
|
579
|
+
result.error,
|
|
580
|
+
);
|
|
581
|
+
}
|
|
578
582
|
},
|
|
579
583
|
() => {
|
|
580
584
|
this.afterSummaryAction();
|
|
@@ -627,6 +631,7 @@ export class RunningSummarizer extends TypedEventEmitter<ISummarizerEvents> impl
|
|
|
627
631
|
let summaryAttempts = 0;
|
|
628
632
|
let summaryAttemptsPerPhase = 0;
|
|
629
633
|
let summaryAttemptPhase = 0;
|
|
634
|
+
let error: any;
|
|
630
635
|
while (summaryAttemptPhase < attemptOptions.length) {
|
|
631
636
|
if (this.cancellationToken.cancelled) {
|
|
632
637
|
return;
|
|
@@ -665,6 +670,8 @@ export class RunningSummarizer extends TypedEventEmitter<ISummarizerEvents> impl
|
|
|
665
670
|
return;
|
|
666
671
|
}
|
|
667
672
|
|
|
673
|
+
error = ackNackResult.error;
|
|
674
|
+
|
|
668
675
|
// Check for retryDelay that can come from summaryNack, upload summary or submit summary flows.
|
|
669
676
|
// Retry the same step only once per retryAfter response.
|
|
670
677
|
const submitResult = await resultSummarize.summarySubmitted;
|
|
@@ -686,6 +693,14 @@ export class RunningSummarizer extends TypedEventEmitter<ISummarizerEvents> impl
|
|
|
686
693
|
await delay(delaySeconds * 1000);
|
|
687
694
|
}
|
|
688
695
|
}
|
|
696
|
+
this.mc.logger.sendErrorEvent(
|
|
697
|
+
{
|
|
698
|
+
eventName: "SummarizeFailed",
|
|
699
|
+
maxAttempts: attemptOptions.length,
|
|
700
|
+
summaryAttempts: summaryAttemptPhase,
|
|
701
|
+
},
|
|
702
|
+
error,
|
|
703
|
+
);
|
|
689
704
|
this.stopSummarizerCallback("failToSummarize");
|
|
690
705
|
}
|
|
691
706
|
|
|
@@ -736,6 +751,7 @@ export class RunningSummarizer extends TypedEventEmitter<ISummarizerEvents> impl
|
|
|
736
751
|
let done = false;
|
|
737
752
|
let status: "success" | "failure" | "canceled" = "success";
|
|
738
753
|
let results: ISummarizeResults | undefined;
|
|
754
|
+
let error: any;
|
|
739
755
|
do {
|
|
740
756
|
currentAttempt++;
|
|
741
757
|
if (this.cancellationToken.cancelled) {
|
|
@@ -770,11 +786,12 @@ export class RunningSummarizer extends TypedEventEmitter<ISummarizerEvents> impl
|
|
|
770
786
|
|
|
771
787
|
// Emit "summarize" event for this failed attempt.
|
|
772
788
|
status = "failure";
|
|
789
|
+
error = ackNackResult.error;
|
|
773
790
|
const eventProps: ISummarizeEventProps = {
|
|
774
791
|
result: status,
|
|
775
792
|
currentAttempt,
|
|
776
793
|
maxAttempts,
|
|
777
|
-
error
|
|
794
|
+
error,
|
|
778
795
|
};
|
|
779
796
|
this.emit("summarize", eventProps);
|
|
780
797
|
|
|
@@ -811,6 +828,9 @@ export class RunningSummarizer extends TypedEventEmitter<ISummarizerEvents> impl
|
|
|
811
828
|
// Ack / nack is the final step, so if it succeeds we're done.
|
|
812
829
|
const ackNackResult = await summarizeResult.receivedSummaryAckOrNack;
|
|
813
830
|
status = ackNackResult.success ? "success" : "failure";
|
|
831
|
+
if (!ackNackResult.success) {
|
|
832
|
+
error = ackNackResult.error;
|
|
833
|
+
}
|
|
814
834
|
const eventProps: ISummarizeEventProps = {
|
|
815
835
|
result: status,
|
|
816
836
|
currentAttempt,
|
|
@@ -823,6 +843,14 @@ export class RunningSummarizer extends TypedEventEmitter<ISummarizerEvents> impl
|
|
|
823
843
|
|
|
824
844
|
// If summarization is still unsuccessful, stop the summarizer.
|
|
825
845
|
if (status === "failure") {
|
|
846
|
+
this.mc.logger.sendErrorEvent(
|
|
847
|
+
{
|
|
848
|
+
eventName: "SummarizeFailed",
|
|
849
|
+
maxAttempts,
|
|
850
|
+
summaryAttempts: currentAttempt,
|
|
851
|
+
},
|
|
852
|
+
error,
|
|
853
|
+
);
|
|
826
854
|
this.stopSummarizerCallback("failToSummarize");
|
|
827
855
|
}
|
|
828
856
|
return results;
|
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
ISummarizerNode,
|
|
9
9
|
ISummarizerNodeConfig,
|
|
10
10
|
ISummarizeResult,
|
|
11
|
-
ISummaryTreeWithStats,
|
|
12
11
|
CreateChildSummarizerNodeParam,
|
|
13
12
|
CreateSummarizerNodeSource,
|
|
14
13
|
SummarizeInternalFn,
|
|
@@ -19,7 +18,6 @@ import {
|
|
|
19
18
|
ISequencedDocumentMessage,
|
|
20
19
|
SummaryType,
|
|
21
20
|
ISnapshotTree,
|
|
22
|
-
SummaryObject,
|
|
23
21
|
} from "@fluidframework/protocol-definitions";
|
|
24
22
|
import {
|
|
25
23
|
ITelemetryLoggerExt,
|
|
@@ -30,15 +28,13 @@ import {
|
|
|
30
28
|
tagCodeArtifacts,
|
|
31
29
|
} from "@fluidframework/telemetry-utils";
|
|
32
30
|
import { assert, unreachableCase } from "@fluidframework/core-utils";
|
|
33
|
-
import {
|
|
31
|
+
import { mergeStats } from "@fluidframework/runtime-utils";
|
|
34
32
|
import {
|
|
35
33
|
EscapedPath,
|
|
36
34
|
ICreateChildDetails,
|
|
37
|
-
IInitialSummary,
|
|
38
35
|
IRefreshSummaryResult,
|
|
39
36
|
ISummarizerNodeRootContract,
|
|
40
37
|
parseSummaryForSubtrees,
|
|
41
|
-
parseSummaryTreeForSubtrees,
|
|
42
38
|
SummaryNode,
|
|
43
39
|
ValidateSummaryResult,
|
|
44
40
|
} from "./summarizerNodeUtils";
|
|
@@ -86,7 +82,6 @@ export class SummarizerNode implements IRootSummarizerNode {
|
|
|
86
82
|
private _changeSequenceNumber: number,
|
|
87
83
|
/** Undefined means created without summary */
|
|
88
84
|
private _latestSummary?: SummaryNode,
|
|
89
|
-
private readonly initialSummary?: IInitialSummary,
|
|
90
85
|
protected wipSummaryLogger?: ITelemetryBaseLogger,
|
|
91
86
|
/** A unique id of this node to be logged when sending telemetry. */
|
|
92
87
|
protected telemetryNodeId?: string,
|
|
@@ -521,7 +516,6 @@ export class SummarizerNode implements IRootSummarizerNode {
|
|
|
521
516
|
config,
|
|
522
517
|
createDetails.changeSequenceNumber,
|
|
523
518
|
createDetails.latestSummary,
|
|
524
|
-
createDetails.initialSummary,
|
|
525
519
|
this.wipSummaryLogger,
|
|
526
520
|
createDetails.telemetryNodeId,
|
|
527
521
|
);
|
|
@@ -549,7 +543,6 @@ export class SummarizerNode implements IRootSummarizerNode {
|
|
|
549
543
|
id: string,
|
|
550
544
|
createParam: CreateChildSummarizerNodeParam,
|
|
551
545
|
): ICreateChildDetails {
|
|
552
|
-
let initialSummary: IInitialSummary | undefined;
|
|
553
546
|
let latestSummary: SummaryNode | undefined;
|
|
554
547
|
let changeSequenceNumber: number;
|
|
555
548
|
|
|
@@ -562,63 +555,12 @@ export class SummarizerNode implements IRootSummarizerNode {
|
|
|
562
555
|
) {
|
|
563
556
|
// Prioritize latest summary if it was after this node was attached.
|
|
564
557
|
latestSummary = parentLatestSummary.createForChild(id);
|
|
565
|
-
} else {
|
|
566
|
-
const summary = convertToSummaryTree(
|
|
567
|
-
createParam.snapshot,
|
|
568
|
-
) as ISummaryTreeWithStats;
|
|
569
|
-
initialSummary = {
|
|
570
|
-
sequenceNumber: createParam.sequenceNumber,
|
|
571
|
-
id,
|
|
572
|
-
summary,
|
|
573
|
-
};
|
|
574
558
|
}
|
|
575
559
|
changeSequenceNumber = createParam.sequenceNumber;
|
|
576
560
|
break;
|
|
577
561
|
}
|
|
578
|
-
case CreateSummarizerNodeSource.FromSummary:
|
|
579
|
-
if (this.initialSummary === undefined) {
|
|
580
|
-
assert(
|
|
581
|
-
!!parentLatestSummary,
|
|
582
|
-
0x1ac /* "Cannot create child from summary if parent does not have latest summary" */,
|
|
583
|
-
);
|
|
584
|
-
}
|
|
585
|
-
// fallthrough to local
|
|
586
|
-
}
|
|
562
|
+
case CreateSummarizerNodeSource.FromSummary:
|
|
587
563
|
case CreateSummarizerNodeSource.Local: {
|
|
588
|
-
const parentInitialSummary = this.initialSummary;
|
|
589
|
-
if (parentInitialSummary !== undefined) {
|
|
590
|
-
let childSummary: SummaryObject | undefined;
|
|
591
|
-
if (parentInitialSummary.summary !== undefined) {
|
|
592
|
-
const { childrenTree } = parseSummaryTreeForSubtrees(
|
|
593
|
-
parentInitialSummary.summary.summary,
|
|
594
|
-
);
|
|
595
|
-
assert(
|
|
596
|
-
childrenTree.type === SummaryType.Tree,
|
|
597
|
-
0x1d6 /* "Parent summary object is not a tree" */,
|
|
598
|
-
);
|
|
599
|
-
childSummary = childrenTree.tree[id];
|
|
600
|
-
}
|
|
601
|
-
if (createParam.type === CreateSummarizerNodeSource.FromSummary) {
|
|
602
|
-
// Locally created would not have differential subtree.
|
|
603
|
-
assert(!!childSummary, 0x1ad /* "Missing child summary tree" */);
|
|
604
|
-
}
|
|
605
|
-
let childSummaryWithStats: ISummaryTreeWithStats | undefined;
|
|
606
|
-
if (childSummary !== undefined) {
|
|
607
|
-
assert(
|
|
608
|
-
childSummary.type === SummaryType.Tree,
|
|
609
|
-
0x1ae /* "Child summary object is not a tree" */,
|
|
610
|
-
);
|
|
611
|
-
childSummaryWithStats = {
|
|
612
|
-
summary: childSummary,
|
|
613
|
-
stats: calculateStats(childSummary),
|
|
614
|
-
};
|
|
615
|
-
}
|
|
616
|
-
initialSummary = {
|
|
617
|
-
sequenceNumber: parentInitialSummary.sequenceNumber,
|
|
618
|
-
id,
|
|
619
|
-
summary: childSummaryWithStats,
|
|
620
|
-
};
|
|
621
|
-
}
|
|
622
564
|
latestSummary = parentLatestSummary?.createForChild(id);
|
|
623
565
|
changeSequenceNumber = parentLatestSummary?.referenceSequenceNumber ?? -1;
|
|
624
566
|
break;
|
|
@@ -629,13 +571,12 @@ export class SummarizerNode implements IRootSummarizerNode {
|
|
|
629
571
|
}
|
|
630
572
|
}
|
|
631
573
|
|
|
632
|
-
const
|
|
574
|
+
const childTelemetryNodeId = `${this.telemetryNodeId ?? ""}/${id}`;
|
|
633
575
|
|
|
634
576
|
return {
|
|
635
|
-
initialSummary,
|
|
636
577
|
latestSummary,
|
|
637
578
|
changeSequenceNumber,
|
|
638
|
-
telemetryNodeId:
|
|
579
|
+
telemetryNodeId: childTelemetryNodeId,
|
|
639
580
|
};
|
|
640
581
|
}
|
|
641
582
|
|
|
@@ -719,7 +660,6 @@ export const createRootSummarizerNode = (
|
|
|
719
660
|
referenceSequenceNumber === undefined
|
|
720
661
|
? undefined
|
|
721
662
|
: SummaryNode.createForRoot(referenceSequenceNumber),
|
|
722
|
-
undefined /* initialSummary */,
|
|
723
663
|
undefined /* wipSummaryLogger */,
|
|
724
664
|
"" /* telemetryNodeId */,
|
|
725
665
|
);
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { ITelemetryLoggerExt, TelemetryDataTag } from "@fluidframework/telemetry-utils";
|
|
7
|
-
import { ISnapshotTree,
|
|
8
|
-
import { channelsTreeName
|
|
7
|
+
import { ISnapshotTree, SummaryObject } from "@fluidframework/protocol-definitions";
|
|
8
|
+
import { channelsTreeName } from "@fluidframework/runtime-definitions";
|
|
9
9
|
|
|
10
10
|
export interface IRefreshSummaryResult {
|
|
11
11
|
/** Tells whether this summary is tracked by this client. */
|
|
@@ -135,21 +135,10 @@ export class SummaryNode {
|
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
/**
|
|
139
|
-
* Information about the initial summary tree found from an attach op.
|
|
140
|
-
*/
|
|
141
|
-
export interface IInitialSummary {
|
|
142
|
-
sequenceNumber: number;
|
|
143
|
-
id: string;
|
|
144
|
-
summary: ISummaryTreeWithStats | undefined;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
138
|
/**
|
|
148
139
|
* Represents the details needed to create a child summarizer node.
|
|
149
140
|
*/
|
|
150
141
|
export interface ICreateChildDetails {
|
|
151
|
-
/** Summary from attach op if known */
|
|
152
|
-
initialSummary: IInitialSummary | undefined;
|
|
153
142
|
/** Latest summary from server node data */
|
|
154
143
|
latestSummary: SummaryNode | undefined;
|
|
155
144
|
/** Sequence number of latest known change to the node */
|
|
@@ -184,23 +173,3 @@ export function parseSummaryForSubtrees(baseSummary: ISnapshotTree): ISubtreeInf
|
|
|
184
173
|
childrenPathPart: undefined,
|
|
185
174
|
};
|
|
186
175
|
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Checks if the summary contains .channels subtree where the children subtrees
|
|
190
|
-
* would be located if exists.
|
|
191
|
-
* @param baseSummary - summary to check
|
|
192
|
-
*/
|
|
193
|
-
export function parseSummaryTreeForSubtrees(summary: ISummaryTree): ISubtreeInfo<SummaryObject> {
|
|
194
|
-
// New versions of snapshots have child nodes isolated in .channels subtree
|
|
195
|
-
const channelsSubtree = summary.tree[channelsTreeName];
|
|
196
|
-
if (channelsSubtree !== undefined) {
|
|
197
|
-
return {
|
|
198
|
-
childrenTree: channelsSubtree,
|
|
199
|
-
childrenPathPart: channelsTreeName,
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
return {
|
|
203
|
-
childrenTree: summary,
|
|
204
|
-
childrenPathPart: undefined,
|
|
205
|
-
};
|
|
206
|
-
}
|
|
@@ -29,7 +29,6 @@ import { SummarizerNode } from "./summarizerNode";
|
|
|
29
29
|
import {
|
|
30
30
|
EscapedPath,
|
|
31
31
|
ICreateChildDetails,
|
|
32
|
-
IInitialSummary,
|
|
33
32
|
ISummarizerNodeRootContract,
|
|
34
33
|
SummaryNode,
|
|
35
34
|
ValidateSummaryResult,
|
|
@@ -111,7 +110,6 @@ export class SummarizerNodeWithGC extends SummarizerNode implements IRootSummari
|
|
|
111
110
|
changeSequenceNumber: number,
|
|
112
111
|
/** Undefined means created without summary */
|
|
113
112
|
latestSummary?: SummaryNode,
|
|
114
|
-
initialSummary?: IInitialSummary,
|
|
115
113
|
wipSummaryLogger?: ITelemetryBaseLogger,
|
|
116
114
|
private readonly getGCDataFn?: (fullGC?: boolean) => Promise<IGarbageCollectionData>,
|
|
117
115
|
getBaseGCDetailsFn?: () => Promise<IGarbageCollectionDetailsBase>,
|
|
@@ -135,7 +133,6 @@ export class SummarizerNodeWithGC extends SummarizerNode implements IRootSummari
|
|
|
135
133
|
config,
|
|
136
134
|
changeSequenceNumber,
|
|
137
135
|
latestSummary,
|
|
138
|
-
initialSummary,
|
|
139
136
|
wipSummaryLogger,
|
|
140
137
|
telemetryId,
|
|
141
138
|
);
|
|
@@ -398,7 +395,6 @@ export class SummarizerNodeWithGC extends SummarizerNode implements IRootSummari
|
|
|
398
395
|
createParam: CreateChildSummarizerNodeParam,
|
|
399
396
|
config: ISummarizerNodeConfigWithGC = {},
|
|
400
397
|
getGCDataFn?: (fullGC?: boolean) => Promise<IGarbageCollectionData>,
|
|
401
|
-
getBaseGCDetailsFn?: () => Promise<IGarbageCollectionDetailsBase>,
|
|
402
398
|
): ISummarizerNodeWithGC {
|
|
403
399
|
assert(!this.children.has(id), 0x1b6 /* "Create SummarizerNode child already exists" */);
|
|
404
400
|
/**
|
|
@@ -423,7 +419,6 @@ export class SummarizerNodeWithGC extends SummarizerNode implements IRootSummari
|
|
|
423
419
|
},
|
|
424
420
|
createDetails.changeSequenceNumber,
|
|
425
421
|
createDetails.latestSummary,
|
|
426
|
-
createDetails.initialSummary,
|
|
427
422
|
this.wipSummaryLogger,
|
|
428
423
|
getGCDataFn,
|
|
429
424
|
getChildBaseGCDetailsFn,
|
|
@@ -563,7 +558,6 @@ export const createRootSummarizerNodeWithGC = (
|
|
|
563
558
|
referenceSequenceNumber === undefined
|
|
564
559
|
? undefined
|
|
565
560
|
: SummaryNode.createForRoot(referenceSequenceNumber),
|
|
566
|
-
undefined /* initialSummary */,
|
|
567
561
|
undefined /* wipSummaryLogger */,
|
|
568
562
|
getGCDataFn,
|
|
569
563
|
getBaseGCDetailsFn,
|
|
@@ -377,7 +377,7 @@ export type EnqueueSummarizeResult =
|
|
|
377
377
|
* @alpha
|
|
378
378
|
*/
|
|
379
379
|
export type SummarizerStopReason =
|
|
380
|
-
/** Summarizer client failed to summarize in all
|
|
380
|
+
/** Summarizer client failed to summarize in all attempts. */
|
|
381
381
|
| "failToSummarize"
|
|
382
382
|
/** Parent client reported that it is no longer connected. */
|
|
383
383
|
| "parentNotConnected"
|