@fluidframework/container-runtime 0.54.0 → 0.55.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 (77) hide show
  1. package/.eslintrc.js +1 -1
  2. package/dist/blobManager.js +1 -1
  3. package/dist/blobManager.js.map +1 -1
  4. package/dist/containerRuntime.d.ts +17 -2
  5. package/dist/containerRuntime.d.ts.map +1 -1
  6. package/dist/containerRuntime.js +31 -21
  7. package/dist/containerRuntime.js.map +1 -1
  8. package/dist/dataStoreContext.d.ts +16 -5
  9. package/dist/dataStoreContext.d.ts.map +1 -1
  10. package/dist/dataStoreContext.js +20 -8
  11. package/dist/dataStoreContext.js.map +1 -1
  12. package/dist/dataStores.d.ts +11 -2
  13. package/dist/dataStores.d.ts.map +1 -1
  14. package/dist/dataStores.js +33 -17
  15. package/dist/dataStores.js.map +1 -1
  16. package/dist/garbageCollection.d.ts +28 -6
  17. package/dist/garbageCollection.d.ts.map +1 -1
  18. package/dist/garbageCollection.js +83 -7
  19. package/dist/garbageCollection.js.map +1 -1
  20. package/dist/index.d.ts +1 -1
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +2 -1
  23. package/dist/index.js.map +1 -1
  24. package/dist/packageVersion.d.ts +1 -1
  25. package/dist/packageVersion.js +1 -1
  26. package/dist/packageVersion.js.map +1 -1
  27. package/dist/summaryFormat.d.ts +2 -0
  28. package/dist/summaryFormat.d.ts.map +1 -1
  29. package/dist/summaryFormat.js +0 -3
  30. package/dist/summaryFormat.js.map +1 -1
  31. package/dist/summaryManager.d.ts +1 -0
  32. package/dist/summaryManager.d.ts.map +1 -1
  33. package/dist/summaryManager.js +7 -2
  34. package/dist/summaryManager.js.map +1 -1
  35. package/lib/blobManager.js +1 -1
  36. package/lib/blobManager.js.map +1 -1
  37. package/lib/containerRuntime.d.ts +17 -2
  38. package/lib/containerRuntime.d.ts.map +1 -1
  39. package/lib/containerRuntime.js +30 -20
  40. package/lib/containerRuntime.js.map +1 -1
  41. package/lib/dataStoreContext.d.ts +16 -5
  42. package/lib/dataStoreContext.d.ts.map +1 -1
  43. package/lib/dataStoreContext.js +20 -8
  44. package/lib/dataStoreContext.js.map +1 -1
  45. package/lib/dataStores.d.ts +11 -2
  46. package/lib/dataStores.d.ts.map +1 -1
  47. package/lib/dataStores.js +33 -17
  48. package/lib/dataStores.js.map +1 -1
  49. package/lib/garbageCollection.d.ts +28 -6
  50. package/lib/garbageCollection.d.ts.map +1 -1
  51. package/lib/garbageCollection.js +83 -7
  52. package/lib/garbageCollection.js.map +1 -1
  53. package/lib/index.d.ts +1 -1
  54. package/lib/index.d.ts.map +1 -1
  55. package/lib/index.js +1 -1
  56. package/lib/index.js.map +1 -1
  57. package/lib/packageVersion.d.ts +1 -1
  58. package/lib/packageVersion.js +1 -1
  59. package/lib/packageVersion.js.map +1 -1
  60. package/lib/summaryFormat.d.ts +2 -0
  61. package/lib/summaryFormat.d.ts.map +1 -1
  62. package/lib/summaryFormat.js +0 -3
  63. package/lib/summaryFormat.js.map +1 -1
  64. package/lib/summaryManager.d.ts +1 -0
  65. package/lib/summaryManager.d.ts.map +1 -1
  66. package/lib/summaryManager.js +7 -2
  67. package/lib/summaryManager.js.map +1 -1
  68. package/package.json +21 -20
  69. package/src/blobManager.ts +1 -1
  70. package/src/containerRuntime.ts +34 -23
  71. package/src/dataStoreContext.ts +31 -9
  72. package/src/dataStores.ts +43 -20
  73. package/src/garbageCollection.ts +112 -10
  74. package/src/index.ts +1 -0
  75. package/src/packageVersion.ts +1 -1
  76. package/src/summaryFormat.ts +2 -3
  77. package/src/summaryManager.ts +9 -3
@@ -6,6 +6,7 @@
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.getSummaryForDatastores = exports.DataStores = void 0;
8
8
  const container_utils_1 = require("@fluidframework/container-utils");
9
+ const datastore_1 = require("@fluidframework/datastore");
9
10
  const runtime_definitions_1 = require("@fluidframework/runtime-definitions");
10
11
  const runtime_utils_1 = require("@fluidframework/runtime-utils");
11
12
  const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
