@fluidframework/container-runtime 0.56.7 → 0.57.1

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.
Files changed (101) hide show
  1. package/dist/blobManager.d.ts.map +1 -1
  2. package/dist/blobManager.js +9 -1
  3. package/dist/blobManager.js.map +1 -1
  4. package/dist/connectionTelemetry.d.ts.map +1 -1
  5. package/dist/connectionTelemetry.js +6 -6
  6. package/dist/connectionTelemetry.js.map +1 -1
  7. package/dist/containerRuntime.d.ts +68 -28
  8. package/dist/containerRuntime.d.ts.map +1 -1
  9. package/dist/containerRuntime.js +148 -89
  10. package/dist/containerRuntime.js.map +1 -1
  11. package/dist/dataStore.d.ts +27 -0
  12. package/dist/dataStore.d.ts.map +1 -0
  13. package/dist/dataStore.js +113 -0
  14. package/dist/dataStore.js.map +1 -0
  15. package/dist/dataStoreContext.d.ts +1 -7
  16. package/dist/dataStoreContext.d.ts.map +1 -1
  17. package/dist/dataStoreContext.js +10 -6
  18. package/dist/dataStoreContext.js.map +1 -1
  19. package/dist/dataStores.d.ts +9 -5
  20. package/dist/dataStores.d.ts.map +1 -1
  21. package/dist/dataStores.js +14 -19
  22. package/dist/dataStores.js.map +1 -1
  23. package/dist/garbageCollection.d.ts +66 -27
  24. package/dist/garbageCollection.d.ts.map +1 -1
  25. package/dist/garbageCollection.js +272 -97
  26. package/dist/garbageCollection.js.map +1 -1
  27. package/dist/index.d.ts +2 -2
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +2 -1
  30. package/dist/index.js.map +1 -1
  31. package/dist/packageVersion.d.ts +1 -1
  32. package/dist/packageVersion.js +1 -1
  33. package/dist/packageVersion.js.map +1 -1
  34. package/dist/runningSummarizer.d.ts +1 -0
  35. package/dist/runningSummarizer.d.ts.map +1 -1
  36. package/dist/runningSummarizer.js +23 -15
  37. package/dist/runningSummarizer.js.map +1 -1
  38. package/dist/summarizerTypes.d.ts +4 -6
  39. package/dist/summarizerTypes.d.ts.map +1 -1
  40. package/dist/summarizerTypes.js.map +1 -1
  41. package/dist/summaryGenerator.d.ts +2 -1
  42. package/dist/summaryGenerator.d.ts.map +1 -1
  43. package/dist/summaryGenerator.js +46 -29
  44. package/dist/summaryGenerator.js.map +1 -1
  45. package/lib/blobManager.d.ts.map +1 -1
  46. package/lib/blobManager.js +9 -1
  47. package/lib/blobManager.js.map +1 -1
  48. package/lib/connectionTelemetry.d.ts.map +1 -1
  49. package/lib/connectionTelemetry.js +6 -6
  50. package/lib/connectionTelemetry.js.map +1 -1
  51. package/lib/containerRuntime.d.ts +68 -28
  52. package/lib/containerRuntime.d.ts.map +1 -1
  53. package/lib/containerRuntime.js +149 -90
  54. package/lib/containerRuntime.js.map +1 -1
  55. package/lib/dataStore.d.ts +27 -0
  56. package/lib/dataStore.d.ts.map +1 -0
  57. package/lib/dataStore.js +108 -0
  58. package/lib/dataStore.js.map +1 -0
  59. package/lib/dataStoreContext.d.ts +1 -7
  60. package/lib/dataStoreContext.d.ts.map +1 -1
  61. package/lib/dataStoreContext.js +10 -6
  62. package/lib/dataStoreContext.js.map +1 -1
  63. package/lib/dataStores.d.ts +9 -5
  64. package/lib/dataStores.d.ts.map +1 -1
  65. package/lib/dataStores.js +13 -18
  66. package/lib/dataStores.js.map +1 -1
  67. package/lib/garbageCollection.d.ts +66 -27
  68. package/lib/garbageCollection.d.ts.map +1 -1
  69. package/lib/garbageCollection.js +274 -99
  70. package/lib/garbageCollection.js.map +1 -1
  71. package/lib/index.d.ts +2 -2
  72. package/lib/index.d.ts.map +1 -1
  73. package/lib/index.js +1 -1
  74. package/lib/index.js.map +1 -1
  75. package/lib/packageVersion.d.ts +1 -1
  76. package/lib/packageVersion.js +1 -1
  77. package/lib/packageVersion.js.map +1 -1
  78. package/lib/runningSummarizer.d.ts +1 -0
  79. package/lib/runningSummarizer.d.ts.map +1 -1
  80. package/lib/runningSummarizer.js +23 -15
  81. package/lib/runningSummarizer.js.map +1 -1
  82. package/lib/summarizerTypes.d.ts +4 -6
  83. package/lib/summarizerTypes.d.ts.map +1 -1
  84. package/lib/summarizerTypes.js.map +1 -1
  85. package/lib/summaryGenerator.d.ts +2 -1
  86. package/lib/summaryGenerator.d.ts.map +1 -1
  87. package/lib/summaryGenerator.js +46 -29
  88. package/lib/summaryGenerator.js.map +1 -1
  89. package/package.json +13 -13
  90. package/src/blobManager.ts +12 -1
  91. package/src/connectionTelemetry.ts +7 -6
  92. package/src/containerRuntime.ts +244 -115
  93. package/src/dataStore.ts +151 -0
  94. package/src/dataStoreContext.ts +11 -14
  95. package/src/dataStores.ts +23 -38
  96. package/src/garbageCollection.ts +385 -150
  97. package/src/index.ts +2 -1
  98. package/src/packageVersion.ts +1 -1
  99. package/src/runningSummarizer.ts +25 -16
  100. package/src/summarizerTypes.ts +4 -8
  101. package/src/summaryGenerator.ts +71 -23
