@fluidframework/container-runtime 2.0.0-internal.7.4.0 → 2.0.0-internal.8.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/api-report/container-runtime.api.md +0 -17
  3. package/dist/container-runtime-alpha.d.ts +3 -32
  4. package/dist/container-runtime-beta.d.ts +0 -8
  5. package/dist/container-runtime-public.d.ts +0 -8
  6. package/dist/container-runtime-untrimmed.d.ts +3 -47
  7. package/dist/containerRuntime.d.ts +6 -36
  8. package/dist/containerRuntime.d.ts.map +1 -1
  9. package/dist/containerRuntime.js +6 -67
  10. package/dist/containerRuntime.js.map +1 -1
  11. package/dist/dataStore.js +0 -12
  12. package/dist/dataStore.js.map +1 -1
  13. package/dist/gc/garbageCollection.d.ts +8 -12
  14. package/dist/gc/garbageCollection.d.ts.map +1 -1
  15. package/dist/gc/garbageCollection.js +71 -103
  16. package/dist/gc/garbageCollection.js.map +1 -1
  17. package/dist/gc/gcDefinitions.d.ts +0 -1
  18. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  19. package/dist/gc/gcDefinitions.js.map +1 -1
  20. package/dist/gc/gcSummaryStateTracker.d.ts +1 -1
  21. package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -1
  22. package/dist/gc/gcSummaryStateTracker.js +3 -0
  23. package/dist/gc/gcSummaryStateTracker.js.map +1 -1
  24. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  25. package/dist/gc/gcTelemetry.js +4 -14
  26. package/dist/gc/gcTelemetry.js.map +1 -1
  27. package/dist/index.d.ts +1 -1
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +1 -2
  30. package/dist/index.js.map +1 -1
  31. package/dist/packageVersion.d.ts +1 -1
  32. package/dist/packageVersion.js +1 -1
  33. package/dist/packageVersion.js.map +1 -1
  34. package/dist/summary/summarizer.d.ts +0 -12
  35. package/dist/summary/summarizer.d.ts.map +1 -1
  36. package/dist/summary/summarizer.js +0 -46
  37. package/dist/summary/summarizer.js.map +1 -1
  38. package/lib/container-runtime-alpha.d.ts +3 -32
  39. package/lib/container-runtime-beta.d.ts +0 -8
  40. package/lib/container-runtime-public.d.ts +0 -8
  41. package/lib/container-runtime-untrimmed.d.ts +3 -47
  42. package/lib/containerRuntime.d.ts +6 -36
  43. package/lib/containerRuntime.d.ts.map +1 -1
  44. package/lib/containerRuntime.js +5 -65
  45. package/lib/containerRuntime.js.map +1 -1
  46. package/lib/dataStore.js +0 -12
  47. package/lib/dataStore.js.map +1 -1
  48. package/lib/gc/garbageCollection.d.ts +8 -12
  49. package/lib/gc/garbageCollection.d.ts.map +1 -1
  50. package/lib/gc/garbageCollection.js +72 -104
  51. package/lib/gc/garbageCollection.js.map +1 -1
  52. package/lib/gc/gcDefinitions.d.ts +0 -1
  53. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  54. package/lib/gc/gcDefinitions.js.map +1 -1
  55. package/lib/gc/gcSummaryStateTracker.d.ts +1 -1
  56. package/lib/gc/gcSummaryStateTracker.d.ts.map +1 -1
  57. package/lib/gc/gcSummaryStateTracker.js +3 -0
  58. package/lib/gc/gcSummaryStateTracker.js.map +1 -1
  59. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  60. package/lib/gc/gcTelemetry.js +4 -14
  61. package/lib/gc/gcTelemetry.js.map +1 -1
  62. package/lib/index.d.ts +1 -1
  63. package/lib/index.d.ts.map +1 -1
  64. package/lib/index.js +1 -1
  65. package/lib/index.js.map +1 -1
  66. package/lib/packageVersion.d.ts +1 -1
  67. package/lib/packageVersion.js +1 -1
  68. package/lib/packageVersion.js.map +1 -1
  69. package/lib/summary/summarizer.d.ts +0 -12
  70. package/lib/summary/summarizer.d.ts.map +1 -1
  71. package/lib/summary/summarizer.js +0 -46
  72. package/lib/summary/summarizer.js.map +1 -1
  73. package/package.json +20 -16
  74. package/src/containerRuntime.ts +7 -88
  75. package/src/dataStore.ts +1 -15
  76. package/src/gc/garbageCollection.ts +92 -119
  77. package/src/gc/gcDefinitions.ts +0 -1
  78. package/src/gc/gcSummaryStateTracker.ts +5 -1
  79. package/src/gc/gcTelemetry.ts +4 -13
  80. package/src/index.ts +0 -1
  81. package/src/packageVersion.ts +1 -1
  82. package/src/summary/summarizer.ts +1 -50
package/lib/dataStore.js CHANGED
@@ -102,12 +102,6 @@ class DataStore {
102
102
  this.aliasState = AliasState.Aliased;
103
103
  return "Success";
104
104
  }
