@fluidframework/container-runtime 0.52.0-44610 → 0.53.0

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 (103) hide show
  1. package/dist/containerHandleContext.d.ts +0 -1
  2. package/dist/containerHandleContext.d.ts.map +1 -1
  3. package/dist/containerHandleContext.js +0 -1
  4. package/dist/containerHandleContext.js.map +1 -1
  5. package/dist/containerRuntime.d.ts +18 -3
  6. package/dist/containerRuntime.d.ts.map +1 -1
  7. package/dist/containerRuntime.js +84 -42
  8. package/dist/containerRuntime.js.map +1 -1
  9. package/dist/dataStoreContext.d.ts +4 -1
  10. package/dist/dataStoreContext.d.ts.map +1 -1
  11. package/dist/dataStoreContext.js +16 -13
  12. package/dist/dataStoreContext.js.map +1 -1
  13. package/dist/dataStores.d.ts +8 -8
  14. package/dist/dataStores.d.ts.map +1 -1
  15. package/dist/dataStores.js +20 -37
  16. package/dist/dataStores.js.map +1 -1
  17. package/dist/garbageCollection.d.ts +61 -14
  18. package/dist/garbageCollection.d.ts.map +1 -1
  19. package/dist/garbageCollection.js +275 -20
  20. package/dist/garbageCollection.js.map +1 -1
  21. package/dist/index.d.ts +2 -2
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +11 -2
  24. package/dist/index.js.map +1 -1
  25. package/dist/packageVersion.d.ts +1 -1
  26. package/dist/packageVersion.d.ts.map +1 -1
  27. package/dist/packageVersion.js +1 -1
  28. package/dist/packageVersion.js.map +1 -1
  29. package/dist/pendingStateManager.d.ts +0 -1
  30. package/dist/pendingStateManager.d.ts.map +1 -1
  31. package/dist/pendingStateManager.js +0 -36
  32. package/dist/pendingStateManager.js.map +1 -1
  33. package/dist/summarizer.d.ts +1 -3
  34. package/dist/summarizer.d.ts.map +1 -1
  35. package/dist/summarizer.js +0 -12
  36. package/dist/summarizer.js.map +1 -1
  37. package/dist/summarizerTypes.d.ts +2 -2
  38. package/dist/summarizerTypes.d.ts.map +1 -1
  39. package/dist/summarizerTypes.js.map +1 -1
  40. package/dist/summaryFormat.d.ts +9 -1
  41. package/dist/summaryFormat.d.ts.map +1 -1
  42. package/dist/summaryFormat.js.map +1 -1
  43. package/dist/summaryGenerator.d.ts.map +1 -1
  44. package/dist/summaryGenerator.js +1 -3
  45. package/dist/summaryGenerator.js.map +1 -1
  46. package/lib/containerHandleContext.d.ts +0 -1
  47. package/lib/containerHandleContext.d.ts.map +1 -1
  48. package/lib/containerHandleContext.js +0 -1
  49. package/lib/containerHandleContext.js.map +1 -1
  50. package/lib/containerRuntime.d.ts +18 -3
  51. package/lib/containerRuntime.d.ts.map +1 -1
  52. package/lib/containerRuntime.js +84 -43
  53. package/lib/containerRuntime.js.map +1 -1
  54. package/lib/dataStoreContext.d.ts +4 -1
  55. package/lib/dataStoreContext.d.ts.map +1 -1
  56. package/lib/dataStoreContext.js +16 -13
  57. package/lib/dataStoreContext.js.map +1 -1
  58. package/lib/dataStores.d.ts +8 -8
  59. package/lib/dataStores.d.ts.map +1 -1
  60. package/lib/dataStores.js +23 -40
  61. package/lib/dataStores.js.map +1 -1
  62. package/lib/garbageCollection.d.ts +61 -14
  63. package/lib/garbageCollection.d.ts.map +1 -1
  64. package/lib/garbageCollection.js +276 -21
  65. package/lib/garbageCollection.js.map +1 -1
  66. package/lib/index.d.ts +2 -2
  67. package/lib/index.d.ts.map +1 -1
  68. package/lib/index.js +2 -1
  69. package/lib/index.js.map +1 -1
  70. package/lib/packageVersion.d.ts +1 -1
  71. package/lib/packageVersion.d.ts.map +1 -1
  72. package/lib/packageVersion.js +1 -1
  73. package/lib/packageVersion.js.map +1 -1
  74. package/lib/pendingStateManager.d.ts +0 -1
  75. package/lib/pendingStateManager.d.ts.map +1 -1
  76. package/lib/pendingStateManager.js +0 -36
  77. package/lib/pendingStateManager.js.map +1 -1
  78. package/lib/summarizer.d.ts +1 -3
  79. package/lib/summarizer.d.ts.map +1 -1
  80. package/lib/summarizer.js +0 -12
  81. package/lib/summarizer.js.map +1 -1
  82. package/lib/summarizerTypes.d.ts +2 -2
  83. package/lib/summarizerTypes.d.ts.map +1 -1
  84. package/lib/summarizerTypes.js.map +1 -1
  85. package/lib/summaryFormat.d.ts +9 -1
  86. package/lib/summaryFormat.d.ts.map +1 -1
  87. package/lib/summaryFormat.js.map +1 -1
  88. package/lib/summaryGenerator.d.ts.map +1 -1
  89. package/lib/summaryGenerator.js +1 -3
  90. package/lib/summaryGenerator.js.map +1 -1
  91. package/package.json +16 -16
  92. package/src/containerHandleContext.ts +0 -1
  93. package/src/containerRuntime.ts +110 -53
  94. package/src/dataStoreContext.ts +15 -14
  95. package/src/dataStores.ts +32 -50
  96. package/src/garbageCollection.ts +390 -18
  97. package/src/index.ts +20 -2
  98. package/src/packageVersion.ts +1 -1
  99. package/src/pendingStateManager.ts +0 -43
  100. package/src/summarizer.ts +0 -15
  101. package/src/summarizerTypes.ts +1 -2
  102. package/src/summaryFormat.ts +10 -1
  103. package/src/summaryGenerator.ts +2 -3
