@fluidframework/driver-utils 0.58.2002 → 0.59.1000

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 (38) hide show
  1. package/dist/blobAggregationStorage.js +1 -1
  2. package/dist/blobAggregationStorage.js.map +1 -1
  3. package/dist/multiDocumentServiceFactory.d.ts +2 -2
  4. package/dist/multiDocumentServiceFactory.d.ts.map +1 -1
  5. package/dist/multiDocumentServiceFactory.js +4 -4
  6. package/dist/multiDocumentServiceFactory.js.map +1 -1
  7. package/dist/packageVersion.d.ts +1 -1
  8. package/dist/packageVersion.js +1 -1
  9. package/dist/packageVersion.js.map +1 -1
  10. package/dist/prefetchDocumentStorageService.d.ts.map +1 -1
  11. package/dist/prefetchDocumentStorageService.js +0 -5
  12. package/dist/prefetchDocumentStorageService.js.map +1 -1
  13. package/dist/runWithRetry.d.ts +1 -1
  14. package/dist/runWithRetry.d.ts.map +1 -1
  15. package/dist/runWithRetry.js +18 -4
  16. package/dist/runWithRetry.js.map +1 -1
  17. package/lib/blobAggregationStorage.js +1 -1
  18. package/lib/blobAggregationStorage.js.map +1 -1
  19. package/lib/multiDocumentServiceFactory.d.ts +2 -2
  20. package/lib/multiDocumentServiceFactory.d.ts.map +1 -1
  21. package/lib/multiDocumentServiceFactory.js +4 -4
  22. package/lib/multiDocumentServiceFactory.js.map +1 -1
  23. package/lib/packageVersion.d.ts +1 -1
  24. package/lib/packageVersion.js +1 -1
  25. package/lib/packageVersion.js.map +1 -1
  26. package/lib/prefetchDocumentStorageService.d.ts.map +1 -1
  27. package/lib/prefetchDocumentStorageService.js +0 -5
  28. package/lib/prefetchDocumentStorageService.js.map +1 -1
  29. package/lib/runWithRetry.d.ts +1 -1
  30. package/lib/runWithRetry.d.ts.map +1 -1
  31. package/lib/runWithRetry.js +18 -4
  32. package/lib/runWithRetry.js.map +1 -1
  33. package/package.json +16 -11
  34. package/src/blobAggregationStorage.ts +1 -1
  35. package/src/multiDocumentServiceFactory.ts +8 -3
  36. package/src/packageVersion.ts +1 -1
  37. package/src/prefetchDocumentStorageService.ts +0 -6
  38. package/src/runWithRetry.ts +23 -3
@@ -74,7 +74,7 @@ class SnapshotExtractor {
74
74
  let subTree = snapshot;
75
75
  for (const subPath of pathSplit.slice(0, pathSplit.length - 1)) {
76
76
  if (subTree.trees[subPath] === undefined) {
77
- subTree.trees[subPath] = { blobs: {}, commits: {}, trees: {} };
77
+ subTree.trees[subPath] = { blobs: {}, trees: {} };
78
78
  }
79
79
  subTree = subTree.trees[subPath];
80
80
  }
@@ -1 +1 @@
1
- {"version":3,"file":"blobAggregationStorage.js","sourceRoot":"","sources":["../src/blobAggregationStorage.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 {\n IDocumentStorageService,\n IDocumentStorageServicePolicies,\n ISummaryContext,\n} from \"@fluidframework/driver-definitions\";\nimport {\n ICreateBlobResponse,\n ISnapshotTree,\n ISummaryHandle,\n ISummaryTree,\n IVersion,\n SummaryType,\n ITree,\n} from \"@fluidframework/protocol-definitions\";\nimport {\n assert,\n bufferToString,\n stringToBuffer,\n unreachableCase,\n fromUtf8ToBase64,\n Uint8ArrayToString,\n } from \"@fluidframework/common-utils\";\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { loggerToMonitoringContext } from \"@fluidframework/telemetry-utils\";\n\n/*\n * Work around for bufferToString having a bug - it can't consume IsoBuffer!\n * To be removed once bufferToString is fixed!\n*/\nfunction bufferToString2(blob: ArrayBufferLike, encoding: \"utf-8\" | \"base64\"): string {\n if (blob instanceof Uint8Array) { // IsoBuffer does not have ctor, so it's not in proto chain :(\n return Uint8ArrayToString(blob, encoding);\n }\n return bufferToString(blob, encoding);\n}\n\n /**\n * Class responsible for aggregating smaller blobs into one and unpacking it later on.\n */\nclass BlobAggregator {\n private readonly content: [string, string][] = [];\n\n public addBlob(key: string, content: string) {\n this.content.push([key, content]);\n }\n\n public getAggregatedBlobContent() {\n if (this.content.length === 0) {\n return undefined;\n }\n return JSON.stringify(this.content);\n }\n\n static load(input: ArrayBufferLike) {\n const data = bufferToString2(input, \"utf-8\");\n return JSON.parse(data) as [string, string][];\n }\n}\n\n/*\n * Base class that deals with unpacking snapshots (in place) containing aggregated blobs\n * It relies on abstract methods for reads and storing unpacked blobs.\n */\nexport abstract class SnapshotExtractor {\n protected readonly aggregatedBlobName = \"__big\";\n protected readonly virtualIdPrefix = \"__\";\n\n // counter for generation of virtual storage IDs\n protected virtualIdCounter = 0;\n protected getNextVirtualId() {\n return `${this.virtualIdPrefix}${++this.virtualIdCounter}`;\n }\n\n abstract getBlob(id: string, tree: ISnapshotTree): Promise<ArrayBufferLike>;\n abstract setBlob(id: string, tree: ISnapshotTree, content: string);\n\n public async unpackSnapshotCore(snapshot: ISnapshotTree, level = 0): Promise<void> {\n for (const key of Object.keys(snapshot.trees)) {\n const obj = snapshot.trees[key];\n await this.unpackSnapshotCore(obj, level + 1);\n }\n\n // For future proof, we will support multiple aggregated blobs with any name\n // that starts with this.aggregatedBlobName\n for (const key of Object.keys(snapshot.blobs)) {\n if (!key.startsWith(this.aggregatedBlobName)) { continue; }\n const blobId = snapshot.blobs[key];\n if (blobId !== undefined) {\n const blob = await this.getBlob(blobId, snapshot);\n for (const [path, value] of BlobAggregator.load(blob)) {\n const id = this.getNextVirtualId();\n this.setBlob(id, snapshot, value);\n const pathSplit = path.split(\"/\");\n let subTree = snapshot;\n for (const subPath of pathSplit.slice(0, pathSplit.length - 1)) {\n if (subTree.trees[subPath] === undefined) {\n subTree.trees[subPath] = { blobs: {}, commits: {}, trees: {}};\n }\n subTree = subTree.trees[subPath];\n }\n const blobName = pathSplit[pathSplit.length - 1];\n assert(subTree.blobs[blobName] === undefined, 0x0f6 /* \"real blob ID exists\" */);\n subTree.blobs[blobName] = id;\n }\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete snapshot.blobs[this.aggregatedBlobName];\n }\n }\n }\n}\n\n/*\n * Snapshot extractor class that works in place, i.e. patches snapshot that has\n * blob content in ISnapshotTree.blobs itself, not in storage.\n * As result, it implements reading and writing of blobs to/from snapshot itself.\n * It follows existing pattern that mixes concerns - ISnapshotTree.blobs is used for two\n * purposes:\n * 1. map path name to blob ID\n * 2. map blob ID to blob content\n * #2 is what storage (IDocumentStorageService) is for, but in places where we do not have it\n * (like loading serialized earlier draft content), blob content is put directly into snapshot.\n * Ideally this should be fixed by using BlobCacheStorageService or something similar and\n * fixing existing flows to allow switching of storage.\n */\nclass SnapshotExtractorInPlace extends SnapshotExtractor {\n public async getBlob(id: string, tree: ISnapshotTree): Promise<ArrayBufferLike> {\n const blob = tree.blobs[id];\n assert(blob !== undefined, 0x0f7 /* \"aggregate blob missing\" */);\n return stringToBuffer(blob, \"base64\");\n }\n\n public setBlob(id: string, tree: ISnapshotTree, content: string) {\n assert(tree.blobs[id] === undefined, 0x0f8 /* \"blob from aggregate blob exists on its own\" */);\n tree.blobs[id] = fromUtf8ToBase64(content);\n }\n}\n\n/*\n * Snapshot packer and extractor.\n * When summary is written it will find and aggregate small blobs into bigger blobs\n * When snapshot is read, it will unpack aggregated blobs and provide them transparently to caller.\n */\nexport class BlobAggregationStorage extends SnapshotExtractor implements IDocumentStorageService {\n // Tells data store if it can use incremental summary (i.e. reuse DDSs from previous summary\n // when only one DDS changed).\n // The answer has to be know long before we enable actual packing. The reason for the is the following:\n // A the moment when we enable packing, we should assume that all clients out there wil already have bits\n // that can unpack properly (i.e. enough time passed since we deployed bits that can unpack)\n // But we can still have clients where some of them already pack, and some do not. If one summary was\n // using packing, then it relies on non-incremental summaries going forward, even if next client who\n // produced summary is not packing!\n // This can have slight improvement by enabling it per file (based on \"did summary we loaded from contain\n // aggregated blobs\"), but that's harder to make reliable, so going for simplicity.\n static readonly fullDataStoreSummaries = true;\n\n protected loadedFromSummary = false;\n\n protected virtualBlobs = new Map<string, ArrayBufferLike>();\n\n static wrap(\n storage: IDocumentStorageService,\n logger: ITelemetryLogger,\n allowPacking?: boolean,\n packingLevel = 2,\n ) {\n if (storage instanceof BlobAggregationStorage) {\n return storage;\n }\n const mc = loggerToMonitoringContext(logger);\n const realAllowPackaging = mc.config.getBoolean(\"FluidAggregateBlobs\") ?? allowPacking ?? false;\n\n // Always create BlobAggregationStorage even if storage is not asking for packing.\n // This is mostly to avoid cases where future changes in policy would result in inability to\n // load old files that were created with aggregation on.\n const minBlobSize = storage.policies?.minBlobSize;\n return new BlobAggregationStorage(storage, logger, realAllowPackaging, packingLevel, minBlobSize);\n }\n\n static async unpackSnapshot(snapshot: ISnapshotTree) {\n const converter = new SnapshotExtractorInPlace();\n await converter.unpackSnapshotCore(snapshot);\n }\n\n public get policies(): IDocumentStorageServicePolicies | undefined {\n const policies = this.storage.policies;\n if (policies) {\n return { ...policies, minBlobSize: undefined };\n }\n }\n\n public async unpackSnapshot(snapshot: ISnapshotTree) {\n // SummarizerNodeWithGC.refreshLatestSummary can call it when this.loadedFromSummary === false\n // (I assumed after file was created)\n // assert(!this.loadedFromSummary, \"unpack without summary\");\n\n this.loadedFromSummary = true;\n await this.unpackSnapshotCore(snapshot);\n }\n\n protected constructor(\n private readonly storage: IDocumentStorageService,\n private readonly logger: ITelemetryLogger,\n private readonly allowPacking: boolean,\n private readonly packingLevel: number,\n private readonly blobCutOffSize?: number)\n {\n super();\n }\n\n public setBlob(id: string, tree: ISnapshotTree, content: string) {\n this.virtualBlobs.set(id, stringToBuffer(content, \"utf-8\"));\n }\n\n public async getBlob(id: string, tree: ISnapshotTree): Promise<ArrayBufferLike> {\n return this.readBlob(id).catch((error) => {\n this.logger.sendErrorEvent({ eventName: \"BlobDedupNoAggregateBlob\" }, error);\n throw error;\n });\n }\n\n public get repositoryUrl() { return this.storage.repositoryUrl; }\n public async getVersions(versionId: string | null, count: number) {\n return this.storage.getVersions(versionId, count);\n }\n\n public async downloadSummary(handle: ISummaryHandle): Promise<ISummaryTree> {\n throw new Error(\"NYI\");\n }\n\n // This is only used through Container.snapshot() for testing purposes\n public async write(root: ITree, parents: string[], message: string, ref: string) {\n return this.storage.write(root, parents, message, ref);\n }\n\n // for now we are not optimizing these blobs, with assumption that this API is used only\n // for big blobs (images)\n public async createBlob(file: ArrayBufferLike): Promise<ICreateBlobResponse> {\n return this.storage.createBlob(file);\n }\n\n public async getSnapshotTree(version?: IVersion): Promise<ISnapshotTree | null> {\n const tree = await this.storage.getSnapshotTree(version);\n if (tree) {\n await this.unpackSnapshot(tree);\n }\n return tree;\n }\n\n public async readBlob(id: string): Promise<ArrayBufferLike> {\n if (this.isRealStorageId(id)) {\n return this.storage.readBlob(id);\n }\n // We support only reading blobs from the summary we loaded from.\n // This may need to be extended to any general summary in the future as runtime usage pattern\n // of storage changes (for example, data stores start to load from recent summary, not from original\n // summary whole container loaded from)\n\n // are there other ways we can get here? createFile is one flow, but we should not be reading blobs\n // in such flow\n assert(this.loadedFromSummary, 0x0f9 /* \"never read summary\" */);\n const blob = this.virtualBlobs.get(id);\n assert(blob !== undefined, 0x0fa /* \"virtual blob not found\" */);\n return blob;\n }\n\n public async uploadSummaryWithContext(summary: ISummaryTree, context: ISummaryContext): Promise<string> {\n const summaryNew = this.allowPacking ? await this.compressSmallBlobs(summary) : summary;\n return this.storage.uploadSummaryWithContext(summaryNew, context);\n }\n\n // For simplification, we assume that\n // - blob aggregation is done at data store level only for now\n // - data store either reuses previous summary, or generates full summary, i.e. there is no partial (some DDS)\n // summary produced by data stores.\n // These simplifications allow us not to touch handles, as they are self-contained (either do not use aggregated\n // blob Or contain aggregated blob that stays relevant for that sub-tree)\n // Note:\n // From perf perspective, it makes sense to place aggregated blobs one level up in the tree not to create extra\n // tree nodes (i.e. have shallow tree with less edges). But that creates problems with reusability of trees at\n // incremental summary time - we would need to understand handles and parse them. In current design we can skip\n // that step because if data store is reused, the hole sub-tree is reused included aggregated blob embedded into it\n // and that means we can do nothing and be correct!\n private async compressSmallBlobs(\n summary: ISummaryTree,\n path = \"\",\n level = 0,\n aggregatorArg?: BlobAggregator): Promise<ISummaryTree>\n {\n if (this.blobCutOffSize === undefined || this.blobCutOffSize < 0) {\n return summary;\n }\n\n let shouldCompress: boolean = false;\n\n let aggregator = aggregatorArg;\n // checking if this is a dataStore tree, since we only pack at data store level\n if (Object.keys(summary.tree).includes(\".component\")) {\n assert(aggregator === undefined, 0x0fb /* \"logic err with aggregator\" */);\n assert(level === this.packingLevel, 0x23b /* \"we are not packing at the right level\" */);\n aggregator = new BlobAggregator();\n shouldCompress = true;\n } else {\n assert(level !== this.packingLevel, 0x23c /* \"we are not packing at the right level\" */);\n }\n\n const newSummary: ISummaryTree = {...summary};\n newSummary.tree = { ...newSummary.tree};\n for (const key of Object.keys(summary.tree)) {\n const obj = summary.tree[key];\n // Get path relative to root of data store (where we do aggregation)\n const newPath = shouldCompress ? key : `${path}/${key}`;\n switch (obj.type) {\n case SummaryType.Tree:\n // If client created empty tree, keep it as is\n // Also do not package search blobs - they are part of storage contract\n if (obj.tree !== {} && key !== \"__search\") {\n const tree = await this.compressSmallBlobs(obj, newPath, level + 1, aggregator);\n newSummary.tree[key] = tree;\n if (tree.tree === {}) {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete newSummary.tree[key];\n }\n }\n break;\n case SummaryType.Blob:\n if (aggregator && typeof obj.content == \"string\" && obj.content.length < this.blobCutOffSize) {\n aggregator.addBlob(newPath, obj.content);\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete newSummary.tree[key];\n }\n break;\n case SummaryType.Handle: {\n // Would be nice to:\n // Trees: expand the tree\n // Blobs: parse handle and ensure it points to real blob, not virtual blob.\n // We can avoid it for now given data store is the granularity of incremental summaries.\n let handlePath = obj.handle;\n if (handlePath.startsWith(\"/\")) {\n handlePath = handlePath.substr(1);\n }\n // Ensure only whole data stores can be reused, no reusing at deeper level!\n assert(level === 0, 0x0fc /* \"tree reuse at lower level\" */);\n assert(handlePath.indexOf(\"/\") === -1,\n 0x0fd /* \"data stores are writing incremental summaries!\" */);\n break;\n }\n case SummaryType.Attachment:\n assert(this.isRealStorageId(obj.id), 0x0fe /* \"attachment is aggregate blob\" */);\n break;\n default:\n unreachableCase(obj, `Unknown type: ${(obj as any).type}`);\n }\n }\n\n assert(newSummary.tree[this.aggregatedBlobName] === undefined, 0x0ff /* \"duplicate aggregate blob\" */);\n if (shouldCompress) {\n // Note: It would be great to add code here to unpack aggregate blob back to normal blobs\n // If only one blob made it into aggregate. Currently that does not happen as we always have\n // at least one .component blob and at least one DDS that has .attributes blob, so it's not an issue.\n // But it's possible that in future that would be great addition!\n // Good news - it's backward compatible change.\n assert(aggregator !== undefined, 0x100 /* \"logic error\" */);\n const content = aggregator.getAggregatedBlobContent();\n if (content !== undefined) {\n newSummary.tree[this.aggregatedBlobName] = {\n type: SummaryType.Blob,\n content,\n };\n }\n }\n return newSummary;\n }\n\n protected isRealStorageId(id: string): boolean {\n return !id.startsWith(this.virtualIdPrefix);\n }\n}\n"]}
1
+ {"version":3,"file":"blobAggregationStorage.js","sourceRoot":"","sources":["../src/blobAggregationStorage.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 {\n IDocumentStorageService,\n IDocumentStorageServicePolicies,\n ISummaryContext,\n} from \"@fluidframework/driver-definitions\";\nimport {\n ICreateBlobResponse,\n ISnapshotTree,\n ISummaryHandle,\n ISummaryTree,\n IVersion,\n SummaryType,\n ITree,\n} from \"@fluidframework/protocol-definitions\";\nimport {\n assert,\n bufferToString,\n stringToBuffer,\n unreachableCase,\n fromUtf8ToBase64,\n Uint8ArrayToString,\n } from \"@fluidframework/common-utils\";\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { loggerToMonitoringContext } from \"@fluidframework/telemetry-utils\";\n\n/*\n * Work around for bufferToString having a bug - it can't consume IsoBuffer!\n * To be removed once bufferToString is fixed!\n*/\nfunction bufferToString2(blob: ArrayBufferLike, encoding: \"utf-8\" | \"base64\"): string {\n if (blob instanceof Uint8Array) { // IsoBuffer does not have ctor, so it's not in proto chain :(\n return Uint8ArrayToString(blob, encoding);\n }\n return bufferToString(blob, encoding);\n}\n\n /**\n * Class responsible for aggregating smaller blobs into one and unpacking it later on.\n */\nclass BlobAggregator {\n private readonly content: [string, string][] = [];\n\n public addBlob(key: string, content: string) {\n this.content.push([key, content]);\n }\n\n public getAggregatedBlobContent() {\n if (this.content.length === 0) {\n return undefined;\n }\n return JSON.stringify(this.content);\n }\n\n static load(input: ArrayBufferLike) {\n const data = bufferToString2(input, \"utf-8\");\n return JSON.parse(data) as [string, string][];\n }\n}\n\n/*\n * Base class that deals with unpacking snapshots (in place) containing aggregated blobs\n * It relies on abstract methods for reads and storing unpacked blobs.\n */\nexport abstract class SnapshotExtractor {\n protected readonly aggregatedBlobName = \"__big\";\n protected readonly virtualIdPrefix = \"__\";\n\n // counter for generation of virtual storage IDs\n protected virtualIdCounter = 0;\n protected getNextVirtualId() {\n return `${this.virtualIdPrefix}${++this.virtualIdCounter}`;\n }\n\n abstract getBlob(id: string, tree: ISnapshotTree): Promise<ArrayBufferLike>;\n abstract setBlob(id: string, tree: ISnapshotTree, content: string);\n\n public async unpackSnapshotCore(snapshot: ISnapshotTree, level = 0): Promise<void> {\n for (const key of Object.keys(snapshot.trees)) {\n const obj = snapshot.trees[key];\n await this.unpackSnapshotCore(obj, level + 1);\n }\n\n // For future proof, we will support multiple aggregated blobs with any name\n // that starts with this.aggregatedBlobName\n for (const key of Object.keys(snapshot.blobs)) {\n if (!key.startsWith(this.aggregatedBlobName)) { continue; }\n const blobId = snapshot.blobs[key];\n if (blobId !== undefined) {\n const blob = await this.getBlob(blobId, snapshot);\n for (const [path, value] of BlobAggregator.load(blob)) {\n const id = this.getNextVirtualId();\n this.setBlob(id, snapshot, value);\n const pathSplit = path.split(\"/\");\n let subTree = snapshot;\n for (const subPath of pathSplit.slice(0, pathSplit.length - 1)) {\n if (subTree.trees[subPath] === undefined) {\n subTree.trees[subPath] = { blobs: {}, trees: {}};\n }\n subTree = subTree.trees[subPath];\n }\n const blobName = pathSplit[pathSplit.length - 1];\n assert(subTree.blobs[blobName] === undefined, 0x0f6 /* \"real blob ID exists\" */);\n subTree.blobs[blobName] = id;\n }\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete snapshot.blobs[this.aggregatedBlobName];\n }\n }\n }\n}\n\n/*\n * Snapshot extractor class that works in place, i.e. patches snapshot that has\n * blob content in ISnapshotTree.blobs itself, not in storage.\n * As result, it implements reading and writing of blobs to/from snapshot itself.\n * It follows existing pattern that mixes concerns - ISnapshotTree.blobs is used for two\n * purposes:\n * 1. map path name to blob ID\n * 2. map blob ID to blob content\n * #2 is what storage (IDocumentStorageService) is for, but in places where we do not have it\n * (like loading serialized earlier draft content), blob content is put directly into snapshot.\n * Ideally this should be fixed by using BlobCacheStorageService or something similar and\n * fixing existing flows to allow switching of storage.\n */\nclass SnapshotExtractorInPlace extends SnapshotExtractor {\n public async getBlob(id: string, tree: ISnapshotTree): Promise<ArrayBufferLike> {\n const blob = tree.blobs[id];\n assert(blob !== undefined, 0x0f7 /* \"aggregate blob missing\" */);\n return stringToBuffer(blob, \"base64\");\n }\n\n public setBlob(id: string, tree: ISnapshotTree, content: string) {\n assert(tree.blobs[id] === undefined, 0x0f8 /* \"blob from aggregate blob exists on its own\" */);\n tree.blobs[id] = fromUtf8ToBase64(content);\n }\n}\n\n/*\n * Snapshot packer and extractor.\n * When summary is written it will find and aggregate small blobs into bigger blobs\n * When snapshot is read, it will unpack aggregated blobs and provide them transparently to caller.\n */\nexport class BlobAggregationStorage extends SnapshotExtractor implements IDocumentStorageService {\n // Tells data store if it can use incremental summary (i.e. reuse DDSs from previous summary\n // when only one DDS changed).\n // The answer has to be know long before we enable actual packing. The reason for the is the following:\n // A the moment when we enable packing, we should assume that all clients out there wil already have bits\n // that can unpack properly (i.e. enough time passed since we deployed bits that can unpack)\n // But we can still have clients where some of them already pack, and some do not. If one summary was\n // using packing, then it relies on non-incremental summaries going forward, even if next client who\n // produced summary is not packing!\n // This can have slight improvement by enabling it per file (based on \"did summary we loaded from contain\n // aggregated blobs\"), but that's harder to make reliable, so going for simplicity.\n static readonly fullDataStoreSummaries = true;\n\n protected loadedFromSummary = false;\n\n protected virtualBlobs = new Map<string, ArrayBufferLike>();\n\n static wrap(\n storage: IDocumentStorageService,\n logger: ITelemetryLogger,\n allowPacking?: boolean,\n packingLevel = 2,\n ) {\n if (storage instanceof BlobAggregationStorage) {\n return storage;\n }\n const mc = loggerToMonitoringContext(logger);\n const realAllowPackaging = mc.config.getBoolean(\"FluidAggregateBlobs\") ?? allowPacking ?? false;\n\n // Always create BlobAggregationStorage even if storage is not asking for packing.\n // This is mostly to avoid cases where future changes in policy would result in inability to\n // load old files that were created with aggregation on.\n const minBlobSize = storage.policies?.minBlobSize;\n return new BlobAggregationStorage(storage, logger, realAllowPackaging, packingLevel, minBlobSize);\n }\n\n static async unpackSnapshot(snapshot: ISnapshotTree) {\n const converter = new SnapshotExtractorInPlace();\n await converter.unpackSnapshotCore(snapshot);\n }\n\n public get policies(): IDocumentStorageServicePolicies | undefined {\n const policies = this.storage.policies;\n if (policies) {\n return { ...policies, minBlobSize: undefined };\n }\n }\n\n public async unpackSnapshot(snapshot: ISnapshotTree) {\n // SummarizerNodeWithGC.refreshLatestSummary can call it when this.loadedFromSummary === false\n // (I assumed after file was created)\n // assert(!this.loadedFromSummary, \"unpack without summary\");\n\n this.loadedFromSummary = true;\n await this.unpackSnapshotCore(snapshot);\n }\n\n protected constructor(\n private readonly storage: IDocumentStorageService,\n private readonly logger: ITelemetryLogger,\n private readonly allowPacking: boolean,\n private readonly packingLevel: number,\n private readonly blobCutOffSize?: number)\n {\n super();\n }\n\n public setBlob(id: string, tree: ISnapshotTree, content: string) {\n this.virtualBlobs.set(id, stringToBuffer(content, \"utf-8\"));\n }\n\n public async getBlob(id: string, tree: ISnapshotTree): Promise<ArrayBufferLike> {\n return this.readBlob(id).catch((error) => {\n this.logger.sendErrorEvent({ eventName: \"BlobDedupNoAggregateBlob\" }, error);\n throw error;\n });\n }\n\n public get repositoryUrl() { return this.storage.repositoryUrl; }\n public async getVersions(versionId: string | null, count: number) {\n return this.storage.getVersions(versionId, count);\n }\n\n public async downloadSummary(handle: ISummaryHandle): Promise<ISummaryTree> {\n throw new Error(\"NYI\");\n }\n\n // This is only used through Container.snapshot() for testing purposes\n public async write(root: ITree, parents: string[], message: string, ref: string) {\n return this.storage.write(root, parents, message, ref);\n }\n\n // for now we are not optimizing these blobs, with assumption that this API is used only\n // for big blobs (images)\n public async createBlob(file: ArrayBufferLike): Promise<ICreateBlobResponse> {\n return this.storage.createBlob(file);\n }\n\n public async getSnapshotTree(version?: IVersion): Promise<ISnapshotTree | null> {\n const tree = await this.storage.getSnapshotTree(version);\n if (tree) {\n await this.unpackSnapshot(tree);\n }\n return tree;\n }\n\n public async readBlob(id: string): Promise<ArrayBufferLike> {\n if (this.isRealStorageId(id)) {\n return this.storage.readBlob(id);\n }\n // We support only reading blobs from the summary we loaded from.\n // This may need to be extended to any general summary in the future as runtime usage pattern\n // of storage changes (for example, data stores start to load from recent summary, not from original\n // summary whole container loaded from)\n\n // are there other ways we can get here? createFile is one flow, but we should not be reading blobs\n // in such flow\n assert(this.loadedFromSummary, 0x0f9 /* \"never read summary\" */);\n const blob = this.virtualBlobs.get(id);\n assert(blob !== undefined, 0x0fa /* \"virtual blob not found\" */);\n return blob;\n }\n\n public async uploadSummaryWithContext(summary: ISummaryTree, context: ISummaryContext): Promise<string> {\n const summaryNew = this.allowPacking ? await this.compressSmallBlobs(summary) : summary;\n return this.storage.uploadSummaryWithContext(summaryNew, context);\n }\n\n // For simplification, we assume that\n // - blob aggregation is done at data store level only for now\n // - data store either reuses previous summary, or generates full summary, i.e. there is no partial (some DDS)\n // summary produced by data stores.\n // These simplifications allow us not to touch handles, as they are self-contained (either do not use aggregated\n // blob Or contain aggregated blob that stays relevant for that sub-tree)\n // Note:\n // From perf perspective, it makes sense to place aggregated blobs one level up in the tree not to create extra\n // tree nodes (i.e. have shallow tree with less edges). But that creates problems with reusability of trees at\n // incremental summary time - we would need to understand handles and parse them. In current design we can skip\n // that step because if data store is reused, the hole sub-tree is reused included aggregated blob embedded into it\n // and that means we can do nothing and be correct!\n private async compressSmallBlobs(\n summary: ISummaryTree,\n path = \"\",\n level = 0,\n aggregatorArg?: BlobAggregator): Promise<ISummaryTree>\n {\n if (this.blobCutOffSize === undefined || this.blobCutOffSize < 0) {\n return summary;\n }\n\n let shouldCompress: boolean = false;\n\n let aggregator = aggregatorArg;\n // checking if this is a dataStore tree, since we only pack at data store level\n if (Object.keys(summary.tree).includes(\".component\")) {\n assert(aggregator === undefined, 0x0fb /* \"logic err with aggregator\" */);\n assert(level === this.packingLevel, 0x23b /* \"we are not packing at the right level\" */);\n aggregator = new BlobAggregator();\n shouldCompress = true;\n } else {\n assert(level !== this.packingLevel, 0x23c /* \"we are not packing at the right level\" */);\n }\n\n const newSummary: ISummaryTree = {...summary};\n newSummary.tree = { ...newSummary.tree};\n for (const key of Object.keys(summary.tree)) {\n const obj = summary.tree[key];\n // Get path relative to root of data store (where we do aggregation)\n const newPath = shouldCompress ? key : `${path}/${key}`;\n switch (obj.type) {\n case SummaryType.Tree:\n // If client created empty tree, keep it as is\n // Also do not package search blobs - they are part of storage contract\n if (obj.tree !== {} && key !== \"__search\") {\n const tree = await this.compressSmallBlobs(obj, newPath, level + 1, aggregator);\n newSummary.tree[key] = tree;\n if (tree.tree === {}) {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete newSummary.tree[key];\n }\n }\n break;\n case SummaryType.Blob:\n if (aggregator && typeof obj.content == \"string\" && obj.content.length < this.blobCutOffSize) {\n aggregator.addBlob(newPath, obj.content);\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete newSummary.tree[key];\n }\n break;\n case SummaryType.Handle: {\n // Would be nice to:\n // Trees: expand the tree\n // Blobs: parse handle and ensure it points to real blob, not virtual blob.\n // We can avoid it for now given data store is the granularity of incremental summaries.\n let handlePath = obj.handle;\n if (handlePath.startsWith(\"/\")) {\n handlePath = handlePath.substr(1);\n }\n // Ensure only whole data stores can be reused, no reusing at deeper level!\n assert(level === 0, 0x0fc /* \"tree reuse at lower level\" */);\n assert(handlePath.indexOf(\"/\") === -1,\n 0x0fd /* \"data stores are writing incremental summaries!\" */);\n break;\n }\n case SummaryType.Attachment:\n assert(this.isRealStorageId(obj.id), 0x0fe /* \"attachment is aggregate blob\" */);\n break;\n default:\n unreachableCase(obj, `Unknown type: ${(obj as any).type}`);\n }\n }\n\n assert(newSummary.tree[this.aggregatedBlobName] === undefined, 0x0ff /* \"duplicate aggregate blob\" */);\n if (shouldCompress) {\n // Note: It would be great to add code here to unpack aggregate blob back to normal blobs\n // If only one blob made it into aggregate. Currently that does not happen as we always have\n // at least one .component blob and at least one DDS that has .attributes blob, so it's not an issue.\n // But it's possible that in future that would be great addition!\n // Good news - it's backward compatible change.\n assert(aggregator !== undefined, 0x100 /* \"logic error\" */);\n const content = aggregator.getAggregatedBlobContent();\n if (content !== undefined) {\n newSummary.tree[this.aggregatedBlobName] = {\n type: SummaryType.Blob,\n content,\n };\n }\n }\n return newSummary;\n }\n\n protected isRealStorageId(id: string): boolean {\n return !id.startsWith(this.virtualIdPrefix);\n }\n}\n"]}
@@ -10,7 +10,7 @@ export declare class MultiDocumentServiceFactory implements IDocumentServiceFact
10
10
  private readonly protocolToDocumentFactoryMap;
11
11
  constructor(documentServiceFactories: IDocumentServiceFactory[]);
12
12
  readonly protocolName = "none:";
13
- createDocumentService(resolvedUrl: IResolvedUrl, logger?: ITelemetryBaseLogger): Promise<IDocumentService>;
14
- createContainer(createNewSummary: ISummaryTree, createNewResolvedUrl: IResolvedUrl, logger?: ITelemetryBaseLogger): Promise<IDocumentService>;
13
+ createDocumentService(resolvedUrl: IResolvedUrl, logger?: ITelemetryBaseLogger, clientIsSummarizer?: boolean): Promise<IDocumentService>;
14
+ createContainer(createNewSummary: ISummaryTree, createNewResolvedUrl: IResolvedUrl, logger?: ITelemetryBaseLogger, clientIsSummarizer?: boolean): Promise<IDocumentService>;
15
15
  }
