@fluidframework/merge-tree 2.12.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 +4 -0
- 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 -16
- 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 +2 -1
- 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 +2 -4
- package/dist/index.js.map +1 -1
- package/dist/mergeTree.d.ts +8 -7
- package/dist/mergeTree.d.ts.map +1 -1
- package/dist/mergeTree.js +190 -216
- package/dist/mergeTree.js.map +1 -1
- 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 +76 -162
- package/dist/mergeTreeNodes.d.ts.map +1 -1
- package/dist/mergeTreeNodes.js +100 -112
- 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 +28 -26
- package/dist/partialLengths.js.map +1 -1
- package/dist/perspective.d.ts +3 -2
- 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 +10 -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.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.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.js +1 -1
- 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 -16
- 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 +2 -1
- 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/mergeTree.d.ts +8 -7
- package/lib/mergeTree.d.ts.map +1 -1
- package/lib/mergeTree.js +177 -205
- package/lib/mergeTree.js.map +1 -1
- 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 +76 -162
- package/lib/mergeTreeNodes.d.ts.map +1 -1
- package/lib/mergeTreeNodes.js +95 -108
- 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 +25 -23
- package/lib/partialLengths.js.map +1 -1
- package/lib/perspective.d.ts +3 -2
- 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 +8 -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.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.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.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.js +1 -1
- 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 +17 -17
- package/src/MergeTreeTextHelper.ts +2 -4
- package/src/attributionPolicy.ts +5 -13
- package/src/client.ts +55 -44
- package/src/endOfTreeSegment.ts +3 -3
- package/src/index.ts +4 -6
- package/src/mergeTree.ts +245 -282
- package/src/mergeTreeNodeWalk.ts +3 -2
- package/src/mergeTreeNodes.ts +190 -322
- package/src/mergeTreeTracking.ts +0 -3
- package/src/partialLengths.ts +42 -27
- package/src/perspective.ts +27 -4
- package/src/referencePositions.ts +4 -1
- package/src/revertibles.ts +19 -13
- 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 +6 -8
- package/src/zamboni.ts +10 -12
package/src/mergeTree.ts
CHANGED
|
@@ -43,29 +43,24 @@ import {
|
|
|
43
43
|
walkAllChildSegments,
|
|
44
44
|
} from "./mergeTreeNodeWalk.js";
|
|
45
45
|
import {
|
|
46
|
-
BlockAction,
|
|
47
|
-
// eslint-disable-next-line import/no-deprecated
|
|
48
46
|
CollaborationWindow,
|
|
49
47
|
IMergeNode,
|
|
50
|
-
// eslint-disable-next-line import/no-deprecated
|
|
51
|
-
IMoveInfo,
|
|
52
|
-
// eslint-disable-next-line import/no-deprecated
|
|
53
|
-
IRemovalInfo,
|
|
54
48
|
ISegmentAction,
|
|
55
49
|
ISegmentChanges,
|
|
56
|
-
ISegmentLeaf,
|
|
57
50
|
InsertContext,
|
|
58
51
|
Marker,
|
|
59
52
|
MaxNodesInBlock,
|
|
60
53
|
MergeBlock,
|
|
61
|
-
// eslint-disable-next-line import/no-deprecated
|
|
62
54
|
SegmentGroup,
|
|
55
|
+
assertSegmentLeaf,
|
|
56
|
+
assignChild,
|
|
57
|
+
isSegmentLeaf,
|
|
63
58
|
reservedMarkerIdKey,
|
|
64
59
|
seqLTE,
|
|
65
|
-
|
|
66
|
-
toRemovalInfo,
|
|
60
|
+
type IMergeNodeBuilder,
|
|
67
61
|
type ISegmentInternal,
|
|
68
|
-
|
|
62
|
+
type ISegmentLeaf,
|
|
63
|
+
type ISegmentPrivate,
|
|
69
64
|
type ObliterateInfo,
|
|
70
65
|
} from "./mergeTreeNodes.js";
|
|
71
66
|
import type { TrackingGroup } from "./mergeTreeTracking.js";
|
|
@@ -90,9 +85,24 @@ import {
|
|
|
90
85
|
refHasTileLabel,
|
|
91
86
|
refTypeIncludesFlag,
|
|
92
87
|
} from "./referencePositions.js";
|
|
93
|
-
// eslint-disable-next-line import/no-deprecated
|
|
94
88
|
import { SegmentGroupCollection } from "./segmentGroupCollection.js";
|
|
95
|
-
|
|
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";
|
|
96
106
|
import {
|
|
97
107
|
copyPropertiesAndManager,
|
|
98
108
|
PropertiesManager,
|
|
@@ -103,39 +113,21 @@ import { Side, type InteriorSequencePlace } from "./sequencePlace.js";
|
|
|
103
113
|
import { SortedSegmentSet } from "./sortedSegmentSet.js";
|
|
104
114
|
import { zamboniSegments } from "./zamboni.js";
|
|
105
115
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
seg.movedSeqs = [moveInfo.movedSeq];
|
|
111
|
-
seg.movedSeq = moveInfo.movedSeq;
|
|
112
|
-
seg.localMovedSeq = moveInfo.localMovedSeq;
|
|
113
|
-
seg.wasMovedOnInsert = moveInfo.wasMovedOnInsert;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// eslint-disable-next-line import/no-deprecated
|
|
117
|
-
function isMoved(segment: ISegmentLeaf): segment is ISegmentLeaf & IMoveInfo {
|
|
118
|
-
return toMoveInfo(segment) !== undefined;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// eslint-disable-next-line import/no-deprecated
|
|
122
|
-
function isRemoved(segment: ISegmentLeaf): segment is ISegmentLeaf & IRemovalInfo {
|
|
123
|
-
return toRemovalInfo(segment) !== undefined;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// eslint-disable-next-line import/no-deprecated
|
|
127
|
-
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 {
|
|
128
120
|
const removalInfo = toRemovalInfo(segment);
|
|
129
121
|
return removalInfo !== undefined && removalInfo.removedSeq !== UnassignedSequenceNumber;
|
|
130
122
|
}
|
|
131
123
|
|
|
132
124
|
// eslint-disable-next-line import/no-deprecated
|
|
133
|
-
function isMovedAndAcked(segment:
|
|
125
|
+
function isMovedAndAcked(segment: ISegmentPrivate): segment is ISegmentLeaf & IMoveInfo {
|
|
134
126
|
const moveInfo = toMoveInfo(segment);
|
|
135
127
|
return moveInfo !== undefined && moveInfo.movedSeq !== UnassignedSequenceNumber;
|
|
136
128
|
}
|
|
137
129
|
|
|
138
|
-
function isRemovedAndAckedOrMovedAndAcked(segment:
|
|
130
|
+
function isRemovedAndAckedOrMovedAndAcked(segment: ISegmentPrivate): boolean {
|
|
139
131
|
return isRemovedAndAcked(segment) || isMovedAndAcked(segment);
|
|
140
132
|
}
|
|
141
133
|
|
|
@@ -188,12 +180,10 @@ function ackSegment(
|
|
|
188
180
|
}
|
|
189
181
|
|
|
190
182
|
case MergeTreeDeltaType.REMOVE: {
|
|
191
|
-
|
|
192
|
-
const removalInfo: IRemovalInfo | undefined = toRemovalInfo(segment);
|
|
193
|
-
assert(removalInfo !== undefined, 0x046 /* "On remove ack, missing removal info!" */);
|
|
183
|
+
assertRemoved(segment);
|
|
194
184
|
segment.localRemovedSeq = undefined;
|
|
195
|
-
if (
|
|
196
|
-
|
|
185
|
+
if (segment.removedSeq === UnassignedSequenceNumber) {
|
|
186
|
+
segment.removedSeq = sequenceNumber;
|
|
197
187
|
return true;
|
|
198
188
|
}
|
|
199
189
|
return false;
|
|
@@ -201,18 +191,16 @@ function ackSegment(
|
|
|
201
191
|
|
|
202
192
|
case MergeTreeDeltaType.OBLITERATE:
|
|
203
193
|
case MergeTreeDeltaType.OBLITERATE_SIDED: {
|
|
204
|
-
|
|
205
|
-
const moveInfo: IMoveInfo | undefined = toMoveInfo(segment);
|
|
206
|
-
assert(moveInfo !== undefined, 0x86e /* On obliterate ack, missing move info! */);
|
|
194
|
+
assertMoved(segment);
|
|
207
195
|
const obliterateInfo = segmentGroup.obliterateInfo;
|
|
208
196
|
assert(obliterateInfo !== undefined, 0xa40 /* must have obliterate info */);
|
|
209
197
|
segment.localMovedSeq = obliterateInfo.localSeq = undefined;
|
|
210
|
-
const seqIdx =
|
|
198
|
+
const seqIdx = segment.movedSeqs.indexOf(UnassignedSequenceNumber);
|
|
211
199
|
assert(seqIdx !== -1, 0x86f /* expected movedSeqs to contain unacked seq */);
|
|
212
|
-
|
|
200
|
+
segment.movedSeqs[seqIdx] = sequenceNumber;
|
|
213
201
|
|
|
214
|
-
if (
|
|
215
|
-
|
|
202
|
+
if (segment.movedSeq === UnassignedSequenceNumber) {
|
|
203
|
+
segment.movedSeq = sequenceNumber;
|
|
216
204
|
return true;
|
|
217
205
|
}
|
|
218
206
|
|
|
@@ -405,7 +393,6 @@ export function findRootMergeBlock(
|
|
|
405
393
|
* entries for all segments visited during excursion.
|
|
406
394
|
* This can reduce the number of times the tree needs to be scanned if a range containing many
|
|
407
395
|
* SlideOnRemove references is removed.
|
|
408
|
-
* @internal
|
|
409
396
|
*/
|
|
410
397
|
function getSlideToSegment(
|
|
411
398
|
segment: ISegmentLeaf | undefined,
|
|
@@ -434,7 +421,8 @@ function getSlideToSegment(
|
|
|
434
421
|
}
|
|
435
422
|
if (
|
|
436
423
|
cache !== undefined &&
|
|
437
|
-
(seg
|
|
424
|
+
(toRemovalInfo(seg)?.removedSeq === toRemovalInfo(segment)?.removedSeq ||
|
|
425
|
+
toMoveInfo(seg)?.movedSeq === toMoveInfo(segment)?.movedSeq)
|
|
438
426
|
) {
|
|
439
427
|
cache.set(seg, result);
|
|
440
428
|
}
|
|
@@ -492,7 +480,7 @@ export function getSlideToSegoff(
|
|
|
492
480
|
segment: ISegmentInternal | undefined;
|
|
493
481
|
offset: number | undefined;
|
|
494
482
|
} {
|
|
495
|
-
if (segoff.segment
|
|
483
|
+
if (!isSegmentLeaf(segoff.segment)) {
|
|
496
484
|
return segoff;
|
|
497
485
|
}
|
|
498
486
|
const [segment, _] = getSlideToSegment(
|
|
@@ -527,7 +515,7 @@ class Obliterates {
|
|
|
527
515
|
* See https://github.com/microsoft/FluidFramework/blob/main/packages/dds/merge-tree/docs/Obliterate.md#remote-perspective
|
|
528
516
|
* for additional context
|
|
529
517
|
*/
|
|
530
|
-
|
|
518
|
+
|
|
531
519
|
private readonly seqOrdered = new DoublyLinkedList<ObliterateInfo>();
|
|
532
520
|
|
|
533
521
|
/**
|
|
@@ -549,7 +537,6 @@ class Obliterates {
|
|
|
549
537
|
}
|
|
550
538
|
}
|
|
551
539
|
|
|
552
|
-
// eslint-disable-next-line import/no-deprecated
|
|
553
540
|
public addOrUpdate(obliterateInfo: ObliterateInfo): void {
|
|
554
541
|
const { seq, start } = obliterateInfo;
|
|
555
542
|
if (seq !== UnassignedSequenceNumber) {
|
|
@@ -562,14 +549,14 @@ class Obliterates {
|
|
|
562
549
|
return this.startOrdered.size === 0;
|
|
563
550
|
}
|
|
564
551
|
|
|
565
|
-
// eslint-disable-next-line import/no-deprecated
|
|
566
552
|
public findOverlapping(seg: ISegmentLeaf): Iterable<ObliterateInfo> {
|
|
567
|
-
// eslint-disable-next-line import/no-deprecated
|
|
568
553
|
const overlapping: ObliterateInfo[] = [];
|
|
569
554
|
for (const start of this.startOrdered.items) {
|
|
570
|
-
|
|
555
|
+
const startSeg = start.getSegment();
|
|
556
|
+
if (isMergeNodeInfo(startSeg) && startSeg.ordinal <= seg.ordinal) {
|
|
571
557
|
const ob = start.properties?.obliterate as ObliterateInfo;
|
|
572
|
-
|
|
558
|
+
const endSeg = ob.end.getSegment();
|
|
559
|
+
if (isMergeNodeInfo(endSeg) && endSeg.ordinal >= seg.ordinal) {
|
|
573
560
|
overlapping.push(ob);
|
|
574
561
|
}
|
|
575
562
|
} else {
|
|
@@ -593,10 +580,8 @@ export class MergeTree {
|
|
|
593
580
|
|
|
594
581
|
private static readonly theUnfinishedNode = { childCount: -1 } as unknown as MergeBlock;
|
|
595
582
|
|
|
596
|
-
// eslint-disable-next-line import/no-deprecated
|
|
597
583
|
public readonly collabWindow = new CollaborationWindow();
|
|
598
584
|
|
|
599
|
-
// eslint-disable-next-line import/no-deprecated
|
|
600
585
|
public readonly pendingSegments = new DoublyLinkedList<SegmentGroup>();
|
|
601
586
|
|
|
602
587
|
public readonly segmentsToScour = new Heap<LRUSegment>(LRUSegmentComparer);
|
|
@@ -675,7 +660,9 @@ export class MergeTree {
|
|
|
675
660
|
0x398 /* localSeq provided for local length without refSeq */,
|
|
676
661
|
);
|
|
677
662
|
assert(segment.seq !== undefined, 0x399 /* segment with no seq in mergeTree */);
|
|
678
|
-
const { seq
|
|
663
|
+
const { seq } = segment;
|
|
664
|
+
const { removedSeq, localRemovedSeq } = removalInfo ?? {};
|
|
665
|
+
const { movedSeq, localMovedSeq } = moveInfo ?? {};
|
|
679
666
|
if (seq === UnassignedSequenceNumber) {
|
|
680
667
|
assert(
|
|
681
668
|
segment.localSeq !== undefined,
|
|
@@ -717,13 +704,13 @@ export class MergeTree {
|
|
|
717
704
|
}
|
|
718
705
|
}
|
|
719
706
|
|
|
720
|
-
private addNode(block: MergeBlock, node:
|
|
707
|
+
private addNode(block: MergeBlock, node: IMergeNodeBuilder): number {
|
|
721
708
|
const index = block.childCount++;
|
|
722
|
-
|
|
709
|
+
assignChild(block, node, index, false);
|
|
723
710
|
return index;
|
|
724
711
|
}
|
|
725
712
|
|
|
726
|
-
public reloadFromSegments(segments:
|
|
713
|
+
public reloadFromSegments(segments: SegmentWithInfo<IInsertionInfo>[]): void {
|
|
727
714
|
// This code assumes that a later call to `startCollaboration()` will initialize partial lengths.
|
|
728
715
|
assert(
|
|
729
716
|
!this.collabWindow.collaborating,
|
|
@@ -733,7 +720,7 @@ export class MergeTree {
|
|
|
733
720
|
const maxChildren = MaxNodesInBlock - 1;
|
|
734
721
|
|
|
735
722
|
// Starting with the leaf segments, recursively builds the B-Tree layer by layer from the bottom up.
|
|
736
|
-
const buildMergeBlock = (nodes:
|
|
723
|
+
const buildMergeBlock = (nodes: IMergeNodeBuilder[]): IRootMergeBlock => {
|
|
737
724
|
const blockCount = Math.ceil(nodes.length / maxChildren); // Compute # blocks require for this level of B-Tree
|
|
738
725
|
const blocks: MergeBlock[] = Array.from({ length: blockCount }); // Pre-alloc array to collect nodes
|
|
739
726
|
|
|
@@ -789,8 +776,8 @@ export class MergeTree {
|
|
|
789
776
|
|
|
790
777
|
// TODO: 'seq' may be less than the current sequence number when inserting pre-ACKed
|
|
791
778
|
// segments from a snapshot. We currently skip these for now.
|
|
792
|
-
if (leaf.parent
|
|
793
|
-
leaf.parent
|
|
779
|
+
if (leaf.parent.needsScour !== true && seq > this.collabWindow.currentSeq) {
|
|
780
|
+
leaf.parent.needsScour = true;
|
|
794
781
|
this.segmentsToScour.add({ segment: leaf, maxSeq: seq });
|
|
795
782
|
}
|
|
796
783
|
}
|
|
@@ -834,34 +821,28 @@ export class MergeTree {
|
|
|
834
821
|
return totalOffset;
|
|
835
822
|
}
|
|
836
823
|
|
|
837
|
-
public getContainingSegment
|
|
824
|
+
public getContainingSegment(
|
|
838
825
|
pos: number,
|
|
839
826
|
refSeq: number,
|
|
840
827
|
clientId: number,
|
|
841
828
|
localSeq?: number,
|
|
842
829
|
): {
|
|
843
|
-
segment:
|
|
830
|
+
segment: ISegmentLeaf | undefined;
|
|
844
831
|
offset: number | undefined;
|
|
845
832
|
} {
|
|
846
833
|
assert(
|
|
847
834
|
localSeq === undefined || clientId === this.collabWindow.clientId,
|
|
848
835
|
0x39b /* localSeq provided for non-local client */,
|
|
849
836
|
);
|
|
850
|
-
let segment:
|
|
837
|
+
let segment: ISegmentLeaf | undefined;
|
|
851
838
|
let offset: number | undefined;
|
|
852
839
|
|
|
853
|
-
const leaf = (
|
|
854
|
-
leafSeg
|
|
855
|
-
segpos: number,
|
|
856
|
-
_refSeq: number,
|
|
857
|
-
_clientId: number,
|
|
858
|
-
start: number,
|
|
859
|
-
): boolean => {
|
|
860
|
-
segment = leafSeg as T;
|
|
840
|
+
const leaf = (leafSeg: ISegmentLeaf, _: number, start: number): boolean => {
|
|
841
|
+
segment = leafSeg;
|
|
861
842
|
offset = start;
|
|
862
843
|
return false;
|
|
863
844
|
};
|
|
864
|
-
this.nodeMap(refSeq, clientId, leaf, undefined,
|
|
845
|
+
this.nodeMap(refSeq, clientId, leaf, undefined, pos, pos + 1, localSeq);
|
|
865
846
|
return { segment, offset };
|
|
866
847
|
}
|
|
867
848
|
|
|
@@ -1091,7 +1072,6 @@ export class MergeTree {
|
|
|
1091
1072
|
return;
|
|
1092
1073
|
}
|
|
1093
1074
|
|
|
1094
|
-
// eslint-disable-next-line import/no-deprecated
|
|
1095
1075
|
const rebaseCollabWindow = new CollaborationWindow();
|
|
1096
1076
|
rebaseCollabWindow.loadFrom(this.collabWindow);
|
|
1097
1077
|
if (refSeq < this.collabWindow.minSeq) {
|
|
@@ -1214,13 +1194,13 @@ export class MergeTree {
|
|
|
1214
1194
|
clientId = this.collabWindow.clientId,
|
|
1215
1195
|
localSeq: number | undefined = this.collabWindow.localSeq,
|
|
1216
1196
|
): number {
|
|
1217
|
-
const seg
|
|
1218
|
-
if (seg
|
|
1197
|
+
const seg = refPos.getSegment();
|
|
1198
|
+
if (!isSegmentLeaf(seg)) {
|
|
1219
1199
|
// We have no idea where this reference is, because it refers to a segment which is not in the tree.
|
|
1220
1200
|
return DetachedReferencePosition;
|
|
1221
1201
|
}
|
|
1222
1202
|
if (refPos.isLeaf()) {
|
|
1223
|
-
return this.getPosition(
|
|
1203
|
+
return this.getPosition(seg, refSeq, clientId, localSeq);
|
|
1224
1204
|
}
|
|
1225
1205
|
if (refTypeIncludesFlag(refPos, ReferenceType.Transient) || seg.localRefs?.has(refPos)) {
|
|
1226
1206
|
if (
|
|
@@ -1229,13 +1209,15 @@ export class MergeTree {
|
|
|
1229
1209
|
!isSegmentPresent(seg, { refSeq, localSeq })
|
|
1230
1210
|
) {
|
|
1231
1211
|
const forward = refPos.slidingPreference === SlidingPreference.FORWARD;
|
|
1212
|
+
const moveInfo = toMoveInfo(seg);
|
|
1213
|
+
const removeInfo = toRemovalInfo(seg);
|
|
1232
1214
|
const slideSeq =
|
|
1233
|
-
|
|
1234
|
-
?
|
|
1235
|
-
:
|
|
1236
|
-
?
|
|
1215
|
+
moveInfo !== undefined && moveInfo.movedSeq !== UnassignedSequenceNumber
|
|
1216
|
+
? moveInfo.movedSeq
|
|
1217
|
+
: removeInfo !== undefined && removeInfo.removedSeq !== UnassignedSequenceNumber
|
|
1218
|
+
? removeInfo.removedSeq
|
|
1237
1219
|
: refSeq;
|
|
1238
|
-
const slideLocalSeq =
|
|
1220
|
+
const slideLocalSeq = moveInfo?.localMovedSeq ?? removeInfo?.localRemovedSeq;
|
|
1239
1221
|
const perspective = new PerspectiveImpl(this, {
|
|
1240
1222
|
refSeq: slideSeq,
|
|
1241
1223
|
localSeq: slideLocalSeq,
|
|
@@ -1272,14 +1254,13 @@ export class MergeTree {
|
|
|
1272
1254
|
let foundMarker: Marker | undefined;
|
|
1273
1255
|
|
|
1274
1256
|
const { segment } = this.getContainingSegment(startPos, UniversalSequenceNumber, clientId);
|
|
1275
|
-
|
|
1276
|
-
if (segWithParent?.parent === undefined) {
|
|
1257
|
+
if (!isSegmentLeaf(segment)) {
|
|
1277
1258
|
return undefined;
|
|
1278
1259
|
}
|
|
1279
1260
|
|
|
1280
1261
|
depthFirstNodeWalk(
|
|
1281
|
-
|
|
1282
|
-
|
|
1262
|
+
segment.parent,
|
|
1263
|
+
segment,
|
|
1283
1264
|
(node) => {
|
|
1284
1265
|
if (node.isLeaf()) {
|
|
1285
1266
|
if (Marker.is(node) && refHasTileLabel(node, markerLabel)) {
|
|
@@ -1310,8 +1291,8 @@ export class MergeTree {
|
|
|
1310
1291
|
private updateRoot(splitNode: MergeBlock | undefined): void {
|
|
1311
1292
|
if (splitNode !== undefined) {
|
|
1312
1293
|
const newRoot = this.makeBlock(2);
|
|
1313
|
-
|
|
1314
|
-
|
|
1294
|
+
assignChild(newRoot, this.root, 0, false);
|
|
1295
|
+
assignChild(newRoot, splitNode, 1, false);
|
|
1315
1296
|
this.root = newRoot;
|
|
1316
1297
|
this.nodeUpdateOrdinals(this.root);
|
|
1317
1298
|
this.nodeUpdateLengthNewStructure(this.root);
|
|
@@ -1339,8 +1320,8 @@ export class MergeTree {
|
|
|
1339
1320
|
if (MergeTree.options.zamboniSegments) {
|
|
1340
1321
|
this.addToLRUSet(pendingSegment, seq);
|
|
1341
1322
|
}
|
|
1342
|
-
if (!nodesToUpdate.includes(pendingSegment.parent
|
|
1343
|
-
nodesToUpdate.push(pendingSegment.parent
|
|
1323
|
+
if (!nodesToUpdate.includes(pendingSegment.parent)) {
|
|
1324
|
+
nodesToUpdate.push(pendingSegment.parent);
|
|
1344
1325
|
}
|
|
1345
1326
|
deltaSegments.push({
|
|
1346
1327
|
segment: pendingSegment,
|
|
@@ -1381,11 +1362,10 @@ export class MergeTree {
|
|
|
1381
1362
|
|
|
1382
1363
|
private addToPendingList(
|
|
1383
1364
|
segment: ISegmentLeaf,
|
|
1384
|
-
|
|
1365
|
+
|
|
1385
1366
|
segmentGroup?: SegmentGroup,
|
|
1386
1367
|
localSeq?: number,
|
|
1387
1368
|
previousProps?: PropertySet,
|
|
1388
|
-
// eslint-disable-next-line import/no-deprecated
|
|
1389
1369
|
): SegmentGroup {
|
|
1390
1370
|
let _segmentGroup = segmentGroup;
|
|
1391
1371
|
if (_segmentGroup === undefined) {
|
|
@@ -1409,7 +1389,7 @@ export class MergeTree {
|
|
|
1409
1389
|
if (previousProps) {
|
|
1410
1390
|
_segmentGroup.previousProps!.push(previousProps);
|
|
1411
1391
|
}
|
|
1412
|
-
|
|
1392
|
+
|
|
1413
1393
|
const segmentGroups = (segment.segmentGroups ??= new SegmentGroupCollection(segment));
|
|
1414
1394
|
segmentGroups.enqueue(_segmentGroup);
|
|
1415
1395
|
return _segmentGroup;
|
|
@@ -1442,7 +1422,7 @@ export class MergeTree {
|
|
|
1442
1422
|
if (relativePos.id) {
|
|
1443
1423
|
marker = this.getMarkerFromId(relativePos.id);
|
|
1444
1424
|
}
|
|
1445
|
-
if (marker) {
|
|
1425
|
+
if (isSegmentLeaf(marker)) {
|
|
1446
1426
|
pos = this.getPosition(marker, refseq, clientId);
|
|
1447
1427
|
if (relativePos.before) {
|
|
1448
1428
|
if (relativePos.offset !== undefined) {
|
|
@@ -1460,7 +1440,7 @@ export class MergeTree {
|
|
|
1460
1440
|
|
|
1461
1441
|
public insertSegments(
|
|
1462
1442
|
pos: number,
|
|
1463
|
-
segments:
|
|
1443
|
+
segments: ISegmentPrivate[],
|
|
1464
1444
|
refSeq: number,
|
|
1465
1445
|
clientId: number,
|
|
1466
1446
|
seq: number,
|
|
@@ -1527,7 +1507,7 @@ export class MergeTree {
|
|
|
1527
1507
|
|
|
1528
1508
|
const { currentSeq, clientId } = this.collabWindow;
|
|
1529
1509
|
|
|
1530
|
-
if (segmentInfo?.segment) {
|
|
1510
|
+
if (isSegmentLeaf(segmentInfo?.segment)) {
|
|
1531
1511
|
const segmentPosition = this.getPosition(segmentInfo.segment, currentSeq, clientId);
|
|
1532
1512
|
return segmentPosition + segmentInfo.offset!;
|
|
1533
1513
|
} else {
|
|
@@ -1537,7 +1517,7 @@ export class MergeTree {
|
|
|
1537
1517
|
}
|
|
1538
1518
|
}
|
|
1539
1519
|
|
|
1540
|
-
private blockInsert<T extends
|
|
1520
|
+
private blockInsert<T extends ISegmentPrivate>(
|
|
1541
1521
|
pos: number,
|
|
1542
1522
|
refSeq: number,
|
|
1543
1523
|
clientId: number,
|
|
@@ -1555,7 +1535,7 @@ export class MergeTree {
|
|
|
1555
1535
|
});
|
|
1556
1536
|
return siblingExists;
|
|
1557
1537
|
};
|
|
1558
|
-
|
|
1538
|
+
|
|
1559
1539
|
let segmentGroup: SegmentGroup;
|
|
1560
1540
|
const saveIfLocal = (locSegment: ISegmentLeaf): void => {
|
|
1561
1541
|
// Save segment so we can assign sequence number when acked by server
|
|
@@ -1570,10 +1550,10 @@ export class MergeTree {
|
|
|
1570
1550
|
// In all other cases this has to be true (checked by addToLRUSet):
|
|
1571
1551
|
// locSegment.seq > this.collabWindow.currentSeq
|
|
1572
1552
|
else if (
|
|
1573
|
-
locSegment.seq
|
|
1553
|
+
locSegment.seq > this.collabWindow.minSeq &&
|
|
1574
1554
|
MergeTree.options.zamboniSegments
|
|
1575
1555
|
) {
|
|
1576
|
-
this.addToLRUSet(locSegment, locSegment.seq
|
|
1556
|
+
this.addToLRUSet(locSegment, locSegment.seq);
|
|
1577
1557
|
}
|
|
1578
1558
|
}
|
|
1579
1559
|
};
|
|
@@ -1582,6 +1562,7 @@ export class MergeTree {
|
|
|
1582
1562
|
_pos: number,
|
|
1583
1563
|
context: InsertContext,
|
|
1584
1564
|
// Keeping this function within the scope of blockInsert for readability.
|
|
1565
|
+
// eslint-disable-next-line unicorn/consistent-function-scoping
|
|
1585
1566
|
): ISegmentChanges => {
|
|
1586
1567
|
const segmentChanges: ISegmentChanges = {};
|
|
1587
1568
|
if (segment) {
|
|
@@ -1594,107 +1575,109 @@ export class MergeTree {
|
|
|
1594
1575
|
return segmentChanges;
|
|
1595
1576
|
};
|
|
1596
1577
|
|
|
1578
|
+
const insertInfo: IInsertionInfo = {
|
|
1579
|
+
clientId,
|
|
1580
|
+
seq,
|
|
1581
|
+
localSeq,
|
|
1582
|
+
};
|
|
1597
1583
|
// TODO: build tree from segs and insert all at once
|
|
1598
1584
|
let insertPos = pos;
|
|
1599
|
-
for (const newSegment of newSegments
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
if (
|
|
1605
|
-
|
|
1606
|
-
if (markerId) {
|
|
1607
|
-
this.idToMarker.set(markerId, newSegment);
|
|
1608
|
-
}
|
|
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);
|
|
1609
1592
|
}
|
|
1593
|
+
}
|
|
1610
1594
|
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1595
|
+
const splitNode = this.insertingWalk(this.root, insertPos, refSeq, clientId, seq, {
|
|
1596
|
+
leaf: onLeaf,
|
|
1597
|
+
candidateSegment: newSegment,
|
|
1598
|
+
continuePredicate: continueFrom,
|
|
1599
|
+
});
|
|
1616
1600
|
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
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
|
+
}
|
|
1626
1610
|
|
|
1627
|
-
|
|
1611
|
+
this.updateRoot(splitNode);
|
|
1628
1612
|
|
|
1629
|
-
|
|
1613
|
+
insertPos += newSegment.cachedLength;
|
|
1630
1614
|
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1615
|
+
if (!this.options?.mergeTreeEnableObliterate || this.obliterates.empty()) {
|
|
1616
|
+
saveIfLocal(newSegment);
|
|
1617
|
+
continue;
|
|
1618
|
+
}
|
|
1635
1619
|
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
}
|
|
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;
|
|
1665
1648
|
}
|
|
1666
1649
|
}
|
|
1650
|
+
}
|
|
1667
1651
|
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
this.addToPendingList(newSegment, oldest.segmentGroup);
|
|
1687
|
-
}
|
|
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
|
+
|
|
1662
|
+
overwriteInfo(newSegment, moveInfo);
|
|
1663
|
+
|
|
1664
|
+
if (moveInfo.localMovedSeq !== undefined) {
|
|
1665
|
+
assert(
|
|
1666
|
+
oldest.segmentGroup !== undefined,
|
|
1667
|
+
0x86c /* expected segment group to exist */,
|
|
1668
|
+
);
|
|
1688
1669
|
|
|
1689
|
-
|
|
1690
|
-
this.blockUpdatePathLengths(newSegment.parent, seq, clientId);
|
|
1691
|
-
}
|
|
1692
|
-
} else if (oldest && newest?.clientId === clientId) {
|
|
1693
|
-
newSegment.prevObliterateByInserter = newest;
|
|
1670
|
+
this.addToPendingList(newSegment, oldest.segmentGroup);
|
|
1694
1671
|
}
|
|
1695
1672
|
|
|
1696
|
-
|
|
1673
|
+
if (newSegment.parent) {
|
|
1674
|
+
this.blockUpdatePathLengths(newSegment.parent, seq, clientId);
|
|
1675
|
+
}
|
|
1676
|
+
} else if (oldest && newest?.clientId === clientId) {
|
|
1677
|
+
newSegment.prevObliterateByInserter = newest;
|
|
1697
1678
|
}
|
|
1679
|
+
|
|
1680
|
+
saveIfLocal(newSegment);
|
|
1698
1681
|
}
|
|
1699
1682
|
}
|
|
1700
1683
|
|
|
@@ -1706,7 +1689,8 @@ export class MergeTree {
|
|
|
1706
1689
|
return {};
|
|
1707
1690
|
}
|
|
1708
1691
|
|
|
1709
|
-
const next
|
|
1692
|
+
const next = segment.splitAt(pos)!;
|
|
1693
|
+
assertSegmentLeaf(next);
|
|
1710
1694
|
|
|
1711
1695
|
if (segment?.segmentGroups) {
|
|
1712
1696
|
next.segmentGroups ??= new SegmentGroupCollection(next);
|
|
@@ -1762,10 +1746,8 @@ export class MergeTree {
|
|
|
1762
1746
|
|
|
1763
1747
|
return (
|
|
1764
1748
|
newSeq > segSeq ||
|
|
1765
|
-
(node.movedSeq !==
|
|
1766
|
-
|
|
1767
|
-
node.movedSeq > seq) ||
|
|
1768
|
-
(node.removedSeq !== undefined &&
|
|
1749
|
+
(isMoved(node) && node.movedSeq !== UnassignedSequenceNumber && node.movedSeq > seq) ||
|
|
1750
|
+
(isRemoved(node) &&
|
|
1769
1751
|
node.removedSeq !== UnassignedSequenceNumber &&
|
|
1770
1752
|
node.removedSeq > seq)
|
|
1771
1753
|
);
|
|
@@ -1788,7 +1770,7 @@ export class MergeTree {
|
|
|
1788
1770
|
const children = block.children;
|
|
1789
1771
|
let childIndex: number;
|
|
1790
1772
|
let child: IMergeNode;
|
|
1791
|
-
let newNode:
|
|
1773
|
+
let newNode: IMergeNodeBuilder | undefined;
|
|
1792
1774
|
let fromSplit: MergeBlock | undefined;
|
|
1793
1775
|
for (childIndex = 0; childIndex < block.childCount; childIndex++) {
|
|
1794
1776
|
child = children[childIndex];
|
|
@@ -1812,7 +1794,7 @@ export class MergeTree {
|
|
|
1812
1794
|
const segment = child;
|
|
1813
1795
|
const segmentChanges = context.leaf(segment, _pos, context);
|
|
1814
1796
|
if (segmentChanges.replaceCurrent) {
|
|
1815
|
-
|
|
1797
|
+
assignChild(block, segmentChanges.replaceCurrent, childIndex, false);
|
|
1816
1798
|
segmentChanges.replaceCurrent.ordinal = child.ordinal;
|
|
1817
1799
|
}
|
|
1818
1800
|
if (segmentChanges.next) {
|
|
@@ -1865,7 +1847,7 @@ export class MergeTree {
|
|
|
1865
1847
|
block.children[i] = block.children[i - 1];
|
|
1866
1848
|
block.children[i].index = i;
|
|
1867
1849
|
}
|
|
1868
|
-
|
|
1850
|
+
assignChild(block, newNode, childIndex, false);
|
|
1869
1851
|
block.childCount++;
|
|
1870
1852
|
block.setOrdinal(newNode, childIndex);
|
|
1871
1853
|
if (block.childCount < MaxNodesInBlock) {
|
|
@@ -1900,7 +1882,7 @@ export class MergeTree {
|
|
|
1900
1882
|
// Update ordinals to reflect lowered child count
|
|
1901
1883
|
this.nodeUpdateOrdinals(node);
|
|
1902
1884
|
for (let i = 0; i < halfCount; i++) {
|
|
1903
|
-
|
|
1885
|
+
assignChild(newNode, node.children[halfCount + i], i, false);
|
|
1904
1886
|
node.children[halfCount + i] = undefined!;
|
|
1905
1887
|
}
|
|
1906
1888
|
this.nodeUpdateLengthNewStructure(node);
|
|
@@ -1937,7 +1919,7 @@ export class MergeTree {
|
|
|
1937
1919
|
clientId: number,
|
|
1938
1920
|
seq: number,
|
|
1939
1921
|
opArgs: IMergeTreeDeltaOpArgs,
|
|
1940
|
-
|
|
1922
|
+
|
|
1941
1923
|
rollback: PropertiesRollback = PropertiesRollback.None,
|
|
1942
1924
|
): void {
|
|
1943
1925
|
if (propsOrAdjust.adjust !== undefined) {
|
|
@@ -1949,7 +1931,7 @@ export class MergeTree {
|
|
|
1949
1931
|
const deltaSegments: IMergeTreeSegmentDelta[] = [];
|
|
1950
1932
|
const localSeq =
|
|
1951
1933
|
seq === UnassignedSequenceNumber ? ++this.collabWindow.localSeq : undefined;
|
|
1952
|
-
|
|
1934
|
+
|
|
1953
1935
|
let segmentGroup: SegmentGroup | undefined;
|
|
1954
1936
|
const opObj = propsOrAdjust.props ?? propsOrAdjust.adjust;
|
|
1955
1937
|
const annotateSegment = (segment: ISegmentLeaf): boolean => {
|
|
@@ -1990,7 +1972,7 @@ export class MergeTree {
|
|
|
1990
1972
|
return true;
|
|
1991
1973
|
};
|
|
1992
1974
|
|
|
1993
|
-
this.nodeMap(refSeq, clientId, annotateSegment, undefined,
|
|
1975
|
+
this.nodeMap(refSeq, clientId, annotateSegment, undefined, start, end);
|
|
1994
1976
|
|
|
1995
1977
|
// OpArgs == undefined => test code
|
|
1996
1978
|
if (deltaSegments.length > 0) {
|
|
@@ -2024,10 +2006,11 @@ export class MergeTree {
|
|
|
2024
2006
|
|
|
2025
2007
|
let _overwrite = false;
|
|
2026
2008
|
const localOverlapWithRefs: ISegmentLeaf[] = [];
|
|
2027
|
-
|
|
2009
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2010
|
+
const movedSegments: SegmentWithInfo<IMoveInfo, ISegmentLeaf>[] = [];
|
|
2028
2011
|
const localSeq =
|
|
2029
2012
|
seq === UnassignedSequenceNumber ? ++this.collabWindow.localSeq : undefined;
|
|
2030
|
-
|
|
2013
|
+
|
|
2031
2014
|
const obliterate: ObliterateInfo = {
|
|
2032
2015
|
clientId,
|
|
2033
2016
|
end: createDetachedLocalReferencePosition(undefined),
|
|
@@ -2041,7 +2024,7 @@ export class MergeTree {
|
|
|
2041
2024
|
const { segment: startSeg } = this.getContainingSegment(start.pos, refSeq, clientId);
|
|
2042
2025
|
const { segment: endSeg } = this.getContainingSegment(end.pos, refSeq, clientId);
|
|
2043
2026
|
assert(
|
|
2044
|
-
startSeg
|
|
2027
|
+
isSegmentLeaf(startSeg) && isSegmentLeaf(endSeg),
|
|
2045
2028
|
0xa3f /* segments cannot be undefined */,
|
|
2046
2029
|
);
|
|
2047
2030
|
|
|
@@ -2078,12 +2061,7 @@ export class MergeTree {
|
|
|
2078
2061
|
}
|
|
2079
2062
|
this.obliterates.addOrUpdate(obliterate);
|
|
2080
2063
|
|
|
2081
|
-
const markMoved = (
|
|
2082
|
-
segment: ISegmentLeaf,
|
|
2083
|
-
pos: number,
|
|
2084
|
-
_start: number,
|
|
2085
|
-
_end: number,
|
|
2086
|
-
): boolean => {
|
|
2064
|
+
const markMoved = (segment: ISegmentLeaf, pos: number): boolean => {
|
|
2087
2065
|
if (
|
|
2088
2066
|
(start.side === Side.After && startPos === pos + segment.cachedLength) || // exclusive start segment
|
|
2089
2067
|
(end.side === Side.Before &&
|
|
@@ -2103,26 +2081,29 @@ export class MergeTree {
|
|
|
2103
2081
|
return true;
|
|
2104
2082
|
}
|
|
2105
2083
|
|
|
2106
|
-
|
|
2084
|
+
const wasMovedOnInsert =
|
|
2107
2085
|
clientId !== segment.clientId &&
|
|
2108
2086
|
segment.seq !== undefined &&
|
|
2109
2087
|
seq !== UnassignedSequenceNumber &&
|
|
2110
|
-
(refSeq < segment.seq || segment.seq === UnassignedSequenceNumber)
|
|
2111
|
-
) {
|
|
2112
|
-
segment.wasMovedOnInsert = true;
|
|
2113
|
-
}
|
|
2088
|
+
(refSeq < segment.seq || segment.seq === UnassignedSequenceNumber);
|
|
2114
2089
|
|
|
2115
2090
|
if (existingMoveInfo === undefined) {
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
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
|
+
});
|
|
2120
2099
|
|
|
2121
|
-
if (!toRemovalInfo(
|
|
2122
|
-
movedSegments.push(
|
|
2100
|
+
if (!toRemovalInfo(movedSeg)) {
|
|
2101
|
+
movedSegments.push(movedSeg);
|
|
2123
2102
|
}
|
|
2124
2103
|
} else {
|
|
2125
2104
|
_overwrite = true;
|
|
2105
|
+
// never move wasMovedOnInsert from true to false
|
|
2106
|
+
existingMoveInfo.wasMovedOnInsert ||= wasMovedOnInsert;
|
|
2126
2107
|
if (existingMoveInfo.movedSeq === UnassignedSequenceNumber) {
|
|
2127
2108
|
// we moved this locally, but someone else moved it first
|
|
2128
2109
|
// so put them at the head of the list
|
|
@@ -2141,7 +2122,7 @@ export class MergeTree {
|
|
|
2141
2122
|
existingMoveInfo.movedSeqs.push(seq);
|
|
2142
2123
|
}
|
|
2143
2124
|
}
|
|
2144
|
-
|
|
2125
|
+
assertMoved(segment);
|
|
2145
2126
|
// Save segment so can assign moved sequence number when acked by server
|
|
2146
2127
|
if (this.collabWindow.collaborating) {
|
|
2147
2128
|
if (
|
|
@@ -2162,12 +2143,7 @@ export class MergeTree {
|
|
|
2162
2143
|
return true;
|
|
2163
2144
|
};
|
|
2164
2145
|
|
|
2165
|
-
const afterMarkMoved = (
|
|
2166
|
-
node: MergeBlock,
|
|
2167
|
-
pos: number,
|
|
2168
|
-
_start: number,
|
|
2169
|
-
_end: number,
|
|
2170
|
-
): boolean => {
|
|
2146
|
+
const afterMarkMoved = (node: MergeBlock): boolean => {
|
|
2171
2147
|
if (_overwrite) {
|
|
2172
2148
|
this.nodeUpdateLengthNewStructure(node);
|
|
2173
2149
|
} else {
|
|
@@ -2180,7 +2156,6 @@ export class MergeTree {
|
|
|
2180
2156
|
refSeq,
|
|
2181
2157
|
clientId,
|
|
2182
2158
|
markMoved,
|
|
2183
|
-
undefined,
|
|
2184
2159
|
afterMarkMoved,
|
|
2185
2160
|
start.pos,
|
|
2186
2161
|
end.pos + 1, // include the segment containing the end reference
|
|
@@ -2193,7 +2168,7 @@ export class MergeTree {
|
|
|
2193
2168
|
if (start.pos !== end.pos || start.side !== end.side) {
|
|
2194
2169
|
this.mergeTreeDeltaCallback?.(opArgs, {
|
|
2195
2170
|
operation: MergeTreeDeltaType.OBLITERATE,
|
|
2196
|
-
deltaSegments: movedSegments,
|
|
2171
|
+
deltaSegments: movedSegments.map((segment) => ({ segment })),
|
|
2197
2172
|
});
|
|
2198
2173
|
}
|
|
2199
2174
|
|
|
@@ -2201,7 +2176,7 @@ export class MergeTree {
|
|
|
2201
2176
|
// so we slide after eventing in case the consumer wants to make reference
|
|
2202
2177
|
// changes at remove time, like add a ref to track undo redo.
|
|
2203
2178
|
if (!this.collabWindow.collaborating || clientId !== this.collabWindow.clientId) {
|
|
2204
|
-
this.slideAckedRemovedSegmentReferences(movedSegments
|
|
2179
|
+
this.slideAckedRemovedSegmentReferences(movedSegments);
|
|
2205
2180
|
}
|
|
2206
2181
|
|
|
2207
2182
|
if (
|
|
@@ -2255,9 +2230,10 @@ export class MergeTree {
|
|
|
2255
2230
|
let _overwrite = false;
|
|
2256
2231
|
this.ensureIntervalBoundary(start, refSeq, clientId);
|
|
2257
2232
|
this.ensureIntervalBoundary(end, refSeq, clientId);
|
|
2258
|
-
|
|
2233
|
+
|
|
2259
2234
|
let segmentGroup: SegmentGroup;
|
|
2260
|
-
|
|
2235
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2236
|
+
const removedSegments: SegmentWithInfo<IRemovalInfo, ISegmentLeaf>[] = [];
|
|
2261
2237
|
const localOverlapWithRefs: ISegmentLeaf[] = [];
|
|
2262
2238
|
const localSeq =
|
|
2263
2239
|
seq === UnassignedSequenceNumber ? ++this.collabWindow.localSeq : undefined;
|
|
@@ -2270,12 +2246,15 @@ export class MergeTree {
|
|
|
2270
2246
|
const existingRemovalInfo = toRemovalInfo(segment);
|
|
2271
2247
|
|
|
2272
2248
|
if (existingRemovalInfo === undefined) {
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
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
|
+
});
|
|
2276
2255
|
|
|
2277
|
-
if (!toMoveInfo(
|
|
2278
|
-
removedSegments.push(
|
|
2256
|
+
if (!toMoveInfo(removed)) {
|
|
2257
|
+
removedSegments.push(removed);
|
|
2279
2258
|
}
|
|
2280
2259
|
} else {
|
|
2281
2260
|
_overwrite = true;
|
|
@@ -2295,7 +2274,7 @@ export class MergeTree {
|
|
|
2295
2274
|
existingRemovalInfo.removedClientIds.push(clientId);
|
|
2296
2275
|
}
|
|
2297
2276
|
}
|
|
2298
|
-
|
|
2277
|
+
assertRemoved(segment);
|
|
2299
2278
|
// Save segment so we can assign removed sequence number when acked by server
|
|
2300
2279
|
if (this.collabWindow.collaborating) {
|
|
2301
2280
|
if (
|
|
@@ -2311,12 +2290,7 @@ export class MergeTree {
|
|
|
2311
2290
|
}
|
|
2312
2291
|
return true;
|
|
2313
2292
|
};
|
|
2314
|
-
const afterMarkRemoved = (
|
|
2315
|
-
node: MergeBlock,
|
|
2316
|
-
pos: number,
|
|
2317
|
-
_start: number,
|
|
2318
|
-
_end: number,
|
|
2319
|
-
): boolean => {
|
|
2293
|
+
const afterMarkRemoved = (node: MergeBlock): boolean => {
|
|
2320
2294
|
if (_overwrite) {
|
|
2321
2295
|
this.nodeUpdateLengthNewStructure(node);
|
|
2322
2296
|
} else {
|
|
@@ -2324,7 +2298,7 @@ export class MergeTree {
|
|
|
2324
2298
|
}
|
|
2325
2299
|
return true;
|
|
2326
2300
|
};
|
|
2327
|
-
this.nodeMap(refSeq, clientId, markRemoved,
|
|
2301
|
+
this.nodeMap(refSeq, clientId, markRemoved, afterMarkRemoved, start, end);
|
|
2328
2302
|
// these segments are already viewed as being removed locally and are not event-ed
|
|
2329
2303
|
// so can slide non-StayOnRemove refs immediately
|
|
2330
2304
|
this.slideAckedRemovedSegmentReferences(localOverlapWithRefs);
|
|
@@ -2332,14 +2306,14 @@ export class MergeTree {
|
|
|
2332
2306
|
if (removedSegments.length > 0) {
|
|
2333
2307
|
this.mergeTreeDeltaCallback?.(opArgs, {
|
|
2334
2308
|
operation: MergeTreeDeltaType.REMOVE,
|
|
2335
|
-
deltaSegments: removedSegments,
|
|
2309
|
+
deltaSegments: removedSegments.map((segment) => ({ segment })),
|
|
2336
2310
|
});
|
|
2337
2311
|
}
|
|
2338
2312
|
// these events are newly removed
|
|
2339
2313
|
// so we slide after eventing in case the consumer wants to make reference
|
|
2340
2314
|
// changes at remove time, like add a ref to track undo redo.
|
|
2341
2315
|
if (!this.collabWindow.collaborating || clientId !== this.collabWindow.clientId) {
|
|
2342
|
-
this.slideAckedRemovedSegmentReferences(removedSegments
|
|
2316
|
+
this.slideAckedRemovedSegmentReferences(removedSegments);
|
|
2343
2317
|
}
|
|
2344
2318
|
|
|
2345
2319
|
if (
|
|
@@ -2354,36 +2328,30 @@ export class MergeTree {
|
|
|
2354
2328
|
/**
|
|
2355
2329
|
* Revert an unacked local op
|
|
2356
2330
|
*/
|
|
2357
|
-
|
|
2331
|
+
|
|
2358
2332
|
public rollback(op: IMergeTreeDeltaOp, localOpMetadata: SegmentGroup): void {
|
|
2359
2333
|
if (op.type === MergeTreeDeltaType.REMOVE) {
|
|
2360
|
-
const pendingSegmentGroup = this.pendingSegments.pop
|
|
2334
|
+
const pendingSegmentGroup = this.pendingSegments.pop()?.data;
|
|
2361
2335
|
if (pendingSegmentGroup === undefined || pendingSegmentGroup !== localOpMetadata) {
|
|
2362
2336
|
throw new Error("Rollback op doesn't match last edit");
|
|
2363
2337
|
}
|
|
2364
2338
|
// Disabling because a for of loop causes the type of segment to be ISegmentLeaf, which does not have parent information stored
|
|
2365
2339
|
// eslint-disable-next-line unicorn/no-array-for-each
|
|
2366
2340
|
pendingSegmentGroup.segments.forEach((segment: ISegmentLeaf) => {
|
|
2367
|
-
const segmentSegmentGroup = segment?.segmentGroups?.pop
|
|
2341
|
+
const segmentSegmentGroup = segment?.segmentGroups?.pop();
|
|
2368
2342
|
assert(
|
|
2369
2343
|
segmentSegmentGroup === pendingSegmentGroup,
|
|
2370
2344
|
0x3ee /* Unexpected segmentGroup in segment */,
|
|
2371
2345
|
);
|
|
2372
2346
|
|
|
2373
2347
|
assert(
|
|
2374
|
-
segment.removedClientIds
|
|
2375
|
-
segment.removedClientIds[0] === this.collabWindow.clientId,
|
|
2348
|
+
isRemoved(segment) && segment.removedClientIds[0] === this.collabWindow.clientId,
|
|
2376
2349
|
0x39d /* Rollback segment removedClientId does not match local client */,
|
|
2377
2350
|
);
|
|
2378
|
-
|
|
2379
|
-
segment
|
|
2380
|
-
segment.localRemovedSeq = undefined;
|
|
2351
|
+
let updateNode: MergeBlock | undefined = segment.parent;
|
|
2352
|
+
removeRemovalInfo(segment);
|
|
2381
2353
|
|
|
2382
|
-
for (
|
|
2383
|
-
let updateNode = segment.parent;
|
|
2384
|
-
updateNode !== undefined;
|
|
2385
|
-
updateNode = updateNode.parent
|
|
2386
|
-
) {
|
|
2354
|
+
for (updateNode; updateNode !== undefined; updateNode = updateNode.parent) {
|
|
2387
2355
|
this.blockUpdateLength(
|
|
2388
2356
|
updateNode,
|
|
2389
2357
|
UnassignedSequenceNumber,
|
|
@@ -2405,7 +2373,7 @@ export class MergeTree {
|
|
|
2405
2373
|
op.type === MergeTreeDeltaType.INSERT ||
|
|
2406
2374
|
op.type === MergeTreeDeltaType.ANNOTATE
|
|
2407
2375
|
) {
|
|
2408
|
-
const pendingSegmentGroup = this.pendingSegments.pop
|
|
2376
|
+
const pendingSegmentGroup = this.pendingSegments.pop()?.data;
|
|
2409
2377
|
if (
|
|
2410
2378
|
pendingSegmentGroup === undefined ||
|
|
2411
2379
|
pendingSegmentGroup !== localOpMetadata ||
|
|
@@ -2414,8 +2382,8 @@ export class MergeTree {
|
|
|
2414
2382
|
throw new Error("Rollback op doesn't match last edit");
|
|
2415
2383
|
}
|
|
2416
2384
|
let i = 0;
|
|
2417
|
-
for (const segment of pendingSegmentGroup.segments
|
|
2418
|
-
const segmentSegmentGroup = segment?.segmentGroups?.pop
|
|
2385
|
+
for (const segment of pendingSegmentGroup.segments) {
|
|
2386
|
+
const segmentSegmentGroup = segment?.segmentGroups?.pop();
|
|
2419
2387
|
assert(
|
|
2420
2388
|
segmentSegmentGroup === pendingSegmentGroup,
|
|
2421
2389
|
0x3ef /* Unexpected segmentGroup in segment */,
|
|
@@ -2467,7 +2435,7 @@ export class MergeTree {
|
|
|
2467
2435
|
}
|
|
2468
2436
|
|
|
2469
2437
|
// If not removed, increase position
|
|
2470
|
-
if (seg
|
|
2438
|
+
if (!isRemoved(seg)) {
|
|
2471
2439
|
segmentPosition += seg.cachedLength;
|
|
2472
2440
|
}
|
|
2473
2441
|
|
|
@@ -2488,7 +2456,7 @@ export class MergeTree {
|
|
|
2488
2456
|
public removeLocalReferencePosition(
|
|
2489
2457
|
lref: LocalReferencePosition,
|
|
2490
2458
|
): LocalReferencePosition | undefined {
|
|
2491
|
-
const segment:
|
|
2459
|
+
const segment: ISegmentPrivate | undefined = lref.getSegment();
|
|
2492
2460
|
return segment?.localRefs?.removeLocalRef(lref);
|
|
2493
2461
|
}
|
|
2494
2462
|
|
|
@@ -2496,7 +2464,7 @@ export class MergeTree {
|
|
|
2496
2464
|
endOfTree = new EndOfTreeSegment(this);
|
|
2497
2465
|
|
|
2498
2466
|
public createLocalReferencePosition(
|
|
2499
|
-
_segment:
|
|
2467
|
+
_segment: ISegmentPrivate | "start" | "end",
|
|
2500
2468
|
offset: number,
|
|
2501
2469
|
refType: ReferenceType,
|
|
2502
2470
|
properties: PropertySet | undefined,
|
|
@@ -2517,7 +2485,6 @@ export class MergeTree {
|
|
|
2517
2485
|
"Can only create SlideOnRemove or Transient local reference position on a removed or obliterated segment",
|
|
2518
2486
|
);
|
|
2519
2487
|
}
|
|
2520
|
-
|
|
2521
2488
|
let segment: ISegmentLeaf;
|
|
2522
2489
|
|
|
2523
2490
|
if (_segment === "start") {
|
|
@@ -2525,6 +2492,7 @@ export class MergeTree {
|
|
|
2525
2492
|
} else if (_segment === "end") {
|
|
2526
2493
|
segment = this.endOfTree;
|
|
2527
2494
|
} else {
|
|
2495
|
+
assertSegmentLeaf(_segment);
|
|
2528
2496
|
segment = _segment;
|
|
2529
2497
|
}
|
|
2530
2498
|
|
|
@@ -2613,7 +2581,7 @@ export class MergeTree {
|
|
|
2613
2581
|
for (let i = 0; i < newOrder.length; i++) {
|
|
2614
2582
|
const seg = newOrder[i];
|
|
2615
2583
|
const { parent, index, ordinal } = currentOrder[i];
|
|
2616
|
-
|
|
2584
|
+
assignChild(parent, seg, index, false);
|
|
2617
2585
|
seg.ordinal = ordinal;
|
|
2618
2586
|
}
|
|
2619
2587
|
|
|
@@ -2811,8 +2779,7 @@ export class MergeTree {
|
|
|
2811
2779
|
this.nodeMap(
|
|
2812
2780
|
refSeq,
|
|
2813
2781
|
clientId,
|
|
2814
|
-
handler,
|
|
2815
|
-
accum,
|
|
2782
|
+
(seg, pos, _start, _end) => handler(seg, pos, refSeq, clientId, _start, _end, accum),
|
|
2816
2783
|
undefined,
|
|
2817
2784
|
start,
|
|
2818
2785
|
end,
|
|
@@ -2844,12 +2811,11 @@ export class MergeTree {
|
|
|
2844
2811
|
* but it will not count as a segment within the range. That is, it will be
|
|
2845
2812
|
* ignored for the purposes of tracking when traversal should end.
|
|
2846
2813
|
*/
|
|
2847
|
-
private nodeMap
|
|
2814
|
+
private nodeMap(
|
|
2848
2815
|
refSeq: number,
|
|
2849
2816
|
clientId: number,
|
|
2850
|
-
leaf:
|
|
2851
|
-
|
|
2852
|
-
post?: BlockAction<TClientData>,
|
|
2817
|
+
leaf: (segment: ISegmentLeaf, pos: number, start: number, end: number) => boolean,
|
|
2818
|
+
post?: (block: MergeBlock) => boolean,
|
|
2853
2819
|
start: number = 0,
|
|
2854
2820
|
end?: number,
|
|
2855
2821
|
localSeq?: number,
|
|
@@ -2895,17 +2861,14 @@ export class MergeTree {
|
|
|
2895
2861
|
}
|
|
2896
2862
|
|
|
2897
2863
|
if (node.isLeaf()) {
|
|
2898
|
-
if (leaf(node, pos,
|
|
2864
|
+
if (leaf(node, pos, start - pos, endPos - pos) === false) {
|
|
2899
2865
|
return NodeAction.Exit;
|
|
2900
2866
|
}
|
|
2901
2867
|
pos = nextPos;
|
|
2902
2868
|
}
|
|
2903
2869
|
},
|
|
2904
2870
|
undefined,
|
|
2905
|
-
post
|
|
2906
|
-
? undefined
|
|
2907
|
-
: (block): boolean =>
|
|
2908
|
-
post(block, pos, refSeq, clientId, start - pos, endPos - pos, accum),
|
|
2871
|
+
post,
|
|
2909
2872
|
);
|
|
2910
2873
|
}
|
|
2911
2874
|
}
|