@fluidframework/merge-tree 2.11.0 → 2.13.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 +45 -0
- package/api-report/merge-tree.legacy.alpha.api.md +50 -19
- package/dist/MergeTreeTextHelper.d.ts.map +1 -1
- package/dist/MergeTreeTextHelper.js +0 -2
- package/dist/MergeTreeTextHelper.js.map +1 -1
- package/dist/attributionPolicy.d.ts.map +1 -1
- package/dist/attributionPolicy.js +6 -15
- package/dist/attributionPolicy.js.map +1 -1
- package/dist/client.d.ts +3 -4
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +39 -28
- package/dist/client.js.map +1 -1
- package/dist/endOfTreeSegment.d.ts +5 -4
- package/dist/endOfTreeSegment.d.ts.map +1 -1
- package/dist/endOfTreeSegment.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -4
- package/dist/index.js.map +1 -1
- package/dist/legacy.d.ts +2 -1
- package/dist/localReference.d.ts +1 -0
- package/dist/localReference.d.ts.map +1 -1
- package/dist/localReference.js +1 -0
- package/dist/localReference.js.map +1 -1
- package/dist/mergeTree.d.ts +8 -7
- package/dist/mergeTree.d.ts.map +1 -1
- package/dist/mergeTree.js +202 -211
- package/dist/mergeTree.js.map +1 -1
- package/dist/mergeTreeNodeWalk.d.ts +5 -5
- package/dist/mergeTreeNodeWalk.d.ts.map +1 -1
- package/dist/mergeTreeNodeWalk.js +3 -2
- package/dist/mergeTreeNodeWalk.js.map +1 -1
- package/dist/mergeTreeNodes.d.ts +181 -159
- package/dist/mergeTreeNodes.d.ts.map +1 -1
- package/dist/mergeTreeNodes.js +121 -109
- package/dist/mergeTreeNodes.js.map +1 -1
- package/dist/mergeTreeTracking.d.ts.map +1 -1
- package/dist/mergeTreeTracking.js +0 -2
- package/dist/mergeTreeTracking.js.map +1 -1
- package/dist/partialLengths.d.ts +2 -2
- package/dist/partialLengths.d.ts.map +1 -1
- package/dist/partialLengths.js +33 -27
- package/dist/partialLengths.js.map +1 -1
- package/dist/perspective.d.ts +10 -9
- package/dist/perspective.d.ts.map +1 -1
- package/dist/perspective.js +11 -4
- package/dist/perspective.js.map +1 -1
- package/dist/referencePositions.d.ts.map +1 -1
- package/dist/referencePositions.js +4 -1
- package/dist/referencePositions.js.map +1 -1
- package/dist/revertibles.d.ts.map +1 -1
- package/dist/revertibles.js +13 -11
- package/dist/revertibles.js.map +1 -1
- package/dist/segmentGroupCollection.d.ts +4 -4
- package/dist/segmentGroupCollection.d.ts.map +1 -1
- package/dist/segmentGroupCollection.js +0 -6
- package/dist/segmentGroupCollection.js.map +1 -1
- package/dist/segmentInfos.d.ts +257 -0
- package/dist/segmentInfos.d.ts.map +1 -0
- package/dist/segmentInfos.js +166 -0
- package/dist/segmentInfos.js.map +1 -0
- package/dist/snapshotLoader.d.ts.map +1 -1
- package/dist/snapshotLoader.js +38 -44
- package/dist/snapshotLoader.js.map +1 -1
- package/dist/snapshotV1.d.ts.map +1 -1
- package/dist/snapshotV1.js +9 -12
- package/dist/snapshotV1.js.map +1 -1
- package/dist/snapshotlegacy.d.ts +2 -2
- package/dist/snapshotlegacy.d.ts.map +1 -1
- package/dist/snapshotlegacy.js +5 -3
- package/dist/snapshotlegacy.js.map +1 -1
- package/dist/sortedSegmentSet.d.ts +4 -4
- package/dist/sortedSegmentSet.d.ts.map +1 -1
- package/dist/sortedSegmentSet.js +5 -8
- package/dist/sortedSegmentSet.js.map +1 -1
- package/dist/test/beastTest.spec.d.ts +0 -2
- package/dist/test/beastTest.spec.d.ts.map +1 -1
- package/dist/test/beastTest.spec.js +1 -5
- package/dist/test/beastTest.spec.js.map +1 -1
- package/dist/test/client.annotateMarker.spec.js.map +1 -1
- package/dist/test/client.applyMsg.spec.js +15 -12
- package/dist/test/client.applyMsg.spec.js.map +1 -1
- package/dist/test/client.attributionFarm.spec.d.ts.map +1 -1
- package/dist/test/client.attributionFarm.spec.js.map +1 -1
- package/dist/test/client.getPosition.spec.js +3 -2
- package/dist/test/client.getPosition.spec.js.map +1 -1
- package/dist/test/client.localReference.spec.js +6 -6
- package/dist/test/client.localReference.spec.js.map +1 -1
- package/dist/test/client.localReferenceFarm.spec.js.map +1 -1
- package/dist/test/client.rollback.spec.js.map +1 -1
- package/dist/test/dirname.cjs +0 -1
- package/dist/test/dirname.cjs.map +1 -1
- package/dist/test/index.d.ts +1 -1
- package/dist/test/index.d.ts.map +1 -1
- package/dist/test/index.js +2 -4
- package/dist/test/index.js.map +1 -1
- package/dist/test/mergeTree.annotate.spec.js +3 -0
- package/dist/test/mergeTree.annotate.spec.js.map +1 -1
- package/dist/test/mergeTree.insertingWalk.spec.js +1 -1
- package/dist/test/mergeTree.insertingWalk.spec.js.map +1 -1
- package/dist/test/mergeTree.markRangeRemoved.spec.js +2 -0
- package/dist/test/mergeTree.markRangeRemoved.spec.js.map +1 -1
- package/dist/test/mergeTree.walk.spec.js.map +1 -1
- package/dist/test/mergeTreeOperationRunner.d.ts.map +1 -1
- package/dist/test/mergeTreeOperationRunner.js +2 -3
- package/dist/test/mergeTreeOperationRunner.js.map +1 -1
- package/dist/test/obliterate.spec.js.map +1 -1
- package/dist/test/propertyManager.spec.js.map +1 -1
- package/dist/test/reconnectHelper.d.ts +2 -1
- package/dist/test/reconnectHelper.d.ts.map +1 -1
- package/dist/test/reconnectHelper.js.map +1 -1
- package/dist/test/resetPendingSegmentsToOp.spec.js.map +1 -1
- package/dist/test/revertibleFarm.spec.js.map +1 -1
- package/dist/test/segmentGroupCollection.spec.js +15 -3
- package/dist/test/segmentGroupCollection.spec.js.map +1 -1
- package/dist/test/snapshot.utils.d.ts +2 -2
- package/dist/test/snapshot.utils.d.ts.map +1 -1
- package/dist/test/snapshot.utils.js.map +1 -1
- package/dist/test/sortedSegmentSet.spec.js +4 -3
- package/dist/test/sortedSegmentSet.spec.js.map +1 -1
- package/dist/test/testClient.d.ts +8 -6
- package/dist/test/testClient.d.ts.map +1 -1
- package/dist/test/testClient.js +29 -27
- package/dist/test/testClient.js.map +1 -1
- package/dist/test/testClientLogger.d.ts.map +1 -1
- package/dist/test/testClientLogger.js +6 -4
- package/dist/test/testClientLogger.js.map +1 -1
- package/dist/test/testUtils.d.ts +2 -2
- package/dist/test/testUtils.d.ts.map +1 -1
- package/dist/test/testUtils.js +32 -8
- package/dist/test/testUtils.js.map +1 -1
- package/dist/test/text.d.ts +2 -2
- package/dist/test/text.d.ts.map +1 -1
- package/dist/test/text.js +12 -6
- package/dist/test/text.js.map +1 -1
- package/dist/test/tracking.spec.js.map +1 -1
- package/dist/test/wordUnitTests.spec.d.ts.map +1 -1
- package/dist/test/wordUnitTests.spec.js +4 -2
- package/dist/test/wordUnitTests.spec.js.map +1 -1
- package/dist/zamboni.d.ts.map +1 -1
- package/dist/zamboni.js +8 -7
- package/dist/zamboni.js.map +1 -1
- package/lib/MergeTreeTextHelper.d.ts.map +1 -1
- package/lib/MergeTreeTextHelper.js +0 -2
- package/lib/MergeTreeTextHelper.js.map +1 -1
- package/lib/attributionPolicy.d.ts.map +1 -1
- package/lib/attributionPolicy.js +6 -15
- package/lib/attributionPolicy.js.map +1 -1
- package/lib/client.d.ts +3 -4
- package/lib/client.d.ts.map +1 -1
- package/lib/client.js +40 -29
- package/lib/client.js.map +1 -1
- package/lib/endOfTreeSegment.d.ts +5 -4
- package/lib/endOfTreeSegment.d.ts.map +1 -1
- package/lib/endOfTreeSegment.js.map +1 -1
- package/lib/index.d.ts +2 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/legacy.d.ts +2 -1
- package/lib/localReference.d.ts +1 -0
- package/lib/localReference.d.ts.map +1 -1
- package/lib/localReference.js +1 -0
- package/lib/localReference.js.map +1 -1
- package/lib/mergeTree.d.ts +8 -7
- package/lib/mergeTree.d.ts.map +1 -1
- package/lib/mergeTree.js +192 -201
- package/lib/mergeTree.js.map +1 -1
- package/lib/mergeTreeNodeWalk.d.ts +5 -5
- package/lib/mergeTreeNodeWalk.d.ts.map +1 -1
- package/lib/mergeTreeNodeWalk.js +3 -2
- package/lib/mergeTreeNodeWalk.js.map +1 -1
- package/lib/mergeTreeNodes.d.ts +181 -159
- package/lib/mergeTreeNodes.d.ts.map +1 -1
- package/lib/mergeTreeNodes.js +115 -105
- package/lib/mergeTreeNodes.js.map +1 -1
- package/lib/mergeTreeTracking.d.ts.map +1 -1
- package/lib/mergeTreeTracking.js +0 -2
- package/lib/mergeTreeTracking.js.map +1 -1
- package/lib/partialLengths.d.ts +2 -2
- package/lib/partialLengths.d.ts.map +1 -1
- package/lib/partialLengths.js +30 -24
- package/lib/partialLengths.js.map +1 -1
- package/lib/perspective.d.ts +10 -9
- package/lib/perspective.d.ts.map +1 -1
- package/lib/perspective.js +11 -4
- package/lib/perspective.js.map +1 -1
- package/lib/referencePositions.d.ts.map +1 -1
- package/lib/referencePositions.js +4 -1
- package/lib/referencePositions.js.map +1 -1
- package/lib/revertibles.d.ts.map +1 -1
- package/lib/revertibles.js +11 -9
- package/lib/revertibles.js.map +1 -1
- package/lib/segmentGroupCollection.d.ts +4 -4
- package/lib/segmentGroupCollection.d.ts.map +1 -1
- package/lib/segmentGroupCollection.js +0 -6
- package/lib/segmentGroupCollection.js.map +1 -1
- package/lib/segmentInfos.d.ts +257 -0
- package/lib/segmentInfos.d.ts.map +1 -0
- package/lib/segmentInfos.js +145 -0
- package/lib/segmentInfos.js.map +1 -0
- package/lib/snapshotLoader.d.ts.map +1 -1
- package/lib/snapshotLoader.js +38 -44
- package/lib/snapshotLoader.js.map +1 -1
- package/lib/snapshotV1.d.ts.map +1 -1
- package/lib/snapshotV1.js +9 -12
- package/lib/snapshotV1.js.map +1 -1
- package/lib/snapshotlegacy.d.ts +2 -2
- package/lib/snapshotlegacy.d.ts.map +1 -1
- package/lib/snapshotlegacy.js +5 -3
- package/lib/snapshotlegacy.js.map +1 -1
- package/lib/sortedSegmentSet.d.ts +4 -4
- package/lib/sortedSegmentSet.d.ts.map +1 -1
- package/lib/sortedSegmentSet.js +5 -8
- package/lib/sortedSegmentSet.js.map +1 -1
- package/lib/test/beastTest.spec.d.ts +0 -2
- package/lib/test/beastTest.spec.d.ts.map +1 -1
- package/lib/test/beastTest.spec.js +0 -3
- package/lib/test/beastTest.spec.js.map +1 -1
- package/lib/test/client.annotateMarker.spec.js.map +1 -1
- package/lib/test/client.applyMsg.spec.js +15 -12
- package/lib/test/client.applyMsg.spec.js.map +1 -1
- package/lib/test/client.attributionFarm.spec.d.ts.map +1 -1
- package/lib/test/client.attributionFarm.spec.js.map +1 -1
- package/lib/test/client.getPosition.spec.js +3 -2
- package/lib/test/client.getPosition.spec.js.map +1 -1
- package/lib/test/client.localReference.spec.js +1 -1
- package/lib/test/client.localReference.spec.js.map +1 -1
- package/lib/test/client.localReferenceFarm.spec.js.map +1 -1
- package/lib/test/client.rollback.spec.js +1 -1
- package/lib/test/client.rollback.spec.js.map +1 -1
- package/lib/test/dirname.cjs +0 -1
- package/lib/test/dirname.cjs.map +1 -1
- package/lib/test/index.d.ts +1 -1
- package/lib/test/index.d.ts.map +1 -1
- package/lib/test/index.js +1 -1
- package/lib/test/index.js.map +1 -1
- package/lib/test/mergeTree.annotate.spec.js +3 -0
- package/lib/test/mergeTree.annotate.spec.js.map +1 -1
- package/lib/test/mergeTree.insertingWalk.spec.js +2 -2
- package/lib/test/mergeTree.insertingWalk.spec.js.map +1 -1
- package/lib/test/mergeTree.markRangeRemoved.spec.js +2 -0
- package/lib/test/mergeTree.markRangeRemoved.spec.js.map +1 -1
- package/lib/test/mergeTree.walk.spec.js.map +1 -1
- package/lib/test/mergeTreeOperationRunner.d.ts.map +1 -1
- package/lib/test/mergeTreeOperationRunner.js +1 -2
- package/lib/test/mergeTreeOperationRunner.js.map +1 -1
- package/lib/test/obliterate.spec.js.map +1 -1
- package/lib/test/propertyManager.spec.js.map +1 -1
- package/lib/test/reconnectHelper.d.ts +2 -1
- package/lib/test/reconnectHelper.d.ts.map +1 -1
- package/lib/test/reconnectHelper.js.map +1 -1
- package/lib/test/resetPendingSegmentsToOp.spec.js +1 -1
- package/lib/test/resetPendingSegmentsToOp.spec.js.map +1 -1
- package/lib/test/revertibleFarm.spec.js.map +1 -1
- package/lib/test/segmentGroupCollection.spec.js +15 -3
- package/lib/test/segmentGroupCollection.spec.js.map +1 -1
- package/lib/test/snapshot.utils.d.ts +2 -2
- package/lib/test/snapshot.utils.d.ts.map +1 -1
- package/lib/test/snapshot.utils.js.map +1 -1
- package/lib/test/sortedSegmentSet.spec.js +4 -3
- package/lib/test/sortedSegmentSet.spec.js.map +1 -1
- package/lib/test/testClient.d.ts +8 -6
- package/lib/test/testClient.d.ts.map +1 -1
- package/lib/test/testClient.js +30 -28
- package/lib/test/testClient.js.map +1 -1
- package/lib/test/testClientLogger.d.ts.map +1 -1
- package/lib/test/testClientLogger.js +5 -3
- package/lib/test/testClientLogger.js.map +1 -1
- package/lib/test/testUtils.d.ts +2 -2
- package/lib/test/testUtils.d.ts.map +1 -1
- package/lib/test/testUtils.js +9 -8
- package/lib/test/testUtils.js.map +1 -1
- package/lib/test/text.d.ts +2 -2
- package/lib/test/text.d.ts.map +1 -1
- package/lib/test/text.js +12 -6
- package/lib/test/text.js.map +1 -1
- package/lib/test/tracking.spec.js.map +1 -1
- package/lib/test/wordUnitTests.spec.d.ts.map +1 -1
- package/lib/test/wordUnitTests.spec.js +4 -2
- package/lib/test/wordUnitTests.spec.js.map +1 -1
- package/lib/zamboni.d.ts.map +1 -1
- package/lib/zamboni.js +7 -6
- package/lib/zamboni.js.map +1 -1
- package/package.json +18 -18
- package/src/MergeTreeTextHelper.ts +2 -4
- package/src/attributionPolicy.ts +5 -11
- package/src/client.ts +55 -44
- package/src/endOfTreeSegment.ts +7 -4
- package/src/index.ts +5 -6
- package/src/localReference.ts +1 -0
- package/src/mergeTree.ts +253 -271
- package/src/mergeTreeNodeWalk.ts +9 -8
- package/src/mergeTreeNodes.ts +300 -305
- package/src/mergeTreeTracking.ts +0 -3
- package/src/partialLengths.ts +44 -25
- package/src/perspective.ts +36 -13
- package/src/referencePositions.ts +4 -1
- package/src/revertibles.ts +20 -16
- package/src/segmentGroupCollection.ts +7 -18
- package/src/segmentInfos.ts +377 -0
- package/src/snapshotLoader.ts +60 -57
- package/src/snapshotV1.ts +14 -16
- package/src/snapshotlegacy.ts +12 -17
- package/src/sortedSegmentSet.ts +12 -15
- package/src/zamboni.ts +10 -12
package/src/mergeTree.ts
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
} from "./constants.js";
|
|
21
21
|
import { EndOfTreeSegment, StartOfTreeSegment } from "./endOfTreeSegment.js";
|
|
22
22
|
import {
|
|
23
|
+
// eslint-disable-next-line import/no-deprecated
|
|
23
24
|
LocalReferenceCollection,
|
|
24
25
|
LocalReferencePosition,
|
|
25
26
|
SlidingPreference,
|
|
@@ -42,27 +43,24 @@ import {
|
|
|
42
43
|
walkAllChildSegments,
|
|
43
44
|
} from "./mergeTreeNodeWalk.js";
|
|
44
45
|
import {
|
|
45
|
-
BlockAction,
|
|
46
|
-
// eslint-disable-next-line import/no-deprecated
|
|
47
46
|
CollaborationWindow,
|
|
48
47
|
IMergeNode,
|
|
49
|
-
IMoveInfo,
|
|
50
|
-
IRemovalInfo,
|
|
51
48
|
ISegmentAction,
|
|
52
49
|
ISegmentChanges,
|
|
53
|
-
ISegmentLeaf,
|
|
54
50
|
InsertContext,
|
|
55
51
|
Marker,
|
|
56
52
|
MaxNodesInBlock,
|
|
57
53
|
MergeBlock,
|
|
58
|
-
// eslint-disable-next-line import/no-deprecated
|
|
59
54
|
SegmentGroup,
|
|
55
|
+
assertSegmentLeaf,
|
|
56
|
+
assignChild,
|
|
57
|
+
isSegmentLeaf,
|
|
60
58
|
reservedMarkerIdKey,
|
|
61
59
|
seqLTE,
|
|
62
|
-
|
|
63
|
-
toRemovalInfo,
|
|
60
|
+
type IMergeNodeBuilder,
|
|
64
61
|
type ISegmentInternal,
|
|
65
|
-
|
|
62
|
+
type ISegmentLeaf,
|
|
63
|
+
type ISegmentPrivate,
|
|
66
64
|
type ObliterateInfo,
|
|
67
65
|
} from "./mergeTreeNodes.js";
|
|
68
66
|
import type { TrackingGroup } from "./mergeTreeTracking.js";
|
|
@@ -87,9 +85,24 @@ import {
|
|
|
87
85
|
refHasTileLabel,
|
|
88
86
|
refTypeIncludesFlag,
|
|
89
87
|
} from "./referencePositions.js";
|
|
90
|
-
// eslint-disable-next-line import/no-deprecated
|
|
91
88
|
import { SegmentGroupCollection } from "./segmentGroupCollection.js";
|
|
92
|
-
|
|
89
|
+
import {
|
|
90
|
+
assertMoved,
|
|
91
|
+
assertRemoved,
|
|
92
|
+
isMergeNodeInfo,
|
|
93
|
+
isMoved,
|
|
94
|
+
isRemoved,
|
|
95
|
+
overwriteInfo,
|
|
96
|
+
removeRemovalInfo,
|
|
97
|
+
toMoveInfo,
|
|
98
|
+
toRemovalInfo,
|
|
99
|
+
type IInsertionInfo,
|
|
100
|
+
// eslint-disable-next-line import/no-deprecated
|
|
101
|
+
type IMoveInfo,
|
|
102
|
+
// eslint-disable-next-line import/no-deprecated
|
|
103
|
+
type IRemovalInfo,
|
|
104
|
+
type SegmentWithInfo,
|
|
105
|
+
} from "./segmentInfos.js";
|
|
93
106
|
import {
|
|
94
107
|
copyPropertiesAndManager,
|
|
95
108
|
PropertiesManager,
|
|
@@ -100,34 +113,21 @@ import { Side, type InteriorSequencePlace } from "./sequencePlace.js";
|
|
|
100
113
|
import { SortedSegmentSet } from "./sortedSegmentSet.js";
|
|
101
114
|
import { zamboniSegments } from "./zamboni.js";
|
|
102
115
|
|
|
103
|
-
function
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
seg.movedSeq = moveInfo.movedSeq;
|
|
108
|
-
seg.localMovedSeq = moveInfo.localMovedSeq;
|
|
109
|
-
seg.wasMovedOnInsert = moveInfo.wasMovedOnInsert;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function isMoved(segment: ISegmentLeaf): segment is ISegmentLeaf & IMoveInfo {
|
|
113
|
-
return toMoveInfo(segment) !== undefined;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function isRemoved(segment: ISegmentLeaf): segment is ISegmentLeaf & IRemovalInfo {
|
|
117
|
-
return toRemovalInfo(segment) !== undefined;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function isRemovedAndAcked(segment: ISegmentLeaf): segment is ISegmentLeaf & IRemovalInfo {
|
|
116
|
+
function isRemovedAndAcked(
|
|
117
|
+
segment: ISegmentPrivate,
|
|
118
|
+
// eslint-disable-next-line import/no-deprecated
|
|
119
|
+
): segment is ISegmentLeaf & IRemovalInfo {
|
|
121
120
|
const removalInfo = toRemovalInfo(segment);
|
|
122
121
|
return removalInfo !== undefined && removalInfo.removedSeq !== UnassignedSequenceNumber;
|
|
123
122
|
}
|
|
124
123
|
|
|
125
|
-
|
|
124
|
+
// eslint-disable-next-line import/no-deprecated
|
|
125
|
+
function isMovedAndAcked(segment: ISegmentPrivate): segment is ISegmentLeaf & IMoveInfo {
|
|
126
126
|
const moveInfo = toMoveInfo(segment);
|
|
127
127
|
return moveInfo !== undefined && moveInfo.movedSeq !== UnassignedSequenceNumber;
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
-
function isRemovedAndAckedOrMovedAndAcked(segment:
|
|
130
|
+
function isRemovedAndAckedOrMovedAndAcked(segment: ISegmentPrivate): boolean {
|
|
131
131
|
return isRemovedAndAcked(segment) || isMovedAndAcked(segment);
|
|
132
132
|
}
|
|
133
133
|
|
|
@@ -180,11 +180,10 @@ function ackSegment(
|
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
case MergeTreeDeltaType.REMOVE: {
|
|
183
|
-
|
|
184
|
-
assert(removalInfo !== undefined, 0x046 /* "On remove ack, missing removal info!" */);
|
|
183
|
+
assertRemoved(segment);
|
|
185
184
|
segment.localRemovedSeq = undefined;
|
|
186
|
-
if (
|
|
187
|
-
|
|
185
|
+
if (segment.removedSeq === UnassignedSequenceNumber) {
|
|
186
|
+
segment.removedSeq = sequenceNumber;
|
|
188
187
|
return true;
|
|
189
188
|
}
|
|
190
189
|
return false;
|
|
@@ -192,17 +191,16 @@ function ackSegment(
|
|
|
192
191
|
|
|
193
192
|
case MergeTreeDeltaType.OBLITERATE:
|
|
194
193
|
case MergeTreeDeltaType.OBLITERATE_SIDED: {
|
|
195
|
-
|
|
196
|
-
assert(moveInfo !== undefined, 0x86e /* On obliterate ack, missing move info! */);
|
|
194
|
+
assertMoved(segment);
|
|
197
195
|
const obliterateInfo = segmentGroup.obliterateInfo;
|
|
198
196
|
assert(obliterateInfo !== undefined, 0xa40 /* must have obliterate info */);
|
|
199
197
|
segment.localMovedSeq = obliterateInfo.localSeq = undefined;
|
|
200
|
-
const seqIdx =
|
|
198
|
+
const seqIdx = segment.movedSeqs.indexOf(UnassignedSequenceNumber);
|
|
201
199
|
assert(seqIdx !== -1, 0x86f /* expected movedSeqs to contain unacked seq */);
|
|
202
|
-
|
|
200
|
+
segment.movedSeqs[seqIdx] = sequenceNumber;
|
|
203
201
|
|
|
204
|
-
if (
|
|
205
|
-
|
|
202
|
+
if (segment.movedSeq === UnassignedSequenceNumber) {
|
|
203
|
+
segment.movedSeq = sequenceNumber;
|
|
206
204
|
return true;
|
|
207
205
|
}
|
|
208
206
|
|
|
@@ -395,7 +393,6 @@ export function findRootMergeBlock(
|
|
|
395
393
|
* entries for all segments visited during excursion.
|
|
396
394
|
* This can reduce the number of times the tree needs to be scanned if a range containing many
|
|
397
395
|
* SlideOnRemove references is removed.
|
|
398
|
-
* @internal
|
|
399
396
|
*/
|
|
400
397
|
function getSlideToSegment(
|
|
401
398
|
segment: ISegmentLeaf | undefined,
|
|
@@ -424,7 +421,8 @@ function getSlideToSegment(
|
|
|
424
421
|
}
|
|
425
422
|
if (
|
|
426
423
|
cache !== undefined &&
|
|
427
|
-
(seg
|
|
424
|
+
(toRemovalInfo(seg)?.removedSeq === toRemovalInfo(segment)?.removedSeq ||
|
|
425
|
+
toMoveInfo(seg)?.movedSeq === toMoveInfo(segment)?.movedSeq)
|
|
428
426
|
) {
|
|
429
427
|
cache.set(seg, result);
|
|
430
428
|
}
|
|
@@ -482,7 +480,7 @@ export function getSlideToSegoff(
|
|
|
482
480
|
segment: ISegmentInternal | undefined;
|
|
483
481
|
offset: number | undefined;
|
|
484
482
|
} {
|
|
485
|
-
if (segoff.segment
|
|
483
|
+
if (!isSegmentLeaf(segoff.segment)) {
|
|
486
484
|
return segoff;
|
|
487
485
|
}
|
|
488
486
|
const [segment, _] = getSlideToSegment(
|
|
@@ -517,7 +515,7 @@ class Obliterates {
|
|
|
517
515
|
* See https://github.com/microsoft/FluidFramework/blob/main/packages/dds/merge-tree/docs/Obliterate.md#remote-perspective
|
|
518
516
|
* for additional context
|
|
519
517
|
*/
|
|
520
|
-
|
|
518
|
+
|
|
521
519
|
private readonly seqOrdered = new DoublyLinkedList<ObliterateInfo>();
|
|
522
520
|
|
|
523
521
|
/**
|
|
@@ -539,7 +537,6 @@ class Obliterates {
|
|
|
539
537
|
}
|
|
540
538
|
}
|
|
541
539
|
|
|
542
|
-
// eslint-disable-next-line import/no-deprecated
|
|
543
540
|
public addOrUpdate(obliterateInfo: ObliterateInfo): void {
|
|
544
541
|
const { seq, start } = obliterateInfo;
|
|
545
542
|
if (seq !== UnassignedSequenceNumber) {
|
|
@@ -552,14 +549,14 @@ class Obliterates {
|
|
|
552
549
|
return this.startOrdered.size === 0;
|
|
553
550
|
}
|
|
554
551
|
|
|
555
|
-
// eslint-disable-next-line import/no-deprecated
|
|
556
552
|
public findOverlapping(seg: ISegmentLeaf): Iterable<ObliterateInfo> {
|
|
557
|
-
// eslint-disable-next-line import/no-deprecated
|
|
558
553
|
const overlapping: ObliterateInfo[] = [];
|
|
559
554
|
for (const start of this.startOrdered.items) {
|
|
560
|
-
|
|
555
|
+
const startSeg = start.getSegment();
|
|
556
|
+
if (isMergeNodeInfo(startSeg) && startSeg.ordinal <= seg.ordinal) {
|
|
561
557
|
const ob = start.properties?.obliterate as ObliterateInfo;
|
|
562
|
-
|
|
558
|
+
const endSeg = ob.end.getSegment();
|
|
559
|
+
if (isMergeNodeInfo(endSeg) && endSeg.ordinal >= seg.ordinal) {
|
|
563
560
|
overlapping.push(ob);
|
|
564
561
|
}
|
|
565
562
|
} else {
|
|
@@ -583,10 +580,8 @@ export class MergeTree {
|
|
|
583
580
|
|
|
584
581
|
private static readonly theUnfinishedNode = { childCount: -1 } as unknown as MergeBlock;
|
|
585
582
|
|
|
586
|
-
// eslint-disable-next-line import/no-deprecated
|
|
587
583
|
public readonly collabWindow = new CollaborationWindow();
|
|
588
584
|
|
|
589
|
-
// eslint-disable-next-line import/no-deprecated
|
|
590
585
|
public readonly pendingSegments = new DoublyLinkedList<SegmentGroup>();
|
|
591
586
|
|
|
592
587
|
public readonly segmentsToScour = new Heap<LRUSegment>(LRUSegmentComparer);
|
|
@@ -665,7 +660,9 @@ export class MergeTree {
|
|
|
665
660
|
0x398 /* localSeq provided for local length without refSeq */,
|
|
666
661
|
);
|
|
667
662
|
assert(segment.seq !== undefined, 0x399 /* segment with no seq in mergeTree */);
|
|
668
|
-
const { seq
|
|
663
|
+
const { seq } = segment;
|
|
664
|
+
const { removedSeq, localRemovedSeq } = removalInfo ?? {};
|
|
665
|
+
const { movedSeq, localMovedSeq } = moveInfo ?? {};
|
|
669
666
|
if (seq === UnassignedSequenceNumber) {
|
|
670
667
|
assert(
|
|
671
668
|
segment.localSeq !== undefined,
|
|
@@ -707,13 +704,13 @@ export class MergeTree {
|
|
|
707
704
|
}
|
|
708
705
|
}
|
|
709
706
|
|
|
710
|
-
private addNode(block: MergeBlock, node:
|
|
707
|
+
private addNode(block: MergeBlock, node: IMergeNodeBuilder): number {
|
|
711
708
|
const index = block.childCount++;
|
|
712
|
-
|
|
709
|
+
assignChild(block, node, index, false);
|
|
713
710
|
return index;
|
|
714
711
|
}
|
|
715
712
|
|
|
716
|
-
public reloadFromSegments(segments:
|
|
713
|
+
public reloadFromSegments(segments: SegmentWithInfo<IInsertionInfo>[]): void {
|
|
717
714
|
// This code assumes that a later call to `startCollaboration()` will initialize partial lengths.
|
|
718
715
|
assert(
|
|
719
716
|
!this.collabWindow.collaborating,
|
|
@@ -723,7 +720,7 @@ export class MergeTree {
|
|
|
723
720
|
const maxChildren = MaxNodesInBlock - 1;
|
|
724
721
|
|
|
725
722
|
// Starting with the leaf segments, recursively builds the B-Tree layer by layer from the bottom up.
|
|
726
|
-
const buildMergeBlock = (nodes:
|
|
723
|
+
const buildMergeBlock = (nodes: IMergeNodeBuilder[]): IRootMergeBlock => {
|
|
727
724
|
const blockCount = Math.ceil(nodes.length / maxChildren); // Compute # blocks require for this level of B-Tree
|
|
728
725
|
const blocks: MergeBlock[] = Array.from({ length: blockCount }); // Pre-alloc array to collect nodes
|
|
729
726
|
|
|
@@ -779,8 +776,8 @@ export class MergeTree {
|
|
|
779
776
|
|
|
780
777
|
// TODO: 'seq' may be less than the current sequence number when inserting pre-ACKed
|
|
781
778
|
// segments from a snapshot. We currently skip these for now.
|
|
782
|
-
if (leaf.parent
|
|
783
|
-
leaf.parent
|
|
779
|
+
if (leaf.parent.needsScour !== true && seq > this.collabWindow.currentSeq) {
|
|
780
|
+
leaf.parent.needsScour = true;
|
|
784
781
|
this.segmentsToScour.add({ segment: leaf, maxSeq: seq });
|
|
785
782
|
}
|
|
786
783
|
}
|
|
@@ -824,34 +821,28 @@ export class MergeTree {
|
|
|
824
821
|
return totalOffset;
|
|
825
822
|
}
|
|
826
823
|
|
|
827
|
-
public getContainingSegment
|
|
824
|
+
public getContainingSegment(
|
|
828
825
|
pos: number,
|
|
829
826
|
refSeq: number,
|
|
830
827
|
clientId: number,
|
|
831
828
|
localSeq?: number,
|
|
832
829
|
): {
|
|
833
|
-
segment:
|
|
830
|
+
segment: ISegmentLeaf | undefined;
|
|
834
831
|
offset: number | undefined;
|
|
835
832
|
} {
|
|
836
833
|
assert(
|
|
837
834
|
localSeq === undefined || clientId === this.collabWindow.clientId,
|
|
838
835
|
0x39b /* localSeq provided for non-local client */,
|
|
839
836
|
);
|
|
840
|
-
let segment:
|
|
837
|
+
let segment: ISegmentLeaf | undefined;
|
|
841
838
|
let offset: number | undefined;
|
|
842
839
|
|
|
843
|
-
const leaf = (
|
|
844
|
-
leafSeg
|
|
845
|
-
segpos: number,
|
|
846
|
-
_refSeq: number,
|
|
847
|
-
_clientId: number,
|
|
848
|
-
start: number,
|
|
849
|
-
): boolean => {
|
|
850
|
-
segment = leafSeg as T;
|
|
840
|
+
const leaf = (leafSeg: ISegmentLeaf, _: number, start: number): boolean => {
|
|
841
|
+
segment = leafSeg;
|
|
851
842
|
offset = start;
|
|
852
843
|
return false;
|
|
853
844
|
};
|
|
854
|
-
this.nodeMap(refSeq, clientId, leaf, undefined,
|
|
845
|
+
this.nodeMap(refSeq, clientId, leaf, undefined, pos, pos + 1, localSeq);
|
|
855
846
|
return { segment, offset };
|
|
856
847
|
}
|
|
857
848
|
|
|
@@ -877,7 +868,9 @@ export class MergeTree {
|
|
|
877
868
|
*/
|
|
878
869
|
private slideAckedRemovedSegmentReferences(segments: ISegmentLeaf[]): void {
|
|
879
870
|
// References are slid in groups to preserve their order.
|
|
871
|
+
// eslint-disable-next-line import/no-deprecated
|
|
880
872
|
let currentForwardSlideGroup: LocalReferenceCollection[] = [];
|
|
873
|
+
// eslint-disable-next-line import/no-deprecated
|
|
881
874
|
let currentBackwardSlideGroup: LocalReferenceCollection[] = [];
|
|
882
875
|
|
|
883
876
|
let currentForwardMaybeEndpoint: "start" | "end" | undefined;
|
|
@@ -891,6 +884,7 @@ export class MergeTree {
|
|
|
891
884
|
const slideGroup = (
|
|
892
885
|
currentSlideDestination: ISegmentLeaf | undefined,
|
|
893
886
|
currentSlideIsForward: boolean | undefined,
|
|
887
|
+
// eslint-disable-next-line import/no-deprecated
|
|
894
888
|
currentSlideGroup: LocalReferenceCollection[],
|
|
895
889
|
pred: (ref: LocalReferencePosition) => boolean,
|
|
896
890
|
maybeEndpoint: "start" | "end" | undefined,
|
|
@@ -915,6 +909,7 @@ export class MergeTree {
|
|
|
915
909
|
|
|
916
910
|
if (maybeEndpoint) {
|
|
917
911
|
const endpoint = maybeEndpoint === "start" ? this.startOfTree : this.endOfTree;
|
|
912
|
+
// eslint-disable-next-line import/no-deprecated
|
|
918
913
|
const localRefs = LocalReferenceCollection.setOrGet(endpoint);
|
|
919
914
|
if (currentSlideIsForward) {
|
|
920
915
|
localRefs.addBeforeTombstones(...endpointRefsToAdd);
|
|
@@ -934,6 +929,7 @@ export class MergeTree {
|
|
|
934
929
|
}
|
|
935
930
|
}
|
|
936
931
|
} else {
|
|
932
|
+
// eslint-disable-next-line import/no-deprecated
|
|
937
933
|
const localRefs = LocalReferenceCollection.setOrGet(currentSlideDestination);
|
|
938
934
|
if (currentSlideIsForward) {
|
|
939
935
|
localRefs.addBeforeTombstones(...nonEndpointRefsToAdd);
|
|
@@ -947,11 +943,13 @@ export class MergeTree {
|
|
|
947
943
|
segment: ISegmentLeaf,
|
|
948
944
|
currentSlideDestination: ISegmentLeaf | undefined,
|
|
949
945
|
currentSlideIsForward: boolean | undefined,
|
|
946
|
+
// eslint-disable-next-line import/no-deprecated
|
|
950
947
|
currentSlideGroup: LocalReferenceCollection[],
|
|
951
948
|
pred: (ref: LocalReferencePosition) => boolean,
|
|
952
949
|
slidingPreference: SlidingPreference,
|
|
953
950
|
currentMaybeEndpoint: "start" | "end" | undefined,
|
|
954
951
|
reassign: (
|
|
952
|
+
// eslint-disable-next-line import/no-deprecated
|
|
955
953
|
localRefs: LocalReferenceCollection,
|
|
956
954
|
slideToSegment: ISegmentLeaf | undefined,
|
|
957
955
|
slideIsForward: boolean,
|
|
@@ -1074,7 +1072,6 @@ export class MergeTree {
|
|
|
1074
1072
|
return;
|
|
1075
1073
|
}
|
|
1076
1074
|
|
|
1077
|
-
// eslint-disable-next-line import/no-deprecated
|
|
1078
1075
|
const rebaseCollabWindow = new CollaborationWindow();
|
|
1079
1076
|
rebaseCollabWindow.loadFrom(this.collabWindow);
|
|
1080
1077
|
if (refSeq < this.collabWindow.minSeq) {
|
|
@@ -1197,13 +1194,13 @@ export class MergeTree {
|
|
|
1197
1194
|
clientId = this.collabWindow.clientId,
|
|
1198
1195
|
localSeq: number | undefined = this.collabWindow.localSeq,
|
|
1199
1196
|
): number {
|
|
1200
|
-
const seg
|
|
1201
|
-
if (seg
|
|
1197
|
+
const seg = refPos.getSegment();
|
|
1198
|
+
if (!isSegmentLeaf(seg)) {
|
|
1202
1199
|
// We have no idea where this reference is, because it refers to a segment which is not in the tree.
|
|
1203
1200
|
return DetachedReferencePosition;
|
|
1204
1201
|
}
|
|
1205
1202
|
if (refPos.isLeaf()) {
|
|
1206
|
-
return this.getPosition(
|
|
1203
|
+
return this.getPosition(seg, refSeq, clientId, localSeq);
|
|
1207
1204
|
}
|
|
1208
1205
|
if (refTypeIncludesFlag(refPos, ReferenceType.Transient) || seg.localRefs?.has(refPos)) {
|
|
1209
1206
|
if (
|
|
@@ -1212,13 +1209,15 @@ export class MergeTree {
|
|
|
1212
1209
|
!isSegmentPresent(seg, { refSeq, localSeq })
|
|
1213
1210
|
) {
|
|
1214
1211
|
const forward = refPos.slidingPreference === SlidingPreference.FORWARD;
|
|
1212
|
+
const moveInfo = toMoveInfo(seg);
|
|
1213
|
+
const removeInfo = toRemovalInfo(seg);
|
|
1215
1214
|
const slideSeq =
|
|
1216
|
-
|
|
1217
|
-
?
|
|
1218
|
-
:
|
|
1219
|
-
?
|
|
1215
|
+
moveInfo !== undefined && moveInfo.movedSeq !== UnassignedSequenceNumber
|
|
1216
|
+
? moveInfo.movedSeq
|
|
1217
|
+
: removeInfo !== undefined && removeInfo.removedSeq !== UnassignedSequenceNumber
|
|
1218
|
+
? removeInfo.removedSeq
|
|
1220
1219
|
: refSeq;
|
|
1221
|
-
const slideLocalSeq =
|
|
1220
|
+
const slideLocalSeq = moveInfo?.localMovedSeq ?? removeInfo?.localRemovedSeq;
|
|
1222
1221
|
const perspective = new PerspectiveImpl(this, {
|
|
1223
1222
|
refSeq: slideSeq,
|
|
1224
1223
|
localSeq: slideLocalSeq,
|
|
@@ -1255,14 +1254,13 @@ export class MergeTree {
|
|
|
1255
1254
|
let foundMarker: Marker | undefined;
|
|
1256
1255
|
|
|
1257
1256
|
const { segment } = this.getContainingSegment(startPos, UniversalSequenceNumber, clientId);
|
|
1258
|
-
|
|
1259
|
-
if (segWithParent?.parent === undefined) {
|
|
1257
|
+
if (!isSegmentLeaf(segment)) {
|
|
1260
1258
|
return undefined;
|
|
1261
1259
|
}
|
|
1262
1260
|
|
|
1263
1261
|
depthFirstNodeWalk(
|
|
1264
|
-
|
|
1265
|
-
|
|
1262
|
+
segment.parent,
|
|
1263
|
+
segment,
|
|
1266
1264
|
(node) => {
|
|
1267
1265
|
if (node.isLeaf()) {
|
|
1268
1266
|
if (Marker.is(node) && refHasTileLabel(node, markerLabel)) {
|
|
@@ -1293,8 +1291,8 @@ export class MergeTree {
|
|
|
1293
1291
|
private updateRoot(splitNode: MergeBlock | undefined): void {
|
|
1294
1292
|
if (splitNode !== undefined) {
|
|
1295
1293
|
const newRoot = this.makeBlock(2);
|
|
1296
|
-
|
|
1297
|
-
|
|
1294
|
+
assignChild(newRoot, this.root, 0, false);
|
|
1295
|
+
assignChild(newRoot, splitNode, 1, false);
|
|
1298
1296
|
this.root = newRoot;
|
|
1299
1297
|
this.nodeUpdateOrdinals(this.root);
|
|
1300
1298
|
this.nodeUpdateLengthNewStructure(this.root);
|
|
@@ -1322,8 +1320,8 @@ export class MergeTree {
|
|
|
1322
1320
|
if (MergeTree.options.zamboniSegments) {
|
|
1323
1321
|
this.addToLRUSet(pendingSegment, seq);
|
|
1324
1322
|
}
|
|
1325
|
-
if (!nodesToUpdate.includes(pendingSegment.parent
|
|
1326
|
-
nodesToUpdate.push(pendingSegment.parent
|
|
1323
|
+
if (!nodesToUpdate.includes(pendingSegment.parent)) {
|
|
1324
|
+
nodesToUpdate.push(pendingSegment.parent);
|
|
1327
1325
|
}
|
|
1328
1326
|
deltaSegments.push({
|
|
1329
1327
|
segment: pendingSegment,
|
|
@@ -1364,11 +1362,10 @@ export class MergeTree {
|
|
|
1364
1362
|
|
|
1365
1363
|
private addToPendingList(
|
|
1366
1364
|
segment: ISegmentLeaf,
|
|
1367
|
-
|
|
1365
|
+
|
|
1368
1366
|
segmentGroup?: SegmentGroup,
|
|
1369
1367
|
localSeq?: number,
|
|
1370
1368
|
previousProps?: PropertySet,
|
|
1371
|
-
// eslint-disable-next-line import/no-deprecated
|
|
1372
1369
|
): SegmentGroup {
|
|
1373
1370
|
let _segmentGroup = segmentGroup;
|
|
1374
1371
|
if (_segmentGroup === undefined) {
|
|
@@ -1392,7 +1389,7 @@ export class MergeTree {
|
|
|
1392
1389
|
if (previousProps) {
|
|
1393
1390
|
_segmentGroup.previousProps!.push(previousProps);
|
|
1394
1391
|
}
|
|
1395
|
-
|
|
1392
|
+
|
|
1396
1393
|
const segmentGroups = (segment.segmentGroups ??= new SegmentGroupCollection(segment));
|
|
1397
1394
|
segmentGroups.enqueue(_segmentGroup);
|
|
1398
1395
|
return _segmentGroup;
|
|
@@ -1425,7 +1422,7 @@ export class MergeTree {
|
|
|
1425
1422
|
if (relativePos.id) {
|
|
1426
1423
|
marker = this.getMarkerFromId(relativePos.id);
|
|
1427
1424
|
}
|
|
1428
|
-
if (marker) {
|
|
1425
|
+
if (isSegmentLeaf(marker)) {
|
|
1429
1426
|
pos = this.getPosition(marker, refseq, clientId);
|
|
1430
1427
|
if (relativePos.before) {
|
|
1431
1428
|
if (relativePos.offset !== undefined) {
|
|
@@ -1443,7 +1440,7 @@ export class MergeTree {
|
|
|
1443
1440
|
|
|
1444
1441
|
public insertSegments(
|
|
1445
1442
|
pos: number,
|
|
1446
|
-
segments:
|
|
1443
|
+
segments: ISegmentPrivate[],
|
|
1447
1444
|
refSeq: number,
|
|
1448
1445
|
clientId: number,
|
|
1449
1446
|
seq: number,
|
|
@@ -1510,7 +1507,7 @@ export class MergeTree {
|
|
|
1510
1507
|
|
|
1511
1508
|
const { currentSeq, clientId } = this.collabWindow;
|
|
1512
1509
|
|
|
1513
|
-
if (segmentInfo?.segment) {
|
|
1510
|
+
if (isSegmentLeaf(segmentInfo?.segment)) {
|
|
1514
1511
|
const segmentPosition = this.getPosition(segmentInfo.segment, currentSeq, clientId);
|
|
1515
1512
|
return segmentPosition + segmentInfo.offset!;
|
|
1516
1513
|
} else {
|
|
@@ -1520,7 +1517,7 @@ export class MergeTree {
|
|
|
1520
1517
|
}
|
|
1521
1518
|
}
|
|
1522
1519
|
|
|
1523
|
-
private blockInsert<T extends
|
|
1520
|
+
private blockInsert<T extends ISegmentPrivate>(
|
|
1524
1521
|
pos: number,
|
|
1525
1522
|
refSeq: number,
|
|
1526
1523
|
clientId: number,
|
|
@@ -1538,7 +1535,7 @@ export class MergeTree {
|
|
|
1538
1535
|
});
|
|
1539
1536
|
return siblingExists;
|
|
1540
1537
|
};
|
|
1541
|
-
|
|
1538
|
+
|
|
1542
1539
|
let segmentGroup: SegmentGroup;
|
|
1543
1540
|
const saveIfLocal = (locSegment: ISegmentLeaf): void => {
|
|
1544
1541
|
// Save segment so we can assign sequence number when acked by server
|
|
@@ -1553,10 +1550,10 @@ export class MergeTree {
|
|
|
1553
1550
|
// In all other cases this has to be true (checked by addToLRUSet):
|
|
1554
1551
|
// locSegment.seq > this.collabWindow.currentSeq
|
|
1555
1552
|
else if (
|
|
1556
|
-
locSegment.seq
|
|
1553
|
+
locSegment.seq > this.collabWindow.minSeq &&
|
|
1557
1554
|
MergeTree.options.zamboniSegments
|
|
1558
1555
|
) {
|
|
1559
|
-
this.addToLRUSet(locSegment, locSegment.seq
|
|
1556
|
+
this.addToLRUSet(locSegment, locSegment.seq);
|
|
1560
1557
|
}
|
|
1561
1558
|
}
|
|
1562
1559
|
};
|
|
@@ -1565,6 +1562,7 @@ export class MergeTree {
|
|
|
1565
1562
|
_pos: number,
|
|
1566
1563
|
context: InsertContext,
|
|
1567
1564
|
// Keeping this function within the scope of blockInsert for readability.
|
|
1565
|
+
// eslint-disable-next-line unicorn/consistent-function-scoping
|
|
1568
1566
|
): ISegmentChanges => {
|
|
1569
1567
|
const segmentChanges: ISegmentChanges = {};
|
|
1570
1568
|
if (segment) {
|
|
@@ -1577,106 +1575,109 @@ export class MergeTree {
|
|
|
1577
1575
|
return segmentChanges;
|
|
1578
1576
|
};
|
|
1579
1577
|
|
|
1578
|
+
const insertInfo: IInsertionInfo = {
|
|
1579
|
+
clientId,
|
|
1580
|
+
seq,
|
|
1581
|
+
localSeq,
|
|
1582
|
+
};
|
|
1580
1583
|
// TODO: build tree from segs and insert all at once
|
|
1581
1584
|
let insertPos = pos;
|
|
1582
|
-
for (const newSegment of newSegments
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
if (
|
|
1588
|
-
|
|
1589
|
-
if (markerId) {
|
|
1590
|
-
this.idToMarker.set(markerId, newSegment);
|
|
1591
|
-
}
|
|
1585
|
+
for (const newSegment of newSegments
|
|
1586
|
+
.filter((s) => s.cachedLength > 0)
|
|
1587
|
+
.map((s) => overwriteInfo(s, insertInfo))) {
|
|
1588
|
+
if (Marker.is(newSegment)) {
|
|
1589
|
+
const markerId = newSegment.getId();
|
|
1590
|
+
if (markerId) {
|
|
1591
|
+
this.idToMarker.set(markerId, newSegment);
|
|
1592
1592
|
}
|
|
1593
|
+
}
|
|
1593
1594
|
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1595
|
+
const splitNode = this.insertingWalk(this.root, insertPos, refSeq, clientId, seq, {
|
|
1596
|
+
leaf: onLeaf,
|
|
1597
|
+
candidateSegment: newSegment,
|
|
1598
|
+
continuePredicate: continueFrom,
|
|
1599
|
+
});
|
|
1599
1600
|
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1601
|
+
if (!isSegmentLeaf(newSegment)) {
|
|
1602
|
+
// Indicates an attempt to insert past the end of the merge-tree's content.
|
|
1603
|
+
const errorConstructor = localSeq === undefined ? DataProcessingError : UsageError;
|
|
1604
|
+
throw new errorConstructor("MergeTree insert failed", {
|
|
1605
|
+
currentSeq: this.collabWindow.currentSeq,
|
|
1606
|
+
minSeq: this.collabWindow.minSeq,
|
|
1607
|
+
segSeq: insertInfo.seq,
|
|
1608
|
+
});
|
|
1609
|
+
}
|
|
1609
1610
|
|
|
1610
|
-
|
|
1611
|
+
this.updateRoot(splitNode);
|
|
1611
1612
|
|
|
1612
|
-
|
|
1613
|
+
insertPos += newSegment.cachedLength;
|
|
1613
1614
|
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1615
|
+
if (!this.options?.mergeTreeEnableObliterate || this.obliterates.empty()) {
|
|
1616
|
+
saveIfLocal(newSegment);
|
|
1617
|
+
continue;
|
|
1618
|
+
}
|
|
1618
1619
|
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
}
|
|
1620
|
+
let oldest: ObliterateInfo | undefined;
|
|
1621
|
+
let normalizedOldestSeq: number = 0;
|
|
1622
|
+
let newest: ObliterateInfo | undefined;
|
|
1623
|
+
let normalizedNewestSeq: number = 0;
|
|
1624
|
+
const movedClientIds: number[] = [];
|
|
1625
|
+
const movedSeqs: number[] = [];
|
|
1626
|
+
for (const ob of this.obliterates.findOverlapping(newSegment)) {
|
|
1627
|
+
// compute a normalized seq that takes into account local seqs
|
|
1628
|
+
// but is still comparable to remote seqs to keep the checks below easy
|
|
1629
|
+
// REMOTE SEQUENCE NUMBERS LOCAL SEQUENCE NUMBERS
|
|
1630
|
+
// [0, 1, 2, 3, ..., 100, ..., 1000, ..., (MAX - MaxLocalSeq), L1, L2, L3, L4, ..., L100, ..., L1000, ...(MAX)]
|
|
1631
|
+
const normalizedObSeq =
|
|
1632
|
+
ob.seq === UnassignedSequenceNumber
|
|
1633
|
+
? Number.MAX_SAFE_INTEGER - this.collabWindow.localSeq + ob.localSeq!
|
|
1634
|
+
: ob.seq;
|
|
1635
|
+
if (normalizedObSeq > refSeq) {
|
|
1636
|
+
if (oldest === undefined || normalizedOldestSeq > normalizedObSeq) {
|
|
1637
|
+
normalizedOldestSeq = normalizedObSeq;
|
|
1638
|
+
oldest = ob;
|
|
1639
|
+
movedClientIds.unshift(ob.clientId);
|
|
1640
|
+
movedSeqs.unshift(ob.seq);
|
|
1641
|
+
} else {
|
|
1642
|
+
movedClientIds.push(ob.clientId);
|
|
1643
|
+
movedSeqs.push(ob.seq);
|
|
1644
|
+
}
|
|
1645
|
+
if (newest === undefined || normalizedNewestSeq < normalizedObSeq) {
|
|
1646
|
+
normalizedNewestSeq = normalizedObSeq;
|
|
1647
|
+
newest = ob;
|
|
1648
1648
|
}
|
|
1649
1649
|
}
|
|
1650
|
+
}
|
|
1650
1651
|
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
markSegmentMoved(newSegment, moveInfo);
|
|
1652
|
+
if (oldest && newest?.clientId !== clientId) {
|
|
1653
|
+
// eslint-disable-next-line import/no-deprecated
|
|
1654
|
+
const moveInfo: IMoveInfo = {
|
|
1655
|
+
movedClientIds,
|
|
1656
|
+
movedSeq: oldest.seq,
|
|
1657
|
+
movedSeqs,
|
|
1658
|
+
localMovedSeq: oldest.localSeq,
|
|
1659
|
+
wasMovedOnInsert: oldest.seq !== UnassignedSequenceNumber,
|
|
1660
|
+
};
|
|
1661
1661
|
|
|
1662
|
-
|
|
1663
|
-
assert(
|
|
1664
|
-
oldest.segmentGroup !== undefined,
|
|
1665
|
-
0x86c /* expected segment group to exist */,
|
|
1666
|
-
);
|
|
1662
|
+
overwriteInfo(newSegment, moveInfo);
|
|
1667
1663
|
|
|
1668
|
-
|
|
1669
|
-
|
|
1664
|
+
if (moveInfo.localMovedSeq !== undefined) {
|
|
1665
|
+
assert(
|
|
1666
|
+
oldest.segmentGroup !== undefined,
|
|
1667
|
+
0x86c /* expected segment group to exist */,
|
|
1668
|
+
);
|
|
1670
1669
|
|
|
1671
|
-
|
|
1672
|
-
this.blockUpdatePathLengths(newSegment.parent, seq, clientId);
|
|
1673
|
-
}
|
|
1674
|
-
} else if (oldest && newest?.clientId === clientId) {
|
|
1675
|
-
newSegment.prevObliterateByInserter = newest;
|
|
1670
|
+
this.addToPendingList(newSegment, oldest.segmentGroup);
|
|
1676
1671
|
}
|
|
1677
1672
|
|
|
1678
|
-
|
|
1673
|
+
if (newSegment.parent) {
|
|
1674
|
+
this.blockUpdatePathLengths(newSegment.parent, seq, clientId);
|
|
1675
|
+
}
|
|
1676
|
+
} else if (oldest && newest?.clientId === clientId) {
|
|
1677
|
+
newSegment.prevObliterateByInserter = newest;
|
|
1679
1678
|
}
|
|
1679
|
+
|
|
1680
|
+
saveIfLocal(newSegment);
|
|
1680
1681
|
}
|
|
1681
1682
|
}
|
|
1682
1683
|
|
|
@@ -1688,7 +1689,8 @@ export class MergeTree {
|
|
|
1688
1689
|
return {};
|
|
1689
1690
|
}
|
|
1690
1691
|
|
|
1691
|
-
const next
|
|
1692
|
+
const next = segment.splitAt(pos)!;
|
|
1693
|
+
assertSegmentLeaf(next);
|
|
1692
1694
|
|
|
1693
1695
|
if (segment?.segmentGroups) {
|
|
1694
1696
|
next.segmentGroups ??= new SegmentGroupCollection(next);
|
|
@@ -1744,10 +1746,8 @@ export class MergeTree {
|
|
|
1744
1746
|
|
|
1745
1747
|
return (
|
|
1746
1748
|
newSeq > segSeq ||
|
|
1747
|
-
(node.movedSeq !==
|
|
1748
|
-
|
|
1749
|
-
node.movedSeq > seq) ||
|
|
1750
|
-
(node.removedSeq !== undefined &&
|
|
1749
|
+
(isMoved(node) && node.movedSeq !== UnassignedSequenceNumber && node.movedSeq > seq) ||
|
|
1750
|
+
(isRemoved(node) &&
|
|
1751
1751
|
node.removedSeq !== UnassignedSequenceNumber &&
|
|
1752
1752
|
node.removedSeq > seq)
|
|
1753
1753
|
);
|
|
@@ -1770,7 +1770,7 @@ export class MergeTree {
|
|
|
1770
1770
|
const children = block.children;
|
|
1771
1771
|
let childIndex: number;
|
|
1772
1772
|
let child: IMergeNode;
|
|
1773
|
-
let newNode:
|
|
1773
|
+
let newNode: IMergeNodeBuilder | undefined;
|
|
1774
1774
|
let fromSplit: MergeBlock | undefined;
|
|
1775
1775
|
for (childIndex = 0; childIndex < block.childCount; childIndex++) {
|
|
1776
1776
|
child = children[childIndex];
|
|
@@ -1794,7 +1794,7 @@ export class MergeTree {
|
|
|
1794
1794
|
const segment = child;
|
|
1795
1795
|
const segmentChanges = context.leaf(segment, _pos, context);
|
|
1796
1796
|
if (segmentChanges.replaceCurrent) {
|
|
1797
|
-
|
|
1797
|
+
assignChild(block, segmentChanges.replaceCurrent, childIndex, false);
|
|
1798
1798
|
segmentChanges.replaceCurrent.ordinal = child.ordinal;
|
|
1799
1799
|
}
|
|
1800
1800
|
if (segmentChanges.next) {
|
|
@@ -1847,7 +1847,7 @@ export class MergeTree {
|
|
|
1847
1847
|
block.children[i] = block.children[i - 1];
|
|
1848
1848
|
block.children[i].index = i;
|
|
1849
1849
|
}
|
|
1850
|
-
|
|
1850
|
+
assignChild(block, newNode, childIndex, false);
|
|
1851
1851
|
block.childCount++;
|
|
1852
1852
|
block.setOrdinal(newNode, childIndex);
|
|
1853
1853
|
if (block.childCount < MaxNodesInBlock) {
|
|
@@ -1882,7 +1882,7 @@ export class MergeTree {
|
|
|
1882
1882
|
// Update ordinals to reflect lowered child count
|
|
1883
1883
|
this.nodeUpdateOrdinals(node);
|
|
1884
1884
|
for (let i = 0; i < halfCount; i++) {
|
|
1885
|
-
|
|
1885
|
+
assignChild(newNode, node.children[halfCount + i], i, false);
|
|
1886
1886
|
node.children[halfCount + i] = undefined!;
|
|
1887
1887
|
}
|
|
1888
1888
|
this.nodeUpdateLengthNewStructure(node);
|
|
@@ -1919,7 +1919,7 @@ export class MergeTree {
|
|
|
1919
1919
|
clientId: number,
|
|
1920
1920
|
seq: number,
|
|
1921
1921
|
opArgs: IMergeTreeDeltaOpArgs,
|
|
1922
|
-
|
|
1922
|
+
|
|
1923
1923
|
rollback: PropertiesRollback = PropertiesRollback.None,
|
|
1924
1924
|
): void {
|
|
1925
1925
|
if (propsOrAdjust.adjust !== undefined) {
|
|
@@ -1931,7 +1931,7 @@ export class MergeTree {
|
|
|
1931
1931
|
const deltaSegments: IMergeTreeSegmentDelta[] = [];
|
|
1932
1932
|
const localSeq =
|
|
1933
1933
|
seq === UnassignedSequenceNumber ? ++this.collabWindow.localSeq : undefined;
|
|
1934
|
-
|
|
1934
|
+
|
|
1935
1935
|
let segmentGroup: SegmentGroup | undefined;
|
|
1936
1936
|
const opObj = propsOrAdjust.props ?? propsOrAdjust.adjust;
|
|
1937
1937
|
const annotateSegment = (segment: ISegmentLeaf): boolean => {
|
|
@@ -1972,7 +1972,7 @@ export class MergeTree {
|
|
|
1972
1972
|
return true;
|
|
1973
1973
|
};
|
|
1974
1974
|
|
|
1975
|
-
this.nodeMap(refSeq, clientId, annotateSegment, undefined,
|
|
1975
|
+
this.nodeMap(refSeq, clientId, annotateSegment, undefined, start, end);
|
|
1976
1976
|
|
|
1977
1977
|
// OpArgs == undefined => test code
|
|
1978
1978
|
if (deltaSegments.length > 0) {
|
|
@@ -2006,10 +2006,11 @@ export class MergeTree {
|
|
|
2006
2006
|
|
|
2007
2007
|
let _overwrite = false;
|
|
2008
2008
|
const localOverlapWithRefs: ISegmentLeaf[] = [];
|
|
2009
|
-
|
|
2009
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2010
|
+
const movedSegments: SegmentWithInfo<IMoveInfo, ISegmentLeaf>[] = [];
|
|
2010
2011
|
const localSeq =
|
|
2011
2012
|
seq === UnassignedSequenceNumber ? ++this.collabWindow.localSeq : undefined;
|
|
2012
|
-
|
|
2013
|
+
|
|
2013
2014
|
const obliterate: ObliterateInfo = {
|
|
2014
2015
|
clientId,
|
|
2015
2016
|
end: createDetachedLocalReferencePosition(undefined),
|
|
@@ -2023,7 +2024,7 @@ export class MergeTree {
|
|
|
2023
2024
|
const { segment: startSeg } = this.getContainingSegment(start.pos, refSeq, clientId);
|
|
2024
2025
|
const { segment: endSeg } = this.getContainingSegment(end.pos, refSeq, clientId);
|
|
2025
2026
|
assert(
|
|
2026
|
-
startSeg
|
|
2027
|
+
isSegmentLeaf(startSeg) && isSegmentLeaf(endSeg),
|
|
2027
2028
|
0xa3f /* segments cannot be undefined */,
|
|
2028
2029
|
);
|
|
2029
2030
|
|
|
@@ -2060,12 +2061,7 @@ export class MergeTree {
|
|
|
2060
2061
|
}
|
|
2061
2062
|
this.obliterates.addOrUpdate(obliterate);
|
|
2062
2063
|
|
|
2063
|
-
const markMoved = (
|
|
2064
|
-
segment: ISegmentLeaf,
|
|
2065
|
-
pos: number,
|
|
2066
|
-
_start: number,
|
|
2067
|
-
_end: number,
|
|
2068
|
-
): boolean => {
|
|
2064
|
+
const markMoved = (segment: ISegmentLeaf, pos: number): boolean => {
|
|
2069
2065
|
if (
|
|
2070
2066
|
(start.side === Side.After && startPos === pos + segment.cachedLength) || // exclusive start segment
|
|
2071
2067
|
(end.side === Side.Before &&
|
|
@@ -2085,26 +2081,29 @@ export class MergeTree {
|
|
|
2085
2081
|
return true;
|
|
2086
2082
|
}
|
|
2087
2083
|
|
|
2088
|
-
|
|
2084
|
+
const wasMovedOnInsert =
|
|
2089
2085
|
clientId !== segment.clientId &&
|
|
2090
2086
|
segment.seq !== undefined &&
|
|
2091
2087
|
seq !== UnassignedSequenceNumber &&
|
|
2092
|
-
(refSeq < segment.seq || segment.seq === UnassignedSequenceNumber)
|
|
2093
|
-
) {
|
|
2094
|
-
segment.wasMovedOnInsert = true;
|
|
2095
|
-
}
|
|
2088
|
+
(refSeq < segment.seq || segment.seq === UnassignedSequenceNumber);
|
|
2096
2089
|
|
|
2097
2090
|
if (existingMoveInfo === undefined) {
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2091
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2092
|
+
const movedSeg = overwriteInfo<IMoveInfo, ISegmentLeaf>(segment, {
|
|
2093
|
+
movedClientIds: [clientId],
|
|
2094
|
+
movedSeq: seq,
|
|
2095
|
+
localMovedSeq: localSeq,
|
|
2096
|
+
movedSeqs: [seq],
|
|
2097
|
+
wasMovedOnInsert,
|
|
2098
|
+
});
|
|
2102
2099
|
|
|
2103
|
-
if (!toRemovalInfo(
|
|
2104
|
-
movedSegments.push(
|
|
2100
|
+
if (!toRemovalInfo(movedSeg)) {
|
|
2101
|
+
movedSegments.push(movedSeg);
|
|
2105
2102
|
}
|
|
2106
2103
|
} else {
|
|
2107
2104
|
_overwrite = true;
|
|
2105
|
+
// never move wasMovedOnInsert from true to false
|
|
2106
|
+
existingMoveInfo.wasMovedOnInsert ||= wasMovedOnInsert;
|
|
2108
2107
|
if (existingMoveInfo.movedSeq === UnassignedSequenceNumber) {
|
|
2109
2108
|
// we moved this locally, but someone else moved it first
|
|
2110
2109
|
// so put them at the head of the list
|
|
@@ -2123,7 +2122,7 @@ export class MergeTree {
|
|
|
2123
2122
|
existingMoveInfo.movedSeqs.push(seq);
|
|
2124
2123
|
}
|
|
2125
2124
|
}
|
|
2126
|
-
|
|
2125
|
+
assertMoved(segment);
|
|
2127
2126
|
// Save segment so can assign moved sequence number when acked by server
|
|
2128
2127
|
if (this.collabWindow.collaborating) {
|
|
2129
2128
|
if (
|
|
@@ -2144,12 +2143,7 @@ export class MergeTree {
|
|
|
2144
2143
|
return true;
|
|
2145
2144
|
};
|
|
2146
2145
|
|
|
2147
|
-
const afterMarkMoved = (
|
|
2148
|
-
node: MergeBlock,
|
|
2149
|
-
pos: number,
|
|
2150
|
-
_start: number,
|
|
2151
|
-
_end: number,
|
|
2152
|
-
): boolean => {
|
|
2146
|
+
const afterMarkMoved = (node: MergeBlock): boolean => {
|
|
2153
2147
|
if (_overwrite) {
|
|
2154
2148
|
this.nodeUpdateLengthNewStructure(node);
|
|
2155
2149
|
} else {
|
|
@@ -2162,7 +2156,6 @@ export class MergeTree {
|
|
|
2162
2156
|
refSeq,
|
|
2163
2157
|
clientId,
|
|
2164
2158
|
markMoved,
|
|
2165
|
-
undefined,
|
|
2166
2159
|
afterMarkMoved,
|
|
2167
2160
|
start.pos,
|
|
2168
2161
|
end.pos + 1, // include the segment containing the end reference
|
|
@@ -2175,7 +2168,7 @@ export class MergeTree {
|
|
|
2175
2168
|
if (start.pos !== end.pos || start.side !== end.side) {
|
|
2176
2169
|
this.mergeTreeDeltaCallback?.(opArgs, {
|
|
2177
2170
|
operation: MergeTreeDeltaType.OBLITERATE,
|
|
2178
|
-
deltaSegments: movedSegments,
|
|
2171
|
+
deltaSegments: movedSegments.map((segment) => ({ segment })),
|
|
2179
2172
|
});
|
|
2180
2173
|
}
|
|
2181
2174
|
|
|
@@ -2183,7 +2176,7 @@ export class MergeTree {
|
|
|
2183
2176
|
// so we slide after eventing in case the consumer wants to make reference
|
|
2184
2177
|
// changes at remove time, like add a ref to track undo redo.
|
|
2185
2178
|
if (!this.collabWindow.collaborating || clientId !== this.collabWindow.clientId) {
|
|
2186
|
-
this.slideAckedRemovedSegmentReferences(movedSegments
|
|
2179
|
+
this.slideAckedRemovedSegmentReferences(movedSegments);
|
|
2187
2180
|
}
|
|
2188
2181
|
|
|
2189
2182
|
if (
|
|
@@ -2237,9 +2230,10 @@ export class MergeTree {
|
|
|
2237
2230
|
let _overwrite = false;
|
|
2238
2231
|
this.ensureIntervalBoundary(start, refSeq, clientId);
|
|
2239
2232
|
this.ensureIntervalBoundary(end, refSeq, clientId);
|
|
2240
|
-
|
|
2233
|
+
|
|
2241
2234
|
let segmentGroup: SegmentGroup;
|
|
2242
|
-
|
|
2235
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2236
|
+
const removedSegments: SegmentWithInfo<IRemovalInfo, ISegmentLeaf>[] = [];
|
|
2243
2237
|
const localOverlapWithRefs: ISegmentLeaf[] = [];
|
|
2244
2238
|
const localSeq =
|
|
2245
2239
|
seq === UnassignedSequenceNumber ? ++this.collabWindow.localSeq : undefined;
|
|
@@ -2252,12 +2246,15 @@ export class MergeTree {
|
|
|
2252
2246
|
const existingRemovalInfo = toRemovalInfo(segment);
|
|
2253
2247
|
|
|
2254
2248
|
if (existingRemovalInfo === undefined) {
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2249
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2250
|
+
const removed = overwriteInfo<IRemovalInfo, ISegmentLeaf>(segment, {
|
|
2251
|
+
removedClientIds: [clientId],
|
|
2252
|
+
removedSeq: seq,
|
|
2253
|
+
localRemovedSeq: localSeq,
|
|
2254
|
+
});
|
|
2258
2255
|
|
|
2259
|
-
if (!toMoveInfo(
|
|
2260
|
-
removedSegments.push(
|
|
2256
|
+
if (!toMoveInfo(removed)) {
|
|
2257
|
+
removedSegments.push(removed);
|
|
2261
2258
|
}
|
|
2262
2259
|
} else {
|
|
2263
2260
|
_overwrite = true;
|
|
@@ -2277,7 +2274,7 @@ export class MergeTree {
|
|
|
2277
2274
|
existingRemovalInfo.removedClientIds.push(clientId);
|
|
2278
2275
|
}
|
|
2279
2276
|
}
|
|
2280
|
-
|
|
2277
|
+
assertRemoved(segment);
|
|
2281
2278
|
// Save segment so we can assign removed sequence number when acked by server
|
|
2282
2279
|
if (this.collabWindow.collaborating) {
|
|
2283
2280
|
if (
|
|
@@ -2293,12 +2290,7 @@ export class MergeTree {
|
|
|
2293
2290
|
}
|
|
2294
2291
|
return true;
|
|
2295
2292
|
};
|
|
2296
|
-
const afterMarkRemoved = (
|
|
2297
|
-
node: MergeBlock,
|
|
2298
|
-
pos: number,
|
|
2299
|
-
_start: number,
|
|
2300
|
-
_end: number,
|
|
2301
|
-
): boolean => {
|
|
2293
|
+
const afterMarkRemoved = (node: MergeBlock): boolean => {
|
|
2302
2294
|
if (_overwrite) {
|
|
2303
2295
|
this.nodeUpdateLengthNewStructure(node);
|
|
2304
2296
|
} else {
|
|
@@ -2306,7 +2298,7 @@ export class MergeTree {
|
|
|
2306
2298
|
}
|
|
2307
2299
|
return true;
|
|
2308
2300
|
};
|
|
2309
|
-
this.nodeMap(refSeq, clientId, markRemoved,
|
|
2301
|
+
this.nodeMap(refSeq, clientId, markRemoved, afterMarkRemoved, start, end);
|
|
2310
2302
|
// these segments are already viewed as being removed locally and are not event-ed
|
|
2311
2303
|
// so can slide non-StayOnRemove refs immediately
|
|
2312
2304
|
this.slideAckedRemovedSegmentReferences(localOverlapWithRefs);
|
|
@@ -2314,14 +2306,14 @@ export class MergeTree {
|
|
|
2314
2306
|
if (removedSegments.length > 0) {
|
|
2315
2307
|
this.mergeTreeDeltaCallback?.(opArgs, {
|
|
2316
2308
|
operation: MergeTreeDeltaType.REMOVE,
|
|
2317
|
-
deltaSegments: removedSegments,
|
|
2309
|
+
deltaSegments: removedSegments.map((segment) => ({ segment })),
|
|
2318
2310
|
});
|
|
2319
2311
|
}
|
|
2320
2312
|
// these events are newly removed
|
|
2321
2313
|
// so we slide after eventing in case the consumer wants to make reference
|
|
2322
2314
|
// changes at remove time, like add a ref to track undo redo.
|
|
2323
2315
|
if (!this.collabWindow.collaborating || clientId !== this.collabWindow.clientId) {
|
|
2324
|
-
this.slideAckedRemovedSegmentReferences(removedSegments
|
|
2316
|
+
this.slideAckedRemovedSegmentReferences(removedSegments);
|
|
2325
2317
|
}
|
|
2326
2318
|
|
|
2327
2319
|
if (
|
|
@@ -2336,36 +2328,30 @@ export class MergeTree {
|
|
|
2336
2328
|
/**
|
|
2337
2329
|
* Revert an unacked local op
|
|
2338
2330
|
*/
|
|
2339
|
-
|
|
2331
|
+
|
|
2340
2332
|
public rollback(op: IMergeTreeDeltaOp, localOpMetadata: SegmentGroup): void {
|
|
2341
2333
|
if (op.type === MergeTreeDeltaType.REMOVE) {
|
|
2342
|
-
const pendingSegmentGroup = this.pendingSegments.pop
|
|
2334
|
+
const pendingSegmentGroup = this.pendingSegments.pop()?.data;
|
|
2343
2335
|
if (pendingSegmentGroup === undefined || pendingSegmentGroup !== localOpMetadata) {
|
|
2344
2336
|
throw new Error("Rollback op doesn't match last edit");
|
|
2345
2337
|
}
|
|
2346
2338
|
// Disabling because a for of loop causes the type of segment to be ISegmentLeaf, which does not have parent information stored
|
|
2347
2339
|
// eslint-disable-next-line unicorn/no-array-for-each
|
|
2348
2340
|
pendingSegmentGroup.segments.forEach((segment: ISegmentLeaf) => {
|
|
2349
|
-
const segmentSegmentGroup = segment?.segmentGroups?.pop
|
|
2341
|
+
const segmentSegmentGroup = segment?.segmentGroups?.pop();
|
|
2350
2342
|
assert(
|
|
2351
2343
|
segmentSegmentGroup === pendingSegmentGroup,
|
|
2352
2344
|
0x3ee /* Unexpected segmentGroup in segment */,
|
|
2353
2345
|
);
|
|
2354
2346
|
|
|
2355
2347
|
assert(
|
|
2356
|
-
segment.removedClientIds
|
|
2357
|
-
segment.removedClientIds[0] === this.collabWindow.clientId,
|
|
2348
|
+
isRemoved(segment) && segment.removedClientIds[0] === this.collabWindow.clientId,
|
|
2358
2349
|
0x39d /* Rollback segment removedClientId does not match local client */,
|
|
2359
2350
|
);
|
|
2360
|
-
|
|
2361
|
-
segment
|
|
2362
|
-
segment.localRemovedSeq = undefined;
|
|
2351
|
+
let updateNode: MergeBlock | undefined = segment.parent;
|
|
2352
|
+
removeRemovalInfo(segment);
|
|
2363
2353
|
|
|
2364
|
-
for (
|
|
2365
|
-
let updateNode = segment.parent;
|
|
2366
|
-
updateNode !== undefined;
|
|
2367
|
-
updateNode = updateNode.parent
|
|
2368
|
-
) {
|
|
2354
|
+
for (updateNode; updateNode !== undefined; updateNode = updateNode.parent) {
|
|
2369
2355
|
this.blockUpdateLength(
|
|
2370
2356
|
updateNode,
|
|
2371
2357
|
UnassignedSequenceNumber,
|
|
@@ -2387,7 +2373,7 @@ export class MergeTree {
|
|
|
2387
2373
|
op.type === MergeTreeDeltaType.INSERT ||
|
|
2388
2374
|
op.type === MergeTreeDeltaType.ANNOTATE
|
|
2389
2375
|
) {
|
|
2390
|
-
const pendingSegmentGroup = this.pendingSegments.pop
|
|
2376
|
+
const pendingSegmentGroup = this.pendingSegments.pop()?.data;
|
|
2391
2377
|
if (
|
|
2392
2378
|
pendingSegmentGroup === undefined ||
|
|
2393
2379
|
pendingSegmentGroup !== localOpMetadata ||
|
|
@@ -2396,8 +2382,8 @@ export class MergeTree {
|
|
|
2396
2382
|
throw new Error("Rollback op doesn't match last edit");
|
|
2397
2383
|
}
|
|
2398
2384
|
let i = 0;
|
|
2399
|
-
for (const segment of pendingSegmentGroup.segments
|
|
2400
|
-
const segmentSegmentGroup = segment?.segmentGroups?.pop
|
|
2385
|
+
for (const segment of pendingSegmentGroup.segments) {
|
|
2386
|
+
const segmentSegmentGroup = segment?.segmentGroups?.pop();
|
|
2401
2387
|
assert(
|
|
2402
2388
|
segmentSegmentGroup === pendingSegmentGroup,
|
|
2403
2389
|
0x3ef /* Unexpected segmentGroup in segment */,
|
|
@@ -2449,7 +2435,7 @@ export class MergeTree {
|
|
|
2449
2435
|
}
|
|
2450
2436
|
|
|
2451
2437
|
// If not removed, increase position
|
|
2452
|
-
if (seg
|
|
2438
|
+
if (!isRemoved(seg)) {
|
|
2453
2439
|
segmentPosition += seg.cachedLength;
|
|
2454
2440
|
}
|
|
2455
2441
|
|
|
@@ -2470,7 +2456,7 @@ export class MergeTree {
|
|
|
2470
2456
|
public removeLocalReferencePosition(
|
|
2471
2457
|
lref: LocalReferencePosition,
|
|
2472
2458
|
): LocalReferencePosition | undefined {
|
|
2473
|
-
const segment:
|
|
2459
|
+
const segment: ISegmentPrivate | undefined = lref.getSegment();
|
|
2474
2460
|
return segment?.localRefs?.removeLocalRef(lref);
|
|
2475
2461
|
}
|
|
2476
2462
|
|
|
@@ -2478,7 +2464,7 @@ export class MergeTree {
|
|
|
2478
2464
|
endOfTree = new EndOfTreeSegment(this);
|
|
2479
2465
|
|
|
2480
2466
|
public createLocalReferencePosition(
|
|
2481
|
-
_segment:
|
|
2467
|
+
_segment: ISegmentPrivate | "start" | "end",
|
|
2482
2468
|
offset: number,
|
|
2483
2469
|
refType: ReferenceType,
|
|
2484
2470
|
properties: PropertySet | undefined,
|
|
@@ -2499,7 +2485,6 @@ export class MergeTree {
|
|
|
2499
2485
|
"Can only create SlideOnRemove or Transient local reference position on a removed or obliterated segment",
|
|
2500
2486
|
);
|
|
2501
2487
|
}
|
|
2502
|
-
|
|
2503
2488
|
let segment: ISegmentLeaf;
|
|
2504
2489
|
|
|
2505
2490
|
if (_segment === "start") {
|
|
@@ -2507,9 +2492,11 @@ export class MergeTree {
|
|
|
2507
2492
|
} else if (_segment === "end") {
|
|
2508
2493
|
segment = this.endOfTree;
|
|
2509
2494
|
} else {
|
|
2495
|
+
assertSegmentLeaf(_segment);
|
|
2510
2496
|
segment = _segment;
|
|
2511
2497
|
}
|
|
2512
2498
|
|
|
2499
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2513
2500
|
const localRefs = LocalReferenceCollection.setOrGet(segment);
|
|
2514
2501
|
|
|
2515
2502
|
const segRef = localRefs.createLocalRef(
|
|
@@ -2594,7 +2581,7 @@ export class MergeTree {
|
|
|
2594
2581
|
for (let i = 0; i < newOrder.length; i++) {
|
|
2595
2582
|
const seg = newOrder[i];
|
|
2596
2583
|
const { parent, index, ordinal } = currentOrder[i];
|
|
2597
|
-
|
|
2584
|
+
assignChild(parent, seg, index, false);
|
|
2598
2585
|
seg.ordinal = ordinal;
|
|
2599
2586
|
}
|
|
2600
2587
|
|
|
@@ -2792,8 +2779,7 @@ export class MergeTree {
|
|
|
2792
2779
|
this.nodeMap(
|
|
2793
2780
|
refSeq,
|
|
2794
2781
|
clientId,
|
|
2795
|
-
handler,
|
|
2796
|
-
accum,
|
|
2782
|
+
(seg, pos, _start, _end) => handler(seg, pos, refSeq, clientId, _start, _end, accum),
|
|
2797
2783
|
undefined,
|
|
2798
2784
|
start,
|
|
2799
2785
|
end,
|
|
@@ -2825,12 +2811,11 @@ export class MergeTree {
|
|
|
2825
2811
|
* but it will not count as a segment within the range. That is, it will be
|
|
2826
2812
|
* ignored for the purposes of tracking when traversal should end.
|
|
2827
2813
|
*/
|
|
2828
|
-
private nodeMap
|
|
2814
|
+
private nodeMap(
|
|
2829
2815
|
refSeq: number,
|
|
2830
2816
|
clientId: number,
|
|
2831
|
-
leaf:
|
|
2832
|
-
|
|
2833
|
-
post?: BlockAction<TClientData>,
|
|
2817
|
+
leaf: (segment: ISegmentLeaf, pos: number, start: number, end: number) => boolean,
|
|
2818
|
+
post?: (block: MergeBlock) => boolean,
|
|
2834
2819
|
start: number = 0,
|
|
2835
2820
|
end?: number,
|
|
2836
2821
|
localSeq?: number,
|
|
@@ -2876,17 +2861,14 @@ export class MergeTree {
|
|
|
2876
2861
|
}
|
|
2877
2862
|
|
|
2878
2863
|
if (node.isLeaf()) {
|
|
2879
|
-
if (leaf(node, pos,
|
|
2864
|
+
if (leaf(node, pos, start - pos, endPos - pos) === false) {
|
|
2880
2865
|
return NodeAction.Exit;
|
|
2881
2866
|
}
|
|
2882
2867
|
pos = nextPos;
|
|
2883
2868
|
}
|
|
2884
2869
|
},
|
|
2885
2870
|
undefined,
|
|
2886
|
-
post
|
|
2887
|
-
? undefined
|
|
2888
|
-
: (block): boolean =>
|
|
2889
|
-
post(block, pos, refSeq, clientId, start - pos, endPos - pos, accum),
|
|
2871
|
+
post,
|
|
2890
2872
|
);
|
|
2891
2873
|
}
|
|
2892
2874
|
}
|