16
16
  //# sourceMappingURL=multiDocumentServiceFactory.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"multiDocumentServiceFactory.d.ts","sourceRoot":"","sources":["../src/multiDocumentServiceFactory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACH,uBAAuB,EACvB,YAAY,EACZ,gBAAgB,EACnB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAG1E,qBAAa,2BAA4B,YAAW,uBAAuB;WACzD,MAAM,CAAC,sBAAsB,EAAE,uBAAuB,GAAG,uBAAuB,EAAE;IAmBhG,OAAO,CAAC,QAAQ,CAAC,4BAA4B,CAAuC;gBAExE,wBAAwB,EAAE,uBAAuB,EAAE;IAM/D,SAAgB,YAAY,WAAW;IACjC,qBAAqB,CAAC,WAAW,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAcnG,eAAe,CACxB,gBAAgB,EAAE,YAAY,EAC9B,oBAAoB,EAAE,YAAY,EAClC,MAAM,CAAC,EAAE,oBAAoB,GAC9B,OAAO,CAAC,gBAAgB,CAAC;CAY/B"}
1
+ {"version":3,"file":"multiDocumentServiceFactory.d.ts","sourceRoot":"","sources":["../src/multiDocumentServiceFactory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACH,uBAAuB,EACvB,YAAY,EACZ,gBAAgB,EACnB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAG1E,qBAAa,2BAA4B,YAAW,uBAAuB;WACzD,MAAM,CAAC,sBAAsB,EAAE,uBAAuB,GAAG,uBAAuB,EAAE;IAmBhG,OAAO,CAAC,QAAQ,CAAC,4BAA4B,CAAuC;gBAExE,wBAAwB,EAAE,uBAAuB,EAAE;IAM/D,SAAgB,YAAY,WAAW;IACjC,qBAAqB,CACvB,WAAW,EAAE,YAAY,EACzB,MAAM,CAAC,EAAE,oBAAoB,EAC7B,kBAAkB,CAAC,EAAE,OAAO,GAC7B,OAAO,CAAC,gBAAgB,CAAC;IAcf,eAAe,CACxB,gBAAgB,EAAE,YAAY,EAC9B,oBAAoB,EAAE,YAAY,EAClC,MAAM,CAAC,EAAE,oBAAoB,EAC7B,kBAAkB,CAAC,EAAE,OAAO,GAC7B,OAAO,CAAC,gBAAgB,CAAC;CAY/B"}
@@ -34,7 +34,7 @@ class MultiDocumentServiceFactory {
34
34
  }
35
35
  return documentServiceFactory;
36
36
  }
