@fluidframework/container-runtime 0.59.4002 → 1.0.2

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 (137) hide show
  1. package/.eslintrc.js +1 -1
  2. package/dist/blobManager.d.ts +2 -2
  3. package/dist/blobManager.d.ts.map +1 -1
  4. package/dist/blobManager.js +12 -11
  5. package/dist/blobManager.js.map +1 -1
  6. package/dist/connectionTelemetry.js +3 -3
  7. package/dist/connectionTelemetry.js.map +1 -1
  8. package/dist/containerRuntime.d.ts +125 -29
  9. package/dist/containerRuntime.d.ts.map +1 -1
  10. package/dist/containerRuntime.js +242 -110
  11. package/dist/containerRuntime.js.map +1 -1
  12. package/dist/dataStoreContext.d.ts +4 -2
  13. package/dist/dataStoreContext.d.ts.map +1 -1
  14. package/dist/dataStoreContext.js +16 -5
  15. package/dist/dataStoreContext.js.map +1 -1
  16. package/dist/dataStores.d.ts +4 -3
  17. package/dist/dataStores.d.ts.map +1 -1
  18. package/dist/dataStores.js +9 -3
  19. package/dist/dataStores.js.map +1 -1
  20. package/dist/garbageCollection.d.ts +3 -3
  21. package/dist/garbageCollection.d.ts.map +1 -1
  22. package/dist/garbageCollection.js +10 -8
  23. package/dist/garbageCollection.js.map +1 -1
  24. package/dist/index.d.ts +2 -2
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +2 -1
  27. package/dist/index.js.map +1 -1
  28. package/dist/orderedClientElection.js +0 -4
  29. package/dist/orderedClientElection.js.map +1 -1
  30. package/dist/packageVersion.d.ts +1 -1
  31. package/dist/packageVersion.d.ts.map +1 -1
  32. package/dist/packageVersion.js +1 -1
  33. package/dist/packageVersion.js.map +1 -1
  34. package/dist/pendingStateManager.d.ts +30 -29
  35. package/dist/pendingStateManager.d.ts.map +1 -1
  36. package/dist/pendingStateManager.js +72 -109
  37. package/dist/pendingStateManager.js.map +1 -1
  38. package/dist/runningSummarizer.d.ts +4 -3
  39. package/dist/runningSummarizer.d.ts.map +1 -1
  40. package/dist/runningSummarizer.js +11 -6
  41. package/dist/runningSummarizer.js.map +1 -1
  42. package/dist/serializedSnapshotStorage.d.ts +58 -0
  43. package/dist/serializedSnapshotStorage.d.ts.map +1 -0
  44. package/dist/serializedSnapshotStorage.js +108 -0
  45. package/dist/serializedSnapshotStorage.js.map +1 -0
  46. package/dist/summarizer.d.ts +11 -4
  47. package/dist/summarizer.d.ts.map +1 -1
  48. package/dist/summarizer.js +18 -9
  49. package/dist/summarizer.js.map +1 -1
  50. package/dist/summarizerHeuristics.d.ts +5 -3
  51. package/dist/summarizerHeuristics.d.ts.map +1 -1
  52. package/dist/summarizerHeuristics.js +10 -3
  53. package/dist/summarizerHeuristics.js.map +1 -1
  54. package/dist/summarizerTypes.d.ts +4 -2
  55. package/dist/summarizerTypes.d.ts.map +1 -1
  56. package/dist/summarizerTypes.js.map +1 -1
  57. package/dist/summaryManager.d.ts +3 -3
  58. package/dist/summaryManager.d.ts.map +1 -1
  59. package/dist/summaryManager.js +7 -7
  60. package/dist/summaryManager.js.map +1 -1
  61. package/garbageCollection.md +9 -1
  62. package/lib/blobManager.d.ts +2 -2
  63. package/lib/blobManager.d.ts.map +1 -1
  64. package/lib/blobManager.js +12 -11
  65. package/lib/blobManager.js.map +1 -1
  66. package/lib/connectionTelemetry.js +3 -3
  67. package/lib/connectionTelemetry.js.map +1 -1
  68. package/lib/containerRuntime.d.ts +125 -29
  69. package/lib/containerRuntime.d.ts.map +1 -1
  70. package/lib/containerRuntime.js +243 -111
  71. package/lib/containerRuntime.js.map +1 -1
  72. package/lib/dataStoreContext.d.ts +4 -2
  73. package/lib/dataStoreContext.d.ts.map +1 -1
  74. package/lib/dataStoreContext.js +16 -5
  75. package/lib/dataStoreContext.js.map +1 -1
  76. package/lib/dataStores.d.ts +4 -3
  77. package/lib/dataStores.d.ts.map +1 -1
  78. package/lib/dataStores.js +9 -3
  79. package/lib/dataStores.js.map +1 -1
  80. package/lib/garbageCollection.d.ts +3 -3
  81. package/lib/garbageCollection.d.ts.map +1 -1
  82. package/lib/garbageCollection.js +10 -8
  83. package/lib/garbageCollection.js.map +1 -1
  84. package/lib/index.d.ts +2 -2
  85. package/lib/index.d.ts.map +1 -1
  86. package/lib/index.js +1 -1
  87. package/lib/index.js.map +1 -1
  88. package/lib/orderedClientElection.js +0 -4
  89. package/lib/orderedClientElection.js.map +1 -1
  90. package/lib/packageVersion.d.ts +1 -1
  91. package/lib/packageVersion.d.ts.map +1 -1
  92. package/lib/packageVersion.js +1 -1
  93. package/lib/packageVersion.js.map +1 -1
  94. package/lib/pendingStateManager.d.ts +30 -29
  95. package/lib/pendingStateManager.d.ts.map +1 -1
  96. package/lib/pendingStateManager.js +72 -109
  97. package/lib/pendingStateManager.js.map +1 -1
  98. package/lib/runningSummarizer.d.ts +4 -3
  99. package/lib/runningSummarizer.d.ts.map +1 -1
  100. package/lib/runningSummarizer.js +11 -6
  101. package/lib/runningSummarizer.js.map +1 -1
  102. package/lib/serializedSnapshotStorage.d.ts +58 -0
  103. package/lib/serializedSnapshotStorage.d.ts.map +1 -0
  104. package/lib/serializedSnapshotStorage.js +104 -0
  105. package/lib/serializedSnapshotStorage.js.map +1 -0
  106. package/lib/summarizer.d.ts +11 -4
  107. package/lib/summarizer.d.ts.map +1 -1
  108. package/lib/summarizer.js +18 -9
  109. package/lib/summarizer.js.map +1 -1
  110. package/lib/summarizerHeuristics.d.ts +5 -3
  111. package/lib/summarizerHeuristics.d.ts.map +1 -1
  112. package/lib/summarizerHeuristics.js +10 -3
  113. package/lib/summarizerHeuristics.js.map +1 -1
  114. package/lib/summarizerTypes.d.ts +4 -2
  115. package/lib/summarizerTypes.d.ts.map +1 -1
  116. package/lib/summarizerTypes.js.map +1 -1
  117. package/lib/summaryManager.d.ts +3 -3
  118. package/lib/summaryManager.d.ts.map +1 -1
  119. package/lib/summaryManager.js +7 -7
  120. package/lib/summaryManager.js.map +1 -1
  121. package/package.json +46 -31
  122. package/src/blobManager.ts +29 -15
  123. package/src/connectionTelemetry.ts +3 -3
  124. package/src/containerRuntime.ts +388 -135
  125. package/src/dataStoreContext.ts +27 -5
  126. package/src/dataStores.ts +15 -3
  127. package/src/garbageCollection.ts +21 -14
  128. package/src/index.ts +7 -1
  129. package/src/orderedClientElection.ts +1 -1
  130. package/src/packageVersion.ts +1 -1
  131. package/src/pendingStateManager.ts +104 -123
  132. package/src/runningSummarizer.ts +20 -10
  133. package/src/serializedSnapshotStorage.ts +146 -0
  134. package/src/summarizer.ts +20 -16
  135. package/src/summarizerHeuristics.ts +21 -5
  136. package/src/summarizerTypes.ts +4 -2
  137. package/src/summaryManager.ts +5 -6
package/.eslintrc.js CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  module.exports = {
7
7
  "extends": [
8
- "@fluidframework/eslint-config-fluid"
8
+ require.resolve("@fluidframework/eslint-config-fluid")
9
9
  ],
10
10
  "parserOptions": {
11
11
  "project": ["./tsconfig.json", "./src/test/tsconfig.json"]
@@ -7,7 +7,7 @@ import { IDocumentStorageService } from "@fluidframework/driver-definitions";
7
7
  import { ISnapshotTree } from "@fluidframework/protocol-definitions";
8
8
  import { ITelemetryLogger } from "@fluidframework/common-definitions";
9
9
  import { IContainerRuntime } from "@fluidframework/container-runtime-definitions";
10
- import { IGarbageCollectionData, ISummaryTreeWithStats } from "@fluidframework/runtime-definitions";
10
+ import { IGarbageCollectionData, ISummaryTreeWithStats, ITelemetryContext } from "@fluidframework/runtime-definitions";
11
11
  /**
12
12
  * This class represents blob (long string)
13
13
  * This object is used only when creating (writing) new blob and serialization purposes.
@@ -89,7 +89,7 @@ export declare class BlobManager {
89
89
  * @param unusedRoutes - These are the blob node ids that are unused and should be deleted.
90
90
  */
91
91
  deleteUnusedRoutes(unusedRoutes: string[]): void;
92
- summarize(): ISummaryTreeWithStats;
92
+ summarize(telemetryContext?: ITelemetryContext): ISummaryTreeWithStats;
93
93
  setRedirectTable(table: Map<string, string>): void;
94
94
  }
95
95
  //# sourceMappingURL=blobManager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"blobManager.d.ts","sourceRoot":"","sources":["../src/blobManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"blobManager.d.ts","sourceRoot":"","sources":["../src/blobManager.ts"],"names":[],"mappings":"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"}
@@ -8,6 +8,7 @@ exports.BlobManager = exports.BlobHandle = void 0;
8
8
  const runtime_utils_1 = require("@fluidframework/runtime-utils");
9
9
  const common_utils_1 = require("@fluidframework/common-utils");
10
10
  const container_definitions_1 = require("@fluidframework/container-definitions");
11
+ const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
11
12
  /**
12
13
  * This class represents blob (long string)
13
14
  * This object is used only when creating (writing) new blob and serialization purposes.
@@ -77,15 +78,9 @@ class BlobManager {
77
78
  (0, common_utils_1.assert)(this.hasBlob(storageId), 0x11f /* "requesting unknown blobs" */);
