@fluidframework/merge-tree 2.3.1 → 2.4.0-297027
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/api-report/merge-tree.legacy.alpha.api.md +26 -7
- package/dist/attributionPolicy.d.ts.map +1 -1
- package/dist/attributionPolicy.js +10 -3
- package/dist/attributionPolicy.js.map +1 -1
- package/dist/client.d.ts +14 -4
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +97 -10
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/legacy.d.ts +1 -0
- package/dist/mergeTree.d.ts +15 -2
- package/dist/mergeTree.d.ts.map +1 -1
- package/dist/mergeTree.js +68 -48
- package/dist/mergeTree.js.map +1 -1
- package/dist/mergeTreeNodes.d.ts +6 -9
- package/dist/mergeTreeNodes.d.ts.map +1 -1
- package/dist/mergeTreeNodes.js +2 -1
- package/dist/mergeTreeNodes.js.map +1 -1
- package/dist/opBuilder.d.ts +15 -1
- package/dist/opBuilder.d.ts.map +1 -1
- package/dist/opBuilder.js +28 -1
- package/dist/opBuilder.js.map +1 -1
- package/dist/ops.d.ts +27 -1
- package/dist/ops.d.ts.map +1 -1
- package/dist/ops.js +1 -0
- package/dist/ops.js.map +1 -1
- package/dist/sequencePlace.d.ts +4 -0
- package/dist/sequencePlace.d.ts.map +1 -1
- package/dist/sequencePlace.js +17 -1
- package/dist/sequencePlace.js.map +1 -1
- package/dist/test/obliterate.concurrent.spec.js +18 -0
- package/dist/test/obliterate.concurrent.spec.js.map +1 -1
- package/dist/test/obliterate.partialLength.spec.js +8 -4
- package/dist/test/obliterate.partialLength.spec.js.map +1 -1
- package/dist/test/obliterate.rangeExpansion.spec.js +109 -53
- package/dist/test/obliterate.rangeExpansion.spec.js.map +1 -1
- package/dist/test/obliterate.spec.js +14 -8
- package/dist/test/obliterate.spec.js.map +1 -1
- package/dist/test/reconnectHelper.d.ts +8 -6
- package/dist/test/reconnectHelper.d.ts.map +1 -1
- package/dist/test/reconnectHelper.js +14 -13
- package/dist/test/reconnectHelper.js.map +1 -1
- package/dist/test/testClient.d.ts +1 -11
- package/dist/test/testClient.d.ts.map +1 -1
- package/dist/test/testClient.js +0 -3
- package/dist/test/testClient.js.map +1 -1
- package/dist/test/testClientLogger.d.ts.map +1 -1
- package/dist/test/testClientLogger.js +19 -8
- package/dist/test/testClientLogger.js.map +1 -1
- package/dist/test/testUtils.d.ts +10 -0
- package/dist/test/testUtils.d.ts.map +1 -1
- package/dist/test/testUtils.js +5 -1
- package/dist/test/testUtils.js.map +1 -1
- package/lib/attributionPolicy.d.ts.map +1 -1
- package/lib/attributionPolicy.js +10 -3
- package/lib/attributionPolicy.js.map +1 -1
- package/lib/client.d.ts +14 -4
- package/lib/client.d.ts.map +1 -1
- package/lib/client.js +98 -11
- package/lib/client.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/legacy.d.ts +1 -0
- package/lib/mergeTree.d.ts +15 -2
- package/lib/mergeTree.d.ts.map +1 -1
- package/lib/mergeTree.js +69 -49
- package/lib/mergeTree.js.map +1 -1
- package/lib/mergeTreeNodes.d.ts +6 -9
- package/lib/mergeTreeNodes.d.ts.map +1 -1
- package/lib/mergeTreeNodes.js +2 -1
- package/lib/mergeTreeNodes.js.map +1 -1
- package/lib/opBuilder.d.ts +15 -1
- package/lib/opBuilder.d.ts.map +1 -1
- package/lib/opBuilder.js +26 -0
- package/lib/opBuilder.js.map +1 -1
- package/lib/ops.d.ts +27 -1
- package/lib/ops.d.ts.map +1 -1
- package/lib/ops.js +1 -0
- package/lib/ops.js.map +1 -1
- package/lib/sequencePlace.d.ts +4 -0
- package/lib/sequencePlace.d.ts.map +1 -1
- package/lib/sequencePlace.js +15 -0
- package/lib/sequencePlace.js.map +1 -1
- package/lib/test/obliterate.concurrent.spec.js +18 -0
- package/lib/test/obliterate.concurrent.spec.js.map +1 -1
- package/lib/test/obliterate.partialLength.spec.js +9 -5
- package/lib/test/obliterate.partialLength.spec.js.map +1 -1
- package/lib/test/obliterate.rangeExpansion.spec.js +109 -53
- package/lib/test/obliterate.rangeExpansion.spec.js.map +1 -1
- package/lib/test/obliterate.spec.js +15 -9
- package/lib/test/obliterate.spec.js.map +1 -1
- package/lib/test/reconnectHelper.d.ts +8 -6
- package/lib/test/reconnectHelper.d.ts.map +1 -1
- package/lib/test/reconnectHelper.js +15 -14
- package/lib/test/reconnectHelper.js.map +1 -1
- package/lib/test/testClient.d.ts +1 -11
- package/lib/test/testClient.d.ts.map +1 -1
- package/lib/test/testClient.js +0 -3
- package/lib/test/testClient.js.map +1 -1
- package/lib/test/testClientLogger.d.ts.map +1 -1
- package/lib/test/testClientLogger.js +19 -8
- package/lib/test/testClientLogger.js.map +1 -1
- package/lib/test/testUtils.d.ts +10 -0
- package/lib/test/testUtils.d.ts.map +1 -1
- package/lib/test/testUtils.js +3 -0
- package/lib/test/testUtils.js.map +1 -1
- package/package.json +30 -17
- package/src/attributionPolicy.ts +5 -0
- package/src/client.ts +138 -20
- package/src/index.ts +1 -0
- package/src/mergeTree.ts +116 -77
- package/src/mergeTreeNodes.ts +9 -10
- package/src/opBuilder.ts +32 -0
- package/src/ops.ts +23 -1
- package/src/sequencePlace.ts +16 -0
package/dist/mergeTree.js
CHANGED
|
@@ -765,13 +765,15 @@ class MergeTree {
|
|
|
765
765
|
segment: pendingSegment,
|
|
766
766
|
});
|
|
767
767
|
});
|
|
768
|
-
if (opArgs.op.type === ops_js_1.MergeTreeDeltaType.OBLITERATE
|
|
768
|
+
if (opArgs.op.type === ops_js_1.MergeTreeDeltaType.OBLITERATE ||
|
|
769
|
+
opArgs.op.type === ops_js_1.MergeTreeDeltaType.OBLITERATE_SIDED) {
|
|
769
770
|
this.obliterates.addOrUpdate(pendingSegmentGroup.obliterateInfo);
|
|
770
771
|
}
|
|
771
772
|
// Perform slides after all segments have been acked, so that
|
|
772
773
|
// positions after slide are final
|
|
773
774
|
if (opArgs.op.type === ops_js_1.MergeTreeDeltaType.REMOVE ||
|
|
774
|
-
opArgs.op.type === ops_js_1.MergeTreeDeltaType.OBLITERATE
|
|
775
|
+
opArgs.op.type === ops_js_1.MergeTreeDeltaType.OBLITERATE ||
|
|
776
|
+
opArgs.op.type === ops_js_1.MergeTreeDeltaType.OBLITERATE_SIDED) {
|
|
775
777
|
this.slideAckedRemovedSegmentReferences(pendingSegmentGroup.segments);
|
|
776
778
|
}
|
|
777
779
|
this.mergeTreeMaintenanceCallback?.({
|
|
@@ -971,9 +973,9 @@ class MergeTree {
|
|
|
971
973
|
});
|
|
972
974
|
}
|
|
973
975
|
this.updateRoot(splitNode);
|
|
974
|
-
saveIfLocal(newSegment);
|
|
975
976
|
insertPos += newSegment.cachedLength;
|
|
976
977
|
if (!this.options?.mergeTreeEnableObliterate || this.obliterates.empty()) {
|
|
978
|
+
saveIfLocal(newSegment);
|
|
977
979
|
continue;
|
|
978
980
|
}
|
|
979
981
|
// eslint-disable-next-line import/no-deprecated
|
|
@@ -1000,13 +1002,13 @@ class MergeTree {
|
|
|
1000
1002
|
movedSeqs.unshift(ob.seq);
|
|
1001
1003
|
}
|
|
1002
1004
|
else {
|
|
1003
|
-
if (newest === undefined || normalizedNewestSeq < normalizedObSeq) {
|
|
1004
|
-
normalizedNewestSeq = normalizedObSeq;
|
|
1005
|
-
newest = ob;
|
|
1006
|
-
}
|
|
1007
1005
|
movedClientIds.push(ob.clientId);
|
|
1008
1006
|
movedSeqs.push(ob.seq);
|
|
1009
1007
|
}
|
|
1008
|
+
if (newest === undefined || normalizedNewestSeq < normalizedObSeq) {
|
|
1009
|
+
normalizedNewestSeq = normalizedObSeq;
|
|
1010
|
+
newest = ob;
|
|
1011
|
+
}
|
|
1010
1012
|
}
|
|
1011
1013
|
}
|
|
1012
1014
|
if (oldest && newest?.clientId !== clientId) {
|
|
@@ -1026,6 +1028,10 @@ class MergeTree {
|
|
|
1026
1028
|
this.blockUpdatePathLengths(newSegment.parent, seq, clientId);
|
|
1027
1029
|
}
|
|
1028
1030
|
}
|
|
1031
|
+
else if (oldest && newest?.clientId === clientId) {
|
|
1032
|
+
newSegment.prevObliterateByInserter = newest;
|
|
1033
|
+
}
|
|
1034
|
+
saveIfLocal(newSegment);
|
|
1029
1035
|
}
|
|
1030
1036
|
}
|
|
1031
1037
|
}
|
|
@@ -1059,16 +1065,7 @@ class MergeTree {
|
|
|
1059
1065
|
}
|
|
1060
1066
|
}
|
|
1061
1067
|
insertingWalk(block, pos, refSeq, clientId, seq, context, isLastChildBlock = true) {
|
|
1062
|
-
let _pos;
|
|
1063
|
-
if (pos === "start") {
|
|
1064
|
-
_pos = 0;
|
|
1065
|
-
}
|
|
1066
|
-
else if (pos === "end") {
|
|
1067
|
-
_pos = this.root.mergeTree?.getLength(refSeq, clientId) ?? 0;
|
|
1068
|
-
}
|
|
1069
|
-
else {
|
|
1070
|
-
_pos = pos;
|
|
1071
|
-
}
|
|
1068
|
+
let _pos = pos;
|
|
1072
1069
|
const children = block.children;
|
|
1073
1070
|
let childIndex;
|
|
1074
1071
|
let child;
|
|
@@ -1241,15 +1238,9 @@ class MergeTree {
|
|
|
1241
1238
|
(0, zamboni_js_1.zamboniSegments)(this);
|
|
1242
1239
|
}
|
|
1243
1240
|
}
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
const
|
|
1247
|
-
(0, internal_1.assert)(startPos !== undefined &&
|
|
1248
|
-
endPos !== undefined &&
|
|
1249
|
-
startSide !== undefined &&
|
|
1250
|
-
endSide !== undefined &&
|
|
1251
|
-
startPos !== "end" &&
|
|
1252
|
-
endPos !== "start", 0x9e2 /* start and end cannot be undefined because they were not passed in as undefined */);
|
|
1241
|
+
obliterateRangeSided(start, end, refSeq, clientId, seq, overwrite = false, opArgs) {
|
|
1242
|
+
const startPos = start.side === sequencePlace_js_1.Side.Before ? start.pos : start.pos + 1;
|
|
1243
|
+
const endPos = end.side === sequencePlace_js_1.Side.Before ? end.pos : end.pos + 1;
|
|
1253
1244
|
this.ensureIntervalBoundary(startPos, refSeq, clientId);
|
|
1254
1245
|
this.ensureIntervalBoundary(endPos, refSeq, clientId);
|
|
1255
1246
|
let _overwrite = overwrite;
|
|
@@ -1266,20 +1257,46 @@ class MergeTree {
|
|
|
1266
1257
|
localSeq,
|
|
1267
1258
|
segmentGroup: undefined,
|
|
1268
1259
|
};
|
|
1269
|
-
const
|
|
1270
|
-
const
|
|
1271
|
-
const { segment: startSeg } = this.getContainingSegment(normalizedStartPos, refSeq, clientId);
|
|
1272
|
-
const { segment: endSeg } = this.getContainingSegment(normalizedEndPos - 1, refSeq, clientId);
|
|
1260
|
+
const { segment: startSeg } = this.getContainingSegment(start.pos, refSeq, clientId);
|
|
1261
|
+
const { segment: endSeg } = this.getContainingSegment(end.pos, refSeq, clientId);
|
|
1273
1262
|
(0, internal_1.assert)(startSeg !== undefined && endSeg !== undefined, 0xa3f /* segments cannot be undefined */);
|
|
1274
|
-
obliterate.start = this.createLocalReferencePosition(startSeg, 0, ops_js_1.ReferenceType.StayOnRemove, {
|
|
1263
|
+
obliterate.start = this.createLocalReferencePosition(startSeg, start.side === sequencePlace_js_1.Side.Before ? 0 : Math.max(startSeg.cachedLength - 1, 0), ops_js_1.ReferenceType.StayOnRemove, {
|
|
1275
1264
|
obliterate,
|
|
1276
1265
|
});
|
|
1277
|
-
obliterate.end = this.createLocalReferencePosition(endSeg, endSeg.cachedLength - 1, ops_js_1.ReferenceType.StayOnRemove, {
|
|
1266
|
+
obliterate.end = this.createLocalReferencePosition(endSeg, end.side === sequencePlace_js_1.Side.Before ? 0 : Math.max(endSeg.cachedLength - 1, 0), ops_js_1.ReferenceType.StayOnRemove, {
|
|
1278
1267
|
obliterate,
|
|
1279
1268
|
});
|
|
1269
|
+
// Always create a segment group for obliterate,
|
|
1270
|
+
// even if there are no segments currently in the obliteration range.
|
|
1271
|
+
// Segments may be concurrently inserted into the obliteration range,
|
|
1272
|
+
// at which point they are added to the segment group.
|
|
1273
|
+
obliterate.segmentGroup = {
|
|
1274
|
+
segments: [],
|
|
1275
|
+
localSeq,
|
|
1276
|
+
refSeq: this.collabWindow.currentSeq,
|
|
1277
|
+
obliterateInfo: obliterate,
|
|
1278
|
+
};
|
|
1279
|
+
if (this.collabWindow.collaborating && clientId === this.collabWindow.clientId) {
|
|
1280
|
+
this.pendingSegments.push(obliterate.segmentGroup);
|
|
1281
|
+
}
|
|
1282
|
+
this.obliterates.addOrUpdate(obliterate);
|
|
1280
1283
|
const markMoved = (segment, pos, _start, _end) => {
|
|
1281
|
-
|
|
1284
|
+
if ((start.side === sequencePlace_js_1.Side.After && startPos === pos + segment.cachedLength) || // exclusive start segment
|
|
1285
|
+
(end.side === sequencePlace_js_1.Side.Before &&
|
|
1286
|
+
endPos === pos &&
|
|
1287
|
+
(0, perspective_js_1.isSegmentPresent)(segment, { refSeq, localSeq })) // exclusive end segment
|
|
1288
|
+
) {
|
|
1289
|
+
// We walk these segments because we want to also walk any concurrently inserted segments between here and the obliterated segments.
|
|
1290
|
+
// These segments are outside of the obliteration range though, so return true to keep walking.
|
|
1291
|
+
return true;
|
|
1292
|
+
}
|
|
1282
1293
|
const existingMoveInfo = (0, mergeTreeNodes_js_1.toMoveInfo)(segment);
|
|
1294
|
+
if (segment.prevObliterateByInserter?.seq === constants_js_1.UnassignedSequenceNumber) {
|
|
1295
|
+
// We chose to not obliterate this segment because we are aware of an unacked local obliteration.
|
|
1296
|
+
// The local obliterate has not been sequenced yet, so it is still the newest obliterate we are aware of.
|
|
1297
|
+
// Other clients will also choose not to obliterate this segment because the most recent obliteration has the same clientId
|
|
1298
|
+
return true;
|
|
1299
|
+
}
|
|
1283
1300
|
if (clientId !== segment.clientId &&
|
|
1284
1301
|
segment.seq !== undefined &&
|
|
1285
1302
|
seq !== constants_js_1.UnassignedSequenceNumber &&
|
|
@@ -1320,7 +1337,6 @@ class MergeTree {
|
|
|
1320
1337
|
if (segment.movedSeq === constants_js_1.UnassignedSequenceNumber &&
|
|
1321
1338
|
clientId === this.collabWindow.clientId) {
|
|
1322
1339
|
obliterate.segmentGroup = this.addToPendingList(segment, obliterate.segmentGroup, localSeq);
|
|
1323
|
-
(_a = obliterate.segmentGroup).obliterateInfo ?? (_a.obliterateInfo = obliterate);
|
|
1324
1340
|
}
|
|
1325
1341
|
else {
|
|
1326
1342
|
if (MergeTree.options.zamboniSegments) {
|
|
@@ -1339,8 +1355,8 @@ class MergeTree {
|
|
|
1339
1355
|
}
|
|
1340
1356
|
return true;
|
|
1341
1357
|
};
|
|
1342
|
-
this.nodeMap(refSeq, clientId, markMoved, undefined, afterMarkMoved, start, end
|
|
1343
|
-
|
|
1358
|
+
this.nodeMap(refSeq, clientId, markMoved, undefined, afterMarkMoved, start.pos, end.pos + 1, // include the segment containing the end reference
|
|
1359
|
+
undefined, seq === constants_js_1.UnassignedSequenceNumber ? undefined : seq);
|
|
1344
1360
|
this.slideAckedRemovedSegmentReferences(localOverlapWithRefs);
|
|
1345
1361
|
// opArgs == undefined => test code
|
|
1346
1362
|
if (movedSegments.length > 0) {
|
|
@@ -1361,6 +1377,17 @@ class MergeTree {
|
|
|
1361
1377
|
(0, zamboni_js_1.zamboniSegments)(this);
|
|
1362
1378
|
}
|
|
1363
1379
|
}
|
|
1380
|
+
obliterateRange(start, end, refSeq, clientId, seq, overwrite = false, opArgs) {
|
|
1381
|
+
errorIfOptionNotTrue(this.options, "mergeTreeEnableObliterate");
|
|
1382
|
+
if (this.options?.mergeTreeEnableSidedObliterate) {
|
|
1383
|
+
(0, internal_1.assert)(typeof start === "object" && typeof end === "object", "Start and end must be of type InteriorSequencePlace if mergeTreeEnableSidedObliterate is enabled.");
|
|
1384
|
+
this.obliterateRangeSided(start, end, refSeq, clientId, seq, overwrite, opArgs);
|
|
1385
|
+
}
|
|
1386
|
+
else {
|
|
1387
|
+
(0, internal_1.assert)(typeof start === "number" && typeof end === "number", "Start and end must be numbers if mergeTreeEnableSidedObliterate is not enabled.");
|
|
1388
|
+
this.obliterateRangeSided({ pos: start, side: sequencePlace_js_1.Side.Before }, { pos: end - 1, side: sequencePlace_js_1.Side.After }, refSeq, clientId, seq, overwrite, opArgs);
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1364
1391
|
markRangeRemoved(start, end, refSeq, clientId, seq, overwrite = false, opArgs) {
|
|
1365
1392
|
let _overwrite = overwrite;
|
|
1366
1393
|
this.ensureIntervalBoundary(start, refSeq, clientId);
|
|
@@ -1809,18 +1836,11 @@ class MergeTree {
|
|
|
1809
1836
|
* ignored for the purposes of tracking when traversal should end.
|
|
1810
1837
|
*/
|
|
1811
1838
|
nodeMap(refSeq, clientId, leaf, accum, post, start = 0, end, localSeq, visibilitySeq = refSeq) {
|
|
1812
|
-
const
|
|
1813
|
-
if (
|
|
1839
|
+
const endPos = end ?? this.nodeLength(this.root, refSeq, clientId, localSeq) ?? 0;
|
|
1840
|
+
if (endPos === start) {
|
|
1814
1841
|
return;
|
|
1815
1842
|
}
|
|
1816
1843
|
let pos = 0;
|
|
1817
|
-
let { startPos, endPos } = (0, sequencePlace_js_1.endpointPosAndSide)(start, end);
|
|
1818
|
-
startPos = startPos === "start" || startPos === undefined ? 0 : startPos;
|
|
1819
|
-
endPos =
|
|
1820
|
-
endPos === "end" || endPos === undefined
|
|
1821
|
-
? this.root.mergeTree?.getLength(refSeq, clientId) ?? 0
|
|
1822
|
-
: endPos;
|
|
1823
|
-
(0, internal_1.assert)(startPos !== "end" && endPos !== "start", 0x9e3 /* start cannot be 'end' and end cannot be 'start' */);
|
|
1824
1844
|
(0, mergeTreeNodeWalk_js_1.depthFirstNodeWalk)(this.root, this.root.children[0], (node) => {
|
|
1825
1845
|
if (endPos <= pos) {
|
|
1826
1846
|
return mergeTreeNodeWalk_js_1.NodeAction.Exit;
|
|
@@ -1837,19 +1857,19 @@ class MergeTree {
|
|
|
1837
1857
|
}
|
|
1838
1858
|
const nextPos = pos + lenAtRefSeq;
|
|
1839
1859
|
// start is beyond the current node, so we can skip it
|
|
1840
|
-
if (
|
|
1860
|
+
if (start >= nextPos) {
|
|
1841
1861
|
pos = nextPos;
|
|
1842
1862
|
return mergeTreeNodeWalk_js_1.NodeAction.Skip;
|
|
1843
1863
|
}
|
|
1844
1864
|
if (node.isLeaf()) {
|
|
1845
|
-
if (leaf(node, pos, refSeq, clientId,
|
|
1865
|
+
if (leaf(node, pos, refSeq, clientId, start - pos, endPos - pos, accum) === false) {
|
|
1846
1866
|
return mergeTreeNodeWalk_js_1.NodeAction.Exit;
|
|
1847
1867
|
}
|
|
1848
1868
|
pos = nextPos;
|
|
1849
1869
|
}
|
|
1850
1870
|
}, undefined, post === undefined
|
|
1851
1871
|
? undefined
|
|
1852
|
-
: (block) => post(block, pos, refSeq, clientId,
|
|
1872
|
+
: (block) => post(block, pos, refSeq, clientId, start - pos, endPos - pos, accum));
|
|
1853
1873
|
}
|
|
1854
1874
|
}
|
|
1855
1875
|
exports.MergeTree = MergeTree;
|