@fluidframework/merge-tree 2.12.0 → 2.20.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 +46 -0
- package/api-report/merge-tree.legacy.alpha.api.md +0 -108
- 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 +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -4
- package/dist/index.js.map +1 -1
- package/dist/legacy.d.ts +0 -4
- package/dist/localReference.d.ts +5 -7
- package/dist/localReference.d.ts.map +1 -1
- package/dist/localReference.js +1 -3
- 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 +187 -228
- 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 +65 -325
- package/dist/mergeTreeNodes.d.ts.map +1 -1
- package/dist/mergeTreeNodes.js +96 -130
- 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/opBuilder.d.ts +0 -5
- package/dist/opBuilder.d.ts.map +1 -1
- package/dist/opBuilder.js +0 -5
- package/dist/opBuilder.js.map +1 -1
- package/dist/package.json +2 -1
- package/dist/partialLengths.d.ts +2 -2
- package/dist/partialLengths.d.ts.map +1 -1
- package/dist/partialLengths.js +29 -31
- 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 +5 -2
- 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 -14
- 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 +251 -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 +36 -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 +28 -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 +1 -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 +0 -4
- package/lib/localReference.d.ts +5 -7
- package/lib/localReference.d.ts.map +1 -1
- package/lib/localReference.js +1 -3
- 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 +175 -220
- 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 +65 -325
- package/lib/mergeTreeNodes.d.ts.map +1 -1
- package/lib/mergeTreeNodes.js +92 -127
- 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/opBuilder.d.ts +0 -5
- package/lib/opBuilder.d.ts.map +1 -1
- package/lib/opBuilder.js +0 -5
- package/lib/opBuilder.js.map +1 -1
- package/lib/partialLengths.d.ts +2 -2
- package/lib/partialLengths.d.ts.map +1 -1
- package/lib/partialLengths.js +26 -28
- 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 +5 -2
- 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 -12
- 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 +251 -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 +36 -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 +29 -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 +77 -19
- package/src/MergeTreeTextHelper.ts +2 -4
- package/src/attributionPolicy.ts +5 -13
- package/src/client.ts +55 -44
- package/src/endOfTreeSegment.ts +3 -5
- package/src/index.ts +0 -7
- package/src/localReference.ts +6 -8
- package/src/mergeTree.ts +233 -290
- package/src/mergeTreeNodeWalk.ts +3 -2
- package/src/mergeTreeNodes.ts +160 -490
- package/src/mergeTreeTracking.ts +0 -3
- package/src/opBuilder.ts +0 -5
- package/src/partialLengths.ts +40 -29
- package/src/perspective.ts +23 -4
- package/src/referencePositions.ts +4 -1
- package/src/revertibles.ts +19 -16
- package/src/segmentGroupCollection.ts +7 -18
- package/src/segmentInfos.ts +371 -0
- package/src/snapshotLoader.ts +56 -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
|
@@ -20,7 +20,6 @@ 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
|
|
24
23
|
LocalReferenceCollection,
|
|
25
24
|
LocalReferencePosition,
|
|
26
25
|
SlidingPreference,
|
|
@@ -43,29 +42,24 @@ import {
|
|
|
43
42
|
walkAllChildSegments,
|
|
44
43
|
} from "./mergeTreeNodeWalk.js";
|
|
45
44
|
import {
|
|
46
|
-
BlockAction,
|
|
47
|
-
// eslint-disable-next-line import/no-deprecated
|
|
48
45
|
CollaborationWindow,
|
|
49
46
|
IMergeNode,
|
|
50
|
-
// eslint-disable-next-line import/no-deprecated
|
|
51
|
-
IMoveInfo,
|
|
52
|
-
// eslint-disable-next-line import/no-deprecated
|
|
53
|
-
IRemovalInfo,
|
|
54
47
|
ISegmentAction,
|
|
55
48
|
ISegmentChanges,
|
|
56
|
-
ISegmentLeaf,
|
|
57
49
|
InsertContext,
|
|
58
50
|
Marker,
|
|
59
51
|
MaxNodesInBlock,
|
|
60
52
|
MergeBlock,
|
|
61
|
-
// eslint-disable-next-line import/no-deprecated
|
|
62
53
|
SegmentGroup,
|
|
54
|
+
assertSegmentLeaf,
|
|
55
|
+
assignChild,
|
|
56
|
+
isSegmentLeaf,
|
|
63
57
|
reservedMarkerIdKey,
|
|
64
58
|
seqLTE,
|
|
65
|
-
|
|
66
|
-
toRemovalInfo,
|
|
59
|
+
type IMergeNodeBuilder,
|
|
67
60
|
type ISegmentInternal,
|
|
68
|
-
|
|
61
|
+
type ISegmentLeaf,
|
|
62
|
+
type ISegmentPrivate,
|
|
69
63
|
type ObliterateInfo,
|
|
70
64
|
} from "./mergeTreeNodes.js";
|
|
71
65
|
import type { TrackingGroup } from "./mergeTreeTracking.js";
|
|
@@ -90,9 +84,22 @@ import {
|
|
|
90
84
|
refHasTileLabel,
|
|
91
85
|
refTypeIncludesFlag,
|
|
92
86
|
} from "./referencePositions.js";
|
|
93
|
-
// eslint-disable-next-line import/no-deprecated
|
|
94
87
|
import { SegmentGroupCollection } from "./segmentGroupCollection.js";
|
|
95
|
-
|
|
88
|
+
import {
|
|
89
|
+
assertMoved,
|
|
90
|
+
assertRemoved,
|
|
91
|
+
isMergeNodeInfo,
|
|
92
|
+
isMoved,
|
|
93
|
+
isRemoved,
|
|
94
|
+
overwriteInfo,
|
|
95
|
+
removeRemovalInfo,
|
|
96
|
+
toMoveInfo,
|
|
97
|
+
toRemovalInfo,
|
|
98
|
+
type IInsertionInfo,
|
|
99
|
+
type IMoveInfo,
|
|
100
|
+
type IRemovalInfo,
|
|
101
|
+
type SegmentWithInfo,
|
|
102
|
+
} from "./segmentInfos.js";
|
|
96
103
|
import {
|
|
97
104
|
copyPropertiesAndManager,
|
|
98
105
|
PropertiesManager,
|
|
@@ -103,39 +110,17 @@ import { Side, type InteriorSequencePlace } from "./sequencePlace.js";
|
|
|
103
110
|
import { SortedSegmentSet } from "./sortedSegmentSet.js";
|
|
104
111
|
import { zamboniSegments } from "./zamboni.js";
|
|
105
112
|
|
|
106
|
-
|
|
107
|
-
function markSegmentMoved(seg: ISegmentLeaf, moveInfo: IMoveInfo): void {
|
|
108
|
-
seg.moveDst = moveInfo.moveDst;
|
|
109
|
-
seg.movedClientIds = [...moveInfo.movedClientIds];
|
|
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 {
|
|
113
|
+
function isRemovedAndAcked(segment: ISegmentPrivate): segment is ISegmentLeaf & IRemovalInfo {
|
|
128
114
|
const removalInfo = toRemovalInfo(segment);
|
|
129
115
|
return removalInfo !== undefined && removalInfo.removedSeq !== UnassignedSequenceNumber;
|
|
130
116
|
}
|
|
131
117
|
|
|
132
|
-
|
|
133
|
-
function isMovedAndAcked(segment: ISegmentLeaf): segment is ISegmentLeaf & IMoveInfo {
|
|
118
|
+
function isMovedAndAcked(segment: ISegmentPrivate): segment is ISegmentLeaf & IMoveInfo {
|
|
134
119
|
const moveInfo = toMoveInfo(segment);
|
|
135
120
|
return moveInfo !== undefined && moveInfo.movedSeq !== UnassignedSequenceNumber;
|
|
136
121
|
}
|
|
137
122
|
|
|
138
|
-
function isRemovedAndAckedOrMovedAndAcked(segment:
|
|
123
|
+
function isRemovedAndAckedOrMovedAndAcked(segment: ISegmentPrivate): boolean {
|
|
139
124
|
return isRemovedAndAcked(segment) || isMovedAndAcked(segment);
|
|
140
125
|
}
|
|
141
126
|
|
|
@@ -188,12 +173,10 @@ function ackSegment(
|
|
|
188
173
|
}
|
|
189
174
|
|
|
190
175
|
case MergeTreeDeltaType.REMOVE: {
|
|
191
|
-
|
|
192
|
-
const removalInfo: IRemovalInfo | undefined = toRemovalInfo(segment);
|
|
193
|
-
assert(removalInfo !== undefined, 0x046 /* "On remove ack, missing removal info!" */);
|
|
176
|
+
assertRemoved(segment);
|
|
194
177
|
segment.localRemovedSeq = undefined;
|
|
195
|
-
if (
|
|
196
|
-
|
|
178
|
+
if (segment.removedSeq === UnassignedSequenceNumber) {
|
|
179
|
+
segment.removedSeq = sequenceNumber;
|
|
197
180
|
return true;
|
|
198
181
|
}
|
|
199
182
|
return false;
|
|
@@ -201,18 +184,16 @@ function ackSegment(
|
|
|
201
184
|
|
|
202
185
|
case MergeTreeDeltaType.OBLITERATE:
|
|
203
186
|
case MergeTreeDeltaType.OBLITERATE_SIDED: {
|
|
204
|
-
|
|
205
|
-
const moveInfo: IMoveInfo | undefined = toMoveInfo(segment);
|
|
206
|
-
assert(moveInfo !== undefined, 0x86e /* On obliterate ack, missing move info! */);
|
|
187
|
+
assertMoved(segment);
|
|
207
188
|
const obliterateInfo = segmentGroup.obliterateInfo;
|
|
208
189
|
assert(obliterateInfo !== undefined, 0xa40 /* must have obliterate info */);
|
|
209
190
|
segment.localMovedSeq = obliterateInfo.localSeq = undefined;
|
|
210
|
-
const seqIdx =
|
|
191
|
+
const seqIdx = segment.movedSeqs.indexOf(UnassignedSequenceNumber);
|
|
211
192
|
assert(seqIdx !== -1, 0x86f /* expected movedSeqs to contain unacked seq */);
|
|
212
|
-
|
|
193
|
+
segment.movedSeqs[seqIdx] = sequenceNumber;
|
|
213
194
|
|
|
214
|
-
if (
|
|
215
|
-
|
|
195
|
+
if (segment.movedSeq === UnassignedSequenceNumber) {
|
|
196
|
+
segment.movedSeq = sequenceNumber;
|
|
216
197
|
return true;
|
|
217
198
|
}
|
|
218
199
|
|
|
@@ -405,7 +386,6 @@ export function findRootMergeBlock(
|
|
|
405
386
|
* entries for all segments visited during excursion.
|
|
406
387
|
* This can reduce the number of times the tree needs to be scanned if a range containing many
|
|
407
388
|
* SlideOnRemove references is removed.
|
|
408
|
-
* @internal
|
|
409
389
|
*/
|
|
410
390
|
function getSlideToSegment(
|
|
411
391
|
segment: ISegmentLeaf | undefined,
|
|
@@ -434,7 +414,8 @@ function getSlideToSegment(
|
|
|
434
414
|
}
|
|
435
415
|
if (
|
|
436
416
|
cache !== undefined &&
|
|
437
|
-
(seg
|
|
417
|
+
(toRemovalInfo(seg)?.removedSeq === toRemovalInfo(segment)?.removedSeq ||
|
|
418
|
+
toMoveInfo(seg)?.movedSeq === toMoveInfo(segment)?.movedSeq)
|
|
438
419
|
) {
|
|
439
420
|
cache.set(seg, result);
|
|
440
421
|
}
|
|
@@ -492,7 +473,7 @@ export function getSlideToSegoff(
|
|
|
492
473
|
segment: ISegmentInternal | undefined;
|
|
493
474
|
offset: number | undefined;
|
|
494
475
|
} {
|
|
495
|
-
if (segoff.segment
|
|
476
|
+
if (!isSegmentLeaf(segoff.segment)) {
|
|
496
477
|
return segoff;
|
|
497
478
|
}
|
|
498
479
|
const [segment, _] = getSlideToSegment(
|
|
@@ -527,7 +508,7 @@ class Obliterates {
|
|
|
527
508
|
* See https://github.com/microsoft/FluidFramework/blob/main/packages/dds/merge-tree/docs/Obliterate.md#remote-perspective
|
|
528
509
|
* for additional context
|
|
529
510
|
*/
|
|
530
|
-
|
|
511
|
+
|
|
531
512
|
private readonly seqOrdered = new DoublyLinkedList<ObliterateInfo>();
|
|
532
513
|
|
|
533
514
|
/**
|
|
@@ -549,7 +530,6 @@ class Obliterates {
|
|
|
549
530
|
}
|
|
550
531
|
}
|
|
551
532
|
|
|
552
|
-
// eslint-disable-next-line import/no-deprecated
|
|
553
533
|
public addOrUpdate(obliterateInfo: ObliterateInfo): void {
|
|
554
534
|
const { seq, start } = obliterateInfo;
|
|
555
535
|
if (seq !== UnassignedSequenceNumber) {
|
|
@@ -562,14 +542,14 @@ class Obliterates {
|
|
|
562
542
|
return this.startOrdered.size === 0;
|
|
563
543
|
}
|
|
564
544
|
|
|
565
|
-
// eslint-disable-next-line import/no-deprecated
|
|
566
545
|
public findOverlapping(seg: ISegmentLeaf): Iterable<ObliterateInfo> {
|
|
567
|
-
// eslint-disable-next-line import/no-deprecated
|
|
568
546
|
const overlapping: ObliterateInfo[] = [];
|
|
569
547
|
for (const start of this.startOrdered.items) {
|
|
570
|
-
|
|
548
|
+
const startSeg = start.getSegment();
|
|
549
|
+
if (isMergeNodeInfo(startSeg) && startSeg.ordinal <= seg.ordinal) {
|
|
571
550
|
const ob = start.properties?.obliterate as ObliterateInfo;
|
|
572
|
-
|
|
551
|
+
const endSeg = ob.end.getSegment();
|
|
552
|
+
if (isMergeNodeInfo(endSeg) && endSeg.ordinal >= seg.ordinal) {
|
|
573
553
|
overlapping.push(ob);
|
|
574
554
|
}
|
|
575
555
|
} else {
|
|
@@ -593,10 +573,8 @@ export class MergeTree {
|
|
|
593
573
|
|
|
594
574
|
private static readonly theUnfinishedNode = { childCount: -1 } as unknown as MergeBlock;
|
|
595
575
|
|
|
596
|
-
// eslint-disable-next-line import/no-deprecated
|
|
597
576
|
public readonly collabWindow = new CollaborationWindow();
|
|
598
577
|
|
|
599
|
-
// eslint-disable-next-line import/no-deprecated
|
|
600
578
|
public readonly pendingSegments = new DoublyLinkedList<SegmentGroup>();
|
|
601
579
|
|
|
602
580
|
public readonly segmentsToScour = new Heap<LRUSegment>(LRUSegmentComparer);
|
|
@@ -675,7 +653,9 @@ export class MergeTree {
|
|
|
675
653
|
0x398 /* localSeq provided for local length without refSeq */,
|
|
676
654
|
);
|
|
677
655
|
assert(segment.seq !== undefined, 0x399 /* segment with no seq in mergeTree */);
|
|
678
|
-
const { seq
|
|
656
|
+
const { seq } = segment;
|
|
657
|
+
const { removedSeq, localRemovedSeq } = removalInfo ?? {};
|
|
658
|
+
const { movedSeq, localMovedSeq } = moveInfo ?? {};
|
|
679
659
|
if (seq === UnassignedSequenceNumber) {
|
|
680
660
|
assert(
|
|
681
661
|
segment.localSeq !== undefined,
|
|
@@ -717,13 +697,13 @@ export class MergeTree {
|
|
|
717
697
|
}
|
|
718
698
|
}
|
|
719
699
|
|
|
720
|
-
private addNode(block: MergeBlock, node:
|
|
700
|
+
private addNode(block: MergeBlock, node: IMergeNodeBuilder): number {
|
|
721
701
|
const index = block.childCount++;
|
|
722
|
-
|
|
702
|
+
assignChild(block, node, index, false);
|
|
723
703
|
return index;
|
|
724
704
|
}
|
|
725
705
|
|
|
726
|
-
public reloadFromSegments(segments:
|
|
706
|
+
public reloadFromSegments(segments: SegmentWithInfo<IInsertionInfo>[]): void {
|
|
727
707
|
// This code assumes that a later call to `startCollaboration()` will initialize partial lengths.
|
|
728
708
|
assert(
|
|
729
709
|
!this.collabWindow.collaborating,
|
|
@@ -733,7 +713,7 @@ export class MergeTree {
|
|
|
733
713
|
const maxChildren = MaxNodesInBlock - 1;
|
|
734
714
|
|
|
735
715
|
// Starting with the leaf segments, recursively builds the B-Tree layer by layer from the bottom up.
|
|
736
|
-
const buildMergeBlock = (nodes:
|
|
716
|
+
const buildMergeBlock = (nodes: IMergeNodeBuilder[]): IRootMergeBlock => {
|
|
737
717
|
const blockCount = Math.ceil(nodes.length / maxChildren); // Compute # blocks require for this level of B-Tree
|
|
738
718
|
const blocks: MergeBlock[] = Array.from({ length: blockCount }); // Pre-alloc array to collect nodes
|
|
739
719
|
|
|
@@ -789,8 +769,8 @@ export class MergeTree {
|
|
|
789
769
|
|
|
790
770
|
// TODO: 'seq' may be less than the current sequence number when inserting pre-ACKed
|
|
791
771
|
// segments from a snapshot. We currently skip these for now.
|
|
792
|
-
if (leaf.parent
|
|
793
|
-
leaf.parent
|
|
772
|
+
if (leaf.parent.needsScour !== true && seq > this.collabWindow.currentSeq) {
|
|
773
|
+
leaf.parent.needsScour = true;
|
|
794
774
|
this.segmentsToScour.add({ segment: leaf, maxSeq: seq });
|
|
795
775
|
}
|
|
796
776
|
}
|
|
@@ -834,34 +814,28 @@ export class MergeTree {
|
|
|
834
814
|
return totalOffset;
|
|
835
815
|
}
|
|
836
816
|
|
|
837
|
-
public getContainingSegment
|
|
817
|
+
public getContainingSegment(
|
|
838
818
|
pos: number,
|
|
839
819
|
refSeq: number,
|
|
840
820
|
clientId: number,
|
|
841
821
|
localSeq?: number,
|
|
842
822
|
): {
|
|
843
|
-
segment:
|
|
823
|
+
segment: ISegmentLeaf | undefined;
|
|
844
824
|
offset: number | undefined;
|
|
845
825
|
} {
|
|
846
826
|
assert(
|
|
847
827
|
localSeq === undefined || clientId === this.collabWindow.clientId,
|
|
848
828
|
0x39b /* localSeq provided for non-local client */,
|
|
849
829
|
);
|
|
850
|
-
let segment:
|
|
830
|
+
let segment: ISegmentLeaf | undefined;
|
|
851
831
|
let offset: number | undefined;
|
|
852
832
|
|
|
853
|
-
const leaf = (
|
|
854
|
-
leafSeg
|
|
855
|
-
segpos: number,
|
|
856
|
-
_refSeq: number,
|
|
857
|
-
_clientId: number,
|
|
858
|
-
start: number,
|
|
859
|
-
): boolean => {
|
|
860
|
-
segment = leafSeg as T;
|
|
833
|
+
const leaf = (leafSeg: ISegmentLeaf, _: number, start: number): boolean => {
|
|
834
|
+
segment = leafSeg;
|
|
861
835
|
offset = start;
|
|
862
836
|
return false;
|
|
863
837
|
};
|
|
864
|
-
this.nodeMap(refSeq, clientId, leaf, undefined,
|
|
838
|
+
this.nodeMap(refSeq, clientId, leaf, undefined, pos, pos + 1, localSeq);
|
|
865
839
|
return { segment, offset };
|
|
866
840
|
}
|
|
867
841
|
|
|
@@ -887,9 +861,7 @@ export class MergeTree {
|
|
|
887
861
|
*/
|
|
888
862
|
private slideAckedRemovedSegmentReferences(segments: ISegmentLeaf[]): void {
|
|
889
863
|
// References are slid in groups to preserve their order.
|
|
890
|
-
// eslint-disable-next-line import/no-deprecated
|
|
891
864
|
let currentForwardSlideGroup: LocalReferenceCollection[] = [];
|
|
892
|
-
// eslint-disable-next-line import/no-deprecated
|
|
893
865
|
let currentBackwardSlideGroup: LocalReferenceCollection[] = [];
|
|
894
866
|
|
|
895
867
|
let currentForwardMaybeEndpoint: "start" | "end" | undefined;
|
|
@@ -903,7 +875,6 @@ export class MergeTree {
|
|
|
903
875
|
const slideGroup = (
|
|
904
876
|
currentSlideDestination: ISegmentLeaf | undefined,
|
|
905
877
|
currentSlideIsForward: boolean | undefined,
|
|
906
|
-
// eslint-disable-next-line import/no-deprecated
|
|
907
878
|
currentSlideGroup: LocalReferenceCollection[],
|
|
908
879
|
pred: (ref: LocalReferencePosition) => boolean,
|
|
909
880
|
maybeEndpoint: "start" | "end" | undefined,
|
|
@@ -928,7 +899,6 @@ export class MergeTree {
|
|
|
928
899
|
|
|
929
900
|
if (maybeEndpoint) {
|
|
930
901
|
const endpoint = maybeEndpoint === "start" ? this.startOfTree : this.endOfTree;
|
|
931
|
-
// eslint-disable-next-line import/no-deprecated
|
|
932
902
|
const localRefs = LocalReferenceCollection.setOrGet(endpoint);
|
|
933
903
|
if (currentSlideIsForward) {
|
|
934
904
|
localRefs.addBeforeTombstones(...endpointRefsToAdd);
|
|
@@ -948,7 +918,6 @@ export class MergeTree {
|
|
|
948
918
|
}
|
|
949
919
|
}
|
|
950
920
|
} else {
|
|
951
|
-
// eslint-disable-next-line import/no-deprecated
|
|
952
921
|
const localRefs = LocalReferenceCollection.setOrGet(currentSlideDestination);
|
|
953
922
|
if (currentSlideIsForward) {
|
|
954
923
|
localRefs.addBeforeTombstones(...nonEndpointRefsToAdd);
|
|
@@ -962,13 +931,11 @@ export class MergeTree {
|
|
|
962
931
|
segment: ISegmentLeaf,
|
|
963
932
|
currentSlideDestination: ISegmentLeaf | undefined,
|
|
964
933
|
currentSlideIsForward: boolean | undefined,
|
|
965
|
-
// eslint-disable-next-line import/no-deprecated
|
|
966
934
|
currentSlideGroup: LocalReferenceCollection[],
|
|
967
935
|
pred: (ref: LocalReferencePosition) => boolean,
|
|
968
936
|
slidingPreference: SlidingPreference,
|
|
969
937
|
currentMaybeEndpoint: "start" | "end" | undefined,
|
|
970
938
|
reassign: (
|
|
971
|
-
// eslint-disable-next-line import/no-deprecated
|
|
972
939
|
localRefs: LocalReferenceCollection,
|
|
973
940
|
slideToSegment: ISegmentLeaf | undefined,
|
|
974
941
|
slideIsForward: boolean,
|
|
@@ -1091,7 +1058,6 @@ export class MergeTree {
|
|
|
1091
1058
|
return;
|
|
1092
1059
|
}
|
|
1093
1060
|
|
|
1094
|
-
// eslint-disable-next-line import/no-deprecated
|
|
1095
1061
|
const rebaseCollabWindow = new CollaborationWindow();
|
|
1096
1062
|
rebaseCollabWindow.loadFrom(this.collabWindow);
|
|
1097
1063
|
if (refSeq < this.collabWindow.minSeq) {
|
|
@@ -1214,13 +1180,13 @@ export class MergeTree {
|
|
|
1214
1180
|
clientId = this.collabWindow.clientId,
|
|
1215
1181
|
localSeq: number | undefined = this.collabWindow.localSeq,
|
|
1216
1182
|
): number {
|
|
1217
|
-
const seg
|
|
1218
|
-
if (seg
|
|
1183
|
+
const seg = refPos.getSegment();
|
|
1184
|
+
if (!isSegmentLeaf(seg)) {
|
|
1219
1185
|
// We have no idea where this reference is, because it refers to a segment which is not in the tree.
|
|
1220
1186
|
return DetachedReferencePosition;
|
|
1221
1187
|
}
|
|
1222
1188
|
if (refPos.isLeaf()) {
|
|
1223
|
-
return this.getPosition(
|
|
1189
|
+
return this.getPosition(seg, refSeq, clientId, localSeq);
|
|
1224
1190
|
}
|
|
1225
1191
|
if (refTypeIncludesFlag(refPos, ReferenceType.Transient) || seg.localRefs?.has(refPos)) {
|
|
1226
1192
|
if (
|
|
@@ -1229,13 +1195,15 @@ export class MergeTree {
|
|
|
1229
1195
|
!isSegmentPresent(seg, { refSeq, localSeq })
|
|
1230
1196
|
) {
|
|
1231
1197
|
const forward = refPos.slidingPreference === SlidingPreference.FORWARD;
|
|
1198
|
+
const moveInfo = toMoveInfo(seg);
|
|
1199
|
+
const removeInfo = toRemovalInfo(seg);
|
|
1232
1200
|
const slideSeq =
|
|
1233
|
-
|
|
1234
|
-
?
|
|
1235
|
-
:
|
|
1236
|
-
?
|
|
1201
|
+
moveInfo !== undefined && moveInfo.movedSeq !== UnassignedSequenceNumber
|
|
1202
|
+
? moveInfo.movedSeq
|
|
1203
|
+
: removeInfo !== undefined && removeInfo.removedSeq !== UnassignedSequenceNumber
|
|
1204
|
+
? removeInfo.removedSeq
|
|
1237
1205
|
: refSeq;
|
|
1238
|
-
const slideLocalSeq =
|
|
1206
|
+
const slideLocalSeq = moveInfo?.localMovedSeq ?? removeInfo?.localRemovedSeq;
|
|
1239
1207
|
const perspective = new PerspectiveImpl(this, {
|
|
1240
1208
|
refSeq: slideSeq,
|
|
1241
1209
|
localSeq: slideLocalSeq,
|
|
@@ -1272,14 +1240,13 @@ export class MergeTree {
|
|
|
1272
1240
|
let foundMarker: Marker | undefined;
|
|
1273
1241
|
|
|
1274
1242
|
const { segment } = this.getContainingSegment(startPos, UniversalSequenceNumber, clientId);
|
|
1275
|
-
|
|
1276
|
-
if (segWithParent?.parent === undefined) {
|
|
1243
|
+
if (!isSegmentLeaf(segment)) {
|
|
1277
1244
|
return undefined;
|
|
1278
1245
|
}
|
|
1279
1246
|
|
|
1280
1247
|
depthFirstNodeWalk(
|
|
1281
|
-
|
|
1282
|
-
|
|
1248
|
+
segment.parent,
|
|
1249
|
+
segment,
|
|
1283
1250
|
(node) => {
|
|
1284
1251
|
if (node.isLeaf()) {
|
|
1285
1252
|
if (Marker.is(node) && refHasTileLabel(node, markerLabel)) {
|
|
@@ -1310,8 +1277,8 @@ export class MergeTree {
|
|
|
1310
1277
|
private updateRoot(splitNode: MergeBlock | undefined): void {
|
|
1311
1278
|
if (splitNode !== undefined) {
|
|
1312
1279
|
const newRoot = this.makeBlock(2);
|
|
1313
|
-
|
|
1314
|
-
|
|
1280
|
+
assignChild(newRoot, this.root, 0, false);
|
|
1281
|
+
assignChild(newRoot, splitNode, 1, false);
|
|
1315
1282
|
this.root = newRoot;
|
|
1316
1283
|
this.nodeUpdateOrdinals(this.root);
|
|
1317
1284
|
this.nodeUpdateLengthNewStructure(this.root);
|
|
@@ -1339,8 +1306,8 @@ export class MergeTree {
|
|
|
1339
1306
|
if (MergeTree.options.zamboniSegments) {
|
|
1340
1307
|
this.addToLRUSet(pendingSegment, seq);
|
|
1341
1308
|
}
|
|
1342
|
-
if (!nodesToUpdate.includes(pendingSegment.parent
|
|
1343
|
-
nodesToUpdate.push(pendingSegment.parent
|
|
1309
|
+
if (!nodesToUpdate.includes(pendingSegment.parent)) {
|
|
1310
|
+
nodesToUpdate.push(pendingSegment.parent);
|
|
1344
1311
|
}
|
|
1345
1312
|
deltaSegments.push({
|
|
1346
1313
|
segment: pendingSegment,
|
|
@@ -1381,11 +1348,10 @@ export class MergeTree {
|
|
|
1381
1348
|
|
|
1382
1349
|
private addToPendingList(
|
|
1383
1350
|
segment: ISegmentLeaf,
|
|
1384
|
-
|
|
1351
|
+
|
|
1385
1352
|
segmentGroup?: SegmentGroup,
|
|
1386
1353
|
localSeq?: number,
|
|
1387
1354
|
previousProps?: PropertySet,
|
|
1388
|
-
// eslint-disable-next-line import/no-deprecated
|
|
1389
1355
|
): SegmentGroup {
|
|
1390
1356
|
let _segmentGroup = segmentGroup;
|
|
1391
1357
|
if (_segmentGroup === undefined) {
|
|
@@ -1409,7 +1375,7 @@ export class MergeTree {
|
|
|
1409
1375
|
if (previousProps) {
|
|
1410
1376
|
_segmentGroup.previousProps!.push(previousProps);
|
|
1411
1377
|
}
|
|
1412
|
-
|
|
1378
|
+
|
|
1413
1379
|
const segmentGroups = (segment.segmentGroups ??= new SegmentGroupCollection(segment));
|
|
1414
1380
|
segmentGroups.enqueue(_segmentGroup);
|
|
1415
1381
|
return _segmentGroup;
|
|
@@ -1442,7 +1408,7 @@ export class MergeTree {
|
|
|
1442
1408
|
if (relativePos.id) {
|
|
1443
1409
|
marker = this.getMarkerFromId(relativePos.id);
|
|
1444
1410
|
}
|
|
1445
|
-
if (marker) {
|
|
1411
|
+
if (isSegmentLeaf(marker)) {
|
|
1446
1412
|
pos = this.getPosition(marker, refseq, clientId);
|
|
1447
1413
|
if (relativePos.before) {
|
|
1448
1414
|
if (relativePos.offset !== undefined) {
|
|
@@ -1460,7 +1426,7 @@ export class MergeTree {
|
|
|
1460
1426
|
|
|
1461
1427
|
public insertSegments(
|
|
1462
1428
|
pos: number,
|
|
1463
|
-
segments:
|
|
1429
|
+
segments: ISegmentPrivate[],
|
|
1464
1430
|
refSeq: number,
|
|
1465
1431
|
clientId: number,
|
|
1466
1432
|
seq: number,
|
|
@@ -1527,7 +1493,7 @@ export class MergeTree {
|
|
|
1527
1493
|
|
|
1528
1494
|
const { currentSeq, clientId } = this.collabWindow;
|
|
1529
1495
|
|
|
1530
|
-
if (segmentInfo?.segment) {
|
|
1496
|
+
if (isSegmentLeaf(segmentInfo?.segment)) {
|
|
1531
1497
|
const segmentPosition = this.getPosition(segmentInfo.segment, currentSeq, clientId);
|
|
1532
1498
|
return segmentPosition + segmentInfo.offset!;
|
|
1533
1499
|
} else {
|
|
@@ -1537,7 +1503,7 @@ export class MergeTree {
|
|
|
1537
1503
|
}
|
|
1538
1504
|
}
|
|
1539
1505
|
|
|
1540
|
-
private blockInsert<T extends
|
|
1506
|
+
private blockInsert<T extends ISegmentPrivate>(
|
|
1541
1507
|
pos: number,
|
|
1542
1508
|
refSeq: number,
|
|
1543
1509
|
clientId: number,
|
|
@@ -1555,7 +1521,7 @@ export class MergeTree {
|
|
|
1555
1521
|
});
|
|
1556
1522
|
return siblingExists;
|
|
1557
1523
|
};
|
|
1558
|
-
|
|
1524
|
+
|
|
1559
1525
|
let segmentGroup: SegmentGroup;
|
|
1560
1526
|
const saveIfLocal = (locSegment: ISegmentLeaf): void => {
|
|
1561
1527
|
// Save segment so we can assign sequence number when acked by server
|
|
@@ -1570,10 +1536,10 @@ export class MergeTree {
|
|
|
1570
1536
|
// In all other cases this has to be true (checked by addToLRUSet):
|
|
1571
1537
|
// locSegment.seq > this.collabWindow.currentSeq
|
|
1572
1538
|
else if (
|
|
1573
|
-
locSegment.seq
|
|
1539
|
+
locSegment.seq > this.collabWindow.minSeq &&
|
|
1574
1540
|
MergeTree.options.zamboniSegments
|
|
1575
1541
|
) {
|
|
1576
|
-
this.addToLRUSet(locSegment, locSegment.seq
|
|
1542
|
+
this.addToLRUSet(locSegment, locSegment.seq);
|
|
1577
1543
|
}
|
|
1578
1544
|
}
|
|
1579
1545
|
};
|
|
@@ -1582,6 +1548,7 @@ export class MergeTree {
|
|
|
1582
1548
|
_pos: number,
|
|
1583
1549
|
context: InsertContext,
|
|
1584
1550
|
// Keeping this function within the scope of blockInsert for readability.
|
|
1551
|
+
// eslint-disable-next-line unicorn/consistent-function-scoping
|
|
1585
1552
|
): ISegmentChanges => {
|
|
1586
1553
|
const segmentChanges: ISegmentChanges = {};
|
|
1587
1554
|
if (segment) {
|
|
@@ -1594,107 +1561,108 @@ export class MergeTree {
|
|
|
1594
1561
|
return segmentChanges;
|
|
1595
1562
|
};
|
|
1596
1563
|
|
|
1564
|
+
const insertInfo: IInsertionInfo = {
|
|
1565
|
+
clientId,
|
|
1566
|
+
seq,
|
|
1567
|
+
localSeq,
|
|
1568
|
+
};
|
|
1597
1569
|
// TODO: build tree from segs and insert all at once
|
|
1598
1570
|
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
|
-
}
|
|
1571
|
+
for (const newSegment of newSegments
|
|
1572
|
+
.filter((s) => s.cachedLength > 0)
|
|
1573
|
+
.map((s) => overwriteInfo(s, insertInfo))) {
|
|
1574
|
+
if (Marker.is(newSegment)) {
|
|
1575
|
+
const markerId = newSegment.getId();
|
|
1576
|
+
if (markerId) {
|
|
1577
|
+
this.idToMarker.set(markerId, newSegment);
|
|
1609
1578
|
}
|
|
1579
|
+
}
|
|
1610
1580
|
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1581
|
+
const splitNode = this.insertingWalk(this.root, insertPos, refSeq, clientId, seq, {
|
|
1582
|
+
leaf: onLeaf,
|
|
1583
|
+
candidateSegment: newSegment,
|
|
1584
|
+
continuePredicate: continueFrom,
|
|
1585
|
+
});
|
|
1616
1586
|
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1587
|
+
if (!isSegmentLeaf(newSegment)) {
|
|
1588
|
+
// Indicates an attempt to insert past the end of the merge-tree's content.
|
|
1589
|
+
const errorConstructor = localSeq === undefined ? DataProcessingError : UsageError;
|
|
1590
|
+
throw new errorConstructor("MergeTree insert failed", {
|
|
1591
|
+
currentSeq: this.collabWindow.currentSeq,
|
|
1592
|
+
minSeq: this.collabWindow.minSeq,
|
|
1593
|
+
segSeq: insertInfo.seq,
|
|
1594
|
+
});
|
|
1595
|
+
}
|
|
1626
1596
|
|
|
1627
|
-
|
|
1597
|
+
this.updateRoot(splitNode);
|
|
1628
1598
|
|
|
1629
|
-
|
|
1599
|
+
insertPos += newSegment.cachedLength;
|
|
1630
1600
|
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1601
|
+
if (!this.options?.mergeTreeEnableObliterate || this.obliterates.empty()) {
|
|
1602
|
+
saveIfLocal(newSegment);
|
|
1603
|
+
continue;
|
|
1604
|
+
}
|
|
1635
1605
|
|
|
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
|
-
}
|
|
1606
|
+
let oldest: ObliterateInfo | undefined;
|
|
1607
|
+
let normalizedOldestSeq: number = 0;
|
|
1608
|
+
let newest: ObliterateInfo | undefined;
|
|
1609
|
+
let normalizedNewestSeq: number = 0;
|
|
1610
|
+
const movedClientIds: number[] = [];
|
|
1611
|
+
const movedSeqs: number[] = [];
|
|
1612
|
+
for (const ob of this.obliterates.findOverlapping(newSegment)) {
|
|
1613
|
+
// compute a normalized seq that takes into account local seqs
|
|
1614
|
+
// but is still comparable to remote seqs to keep the checks below easy
|
|
1615
|
+
// REMOTE SEQUENCE NUMBERS LOCAL SEQUENCE NUMBERS
|
|
1616
|
+
// [0, 1, 2, 3, ..., 100, ..., 1000, ..., (MAX - MaxLocalSeq), L1, L2, L3, L4, ..., L100, ..., L1000, ...(MAX)]
|
|
1617
|
+
const normalizedObSeq =
|
|
1618
|
+
ob.seq === UnassignedSequenceNumber
|
|
1619
|
+
? Number.MAX_SAFE_INTEGER - this.collabWindow.localSeq + ob.localSeq!
|
|
1620
|
+
: ob.seq;
|
|
1621
|
+
if (normalizedObSeq > refSeq) {
|
|
1622
|
+
if (oldest === undefined || normalizedOldestSeq > normalizedObSeq) {
|
|
1623
|
+
normalizedOldestSeq = normalizedObSeq;
|
|
1624
|
+
oldest = ob;
|
|
1625
|
+
movedClientIds.unshift(ob.clientId);
|
|
1626
|
+
movedSeqs.unshift(ob.seq);
|
|
1627
|
+
} else {
|
|
1628
|
+
movedClientIds.push(ob.clientId);
|
|
1629
|
+
movedSeqs.push(ob.seq);
|
|
1630
|
+
}
|
|
1631
|
+
if (newest === undefined || normalizedNewestSeq < normalizedObSeq) {
|
|
1632
|
+
normalizedNewestSeq = normalizedObSeq;
|
|
1633
|
+
newest = ob;
|
|
1665
1634
|
}
|
|
1666
1635
|
}
|
|
1636
|
+
}
|
|
1667
1637
|
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
};
|
|
1638
|
+
if (oldest && newest?.clientId !== clientId) {
|
|
1639
|
+
const moveInfo: IMoveInfo = {
|
|
1640
|
+
movedClientIds,
|
|
1641
|
+
movedSeq: oldest.seq,
|
|
1642
|
+
movedSeqs,
|
|
1643
|
+
localMovedSeq: oldest.localSeq,
|
|
1644
|
+
wasMovedOnInsert: oldest.seq !== UnassignedSequenceNumber,
|
|
1645
|
+
};
|
|
1677
1646
|
|
|
1678
|
-
|
|
1647
|
+
overwriteInfo(newSegment, moveInfo);
|
|
1679
1648
|
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
this.addToPendingList(newSegment, oldest.segmentGroup);
|
|
1687
|
-
}
|
|
1649
|
+
if (moveInfo.localMovedSeq !== undefined) {
|
|
1650
|
+
assert(
|
|
1651
|
+
oldest.segmentGroup !== undefined,
|
|
1652
|
+
0x86c /* expected segment group to exist */,
|
|
1653
|
+
);
|
|
1688
1654
|
|
|
1689
|
-
|
|
1690
|
-
this.blockUpdatePathLengths(newSegment.parent, seq, clientId);
|
|
1691
|
-
}
|
|
1692
|
-
} else if (oldest && newest?.clientId === clientId) {
|
|
1693
|
-
newSegment.prevObliterateByInserter = newest;
|
|
1655
|
+
this.addToPendingList(newSegment, oldest.segmentGroup);
|
|
1694
1656
|
}
|
|
1695
1657
|
|
|
1696
|
-
|
|
1658
|
+
if (newSegment.parent) {
|
|
1659
|
+
this.blockUpdatePathLengths(newSegment.parent, seq, clientId);
|
|
1660
|
+
}
|
|
1661
|
+
} else if (oldest && newest?.clientId === clientId) {
|
|
1662
|
+
newSegment.prevObliterateByInserter = newest;
|
|
1697
1663
|
}
|
|
1664
|
+
|
|
1665
|
+
saveIfLocal(newSegment);
|
|
1698
1666
|
}
|
|
1699
1667
|
}
|
|
1700
1668
|
|
|
@@ -1706,7 +1674,8 @@ export class MergeTree {
|
|
|
1706
1674
|
return {};
|
|
1707
1675
|
}
|
|
1708
1676
|
|
|
1709
|
-
const next
|
|
1677
|
+
const next = segment.splitAt(pos)!;
|
|
1678
|
+
assertSegmentLeaf(next);
|
|
1710
1679
|
|
|
1711
1680
|
if (segment?.segmentGroups) {
|
|
1712
1681
|
next.segmentGroups ??= new SegmentGroupCollection(next);
|
|
@@ -1762,10 +1731,8 @@ export class MergeTree {
|
|
|
1762
1731
|
|
|
1763
1732
|
return (
|
|
1764
1733
|
newSeq > segSeq ||
|
|
1765
|
-
(node.movedSeq !==
|
|
1766
|
-
|
|
1767
|
-
node.movedSeq > seq) ||
|
|
1768
|
-
(node.removedSeq !== undefined &&
|
|
1734
|
+
(isMoved(node) && node.movedSeq !== UnassignedSequenceNumber && node.movedSeq > seq) ||
|
|
1735
|
+
(isRemoved(node) &&
|
|
1769
1736
|
node.removedSeq !== UnassignedSequenceNumber &&
|
|
1770
1737
|
node.removedSeq > seq)
|
|
1771
1738
|
);
|
|
@@ -1788,7 +1755,7 @@ export class MergeTree {
|
|
|
1788
1755
|
const children = block.children;
|
|
1789
1756
|
let childIndex: number;
|
|
1790
1757
|
let child: IMergeNode;
|
|
1791
|
-
let newNode:
|
|
1758
|
+
let newNode: IMergeNodeBuilder | undefined;
|
|
1792
1759
|
let fromSplit: MergeBlock | undefined;
|
|
1793
1760
|
for (childIndex = 0; childIndex < block.childCount; childIndex++) {
|
|
1794
1761
|
child = children[childIndex];
|
|
@@ -1812,7 +1779,7 @@ export class MergeTree {
|
|
|
1812
1779
|
const segment = child;
|
|
1813
1780
|
const segmentChanges = context.leaf(segment, _pos, context);
|
|
1814
1781
|
if (segmentChanges.replaceCurrent) {
|
|
1815
|
-
|
|
1782
|
+
assignChild(block, segmentChanges.replaceCurrent, childIndex, false);
|
|
1816
1783
|
segmentChanges.replaceCurrent.ordinal = child.ordinal;
|
|
1817
1784
|
}
|
|
1818
1785
|
if (segmentChanges.next) {
|
|
@@ -1865,7 +1832,7 @@ export class MergeTree {
|
|
|
1865
1832
|
block.children[i] = block.children[i - 1];
|
|
1866
1833
|
block.children[i].index = i;
|
|
1867
1834
|
}
|
|
1868
|
-
|
|
1835
|
+
assignChild(block, newNode, childIndex, false);
|
|
1869
1836
|
block.childCount++;
|
|
1870
1837
|
block.setOrdinal(newNode, childIndex);
|
|
1871
1838
|
if (block.childCount < MaxNodesInBlock) {
|
|
@@ -1900,7 +1867,7 @@ export class MergeTree {
|
|
|
1900
1867
|
// Update ordinals to reflect lowered child count
|
|
1901
1868
|
this.nodeUpdateOrdinals(node);
|
|
1902
1869
|
for (let i = 0; i < halfCount; i++) {
|
|
1903
|
-
|
|
1870
|
+
assignChild(newNode, node.children[halfCount + i], i, false);
|
|
1904
1871
|
node.children[halfCount + i] = undefined!;
|
|
1905
1872
|
}
|
|
1906
1873
|
this.nodeUpdateLengthNewStructure(node);
|
|
@@ -1937,7 +1904,7 @@ export class MergeTree {
|
|
|
1937
1904
|
clientId: number,
|
|
1938
1905
|
seq: number,
|
|
1939
1906
|
opArgs: IMergeTreeDeltaOpArgs,
|
|
1940
|
-
|
|
1907
|
+
|
|
1941
1908
|
rollback: PropertiesRollback = PropertiesRollback.None,
|
|
1942
1909
|
): void {
|
|
1943
1910
|
if (propsOrAdjust.adjust !== undefined) {
|
|
@@ -1949,7 +1916,7 @@ export class MergeTree {
|
|
|
1949
1916
|
const deltaSegments: IMergeTreeSegmentDelta[] = [];
|
|
1950
1917
|
const localSeq =
|
|
1951
1918
|
seq === UnassignedSequenceNumber ? ++this.collabWindow.localSeq : undefined;
|
|
1952
|
-
|
|
1919
|
+
|
|
1953
1920
|
let segmentGroup: SegmentGroup | undefined;
|
|
1954
1921
|
const opObj = propsOrAdjust.props ?? propsOrAdjust.adjust;
|
|
1955
1922
|
const annotateSegment = (segment: ISegmentLeaf): boolean => {
|
|
@@ -1990,7 +1957,7 @@ export class MergeTree {
|
|
|
1990
1957
|
return true;
|
|
1991
1958
|
};
|
|
1992
1959
|
|
|
1993
|
-
this.nodeMap(refSeq, clientId, annotateSegment, undefined,
|
|
1960
|
+
this.nodeMap(refSeq, clientId, annotateSegment, undefined, start, end);
|
|
1994
1961
|
|
|
1995
1962
|
// OpArgs == undefined => test code
|
|
1996
1963
|
if (deltaSegments.length > 0) {
|
|
@@ -2024,10 +1991,10 @@ export class MergeTree {
|
|
|
2024
1991
|
|
|
2025
1992
|
let _overwrite = false;
|
|
2026
1993
|
const localOverlapWithRefs: ISegmentLeaf[] = [];
|
|
2027
|
-
const movedSegments:
|
|
1994
|
+
const movedSegments: SegmentWithInfo<IMoveInfo, ISegmentLeaf>[] = [];
|
|
2028
1995
|
const localSeq =
|
|
2029
1996
|
seq === UnassignedSequenceNumber ? ++this.collabWindow.localSeq : undefined;
|
|
2030
|
-
|
|
1997
|
+
|
|
2031
1998
|
const obliterate: ObliterateInfo = {
|
|
2032
1999
|
clientId,
|
|
2033
2000
|
end: createDetachedLocalReferencePosition(undefined),
|
|
@@ -2041,7 +2008,7 @@ export class MergeTree {
|
|
|
2041
2008
|
const { segment: startSeg } = this.getContainingSegment(start.pos, refSeq, clientId);
|
|
2042
2009
|
const { segment: endSeg } = this.getContainingSegment(end.pos, refSeq, clientId);
|
|
2043
2010
|
assert(
|
|
2044
|
-
startSeg
|
|
2011
|
+
isSegmentLeaf(startSeg) && isSegmentLeaf(endSeg),
|
|
2045
2012
|
0xa3f /* segments cannot be undefined */,
|
|
2046
2013
|
);
|
|
2047
2014
|
|
|
@@ -2078,12 +2045,7 @@ export class MergeTree {
|
|
|
2078
2045
|
}
|
|
2079
2046
|
this.obliterates.addOrUpdate(obliterate);
|
|
2080
2047
|
|
|
2081
|
-
const markMoved = (
|
|
2082
|
-
segment: ISegmentLeaf,
|
|
2083
|
-
pos: number,
|
|
2084
|
-
_start: number,
|
|
2085
|
-
_end: number,
|
|
2086
|
-
): boolean => {
|
|
2048
|
+
const markMoved = (segment: ISegmentLeaf, pos: number): boolean => {
|
|
2087
2049
|
if (
|
|
2088
2050
|
(start.side === Side.After && startPos === pos + segment.cachedLength) || // exclusive start segment
|
|
2089
2051
|
(end.side === Side.Before &&
|
|
@@ -2103,26 +2065,28 @@ export class MergeTree {
|
|
|
2103
2065
|
return true;
|
|
2104
2066
|
}
|
|
2105
2067
|
|
|
2106
|
-
|
|
2068
|
+
const wasMovedOnInsert =
|
|
2107
2069
|
clientId !== segment.clientId &&
|
|
2108
2070
|
segment.seq !== undefined &&
|
|
2109
2071
|
seq !== UnassignedSequenceNumber &&
|
|
2110
|
-
(refSeq < segment.seq || segment.seq === UnassignedSequenceNumber)
|
|
2111
|
-
) {
|
|
2112
|
-
segment.wasMovedOnInsert = true;
|
|
2113
|
-
}
|
|
2072
|
+
(refSeq < segment.seq || segment.seq === UnassignedSequenceNumber);
|
|
2114
2073
|
|
|
2115
2074
|
if (existingMoveInfo === undefined) {
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2075
|
+
const movedSeg = overwriteInfo<IMoveInfo, ISegmentLeaf>(segment, {
|
|
2076
|
+
movedClientIds: [clientId],
|
|
2077
|
+
movedSeq: seq,
|
|
2078
|
+
localMovedSeq: localSeq,
|
|
2079
|
+
movedSeqs: [seq],
|
|
2080
|
+
wasMovedOnInsert,
|
|
2081
|
+
});
|
|
2120
2082
|
|
|
2121
|
-
if (!toRemovalInfo(
|
|
2122
|
-
movedSegments.push(
|
|
2083
|
+
if (!toRemovalInfo(movedSeg)) {
|
|
2084
|
+
movedSegments.push(movedSeg);
|
|
2123
2085
|
}
|
|
2124
2086
|
} else {
|
|
2125
2087
|
_overwrite = true;
|
|
2088
|
+
// never move wasMovedOnInsert from true to false
|
|
2089
|
+
existingMoveInfo.wasMovedOnInsert ||= wasMovedOnInsert;
|
|
2126
2090
|
if (existingMoveInfo.movedSeq === UnassignedSequenceNumber) {
|
|
2127
2091
|
// we moved this locally, but someone else moved it first
|
|
2128
2092
|
// so put them at the head of the list
|
|
@@ -2141,7 +2105,7 @@ export class MergeTree {
|
|
|
2141
2105
|
existingMoveInfo.movedSeqs.push(seq);
|
|
2142
2106
|
}
|
|
2143
2107
|
}
|
|
2144
|
-
|
|
2108
|
+
assertMoved(segment);
|
|
2145
2109
|
// Save segment so can assign moved sequence number when acked by server
|
|
2146
2110
|
if (this.collabWindow.collaborating) {
|
|
2147
2111
|
if (
|
|
@@ -2162,12 +2126,7 @@ export class MergeTree {
|
|
|
2162
2126
|
return true;
|
|
2163
2127
|
};
|
|
2164
2128
|
|
|
2165
|
-
const afterMarkMoved = (
|
|
2166
|
-
node: MergeBlock,
|
|
2167
|
-
pos: number,
|
|
2168
|
-
_start: number,
|
|
2169
|
-
_end: number,
|
|
2170
|
-
): boolean => {
|
|
2129
|
+
const afterMarkMoved = (node: MergeBlock): boolean => {
|
|
2171
2130
|
if (_overwrite) {
|
|
2172
2131
|
this.nodeUpdateLengthNewStructure(node);
|
|
2173
2132
|
} else {
|
|
@@ -2180,7 +2139,6 @@ export class MergeTree {
|
|
|
2180
2139
|
refSeq,
|
|
2181
2140
|
clientId,
|
|
2182
2141
|
markMoved,
|
|
2183
|
-
undefined,
|
|
2184
2142
|
afterMarkMoved,
|
|
2185
2143
|
start.pos,
|
|
2186
2144
|
end.pos + 1, // include the segment containing the end reference
|
|
@@ -2193,7 +2151,7 @@ export class MergeTree {
|
|
|
2193
2151
|
if (start.pos !== end.pos || start.side !== end.side) {
|
|
2194
2152
|
this.mergeTreeDeltaCallback?.(opArgs, {
|
|
2195
2153
|
operation: MergeTreeDeltaType.OBLITERATE,
|
|
2196
|
-
deltaSegments: movedSegments,
|
|
2154
|
+
deltaSegments: movedSegments.map((segment) => ({ segment })),
|
|
2197
2155
|
});
|
|
2198
2156
|
}
|
|
2199
2157
|
|
|
@@ -2201,7 +2159,7 @@ export class MergeTree {
|
|
|
2201
2159
|
// so we slide after eventing in case the consumer wants to make reference
|
|
2202
2160
|
// changes at remove time, like add a ref to track undo redo.
|
|
2203
2161
|
if (!this.collabWindow.collaborating || clientId !== this.collabWindow.clientId) {
|
|
2204
|
-
this.slideAckedRemovedSegmentReferences(movedSegments
|
|
2162
|
+
this.slideAckedRemovedSegmentReferences(movedSegments);
|
|
2205
2163
|
}
|
|
2206
2164
|
|
|
2207
2165
|
if (
|
|
@@ -2255,9 +2213,9 @@ export class MergeTree {
|
|
|
2255
2213
|
let _overwrite = false;
|
|
2256
2214
|
this.ensureIntervalBoundary(start, refSeq, clientId);
|
|
2257
2215
|
this.ensureIntervalBoundary(end, refSeq, clientId);
|
|
2258
|
-
|
|
2216
|
+
|
|
2259
2217
|
let segmentGroup: SegmentGroup;
|
|
2260
|
-
const removedSegments:
|
|
2218
|
+
const removedSegments: SegmentWithInfo<IRemovalInfo, ISegmentLeaf>[] = [];
|
|
2261
2219
|
const localOverlapWithRefs: ISegmentLeaf[] = [];
|
|
2262
2220
|
const localSeq =
|
|
2263
2221
|
seq === UnassignedSequenceNumber ? ++this.collabWindow.localSeq : undefined;
|
|
@@ -2270,12 +2228,14 @@ export class MergeTree {
|
|
|
2270
2228
|
const existingRemovalInfo = toRemovalInfo(segment);
|
|
2271
2229
|
|
|
2272
2230
|
if (existingRemovalInfo === undefined) {
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2231
|
+
const removed = overwriteInfo<IRemovalInfo, ISegmentLeaf>(segment, {
|
|
2232
|
+
removedClientIds: [clientId],
|
|
2233
|
+
removedSeq: seq,
|
|
2234
|
+
localRemovedSeq: localSeq,
|
|
2235
|
+
});
|
|
2276
2236
|
|
|
2277
|
-
if (!toMoveInfo(
|
|
2278
|
-
removedSegments.push(
|
|
2237
|
+
if (!toMoveInfo(removed)) {
|
|
2238
|
+
removedSegments.push(removed);
|
|
2279
2239
|
}
|
|
2280
2240
|
} else {
|
|
2281
2241
|
_overwrite = true;
|
|
@@ -2295,7 +2255,7 @@ export class MergeTree {
|
|
|
2295
2255
|
existingRemovalInfo.removedClientIds.push(clientId);
|
|
2296
2256
|
}
|
|
2297
2257
|
}
|
|
2298
|
-
|
|
2258
|
+
assertRemoved(segment);
|
|
2299
2259
|
// Save segment so we can assign removed sequence number when acked by server
|
|
2300
2260
|
if (this.collabWindow.collaborating) {
|
|
2301
2261
|
if (
|
|
@@ -2311,12 +2271,7 @@ export class MergeTree {
|
|
|
2311
2271
|
}
|
|
2312
2272
|
return true;
|
|
2313
2273
|
};
|
|
2314
|
-
const afterMarkRemoved = (
|
|
2315
|
-
node: MergeBlock,
|
|
2316
|
-
pos: number,
|
|
2317
|
-
_start: number,
|
|
2318
|
-
_end: number,
|
|
2319
|
-
): boolean => {
|
|
2274
|
+
const afterMarkRemoved = (node: MergeBlock): boolean => {
|
|
2320
2275
|
if (_overwrite) {
|
|
2321
2276
|
this.nodeUpdateLengthNewStructure(node);
|
|
2322
2277
|
} else {
|
|
@@ -2324,7 +2279,7 @@ export class MergeTree {
|
|
|
2324
2279
|
}
|
|
2325
2280
|
return true;
|
|
2326
2281
|
};
|
|
2327
|
-
this.nodeMap(refSeq, clientId, markRemoved,
|
|
2282
|
+
this.nodeMap(refSeq, clientId, markRemoved, afterMarkRemoved, start, end);
|
|
2328
2283
|
// these segments are already viewed as being removed locally and are not event-ed
|
|
2329
2284
|
// so can slide non-StayOnRemove refs immediately
|
|
2330
2285
|
this.slideAckedRemovedSegmentReferences(localOverlapWithRefs);
|
|
@@ -2332,14 +2287,14 @@ export class MergeTree {
|
|
|
2332
2287
|
if (removedSegments.length > 0) {
|
|
2333
2288
|
this.mergeTreeDeltaCallback?.(opArgs, {
|
|
2334
2289
|
operation: MergeTreeDeltaType.REMOVE,
|
|
2335
|
-
deltaSegments: removedSegments,
|
|
2290
|
+
deltaSegments: removedSegments.map((segment) => ({ segment })),
|
|
2336
2291
|
});
|
|
2337
2292
|
}
|
|
2338
2293
|
// these events are newly removed
|
|
2339
2294
|
// so we slide after eventing in case the consumer wants to make reference
|
|
2340
2295
|
// changes at remove time, like add a ref to track undo redo.
|
|
2341
2296
|
if (!this.collabWindow.collaborating || clientId !== this.collabWindow.clientId) {
|
|
2342
|
-
this.slideAckedRemovedSegmentReferences(removedSegments
|
|
2297
|
+
this.slideAckedRemovedSegmentReferences(removedSegments);
|
|
2343
2298
|
}
|
|
2344
2299
|
|
|
2345
2300
|
if (
|
|
@@ -2354,36 +2309,30 @@ export class MergeTree {
|
|
|
2354
2309
|
/**
|
|
2355
2310
|
* Revert an unacked local op
|
|
2356
2311
|
*/
|
|
2357
|
-
|
|
2312
|
+
|
|
2358
2313
|
public rollback(op: IMergeTreeDeltaOp, localOpMetadata: SegmentGroup): void {
|
|
2359
2314
|
if (op.type === MergeTreeDeltaType.REMOVE) {
|
|
2360
|
-
const pendingSegmentGroup = this.pendingSegments.pop
|
|
2315
|
+
const pendingSegmentGroup = this.pendingSegments.pop()?.data;
|
|
2361
2316
|
if (pendingSegmentGroup === undefined || pendingSegmentGroup !== localOpMetadata) {
|
|
2362
2317
|
throw new Error("Rollback op doesn't match last edit");
|
|
2363
2318
|
}
|
|
2364
2319
|
// Disabling because a for of loop causes the type of segment to be ISegmentLeaf, which does not have parent information stored
|
|
2365
2320
|
// eslint-disable-next-line unicorn/no-array-for-each
|
|
2366
2321
|
pendingSegmentGroup.segments.forEach((segment: ISegmentLeaf) => {
|
|
2367
|
-
const segmentSegmentGroup = segment?.segmentGroups?.pop
|
|
2322
|
+
const segmentSegmentGroup = segment?.segmentGroups?.pop();
|
|
2368
2323
|
assert(
|
|
2369
2324
|
segmentSegmentGroup === pendingSegmentGroup,
|
|
2370
2325
|
0x3ee /* Unexpected segmentGroup in segment */,
|
|
2371
2326
|
);
|
|
2372
2327
|
|
|
2373
2328
|
assert(
|
|
2374
|
-
segment.removedClientIds
|
|
2375
|
-
segment.removedClientIds[0] === this.collabWindow.clientId,
|
|
2329
|
+
isRemoved(segment) && segment.removedClientIds[0] === this.collabWindow.clientId,
|
|
2376
2330
|
0x39d /* Rollback segment removedClientId does not match local client */,
|
|
2377
2331
|
);
|
|
2378
|
-
|
|
2379
|
-
segment
|
|
2380
|
-
segment.localRemovedSeq = undefined;
|
|
2332
|
+
let updateNode: MergeBlock | undefined = segment.parent;
|
|
2333
|
+
removeRemovalInfo(segment);
|
|
2381
2334
|
|
|
2382
|
-
for (
|
|
2383
|
-
let updateNode = segment.parent;
|
|
2384
|
-
updateNode !== undefined;
|
|
2385
|
-
updateNode = updateNode.parent
|
|
2386
|
-
) {
|
|
2335
|
+
for (updateNode; updateNode !== undefined; updateNode = updateNode.parent) {
|
|
2387
2336
|
this.blockUpdateLength(
|
|
2388
2337
|
updateNode,
|
|
2389
2338
|
UnassignedSequenceNumber,
|
|
@@ -2405,7 +2354,7 @@ export class MergeTree {
|
|
|
2405
2354
|
op.type === MergeTreeDeltaType.INSERT ||
|
|
2406
2355
|
op.type === MergeTreeDeltaType.ANNOTATE
|
|
2407
2356
|
) {
|
|
2408
|
-
const pendingSegmentGroup = this.pendingSegments.pop
|
|
2357
|
+
const pendingSegmentGroup = this.pendingSegments.pop()?.data;
|
|
2409
2358
|
if (
|
|
2410
2359
|
pendingSegmentGroup === undefined ||
|
|
2411
2360
|
pendingSegmentGroup !== localOpMetadata ||
|
|
@@ -2414,8 +2363,8 @@ export class MergeTree {
|
|
|
2414
2363
|
throw new Error("Rollback op doesn't match last edit");
|
|
2415
2364
|
}
|
|
2416
2365
|
let i = 0;
|
|
2417
|
-
for (const segment of pendingSegmentGroup.segments
|
|
2418
|
-
const segmentSegmentGroup = segment?.segmentGroups?.pop
|
|
2366
|
+
for (const segment of pendingSegmentGroup.segments) {
|
|
2367
|
+
const segmentSegmentGroup = segment?.segmentGroups?.pop();
|
|
2419
2368
|
assert(
|
|
2420
2369
|
segmentSegmentGroup === pendingSegmentGroup,
|
|
2421
2370
|
0x3ef /* Unexpected segmentGroup in segment */,
|
|
@@ -2467,7 +2416,7 @@ export class MergeTree {
|
|
|
2467
2416
|
}
|
|
2468
2417
|
|
|
2469
2418
|
// If not removed, increase position
|
|
2470
|
-
if (seg
|
|
2419
|
+
if (!isRemoved(seg)) {
|
|
2471
2420
|
segmentPosition += seg.cachedLength;
|
|
2472
2421
|
}
|
|
2473
2422
|
|
|
@@ -2488,7 +2437,7 @@ export class MergeTree {
|
|
|
2488
2437
|
public removeLocalReferencePosition(
|
|
2489
2438
|
lref: LocalReferencePosition,
|
|
2490
2439
|
): LocalReferencePosition | undefined {
|
|
2491
|
-
const segment:
|
|
2440
|
+
const segment: ISegmentPrivate | undefined = lref.getSegment();
|
|
2492
2441
|
return segment?.localRefs?.removeLocalRef(lref);
|
|
2493
2442
|
}
|
|
2494
2443
|
|
|
@@ -2496,7 +2445,7 @@ export class MergeTree {
|
|
|
2496
2445
|
endOfTree = new EndOfTreeSegment(this);
|
|
2497
2446
|
|
|
2498
2447
|
public createLocalReferencePosition(
|
|
2499
|
-
_segment:
|
|
2448
|
+
_segment: ISegmentPrivate | "start" | "end",
|
|
2500
2449
|
offset: number,
|
|
2501
2450
|
refType: ReferenceType,
|
|
2502
2451
|
properties: PropertySet | undefined,
|
|
@@ -2517,7 +2466,6 @@ export class MergeTree {
|
|
|
2517
2466
|
"Can only create SlideOnRemove or Transient local reference position on a removed or obliterated segment",
|
|
2518
2467
|
);
|
|
2519
2468
|
}
|
|
2520
|
-
|
|
2521
2469
|
let segment: ISegmentLeaf;
|
|
2522
2470
|
|
|
2523
2471
|
if (_segment === "start") {
|
|
@@ -2525,10 +2473,10 @@ export class MergeTree {
|
|
|
2525
2473
|
} else if (_segment === "end") {
|
|
2526
2474
|
segment = this.endOfTree;
|
|
2527
2475
|
} else {
|
|
2476
|
+
assertSegmentLeaf(_segment);
|
|
2528
2477
|
segment = _segment;
|
|
2529
2478
|
}
|
|
2530
2479
|
|
|
2531
|
-
// eslint-disable-next-line import/no-deprecated
|
|
2532
2480
|
const localRefs = LocalReferenceCollection.setOrGet(segment);
|
|
2533
2481
|
|
|
2534
2482
|
const segRef = localRefs.createLocalRef(
|
|
@@ -2613,7 +2561,7 @@ export class MergeTree {
|
|
|
2613
2561
|
for (let i = 0; i < newOrder.length; i++) {
|
|
2614
2562
|
const seg = newOrder[i];
|
|
2615
2563
|
const { parent, index, ordinal } = currentOrder[i];
|
|
2616
|
-
|
|
2564
|
+
assignChild(parent, seg, index, false);
|
|
2617
2565
|
seg.ordinal = ordinal;
|
|
2618
2566
|
}
|
|
2619
2567
|
|
|
@@ -2811,8 +2759,7 @@ export class MergeTree {
|
|
|
2811
2759
|
this.nodeMap(
|
|
2812
2760
|
refSeq,
|
|
2813
2761
|
clientId,
|
|
2814
|
-
handler,
|
|
2815
|
-
accum,
|
|
2762
|
+
(seg, pos, _start, _end) => handler(seg, pos, refSeq, clientId, _start, _end, accum),
|
|
2816
2763
|
undefined,
|
|
2817
2764
|
start,
|
|
2818
2765
|
end,
|
|
@@ -2844,12 +2791,11 @@ export class MergeTree {
|
|
|
2844
2791
|
* but it will not count as a segment within the range. That is, it will be
|
|
2845
2792
|
* ignored for the purposes of tracking when traversal should end.
|
|
2846
2793
|
*/
|
|
2847
|
-
private nodeMap
|
|
2794
|
+
private nodeMap(
|
|
2848
2795
|
refSeq: number,
|
|
2849
2796
|
clientId: number,
|
|
2850
|
-
leaf:
|
|
2851
|
-
|
|
2852
|
-
post?: BlockAction<TClientData>,
|
|
2797
|
+
leaf: (segment: ISegmentLeaf, pos: number, start: number, end: number) => boolean,
|
|
2798
|
+
post?: (block: MergeBlock) => boolean,
|
|
2853
2799
|
start: number = 0,
|
|
2854
2800
|
end?: number,
|
|
2855
2801
|
localSeq?: number,
|
|
@@ -2895,17 +2841,14 @@ export class MergeTree {
|
|
|
2895
2841
|
}
|
|
2896
2842
|
|
|
2897
2843
|
if (node.isLeaf()) {
|
|
2898
|
-
if (leaf(node, pos,
|
|
2844
|
+
if (leaf(node, pos, start - pos, endPos - pos) === false) {
|
|
2899
2845
|
return NodeAction.Exit;
|
|
2900
2846
|
}
|
|
2901
2847
|
pos = nextPos;
|
|
2902
2848
|
}
|
|
2903
2849
|
},
|
|
2904
2850
|
undefined,
|
|
2905
|
-
post
|
|
2906
|
-
? undefined
|
|
2907
|
-
: (block): boolean =>
|
|
2908
|
-
post(block, pos, refSeq, clientId, start - pos, endPos - pos, accum),
|
|
2851
|
+
post,
|
|
2909
2852
|
);
|
|
2910
2853
|
}
|
|
2911
2854
|
}
|