@fluidframework/merge-tree 2.4.0-297027 → 2.4.0-297385
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/api-report/merge-tree.legacy.alpha.api.md +0 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/localReference.d.ts +1 -1
- package/dist/localReference.d.ts.map +1 -1
- package/dist/localReference.js.map +1 -1
- package/dist/mergeTree.d.ts +7 -7
- package/dist/mergeTree.d.ts.map +1 -1
- package/dist/mergeTree.js +33 -5
- package/dist/mergeTree.js.map +1 -1
- package/dist/mergeTreeNodes.d.ts +27 -8
- package/dist/mergeTreeNodes.d.ts.map +1 -1
- package/dist/mergeTreeNodes.js +0 -17
- package/dist/mergeTreeNodes.js.map +1 -1
- package/dist/revertibles.d.ts.map +1 -1
- package/dist/revertibles.js +4 -2
- package/dist/revertibles.js.map +1 -1
- package/dist/snapshotV1.d.ts.map +1 -1
- package/dist/snapshotV1.js +0 -2
- package/dist/snapshotV1.js.map +1 -1
- package/dist/snapshotlegacy.d.ts.map +1 -1
- package/dist/snapshotlegacy.js +0 -1
- package/dist/snapshotlegacy.js.map +1 -1
- package/dist/test/client.annotateMarker.spec.js.map +1 -1
- package/dist/test/client.applyMsg.spec.js +3 -3
- package/dist/test/client.applyMsg.spec.js.map +1 -1
- package/dist/test/client.localReference.spec.js.map +1 -1
- package/dist/test/client.rollback.spec.js.map +1 -1
- package/dist/test/mergeTree.annotate.spec.js +29 -19
- package/dist/test/mergeTree.annotate.spec.js.map +1 -1
- package/dist/test/obliterate.spec.js.map +1 -1
- package/dist/test/revertibleFarm.spec.js.map +1 -1
- package/dist/zamboni.js +2 -1
- package/dist/zamboni.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/localReference.d.ts +1 -1
- package/lib/localReference.d.ts.map +1 -1
- package/lib/localReference.js.map +1 -1
- package/lib/mergeTree.d.ts +7 -7
- package/lib/mergeTree.d.ts.map +1 -1
- package/lib/mergeTree.js +35 -7
- package/lib/mergeTree.js.map +1 -1
- package/lib/mergeTreeNodes.d.ts +27 -8
- package/lib/mergeTreeNodes.d.ts.map +1 -1
- package/lib/mergeTreeNodes.js +0 -17
- package/lib/mergeTreeNodes.js.map +1 -1
- package/lib/revertibles.d.ts.map +1 -1
- package/lib/revertibles.js +5 -3
- package/lib/revertibles.js.map +1 -1
- package/lib/snapshotV1.d.ts.map +1 -1
- package/lib/snapshotV1.js +0 -2
- package/lib/snapshotV1.js.map +1 -1
- package/lib/snapshotlegacy.d.ts.map +1 -1
- package/lib/snapshotlegacy.js +0 -1
- package/lib/snapshotlegacy.js.map +1 -1
- package/lib/test/client.annotateMarker.spec.js.map +1 -1
- package/lib/test/client.applyMsg.spec.js +3 -3
- package/lib/test/client.applyMsg.spec.js.map +1 -1
- package/lib/test/client.localReference.spec.js.map +1 -1
- package/lib/test/client.rollback.spec.js.map +1 -1
- package/lib/test/mergeTree.annotate.spec.js +29 -19
- package/lib/test/mergeTree.annotate.spec.js.map +1 -1
- package/lib/test/obliterate.spec.js.map +1 -1
- package/lib/test/revertibleFarm.spec.js.map +1 -1
- package/lib/zamboni.js +2 -1
- package/lib/zamboni.js.map +1 -1
- package/package.json +17 -17
- package/src/index.ts +1 -0
- package/src/localReference.ts +5 -5
- package/src/mergeTree.ts +92 -53
- package/src/mergeTreeNodes.ts +35 -29
- package/src/revertibles.ts +12 -5
- package/src/snapshotV1.ts +0 -2
- package/src/snapshotlegacy.ts +0 -1
- package/src/zamboni.ts +3 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/merge-tree",
|
|
3
|
-
"version": "2.4.0-
|
|
3
|
+
"version": "2.4.0-297385",
|
|
4
4
|
"description": "Merge tree",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -79,30 +79,30 @@
|
|
|
79
79
|
"temp-directory": "nyc/.nyc_output"
|
|
80
80
|
},
|
|
81
81
|
"dependencies": {
|
|
82
|
-
"@fluid-internal/client-utils": "2.4.0-
|
|
83
|
-
"@fluidframework/container-definitions": "2.4.0-
|
|
84
|
-
"@fluidframework/core-interfaces": "2.4.0-
|
|
85
|
-
"@fluidframework/core-utils": "2.4.0-
|
|
86
|
-
"@fluidframework/datastore-definitions": "2.4.0-
|
|
87
|
-
"@fluidframework/driver-definitions": "2.4.0-
|
|
88
|
-
"@fluidframework/runtime-definitions": "2.4.0-
|
|
89
|
-
"@fluidframework/runtime-utils": "2.4.0-
|
|
90
|
-
"@fluidframework/shared-object-base": "2.4.0-
|
|
91
|
-
"@fluidframework/telemetry-utils": "2.4.0-
|
|
82
|
+
"@fluid-internal/client-utils": "2.4.0-297385",
|
|
83
|
+
"@fluidframework/container-definitions": "2.4.0-297385",
|
|
84
|
+
"@fluidframework/core-interfaces": "2.4.0-297385",
|
|
85
|
+
"@fluidframework/core-utils": "2.4.0-297385",
|
|
86
|
+
"@fluidframework/datastore-definitions": "2.4.0-297385",
|
|
87
|
+
"@fluidframework/driver-definitions": "2.4.0-297385",
|
|
88
|
+
"@fluidframework/runtime-definitions": "2.4.0-297385",
|
|
89
|
+
"@fluidframework/runtime-utils": "2.4.0-297385",
|
|
90
|
+
"@fluidframework/shared-object-base": "2.4.0-297385",
|
|
91
|
+
"@fluidframework/telemetry-utils": "2.4.0-297385"
|
|
92
92
|
},
|
|
93
93
|
"devDependencies": {
|
|
94
94
|
"@arethetypeswrong/cli": "^0.15.2",
|
|
95
95
|
"@biomejs/biome": "~1.8.3",
|
|
96
|
-
"@fluid-internal/mocha-test-setup": "2.4.0-
|
|
97
|
-
"@fluid-private/stochastic-test-utils": "2.4.0-
|
|
98
|
-
"@fluid-private/test-pairwise-generator": "2.4.0-
|
|
96
|
+
"@fluid-internal/mocha-test-setup": "2.4.0-297385",
|
|
97
|
+
"@fluid-private/stochastic-test-utils": "2.4.0-297385",
|
|
98
|
+
"@fluid-private/test-pairwise-generator": "2.4.0-297385",
|
|
99
99
|
"@fluid-tools/benchmark": "^0.50.0",
|
|
100
100
|
"@fluid-tools/build-cli": "^0.46.0",
|
|
101
101
|
"@fluidframework/build-common": "^2.0.3",
|
|
102
102
|
"@fluidframework/build-tools": "^0.46.0",
|
|
103
103
|
"@fluidframework/eslint-config-fluid": "^5.4.0",
|
|
104
|
-
"@fluidframework/merge-tree-previous": "npm:@fluidframework/merge-tree
|
|
105
|
-
"@fluidframework/test-runtime-utils": "2.4.0-
|
|
104
|
+
"@fluidframework/merge-tree-previous": "npm:@fluidframework/merge-tree@~2.3.0",
|
|
105
|
+
"@fluidframework/test-runtime-utils": "2.4.0-297385",
|
|
106
106
|
"@microsoft/api-extractor": "7.47.8",
|
|
107
107
|
"@types/diff": "^3.5.1",
|
|
108
108
|
"@types/mocha": "^9.1.1",
|
|
@@ -137,7 +137,7 @@
|
|
|
137
137
|
"backCompat": false
|
|
138
138
|
}
|
|
139
139
|
},
|
|
140
|
-
"entrypoint": "
|
|
140
|
+
"entrypoint": "legacy"
|
|
141
141
|
},
|
|
142
142
|
"scripts": {
|
|
143
143
|
"api": "fluid-build . --task api",
|
package/src/index.ts
CHANGED
package/src/localReference.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { assert } from "@fluidframework/core-utils/internal";
|
|
|
7
7
|
import { UsageError } from "@fluidframework/telemetry-utils/internal";
|
|
8
8
|
|
|
9
9
|
import { DoublyLinkedList, ListNode, walkList } from "./collections/index.js";
|
|
10
|
-
import { ISegment } from "./mergeTreeNodes.js";
|
|
10
|
+
import { ISegmentInternal, type ISegment } from "./mergeTreeNodes.js";
|
|
11
11
|
import { TrackingGroup, TrackingGroupCollection } from "./mergeTreeTracking.js";
|
|
12
12
|
import { ReferenceType } from "./ops.js";
|
|
13
13
|
import { PropertySet, addProperties } from "./properties.js";
|
|
@@ -86,7 +86,7 @@ export interface LocalReferencePosition extends ReferencePosition {
|
|
|
86
86
|
class LocalReference implements LocalReferencePosition {
|
|
87
87
|
public properties: PropertySet | undefined;
|
|
88
88
|
|
|
89
|
-
private segment:
|
|
89
|
+
private segment: ISegmentInternal | undefined;
|
|
90
90
|
private offset: number = 0;
|
|
91
91
|
private listNode: ListNode<LocalReference> | undefined;
|
|
92
92
|
|
|
@@ -109,7 +109,7 @@ class LocalReference implements LocalReferencePosition {
|
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
public link(
|
|
112
|
-
segment:
|
|
112
|
+
segment: ISegmentInternal | undefined,
|
|
113
113
|
offset: number,
|
|
114
114
|
listNode: ListNode<LocalReference> | undefined,
|
|
115
115
|
): void {
|
|
@@ -132,7 +132,7 @@ class LocalReference implements LocalReferencePosition {
|
|
|
132
132
|
this.offset = offset;
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
-
public isLeaf(): this is
|
|
135
|
+
public isLeaf(): this is ISegmentInternal {
|
|
136
136
|
return false;
|
|
137
137
|
}
|
|
138
138
|
|
|
@@ -140,7 +140,7 @@ class LocalReference implements LocalReferencePosition {
|
|
|
140
140
|
this.properties = addProperties(this.properties, newProps);
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
-
public getSegment():
|
|
143
|
+
public getSegment(): ISegmentInternal | undefined {
|
|
144
144
|
return this.segment;
|
|
145
145
|
}
|
|
146
146
|
|
package/src/mergeTree.ts
CHANGED
|
@@ -49,7 +49,6 @@ import {
|
|
|
49
49
|
IMergeNode,
|
|
50
50
|
IMoveInfo,
|
|
51
51
|
IRemovalInfo,
|
|
52
|
-
ISegment,
|
|
53
52
|
ISegmentAction,
|
|
54
53
|
ISegmentChanges,
|
|
55
54
|
ISegmentLeaf,
|
|
@@ -63,6 +62,7 @@ import {
|
|
|
63
62
|
seqLTE,
|
|
64
63
|
toMoveInfo,
|
|
65
64
|
toRemovalInfo,
|
|
65
|
+
type ISegmentInternal,
|
|
66
66
|
// eslint-disable-next-line import/no-deprecated
|
|
67
67
|
type ObliterateInfo,
|
|
68
68
|
} from "./mergeTreeNodes.js";
|
|
@@ -80,7 +80,7 @@ import {
|
|
|
80
80
|
} from "./ops.js";
|
|
81
81
|
import { PartialSequenceLengths } from "./partialLengths.js";
|
|
82
82
|
import { PerspectiveImpl, isSegmentPresent } from "./perspective.js";
|
|
83
|
-
import { PropertySet, createMap, extend, extendIfUndefined } from "./properties.js";
|
|
83
|
+
import { PropertySet, clone, createMap, extend, extendIfUndefined } from "./properties.js";
|
|
84
84
|
import {
|
|
85
85
|
DetachedReferencePosition,
|
|
86
86
|
ReferencePosition,
|
|
@@ -89,12 +89,14 @@ import {
|
|
|
89
89
|
refTypeIncludesFlag,
|
|
90
90
|
} from "./referencePositions.js";
|
|
91
91
|
// eslint-disable-next-line import/no-deprecated
|
|
92
|
-
import {
|
|
92
|
+
import { SegmentGroupCollection } from "./segmentGroupCollection.js";
|
|
93
|
+
// eslint-disable-next-line import/no-deprecated
|
|
94
|
+
import { PropertiesManager, PropertiesRollback } from "./segmentPropertiesManager.js";
|
|
93
95
|
import { Side, type InteriorSequencePlace } from "./sequencePlace.js";
|
|
94
96
|
import { SortedSegmentSet } from "./sortedSegmentSet.js";
|
|
95
97
|
import { zamboniSegments } from "./zamboni.js";
|
|
96
98
|
|
|
97
|
-
function markSegmentMoved(seg:
|
|
99
|
+
function markSegmentMoved(seg: ISegmentLeaf, moveInfo: IMoveInfo): void {
|
|
98
100
|
seg.moveDst = moveInfo.moveDst;
|
|
99
101
|
seg.movedClientIds = [...moveInfo.movedClientIds];
|
|
100
102
|
seg.movedSeqs = [moveInfo.movedSeq];
|
|
@@ -103,29 +105,29 @@ function markSegmentMoved(seg: ISegment, moveInfo: IMoveInfo): void {
|
|
|
103
105
|
seg.wasMovedOnInsert = moveInfo.wasMovedOnInsert;
|
|
104
106
|
}
|
|
105
107
|
|
|
106
|
-
function isMoved(segment:
|
|
108
|
+
function isMoved(segment: ISegmentLeaf): segment is ISegmentLeaf & IMoveInfo {
|
|
107
109
|
return toMoveInfo(segment) !== undefined;
|
|
108
110
|
}
|
|
109
111
|
|
|
110
|
-
function isRemoved(segment:
|
|
112
|
+
function isRemoved(segment: ISegmentLeaf): segment is ISegmentLeaf & IRemovalInfo {
|
|
111
113
|
return toRemovalInfo(segment) !== undefined;
|
|
112
114
|
}
|
|
113
115
|
|
|
114
|
-
function isRemovedAndAcked(segment:
|
|
116
|
+
function isRemovedAndAcked(segment: ISegmentLeaf): segment is ISegmentLeaf & IRemovalInfo {
|
|
115
117
|
const removalInfo = toRemovalInfo(segment);
|
|
116
118
|
return removalInfo !== undefined && removalInfo.removedSeq !== UnassignedSequenceNumber;
|
|
117
119
|
}
|
|
118
120
|
|
|
119
|
-
function isMovedAndAcked(segment:
|
|
121
|
+
function isMovedAndAcked(segment: ISegmentLeaf): segment is ISegmentLeaf & IMoveInfo {
|
|
120
122
|
const moveInfo = toMoveInfo(segment);
|
|
121
123
|
return moveInfo !== undefined && moveInfo.movedSeq !== UnassignedSequenceNumber;
|
|
122
124
|
}
|
|
123
125
|
|
|
124
|
-
function isRemovedAndAckedOrMovedAndAcked(segment:
|
|
126
|
+
function isRemovedAndAckedOrMovedAndAcked(segment: ISegmentLeaf): boolean {
|
|
125
127
|
return isRemovedAndAcked(segment) || isMovedAndAcked(segment);
|
|
126
128
|
}
|
|
127
129
|
|
|
128
|
-
function isRemovedOrMoved(segment:
|
|
130
|
+
function isRemovedOrMoved(segment: ISegmentLeaf): boolean {
|
|
129
131
|
return isRemoved(segment) || isMoved(segment);
|
|
130
132
|
}
|
|
131
133
|
|
|
@@ -315,11 +317,11 @@ export function findRootMergeBlock(
|
|
|
315
317
|
* @internal
|
|
316
318
|
*/
|
|
317
319
|
function getSlideToSegment(
|
|
318
|
-
segment:
|
|
320
|
+
segment: ISegmentLeaf | undefined,
|
|
319
321
|
slidingPreference: SlidingPreference = SlidingPreference.FORWARD,
|
|
320
|
-
cache?: Map<
|
|
322
|
+
cache?: Map<ISegmentLeaf, { seg?: ISegmentLeaf }>,
|
|
321
323
|
useNewSlidingBehavior: boolean = false,
|
|
322
|
-
): [
|
|
324
|
+
): [ISegmentLeaf | undefined, "start" | "end" | undefined] {
|
|
323
325
|
if (
|
|
324
326
|
!segment ||
|
|
325
327
|
!isRemovedAndAckedOrMovedAndAcked(segment) ||
|
|
@@ -332,9 +334,9 @@ function getSlideToSegment(
|
|
|
332
334
|
if (cachedSegment !== undefined) {
|
|
333
335
|
return [cachedSegment.seg, undefined];
|
|
334
336
|
}
|
|
335
|
-
const result: { seg?:
|
|
337
|
+
const result: { seg?: ISegmentLeaf } = {};
|
|
336
338
|
cache?.set(segment, result);
|
|
337
|
-
const goFurtherToFindSlideToSegment = (seg:
|
|
339
|
+
const goFurtherToFindSlideToSegment = (seg: ISegmentLeaf): boolean => {
|
|
338
340
|
if (seg.seq !== UnassignedSequenceNumber && !isRemovedAndAckedOrMovedAndAcked(seg)) {
|
|
339
341
|
result.seg = seg;
|
|
340
342
|
return false;
|
|
@@ -392,11 +394,11 @@ function getSlideToSegment(
|
|
|
392
394
|
* @internal
|
|
393
395
|
*/
|
|
394
396
|
export function getSlideToSegoff(
|
|
395
|
-
segoff: { segment:
|
|
397
|
+
segoff: { segment: ISegmentInternal | undefined; offset: number | undefined },
|
|
396
398
|
slidingPreference: SlidingPreference = SlidingPreference.FORWARD,
|
|
397
399
|
useNewSlidingBehavior: boolean = false,
|
|
398
400
|
): {
|
|
399
|
-
segment:
|
|
401
|
+
segment: ISegmentInternal | undefined;
|
|
400
402
|
offset: number | undefined;
|
|
401
403
|
} {
|
|
402
404
|
if (segoff.segment === undefined) {
|
|
@@ -470,7 +472,7 @@ class Obliterates {
|
|
|
470
472
|
}
|
|
471
473
|
|
|
472
474
|
// eslint-disable-next-line import/no-deprecated
|
|
473
|
-
public findOverlapping(seg:
|
|
475
|
+
public findOverlapping(seg: ISegmentLeaf): Iterable<ObliterateInfo> {
|
|
474
476
|
// eslint-disable-next-line import/no-deprecated
|
|
475
477
|
const overlapping: ObliterateInfo[] = [];
|
|
476
478
|
for (const start of this.startOrdered.items) {
|
|
@@ -555,7 +557,7 @@ export class MergeTree {
|
|
|
555
557
|
* numbers corresponding to un-acked operations give valid results.
|
|
556
558
|
*/
|
|
557
559
|
public localNetLength(
|
|
558
|
-
segment:
|
|
560
|
+
segment: ISegmentLeaf,
|
|
559
561
|
refSeq?: number,
|
|
560
562
|
localSeq?: number,
|
|
561
563
|
): number | undefined {
|
|
@@ -631,7 +633,7 @@ export class MergeTree {
|
|
|
631
633
|
return index;
|
|
632
634
|
}
|
|
633
635
|
|
|
634
|
-
public reloadFromSegments(segments:
|
|
636
|
+
public reloadFromSegments(segments: ISegmentLeaf[]): void {
|
|
635
637
|
// This code assumes that a later call to `startCollaboration()` will initialize partial lengths.
|
|
636
638
|
assert(
|
|
637
639
|
!this.collabWindow.collaborating,
|
|
@@ -742,7 +744,7 @@ export class MergeTree {
|
|
|
742
744
|
return totalOffset;
|
|
743
745
|
}
|
|
744
746
|
|
|
745
|
-
public getContainingSegment<T extends
|
|
747
|
+
public getContainingSegment<T extends ISegmentLeaf>(
|
|
746
748
|
pos: number,
|
|
747
749
|
refSeq: number,
|
|
748
750
|
clientId: number,
|
|
@@ -759,7 +761,7 @@ export class MergeTree {
|
|
|
759
761
|
let offset: number | undefined;
|
|
760
762
|
|
|
761
763
|
const leaf = (
|
|
762
|
-
leafSeg:
|
|
764
|
+
leafSeg: ISegmentLeaf,
|
|
763
765
|
segpos: number,
|
|
764
766
|
_refSeq: number,
|
|
765
767
|
_clientId: number,
|
|
@@ -793,17 +795,17 @@ export class MergeTree {
|
|
|
793
795
|
*
|
|
794
796
|
* @param segments - An array of (not necessarily contiguous) segments with increasing ordinals.
|
|
795
797
|
*/
|
|
796
|
-
private slideAckedRemovedSegmentReferences(segments:
|
|
798
|
+
private slideAckedRemovedSegmentReferences(segments: ISegmentLeaf[]): void {
|
|
797
799
|
// References are slid in groups to preserve their order.
|
|
798
800
|
let currentForwardSlideGroup: LocalReferenceCollection[] = [];
|
|
799
801
|
let currentBackwardSlideGroup: LocalReferenceCollection[] = [];
|
|
800
802
|
|
|
801
803
|
let currentForwardMaybeEndpoint: "start" | "end" | undefined;
|
|
802
|
-
let currentForwardSlideDestination:
|
|
804
|
+
let currentForwardSlideDestination: ISegmentLeaf | undefined;
|
|
803
805
|
let currentForwardSlideIsForward: boolean | undefined;
|
|
804
806
|
|
|
805
807
|
let currentBackwardMaybeEndpoint: "start" | "end" | undefined;
|
|
806
|
-
let currentBackwardSlideDestination:
|
|
808
|
+
let currentBackwardSlideDestination: ISegmentLeaf | undefined;
|
|
807
809
|
let currentBackwardSlideIsForward: boolean | undefined;
|
|
808
810
|
|
|
809
811
|
const slideGroup = (
|
|
@@ -862,8 +864,8 @@ export class MergeTree {
|
|
|
862
864
|
};
|
|
863
865
|
|
|
864
866
|
const trySlideSegment = (
|
|
865
|
-
segment:
|
|
866
|
-
currentSlideDestination:
|
|
867
|
+
segment: ISegmentLeaf,
|
|
868
|
+
currentSlideDestination: ISegmentLeaf | undefined,
|
|
867
869
|
currentSlideIsForward: boolean | undefined,
|
|
868
870
|
currentSlideGroup: LocalReferenceCollection[],
|
|
869
871
|
pred: (ref: LocalReferencePosition) => boolean,
|
|
@@ -871,7 +873,7 @@ export class MergeTree {
|
|
|
871
873
|
currentMaybeEndpoint: "start" | "end" | undefined,
|
|
872
874
|
reassign: (
|
|
873
875
|
localRefs: LocalReferenceCollection,
|
|
874
|
-
slideToSegment:
|
|
876
|
+
slideToSegment: ISegmentLeaf | undefined,
|
|
875
877
|
slideIsForward: boolean,
|
|
876
878
|
maybeEndpoint: "start" | "end" | undefined,
|
|
877
879
|
) => void,
|
|
@@ -916,8 +918,8 @@ export class MergeTree {
|
|
|
916
918
|
}
|
|
917
919
|
};
|
|
918
920
|
|
|
919
|
-
const forwardSegmentCache = new Map<
|
|
920
|
-
const backwardSegmentCache = new Map<
|
|
921
|
+
const forwardSegmentCache = new Map<ISegmentLeaf, { seg?: ISegmentLeaf }>();
|
|
922
|
+
const backwardSegmentCache = new Map<ISegmentLeaf, { seg?: ISegmentLeaf }>();
|
|
921
923
|
for (const segment of segments) {
|
|
922
924
|
assert(
|
|
923
925
|
isRemovedAndAckedOrMovedAndAcked(segment),
|
|
@@ -1283,7 +1285,7 @@ export class MergeTree {
|
|
|
1283
1285
|
}
|
|
1284
1286
|
|
|
1285
1287
|
private addToPendingList(
|
|
1286
|
-
segment:
|
|
1288
|
+
segment: ISegmentLeaf,
|
|
1287
1289
|
// eslint-disable-next-line import/no-deprecated
|
|
1288
1290
|
segmentGroup?: SegmentGroup,
|
|
1289
1291
|
localSeq?: number,
|
|
@@ -1312,8 +1314,9 @@ export class MergeTree {
|
|
|
1312
1314
|
if (previousProps) {
|
|
1313
1315
|
_segmentGroup.previousProps!.push(previousProps);
|
|
1314
1316
|
}
|
|
1315
|
-
|
|
1316
|
-
segment.segmentGroups
|
|
1317
|
+
// eslint-disable-next-line import/no-deprecated
|
|
1318
|
+
const segmentGroups = (segment.segmentGroups ??= new SegmentGroupCollection(segment));
|
|
1319
|
+
segmentGroups.enqueue(_segmentGroup);
|
|
1317
1320
|
return _segmentGroup;
|
|
1318
1321
|
}
|
|
1319
1322
|
|
|
@@ -1362,7 +1365,7 @@ export class MergeTree {
|
|
|
1362
1365
|
|
|
1363
1366
|
public insertSegments(
|
|
1364
1367
|
pos: number,
|
|
1365
|
-
segments:
|
|
1368
|
+
segments: ISegmentLeaf[],
|
|
1366
1369
|
refSeq: number,
|
|
1367
1370
|
clientId: number,
|
|
1368
1371
|
seq: number,
|
|
@@ -1459,7 +1462,7 @@ export class MergeTree {
|
|
|
1459
1462
|
};
|
|
1460
1463
|
// eslint-disable-next-line import/no-deprecated
|
|
1461
1464
|
let segmentGroup: SegmentGroup;
|
|
1462
|
-
const saveIfLocal = (locSegment:
|
|
1465
|
+
const saveIfLocal = (locSegment: ISegmentLeaf): void => {
|
|
1463
1466
|
// Save segment so we can assign sequence number when acked by server
|
|
1464
1467
|
if (this.collabWindow.collaborating) {
|
|
1465
1468
|
if (
|
|
@@ -1480,7 +1483,7 @@ export class MergeTree {
|
|
|
1480
1483
|
}
|
|
1481
1484
|
};
|
|
1482
1485
|
const onLeaf = (
|
|
1483
|
-
segment:
|
|
1486
|
+
segment: ISegmentLeaf | undefined,
|
|
1484
1487
|
_pos: number,
|
|
1485
1488
|
context: InsertContext,
|
|
1486
1489
|
// Keeping this function within the scope of blockInsert for readability.
|
|
@@ -1603,14 +1606,42 @@ export class MergeTree {
|
|
|
1603
1606
|
}
|
|
1604
1607
|
|
|
1605
1608
|
private readonly splitLeafSegment = (
|
|
1606
|
-
segment:
|
|
1609
|
+
segment: ISegmentLeaf | undefined,
|
|
1607
1610
|
pos: number,
|
|
1608
1611
|
): ISegmentChanges => {
|
|
1609
1612
|
if (!(pos > 0 && segment)) {
|
|
1610
1613
|
return {};
|
|
1611
1614
|
}
|
|
1612
1615
|
|
|
1613
|
-
const next = segment.splitAt(pos)!;
|
|
1616
|
+
const next: ISegmentLeaf = segment.splitAt(pos)!;
|
|
1617
|
+
|
|
1618
|
+
if (segment?.segmentGroups) {
|
|
1619
|
+
// eslint-disable-next-line import/no-deprecated
|
|
1620
|
+
next.segmentGroups ??= new SegmentGroupCollection(next);
|
|
1621
|
+
segment.segmentGroups.copyTo(next);
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
if (segment.prevObliterateByInserter) {
|
|
1625
|
+
next.prevObliterateByInserter = segment.prevObliterateByInserter;
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
if (segment.properties) {
|
|
1629
|
+
if (segment.propertyManager === undefined) {
|
|
1630
|
+
next.properties = clone(segment.properties);
|
|
1631
|
+
} else {
|
|
1632
|
+
// eslint-disable-next-line import/no-deprecated
|
|
1633
|
+
next.propertyManager ??= new PropertiesManager();
|
|
1634
|
+
next.properties = segment.propertyManager.copyTo(
|
|
1635
|
+
segment.properties,
|
|
1636
|
+
next.properties,
|
|
1637
|
+
next.propertyManager,
|
|
1638
|
+
);
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
if (segment.localRefs) {
|
|
1642
|
+
segment.localRefs.split(pos, next);
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1614
1645
|
this.mergeTreeMaintenanceCallback?.(
|
|
1615
1646
|
{
|
|
1616
1647
|
operation: MergeTreeMaintenanceType.SPLIT,
|
|
@@ -1827,6 +1858,7 @@ export class MergeTree {
|
|
|
1827
1858
|
clientId: number,
|
|
1828
1859
|
seq: number,
|
|
1829
1860
|
opArgs: IMergeTreeDeltaOpArgs,
|
|
1861
|
+
|
|
1830
1862
|
// eslint-disable-next-line import/no-deprecated
|
|
1831
1863
|
rollback: PropertiesRollback = PropertiesRollback.None,
|
|
1832
1864
|
): void {
|
|
@@ -1837,19 +1869,25 @@ export class MergeTree {
|
|
|
1837
1869
|
seq === UnassignedSequenceNumber ? ++this.collabWindow.localSeq : undefined;
|
|
1838
1870
|
// eslint-disable-next-line import/no-deprecated
|
|
1839
1871
|
let segmentGroup: SegmentGroup | undefined;
|
|
1840
|
-
const annotateSegment = (segment:
|
|
1872
|
+
const annotateSegment = (segment: ISegmentLeaf): boolean => {
|
|
1841
1873
|
assert(
|
|
1842
1874
|
!Marker.is(segment) ||
|
|
1843
1875
|
!(reservedMarkerIdKey in props) ||
|
|
1844
1876
|
props.markerId === segment.properties?.markerId,
|
|
1845
1877
|
0x5ad /* Cannot change the markerId of an existing marker */,
|
|
1846
1878
|
);
|
|
1847
|
-
|
|
1879
|
+
|
|
1880
|
+
// eslint-disable-next-line import/no-deprecated
|
|
1881
|
+
const propertyManager = (segment.propertyManager ??= new PropertiesManager());
|
|
1882
|
+
const properties = (segment.properties ??= createMap());
|
|
1883
|
+
const propertyDeltas = propertyManager.addProperties(
|
|
1884
|
+
properties,
|
|
1848
1885
|
props,
|
|
1849
1886
|
seq,
|
|
1850
1887
|
this.collabWindow.collaborating,
|
|
1851
1888
|
rollback,
|
|
1852
1889
|
);
|
|
1890
|
+
|
|
1853
1891
|
if (!isRemovedOrMoved(segment)) {
|
|
1854
1892
|
deltaSegments.push({ segment, propertyDeltas });
|
|
1855
1893
|
}
|
|
@@ -1904,7 +1942,7 @@ export class MergeTree {
|
|
|
1904
1942
|
this.ensureIntervalBoundary(endPos, refSeq, clientId);
|
|
1905
1943
|
|
|
1906
1944
|
let _overwrite = overwrite;
|
|
1907
|
-
const localOverlapWithRefs:
|
|
1945
|
+
const localOverlapWithRefs: ISegmentLeaf[] = [];
|
|
1908
1946
|
const movedSegments: IMergeTreeSegmentDelta[] = [];
|
|
1909
1947
|
const localSeq =
|
|
1910
1948
|
seq === UnassignedSequenceNumber ? ++this.collabWindow.localSeq : undefined;
|
|
@@ -1960,7 +1998,7 @@ export class MergeTree {
|
|
|
1960
1998
|
this.obliterates.addOrUpdate(obliterate);
|
|
1961
1999
|
|
|
1962
2000
|
const markMoved = (
|
|
1963
|
-
segment:
|
|
2001
|
+
segment: ISegmentLeaf,
|
|
1964
2002
|
pos: number,
|
|
1965
2003
|
_start: number,
|
|
1966
2004
|
_end: number,
|
|
@@ -2142,11 +2180,11 @@ export class MergeTree {
|
|
|
2142
2180
|
// eslint-disable-next-line import/no-deprecated
|
|
2143
2181
|
let segmentGroup: SegmentGroup;
|
|
2144
2182
|
const removedSegments: IMergeTreeSegmentDelta[] = [];
|
|
2145
|
-
const localOverlapWithRefs:
|
|
2183
|
+
const localOverlapWithRefs: ISegmentLeaf[] = [];
|
|
2146
2184
|
const localSeq =
|
|
2147
2185
|
seq === UnassignedSequenceNumber ? ++this.collabWindow.localSeq : undefined;
|
|
2148
2186
|
const markRemoved = (
|
|
2149
|
-
segment:
|
|
2187
|
+
segment: ISegmentLeaf,
|
|
2150
2188
|
pos: number,
|
|
2151
2189
|
_start: number,
|
|
2152
2190
|
_end: number,
|
|
@@ -2245,10 +2283,10 @@ export class MergeTree {
|
|
|
2245
2283
|
if (pendingSegmentGroup === undefined || pendingSegmentGroup !== localOpMetadata) {
|
|
2246
2284
|
throw new Error("Rollback op doesn't match last edit");
|
|
2247
2285
|
}
|
|
2248
|
-
// Disabling because a for of loop causes the type of segment to be
|
|
2286
|
+
// Disabling because a for of loop causes the type of segment to be ISegmentLeaf, which does not have parent information stored
|
|
2249
2287
|
// eslint-disable-next-line unicorn/no-array-for-each
|
|
2250
2288
|
pendingSegmentGroup.segments.forEach((segment: ISegmentLeaf) => {
|
|
2251
|
-
const segmentSegmentGroup = segment
|
|
2289
|
+
const segmentSegmentGroup = segment?.segmentGroups?.pop?.();
|
|
2252
2290
|
assert(
|
|
2253
2291
|
segmentSegmentGroup === pendingSegmentGroup,
|
|
2254
2292
|
0x3ee /* Unexpected segmentGroup in segment */,
|
|
@@ -2298,8 +2336,8 @@ export class MergeTree {
|
|
|
2298
2336
|
throw new Error("Rollback op doesn't match last edit");
|
|
2299
2337
|
}
|
|
2300
2338
|
let i = 0;
|
|
2301
|
-
for (const segment of pendingSegmentGroup.segments) {
|
|
2302
|
-
const segmentSegmentGroup = segment
|
|
2339
|
+
for (const segment of pendingSegmentGroup.segments as ISegmentLeaf[]) {
|
|
2340
|
+
const segmentSegmentGroup = segment?.segmentGroups?.pop?.();
|
|
2303
2341
|
assert(
|
|
2304
2342
|
segmentSegmentGroup === pendingSegmentGroup,
|
|
2305
2343
|
0x3ef /* Unexpected segmentGroup in segment */,
|
|
@@ -2330,6 +2368,7 @@ export class MergeTree {
|
|
|
2330
2368
|
this.collabWindow.clientId,
|
|
2331
2369
|
UniversalSequenceNumber,
|
|
2332
2370
|
{ op: annotateOp },
|
|
2371
|
+
|
|
2333
2372
|
// eslint-disable-next-line import/no-deprecated
|
|
2334
2373
|
PropertiesRollback.Rollback,
|
|
2335
2374
|
);
|
|
@@ -2344,7 +2383,7 @@ export class MergeTree {
|
|
|
2344
2383
|
/**
|
|
2345
2384
|
* Walk the segments up to the current segment and calculate its position
|
|
2346
2385
|
*/
|
|
2347
|
-
private findRollbackPosition(segment:
|
|
2386
|
+
private findRollbackPosition(segment: ISegmentLeaf): number {
|
|
2348
2387
|
let segmentPosition = 0;
|
|
2349
2388
|
walkAllChildSegments(this.root, (seg) => {
|
|
2350
2389
|
// If we've found the desired segment, terminate the walk and return 'segmentPosition'.
|
|
@@ -2447,7 +2486,7 @@ export class MergeTree {
|
|
|
2447
2486
|
}
|
|
2448
2487
|
|
|
2449
2488
|
for (
|
|
2450
|
-
let segmentToSlide: ListNode<
|
|
2489
|
+
let segmentToSlide: ListNode<ISegmentLeaf> | undefined = lastLocalSegment,
|
|
2451
2490
|
nearerSegment = lastLocalSegment?.prev;
|
|
2452
2491
|
segmentToSlide !== undefined;
|
|
2453
2492
|
segmentToSlide = nearerSegment, nearerSegment = nearerSegment?.prev
|
|
@@ -2485,7 +2524,7 @@ export class MergeTree {
|
|
|
2485
2524
|
const newOrder = Array.from(affectedSegments, ({ data }) => data);
|
|
2486
2525
|
for (const seg of newOrder)
|
|
2487
2526
|
seg.localRefs?.walkReferences((lref) => lref.callbacks?.beforeSlide?.(lref));
|
|
2488
|
-
const perSegmentTrackingGroups = new Map<
|
|
2527
|
+
const perSegmentTrackingGroups = new Map<ISegmentLeaf, TrackingGroup[]>();
|
|
2489
2528
|
for (const segment of newOrder) {
|
|
2490
2529
|
const { trackingCollection } = segment;
|
|
2491
2530
|
const trackingGroups = [...trackingCollection.trackingGroups];
|
|
@@ -2550,7 +2589,7 @@ export class MergeTree {
|
|
|
2550
2589
|
* it can fix up its local state to align with what would be expected of the op it resubmits.
|
|
2551
2590
|
*/
|
|
2552
2591
|
public normalizeSegmentsOnRebase(): void {
|
|
2553
|
-
let currentRangeToNormalize = new DoublyLinkedList<
|
|
2592
|
+
let currentRangeToNormalize = new DoublyLinkedList<ISegmentLeaf>();
|
|
2554
2593
|
let rangeContainsLocalSegs = false;
|
|
2555
2594
|
let rangeContainsRemoteRemovedSegs = false;
|
|
2556
2595
|
const normalize = (): void => {
|
|
@@ -2573,7 +2612,7 @@ export class MergeTree {
|
|
|
2573
2612
|
currentRangeToNormalize.push(seg);
|
|
2574
2613
|
} else {
|
|
2575
2614
|
normalize();
|
|
2576
|
-
currentRangeToNormalize = new DoublyLinkedList<
|
|
2615
|
+
currentRangeToNormalize = new DoublyLinkedList<ISegmentLeaf>();
|
|
2577
2616
|
rangeContainsLocalSegs = false;
|
|
2578
2617
|
rangeContainsRemoteRemovedSegs = false;
|
|
2579
2618
|
}
|
package/src/mergeTreeNodes.ts
CHANGED
|
@@ -48,11 +48,43 @@ export interface IMergeNodeCommon {
|
|
|
48
48
|
ordinal: string;
|
|
49
49
|
isLeaf(): this is ISegment;
|
|
50
50
|
}
|
|
51
|
+
|
|
51
52
|
/**
|
|
53
|
+
* This interface exposes internal things to dds that leverage merge tree,
|
|
54
|
+
* like sequence and matrix.
|
|
55
|
+
*
|
|
56
|
+
* We use tiered interface to control visibility of segment properties.
|
|
57
|
+
* This sits between ISegment and ISegmentLeaf. It should only expose
|
|
58
|
+
* things tagged internal.
|
|
59
|
+
*
|
|
60
|
+
* @internal
|
|
61
|
+
*/
|
|
62
|
+
export type ISegmentInternal = ISegment & {
|
|
63
|
+
localRefs?: LocalReferenceCollection;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* We use tiered interface to control visibility of segment properties.
|
|
68
|
+
* This is the lowest interface and is not exported, it site below ISegment and ISegmentInternal.
|
|
69
|
+
* It should only expose unexported things.
|
|
70
|
+
*
|
|
52
71
|
* someday we may split tree leaves from segments, but for now they are the same
|
|
53
72
|
* this is just a convenience type that makes it clear that we need something that is both a segment and a leaf node
|
|
54
73
|
*/
|
|
55
|
-
export type ISegmentLeaf =
|
|
74
|
+
export type ISegmentLeaf = ISegmentInternal & {
|
|
75
|
+
parent?: MergeBlock;
|
|
76
|
+
// eslint-disable-next-line import/no-deprecated
|
|
77
|
+
segmentGroups?: SegmentGroupCollection;
|
|
78
|
+
// eslint-disable-next-line import/no-deprecated
|
|
79
|
+
propertyManager?: PropertiesManager;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* If a segment is inserted into an obliterated range,
|
|
83
|
+
* but the newest obliteration of that range was by the inserting client,
|
|
84
|
+
* then the segment is not obliterated because it is aware of the latest obliteration.
|
|
85
|
+
*/
|
|
86
|
+
prevObliterateByInserter?: ObliterateInfo;
|
|
87
|
+
};
|
|
56
88
|
export type IMergeNode = MergeBlock | ISegmentLeaf;
|
|
57
89
|
|
|
58
90
|
/**
|
|
@@ -160,13 +192,6 @@ export interface IMoveInfo {
|
|
|
160
192
|
* calculations
|
|
161
193
|
*/
|
|
162
194
|
wasMovedOnInsert: boolean;
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* If a segment is inserted into an obliterated range,
|
|
166
|
-
* but the newest obliteration of that range was by the inserting client,
|
|
167
|
-
* then the segment is not obliterated because it is aware of the latest obliteration.
|
|
168
|
-
*/
|
|
169
|
-
prevObliterateByInserter?: ObliterateInfo;
|
|
170
195
|
}
|
|
171
196
|
|
|
172
197
|
export function toMoveInfo(maybe: Partial<IMoveInfo> | undefined): IMoveInfo | undefined {
|
|
@@ -395,6 +420,7 @@ export interface SegmentActions<TClientData> {
|
|
|
395
420
|
* @deprecated This functionality was not meant to be exported and will be removed in a future release
|
|
396
421
|
* @legacy
|
|
397
422
|
* @alpha
|
|
423
|
+
* @privateRemarks After deprecation period this interface should be made internal
|
|
398
424
|
*/
|
|
399
425
|
export interface ObliterateInfo {
|
|
400
426
|
start: LocalReferencePosition;
|
|
@@ -705,7 +731,6 @@ export abstract class BaseSegment implements ISegment {
|
|
|
705
731
|
return undefined;
|
|
706
732
|
}
|
|
707
733
|
|
|
708
|
-
this.copyPropertiesTo(leafSegment);
|
|
709
734
|
// eslint-disable-next-line @typescript-eslint/no-this-alias, unicorn/no-this-assignment
|
|
710
735
|
const thisAsMergeSegment: ISegmentLeaf = this;
|
|
711
736
|
leafSegment.parent = thisAsMergeSegment.parent;
|
|
@@ -729,11 +754,8 @@ export abstract class BaseSegment implements ISegment {
|
|
|
729
754
|
leafSegment.movedSeqs = this.movedSeqs?.slice();
|
|
730
755
|
leafSegment.localMovedSeq = this.localMovedSeq;
|
|
731
756
|
leafSegment.wasMovedOnInsert = this.wasMovedOnInsert;
|
|
732
|
-
|
|
757
|
+
|
|
733
758
|
this.trackingCollection.copyTo(leafSegment);
|
|
734
|
-
if (this.localRefs) {
|
|
735
|
-
this.localRefs.split(pos, leafSegment);
|
|
736
|
-
}
|
|
737
759
|
if (this.attribution) {
|
|
738
760
|
leafSegment.attribution = this.attribution.splitAt(pos);
|
|
739
761
|
}
|
|
@@ -741,22 +763,6 @@ export abstract class BaseSegment implements ISegment {
|
|
|
741
763
|
return leafSegment;
|
|
742
764
|
}
|
|
743
765
|
|
|
744
|
-
private copyPropertiesTo(other: ISegment): void {
|
|
745
|
-
if (this.properties !== undefined) {
|
|
746
|
-
if (this.propertyManager) {
|
|
747
|
-
// eslint-disable-next-line import/no-deprecated
|
|
748
|
-
other.propertyManager = new PropertiesManager();
|
|
749
|
-
other.properties = this.propertyManager.copyTo(
|
|
750
|
-
this.properties,
|
|
751
|
-
other.properties,
|
|
752
|
-
other.propertyManager,
|
|
753
|
-
);
|
|
754
|
-
} else {
|
|
755
|
-
other.properties = clone(this.properties);
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
|
|
760
766
|
public abstract clone(): ISegment;
|
|
761
767
|
|
|
762
768
|
public append(other: ISegment): void {
|