@fluidframework/datastore 2.0.0-rc.2.0.0 → 2.0.0-rc.2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dataStoreRuntime.d.ts +1 -0
- package/dist/dataStoreRuntime.d.ts.map +1 -1
- package/dist/dataStoreRuntime.js +16 -8
- package/dist/dataStoreRuntime.js.map +1 -1
- package/dist/datastore-alpha.d.ts +1 -0
- package/dist/datastore-untrimmed.d.ts +1 -0
- package/dist/localChannelContext.d.ts +1 -1
- package/dist/localChannelContext.d.ts.map +1 -1
- package/dist/localChannelContext.js +19 -9
- package/dist/localChannelContext.js.map +1 -1
- package/lib/dataStoreRuntime.d.ts +1 -0
- package/lib/dataStoreRuntime.d.ts.map +1 -1
- package/lib/dataStoreRuntime.js +16 -8
- package/lib/dataStoreRuntime.js.map +1 -1
- package/lib/datastore-alpha.d.ts +1 -0
- package/lib/datastore-untrimmed.d.ts +1 -0
- package/lib/localChannelContext.d.ts +1 -1
- package/lib/localChannelContext.d.ts.map +1 -1
- package/lib/localChannelContext.js +19 -6
- package/lib/localChannelContext.js.map +1 -1
- package/package.json +14 -16
- package/src/dataStoreRuntime.ts +39 -20
- package/src/localChannelContext.ts +22 -6
|
@@ -2,9 +2,6 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
-
import lodashPkg from "lodash";
|
|
6
|
-
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
7
|
-
const { cloneDeep } = lodashPkg;
|
|
8
5
|
import { DataProcessingError } from "@fluidframework/telemetry-utils";
|
|
9
6
|
import { assert, Lazy, LazyPromise } from "@fluidframework/core-utils";
|
|
10
7
|
import { createChannelServiceEndpoints, loadChannel, loadChannelFactoryAndAttributes, summarizeChannel, summarizeChannelAsync, } from "./channelContext.js";
|
|
@@ -122,10 +119,10 @@ export class LocalChannelContextBase {
|
|
|
122
119
|
}
|
|
123
120
|
}
|
|
124
121
|
export class RehydratedLocalChannelContext extends LocalChannelContextBase {
|
|
125
|
-
constructor(id, registry, runtime, dataStoreContext, storageService, logger, submitFn, dirtyFn, addedGCOutboundReferenceFn, snapshotTree) {
|
|
122
|
+
constructor(id, registry, runtime, dataStoreContext, storageService, logger, submitFn, dirtyFn, addedGCOutboundReferenceFn, snapshotTree, extraBlob) {
|
|
126
123
|
super(id, runtime, new Lazy(() => {
|
|
127
|
-
const blobMap = new Map();
|
|
128
|
-
const clonedSnapshotTree =
|
|
124
|
+
const blobMap = new Map(extraBlob);
|
|
125
|
+
const clonedSnapshotTree = cloneSnapshotTree(this.snapshotTree);
|
|
129
126
|
// 0.47 back-compat Need to sanitize if snapshotTree.blobs still contains blob contents too.
|
|
130
127
|
// This is for older snapshot which is generated by loader <=0.47 version which still contains
|
|
131
128
|
// the contents within blobs. After a couple of revisions we can remove it.
|
|
@@ -200,4 +197,20 @@ export class LocalChannelContext extends LocalChannelContextBase {
|
|
|
200
197
|
throw new Error("no stashed ops on local channel");
|
|
201
198
|
}
|
|
202
199
|
}
|
|
200
|
+
/**
|
|
201
|
+
* Deep clones a snapshot tree.
|
|
202
|
+
*
|
|
203
|
+
* TODO: Investigate replacing this with a deep clone utility.
|
|
204
|
+
* This is a temporary solution to avoid issues with lodash deepClone and ungap structuredClone.
|
|
205
|
+
* Using lodash caused a significant bundle size regression. structuredClone cannot be used since
|
|
206
|
+
* it does not support ArrayBuffer data types, and ISnapshotTree can contain blobContents properties,
|
|
207
|
+
* which are ArrayBuffer data types.
|
|
208
|
+
*/
|
|
209
|
+
function cloneSnapshotTree(tree) {
|
|
210
|
+
const clone = { ...tree, blobs: { ...tree.blobs }, trees: {} };
|
|
211
|
+
for (const [k, v] of Object.entries(tree.trees)) {
|
|
212
|
+
clone.trees[k] = cloneSnapshotTree(v);
|
|
213
|
+
}
|
|
214
|
+
return clone;
|
|
215
|
+
}
|
|
203
216
|
//# sourceMappingURL=localChannelContext.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"localChannelContext.js","sourceRoot":"","sources":["../src/localChannelContext.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 lodashPkg from \"lodash\";\n// eslint-disable-next-line @typescript-eslint/unbound-method\nconst { cloneDeep } = lodashPkg;\n\nimport { DataProcessingError, ITelemetryLoggerExt } from \"@fluidframework/telemetry-utils\";\nimport { IDocumentStorageService } from \"@fluidframework/driver-definitions\";\nimport { ISequencedDocumentMessage, ISnapshotTree } from \"@fluidframework/protocol-definitions\";\nimport { IChannel, IFluidDataStoreRuntime } from \"@fluidframework/datastore-definitions\";\nimport {\n\tIFluidDataStoreContext,\n\tIGarbageCollectionData,\n\tISummarizeResult,\n\tITelemetryContext,\n} from \"@fluidframework/runtime-definitions\";\nimport { assert, Lazy, LazyPromise } from \"@fluidframework/core-utils\";\nimport { IFluidHandle } from \"@fluidframework/core-interfaces\";\nimport { ISnapshotTreeWithBlobContents } from \"@fluidframework/container-definitions\";\nimport {\n\tChannelServiceEndpoints,\n\tcreateChannelServiceEndpoints,\n\tIChannelContext,\n\tloadChannel,\n\tloadChannelFactoryAndAttributes,\n\tsummarizeChannel,\n\tsummarizeChannelAsync,\n} from \"./channelContext.js\";\nimport { ISharedObjectRegistry } from \"./dataStoreRuntime.js\";\n\n/**\n * Channel context for a locally created channel\n */\nexport abstract class LocalChannelContextBase implements IChannelContext {\n\tprivate globallyVisible = false;\n\tprotected readonly pending: ISequencedDocumentMessage[] = [];\n\tconstructor(\n\t\tprotected readonly id: string,\n\t\tprotected readonly runtime: IFluidDataStoreRuntime,\n\t\tprotected readonly services: Lazy<ChannelServiceEndpoints>,\n\t\tprivate readonly channelP: Promise<IChannel>,\n\t\tprivate _channel?: IChannel,\n\t) {\n\t\tassert(!this.id.includes(\"/\"), 0x30f /* Channel context ID cannot contain slashes */);\n\t}\n\n\tprotected get isGloballyVisible() {\n\t\treturn this.globallyVisible;\n\t}\n\n\tpublic async getChannel(): Promise<IChannel> {\n\t\tif (this._channel === undefined) {\n\t\t\treturn this.channelP.then((c) => (this._channel = c));\n\t\t}\n\t\treturn this.channelP;\n\t}\n\n\tpublic get isLoaded(): boolean {\n\t\treturn this._channel !== undefined;\n\t}\n\n\tpublic setConnectionState(connected: boolean, clientId?: string) {\n\t\t// Connection events are ignored if the data store is not yet globallyVisible or loaded\n\t\tif (this.globallyVisible && this.isLoaded) {\n\t\t\tthis.services.value.deltaConnection.setConnectionState(connected);\n\t\t}\n\t}\n\n\tpublic processOp(\n\t\tmessage: ISequencedDocumentMessage,\n\t\tlocal: boolean,\n\t\tlocalOpMetadata: unknown,\n\t): void {\n\t\tassert(\n\t\t\tthis.globallyVisible,\n\t\t\t0x2d3 /* \"Local channel must be globally visible when processing op\" */,\n\t\t);\n\n\t\t// A local channel may not be loaded in case where we rehydrate the container from a snapshot because of\n\t\t// delay loading. So after the container is attached and some other client joins which start generating\n\t\t// ops for this channel. So not loaded local channel can still receive ops and we store them to process later.\n\t\tif (this.isLoaded) {\n\t\t\tthis.services.value.deltaConnection.process(message, local, localOpMetadata);\n\t\t} else {\n\t\t\tassert(\n\t\t\t\tlocal === false,\n\t\t\t\t0x189 /* \"Should always be remote because a local dds shouldn't generate ops before loading\" */,\n\t\t\t);\n\t\t\tthis.pending.push(message);\n\t\t}\n\t}\n\n\tpublic reSubmit(content: any, localOpMetadata: unknown) {\n\t\tassert(this.isLoaded, 0x18a /* \"Channel should be loaded to resubmit ops\" */);\n\t\tassert(\n\t\t\tthis.globallyVisible,\n\t\t\t0x2d4 /* \"Local channel must be globally visible when resubmitting op\" */,\n\t\t);\n\t\tthis.services.value.deltaConnection.reSubmit(content, localOpMetadata);\n\t}\n\tpublic rollback(content: any, localOpMetadata: unknown) {\n\t\tassert(this.isLoaded, 0x2ee /* \"Channel should be loaded to rollback ops\" */);\n\t\tassert(\n\t\t\tthis.globallyVisible,\n\t\t\t0x2ef /* \"Local channel must be globally visible when rolling back op\" */,\n\t\t);\n\t\tthis.services.value.deltaConnection.rollback(content, localOpMetadata);\n\t}\n\n\tpublic abstract applyStashedOp(content: unknown): unknown;\n\n\t/**\n\t * Returns a summary at the current sequence number.\n\t * @param fullTree - true to bypass optimizations and force a full summary tree\n\t * @param trackState - This tells whether we should track state from this summary.\n\t * @param telemetryContext - summary data passed through the layers for telemetry purposes\n\t */\n\tpublic async summarize(\n\t\tfullTree: boolean = false,\n\t\ttrackState: boolean = false,\n\t\ttelemetryContext?: ITelemetryContext,\n\t): Promise<ISummarizeResult> {\n\t\tconst channel = await this.getChannel();\n\t\treturn summarizeChannelAsync(channel, fullTree, trackState, telemetryContext);\n\t}\n\n\t/**\n\t * For crafting the DataStore attach op. Only to be called when the channel is loaded (if applicable).\n\t *\n\t * Synchronously generates the channel's attach summary to be joined with the same from the DataStore's other channels\n\t */\n\tpublic getAttachSummary(telemetryContext?: ITelemetryContext): ISummarizeResult {\n\t\tassert(\n\t\t\tthis._channel !== undefined,\n\t\t\t0x18d /* \"Channel should be loaded to take snapshot\" */,\n\t\t);\n\t\treturn summarizeChannel(\n\t\t\tthis._channel,\n\t\t\ttrue /* fullTree */,\n\t\t\tfalse /* trackState */,\n\t\t\ttelemetryContext,\n\t\t);\n\t}\n\n\t/**\n\t * For crafting the DataStore attach op. Only to be called when the channel is loaded (if applicable).\n\t *\n\t * Synchronously generates the channel's attach GC data (set of outbound routes in the initial state)\n\t * to be joined with the same from the DataStore's other channels\n\t */\n\tpublic getAttachGCData(telemetryContext?: ITelemetryContext): IGarbageCollectionData {\n\t\tassert(\n\t\t\tthis._channel !== undefined,\n\t\t\t0x8fd /* Local Channel should be loaded before being attached */,\n\t\t);\n\n\t\t// We need the GC Data to detect references added in this attach op\n\t\treturn this._channel.getGCData(/* fullGC: */ true);\n\t}\n\n\tpublic makeVisible(): void {\n\t\tif (this.globallyVisible) {\n\t\t\tthrow new Error(\"Channel is already globally visible\");\n\t\t}\n\n\t\tif (this.isLoaded) {\n\t\t\tassert(!!this._channel, 0x192 /* \"Channel should be there if loaded!!\" */);\n\t\t\tthis._channel.connect(this.services.value);\n\t\t}\n\t\tthis.globallyVisible = true;\n\t}\n\n\t/**\n\t * Returns the data used for garbage collection. This includes a list of GC nodes that represent this context.\n\t * Each node has a set of outbound routes to other GC nodes in the document. This should be called only after\n\t * the context has loaded.\n\t * @param fullGC - true to bypass optimizations and force full generation of GC data.\n\t */\n\tpublic async getGCData(fullGC: boolean = false): Promise<IGarbageCollectionData> {\n\t\tconst channel = await this.getChannel();\n\t\treturn channel.getGCData(fullGC);\n\t}\n\n\tpublic updateUsedRoutes(usedRoutes: string[]) {\n\t\t/**\n\t\t * Currently, DDSes are always considered referenced and are not garbage collected.\n\t\t * Once we have GC at DDS level, this channel context's used routes will be updated as per the passed\n\t\t * value. See - https://github.com/microsoft/FluidFramework/issues/4611\n\t\t */\n\t}\n}\n\nexport class RehydratedLocalChannelContext extends LocalChannelContextBase {\n\tprivate readonly dirtyFn: () => void;\n\tconstructor(\n\t\tid: string,\n\t\tregistry: ISharedObjectRegistry,\n\t\truntime: IFluidDataStoreRuntime,\n\t\tdataStoreContext: IFluidDataStoreContext,\n\t\tstorageService: IDocumentStorageService,\n\t\tlogger: ITelemetryLoggerExt,\n\t\tsubmitFn: (content: any, localOpMetadata: unknown) => void,\n\t\tdirtyFn: (address: string) => void,\n\t\taddedGCOutboundReferenceFn: (srcHandle: IFluidHandle, outboundHandle: IFluidHandle) => void,\n\t\tprivate readonly snapshotTree: ISnapshotTree,\n\t) {\n\t\tsuper(\n\t\t\tid,\n\t\t\truntime,\n\t\t\tnew Lazy(() => {\n\t\t\t\tconst blobMap: Map<string, ArrayBufferLike> = new Map<string, ArrayBufferLike>();\n\t\t\t\tconst clonedSnapshotTree = cloneDeep(this.snapshotTree);\n\t\t\t\t// 0.47 back-compat Need to sanitize if snapshotTree.blobs still contains blob contents too.\n\t\t\t\t// This is for older snapshot which is generated by loader <=0.47 version which still contains\n\t\t\t\t// the contents within blobs. After a couple of revisions we can remove it.\n\t\t\t\tif (this.isSnapshotInOldFormatAndCollectBlobs(clonedSnapshotTree, blobMap)) {\n\t\t\t\t\tthis.sanitizeSnapshot(clonedSnapshotTree);\n\t\t\t\t}\n\t\t\t\treturn createChannelServiceEndpoints(\n\t\t\t\t\tdataStoreContext.connected,\n\t\t\t\t\tsubmitFn,\n\t\t\t\t\tthis.dirtyFn,\n\t\t\t\t\taddedGCOutboundReferenceFn,\n\t\t\t\t\t() => this.isGloballyVisible,\n\t\t\t\t\tstorageService,\n\t\t\t\t\tlogger,\n\t\t\t\t\tclonedSnapshotTree,\n\t\t\t\t\tblobMap,\n\t\t\t\t);\n\t\t\t}),\n\t\t\tnew LazyPromise<IChannel>(async () => {\n\t\t\t\ttry {\n\t\t\t\t\tconst { attributes, factory } = await loadChannelFactoryAndAttributes(\n\t\t\t\t\t\tdataStoreContext,\n\t\t\t\t\t\tthis.services.value,\n\t\t\t\t\t\tthis.id,\n\t\t\t\t\t\tregistry,\n\t\t\t\t\t);\n\t\t\t\t\tconst channel = await loadChannel(\n\t\t\t\t\t\truntime,\n\t\t\t\t\t\tattributes,\n\t\t\t\t\t\tfactory,\n\t\t\t\t\t\tthis.services.value,\n\t\t\t\t\t\tlogger,\n\t\t\t\t\t\tthis.id,\n\t\t\t\t\t);\n\t\t\t\t\t// Send all pending messages to the channel\n\t\t\t\t\tfor (const message of this.pending) {\n\t\t\t\t\t\tthis.services.value.deltaConnection.process(\n\t\t\t\t\t\t\tmessage,\n\t\t\t\t\t\t\tfalse,\n\t\t\t\t\t\t\tundefined /* localOpMetadata */,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treturn channel;\n\t\t\t\t} catch (err) {\n\t\t\t\t\tthrow DataProcessingError.wrapIfUnrecognized(\n\t\t\t\t\t\terr,\n\t\t\t\t\t\t\"rehydratedLocalChannelContextFailedToLoadChannel\",\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}),\n\t\t);\n\n\t\tthis.dirtyFn = () => {\n\t\t\tdirtyFn(id);\n\t\t};\n\t}\n\n\tpublic override applyStashedOp(content) {\n\t\treturn this.services.value.deltaConnection.applyStashedOp(content);\n\t}\n\n\tprivate isSnapshotInOldFormatAndCollectBlobs(\n\t\tsnapshotTree: ISnapshotTreeWithBlobContents,\n\t\tblobMap: Map<string, ArrayBufferLike>,\n\t): boolean {\n\t\tlet sanitize = false;\n\t\tconst blobsContents = snapshotTree.blobsContents;\n\t\tif (blobsContents !== undefined) {\n\t\t\tObject.entries(blobsContents).forEach(([key, value]) => {\n\t\t\t\tblobMap.set(key, value);\n\t\t\t\tif (snapshotTree.blobs[key] !== undefined) {\n\t\t\t\t\tsanitize = true;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\tfor (const value of Object.values(snapshotTree.trees)) {\n\t\t\tsanitize = sanitize || this.isSnapshotInOldFormatAndCollectBlobs(value, blobMap);\n\t\t}\n\t\treturn sanitize;\n\t}\n\n\tprivate sanitizeSnapshot(snapshotTree: ISnapshotTree) {\n\t\tconst blobMapInitial = new Map(Object.entries(snapshotTree.blobs));\n\t\tfor (const [blobName, blobId] of blobMapInitial.entries()) {\n\t\t\tconst blobValue = blobMapInitial.get(blobId);\n\t\t\tif (blobValue === undefined) {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n\t\t\t\tdelete snapshotTree.blobs[blobName];\n\t\t\t}\n\t\t}\n\t\tfor (const value of Object.values(snapshotTree.trees)) {\n\t\t\tthis.sanitizeSnapshot(value);\n\t\t}\n\t}\n}\n\nexport class LocalChannelContext extends LocalChannelContextBase {\n\tprivate readonly dirtyFn: () => void;\n\tconstructor(\n\t\tpublic readonly channel: IChannel,\n\t\truntime: IFluidDataStoreRuntime,\n\t\tdataStoreContext: IFluidDataStoreContext,\n\t\tstorageService: IDocumentStorageService,\n\t\tlogger: ITelemetryLoggerExt,\n\t\tsubmitFn: (content: any, localOpMetadata: unknown) => void,\n\t\tdirtyFn: (address: string) => void,\n\t\taddedGCOutboundReferenceFn: (srcHandle: IFluidHandle, outboundHandle: IFluidHandle) => void,\n\t) {\n\t\tsuper(\n\t\t\tchannel.id,\n\t\t\truntime,\n\t\t\tnew Lazy(() => {\n\t\t\t\treturn createChannelServiceEndpoints(\n\t\t\t\t\tdataStoreContext.connected,\n\t\t\t\t\tsubmitFn,\n\t\t\t\t\tthis.dirtyFn,\n\t\t\t\t\taddedGCOutboundReferenceFn,\n\t\t\t\t\t() => this.isGloballyVisible,\n\t\t\t\t\tstorageService,\n\t\t\t\t\tlogger,\n\t\t\t\t);\n\t\t\t}),\n\t\t\tPromise.resolve(channel),\n\t\t\tchannel,\n\t\t);\n\t\tthis.channel = channel;\n\n\t\tthis.dirtyFn = () => {\n\t\t\tdirtyFn(channel.id);\n\t\t};\n\t}\n\n\tpublic applyStashedOp() {\n\t\tthrow new Error(\"no stashed ops on local channel\");\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"localChannelContext.js","sourceRoot":"","sources":["../src/localChannelContext.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,mBAAmB,EAAuB,MAAM,iCAAiC,CAAC;AAU3F,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAGvE,OAAO,EAEN,6BAA6B,EAE7B,WAAW,EACX,+BAA+B,EAC/B,gBAAgB,EAChB,qBAAqB,GACrB,MAAM,qBAAqB,CAAC;AAG7B;;GAEG;AACH,MAAM,OAAgB,uBAAuB;IAG5C,YACoB,EAAU,EACV,OAA+B,EAC/B,QAAuC,EACzC,QAA2B,EACpC,QAAmB;QAJR,OAAE,GAAF,EAAE,CAAQ;QACV,YAAO,GAAP,OAAO,CAAwB;QAC/B,aAAQ,GAAR,QAAQ,CAA+B;QACzC,aAAQ,GAAR,QAAQ,CAAmB;QACpC,aAAQ,GAAR,QAAQ,CAAW;QAPpB,oBAAe,GAAG,KAAK,CAAC;QACb,YAAO,GAAgC,EAAE,CAAC;QAQ5D,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,+CAA+C,CAAC,CAAC;IACvF,CAAC;IAED,IAAc,iBAAiB;QAC9B,OAAO,IAAI,CAAC,eAAe,CAAC;IAC7B,CAAC;IAEM,KAAK,CAAC,UAAU;QACtB,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE;YAChC,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC;SACtD;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC;IACtB,CAAC;IAED,IAAW,QAAQ;QAClB,OAAO,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC;IACpC,CAAC;IAEM,kBAAkB,CAAC,SAAkB,EAAE,QAAiB;QAC9D,uFAAuF;QACvF,IAAI,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,QAAQ,EAAE;YAC1C,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,eAAe,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC;SAClE;IACF,CAAC;IAEM,SAAS,CACf,OAAkC,EAClC,KAAc,EACd,eAAwB;QAExB,MAAM,CACL,IAAI,CAAC,eAAe,EACpB,KAAK,CAAC,iEAAiE,CACvE,CAAC;QAEF,wGAAwG;QACxG,uGAAuG;QACvG,8GAA8G;QAC9G,IAAI,IAAI,CAAC,QAAQ,EAAE;YAClB,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,eAAe,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,EAAE,eAAe,CAAC,CAAC;SAC7E;aAAM;YACN,MAAM,CACL,KAAK,KAAK,KAAK,EACf,KAAK,CAAC,yFAAyF,CAC/F,CAAC;YACF,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;SAC3B;IACF,CAAC;IAEM,QAAQ,CAAC,OAAY,EAAE,eAAwB;QACrD,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,gDAAgD,CAAC,CAAC;QAC9E,MAAM,CACL,IAAI,CAAC,eAAe,EACpB,KAAK,CAAC,mEAAmE,CACzE,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,eAAe,CAAC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;IACxE,CAAC;IACM,QAAQ,CAAC,OAAY,EAAE,eAAwB;QACrD,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,gDAAgD,CAAC,CAAC;QAC9E,MAAM,CACL,IAAI,CAAC,eAAe,EACpB,KAAK,CAAC,mEAAmE,CACzE,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,eAAe,CAAC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;IACxE,CAAC;IAID;;;;;OAKG;IACI,KAAK,CAAC,SAAS,CACrB,WAAoB,KAAK,EACzB,aAAsB,KAAK,EAC3B,gBAAoC;QAEpC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;QACxC,OAAO,qBAAqB,CAAC,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,gBAAgB,CAAC,CAAC;IAC/E,CAAC;IAED;;;;OAIG;IACI,gBAAgB,CAAC,gBAAoC;QAC3D,MAAM,CACL,IAAI,CAAC,QAAQ,KAAK,SAAS,EAC3B,KAAK,CAAC,iDAAiD,CACvD,CAAC;QACF,OAAO,gBAAgB,CACtB,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,cAAc,EACnB,KAAK,CAAC,gBAAgB,EACtB,gBAAgB,CAChB,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACI,eAAe,CAAC,gBAAoC;QAC1D,MAAM,CACL,IAAI,CAAC,QAAQ,KAAK,SAAS,EAC3B,KAAK,CAAC,0DAA0D,CAChE,CAAC;QAEF,mEAAmE;QACnE,OAAO,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IACpD,CAAC;IAEM,WAAW;QACjB,IAAI,IAAI,CAAC,eAAe,EAAE;YACzB,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;SACvD;QAED,IAAI,IAAI,CAAC,QAAQ,EAAE;YAClB,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,2CAA2C,CAAC,CAAC;YAC3E,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;SAC3C;QACD,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;IAC7B,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,SAAS,CAAC,SAAkB,KAAK;QAC7C,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;QACxC,OAAO,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAClC,CAAC;IAEM,gBAAgB,CAAC,UAAoB;QAC3C;;;;WAIG;IACJ,CAAC;CACD;AAED,MAAM,OAAO,6BAA8B,SAAQ,uBAAuB;IAEzE,YACC,EAAU,EACV,QAA+B,EAC/B,OAA+B,EAC/B,gBAAwC,EACxC,cAAuC,EACvC,MAA2B,EAC3B,QAA0D,EAC1D,OAAkC,EAClC,0BAA2F,EAC1E,YAA2B,EAC5C,SAAwC;QAExC,KAAK,CACJ,EAAE,EACF,OAAO,EACP,IAAI,IAAI,CAAC,GAAG,EAAE;YACb,MAAM,OAAO,GAAiC,IAAI,GAAG,CACpD,SAAS,CACT,CAAC;YACF,MAAM,kBAAkB,GAAG,iBAAiB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAChE,4FAA4F;YAC5F,8FAA8F;YAC9F,2EAA2E;YAC3E,IAAI,IAAI,CAAC,oCAAoC,CAAC,kBAAkB,EAAE,OAAO,CAAC,EAAE;gBAC3E,IAAI,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;aAC1C;YACD,OAAO,6BAA6B,CACnC,gBAAgB,CAAC,SAAS,EAC1B,QAAQ,EACR,IAAI,CAAC,OAAO,EACZ,0BAA0B,EAC1B,GAAG,EAAE,CAAC,IAAI,CAAC,iBAAiB,EAC5B,cAAc,EACd,MAAM,EACN,kBAAkB,EAClB,OAAO,CACP,CAAC;QACH,CAAC,CAAC,EACF,IAAI,WAAW,CAAW,KAAK,IAAI,EAAE;YACpC,IAAI;gBACH,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,MAAM,+BAA+B,CACpE,gBAAgB,EAChB,IAAI,CAAC,QAAQ,CAAC,KAAK,EACnB,IAAI,CAAC,EAAE,EACP,QAAQ,CACR,CAAC;gBACF,MAAM,OAAO,GAAG,MAAM,WAAW,CAChC,OAAO,EACP,UAAU,EACV,OAAO,EACP,IAAI,CAAC,QAAQ,CAAC,KAAK,EACnB,MAAM,EACN,IAAI,CAAC,EAAE,CACP,CAAC;gBACF,2CAA2C;gBAC3C,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,OAAO,EAAE;oBACnC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,eAAe,CAAC,OAAO,CAC1C,OAAO,EACP,KAAK,EACL,SAAS,CAAC,qBAAqB,CAC/B,CAAC;iBACF;gBACD,OAAO,OAAO,CAAC;aACf;YAAC,OAAO,GAAG,EAAE;gBACb,MAAM,mBAAmB,CAAC,kBAAkB,CAC3C,GAAG,EACH,kDAAkD,EAClD,SAAS,CACT,CAAC;aACF;QACF,CAAC,CAAC,CACF,CAAC;QA9De,iBAAY,GAAZ,YAAY,CAAe;QAgE5C,IAAI,CAAC,OAAO,GAAG,GAAG,EAAE;YACnB,OAAO,CAAC,EAAE,CAAC,CAAC;QACb,CAAC,CAAC;IACH,CAAC;IAEe,cAAc,CAAC,OAAO;QACrC,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,eAAe,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;IACpE,CAAC;IAEO,oCAAoC,CAC3C,YAA2C,EAC3C,OAAqC;QAErC,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,MAAM,aAAa,GAAG,YAAY,CAAC,aAAa,CAAC;QACjD,IAAI,aAAa,KAAK,SAAS,EAAE;YAChC,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;gBACtD,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;gBACxB,IAAI,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE;oBAC1C,QAAQ,GAAG,IAAI,CAAC;iBAChB;YACF,CAAC,CAAC,CAAC;SACH;QACD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE;YACtD,QAAQ,GAAG,QAAQ,IAAI,IAAI,CAAC,oCAAoC,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;SACjF;QACD,OAAO,QAAQ,CAAC;IACjB,CAAC;IAEO,gBAAgB,CAAC,YAA2B;QACnD,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;QACnE,KAAK,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,cAAc,CAAC,OAAO,EAAE,EAAE;YAC1D,MAAM,SAAS,GAAG,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC7C,IAAI,SAAS,KAAK,SAAS,EAAE;gBAC5B,gEAAgE;gBAChE,OAAO,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;aACpC;SACD;QACD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE;YACtD,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;SAC7B;IACF,CAAC;CACD;AAED,MAAM,OAAO,mBAAoB,SAAQ,uBAAuB;IAE/D,YACiB,OAAiB,EACjC,OAA+B,EAC/B,gBAAwC,EACxC,cAAuC,EACvC,MAA2B,EAC3B,QAA0D,EAC1D,OAAkC,EAClC,0BAA2F;QAE3F,KAAK,CACJ,OAAO,CAAC,EAAE,EACV,OAAO,EACP,IAAI,IAAI,CAAC,GAAG,EAAE;YACb,OAAO,6BAA6B,CACnC,gBAAgB,CAAC,SAAS,EAC1B,QAAQ,EACR,IAAI,CAAC,OAAO,EACZ,0BAA0B,EAC1B,GAAG,EAAE,CAAC,IAAI,CAAC,iBAAiB,EAC5B,cAAc,EACd,MAAM,CACN,CAAC;QACH,CAAC,CAAC,EACF,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,EACxB,OAAO,CACP,CAAC;QAzBc,YAAO,GAAP,OAAO,CAAU;QA0BjC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QAEvB,IAAI,CAAC,OAAO,GAAG,GAAG,EAAE;YACnB,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACrB,CAAC,CAAC;IACH,CAAC;IAEM,cAAc;QACpB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACpD,CAAC;CACD;AAED;;;;;;;;GAQG;AACH,SAAS,iBAAiB,CAAC,IAAmB;IAC7C,MAAM,KAAK,GAAG,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IAC/D,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;QAChD,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAAC;KACtC;IACD,OAAO,KAAK,CAAC;AACd,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { DataProcessingError, ITelemetryLoggerExt } from \"@fluidframework/telemetry-utils\";\nimport { IDocumentStorageService } from \"@fluidframework/driver-definitions\";\nimport { ISequencedDocumentMessage, ISnapshotTree } from \"@fluidframework/protocol-definitions\";\nimport { IChannel, IFluidDataStoreRuntime } from \"@fluidframework/datastore-definitions\";\nimport {\n\tIFluidDataStoreContext,\n\tIGarbageCollectionData,\n\tISummarizeResult,\n\tITelemetryContext,\n} from \"@fluidframework/runtime-definitions\";\nimport { assert, Lazy, LazyPromise } from \"@fluidframework/core-utils\";\nimport { IFluidHandle } from \"@fluidframework/core-interfaces\";\nimport { ISnapshotTreeWithBlobContents } from \"@fluidframework/container-definitions\";\nimport {\n\tChannelServiceEndpoints,\n\tcreateChannelServiceEndpoints,\n\tIChannelContext,\n\tloadChannel,\n\tloadChannelFactoryAndAttributes,\n\tsummarizeChannel,\n\tsummarizeChannelAsync,\n} from \"./channelContext.js\";\nimport { ISharedObjectRegistry } from \"./dataStoreRuntime.js\";\n\n/**\n * Channel context for a locally created channel\n */\nexport abstract class LocalChannelContextBase implements IChannelContext {\n\tprivate globallyVisible = false;\n\tprotected readonly pending: ISequencedDocumentMessage[] = [];\n\tconstructor(\n\t\tprotected readonly id: string,\n\t\tprotected readonly runtime: IFluidDataStoreRuntime,\n\t\tprotected readonly services: Lazy<ChannelServiceEndpoints>,\n\t\tprivate readonly channelP: Promise<IChannel>,\n\t\tprivate _channel?: IChannel,\n\t) {\n\t\tassert(!this.id.includes(\"/\"), 0x30f /* Channel context ID cannot contain slashes */);\n\t}\n\n\tprotected get isGloballyVisible() {\n\t\treturn this.globallyVisible;\n\t}\n\n\tpublic async getChannel(): Promise<IChannel> {\n\t\tif (this._channel === undefined) {\n\t\t\treturn this.channelP.then((c) => (this._channel = c));\n\t\t}\n\t\treturn this.channelP;\n\t}\n\n\tpublic get isLoaded(): boolean {\n\t\treturn this._channel !== undefined;\n\t}\n\n\tpublic setConnectionState(connected: boolean, clientId?: string) {\n\t\t// Connection events are ignored if the data store is not yet globallyVisible or loaded\n\t\tif (this.globallyVisible && this.isLoaded) {\n\t\t\tthis.services.value.deltaConnection.setConnectionState(connected);\n\t\t}\n\t}\n\n\tpublic processOp(\n\t\tmessage: ISequencedDocumentMessage,\n\t\tlocal: boolean,\n\t\tlocalOpMetadata: unknown,\n\t): void {\n\t\tassert(\n\t\t\tthis.globallyVisible,\n\t\t\t0x2d3 /* \"Local channel must be globally visible when processing op\" */,\n\t\t);\n\n\t\t// A local channel may not be loaded in case where we rehydrate the container from a snapshot because of\n\t\t// delay loading. So after the container is attached and some other client joins which start generating\n\t\t// ops for this channel. So not loaded local channel can still receive ops and we store them to process later.\n\t\tif (this.isLoaded) {\n\t\t\tthis.services.value.deltaConnection.process(message, local, localOpMetadata);\n\t\t} else {\n\t\t\tassert(\n\t\t\t\tlocal === false,\n\t\t\t\t0x189 /* \"Should always be remote because a local dds shouldn't generate ops before loading\" */,\n\t\t\t);\n\t\t\tthis.pending.push(message);\n\t\t}\n\t}\n\n\tpublic reSubmit(content: any, localOpMetadata: unknown) {\n\t\tassert(this.isLoaded, 0x18a /* \"Channel should be loaded to resubmit ops\" */);\n\t\tassert(\n\t\t\tthis.globallyVisible,\n\t\t\t0x2d4 /* \"Local channel must be globally visible when resubmitting op\" */,\n\t\t);\n\t\tthis.services.value.deltaConnection.reSubmit(content, localOpMetadata);\n\t}\n\tpublic rollback(content: any, localOpMetadata: unknown) {\n\t\tassert(this.isLoaded, 0x2ee /* \"Channel should be loaded to rollback ops\" */);\n\t\tassert(\n\t\t\tthis.globallyVisible,\n\t\t\t0x2ef /* \"Local channel must be globally visible when rolling back op\" */,\n\t\t);\n\t\tthis.services.value.deltaConnection.rollback(content, localOpMetadata);\n\t}\n\n\tpublic abstract applyStashedOp(content: unknown): unknown;\n\n\t/**\n\t * Returns a summary at the current sequence number.\n\t * @param fullTree - true to bypass optimizations and force a full summary tree\n\t * @param trackState - This tells whether we should track state from this summary.\n\t * @param telemetryContext - summary data passed through the layers for telemetry purposes\n\t */\n\tpublic async summarize(\n\t\tfullTree: boolean = false,\n\t\ttrackState: boolean = false,\n\t\ttelemetryContext?: ITelemetryContext,\n\t): Promise<ISummarizeResult> {\n\t\tconst channel = await this.getChannel();\n\t\treturn summarizeChannelAsync(channel, fullTree, trackState, telemetryContext);\n\t}\n\n\t/**\n\t * For crafting the DataStore attach op. Only to be called when the channel is loaded (if applicable).\n\t *\n\t * Synchronously generates the channel's attach summary to be joined with the same from the DataStore's other channels\n\t */\n\tpublic getAttachSummary(telemetryContext?: ITelemetryContext): ISummarizeResult {\n\t\tassert(\n\t\t\tthis._channel !== undefined,\n\t\t\t0x18d /* \"Channel should be loaded to take snapshot\" */,\n\t\t);\n\t\treturn summarizeChannel(\n\t\t\tthis._channel,\n\t\t\ttrue /* fullTree */,\n\t\t\tfalse /* trackState */,\n\t\t\ttelemetryContext,\n\t\t);\n\t}\n\n\t/**\n\t * For crafting the DataStore attach op. Only to be called when the channel is loaded (if applicable).\n\t *\n\t * Synchronously generates the channel's attach GC data (set of outbound routes in the initial state)\n\t * to be joined with the same from the DataStore's other channels\n\t */\n\tpublic getAttachGCData(telemetryContext?: ITelemetryContext): IGarbageCollectionData {\n\t\tassert(\n\t\t\tthis._channel !== undefined,\n\t\t\t0x8fd /* Local Channel should be loaded before being attached */,\n\t\t);\n\n\t\t// We need the GC Data to detect references added in this attach op\n\t\treturn this._channel.getGCData(/* fullGC: */ true);\n\t}\n\n\tpublic makeVisible(): void {\n\t\tif (this.globallyVisible) {\n\t\t\tthrow new Error(\"Channel is already globally visible\");\n\t\t}\n\n\t\tif (this.isLoaded) {\n\t\t\tassert(!!this._channel, 0x192 /* \"Channel should be there if loaded!!\" */);\n\t\t\tthis._channel.connect(this.services.value);\n\t\t}\n\t\tthis.globallyVisible = true;\n\t}\n\n\t/**\n\t * Returns the data used for garbage collection. This includes a list of GC nodes that represent this context.\n\t * Each node has a set of outbound routes to other GC nodes in the document. This should be called only after\n\t * the context has loaded.\n\t * @param fullGC - true to bypass optimizations and force full generation of GC data.\n\t */\n\tpublic async getGCData(fullGC: boolean = false): Promise<IGarbageCollectionData> {\n\t\tconst channel = await this.getChannel();\n\t\treturn channel.getGCData(fullGC);\n\t}\n\n\tpublic updateUsedRoutes(usedRoutes: string[]) {\n\t\t/**\n\t\t * Currently, DDSes are always considered referenced and are not garbage collected.\n\t\t * Once we have GC at DDS level, this channel context's used routes will be updated as per the passed\n\t\t * value. See - https://github.com/microsoft/FluidFramework/issues/4611\n\t\t */\n\t}\n}\n\nexport class RehydratedLocalChannelContext extends LocalChannelContextBase {\n\tprivate readonly dirtyFn: () => void;\n\tconstructor(\n\t\tid: string,\n\t\tregistry: ISharedObjectRegistry,\n\t\truntime: IFluidDataStoreRuntime,\n\t\tdataStoreContext: IFluidDataStoreContext,\n\t\tstorageService: IDocumentStorageService,\n\t\tlogger: ITelemetryLoggerExt,\n\t\tsubmitFn: (content: any, localOpMetadata: unknown) => void,\n\t\tdirtyFn: (address: string) => void,\n\t\taddedGCOutboundReferenceFn: (srcHandle: IFluidHandle, outboundHandle: IFluidHandle) => void,\n\t\tprivate readonly snapshotTree: ISnapshotTree,\n\t\textraBlob?: Map<string, ArrayBufferLike>,\n\t) {\n\t\tsuper(\n\t\t\tid,\n\t\t\truntime,\n\t\t\tnew Lazy(() => {\n\t\t\t\tconst blobMap: Map<string, ArrayBufferLike> = new Map<string, ArrayBufferLike>(\n\t\t\t\t\textraBlob,\n\t\t\t\t);\n\t\t\t\tconst clonedSnapshotTree = cloneSnapshotTree(this.snapshotTree);\n\t\t\t\t// 0.47 back-compat Need to sanitize if snapshotTree.blobs still contains blob contents too.\n\t\t\t\t// This is for older snapshot which is generated by loader <=0.47 version which still contains\n\t\t\t\t// the contents within blobs. After a couple of revisions we can remove it.\n\t\t\t\tif (this.isSnapshotInOldFormatAndCollectBlobs(clonedSnapshotTree, blobMap)) {\n\t\t\t\t\tthis.sanitizeSnapshot(clonedSnapshotTree);\n\t\t\t\t}\n\t\t\t\treturn createChannelServiceEndpoints(\n\t\t\t\t\tdataStoreContext.connected,\n\t\t\t\t\tsubmitFn,\n\t\t\t\t\tthis.dirtyFn,\n\t\t\t\t\taddedGCOutboundReferenceFn,\n\t\t\t\t\t() => this.isGloballyVisible,\n\t\t\t\t\tstorageService,\n\t\t\t\t\tlogger,\n\t\t\t\t\tclonedSnapshotTree,\n\t\t\t\t\tblobMap,\n\t\t\t\t);\n\t\t\t}),\n\t\t\tnew LazyPromise<IChannel>(async () => {\n\t\t\t\ttry {\n\t\t\t\t\tconst { attributes, factory } = await loadChannelFactoryAndAttributes(\n\t\t\t\t\t\tdataStoreContext,\n\t\t\t\t\t\tthis.services.value,\n\t\t\t\t\t\tthis.id,\n\t\t\t\t\t\tregistry,\n\t\t\t\t\t);\n\t\t\t\t\tconst channel = await loadChannel(\n\t\t\t\t\t\truntime,\n\t\t\t\t\t\tattributes,\n\t\t\t\t\t\tfactory,\n\t\t\t\t\t\tthis.services.value,\n\t\t\t\t\t\tlogger,\n\t\t\t\t\t\tthis.id,\n\t\t\t\t\t);\n\t\t\t\t\t// Send all pending messages to the channel\n\t\t\t\t\tfor (const message of this.pending) {\n\t\t\t\t\t\tthis.services.value.deltaConnection.process(\n\t\t\t\t\t\t\tmessage,\n\t\t\t\t\t\t\tfalse,\n\t\t\t\t\t\t\tundefined /* localOpMetadata */,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treturn channel;\n\t\t\t\t} catch (err) {\n\t\t\t\t\tthrow DataProcessingError.wrapIfUnrecognized(\n\t\t\t\t\t\terr,\n\t\t\t\t\t\t\"rehydratedLocalChannelContextFailedToLoadChannel\",\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}),\n\t\t);\n\n\t\tthis.dirtyFn = () => {\n\t\t\tdirtyFn(id);\n\t\t};\n\t}\n\n\tpublic override applyStashedOp(content) {\n\t\treturn this.services.value.deltaConnection.applyStashedOp(content);\n\t}\n\n\tprivate isSnapshotInOldFormatAndCollectBlobs(\n\t\tsnapshotTree: ISnapshotTreeWithBlobContents,\n\t\tblobMap: Map<string, ArrayBufferLike>,\n\t): boolean {\n\t\tlet sanitize = false;\n\t\tconst blobsContents = snapshotTree.blobsContents;\n\t\tif (blobsContents !== undefined) {\n\t\t\tObject.entries(blobsContents).forEach(([key, value]) => {\n\t\t\t\tblobMap.set(key, value);\n\t\t\t\tif (snapshotTree.blobs[key] !== undefined) {\n\t\t\t\t\tsanitize = true;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\tfor (const value of Object.values(snapshotTree.trees)) {\n\t\t\tsanitize = sanitize || this.isSnapshotInOldFormatAndCollectBlobs(value, blobMap);\n\t\t}\n\t\treturn sanitize;\n\t}\n\n\tprivate sanitizeSnapshot(snapshotTree: ISnapshotTree) {\n\t\tconst blobMapInitial = new Map(Object.entries(snapshotTree.blobs));\n\t\tfor (const [blobName, blobId] of blobMapInitial.entries()) {\n\t\t\tconst blobValue = blobMapInitial.get(blobId);\n\t\t\tif (blobValue === undefined) {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n\t\t\t\tdelete snapshotTree.blobs[blobName];\n\t\t\t}\n\t\t}\n\t\tfor (const value of Object.values(snapshotTree.trees)) {\n\t\t\tthis.sanitizeSnapshot(value);\n\t\t}\n\t}\n}\n\nexport class LocalChannelContext extends LocalChannelContextBase {\n\tprivate readonly dirtyFn: () => void;\n\tconstructor(\n\t\tpublic readonly channel: IChannel,\n\t\truntime: IFluidDataStoreRuntime,\n\t\tdataStoreContext: IFluidDataStoreContext,\n\t\tstorageService: IDocumentStorageService,\n\t\tlogger: ITelemetryLoggerExt,\n\t\tsubmitFn: (content: any, localOpMetadata: unknown) => void,\n\t\tdirtyFn: (address: string) => void,\n\t\taddedGCOutboundReferenceFn: (srcHandle: IFluidHandle, outboundHandle: IFluidHandle) => void,\n\t) {\n\t\tsuper(\n\t\t\tchannel.id,\n\t\t\truntime,\n\t\t\tnew Lazy(() => {\n\t\t\t\treturn createChannelServiceEndpoints(\n\t\t\t\t\tdataStoreContext.connected,\n\t\t\t\t\tsubmitFn,\n\t\t\t\t\tthis.dirtyFn,\n\t\t\t\t\taddedGCOutboundReferenceFn,\n\t\t\t\t\t() => this.isGloballyVisible,\n\t\t\t\t\tstorageService,\n\t\t\t\t\tlogger,\n\t\t\t\t);\n\t\t\t}),\n\t\t\tPromise.resolve(channel),\n\t\t\tchannel,\n\t\t);\n\t\tthis.channel = channel;\n\n\t\tthis.dirtyFn = () => {\n\t\t\tdirtyFn(channel.id);\n\t\t};\n\t}\n\n\tpublic applyStashedOp() {\n\t\tthrow new Error(\"no stashed ops on local channel\");\n\t}\n}\n\n/**\n * Deep clones a snapshot tree.\n *\n * TODO: Investigate replacing this with a deep clone utility.\n * This is a temporary solution to avoid issues with lodash deepClone and ungap structuredClone.\n * Using lodash caused a significant bundle size regression. structuredClone cannot be used since\n * it does not support ArrayBuffer data types, and ISnapshotTree can contain blobContents properties,\n * which are ArrayBuffer data types.\n */\nfunction cloneSnapshotTree(tree: ISnapshotTree): ISnapshotTree {\n\tconst clone = { ...tree, blobs: { ...tree.blobs }, trees: {} };\n\tfor (const [k, v] of Object.entries(tree.trees)) {\n\t\tclone.trees[k] = cloneSnapshotTree(v);\n\t}\n\treturn clone;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/datastore",
|
|
3
|
-
"version": "2.0.0-rc.2.0.
|
|
3
|
+
"version": "2.0.0-rc.2.0.2",
|
|
4
4
|
"description": "Fluid data store implementation",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -77,32 +77,30 @@
|
|
|
77
77
|
"temp-directory": "nyc/.nyc_output"
|
|
78
78
|
},
|
|
79
79
|
"dependencies": {
|
|
80
|
-
"@fluid-internal/client-utils": ">=2.0.0-rc.2.0.
|
|
81
|
-
"@fluidframework/container-definitions": ">=2.0.0-rc.2.0.
|
|
82
|
-
"@fluidframework/core-interfaces": ">=2.0.0-rc.2.0.
|
|
83
|
-
"@fluidframework/core-utils": ">=2.0.0-rc.2.0.
|
|
84
|
-
"@fluidframework/datastore-definitions": ">=2.0.0-rc.2.0.
|
|
85
|
-
"@fluidframework/driver-definitions": ">=2.0.0-rc.2.0.
|
|
86
|
-
"@fluidframework/driver-utils": ">=2.0.0-rc.2.0.
|
|
87
|
-
"@fluidframework/id-compressor": ">=2.0.0-rc.2.0.
|
|
80
|
+
"@fluid-internal/client-utils": ">=2.0.0-rc.2.0.2 <2.0.0-rc.2.1.0",
|
|
81
|
+
"@fluidframework/container-definitions": ">=2.0.0-rc.2.0.2 <2.0.0-rc.2.1.0",
|
|
82
|
+
"@fluidframework/core-interfaces": ">=2.0.0-rc.2.0.2 <2.0.0-rc.2.1.0",
|
|
83
|
+
"@fluidframework/core-utils": ">=2.0.0-rc.2.0.2 <2.0.0-rc.2.1.0",
|
|
84
|
+
"@fluidframework/datastore-definitions": ">=2.0.0-rc.2.0.2 <2.0.0-rc.2.1.0",
|
|
85
|
+
"@fluidframework/driver-definitions": ">=2.0.0-rc.2.0.2 <2.0.0-rc.2.1.0",
|
|
86
|
+
"@fluidframework/driver-utils": ">=2.0.0-rc.2.0.2 <2.0.0-rc.2.1.0",
|
|
87
|
+
"@fluidframework/id-compressor": ">=2.0.0-rc.2.0.2 <2.0.0-rc.2.1.0",
|
|
88
88
|
"@fluidframework/protocol-definitions": "^3.2.0",
|
|
89
|
-
"@fluidframework/runtime-definitions": ">=2.0.0-rc.2.0.
|
|
90
|
-
"@fluidframework/runtime-utils": ">=2.0.0-rc.2.0.
|
|
91
|
-
"@fluidframework/telemetry-utils": ">=2.0.0-rc.2.0.
|
|
92
|
-
"lodash": "^4.17.21",
|
|
89
|
+
"@fluidframework/runtime-definitions": ">=2.0.0-rc.2.0.2 <2.0.0-rc.2.1.0",
|
|
90
|
+
"@fluidframework/runtime-utils": ">=2.0.0-rc.2.0.2 <2.0.0-rc.2.1.0",
|
|
91
|
+
"@fluidframework/telemetry-utils": ">=2.0.0-rc.2.0.2 <2.0.0-rc.2.1.0",
|
|
93
92
|
"uuid": "^9.0.0"
|
|
94
93
|
},
|
|
95
94
|
"devDependencies": {
|
|
96
95
|
"@arethetypeswrong/cli": "^0.13.3",
|
|
97
|
-
"@fluid-internal/mocha-test-setup": ">=2.0.0-rc.2.0.
|
|
96
|
+
"@fluid-internal/mocha-test-setup": ">=2.0.0-rc.2.0.2 <2.0.0-rc.2.1.0",
|
|
98
97
|
"@fluid-tools/build-cli": "^0.34.0",
|
|
99
98
|
"@fluidframework/build-common": "^2.0.3",
|
|
100
99
|
"@fluidframework/build-tools": "^0.34.0",
|
|
101
100
|
"@fluidframework/datastore-previous": "npm:@fluidframework/datastore@2.0.0-internal.8.0.0",
|
|
102
101
|
"@fluidframework/eslint-config-fluid": "^4.0.0",
|
|
103
|
-
"@fluidframework/test-runtime-utils": ">=2.0.0-rc.2.0.
|
|
102
|
+
"@fluidframework/test-runtime-utils": ">=2.0.0-rc.2.0.2 <2.0.0-rc.2.1.0",
|
|
104
103
|
"@microsoft/api-extractor": "^7.42.3",
|
|
105
|
-
"@types/lodash": "^4.14.118",
|
|
106
104
|
"@types/mocha": "^9.1.1",
|
|
107
105
|
"@types/node": "^18.19.0",
|
|
108
106
|
"@types/uuid": "^9.0.2",
|
package/src/dataStoreRuntime.ts
CHANGED
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
IDocumentMessage,
|
|
31
31
|
ISequencedDocumentMessage,
|
|
32
32
|
SummaryType,
|
|
33
|
+
type ISnapshotTree,
|
|
33
34
|
ISummaryBlob,
|
|
34
35
|
ISummaryTree,
|
|
35
36
|
IQuorumClients,
|
|
@@ -260,18 +261,8 @@ export class FluidDataStoreRuntime
|
|
|
260
261
|
// container from snapshot where we load detached container from a snapshot, isLocalDataStore would be
|
|
261
262
|
// true. In this case create a RehydratedLocalChannelContext.
|
|
262
263
|
if (dataStoreContext.isLocalDataStore) {
|
|
263
|
-
channelContext =
|
|
264
|
+
channelContext = this.createRehydratedLocalChannelContext(
|
|
264
265
|
path,
|
|
265
|
-
this.sharedObjectRegistry,
|
|
266
|
-
this,
|
|
267
|
-
this.dataStoreContext,
|
|
268
|
-
this.dataStoreContext.storage,
|
|
269
|
-
this.logger,
|
|
270
|
-
(content, localOpMetadata) =>
|
|
271
|
-
this.submitChannelOp(path, content, localOpMetadata),
|
|
272
|
-
(address: string) => this.setChannelDirty(address),
|
|
273
|
-
(srcHandle: IFluidHandle, outboundHandle: IFluidHandle) =>
|
|
274
|
-
this.addedGCOutboundReference(srcHandle, outboundHandle),
|
|
275
266
|
tree.trees[path],
|
|
276
267
|
);
|
|
277
268
|
// This is the case of rehydrating a detached container from snapshot. Now due to delay loading of
|
|
@@ -503,6 +494,27 @@ export class FluidDataStoreRuntime
|
|
|
503
494
|
this.contexts.set(channel.id, context);
|
|
504
495
|
}
|
|
505
496
|
|
|
497
|
+
private createRehydratedLocalChannelContext(
|
|
498
|
+
id: string,
|
|
499
|
+
tree: ISnapshotTree,
|
|
500
|
+
flatBlobs?: Map<string, ArrayBufferLike>,
|
|
501
|
+
) {
|
|
502
|
+
return new RehydratedLocalChannelContext(
|
|
503
|
+
id,
|
|
504
|
+
this.sharedObjectRegistry,
|
|
505
|
+
this,
|
|
506
|
+
this.dataStoreContext,
|
|
507
|
+
this.dataStoreContext.storage,
|
|
508
|
+
this.logger,
|
|
509
|
+
(content, localOpMetadata) => this.submitChannelOp(id, content, localOpMetadata),
|
|
510
|
+
(address: string) => this.setChannelDirty(address),
|
|
511
|
+
(srcHandle: IFluidHandle, outboundHandle: IFluidHandle) =>
|
|
512
|
+
this.addedGCOutboundReference(srcHandle, outboundHandle),
|
|
513
|
+
tree,
|
|
514
|
+
flatBlobs,
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
|
|
506
518
|
/**
|
|
507
519
|
* Binds a channel with the runtime. If the runtime is attached we will attach the channel right away.
|
|
508
520
|
* If the runtime is not attached we will defer the attach until the runtime attaches.
|
|
@@ -1083,16 +1095,23 @@ export class FluidDataStoreRuntime
|
|
|
1083
1095
|
switch (type) {
|
|
1084
1096
|
case DataStoreMessageType.Attach: {
|
|
1085
1097
|
const attachMessage = content.content as IAttachMessage;
|
|
1086
|
-
|
|
1087
|
-
const
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
const
|
|
1091
|
-
attachMessage,
|
|
1092
|
-
|
|
1098
|
+
|
|
1099
|
+
const flatBlobs = new Map<string, ArrayBufferLike>();
|
|
1100
|
+
const snapshotTree = buildSnapshotTree(attachMessage.snapshot.entries, flatBlobs);
|
|
1101
|
+
|
|
1102
|
+
const channelContext = this.createRehydratedLocalChannelContext(
|
|
1103
|
+
attachMessage.id,
|
|
1104
|
+
snapshotTree,
|
|
1105
|
+
flatBlobs,
|
|
1093
1106
|
);
|
|
1094
|
-
|
|
1095
|
-
this.contexts.set(attachMessage.id,
|
|
1107
|
+
await channelContext.getChannel();
|
|
1108
|
+
this.contexts.set(attachMessage.id, channelContext);
|
|
1109
|
+
if (this.attachState === AttachState.Detached) {
|
|
1110
|
+
this.localChannelContextQueue.set(attachMessage.id, channelContext);
|
|
1111
|
+
} else {
|
|
1112
|
+
channelContext.makeVisible();
|
|
1113
|
+
this.pendingAttach.add(attachMessage.id);
|
|
1114
|
+
}
|
|
1096
1115
|
return;
|
|
1097
1116
|
}
|
|
1098
1117
|
case DataStoreMessageType.ChannelOp: {
|
|
@@ -3,10 +3,6 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import lodashPkg from "lodash";
|
|
7
|
-
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
8
|
-
const { cloneDeep } = lodashPkg;
|
|
9
|
-
|
|
10
6
|
import { DataProcessingError, ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
|
|
11
7
|
import { IDocumentStorageService } from "@fluidframework/driver-definitions";
|
|
12
8
|
import { ISequencedDocumentMessage, ISnapshotTree } from "@fluidframework/protocol-definitions";
|
|
@@ -206,13 +202,16 @@ export class RehydratedLocalChannelContext extends LocalChannelContextBase {
|
|
|
206
202
|
dirtyFn: (address: string) => void,
|
|
207
203
|
addedGCOutboundReferenceFn: (srcHandle: IFluidHandle, outboundHandle: IFluidHandle) => void,
|
|
208
204
|
private readonly snapshotTree: ISnapshotTree,
|
|
205
|
+
extraBlob?: Map<string, ArrayBufferLike>,
|
|
209
206
|
) {
|
|
210
207
|
super(
|
|
211
208
|
id,
|
|
212
209
|
runtime,
|
|
213
210
|
new Lazy(() => {
|
|
214
|
-
const blobMap: Map<string, ArrayBufferLike> = new Map<string, ArrayBufferLike>(
|
|
215
|
-
|
|
211
|
+
const blobMap: Map<string, ArrayBufferLike> = new Map<string, ArrayBufferLike>(
|
|
212
|
+
extraBlob,
|
|
213
|
+
);
|
|
214
|
+
const clonedSnapshotTree = cloneSnapshotTree(this.snapshotTree);
|
|
216
215
|
// 0.47 back-compat Need to sanitize if snapshotTree.blobs still contains blob contents too.
|
|
217
216
|
// This is for older snapshot which is generated by loader <=0.47 version which still contains
|
|
218
217
|
// the contents within blobs. After a couple of revisions we can remove it.
|
|
@@ -350,3 +349,20 @@ export class LocalChannelContext extends LocalChannelContextBase {
|
|
|
350
349
|
throw new Error("no stashed ops on local channel");
|
|
351
350
|
}
|
|
352
351
|
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Deep clones a snapshot tree.
|
|
355
|
+
*
|
|
356
|
+
* TODO: Investigate replacing this with a deep clone utility.
|
|
357
|
+
* This is a temporary solution to avoid issues with lodash deepClone and ungap structuredClone.
|
|
358
|
+
* Using lodash caused a significant bundle size regression. structuredClone cannot be used since
|
|
359
|
+
* it does not support ArrayBuffer data types, and ISnapshotTree can contain blobContents properties,
|
|
360
|
+
* which are ArrayBuffer data types.
|
|
361
|
+
*/
|
|
362
|
+
function cloneSnapshotTree(tree: ISnapshotTree): ISnapshotTree {
|
|
363
|
+
const clone = { ...tree, blobs: { ...tree.blobs }, trees: {} };
|
|
364
|
+
for (const [k, v] of Object.entries(tree.trees)) {
|
|
365
|
+
clone.trees[k] = cloneSnapshotTree(v);
|
|
366
|
+
}
|
|
367
|
+
return clone;
|
|
368
|
+
}
|