@fluidframework/merge-tree 2.101.0 → 2.102.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/dist/snapshotLoader.d.ts.map +1 -1
- package/dist/snapshotLoader.js +21 -11
- package/dist/snapshotLoader.js.map +1 -1
- package/lib/snapshotLoader.d.ts.map +1 -1
- package/lib/snapshotLoader.js +21 -11
- package/lib/snapshotLoader.js.map +1 -1
- package/package.json +16 -16
- package/src/snapshotLoader.ts +21 -21
package/CHANGELOG.md
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snapshotLoader.d.ts","sourceRoot":"","sources":["../src/snapshotLoader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,KAAK,EACX,sBAAsB,EACtB,sBAAsB,EACtB,MAAM,gDAAgD,CAAC;AACxD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,6CAA6C,CAAC;AAC7F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6CAA6C,CAAC;AACpF,OAAO,EACN,KAAK,mBAAmB,EAGxB,MAAM,0CAA0C,CAAC;AAElD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAoBhD,qBAAa,cAAc;IAIzB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAExB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAE1B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAR5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;gBAG3B,OAAO,EAAE,sBAAsB,EAE/B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,SAAS,EACrC,MAAM,EAAE,mBAAmB,EACV,UAAU,EAAE,gBAAgB;IAKjC,UAAU,CACtB,QAAQ,EAAE,sBAAsB,GAC9B,OAAO,CAAC;QAAE,WAAW,EAAE,OAAO,CAAC,yBAAyB,EAAE,CAAC,CAAA;KAAE,CAAC;YAiBnD,qBAAqB;IA2BnC,OAAO,CAAC,QAAQ,CAAC,aAAa,
|
|
1
|
+
{"version":3,"file":"snapshotLoader.d.ts","sourceRoot":"","sources":["../src/snapshotLoader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,KAAK,EACX,sBAAsB,EACtB,sBAAsB,EACtB,MAAM,gDAAgD,CAAC;AACxD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,6CAA6C,CAAC;AAC7F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6CAA6C,CAAC;AACpF,OAAO,EACN,KAAK,mBAAmB,EAGxB,MAAM,0CAA0C,CAAC;AAElD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAoBhD,qBAAa,cAAc;IAIzB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAExB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAE1B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAR5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;gBAG3B,OAAO,EAAE,sBAAsB,EAE/B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,SAAS,EACrC,MAAM,EAAE,mBAAmB,EACV,UAAU,EAAE,gBAAgB;IAKjC,UAAU,CACtB,QAAQ,EAAE,sBAAsB,GAC9B,OAAO,CAAC;QAAE,WAAW,EAAE,OAAO,CAAC,yBAAyB,EAAE,CAAC,CAAA;KAAE,CAAC;YAiBnD,qBAAqB;IA2BnC,OAAO,CAAC,QAAQ,CAAC,aAAa,CA4E5B;IAEF,OAAO,CAAC,UAAU;YAsCJ,QAAQ;IA2FtB,OAAO,CAAC,kBAAkB;IAsB1B;;;;;OAKG;YACW,cAAc;CAQ5B"}
|
package/dist/snapshotLoader.js
CHANGED
|
@@ -74,20 +74,26 @@ class SnapshotLoader {
|
|
|
74
74
|
// out ok since none of these values end up being used. (specifically, the 'firstRemovedSeq' is fake
|
|
75
75
|
// for all values other than the actual first remove).
|
|
76
76
|
// This issue only affects V1 summaries, as the strategy in snapshotlegacy avoids storing merge info directly.
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
77
|
+
for (const id of spec.removedClientIds) {
|
|
78
|
+
removes.push({
|
|
79
|
+
type: "setRemove",
|
|
80
|
+
seq: firstRemovedSeq,
|
|
81
|
+
clientId: this.client.getOrAddShortClientId(id),
|
|
82
|
+
});
|
|
83
|
+
}
|
|
82
84
|
}
|
|
83
85
|
if (spec.movedSeq !== undefined) {
|
|
84
86
|
(0, internal_1.assert)(spec.movedClientIds !== undefined && spec.movedSeqs !== undefined, 0xaa5 /* must have movedIds ids */);
|
|
85
87
|
(0, internal_1.assert)(spec.movedClientIds.length === spec.movedSeqs.length, 0xb5f /* Expected same length for client ids and seqs */);
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
// Avoid spreading into push: a large array could exceed the engine's
|
|
89
|
+
// argument-count limit and throw RangeError.
|
|
90
|
+
for (let i = 0; i < spec.movedClientIds.length; i++) {
|
|
91
|
+
removes.push({
|
|
92
|
+
type: "sliceRemove",
|
|
93
|
+
seq: spec.movedSeqs[i],
|
|
94
|
+
clientId: this.client.getOrAddShortClientId(spec.movedClientIds[i]),
|
|
95
|
+
});
|
|
96
|
+
}
|
|
91
97
|
}
|
|
92
98
|
if (removes.length > 0) {
|
|
93
99
|
removes.sort(opstampUtils.compare);
|
|
@@ -177,7 +183,11 @@ class SnapshotLoader {
|
|
|
177
183
|
const newSegs = chunk.segments.map((element) => this.specToSegment(element));
|
|
178
184
|
this.extractAttribution(newSegs, chunk);
|
|
179
185
|
chunksWithAttribution += chunk.attribution === undefined ? 0 : 1;
|
|
180
|
-
|
|
186
|
+
// Avoid `push(...newSegs)`: spreading a large array into a variadic call
|
|
187
|
+
// can exceed the engine's argument-count limit and throw RangeError.
|
|
188
|
+
for (const seg of newSegs) {
|
|
189
|
+
segs.push(seg);
|
|
190
|
+
}
|
|
181
191
|
}
|
|
182
192
|
(0, internal_1.assert)(chunksWithAttribution === 0 ||
|
|
183
193
|
chunksWithAttribution === headerMetadata.orderedChunkMetadata.length, 0x4c0 /* all or no chunks should have attribution information */);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snapshotLoader.js","sourceRoot":"","sources":["../src/snapshotLoader.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\n/* eslint-disable @typescript-eslint/no-non-null-assertion */\n\nimport { bufferToString } from \"@fluid-internal/client-utils\";\nimport { AttachState } from \"@fluidframework/container-definitions\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type {\n\tIFluidDataStoreRuntime,\n\tIChannelStorageService,\n} from \"@fluidframework/datastore-definitions/internal\";\nimport type { ISequencedDocumentMessage } from \"@fluidframework/driver-definitions/internal\";\nimport type { IFluidSerializer } from \"@fluidframework/shared-object-base/internal\";\nimport {\n\ttype ITelemetryLoggerExt,\n\tUsageError,\n\tcreateChildLogger,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nimport type { Client } from \"./client.js\";\nimport { NonCollabClient, UniversalSequenceNumber } from \"./constants.js\";\nimport type { MergeTree } from \"./mergeTree.js\";\nimport type { ISegmentPrivate } from \"./mergeTreeNodes.js\";\nimport type { IJSONSegment } from \"./ops.js\";\nimport { PriorPerspective } from \"./perspective.js\";\nimport {\n\ttype IHasRemovalInfo,\n\toverwriteInfo,\n\ttype IHasInsertionInfo,\n\ttype SegmentWithInfo,\n} from \"./segmentInfos.js\";\nimport {\n\ttype IJSONSegmentWithMergeInfo,\n\ttype MergeTreeChunkV1,\n\thasMergeInfo,\n} from \"./snapshotChunks.js\";\nimport { SnapshotV1 } from \"./snapshotV1.js\";\nimport { SnapshotLegacy } from \"./snapshotlegacy.js\";\nimport type { RemoveOperationStamp } from \"./stamps.js\";\nimport * as opstampUtils from \"./stamps.js\";\n\nexport class SnapshotLoader {\n\tprivate readonly logger: ITelemetryLoggerExt;\n\n\tconstructor(\n\t\tprivate readonly runtime: IFluidDataStoreRuntime,\n\n\t\tprivate readonly client: Client,\n\t\tprivate readonly mergeTree: MergeTree,\n\t\tlogger: ITelemetryLoggerExt,\n\t\tprivate readonly serializer: IFluidSerializer,\n\t) {\n\t\tthis.logger = createChildLogger({ logger, namespace: \"SnapshotLoader\" });\n\t}\n\n\tpublic async initialize(\n\t\tservices: IChannelStorageService,\n\t): Promise<{ catchupOpsP: Promise<ISequencedDocumentMessage[]> }> {\n\t\tconst headerLoadedP = services.readBlob(SnapshotLegacy.header).then((header) => {\n\t\t\tassert(!!header, 0x05f /* \"Missing blob header on legacy snapshot!\" */);\n\t\t\treturn this.loadHeader(bufferToString(header, \"utf8\"));\n\t\t});\n\n\t\tconst catchupOpsP = this.loadBodyAndCatchupOps(headerLoadedP, services);\n\n\t\tcatchupOpsP.catch((error) =>\n\t\t\tthis.logger.sendErrorEvent({ eventName: \"CatchupOpsLoadFailure\" }, error),\n\t\t);\n\n\t\tawait headerLoadedP;\n\n\t\treturn { catchupOpsP };\n\t}\n\n\tprivate async loadBodyAndCatchupOps(\n\t\theaderChunkP: Promise<MergeTreeChunkV1>,\n\t\tservices: IChannelStorageService,\n\t): Promise<ISequencedDocumentMessage[]> {\n\t\tconst blobsP = services.list(\"\");\n\t\tconst headerChunk = await headerChunkP;\n\n\t\t// TODO we shouldn't need to wait on the body being complete to finish initialization.\n\t\t// To fully support this we need to be able to process inbound ops for pending segments.\n\t\tawait this.loadBody(headerChunk, services);\n\n\t\tconst blobs = await blobsP;\n\t\tif (blobs.length === headerChunk.headerMetadata!.orderedChunkMetadata.length + 1) {\n\t\t\tfor (const md of headerChunk.headerMetadata!.orderedChunkMetadata)\n\t\t\t\tblobs.splice(blobs.indexOf(md.id), 1);\n\t\t\tassert(blobs.length === 1, 0x060 /* There should be only one blob with catch up ops */);\n\n\t\t\t// TODO: The 'Snapshot.catchupOps' tree entry is purely for backwards compatibility.\n\t\t\t// (See https://github.com/microsoft/FluidFramework/issues/84)\n\n\t\t\treturn this.loadCatchupOps(services.readBlob(blobs[0]), this.serializer);\n\t\t} else if (blobs.length !== headerChunk.headerMetadata!.orderedChunkMetadata.length) {\n\t\t\tthrow new Error(\"Unexpected blobs in snapshot\");\n\t\t}\n\t\treturn [];\n\t}\n\n\tprivate readonly specToSegment = (\n\t\tspec: IJSONSegment | IJSONSegmentWithMergeInfo,\n\t): SegmentWithInfo<IHasInsertionInfo> => {\n\t\tif (hasMergeInfo(spec)) {\n\t\t\tconst seg = overwriteInfo<IHasInsertionInfo>(this.client.specToSegment(spec.json), {\n\t\t\t\tinsert: {\n\t\t\t\t\ttype: \"insert\",\n\t\t\t\t\tseq: spec.seq ?? UniversalSequenceNumber,\n\t\t\t\t\tclientId:\n\t\t\t\t\t\tspec.client === undefined\n\t\t\t\t\t\t\t? NonCollabClient\n\t\t\t\t\t\t\t: this.client.getOrAddShortClientId(spec.client),\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tconst removes: RemoveOperationStamp[] = [];\n\n\t\t\tif (spec.removedSeq !== undefined) {\n\t\t\t\t// this format had a bug where it didn't store all the overlap clients\n\t\t\t\t// this is for back compat, so we change the singular id to an array\n\t\t\t\t// this will only cause problems if there is an overlapping delete\n\t\t\t\t// spanning the snapshot, which should be rare\n\t\t\t\tconst specAsBuggyFormat: IJSONSegmentWithMergeInfo & { removedClient?: string } = spec;\n\t\t\t\tif (specAsBuggyFormat.removedClient !== undefined) {\n\t\t\t\t\tspec.removedClientIds ??= [specAsBuggyFormat.removedClient];\n\t\t\t\t}\n\t\t\t\tassert(spec.removedClientIds !== undefined, 0xaac /* must have removedClient ids */);\n\t\t\t\tconst firstRemovedSeq = spec.removedSeq;\n\t\t\t\t// TODO:AB#32299: To correctly support perspectives from other clients which don't assume they have seen\n\t\t\t\t// all ops, we need to actually record these in the summary. For now we use fake data, and it turns\n\t\t\t\t// out ok since none of these values end up being used. (specifically, the 'firstRemovedSeq' is fake\n\t\t\t\t// for all values other than the actual first remove).\n\t\t\t\t// This issue only affects V1 summaries, as the strategy in snapshotlegacy avoids storing merge info directly.\n\t\t\t\tremoves.push(\n\t\t\t\t\t...spec.removedClientIds.map(\n\t\t\t\t\t\t(id) =>\n\t\t\t\t\t\t\t({\n\t\t\t\t\t\t\t\ttype: \"setRemove\",\n\t\t\t\t\t\t\t\tseq: firstRemovedSeq,\n\t\t\t\t\t\t\t\tclientId: this.client.getOrAddShortClientId(id),\n\t\t\t\t\t\t\t}) as const,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (spec.movedSeq !== undefined) {\n\t\t\t\tassert(\n\t\t\t\t\tspec.movedClientIds !== undefined && spec.movedSeqs !== undefined,\n\t\t\t\t\t0xaa5 /* must have movedIds ids */,\n\t\t\t\t);\n\t\t\t\tassert(\n\t\t\t\t\tspec.movedClientIds.length === spec.movedSeqs.length,\n\t\t\t\t\t0xb5f /* Expected same length for client ids and seqs */,\n\t\t\t\t);\n\n\t\t\t\tremoves.push(\n\t\t\t\t\t...spec.movedClientIds.map(\n\t\t\t\t\t\t(id, i) =>\n\t\t\t\t\t\t\t({\n\t\t\t\t\t\t\t\ttype: \"sliceRemove\",\n\t\t\t\t\t\t\t\tseq: spec.movedSeqs![i],\n\t\t\t\t\t\t\t\tclientId: this.client.getOrAddShortClientId(id),\n\t\t\t\t\t\t\t}) as const,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (removes.length > 0) {\n\t\t\t\tremoves.sort(opstampUtils.compare);\n\t\t\t\toverwriteInfo<IHasRemovalInfo>(seg, { removes });\n\t\t\t}\n\n\t\t\treturn seg;\n\t\t}\n\t\treturn overwriteInfo(this.client.specToSegment(spec), {\n\t\t\tinsert: {\n\t\t\t\ttype: \"insert\",\n\t\t\t\tseq: UniversalSequenceNumber,\n\t\t\t\tclientId: NonCollabClient,\n\t\t\t},\n\t\t});\n\t};\n\n\tprivate loadHeader(header: string): MergeTreeChunkV1 {\n\t\tconst chunk = SnapshotV1.processChunk(\n\t\t\tSnapshotLegacy.header,\n\t\t\theader,\n\t\t\tthis.logger,\n\t\t\tthis.mergeTree.options,\n\t\t\tthis.serializer,\n\t\t);\n\t\tconst segs = chunk.segments.map((element) => this.specToSegment(element));\n\t\tthis.extractAttribution(segs, chunk);\n\n\t\tthis.mergeTree.reloadFromSegments(segs);\n\n\t\tif (chunk.headerMetadata === undefined) {\n\t\t\tthrow new Error(\"header metadata not available\");\n\t\t}\n\t\t// If we load a detached container from snapshot, then we don't supply a default clientId\n\t\t// because we don't want to start collaboration.\n\t\tif (this.runtime.attachState !== AttachState.Detached) {\n\t\t\t// specify a default client id, \"snapshot\" here as we\n\t\t\t// should enter collaboration/op sending mode if we load\n\t\t\t// a snapshot in any case (summary or attach message)\n\t\t\t// once we get a client id this will be called with that\n\t\t\t// clientId in the connected event\n\t\t\tthis.client.startOrUpdateCollaboration(\n\t\t\t\tthis.runtime.clientId ?? \"snapshot\",\n\n\t\t\t\t// TODO: Make 'minSeq' non-optional once the new snapshot format becomes the default?\n\t\t\t\t// (See https://github.com/microsoft/FluidFramework/issues/84)\n\t\t\t\t/* minSeq: */ chunk.headerMetadata.minSequenceNumber ??\n\t\t\t\t\tchunk.headerMetadata.sequenceNumber,\n\t\t\t\t/* currentSeq: */ chunk.headerMetadata.sequenceNumber,\n\t\t\t);\n\t\t}\n\n\t\treturn chunk;\n\t}\n\n\tprivate async loadBody(\n\t\tchunk1: MergeTreeChunkV1,\n\t\tservices: IChannelStorageService,\n\t): Promise<void> {\n\t\tconst headerMetadata = chunk1.headerMetadata!;\n\t\tassert(chunk1.length <= headerMetadata.totalLength, 0x061 /* \"Mismatch in totalLength\" */);\n\n\t\tassert(\n\t\t\tchunk1.segmentCount <= headerMetadata.totalSegmentCount,\n\t\t\t0x062 /* \"Mismatch in totalSegmentCount\" */,\n\t\t);\n\n\t\tif (chunk1.segmentCount === headerMetadata.totalSegmentCount) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet chunksWithAttribution = chunk1.attribution === undefined ? 0 : 1;\n\t\tconst segs: SegmentWithInfo<IHasInsertionInfo>[] = [];\n\t\tlet lengthSofar = chunk1.length;\n\t\tfor (\n\t\t\tlet chunkIndex = 1;\n\t\t\tchunkIndex < headerMetadata.orderedChunkMetadata.length;\n\t\t\tchunkIndex++\n\t\t) {\n\t\t\tconst chunk = await SnapshotV1.loadChunk(\n\t\t\t\tservices,\n\t\t\t\theaderMetadata.orderedChunkMetadata[chunkIndex].id,\n\t\t\t\tthis.logger,\n\t\t\t\tthis.mergeTree.options,\n\t\t\t\tthis.serializer,\n\t\t\t);\n\t\t\tlengthSofar += chunk.length;\n\t\t\t// Deserialize each chunk segment and append it to the end of the MergeTree.\n\t\t\tconst newSegs = chunk.segments.map((element) => this.specToSegment(element));\n\t\t\tthis.extractAttribution(newSegs, chunk);\n\t\t\tchunksWithAttribution += chunk.attribution === undefined ? 0 : 1;\n\t\t\tsegs.push(...newSegs);\n\t\t}\n\n\t\tassert(\n\t\t\tchunksWithAttribution === 0 ||\n\t\t\t\tchunksWithAttribution === headerMetadata.orderedChunkMetadata.length,\n\t\t\t0x4c0 /* all or no chunks should have attribution information */,\n\t\t);\n\n\t\tassert(lengthSofar === headerMetadata.totalLength, 0x063 /* \"Mismatch in totalLength\" */);\n\n\t\tassert(\n\t\t\tchunk1.segmentCount + segs.length === headerMetadata.totalSegmentCount,\n\t\t\t0x064 /* \"Mismatch in totalSegmentCount\" */,\n\t\t);\n\n\t\t// Helper to insert segments at the end of the MergeTree.\n\t\tconst mergeTree = this.mergeTree;\n\t\tconst append = (segments: ISegmentPrivate[], clientId: number, seq: number): void => {\n\t\t\tmergeTree.insertSegments(\n\t\t\t\tmergeTree.root.cachedLength ?? 0,\n\t\t\t\tsegments,\n\t\t\t\tnew PriorPerspective(UniversalSequenceNumber, clientId),\n\t\t\t\t{ seq, clientId },\n\t\t\t\tundefined,\n\t\t\t);\n\t\t};\n\n\t\t// Helpers to batch-insert segments that are below the min seq\n\t\tconst batch: SegmentWithInfo<IHasInsertionInfo>[] = [];\n\t\tconst flushBatch = (): void => {\n\t\t\tif (batch.length > 0) {\n\t\t\t\tappend(batch, NonCollabClient, UniversalSequenceNumber);\n\t\t\t}\n\t\t};\n\n\t\tfor (const seg of segs) {\n\t\t\tconst { clientId, seq } = seg.insert;\n\t\t\t// If the segment can be batch inserted, add it to the 'batch' array. Otherwise, flush\n\t\t\t// any batched segments and then insert the current segment individually.\n\t\t\tif (clientId === NonCollabClient && seq === UniversalSequenceNumber) {\n\t\t\t\tbatch.push(seg);\n\t\t\t} else {\n\t\t\t\tflushBatch();\n\t\t\t\tappend([seg], clientId, seq);\n\t\t\t}\n\t\t}\n\n\t\tflushBatch();\n\t}\n\n\tprivate extractAttribution(segments: ISegmentPrivate[], chunk: MergeTreeChunkV1): void {\n\t\tif (chunk.attribution) {\n\t\t\tconst { attributionPolicy } = this.mergeTree;\n\t\t\tif (attributionPolicy === undefined) {\n\t\t\t\tthrow new UsageError(\n\t\t\t\t\t\"Attribution policy must be provided when loading a document with attribution information.\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst { isAttached, attach, serializer } = attributionPolicy;\n\t\t\tif (!isAttached) {\n\t\t\t\tattach(this.client);\n\t\t\t}\n\t\t\tserializer.populateAttributionCollections(segments, chunk.attribution);\n\t\t} else {\n\t\t\tconst { attributionPolicy } = this.mergeTree;\n\t\t\tif (attributionPolicy?.isAttached) {\n\t\t\t\tattributionPolicy?.detach();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * If loading from a snapshot, get the catchup messages.\n\t * @param rawMessages - The messages in original encoding\n\t * @returns The decoded messages with parsed+hydrated handles. Matches the format that will be passed in\n\t * SharedObject.processCore.\n\t */\n\tprivate async loadCatchupOps(\n\t\trawMessages: Promise<ArrayBufferLike>,\n\t\tserializer: IFluidSerializer,\n\t): Promise<ISequencedDocumentMessage[]> {\n\t\treturn serializer.parse(\n\t\t\tbufferToString(await rawMessages, \"utf8\"),\n\t\t) as ISequencedDocumentMessage[];\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"snapshotLoader.js","sourceRoot":"","sources":["../src/snapshotLoader.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\n/* eslint-disable @typescript-eslint/no-non-null-assertion */\n\nimport { bufferToString } from \"@fluid-internal/client-utils\";\nimport { AttachState } from \"@fluidframework/container-definitions\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type {\n\tIFluidDataStoreRuntime,\n\tIChannelStorageService,\n} from \"@fluidframework/datastore-definitions/internal\";\nimport type { ISequencedDocumentMessage } from \"@fluidframework/driver-definitions/internal\";\nimport type { IFluidSerializer } from \"@fluidframework/shared-object-base/internal\";\nimport {\n\ttype ITelemetryLoggerExt,\n\tUsageError,\n\tcreateChildLogger,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nimport type { Client } from \"./client.js\";\nimport { NonCollabClient, UniversalSequenceNumber } from \"./constants.js\";\nimport type { MergeTree } from \"./mergeTree.js\";\nimport type { ISegmentPrivate } from \"./mergeTreeNodes.js\";\nimport type { IJSONSegment } from \"./ops.js\";\nimport { PriorPerspective } from \"./perspective.js\";\nimport {\n\ttype IHasRemovalInfo,\n\toverwriteInfo,\n\ttype IHasInsertionInfo,\n\ttype SegmentWithInfo,\n} from \"./segmentInfos.js\";\nimport {\n\ttype IJSONSegmentWithMergeInfo,\n\ttype MergeTreeChunkV1,\n\thasMergeInfo,\n} from \"./snapshotChunks.js\";\nimport { SnapshotV1 } from \"./snapshotV1.js\";\nimport { SnapshotLegacy } from \"./snapshotlegacy.js\";\nimport type { RemoveOperationStamp } from \"./stamps.js\";\nimport * as opstampUtils from \"./stamps.js\";\n\nexport class SnapshotLoader {\n\tprivate readonly logger: ITelemetryLoggerExt;\n\n\tconstructor(\n\t\tprivate readonly runtime: IFluidDataStoreRuntime,\n\n\t\tprivate readonly client: Client,\n\t\tprivate readonly mergeTree: MergeTree,\n\t\tlogger: ITelemetryLoggerExt,\n\t\tprivate readonly serializer: IFluidSerializer,\n\t) {\n\t\tthis.logger = createChildLogger({ logger, namespace: \"SnapshotLoader\" });\n\t}\n\n\tpublic async initialize(\n\t\tservices: IChannelStorageService,\n\t): Promise<{ catchupOpsP: Promise<ISequencedDocumentMessage[]> }> {\n\t\tconst headerLoadedP = services.readBlob(SnapshotLegacy.header).then((header) => {\n\t\t\tassert(!!header, 0x05f /* \"Missing blob header on legacy snapshot!\" */);\n\t\t\treturn this.loadHeader(bufferToString(header, \"utf8\"));\n\t\t});\n\n\t\tconst catchupOpsP = this.loadBodyAndCatchupOps(headerLoadedP, services);\n\n\t\tcatchupOpsP.catch((error) =>\n\t\t\tthis.logger.sendErrorEvent({ eventName: \"CatchupOpsLoadFailure\" }, error),\n\t\t);\n\n\t\tawait headerLoadedP;\n\n\t\treturn { catchupOpsP };\n\t}\n\n\tprivate async loadBodyAndCatchupOps(\n\t\theaderChunkP: Promise<MergeTreeChunkV1>,\n\t\tservices: IChannelStorageService,\n\t): Promise<ISequencedDocumentMessage[]> {\n\t\tconst blobsP = services.list(\"\");\n\t\tconst headerChunk = await headerChunkP;\n\n\t\t// TODO we shouldn't need to wait on the body being complete to finish initialization.\n\t\t// To fully support this we need to be able to process inbound ops for pending segments.\n\t\tawait this.loadBody(headerChunk, services);\n\n\t\tconst blobs = await blobsP;\n\t\tif (blobs.length === headerChunk.headerMetadata!.orderedChunkMetadata.length + 1) {\n\t\t\tfor (const md of headerChunk.headerMetadata!.orderedChunkMetadata)\n\t\t\t\tblobs.splice(blobs.indexOf(md.id), 1);\n\t\t\tassert(blobs.length === 1, 0x060 /* There should be only one blob with catch up ops */);\n\n\t\t\t// TODO: The 'Snapshot.catchupOps' tree entry is purely for backwards compatibility.\n\t\t\t// (See https://github.com/microsoft/FluidFramework/issues/84)\n\n\t\t\treturn this.loadCatchupOps(services.readBlob(blobs[0]), this.serializer);\n\t\t} else if (blobs.length !== headerChunk.headerMetadata!.orderedChunkMetadata.length) {\n\t\t\tthrow new Error(\"Unexpected blobs in snapshot\");\n\t\t}\n\t\treturn [];\n\t}\n\n\tprivate readonly specToSegment = (\n\t\tspec: IJSONSegment | IJSONSegmentWithMergeInfo,\n\t): SegmentWithInfo<IHasInsertionInfo> => {\n\t\tif (hasMergeInfo(spec)) {\n\t\t\tconst seg = overwriteInfo<IHasInsertionInfo>(this.client.specToSegment(spec.json), {\n\t\t\t\tinsert: {\n\t\t\t\t\ttype: \"insert\",\n\t\t\t\t\tseq: spec.seq ?? UniversalSequenceNumber,\n\t\t\t\t\tclientId:\n\t\t\t\t\t\tspec.client === undefined\n\t\t\t\t\t\t\t? NonCollabClient\n\t\t\t\t\t\t\t: this.client.getOrAddShortClientId(spec.client),\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tconst removes: RemoveOperationStamp[] = [];\n\n\t\t\tif (spec.removedSeq !== undefined) {\n\t\t\t\t// this format had a bug where it didn't store all the overlap clients\n\t\t\t\t// this is for back compat, so we change the singular id to an array\n\t\t\t\t// this will only cause problems if there is an overlapping delete\n\t\t\t\t// spanning the snapshot, which should be rare\n\t\t\t\tconst specAsBuggyFormat: IJSONSegmentWithMergeInfo & { removedClient?: string } = spec;\n\t\t\t\tif (specAsBuggyFormat.removedClient !== undefined) {\n\t\t\t\t\tspec.removedClientIds ??= [specAsBuggyFormat.removedClient];\n\t\t\t\t}\n\t\t\t\tassert(spec.removedClientIds !== undefined, 0xaac /* must have removedClient ids */);\n\t\t\t\tconst firstRemovedSeq = spec.removedSeq;\n\t\t\t\t// TODO:AB#32299: To correctly support perspectives from other clients which don't assume they have seen\n\t\t\t\t// all ops, we need to actually record these in the summary. For now we use fake data, and it turns\n\t\t\t\t// out ok since none of these values end up being used. (specifically, the 'firstRemovedSeq' is fake\n\t\t\t\t// for all values other than the actual first remove).\n\t\t\t\t// This issue only affects V1 summaries, as the strategy in snapshotlegacy avoids storing merge info directly.\n\t\t\t\tfor (const id of spec.removedClientIds) {\n\t\t\t\t\tremoves.push({\n\t\t\t\t\t\ttype: \"setRemove\",\n\t\t\t\t\t\tseq: firstRemovedSeq,\n\t\t\t\t\t\tclientId: this.client.getOrAddShortClientId(id),\n\t\t\t\t\t} as const);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (spec.movedSeq !== undefined) {\n\t\t\t\tassert(\n\t\t\t\t\tspec.movedClientIds !== undefined && spec.movedSeqs !== undefined,\n\t\t\t\t\t0xaa5 /* must have movedIds ids */,\n\t\t\t\t);\n\t\t\t\tassert(\n\t\t\t\t\tspec.movedClientIds.length === spec.movedSeqs.length,\n\t\t\t\t\t0xb5f /* Expected same length for client ids and seqs */,\n\t\t\t\t);\n\n\t\t\t\t// Avoid spreading into push: a large array could exceed the engine's\n\t\t\t\t// argument-count limit and throw RangeError.\n\t\t\t\tfor (let i = 0; i < spec.movedClientIds.length; i++) {\n\t\t\t\t\tremoves.push({\n\t\t\t\t\t\ttype: \"sliceRemove\",\n\t\t\t\t\t\tseq: spec.movedSeqs[i],\n\t\t\t\t\t\tclientId: this.client.getOrAddShortClientId(spec.movedClientIds[i]),\n\t\t\t\t\t} as const);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (removes.length > 0) {\n\t\t\t\tremoves.sort(opstampUtils.compare);\n\t\t\t\toverwriteInfo<IHasRemovalInfo>(seg, { removes });\n\t\t\t}\n\n\t\t\treturn seg;\n\t\t}\n\t\treturn overwriteInfo(this.client.specToSegment(spec), {\n\t\t\tinsert: {\n\t\t\t\ttype: \"insert\",\n\t\t\t\tseq: UniversalSequenceNumber,\n\t\t\t\tclientId: NonCollabClient,\n\t\t\t},\n\t\t});\n\t};\n\n\tprivate loadHeader(header: string): MergeTreeChunkV1 {\n\t\tconst chunk = SnapshotV1.processChunk(\n\t\t\tSnapshotLegacy.header,\n\t\t\theader,\n\t\t\tthis.logger,\n\t\t\tthis.mergeTree.options,\n\t\t\tthis.serializer,\n\t\t);\n\t\tconst segs = chunk.segments.map((element) => this.specToSegment(element));\n\t\tthis.extractAttribution(segs, chunk);\n\n\t\tthis.mergeTree.reloadFromSegments(segs);\n\n\t\tif (chunk.headerMetadata === undefined) {\n\t\t\tthrow new Error(\"header metadata not available\");\n\t\t}\n\t\t// If we load a detached container from snapshot, then we don't supply a default clientId\n\t\t// because we don't want to start collaboration.\n\t\tif (this.runtime.attachState !== AttachState.Detached) {\n\t\t\t// specify a default client id, \"snapshot\" here as we\n\t\t\t// should enter collaboration/op sending mode if we load\n\t\t\t// a snapshot in any case (summary or attach message)\n\t\t\t// once we get a client id this will be called with that\n\t\t\t// clientId in the connected event\n\t\t\tthis.client.startOrUpdateCollaboration(\n\t\t\t\tthis.runtime.clientId ?? \"snapshot\",\n\n\t\t\t\t// TODO: Make 'minSeq' non-optional once the new snapshot format becomes the default?\n\t\t\t\t// (See https://github.com/microsoft/FluidFramework/issues/84)\n\t\t\t\t/* minSeq: */ chunk.headerMetadata.minSequenceNumber ??\n\t\t\t\t\tchunk.headerMetadata.sequenceNumber,\n\t\t\t\t/* currentSeq: */ chunk.headerMetadata.sequenceNumber,\n\t\t\t);\n\t\t}\n\n\t\treturn chunk;\n\t}\n\n\tprivate async loadBody(\n\t\tchunk1: MergeTreeChunkV1,\n\t\tservices: IChannelStorageService,\n\t): Promise<void> {\n\t\tconst headerMetadata = chunk1.headerMetadata!;\n\t\tassert(chunk1.length <= headerMetadata.totalLength, 0x061 /* \"Mismatch in totalLength\" */);\n\n\t\tassert(\n\t\t\tchunk1.segmentCount <= headerMetadata.totalSegmentCount,\n\t\t\t0x062 /* \"Mismatch in totalSegmentCount\" */,\n\t\t);\n\n\t\tif (chunk1.segmentCount === headerMetadata.totalSegmentCount) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet chunksWithAttribution = chunk1.attribution === undefined ? 0 : 1;\n\t\tconst segs: SegmentWithInfo<IHasInsertionInfo>[] = [];\n\t\tlet lengthSofar = chunk1.length;\n\t\tfor (\n\t\t\tlet chunkIndex = 1;\n\t\t\tchunkIndex < headerMetadata.orderedChunkMetadata.length;\n\t\t\tchunkIndex++\n\t\t) {\n\t\t\tconst chunk = await SnapshotV1.loadChunk(\n\t\t\t\tservices,\n\t\t\t\theaderMetadata.orderedChunkMetadata[chunkIndex].id,\n\t\t\t\tthis.logger,\n\t\t\t\tthis.mergeTree.options,\n\t\t\t\tthis.serializer,\n\t\t\t);\n\t\t\tlengthSofar += chunk.length;\n\t\t\t// Deserialize each chunk segment and append it to the end of the MergeTree.\n\t\t\tconst newSegs = chunk.segments.map((element) => this.specToSegment(element));\n\t\t\tthis.extractAttribution(newSegs, chunk);\n\t\t\tchunksWithAttribution += chunk.attribution === undefined ? 0 : 1;\n\t\t\t// Avoid `push(...newSegs)`: spreading a large array into a variadic call\n\t\t\t// can exceed the engine's argument-count limit and throw RangeError.\n\t\t\tfor (const seg of newSegs) {\n\t\t\t\tsegs.push(seg);\n\t\t\t}\n\t\t}\n\n\t\tassert(\n\t\t\tchunksWithAttribution === 0 ||\n\t\t\t\tchunksWithAttribution === headerMetadata.orderedChunkMetadata.length,\n\t\t\t0x4c0 /* all or no chunks should have attribution information */,\n\t\t);\n\n\t\tassert(lengthSofar === headerMetadata.totalLength, 0x063 /* \"Mismatch in totalLength\" */);\n\n\t\tassert(\n\t\t\tchunk1.segmentCount + segs.length === headerMetadata.totalSegmentCount,\n\t\t\t0x064 /* \"Mismatch in totalSegmentCount\" */,\n\t\t);\n\n\t\t// Helper to insert segments at the end of the MergeTree.\n\t\tconst mergeTree = this.mergeTree;\n\t\tconst append = (segments: ISegmentPrivate[], clientId: number, seq: number): void => {\n\t\t\tmergeTree.insertSegments(\n\t\t\t\tmergeTree.root.cachedLength ?? 0,\n\t\t\t\tsegments,\n\t\t\t\tnew PriorPerspective(UniversalSequenceNumber, clientId),\n\t\t\t\t{ seq, clientId },\n\t\t\t\tundefined,\n\t\t\t);\n\t\t};\n\n\t\t// Helpers to batch-insert segments that are below the min seq\n\t\tconst batch: SegmentWithInfo<IHasInsertionInfo>[] = [];\n\t\tconst flushBatch = (): void => {\n\t\t\tif (batch.length > 0) {\n\t\t\t\tappend(batch, NonCollabClient, UniversalSequenceNumber);\n\t\t\t}\n\t\t};\n\n\t\tfor (const seg of segs) {\n\t\t\tconst { clientId, seq } = seg.insert;\n\t\t\t// If the segment can be batch inserted, add it to the 'batch' array. Otherwise, flush\n\t\t\t// any batched segments and then insert the current segment individually.\n\t\t\tif (clientId === NonCollabClient && seq === UniversalSequenceNumber) {\n\t\t\t\tbatch.push(seg);\n\t\t\t} else {\n\t\t\t\tflushBatch();\n\t\t\t\tappend([seg], clientId, seq);\n\t\t\t}\n\t\t}\n\n\t\tflushBatch();\n\t}\n\n\tprivate extractAttribution(segments: ISegmentPrivate[], chunk: MergeTreeChunkV1): void {\n\t\tif (chunk.attribution) {\n\t\t\tconst { attributionPolicy } = this.mergeTree;\n\t\t\tif (attributionPolicy === undefined) {\n\t\t\t\tthrow new UsageError(\n\t\t\t\t\t\"Attribution policy must be provided when loading a document with attribution information.\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst { isAttached, attach, serializer } = attributionPolicy;\n\t\t\tif (!isAttached) {\n\t\t\t\tattach(this.client);\n\t\t\t}\n\t\t\tserializer.populateAttributionCollections(segments, chunk.attribution);\n\t\t} else {\n\t\t\tconst { attributionPolicy } = this.mergeTree;\n\t\t\tif (attributionPolicy?.isAttached) {\n\t\t\t\tattributionPolicy?.detach();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * If loading from a snapshot, get the catchup messages.\n\t * @param rawMessages - The messages in original encoding\n\t * @returns The decoded messages with parsed+hydrated handles. Matches the format that will be passed in\n\t * SharedObject.processCore.\n\t */\n\tprivate async loadCatchupOps(\n\t\trawMessages: Promise<ArrayBufferLike>,\n\t\tserializer: IFluidSerializer,\n\t): Promise<ISequencedDocumentMessage[]> {\n\t\treturn serializer.parse(\n\t\t\tbufferToString(await rawMessages, \"utf8\"),\n\t\t) as ISequencedDocumentMessage[];\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snapshotLoader.d.ts","sourceRoot":"","sources":["../src/snapshotLoader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,KAAK,EACX,sBAAsB,EACtB,sBAAsB,EACtB,MAAM,gDAAgD,CAAC;AACxD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,6CAA6C,CAAC;AAC7F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6CAA6C,CAAC;AACpF,OAAO,EACN,KAAK,mBAAmB,EAGxB,MAAM,0CAA0C,CAAC;AAElD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAoBhD,qBAAa,cAAc;IAIzB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAExB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAE1B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAR5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;gBAG3B,OAAO,EAAE,sBAAsB,EAE/B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,SAAS,EACrC,MAAM,EAAE,mBAAmB,EACV,UAAU,EAAE,gBAAgB;IAKjC,UAAU,CACtB,QAAQ,EAAE,sBAAsB,GAC9B,OAAO,CAAC;QAAE,WAAW,EAAE,OAAO,CAAC,yBAAyB,EAAE,CAAC,CAAA;KAAE,CAAC;YAiBnD,qBAAqB;IA2BnC,OAAO,CAAC,QAAQ,CAAC,aAAa,
|
|
1
|
+
{"version":3,"file":"snapshotLoader.d.ts","sourceRoot":"","sources":["../src/snapshotLoader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,KAAK,EACX,sBAAsB,EACtB,sBAAsB,EACtB,MAAM,gDAAgD,CAAC;AACxD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,6CAA6C,CAAC;AAC7F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6CAA6C,CAAC;AACpF,OAAO,EACN,KAAK,mBAAmB,EAGxB,MAAM,0CAA0C,CAAC;AAElD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAoBhD,qBAAa,cAAc;IAIzB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAExB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAE1B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAR5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;gBAG3B,OAAO,EAAE,sBAAsB,EAE/B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,SAAS,EACrC,MAAM,EAAE,mBAAmB,EACV,UAAU,EAAE,gBAAgB;IAKjC,UAAU,CACtB,QAAQ,EAAE,sBAAsB,GAC9B,OAAO,CAAC;QAAE,WAAW,EAAE,OAAO,CAAC,yBAAyB,EAAE,CAAC,CAAA;KAAE,CAAC;YAiBnD,qBAAqB;IA2BnC,OAAO,CAAC,QAAQ,CAAC,aAAa,CA4E5B;IAEF,OAAO,CAAC,UAAU;YAsCJ,QAAQ;IA2FtB,OAAO,CAAC,kBAAkB;IAsB1B;;;;;OAKG;YACW,cAAc;CAQ5B"}
|
package/lib/snapshotLoader.js
CHANGED
|
@@ -48,20 +48,26 @@ export class SnapshotLoader {
|
|
|
48
48
|
// out ok since none of these values end up being used. (specifically, the 'firstRemovedSeq' is fake
|
|
49
49
|
// for all values other than the actual first remove).
|
|
50
50
|
// This issue only affects V1 summaries, as the strategy in snapshotlegacy avoids storing merge info directly.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
for (const id of spec.removedClientIds) {
|
|
52
|
+
removes.push({
|
|
53
|
+
type: "setRemove",
|
|
54
|
+
seq: firstRemovedSeq,
|
|
55
|
+
clientId: this.client.getOrAddShortClientId(id),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
56
58
|
}
|
|
57
59
|
if (spec.movedSeq !== undefined) {
|
|
58
60
|
assert(spec.movedClientIds !== undefined && spec.movedSeqs !== undefined, 0xaa5 /* must have movedIds ids */);
|
|
59
61
|
assert(spec.movedClientIds.length === spec.movedSeqs.length, 0xb5f /* Expected same length for client ids and seqs */);
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
// Avoid spreading into push: a large array could exceed the engine's
|
|
63
|
+
// argument-count limit and throw RangeError.
|
|
64
|
+
for (let i = 0; i < spec.movedClientIds.length; i++) {
|
|
65
|
+
removes.push({
|
|
66
|
+
type: "sliceRemove",
|
|
67
|
+
seq: spec.movedSeqs[i],
|
|
68
|
+
clientId: this.client.getOrAddShortClientId(spec.movedClientIds[i]),
|
|
69
|
+
});
|
|
70
|
+
}
|
|
65
71
|
}
|
|
66
72
|
if (removes.length > 0) {
|
|
67
73
|
removes.sort(opstampUtils.compare);
|
|
@@ -151,7 +157,11 @@ export class SnapshotLoader {
|
|
|
151
157
|
const newSegs = chunk.segments.map((element) => this.specToSegment(element));
|
|
152
158
|
this.extractAttribution(newSegs, chunk);
|
|
153
159
|
chunksWithAttribution += chunk.attribution === undefined ? 0 : 1;
|
|
154
|
-
|
|
160
|
+
// Avoid `push(...newSegs)`: spreading a large array into a variadic call
|
|
161
|
+
// can exceed the engine's argument-count limit and throw RangeError.
|
|
162
|
+
for (const seg of newSegs) {
|
|
163
|
+
segs.push(seg);
|
|
164
|
+
}
|
|
155
165
|
}
|
|
156
166
|
assert(chunksWithAttribution === 0 ||
|
|
157
167
|
chunksWithAttribution === headerMetadata.orderedChunkMetadata.length, 0x4c0 /* all or no chunks should have attribution information */);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snapshotLoader.js","sourceRoot":"","sources":["../src/snapshotLoader.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\n/* eslint-disable @typescript-eslint/no-non-null-assertion */\n\nimport { bufferToString } from \"@fluid-internal/client-utils\";\nimport { AttachState } from \"@fluidframework/container-definitions\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type {\n\tIFluidDataStoreRuntime,\n\tIChannelStorageService,\n} from \"@fluidframework/datastore-definitions/internal\";\nimport type { ISequencedDocumentMessage } from \"@fluidframework/driver-definitions/internal\";\nimport type { IFluidSerializer } from \"@fluidframework/shared-object-base/internal\";\nimport {\n\ttype ITelemetryLoggerExt,\n\tUsageError,\n\tcreateChildLogger,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nimport type { Client } from \"./client.js\";\nimport { NonCollabClient, UniversalSequenceNumber } from \"./constants.js\";\nimport type { MergeTree } from \"./mergeTree.js\";\nimport type { ISegmentPrivate } from \"./mergeTreeNodes.js\";\nimport type { IJSONSegment } from \"./ops.js\";\nimport { PriorPerspective } from \"./perspective.js\";\nimport {\n\ttype IHasRemovalInfo,\n\toverwriteInfo,\n\ttype IHasInsertionInfo,\n\ttype SegmentWithInfo,\n} from \"./segmentInfos.js\";\nimport {\n\ttype IJSONSegmentWithMergeInfo,\n\ttype MergeTreeChunkV1,\n\thasMergeInfo,\n} from \"./snapshotChunks.js\";\nimport { SnapshotV1 } from \"./snapshotV1.js\";\nimport { SnapshotLegacy } from \"./snapshotlegacy.js\";\nimport type { RemoveOperationStamp } from \"./stamps.js\";\nimport * as opstampUtils from \"./stamps.js\";\n\nexport class SnapshotLoader {\n\tprivate readonly logger: ITelemetryLoggerExt;\n\n\tconstructor(\n\t\tprivate readonly runtime: IFluidDataStoreRuntime,\n\n\t\tprivate readonly client: Client,\n\t\tprivate readonly mergeTree: MergeTree,\n\t\tlogger: ITelemetryLoggerExt,\n\t\tprivate readonly serializer: IFluidSerializer,\n\t) {\n\t\tthis.logger = createChildLogger({ logger, namespace: \"SnapshotLoader\" });\n\t}\n\n\tpublic async initialize(\n\t\tservices: IChannelStorageService,\n\t): Promise<{ catchupOpsP: Promise<ISequencedDocumentMessage[]> }> {\n\t\tconst headerLoadedP = services.readBlob(SnapshotLegacy.header).then((header) => {\n\t\t\tassert(!!header, 0x05f /* \"Missing blob header on legacy snapshot!\" */);\n\t\t\treturn this.loadHeader(bufferToString(header, \"utf8\"));\n\t\t});\n\n\t\tconst catchupOpsP = this.loadBodyAndCatchupOps(headerLoadedP, services);\n\n\t\tcatchupOpsP.catch((error) =>\n\t\t\tthis.logger.sendErrorEvent({ eventName: \"CatchupOpsLoadFailure\" }, error),\n\t\t);\n\n\t\tawait headerLoadedP;\n\n\t\treturn { catchupOpsP };\n\t}\n\n\tprivate async loadBodyAndCatchupOps(\n\t\theaderChunkP: Promise<MergeTreeChunkV1>,\n\t\tservices: IChannelStorageService,\n\t): Promise<ISequencedDocumentMessage[]> {\n\t\tconst blobsP = services.list(\"\");\n\t\tconst headerChunk = await headerChunkP;\n\n\t\t// TODO we shouldn't need to wait on the body being complete to finish initialization.\n\t\t// To fully support this we need to be able to process inbound ops for pending segments.\n\t\tawait this.loadBody(headerChunk, services);\n\n\t\tconst blobs = await blobsP;\n\t\tif (blobs.length === headerChunk.headerMetadata!.orderedChunkMetadata.length + 1) {\n\t\t\tfor (const md of headerChunk.headerMetadata!.orderedChunkMetadata)\n\t\t\t\tblobs.splice(blobs.indexOf(md.id), 1);\n\t\t\tassert(blobs.length === 1, 0x060 /* There should be only one blob with catch up ops */);\n\n\t\t\t// TODO: The 'Snapshot.catchupOps' tree entry is purely for backwards compatibility.\n\t\t\t// (See https://github.com/microsoft/FluidFramework/issues/84)\n\n\t\t\treturn this.loadCatchupOps(services.readBlob(blobs[0]), this.serializer);\n\t\t} else if (blobs.length !== headerChunk.headerMetadata!.orderedChunkMetadata.length) {\n\t\t\tthrow new Error(\"Unexpected blobs in snapshot\");\n\t\t}\n\t\treturn [];\n\t}\n\n\tprivate readonly specToSegment = (\n\t\tspec: IJSONSegment | IJSONSegmentWithMergeInfo,\n\t): SegmentWithInfo<IHasInsertionInfo> => {\n\t\tif (hasMergeInfo(spec)) {\n\t\t\tconst seg = overwriteInfo<IHasInsertionInfo>(this.client.specToSegment(spec.json), {\n\t\t\t\tinsert: {\n\t\t\t\t\ttype: \"insert\",\n\t\t\t\t\tseq: spec.seq ?? UniversalSequenceNumber,\n\t\t\t\t\tclientId:\n\t\t\t\t\t\tspec.client === undefined\n\t\t\t\t\t\t\t? NonCollabClient\n\t\t\t\t\t\t\t: this.client.getOrAddShortClientId(spec.client),\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tconst removes: RemoveOperationStamp[] = [];\n\n\t\t\tif (spec.removedSeq !== undefined) {\n\t\t\t\t// this format had a bug where it didn't store all the overlap clients\n\t\t\t\t// this is for back compat, so we change the singular id to an array\n\t\t\t\t// this will only cause problems if there is an overlapping delete\n\t\t\t\t// spanning the snapshot, which should be rare\n\t\t\t\tconst specAsBuggyFormat: IJSONSegmentWithMergeInfo & { removedClient?: string } = spec;\n\t\t\t\tif (specAsBuggyFormat.removedClient !== undefined) {\n\t\t\t\t\tspec.removedClientIds ??= [specAsBuggyFormat.removedClient];\n\t\t\t\t}\n\t\t\t\tassert(spec.removedClientIds !== undefined, 0xaac /* must have removedClient ids */);\n\t\t\t\tconst firstRemovedSeq = spec.removedSeq;\n\t\t\t\t// TODO:AB#32299: To correctly support perspectives from other clients which don't assume they have seen\n\t\t\t\t// all ops, we need to actually record these in the summary. For now we use fake data, and it turns\n\t\t\t\t// out ok since none of these values end up being used. (specifically, the 'firstRemovedSeq' is fake\n\t\t\t\t// for all values other than the actual first remove).\n\t\t\t\t// This issue only affects V1 summaries, as the strategy in snapshotlegacy avoids storing merge info directly.\n\t\t\t\tremoves.push(\n\t\t\t\t\t...spec.removedClientIds.map(\n\t\t\t\t\t\t(id) =>\n\t\t\t\t\t\t\t({\n\t\t\t\t\t\t\t\ttype: \"setRemove\",\n\t\t\t\t\t\t\t\tseq: firstRemovedSeq,\n\t\t\t\t\t\t\t\tclientId: this.client.getOrAddShortClientId(id),\n\t\t\t\t\t\t\t}) as const,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (spec.movedSeq !== undefined) {\n\t\t\t\tassert(\n\t\t\t\t\tspec.movedClientIds !== undefined && spec.movedSeqs !== undefined,\n\t\t\t\t\t0xaa5 /* must have movedIds ids */,\n\t\t\t\t);\n\t\t\t\tassert(\n\t\t\t\t\tspec.movedClientIds.length === spec.movedSeqs.length,\n\t\t\t\t\t0xb5f /* Expected same length for client ids and seqs */,\n\t\t\t\t);\n\n\t\t\t\tremoves.push(\n\t\t\t\t\t...spec.movedClientIds.map(\n\t\t\t\t\t\t(id, i) =>\n\t\t\t\t\t\t\t({\n\t\t\t\t\t\t\t\ttype: \"sliceRemove\",\n\t\t\t\t\t\t\t\tseq: spec.movedSeqs![i],\n\t\t\t\t\t\t\t\tclientId: this.client.getOrAddShortClientId(id),\n\t\t\t\t\t\t\t}) as const,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (removes.length > 0) {\n\t\t\t\tremoves.sort(opstampUtils.compare);\n\t\t\t\toverwriteInfo<IHasRemovalInfo>(seg, { removes });\n\t\t\t}\n\n\t\t\treturn seg;\n\t\t}\n\t\treturn overwriteInfo(this.client.specToSegment(spec), {\n\t\t\tinsert: {\n\t\t\t\ttype: \"insert\",\n\t\t\t\tseq: UniversalSequenceNumber,\n\t\t\t\tclientId: NonCollabClient,\n\t\t\t},\n\t\t});\n\t};\n\n\tprivate loadHeader(header: string): MergeTreeChunkV1 {\n\t\tconst chunk = SnapshotV1.processChunk(\n\t\t\tSnapshotLegacy.header,\n\t\t\theader,\n\t\t\tthis.logger,\n\t\t\tthis.mergeTree.options,\n\t\t\tthis.serializer,\n\t\t);\n\t\tconst segs = chunk.segments.map((element) => this.specToSegment(element));\n\t\tthis.extractAttribution(segs, chunk);\n\n\t\tthis.mergeTree.reloadFromSegments(segs);\n\n\t\tif (chunk.headerMetadata === undefined) {\n\t\t\tthrow new Error(\"header metadata not available\");\n\t\t}\n\t\t// If we load a detached container from snapshot, then we don't supply a default clientId\n\t\t// because we don't want to start collaboration.\n\t\tif (this.runtime.attachState !== AttachState.Detached) {\n\t\t\t// specify a default client id, \"snapshot\" here as we\n\t\t\t// should enter collaboration/op sending mode if we load\n\t\t\t// a snapshot in any case (summary or attach message)\n\t\t\t// once we get a client id this will be called with that\n\t\t\t// clientId in the connected event\n\t\t\tthis.client.startOrUpdateCollaboration(\n\t\t\t\tthis.runtime.clientId ?? \"snapshot\",\n\n\t\t\t\t// TODO: Make 'minSeq' non-optional once the new snapshot format becomes the default?\n\t\t\t\t// (See https://github.com/microsoft/FluidFramework/issues/84)\n\t\t\t\t/* minSeq: */ chunk.headerMetadata.minSequenceNumber ??\n\t\t\t\t\tchunk.headerMetadata.sequenceNumber,\n\t\t\t\t/* currentSeq: */ chunk.headerMetadata.sequenceNumber,\n\t\t\t);\n\t\t}\n\n\t\treturn chunk;\n\t}\n\n\tprivate async loadBody(\n\t\tchunk1: MergeTreeChunkV1,\n\t\tservices: IChannelStorageService,\n\t): Promise<void> {\n\t\tconst headerMetadata = chunk1.headerMetadata!;\n\t\tassert(chunk1.length <= headerMetadata.totalLength, 0x061 /* \"Mismatch in totalLength\" */);\n\n\t\tassert(\n\t\t\tchunk1.segmentCount <= headerMetadata.totalSegmentCount,\n\t\t\t0x062 /* \"Mismatch in totalSegmentCount\" */,\n\t\t);\n\n\t\tif (chunk1.segmentCount === headerMetadata.totalSegmentCount) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet chunksWithAttribution = chunk1.attribution === undefined ? 0 : 1;\n\t\tconst segs: SegmentWithInfo<IHasInsertionInfo>[] = [];\n\t\tlet lengthSofar = chunk1.length;\n\t\tfor (\n\t\t\tlet chunkIndex = 1;\n\t\t\tchunkIndex < headerMetadata.orderedChunkMetadata.length;\n\t\t\tchunkIndex++\n\t\t) {\n\t\t\tconst chunk = await SnapshotV1.loadChunk(\n\t\t\t\tservices,\n\t\t\t\theaderMetadata.orderedChunkMetadata[chunkIndex].id,\n\t\t\t\tthis.logger,\n\t\t\t\tthis.mergeTree.options,\n\t\t\t\tthis.serializer,\n\t\t\t);\n\t\t\tlengthSofar += chunk.length;\n\t\t\t// Deserialize each chunk segment and append it to the end of the MergeTree.\n\t\t\tconst newSegs = chunk.segments.map((element) => this.specToSegment(element));\n\t\t\tthis.extractAttribution(newSegs, chunk);\n\t\t\tchunksWithAttribution += chunk.attribution === undefined ? 0 : 1;\n\t\t\tsegs.push(...newSegs);\n\t\t}\n\n\t\tassert(\n\t\t\tchunksWithAttribution === 0 ||\n\t\t\t\tchunksWithAttribution === headerMetadata.orderedChunkMetadata.length,\n\t\t\t0x4c0 /* all or no chunks should have attribution information */,\n\t\t);\n\n\t\tassert(lengthSofar === headerMetadata.totalLength, 0x063 /* \"Mismatch in totalLength\" */);\n\n\t\tassert(\n\t\t\tchunk1.segmentCount + segs.length === headerMetadata.totalSegmentCount,\n\t\t\t0x064 /* \"Mismatch in totalSegmentCount\" */,\n\t\t);\n\n\t\t// Helper to insert segments at the end of the MergeTree.\n\t\tconst mergeTree = this.mergeTree;\n\t\tconst append = (segments: ISegmentPrivate[], clientId: number, seq: number): void => {\n\t\t\tmergeTree.insertSegments(\n\t\t\t\tmergeTree.root.cachedLength ?? 0,\n\t\t\t\tsegments,\n\t\t\t\tnew PriorPerspective(UniversalSequenceNumber, clientId),\n\t\t\t\t{ seq, clientId },\n\t\t\t\tundefined,\n\t\t\t);\n\t\t};\n\n\t\t// Helpers to batch-insert segments that are below the min seq\n\t\tconst batch: SegmentWithInfo<IHasInsertionInfo>[] = [];\n\t\tconst flushBatch = (): void => {\n\t\t\tif (batch.length > 0) {\n\t\t\t\tappend(batch, NonCollabClient, UniversalSequenceNumber);\n\t\t\t}\n\t\t};\n\n\t\tfor (const seg of segs) {\n\t\t\tconst { clientId, seq } = seg.insert;\n\t\t\t// If the segment can be batch inserted, add it to the 'batch' array. Otherwise, flush\n\t\t\t// any batched segments and then insert the current segment individually.\n\t\t\tif (clientId === NonCollabClient && seq === UniversalSequenceNumber) {\n\t\t\t\tbatch.push(seg);\n\t\t\t} else {\n\t\t\t\tflushBatch();\n\t\t\t\tappend([seg], clientId, seq);\n\t\t\t}\n\t\t}\n\n\t\tflushBatch();\n\t}\n\n\tprivate extractAttribution(segments: ISegmentPrivate[], chunk: MergeTreeChunkV1): void {\n\t\tif (chunk.attribution) {\n\t\t\tconst { attributionPolicy } = this.mergeTree;\n\t\t\tif (attributionPolicy === undefined) {\n\t\t\t\tthrow new UsageError(\n\t\t\t\t\t\"Attribution policy must be provided when loading a document with attribution information.\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst { isAttached, attach, serializer } = attributionPolicy;\n\t\t\tif (!isAttached) {\n\t\t\t\tattach(this.client);\n\t\t\t}\n\t\t\tserializer.populateAttributionCollections(segments, chunk.attribution);\n\t\t} else {\n\t\t\tconst { attributionPolicy } = this.mergeTree;\n\t\t\tif (attributionPolicy?.isAttached) {\n\t\t\t\tattributionPolicy?.detach();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * If loading from a snapshot, get the catchup messages.\n\t * @param rawMessages - The messages in original encoding\n\t * @returns The decoded messages with parsed+hydrated handles. Matches the format that will be passed in\n\t * SharedObject.processCore.\n\t */\n\tprivate async loadCatchupOps(\n\t\trawMessages: Promise<ArrayBufferLike>,\n\t\tserializer: IFluidSerializer,\n\t): Promise<ISequencedDocumentMessage[]> {\n\t\treturn serializer.parse(\n\t\t\tbufferToString(await rawMessages, \"utf8\"),\n\t\t) as ISequencedDocumentMessage[];\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"snapshotLoader.js","sourceRoot":"","sources":["../src/snapshotLoader.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\n/* eslint-disable @typescript-eslint/no-non-null-assertion */\n\nimport { bufferToString } from \"@fluid-internal/client-utils\";\nimport { AttachState } from \"@fluidframework/container-definitions\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type {\n\tIFluidDataStoreRuntime,\n\tIChannelStorageService,\n} from \"@fluidframework/datastore-definitions/internal\";\nimport type { ISequencedDocumentMessage } from \"@fluidframework/driver-definitions/internal\";\nimport type { IFluidSerializer } from \"@fluidframework/shared-object-base/internal\";\nimport {\n\ttype ITelemetryLoggerExt,\n\tUsageError,\n\tcreateChildLogger,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nimport type { Client } from \"./client.js\";\nimport { NonCollabClient, UniversalSequenceNumber } from \"./constants.js\";\nimport type { MergeTree } from \"./mergeTree.js\";\nimport type { ISegmentPrivate } from \"./mergeTreeNodes.js\";\nimport type { IJSONSegment } from \"./ops.js\";\nimport { PriorPerspective } from \"./perspective.js\";\nimport {\n\ttype IHasRemovalInfo,\n\toverwriteInfo,\n\ttype IHasInsertionInfo,\n\ttype SegmentWithInfo,\n} from \"./segmentInfos.js\";\nimport {\n\ttype IJSONSegmentWithMergeInfo,\n\ttype MergeTreeChunkV1,\n\thasMergeInfo,\n} from \"./snapshotChunks.js\";\nimport { SnapshotV1 } from \"./snapshotV1.js\";\nimport { SnapshotLegacy } from \"./snapshotlegacy.js\";\nimport type { RemoveOperationStamp } from \"./stamps.js\";\nimport * as opstampUtils from \"./stamps.js\";\n\nexport class SnapshotLoader {\n\tprivate readonly logger: ITelemetryLoggerExt;\n\n\tconstructor(\n\t\tprivate readonly runtime: IFluidDataStoreRuntime,\n\n\t\tprivate readonly client: Client,\n\t\tprivate readonly mergeTree: MergeTree,\n\t\tlogger: ITelemetryLoggerExt,\n\t\tprivate readonly serializer: IFluidSerializer,\n\t) {\n\t\tthis.logger = createChildLogger({ logger, namespace: \"SnapshotLoader\" });\n\t}\n\n\tpublic async initialize(\n\t\tservices: IChannelStorageService,\n\t): Promise<{ catchupOpsP: Promise<ISequencedDocumentMessage[]> }> {\n\t\tconst headerLoadedP = services.readBlob(SnapshotLegacy.header).then((header) => {\n\t\t\tassert(!!header, 0x05f /* \"Missing blob header on legacy snapshot!\" */);\n\t\t\treturn this.loadHeader(bufferToString(header, \"utf8\"));\n\t\t});\n\n\t\tconst catchupOpsP = this.loadBodyAndCatchupOps(headerLoadedP, services);\n\n\t\tcatchupOpsP.catch((error) =>\n\t\t\tthis.logger.sendErrorEvent({ eventName: \"CatchupOpsLoadFailure\" }, error),\n\t\t);\n\n\t\tawait headerLoadedP;\n\n\t\treturn { catchupOpsP };\n\t}\n\n\tprivate async loadBodyAndCatchupOps(\n\t\theaderChunkP: Promise<MergeTreeChunkV1>,\n\t\tservices: IChannelStorageService,\n\t): Promise<ISequencedDocumentMessage[]> {\n\t\tconst blobsP = services.list(\"\");\n\t\tconst headerChunk = await headerChunkP;\n\n\t\t// TODO we shouldn't need to wait on the body being complete to finish initialization.\n\t\t// To fully support this we need to be able to process inbound ops for pending segments.\n\t\tawait this.loadBody(headerChunk, services);\n\n\t\tconst blobs = await blobsP;\n\t\tif (blobs.length === headerChunk.headerMetadata!.orderedChunkMetadata.length + 1) {\n\t\t\tfor (const md of headerChunk.headerMetadata!.orderedChunkMetadata)\n\t\t\t\tblobs.splice(blobs.indexOf(md.id), 1);\n\t\t\tassert(blobs.length === 1, 0x060 /* There should be only one blob with catch up ops */);\n\n\t\t\t// TODO: The 'Snapshot.catchupOps' tree entry is purely for backwards compatibility.\n\t\t\t// (See https://github.com/microsoft/FluidFramework/issues/84)\n\n\t\t\treturn this.loadCatchupOps(services.readBlob(blobs[0]), this.serializer);\n\t\t} else if (blobs.length !== headerChunk.headerMetadata!.orderedChunkMetadata.length) {\n\t\t\tthrow new Error(\"Unexpected blobs in snapshot\");\n\t\t}\n\t\treturn [];\n\t}\n\n\tprivate readonly specToSegment = (\n\t\tspec: IJSONSegment | IJSONSegmentWithMergeInfo,\n\t): SegmentWithInfo<IHasInsertionInfo> => {\n\t\tif (hasMergeInfo(spec)) {\n\t\t\tconst seg = overwriteInfo<IHasInsertionInfo>(this.client.specToSegment(spec.json), {\n\t\t\t\tinsert: {\n\t\t\t\t\ttype: \"insert\",\n\t\t\t\t\tseq: spec.seq ?? UniversalSequenceNumber,\n\t\t\t\t\tclientId:\n\t\t\t\t\t\tspec.client === undefined\n\t\t\t\t\t\t\t? NonCollabClient\n\t\t\t\t\t\t\t: this.client.getOrAddShortClientId(spec.client),\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tconst removes: RemoveOperationStamp[] = [];\n\n\t\t\tif (spec.removedSeq !== undefined) {\n\t\t\t\t// this format had a bug where it didn't store all the overlap clients\n\t\t\t\t// this is for back compat, so we change the singular id to an array\n\t\t\t\t// this will only cause problems if there is an overlapping delete\n\t\t\t\t// spanning the snapshot, which should be rare\n\t\t\t\tconst specAsBuggyFormat: IJSONSegmentWithMergeInfo & { removedClient?: string } = spec;\n\t\t\t\tif (specAsBuggyFormat.removedClient !== undefined) {\n\t\t\t\t\tspec.removedClientIds ??= [specAsBuggyFormat.removedClient];\n\t\t\t\t}\n\t\t\t\tassert(spec.removedClientIds !== undefined, 0xaac /* must have removedClient ids */);\n\t\t\t\tconst firstRemovedSeq = spec.removedSeq;\n\t\t\t\t// TODO:AB#32299: To correctly support perspectives from other clients which don't assume they have seen\n\t\t\t\t// all ops, we need to actually record these in the summary. For now we use fake data, and it turns\n\t\t\t\t// out ok since none of these values end up being used. (specifically, the 'firstRemovedSeq' is fake\n\t\t\t\t// for all values other than the actual first remove).\n\t\t\t\t// This issue only affects V1 summaries, as the strategy in snapshotlegacy avoids storing merge info directly.\n\t\t\t\tfor (const id of spec.removedClientIds) {\n\t\t\t\t\tremoves.push({\n\t\t\t\t\t\ttype: \"setRemove\",\n\t\t\t\t\t\tseq: firstRemovedSeq,\n\t\t\t\t\t\tclientId: this.client.getOrAddShortClientId(id),\n\t\t\t\t\t} as const);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (spec.movedSeq !== undefined) {\n\t\t\t\tassert(\n\t\t\t\t\tspec.movedClientIds !== undefined && spec.movedSeqs !== undefined,\n\t\t\t\t\t0xaa5 /* must have movedIds ids */,\n\t\t\t\t);\n\t\t\t\tassert(\n\t\t\t\t\tspec.movedClientIds.length === spec.movedSeqs.length,\n\t\t\t\t\t0xb5f /* Expected same length for client ids and seqs */,\n\t\t\t\t);\n\n\t\t\t\t// Avoid spreading into push: a large array could exceed the engine's\n\t\t\t\t// argument-count limit and throw RangeError.\n\t\t\t\tfor (let i = 0; i < spec.movedClientIds.length; i++) {\n\t\t\t\t\tremoves.push({\n\t\t\t\t\t\ttype: \"sliceRemove\",\n\t\t\t\t\t\tseq: spec.movedSeqs[i],\n\t\t\t\t\t\tclientId: this.client.getOrAddShortClientId(spec.movedClientIds[i]),\n\t\t\t\t\t} as const);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (removes.length > 0) {\n\t\t\t\tremoves.sort(opstampUtils.compare);\n\t\t\t\toverwriteInfo<IHasRemovalInfo>(seg, { removes });\n\t\t\t}\n\n\t\t\treturn seg;\n\t\t}\n\t\treturn overwriteInfo(this.client.specToSegment(spec), {\n\t\t\tinsert: {\n\t\t\t\ttype: \"insert\",\n\t\t\t\tseq: UniversalSequenceNumber,\n\t\t\t\tclientId: NonCollabClient,\n\t\t\t},\n\t\t});\n\t};\n\n\tprivate loadHeader(header: string): MergeTreeChunkV1 {\n\t\tconst chunk = SnapshotV1.processChunk(\n\t\t\tSnapshotLegacy.header,\n\t\t\theader,\n\t\t\tthis.logger,\n\t\t\tthis.mergeTree.options,\n\t\t\tthis.serializer,\n\t\t);\n\t\tconst segs = chunk.segments.map((element) => this.specToSegment(element));\n\t\tthis.extractAttribution(segs, chunk);\n\n\t\tthis.mergeTree.reloadFromSegments(segs);\n\n\t\tif (chunk.headerMetadata === undefined) {\n\t\t\tthrow new Error(\"header metadata not available\");\n\t\t}\n\t\t// If we load a detached container from snapshot, then we don't supply a default clientId\n\t\t// because we don't want to start collaboration.\n\t\tif (this.runtime.attachState !== AttachState.Detached) {\n\t\t\t// specify a default client id, \"snapshot\" here as we\n\t\t\t// should enter collaboration/op sending mode if we load\n\t\t\t// a snapshot in any case (summary or attach message)\n\t\t\t// once we get a client id this will be called with that\n\t\t\t// clientId in the connected event\n\t\t\tthis.client.startOrUpdateCollaboration(\n\t\t\t\tthis.runtime.clientId ?? \"snapshot\",\n\n\t\t\t\t// TODO: Make 'minSeq' non-optional once the new snapshot format becomes the default?\n\t\t\t\t// (See https://github.com/microsoft/FluidFramework/issues/84)\n\t\t\t\t/* minSeq: */ chunk.headerMetadata.minSequenceNumber ??\n\t\t\t\t\tchunk.headerMetadata.sequenceNumber,\n\t\t\t\t/* currentSeq: */ chunk.headerMetadata.sequenceNumber,\n\t\t\t);\n\t\t}\n\n\t\treturn chunk;\n\t}\n\n\tprivate async loadBody(\n\t\tchunk1: MergeTreeChunkV1,\n\t\tservices: IChannelStorageService,\n\t): Promise<void> {\n\t\tconst headerMetadata = chunk1.headerMetadata!;\n\t\tassert(chunk1.length <= headerMetadata.totalLength, 0x061 /* \"Mismatch in totalLength\" */);\n\n\t\tassert(\n\t\t\tchunk1.segmentCount <= headerMetadata.totalSegmentCount,\n\t\t\t0x062 /* \"Mismatch in totalSegmentCount\" */,\n\t\t);\n\n\t\tif (chunk1.segmentCount === headerMetadata.totalSegmentCount) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet chunksWithAttribution = chunk1.attribution === undefined ? 0 : 1;\n\t\tconst segs: SegmentWithInfo<IHasInsertionInfo>[] = [];\n\t\tlet lengthSofar = chunk1.length;\n\t\tfor (\n\t\t\tlet chunkIndex = 1;\n\t\t\tchunkIndex < headerMetadata.orderedChunkMetadata.length;\n\t\t\tchunkIndex++\n\t\t) {\n\t\t\tconst chunk = await SnapshotV1.loadChunk(\n\t\t\t\tservices,\n\t\t\t\theaderMetadata.orderedChunkMetadata[chunkIndex].id,\n\t\t\t\tthis.logger,\n\t\t\t\tthis.mergeTree.options,\n\t\t\t\tthis.serializer,\n\t\t\t);\n\t\t\tlengthSofar += chunk.length;\n\t\t\t// Deserialize each chunk segment and append it to the end of the MergeTree.\n\t\t\tconst newSegs = chunk.segments.map((element) => this.specToSegment(element));\n\t\t\tthis.extractAttribution(newSegs, chunk);\n\t\t\tchunksWithAttribution += chunk.attribution === undefined ? 0 : 1;\n\t\t\t// Avoid `push(...newSegs)`: spreading a large array into a variadic call\n\t\t\t// can exceed the engine's argument-count limit and throw RangeError.\n\t\t\tfor (const seg of newSegs) {\n\t\t\t\tsegs.push(seg);\n\t\t\t}\n\t\t}\n\n\t\tassert(\n\t\t\tchunksWithAttribution === 0 ||\n\t\t\t\tchunksWithAttribution === headerMetadata.orderedChunkMetadata.length,\n\t\t\t0x4c0 /* all or no chunks should have attribution information */,\n\t\t);\n\n\t\tassert(lengthSofar === headerMetadata.totalLength, 0x063 /* \"Mismatch in totalLength\" */);\n\n\t\tassert(\n\t\t\tchunk1.segmentCount + segs.length === headerMetadata.totalSegmentCount,\n\t\t\t0x064 /* \"Mismatch in totalSegmentCount\" */,\n\t\t);\n\n\t\t// Helper to insert segments at the end of the MergeTree.\n\t\tconst mergeTree = this.mergeTree;\n\t\tconst append = (segments: ISegmentPrivate[], clientId: number, seq: number): void => {\n\t\t\tmergeTree.insertSegments(\n\t\t\t\tmergeTree.root.cachedLength ?? 0,\n\t\t\t\tsegments,\n\t\t\t\tnew PriorPerspective(UniversalSequenceNumber, clientId),\n\t\t\t\t{ seq, clientId },\n\t\t\t\tundefined,\n\t\t\t);\n\t\t};\n\n\t\t// Helpers to batch-insert segments that are below the min seq\n\t\tconst batch: SegmentWithInfo<IHasInsertionInfo>[] = [];\n\t\tconst flushBatch = (): void => {\n\t\t\tif (batch.length > 0) {\n\t\t\t\tappend(batch, NonCollabClient, UniversalSequenceNumber);\n\t\t\t}\n\t\t};\n\n\t\tfor (const seg of segs) {\n\t\t\tconst { clientId, seq } = seg.insert;\n\t\t\t// If the segment can be batch inserted, add it to the 'batch' array. Otherwise, flush\n\t\t\t// any batched segments and then insert the current segment individually.\n\t\t\tif (clientId === NonCollabClient && seq === UniversalSequenceNumber) {\n\t\t\t\tbatch.push(seg);\n\t\t\t} else {\n\t\t\t\tflushBatch();\n\t\t\t\tappend([seg], clientId, seq);\n\t\t\t}\n\t\t}\n\n\t\tflushBatch();\n\t}\n\n\tprivate extractAttribution(segments: ISegmentPrivate[], chunk: MergeTreeChunkV1): void {\n\t\tif (chunk.attribution) {\n\t\t\tconst { attributionPolicy } = this.mergeTree;\n\t\t\tif (attributionPolicy === undefined) {\n\t\t\t\tthrow new UsageError(\n\t\t\t\t\t\"Attribution policy must be provided when loading a document with attribution information.\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst { isAttached, attach, serializer } = attributionPolicy;\n\t\t\tif (!isAttached) {\n\t\t\t\tattach(this.client);\n\t\t\t}\n\t\t\tserializer.populateAttributionCollections(segments, chunk.attribution);\n\t\t} else {\n\t\t\tconst { attributionPolicy } = this.mergeTree;\n\t\t\tif (attributionPolicy?.isAttached) {\n\t\t\t\tattributionPolicy?.detach();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * If loading from a snapshot, get the catchup messages.\n\t * @param rawMessages - The messages in original encoding\n\t * @returns The decoded messages with parsed+hydrated handles. Matches the format that will be passed in\n\t * SharedObject.processCore.\n\t */\n\tprivate async loadCatchupOps(\n\t\trawMessages: Promise<ArrayBufferLike>,\n\t\tserializer: IFluidSerializer,\n\t): Promise<ISequencedDocumentMessage[]> {\n\t\treturn serializer.parse(\n\t\t\tbufferToString(await rawMessages, \"utf8\"),\n\t\t) as ISequencedDocumentMessage[];\n\t}\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/merge-tree",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.102.0",
|
|
4
4
|
"description": "Merge tree",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -81,30 +81,30 @@
|
|
|
81
81
|
"temp-directory": "nyc/.nyc_output"
|
|
82
82
|
},
|
|
83
83
|
"dependencies": {
|
|
84
|
-
"@fluid-internal/client-utils": "~2.
|
|
85
|
-
"@fluidframework/container-definitions": "~2.
|
|
86
|
-
"@fluidframework/core-interfaces": "~2.
|
|
87
|
-
"@fluidframework/core-utils": "~2.
|
|
88
|
-
"@fluidframework/datastore-definitions": "~2.
|
|
89
|
-
"@fluidframework/driver-definitions": "~2.
|
|
90
|
-
"@fluidframework/runtime-definitions": "~2.
|
|
91
|
-
"@fluidframework/runtime-utils": "~2.
|
|
92
|
-
"@fluidframework/shared-object-base": "~2.
|
|
93
|
-
"@fluidframework/telemetry-utils": "~2.
|
|
84
|
+
"@fluid-internal/client-utils": "~2.102.0",
|
|
85
|
+
"@fluidframework/container-definitions": "~2.102.0",
|
|
86
|
+
"@fluidframework/core-interfaces": "~2.102.0",
|
|
87
|
+
"@fluidframework/core-utils": "~2.102.0",
|
|
88
|
+
"@fluidframework/datastore-definitions": "~2.102.0",
|
|
89
|
+
"@fluidframework/driver-definitions": "~2.102.0",
|
|
90
|
+
"@fluidframework/runtime-definitions": "~2.102.0",
|
|
91
|
+
"@fluidframework/runtime-utils": "~2.102.0",
|
|
92
|
+
"@fluidframework/shared-object-base": "~2.102.0",
|
|
93
|
+
"@fluidframework/telemetry-utils": "~2.102.0"
|
|
94
94
|
},
|
|
95
95
|
"devDependencies": {
|
|
96
96
|
"@arethetypeswrong/cli": "^0.18.2",
|
|
97
97
|
"@biomejs/biome": "~2.4.5",
|
|
98
|
-
"@fluid-internal/mocha-test-setup": "~2.
|
|
99
|
-
"@fluid-private/stochastic-test-utils": "~2.
|
|
100
|
-
"@fluid-private/test-pairwise-generator": "~2.
|
|
98
|
+
"@fluid-internal/mocha-test-setup": "~2.102.0",
|
|
99
|
+
"@fluid-private/stochastic-test-utils": "~2.102.0",
|
|
100
|
+
"@fluid-private/test-pairwise-generator": "~2.102.0",
|
|
101
101
|
"@fluid-tools/benchmark": "^0.59.0",
|
|
102
102
|
"@fluid-tools/build-cli": "^0.65.0",
|
|
103
103
|
"@fluidframework/build-common": "^2.0.3",
|
|
104
104
|
"@fluidframework/build-tools": "^0.65.0",
|
|
105
105
|
"@fluidframework/eslint-config-fluid": "^9.0.0",
|
|
106
|
-
"@fluidframework/merge-tree-previous": "npm:@fluidframework/merge-tree@2.
|
|
107
|
-
"@fluidframework/test-runtime-utils": "~2.
|
|
106
|
+
"@fluidframework/merge-tree-previous": "npm:@fluidframework/merge-tree@2.101.0",
|
|
107
|
+
"@fluidframework/test-runtime-utils": "~2.102.0",
|
|
108
108
|
"@microsoft/api-extractor": "7.58.1",
|
|
109
109
|
"@types/diff": "^3.5.1",
|
|
110
110
|
"@types/mocha": "^10.0.10",
|
package/src/snapshotLoader.ts
CHANGED
|
@@ -135,16 +135,13 @@ export class SnapshotLoader {
|
|
|
135
135
|
// out ok since none of these values end up being used. (specifically, the 'firstRemovedSeq' is fake
|
|
136
136
|
// for all values other than the actual first remove).
|
|
137
137
|
// This issue only affects V1 summaries, as the strategy in snapshotlegacy avoids storing merge info directly.
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}) as const,
|
|
146
|
-
),
|
|
147
|
-
);
|
|
138
|
+
for (const id of spec.removedClientIds) {
|
|
139
|
+
removes.push({
|
|
140
|
+
type: "setRemove",
|
|
141
|
+
seq: firstRemovedSeq,
|
|
142
|
+
clientId: this.client.getOrAddShortClientId(id),
|
|
143
|
+
} as const);
|
|
144
|
+
}
|
|
148
145
|
}
|
|
149
146
|
if (spec.movedSeq !== undefined) {
|
|
150
147
|
assert(
|
|
@@ -156,16 +153,15 @@ export class SnapshotLoader {
|
|
|
156
153
|
0xb5f /* Expected same length for client ids and seqs */,
|
|
157
154
|
);
|
|
158
155
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
);
|
|
156
|
+
// Avoid spreading into push: a large array could exceed the engine's
|
|
157
|
+
// argument-count limit and throw RangeError.
|
|
158
|
+
for (let i = 0; i < spec.movedClientIds.length; i++) {
|
|
159
|
+
removes.push({
|
|
160
|
+
type: "sliceRemove",
|
|
161
|
+
seq: spec.movedSeqs[i],
|
|
162
|
+
clientId: this.client.getOrAddShortClientId(spec.movedClientIds[i]),
|
|
163
|
+
} as const);
|
|
164
|
+
}
|
|
169
165
|
}
|
|
170
166
|
|
|
171
167
|
if (removes.length > 0) {
|
|
@@ -258,7 +254,11 @@ export class SnapshotLoader {
|
|
|
258
254
|
const newSegs = chunk.segments.map((element) => this.specToSegment(element));
|
|
259
255
|
this.extractAttribution(newSegs, chunk);
|
|
260
256
|
chunksWithAttribution += chunk.attribution === undefined ? 0 : 1;
|
|
261
|
-
|
|
257
|
+
// Avoid `push(...newSegs)`: spreading a large array into a variadic call
|
|
258
|
+
// can exceed the engine's argument-count limit and throw RangeError.
|
|
259
|
+
for (const seg of newSegs) {
|
|
260
|
+
segs.push(seg);
|
|
261
|
+
}
|
|
262
262
|
}
|
|
263
263
|
|
|
264
264
|
assert(
|