package/src/index.ts CHANGED
@@ -10,12 +10,14 @@ export {
10
10
  IGCRuntimeOptions,
11
11
  ISummaryRuntimeOptions,
12
12
  IContainerRuntimeOptions,
13
+ IRootSummaryTreeWithStats,
13
14
  isRuntimeMessage,
14
15
  RuntimeMessage,
15
16
  unpackRuntimeMessage,
16
17
  ScheduleManager,
17
18
  agentSchedulerId,
18
19
  ContainerRuntime,
20
+ RuntimeHeaders,
19
21
  } from "./containerRuntime";
20
22
  export { DeltaScheduler } from "./deltaScheduler";
21
23
  export { FluidDataStoreRegistry } from "./dataStoreRegistry";
@@ -24,7 +26,6 @@ export {
24
26
  gcTreeKey,
25
27
  IGarbageCollectionRuntime,
26
28
  IGCStats,
27
- IUsedStateStats,
28
29
  } from "./garbageCollection";
29
30
  export {
30
31
  IPendingFlush,
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/container-runtime";
9
- export const pkgVersion = "0.56.7";
9
+ export const pkgVersion = "0.57.1";
@@ -93,6 +93,7 @@ export class RunningSummarizer implements IDisposable {
93
93
  readonly resultsBuilder: SummarizeResultBuilder;
94
94
  } | undefined;
95
95
  private summarizeCount = 0;
96
+ private totalSuccessfulAttempts = 0;
96
97
 
97
98
  private constructor(
98
99
  baseLogger: ITelemetryLogger,
@@ -107,7 +108,14 @@ export class RunningSummarizer implements IDisposable {
107
108
  { disableHeuristics = false }: Readonly<Partial<ISummarizerOptions>> = {},
108
109
  ) {
109
110
  this.logger = ChildLogger.create(
110
- baseLogger, "Running", { all: { summaryGenTag: () => this.summarizeCount } });
111
+ baseLogger, "Running",
112
+ {
113
+ all: {
114
+ summarizeCount: () => this.summarizeCount,
115
+ summarizerSuccessfulAttempts: () => this.totalSuccessfulAttempts,
116
+ },
117
+ },
118
+ );
111
119
 
112
120
  if (!disableHeuristics) {
113
121
  this.heuristicRunner = new SummarizeHeuristicRunner(
@@ -124,7 +132,7 @@ export class RunningSummarizer implements IDisposable {
124
132
  maxAckWaitTime,
125
133
  () => {
126
134
  this.raiseSummarizingError("summaryAckWaitTimeout");
127
- // Note: summaryGenTag (from ChildLogger definition) may be 0,
135
+ // Note: summarizeCount (from ChildLogger definition) may be 0,
128
136
  // since this code path is hit when RunningSummarizer first starts up,
129
137
  // before this instance has kicked off a new summarize run.
130
138
  this.logger.sendErrorEvent({
@@ -152,6 +160,7 @@ export class RunningSummarizer implements IDisposable {
152
160
  this.heuristicData,
153
161
  this.submitSummaryCallback,
154
162
  this.raiseSummarizingError,
163
+ () => { this.totalSuccessfulAttempts++; },
155
164
  this.summaryWatcher,
156
165
  this.logger,
157
166
  );
@@ -183,8 +192,7 @@ export class RunningSummarizer implements IDisposable {
183
192
  switch (op.type) {
184
193
  case MessageType.ClientLeave:
185
194
  case MessageType.ClientJoin:
186
- case MessageType.Propose:
187
- case MessageType.Reject: {
195
+ case MessageType.Propose: {
188
196
  // Synchronously handle quorum ops like regular ops
189
197
  this.handleOp(undefined, op);
190
198
  return;
@@ -338,27 +346,27 @@ export class RunningSummarizer implements IDisposable {
338
346
  { refreshLatestAck: true, fullTree: true, delaySeconds: 10 * 60 },
339
347
  ];
340
348
  let overrideDelaySeconds: number | undefined;
341
- let totalAttempts = 0;
342
- let attemptPerPhase = 0;
349
+ let summaryAttempts = 0;
350
+ let summaryAttemptsPerPhase = 0;
343
351
 
344
352
  let lastResult: { message: string; error: any; } | undefined;
345
353
 
346
- for (let attemptPhase = 0; attemptPhase < attempts.length;) {
354
+ for (let summaryAttemptPhase = 0; summaryAttemptPhase < attempts.length;) {
347
355
  if (this.cancellationToken.cancelled) {
348
356
  return;
349
357
  }
350
358
 
351
- totalAttempts++;
352
- attemptPerPhase++;
359
+ summaryAttempts++;
360
+ summaryAttemptsPerPhase++;
353
361
 
354
- const { delaySeconds: regularDelaySeconds = 0, ...options } = attempts[attemptPhase];
362
+ const { delaySeconds: regularDelaySeconds = 0, ...options } = attempts[summaryAttemptPhase];
355
363
  const delaySeconds = overrideDelaySeconds ?? regularDelaySeconds;
356
364
 
357
365
  const summarizeProps: ITelemetryProperties = {
358
366
  summarizeReason,
359
- summarizeTotalAttempts: totalAttempts,
360
- summarizeAttemptsPerPhase: attemptPerPhase,
361
- summarizeAttemptPhase: attemptPhase + 1, // make everything 1-based
367
+ summaryAttempts,
368
+ summaryAttemptsPerPhase,
369
+ summaryAttemptPhase: summaryAttemptPhase + 1, // make everything 1-based
362
370
  ...options,
363
371
  };
364
372
 
@@ -377,14 +385,15 @@ export class RunningSummarizer implements IDisposable {
377
385
  const result = await resultSummarize.receivedSummaryAckOrNack;
378
386
 
379
387
  if (result.success) {
388
+ this.totalSuccessfulAttempts++;
380
389
  return;
381
390
  }
382
391
  // Check for retryDelay that can come from summaryNack or upload summary flow.
383
392
  // Retry the same step only once per retryAfter response.
384
393
  overrideDelaySeconds = result.retryAfterSeconds;
385
- if (overrideDelaySeconds === undefined || attemptPerPhase > 1) {
386
- attemptPhase++;
387
- attemptPerPhase = 0;
394
+ if (overrideDelaySeconds === undefined || summaryAttemptsPerPhase > 1) {
395
+ summaryAttemptPhase++;
396
+ summaryAttemptsPerPhase = 0;
388
397
  }
389
398
  lastResult = result;
390
399
  }
@@ -20,14 +20,6 @@ import {
20
20
  import { ISummaryStats } from "@fluidframework/runtime-definitions";
21
21
  import { ISummaryAckMessage, ISummaryNackMessage, ISummaryOpMessage } from "./summaryCollection";
22
22
 
23
- declare module "@fluidframework/core-interfaces" {
24
- export interface IFluidObject {
25
- /** @deprecated - use `FluidObject<ISummarizer>` instead */
26
- readonly ISummarizer?: ISummarizer;
27
-
28
- }
29
- }
30
-
31
23
  /**
32
24
  * @deprecated - This will be removed in a later release.
33
25
  */
@@ -144,8 +136,12 @@ export interface IEnqueueSummarizeOptions extends IOnDemandSummarizeOptions {
144
136
  * only relevant at the root of the tree.
145
137
  */
146
138
  export interface IGeneratedSummaryStats extends ISummaryStats {
139
+ /** The total number of data stores in the container. */
147
140
  readonly dataStoreCount: number;
141
+ /** The number of data stores that were summarized in this summary. */
148
142
  readonly summarizedDataStoreCount: number;
143
+ /** The number of data stores whose GC reference state was updated in this summary. */
144
+ readonly gcStateUpdatedDataStoreCount?: number;
149
145
  }
150
146
 
151
147
  /** Base results for all submitSummary attempts. */
@@ -153,6 +153,7 @@ export class SummaryGenerator {
153
153
  private readonly heuristicData: ISummarizeHeuristicData,
154
154
  private readonly submitSummaryCallback: (options: ISubmitSummaryOptions) => Promise<SubmitSummaryResult>,
155
155
  private readonly raiseSummarizingError: (errorCode: string) => void,
156
+ private readonly successfulSummaryCallback: () => void,
156
157
  private readonly summaryWatcher: Pick<IClientSummaryWatcher, "watchSummary">,
157
158
  private readonly logger: ITelemetryLogger,
158
159
  ) {
@@ -193,13 +194,21 @@ export class SummaryGenerator {
193
194
  ): Promise<void> {
194
195
  const { refreshLatestAck, fullTree } = options;
195
196
  const logger = ChildLogger.create(this.logger, undefined, { all: summarizeProps });
197
+
198
+ const timeSinceLastAttempt = Date.now() - this.heuristicData.lastAttempt.summaryTime;
199
+ const timeSinceLastSummary = Date.now() - this.heuristicData.lastSuccessfulSummary.summaryTime;
200
+ let summarizeTelemetryProps: Record<string, string | number | boolean | undefined> = {
201
+ fullTree,
202
+ timeSinceLastAttempt,
203
+ timeSinceLastSummary,
204
+ }
205
+
196
206
  const summarizeEvent = PerformanceEvent.start(logger, {
197
207
  eventName: "Summarize",
198
208
  refreshLatestAck,
199
- fullTree,
200
- timeSinceLastAttempt: Date.now() - this.heuristicData.lastAttempt.summaryTime,
201
- timeSinceLastSummary: Date.now() - this.heuristicData.lastSuccessfulSummary.summaryTime,
209
+ ...summarizeTelemetryProps,
202
210
  });
211
+
203
212
  // Helper functions to report failures and return.
204
213
  const getFailMessage =
205
214
  (errorCode: keyof typeof summarizeErrors) => `${errorCode}: ${summarizeErrors[errorCode]}`;
@@ -231,10 +240,15 @@ export class SummaryGenerator {
231
240
 
232
241
  // Wait to generate and send summary
233
242
  this.summarizeTimer.start();
243
+
234
244
  // Use record type to prevent unexpected value types
235
245
  let summaryData: SubmitSummaryResult | undefined;
236
- let generateTelemetryProps: Record<string, string | number | boolean | undefined> = {};
237
246
  try {
247
+ const generateSummaryEvent = PerformanceEvent.start(logger, {
248
+ eventName: "Summarize",
249
+ ...summarizeTelemetryProps,
250
+ });
251
+
238
252
  summaryData = await this.submitSummaryCallback({
239
253
  fullTree,
240
254
  refreshLatestAck,
@@ -243,30 +257,32 @@ export class SummaryGenerator {
243
257
  });
244
258
 
245
259
  // Cumulatively add telemetry properties based on how far generateSummary went.
246
- const { referenceSequenceNumber: refSequenceNumber } = summaryData;
247
- const opsSinceLastSummary = refSequenceNumber - this.heuristicData.lastSuccessfulSummary.refSequenceNumber;
248
- generateTelemetryProps = {
249
- referenceSequenceNumber: refSequenceNumber,
250
- opsSinceLastAttempt: refSequenceNumber - this.heuristicData.lastAttempt.refSequenceNumber,
260
+ const referenceSequenceNumber = summaryData.referenceSequenceNumber;
261
+ const opsSinceLastSummary =
262
+ referenceSequenceNumber - this.heuristicData.lastSuccessfulSummary.refSequenceNumber;
263
+ summarizeTelemetryProps = {
264
+ ...summarizeTelemetryProps,
265
+ referenceSequenceNumber,
266
+ opsSinceLastAttempt: referenceSequenceNumber - this.heuristicData.lastAttempt.refSequenceNumber,
251
267
  opsSinceLastSummary,
252
268
  };
253
269
  if (summaryData.stage !== "base") {
254
- generateTelemetryProps = {
255
- ...generateTelemetryProps,
270
+ summarizeTelemetryProps = {
271
+ ...summarizeTelemetryProps,
256
272
  ...summaryData.summaryStats,
257
273
  generateDuration: summaryData.generateDuration,
258
274
  };
259
275
 
260
276
  if (summaryData.stage !== "generate") {
261
- generateTelemetryProps = {
262
- ...generateTelemetryProps,
277
+ summarizeTelemetryProps = {
278
+ ...summarizeTelemetryProps,
263
279
  handle: summaryData.handle,
264
280
  uploadDuration: summaryData.uploadDuration,
265
281
  };
266
282
 
267
283
  if (summaryData.stage !== "upload") {
268
- generateTelemetryProps = {
269
- ...generateTelemetryProps,
284
+ summarizeTelemetryProps = {
285
+ ...summarizeTelemetryProps,
270
286
  clientSequenceNumber: summaryData.clientSequenceNumber,
271
287
  };
272
288
  }
@@ -274,11 +290,33 @@ export class SummaryGenerator {
274
290
  }
275
291
 
276
292
  if (summaryData.stage !== "submit") {
277
- return fail("submitSummaryFailure", summaryData.error, generateTelemetryProps);
293
+ return fail("submitSummaryFailure", summaryData.error, summarizeTelemetryProps);
294
+ }
295
+
296
+ /**
297
+ * With incremental summaries, if the full tree was not summarized, only data stores that changed should
298
+ * be summarized. A data store is considered changed if either or both of the following is true:
299
+ * - It has received an op.
300
+ * - Its reference state changed, i.e., it went from referenced to unreferenced or vice-versa.
301
+ *
302
+ * In the extreme case, every op can be for a different data store and each op can result in the reference
303
+ * state change of multiple data stores. So, the total number of data stores that are summarized should not
304
+ * exceed the number of ops since last summary + number of data store whose reference state changed.
305
+ */
306
+ if (!fullTree && !summaryData.forcedFullTree) {
307
+ const { summarizedDataStoreCount, gcStateUpdatedDataStoreCount = 0 } = summaryData.summaryStats;
308
+ if (summarizedDataStoreCount > gcStateUpdatedDataStoreCount + opsSinceLastSummary) {
309
+ logger.sendErrorEvent({
310
+ eventName: "IncrementalSummaryViolation",
311
+ summarizedDataStoreCount,
312
+ gcStateUpdatedDataStoreCount,
313
+ opsSinceLastSummary,
314
+ });
315
+ }
278
316
  }
279
317
 
280
318
  // Log event here on summary success only, as Summarize_cancel duplicates failure logging.
281
- logger.sendTelemetryEvent({ eventName: "GenerateSummary", ...generateTelemetryProps });
319
+ generateSummaryEvent.reportEvent("generate", {...summarizeTelemetryProps});
282
320
  resultsBuilder.summarySubmitted.resolve({ success: true, data: summaryData });
283
321
  } catch (error) {
284
322
  return fail("submitSummaryFailure", error);
@@ -306,9 +344,10 @@ export class SummaryGenerator {
306
344
  success: true,
307
345
  data: { summarizeOp, broadcastDuration },
308
346
  });
347
+
309
348
  this.heuristicData.lastAttempt.summarySequenceNumber = summarizeOp.sequenceNumber;
310
349
  logger.sendTelemetryEvent({
311
- eventName: "SummaryOp",
350
+ eventName: "Summarize_Op",
312
351
  duration: broadcastDuration,
313
352
  referenceSequenceNumber: summarizeOp.referenceSequenceNumber,
314
353
  summarySequenceNumber: summarizeOp.sequenceNumber,
@@ -328,14 +367,22 @@ export class SummaryGenerator {
328
367
 
329
368
  // Update for success/failure
330
369
  const ackNackDuration = Date.now() - this.heuristicData.lastAttempt.summaryTime;
331
- const telemetryProps: Record<string, number> = {
370
+
371
+ // adding new properties
372
+ summarizeTelemetryProps = {
332
373
  ackWaitDuration: ackNackDuration,
333
- sequenceNumber: ackNackOp.sequenceNumber,
374
+ ackNackSequenceNumber: ackNackOp.sequenceNumber,
334
375
  summarySequenceNumber: ackNackOp.contents.summaryProposal.summarySequenceNumber,
376
+ ...summarizeTelemetryProps,
335
377
  };
336
378
  if (ackNackOp.type === MessageType.SummaryAck) {
337
379
  this.heuristicData.markLastAttemptAsSuccessful();
338
- summarizeEvent.end({ ...telemetryProps, handle: ackNackOp.contents.handle, message: "summaryAck" });
380
+ this.successfulSummaryCallback();
381
+ summarizeEvent.end({
382
+ ...summarizeTelemetryProps,
383
+ handle: ackNackOp.contents.handle,
384
+ message: "summaryAck",
385
+ });
339
386
  resultsBuilder.receivedSummaryAckOrNack.resolve({ success: true, data: {
340
387
  summaryAckOp: ackNackOp,
341
388
  ackNackDuration,
@@ -349,13 +396,14 @@ export class SummaryGenerator {
349
396
 
350
397
  const error = new LoggingError(`summaryNack: ${message}`, { retryAfterSeconds });
351
398
  logger.sendErrorEvent(
352
- { eventName: "SummaryNack", ...generateTelemetryProps, retryAfterSeconds }, error);
399
+ { eventName: "SummaryNack", ...summarizeTelemetryProps, retryAfterSeconds }, error);
400
+
353
401
  assert(getRetryDelaySecondsFromError(error) === retryAfterSeconds, 0x25f /* "retryAfterSeconds" */);
354
402
  // This will only set resultsBuilder.receivedSummaryAckOrNack, as other promises are already set.
355
403
  return fail(
356
404
  "summaryNack",
357
405
  error,
358
- { ...telemetryProps, nackRetryAfter: retryAfterSeconds },
406
+ { ...summarizeTelemetryProps, nackRetryAfter: retryAfterSeconds },
359
407
  { summaryNackOp: ackNackOp, ackNackDuration },
360
408
  );
361
409
  }