37
- async createDocumentService(resolvedUrl, logger) {
37
+ async createDocumentService(resolvedUrl, logger, clientIsSummarizer) {
38
38
  fluidResolvedUrl_1.ensureFluidResolvedUrl(resolvedUrl);
39
39
  const urlObj = url_1.parse(resolvedUrl.url);
40
40
  if (urlObj.protocol === undefined || urlObj.protocol === null) {
@@ -44,9 +44,9 @@ class MultiDocumentServiceFactory {
44
44
  if (factory === undefined) {
45
45
  throw new Error("Unknown Fluid protocol");
46
46
  }
47
- return factory.createDocumentService(resolvedUrl, logger);
47
+ return factory.createDocumentService(resolvedUrl, logger, clientIsSummarizer);
48
48
  }
49
- async createContainer(createNewSummary, createNewResolvedUrl, logger) {
49
+ async createContainer(createNewSummary, createNewResolvedUrl, logger, clientIsSummarizer) {
50
50
  fluidResolvedUrl_1.ensureFluidResolvedUrl(createNewResolvedUrl);
51
51
  const urlObj = url_1.parse(createNewResolvedUrl.url);
52
52
  if (urlObj.protocol === undefined || urlObj.protocol === null) {
@@ -56,7 +56,7 @@ class MultiDocumentServiceFactory {
56
56
  if (factory === undefined) {
57
57
  throw new Error("Unknown Fluid protocol");
58
58
  }
59
- return factory.createContainer(createNewSummary, createNewResolvedUrl, logger);
59
+ return factory.createContainer(createNewSummary, createNewResolvedUrl, logger, clientIsSummarizer);
60
60
  }
61
61
  }
62
62
  exports.MultiDocumentServiceFactory = MultiDocumentServiceFactory;
@@ -1 +1 @@
1
- {"version":3,"file":"multiDocumentServiceFactory.js","sourceRoot":"","sources":["../src/multiDocumentServiceFactory.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,6BAA4B;AAQ5B,yDAA4D;AAE5D,MAAa,2BAA2B;IAsBpC,YAAY,wBAAmD;QAM/C,iBAAY,GAAG,OAAO,CAAC;QALnC,IAAI,CAAC,4BAA4B,GAAG,IAAI,GAAG,EAAE,CAAC;QAC9C,wBAAwB,CAAC,OAAO,CAAC,CAAC,OAAgC,EAAE,EAAE;YAClE,IAAI,CAAC,4BAA4B,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QACzE,CAAC,CAAC,CAAC;IACP,CAAC;IA1BM,MAAM,CAAC,MAAM,CAAC,sBAA2E;QAC5F,IAAI,KAAK,CAAC,OAAO,CAAC,sBAAsB,CAAC,EAAE;YACvC,MAAM,SAAS,GAA8B,EAAE,CAAC;YAChD,sBAAsB,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;gBACvC,MAAM,UAAU,GAAG,OAAsC,CAAC;gBAC1D,IAAI,UAAU,CAAC,4BAA4B,KAAK,SAAS,EAAE;oBACvD,SAAS,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,4BAA4B,CAAC,MAAM,EAAE,CAAC,CAAC;iBACvE;qBAAM;oBACH,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;iBAC3B;YACL,CAAC,CAAC,CAAC;YACH,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE;gBACxB,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC;aACvB;YACD,OAAO,IAAI,2BAA2B,CAAC,SAAS,CAAC,CAAC;SACrD;QACD,OAAO,sBAAsB,CAAC;IAClC,CAAC;IAWD,KAAK,CAAC,qBAAqB,CAAC,WAAyB,EAAE,MAA6B;QAChF,yCAAsB,CAAC,WAAW,CAAC,CAAC;QACpC,MAAM,MAAM,GAAG,WAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACtC,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,KAAK,IAAI,EAAE;YAC3D,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;SAC3C;QACD,MAAM,OAAO,GAAwC,IAAI,CAAC,4BAA4B,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC5G,IAAI,OAAO,KAAK,SAAS,EAAE;YACvB,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;SAC7C;QAED,OAAO,OAAO,CAAC,qBAAqB,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IAC9D,CAAC;IAEM,KAAK,CAAC,eAAe,CACxB,gBAA8B,EAC9B,oBAAkC,EAClC,MAA6B;QAE7B,yCAAsB,CAAC,oBAAoB,CAAC,CAAC;QAC7C,MAAM,MAAM,GAAG,WAAK,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC;QAC/C,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,KAAK,IAAI,EAAE;YAC3D,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;SAC3C;QACD,MAAM,OAAO,GAAwC,IAAI,CAAC,4BAA4B,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC5G,IAAI,OAAO,KAAK,SAAS,EAAE;YACvB,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;SAC7C;QACD,OAAO,OAAO,CAAC,eAAe,CAAC,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,CAAC,CAAC;IACnF,CAAC;CACJ;AA3DD,kEA2DC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { parse } from \"url\";\nimport {\n IDocumentServiceFactory,\n IResolvedUrl,\n IDocumentService,\n} from \"@fluidframework/driver-definitions\";\nimport { ISummaryTree } from \"@fluidframework/protocol-definitions\";\nimport { ITelemetryBaseLogger } from \"@fluidframework/common-definitions\";\nimport { ensureFluidResolvedUrl } from \"./fluidResolvedUrl\";\n\nexport class MultiDocumentServiceFactory implements IDocumentServiceFactory {\n public static create(documentServiceFactory: IDocumentServiceFactory | IDocumentServiceFactory[]) {\n if (Array.isArray(documentServiceFactory)) {\n const factories: IDocumentServiceFactory[] = [];\n documentServiceFactory.forEach((factory) => {\n const maybeMulti = factory as MultiDocumentServiceFactory;\n if (maybeMulti.protocolToDocumentFactoryMap !== undefined) {\n factories.push(...maybeMulti.protocolToDocumentFactoryMap.values());\n } else {\n factories.push(factory);\n }\n });\n if (factories.length === 1) {\n return factories[0];\n }\n return new MultiDocumentServiceFactory(factories);\n }\n return documentServiceFactory;\n }\n\n private readonly protocolToDocumentFactoryMap: Map<string, IDocumentServiceFactory>;\n\n constructor(documentServiceFactories: IDocumentServiceFactory[]) {\n this.protocolToDocumentFactoryMap = new Map();\n documentServiceFactories.forEach((factory: IDocumentServiceFactory) => {\n this.protocolToDocumentFactoryMap.set(factory.protocolName, factory);\n });\n }\n public readonly protocolName = \"none:\";\n async createDocumentService(resolvedUrl: IResolvedUrl, logger?: ITelemetryBaseLogger): Promise<IDocumentService> {\n ensureFluidResolvedUrl(resolvedUrl);\n const urlObj = parse(resolvedUrl.url);\n if (urlObj.protocol === undefined || urlObj.protocol === null) {\n throw new Error(\"No protocol provided\");\n }\n const factory: IDocumentServiceFactory | undefined = this.protocolToDocumentFactoryMap.get(urlObj.protocol);\n if (factory === undefined) {\n throw new Error(\"Unknown Fluid protocol\");\n }\n\n return factory.createDocumentService(resolvedUrl, logger);\n }\n\n public async createContainer(\n createNewSummary: ISummaryTree,\n createNewResolvedUrl: IResolvedUrl,\n logger?: ITelemetryBaseLogger,\n ): Promise<IDocumentService> {\n ensureFluidResolvedUrl(createNewResolvedUrl);\n const urlObj = parse(createNewResolvedUrl.url);\n if (urlObj.protocol === undefined || urlObj.protocol === null) {\n throw new Error(\"No protocol provided\");\n }\n const factory: IDocumentServiceFactory | undefined = this.protocolToDocumentFactoryMap.get(urlObj.protocol);\n if (factory === undefined) {\n throw new Error(\"Unknown Fluid protocol\");\n }\n return factory.createContainer(createNewSummary, createNewResolvedUrl, logger);\n }\n}\n"]}
1
+ {"version":3,"file":"multiDocumentServiceFactory.js","sourceRoot":"","sources":["../src/multiDocumentServiceFactory.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,6BAA4B;AAQ5B,yDAA4D;AAE5D,MAAa,2BAA2B;IAsBpC,YAAY,wBAAmD;QAM/C,iBAAY,GAAG,OAAO,CAAC;QALnC,IAAI,CAAC,4BAA4B,GAAG,IAAI,GAAG,EAAE,CAAC;QAC9C,wBAAwB,CAAC,OAAO,CAAC,CAAC,OAAgC,EAAE,EAAE;YAClE,IAAI,CAAC,4BAA4B,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QACzE,CAAC,CAAC,CAAC;IACP,CAAC;IA1BM,MAAM,CAAC,MAAM,CAAC,sBAA2E;QAC5F,IAAI,KAAK,CAAC,OAAO,CAAC,sBAAsB,CAAC,EAAE;YACvC,MAAM,SAAS,GAA8B,EAAE,CAAC;YAChD,sBAAsB,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;gBACvC,MAAM,UAAU,GAAG,OAAsC,CAAC;gBAC1D,IAAI,UAAU,CAAC,4BAA4B,KAAK,SAAS,EAAE;oBACvD,SAAS,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,4BAA4B,CAAC,MAAM,EAAE,CAAC,CAAC;iBACvE;qBAAM;oBACH,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;iBAC3B;YACL,CAAC,CAAC,CAAC;YACH,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE;gBACxB,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC;aACvB;YACD,OAAO,IAAI,2BAA2B,CAAC,SAAS,CAAC,CAAC;SACrD;QACD,OAAO,sBAAsB,CAAC;IAClC,CAAC;IAWD,KAAK,CAAC,qBAAqB,CACvB,WAAyB,EACzB,MAA6B,EAC7B,kBAA4B;QAE5B,yCAAsB,CAAC,WAAW,CAAC,CAAC;QACpC,MAAM,MAAM,GAAG,WAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACtC,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,KAAK,IAAI,EAAE;YAC3D,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;SAC3C;QACD,MAAM,OAAO,GAAwC,IAAI,CAAC,4BAA4B,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC5G,IAAI,OAAO,KAAK,SAAS,EAAE;YACvB,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;SAC7C;QAED,OAAO,OAAO,CAAC,qBAAqB,CAAC,WAAW,EAAE,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAClF,CAAC;IAEM,KAAK,CAAC,eAAe,CACxB,gBAA8B,EAC9B,oBAAkC,EAClC,MAA6B,EAC7B,kBAA4B;QAE5B,yCAAsB,CAAC,oBAAoB,CAAC,CAAC;QAC7C,MAAM,MAAM,GAAG,WAAK,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC;QAC/C,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,KAAK,IAAI,EAAE;YAC3D,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;SAC3C;QACD,MAAM,OAAO,GAAwC,IAAI,CAAC,4BAA4B,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC5G,IAAI,OAAO,KAAK,SAAS,EAAE;YACvB,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;SAC7C;QACD,OAAO,OAAO,CAAC,eAAe,CAAC,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,EAAE,kBAAkB,CAAC,CAAC;IACvG,CAAC;CACJ;AAhED,kEAgEC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { parse } from \"url\";\nimport {\n IDocumentServiceFactory,\n IResolvedUrl,\n IDocumentService,\n} from \"@fluidframework/driver-definitions\";\nimport { ISummaryTree } from \"@fluidframework/protocol-definitions\";\nimport { ITelemetryBaseLogger } from \"@fluidframework/common-definitions\";\nimport { ensureFluidResolvedUrl } from \"./fluidResolvedUrl\";\n\nexport class MultiDocumentServiceFactory implements IDocumentServiceFactory {\n public static create(documentServiceFactory: IDocumentServiceFactory | IDocumentServiceFactory[]) {\n if (Array.isArray(documentServiceFactory)) {\n const factories: IDocumentServiceFactory[] = [];\n documentServiceFactory.forEach((factory) => {\n const maybeMulti = factory as MultiDocumentServiceFactory;\n if (maybeMulti.protocolToDocumentFactoryMap !== undefined) {\n factories.push(...maybeMulti.protocolToDocumentFactoryMap.values());\n } else {\n factories.push(factory);\n }\n });\n if (factories.length === 1) {\n return factories[0];\n }\n return new MultiDocumentServiceFactory(factories);\n }\n return documentServiceFactory;\n }\n\n private readonly protocolToDocumentFactoryMap: Map<string, IDocumentServiceFactory>;\n\n constructor(documentServiceFactories: IDocumentServiceFactory[]) {\n this.protocolToDocumentFactoryMap = new Map();\n documentServiceFactories.forEach((factory: IDocumentServiceFactory) => {\n this.protocolToDocumentFactoryMap.set(factory.protocolName, factory);\n });\n }\n public readonly protocolName = \"none:\";\n async createDocumentService(\n resolvedUrl: IResolvedUrl,\n logger?: ITelemetryBaseLogger,\n clientIsSummarizer?: boolean,\n ): Promise<IDocumentService> {\n ensureFluidResolvedUrl(resolvedUrl);\n const urlObj = parse(resolvedUrl.url);\n if (urlObj.protocol === undefined || urlObj.protocol === null) {\n throw new Error(\"No protocol provided\");\n }\n const factory: IDocumentServiceFactory | undefined = this.protocolToDocumentFactoryMap.get(urlObj.protocol);\n if (factory === undefined) {\n throw new Error(\"Unknown Fluid protocol\");\n }\n\n return factory.createDocumentService(resolvedUrl, logger, clientIsSummarizer);\n }\n\n public async createContainer(\n createNewSummary: ISummaryTree,\n createNewResolvedUrl: IResolvedUrl,\n logger?: ITelemetryBaseLogger,\n clientIsSummarizer?: boolean,\n ): Promise<IDocumentService> {\n ensureFluidResolvedUrl(createNewResolvedUrl);\n const urlObj = parse(createNewResolvedUrl.url);\n if (urlObj.protocol === undefined || urlObj.protocol === null) {\n throw new Error(\"No protocol provided\");\n }\n const factory: IDocumentServiceFactory | undefined = this.protocolToDocumentFactoryMap.get(urlObj.protocol);\n if (factory === undefined) {\n throw new Error(\"Unknown Fluid protocol\");\n }\n return factory.createContainer(createNewSummary, createNewResolvedUrl, logger, clientIsSummarizer);\n }\n}\n"]}
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export declare const pkgName = "@fluidframework/driver-utils";
8
- export declare const pkgVersion = "0.58.2002";
8
+ export declare const pkgVersion = "0.59.1000";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -8,5 +8,5 @@
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.pkgVersion = exports.pkgName = void 0;
10
10
  exports.pkgName = "@fluidframework/driver-utils";
11
- exports.pkgVersion = "0.58.2002";
11
+ exports.pkgVersion = "0.59.1000";
12
12
  //# sourceMappingURL=packageVersion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,8BAA8B,CAAC;AACzC,QAAA,UAAU,GAAG,WAAW,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/driver-utils\";\nexport const pkgVersion = \"0.58.2002\";\n"]}
1
+ {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,8BAA8B,CAAC;AACzC,QAAA,UAAU,GAAG,WAAW,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/driver-utils\";\nexport const pkgVersion = \"0.59.1000\";\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"prefetchDocumentStorageService.d.ts","sourceRoot":"","sources":["../src/prefetchDocumentStorageService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,EACH,aAAa,EACb,QAAQ,EACX,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAG5E,qBAAa,8BAA+B,SAAQ,2BAA2B;IAE3E,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA+C;IAC7E,OAAO,CAAC,eAAe,CAAQ;IAE/B,IAAW,QAAQ;;;;kBAKlB;IAEY,eAAe,CAAC,OAAO,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAYlE,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAGxD,YAAY;YAKL,UAAU;IAkBxB,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,gBAAgB;CAyB3B"}
1
+ {"version":3,"file":"prefetchDocumentStorageService.d.ts","sourceRoot":"","sources":["../src/prefetchDocumentStorageService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,EACH,aAAa,EACb,QAAQ,EACX,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAG5E,qBAAa,8BAA+B,SAAQ,2BAA2B;IAE3E,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA+C;IAC7E,OAAO,CAAC,eAAe,CAAQ;IAE/B,IAAW,QAAQ;;;;kBAKlB;IAEY,eAAe,CAAC,OAAO,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAYlE,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAGxD,YAAY;YAKL,UAAU;IAkBxB,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,gBAAgB;CAmB3B"}
@@ -81,11 +81,6 @@ class PrefetchDocumentStorageService extends documentStorageServiceProxy_1.Docum
81
81
  }
82
82
  }
83
83
  }
84
- for (const commit of Object.keys(tree.commits)) {
85
- // We don't care if the prefetch succeeds
86
- void this.getVersions(tree.commits[commit], 1)
87
- .then(async (moduleCommit) => this.getSnapshotTree(moduleCommit[0]));
88
- }
89
84
  for (const subTree of Object.keys(tree.trees)) {
90
85
  this.prefetchTreeCore(tree.trees[subTree], secondary);
91
86
  }
@@ -1 +1 @@
1
- {"version":3,"file":"prefetchDocumentStorageService.js","sourceRoot":"","sources":["../src/prefetchDocumentStorageService.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 */\nimport { LoaderCachingPolicy } from \"@fluidframework/driver-definitions\";\nimport {\n ISnapshotTree,\n IVersion,\n} from \"@fluidframework/protocol-definitions\";\nimport { DocumentStorageServiceProxy } from \"./documentStorageServiceProxy\";\nimport { canRetryOnError } from \"./network\";\n\nexport class PrefetchDocumentStorageService extends DocumentStorageServiceProxy {\n // BlobId -> blob prefetchCache cache\n private readonly prefetchCache = new Map<string, Promise<ArrayBufferLike>>();\n private prefetchEnabled = true;\n\n public get policies() {\n const policies = this.internalStorageService.policies;\n if (policies) {\n return { ...policies, caching: LoaderCachingPolicy.NoCaching };\n }\n }\n\n public async getSnapshotTree(version?: IVersion): Promise<ISnapshotTree | null> {\n const p = this.internalStorageService.getSnapshotTree(version);\n if (this.prefetchEnabled) {\n // We don't care if the prefetch succeeds\n void p.then((tree: ISnapshotTree | null | undefined) => {\n if (tree === null || tree === undefined) { return; }\n this.prefetchTree(tree);\n });\n }\n return p;\n }\n\n public async readBlob(blobId: string): Promise<ArrayBufferLike> {\n return this.cachedRead(blobId);\n }\n public stopPrefetch() {\n this.prefetchEnabled = false;\n this.prefetchCache.clear();\n }\n\n private async cachedRead(blobId: string): Promise<ArrayBufferLike> {\n if (this.prefetchEnabled) {\n const prefetchedBlobP = this.prefetchCache.get(blobId);\n if (prefetchedBlobP !== undefined) {\n return prefetchedBlobP;\n }\n const prefetchedBlobPFromStorage = this.internalStorageService.readBlob(blobId);\n this.prefetchCache.set(blobId, prefetchedBlobPFromStorage.catch((error) => {\n if (canRetryOnError(error)) {\n this.prefetchCache.delete(blobId);\n }\n throw error;\n }));\n return prefetchedBlobPFromStorage;\n }\n return this.internalStorageService.readBlob(blobId);\n }\n\n private prefetchTree(tree: ISnapshotTree) {\n const secondary: string[] = [];\n this.prefetchTreeCore(tree, secondary);\n\n for (const blob of secondary) {\n // We don't care if the prefetch succeeds\n void this.cachedRead(blob);\n }\n }\n\n private prefetchTreeCore(tree: ISnapshotTree, secondary: string[]) {\n for (const blobKey of Object.keys(tree.blobs)) {\n const blob = tree.blobs[blobKey];\n if (blobKey.startsWith(\".\") || blobKey === \"header\" || blobKey.startsWith(\"quorum\")) {\n if (blob !== null) {\n // We don't care if the prefetch succeeds\n void this.cachedRead(blob);\n }\n } else if (!blobKey.startsWith(\"deltas\")) {\n if (blob !== null) {\n secondary.push(blob);\n }\n }\n }\n\n for (const commit of Object.keys(tree.commits)) {\n // We don't care if the prefetch succeeds\n void this.getVersions(tree.commits[commit], 1)\n .then(async (moduleCommit) => this.getSnapshotTree(moduleCommit[0]));\n }\n\n for (const subTree of Object.keys(tree.trees)) {\n this.prefetchTreeCore(tree.trees[subTree], secondary);\n }\n }\n}\n"]}
1
+ {"version":3,"file":"prefetchDocumentStorageService.js","sourceRoot":"","sources":["../src/prefetchDocumentStorageService.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 */\nimport { LoaderCachingPolicy } from \"@fluidframework/driver-definitions\";\nimport {\n ISnapshotTree,\n IVersion,\n} from \"@fluidframework/protocol-definitions\";\nimport { DocumentStorageServiceProxy } from \"./documentStorageServiceProxy\";\nimport { canRetryOnError } from \"./network\";\n\nexport class PrefetchDocumentStorageService extends DocumentStorageServiceProxy {\n // BlobId -> blob prefetchCache cache\n private readonly prefetchCache = new Map<string, Promise<ArrayBufferLike>>();\n private prefetchEnabled = true;\n\n public get policies() {\n const policies = this.internalStorageService.policies;\n if (policies) {\n return { ...policies, caching: LoaderCachingPolicy.NoCaching };\n }\n }\n\n public async getSnapshotTree(version?: IVersion): Promise<ISnapshotTree | null> {\n const p = this.internalStorageService.getSnapshotTree(version);\n if (this.prefetchEnabled) {\n // We don't care if the prefetch succeeds\n void p.then((tree: ISnapshotTree | null | undefined) => {\n if (tree === null || tree === undefined) { return; }\n this.prefetchTree(tree);\n });\n }\n return p;\n }\n\n public async readBlob(blobId: string): Promise<ArrayBufferLike> {\n return this.cachedRead(blobId);\n }\n public stopPrefetch() {\n this.prefetchEnabled = false;\n this.prefetchCache.clear();\n }\n\n private async cachedRead(blobId: string): Promise<ArrayBufferLike> {\n if (this.prefetchEnabled) {\n const prefetchedBlobP = this.prefetchCache.get(blobId);\n if (prefetchedBlobP !== undefined) {\n return prefetchedBlobP;\n }\n const prefetchedBlobPFromStorage = this.internalStorageService.readBlob(blobId);\n this.prefetchCache.set(blobId, prefetchedBlobPFromStorage.catch((error) => {\n if (canRetryOnError(error)) {\n this.prefetchCache.delete(blobId);\n }\n throw error;\n }));\n return prefetchedBlobPFromStorage;\n }\n return this.internalStorageService.readBlob(blobId);\n }\n\n private prefetchTree(tree: ISnapshotTree) {\n const secondary: string[] = [];\n this.prefetchTreeCore(tree, secondary);\n\n for (const blob of secondary) {\n // We don't care if the prefetch succeeds\n void this.cachedRead(blob);\n }\n }\n\n private prefetchTreeCore(tree: ISnapshotTree, secondary: string[]) {\n for (const blobKey of Object.keys(tree.blobs)) {\n const blob = tree.blobs[blobKey];\n if (blobKey.startsWith(\".\") || blobKey === \"header\" || blobKey.startsWith(\"quorum\")) {\n if (blob !== null) {\n // We don't care if the prefetch succeeds\n void this.cachedRead(blob);\n }\n } else if (!blobKey.startsWith(\"deltas\")) {\n if (blob !== null) {\n secondary.push(blob);\n }\n }\n }\n\n for (const subTree of Object.keys(tree.trees)) {\n this.prefetchTreeCore(tree.trees[subTree], secondary);\n }\n }\n}\n"]}
@@ -27,7 +27,7 @@ export interface IProgress {
27
27
  * as well as information provided by service (like 429 error asking to wait for some time before retry)
28
28
  * @param error - error object returned from the call.
29
29
  */
30
- retry?(delayInMs: number, error: any): void;
30
+ onRetry?(delayInMs: number, error: any): void;
31
31
  }
32
32
  export declare function runWithRetry<T>(api: (cancel?: AbortSignal) => Promise<T>, fetchCallName: string, logger: ITelemetryLogger, progress: IProgress): Promise<T>;
33
33
  //# sourceMappingURL=runWithRetry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"runWithRetry.d.ts","sourceRoot":"","sources":["../src/runWithRetry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAItE;;;GAGG;AACH,MAAM,WAAW,SAAS;IACtB;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IAErB;;;;;;;OAOG;IACH,KAAK,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI,CAAC;CAC/C;AAED,wBAAsB,YAAY,CAAC,CAAC,EAChC,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,EACzC,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,gBAAgB,EACxB,QAAQ,EAAE,SAAS,GACpB,OAAO,CAAC,CAAC,CAAC,CA0CZ"}
1
+ {"version":3,"file":"runWithRetry.d.ts","sourceRoot":"","sources":["../src/runWithRetry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAOtE;;;GAGG;AACH,MAAM,WAAW,SAAS;IACtB;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IAErB;;;;;;;OAOG;IACH,OAAO,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI,CAAC;CACjD;AAED,wBAAsB,YAAY,CAAC,CAAC,EAChC,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,EACzC,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,gBAAgB,EACxB,QAAQ,EAAE,SAAS,GACpB,OAAO,CAAC,CAAC,CAAC,CA2DZ"}
@@ -6,9 +6,12 @@
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.runWithRetry = void 0;
8
8
  const common_utils_1 = require("@fluidframework/common-utils");
9
+ const driver_definitions_1 = require("@fluidframework/driver-definitions");
9
10
  const network_1 = require("./network");
11
+ const packageVersion_1 = require("./packageVersion");
12
+ const _1 = require(".");
10
13
  async function runWithRetry(api, fetchCallName, logger, progress) {
11
- var _a;
14
+ var _a, _b;
12
15
  let result;
13
16
  let success = false;
14
17
  let retryAfterMs = 1000; // has to be positive!
@@ -27,16 +30,26 @@ async function runWithRetry(api, fetchCallName, logger, progress) {
27
30
  eventName: `${fetchCallName}_cancel`,
28
31
  retry: numRetries,
29
32
  duration: common_utils_1.performance.now() - startTime,
33
+ fetchCallName,
30
34
  }, err);
31
35
  throw err;
32
36
  }
37
+ if (((_a = progress.cancel) === null || _a === void 0 ? void 0 : _a.aborted) === true) {
38
+ logger.sendTelemetryEvent({
39
+ eventName: `${fetchCallName}_runWithRetryAborted`,
40
+ retry: numRetries,
41
+ duration: common_utils_1.performance.now() - startTime,
42
+ fetchCallName,
43
+ }, err);
44
+ throw new _1.NonRetryableError("runWithRetry was Aborted", driver_definitions_1.DriverErrorType.genericError, { driverVersion: packageVersion_1.pkgVersion, fetchCallName });
45
+ }
33
46
  numRetries++;
34
47
  lastError = err;
35
48
  // If the error is throttling error, then wait for the specified time before retrying.
36
49
  // If the waitTime is not specified, then we start with retrying immediately to max of 8s.
37
- retryAfterMs = (_a = network_1.getRetryDelayFromError(err)) !== null && _a !== void 0 ? _a : Math.min(retryAfterMs * 2, 8000);
38
- if (progress.retry) {
39
- progress.retry(retryAfterMs, err);
50
+ retryAfterMs = (_b = network_1.getRetryDelayFromError(err)) !== null && _b !== void 0 ? _b : Math.min(retryAfterMs * 2, 8000);
51
+ if (progress.onRetry) {
52
+ progress.onRetry(retryAfterMs, err);
40
53
  }
41
54
  await common_utils_1.delay(retryAfterMs);
42
55
  }
@@ -46,6 +59,7 @@ async function runWithRetry(api, fetchCallName, logger, progress) {
46
59
  eventName: `${fetchCallName}_lastError`,
47
60
  retry: numRetries,
48
61
  duration: common_utils_1.performance.now() - startTime,
62
+ fetchCallName,
49
63
  }, lastError);
50
64
  }
51
65
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
@@ -1 +1 @@
1
- {"version":3,"file":"runWithRetry.js","sourceRoot":"","sources":["../src/runWithRetry.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAGH,+DAAkE;AAClE,uCAAoE;AA8B7D,KAAK,UAAU,YAAY,CAC9B,GAAyC,EACzC,aAAqB,EACrB,MAAwB,EACxB,QAAmB;;IAEnB,IAAI,MAAqB,CAAC;IAC1B,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,YAAY,GAAG,IAAI,CAAC,CAAC,sBAAsB;IAC/C,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,MAAM,SAAS,GAAG,0BAAW,CAAC,GAAG,EAAE,CAAC;IACpC,IAAI,SAAc,CAAC;IACnB,GAAG;QACC,IAAI;YACA,MAAM,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YACpC,OAAO,GAAG,IAAI,CAAC;SAClB;QAAC,OAAO,GAAG,EAAE;YACV,qDAAqD;YACrD,IAAI,CAAC,yBAAe,CAAC,GAAG,CAAC,EAAE;gBACvB,MAAM,CAAC,kBAAkB,CAAC;oBACtB,SAAS,EAAE,GAAG,aAAa,SAAS;oBACpC,KAAK,EAAE,UAAU;oBACjB,QAAQ,EAAE,0BAAW,CAAC,GAAG,EAAE,GAAG,SAAS;iBAC1C,EAAE,GAAG,CAAC,CAAC;gBACR,MAAM,GAAG,CAAC;aACb;YACD,UAAU,EAAE,CAAC;YACb,SAAS,GAAG,GAAG,CAAC;YAChB,sFAAsF;YACtF,0FAA0F;YAC1F,YAAY,SAAG,gCAAsB,CAAC,GAAG,CAAC,mCAAI,IAAI,CAAC,GAAG,CAAC,YAAY,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;YAC/E,IAAI,QAAQ,CAAC,KAAK,EAAE;gBAChB,QAAQ,CAAC,KAAK,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;aACrC;YACD,MAAM,oBAAK,CAAC,YAAY,CAAC,CAAC;SAC7B;KACJ,QAAQ,CAAC,OAAO,EAAE;IACnB,IAAI,UAAU,GAAG,CAAC,EAAE;QAChB,MAAM,CAAC,kBAAkB,CAAC;YACtB,SAAS,EAAE,GAAG,aAAa,YAAY;YACvC,KAAK,EAAE,UAAU;YACjB,QAAQ,EAAE,0BAAW,CAAC,GAAG,EAAE,GAAG,SAAS;SAC1C,EACD,SAAS,CAAC,CAAC;KACd;IACD,oEAAoE;IACpE,OAAO,MAAO,CAAC;AACnB,CAAC;AA/CD,oCA+CC","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 { delay, performance } from \"@fluidframework/common-utils\";\nimport { canRetryOnError, getRetryDelayFromError } from \"./network\";\n\n/**\n * Interface describing an object passed to various network APIs.\n * It allows caller to control cancellation, as well as learn about any delays.\n */\nexport interface IProgress {\n /**\n * Abort signal used to cancel operation\n * Note that most of the layers do not use this signal yet. We need to change that over time.\n * Please consult with API documentation / implementation.\n * Note that number of layers may not check this signal while holding this request in a queue,\n * so it may take a while it takes effect. This can be improved in the future.\n * Layers in question are:\n * - driver (RateLimiter)\n * - runWithRetry\n */\n cancel?: AbortSignal;\n\n /**\n * Called whenever api returns cancellable error and the call is going to be retried.\n * Any exception thrown from this call back result in cancellation of operation\n * and propagation of thrown exception.\n * @param delayInMs - delay before next retry. This value will depend on internal back-off logic,\n * as well as information provided by service (like 429 error asking to wait for some time before retry)\n * @param error - error object returned from the call.\n */\n retry?(delayInMs: number, error: any): void;\n}\n\nexport async function runWithRetry<T>(\n api: (cancel?: AbortSignal) => Promise<T>,\n fetchCallName: string,\n logger: ITelemetryLogger,\n progress: IProgress,\n): Promise<T> {\n let result: T | undefined;\n let success = false;\n let retryAfterMs = 1000; // has to be positive!\n let numRetries = 0;\n const startTime = performance.now();\n let lastError: any;\n do {\n try {\n result = await api(progress.cancel);\n success = true;\n } catch (err) {\n // If it is not retriable, then just throw the error.\n if (!canRetryOnError(err)) {\n logger.sendTelemetryEvent({\n eventName: `${fetchCallName}_cancel`,\n retry: numRetries,\n duration: performance.now() - startTime,\n }, err);\n throw err;\n }\n numRetries++;\n lastError = err;\n // If the error is throttling error, then wait for the specified time before retrying.\n // If the waitTime is not specified, then we start with retrying immediately to max of 8s.\n retryAfterMs = getRetryDelayFromError(err) ?? Math.min(retryAfterMs * 2, 8000);\n if (progress.retry) {\n progress.retry(retryAfterMs, err);\n }\n await delay(retryAfterMs);\n }\n } while (!success);\n if (numRetries > 0) {\n logger.sendTelemetryEvent({\n eventName: `${fetchCallName}_lastError`,\n retry: numRetries,\n duration: performance.now() - startTime,\n },\n lastError);\n }\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return result!;\n}\n"]}
1
+ {"version":3,"file":"runWithRetry.js","sourceRoot":"","sources":["../src/runWithRetry.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAGH,+DAAkE;AAClE,2EAAqE;AACrE,uCAAoE;AACpE,qDAA8C;AAC9C,wBAAsC;AA8B/B,KAAK,UAAU,YAAY,CAC9B,GAAyC,EACzC,aAAqB,EACrB,MAAwB,EACxB,QAAmB;;IAEnB,IAAI,MAAqB,CAAC;IAC1B,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,YAAY,GAAG,IAAI,CAAC,CAAC,sBAAsB;IAC/C,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,MAAM,SAAS,GAAG,0BAAW,CAAC,GAAG,EAAE,CAAC;IACpC,IAAI,SAAc,CAAC;IACnB,GAAG;QACC,IAAI;YACA,MAAM,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YACpC,OAAO,GAAG,IAAI,CAAC;SAClB;QAAC,OAAO,GAAG,EAAE;YACV,qDAAqD;YACrD,IAAI,CAAC,yBAAe,CAAC,GAAG,CAAC,EAAE;gBACvB,MAAM,CAAC,kBAAkB,CAAC;oBACtB,SAAS,EAAE,GAAG,aAAa,SAAS;oBACpC,KAAK,EAAE,UAAU;oBACjB,QAAQ,EAAE,0BAAW,CAAC,GAAG,EAAE,GAAG,SAAS;oBACvC,aAAa;iBAChB,EAAE,GAAG,CAAC,CAAC;gBACR,MAAM,GAAG,CAAC;aACb;YAED,IAAI,OAAA,QAAQ,CAAC,MAAM,0CAAE,OAAO,MAAK,IAAI,EAAE;gBACnC,MAAM,CAAC,kBAAkB,CAAC;oBACtB,SAAS,EAAE,GAAG,aAAa,sBAAsB;oBACjD,KAAK,EAAE,UAAU;oBACjB,QAAQ,EAAE,0BAAW,CAAC,GAAG,EAAE,GAAG,SAAS;oBACvC,aAAa;iBAChB,EAAE,GAAG,CAAC,CAAC;gBACR,MAAM,IAAI,oBAAiB,CACvB,0BAA0B,EAC1B,oCAAe,CAAC,YAAY,EAC5B,EAAE,aAAa,EAAE,2BAAU,EAAE,aAAa,EAAE,CAC/C,CAAC;aACL;YAED,UAAU,EAAE,CAAC;YACb,SAAS,GAAG,GAAG,CAAC;YAChB,sFAAsF;YACtF,0FAA0F;YAC1F,YAAY,SAAG,gCAAsB,CAAC,GAAG,CAAC,mCAAI,IAAI,CAAC,GAAG,CAAC,YAAY,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;YAC/E,IAAI,QAAQ,CAAC,OAAO,EAAE;gBAClB,QAAQ,CAAC,OAAO,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;aACvC;YACD,MAAM,oBAAK,CAAC,YAAY,CAAC,CAAC;SAC7B;KACJ,QAAQ,CAAC,OAAO,EAAE;IACnB,IAAI,UAAU,GAAG,CAAC,EAAE;QAChB,MAAM,CAAC,kBAAkB,CAAC;YACtB,SAAS,EAAE,GAAG,aAAa,YAAY;YACvC,KAAK,EAAE,UAAU;YACjB,QAAQ,EAAE,0BAAW,CAAC,GAAG,EAAE,GAAG,SAAS;YACvC,aAAa;SAChB,EACD,SAAS,CAAC,CAAC;KACd;IACD,oEAAoE;IACpE,OAAO,MAAO,CAAC;AACnB,CAAC;AAhED,oCAgEC","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 { delay, performance } from \"@fluidframework/common-utils\";\nimport { DriverErrorType } from \"@fluidframework/driver-definitions\";\nimport { canRetryOnError, getRetryDelayFromError } from \"./network\";\nimport { pkgVersion } from \"./packageVersion\";\nimport { NonRetryableError } from \".\";\n\n/**\n * Interface describing an object passed to various network APIs.\n * It allows caller to control cancellation, as well as learn about any delays.\n */\nexport interface IProgress {\n /**\n * Abort signal used to cancel operation\n * Note that most of the layers do not use this signal yet. We need to change that over time.\n * Please consult with API documentation / implementation.\n * Note that number of layers may not check this signal while holding this request in a queue,\n * so it may take a while it takes effect. This can be improved in the future.\n * Layers in question are:\n * - driver (RateLimiter)\n * - runWithRetry\n */\n cancel?: AbortSignal;\n\n /**\n * Called whenever api returns cancellable error and the call is going to be retried.\n * Any exception thrown from this call back result in cancellation of operation\n * and propagation of thrown exception.\n * @param delayInMs - delay before next retry. This value will depend on internal back-off logic,\n * as well as information provided by service (like 429 error asking to wait for some time before retry)\n * @param error - error object returned from the call.\n */\n onRetry?(delayInMs: number, error: any): void;\n}\n\nexport async function runWithRetry<T>(\n api: (cancel?: AbortSignal) => Promise<T>,\n fetchCallName: string,\n logger: ITelemetryLogger,\n progress: IProgress,\n): Promise<T> {\n let result: T | undefined;\n let success = false;\n let retryAfterMs = 1000; // has to be positive!\n let numRetries = 0;\n const startTime = performance.now();\n let lastError: any;\n do {\n try {\n result = await api(progress.cancel);\n success = true;\n } catch (err) {\n // If it is not retriable, then just throw the error.\n if (!canRetryOnError(err)) {\n logger.sendTelemetryEvent({\n eventName: `${fetchCallName}_cancel`,\n retry: numRetries,\n duration: performance.now() - startTime,\n fetchCallName,\n }, err);\n throw err;\n }\n\n if (progress.cancel?.aborted === true) {\n logger.sendTelemetryEvent({\n eventName: `${fetchCallName}_runWithRetryAborted`,\n retry: numRetries,\n duration: performance.now() - startTime,\n fetchCallName,\n }, err);\n throw new NonRetryableError(\n \"runWithRetry was Aborted\",\n DriverErrorType.genericError,\n { driverVersion: pkgVersion, fetchCallName },\n );\n }\n\n numRetries++;\n lastError = err;\n // If the error is throttling error, then wait for the specified time before retrying.\n // If the waitTime is not specified, then we start with retrying immediately to max of 8s.\n retryAfterMs = getRetryDelayFromError(err) ?? Math.min(retryAfterMs * 2, 8000);\n if (progress.onRetry) {\n progress.onRetry(retryAfterMs, err);\n }\n await delay(retryAfterMs);\n }\n } while (!success);\n if (numRetries > 0) {\n logger.sendTelemetryEvent({\n eventName: `${fetchCallName}_lastError`,\n retry: numRetries,\n duration: performance.now() - startTime,\n fetchCallName,\n },\n lastError);\n }\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return result!;\n}\n"]}
@@ -71,7 +71,7 @@ export class SnapshotExtractor {
71
71
  let subTree = snapshot;
72
72
  for (const subPath of pathSplit.slice(0, pathSplit.length - 1)) {
73
73
  if (subTree.trees[subPath] === undefined) {
74
- subTree.trees[subPath] = { blobs: {}, commits: {}, trees: {} };
74
+ subTree.trees[subPath] = { blobs: {}, trees: {} };
75
75
  }
76
76
  subTree = subTree.trees[subPath];
77
77
  }
@@ -1 +1 @@
1
- {"version":3,"file":"blobAggregationStorage.js","sourceRoot":"","sources":["../src/blobAggregationStorage.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 {\n IDocumentStorageService,\n IDocumentStorageServicePolicies,\n ISummaryContext,\n} from \"@fluidframework/driver-definitions\";\nimport {\n ICreateBlobResponse,\n ISnapshotTree,\n ISummaryHandle,\n ISummaryTree,\n IVersion,\n SummaryType,\n ITree,\n} from \"@fluidframework/protocol-definitions\";\nimport {\n assert,\n bufferToString,\n stringToBuffer,\n unreachableCase,\n fromUtf8ToBase64,\n Uint8ArrayToString,\n } from \"@fluidframework/common-utils\";\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { loggerToMonitoringContext } from \"@fluidframework/telemetry-utils\";\n\n/*\n * Work around for bufferToString having a bug - it can't consume IsoBuffer!\n * To be removed once bufferToString is fixed!\n*/\nfunction bufferToString2(blob: ArrayBufferLike, encoding: \"utf-8\" | \"base64\"): string {\n if (blob instanceof Uint8Array) { // IsoBuffer does not have ctor, so it's not in proto chain :(\n return Uint8ArrayToString(blob, encoding);\n }\n return bufferToString(blob, encoding);\n}\n\n /**\n * Class responsible for aggregating smaller blobs into one and unpacking it later on.\n */\nclass BlobAggregator {\n private readonly content: [string, string][] = [];\n\n public addBlob(key: string, content: string) {\n this.content.push([key, content]);\n }\n\n public getAggregatedBlobContent() {\n if (this.content.length === 0) {\n return undefined;\n }\n return JSON.stringify(this.content);\n }\n\n static load(input: ArrayBufferLike) {\n const data = bufferToString2(input, \"utf-8\");\n return JSON.parse(data) as [string, string][];\n }\n}\n\n/*\n * Base class that deals with unpacking snapshots (in place) containing aggregated blobs\n * It relies on abstract methods for reads and storing unpacked blobs.\n */\nexport abstract class SnapshotExtractor {\n protected readonly aggregatedBlobName = \"__big\";\n protected readonly virtualIdPrefix = \"__\";\n\n // counter for generation of virtual storage IDs\n protected virtualIdCounter = 0;\n protected getNextVirtualId() {\n return `${this.virtualIdPrefix}${++this.virtualIdCounter}`;\n }\n\n abstract getBlob(id: string, tree: ISnapshotTree): Promise<ArrayBufferLike>;\n abstract setBlob(id: string, tree: ISnapshotTree, content: string);\n\n public async unpackSnapshotCore(snapshot: ISnapshotTree, level = 0): Promise<void> {\n for (const key of Object.keys(snapshot.trees)) {\n const obj = snapshot.trees[key];\n await this.unpackSnapshotCore(obj, level + 1);\n }\n\n // For future proof, we will support multiple aggregated blobs with any name\n // that starts with this.aggregatedBlobName\n for (const key of Object.keys(snapshot.blobs)) {\n if (!key.startsWith(this.aggregatedBlobName)) { continue; }\n const blobId = snapshot.blobs[key];\n if (blobId !== undefined) {\n const blob = await this.getBlob(blobId, snapshot);\n for (const [path, value] of BlobAggregator.load(blob)) {\n const id = this.getNextVirtualId();\n this.setBlob(id, snapshot, value);\n const pathSplit = path.split(\"/\");\n let subTree = snapshot;\n for (const subPath of pathSplit.slice(0, pathSplit.length - 1)) {\n if (subTree.trees[subPath] === undefined) {\n subTree.trees[subPath] = { blobs: {}, commits: {}, trees: {}};\n }\n subTree = subTree.trees[subPath];\n }\n const blobName = pathSplit[pathSplit.length - 1];\n assert(subTree.blobs[blobName] === undefined, 0x0f6 /* \"real blob ID exists\" */);\n subTree.blobs[blobName] = id;\n }\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete snapshot.blobs[this.aggregatedBlobName];\n }\n }\n }\n}\n\n/*\n * Snapshot extractor class that works in place, i.e. patches snapshot that has\n * blob content in ISnapshotTree.blobs itself, not in storage.\n * As result, it implements reading and writing of blobs to/from snapshot itself.\n * It follows existing pattern that mixes concerns - ISnapshotTree.blobs is used for two\n * purposes:\n * 1. map path name to blob ID\n * 2. map blob ID to blob content\n * #2 is what storage (IDocumentStorageService) is for, but in places where we do not have it\n * (like loading serialized earlier draft content), blob content is put directly into snapshot.\n * Ideally this should be fixed by using BlobCacheStorageService or something similar and\n * fixing existing flows to allow switching of storage.\n */\nclass SnapshotExtractorInPlace extends SnapshotExtractor {\n public async getBlob(id: string, tree: ISnapshotTree): Promise<ArrayBufferLike> {\n const blob = tree.blobs[id];\n assert(blob !== undefined, 0x0f7 /* \"aggregate blob missing\" */);\n return stringToBuffer(blob, \"base64\");\n }\n\n public setBlob(id: string, tree: ISnapshotTree, content: string) {\n assert(tree.blobs[id] === undefined, 0x0f8 /* \"blob from aggregate blob exists on its own\" */);\n tree.blobs[id] = fromUtf8ToBase64(content);\n }\n}\n\n/*\n * Snapshot packer and extractor.\n * When summary is written it will find and aggregate small blobs into bigger blobs\n * When snapshot is read, it will unpack aggregated blobs and provide them transparently to caller.\n */\nexport class BlobAggregationStorage extends SnapshotExtractor implements IDocumentStorageService {\n // Tells data store if it can use incremental summary (i.e. reuse DDSs from previous summary\n // when only one DDS changed).\n // The answer has to be know long before we enable actual packing. The reason for the is the following:\n // A the moment when we enable packing, we should assume that all clients out there wil already have bits\n // that can unpack properly (i.e. enough time passed since we deployed bits that can unpack)\n // But we can still have clients where some of them already pack, and some do not. If one summary was\n // using packing, then it relies on non-incremental summaries going forward, even if next client who\n // produced summary is not packing!\n // This can have slight improvement by enabling it per file (based on \"did summary we loaded from contain\n // aggregated blobs\"), but that's harder to make reliable, so going for simplicity.\n static readonly fullDataStoreSummaries = true;\n\n protected loadedFromSummary = false;\n\n protected virtualBlobs = new Map<string, ArrayBufferLike>();\n\n static wrap(\n storage: IDocumentStorageService,\n logger: ITelemetryLogger,\n allowPacking?: boolean,\n packingLevel = 2,\n ) {\n if (storage instanceof BlobAggregationStorage) {\n return storage;\n }\n const mc = loggerToMonitoringContext(logger);\n const realAllowPackaging = mc.config.getBoolean(\"FluidAggregateBlobs\") ?? allowPacking ?? false;\n\n // Always create BlobAggregationStorage even if storage is not asking for packing.\n // This is mostly to avoid cases where future changes in policy would result in inability to\n // load old files that were created with aggregation on.\n const minBlobSize = storage.policies?.minBlobSize;\n return new BlobAggregationStorage(storage, logger, realAllowPackaging, packingLevel, minBlobSize);\n }\n\n static async unpackSnapshot(snapshot: ISnapshotTree) {\n const converter = new SnapshotExtractorInPlace();\n await converter.unpackSnapshotCore(snapshot);\n }\n\n public get policies(): IDocumentStorageServicePolicies | undefined {\n const policies = this.storage.policies;\n if (policies) {\n return { ...policies, minBlobSize: undefined };\n }\n }\n\n public async unpackSnapshot(snapshot: ISnapshotTree) {\n // SummarizerNodeWithGC.refreshLatestSummary can call it when this.loadedFromSummary === false\n // (I assumed after file was created)\n // assert(!this.loadedFromSummary, \"unpack without summary\");\n\n this.loadedFromSummary = true;\n await this.unpackSnapshotCore(snapshot);\n }\n\n protected constructor(\n private readonly storage: IDocumentStorageService,\n private readonly logger: ITelemetryLogger,\n private readonly allowPacking: boolean,\n private readonly packingLevel: number,\n private readonly blobCutOffSize?: number)\n {\n super();\n }\n\n public setBlob(id: string, tree: ISnapshotTree, content: string) {\n this.virtualBlobs.set(id, stringToBuffer(content, \"utf-8\"));\n }\n\n public async getBlob(id: string, tree: ISnapshotTree): Promise<ArrayBufferLike> {\n return this.readBlob(id).catch((error) => {\n this.logger.sendErrorEvent({ eventName: \"BlobDedupNoAggregateBlob\" }, error);\n throw error;\n });\n }\n\n public get repositoryUrl() { return this.storage.repositoryUrl; }\n public async getVersions(versionId: string | null, count: number) {\n return this.storage.getVersions(versionId, count);\n }\n\n public async downloadSummary(handle: ISummaryHandle): Promise<ISummaryTree> {\n throw new Error(\"NYI\");\n }\n\n // This is only used through Container.snapshot() for testing purposes\n public async write(root: ITree, parents: string[], message: string, ref: string) {\n return this.storage.write(root, parents, message, ref);\n }\n\n // for now we are not optimizing these blobs, with assumption that this API is used only\n // for big blobs (images)\n public async createBlob(file: ArrayBufferLike): Promise<ICreateBlobResponse> {\n return this.storage.createBlob(file);\n }\n\n public async getSnapshotTree(version?: IVersion): Promise<ISnapshotTree | null> {\n const tree = await this.storage.getSnapshotTree(version);\n if (tree) {\n await this.unpackSnapshot(tree);\n }\n return tree;\n }\n\n public async readBlob(id: string): Promise<ArrayBufferLike> {\n if (this.isRealStorageId(id)) {\n return this.storage.readBlob(id);\n }\n // We support only reading blobs from the summary we loaded from.\n // This may need to be extended to any general summary in the future as runtime usage pattern\n // of storage changes (for example, data stores start to load from recent summary, not from original\n // summary whole container loaded from)\n\n // are there other ways we can get here? createFile is one flow, but we should not be reading blobs\n // in such flow\n assert(this.loadedFromSummary, 0x0f9 /* \"never read summary\" */);\n const blob = this.virtualBlobs.get(id);\n assert(blob !== undefined, 0x0fa /* \"virtual blob not found\" */);\n return blob;\n }\n\n public async uploadSummaryWithContext(summary: ISummaryTree, context: ISummaryContext): Promise<string> {\n const summaryNew = this.allowPacking ? await this.compressSmallBlobs(summary) : summary;\n return this.storage.uploadSummaryWithContext(summaryNew, context);\n }\n\n // For simplification, we assume that\n // - blob aggregation is done at data store level only for now\n // - data store either reuses previous summary, or generates full summary, i.e. there is no partial (some DDS)\n // summary produced by data stores.\n // These simplifications allow us not to touch handles, as they are self-contained (either do not use aggregated\n // blob Or contain aggregated blob that stays relevant for that sub-tree)\n // Note:\n // From perf perspective, it makes sense to place aggregated blobs one level up in the tree not to create extra\n // tree nodes (i.e. have shallow tree with less edges). But that creates problems with reusability of trees at\n // incremental summary time - we would need to understand handles and parse them. In current design we can skip\n // that step because if data store is reused, the hole sub-tree is reused included aggregated blob embedded into it\n // and that means we can do nothing and be correct!\n private async compressSmallBlobs(\n summary: ISummaryTree,\n path = \"\",\n level = 0,\n aggregatorArg?: BlobAggregator): Promise<ISummaryTree>\n {\n if (this.blobCutOffSize === undefined || this.blobCutOffSize < 0) {\n return summary;\n }\n\n let shouldCompress: boolean = false;\n\n let aggregator = aggregatorArg;\n // checking if this is a dataStore tree, since we only pack at data store level\n if (Object.keys(summary.tree).includes(\".component\")) {\n assert(aggregator === undefined, 0x0fb /* \"logic err with aggregator\" */);\n assert(level === this.packingLevel, 0x23b /* \"we are not packing at the right level\" */);\n aggregator = new BlobAggregator();\n shouldCompress = true;\n } else {\n assert(level !== this.packingLevel, 0x23c /* \"we are not packing at the right level\" */);\n }\n\n const newSummary: ISummaryTree = {...summary};\n newSummary.tree = { ...newSummary.tree};\n for (const key of Object.keys(summary.tree)) {\n const obj = summary.tree[key];\n // Get path relative to root of data store (where we do aggregation)\n const newPath = shouldCompress ? key : `${path}/${key}`;\n switch (obj.type) {\n case SummaryType.Tree:\n // If client created empty tree, keep it as is\n // Also do not package search blobs - they are part of storage contract\n if (obj.tree !== {} && key !== \"__search\") {\n const tree = await this.compressSmallBlobs(obj, newPath, level + 1, aggregator);\n newSummary.tree[key] = tree;\n if (tree.tree === {}) {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete newSummary.tree[key];\n }\n }\n break;\n case SummaryType.Blob:\n if (aggregator && typeof obj.content == \"string\" && obj.content.length < this.blobCutOffSize) {\n aggregator.addBlob(newPath, obj.content);\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete newSummary.tree[key];\n }\n break;\n case SummaryType.Handle: {\n // Would be nice to:\n // Trees: expand the tree\n // Blobs: parse handle and ensure it points to real blob, not virtual blob.\n // We can avoid it for now given data store is the granularity of incremental summaries.\n let handlePath = obj.handle;\n if (handlePath.startsWith(\"/\")) {\n handlePath = handlePath.substr(1);\n }\n // Ensure only whole data stores can be reused, no reusing at deeper level!\n assert(level === 0, 0x0fc /* \"tree reuse at lower level\" */);\n assert(handlePath.indexOf(\"/\") === -1,\n 0x0fd /* \"data stores are writing incremental summaries!\" */);\n break;\n }\n case SummaryType.Attachment:\n assert(this.isRealStorageId(obj.id), 0x0fe /* \"attachment is aggregate blob\" */);\n break;\n default:\n unreachableCase(obj, `Unknown type: ${(obj as any).type}`);\n }\n }\n\n assert(newSummary.tree[this.aggregatedBlobName] === undefined, 0x0ff /* \"duplicate aggregate blob\" */);\n if (shouldCompress) {\n // Note: It would be great to add code here to unpack aggregate blob back to normal blobs\n // If only one blob made it into aggregate. Currently that does not happen as we always have\n // at least one .component blob and at least one DDS that has .attributes blob, so it's not an issue.\n // But it's possible that in future that would be great addition!\n // Good news - it's backward compatible change.\n assert(aggregator !== undefined, 0x100 /* \"logic error\" */);\n const content = aggregator.getAggregatedBlobContent();\n if (content !== undefined) {\n newSummary.tree[this.aggregatedBlobName] = {\n type: SummaryType.Blob,\n content,\n };\n }\n }\n return newSummary;\n }\n\n protected isRealStorageId(id: string): boolean {\n return !id.startsWith(this.virtualIdPrefix);\n }\n}\n"]}
1
+ {"version":3,"file":"blobAggregationStorage.js","sourceRoot":"","sources":["../src/blobAggregationStorage.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 {\n IDocumentStorageService,\n IDocumentStorageServicePolicies,\n ISummaryContext,\n} from \"@fluidframework/driver-definitions\";\nimport {\n ICreateBlobResponse,\n ISnapshotTree,\n ISummaryHandle,\n ISummaryTree,\n IVersion,\n SummaryType,\n ITree,\n} from \"@fluidframework/protocol-definitions\";\nimport {\n assert,\n bufferToString,\n stringToBuffer,\n unreachableCase,\n fromUtf8ToBase64,\n Uint8ArrayToString,\n } from \"@fluidframework/common-utils\";\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { loggerToMonitoringContext } from \"@fluidframework/telemetry-utils\";\n\n/*\n * Work around for bufferToString having a bug - it can't consume IsoBuffer!\n * To be removed once bufferToString is fixed!\n*/\nfunction bufferToString2(blob: ArrayBufferLike, encoding: \"utf-8\" | \"base64\"): string {\n if (blob instanceof Uint8Array) { // IsoBuffer does not have ctor, so it's not in proto chain :(\n return Uint8ArrayToString(blob, encoding);\n }\n return bufferToString(blob, encoding);\n}\n\n /**\n * Class responsible for aggregating smaller blobs into one and unpacking it later on.\n */\nclass BlobAggregator {\n private readonly content: [string, string][] = [];\n\n public addBlob(key: string, content: string) {\n this.content.push([key, content]);\n }\n\n public getAggregatedBlobContent() {\n if (this.content.length === 0) {\n return undefined;\n }\n return JSON.stringify(this.content);\n }\n\n static load(input: ArrayBufferLike) {\n const data = bufferToString2(input, \"utf-8\");\n return JSON.parse(data) as [string, string][];\n }\n}\n\n/*\n * Base class that deals with unpacking snapshots (in place) containing aggregated blobs\n * It relies on abstract methods for reads and storing unpacked blobs.\n */\nexport abstract class SnapshotExtractor {\n protected readonly aggregatedBlobName = \"__big\";\n protected readonly virtualIdPrefix = \"__\";\n\n // counter for generation of virtual storage IDs\n protected virtualIdCounter = 0;\n protected getNextVirtualId() {\n return `${this.virtualIdPrefix}${++this.virtualIdCounter}`;\n }\n\n abstract getBlob(id: string, tree: ISnapshotTree): Promise<ArrayBufferLike>;\n abstract setBlob(id: string, tree: ISnapshotTree, content: string);\n\n public async unpackSnapshotCore(snapshot: ISnapshotTree, level = 0): Promise<void> {\n for (const key of Object.keys(snapshot.trees)) {\n const obj = snapshot.trees[key];\n await this.unpackSnapshotCore(obj, level + 1);\n }\n\n // For future proof, we will support multiple aggregated blobs with any name\n // that starts with this.aggregatedBlobName\n for (const key of Object.keys(snapshot.blobs)) {\n if (!key.startsWith(this.aggregatedBlobName)) { continue; }\n const blobId = snapshot.blobs[key];\n if (blobId !== undefined) {\n const blob = await this.getBlob(blobId, snapshot);\n for (const [path, value] of BlobAggregator.load(blob)) {\n const id = this.getNextVirtualId();\n this.setBlob(id, snapshot, value);\n const pathSplit = path.split(\"/\");\n let subTree = snapshot;\n for (const subPath of pathSplit.slice(0, pathSplit.length - 1)) {\n if (subTree.trees[subPath] === undefined) {\n subTree.trees[subPath] = { blobs: {}, trees: {}};\n }\n subTree = subTree.trees[subPath];\n }\n const blobName = pathSplit[pathSplit.length - 1];\n assert(subTree.blobs[blobName] === undefined, 0x0f6 /* \"real blob ID exists\" */);\n subTree.blobs[blobName] = id;\n }\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete snapshot.blobs[this.aggregatedBlobName];\n }\n }\n }\n}\n\n/*\n * Snapshot extractor class that works in place, i.e. patches snapshot that has\n * blob content in ISnapshotTree.blobs itself, not in storage.\n * As result, it implements reading and writing of blobs to/from snapshot itself.\n * It follows existing pattern that mixes concerns - ISnapshotTree.blobs is used for two\n * purposes:\n * 1. map path name to blob ID\n * 2. map blob ID to blob content\n * #2 is what storage (IDocumentStorageService) is for, but in places where we do not have it\n * (like loading serialized earlier draft content), blob content is put directly into snapshot.\n * Ideally this should be fixed by using BlobCacheStorageService or something similar and\n * fixing existing flows to allow switching of storage.\n */\nclass SnapshotExtractorInPlace extends SnapshotExtractor {\n public async getBlob(id: string, tree: ISnapshotTree): Promise<ArrayBufferLike> {\n const blob = tree.blobs[id];\n assert(blob !== undefined, 0x0f7 /* \"aggregate blob missing\" */);\n return stringToBuffer(blob, \"base64\");\n }\n\n public setBlob(id: string, tree: ISnapshotTree, content: string) {\n assert(tree.blobs[id] === undefined, 0x0f8 /* \"blob from aggregate blob exists on its own\" */);\n tree.blobs[id] = fromUtf8ToBase64(content);\n }\n}\n\n/*\n * Snapshot packer and extractor.\n * When summary is written it will find and aggregate small blobs into bigger blobs\n * When snapshot is read, it will unpack aggregated blobs and provide them transparently to caller.\n */\nexport class BlobAggregationStorage extends SnapshotExtractor implements IDocumentStorageService {\n // Tells data store if it can use incremental summary (i.e. reuse DDSs from previous summary\n // when only one DDS changed).\n // The answer has to be know long before we enable actual packing. The reason for the is the following:\n // A the moment when we enable packing, we should assume that all clients out there wil already have bits\n // that can unpack properly (i.e. enough time passed since we deployed bits that can unpack)\n // But we can still have clients where some of them already pack, and some do not. If one summary was\n // using packing, then it relies on non-incremental summaries going forward, even if next client who\n // produced summary is not packing!\n // This can have slight improvement by enabling it per file (based on \"did summary we loaded from contain\n // aggregated blobs\"), but that's harder to make reliable, so going for simplicity.\n static readonly fullDataStoreSummaries = true;\n\n protected loadedFromSummary = false;\n\n protected virtualBlobs = new Map<string, ArrayBufferLike>();\n\n static wrap(\n storage: IDocumentStorageService,\n logger: ITelemetryLogger,\n allowPacking?: boolean,\n packingLevel = 2,\n ) {\n if (storage instanceof BlobAggregationStorage) {\n return storage;\n }\n const mc = loggerToMonitoringContext(logger);\n const realAllowPackaging = mc.config.getBoolean(\"FluidAggregateBlobs\") ?? allowPacking ?? false;\n\n // Always create BlobAggregationStorage even if storage is not asking for packing.\n // This is mostly to avoid cases where future changes in policy would result in inability to\n // load old files that were created with aggregation on.\n const minBlobSize = storage.policies?.minBlobSize;\n return new BlobAggregationStorage(storage, logger, realAllowPackaging, packingLevel, minBlobSize);\n }\n\n static async unpackSnapshot(snapshot: ISnapshotTree) {\n const converter = new SnapshotExtractorInPlace();\n await converter.unpackSnapshotCore(snapshot);\n }\n\n public get policies(): IDocumentStorageServicePolicies | undefined {\n const policies = this.storage.policies;\n if (policies) {\n return { ...policies, minBlobSize: undefined };\n }\n }\n\n public async unpackSnapshot(snapshot: ISnapshotTree) {\n // SummarizerNodeWithGC.refreshLatestSummary can call it when this.loadedFromSummary === false\n // (I assumed after file was created)\n // assert(!this.loadedFromSummary, \"unpack without summary\");\n\n this.loadedFromSummary = true;\n await this.unpackSnapshotCore(snapshot);\n }\n\n protected constructor(\n private readonly storage: IDocumentStorageService,\n private readonly logger: ITelemetryLogger,\n private readonly allowPacking: boolean,\n private readonly packingLevel: number,\n private readonly blobCutOffSize?: number)\n {\n super();\n }\n\n public setBlob(id: string, tree: ISnapshotTree, content: string) {\n this.virtualBlobs.set(id, stringToBuffer(content, \"utf-8\"));\n }\n\n public async getBlob(id: string, tree: ISnapshotTree): Promise<ArrayBufferLike> {\n return this.readBlob(id).catch((error) => {\n this.logger.sendErrorEvent({ eventName: \"BlobDedupNoAggregateBlob\" }, error);\n throw error;\n });\n }\n\n public get repositoryUrl() { return this.storage.repositoryUrl; }\n public async getVersions(versionId: string | null, count: number) {\n return this.storage.getVersions(versionId, count);\n }\n\n public async downloadSummary(handle: ISummaryHandle): Promise<ISummaryTree> {\n throw new Error(\"NYI\");\n }\n\n // This is only used through Container.snapshot() for testing purposes\n public async write(root: ITree, parents: string[], message: string, ref: string) {\n return this.storage.write(root, parents, message, ref);\n }\n\n // for now we are not optimizing these blobs, with assumption that this API is used only\n // for big blobs (images)\n public async createBlob(file: ArrayBufferLike): Promise<ICreateBlobResponse> {\n return this.storage.createBlob(file);\n }\n\n public async getSnapshotTree(version?: IVersion): Promise<ISnapshotTree | null> {\n const tree = await this.storage.getSnapshotTree(version);\n if (tree) {\n await this.unpackSnapshot(tree);\n }\n return tree;\n }\n\n public async readBlob(id: string): Promise<ArrayBufferLike> {\n if (this.isRealStorageId(id)) {\n return this.storage.readBlob(id);\n }\n // We support only reading blobs from the summary we loaded from.\n // This may need to be extended to any general summary in the future as runtime usage pattern\n // of storage changes (for example, data stores start to load from recent summary, not from original\n // summary whole container loaded from)\n\n // are there other ways we can get here? createFile is one flow, but we should not be reading blobs\n // in such flow\n assert(this.loadedFromSummary, 0x0f9 /* \"never read summary\" */);\n const blob = this.virtualBlobs.get(id);\n assert(blob !== undefined, 0x0fa /* \"virtual blob not found\" */);\n return blob;\n }\n\n public async uploadSummaryWithContext(summary: ISummaryTree, context: ISummaryContext): Promise<string> {\n const summaryNew = this.allowPacking ? await this.compressSmallBlobs(summary) : summary;\n return this.storage.uploadSummaryWithContext(summaryNew, context);\n }\n\n // For simplification, we assume that\n // - blob aggregation is done at data store level only for now\n // - data store either reuses previous summary, or generates full summary, i.e. there is no partial (some DDS)\n // summary produced by data stores.\n // These simplifications allow us not to touch handles, as they are self-contained (either do not use aggregated\n // blob Or contain aggregated blob that stays relevant for that sub-tree)\n // Note:\n // From perf perspective, it makes sense to place aggregated blobs one level up in the tree not to create extra\n // tree nodes (i.e. have shallow tree with less edges). But that creates problems with reusability of trees at\n // incremental summary time - we would need to understand handles and parse them. In current design we can skip\n // that step because if data store is reused, the hole sub-tree is reused included aggregated blob embedded into it\n // and that means we can do nothing and be correct!\n private async compressSmallBlobs(\n summary: ISummaryTree,\n path = \"\",\n level = 0,\n aggregatorArg?: BlobAggregator): Promise<ISummaryTree>\n {\n if (this.blobCutOffSize === undefined || this.blobCutOffSize < 0) {\n return summary;\n }\n\n let shouldCompress: boolean = false;\n\n let aggregator = aggregatorArg;\n // checking if this is a dataStore tree, since we only pack at data store level\n if (Object.keys(summary.tree).includes(\".component\")) {\n assert(aggregator === undefined, 0x0fb /* \"logic err with aggregator\" */);\n assert(level === this.packingLevel, 0x23b /* \"we are not packing at the right level\" */);\n aggregator = new BlobAggregator();\n shouldCompress = true;\n } else {\n assert(level !== this.packingLevel, 0x23c /* \"we are not packing at the right level\" */);\n }\n\n const newSummary: ISummaryTree = {...summary};\n newSummary.tree = { ...newSummary.tree};\n for (const key of Object.keys(summary.tree)) {\n const obj = summary.tree[key];\n // Get path relative to root of data store (where we do aggregation)\n const newPath = shouldCompress ? key : `${path}/${key}`;\n switch (obj.type) {\n case SummaryType.Tree:\n // If client created empty tree, keep it as is\n // Also do not package search blobs - they are part of storage contract\n if (obj.tree !== {} && key !== \"__search\") {\n const tree = await this.compressSmallBlobs(obj, newPath, level + 1, aggregator);\n newSummary.tree[key] = tree;\n if (tree.tree === {}) {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete newSummary.tree[key];\n }\n }\n break;\n case SummaryType.Blob:\n if (aggregator && typeof obj.content == \"string\" && obj.content.length < this.blobCutOffSize) {\n aggregator.addBlob(newPath, obj.content);\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete newSummary.tree[key];\n }\n break;\n case SummaryType.Handle: {\n // Would be nice to:\n // Trees: expand the tree\n // Blobs: parse handle and ensure it points to real blob, not virtual blob.\n // We can avoid it for now given data store is the granularity of incremental summaries.\n let handlePath = obj.handle;\n if (handlePath.startsWith(\"/\")) {\n handlePath = handlePath.substr(1);\n }\n // Ensure only whole data stores can be reused, no reusing at deeper level!\n assert(level === 0, 0x0fc /* \"tree reuse at lower level\" */);\n assert(handlePath.indexOf(\"/\") === -1,\n 0x0fd /* \"data stores are writing incremental summaries!\" */);\n break;\n }\n case SummaryType.Attachment:\n assert(this.isRealStorageId(obj.id), 0x0fe /* \"attachment is aggregate blob\" */);\n break;\n default:\n unreachableCase(obj, `Unknown type: ${(obj as any).type}`);\n }\n }\n\n assert(newSummary.tree[this.aggregatedBlobName] === undefined, 0x0ff /* \"duplicate aggregate blob\" */);\n if (shouldCompress) {\n // Note: It would be great to add code here to unpack aggregate blob back to normal blobs\n // If only one blob made it into aggregate. Currently that does not happen as we always have\n // at least one .component blob and at least one DDS that has .attributes blob, so it's not an issue.\n // But it's possible that in future that would be great addition!\n // Good news - it's backward compatible change.\n assert(aggregator !== undefined, 0x100 /* \"logic error\" */);\n const content = aggregator.getAggregatedBlobContent();\n if (content !== undefined) {\n newSummary.tree[this.aggregatedBlobName] = {\n type: SummaryType.Blob,\n content,\n };\n }\n }\n return newSummary;\n }\n\n protected isRealStorageId(id: string): boolean {\n return !id.startsWith(this.virtualIdPrefix);\n }\n}\n"]}
@@ -10,7 +10,7 @@ export declare class MultiDocumentServiceFactory implements IDocumentServiceFact
10
10
  private readonly protocolToDocumentFactoryMap;
11
11
  constructor(documentServiceFactories: IDocumentServiceFactory[]);
12
12
  readonly protocolName = "none:";
13
- createDocumentService(resolvedUrl: IResolvedUrl, logger?: ITelemetryBaseLogger): Promise<IDocumentService>;
14
- createContainer(createNewSummary: ISummaryTree, createNewResolvedUrl: IResolvedUrl, logger?: ITelemetryBaseLogger): Promise<IDocumentService>;
13
+ createDocumentService(resolvedUrl: IResolvedUrl, logger?: ITelemetryBaseLogger, clientIsSummarizer?: boolean): Promise<IDocumentService>;
14
+ createContainer(createNewSummary: ISummaryTree, createNewResolvedUrl: IResolvedUrl, logger?: ITelemetryBaseLogger, clientIsSummarizer?: boolean): Promise<IDocumentService>;
15
15
  }
16
16
  //# sourceMappingURL=multiDocumentServiceFactory.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"multiDocumentServiceFactory.d.ts","sourceRoot":"","sources":["../src/multiDocumentServiceFactory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACH,uBAAuB,EACvB,YAAY,EACZ,gBAAgB,EACnB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAG1E,qBAAa,2BAA4B,YAAW,uBAAuB;WACzD,MAAM,CAAC,sBAAsB,EAAE,uBAAuB,GAAG,uBAAuB,EAAE;IAmBhG,OAAO,CAAC,QAAQ,CAAC,4BAA4B,CAAuC;gBAExE,wBAAwB,EAAE,uBAAuB,EAAE;IAM/D,SAAgB,YAAY,WAAW;IACjC,qBAAqB,CAAC,WAAW,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAcnG,eAAe,CACxB,gBAAgB,EAAE,YAAY,EAC9B,oBAAoB,EAAE,YAAY,EAClC,MAAM,CAAC,EAAE,oBAAoB,GAC9B,OAAO,CAAC,gBAAgB,CAAC;CAY/B"}
1
+ {"version":3,"file":"multiDocumentServiceFactory.d.ts","sourceRoot":"","sources":["../src/multiDocumentServiceFactory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACH,uBAAuB,EACvB,YAAY,EACZ,gBAAgB,EACnB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAG1E,qBAAa,2BAA4B,YAAW,uBAAuB;WACzD,MAAM,CAAC,sBAAsB,EAAE,uBAAuB,GAAG,uBAAuB,EAAE;IAmBhG,OAAO,CAAC,QAAQ,CAAC,4BAA4B,CAAuC;gBAExE,wBAAwB,EAAE,uBAAuB,EAAE;IAM/D,SAAgB,YAAY,WAAW;IACjC,qBAAqB,CACvB,WAAW,EAAE,YAAY,EACzB,MAAM,CAAC,EAAE,oBAAoB,EAC7B,kBAAkB,CAAC,EAAE,OAAO,GAC7B,OAAO,CAAC,gBAAgB,CAAC;IAcf,eAAe,CACxB,gBAAgB,EAAE,YAAY,EAC9B,oBAAoB,EAAE,YAAY,EAClC,MAAM,CAAC,EAAE,oBAAoB,EAC7B,kBAAkB,CAAC,EAAE,OAAO,GAC7B,OAAO,CAAC,gBAAgB,CAAC;CAY/B"}
@@ -31,7 +31,7 @@ export class MultiDocumentServiceFactory {
31
31
  }
32
32
  return documentServiceFactory;
33
33
  }
34
- async createDocumentService(resolvedUrl, logger) {
34
+ async createDocumentService(resolvedUrl, logger, clientIsSummarizer) {
35
35
  ensureFluidResolvedUrl(resolvedUrl);
36
36
  const urlObj = parse(resolvedUrl.url);
37
37
  if (urlObj.protocol === undefined || urlObj.protocol === null) {
@@ -41,9 +41,9 @@ export class MultiDocumentServiceFactory {
41
41
  if (factory === undefined) {
42
42
  throw new Error("Unknown Fluid protocol");
43
43
  }
44
- return factory.createDocumentService(resolvedUrl, logger);
44
+ return factory.createDocumentService(resolvedUrl, logger, clientIsSummarizer);
45
45
  }
46
- async createContainer(createNewSummary, createNewResolvedUrl, logger) {
46
+ async createContainer(createNewSummary, createNewResolvedUrl, logger, clientIsSummarizer) {
47
47
  ensureFluidResolvedUrl(createNewResolvedUrl);
48
48
  const urlObj = parse(createNewResolvedUrl.url);
49
49
  if (urlObj.protocol === undefined || urlObj.protocol === null) {
@@ -53,7 +53,7 @@ export class MultiDocumentServiceFactory {
53
53
  if (factory === undefined) {
54
54
  throw new Error("Unknown Fluid protocol");
55
55
  }
56
- return factory.createContainer(createNewSummary, createNewResolvedUrl, logger);
56
+ return factory.createContainer(createNewSummary, createNewResolvedUrl, logger, clientIsSummarizer);
57
57
  }
58
58
  }
59
59
  //# sourceMappingURL=multiDocumentServiceFactory.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"multiDocumentServiceFactory.js","sourceRoot":"","sources":["../src/multiDocumentServiceFactory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,KAAK,CAAC;AAQ5B,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,MAAM,OAAO,2BAA2B;IAsBpC,YAAY,wBAAmD;QAM/C,iBAAY,GAAG,OAAO,CAAC;QALnC,IAAI,CAAC,4BAA4B,GAAG,IAAI,GAAG,EAAE,CAAC;QAC9C,wBAAwB,CAAC,OAAO,CAAC,CAAC,OAAgC,EAAE,EAAE;YAClE,IAAI,CAAC,4BAA4B,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QACzE,CAAC,CAAC,CAAC;IACP,CAAC;IA1BM,MAAM,CAAC,MAAM,CAAC,sBAA2E;QAC5F,IAAI,KAAK,CAAC,OAAO,CAAC,sBAAsB,CAAC,EAAE;YACvC,MAAM,SAAS,GAA8B,EAAE,CAAC;YAChD,sBAAsB,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;gBACvC,MAAM,UAAU,GAAG,OAAsC,CAAC;gBAC1D,IAAI,UAAU,CAAC,4BAA4B,KAAK,SAAS,EAAE;oBACvD,SAAS,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,4BAA4B,CAAC,MAAM,EAAE,CAAC,CAAC;iBACvE;qBAAM;oBACH,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;iBAC3B;YACL,CAAC,CAAC,CAAC;YACH,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE;gBACxB,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC;aACvB;YACD,OAAO,IAAI,2BAA2B,CAAC,SAAS,CAAC,CAAC;SACrD;QACD,OAAO,sBAAsB,CAAC;IAClC,CAAC;IAWD,KAAK,CAAC,qBAAqB,CAAC,WAAyB,EAAE,MAA6B;QAChF,sBAAsB,CAAC,WAAW,CAAC,CAAC;QACpC,MAAM,MAAM,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACtC,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,KAAK,IAAI,EAAE;YAC3D,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;SAC3C;QACD,MAAM,OAAO,GAAwC,IAAI,CAAC,4BAA4B,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC5G,IAAI,OAAO,KAAK,SAAS,EAAE;YACvB,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;SAC7C;QAED,OAAO,OAAO,CAAC,qBAAqB,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IAC9D,CAAC;IAEM,KAAK,CAAC,eAAe,CACxB,gBAA8B,EAC9B,oBAAkC,EAClC,MAA6B;QAE7B,sBAAsB,CAAC,oBAAoB,CAAC,CAAC;QAC7C,MAAM,MAAM,GAAG,KAAK,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC;QAC/C,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,KAAK,IAAI,EAAE;YAC3D,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;SAC3C;QACD,MAAM,OAAO,GAAwC,IAAI,CAAC,4BAA4B,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC5G,IAAI,OAAO,KAAK,SAAS,EAAE;YACvB,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;SAC7C;QACD,OAAO,OAAO,CAAC,eAAe,CAAC,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,CAAC,CAAC;IACnF,CAAC;CACJ","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { parse } from \"url\";\nimport {\n IDocumentServiceFactory,\n IResolvedUrl,\n IDocumentService,\n} from \"@fluidframework/driver-definitions\";\nimport { ISummaryTree } from \"@fluidframework/protocol-definitions\";\nimport { ITelemetryBaseLogger } from \"@fluidframework/common-definitions\";\nimport { ensureFluidResolvedUrl } from \"./fluidResolvedUrl\";\n\nexport class MultiDocumentServiceFactory implements IDocumentServiceFactory {\n public static create(documentServiceFactory: IDocumentServiceFactory | IDocumentServiceFactory[]) {\n if (Array.isArray(documentServiceFactory)) {\n const factories: IDocumentServiceFactory[] = [];\n documentServiceFactory.forEach((factory) => {\n const maybeMulti = factory as MultiDocumentServiceFactory;\n if (maybeMulti.protocolToDocumentFactoryMap !== undefined) {\n factories.push(...maybeMulti.protocolToDocumentFactoryMap.values());\n } else {\n factories.push(factory);\n }\n });\n if (factories.length === 1) {\n return factories[0];\n }\n return new MultiDocumentServiceFactory(factories);\n }\n return documentServiceFactory;\n }\n\n private readonly protocolToDocumentFactoryMap: Map<string, IDocumentServiceFactory>;\n\n constructor(documentServiceFactories: IDocumentServiceFactory[]) {\n this.protocolToDocumentFactoryMap = new Map();\n documentServiceFactories.forEach((factory: IDocumentServiceFactory) => {\n this.protocolToDocumentFactoryMap.set(factory.protocolName, factory);\n });\n }\n public readonly protocolName = \"none:\";\n async createDocumentService(resolvedUrl: IResolvedUrl, logger?: ITelemetryBaseLogger): Promise<IDocumentService> {\n ensureFluidResolvedUrl(resolvedUrl);\n const urlObj = parse(resolvedUrl.url);\n if (urlObj.protocol === undefined || urlObj.protocol === null) {\n throw new Error(\"No protocol provided\");\n }\n const factory: IDocumentServiceFactory | undefined = this.protocolToDocumentFactoryMap.get(urlObj.protocol);\n if (factory === undefined) {\n throw new Error(\"Unknown Fluid protocol\");\n }\n\n return factory.createDocumentService(resolvedUrl, logger);\n }\n\n public async createContainer(\n createNewSummary: ISummaryTree,\n createNewResolvedUrl: IResolvedUrl,\n logger?: ITelemetryBaseLogger,\n ): Promise<IDocumentService> {\n ensureFluidResolvedUrl(createNewResolvedUrl);\n const urlObj = parse(createNewResolvedUrl.url);\n if (urlObj.protocol === undefined || urlObj.protocol === null) {\n throw new Error(\"No protocol provided\");\n }\n const factory: IDocumentServiceFactory | undefined = this.protocolToDocumentFactoryMap.get(urlObj.protocol);\n if (factory === undefined) {\n throw new Error(\"Unknown Fluid protocol\");\n }\n return factory.createContainer(createNewSummary, createNewResolvedUrl, logger);\n }\n}\n"]}
1
+ {"version":3,"file":"multiDocumentServiceFactory.js","sourceRoot":"","sources":["../src/multiDocumentServiceFactory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,KAAK,CAAC;AAQ5B,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,MAAM,OAAO,2BAA2B;IAsBpC,YAAY,wBAAmD;QAM/C,iBAAY,GAAG,OAAO,CAAC;QALnC,IAAI,CAAC,4BAA4B,GAAG,IAAI,GAAG,EAAE,CAAC;QAC9C,wBAAwB,CAAC,OAAO,CAAC,CAAC,OAAgC,EAAE,EAAE;YAClE,IAAI,CAAC,4BAA4B,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QACzE,CAAC,CAAC,CAAC;IACP,CAAC;IA1BM,MAAM,CAAC,MAAM,CAAC,sBAA2E;QAC5F,IAAI,KAAK,CAAC,OAAO,CAAC,sBAAsB,CAAC,EAAE;YACvC,MAAM,SAAS,GAA8B,EAAE,CAAC;YAChD,sBAAsB,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;gBACvC,MAAM,UAAU,GAAG,OAAsC,CAAC;gBAC1D,IAAI,UAAU,CAAC,4BAA4B,KAAK,SAAS,EAAE;oBACvD,SAAS,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,4BAA4B,CAAC,MAAM,EAAE,CAAC,CAAC;iBACvE;qBAAM;oBACH,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;iBAC3B;YACL,CAAC,CAAC,CAAC;YACH,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE;gBACxB,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC;aACvB;YACD,OAAO,IAAI,2BAA2B,CAAC,SAAS,CAAC,CAAC;SACrD;QACD,OAAO,sBAAsB,CAAC;IAClC,CAAC;IAWD,KAAK,CAAC,qBAAqB,CACvB,WAAyB,EACzB,MAA6B,EAC7B,kBAA4B;QAE5B,sBAAsB,CAAC,WAAW,CAAC,CAAC;QACpC,MAAM,MAAM,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACtC,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,KAAK,IAAI,EAAE;YAC3D,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;SAC3C;QACD,MAAM,OAAO,GAAwC,IAAI,CAAC,4BAA4B,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC5G,IAAI,OAAO,KAAK,SAAS,EAAE;YACvB,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;SAC7C;QAED,OAAO,OAAO,CAAC,qBAAqB,CAAC,WAAW,EAAE,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAClF,CAAC;IAEM,KAAK,CAAC,eAAe,CACxB,gBAA8B,EAC9B,oBAAkC,EAClC,MAA6B,EAC7B,kBAA4B;QAE5B,sBAAsB,CAAC,oBAAoB,CAAC,CAAC;QAC7C,MAAM,MAAM,GAAG,KAAK,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC;QAC/C,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,KAAK,IAAI,EAAE;YAC3D,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;SAC3C;QACD,MAAM,OAAO,GAAwC,IAAI,CAAC,4BAA4B,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC5G,IAAI,OAAO,KAAK,SAAS,EAAE;YACvB,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;SAC7C;QACD,OAAO,OAAO,CAAC,eAAe,CAAC,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,EAAE,kBAAkB,CAAC,CAAC;IACvG,CAAC;CACJ","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { parse } from \"url\";\nimport {\n IDocumentServiceFactory,\n IResolvedUrl,\n IDocumentService,\n} from \"@fluidframework/driver-definitions\";\nimport { ISummaryTree } from \"@fluidframework/protocol-definitions\";\nimport { ITelemetryBaseLogger } from \"@fluidframework/common-definitions\";\nimport { ensureFluidResolvedUrl } from \"./fluidResolvedUrl\";\n\nexport class MultiDocumentServiceFactory implements IDocumentServiceFactory {\n public static create(documentServiceFactory: IDocumentServiceFactory | IDocumentServiceFactory[]) {\n if (Array.isArray(documentServiceFactory)) {\n const factories: IDocumentServiceFactory[] = [];\n documentServiceFactory.forEach((factory) => {\n const maybeMulti = factory as MultiDocumentServiceFactory;\n if (maybeMulti.protocolToDocumentFactoryMap !== undefined) {\n factories.push(...maybeMulti.protocolToDocumentFactoryMap.values());\n } else {\n factories.push(factory);\n }\n });\n if (factories.length === 1) {\n return factories[0];\n }\n return new MultiDocumentServiceFactory(factories);\n }\n return documentServiceFactory;\n }\n\n private readonly protocolToDocumentFactoryMap: Map<string, IDocumentServiceFactory>;\n\n constructor(documentServiceFactories: IDocumentServiceFactory[]) {\n this.protocolToDocumentFactoryMap = new Map();\n documentServiceFactories.forEach((factory: IDocumentServiceFactory) => {\n this.protocolToDocumentFactoryMap.set(factory.protocolName, factory);\n });\n }\n public readonly protocolName = \"none:\";\n async createDocumentService(\n resolvedUrl: IResolvedUrl,\n logger?: ITelemetryBaseLogger,\n clientIsSummarizer?: boolean,\n ): Promise<IDocumentService> {\n ensureFluidResolvedUrl(resolvedUrl);\n const urlObj = parse(resolvedUrl.url);\n if (urlObj.protocol === undefined || urlObj.protocol === null) {\n throw new Error(\"No protocol provided\");\n }\n const factory: IDocumentServiceFactory | undefined = this.protocolToDocumentFactoryMap.get(urlObj.protocol);\n if (factory === undefined) {\n throw new Error(\"Unknown Fluid protocol\");\n }\n\n return factory.createDocumentService(resolvedUrl, logger, clientIsSummarizer);\n }\n\n public async createContainer(\n createNewSummary: ISummaryTree,\n createNewResolvedUrl: IResolvedUrl,\n logger?: ITelemetryBaseLogger,\n clientIsSummarizer?: boolean,\n ): Promise<IDocumentService> {\n ensureFluidResolvedUrl(createNewResolvedUrl);\n const urlObj = parse(createNewResolvedUrl.url);\n if (urlObj.protocol === undefined || urlObj.protocol === null) {\n throw new Error(\"No protocol provided\");\n }\n const factory: IDocumentServiceFactory | undefined = this.protocolToDocumentFactoryMap.get(urlObj.protocol);\n if (factory === undefined) {\n throw new Error(\"Unknown Fluid protocol\");\n }\n return factory.createContainer(createNewSummary, createNewResolvedUrl, logger, clientIsSummarizer);\n }\n}\n"]}
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export declare const pkgName = "@fluidframework/driver-utils";
8
- export declare const pkgVersion = "0.58.2002";
8
+ export declare const pkgVersion = "0.59.1000";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export const pkgName = "@fluidframework/driver-utils";
8
- export const pkgVersion = "0.58.2002";
8
+ export const pkgVersion = "0.59.1000";
9
9
  //# sourceMappingURL=packageVersion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,8BAA8B,CAAC;AACtD,MAAM,CAAC,MAAM,UAAU,GAAG,WAAW,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/driver-utils\";\nexport const pkgVersion = \"0.58.2002\";\n"]}
1
+ {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,8BAA8B,CAAC;AACtD,MAAM,CAAC,MAAM,UAAU,GAAG,WAAW,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/driver-utils\";\nexport const pkgVersion = \"0.59.1000\";\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"prefetchDocumentStorageService.d.ts","sourceRoot":"","sources":["../src/prefetchDocumentStorageService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,EACH,aAAa,EACb,QAAQ,EACX,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAG5E,qBAAa,8BAA+B,SAAQ,2BAA2B;IAE3E,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA+C;IAC7E,OAAO,CAAC,eAAe,CAAQ;IAE/B,IAAW,QAAQ;;;;kBAKlB;IAEY,eAAe,CAAC,OAAO,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAYlE,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAGxD,YAAY;YAKL,UAAU;IAkBxB,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,gBAAgB;CAyB3B"}
1
+ {"version":3,"file":"prefetchDocumentStorageService.d.ts","sourceRoot":"","sources":["../src/prefetchDocumentStorageService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,EACH,aAAa,EACb,QAAQ,EACX,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAG5E,qBAAa,8BAA+B,SAAQ,2BAA2B;IAE3E,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA+C;IAC7E,OAAO,CAAC,eAAe,CAAQ;IAE/B,IAAW,QAAQ;;;;kBAKlB;IAEY,eAAe,CAAC,OAAO,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAYlE,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAGxD,YAAY;YAKL,UAAU;IAkBxB,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,gBAAgB;CAmB3B"}
@@ -78,11 +78,6 @@ export class PrefetchDocumentStorageService extends DocumentStorageServiceProxy
78
78
  }
79
79
  }
80
80
  }
81
- for (const commit of Object.keys(tree.commits)) {
82
- // We don't care if the prefetch succeeds
83
- void this.getVersions(tree.commits[commit], 1)
84
- .then(async (moduleCommit) => this.getSnapshotTree(moduleCommit[0]));
85
- }
86
81
  for (const subTree of Object.keys(tree.trees)) {
87
82
  this.prefetchTreeCore(tree.trees[subTree], secondary);
88
83
  }
@@ -1 +1 @@
1
- {"version":3,"file":"prefetchDocumentStorageService.js","sourceRoot":"","sources":["../src/prefetchDocumentStorageService.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 */\nimport { LoaderCachingPolicy } from \"@fluidframework/driver-definitions\";\nimport {\n ISnapshotTree,\n IVersion,\n} from \"@fluidframework/protocol-definitions\";\nimport { DocumentStorageServiceProxy } from \"./documentStorageServiceProxy\";\nimport { canRetryOnError } from \"./network\";\n\nexport class PrefetchDocumentStorageService extends DocumentStorageServiceProxy {\n // BlobId -> blob prefetchCache cache\n private readonly prefetchCache = new Map<string, Promise<ArrayBufferLike>>();\n private prefetchEnabled = true;\n\n public get policies() {\n const policies = this.internalStorageService.policies;\n if (policies) {\n return { ...policies, caching: LoaderCachingPolicy.NoCaching };\n }\n }\n\n public async getSnapshotTree(version?: IVersion): Promise<ISnapshotTree | null> {\n const p = this.internalStorageService.getSnapshotTree(version);\n if (this.prefetchEnabled) {\n // We don't care if the prefetch succeeds\n void p.then((tree: ISnapshotTree | null | undefined) => {\n if (tree === null || tree === undefined) { return; }\n this.prefetchTree(tree);\n });\n }\n return p;\n }\n\n public async readBlob(blobId: string): Promise<ArrayBufferLike> {\n return this.cachedRead(blobId);\n }\n public stopPrefetch() {\n this.prefetchEnabled = false;\n this.prefetchCache.clear();\n }\n\n private async cachedRead(blobId: string): Promise<ArrayBufferLike> {\n if (this.prefetchEnabled) {\n const prefetchedBlobP = this.prefetchCache.get(blobId);\n if (prefetchedBlobP !== undefined) {\n return prefetchedBlobP;\n }\n const prefetchedBlobPFromStorage = this.internalStorageService.readBlob(blobId);\n this.prefetchCache.set(blobId, prefetchedBlobPFromStorage.catch((error) => {\n if (canRetryOnError(error)) {\n this.prefetchCache.delete(blobId);\n }\n throw error;\n }));\n return prefetchedBlobPFromStorage;\n }\n return this.internalStorageService.readBlob(blobId);\n }\n\n private prefetchTree(tree: ISnapshotTree) {\n const secondary: string[] = [];\n this.prefetchTreeCore(tree, secondary);\n\n for (const blob of secondary) {\n // We don't care if the prefetch succeeds\n void this.cachedRead(blob);\n }\n }\n\n private prefetchTreeCore(tree: ISnapshotTree, secondary: string[]) {\n for (const blobKey of Object.keys(tree.blobs)) {\n const blob = tree.blobs[blobKey];\n if (blobKey.startsWith(\".\") || blobKey === \"header\" || blobKey.startsWith(\"quorum\")) {\n if (blob !== null) {\n // We don't care if the prefetch succeeds\n void this.cachedRead(blob);\n }\n } else if (!blobKey.startsWith(\"deltas\")) {\n if (blob !== null) {\n secondary.push(blob);\n }\n }\n }\n\n for (const commit of Object.keys(tree.commits)) {\n // We don't care if the prefetch succeeds\n void this.getVersions(tree.commits[commit], 1)\n .then(async (moduleCommit) => this.getSnapshotTree(moduleCommit[0]));\n }\n\n for (const subTree of Object.keys(tree.trees)) {\n this.prefetchTreeCore(tree.trees[subTree], secondary);\n }\n }\n}\n"]}
1
+ {"version":3,"file":"prefetchDocumentStorageService.js","sourceRoot":"","sources":["../src/prefetchDocumentStorageService.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 */\nimport { LoaderCachingPolicy } from \"@fluidframework/driver-definitions\";\nimport {\n ISnapshotTree,\n IVersion,\n} from \"@fluidframework/protocol-definitions\";\nimport { DocumentStorageServiceProxy } from \"./documentStorageServiceProxy\";\nimport { canRetryOnError } from \"./network\";\n\nexport class PrefetchDocumentStorageService extends DocumentStorageServiceProxy {\n // BlobId -> blob prefetchCache cache\n private readonly prefetchCache = new Map<string, Promise<ArrayBufferLike>>();\n private prefetchEnabled = true;\n\n public get policies() {\n const policies = this.internalStorageService.policies;\n if (policies) {\n return { ...policies, caching: LoaderCachingPolicy.NoCaching };\n }\n }\n\n public async getSnapshotTree(version?: IVersion): Promise<ISnapshotTree | null> {\n const p = this.internalStorageService.getSnapshotTree(version);\n if (this.prefetchEnabled) {\n // We don't care if the prefetch succeeds\n void p.then((tree: ISnapshotTree | null | undefined) => {\n if (tree === null || tree === undefined) { return; }\n this.prefetchTree(tree);\n });\n }\n return p;\n }\n\n public async readBlob(blobId: string): Promise<ArrayBufferLike> {\n return this.cachedRead(blobId);\n }\n public stopPrefetch() {\n this.prefetchEnabled = false;\n this.prefetchCache.clear();\n }\n\n private async cachedRead(blobId: string): Promise<ArrayBufferLike> {\n if (this.prefetchEnabled) {\n const prefetchedBlobP = this.prefetchCache.get(blobId);\n if (prefetchedBlobP !== undefined) {\n return prefetchedBlobP;\n }\n const prefetchedBlobPFromStorage = this.internalStorageService.readBlob(blobId);\n this.prefetchCache.set(blobId, prefetchedBlobPFromStorage.catch((error) => {\n if (canRetryOnError(error)) {\n this.prefetchCache.delete(blobId);\n }\n throw error;\n }));\n return prefetchedBlobPFromStorage;\n }\n return this.internalStorageService.readBlob(blobId);\n }\n\n private prefetchTree(tree: ISnapshotTree) {\n const secondary: string[] = [];\n this.prefetchTreeCore(tree, secondary);\n\n for (const blob of secondary) {\n // We don't care if the prefetch succeeds\n void this.cachedRead(blob);\n }\n }\n\n private prefetchTreeCore(tree: ISnapshotTree, secondary: string[]) {\n for (const blobKey of Object.keys(tree.blobs)) {\n const blob = tree.blobs[blobKey];\n if (blobKey.startsWith(\".\") || blobKey === \"header\" || blobKey.startsWith(\"quorum\")) {\n if (blob !== null) {\n // We don't care if the prefetch succeeds\n void this.cachedRead(blob);\n }\n } else if (!blobKey.startsWith(\"deltas\")) {\n if (blob !== null) {\n secondary.push(blob);\n }\n }\n }\n\n for (const subTree of Object.keys(tree.trees)) {\n this.prefetchTreeCore(tree.trees[subTree], secondary);\n }\n }\n}\n"]}
@@ -27,7 +27,7 @@ export interface IProgress {
27
27
  * as well as information provided by service (like 429 error asking to wait for some time before retry)
28
28
  * @param error - error object returned from the call.
29
29
  */
30
- retry?(delayInMs: number, error: any): void;
30
+ onRetry?(delayInMs: number, error: any): void;
31
31
  }
32
32
  export declare function runWithRetry<T>(api: (cancel?: AbortSignal) => Promise<T>, fetchCallName: string, logger: ITelemetryLogger, progress: IProgress): Promise<T>;
33
33
  //# sourceMappingURL=runWithRetry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"runWithRetry.d.ts","sourceRoot":"","sources":["../src/runWithRetry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAItE;;;GAGG;AACH,MAAM,WAAW,SAAS;IACtB;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IAErB;;;;;;;OAOG;IACH,KAAK,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI,CAAC;CAC/C;AAED,wBAAsB,YAAY,CAAC,CAAC,EAChC,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,EACzC,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,gBAAgB,EACxB,QAAQ,EAAE,SAAS,GACpB,OAAO,CAAC,CAAC,CAAC,CA0CZ"}
1
+ {"version":3,"file":"runWithRetry.d.ts","sourceRoot":"","sources":["../src/runWithRetry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAOtE;;;GAGG;AACH,MAAM,WAAW,SAAS;IACtB;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IAErB;;;;;;;OAOG;IACH,OAAO,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI,CAAC;CACjD;AAED,wBAAsB,YAAY,CAAC,CAAC,EAChC,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,EACzC,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,gBAAgB,EACxB,QAAQ,EAAE,SAAS,GACpB,OAAO,CAAC,CAAC,CAAC,CA2DZ"}
@@ -3,9 +3,12 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
  import { delay, performance } from "@fluidframework/common-utils";
6
+ import { DriverErrorType } from "@fluidframework/driver-definitions";
6
7
  import { canRetryOnError, getRetryDelayFromError } from "./network";
8
+ import { pkgVersion } from "./packageVersion";
9
+ import { NonRetryableError } from ".";
7
10
  export async function runWithRetry(api, fetchCallName, logger, progress) {
8
- var _a;
11
+ var _a, _b;
9
12
  let result;
10
13
  let success = false;
11
14
  let retryAfterMs = 1000; // has to be positive!
@@ -24,16 +27,26 @@ export async function runWithRetry(api, fetchCallName, logger, progress) {
24
27
  eventName: `${fetchCallName}_cancel`,
25
28
  retry: numRetries,
26
29
  duration: performance.now() - startTime,
30
+ fetchCallName,
27
31
  }, err);
28
32
  throw err;
29
33
  }
34
+ if (((_a = progress.cancel) === null || _a === void 0 ? void 0 : _a.aborted) === true) {
35
+ logger.sendTelemetryEvent({
36
+ eventName: `${fetchCallName}_runWithRetryAborted`,
37
+ retry: numRetries,
38
+ duration: performance.now() - startTime,
39
+ fetchCallName,
40
+ }, err);
41
+ throw new NonRetryableError("runWithRetry was Aborted", DriverErrorType.genericError, { driverVersion: pkgVersion, fetchCallName });
42
+ }
30
43
  numRetries++;
31
44
  lastError = err;
32
45
  // If the error is throttling error, then wait for the specified time before retrying.
33
46
  // If the waitTime is not specified, then we start with retrying immediately to max of 8s.
34
- retryAfterMs = (_a = getRetryDelayFromError(err)) !== null && _a !== void 0 ? _a : Math.min(retryAfterMs * 2, 8000);
35
- if (progress.retry) {
36
- progress.retry(retryAfterMs, err);
47
+ retryAfterMs = (_b = getRetryDelayFromError(err)) !== null && _b !== void 0 ? _b : Math.min(retryAfterMs * 2, 8000);
48
+ if (progress.onRetry) {
49
+ progress.onRetry(retryAfterMs, err);
37
50
  }
38
51
  await delay(retryAfterMs);
39
52
  }
@@ -43,6 +56,7 @@ export async function runWithRetry(api, fetchCallName, logger, progress) {
43
56
  eventName: `${fetchCallName}_lastError`,
44
57
  retry: numRetries,
45
58
  duration: performance.now() - startTime,
59
+ fetchCallName,
46
60
  }, lastError);
47
61
  }
48
62
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
@@ -1 +1 @@
1
- {"version":3,"file":"runWithRetry.js","sourceRoot":"","sources":["../src/runWithRetry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AA8BpE,MAAM,CAAC,KAAK,UAAU,YAAY,CAC9B,GAAyC,EACzC,aAAqB,EACrB,MAAwB,EACxB,QAAmB;;IAEnB,IAAI,MAAqB,CAAC;IAC1B,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,YAAY,GAAG,IAAI,CAAC,CAAC,sBAAsB;IAC/C,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IACpC,IAAI,SAAc,CAAC;IACnB,GAAG;QACC,IAAI;YACA,MAAM,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YACpC,OAAO,GAAG,IAAI,CAAC;SAClB;QAAC,OAAO,GAAG,EAAE;YACV,qDAAqD;YACrD,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE;gBACvB,MAAM,CAAC,kBAAkB,CAAC;oBACtB,SAAS,EAAE,GAAG,aAAa,SAAS;oBACpC,KAAK,EAAE,UAAU;oBACjB,QAAQ,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,SAAS;iBAC1C,EAAE,GAAG,CAAC,CAAC;gBACR,MAAM,GAAG,CAAC;aACb;YACD,UAAU,EAAE,CAAC;YACb,SAAS,GAAG,GAAG,CAAC;YAChB,sFAAsF;YACtF,0FAA0F;YAC1F,YAAY,SAAG,sBAAsB,CAAC,GAAG,CAAC,mCAAI,IAAI,CAAC,GAAG,CAAC,YAAY,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;YAC/E,IAAI,QAAQ,CAAC,KAAK,EAAE;gBAChB,QAAQ,CAAC,KAAK,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;aACrC;YACD,MAAM,KAAK,CAAC,YAAY,CAAC,CAAC;SAC7B;KACJ,QAAQ,CAAC,OAAO,EAAE;IACnB,IAAI,UAAU,GAAG,CAAC,EAAE;QAChB,MAAM,CAAC,kBAAkB,CAAC;YACtB,SAAS,EAAE,GAAG,aAAa,YAAY;YACvC,KAAK,EAAE,UAAU;YACjB,QAAQ,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,SAAS;SAC1C,EACD,SAAS,CAAC,CAAC;KACd;IACD,oEAAoE;IACpE,OAAO,MAAO,CAAC;AACnB,CAAC","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 { delay, performance } from \"@fluidframework/common-utils\";\nimport { canRetryOnError, getRetryDelayFromError } from \"./network\";\n\n/**\n * Interface describing an object passed to various network APIs.\n * It allows caller to control cancellation, as well as learn about any delays.\n */\nexport interface IProgress {\n /**\n * Abort signal used to cancel operation\n * Note that most of the layers do not use this signal yet. We need to change that over time.\n * Please consult with API documentation / implementation.\n * Note that number of layers may not check this signal while holding this request in a queue,\n * so it may take a while it takes effect. This can be improved in the future.\n * Layers in question are:\n * - driver (RateLimiter)\n * - runWithRetry\n */\n cancel?: AbortSignal;\n\n /**\n * Called whenever api returns cancellable error and the call is going to be retried.\n * Any exception thrown from this call back result in cancellation of operation\n * and propagation of thrown exception.\n * @param delayInMs - delay before next retry. This value will depend on internal back-off logic,\n * as well as information provided by service (like 429 error asking to wait for some time before retry)\n * @param error - error object returned from the call.\n */\n retry?(delayInMs: number, error: any): void;\n}\n\nexport async function runWithRetry<T>(\n api: (cancel?: AbortSignal) => Promise<T>,\n fetchCallName: string,\n logger: ITelemetryLogger,\n progress: IProgress,\n): Promise<T> {\n let result: T | undefined;\n let success = false;\n let retryAfterMs = 1000; // has to be positive!\n let numRetries = 0;\n const startTime = performance.now();\n let lastError: any;\n do {\n try {\n result = await api(progress.cancel);\n success = true;\n } catch (err) {\n // If it is not retriable, then just throw the error.\n if (!canRetryOnError(err)) {\n logger.sendTelemetryEvent({\n eventName: `${fetchCallName}_cancel`,\n retry: numRetries,\n duration: performance.now() - startTime,\n }, err);\n throw err;\n }\n numRetries++;\n lastError = err;\n // If the error is throttling error, then wait for the specified time before retrying.\n // If the waitTime is not specified, then we start with retrying immediately to max of 8s.\n retryAfterMs = getRetryDelayFromError(err) ?? Math.min(retryAfterMs * 2, 8000);\n if (progress.retry) {\n progress.retry(retryAfterMs, err);\n }\n await delay(retryAfterMs);\n }\n } while (!success);\n if (numRetries > 0) {\n logger.sendTelemetryEvent({\n eventName: `${fetchCallName}_lastError`,\n retry: numRetries,\n duration: performance.now() - startTime,\n },\n lastError);\n }\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return result!;\n}\n"]}
1
+ {"version":3,"file":"runWithRetry.js","sourceRoot":"","sources":["../src/runWithRetry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,GAAG,CAAC;AA8BtC,MAAM,CAAC,KAAK,UAAU,YAAY,CAC9B,GAAyC,EACzC,aAAqB,EACrB,MAAwB,EACxB,QAAmB;;IAEnB,IAAI,MAAqB,CAAC;IAC1B,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,YAAY,GAAG,IAAI,CAAC,CAAC,sBAAsB;IAC/C,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IACpC,IAAI,SAAc,CAAC;IACnB,GAAG;QACC,IAAI;YACA,MAAM,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YACpC,OAAO,GAAG,IAAI,CAAC;SAClB;QAAC,OAAO,GAAG,EAAE;YACV,qDAAqD;YACrD,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE;gBACvB,MAAM,CAAC,kBAAkB,CAAC;oBACtB,SAAS,EAAE,GAAG,aAAa,SAAS;oBACpC,KAAK,EAAE,UAAU;oBACjB,QAAQ,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,SAAS;oBACvC,aAAa;iBAChB,EAAE,GAAG,CAAC,CAAC;gBACR,MAAM,GAAG,CAAC;aACb;YAED,IAAI,OAAA,QAAQ,CAAC,MAAM,0CAAE,OAAO,MAAK,IAAI,EAAE;gBACnC,MAAM,CAAC,kBAAkB,CAAC;oBACtB,SAAS,EAAE,GAAG,aAAa,sBAAsB;oBACjD,KAAK,EAAE,UAAU;oBACjB,QAAQ,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,SAAS;oBACvC,aAAa;iBAChB,EAAE,GAAG,CAAC,CAAC;gBACR,MAAM,IAAI,iBAAiB,CACvB,0BAA0B,EAC1B,eAAe,CAAC,YAAY,EAC5B,EAAE,aAAa,EAAE,UAAU,EAAE,aAAa,EAAE,CAC/C,CAAC;aACL;YAED,UAAU,EAAE,CAAC;YACb,SAAS,GAAG,GAAG,CAAC;YAChB,sFAAsF;YACtF,0FAA0F;YAC1F,YAAY,SAAG,sBAAsB,CAAC,GAAG,CAAC,mCAAI,IAAI,CAAC,GAAG,CAAC,YAAY,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;YAC/E,IAAI,QAAQ,CAAC,OAAO,EAAE;gBAClB,QAAQ,CAAC,OAAO,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;aACvC;YACD,MAAM,KAAK,CAAC,YAAY,CAAC,CAAC;SAC7B;KACJ,QAAQ,CAAC,OAAO,EAAE;IACnB,IAAI,UAAU,GAAG,CAAC,EAAE;QAChB,MAAM,CAAC,kBAAkB,CAAC;YACtB,SAAS,EAAE,GAAG,aAAa,YAAY;YACvC,KAAK,EAAE,UAAU;YACjB,QAAQ,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,SAAS;YACvC,aAAa;SAChB,EACD,SAAS,CAAC,CAAC;KACd;IACD,oEAAoE;IACpE,OAAO,MAAO,CAAC;AACnB,CAAC","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 { delay, performance } from \"@fluidframework/common-utils\";\nimport { DriverErrorType } from \"@fluidframework/driver-definitions\";\nimport { canRetryOnError, getRetryDelayFromError } from \"./network\";\nimport { pkgVersion } from \"./packageVersion\";\nimport { NonRetryableError } from \".\";\n\n/**\n * Interface describing an object passed to various network APIs.\n * It allows caller to control cancellation, as well as learn about any delays.\n */\nexport interface IProgress {\n /**\n * Abort signal used to cancel operation\n * Note that most of the layers do not use this signal yet. We need to change that over time.\n * Please consult with API documentation / implementation.\n * Note that number of layers may not check this signal while holding this request in a queue,\n * so it may take a while it takes effect. This can be improved in the future.\n * Layers in question are:\n * - driver (RateLimiter)\n * - runWithRetry\n */\n cancel?: AbortSignal;\n\n /**\n * Called whenever api returns cancellable error and the call is going to be retried.\n * Any exception thrown from this call back result in cancellation of operation\n * and propagation of thrown exception.\n * @param delayInMs - delay before next retry. This value will depend on internal back-off logic,\n * as well as information provided by service (like 429 error asking to wait for some time before retry)\n * @param error - error object returned from the call.\n */\n onRetry?(delayInMs: number, error: any): void;\n}\n\nexport async function runWithRetry<T>(\n api: (cancel?: AbortSignal) => Promise<T>,\n fetchCallName: string,\n logger: ITelemetryLogger,\n progress: IProgress,\n): Promise<T> {\n let result: T | undefined;\n let success = false;\n let retryAfterMs = 1000; // has to be positive!\n let numRetries = 0;\n const startTime = performance.now();\n let lastError: any;\n do {\n try {\n result = await api(progress.cancel);\n success = true;\n } catch (err) {\n // If it is not retriable, then just throw the error.\n if (!canRetryOnError(err)) {\n logger.sendTelemetryEvent({\n eventName: `${fetchCallName}_cancel`,\n retry: numRetries,\n duration: performance.now() - startTime,\n fetchCallName,\n }, err);\n throw err;\n }\n\n if (progress.cancel?.aborted === true) {\n logger.sendTelemetryEvent({\n eventName: `${fetchCallName}_runWithRetryAborted`,\n retry: numRetries,\n duration: performance.now() - startTime,\n fetchCallName,\n }, err);\n throw new NonRetryableError(\n \"runWithRetry was Aborted\",\n DriverErrorType.genericError,\n { driverVersion: pkgVersion, fetchCallName },\n );\n }\n\n numRetries++;\n lastError = err;\n // If the error is throttling error, then wait for the specified time before retrying.\n // If the waitTime is not specified, then we start with retrying immediately to max of 8s.\n retryAfterMs = getRetryDelayFromError(err) ?? Math.min(retryAfterMs * 2, 8000);\n if (progress.onRetry) {\n progress.onRetry(retryAfterMs, err);\n }\n await delay(retryAfterMs);\n }\n } while (!success);\n if (numRetries > 0) {\n logger.sendTelemetryEvent({\n eventName: `${fetchCallName}_lastError`,\n retry: numRetries,\n duration: performance.now() - startTime,\n fetchCallName,\n },\n lastError);\n }\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return result!;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/driver-utils",
3
- "version": "0.58.2002",
3
+ "version": "0.59.1000",
4
4
  "description": "Collection of utility functions for Fluid drivers",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -32,7 +32,7 @@
32
32
  "lint:fix": "npm run eslint:fix",
33
33
  "test": "npm run test:mocha",
34
34
  "test:coverage": "nyc npm test -- --reporter xunit --reporter-option output=nyc/junit-report.xml",
35
- "test:mocha": "mocha --recursive dist/test -r node_modules/@fluidframework/mocha-test-setup --unhandled-rejections=strict",
35
+ "test:mocha": "mocha --ignore 'dist/test/types/*' --recursive dist/test -r node_modules/@fluidframework/mocha-test-setup --unhandled-rejections=strict",
36
36
  "test:mocha:verbose": "cross-env FLUID_TEST_VERBOSE=1 npm run test:mocha",
37
37
  "tsc": "tsc",
38
38
  "tsfmt": "tsfmt --verify",
@@ -61,20 +61,21 @@
61
61
  "dependencies": {
62
62
  "@fluidframework/common-definitions": "^0.20.1",
63
63
  "@fluidframework/common-utils": "^0.32.1",
64
- "@fluidframework/core-interfaces": "^0.42.0",
65
- "@fluidframework/driver-definitions": "^0.45.1000",
66
- "@fluidframework/gitresources": "^0.1035.1000",
67
- "@fluidframework/protocol-base": "^0.1035.1000",
68
- "@fluidframework/protocol-definitions": "^0.1027.1000",
69
- "@fluidframework/telemetry-utils": "^0.58.2002",
64
+ "@fluidframework/core-interfaces": "^0.43.1000",
65
+ "@fluidframework/driver-definitions": "^0.46.1000",
66
+ "@fluidframework/gitresources": "^0.1036.1000",
67
+ "@fluidframework/protocol-base": "^0.1036.1000",
68
+ "@fluidframework/protocol-definitions": "^0.1028.1000",
69
+ "@fluidframework/telemetry-utils": "^0.59.1000",
70
70
  "axios": "^0.26.0",
71
71
  "uuid": "^8.3.1"
72
72
  },
73
73
  "devDependencies": {
74
74
  "@fluidframework/build-common": "^0.23.0",
75
- "@fluidframework/eslint-config-fluid": "^0.27.0",
76
- "@fluidframework/mocha-test-setup": "^0.58.2002",
77
- "@fluidframework/runtime-utils": "^0.58.2002",
75
+ "@fluidframework/driver-utils-previous": "npm:@fluidframework/driver-utils@^0.58.0",
76
+ "@fluidframework/eslint-config-fluid": "^0.28.1000",
77
+ "@fluidframework/mocha-test-setup": "^0.59.1000",
78
+ "@fluidframework/runtime-utils": "^0.59.1000",
78
79
  "@microsoft/api-extractor": "^7.16.1",
79
80
  "@rushstack/eslint-config": "^2.5.1",
80
81
  "@types/mocha": "^8.2.2",
@@ -96,5 +97,9 @@
96
97
  "rimraf": "^2.6.2",
97
98
  "typescript": "~4.1.3",
98
99
  "typescript-formatter": "7.1.0"
100
+ },
101
+ "typeValidation": {
102
+ "version": "0.59.1000",
103
+ "broken": {}
99
104
  }
100
105
  }
@@ -99,7 +99,7 @@ export abstract class SnapshotExtractor {
99
99
  let subTree = snapshot;
100
100
  for (const subPath of pathSplit.slice(0, pathSplit.length - 1)) {
101
101
  if (subTree.trees[subPath] === undefined) {
102
- subTree.trees[subPath] = { blobs: {}, commits: {}, trees: {}};
102
+ subTree.trees[subPath] = { blobs: {}, trees: {}};
103
103
  }
104
104
  subTree = subTree.trees[subPath];
105
105
  }
@@ -42,7 +42,11 @@ export class MultiDocumentServiceFactory implements IDocumentServiceFactory {
42
42
  });
43
43
  }
44
44
  public readonly protocolName = "none:";
45
- async createDocumentService(resolvedUrl: IResolvedUrl, logger?: ITelemetryBaseLogger): Promise<IDocumentService> {
45
+ async createDocumentService(
46
+ resolvedUrl: IResolvedUrl,
47
+ logger?: ITelemetryBaseLogger,
48
+ clientIsSummarizer?: boolean,
49
+ ): Promise<IDocumentService> {
46
50
  ensureFluidResolvedUrl(resolvedUrl);
47
51
  const urlObj = parse(resolvedUrl.url);
48
52
  if (urlObj.protocol === undefined || urlObj.protocol === null) {
@@ -53,13 +57,14 @@ export class MultiDocumentServiceFactory implements IDocumentServiceFactory {
53
57
  throw new Error("Unknown Fluid protocol");
54
58
  }
55
59
 
56
- return factory.createDocumentService(resolvedUrl, logger);
60
+ return factory.createDocumentService(resolvedUrl, logger, clientIsSummarizer);
57
61
  }
58
62
 
59
63
  public async createContainer(
60
64
  createNewSummary: ISummaryTree,
61
65
  createNewResolvedUrl: IResolvedUrl,
62
66
  logger?: ITelemetryBaseLogger,
67
+ clientIsSummarizer?: boolean,
63
68
  ): Promise<IDocumentService> {
64
69
  ensureFluidResolvedUrl(createNewResolvedUrl);
65
70
  const urlObj = parse(createNewResolvedUrl.url);
@@ -70,6 +75,6 @@ export class MultiDocumentServiceFactory implements IDocumentServiceFactory {
70
75
  if (factory === undefined) {
71
76
  throw new Error("Unknown Fluid protocol");
72
77
  }
73
- return factory.createContainer(createNewSummary, createNewResolvedUrl, logger);
78
+ return factory.createContainer(createNewSummary, createNewResolvedUrl, logger, clientIsSummarizer);
74
79
  }
75
80
  }
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/driver-utils";
9
- export const pkgVersion = "0.58.2002";
9
+ export const pkgVersion = "0.59.1000";
@@ -85,12 +85,6 @@ export class PrefetchDocumentStorageService extends DocumentStorageServiceProxy
85
85
  }
86
86
  }
87
87
 
88
- for (const commit of Object.keys(tree.commits)) {
89
- // We don't care if the prefetch succeeds
90
- void this.getVersions(tree.commits[commit], 1)
91
- .then(async (moduleCommit) => this.getSnapshotTree(moduleCommit[0]));
92
- }
93
-
94
88
  for (const subTree of Object.keys(tree.trees)) {
95
89
  this.prefetchTreeCore(tree.trees[subTree], secondary);
96
90
  }
@@ -5,7 +5,10 @@
5
5
 
6
6
  import { ITelemetryLogger } from "@fluidframework/common-definitions";
7
7
  import { delay, performance } from "@fluidframework/common-utils";
8
+ import { DriverErrorType } from "@fluidframework/driver-definitions";
8
9
  import { canRetryOnError, getRetryDelayFromError } from "./network";
10
+ import { pkgVersion } from "./packageVersion";
11
+ import { NonRetryableError } from ".";
9
12
 
10
13
  /**
11
14
  * Interface describing an object passed to various network APIs.
@@ -32,7 +35,7 @@ export interface IProgress {
32
35
  * as well as information provided by service (like 429 error asking to wait for some time before retry)
33
36
  * @param error - error object returned from the call.
34
37
  */
35
- retry?(delayInMs: number, error: any): void;
38
+ onRetry?(delayInMs: number, error: any): void;
36
39
  }
37
40
 
38
41
  export async function runWithRetry<T>(
@@ -58,16 +61,32 @@ export async function runWithRetry<T>(
58
61
  eventName: `${fetchCallName}_cancel`,
59
62
  retry: numRetries,
60
63
  duration: performance.now() - startTime,
64
+ fetchCallName,
61
65
  }, err);
62
66
  throw err;
63
67
  }
68
+
69
+ if (progress.cancel?.aborted === true) {
70
+ logger.sendTelemetryEvent({
71
+ eventName: `${fetchCallName}_runWithRetryAborted`,
72
+ retry: numRetries,
73
+ duration: performance.now() - startTime,
74
+ fetchCallName,
75
+ }, err);
76
+ throw new NonRetryableError(
77
+ "runWithRetry was Aborted",
78
+ DriverErrorType.genericError,
79
+ { driverVersion: pkgVersion, fetchCallName },
80
+ );
81
+ }
82
+
64
83
  numRetries++;
65
84
  lastError = err;
66
85
  // If the error is throttling error, then wait for the specified time before retrying.
67
86
  // If the waitTime is not specified, then we start with retrying immediately to max of 8s.
68
87
  retryAfterMs = getRetryDelayFromError(err) ?? Math.min(retryAfterMs * 2, 8000);
69
- if (progress.retry) {
70
- progress.retry(retryAfterMs, err);
88
+ if (progress.onRetry) {
89
+ progress.onRetry(retryAfterMs, err);
71
90
  }
72
91
  await delay(retryAfterMs);
73
92
  }
@@ -77,6 +96,7 @@ export async function runWithRetry<T>(
77
96
  eventName: `${fetchCallName}_lastError`,
78
97
  retry: numRetries,
79
98
  duration: performance.now() - startTime,
99
+ fetchCallName,
80
100
  },
81
101
  lastError);
82
102
  }