78
79
  // When this blob is retrieved, let the container runtime know that the corresponding GC node got updated.
79
80
  this.gcNodeUpdated(this.getBlobGCNodePath(blobId));
80
- return new BlobHandle(`${BlobManager.basePath}/${storageId}`, this.routeContext, async () => {
81
- return this.getStorage().readBlob(storageId).catch((error) => {
82
- this.logger.sendErrorEvent({
83
- eventName: "AttachmentReadBlobError",
84
- id: storageId,
85
- }, error);
86
- throw error;
87
- });
88
- });
81
+ return new BlobHandle(`${BlobManager.basePath}/${storageId}`, this.routeContext, async () => telemetry_utils_1.PerformanceEvent.timedExecAsync(this.logger, { eventName: "AttachmentReadBlob", id: storageId }, async () => {
82
+ return this.getStorage().readBlob(storageId);
83
+ }, { end: true, cancel: "error" }));
89
84
  }
90
85
  async createBlob(blob) {
91
86
  var _a, _b;
@@ -94,7 +89,13 @@ class BlobManager {
94
89
  this.logger.sendTelemetryEvent({ eventName: "CreateBlobWhileAttaching" });
95
90
  await new Promise((resolve) => this.runtime.once("attached", resolve));
96
91
  }
97
- const response = await this.getStorage().createBlob(blob);
92
+ if (!this.runtime.connected && this.runtime.attachState === container_definitions_1.AttachState.Attached) {
93
+ // see https://github.com/microsoft/FluidFramework/issues/8246
94
+ // Avoid getting storage if we are offline since it might be undefined. In the future we will return
95
+ // handles immediately while offline
96
+ await new Promise((resolve) => this.runtime.once("connected", resolve));
97
+ }
98
+ const response = await telemetry_utils_1.PerformanceEvent.timedExecAsync(this.logger, { eventName: "createBlob" }, async () => this.getStorage().createBlob(blob), { end: true, cancel: "error" });
98
99
  const handle = new BlobHandle(`${BlobManager.basePath}/${response.id}`, this.routeContext,
99
100
  // get() should go through BlobManager.getBlob() so handles created while detached can be redirected
100
101
  // to the correct storage id after they are uploaded
@@ -217,7 +218,7 @@ class BlobManager {
217
218
  this.blobIds.delete(blobId);
218
219
  }
219
220
  }
220
- summarize() {
221
+ summarize(telemetryContext) {
221
222
  // If we have a redirect table it means the container is about to transition to "Attaching" state, so we need
222
223
  // to return an actual snapshot containing all the real storage IDs we know about.
223
224
  const attachingOrAttached = !!this.redirectTable || this.runtime.attachState !== container_definitions_1.AttachState.Detached;
@@ -1 +1 @@
1
- {"version":3,"file":"blobManager.js","sourceRoot":"","sources":["../src/blobManager.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 { IFluidHandle, IFluidHandleContext } from \"@fluidframework/core-interfaces\";\nimport { IDocumentStorageService } from \"@fluidframework/driver-definitions\";\nimport { ISnapshotTree } from \"@fluidframework/protocol-definitions\";\nimport { generateHandleContextPath, SummaryTreeBuilder } from \"@fluidframework/runtime-utils\";\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { assert, Deferred } from \"@fluidframework/common-utils\";\nimport { IContainerRuntime } from \"@fluidframework/container-runtime-definitions\";\nimport { AttachState } from \"@fluidframework/container-definitions\";\nimport { IGarbageCollectionData, ISummaryTreeWithStats } from \"@fluidframework/runtime-definitions\";\n\n/**\n * This class represents blob (long string)\n * This object is used only when creating (writing) new blob and serialization purposes.\n * De-serialization process goes through FluidObjectHandle and request flow:\n * DataObject.request() recognizes requests in the form of `/blobs/<id>`\n * and loads blob.\n */\nexport class BlobHandle implements IFluidHandle<ArrayBufferLike> {\n private attached: boolean = false;\n\n public get IFluidHandle(): IFluidHandle { return this; }\n\n public get isAttached(): boolean {\n return this.attached;\n }\n\n public readonly absolutePath: string;\n\n constructor(\n public readonly path: string,\n public readonly routeContext: IFluidHandleContext,\n public get: () => Promise<any>,\n ) {\n this.absolutePath = generateHandleContextPath(path, this.routeContext);\n }\n\n public attachGraph() {\n this.attached = true;\n }\n\n public bind(handle: IFluidHandle) {\n throw new Error(\"Cannot bind to blob handle\");\n }\n}\n\n/**\n * Information from a snapshot needed to load BlobManager\n */\nexport interface IBlobManagerLoadInfo {\n ids?: string[];\n redirectTable?: [string, string][];\n}\n\nexport class BlobManager {\n public static readonly basePath = \"_blobs\";\n private static readonly redirectTableBlobName = \".redirectTable\";\n // uploaded blob IDs\n private readonly blobIds: Set<string> = new Set();\n // blobs for which upload is pending. maps to a promise that will resolve once the blob has been uploaded and a\n // BlobAttach op has round-tripped.\n private readonly pendingBlobIds: Map<string, Deferred<void>> = new Map();\n // blobs uploaded while detached; cleared upon attach\n private readonly detachedBlobIds: Set<string> = new Set();\n // map of detached blob IDs to IDs used by storage. used to support blob handles given out while detached\n private redirectTable: Map<string, string> | undefined;\n\n constructor(\n private readonly routeContext: IFluidHandleContext,\n snapshot: IBlobManagerLoadInfo,\n private readonly getStorage: () => IDocumentStorageService,\n private readonly attachBlobCallback: (blobId: string) => void,\n // To be called when a blob node is requested. blobPath is the path of the blob's node in GC's graph. It's\n // of the format `/<BlobManager.basePath>/<blobId>`.\n private readonly gcNodeUpdated: (blobPath: string) => void,\n private readonly runtime: IContainerRuntime,\n private readonly logger: ITelemetryLogger,\n ) {\n this.runtime.once(\"dispose\", () => {\n for (const promise of this.pendingBlobIds.values()) {\n promise.reject(new Error(\"runtime disposed while blobAttach op in flight\"));\n }\n });\n this.load(snapshot);\n }\n\n private hasBlob(id: string): boolean {\n return this.blobIds.has(id) || this.detachedBlobIds.has(id);\n }\n\n /**\n * For a blobId, returns its path in GC's graph. The node path is of the format `/<BlobManager.basePath>/<blobId>`\n * This path must match the path of the blob handle returned by the createBlob API because blobs are marked\n * referenced by storing these handles in a referenced DDS.\n */\n private getBlobGCNodePath(blobId: string) {\n return `/${BlobManager.basePath}/${blobId}`;\n }\n\n public async getBlob(blobId: string): Promise<IFluidHandle<ArrayBufferLike>> {\n const storageId = this.redirectTable?.get(blobId) ?? blobId;\n assert(this.hasBlob(storageId), 0x11f /* \"requesting unknown blobs\" */);\n\n // When this blob is retrieved, let the container runtime know that the corresponding GC node got updated.\n this.gcNodeUpdated(this.getBlobGCNodePath(blobId));\n\n return new BlobHandle(\n `${BlobManager.basePath}/${storageId}`,\n this.routeContext,\n async () => {\n return this.getStorage().readBlob(storageId).catch((error) => {\n this.logger.sendErrorEvent(\n {\n eventName: \"AttachmentReadBlobError\",\n id: storageId,\n },\n error,\n );\n throw error;\n });\n },\n );\n }\n\n public async createBlob(blob: ArrayBufferLike): Promise<IFluidHandle<ArrayBufferLike>> {\n if (this.runtime.attachState === AttachState.Attaching) {\n // blob upload is not supported in \"Attaching\" state\n this.logger.sendTelemetryEvent({ eventName: \"CreateBlobWhileAttaching\" });\n await new Promise<void>((resolve) => this.runtime.once(\"attached\", resolve));\n }\n\n const response = await this.getStorage().createBlob(blob);\n const handle = new BlobHandle(\n `${BlobManager.basePath}/${response.id}`,\n this.routeContext,\n // get() should go through BlobManager.getBlob() so handles created while detached can be redirected\n // to the correct storage id after they are uploaded\n async () => this.getBlob(response.id).then(async (h) => h.get()),\n );\n\n if (this.runtime.attachState === AttachState.Detached) {\n this.detachedBlobIds.add(response.id);\n return handle;\n }\n\n // Note - server will de-dup blobs, so we might get existing blobId!\n if (this.pendingBlobIds.has(response.id)) {\n await this.pendingBlobIds.get(response.id)?.promise;\n } else if (!this.blobIds.has(response.id)) {\n this.pendingBlobIds.set(response.id, new Deferred<void>());\n\n // send blob attach op and wait until we see it to return the handle\n this.attachBlobCallback(response.id);\n await this.pendingBlobIds.get(response.id)?.promise;\n }\n\n return handle;\n }\n\n public processBlobAttachOp(blobId: string, local: boolean) {\n if (local) {\n const pendingBlobP = this.pendingBlobIds.get(blobId);\n assert(pendingBlobP !== undefined, 0x1f8 /* \"local BlobAttach op with no pending blob\" */);\n pendingBlobP.resolve();\n this.pendingBlobIds.delete(blobId);\n }\n this.blobIds.add(blobId);\n }\n\n /**\n * Reads blobs needed to load BlobManager from storage.\n */\n public static async load(\n blobsTree: ISnapshotTree | undefined,\n tryFetchBlob: (id: string) => Promise<[string, string][]>,\n ): Promise<IBlobManagerLoadInfo> {\n if (!blobsTree) {\n return {};\n }\n let redirectTable;\n const tableId = blobsTree.blobs[this.redirectTableBlobName];\n if (tableId) {\n redirectTable = await tryFetchBlob(tableId);\n }\n const ids = Object.entries(blobsTree.blobs)\n .filter(([k, _]) => k !== this.redirectTableBlobName).map(([_, v]) => v);\n return { ids, redirectTable };\n }\n\n /**\n * Load a set of previously attached blob IDs from a previous snapshot. Note\n * that BlobManager tracking and reporting attached blobs is a temporary\n * solution since storage expects attached blobs to be reported and any that\n * are not reported as attached may be GCed. In the future attached blob\n * IDs will be collected at summarization time, and runtime will not care\n * about the existence or specific formatting of this tree in returned\n * snapshots.\n *\n * @param blobsTree - Tree containing IDs of previously attached blobs. This\n * corresponds to snapshot() below. We look for the IDs in the blob entries\n * of the tree since the both the r11s and SPO drivers replace the\n * attachment types returned in snapshot() with blobs.\n */\n private load(snapshot: IBlobManagerLoadInfo): void {\n if (snapshot.ids) {\n const detached = this.runtime.attachState === AttachState.Detached;\n snapshot.ids.map((entry) => detached ? this.detachedBlobIds.add(entry) : this.blobIds.add(entry));\n }\n if (snapshot.redirectTable) {\n this.redirectTable = new Map(snapshot.redirectTable);\n }\n this.logger.sendTelemetryEvent({\n eventName: \"AttachmentBlobsLoaded\",\n count: snapshot.ids?.length ?? 0,\n redirectTable: snapshot.redirectTable?.length,\n });\n }\n\n /**\n * Generates data used for garbage collection. Each blob uploaded represents a node in the GC graph as it can be\n * individually referenced by storing its handle in a referenced DDS. Returns the list of blob ids as GC nodes.\n * @param fullGC - true to bypass optimizations and force full generation of GC data. BlobManager doesn't care\n * about this for now because the data is a simple list of blob ids.\n */\n public getGCData(fullGC: boolean = false): IGarbageCollectionData {\n const gcData: IGarbageCollectionData = { gcNodes: {} };\n\n this.blobIds.forEach((blobId: string) => {\n gcData.gcNodes[this.getBlobGCNodePath(blobId)] = [];\n });\n\n /**\n * For all blobs in the redirect table, the handle returned on creation is based off of the localId. So, these\n * nodes can be referenced by storing the localId handle. When that happens, the corresponding storageId node\n * must also be marked referenced. So, we add a route from the localId node to the storageId node.\n * Note that because of de-duping, there can be multiple localIds that all redirect to the same storageId or\n * a blob may be referenced via its storageId handle.\n */\n if (this.redirectTable !== undefined) {\n for (const [localId, storageId] of this.redirectTable) {\n // Add node for the localId and add a route to the storageId node. The storageId node will have been\n // added above when adding nodes for this.blobIds.\n gcData.gcNodes[this.getBlobGCNodePath(localId)] = [this.getBlobGCNodePath(storageId)];\n }\n }\n\n return gcData;\n }\n\n /**\n * When running GC in test mode, this is called to delete blobs that are unused.\n * @param unusedRoutes - These are the blob node ids that are unused and should be deleted.\n */\n public deleteUnusedRoutes(unusedRoutes: string[]): void {\n // The routes or blob node paths are in the same format as returned in getGCData -\n // `/<BlobManager.basePath>/<blobId>`.\n for (const route of unusedRoutes) {\n const pathParts = route.split(\"/\");\n assert(\n pathParts.length === 3 && pathParts[1] === BlobManager.basePath,\n 0x2d5 /* \"Invalid blob node id in unused routes.\" */,\n );\n const blobId = pathParts[2];\n\n // The unused blobId could be a localId. If so, remove it from the redirect table and continue. The\n // corresponding storageId may still be used either directly or via other localIds.\n if (this.redirectTable?.has(blobId)) {\n this.redirectTable.delete(blobId);\n continue;\n }\n this.blobIds.delete(blobId);\n }\n }\n\n public summarize(): ISummaryTreeWithStats {\n // If we have a redirect table it means the container is about to transition to \"Attaching\" state, so we need\n // to return an actual snapshot containing all the real storage IDs we know about.\n const attachingOrAttached = !!this.redirectTable || this.runtime.attachState !== AttachState.Detached;\n const blobIds = attachingOrAttached ? this.blobIds : this.detachedBlobIds;\n const builder = new SummaryTreeBuilder();\n blobIds.forEach((blobId) => {\n builder.addAttachment(blobId);\n });\n\n if (this.redirectTable && this.redirectTable.size > 0) {\n builder.addBlob(\n BlobManager.redirectTableBlobName,\n JSON.stringify(Array.from(this.redirectTable.entries())),\n );\n }\n\n return builder.getSummaryTree();\n }\n\n public setRedirectTable(table: Map<string, string>) {\n assert(this.runtime.attachState === AttachState.Detached,\n 0x252 /* \"redirect table can only be set in detached container\" */);\n assert(!this.redirectTable, 0x253 /* \"redirect table already exists\" */);\n for (const [localId, storageId] of table) {\n assert(this.detachedBlobIds.delete(localId), 0x254 /* \"unrecognized id in redirect table\" */);\n this.blobIds.add(storageId);\n }\n assert(this.detachedBlobIds.size === 0, 0x255 /* \"detached blob id absent in redirect table\" */);\n this.redirectTable = table;\n }\n}\n"]}
1
+ {"version":3,"file":"blobManager.js","sourceRoot":"","sources":["../src/blobManager.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 { IFluidHandle, IFluidHandleContext } from \"@fluidframework/core-interfaces\";\nimport { IDocumentStorageService } from \"@fluidframework/driver-definitions\";\nimport { ISnapshotTree } from \"@fluidframework/protocol-definitions\";\nimport { generateHandleContextPath, SummaryTreeBuilder } from \"@fluidframework/runtime-utils\";\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { assert, Deferred } from \"@fluidframework/common-utils\";\nimport { IContainerRuntime } from \"@fluidframework/container-runtime-definitions\";\nimport { AttachState } from \"@fluidframework/container-definitions\";\nimport { PerformanceEvent } from \"@fluidframework/telemetry-utils\";\nimport {\n IGarbageCollectionData,\n ISummaryTreeWithStats,\n ITelemetryContext,\n} from \"@fluidframework/runtime-definitions\";\n\n/**\n * This class represents blob (long string)\n * This object is used only when creating (writing) new blob and serialization purposes.\n * De-serialization process goes through FluidObjectHandle and request flow:\n * DataObject.request() recognizes requests in the form of `/blobs/<id>`\n * and loads blob.\n */\nexport class BlobHandle implements IFluidHandle<ArrayBufferLike> {\n private attached: boolean = false;\n\n public get IFluidHandle(): IFluidHandle { return this; }\n\n public get isAttached(): boolean {\n return this.attached;\n }\n\n public readonly absolutePath: string;\n\n constructor(\n public readonly path: string,\n public readonly routeContext: IFluidHandleContext,\n public get: () => Promise<any>,\n ) {\n this.absolutePath = generateHandleContextPath(path, this.routeContext);\n }\n\n public attachGraph() {\n this.attached = true;\n }\n\n public bind(handle: IFluidHandle) {\n throw new Error(\"Cannot bind to blob handle\");\n }\n}\n\n/**\n * Information from a snapshot needed to load BlobManager\n */\nexport interface IBlobManagerLoadInfo {\n ids?: string[];\n redirectTable?: [string, string][];\n}\n\nexport class BlobManager {\n public static readonly basePath = \"_blobs\";\n private static readonly redirectTableBlobName = \".redirectTable\";\n // uploaded blob IDs\n private readonly blobIds: Set<string> = new Set();\n // blobs for which upload is pending. maps to a promise that will resolve once the blob has been uploaded and a\n // BlobAttach op has round-tripped.\n private readonly pendingBlobIds: Map<string, Deferred<void>> = new Map();\n // blobs uploaded while detached; cleared upon attach\n private readonly detachedBlobIds: Set<string> = new Set();\n // map of detached blob IDs to IDs used by storage. used to support blob handles given out while detached\n private redirectTable: Map<string, string> | undefined;\n\n constructor(\n private readonly routeContext: IFluidHandleContext,\n snapshot: IBlobManagerLoadInfo,\n private readonly getStorage: () => IDocumentStorageService,\n private readonly attachBlobCallback: (blobId: string) => void,\n // To be called when a blob node is requested. blobPath is the path of the blob's node in GC's graph. It's\n // of the format `/<BlobManager.basePath>/<blobId>`.\n private readonly gcNodeUpdated: (blobPath: string) => void,\n private readonly runtime: IContainerRuntime,\n private readonly logger: ITelemetryLogger,\n ) {\n this.runtime.once(\"dispose\", () => {\n for (const promise of this.pendingBlobIds.values()) {\n promise.reject(new Error(\"runtime disposed while blobAttach op in flight\"));\n }\n });\n this.load(snapshot);\n }\n\n private hasBlob(id: string): boolean {\n return this.blobIds.has(id) || this.detachedBlobIds.has(id);\n }\n\n /**\n * For a blobId, returns its path in GC's graph. The node path is of the format `/<BlobManager.basePath>/<blobId>`\n * This path must match the path of the blob handle returned by the createBlob API because blobs are marked\n * referenced by storing these handles in a referenced DDS.\n */\n private getBlobGCNodePath(blobId: string) {\n return `/${BlobManager.basePath}/${blobId}`;\n }\n\n public async getBlob(blobId: string): Promise<IFluidHandle<ArrayBufferLike>> {\n const storageId = this.redirectTable?.get(blobId) ?? blobId;\n assert(this.hasBlob(storageId), 0x11f /* \"requesting unknown blobs\" */);\n\n // When this blob is retrieved, let the container runtime know that the corresponding GC node got updated.\n this.gcNodeUpdated(this.getBlobGCNodePath(blobId));\n\n return new BlobHandle(\n `${BlobManager.basePath}/${storageId}`,\n this.routeContext,\n async () => PerformanceEvent.timedExecAsync(\n this.logger,\n { eventName: \"AttachmentReadBlob\", id: storageId },\n async () => {\n return this.getStorage().readBlob(storageId);\n },\n { end: true, cancel: \"error\" },\n ),\n );\n }\n\n public async createBlob(blob: ArrayBufferLike): Promise<IFluidHandle<ArrayBufferLike>> {\n if (this.runtime.attachState === AttachState.Attaching) {\n // blob upload is not supported in \"Attaching\" state\n this.logger.sendTelemetryEvent({ eventName: \"CreateBlobWhileAttaching\" });\n await new Promise<void>((resolve) => this.runtime.once(\"attached\", resolve));\n }\n\n if (!this.runtime.connected && this.runtime.attachState === AttachState.Attached) {\n // see https://github.com/microsoft/FluidFramework/issues/8246\n // Avoid getting storage if we are offline since it might be undefined. In the future we will return\n // handles immediately while offline\n await new Promise((resolve) => this.runtime.once(\"connected\", resolve));\n }\n\n const response = await PerformanceEvent.timedExecAsync(\n this.logger,\n { eventName: \"createBlob\" },\n async () => this.getStorage().createBlob(blob),\n { end: true, cancel: \"error\" },\n );\n\n const handle = new BlobHandle(\n `${BlobManager.basePath}/${response.id}`,\n this.routeContext,\n // get() should go through BlobManager.getBlob() so handles created while detached can be redirected\n // to the correct storage id after they are uploaded\n async () => this.getBlob(response.id).then(async (h) => h.get()),\n );\n\n if (this.runtime.attachState === AttachState.Detached) {\n this.detachedBlobIds.add(response.id);\n return handle;\n }\n\n // Note - server will de-dup blobs, so we might get existing blobId!\n if (this.pendingBlobIds.has(response.id)) {\n await this.pendingBlobIds.get(response.id)?.promise;\n } else if (!this.blobIds.has(response.id)) {\n this.pendingBlobIds.set(response.id, new Deferred<void>());\n\n // send blob attach op and wait until we see it to return the handle\n this.attachBlobCallback(response.id);\n await this.pendingBlobIds.get(response.id)?.promise;\n }\n\n return handle;\n }\n\n public processBlobAttachOp(blobId: string, local: boolean) {\n if (local) {\n const pendingBlobP = this.pendingBlobIds.get(blobId);\n assert(pendingBlobP !== undefined, 0x1f8 /* \"local BlobAttach op with no pending blob\" */);\n pendingBlobP.resolve();\n this.pendingBlobIds.delete(blobId);\n }\n this.blobIds.add(blobId);\n }\n\n /**\n * Reads blobs needed to load BlobManager from storage.\n */\n public static async load(\n blobsTree: ISnapshotTree | undefined,\n tryFetchBlob: (id: string) => Promise<[string, string][]>,\n ): Promise<IBlobManagerLoadInfo> {\n if (!blobsTree) {\n return {};\n }\n let redirectTable;\n const tableId = blobsTree.blobs[this.redirectTableBlobName];\n if (tableId) {\n redirectTable = await tryFetchBlob(tableId);\n }\n const ids = Object.entries(blobsTree.blobs)\n .filter(([k, _]) => k !== this.redirectTableBlobName).map(([_, v]) => v);\n return { ids, redirectTable };\n }\n\n /**\n * Load a set of previously attached blob IDs from a previous snapshot. Note\n * that BlobManager tracking and reporting attached blobs is a temporary\n * solution since storage expects attached blobs to be reported and any that\n * are not reported as attached may be GCed. In the future attached blob\n * IDs will be collected at summarization time, and runtime will not care\n * about the existence or specific formatting of this tree in returned\n * snapshots.\n *\n * @param blobsTree - Tree containing IDs of previously attached blobs. This\n * corresponds to snapshot() below. We look for the IDs in the blob entries\n * of the tree since the both the r11s and SPO drivers replace the\n * attachment types returned in snapshot() with blobs.\n */\n private load(snapshot: IBlobManagerLoadInfo): void {\n if (snapshot.ids) {\n const detached = this.runtime.attachState === AttachState.Detached;\n snapshot.ids.map((entry) => detached ? this.detachedBlobIds.add(entry) : this.blobIds.add(entry));\n }\n if (snapshot.redirectTable) {\n this.redirectTable = new Map(snapshot.redirectTable);\n }\n this.logger.sendTelemetryEvent({\n eventName: \"AttachmentBlobsLoaded\",\n count: snapshot.ids?.length ?? 0,\n redirectTable: snapshot.redirectTable?.length,\n });\n }\n\n /**\n * Generates data used for garbage collection. Each blob uploaded represents a node in the GC graph as it can be\n * individually referenced by storing its handle in a referenced DDS. Returns the list of blob ids as GC nodes.\n * @param fullGC - true to bypass optimizations and force full generation of GC data. BlobManager doesn't care\n * about this for now because the data is a simple list of blob ids.\n */\n public getGCData(fullGC: boolean = false): IGarbageCollectionData {\n const gcData: IGarbageCollectionData = { gcNodes: {} };\n\n this.blobIds.forEach((blobId: string) => {\n gcData.gcNodes[this.getBlobGCNodePath(blobId)] = [];\n });\n\n /**\n * For all blobs in the redirect table, the handle returned on creation is based off of the localId. So, these\n * nodes can be referenced by storing the localId handle. When that happens, the corresponding storageId node\n * must also be marked referenced. So, we add a route from the localId node to the storageId node.\n * Note that because of de-duping, there can be multiple localIds that all redirect to the same storageId or\n * a blob may be referenced via its storageId handle.\n */\n if (this.redirectTable !== undefined) {\n for (const [localId, storageId] of this.redirectTable) {\n // Add node for the localId and add a route to the storageId node. The storageId node will have been\n // added above when adding nodes for this.blobIds.\n gcData.gcNodes[this.getBlobGCNodePath(localId)] = [this.getBlobGCNodePath(storageId)];\n }\n }\n\n return gcData;\n }\n\n /**\n * When running GC in test mode, this is called to delete blobs that are unused.\n * @param unusedRoutes - These are the blob node ids that are unused and should be deleted.\n */\n public deleteUnusedRoutes(unusedRoutes: string[]): void {\n // The routes or blob node paths are in the same format as returned in getGCData -\n // `/<BlobManager.basePath>/<blobId>`.\n for (const route of unusedRoutes) {\n const pathParts = route.split(\"/\");\n assert(\n pathParts.length === 3 && pathParts[1] === BlobManager.basePath,\n 0x2d5 /* \"Invalid blob node id in unused routes.\" */,\n );\n const blobId = pathParts[2];\n\n // The unused blobId could be a localId. If so, remove it from the redirect table and continue. The\n // corresponding storageId may still be used either directly or via other localIds.\n if (this.redirectTable?.has(blobId)) {\n this.redirectTable.delete(blobId);\n continue;\n }\n this.blobIds.delete(blobId);\n }\n }\n\n public summarize(telemetryContext?: ITelemetryContext): ISummaryTreeWithStats {\n // If we have a redirect table it means the container is about to transition to \"Attaching\" state, so we need\n // to return an actual snapshot containing all the real storage IDs we know about.\n const attachingOrAttached = !!this.redirectTable || this.runtime.attachState !== AttachState.Detached;\n const blobIds = attachingOrAttached ? this.blobIds : this.detachedBlobIds;\n const builder = new SummaryTreeBuilder();\n blobIds.forEach((blobId) => {\n builder.addAttachment(blobId);\n });\n\n if (this.redirectTable && this.redirectTable.size > 0) {\n builder.addBlob(\n BlobManager.redirectTableBlobName,\n JSON.stringify(Array.from(this.redirectTable.entries())),\n );\n }\n\n return builder.getSummaryTree();\n }\n\n public setRedirectTable(table: Map<string, string>) {\n assert(this.runtime.attachState === AttachState.Detached,\n 0x252 /* \"redirect table can only be set in detached container\" */);\n assert(!this.redirectTable, 0x253 /* \"redirect table already exists\" */);\n for (const [localId, storageId] of table) {\n assert(this.detachedBlobIds.delete(localId), 0x254 /* \"unrecognized id in redirect table\" */);\n this.blobIds.add(storageId);\n }\n assert(this.detachedBlobIds.size === 0, 0x255 /* \"detached blob id absent in redirect table\" */);\n this.redirectTable = table;\n }\n}\n"]}
@@ -105,16 +105,16 @@ class OpPerfTelemetry {
105
105
  });
106
106
  }
107
107
  recordPingTime(latency) {
108
- this.pongCount++;
109
108
  this.pingLatency = latency;
110
- // logging one in every 100 pongs
111
- if (this.pongCount === 100) {
109
+ // logging one in every 1000 pongs, including the first time, if it is a "write" client.
110
+ if (this.pongCount % 1000 === 0 && this.deltaManager.active) {
112
111
  this.logger.sendPerformanceEvent({
113
112
  eventName: "DeltaLatency",
114
113
  duration: latency,
115
114
  });
116
115
  this.pongCount = 0;
117
116
  }
117
+ this.pongCount++;
118
118
  }
119
119
  beforeOpSubmit(message) {
120
120
  // start with first client op and measure latency every 500 client ops
@@ -1 +1 @@
1
- {"version":3,"file":"connectionTelemetry.js","sourceRoot":"","sources":["../src/connectionTelemetry.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 } from \"@fluidframework/common-definitions\";\nimport { ChildLogger, TelemetryLogger } from \"@fluidframework/telemetry-utils\";\nimport { IDeltaManager } from \"@fluidframework/container-definitions\";\nimport {\n IDocumentMessage,\n ISequencedDocumentMessage,\n MessageType,\n} from \"@fluidframework/protocol-definitions\";\nimport { assert, performance } from \"@fluidframework/common-utils\";\n\n/**\n * We report various latency-related errors when waiting for op roundtrip takes longer than that amout of time.\n */\nexport const latencyThreshold = 5000;\n\n// Phases in OpPerfTelemetry:\n// 1.\tOp sits in a buffer in DeltaManager (DM) queue, then in outbound queue for some time.\n// \t - Note: We do not differentiate these two today in telemetry, but first one is due to batches,\n// second one might happen due to outbound queue being paused.\n// 2.\tOp is sent to service and back.\n// 3.\tOp sits in inbound queue.\n// 4.\tOp is processed.\ninterface IOpPerfTelemetryProperties {\n /** Measure time between (1) and (2) - Measure time outbound op is sitting in queue due to active batch */\n durationOutboundQueue: number;\n /** Measure time between (2) and (3) - Track how long op is sitting in inbound queue until it is processed */\n durationInboundQueue: number;\n /** Measure time between (3) and (4) - Time between DM's inbound \"push\" event until DM's \"op\" event */\n durationInboundToProcessing: number;\n /** Length of the DeltaManager's inbound queue at the time of the DM's inbound \"push\" event (3) */\n lengthInboundQueue: number;\n}\n\n/**\n * Timings collected at various moments during the op processing.\n */\n interface IOpPerfTimings {\n /** Starting time for (1) */\n opStartTimeForLatencyStatistics: number;\n /** Starting time for (2) */\n opStartTimeSittingInboundQueue: number;\n /** Starting time for (3) */\n opStartTimeInboundPushEvent: number;\n}\n\nclass OpPerfTelemetry {\n private pongCount: number = 0;\n private pingLatency: number | undefined;\n\n // Collab window tracking. This is timestamp of %1000 message.\n private sequenceNumberForMsnTracking: number | undefined;\n private msnTrackingTimestamp: number = 0;\n // To track round trip time for every %500 client message.\n private clientSequenceNumberForLatencyStatistics: number | undefined;\n\n private opProcessingTimes: Partial<IOpPerfTimings> = {};\n\n // Performance Data to be reported for ops round trips and processing.\n private opPerfData: Partial<IOpPerfTelemetryProperties> = {};\n\n private firstConnection = true;\n private connectionOpSeqNumber: number | undefined;\n private readonly bootTime = performance.now();\n private connectionStartTime = 0;\n private gap = 0;\n\n private readonly logger: ITelemetryLogger;\n\n public constructor(\n private clientId: string | undefined,\n private readonly deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>,\n logger: ITelemetryLogger) {\n this.logger = ChildLogger.create(logger, \"OpPerf\");\n\n this.deltaManager.on(\"pong\", (latency) => this.recordPingTime(latency));\n this.deltaManager.on(\"submitOp\", (message) => this.beforeOpSubmit(message));\n\n this.deltaManager.on(\"op\", (message) => this.afterProcessingOp(message));\n\n this.deltaManager.on(\"connect\", (details, opsBehind) => {\n this.clientId = details.clientId;\n if (opsBehind !== undefined) {\n this.connectionOpSeqNumber = this.deltaManager.lastKnownSeqNumber;\n this.gap = opsBehind;\n this.connectionStartTime = performance.now();\n\n // We might be already up-today. If so, report it right away.\n if (this.gap <= 0) {\n this.reportGettingUpToDate();\n }\n }\n });\n this.deltaManager.on(\"disconnect\", () => {\n this.sequenceNumberForMsnTracking = undefined;\n this.clientSequenceNumberForLatencyStatistics = undefined;\n this.opProcessingTimes = {};\n this.opPerfData = {};\n this.connectionOpSeqNumber = undefined;\n this.firstConnection = false;\n });\n\n this.deltaManager.outbound.on(\"push\", (messages) => {\n for (const msg of messages) {\n if (msg.type === MessageType.Operation &&\n this.clientSequenceNumberForLatencyStatistics === msg.clientSequenceNumber) {\n assert(this.opProcessingTimes.opStartTimeSittingInboundQueue === undefined,\n 0x2c8 /* \"opStartTimeSittingInboundQueue should be undefined\" */);\n assert(this.opPerfData.durationInboundQueue === undefined,\n 0x2c9 /* \"durationInboundQueue should be undefined\" */);\n this.opProcessingTimes.opStartTimeSittingInboundQueue = Date.now();\n\n assert(this.opPerfData.durationOutboundQueue === undefined,\n 0x2ca /* \"durationOutboundQueue should be undefined\" */);\n\n assert(this.opProcessingTimes.opStartTimeForLatencyStatistics !== undefined,\n 0x2cb /* \"opStartTimeForLatencyStatistics should be undefined\" */);\n\n this.opPerfData.durationOutboundQueue = this.opProcessingTimes.opStartTimeSittingInboundQueue\n - this.opProcessingTimes.opStartTimeForLatencyStatistics;\n }\n }\n });\n\n this.deltaManager.inbound.on(\"push\", (message: ISequencedDocumentMessage) => {\n if (this.clientId === message.clientId &&\n message.type === MessageType.Operation &&\n this.clientSequenceNumberForLatencyStatistics === message.clientSequenceNumber &&\n this.opProcessingTimes.opStartTimeSittingInboundQueue !== undefined) {\n this.opProcessingTimes.opStartTimeInboundPushEvent = Date.now();\n this.opPerfData.durationInboundQueue = this.opProcessingTimes.opStartTimeInboundPushEvent\n - this.opProcessingTimes.opStartTimeSittingInboundQueue;\n this.opProcessingTimes.opStartTimeSittingInboundQueue = undefined;\n this.opPerfData.lengthInboundQueue = this.deltaManager.inbound.length;\n }\n });\n\n this.deltaManager.inbound.on(\"idle\", (count: number, duration: number) => {\n // Do not want to log zero for sure.\n // We are more interested in aggregates, so logging only if we are processing some number of ops\n // Cut-off is arbitrary - can be increased or decreased based on amount of data collected and questions we\n // want to get answered\n // back-compat: Once 0.36 loader version saturates (count & duration args were added there),\n // we can remove typeof check.\n if (typeof count === \"number\" && count >= 100) {\n this.logger.sendPerformanceEvent({\n eventName: \"GetDeltas_OpProcessing\",\n count,\n duration,\n });\n }\n });\n }\n\n private reportGettingUpToDate() {\n this.connectionOpSeqNumber = undefined;\n this.logger.sendPerformanceEvent({\n eventName: \"ConnectionSpeed\",\n duration: performance.now() - this.connectionStartTime,\n ops: this.gap,\n // track time to connect only for first connection.\n timeToConnect: this.firstConnection ?\n TelemetryLogger.formatTick(this.connectionStartTime - this.bootTime) :\n undefined,\n firstConnection: this.firstConnection,\n });\n }\n\n private recordPingTime(latency: number) {\n this.pongCount++;\n this.pingLatency = latency;\n // logging one in every 100 pongs\n if (this.pongCount === 100) {\n this.logger.sendPerformanceEvent({\n eventName: \"DeltaLatency\",\n duration: latency,\n });\n this.pongCount = 0;\n }\n }\n\n private beforeOpSubmit(message: IDocumentMessage) {\n // start with first client op and measure latency every 500 client ops\n if (this.clientSequenceNumberForLatencyStatistics === undefined &&\n message.clientSequenceNumber % 500 === 1) {\n assert(this.opProcessingTimes.opStartTimeSittingInboundQueue === undefined,\n 0x2cc /* \"OpTimeSittingInboundQueue should be undefined\" */);\n assert(this.opPerfData.durationInboundQueue === undefined,\n 0x2cd /* \"durationInboundQueue should be undefined\" */);\n this.opProcessingTimes.opStartTimeForLatencyStatistics = Date.now();\n this.clientSequenceNumberForLatencyStatistics = message.clientSequenceNumber;\n }\n }\n\n private afterProcessingOp(message: ISequencedDocumentMessage) {\n const sequenceNumber = message.sequenceNumber;\n\n if (sequenceNumber === this.connectionOpSeqNumber) {\n this.reportGettingUpToDate();\n }\n\n // Record collab window max size after every 1000th op.\n if (this.sequenceNumberForMsnTracking === undefined && sequenceNumber % 1000 === 0) {\n this.sequenceNumberForMsnTracking = sequenceNumber;\n this.msnTrackingTimestamp = message.timestamp;\n }\n if (this.sequenceNumberForMsnTracking !== undefined &&\n message.minimumSequenceNumber >= this.sequenceNumberForMsnTracking) {\n assert(this.msnTrackingTimestamp !== undefined,\n 0x2ce /* \"msnTrackingTimestamp should not be undefined\" */);\n this.logger.sendPerformanceEvent({\n eventName: \"MsnStatistics\",\n sequenceNumber,\n msnDistance: sequenceNumber - this.sequenceNumberForMsnTracking,\n duration: message.timestamp - this.msnTrackingTimestamp,\n });\n this.sequenceNumberForMsnTracking = undefined;\n }\n\n if (this.clientId === message.clientId &&\n this.clientSequenceNumberForLatencyStatistics === message.clientSequenceNumber) {\n assert(this.opProcessingTimes.opStartTimeForLatencyStatistics !== undefined,\n 0x120 /* \"Undefined latency statistics (op send time)\" */);\n const currentTime = Date.now();\n\n if (this.opProcessingTimes.opStartTimeInboundPushEvent !== undefined) {\n this.opPerfData.durationInboundToProcessing = currentTime\n - this.opProcessingTimes.opStartTimeInboundPushEvent;\n }\n\n const duration = currentTime - this.opProcessingTimes.opStartTimeForLatencyStatistics;\n\n // One of the core expectations for Fluid service is to be fast.\n // When it's not the case, we want to learn about it and be able to investigate, so\n // raise awareness.\n // This also helps identify cases where it's due to client behavior (sending too many ops)\n // that results in overwhelming ordering service and thus starting to see long latencies.\n // The threshold could be adjusted, but ideally it stays workload-agnostic, as service\n // performance impacts all workloads relying on service.\n const category = duration > latencyThreshold ? \"error\" : \"performance\";\n\n this.logger.sendPerformanceEvent({\n eventName: \"OpRoundtripTime\",\n sequenceNumber,\n referenceSequenceNumber: message.referenceSequenceNumber,\n duration,\n category,\n pingLatency: this.pingLatency,\n msnDistance: this.deltaManager.lastSequenceNumber - this.deltaManager.minimumSequenceNumber,\n ...this.opPerfData,\n });\n this.clientSequenceNumberForLatencyStatistics = undefined;\n this.opPerfData = {};\n }\n }\n}\n\nexport function ReportOpPerfTelemetry(\n clientId: string | undefined,\n deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>,\n logger: ITelemetryLogger) {\n new OpPerfTelemetry(clientId, deltaManager, logger);\n}\n"]}
1
+ {"version":3,"file":"connectionTelemetry.js","sourceRoot":"","sources":["../src/connectionTelemetry.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 } from \"@fluidframework/common-definitions\";\nimport { ChildLogger, TelemetryLogger } from \"@fluidframework/telemetry-utils\";\nimport { IDeltaManager } from \"@fluidframework/container-definitions\";\nimport {\n IDocumentMessage,\n ISequencedDocumentMessage,\n MessageType,\n} from \"@fluidframework/protocol-definitions\";\nimport { assert, performance } from \"@fluidframework/common-utils\";\n\n/**\n * We report various latency-related errors when waiting for op roundtrip takes longer than that amout of time.\n */\nexport const latencyThreshold = 5000;\n\n// Phases in OpPerfTelemetry:\n// 1.\tOp sits in a buffer in DeltaManager (DM) queue, then in outbound queue for some time.\n// \t - Note: We do not differentiate these two today in telemetry, but first one is due to batches,\n// second one might happen due to outbound queue being paused.\n// 2.\tOp is sent to service and back.\n// 3.\tOp sits in inbound queue.\n// 4.\tOp is processed.\ninterface IOpPerfTelemetryProperties {\n /** Measure time between (1) and (2) - Measure time outbound op is sitting in queue due to active batch */\n durationOutboundQueue: number;\n /** Measure time between (2) and (3) - Track how long op is sitting in inbound queue until it is processed */\n durationInboundQueue: number;\n /** Measure time between (3) and (4) - Time between DM's inbound \"push\" event until DM's \"op\" event */\n durationInboundToProcessing: number;\n /** Length of the DeltaManager's inbound queue at the time of the DM's inbound \"push\" event (3) */\n lengthInboundQueue: number;\n}\n\n/**\n * Timings collected at various moments during the op processing.\n */\n interface IOpPerfTimings {\n /** Starting time for (1) */\n opStartTimeForLatencyStatistics: number;\n /** Starting time for (2) */\n opStartTimeSittingInboundQueue: number;\n /** Starting time for (3) */\n opStartTimeInboundPushEvent: number;\n}\n\nclass OpPerfTelemetry {\n private pongCount: number = 0;\n private pingLatency: number | undefined;\n\n // Collab window tracking. This is timestamp of %1000 message.\n private sequenceNumberForMsnTracking: number | undefined;\n private msnTrackingTimestamp: number = 0;\n // To track round trip time for every %500 client message.\n private clientSequenceNumberForLatencyStatistics: number | undefined;\n\n private opProcessingTimes: Partial<IOpPerfTimings> = {};\n\n // Performance Data to be reported for ops round trips and processing.\n private opPerfData: Partial<IOpPerfTelemetryProperties> = {};\n\n private firstConnection = true;\n private connectionOpSeqNumber: number | undefined;\n private readonly bootTime = performance.now();\n private connectionStartTime = 0;\n private gap = 0;\n\n private readonly logger: ITelemetryLogger;\n\n public constructor(\n private clientId: string | undefined,\n private readonly deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>,\n logger: ITelemetryLogger) {\n this.logger = ChildLogger.create(logger, \"OpPerf\");\n\n this.deltaManager.on(\"pong\", (latency) => this.recordPingTime(latency));\n this.deltaManager.on(\"submitOp\", (message) => this.beforeOpSubmit(message));\n\n this.deltaManager.on(\"op\", (message) => this.afterProcessingOp(message));\n\n this.deltaManager.on(\"connect\", (details, opsBehind) => {\n this.clientId = details.clientId;\n if (opsBehind !== undefined) {\n this.connectionOpSeqNumber = this.deltaManager.lastKnownSeqNumber;\n this.gap = opsBehind;\n this.connectionStartTime = performance.now();\n\n // We might be already up-today. If so, report it right away.\n if (this.gap <= 0) {\n this.reportGettingUpToDate();\n }\n }\n });\n this.deltaManager.on(\"disconnect\", () => {\n this.sequenceNumberForMsnTracking = undefined;\n this.clientSequenceNumberForLatencyStatistics = undefined;\n this.opProcessingTimes = {};\n this.opPerfData = {};\n this.connectionOpSeqNumber = undefined;\n this.firstConnection = false;\n });\n\n this.deltaManager.outbound.on(\"push\", (messages) => {\n for (const msg of messages) {\n if (msg.type === MessageType.Operation &&\n this.clientSequenceNumberForLatencyStatistics === msg.clientSequenceNumber) {\n assert(this.opProcessingTimes.opStartTimeSittingInboundQueue === undefined,\n 0x2c8 /* \"opStartTimeSittingInboundQueue should be undefined\" */);\n assert(this.opPerfData.durationInboundQueue === undefined,\n 0x2c9 /* \"durationInboundQueue should be undefined\" */);\n this.opProcessingTimes.opStartTimeSittingInboundQueue = Date.now();\n\n assert(this.opPerfData.durationOutboundQueue === undefined,\n 0x2ca /* \"durationOutboundQueue should be undefined\" */);\n\n assert(this.opProcessingTimes.opStartTimeForLatencyStatistics !== undefined,\n 0x2cb /* \"opStartTimeForLatencyStatistics should be undefined\" */);\n\n this.opPerfData.durationOutboundQueue = this.opProcessingTimes.opStartTimeSittingInboundQueue\n - this.opProcessingTimes.opStartTimeForLatencyStatistics;\n }\n }\n });\n\n this.deltaManager.inbound.on(\"push\", (message: ISequencedDocumentMessage) => {\n if (this.clientId === message.clientId &&\n message.type === MessageType.Operation &&\n this.clientSequenceNumberForLatencyStatistics === message.clientSequenceNumber &&\n this.opProcessingTimes.opStartTimeSittingInboundQueue !== undefined) {\n this.opProcessingTimes.opStartTimeInboundPushEvent = Date.now();\n this.opPerfData.durationInboundQueue = this.opProcessingTimes.opStartTimeInboundPushEvent\n - this.opProcessingTimes.opStartTimeSittingInboundQueue;\n this.opProcessingTimes.opStartTimeSittingInboundQueue = undefined;\n this.opPerfData.lengthInboundQueue = this.deltaManager.inbound.length;\n }\n });\n\n this.deltaManager.inbound.on(\"idle\", (count: number, duration: number) => {\n // Do not want to log zero for sure.\n // We are more interested in aggregates, so logging only if we are processing some number of ops\n // Cut-off is arbitrary - can be increased or decreased based on amount of data collected and questions we\n // want to get answered\n // back-compat: Once 0.36 loader version saturates (count & duration args were added there),\n // we can remove typeof check.\n if (typeof count === \"number\" && count >= 100) {\n this.logger.sendPerformanceEvent({\n eventName: \"GetDeltas_OpProcessing\",\n count,\n duration,\n });\n }\n });\n }\n\n private reportGettingUpToDate() {\n this.connectionOpSeqNumber = undefined;\n this.logger.sendPerformanceEvent({\n eventName: \"ConnectionSpeed\",\n duration: performance.now() - this.connectionStartTime,\n ops: this.gap,\n // track time to connect only for first connection.\n timeToConnect: this.firstConnection ?\n TelemetryLogger.formatTick(this.connectionStartTime - this.bootTime) :\n undefined,\n firstConnection: this.firstConnection,\n });\n }\n\n private recordPingTime(latency: number) {\n this.pingLatency = latency;\n // logging one in every 1000 pongs, including the first time, if it is a \"write\" client.\n if (this.pongCount % 1000 === 0 && this.deltaManager.active) {\n this.logger.sendPerformanceEvent({\n eventName: \"DeltaLatency\",\n duration: latency,\n });\n this.pongCount = 0;\n }\n this.pongCount++;\n }\n\n private beforeOpSubmit(message: IDocumentMessage) {\n // start with first client op and measure latency every 500 client ops\n if (this.clientSequenceNumberForLatencyStatistics === undefined &&\n message.clientSequenceNumber % 500 === 1) {\n assert(this.opProcessingTimes.opStartTimeSittingInboundQueue === undefined,\n 0x2cc /* \"OpTimeSittingInboundQueue should be undefined\" */);\n assert(this.opPerfData.durationInboundQueue === undefined,\n 0x2cd /* \"durationInboundQueue should be undefined\" */);\n this.opProcessingTimes.opStartTimeForLatencyStatistics = Date.now();\n this.clientSequenceNumberForLatencyStatistics = message.clientSequenceNumber;\n }\n }\n\n private afterProcessingOp(message: ISequencedDocumentMessage) {\n const sequenceNumber = message.sequenceNumber;\n\n if (sequenceNumber === this.connectionOpSeqNumber) {\n this.reportGettingUpToDate();\n }\n\n // Record collab window max size after every 1000th op.\n if (this.sequenceNumberForMsnTracking === undefined && sequenceNumber % 1000 === 0) {\n this.sequenceNumberForMsnTracking = sequenceNumber;\n this.msnTrackingTimestamp = message.timestamp;\n }\n if (this.sequenceNumberForMsnTracking !== undefined &&\n message.minimumSequenceNumber >= this.sequenceNumberForMsnTracking) {\n assert(this.msnTrackingTimestamp !== undefined,\n 0x2ce /* \"msnTrackingTimestamp should not be undefined\" */);\n this.logger.sendPerformanceEvent({\n eventName: \"MsnStatistics\",\n sequenceNumber,\n msnDistance: sequenceNumber - this.sequenceNumberForMsnTracking,\n duration: message.timestamp - this.msnTrackingTimestamp,\n });\n this.sequenceNumberForMsnTracking = undefined;\n }\n\n if (this.clientId === message.clientId &&\n this.clientSequenceNumberForLatencyStatistics === message.clientSequenceNumber) {\n assert(this.opProcessingTimes.opStartTimeForLatencyStatistics !== undefined,\n 0x120 /* \"Undefined latency statistics (op send time)\" */);\n const currentTime = Date.now();\n\n if (this.opProcessingTimes.opStartTimeInboundPushEvent !== undefined) {\n this.opPerfData.durationInboundToProcessing = currentTime\n - this.opProcessingTimes.opStartTimeInboundPushEvent;\n }\n\n const duration = currentTime - this.opProcessingTimes.opStartTimeForLatencyStatistics;\n\n // One of the core expectations for Fluid service is to be fast.\n // When it's not the case, we want to learn about it and be able to investigate, so\n // raise awareness.\n // This also helps identify cases where it's due to client behavior (sending too many ops)\n // that results in overwhelming ordering service and thus starting to see long latencies.\n // The threshold could be adjusted, but ideally it stays workload-agnostic, as service\n // performance impacts all workloads relying on service.\n const category = duration > latencyThreshold ? \"error\" : \"performance\";\n\n this.logger.sendPerformanceEvent({\n eventName: \"OpRoundtripTime\",\n sequenceNumber,\n referenceSequenceNumber: message.referenceSequenceNumber,\n duration,\n category,\n pingLatency: this.pingLatency,\n msnDistance: this.deltaManager.lastSequenceNumber - this.deltaManager.minimumSequenceNumber,\n ...this.opPerfData,\n });\n this.clientSequenceNumberForLatencyStatistics = undefined;\n this.opPerfData = {};\n }\n }\n}\n\nexport function ReportOpPerfTelemetry(\n clientId: string | undefined,\n deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>,\n logger: ITelemetryLogger) {\n new OpPerfTelemetry(clientId, deltaManager, logger);\n}\n"]}
@@ -6,15 +6,16 @@
6
6
  import { EventEmitter } from "events";
7
7
  import { ITelemetryLogger } from "@fluidframework/common-definitions";
8
8
  import { FluidObject, IFluidHandle, IFluidHandleContext, IFluidRouter, IRequest, IResponse } from "@fluidframework/core-interfaces";
9
- import { IAudience, IFluidTokenProvider, IContainerContext, IDeltaManager, IRuntime, ICriticalContainerError, AttachState, ILoaderOptions } from "@fluidframework/container-definitions";
9
+ import { IAudience, IFluidTokenProvider, IContainerContext, IDeltaManager, IRuntime, ICriticalContainerError, AttachState, ILoaderOptions, ISnapshotTreeWithBlobContents } from "@fluidframework/container-definitions";
10
10
  import { IContainerRuntime, IContainerRuntimeEvents } from "@fluidframework/container-runtime-definitions";
11
11
  import { TypedEventEmitter } from "@fluidframework/common-utils";
12
12
  import { IDocumentStorageService } from "@fluidframework/driver-definitions";
13
- import { IClientDetails, IDocumentMessage, IQuorumClients, ISequencedDocumentMessage, ISignalMessage, ISummaryConfiguration, ISummaryTree, MessageType } from "@fluidframework/protocol-definitions";
14
- import { FlushMode, IFluidDataStoreContextDetached, IFluidDataStoreRegistry, IGarbageCollectionData, NamedFluidDataStoreRegistryEntries, ISummaryTreeWithStats, IDataStore } from "@fluidframework/runtime-definitions";
13
+ import { IClientDetails, IDocumentMessage, IQuorumClients, ISequencedDocumentMessage, ISignalMessage, ISnapshotTree, ISummaryTree, MessageType } from "@fluidframework/protocol-definitions";
14
+ import { FlushMode, IFluidDataStoreContextDetached, IFluidDataStoreRegistry, IGarbageCollectionData, NamedFluidDataStoreRegistryEntries, ISummaryTreeWithStats, IDataStore, ITelemetryContext } from "@fluidframework/runtime-definitions";
15
15
  import { IPendingLocalState } from "./pendingStateManager";
16
16
  import { SubmitSummaryResult, ISubmitSummaryOptions, ISummarizer, ISummarizerInternalsProvider, ISummarizerOptions, ISummarizerRuntime } from "./summarizerTypes";
17
17
  import { GCNodeType, IGarbageCollectionRuntime, IGCStats } from "./garbageCollection";
18
+ import { ISerializedBaseSnapshotBlobs } from "./serializedSnapshotStorage";
18
19
  export declare enum ContainerMessageType {
19
20
  FluidDataStoreOp = "component",
20
21
  Attach = "attach",
@@ -33,6 +34,58 @@ export interface ContainerRuntimeMessage {
33
34
  contents: any;
34
35
  type: ContainerMessageType;
35
36
  }
37
+ export interface ISummaryBaseConfiguration {
38
+ /**
39
+ * Delay before first attempt to spawn summarizing container.
40
+ */
41
+ initialSummarizerDelayMs: number;
42
+ /**
43
+ * Flag that will enable changing elected summarizer client after maxOpsSinceLastSummary.
44
+ * This defaults to false (disabled) and must be explicitly set to true to enable.
45
+ */
46
+ summarizerClientElection: boolean;
47
+ /**
48
+ * Defines the maximum allowed time to wait for a pending summary ack.
49
+ * The maximum amount of time client will wait for a summarize is the minimum of
50
+ * maxSummarizeAckWaitTime (currently 10 * 60 * 1000) and maxAckWaitTime.
51
+ */
52
+ maxAckWaitTime: number;
53
+ /**
54
+ * Defines the maximum number of Ops in between Summaries that can be
55
+ * allowed before forcibly electing a new summarizer client.
56
+ */
57
+ maxOpsSinceLastSummary: number;
58
+ }
59
+ export interface ISummaryConfigurationHeuristics extends ISummaryBaseConfiguration {
60
+ state: "enabled";
61
+ /**
62
+ * Defines the maximum allowed time in between summarizations.
63
+ */
64
+ idleTime: number;
65
+ /**
66
+ * Defines the maximum allowed time, since the last received Ack, before running the summary
67
+ * with reason maxTime.
68
+ */
69
+ maxTime: number;
70
+ /**
71
+ * Defines the maximum number of Ops, since the last received Ack, that can be allowed
72
+ * before running the summary with reason maxOps.
73
+ */
74
+ maxOps: number;
75
+ /**
76
+ * Defnines the minimum number of Ops, since the last received Ack, that can be allowed
77
+ * before running the last summary.
78
+ */
79
+ minOpsForLastSummaryAttempt: number;
80
+ }
81
+ export interface ISummaryConfigurationDisableSummarizer {
82
+ state: "disabled";
83
+ }
84
+ export interface ISummaryConfigurationDisableHeuristics extends ISummaryBaseConfiguration {
85
+ state: "disableHeuristics";
86
+ }
87
+ export declare type ISummaryConfiguration = ISummaryConfigurationDisableSummarizer | ISummaryConfigurationDisableHeuristics | ISummaryConfigurationHeuristics;
88
+ export declare const DefaultSummaryConfiguration: ISummaryConfiguration;
36
89
  export interface IGCRuntimeOptions {
37
90
  /**
38
91
  * Flag that if true, will enable running garbage collection (GC) in a container. GC has mark phase and sweep phase.
@@ -65,27 +118,33 @@ export interface IGCRuntimeOptions {
65
118
  [key: string]: any;
66
119
  }
67
120
  export interface ISummaryRuntimeOptions {
121
+ /** Override summary configurations set by the server. */
122
+ summaryConfigOverrides?: ISummaryConfiguration;
123
+ disableIsolatedChannels?: boolean;
68
124
  /**
125
+ * @deprecated - use `summaryConfigOverrides.initialSummarizerDelayMs` instead.
126
+ * Delay before first attempt to spawn summarizing container.
127
+ */
128
+ initialSummarizerDelayMs?: number;
129
+ /**
130
+ * @deprecated - use `summaryConfigOverrides.disableSummaries` instead.
69
131
  * Flag that disables summaries if it is set to true.
70
132
  */
71
133
  disableSummaries?: boolean;
72
134
  /**
73
- * @deprecated - To disable summaries, please set disableSummaries===true.
74
- * Flag that will generate summaries if connected to a service that supports them.
75
- * This defaults to true and must be explicitly set to false to disable.
135
+ * @deprecated - use `summaryConfigOverrides.maxOpsSinceLastSummary` instead.
136
+ * Defaults to 7000 ops
76
137
  */
77
- generateSummaries?: boolean;
78
- initialSummarizerDelayMs?: number;
79
- /** Override summary configurations set by the server. */
80
- summaryConfigOverrides?: Partial<ISummaryConfiguration>;
81
- disableIsolatedChannels?: boolean;
82
138
  maxOpsSinceLastSummary?: number;
83
139
  /**
84
- * Flag that will enable changing elected summarizer client after maxOpsSinceLastSummary.
85
- * THis defaults to false (disabled) and must be explicitly set to true to enable.
86
- */
140
+ * @deprecated - use `summaryConfigOverrides.summarizerClientElection` instead.
141
+ * Flag that will enable changing elected summarizer client after maxOpsSinceLastSummary.
142
+ * This defaults to false (disabled) and must be explicitly set to true to enable.
143
+ */
87
144
  summarizerClientElection?: boolean;
88
- /** Options that control the running summarizer behavior. */
145
+ /**
146
+ * @deprecated - use `summaryConfigOverrides.state = "DisableHeuristics"` instead.
147
+ * Options that control the running summarizer behavior. */
89
148
  summarizerOptions?: Readonly<Partial<ISummarizerOptions>>;
90
149
  }
91
150
  /**
@@ -116,6 +175,10 @@ export interface IContainerRuntimeOptions {
116
175
  * By default, flush mode is TurnBased.
117
176
  */
118
177
  readonly flushMode?: FlushMode;
178
+ /**
179
+ * Save enough runtime state to be able to serialize upon request and load to the same state in a new container.
180
+ */
181
+ readonly enableOfflineLoad?: boolean;
119
182
  }
120
183
  /**
121
184
  * The summary tree returned by the root node. It adds state relevant to the root of the tree.
@@ -138,6 +201,32 @@ export declare enum RuntimeHeaders {
138
201
  /** True if the request is coming from an IFluidHandle. */
139
202
  viaHandle = "viaHandle"
140
203
  }
204
+ /**
205
+ * State saved when the container closes, to be given back to a newly
206
+ * instantiated runtime in a new instance of the container, so it can load to the
207
+ * same state
208
+ */
209
+ export interface IPendingRuntimeState {
210
+ /**
211
+ * Pending ops from PendingStateManager
212
+ */
213
+ pending?: IPendingLocalState;
214
+ /**
215
+ * A base snapshot at a sequence number prior to the first pending op
216
+ */
217
+ baseSnapshot: ISnapshotTree;
218
+ /**
219
+ * Serialized blobs from the base snapshot. Used to load offline since
220
+ * storage is not available.
221
+ */
222
+ snapshotBlobs: ISerializedBaseSnapshotBlobs;
223
+ /**
224
+ * All runtime ops since base snapshot sequence number up to the latest op
225
+ * seen when the container was closed. Used to apply stashed (saved pending)
226
+ * ops at the same sequence number at which they were made.
227
+ */
228
+ savedOps: ISequencedDocumentMessage[];
229
+ }
141
230
  export declare enum RuntimeMessage {
142
231
  FluidDataStoreOp = "component",
143
232
  Attach = "attach",
@@ -190,7 +279,9 @@ export declare class ContainerRuntime extends TypedEventEmitter<IContainerRuntim
190
279
  private readonly runtimeOptions;
191
280
  private readonly containerScope;
192
281
  readonly logger: ITelemetryLogger;
282
+ private readonly _storage;
193
283
  private readonly requestHandler?;
284
+ private readonly summaryConfiguration;
194
285
  get IContainerRuntime(): this;
195
286
  get IFluidRouter(): this;
196
287
  /**
@@ -234,12 +325,12 @@ export declare class ContainerRuntime extends TypedEventEmitter<IContainerRuntim
234
325
  private needsFlush;
235
326
  private flushTrigger;
236
327
  private _connected;
237
- private paused;
328
+ private readonly savedOps;
329
+ private baseSnapshotBlobs?;
238
330
  private consecutiveReconnects;
239
331
  get connected(): boolean;
240
332
  /** clientId of parent (non-summarizing) container that owns summarizer container */
241
333
  get summarizerClientId(): string | undefined;
242
- private get summaryConfiguration();
243
334
  private _disposed;
244
335
  get disposed(): boolean;
245
336
  private dirtyContainer;
@@ -266,7 +357,16 @@ export declare class ContainerRuntime extends TypedEventEmitter<IContainerRuntim
266
357
  /** The last message processed at the time of the last summary. */
267
358
  private messageAtLastSummary;
268
359
  private get summarizer();
269
- private get summariesDisabled();
360
+ private readonly summariesDisabled;
361
+ private isSummariesDisabled;
362
+ private readonly heuristicsDisabled;
363
+ private isHeuristicsDisabled;
364
+ private readonly summarizerClientElectionEnabled;
365
+ private isSummarizerClientElectionEnabled;
366
+ private readonly maxOpsSinceLastSummary;
367
+ private getMaxOpsSinceLastSummary;
368
+ private readonly initialSummarizerDelayMs;
369
+ private getInitialSummarizerDelayMs;
270
370
  private readonly createContainerMetadata;
271
371
  /**
272
372
  * The summary number of the next summary that will be generated for this container. This is incremented every time
@@ -294,15 +394,6 @@ export declare class ContainerRuntime extends TypedEventEmitter<IContainerRuntim
294
394
  private shouldContinueReconnecting;
295
395
  private resetReconnectCount;
296
396
  private replayPendingStates;
297
- /**
298
- * Used to apply stashed ops at their reference sequence number.
299
- * Normal op processing is synchronous, but applying stashed ops is async since the
300
- * data store may not be loaded yet, so we pause DeltaManager between ops.
301
- * It's also important that we see each op so we know all stashed ops have
302
- * been applied by "connected" event, but process() doesn't see system ops,
303
- * so we listen directly from DeltaManager instead.
304
- */
305
- private readonly onOp;
306
397
  private applyStashedOp;
307
398
  setConnectionState(connected: boolean, clientId?: string): void;
308
399
  process(messageArg: ISequencedDocumentMessage, local: boolean): void;
@@ -368,8 +459,9 @@ export declare class ContainerRuntime extends TypedEventEmitter<IContainerRuntim
368
459
  * @param blobRedirectTable - A table passed during the attach process. While detached, blob upload is supported
369
460
  * using IDs generated locally. After attach, these IDs cannot be used, so this table maps the old local IDs to the
370
461
  * new storage IDs so requests can be redirected.
462
+ * @param telemetryContext - summary data passed through the layers for telemetry purposes
371
463
  */
372
- createSummary(blobRedirectTable?: Map<string, string>): ISummaryTree;
464
+ createSummary(blobRedirectTable?: Map<string, string>, telemetryContext?: ITelemetryContext): ISummaryTree;
373
465
  getAbsoluteUrl(relativeUrl: string): Promise<string | undefined>;
374
466
  private summarizeInternal;
375
467
  /**
@@ -486,6 +578,7 @@ export declare class ContainerRuntime extends TypedEventEmitter<IContainerRuntim
486
578
  * @param localOpMetadata - The local metadata associated with the original message.
487
579
  */
488
580
  private reSubmit;
581
+ private rollback;
489
582
  /** Implementation of ISummarizerInternalsProvider.refreshLatestSummaryAck */
490
583
  refreshLatestSummaryAck(proposalHandle: string | undefined, ackHandle: string, summaryRefSeq: number, summaryLogger: ITelemetryLogger): Promise<void>;
491
584
  /**
@@ -496,7 +589,9 @@ export declare class ContainerRuntime extends TypedEventEmitter<IContainerRuntim
496
589
  */
497
590
  private refreshLatestSummaryAckFromServer;
498
591
  private fetchSnapshotFromStorage;
499
- getPendingLocalState(): IPendingLocalState | undefined;
592
+ notifyAttaching(snapshot: ISnapshotTreeWithBlobContents): void;
593
+ getSnapshotBlobs(): Promise<void>;
594
+ getPendingLocalState(): IPendingRuntimeState;
500
595
  readonly summarizeOnDemand: ISummarizer["summarizeOnDemand"];
501
596
  readonly enqueueSummarize: ISummarizer["enqueueSummarize"];
502
597
  /**
@@ -504,5 +599,6 @@ export declare class ContainerRuntime extends TypedEventEmitter<IContainerRuntim
504
599
  * @param loaderRouter - the loader acting as an IFluidRouter
505
600
  * */
506
601
  private formRequestSummarizerFn;
602
+ private processSavedOps;
507
603
  }
508
604
  //# sourceMappingURL=containerRuntime.d.ts.map