@@ -32,7 +33,7 @@ const isDataStoreAliasMessage = (maybeDataStoreAliasMessage) => {
32
33
  * but eventually could be hosted on any channel once we formalize the channel api boundary.
33
34
  */
34
35
  class DataStores {
35
- constructor(baseSnapshot, runtime, submitAttachFn, getCreateChildSummarizerNodeFn, deleteChildSummarizerNodeFn, baseLogger, getDataStoreBaseGCDetails, dataStoreChanged, aliasMap, contexts = new dataStoreContexts_1.DataStoreContexts(baseLogger)) {
36
+ constructor(baseSnapshot, runtime, submitAttachFn, getCreateChildSummarizerNodeFn, deleteChildSummarizerNodeFn, baseLogger, getBaseGCDetails, dataStoreChanged, aliasMap, contexts = new dataStoreContexts_1.DataStoreContexts(baseLogger)) {
36
37
  this.baseSnapshot = baseSnapshot;
37
38
  this.runtime = runtime;
38
39
  this.submitAttachFn = submitAttachFn;
@@ -46,14 +47,18 @@ class DataStores {
46
47
  // 0.24 back-compat attachingBeforeSummary
47
48
  this.attachOpFiredForDataStore = new Set();
48
49
  this.disposeOnce = new common_utils_1.Lazy(() => this.contexts.dispose());
50
+ // Stores the ids of new data stores between two GC runs. This is used to notify the garbage collector of new
51
+ // root data stores that are added.
52
+ this.dataStoresSinceLastGC = [];
49
53
  this.dispose = () => this.disposeOnce.value;
50
54
  this.logger = telemetry_utils_1.ChildLogger.create(baseLogger);
51
- const baseDataStoresGCDetailsP = new common_utils_1.LazyPromise(async () => {
52
- return getDataStoreBaseGCDetails();
55
+ this.containerRuntimeHandle = new datastore_1.FluidObjectHandle(this.runtime, "/", this.runtime.IFluidHandleContext);
56
+ const baseGCDetailsP = new common_utils_1.LazyPromise(async () => {
57
+ return getBaseGCDetails();
53
58
  });
54
- // Returns the base summary GC details for the data store with the given id.
59
+ // Returns the base GC details for the data store with the given id.
55
60
  const dataStoreBaseGCDetails = async (dataStoreId) => {
56
- const baseGCDetails = await baseDataStoresGCDetailsP;
61
+ const baseGCDetails = await baseGCDetailsP;
57
62
  return baseGCDetails.get(dataStoreId);
58
63
  };
59
64
  // Extract stores stored inside the snapshot
@@ -95,6 +100,7 @@ class DataStores {
95
100
  processAttachMessage(message, local) {
96
101
  var _a, _b;
97
102
  const attachMessage = message.contents;
103
+ this.dataStoresSinceLastGC.push(attachMessage.id);
98
104
  // The local object has already been attached
99
105
  if (local) {
100
106
  common_utils_1.assert(this.pendingAttach.has(attachMessage.id), 0x15e /* "Local object does not have matching attach message id" */);
@@ -103,7 +109,7 @@ class DataStores {
103
109
  return;
104
110
  }
105
111
  // If a non-local operation then go and create the object, otherwise mark it as officially attached.
106
- if (this.contexts.has(attachMessage.id)) {
112
+ if (this.alreadyProcessed(attachMessage.id)) {
107
113
  // TODO: dataStoreId may require a different tag from PackageData #7488
108
114
  const error = new container_utils_1.DataCorruptionError("duplicateDataStoreCreatedWithExistingId", Object.assign(Object.assign({}, container_utils_1.extractSafePropertiesFromMessage(message)), { dataStoreId: {
109
115
  value: attachMessage.id,
@@ -129,9 +135,6 @@ class DataStores {
129
135
  },
130
136
  }), pkg);
131
137
  this.contexts.addBoundOrRemoted(remotedFluidDataStoreContext);
132
- // Equivalent of nextTick() - Prefetch once all current ops have completed
133
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
134
- Promise.resolve().then(async () => remotedFluidDataStoreContext.realize());
135
138
  }
136
139
  processAliasMessage(message, localOpMetadata, local) {
137
140
  const aliasMessage = message.contents;
@@ -145,14 +148,7 @@ class DataStores {
145
148
  }
146
149
  }
147
150
  processAliasMessageCore(aliasMessage) {
148
- const existingMapping = this.aliasMap.get(aliasMessage.alias);
149
- if (existingMapping !== undefined) {
150
- return false;
151
- }
152
- // Unlikely scenario, but we may receive an alias OP with the alias value
153
- // equal to one of the ids supplied to `createRootDataStore` in the past
154
- const maybeContextWithAliasAsId = this.contexts.get(aliasMessage.alias);
155
- if (maybeContextWithAliasAsId !== undefined) {
151
+ if (this.alreadyProcessed(aliasMessage.alias)) {
156
152
  return false;
157
153
  }
158
154
  const currentContext = this.contexts.get(aliasMessage.internalId);
@@ -167,6 +163,9 @@ class DataStores {
167
163
  currentContext.setRoot();
168
164
  return true;
169
165
  }
166
+ alreadyProcessed(id) {
167
+ return this.aliasMap.get(id) !== undefined || this.contexts.get(id) !== undefined;
168
+ }
170
169
  bindFluidDataStore(fluidDataStoreRuntime) {
171
170
  const id = fluidDataStoreRuntime.id;
172
171
  const localContext = this.contexts.getUnbound(id);
@@ -324,6 +323,23 @@ class DataStores {
324
323
  } while (notBoundContextsLength !== this.contexts.notBoundLength());
325
324
  return builder.getSummaryTree();
326
325
  }
326
+ /**
327
+ * Before GC runs, called by the garbage collector to update any pending GC state.
328
+ * The garbage collector needs to know all outbound references that are added. Since root data stores are not
329
+ * explicitly marked as referenced, notify GC of new root data stores that were added since the last GC run.
330
+ */
331
+ async updateStateBeforeGC() {
332
+ for (const id of this.dataStoresSinceLastGC) {
333
+ const context = this.contexts.get(id);
334
+ common_utils_1.assert(context !== undefined, 0x2b6 /* `Missing data store context with id ${id}` */);
335
+ if (await context.isRoot()) {
336
+ // A root data store is basically a reference from the container runtime to the data store.
337
+ const handle = new datastore_1.FluidObjectHandle(context, id, this.runtime.IFluidHandleContext);
338
+ this.runtime.addedGCOutboundReference(this.containerRuntimeHandle, handle);
339
+ }
340
+ }
341
+ this.dataStoresSinceLastGC = [];
342
+ }
327
343
  /**
328
344
  * Generates data used for garbage collection. It does the following:
329
345
  * 1. Calls into each child data store context to get its GC data.
@@ -1 +1 @@
1
- {"version":3,"file":"dataStores.js","sourceRoot":"","sources":["../src/dataStores.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger, ITelemetryBaseLogger, IDisposable } from \"@fluidframework/common-definitions\";\nimport { DataCorruptionError, extractSafePropertiesFromMessage } from \"@fluidframework/container-utils\";\nimport {\n ISequencedDocumentMessage,\n ISnapshotTree,\n} from \"@fluidframework/protocol-definitions\";\nimport {\n channelsTreeName,\n CreateChildSummarizerNodeFn,\n CreateChildSummarizerNodeParam,\n CreateSummarizerNodeSource,\n IAttachMessage,\n IEnvelope,\n IFluidDataStoreChannel,\n IFluidDataStoreContextDetached,\n IGarbageCollectionData,\n IGarbageCollectionSummaryDetails,\n IInboundSignalMessage,\n InboundAttachMessage,\n ISummarizeResult,\n ISummaryTreeWithStats,\n} from \"@fluidframework/runtime-definitions\";\nimport {\n convertSnapshotTreeToSummaryTree,\n convertToSummaryTree,\n create404Response,\n responseToException,\n SummaryTreeBuilder,\n} from \"@fluidframework/runtime-utils\";\nimport { ChildLogger, TelemetryDataTag } from \"@fluidframework/telemetry-utils\";\nimport { AttachState } from \"@fluidframework/container-definitions\";\nimport { BlobCacheStorageService, buildSnapshotTree } from \"@fluidframework/driver-utils\";\nimport { assert, Lazy, LazyPromise } from \"@fluidframework/common-utils\";\nimport { v4 as uuid } from \"uuid\";\nimport { GCDataBuilder, unpackChildNodesUsedRoutes } from \"@fluidframework/garbage-collector\";\nimport { DataStoreContexts } from \"./dataStoreContexts\";\nimport { ContainerRuntime } from \"./containerRuntime\";\nimport {\n FluidDataStoreContext,\n RemotedFluidDataStoreContext,\n LocalFluidDataStoreContext,\n createAttributesBlob,\n LocalDetachedFluidDataStoreContext,\n} from \"./dataStoreContext\";\nimport { IContainerRuntimeMetadata, nonDataStorePaths, rootHasIsolatedChannels } from \"./summaryFormat\";\nimport { IUsedStateStats } from \"./garbageCollection\";\n\ntype PendingAliasResolve = (success: boolean) => void;\n\n/**\n * Interface for an op to be used for assigning an\n * alias to a datastore\n */\ninterface IDataStoreAliasMessage {\n /** The internal id of the datastore */\n readonly internalId: string;\n /** The alias name to be assigned to the datastore */\n readonly alias: string;\n}\n\n/**\n * Type guard that returns true if the given alias message is actually an instance of\n * a class which implements @see IDataStoreAliasMessage\n * @param maybeDataStoreAliasMessage - message object to be validated\n * @returns True if the @see IDataStoreAliasMessage is fully implemented, false otherwise\n */\nconst isDataStoreAliasMessage = (\n maybeDataStoreAliasMessage: any,\n): maybeDataStoreAliasMessage is IDataStoreAliasMessage => {\n return typeof maybeDataStoreAliasMessage?.internalId === \"string\"\n && typeof maybeDataStoreAliasMessage?.alias === \"string\";\n};\n\n /**\n * This class encapsulates data store handling. Currently it is only used by the container runtime,\n * but eventually could be hosted on any channel once we formalize the channel api boundary.\n */\nexport class DataStores implements IDisposable {\n // Stores tracked by the Domain\n private readonly pendingAttach = new Map<string, IAttachMessage>();\n // 0.24 back-compat attachingBeforeSummary\n public readonly attachOpFiredForDataStore = new Set<string>();\n\n private readonly logger: ITelemetryLogger;\n\n private readonly disposeOnce = new Lazy<void>(() => this.contexts.dispose());\n\n public readonly containerLoadStats: {\n // number of dataStores during loadContainer\n readonly containerLoadDataStoreCount: number;\n // number of unreferenced dataStores during loadContainer\n readonly referencedDataStoreCount: number;\n };\n\n constructor(\n private readonly baseSnapshot: ISnapshotTree | undefined,\n private readonly runtime: ContainerRuntime,\n private readonly submitAttachFn: (attachContent: any) => void,\n private readonly getCreateChildSummarizerNodeFn:\n (id: string, createParam: CreateChildSummarizerNodeParam) => CreateChildSummarizerNodeFn,\n private readonly deleteChildSummarizerNodeFn: (id: string) => void,\n baseLogger: ITelemetryBaseLogger,\n getDataStoreBaseGCDetails: () => Promise<Map<string, IGarbageCollectionSummaryDetails>>,\n private readonly dataStoreChanged: (id: string) => void,\n private readonly aliasMap: Map<string, string>,\n private readonly contexts: DataStoreContexts = new DataStoreContexts(baseLogger),\n ) {\n this.logger = ChildLogger.create(baseLogger);\n\n const baseDataStoresGCDetailsP = new LazyPromise(async () => {\n return getDataStoreBaseGCDetails();\n });\n // Returns the base summary GC details for the data store with the given id.\n const dataStoreBaseGCDetails = async (dataStoreId: string) => {\n const baseGCDetails = await baseDataStoresGCDetailsP;\n return baseGCDetails.get(dataStoreId);\n };\n\n // Extract stores stored inside the snapshot\n const fluidDataStores = new Map<string, ISnapshotTree>();\n if (baseSnapshot) {\n for (const [key, value] of Object.entries(baseSnapshot.trees)) {\n fluidDataStores.set(key, value);\n }\n }\n\n let unreferencedDataStoreCount = 0;\n // Create a context for each of them\n for (const [key, value] of fluidDataStores) {\n let dataStoreContext: FluidDataStoreContext;\n\n // counting number of unreferenced data stores\n if (value.unreferenced) {\n unreferencedDataStoreCount++;\n }\n // If we have a detached container, then create local data store contexts.\n if (this.runtime.attachState !== AttachState.Detached) {\n dataStoreContext = new RemotedFluidDataStoreContext(\n key,\n value,\n async () => dataStoreBaseGCDetails(key),\n this.runtime,\n this.runtime.storage,\n this.runtime.scope,\n this.getCreateChildSummarizerNodeFn(key, { type: CreateSummarizerNodeSource.FromSummary }));\n } else {\n if (typeof value !== \"object\") {\n throw new Error(\"Snapshot should be there to load from!!\");\n }\n const snapshotTree = value;\n dataStoreContext = new LocalFluidDataStoreContext(\n key,\n undefined,\n this.runtime,\n this.runtime.storage,\n this.runtime.scope,\n this.getCreateChildSummarizerNodeFn(key, { type: CreateSummarizerNodeSource.FromSummary }),\n (cr: IFluidDataStoreChannel) => this.bindFluidDataStore(cr),\n snapshotTree,\n undefined,\n );\n }\n this.contexts.addBoundOrRemoted(dataStoreContext);\n }\n this.containerLoadStats = {\n containerLoadDataStoreCount: fluidDataStores.size,\n referencedDataStoreCount: fluidDataStores.size - unreferencedDataStoreCount,\n };\n }\n\n public aliases(): ReadonlyMap<string, string> {\n return this.aliasMap;\n }\n\n public processAttachMessage(message: ISequencedDocumentMessage, local: boolean) {\n const attachMessage = message.contents as InboundAttachMessage;\n // The local object has already been attached\n if (local) {\n assert(this.pendingAttach.has(attachMessage.id),\n 0x15e /* \"Local object does not have matching attach message id\" */);\n this.contexts.get(attachMessage.id)?.emit(\"attached\");\n this.pendingAttach.delete(attachMessage.id);\n return;\n }\n\n // If a non-local operation then go and create the object, otherwise mark it as officially attached.\n if (this.contexts.has(attachMessage.id)) {\n // TODO: dataStoreId may require a different tag from PackageData #7488\n const error = new DataCorruptionError(\n \"duplicateDataStoreCreatedWithExistingId\",\n {\n ...extractSafePropertiesFromMessage(message),\n dataStoreId: {\n value: attachMessage.id,\n tag: TelemetryDataTag.PackageData,\n },\n },\n );\n throw error;\n }\n\n const flatBlobs = new Map<string, ArrayBufferLike>();\n let snapshotTree: ISnapshotTree | undefined;\n if (attachMessage.snapshot) {\n snapshotTree = buildSnapshotTree(attachMessage.snapshot.entries, flatBlobs);\n }\n\n // Include the type of attach message which is the pkg of the store to be\n // used by RemotedFluidDataStoreContext in case it is not in the snapshot.\n const pkg = [attachMessage.type];\n const remotedFluidDataStoreContext = new RemotedFluidDataStoreContext(\n attachMessage.id,\n snapshotTree,\n // New data stores begin with empty GC details since GC hasn't run on them yet.\n async () => { return {}; },\n this.runtime,\n new BlobCacheStorageService(this.runtime.storage, flatBlobs),\n this.runtime.scope,\n this.getCreateChildSummarizerNodeFn(\n attachMessage.id,\n {\n type: CreateSummarizerNodeSource.FromAttach,\n sequenceNumber: message.sequenceNumber,\n snapshot: attachMessage.snapshot ?? {\n entries: [createAttributesBlob(\n pkg,\n true /* isRootDataStore */,\n this.runtime.disableIsolatedChannels,\n )],\n },\n }),\n pkg);\n\n this.contexts.addBoundOrRemoted(remotedFluidDataStoreContext);\n\n // Equivalent of nextTick() - Prefetch once all current ops have completed\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n Promise.resolve().then(async () => remotedFluidDataStoreContext.realize());\n }\n\n public processAliasMessage(\n message: ISequencedDocumentMessage,\n localOpMetadata: unknown,\n local: boolean,\n ): void {\n const aliasMessage = message.contents as IDataStoreAliasMessage;\n if (!isDataStoreAliasMessage(aliasMessage)) {\n throw new DataCorruptionError(\n \"malformedDataStoreAliasMessage\",\n {\n ...extractSafePropertiesFromMessage(message),\n },\n );\n }\n\n const resolve = localOpMetadata as PendingAliasResolve;\n const aliasResult = this.processAliasMessageCore(aliasMessage);\n if (local) {\n resolve(aliasResult);\n }\n }\n\n private processAliasMessageCore(aliasMessage: IDataStoreAliasMessage): boolean {\n const existingMapping = this.aliasMap.get(aliasMessage.alias);\n if (existingMapping !== undefined) {\n return false;\n }\n\n // Unlikely scenario, but we may receive an alias OP with the alias value\n // equal to one of the ids supplied to `createRootDataStore` in the past\n const maybeContextWithAliasAsId = this.contexts.get(aliasMessage.alias);\n if (maybeContextWithAliasAsId !== undefined) {\n return false;\n }\n\n const currentContext = this.contexts.get(aliasMessage.internalId);\n if (currentContext === undefined) {\n this.logger.sendErrorEvent({\n eventName: \"AliasFluidDataStoreNotFound\",\n fluidDataStoreId: aliasMessage.internalId,\n });\n return false;\n }\n\n this.aliasMap.set(aliasMessage.alias, currentContext.id);\n currentContext.setRoot();\n return true;\n }\n\n public bindFluidDataStore(fluidDataStoreRuntime: IFluidDataStoreChannel): void {\n const id = fluidDataStoreRuntime.id;\n const localContext = this.contexts.getUnbound(id);\n assert(!!localContext, 0x15f /* \"Could not find unbound context to bind\" */);\n\n // If the container is detached, we don't need to send OP or add to pending attach because\n // we will summarize it while uploading the create new summary and make it known to other\n // clients.\n if (this.runtime.attachState !== AttachState.Detached) {\n localContext.emit(\"attaching\");\n const message = localContext.generateAttachMessage();\n\n this.pendingAttach.set(id, message);\n this.submitAttachFn(message);\n this.attachOpFiredForDataStore.add(id);\n }\n\n this.contexts.bind(fluidDataStoreRuntime.id);\n }\n\n public createDetachedDataStoreCore(\n pkg: Readonly<string[]>,\n isRoot: boolean,\n id = uuid()): IFluidDataStoreContextDetached\n {\n const context = new LocalDetachedFluidDataStoreContext(\n id,\n pkg,\n this.runtime,\n this.runtime.storage,\n this.runtime.scope,\n this.getCreateChildSummarizerNodeFn(id, { type: CreateSummarizerNodeSource.Local }),\n (cr: IFluidDataStoreChannel) => this.bindFluidDataStore(cr),\n isRoot,\n );\n this.contexts.addUnbound(context);\n return context;\n }\n\n public _createFluidDataStoreContext(pkg: string[], id: string, isRoot: boolean, props?: any) {\n const context = new LocalFluidDataStoreContext(\n id,\n pkg,\n this.runtime,\n this.runtime.storage,\n this.runtime.scope,\n this.getCreateChildSummarizerNodeFn(id, { type: CreateSummarizerNodeSource.Local }),\n (cr: IFluidDataStoreChannel) => this.bindFluidDataStore(cr),\n undefined,\n isRoot,\n props,\n );\n this.contexts.addUnbound(context);\n return context;\n }\n\n public get disposed() {return this.disposeOnce.evaluated;}\n public readonly dispose = () => this.disposeOnce.value;\n\n public resubmitDataStoreOp(content: any, localOpMetadata: unknown) {\n const envelope = content as IEnvelope;\n const context = this.contexts.get(envelope.address);\n assert(!!context, 0x160 /* \"There should be a store context for the op\" */);\n context.reSubmit(envelope.contents, localOpMetadata);\n }\n\n public async applyStashedOp(content: any): Promise<unknown> {\n const envelope = content as IEnvelope;\n const context = this.contexts.get(envelope.address);\n assert(!!context, 0x161 /* \"There should be a store context for the op\" */);\n return context.applyStashedOp(envelope.contents);\n }\n\n public async applyStashedAttachOp(message: IAttachMessage) {\n this.pendingAttach.set(message.id, message);\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n this.processAttachMessage({ contents: message } as ISequencedDocumentMessage, false);\n }\n\n public processFluidDataStoreOp(message: ISequencedDocumentMessage, local: boolean, localMessageMetadata: unknown) {\n const envelope = message.contents as IEnvelope;\n const transformed = { ...message, contents: envelope.contents };\n const context = this.contexts.get(envelope.address);\n assert(!!context, 0x162 /* \"There should be a store context for the op\" */);\n context.process(transformed, local, localMessageMetadata);\n\n // Notify that a data store changed. This is used to detect if a deleted data store is being used.\n this.dataStoreChanged(envelope.address);\n }\n\n public async getDataStore(id: string, wait: boolean): Promise<FluidDataStoreContext> {\n const internalId = this.aliasMap.get(id) ?? id;\n\n const context = await this.contexts.getBoundOrRemoted(internalId, wait);\n if (context === undefined) {\n // The requested data store does not exits. Throw a 404 response exception.\n const request = { url: id };\n throw responseToException(create404Response(request), request);\n }\n\n return context;\n }\n\n public processSignal(address: string, message: IInboundSignalMessage, local: boolean) {\n const context = this.contexts.get(address);\n if (!context) {\n // Attach message may not have been processed yet\n assert(!local, 0x163 /* \"Missing datastore for local signal\" */);\n this.logger.sendTelemetryEvent({\n eventName: \"SignalFluidDataStoreNotFound\",\n fluidDataStoreId: address,\n });\n return;\n }\n\n context.processSignal(message, local);\n }\n\n public setConnectionState(connected: boolean, clientId?: string) {\n for (const [fluidDataStore, context] of this.contexts) {\n try {\n context.setConnectionState(connected, clientId);\n } catch (error) {\n this.logger.sendErrorEvent({\n eventName: \"SetConnectionStateError\",\n clientId,\n fluidDataStore,\n }, error);\n }\n }\n }\n\n public setAttachState(attachState: AttachState.Attaching | AttachState.Attached): void {\n let eventName: \"attaching\" | \"attached\";\n if (attachState === AttachState.Attaching) {\n eventName = \"attaching\";\n } else {\n eventName = \"attached\";\n }\n for (const [,context] of this.contexts) {\n // Fire only for bounded stores.\n if (!this.contexts.isNotBound(context.id)) {\n context.emit(eventName);\n }\n }\n }\n\n public get size(): number {\n return this.contexts.size;\n }\n\n public async summarize(fullTree: boolean, trackState: boolean): Promise<ISummaryTreeWithStats> {\n const summaryBuilder = new SummaryTreeBuilder();\n\n // Iterate over each store and ask it to snapshot\n await Promise.all(Array.from(this.contexts)\n .filter(([_, context]) => {\n // Summarizer works only with clients with no local changes!\n assert(context.attachState !== AttachState.Attaching,\n 0x165 /* \"Summarizer cannot work if client has local changes\" */);\n return context.attachState === AttachState.Attached;\n }).map(async ([contextId, context]) => {\n const contextSummary = await context.summarize(fullTree, trackState);\n summaryBuilder.addWithStats(contextId, contextSummary);\n }));\n\n return summaryBuilder.getSummaryTree();\n }\n\n public createSummary(): ISummaryTreeWithStats {\n const builder = new SummaryTreeBuilder();\n // Attaching graph of some stores can cause other stores to get bound too.\n // So keep taking summary until no new stores get bound.\n let notBoundContextsLength: number;\n do {\n const builderTree = builder.summary.tree;\n notBoundContextsLength = this.contexts.notBoundLength();\n // Iterate over each data store and ask it to snapshot\n Array.from(this.contexts)\n .filter(([key, _]) =>\n // Take summary of bounded data stores only, make sure we haven't summarized them already\n // and no attach op has been fired for that data store because for loader versions <= 0.24\n // we set attach state as \"attaching\" before taking createNew summary.\n !(this.contexts.isNotBound(key)\n || builderTree[key]\n || this.attachOpFiredForDataStore.has(key)),\n )\n .map(([key, value]) => {\n let dataStoreSummary: ISummarizeResult;\n if (value.isLoaded) {\n const snapshot = value.generateAttachMessage().snapshot;\n dataStoreSummary = convertToSummaryTree(snapshot, true);\n } else {\n // If this data store is not yet loaded, then there should be no changes in the snapshot from\n // which it was created as it is detached container. So just use the previous snapshot.\n assert(!!this.baseSnapshot,\n 0x166 /* \"BaseSnapshot should be there as detached container loaded from snapshot\" */);\n dataStoreSummary = convertSnapshotTreeToSummaryTree(this.baseSnapshot.trees[key]);\n }\n builder.addWithStats(key, dataStoreSummary);\n });\n } while (notBoundContextsLength !== this.contexts.notBoundLength());\n\n return builder.getSummaryTree();\n }\n\n /**\n * Generates data used for garbage collection. It does the following:\n * 1. Calls into each child data store context to get its GC data.\n * 2. Prefixes the child context's id to the GC nodes in the child's GC data. This makes sure that the node can be\n * identified as belonging to the child.\n * 3. Adds a GC node for this channel to the nodes received from the children. All these nodes together represent\n * the GC data of this channel.\n * @param fullGC - true to bypass optimizations and force full generation of GC data.\n */\n public async getGCData(fullGC: boolean = false): Promise<IGarbageCollectionData> {\n const builder = new GCDataBuilder();\n // Iterate over each store and get their GC data.\n await Promise.all(Array.from(this.contexts)\n .filter(([_, context]) => {\n // Get GC data only for attached contexts. Detached contexts are not connected in the GC reference\n // graph so any references they might have won't be connected as well.\n return context.attachState === AttachState.Attached;\n }).map(async ([contextId, context]) => {\n const contextGCData = await context.getGCData(fullGC);\n // Prefix the child's id to the ids of its GC nodes so they can be identified as belonging to the child.\n // This also gradually builds the id of each node to be a path from the root.\n builder.prefixAndAddNodes(contextId, contextGCData.gcNodes);\n }));\n\n // Get the outbound routes and add a GC node for this channel.\n builder.addNode(\"/\", await this.getOutboundRoutes());\n return builder.getGCData();\n }\n\n /**\n * After GC has run, called to notify this Container's data stores of routes that are used in it.\n * @param usedRoutes - The routes that are used in all data stores in this Container.\n * @param gcTimestamp - The time when GC was run that generated these used routes. If any node node becomes\n * unreferenced as part of this GC run, this should be used to update the time when it happens.\n * @returns the statistics of the used state of the data stores.\n */\n public updateUsedRoutes(usedRoutes: string[], gcTimestamp?: number): IUsedStateStats {\n // Get a map of data store ids to routes used in it.\n const usedDataStoreRoutes = unpackChildNodesUsedRoutes(usedRoutes);\n\n // Verify that the used routes are correct.\n for (const [id] of usedDataStoreRoutes) {\n assert(this.contexts.has(id), 0x167 /* \"Used route does not belong to any known data store\" */);\n }\n\n // Update the used routes in each data store. Used routes is empty for unused data stores.\n for (const [contextId, context] of this.contexts) {\n context.updateUsedRoutes(usedDataStoreRoutes.get(contextId) ?? [], gcTimestamp);\n }\n\n // Return the number of data stores that are unused.\n const dataStoreCount = this.contexts.size;\n return {\n totalNodeCount: dataStoreCount,\n unusedNodeCount: dataStoreCount - usedDataStoreRoutes.size,\n };\n }\n\n /**\n * When running GC in test mode, this is called to delete objects whose routes are unused. This enables testing\n * scenarios with accessing deleted content.\n * @param unusedRoutes - The routes that are unused in all data stores in this Container.\n */\n public deleteUnusedRoutes(unusedRoutes: string[]) {\n for (const route of unusedRoutes) {\n const dataStoreId = route.split(\"/\")[1];\n // Delete the contexts of unused data stores.\n this.contexts.delete(dataStoreId);\n // Delete the summarizer node of the unused data stores.\n this.deleteChildSummarizerNodeFn(dataStoreId);\n }\n }\n\n /**\n * Returns the outbound routes of this channel. Only root data stores are considered referenced and their paths are\n * part of outbound routes.\n */\n private async getOutboundRoutes(): Promise<string[]> {\n const outboundRoutes: string[] = [];\n for (const [contextId, context] of this.contexts) {\n const isRootDataStore = await context.isRoot();\n if (isRootDataStore) {\n outboundRoutes.push(`/${contextId}`);\n }\n }\n return outboundRoutes;\n }\n}\n\nexport function getSummaryForDatastores(\n snapshot: ISnapshotTree | undefined,\n metadata?: IContainerRuntimeMetadata,\n): ISnapshotTree | undefined {\n if (!snapshot) {\n return undefined;\n }\n\n if (rootHasIsolatedChannels(metadata)) {\n const datastoresSnapshot = snapshot.trees[channelsTreeName];\n assert(!!datastoresSnapshot, 0x168 /* `expected ${channelsTreeName} tree in snapshot` */);\n return datastoresSnapshot;\n } else {\n // back-compat: strip out all non-datastore paths before giving to DataStores object.\n const datastoresTrees: ISnapshotTree[\"trees\"] = {};\n for (const [key, value] of Object.entries(snapshot.trees)) {\n if (!nonDataStorePaths.includes(key)) {\n datastoresTrees[key] = value;\n }\n }\n return {\n ...snapshot,\n trees: datastoresTrees,\n };\n }\n}\n"]}
1
+ {"version":3,"file":"dataStores.js","sourceRoot":"","sources":["../src/dataStores.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAGH,qEAAwG;AAExG,yDAA8D;AAK9D,6EAe6C;AAC7C,iEAMuC;AACvC,qEAAgF;AAChF,iFAAoE;AACpE,+DAA0F;AAC1F,+DAAyE;AACzE,+BAAkC;AAClC,yEAA8F;AAC9F,2DAAwD;AAExD,yDAM4B;AAC5B,mDAAwG;AAgBxG;;;;;GAKG;AACH,MAAM,uBAAuB,GAAG,CAC5B,0BAA+B,EACqB,EAAE;IACtD,OAAO,QAAO,0BAA0B,aAA1B,0BAA0B,uBAA1B,0BAA0B,CAAE,UAAU,CAAA,KAAK,QAAQ;WAC1D,QAAO,0BAA0B,aAA1B,0BAA0B,uBAA1B,0BAA0B,CAAE,KAAK,CAAA,KAAK,QAAQ,CAAC;AACjE,CAAC,CAAC;AAED;;;GAGG;AACJ,MAAa,UAAU;IAwBnB,YACqB,YAAuC,EACvC,OAAyB,EACzB,cAA4C,EAC5C,8BAC4E,EAC5E,2BAAiD,EAClE,UAAgC,EAChC,gBAA2E,EAC1D,gBAAsC,EACtC,QAA6B,EAC7B,WAA8B,IAAI,qCAAiB,CAAC,UAAU,CAAC;QAV/D,iBAAY,GAAZ,YAAY,CAA2B;QACvC,YAAO,GAAP,OAAO,CAAkB;QACzB,mBAAc,GAAd,cAAc,CAA8B;QAC5C,mCAA8B,GAA9B,8BAA8B,CAC8C;QAC5E,gCAA2B,GAA3B,2BAA2B,CAAsB;QAGjD,qBAAgB,GAAhB,gBAAgB,CAAsB;QACtC,aAAQ,GAAR,QAAQ,CAAqB;QAC7B,aAAQ,GAAR,QAAQ,CAAuD;QAlCpF,+BAA+B;QACd,kBAAa,GAAG,IAAI,GAAG,EAA0B,CAAC;QACnE,0CAA0C;QAC1B,8BAAyB,GAAG,IAAI,GAAG,EAAU,CAAC;QAI7C,gBAAW,GAAG,IAAI,mBAAI,CAAO,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;QAS7E,6GAA6G;QAC7G,mCAAmC;QAC3B,0BAAqB,GAAa,EAAE,CAAC;QA6P7B,YAAO,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;QA3OnD,IAAI,CAAC,MAAM,GAAG,6BAAW,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC7C,IAAI,CAAC,sBAAsB,GAAG,IAAI,6BAAiB,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;QAEzG,MAAM,cAAc,GAAG,IAAI,0BAAW,CAAC,KAAK,IAAI,EAAE;YAC9C,OAAO,gBAAgB,EAAE,CAAC;QAC9B,CAAC,CAAC,CAAC;QACH,oEAAoE;QACpE,MAAM,sBAAsB,GAAG,KAAK,EAAE,WAAmB,EAAE,EAAE;YACzD,MAAM,aAAa,GAAG,MAAM,cAAc,CAAC;YAC3C,OAAO,aAAa,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAC1C,CAAC,CAAC;QAEF,4CAA4C;QAC5C,MAAM,eAAe,GAAG,IAAI,GAAG,EAAyB,CAAC;QACzD,IAAI,YAAY,EAAE;YACd,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE;gBAC3D,eAAe,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;aACnC;SACJ;QAED,IAAI,0BAA0B,GAAG,CAAC,CAAC;QACnC,oCAAoC;QACpC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,eAAe,EAAE;YACxC,IAAI,gBAAuC,CAAC;YAE5C,8CAA8C;YAC9C,IAAI,KAAK,CAAC,YAAY,EAAE;gBACpB,0BAA0B,EAAE,CAAC;aAChC;YACD,0EAA0E;YAC1E,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,KAAK,mCAAW,CAAC,QAAQ,EAAE;gBACnD,gBAAgB,GAAG,IAAI,+CAA4B,CAC/C,GAAG,EACH,KAAK,EACL,KAAK,IAAI,EAAE,CAAC,sBAAsB,CAAC,GAAG,CAAC,EACvC,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,OAAO,CAAC,OAAO,EACpB,IAAI,CAAC,OAAO,CAAC,KAAK,EAClB,IAAI,CAAC,8BAA8B,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,gDAA0B,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;aACnG;iBAAM;gBACH,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;oBAC3B,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;iBAC9D;gBACD,MAAM,YAAY,GAAG,KAAK,CAAC;gBAC3B,gBAAgB,GAAG,IAAI,6CAA0B,CAC7C,GAAG,EACH,SAAS,EACT,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,OAAO,CAAC,OAAO,EACpB,IAAI,CAAC,OAAO,CAAC,KAAK,EAClB,IAAI,CAAC,8BAA8B,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,gDAA0B,CAAC,WAAW,EAAE,CAAC,EAC1F,CAAC,EAA0B,EAAE,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,EAAE,CAAC,EAC3D,YAAY,EACZ,SAAS,CACZ,CAAC;aACL;YACD,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,CAAC;SACrD;QACD,IAAI,CAAC,kBAAkB,GAAG;YACtB,2BAA2B,EAAE,eAAe,CAAC,IAAI;YACjD,wBAAwB,EAAE,eAAe,CAAC,IAAI,GAAG,0BAA0B;SAC9E,CAAC;IACN,CAAC;IAEM,OAAO;QACV,OAAO,IAAI,CAAC,QAAQ,CAAC;IACzB,CAAC;IAEM,oBAAoB,CAAC,OAAkC,EAAE,KAAc;;QAC1E,MAAM,aAAa,GAAG,OAAO,CAAC,QAAgC,CAAC;QAE/D,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;QAElD,6CAA6C;QAC7C,IAAI,KAAK,EAAE;YACP,qBAAM,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC,EAC3C,KAAK,CAAC,6DAA6D,CAAC,CAAC;YACzE,MAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC,0CAAE,IAAI,CAAC,UAAU,EAAE;YACtD,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;YAC5C,OAAO;SACV;QAEA,oGAAoG;QACrG,IAAI,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,EAAE,CAAC,EAAE;YACzC,uEAAuE;YACvE,MAAM,KAAK,GAAG,IAAI,qCAAmB,CACjC,yCAAyC,kCAElC,kDAAgC,CAAC,OAAO,CAAC,KAC5C,WAAW,EAAE;oBACT,KAAK,EAAE,aAAa,CAAC,EAAE;oBACvB,GAAG,EAAE,kCAAgB,CAAC,WAAW;iBACpC,IAER,CAAC;YACF,MAAM,KAAK,CAAC;SACf;QAED,MAAM,SAAS,GAAG,IAAI,GAAG,EAA2B,CAAC;QACrD,IAAI,YAAuC,CAAC;QAC5C,IAAI,aAAa,CAAC,QAAQ,EAAE;YACxB,YAAY,GAAG,gCAAiB,CAAC,aAAa,CAAC,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;SAC/E;QAED,yEAAyE;QACzE,0EAA0E;QAC1E,MAAM,GAAG,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QACjC,MAAM,4BAA4B,GAAG,IAAI,+CAA4B,CACjE,aAAa,CAAC,EAAE,EAChB,YAAY;QACZ,+EAA+E;QAC/E,KAAK,IAAI,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC,CAAC,EAC1B,IAAI,CAAC,OAAO,EACZ,IAAI,sCAAuB,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,SAAS,CAAC,EAC5D,IAAI,CAAC,OAAO,CAAC,KAAK,EAClB,IAAI,CAAC,8BAA8B,CAC/B,aAAa,CAAC,EAAE,EAChB;YACI,IAAI,EAAE,gDAA0B,CAAC,UAAU;YAC3C,cAAc,EAAE,OAAO,CAAC,cAAc;YACtC,QAAQ,QAAE,aAAa,CAAC,QAAQ,mCAAI;gBAChC,OAAO,EAAE,CAAC,uCAAoB,CAC1B,GAAG,EACH,IAAI,CAAC,qBAAqB,EAC1B,IAAI,CAAC,OAAO,CAAC,uBAAuB,CACvC,CAAC;aACL;SACJ,CAAC,EACN,GAAG,CAAC,CAAC;QAET,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,4BAA4B,CAAC,CAAC;IAClE,CAAC;IAEM,mBAAmB,CACtB,OAAkC,EAClC,eAAwB,EACxB,KAAc;QAEd,MAAM,YAAY,GAAG,OAAO,CAAC,QAAkC,CAAC;QAChE,IAAI,CAAC,uBAAuB,CAAC,YAAY,CAAC,EAAE;YACxC,MAAM,IAAI,qCAAmB,CACzB,gCAAgC,oBAEzB,kDAAgC,CAAC,OAAO,CAAC,EAEnD,CAAC;SACL;QAED,MAAM,OAAO,GAAG,eAAsC,CAAC;QACvD,MAAM,WAAW,GAAG,IAAI,CAAC,uBAAuB,CAAC,YAAY,CAAC,CAAC;QAC/D,IAAI,KAAK,EAAE;YACP,OAAO,CAAC,WAAW,CAAC,CAAC;SACxB;IACL,CAAC;IAEO,uBAAuB,CAAC,YAAoC;QAChE,IAAI,IAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE;YAC3C,OAAO,KAAK,CAAC;SAChB;QAED,MAAM,cAAc,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;QAClE,IAAI,cAAc,KAAK,SAAS,EAAE;YAC9B,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC;gBACvB,SAAS,EAAE,6BAA6B;gBACxC,gBAAgB,EAAE,YAAY,CAAC,UAAU;aAC5C,CAAC,CAAC;YACH,OAAO,KAAK,CAAC;SAChB;QAED,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,EAAE,cAAc,CAAC,EAAE,CAAC,CAAC;QACzD,cAAc,CAAC,OAAO,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IAChB,CAAC;IAEO,gBAAgB,CAAC,EAAU;QAC/B,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,SAAS,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,SAAS,CAAC;IACtF,CAAC;IAEM,kBAAkB,CAAC,qBAA6C;QACnE,MAAM,EAAE,GAAG,qBAAqB,CAAC,EAAE,CAAC;QACpC,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QAClD,qBAAM,CAAC,CAAC,CAAC,YAAY,EAAE,KAAK,CAAC,8CAA8C,CAAC,CAAC;QAE7E,0FAA0F;QAC1F,yFAAyF;QACzF,WAAW;QACX,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,KAAK,mCAAW,CAAC,QAAQ,EAAE;YACnD,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC/B,MAAM,OAAO,GAAG,YAAY,CAAC,qBAAqB,EAAE,CAAC;YAErD,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YACpC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;YAC7B,IAAI,CAAC,yBAAyB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;SAC1C;QAED,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,qBAAqB,CAAC,EAAE,CAAC,CAAC;IACjD,CAAC;IAEM,2BAA2B,CAC9B,GAAuB,EACvB,MAAe,EACf,EAAE,GAAG,SAAI,EAAE;QAEX,MAAM,OAAO,GAAG,IAAI,qDAAkC,CAClD,EAAE,EACF,GAAG,EACH,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,OAAO,CAAC,OAAO,EACpB,IAAI,CAAC,OAAO,CAAC,KAAK,EAClB,IAAI,CAAC,8BAA8B,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,gDAA0B,CAAC,KAAK,EAAE,CAAC,EACnF,CAAC,EAA0B,EAAE,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,EAAE,CAAC,EAC3D,MAAM,CACT,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAClC,OAAO,OAAO,CAAC;IACnB,CAAC;IAEM,4BAA4B,CAAC,GAAa,EAAE,EAAU,EAAE,MAAe,EAAE,KAAW;QACvF,MAAM,OAAO,GAAG,IAAI,6CAA0B,CAC1C,EAAE,EACF,GAAG,EACH,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,OAAO,CAAC,OAAO,EACpB,IAAI,CAAC,OAAO,CAAC,KAAK,EAClB,IAAI,CAAC,8BAA8B,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,gDAA0B,CAAC,KAAK,EAAE,CAAC,EACnF,CAAC,EAA0B,EAAE,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,EAAE,CAAC,EAC3D,SAAS,EACT,MAAM,EACN,KAAK,CACR,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAClC,OAAO,OAAO,CAAC;IACnB,CAAC;IAED,IAAW,QAAQ,KAAI,OAAO,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAA,CAAC;IAGnD,mBAAmB,CAAC,OAAY,EAAE,eAAwB;QAC7D,MAAM,QAAQ,GAAG,OAAoB,CAAC;QACtC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACpD,qBAAM,CAAC,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC,kDAAkD,CAAC,CAAC;QAC5E,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;IACzD,CAAC;IAEM,KAAK,CAAC,cAAc,CAAC,OAAY;QACpC,MAAM,QAAQ,GAAG,OAAoB,CAAC;QACtC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACpD,qBAAM,CAAC,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC,kDAAkD,CAAC,CAAC;QAC5E,OAAO,OAAO,CAAC,cAAc,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACrD,CAAC;IAEM,KAAK,CAAC,oBAAoB,CAAC,OAAuB;QACrD,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAC5C,yEAAyE;QACzE,IAAI,CAAC,oBAAoB,CAAC,EAAE,QAAQ,EAAE,OAAO,EAA+B,EAAE,KAAK,CAAC,CAAC;IACzF,CAAC;IAEM,uBAAuB,CAAC,OAAkC,EAAE,KAAc,EAAE,oBAA6B;QAC5G,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAqB,CAAC;QAC/C,MAAM,WAAW,mCAAQ,OAAO,KAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,GAAE,CAAC;QAChE,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACpD,qBAAM,CAAC,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC,kDAAkD,CAAC,CAAC;QAC5E,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,EAAE,oBAAoB,CAAC,CAAC;QAE1D,kGAAkG;QAClG,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC;IAEM,KAAK,CAAC,YAAY,CAAC,EAAU,EAAE,IAAa;;QAC/C,MAAM,UAAU,SAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,mCAAI,EAAE,CAAC;QAE/C,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QACxE,IAAI,OAAO,KAAK,SAAS,EAAE;YACvB,2EAA2E;YAC3E,MAAM,OAAO,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC;YAC5B,MAAM,mCAAmB,CAAC,iCAAiB,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC;SAClE;QAED,OAAO,OAAO,CAAC;IACnB,CAAC;IAEM,aAAa,CAAC,OAAe,EAAE,OAA8B,EAAE,KAAc;QAChF,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC3C,IAAI,CAAC,OAAO,EAAE;YACV,iDAAiD;YACjD,qBAAM,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,0CAA0C,CAAC,CAAC;YACjE,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC;gBAC3B,SAAS,EAAE,8BAA8B;gBACzC,gBAAgB,EAAE,OAAO;aAC5B,CAAC,CAAC;YACH,OAAO;SACV;QAED,OAAO,CAAC,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC1C,CAAC;IAEM,kBAAkB,CAAC,SAAkB,EAAE,QAAiB;QAC3D,KAAK,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE;YACnD,IAAI;gBACA,OAAO,CAAC,kBAAkB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;aACnD;YAAC,OAAO,KAAK,EAAE;gBACZ,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC;oBACvB,SAAS,EAAE,yBAAyB;oBACpC,QAAQ;oBACR,cAAc;iBACjB,EAAE,KAAK,CAAC,CAAC;aACb;SACJ;IACL,CAAC;IAEM,cAAc,CAAC,WAAyD;QAC3E,IAAI,SAAmC,CAAC;QACxC,IAAI,WAAW,KAAK,mCAAW,CAAC,SAAS,EAAE;YACvC,SAAS,GAAG,WAAW,CAAC;SAC3B;aAAM;YACH,SAAS,GAAG,UAAU,CAAC;SAC1B;QACD,KAAK,MAAM,CAAC,EAAC,OAAO,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE;YACpC,gCAAgC;YAChC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE;gBACvC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;aAC3B;SACJ;IACL,CAAC;IAED,IAAW,IAAI;QACX,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;IAC9B,CAAC;IAEM,KAAK,CAAC,SAAS,CAAC,QAAiB,EAAE,UAAmB;QACzD,MAAM,cAAc,GAAG,IAAI,kCAAkB,EAAE,CAAC;QAEhD,iDAAiD;QACjD,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;aACtC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,EAAE;YACrB,4DAA4D;YAC5D,qBAAM,CAAC,OAAO,CAAC,WAAW,KAAK,mCAAW,CAAC,SAAS,EAChD,KAAK,CAAC,0DAA0D,CAAC,CAAC;YACtE,OAAO,OAAO,CAAC,WAAW,KAAK,mCAAW,CAAC,QAAQ,CAAC;QACxD,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE;YAClC,MAAM,cAAc,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;YACrE,cAAc,CAAC,YAAY,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;QAC3D,CAAC,CAAC,CAAC,CAAC;QAER,OAAO,cAAc,CAAC,cAAc,EAAE,CAAC;IAC3C,CAAC;IAEM,aAAa;QAChB,MAAM,OAAO,GAAG,IAAI,kCAAkB,EAAE,CAAC;QACzC,0EAA0E;QAC1E,wDAAwD;QACxD,IAAI,sBAA8B,CAAC;QACnC,GAAG;YACC,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;YACzC,sBAAsB,GAAG,IAAI,CAAC,QAAQ,CAAC,cAAc,EAAE,CAAC;YACxD,sDAAsD;YACtD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;iBACpB,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE;YACjB,yFAAyF;YACzF,0FAA0F;YAC1F,sEAAsE;YACtE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC;mBACxB,WAAW,CAAC,GAAG,CAAC;mBAChB,IAAI,CAAC,yBAAyB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAClD;iBACA,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;gBAClB,IAAI,gBAAkC,CAAC;gBACvC,IAAI,KAAK,CAAC,QAAQ,EAAE;oBAChB,MAAM,QAAQ,GAAG,KAAK,CAAC,qBAAqB,EAAE,CAAC,QAAQ,CAAC;oBACxD,gBAAgB,GAAG,oCAAoB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;iBAC3D;qBAAM;oBACH,6FAA6F;oBAC7F,uFAAuF;oBACvF,qBAAM,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,EACtB,KAAK,CAAC,+EAA+E,CAAC,CAAC;oBAC3F,gBAAgB,GAAG,gDAAgC,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;iBACrF;gBACD,OAAO,CAAC,YAAY,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;YAChD,CAAC,CAAC,CAAC;SACV,QAAQ,sBAAsB,KAAK,IAAI,CAAC,QAAQ,CAAC,cAAc,EAAE,EAAE;QAEpE,OAAO,OAAO,CAAC,cAAc,EAAE,CAAC;IACpC,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,mBAAmB;QAC5B,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,qBAAqB,EAAE;YACzC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACtC,qBAAM,CAAC,OAAO,KAAK,SAAS,EAAE,KAAK,CAAC,gDAAgD,CAAC,CAAC;YACtF,IAAI,MAAM,OAAO,CAAC,MAAM,EAAE,EAAE;gBACxB,2FAA2F;gBAC3F,MAAM,MAAM,GAAG,IAAI,6BAAiB,CAAC,OAAO,EAAE,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;gBACpF,IAAI,CAAC,OAAO,CAAC,wBAAwB,CAAC,IAAI,CAAC,sBAAsB,EAAE,MAAM,CAAC,CAAC;aAC9E;SACJ;QACD,IAAI,CAAC,qBAAqB,GAAG,EAAE,CAAC;IACpC,CAAC;IAED;;;;;;;;OAQG;IACI,KAAK,CAAC,SAAS,CAAC,SAAkB,KAAK;QAC1C,MAAM,OAAO,GAAG,IAAI,iCAAa,EAAE,CAAC;QACpC,iDAAiD;QACjD,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;aACtC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,EAAE;YACrB,kGAAkG;YAClG,sEAAsE;YACtE,OAAO,OAAO,CAAC,WAAW,KAAK,mCAAW,CAAC,QAAQ,CAAC;QACxD,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE;YAClC,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YACtD,wGAAwG;YACxG,6EAA6E;YAC7E,OAAO,CAAC,iBAAiB,CAAC,SAAS,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;QAChE,CAAC,CAAC,CAAC,CAAC;QAER,8DAA8D;QAC9D,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,IAAI,CAAC,iBAAiB,EAAE,CAAC,CAAC;QACrD,OAAO,OAAO,CAAC,SAAS,EAAE,CAAC;IAC/B,CAAC;IAED;;;;;;OAMG;IACI,gBAAgB,CAAC,UAAoB,EAAE,WAAoB;;QAC9D,oDAAoD;QACpD,MAAM,mBAAmB,GAAG,8CAA0B,CAAC,UAAU,CAAC,CAAC;QAEnE,2CAA2C;QAC3C,KAAK,MAAM,CAAC,EAAE,CAAC,IAAI,mBAAmB,EAAE;YACpC,qBAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,0DAA0D,CAAC,CAAC;SACnG;QAED,0FAA0F;QAC1F,KAAK,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE;YAC9C,OAAO,CAAC,gBAAgB,OAAC,mBAAmB,CAAC,GAAG,CAAC,SAAS,CAAC,mCAAI,EAAE,EAAE,WAAW,CAAC,CAAC;SACnF;QAED,oDAAoD;QACpD,MAAM,cAAc,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;QAC1C,OAAO;YACH,cAAc,EAAE,cAAc;YAC9B,eAAe,EAAE,cAAc,GAAG,mBAAmB,CAAC,IAAI;SAC7D,CAAC;IACN,CAAC;IAED;;;;OAIG;IACI,kBAAkB,CAAC,YAAsB;QAC5C,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE;YAC9B,MAAM,WAAW,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACxC,6CAA6C;YAC7C,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YAClC,wDAAwD;YACxD,IAAI,CAAC,2BAA2B,CAAC,WAAW,CAAC,CAAC;SACjD;IACL,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,iBAAiB;QAC3B,MAAM,cAAc,GAAa,EAAE,CAAC;QACpC,KAAK,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE;YAC9C,MAAM,eAAe,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC;YAC/C,IAAI,eAAe,EAAE;gBACjB,cAAc,CAAC,IAAI,CAAC,IAAI,SAAS,EAAE,CAAC,CAAC;aACxC;SACJ;QACD,OAAO,cAAc,CAAC;IAC1B,CAAC;CACJ;AA9gBD,gCA8gBC;AAED,SAAgB,uBAAuB,CACnC,QAAmC,EACnC,QAAoC;IAEpC,IAAI,CAAC,QAAQ,EAAE;QACX,OAAO,SAAS,CAAC;KACpB;IAED,IAAI,uCAAuB,CAAC,QAAQ,CAAC,EAAE;QACnC,MAAM,kBAAkB,GAAG,QAAQ,CAAC,KAAK,CAAC,sCAAgB,CAAC,CAAC;QAC5D,qBAAM,CAAC,CAAC,CAAC,kBAAkB,EAAE,KAAK,CAAC,qDAAqD,CAAC,CAAC;QAC1F,OAAO,kBAAkB,CAAC;KAC7B;SAAM;QACH,qFAAqF;QACrF,MAAM,eAAe,GAA2B,EAAE,CAAC;QACnD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;YACvD,IAAI,CAAC,iCAAiB,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;gBAClC,eAAe,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;aAChC;SACJ;QACD,uCACO,QAAQ,KACX,KAAK,EAAE,eAAe,IACxB;KACL;AACL,CAAC;AAzBD,0DAyBC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger, ITelemetryBaseLogger, IDisposable } from \"@fluidframework/common-definitions\";\nimport { DataCorruptionError, extractSafePropertiesFromMessage } from \"@fluidframework/container-utils\";\nimport { IFluidHandle } from \"@fluidframework/core-interfaces\";\nimport { FluidObjectHandle } from \"@fluidframework/datastore\";\nimport {\n ISequencedDocumentMessage,\n ISnapshotTree,\n} from \"@fluidframework/protocol-definitions\";\nimport {\n channelsTreeName,\n CreateChildSummarizerNodeFn,\n CreateChildSummarizerNodeParam,\n CreateSummarizerNodeSource,\n IAttachMessage,\n IEnvelope,\n IFluidDataStoreChannel,\n IFluidDataStoreContextDetached,\n IGarbageCollectionData,\n IGarbageCollectionDetailsBase,\n IInboundSignalMessage,\n InboundAttachMessage,\n ISummarizeResult,\n ISummaryTreeWithStats,\n} from \"@fluidframework/runtime-definitions\";\nimport {\n convertSnapshotTreeToSummaryTree,\n convertToSummaryTree,\n create404Response,\n responseToException,\n SummaryTreeBuilder,\n} from \"@fluidframework/runtime-utils\";\nimport { ChildLogger, TelemetryDataTag } from \"@fluidframework/telemetry-utils\";\nimport { AttachState } from \"@fluidframework/container-definitions\";\nimport { BlobCacheStorageService, buildSnapshotTree } from \"@fluidframework/driver-utils\";\nimport { assert, Lazy, LazyPromise } from \"@fluidframework/common-utils\";\nimport { v4 as uuid } from \"uuid\";\nimport { GCDataBuilder, unpackChildNodesUsedRoutes } from \"@fluidframework/garbage-collector\";\nimport { DataStoreContexts } from \"./dataStoreContexts\";\nimport { ContainerRuntime } from \"./containerRuntime\";\nimport {\n FluidDataStoreContext,\n RemotedFluidDataStoreContext,\n LocalFluidDataStoreContext,\n createAttributesBlob,\n LocalDetachedFluidDataStoreContext,\n} from \"./dataStoreContext\";\nimport { IContainerRuntimeMetadata, nonDataStorePaths, rootHasIsolatedChannels } from \"./summaryFormat\";\nimport { IUsedStateStats } from \"./garbageCollection\";\n\ntype PendingAliasResolve = (success: boolean) => void;\n\n/**\n * Interface for an op to be used for assigning an\n * alias to a datastore\n */\ninterface IDataStoreAliasMessage {\n /** The internal id of the datastore */\n readonly internalId: string;\n /** The alias name to be assigned to the datastore */\n readonly alias: string;\n}\n\n/**\n * Type guard that returns true if the given alias message is actually an instance of\n * a class which implements @see IDataStoreAliasMessage\n * @param maybeDataStoreAliasMessage - message object to be validated\n * @returns True if the @see IDataStoreAliasMessage is fully implemented, false otherwise\n */\nconst isDataStoreAliasMessage = (\n maybeDataStoreAliasMessage: any,\n): maybeDataStoreAliasMessage is IDataStoreAliasMessage => {\n return typeof maybeDataStoreAliasMessage?.internalId === \"string\"\n && typeof maybeDataStoreAliasMessage?.alias === \"string\";\n};\n\n /**\n * This class encapsulates data store handling. Currently it is only used by the container runtime,\n * but eventually could be hosted on any channel once we formalize the channel api boundary.\n */\nexport class DataStores implements IDisposable {\n // Stores tracked by the Domain\n private readonly pendingAttach = new Map<string, IAttachMessage>();\n // 0.24 back-compat attachingBeforeSummary\n public readonly attachOpFiredForDataStore = new Set<string>();\n\n private readonly logger: ITelemetryLogger;\n\n private readonly disposeOnce = new Lazy<void>(() => this.contexts.dispose());\n\n public readonly containerLoadStats: {\n // number of dataStores during loadContainer\n readonly containerLoadDataStoreCount: number;\n // number of unreferenced dataStores during loadContainer\n readonly referencedDataStoreCount: number;\n };\n\n // Stores the ids of new data stores between two GC runs. This is used to notify the garbage collector of new\n // root data stores that are added.\n private dataStoresSinceLastGC: string[] = [];\n // The handle to the container runtime. This is used mainly for GC purposes to represent outbound reference from\n // the container runtime to other nodes.\n private readonly containerRuntimeHandle: IFluidHandle;\n\n constructor(\n private readonly baseSnapshot: ISnapshotTree | undefined,\n private readonly runtime: ContainerRuntime,\n private readonly submitAttachFn: (attachContent: any) => void,\n private readonly getCreateChildSummarizerNodeFn:\n (id: string, createParam: CreateChildSummarizerNodeParam) => CreateChildSummarizerNodeFn,\n private readonly deleteChildSummarizerNodeFn: (id: string) => void,\n baseLogger: ITelemetryBaseLogger,\n getBaseGCDetails: () => Promise<Map<string, IGarbageCollectionDetailsBase>>,\n private readonly dataStoreChanged: (id: string) => void,\n private readonly aliasMap: Map<string, string>,\n private readonly contexts: DataStoreContexts = new DataStoreContexts(baseLogger),\n ) {\n this.logger = ChildLogger.create(baseLogger);\n this.containerRuntimeHandle = new FluidObjectHandle(this.runtime, \"/\", this.runtime.IFluidHandleContext);\n\n const baseGCDetailsP = new LazyPromise(async () => {\n return getBaseGCDetails();\n });\n // Returns the base GC details for the data store with the given id.\n const dataStoreBaseGCDetails = async (dataStoreId: string) => {\n const baseGCDetails = await baseGCDetailsP;\n return baseGCDetails.get(dataStoreId);\n };\n\n // Extract stores stored inside the snapshot\n const fluidDataStores = new Map<string, ISnapshotTree>();\n if (baseSnapshot) {\n for (const [key, value] of Object.entries(baseSnapshot.trees)) {\n fluidDataStores.set(key, value);\n }\n }\n\n let unreferencedDataStoreCount = 0;\n // Create a context for each of them\n for (const [key, value] of fluidDataStores) {\n let dataStoreContext: FluidDataStoreContext;\n\n // counting number of unreferenced data stores\n if (value.unreferenced) {\n unreferencedDataStoreCount++;\n }\n // If we have a detached container, then create local data store contexts.\n if (this.runtime.attachState !== AttachState.Detached) {\n dataStoreContext = new RemotedFluidDataStoreContext(\n key,\n value,\n async () => dataStoreBaseGCDetails(key),\n this.runtime,\n this.runtime.storage,\n this.runtime.scope,\n this.getCreateChildSummarizerNodeFn(key, { type: CreateSummarizerNodeSource.FromSummary }));\n } else {\n if (typeof value !== \"object\") {\n throw new Error(\"Snapshot should be there to load from!!\");\n }\n const snapshotTree = value;\n dataStoreContext = new LocalFluidDataStoreContext(\n key,\n undefined,\n this.runtime,\n this.runtime.storage,\n this.runtime.scope,\n this.getCreateChildSummarizerNodeFn(key, { type: CreateSummarizerNodeSource.FromSummary }),\n (cr: IFluidDataStoreChannel) => this.bindFluidDataStore(cr),\n snapshotTree,\n undefined,\n );\n }\n this.contexts.addBoundOrRemoted(dataStoreContext);\n }\n this.containerLoadStats = {\n containerLoadDataStoreCount: fluidDataStores.size,\n referencedDataStoreCount: fluidDataStores.size - unreferencedDataStoreCount,\n };\n }\n\n public aliases(): ReadonlyMap<string, string> {\n return this.aliasMap;\n }\n\n public processAttachMessage(message: ISequencedDocumentMessage, local: boolean) {\n const attachMessage = message.contents as InboundAttachMessage;\n\n this.dataStoresSinceLastGC.push(attachMessage.id);\n\n // The local object has already been attached\n if (local) {\n assert(this.pendingAttach.has(attachMessage.id),\n 0x15e /* \"Local object does not have matching attach message id\" */);\n this.contexts.get(attachMessage.id)?.emit(\"attached\");\n this.pendingAttach.delete(attachMessage.id);\n return;\n }\n\n // If a non-local operation then go and create the object, otherwise mark it as officially attached.\n if (this.alreadyProcessed(attachMessage.id)) {\n // TODO: dataStoreId may require a different tag from PackageData #7488\n const error = new DataCorruptionError(\n \"duplicateDataStoreCreatedWithExistingId\",\n {\n ...extractSafePropertiesFromMessage(message),\n dataStoreId: {\n value: attachMessage.id,\n tag: TelemetryDataTag.PackageData,\n },\n },\n );\n throw error;\n }\n\n const flatBlobs = new Map<string, ArrayBufferLike>();\n let snapshotTree: ISnapshotTree | undefined;\n if (attachMessage.snapshot) {\n snapshotTree = buildSnapshotTree(attachMessage.snapshot.entries, flatBlobs);\n }\n\n // Include the type of attach message which is the pkg of the store to be\n // used by RemotedFluidDataStoreContext in case it is not in the snapshot.\n const pkg = [attachMessage.type];\n const remotedFluidDataStoreContext = new RemotedFluidDataStoreContext(\n attachMessage.id,\n snapshotTree,\n // New data stores begin with empty GC details since GC hasn't run on them yet.\n async () => { return {}; },\n this.runtime,\n new BlobCacheStorageService(this.runtime.storage, flatBlobs),\n this.runtime.scope,\n this.getCreateChildSummarizerNodeFn(\n attachMessage.id,\n {\n type: CreateSummarizerNodeSource.FromAttach,\n sequenceNumber: message.sequenceNumber,\n snapshot: attachMessage.snapshot ?? {\n entries: [createAttributesBlob(\n pkg,\n true /* isRootDataStore */,\n this.runtime.disableIsolatedChannels,\n )],\n },\n }),\n pkg);\n\n this.contexts.addBoundOrRemoted(remotedFluidDataStoreContext);\n }\n\n public processAliasMessage(\n message: ISequencedDocumentMessage,\n localOpMetadata: unknown,\n local: boolean,\n ): void {\n const aliasMessage = message.contents as IDataStoreAliasMessage;\n if (!isDataStoreAliasMessage(aliasMessage)) {\n throw new DataCorruptionError(\n \"malformedDataStoreAliasMessage\",\n {\n ...extractSafePropertiesFromMessage(message),\n },\n );\n }\n\n const resolve = localOpMetadata as PendingAliasResolve;\n const aliasResult = this.processAliasMessageCore(aliasMessage);\n if (local) {\n resolve(aliasResult);\n }\n }\n\n private processAliasMessageCore(aliasMessage: IDataStoreAliasMessage): boolean {\n if (this.alreadyProcessed(aliasMessage.alias)) {\n return false;\n }\n\n const currentContext = this.contexts.get(aliasMessage.internalId);\n if (currentContext === undefined) {\n this.logger.sendErrorEvent({\n eventName: \"AliasFluidDataStoreNotFound\",\n fluidDataStoreId: aliasMessage.internalId,\n });\n return false;\n }\n\n this.aliasMap.set(aliasMessage.alias, currentContext.id);\n currentContext.setRoot();\n return true;\n }\n\n private alreadyProcessed(id: string): boolean {\n return this.aliasMap.get(id) !== undefined || this.contexts.get(id) !== undefined;\n }\n\n public bindFluidDataStore(fluidDataStoreRuntime: IFluidDataStoreChannel): void {\n const id = fluidDataStoreRuntime.id;\n const localContext = this.contexts.getUnbound(id);\n assert(!!localContext, 0x15f /* \"Could not find unbound context to bind\" */);\n\n // If the container is detached, we don't need to send OP or add to pending attach because\n // we will summarize it while uploading the create new summary and make it known to other\n // clients.\n if (this.runtime.attachState !== AttachState.Detached) {\n localContext.emit(\"attaching\");\n const message = localContext.generateAttachMessage();\n\n this.pendingAttach.set(id, message);\n this.submitAttachFn(message);\n this.attachOpFiredForDataStore.add(id);\n }\n\n this.contexts.bind(fluidDataStoreRuntime.id);\n }\n\n public createDetachedDataStoreCore(\n pkg: Readonly<string[]>,\n isRoot: boolean,\n id = uuid()): IFluidDataStoreContextDetached\n {\n const context = new LocalDetachedFluidDataStoreContext(\n id,\n pkg,\n this.runtime,\n this.runtime.storage,\n this.runtime.scope,\n this.getCreateChildSummarizerNodeFn(id, { type: CreateSummarizerNodeSource.Local }),\n (cr: IFluidDataStoreChannel) => this.bindFluidDataStore(cr),\n isRoot,\n );\n this.contexts.addUnbound(context);\n return context;\n }\n\n public _createFluidDataStoreContext(pkg: string[], id: string, isRoot: boolean, props?: any) {\n const context = new LocalFluidDataStoreContext(\n id,\n pkg,\n this.runtime,\n this.runtime.storage,\n this.runtime.scope,\n this.getCreateChildSummarizerNodeFn(id, { type: CreateSummarizerNodeSource.Local }),\n (cr: IFluidDataStoreChannel) => this.bindFluidDataStore(cr),\n undefined,\n isRoot,\n props,\n );\n this.contexts.addUnbound(context);\n return context;\n }\n\n public get disposed() {return this.disposeOnce.evaluated;}\n public readonly dispose = () => this.disposeOnce.value;\n\n public resubmitDataStoreOp(content: any, localOpMetadata: unknown) {\n const envelope = content as IEnvelope;\n const context = this.contexts.get(envelope.address);\n assert(!!context, 0x160 /* \"There should be a store context for the op\" */);\n context.reSubmit(envelope.contents, localOpMetadata);\n }\n\n public async applyStashedOp(content: any): Promise<unknown> {\n const envelope = content as IEnvelope;\n const context = this.contexts.get(envelope.address);\n assert(!!context, 0x161 /* \"There should be a store context for the op\" */);\n return context.applyStashedOp(envelope.contents);\n }\n\n public async applyStashedAttachOp(message: IAttachMessage) {\n this.pendingAttach.set(message.id, message);\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n this.processAttachMessage({ contents: message } as ISequencedDocumentMessage, false);\n }\n\n public processFluidDataStoreOp(message: ISequencedDocumentMessage, local: boolean, localMessageMetadata: unknown) {\n const envelope = message.contents as IEnvelope;\n const transformed = { ...message, contents: envelope.contents };\n const context = this.contexts.get(envelope.address);\n assert(!!context, 0x162 /* \"There should be a store context for the op\" */);\n context.process(transformed, local, localMessageMetadata);\n\n // Notify that a data store changed. This is used to detect if a deleted data store is being used.\n this.dataStoreChanged(envelope.address);\n }\n\n public async getDataStore(id: string, wait: boolean): Promise<FluidDataStoreContext> {\n const internalId = this.aliasMap.get(id) ?? id;\n\n const context = await this.contexts.getBoundOrRemoted(internalId, wait);\n if (context === undefined) {\n // The requested data store does not exits. Throw a 404 response exception.\n const request = { url: id };\n throw responseToException(create404Response(request), request);\n }\n\n return context;\n }\n\n public processSignal(address: string, message: IInboundSignalMessage, local: boolean) {\n const context = this.contexts.get(address);\n if (!context) {\n // Attach message may not have been processed yet\n assert(!local, 0x163 /* \"Missing datastore for local signal\" */);\n this.logger.sendTelemetryEvent({\n eventName: \"SignalFluidDataStoreNotFound\",\n fluidDataStoreId: address,\n });\n return;\n }\n\n context.processSignal(message, local);\n }\n\n public setConnectionState(connected: boolean, clientId?: string) {\n for (const [fluidDataStore, context] of this.contexts) {\n try {\n context.setConnectionState(connected, clientId);\n } catch (error) {\n this.logger.sendErrorEvent({\n eventName: \"SetConnectionStateError\",\n clientId,\n fluidDataStore,\n }, error);\n }\n }\n }\n\n public setAttachState(attachState: AttachState.Attaching | AttachState.Attached): void {\n let eventName: \"attaching\" | \"attached\";\n if (attachState === AttachState.Attaching) {\n eventName = \"attaching\";\n } else {\n eventName = \"attached\";\n }\n for (const [,context] of this.contexts) {\n // Fire only for bounded stores.\n if (!this.contexts.isNotBound(context.id)) {\n context.emit(eventName);\n }\n }\n }\n\n public get size(): number {\n return this.contexts.size;\n }\n\n public async summarize(fullTree: boolean, trackState: boolean): Promise<ISummaryTreeWithStats> {\n const summaryBuilder = new SummaryTreeBuilder();\n\n // Iterate over each store and ask it to snapshot\n await Promise.all(Array.from(this.contexts)\n .filter(([_, context]) => {\n // Summarizer works only with clients with no local changes!\n assert(context.attachState !== AttachState.Attaching,\n 0x165 /* \"Summarizer cannot work if client has local changes\" */);\n return context.attachState === AttachState.Attached;\n }).map(async ([contextId, context]) => {\n const contextSummary = await context.summarize(fullTree, trackState);\n summaryBuilder.addWithStats(contextId, contextSummary);\n }));\n\n return summaryBuilder.getSummaryTree();\n }\n\n public createSummary(): ISummaryTreeWithStats {\n const builder = new SummaryTreeBuilder();\n // Attaching graph of some stores can cause other stores to get bound too.\n // So keep taking summary until no new stores get bound.\n let notBoundContextsLength: number;\n do {\n const builderTree = builder.summary.tree;\n notBoundContextsLength = this.contexts.notBoundLength();\n // Iterate over each data store and ask it to snapshot\n Array.from(this.contexts)\n .filter(([key, _]) =>\n // Take summary of bounded data stores only, make sure we haven't summarized them already\n // and no attach op has been fired for that data store because for loader versions <= 0.24\n // we set attach state as \"attaching\" before taking createNew summary.\n !(this.contexts.isNotBound(key)\n || builderTree[key]\n || this.attachOpFiredForDataStore.has(key)),\n )\n .map(([key, value]) => {\n let dataStoreSummary: ISummarizeResult;\n if (value.isLoaded) {\n const snapshot = value.generateAttachMessage().snapshot;\n dataStoreSummary = convertToSummaryTree(snapshot, true);\n } else {\n // If this data store is not yet loaded, then there should be no changes in the snapshot from\n // which it was created as it is detached container. So just use the previous snapshot.\n assert(!!this.baseSnapshot,\n 0x166 /* \"BaseSnapshot should be there as detached container loaded from snapshot\" */);\n dataStoreSummary = convertSnapshotTreeToSummaryTree(this.baseSnapshot.trees[key]);\n }\n builder.addWithStats(key, dataStoreSummary);\n });\n } while (notBoundContextsLength !== this.contexts.notBoundLength());\n\n return builder.getSummaryTree();\n }\n\n /**\n * Before GC runs, called by the garbage collector to update any pending GC state.\n * The garbage collector needs to know all outbound references that are added. Since root data stores are not\n * explicitly marked as referenced, notify GC of new root data stores that were added since the last GC run.\n */\n public async updateStateBeforeGC(): Promise<void> {\n for (const id of this.dataStoresSinceLastGC) {\n const context = this.contexts.get(id);\n assert(context !== undefined, 0x2b6 /* `Missing data store context with id ${id}` */);\n if (await context.isRoot()) {\n // A root data store is basically a reference from the container runtime to the data store.\n const handle = new FluidObjectHandle(context, id, this.runtime.IFluidHandleContext);\n this.runtime.addedGCOutboundReference(this.containerRuntimeHandle, handle);\n }\n }\n this.dataStoresSinceLastGC = [];\n }\n\n /**\n * Generates data used for garbage collection. It does the following:\n * 1. Calls into each child data store context to get its GC data.\n * 2. Prefixes the child context's id to the GC nodes in the child's GC data. This makes sure that the node can be\n * identified as belonging to the child.\n * 3. Adds a GC node for this channel to the nodes received from the children. All these nodes together represent\n * the GC data of this channel.\n * @param fullGC - true to bypass optimizations and force full generation of GC data.\n */\n public async getGCData(fullGC: boolean = false): Promise<IGarbageCollectionData> {\n const builder = new GCDataBuilder();\n // Iterate over each store and get their GC data.\n await Promise.all(Array.from(this.contexts)\n .filter(([_, context]) => {\n // Get GC data only for attached contexts. Detached contexts are not connected in the GC reference\n // graph so any references they might have won't be connected as well.\n return context.attachState === AttachState.Attached;\n }).map(async ([contextId, context]) => {\n const contextGCData = await context.getGCData(fullGC);\n // Prefix the child's id to the ids of its GC nodes so they can be identified as belonging to the child.\n // This also gradually builds the id of each node to be a path from the root.\n builder.prefixAndAddNodes(contextId, contextGCData.gcNodes);\n }));\n\n // Get the outbound routes and add a GC node for this channel.\n builder.addNode(\"/\", await this.getOutboundRoutes());\n return builder.getGCData();\n }\n\n /**\n * After GC has run, called to notify this Container's data stores of routes that are used in it.\n * @param usedRoutes - The routes that are used in all data stores in this Container.\n * @param gcTimestamp - The time when GC was run that generated these used routes. If any node node becomes\n * unreferenced as part of this GC run, this should be used to update the time when it happens.\n * @returns the statistics of the used state of the data stores.\n */\n public updateUsedRoutes(usedRoutes: string[], gcTimestamp?: number): IUsedStateStats {\n // Get a map of data store ids to routes used in it.\n const usedDataStoreRoutes = unpackChildNodesUsedRoutes(usedRoutes);\n\n // Verify that the used routes are correct.\n for (const [id] of usedDataStoreRoutes) {\n assert(this.contexts.has(id), 0x167 /* \"Used route does not belong to any known data store\" */);\n }\n\n // Update the used routes in each data store. Used routes is empty for unused data stores.\n for (const [contextId, context] of this.contexts) {\n context.updateUsedRoutes(usedDataStoreRoutes.get(contextId) ?? [], gcTimestamp);\n }\n\n // Return the number of data stores that are unused.\n const dataStoreCount = this.contexts.size;\n return {\n totalNodeCount: dataStoreCount,\n unusedNodeCount: dataStoreCount - usedDataStoreRoutes.size,\n };\n }\n\n /**\n * When running GC in test mode, this is called to delete objects whose routes are unused. This enables testing\n * scenarios with accessing deleted content.\n * @param unusedRoutes - The routes that are unused in all data stores in this Container.\n */\n public deleteUnusedRoutes(unusedRoutes: string[]) {\n for (const route of unusedRoutes) {\n const dataStoreId = route.split(\"/\")[1];\n // Delete the contexts of unused data stores.\n this.contexts.delete(dataStoreId);\n // Delete the summarizer node of the unused data stores.\n this.deleteChildSummarizerNodeFn(dataStoreId);\n }\n }\n\n /**\n * Returns the outbound routes of this channel. Only root data stores are considered referenced and their paths are\n * part of outbound routes.\n */\n private async getOutboundRoutes(): Promise<string[]> {\n const outboundRoutes: string[] = [];\n for (const [contextId, context] of this.contexts) {\n const isRootDataStore = await context.isRoot();\n if (isRootDataStore) {\n outboundRoutes.push(`/${contextId}`);\n }\n }\n return outboundRoutes;\n }\n}\n\nexport function getSummaryForDatastores(\n snapshot: ISnapshotTree | undefined,\n metadata?: IContainerRuntimeMetadata,\n): ISnapshotTree | undefined {\n if (!snapshot) {\n return undefined;\n }\n\n if (rootHasIsolatedChannels(metadata)) {\n const datastoresSnapshot = snapshot.trees[channelsTreeName];\n assert(!!datastoresSnapshot, 0x168 /* `expected ${channelsTreeName} tree in snapshot` */);\n return datastoresSnapshot;\n } else {\n // back-compat: strip out all non-datastore paths before giving to DataStores object.\n const datastoresTrees: ISnapshotTree[\"trees\"] = {};\n for (const [key, value] of Object.entries(snapshot.trees)) {\n if (!nonDataStorePaths.includes(key)) {\n datastoresTrees[key] = value;\n }\n }\n return {\n ...snapshot,\n trees: datastoresTrees,\n };\n }\n}\n"]}
@@ -3,8 +3,9 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
  import { ITelemetryLogger } from "@fluidframework/common-definitions";
6
+ import { ICriticalContainerError } from "@fluidframework/container-definitions";
6
7
  import { ISnapshotTree } from "@fluidframework/protocol-definitions";
7
- import { IGarbageCollectionData, IGarbageCollectionSummaryDetails, ISummaryTreeWithStats } from "@fluidframework/runtime-definitions";
8
+ import { IGarbageCollectionData, IGarbageCollectionDetailsBase, ISummaryTreeWithStats } from "@fluidframework/runtime-definitions";
8
9
  import { ReadAndParseBlob, RefreshSummaryResult } from "@fluidframework/runtime-utils";
9
10
  import { IGCRuntimeOptions } from "./containerRuntime";
10
11
  import { IContainerRuntimeMetadata } from "./summaryFormat";
@@ -24,6 +25,8 @@ export interface IGCStats {
24
25
  }
25
26
  /** Defines the APIs for the runtime object to be passed to the garbage collector. */
26
27
  export interface IGarbageCollectionRuntime {
28
+ /** Before GC runs, called to notify the runtime to update any pending GC state. */
29
+ updateStateBeforeGC(): Promise<void>;
27
30
  /** Returns the garbage collection data of the runtime. */
28
31
  getGCData(fullGC?: boolean): Promise<IGarbageCollectionData>;
29
32
  /** After GC has run, called to notify the runtime of routes that are used in it. */
@@ -33,6 +36,8 @@ export interface IGarbageCollectionRuntime {
33
36
  export interface IGarbageCollector {
34
37
  /** Tells whether GC should run or not. */
35
38
  readonly shouldRunGC: boolean;
39
+ /** The time in ms to expire a session for a client for gc. */
40
+ readonly sessionExpiryTimeoutMs: number | undefined;
36
41
  /**
37
42
  * This tracks two things:
38
43
  * 1. Whether GC is enabled - If this is 0, GC is disabled. If this is greater than 0, GC is enabled.
@@ -53,11 +58,12 @@ export interface IGarbageCollector {
53
58
  /** Summarizes the GC data and returns it as a summary tree. */
54
59
  summarize(): ISummaryTreeWithStats | undefined;
55
60
  /** Returns a map of each data store id to its GC details in the base summary. */
56
- getDataStoreBaseGCDetails(): Promise<Map<string, IGarbageCollectionSummaryDetails>>;
61
+ getDataStoreBaseGCDetails(): Promise<Map<string, IGarbageCollectionDetailsBase>>;
57
62
  /** Called when the latest summary of the system has been refreshed. */
58
63
  latestSummaryStateRefreshed(result: RefreshSummaryResult, readAndParseBlob: ReadAndParseBlob): Promise<void>;
59
64
  /** Called when a node is changed. Used to detect and log when an inactive node is changed. */
60
65
  nodeChanged(id: string): void;
66
+ dispose(): void;
61
67
  /** Called when a reference is added to a node. Used to identify nodes that were referenced between summaries. */
62
68
  addedOutboundReference(fromNodeId: string, toNodeId: string): void;
63
69
  }
@@ -72,11 +78,16 @@ export declare class GarbageCollector implements IGarbageCollector {
72
78
  private readonly deleteUnusedRoutes;
73
79
  /** Returns the current timestamp to be assigned to nodes that become unreferenced. */
74
80
  private readonly getCurrentTimestampMs;
75
- static create(provider: IGarbageCollectionRuntime, gcOptions: IGCRuntimeOptions, deleteUnusedRoutes: (unusedRoutes: string[]) => void, getCurrentTimestampMs: () => number, baseSnapshot: ISnapshotTree | undefined, readAndParseBlob: ReadAndParseBlob, baseLogger: ITelemetryLogger, existing: boolean, metadata?: IContainerRuntimeMetadata): IGarbageCollector;
81
+ private readonly closeFn;
82
+ static create(provider: IGarbageCollectionRuntime, gcOptions: IGCRuntimeOptions, deleteUnusedRoutes: (unusedRoutes: string[]) => void, getCurrentTimestampMs: () => number, closeFn: (error?: ICriticalContainerError) => void, baseSnapshot: ISnapshotTree | undefined, readAndParseBlob: ReadAndParseBlob, baseLogger: ITelemetryLogger, existing: boolean, metadata?: IContainerRuntimeMetadata): IGarbageCollector;
76
83
  /**
77
84
  * Tells whether GC should be run based on the GC options and local storage flags.
78
85
  */
79
86
  readonly shouldRunGC: boolean;
87
+ /**
88
+ * The time in ms to expire a session for a client for gc.
89
+ */
90
+ readonly sessionExpiryTimeoutMs: number | undefined;
80
91
  /**
81
92
  * This tracks two things:
82
93
  * 1. Whether GC is enabled - If this is 0, GC is disabled. If this is greater than 0, GC is enabled.
@@ -111,11 +122,12 @@ export declare class GarbageCollector implements IGarbageCollector {
111
122
  private readonly dataStoreGCDetailsP;
112
123
  private readonly deleteTimeoutMs;
113
124
  private readonly unreferencedNodesState;
125
+ private sessionExpiryTimer?;
114
126
  protected constructor(provider: IGarbageCollectionRuntime, gcOptions: IGCRuntimeOptions,
115
127
  /** After GC has run, called to delete objects in the runtime whose routes are unused. */
116
128
  deleteUnusedRoutes: (unusedRoutes: string[]) => void,
117
129
  /** Returns the current timestamp to be assigned to nodes that become unreferenced. */
118
- getCurrentTimestampMs: () => number, baseSnapshot: ISnapshotTree | undefined, readAndParseBlob: ReadAndParseBlob, baseLogger: ITelemetryLogger, existing: boolean, metadata?: IContainerRuntimeMetadata);
130
+ getCurrentTimestampMs: () => number, closeFn: (error?: ICriticalContainerError) => void, baseSnapshot: ISnapshotTree | undefined, readAndParseBlob: ReadAndParseBlob, baseLogger: ITelemetryLogger, existing: boolean, metadata?: IContainerRuntimeMetadata);
119
131
  /**
120
132
  * Runs garbage collection and udpates the reference / used state of the nodes in the container.
121
133
  * @returns the number of data stores that have been marked as unreferenced.
@@ -136,9 +148,9 @@ export declare class GarbageCollector implements IGarbageCollector {
136
148
  summarize(): ISummaryTreeWithStats | undefined;
137
149
  /**
138
150
  * Returns a map of data store ids to their base GC details generated from the base summary.This is used to
139
- * initialize the data stores with their base GC state.
151
+ * initialize the GC state of data stores.
140
152
  */
141
- getDataStoreBaseGCDetails(): Promise<Map<string, IGarbageCollectionSummaryDetails>>;
153
+ getDataStoreBaseGCDetails(): Promise<Map<string, IGarbageCollectionDetailsBase>>;
142
154
  /**
143
155
  * Called when the latest summary of the system has been refreshed. This will be used to update the state of the
144
156
  * latest summary tracked.
@@ -148,6 +160,7 @@ export declare class GarbageCollector implements IGarbageCollector {
148
160
  * Called when a node with the given id is changed. If the node is inactive, log an error.
149
161
  */
150
162
  nodeChanged(id: string): void;
163
+ dispose(): void;
151
164
  /**
152
165
  * Called when an outbound reference is added to a node. This is used to identify all nodes that have been
153
166
  * referenced between summaries so that their unreferenced timestamp can be reset.
@@ -179,5 +192,14 @@ export declare class GarbageCollector implements IGarbageCollector {
179
192
  * If these nodes are currently unreferenced, they will be assigned new unreferenced state by the current run.
180
193
  */
181
194
  private updateStateSinceLatestRun;
195
+ /**
196
+ * Validates that all new references are correctly identified and processed. The basic principle for validation is
197
+ * that we should not have new references in the reference graph (GC data) that have not been notified to the
198
+ * garbage collector via `referenceAdded`.
199
+ * We validate that the references in the current reference graph should be a subset of the references in the last
200
+ * run's reference graph + references since the last run.
201
+ * @param currentGCData - The GC data (reference graph) from the current GC run.
202
+ */
203
+ private validateReferenceCorrectness;
182
204
  }
183
205
  //# sourceMappingURL=garbageCollection.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"garbageCollection.d.ts","sourceRoot":"","sources":["../src/garbageCollection.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"garbageCollection.d.ts","sourceRoot":"","sources":["../src/garbageCollection.ts"],"names":[],"mappings":"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"}
@@ -74,12 +74,13 @@ class GarbageCollector {
74
74
  /** After GC has run, called to delete objects in the runtime whose routes are unused. */
75
75
  deleteUnusedRoutes,
76
76
  /** Returns the current timestamp to be assigned to nodes that become unreferenced. */
77
- getCurrentTimestampMs, baseSnapshot, readAndParseBlob, baseLogger, existing, metadata) {
77
+ getCurrentTimestampMs, closeFn, baseSnapshot, readAndParseBlob, baseLogger, existing, metadata) {
78
78
  var _a, _b, _c, _d;
79
79
  this.provider = provider;
80
80
  this.gcOptions = gcOptions;
81
81
  this.deleteUnusedRoutes = deleteUnusedRoutes;
82
82
  this.getCurrentTimestampMs = getCurrentTimestampMs;
83
+ this.closeFn = closeFn;
83
84
  /**
84
85
  * Tells whether the GC data should be written to the root of the summary tree. We do this under 2 conditions:
85
86
  * 1. If `writeDataAtRoot` GC option is enabled.
@@ -98,16 +99,31 @@ class GarbageCollector {
98
99
  this.deleteTimeoutMs = (_a = this.gcOptions.deleteTimeoutMs) !== null && _a !== void 0 ? _a : defaultDeleteTimeoutMs;
99
100
  let prevSummaryGCVersion;
100
101
  // GC can only be enabled during creation. After that, it can never be enabled again. So, for existing
101
- // documents, we get this information from the metadata blob.
102
+ // documents, we get this information from the metadata blob. Similarly the session timeout should be
103
+ // consistent across all clients, thus we grab it as well from the metadata blob, and set it once on creation.
102
104
  if (existing) {
103
105
  prevSummaryGCVersion = summaryFormat_1.getGCVersion(metadata);
104
106
  // Existing documents which did not have metadata blob or had GC disabled have version as 0. For all
105
107
  // other exsiting documents, GC is enabled.
106
108
  this.gcEnabled = prevSummaryGCVersion > 0;
109
+ this.sessionExpiryTimeoutMs = metadata === null || metadata === void 0 ? void 0 : metadata.sessionExpiryTimeoutMs;
107
110
  }
108
111
  else {
109
112
  // For new documents, GC has to be exlicitly enabled via the gcAllowed flag in GC options.
110
113
  this.gcEnabled = gcOptions.gcAllowed === true;
114
+ this.sessionExpiryTimeoutMs = this.gcOptions.gcTestSessionTimeoutMs;
115
+ }
116
+ // If session expiry is enabled, we need to close the container when the timeout expires
117
+ if (this.sessionExpiryTimeoutMs !== undefined) {
118
+ // TODO: Change to ClientSessionExpiredError, issue https://github.com/microsoft/FluidFramework/issues/8605
119
+ // this.sessionExpiryTimer = setTimeout(() => this.closeFn(
120
+ // new ClientSessionExpiredError(`Client expired, it has lasted ${this.sessionExpiryTimeoutMs} ms.`,
121
+ // this.sessionExpiryTimeoutMs)),
122
+ // this.sessionExpiryTimeoutMs);
123
+ this.sessionExpiryTimer = setTimeout(() => this.closeFn({
124
+ errorType: "clientSessionExpiredError",
125
+ message: `The client has reached the expiry time of ${this.sessionExpiryTimeoutMs} ms.`,
126
+ }), this.sessionExpiryTimeoutMs);
111
127
  }
112
128
  // For existing document, the latest summary is the one that we loaded from. So, use its GC version as the
113
129
  // latest tracked GC version. For new documents, we will be writing the first summary with the current version.
@@ -121,7 +137,8 @@ class GarbageCollector {
121
137
  // Whether GC sweep phase should run or not. If this is false, only GC mark phase is run. Can override with
122
138
  // localStorage flag.
123
139
  this.shouldRunSweep = this.shouldRunGC &&
124
- ((_c = this.mc.config.getBoolean(runSweepKey)) !== null && _c !== void 0 ? _c : gcOptions.runSweep === true);
140
+ ((_c = this.mc.config.getBoolean(runSweepKey)) !== null && _c !== void 0 ? _c : gcOptions.runSweep === true)
141
+ && this.sessionExpiryTimer !== undefined;
125
142
  // Whether we are running in test mode. In this mode, unreferenced nodes are immediately deleted.
126
143
  this.testMode = (_d = this.mc.config.getBoolean(gcTestModeKey)) !== null && _d !== void 0 ? _d : gcOptions.runGCInTestMode === true;
127
144
  // If `writeDataAtRoot` GC option is true, we should write the GC data into the root of the summary tree. This
@@ -199,7 +216,7 @@ class GarbageCollector {
199
216
  this.gcDataFromLastRun = { gcNodes };
200
217
  });
201
218
  // Get the GC details for each data store from the GC state in the base summary. This is returned in
202
- // getDataStoreBaseGCDetails and is used to initialize each data store's base GC details.
219
+ // getDataStoreBaseGCDetails and is used to initialize each data store's GC state.
203
220
  this.dataStoreGCDetailsP = new common_utils_1.LazyPromise(async () => {
204
221
  const baseState = await baseSummaryStateP;
205
222
  if (baseState === undefined) {
@@ -227,8 +244,8 @@ class GarbageCollector {
227
244
  return dataStoreGCDetailsMap;
228
245
  });
229
246
  }
230
- static create(provider, gcOptions, deleteUnusedRoutes, getCurrentTimestampMs, baseSnapshot, readAndParseBlob, baseLogger, existing, metadata) {
231
- return new GarbageCollector(provider, gcOptions, deleteUnusedRoutes, getCurrentTimestampMs, baseSnapshot, readAndParseBlob, baseLogger, existing, metadata);
247
+ static create(provider, gcOptions, deleteUnusedRoutes, getCurrentTimestampMs, closeFn, baseSnapshot, readAndParseBlob, baseLogger, existing, metadata) {
248
+ return new GarbageCollector(provider, gcOptions, deleteUnusedRoutes, getCurrentTimestampMs, closeFn, baseSnapshot, readAndParseBlob, baseLogger, existing, metadata);
232
249
  }
233
250
  /**
234
251
  * This tracks two things:
@@ -258,6 +275,8 @@ class GarbageCollector {
258
275
  const { logger = this.mc.logger, runSweep = this.shouldRunSweep, fullGC = this.gcOptions.runFullGC === true || this.hasGCVersionChanged, } = options;
259
276
  return telemetry_utils_1.PerformanceEvent.timedExecAsync(logger, { eventName: "GarbageCollection" }, async (event) => {
260
277
  await this.initializeBaseStateP;
278
+ // Let the runtime update its pending state before GC runs.
279
+ await this.provider.updateStateBeforeGC();
261
280
  const gcStats = {};
262
281
  // Get the runtime's GC data and run GC on the reference graph in it.
263
282
  const gcData = await this.provider.getGCData(fullGC);
@@ -307,7 +326,7 @@ class GarbageCollector {
307
326
  }
308
327
  /**
309
328
  * Returns a map of data store ids to their base GC details generated from the base summary.This is used to
310
- * initialize the data stores with their base GC state.
329
+ * initialize the GC state of data stores.
311
330
  */
312
331
  async getDataStoreBaseGCDetails() {
313
332
  return this.dataStoreGCDetailsP;
@@ -339,6 +358,12 @@ class GarbageCollector {
339
358
  const nodeId = id.startsWith("/") ? id : `/${id}`;
340
359
  (_a = this.unreferencedNodesState.get(nodeId)) === null || _a === void 0 ? void 0 : _a.logIfInactive(this.mc.logger, "inactiveObjectChanged", this.getCurrentTimestampMs(), this.deleteTimeoutMs, nodeId);
341
360
  }
361
+ dispose() {
362
+ if (this.sessionExpiryTimer !== undefined) {
363
+ clearTimeout(this.sessionExpiryTimer);
364
+ this.sessionExpiryTimer = undefined;
365
+ }
366
+ }
342
367
  /**
343
368
  * Called when an outbound reference is added to a node. This is used to identify all nodes that have been
344
369
  * referenced between summaries so that their unreferenced timestamp can be reset.
@@ -414,6 +439,8 @@ class GarbageCollector {
414
439
  if (this.gcDataFromLastRun === undefined || this.referencesSinceLastRun.size === 0) {
415
440
  return;
416
441
  }
442
+ // Validate that we have identified all references correctly.
443
+ this.validateReferenceCorrectness(currentGCData);
417
444
  /**
418
445
  * Generate a super set of the GC data that contains the nodes and edges from last run, plus any new node and
419
446
  * edges that have been added since then. To do this, combine the GC data from the last run and the current
@@ -454,6 +481,55 @@ class GarbageCollector {
454
481
  }
455
482
  }
456
483
  }
484
+ /**
485
+ * Validates that all new references are correctly identified and processed. The basic principle for validation is
486
+ * that we should not have new references in the reference graph (GC data) that have not been notified to the
487
+ * garbage collector via `referenceAdded`.
488
+ * We validate that the references in the current reference graph should be a subset of the references in the last
489
+ * run's reference graph + references since the last run.
490
+ * @param currentGCData - The GC data (reference graph) from the current GC run.
491
+ */
492
+ validateReferenceCorrectness(currentGCData) {
493
+ common_utils_1.assert(this.gcDataFromLastRun !== undefined, 0x2b7
494
+ /* "Can't validate correctness without GC data from last run" */ );
495
+ // Get a list of all the outbound routes (or references) in the current GC data.
496
+ const currentReferences = [];
497
+ for (const [nodeId, outboundRoutes] of Object.entries(currentGCData.gcNodes)) {
498
+ /**
499
+ * Remove routes from a child node to its parent which is added implicitly by the runtime. For instance,
500
+ * each adds its data store as an outbound route to mark it as referenced if the DDS is referenced.
501
+ * We won't get any explicit notification for these references so they must be removed before validation.
502
+ */
503
+ const explicitRoutes = outboundRoutes.filter((route) => !nodeId.startsWith(route));
504
+ currentReferences.push(...explicitRoutes);
505
+ }
506
+ // Get a list of outbound routes (or references) from the last run's GC data plus references added since the
507
+ // last run that were notified via `referenceAdded`.
508
+ const explicitReferences = [];
509
+ for (const [, outboundRoutes] of Object.entries(this.gcDataFromLastRun.gcNodes)) {
510
+ explicitReferences.push(...outboundRoutes);
511
+ }
512
+ this.referencesSinceLastRun.forEach((outboundRoutes) => {
513
+ explicitReferences.push(...outboundRoutes);
514
+ });
515
+ // Validate that the current reference graph doesn't have references that we are not already aware of. If this
516
+ // happens, it might indicate data corruption since we may delete objects prematurely.
517
+ currentReferences.forEach((route) => {
518
+ // Validate references for data stores only whose routes are of the format "/dataStoreId". Currently, layers
519
+ // below data stores don't have GC implemented so there is no guarantee their references will be notified.
520
+ if (route.split("/").length === 2 && !explicitReferences.includes(route)) {
521
+ // We should ideally throw a data corruption error here. However, send an error for now until we have
522
+ // implemented sweep and have reasonable confidence in the sweep process.
523
+ // To be enabled when this issue is fixed - https://github.com/microsoft/FluidFramework/issues/8672
524
+ /**
525
+ this.mc.logger.sendErrorEvent({
526
+ eventName: "gcUnknownOutboundRoute",
527
+ route,
528
+ });
529
+ */
530
+ }
531
+ });
532
+ }
457
533
  }
458
534
  exports.GarbageCollector = GarbageCollector;
459
535
  /**