@@ -188,6 +188,11 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
188
188
  return this._containerRuntime.disableIsolatedChannels;
189
189
  }
190
190
 
191
+ /** Tells whether GC data will be written at the root of the summary tree. If so, data store should not write it. */
192
+ protected get writeGCDataAtRoot(): boolean {
193
+ return this._containerRuntime.writeGCDataAtRoot;
194
+ }
195
+
191
196
  protected registry: IFluidDataStoreRegistry | undefined;
192
197
 
193
198
  protected detachedRuntimeCreation = false;
@@ -416,8 +421,10 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
416
421
  const attributes = createAttributes(pkg, isRootDataStore, this.disableIsolatedChannels);
417
422
  addBlobToSummary(summarizeResult, dataStoreAttributesBlobName, JSON.stringify(attributes));
418
423
 
419
- // Add GC details to the summary.
420
- addBlobToSummary(summarizeResult, gcBlobKey, JSON.stringify(this.summarizerNode.getGCSummaryDetails()));
424
+ // Add GC data to the summary if it's not written at the root.
425
+ if (!this.writeGCDataAtRoot) {
426
+ addBlobToSummary(summarizeResult, gcBlobKey, JSON.stringify(this.summarizerNode.getGCSummaryDetails()));
427
+ }
421
428
 
422
429
  // If we are not referenced, mark the summary tree as unreferenced. Also, update unreferenced blob
423
430
  // size in the summary stats with the blobs size of this data store.