105
- /**
106
- * @deprecated Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
107
- */
108
- async request(request) {
109
- return this.fluidDataStoreChannel.request(request);
110
- }
111
105
  /**
112
106
  * {@inheritDoc @fluidframework/runtime-definitions#IDataStore.entryPoint}
113
107
  */
@@ -123,12 +117,6 @@ class DataStore {
123
117
  this.aliasState = AliasState.None;
124
118
  this.pendingAliases = datastores.pendingAliases;
125
119
  }
126
- /**
127
- * @deprecated Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
128
- */
129
- get IFluidRouter() {
130
- return this.fluidDataStoreChannel;
131
- }
132
120
  async ackBasedPromise(executor) {
133
121
  let rejectBecauseDispose;
134
122
  return new Promise((resolve, reject) => {
@@ -1 +1 @@
1
- {"version":3,"file":"dataStore.js","sourceRoot":"","sources":["../src/dataStore.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 { ITelemetryLoggerExt, TelemetryDataTag, UsageError } from \"@fluidframework/telemetry-utils\";\nimport { assert, unreachableCase } from \"@fluidframework/core-utils\";\nimport { AttachState } from \"@fluidframework/container-definitions\";\nimport { FluidObject, IFluidHandle, IRequest, IResponse } from \"@fluidframework/core-interfaces\";\nimport {\n\tAliasResult,\n\tIDataStore,\n\tIFluidDataStoreChannel,\n} from \"@fluidframework/runtime-definitions\";\nimport { ContainerRuntime } from \"./containerRuntime\";\nimport { DataStores } from \"./dataStores\";\n\n/**\n * Interface for an op to be used for assigning an\n * alias to a datastore\n */\nexport interface IDataStoreAliasMessage {\n\t/** The internal id of the datastore */\n\treadonly internalId: string;\n\t/** The alias name to be assigned to the datastore */\n\treadonly 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 {@link IDataStoreAliasMessage}\n * @param maybeDataStoreAliasMessage - message object to be validated\n * @returns True if the {@link IDataStoreAliasMessage} is fully implemented, false otherwise\n */\nexport const isDataStoreAliasMessage = (\n\tmaybeDataStoreAliasMessage: any,\n): maybeDataStoreAliasMessage is IDataStoreAliasMessage => {\n\treturn (\n\t\ttypeof maybeDataStoreAliasMessage?.internalId === \"string\" &&\n\t\ttypeof maybeDataStoreAliasMessage?.alias === \"string\"\n\t);\n};\n\nexport const channelToDataStore = (\n\tfluidDataStoreChannel: IFluidDataStoreChannel,\n\tinternalId: string,\n\truntime: ContainerRuntime,\n\tdatastores: DataStores,\n\tlogger: ITelemetryLoggerExt,\n): IDataStore => new DataStore(fluidDataStoreChannel, internalId, runtime, datastores, logger);\n\nenum AliasState {\n\tAliased = \"Aliased\",\n\tAliasing = \"Aliasing\",\n\tNone = \"None\",\n}\n\nclass DataStore implements IDataStore {\n\tprivate aliasState: AliasState = AliasState.None;\n\tprivate alias: string | undefined;\n\tprivate readonly pendingAliases: Map<string, Promise<AliasResult>>;\n\tprivate aliasResult: Promise<AliasResult> | undefined;\n\n\t/**\n\t * {@inheritDoc @fluidframework/runtime-definitions#IDataStore.trySetAlias}\n\t */\n\tasync trySetAlias(alias: string): Promise<AliasResult> {\n\t\tif (alias.includes(\"/\")) {\n\t\t\tthrow new UsageError(`The alias cannot contain slashes: '${alias}'`);\n\t\t}\n\n\t\tswitch (this.aliasState) {\n\t\t\t// If we're already aliasing, check if it's for the same value and return\n\t\t\t// the stored promise, otherwise return 'AlreadyAliased'\n\t\t\tcase AliasState.Aliasing:\n\t\t\t\tassert(\n\t\t\t\t\tthis.aliasResult !== undefined,\n\t\t\t\t\t0x316 /* There should be a cached promise of in-progress aliasing */,\n\t\t\t\t);\n\t\t\t\tawait this.aliasResult;\n\t\t\t\treturn this.alias === alias ? \"Success\" : \"AlreadyAliased\";\n\n\t\t\t// If this datastore is already aliased, return true only if this\n\t\t\t// is a repeated call for the same alias\n\t\t\tcase AliasState.Aliased:\n\t\t\t\treturn this.alias === alias ? \"Success\" : \"AlreadyAliased\";\n\n\t\t\tcase AliasState.None: {\n\t\t\t\tconst existingAlias = this.pendingAliases.get(alias);\n\t\t\t\tif (existingAlias !== undefined) {\n\t\t\t\t\t// There is already another datastore which will be aliased\n\t\t\t\t\t// to the same name\n\t\t\t\t\treturn \"Conflict\";\n\t\t\t\t}\n\n\t\t\t\t// There is no current or past alias operation for this datastore,\n\t\t\t\t// or for this alias, so it is safe to continue execution\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tunreachableCase(this.aliasState);\n\t\t}\n\n\t\tthis.aliasState = AliasState.Aliasing;\n\t\tthis.aliasResult = this.trySetAliasInternal(alias);\n\t\tthis.pendingAliases.set(alias, this.aliasResult);\n\t\treturn this.aliasResult;\n\t}\n\n\tasync trySetAliasInternal(alias: string): Promise<AliasResult> {\n\t\tconst message: IDataStoreAliasMessage = {\n\t\t\tinternalId: this.internalId,\n\t\t\talias,\n\t\t};\n\n\t\tthis.fluidDataStoreChannel.makeVisibleAndAttachGraph();\n\n\t\tif (this.runtime.attachState === AttachState.Detached) {\n\t\t\tconst localResult = this.datastores.processAliasMessageCore(message);\n\t\t\t// Explicitly lock-out future attempts of aliasing,\n\t\t\t// regardless of result\n\t\t\tthis.aliasState = AliasState.Aliased;\n\t\t\treturn localResult ? \"Success\" : \"Conflict\";\n\t\t}\n\n\t\tconst aliased = await this.ackBasedPromise<boolean>((resolve) => {\n\t\t\tthis.runtime.submitDataStoreAliasOp(message, resolve);\n\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tthis.logger.sendErrorEvent(\n\t\t\t\t\t{\n\t\t\t\t\t\teventName: \"AliasingException\",\n\t\t\t\t\t\talias: {\n\t\t\t\t\t\t\tvalue: alias,\n\t\t\t\t\t\t\ttag: TelemetryDataTag.UserData,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tinternalId: {\n\t\t\t\t\t\t\tvalue: this.internalId,\n\t\t\t\t\t\t\ttag: TelemetryDataTag.CodeArtifact,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\terror,\n\t\t\t\t);\n\n\t\t\t\treturn false;\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tthis.pendingAliases.delete(alias);\n\t\t\t});\n\n\t\tif (!aliased) {\n\t\t\tthis.aliasState = AliasState.None;\n\t\t\tthis.aliasResult = undefined;\n\t\t\treturn \"Conflict\";\n\t\t}\n\n\t\tthis.alias = alias;\n\t\tthis.aliasState = AliasState.Aliased;\n\t\treturn \"Success\";\n\t}\n\n\t/**\n\t * @deprecated Will be removed in future major release. Migrate all usage of IFluidRouter to the \"entryPoint\" pattern. Refer to Removing-IFluidRouter.md\n\t */\n\tpublic async request(request: IRequest): Promise<IResponse> {\n\t\treturn this.fluidDataStoreChannel.request(request);\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/runtime-definitions#IDataStore.entryPoint}\n\t */\n\tget entryPoint(): IFluidHandle<FluidObject> {\n\t\treturn this.fluidDataStoreChannel.entryPoint;\n\t}\n\n\tconstructor(\n\t\tprivate readonly fluidDataStoreChannel: IFluidDataStoreChannel,\n\t\tprivate readonly internalId: string,\n\t\tprivate readonly runtime: ContainerRuntime,\n\t\tprivate readonly datastores: DataStores,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t) {\n\t\tthis.pendingAliases = datastores.pendingAliases;\n\t}\n\n\t/**\n\t * @deprecated Will be removed in future major release. Migrate all usage of IFluidRouter to the \"entryPoint\" pattern. Refer to Removing-IFluidRouter.md\n\t */\n\tpublic get IFluidRouter() {\n\t\treturn this.fluidDataStoreChannel;\n\t}\n\n\tprivate async ackBasedPromise<T>(\n\t\texecutor: (\n\t\t\tresolve: (value: T | PromiseLike<T>) => void,\n\t\t\treject: (reason?: any) => void,\n\t\t) => void,\n\t): Promise<T> {\n\t\tlet rejectBecauseDispose: () => void;\n\t\treturn new Promise<T>((resolve, reject) => {\n\t\t\trejectBecauseDispose = () =>\n\t\t\t\treject(\n\t\t\t\t\tnew Error(\"ContainerRuntime disposed while this ack-based Promise was pending\"),\n\t\t\t\t);\n\n\t\t\tif (this.runtime.disposed) {\n\t\t\t\trejectBecauseDispose();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.runtime.on(\"dispose\", rejectBecauseDispose);\n\t\t\texecutor(resolve, reject);\n\t\t}).finally(() => {\n\t\t\tthis.runtime.off(\"dispose\", rejectBecauseDispose);\n\t\t});\n\t}\n}\n"]}
1
+ {"version":3,"file":"dataStore.js","sourceRoot":"","sources":["../src/dataStore.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 { ITelemetryLoggerExt, TelemetryDataTag, UsageError } from \"@fluidframework/telemetry-utils\";\nimport { assert, unreachableCase } from \"@fluidframework/core-utils\";\nimport { AttachState } from \"@fluidframework/container-definitions\";\nimport { FluidObject, IFluidHandle } from \"@fluidframework/core-interfaces\";\nimport {\n\tAliasResult,\n\tIDataStore,\n\tIFluidDataStoreChannel,\n} from \"@fluidframework/runtime-definitions\";\nimport { ContainerRuntime } from \"./containerRuntime\";\nimport { DataStores } from \"./dataStores\";\n\n/**\n * Interface for an op to be used for assigning an\n * alias to a datastore\n */\nexport interface IDataStoreAliasMessage {\n\t/** The internal id of the datastore */\n\treadonly internalId: string;\n\t/** The alias name to be assigned to the datastore */\n\treadonly 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 {@link IDataStoreAliasMessage}\n * @param maybeDataStoreAliasMessage - message object to be validated\n * @returns True if the {@link IDataStoreAliasMessage} is fully implemented, false otherwise\n */\nexport const isDataStoreAliasMessage = (\n\tmaybeDataStoreAliasMessage: any,\n): maybeDataStoreAliasMessage is IDataStoreAliasMessage => {\n\treturn (\n\t\ttypeof maybeDataStoreAliasMessage?.internalId === \"string\" &&\n\t\ttypeof maybeDataStoreAliasMessage?.alias === \"string\"\n\t);\n};\n\nexport const channelToDataStore = (\n\tfluidDataStoreChannel: IFluidDataStoreChannel,\n\tinternalId: string,\n\truntime: ContainerRuntime,\n\tdatastores: DataStores,\n\tlogger: ITelemetryLoggerExt,\n): IDataStore => new DataStore(fluidDataStoreChannel, internalId, runtime, datastores, logger);\n\nenum AliasState {\n\tAliased = \"Aliased\",\n\tAliasing = \"Aliasing\",\n\tNone = \"None\",\n}\n\nclass DataStore implements IDataStore {\n\tprivate aliasState: AliasState = AliasState.None;\n\tprivate alias: string | undefined;\n\tprivate readonly pendingAliases: Map<string, Promise<AliasResult>>;\n\tprivate aliasResult: Promise<AliasResult> | undefined;\n\n\t/**\n\t * {@inheritDoc @fluidframework/runtime-definitions#IDataStore.trySetAlias}\n\t */\n\tasync trySetAlias(alias: string): Promise<AliasResult> {\n\t\tif (alias.includes(\"/\")) {\n\t\t\tthrow new UsageError(`The alias cannot contain slashes: '${alias}'`);\n\t\t}\n\n\t\tswitch (this.aliasState) {\n\t\t\t// If we're already aliasing, check if it's for the same value and return\n\t\t\t// the stored promise, otherwise return 'AlreadyAliased'\n\t\t\tcase AliasState.Aliasing:\n\t\t\t\tassert(\n\t\t\t\t\tthis.aliasResult !== undefined,\n\t\t\t\t\t0x316 /* There should be a cached promise of in-progress aliasing */,\n\t\t\t\t);\n\t\t\t\tawait this.aliasResult;\n\t\t\t\treturn this.alias === alias ? \"Success\" : \"AlreadyAliased\";\n\n\t\t\t// If this datastore is already aliased, return true only if this\n\t\t\t// is a repeated call for the same alias\n\t\t\tcase AliasState.Aliased:\n\t\t\t\treturn this.alias === alias ? \"Success\" : \"AlreadyAliased\";\n\n\t\t\tcase AliasState.None: {\n\t\t\t\tconst existingAlias = this.pendingAliases.get(alias);\n\t\t\t\tif (existingAlias !== undefined) {\n\t\t\t\t\t// There is already another datastore which will be aliased\n\t\t\t\t\t// to the same name\n\t\t\t\t\treturn \"Conflict\";\n\t\t\t\t}\n\n\t\t\t\t// There is no current or past alias operation for this datastore,\n\t\t\t\t// or for this alias, so it is safe to continue execution\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tunreachableCase(this.aliasState);\n\t\t}\n\n\t\tthis.aliasState = AliasState.Aliasing;\n\t\tthis.aliasResult = this.trySetAliasInternal(alias);\n\t\tthis.pendingAliases.set(alias, this.aliasResult);\n\t\treturn this.aliasResult;\n\t}\n\n\tasync trySetAliasInternal(alias: string): Promise<AliasResult> {\n\t\tconst message: IDataStoreAliasMessage = {\n\t\t\tinternalId: this.internalId,\n\t\t\talias,\n\t\t};\n\n\t\tthis.fluidDataStoreChannel.makeVisibleAndAttachGraph();\n\n\t\tif (this.runtime.attachState === AttachState.Detached) {\n\t\t\tconst localResult = this.datastores.processAliasMessageCore(message);\n\t\t\t// Explicitly lock-out future attempts of aliasing,\n\t\t\t// regardless of result\n\t\t\tthis.aliasState = AliasState.Aliased;\n\t\t\treturn localResult ? \"Success\" : \"Conflict\";\n\t\t}\n\n\t\tconst aliased = await this.ackBasedPromise<boolean>((resolve) => {\n\t\t\tthis.runtime.submitDataStoreAliasOp(message, resolve);\n\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tthis.logger.sendErrorEvent(\n\t\t\t\t\t{\n\t\t\t\t\t\teventName: \"AliasingException\",\n\t\t\t\t\t\talias: {\n\t\t\t\t\t\t\tvalue: alias,\n\t\t\t\t\t\t\ttag: TelemetryDataTag.UserData,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tinternalId: {\n\t\t\t\t\t\t\tvalue: this.internalId,\n\t\t\t\t\t\t\ttag: TelemetryDataTag.CodeArtifact,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\terror,\n\t\t\t\t);\n\n\t\t\t\treturn false;\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tthis.pendingAliases.delete(alias);\n\t\t\t});\n\n\t\tif (!aliased) {\n\t\t\tthis.aliasState = AliasState.None;\n\t\t\tthis.aliasResult = undefined;\n\t\t\treturn \"Conflict\";\n\t\t}\n\n\t\tthis.alias = alias;\n\t\tthis.aliasState = AliasState.Aliased;\n\t\treturn \"Success\";\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/runtime-definitions#IDataStore.entryPoint}\n\t */\n\tget entryPoint(): IFluidHandle<FluidObject> {\n\t\treturn this.fluidDataStoreChannel.entryPoint;\n\t}\n\n\tconstructor(\n\t\tprivate readonly fluidDataStoreChannel: IFluidDataStoreChannel,\n\t\tprivate readonly internalId: string,\n\t\tprivate readonly runtime: ContainerRuntime,\n\t\tprivate readonly datastores: DataStores,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t) {\n\t\tthis.pendingAliases = datastores.pendingAliases;\n\t}\n\n\tprivate async ackBasedPromise<T>(\n\t\texecutor: (\n\t\t\tresolve: (value: T | PromiseLike<T>) => void,\n\t\t\treject: (reason?: any) => void,\n\t\t) => void,\n\t): Promise<T> {\n\t\tlet rejectBecauseDispose: () => void;\n\t\treturn new Promise<T>((resolve, reject) => {\n\t\t\trejectBecauseDispose = () =>\n\t\t\t\treject(\n\t\t\t\t\tnew Error(\"ContainerRuntime disposed while this ack-based Promise was pending\"),\n\t\t\t\t);\n\n\t\t\tif (this.runtime.disposed) {\n\t\t\t\trejectBecauseDispose();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.runtime.on(\"dispose\", rejectBecauseDispose);\n\t\t\texecutor(resolve, reject);\n\t\t}).finally(() => {\n\t\t\tthis.runtime.off(\"dispose\", rejectBecauseDispose);\n\t\t});\n\t}\n}\n"]}
@@ -60,30 +60,26 @@ export declare class GarbageCollector implements IGarbageCollector {
60
60
  private readonly getNodePackagePath;
61
61
  /** Returns the timestamp of the last summary generated for this container. */
62
62
  private readonly getLastSummaryTimestampMs;
63
- /** Returns true if connection is active, i.e. it's "write" connection and the runtime is connected. */
64
- private readonly activeConnection;
65
63
  private readonly submitMessage;
66
64
  get summaryStateNeedsReset(): boolean;
67
65
  /** Returns the count of data stores whose GC state updated since the last summary. */
68
66
  get updatedDSCountSinceLastSummary(): number;
69
67
  protected constructor(createParams: IGarbageCollectorCreateParams);
70
68
  /**
71
- * Called during container initialization. Initialize from the tombstone state in the base snapshot. This is done
72
- * during initialization so that deleted or tombstoned objects are marked as such before they are loaded or used.
69
+ * Called during container initialization. Initializes the tombstone and deleted nodes state from the base snapshot.
70
+ * Also, initializes the GC state including unreferenced nodes tracking if a current reference timestamp exists.
71
+ * Note that if there is any GC state in the base snapshot, then there will definitely be a reference timestamp
72
+ * to work with - The GC state would have been generated using a timestamp which is part of the snapshot.
73
73
  */
74
74
  initializeBaseState(): Promise<void>;
75
75
  /**
76
- * Update state from the given snapshot data. This is done during load and during refreshing state from a snapshot.
77
- * All current tracking is reset and updated from the data in the snapshot.
78
- * @param snapshotData - The snapshot data to update state from. If this is undefined, all GC state and tracking
79
- * is reset.
80
- * @param currentReferenceTimestampMs - The current reference timestamp for marking unreferenced nodes' unreferenced
81
- * timestamp.
76
+ * Initialize the GC state if not already initialized. If GC state is already initialized, update the unreferenced
77
+ * state tracking as per the current reference timestamp.
82
78
  */
83
- private updateStateFromSnapshotData;
79
+ private initializeOrUpdateGCState;
84
80
  /**
85
81
  * Called when the connection state of the runtime changes, i.e., it connects or disconnects. GC subscribes to this
86
- * to initialize the base state for non-summarizer clients so that they can track inactive / sweep-ready nodes.
82
+ * to initialize or update the unreference state tracking.
87
83
  * @param connected - Whether the runtime connected / disconnected.
88
84
  * @param clientId - The clientId of this runtime.
89
85
  */
@@ -1 +1 @@
1
- {"version":3,"file":"garbageCollection.d.ts","sourceRoot":"","sources":["../../src/gc/garbageCollection.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"garbageCollection.d.ts","sourceRoot":"","sources":["../../src/gc/garbageCollection.ts"],"names":[],"mappings":"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"}
@@ -2,10 +2,11 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- import { LazyPromise, Timer } from "@fluidframework/core-utils";
5
+ import { assert, LazyPromise, Timer } from "@fluidframework/core-utils";
6
6
  import { gcTreeKey, } from "@fluidframework/runtime-definitions";
7
7
  import { createResponseError, responseToException } from "@fluidframework/runtime-utils";
8
8
  import { createChildLogger, createChildMonitoringContext, DataProcessingError, PerformanceEvent, } from "@fluidframework/telemetry-utils";
9
+ import { BlobManager } from "../blobManager";
9
10
  import { InactiveResponseHeaderKey, TombstoneResponseHeaderKey, } from "../containerRuntime";
10
11
  import { ClientSessionExpiredError } from "../error";
11
12
  import { ContainerMessageType } from "../messageTypes";
@@ -80,7 +81,6 @@ export class GarbageCollector {
80
81
  this.isSummarizerClient = createParams.isSummarizerClient;
81
82
  this.getNodePackagePath = createParams.getNodePackagePath;
82
83
  this.getLastSummaryTimestampMs = createParams.getLastSummaryTimestampMs;
83
- this.activeConnection = createParams.activeConnection;
84
84
  this.submitMessage = createParams.submitMessage;
85
85
  const baseSnapshot = createParams.baseSnapshot;
86
86
  const readAndParseBlob = createParams.readAndParseBlob;
@@ -141,28 +141,14 @@ export class GarbageCollector {
141
141
  }
142
142
  });
143
143
  /**
144
- * Set up the initializer which initializes the GC state from the data in base snapshot. This is done when
145
- * connected in write mode or when GC runs the first time. It sets up all unreferenced nodes from the base
146
- * GC state and updates their inactive or sweep-ready state.
144
+ * Set up the initializer which initializes the GC state from the data in base snapshot. It sets up GC data
145
+ * from the base GC state and starts tracking the state of unreferenced nodes.
146
+ *
147
+ * Must only be called if there is a current reference timestamp.
147
148
  */
148
149
  this.initializeGCStateFromBaseSnapshotP = new LazyPromise(async () => {
149
- /**
150
- * If there is no current reference timestamp, skip initialization. We need the current timestamp to track
151
- * how long objects have been unreferenced and if they can be deleted.
152
- *
153
- * Note that the only scenario where there is no reference timestamp is when no ops have ever been processed
154
- * for this container and it is in read mode. In this scenario, there is no point in running GC anyway
155
- * because references in the container do not change without any ops, i.e., there is nothing to collect.
156
- */
157
150
  const currentReferenceTimestampMs = this.runtime.getCurrentReferenceTimestampMs();
158
- if (currentReferenceTimestampMs === undefined) {
159
- // Log an event so we can evaluate how often we run into this scenario.
160
- this.mc.logger.sendErrorEvent({
161
- eventName: "GarbageCollectorInitializedWithoutTimestamp",
162
- gcConfigs: JSON.stringify(this.configs),
163
- });
164
- return;
165
- }
151
+ assert(currentReferenceTimestampMs !== undefined, "Trying to initialize GC state without current timestamp");
166
152
  /**
167
153
  * The base snapshot data will not be present if the container is loaded from:
168
154
  * 1. The first summary created by the detached container.
@@ -170,11 +156,20 @@ export class GarbageCollector {
170
156
  * 3. A summary that was generated before GC even existed.
171
157
  */
172
158
  const baseSnapshotData = await this.baseSnapshotDataP;
173
- if (baseSnapshotData === undefined) {
159
+ this.summaryStateTracker.initializeBaseState(baseSnapshotData);
160
+ if (baseSnapshotData?.gcState === undefined) {
174
161
  return;
175
162
  }
176
- this.updateStateFromSnapshotData(baseSnapshotData, currentReferenceTimestampMs);
177
- this.summaryStateTracker.initializeBaseState(baseSnapshotData);
163
+ // Update unreferenced state tracking as per the GC state in the snapshot data and update gcDataFromLastRun
164
+ // to the GC data from the snapshot data.
165
+ const gcNodes = {};
166
+ for (const [nodeId, nodeData] of Object.entries(baseSnapshotData.gcState.gcNodes)) {
167
+ if (nodeData.unreferencedTimestampMs !== undefined) {
168
+ this.unreferencedNodesState.set(nodeId, new UnreferencedStateTracker(nodeData.unreferencedTimestampMs, this.configs.inactiveTimeoutMs, currentReferenceTimestampMs, this.configs.sweepTimeoutMs, this.configs.sweepGracePeriodMs));
169
+ }
170
+ gcNodes[nodeId] = Array.from(nodeData.outboundRoutes);
171
+ }
172
+ this.gcDataFromLastRun = { gcNodes };
178
173
  });
179
174
  // Get the GC details from the GC state in the base summary. This is returned in getBaseGCDetails which is
180
175
  // used to initialize the GC state of all the nodes in the container.
@@ -203,8 +198,10 @@ export class GarbageCollector {
203
198
  });
204
199
  }
205
200
  /**
206
- * Called during container initialization. Initialize from the tombstone state in the base snapshot. This is done
207
- * during initialization so that deleted or tombstoned objects are marked as such before they are loaded or used.
201
+ * Called during container initialization. Initializes the tombstone and deleted nodes state from the base snapshot.
202
+ * Also, initializes the GC state including unreferenced nodes tracking if a current reference timestamp exists.
203
+ * Note that if there is any GC state in the base snapshot, then there will definitely be a reference timestamp
204
+ * to work with - The GC state would have been generated using a timestamp which is part of the snapshot.
208
205
  */
209
206
  async initializeBaseState() {
210
207
  const baseSnapshotData = await this.baseSnapshotDataP;
@@ -229,98 +226,51 @@ export class GarbageCollector {
229
226
  this.tombstones = Array.from(baseSnapshotData.tombstones);
230
227
  this.runtime.updateTombstonedRoutes(this.tombstones);
231
228
  }
229
+ await this.initializeOrUpdateGCState();
232
230
  }
233
231
  /**
234
- * Update state from the given snapshot data. This is done during load and during refreshing state from a snapshot.
235
- * All current tracking is reset and updated from the data in the snapshot.
236
- * @param snapshotData - The snapshot data to update state from. If this is undefined, all GC state and tracking
237
- * is reset.
238
- * @param currentReferenceTimestampMs - The current reference timestamp for marking unreferenced nodes' unreferenced
239
- * timestamp.
232
+ * Initialize the GC state if not already initialized. If GC state is already initialized, update the unreferenced
233
+ * state tracking as per the current reference timestamp.
240
234
  */
241
- updateStateFromSnapshotData(snapshotData, currentReferenceTimestampMs) {
242
- /**
243
- * Note: "newReferencesSinceLastRun" is not reset here. This is done because there may be references since the
244
- * snapshot that we are updating state from. For example, this client may have processed ops till seq#1000 and
245
- * its refreshing state from a summary that happened at seq#900. In this case, there may be references between
246
- * seq#901 and seq#1000 that we don't want to reset.
247
- * Unfortunately, there is no way to track the seq# of ops that add references, so we choose to not reset any
248
- * references here. This should be fine because, in the worst case, we may end up updating the unreferenced
249
- * timestamp of a node which will delay its deletion. Although not ideal, this will only happen in rare
250
- * scenarios, so it should be okay.
251
- */
252
- // Clear all existing unreferenced state tracking.
253
- for (const [, nodeStateTracker] of this.unreferencedNodesState) {
254
- nodeStateTracker.stopTracking();
255
- }
256
- this.unreferencedNodesState.clear();
257
- // If running sweep, the tombstone state represents the list of nodes that have been deleted during sweep.
258
- // If running in tombstone mode, the tombstone state represents the list of nodes that have been marked as
259
- // tombstones.
260
- // If this call is because we are refreshing from a snapshot due to an ack, it is likely that the GC state
261
- // in the snapshot is newer than this client's. And so, the deleted / tombstone nodes need to be updated.
262
- if (this.configs.shouldRunSweep) {
263
- const snapshotDeletedNodes = snapshotData?.deletedNodes
264
- ? new Set(snapshotData.deletedNodes)
265
- : undefined;
266
- // If the snapshot contains deleted nodes that are not yet deleted by this client, ask the runtime to
267
- // delete them.
268
- if (snapshotDeletedNodes !== undefined) {
269
- const newDeletedNodes = [];
270
- for (const nodeId of snapshotDeletedNodes) {
271
- if (!this.deletedNodes.has(nodeId)) {
272
- newDeletedNodes.push(nodeId);
273
- }
274
- }
275
- if (newDeletedNodes.length > 0) {
276
- // Call container runtime to delete these nodes and add deleted nodes to this.deletedNodes.
277
- }
278
- }
279
- }
280
- else if (this.configs.tombstoneMode) {
281
- // The snapshot may contain more or fewer tombstone nodes than this client. Update tombstone state and
282
- // notify the runtime to update its state as well.
283
- this.tombstones = snapshotData?.tombstones ? Array.from(snapshotData.tombstones) : [];
284
- this.runtime.updateTombstonedRoutes(this.tombstones);
235
+ async initializeOrUpdateGCState() {
236
+ const currentReferenceTimestampMs = this.runtime.getCurrentReferenceTimestampMs();
237
+ if (currentReferenceTimestampMs === undefined) {
238
+ return;
285
239
  }
286
- // If there is no snapshot data, it means this snapshot was generated with GC disabled. Unset all GC state.
287
- if (snapshotData?.gcState === undefined) {
288
- this.gcDataFromLastRun = undefined;
240
+ // If the GC state hasn't been initialized yet, initialize it and return.
241
+ if (this.gcDataFromLastRun === undefined) {
242
+ await this.initializeGCStateFromBaseSnapshotP;
289
243
  return;
290
244
  }
291
- // Update unreferenced state tracking as per the GC state in the snapshot data and update gcDataFromLastRun
292
- // to the GC data from the snapshot data.
293
- const gcNodes = {};
294
- for (const [nodeId, nodeData] of Object.entries(snapshotData.gcState.gcNodes)) {
295
- if (nodeData.unreferencedTimestampMs !== undefined) {
296
- this.unreferencedNodesState.set(nodeId, new UnreferencedStateTracker(nodeData.unreferencedTimestampMs, this.configs.inactiveTimeoutMs, currentReferenceTimestampMs, this.configs.sweepTimeoutMs, this.configs.sweepGracePeriodMs));
297
- }
298
- gcNodes[nodeId] = Array.from(nodeData.outboundRoutes);
245
+ // If the GC state has been initialized, update the tracking of unreferenced nodes as per the current
246
+ // reference timestamp.
247
+ for (const [, nodeStateTracker] of this.unreferencedNodesState) {
248
+ nodeStateTracker.updateTracking(currentReferenceTimestampMs);
299
249
  }
300
- this.gcDataFromLastRun = { gcNodes };
301
250
  }
302
251
  /**
303
252
  * Called when the connection state of the runtime changes, i.e., it connects or disconnects. GC subscribes to this
304
- * to initialize the base state for non-summarizer clients so that they can track inactive / sweep-ready nodes.
253
+ * to initialize or update the unreference state tracking.
305
254
  * @param connected - Whether the runtime connected / disconnected.
306
255
  * @param clientId - The clientId of this runtime.
307
256
  */
308
257
  setConnectionState(connected, clientId) {
309
258
  /**
310
- * For all clients, initialize the base state when the container becomes active, i.e., it transitions
311
- * to "write" mode. This will ensure that the container's own join op is processed and there is a recent
312
- * reference timestamp that will be used to update the state of unreferenced nodes. Also, all trailing ops which
313
- * could affect the GC state will have been processed.
259
+ * When the client connects (or reconnects), attempt to initialize or update the GC state. This will keep
260
+ * the unreferenced state tracking updated as per the reference timestamp at the time of connection.
314
261
  *
315
- * If GC is up-to-date for the client and the summarizing client, there will be an doubling of both
316
- * InactiveObject_Loaded and SweepReady_Loaded errors, as there will be one from the sending client and one from
317
- * the receiving summarizer client.
318
- *
319
- * Ideally, this initialization should only be done for summarizer client. However, we are currently rolling out
320
- * sweep in phases and we want to track when inactive and sweep-ready objects are used in any client.
262
+ * During GC initialization and during connections in read mode, it is possible that either no ops are
263
+ * processed or only trailing ops are processed. This means that the GC state is not initialized or initialized
264
+ * with an older reference timestamp. So, doing this on every connection will keep the unreferenced state
265
+ * tracking up-to-date.
321
266
  */
322
- if (this.activeConnection() && this.configs.shouldRunGC) {
323
- this.initializeGCStateFromBaseSnapshotP.catch((error) => { });
267
+ if (connected && this.configs.shouldRunGC) {
268
+ this.initializeOrUpdateGCState().catch((error) => {
269
+ this.mc.logger.sendErrorEvent({
270
+ eventName: "GCInitializationOrUpdateFailed",
271
+ gcConfigs: JSON.stringify(this.configs),
272
+ }, error);
273
+ });
324
274
  }
325
275
  }
326
276
  /**
@@ -377,8 +327,11 @@ export class GarbageCollector {
377
327
  const gcStats = await this.runGC(fullGC, currentReferenceTimestampMs, logger);
378
328
  event.end({
379
329
  ...gcStats,
380
- timestamp: currentReferenceTimestampMs,
381
- sweep: this.configs.shouldRunSweep,
330
+ details: {
331
+ timestamp: currentReferenceTimestampMs,
332
+ sweep: this.configs.shouldRunSweep,
333
+ tombstone: this.configs.throwOnTombstoneLoad,
334
+ },
382
335
  });
383
336
  /** Post-GC steps */
384
337
  // Log pending unreferenced events such as a node being used after inactive. This is done after GC runs and
@@ -871,9 +824,24 @@ export class GarbageCollector {
871
824
  deletedDataStoreCount: 0,
872
825
  deletedAttachmentBlobCount: 0,
873
826
  };
827
+ // The runtime can't reliably identify the type of deleted nodes. So, get the type here. This should
828
+ // be good enough because the only types that participate in GC today are data stores, DDSes and blobs.
829
+ const getDeletedNodeType = (nodeId) => {
830
+ const pathParts = nodeId.split("/");
831
+ if (pathParts[1] === BlobManager.basePath) {
832
+ return GCNodeType.Blob;
833
+ }
834
+ if (pathParts.length === 2) {
835
+ return GCNodeType.DataStore;
836
+ }
837
+ if (pathParts.length === 3) {
838
+ return GCNodeType.SubDataStore;
839
+ }
840
+ return GCNodeType.Other;
841
+ };
874
842
  for (const nodeId of deletedNodes) {
875
843
  sweepPhaseStats.deletedNodeCount++;
876
- const nodeType = this.runtime.getNodeType(nodeId);
844
+ const nodeType = getDeletedNodeType(nodeId);
877
845
  if (nodeType === GCNodeType.DataStore) {
878
846
  sweepPhaseStats.deletedDataStoreCount++;
879
847
  }