@@ -675,6 +682,7 @@ export class RemotedFluidDataStoreContext extends FluidDataStoreContext {
675
682
  constructor(
676
683
  id: string,
677
684
  private readonly initSnapshotValue: ISnapshotTree | string | undefined,
685
+ private readonly getBaseSummaryGCDetails: () => Promise<IGarbageCollectionSummaryDetails | undefined>,
678
686
  runtime: ContainerRuntime,
679
687
  storage: IDocumentStorageService,
680
688
  scope: FluidObject,
@@ -760,16 +768,7 @@ export class RemotedFluidDataStoreContext extends FluidDataStoreContext {
760
768
  });
761
769
 
762
770
  private readonly gcDetailsInInitialSummaryP = new LazyPromise<IGarbageCollectionSummaryDetails>(async () => {
763
- // If the initial snapshot is undefined or string, the snapshot is in old format and won't have GC details.
764
- if (!(!this.initSnapshotValue || typeof this.initSnapshotValue === "string")
765
- && this.initSnapshotValue.blobs[gcBlobKey] !== undefined) {
766
- return readAndParse<IGarbageCollectionSummaryDetails>(
767
- this.storage,
768
- this.initSnapshotValue.blobs[gcBlobKey],
769
- );
770
- } else {
771
- return {};
772
- }
771
+ return (await this.getBaseSummaryGCDetails()) ?? {};
773
772
  });
774
773
 
775
774
  protected async getInitialSnapshotDetails(): Promise<ISnapshotDetails> {
@@ -850,8 +849,10 @@ export class LocalFluidDataStoreContextBase extends FluidDataStoreContext {
850
849
  );
851
850
  addBlobToSummary(summarizeResult, dataStoreAttributesBlobName, JSON.stringify(attributes));
852
851
 
853
- // Add GC details to the summary.
854
- addBlobToSummary(summarizeResult, gcBlobKey, JSON.stringify(this.summarizerNode.getGCSummaryDetails()));
852
+ // Add GC data to the summary if it's not written at the root.
853
+ if (!this.writeGCDataAtRoot) {
854
+ addBlobToSummary(summarizeResult, gcBlobKey, JSON.stringify(this.summarizerNode.getGCSummaryDetails()));
855
+ }
855
856
 
856
857
  // Attach message needs the summary in ITree format. Convert the ISummaryTree into an ITree.
857
858
  const snapshot = convertSummaryTreeToITree(summarizeResult.summary);
package/src/dataStores.ts CHANGED
@@ -8,8 +8,6 @@ import { DataCorruptionError, extractSafePropertiesFromMessage } from "@fluidfra
8
8
  import {
9
9
  ISequencedDocumentMessage,
10
10
  ISnapshotTree,
11
- ITreeEntry,
12
- SummaryType,
13
11
  } from "@fluidframework/protocol-definitions";
14
12
  import {
15
13
  channelsTreeName,
@@ -21,6 +19,7 @@ import {
21
19
  IFluidDataStoreChannel,
22
20
  IFluidDataStoreContextDetached,
23
21
  IGarbageCollectionData,
22
+ IGarbageCollectionSummaryDetails,
24
23
  IInboundSignalMessage,
25
24
  InboundAttachMessage,
26
25
  ISummarizeResult,
@@ -28,7 +27,6 @@ import {
28
27
  } from "@fluidframework/runtime-definitions";
29
28
  import {
30
29
  convertSnapshotTreeToSummaryTree,
31
- convertSummaryTreeToITree,
32
30
  convertToSummaryTree,
33
31
  create404Response,
34
32
  responseToException,
@@ -37,10 +35,9 @@ import {
37
35
  import { ChildLogger, TelemetryDataTag } from "@fluidframework/telemetry-utils";
38
36
  import { AttachState } from "@fluidframework/container-definitions";
39
37
  import { BlobCacheStorageService, buildSnapshotTree } from "@fluidframework/driver-utils";
40
- import { assert, Lazy } from "@fluidframework/common-utils";
38
+ import { assert, Lazy, LazyPromise } from "@fluidframework/common-utils";
41
39
  import { v4 as uuid } from "uuid";
42
- import { TreeTreeEntry } from "@fluidframework/protocol-base";
43
- import { GCDataBuilder, getChildNodesUsedRoutes } from "@fluidframework/garbage-collector";
40
+ import { GCDataBuilder, unpackChildNodesUsedRoutes } from "@fluidframework/garbage-collector";
44
41
  import { DataStoreContexts } from "./dataStoreContexts";
45
42
  import { ContainerRuntime } from "./containerRuntime";
46
43
  import {
@@ -67,6 +64,13 @@ export class DataStores implements IDisposable {
67
64
 
68
65
  private readonly disposeOnce = new Lazy<void>(() => this.contexts.dispose());
69
66
 
67
+ public readonly containerLoadStats: {
68
+ // number of dataStores during loadContainer
69
+ readonly containerLoadDataStoreCount: number;
70
+ // number of unreferenced dataStores during loadContainer
71
+ readonly referencedDataStoreCount: number;
72
+ };
73
+
70
74
  constructor(
71
75
  private readonly baseSnapshot: ISnapshotTree | undefined,
72
76
  private readonly runtime: ContainerRuntime,
@@ -75,12 +79,23 @@ export class DataStores implements IDisposable {
75
79
  (id: string, createParam: CreateChildSummarizerNodeParam) => CreateChildSummarizerNodeFn,
76
80
  private readonly deleteChildSummarizerNodeFn: (id: string) => void,
77
81
  baseLogger: ITelemetryBaseLogger,
82
+ getDataStoreBaseGCDetails: () => Promise<Map<string, IGarbageCollectionSummaryDetails>>,
83
+ private readonly dataStoreChanged: (id: string) => void,
78
84
  private readonly contexts: DataStoreContexts = new DataStoreContexts(baseLogger),
79
85
  ) {
80
86
  this.logger = ChildLogger.create(baseLogger);
87
+
88
+ const baseDataStoresGCDetailsP = new LazyPromise(async () => {
89
+ return getDataStoreBaseGCDetails();
90
+ });
91
+ // Returns the base summary GC details for the data store with the given id.
92
+ const dataStoreBaseGCDetails = async (dataStoreId: string) => {
93
+ const baseGCDetails = await baseDataStoresGCDetailsP;
94
+ return baseGCDetails.get(dataStoreId);
95
+ };
96
+
81
97
  // Extract stores stored inside the snapshot
82
98
  const fluidDataStores = new Map<string, ISnapshotTree>();
83
-
84
99
  if (baseSnapshot) {
85
100
  for (const [key, value] of Object.entries(baseSnapshot.trees)) {
86
101
  fluidDataStores.set(key, value);
@@ -101,6 +116,7 @@ export class DataStores implements IDisposable {
101
116
  dataStoreContext = new RemotedFluidDataStoreContext(
102
117
  key,
103
118
  value,
119
+ async () => dataStoreBaseGCDetails(key),
104
120
  this.runtime,
105
121
  this.runtime.storage,
106
122
  this.runtime.scope,
@@ -124,11 +140,10 @@ export class DataStores implements IDisposable {
124
140
  }
125
141
  this.contexts.addBoundOrRemoted(dataStoreContext);
126
142
  }
127
- this.logger.sendTelemetryEvent({
128
- eventName: "ContainerLoadStats",
129
- dataStoreCount: fluidDataStores.size,
143
+ this.containerLoadStats = {
144
+ containerLoadDataStoreCount: fluidDataStores.size,
130
145
  referencedDataStoreCount: fluidDataStores.size - unreferencedDataStoreCount,
131
- });
146
+ };
132
147
  }
133
148
 
134
149
  public processAttachMessage(message: ISequencedDocumentMessage, local: boolean) {
@@ -170,6 +185,8 @@ export class DataStores implements IDisposable {
170
185
  const remotedFluidDataStoreContext = new RemotedFluidDataStoreContext(
171
186
  attachMessage.id,
172
187
  snapshotTree,
188
+ // New data stores begin with empty GC details since GC hasn't run on them yet.
189
+ async () => { return {}; },
173
190
  this.runtime,
174
191
  new BlobCacheStorageService(this.runtime.storage, flatBlobs),
175
192
  this.runtime.scope,
@@ -281,6 +298,9 @@ export class DataStores implements IDisposable {
281
298
  const context = this.contexts.get(envelope.address);
282
299
  assert(!!context, 0x162 /* "There should be a store context for the op" */);
283
300
  context.process(transformed, local, localMessageMetadata);
301
+
302
+ // Notify that a data store changed. This is used to detect if a deleted data store is being used.
303
+ this.dataStoreChanged(envelope.address);
284
304
  }
285
305
 
286
306
  public async getDataStore(id: string, wait: boolean): Promise<FluidDataStoreContext> {
@@ -339,44 +359,6 @@ export class DataStores implements IDisposable {
339
359
  }
340
360
  }
341
361
 
342
- /**
343
- * Notifies this object to take the snapshot of the container.
344
- * @deprecated - Use summarize to get summary of the container runtime.
345
- */
346
- public async snapshot(): Promise<ITreeEntry[]> {
347
- // Iterate over each store and ask it to snapshot
348
- const fluidDataStoreSnapshotsP = Array.from(this.contexts).map(async ([fluidDataStoreId, value]) => {
349
- const summaryTree = await value.summarize(true /* fullTree */, false /* trackState */);
350
- assert(
351
- summaryTree.summary.type === SummaryType.Tree,
352
- 0x164 /* "summarize should always return a tree when fullTree is true" */);
353
- // back-compat summary - Remove this once snapshot is removed.
354
- const snapshot = convertSummaryTreeToITree(summaryTree.summary);
355
-
356
- // If ID exists then previous commit is still valid
357
- return {
358
- fluidDataStoreId,
359
- snapshot,
360
- };
361
- });
362
-
363
- const entries: ITreeEntry[] = [];
364
-
365
- // Add in module references to the store snapshots
366
- const fluidDataStoreSnapshots = await Promise.all(fluidDataStoreSnapshotsP);
367
-
368
- // Sort for better diffing of snapshots (in replay tool, used to find bugs in snapshotting logic)
369
- fluidDataStoreSnapshots.sort((a, b) => a?.fluidDataStoreId.localeCompare(b.fluidDataStoreId));
370
-
371
- for (const fluidDataStoreSnapshot of fluidDataStoreSnapshots) {
372
- entries.push(new TreeTreeEntry(
373
- fluidDataStoreSnapshot.fluidDataStoreId,
374
- fluidDataStoreSnapshot.snapshot,
375
- ));
376
- }
377
- return entries;
378
- }
379
-
380
362
  public get size(): number {
381
363
  return this.contexts.size;
382
364
  }
@@ -474,7 +456,7 @@ export class DataStores implements IDisposable {
474
456
  */
475
457
  public updateUsedRoutes(usedRoutes: string[], gcTimestamp?: number): IUsedStateStats {
476
458
  // Get a map of data store ids to routes used in it.
477
- const usedDataStoreRoutes = getChildNodesUsedRoutes(usedRoutes);
459
+ const usedDataStoreRoutes = unpackChildNodesUsedRoutes(usedRoutes);
478
460
 
479
461
  // Verify that the used routes are correct.
480
462
  for (const [id] of usedDataStoreRoutes) {