@fluidframework/merge-tree 0.59.4001 → 1.1.0-75972
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/.eslintrc.js +1 -1
- package/README.md +1 -1
- package/REFERENCEPOSITIONS.md +199 -0
- package/dist/client.d.ts +30 -4
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +89 -47
- package/dist/client.js.map +1 -1
- package/dist/collections.d.ts +5 -4
- package/dist/collections.d.ts.map +1 -1
- package/dist/collections.js +17 -18
- package/dist/collections.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/localReference.d.ts +11 -3
- package/dist/localReference.d.ts.map +1 -1
- package/dist/localReference.js +25 -8
- package/dist/localReference.js.map +1 -1
- package/dist/mergeTree.d.ts +23 -3
- package/dist/mergeTree.d.ts.map +1 -1
- package/dist/mergeTree.js +136 -48
- package/dist/mergeTree.js.map +1 -1
- package/dist/mergeTreeDeltaCallback.d.ts +8 -10
- package/dist/mergeTreeDeltaCallback.d.ts.map +1 -1
- package/dist/mergeTreeDeltaCallback.js +6 -10
- package/dist/mergeTreeDeltaCallback.js.map +1 -1
- package/dist/opBuilder.js +6 -5
- package/dist/opBuilder.js.map +1 -1
- package/dist/ops.d.ts +12 -10
- package/dist/ops.d.ts.map +1 -1
- package/dist/ops.js +7 -7
- package/dist/ops.js.map +1 -1
- package/dist/referencePositions.d.ts +1 -1
- package/dist/referencePositions.d.ts.map +1 -1
- package/dist/referencePositions.js +3 -2
- package/dist/referencePositions.js.map +1 -1
- package/lib/client.d.ts +30 -4
- package/lib/client.d.ts.map +1 -1
- package/lib/client.js +89 -47
- package/lib/client.js.map +1 -1
- package/lib/collections.d.ts +5 -4
- package/lib/collections.d.ts.map +1 -1
- package/lib/collections.js +17 -18
- package/lib/collections.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/localReference.d.ts +11 -3
- package/lib/localReference.d.ts.map +1 -1
- package/lib/localReference.js +23 -7
- package/lib/localReference.js.map +1 -1
- package/lib/mergeTree.d.ts +23 -3
- package/lib/mergeTree.d.ts.map +1 -1
- package/lib/mergeTree.js +137 -49
- package/lib/mergeTree.js.map +1 -1
- package/lib/mergeTreeDeltaCallback.d.ts +8 -10
- package/lib/mergeTreeDeltaCallback.d.ts.map +1 -1
- package/lib/mergeTreeDeltaCallback.js +6 -10
- package/lib/mergeTreeDeltaCallback.js.map +1 -1
- package/lib/opBuilder.js +6 -5
- package/lib/opBuilder.js.map +1 -1
- package/lib/ops.d.ts +12 -10
- package/lib/ops.d.ts.map +1 -1
- package/lib/ops.js +7 -7
- package/lib/ops.js.map +1 -1
- package/lib/referencePositions.d.ts +1 -1
- package/lib/referencePositions.d.ts.map +1 -1
- package/lib/referencePositions.js +3 -2
- package/lib/referencePositions.js.map +1 -1
- package/package.json +17 -94
- package/src/client.ts +87 -27
- package/src/collections.ts +5 -4
- package/src/index.ts +1 -1
- package/src/localReference.ts +33 -8
- package/src/mergeTree.ts +136 -43
- package/src/mergeTreeDeltaCallback.ts +8 -10
- package/src/ops.ts +13 -10
- package/src/referencePositions.ts +3 -2
package/.eslintrc.js
CHANGED
package/README.md
CHANGED
|
@@ -89,7 +89,7 @@ A segment was inserted and/or removed on the remote client at the time client se
|
|
|
89
89
|
|
|
90
90
|
* The referenced sequence number is greater than or equal the server-assigned sequence number of the operation
|
|
91
91
|
that inserted/removed the segment.
|
|
92
|
-
* The client sent the operation that resulted in insertion/removal. (In which case, the client hadn't yet
|
|
92
|
+
* The client sent the operation that resulted in insertion/removal. (In which case, the client hadn't yet received
|
|
93
93
|
their sequenced op from the server but was aware of the insertion/removal because the client produced it locally.)
|
|
94
94
|
|
|
95
95
|
If both above conditions are false, then the insertion/removal happened "after" the remote operation, and
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# ReferencePosition Documentation
|
|
2
|
+
|
|
3
|
+
ReferencePositions are used to indicates a MergeTree position which is stable as operations are performed. There are two
|
|
4
|
+
types:
|
|
5
|
+
|
|
6
|
+
1. LocalReferences refer to a segment and offset within that segment
|
|
7
|
+
2. Markers are actual segments in the Merge Tree
|
|
8
|
+
|
|
9
|
+
The function `Client.localReferencePositionToPosition` returns the numerical position of a reference in the client's
|
|
10
|
+
current view.
|
|
11
|
+
|
|
12
|
+
## LocalReference behavior on Remove
|
|
13
|
+
|
|
14
|
+
By default, LocalReferences become detached when the segment they reference is removed.
|
|
15
|
+
The ReferenceTypes SlideOnRemove, StayOnRemove, and Transient change this behavior.
|
|
16
|
+
They are only valid for LocalReferences.
|
|
17
|
+
They are exclusive - a reference may be at most one of these types.
|
|
18
|
+
|
|
19
|
+
### SlideOnRemove
|
|
20
|
+
|
|
21
|
+
The reference will slide to the next farthest segment when the segment is removed and the remove has been acknowledged.
|
|
22
|
+
Sliding will look for the next valid segment.
|
|
23
|
+
A valid segment is one whose creation has been acknowledged and either hasn't been removed
|
|
24
|
+
or the remove is pending (not acknowledged).
|
|
25
|
+
If a farther segment is found, then the LocalReference will be changed to refer to that segment and have offset 0.
|
|
26
|
+
In the event that the slide is happening on the acknowledgement of a remove, the slide to a farther segment will not
|
|
27
|
+
change the numerical position of the reference.
|
|
28
|
+
If there is no there is no valid segment farther in the tree, then the slide will place the reference on the last valid segment.
|
|
29
|
+
The offset will be set to the last position in that segment.
|
|
30
|
+
In the event that the slide is happening on the acknowledgement of a remove, the reference would have been on the removed
|
|
31
|
+
segment. This slide from the removed segment to a nearer segment does change the numerical position of the reference.
|
|
32
|
+
If there is no valid position (all segments removed and acknowledged) then the reference is detached.
|
|
33
|
+
|
|
34
|
+
### StayOnRemove
|
|
35
|
+
|
|
36
|
+
The reference will stay on removed segments.
|
|
37
|
+
This behavior is only defined until the removed segment is cleaned up by Zamboni.
|
|
38
|
+
This is intended to be used only while collaborating (see below) while waiting for an acknowledgement.
|
|
39
|
+
|
|
40
|
+
### Transient
|
|
41
|
+
|
|
42
|
+
The reference is not tracked by the MergeTree.
|
|
43
|
+
It will continue to reference removed segments.
|
|
44
|
+
This behavior is only defined until the removed segment is cleaned up by Zamboni.
|
|
45
|
+
This is intended to be used to create transient references which may be compared with other references.
|
|
46
|
+
|
|
47
|
+
### Detached LocalReferences
|
|
48
|
+
|
|
49
|
+
A detached LocalReference does not reference a segment in the MergeTree.
|
|
50
|
+
It's position is defined to be `LocalReference.DetachedPosition` (-1).
|
|
51
|
+
|
|
52
|
+
### LocalReferences on Removed Segments
|
|
53
|
+
|
|
54
|
+
LocalReferences may reference removed segments:
|
|
55
|
+
|
|
56
|
+
* SlideOnRemove references may reference a removed segment which is pending (not acknoweldged)
|
|
57
|
+
* StayOnRemove references may reference removed segments
|
|
58
|
+
* Transient references may reference removed segments
|
|
59
|
+
|
|
60
|
+
The numerical position of a reference which is on a removed segment will be one more than the previous (nearer) segment.
|
|
61
|
+
If there is a farther segment that is not removed, this will be the same as the position of the start of that segment.
|
|
62
|
+
If there is no farther segment, then the reference position will be the length of the tree (one more than the last valid
|
|
63
|
+
position in the tree).
|
|
64
|
+
|
|
65
|
+
## Eventually Consistent References
|
|
66
|
+
|
|
67
|
+
Markers are segments in the MergeTree and are eventually consistent.
|
|
68
|
+
LocalReferences may be used as part of an eventually consistent feature.
|
|
69
|
+
For example, SharedIntervals are built using LocalReferences.
|
|
70
|
+
|
|
71
|
+
### Implementing Eventually Consistent LocalReferences
|
|
72
|
+
|
|
73
|
+
To implement an operation which creates LocalReferences which will be have an eventually consistent position:
|
|
74
|
+
|
|
75
|
+
1. Locally create the reference as StayOnRemove
|
|
76
|
+
2. Send the reference numerical position in an op
|
|
77
|
+
3. On acknowledgement of the local create:
|
|
78
|
+
1. set the `refType` of the reference to include `SlideOnRemove`
|
|
79
|
+
2. call `Client.getSlideToSegment` with the references current segment and offset to get the proper new location
|
|
80
|
+
3. Delete the old reference and create a new one with the returned values
|
|
81
|
+
4. Remote clients, on receiving the op, call `Client.getContainingSegment` followed by `Client.getSlideToSegment`
|
|
82
|
+
on the result. Call `Client.createLocalReferencePosition` with the result to create a `SlideOnRemove` reference.
|
|
83
|
+
5. If there is a dependency on the comparison of reference positions (such as the index in IntervalCollections)
|
|
84
|
+
must listen to the `beforeSlide` and `afterSlide` events on `IReferencePositionEvents`. When slide occurs the
|
|
85
|
+
relative position of references may have changed.
|
|
86
|
+
|
|
87
|
+
### Implementation Notes
|
|
88
|
+
|
|
89
|
+
This is the state diagram for the implementation of Eventually Consistent References.
|
|
90
|
+
|
|
91
|
+
```mermaid
|
|
92
|
+
flowchart LR
|
|
93
|
+
subgraph StayOnRemove
|
|
94
|
+
localCreate[Local Create Ref]
|
|
95
|
+
pendingRef(("Ref:StayOnRemove\nSegment:Pending|Normal"))
|
|
96
|
+
pendingRefPendingRemove((Ref:StayOnRemove\nSegment:Pending Remove))
|
|
97
|
+
pendingRefRemoved((Ref:StayOnRemove\nSegment:Removed))
|
|
98
|
+
localCreate-->pendingRef
|
|
99
|
+
pendingRef--local remove-->pendingRefPendingRemove
|
|
100
|
+
pendingRefPendingRemove--remote remove-->pendingRefRemoved
|
|
101
|
+
pendingRef--remote remove-->pendingRefRemoved
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
subgraph SlideOnRemove
|
|
105
|
+
remoteCreate[Remote Create Ref]
|
|
106
|
+
remoteChoice{Segment Removed?}
|
|
107
|
+
ref((Ref:SlideOnRemove\nSegment:Normal))
|
|
108
|
+
refPendingRemove((Ref:SlideOnRemove\nSegment:Pending Remove))
|
|
109
|
+
|
|
110
|
+
remoteCreate-->remoteChoice
|
|
111
|
+
remoteChoice--no-->ref
|
|
112
|
+
remoteChoice--locally-->refPendingRemove
|
|
113
|
+
ref--local remove-->refPendingRemove
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
slide{Slide To}
|
|
117
|
+
detached((Ref:Detached))
|
|
118
|
+
|
|
119
|
+
pendingRef--create ack-->ref
|
|
120
|
+
pendingRefPendingRemove--create ack-->refPendingRemove
|
|
121
|
+
pendingRefRemoved--create ack-->slide
|
|
122
|
+
remoteChoice--yes-->slide
|
|
123
|
+
ref--remote remove-->slide
|
|
124
|
+
refPendingRemove--remove ack-->slide
|
|
125
|
+
refPendingRemove--remote remove-->slide
|
|
126
|
+
slide--segment-->ref
|
|
127
|
+
slide--locally removed segment-->refPendingRemove
|
|
128
|
+
slide--no segment-->detached
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
This algorithm works because it ensures that slid reference slide to the same segment.
|
|
132
|
+
The slide only happens when both the creation of the reference and removal of the segment have been acknowledged.
|
|
133
|
+
When sliding we do not consider any local (unacknowledged) ops.
|
|
134
|
+
|
|
135
|
+
Keeping references on removed segments until they can be slid works well in most cases because of these properties:
|
|
136
|
+
|
|
137
|
+
1. Interval positions on removed segments appear as if they were on the following position in the string.
|
|
138
|
+
If the removed segment is between positions 5 and 6, the interval positions on the removed segment appear to be at
|
|
139
|
+
position 6. This matches where they will eventually slide, so slide will not cause a change in position as long as
|
|
140
|
+
segments are not slid over and it is not necessary to slide to the near end of the string.
|
|
141
|
+
2. Text inserted at the same location as the removed segment is inserted before the removed segment.
|
|
142
|
+
So if the removed segment is between 0 and 1 (“A[removed]B”), insertText(1, “X”) inserts before the removed segment
|
|
143
|
+
(“AX[removed]B”). This makes it hard to end up with local only segments to be slid over, which will mean it is rare
|
|
144
|
+
that slide visibly changes the interval position. It can still happen if there is a conflicting remove, but that is
|
|
145
|
+
much less likely.
|
|
146
|
+
|
|
147
|
+
#### Conflict Scenarios
|
|
148
|
+
|
|
149
|
+
Considering Create Interval / Remove Range conflicts, here are the scenarios
|
|
150
|
+
(before indicates the relative sequence order):
|
|
151
|
+
|
|
152
|
+
1. Local create before local remove. Interval position needs to slide on ack of the local remove.
|
|
153
|
+
2. Remote create before remote remove. Slide on receiving the remove.
|
|
154
|
+
3. Local remove before local create. This is impossible – once the segment is removed locally an
|
|
155
|
+
interval position can’t be created on it.
|
|
156
|
+
4. Remote remove before remote create. (Possible if ops are from different remote clients).
|
|
157
|
+
Slide on receiving the remote create.
|
|
158
|
+
5. Remote create before local remove. Slide on the ack of the local remove.
|
|
159
|
+
6. Local create before remote remove. Slide on receiving the remove.
|
|
160
|
+
7. Local remove before remote create. Slide on receiving the create.
|
|
161
|
+
8. Remote remove before local create. Slide on receiving the ack of the create.
|
|
162
|
+
|
|
163
|
+
### Why Eventually Consistent References Can Not Have Stable Order
|
|
164
|
+
|
|
165
|
+
In an ideal system reference positions would have stable order. Specifically:
|
|
166
|
+
|
|
167
|
+
1. If in any client state the position of a reference is less than the position of a specific item in the sequence,
|
|
168
|
+
then the position of that reference would always be less than or equal to the position of that item.
|
|
169
|
+
2. If in any client state the position of reference A is less than the position of reference B,
|
|
170
|
+
then the position of reference A would always be less than or equal to the position of reference B.
|
|
171
|
+
|
|
172
|
+
Neither of these properties is true for SlideOnRemove references. This is a result of them sliding over local
|
|
173
|
+
only segments. This could change the relative positions of the sliding reference at items that are slide over,
|
|
174
|
+
as well as any references on those items. Note that these properties do hold for items and references
|
|
175
|
+
once the creation has been acknowledged (sequenced by the server).
|
|
176
|
+
|
|
177
|
+
Supporting stable order is not possible in the current system because:
|
|
178
|
+
|
|
179
|
+
1. Removing a range may cause an multiple references that had been at different positions to all be at the same
|
|
180
|
+
position.
|
|
181
|
+
2. To preserve stable ordering, an insert that conflicts with that remove would need to be after some of those
|
|
182
|
+
references and before others.
|
|
183
|
+
3. Insertion position is specified as a numerical offset in the sequence, so can't specify where in the set
|
|
184
|
+
of references at a position to be inserted. (Technically there is enough information to do this within the
|
|
185
|
+
collab window. But that information is lost if reconnect/resubmit is required.)
|
|
186
|
+
|
|
187
|
+
Therefore implementing eventually consistent references with stable order would require adding additional
|
|
188
|
+
information to insert ops.
|
|
189
|
+
|
|
190
|
+
## Tests
|
|
191
|
+
|
|
192
|
+
* `packages\dds\merge-tree\src\test\client.localReference.spec.ts`
|
|
193
|
+
unit tests for LocalReferences
|
|
194
|
+
* `packages\dds\sequence\src\test\intervalCollection.spec.ts`
|
|
195
|
+
test LocalReferences as used in interval collections (including eventual consistency)
|
|
196
|
+
* `packages\test\test-end-to-end-tests\src\test\sharedInterval.spec.ts`
|
|
197
|
+
end-to-end tests using LocalReferences for interval collections.
|
|
198
|
+
These tests have only been minimally updated to reflect this implementation,
|
|
199
|
+
so they do not comprehensively test LocalReferences.
|
package/dist/client.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions"
|
|
|
8
8
|
import { IFluidDataStoreRuntime, IChannelStorageService } from "@fluidframework/datastore-definitions";
|
|
9
9
|
import { ISummaryTreeWithStats } from "@fluidframework/runtime-definitions";
|
|
10
10
|
import { ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
11
|
-
import { LocalReference } from "./localReference";
|
|
11
|
+
import { LocalReference, LocalReferencePosition } from "./localReference";
|
|
12
12
|
import { CollaborationWindow, ISegment, ISegmentAction, Marker, MergeTree, SegmentGroup } from "./mergeTree";
|
|
13
13
|
import { MergeTreeDeltaCallback } from "./mergeTreeDeltaCallback";
|
|
14
14
|
import { ICombiningOp, IJSONSegment, IMergeTreeAnnotateMsg, IMergeTreeDeltaOp, IMergeTreeGroupMsg, IMergeTreeInsertMsg, IMergeTreeRemoveMsg, IMergeTreeOp, IRelativePosition, ReferenceType } from "./ops";
|
|
@@ -109,9 +109,9 @@ export declare class Client {
|
|
|
109
109
|
/**
|
|
110
110
|
* @deprecated - use removeReferencePosition instead
|
|
111
111
|
*/
|
|
112
|
-
removeLocalReference(lref: LocalReference):
|
|
113
|
-
createLocalReferencePosition(segment: ISegment, offset: number, refType: ReferenceType, properties: PropertySet | undefined):
|
|
114
|
-
removeLocalReferencePosition(lref:
|
|
112
|
+
removeLocalReference(lref: LocalReference): LocalReferencePosition | undefined;
|
|
113
|
+
createLocalReferencePosition(segment: ISegment, offset: number | undefined, refType: ReferenceType, properties: PropertySet | undefined): LocalReferencePosition;
|
|
114
|
+
removeLocalReferencePosition(lref: LocalReferencePosition): LocalReferencePosition | undefined;
|
|
115
115
|
localReferencePositionToPosition(lref: ReferencePosition): number;
|
|
116
116
|
/**
|
|
117
117
|
* Given a position specified relative to a marker id, lookup the marker
|
|
@@ -152,6 +152,11 @@ export declare class Client {
|
|
|
152
152
|
* @param clientArgs - The client args for the op
|
|
153
153
|
*/
|
|
154
154
|
private getValidOpRange;
|
|
155
|
+
/**
|
|
156
|
+
* Gets the client args from the op if remote, otherwise uses the local clients info
|
|
157
|
+
* @param sequencedMessage - The sequencedMessage to get the client sequence args for
|
|
158
|
+
*/
|
|
159
|
+
private getClientSequenceArgsForMessage;
|
|
155
160
|
/**
|
|
156
161
|
* Gets the client args from the op if remote, otherwise uses the local clients info
|
|
157
162
|
* @param opArgs - The op arg to get the client sequence args for
|
|
@@ -173,6 +178,15 @@ export declare class Client {
|
|
|
173
178
|
* @param localSeq - The localSeq to find the position of the segment at
|
|
174
179
|
*/
|
|
175
180
|
protected findReconnectionPosition(segment: ISegment, localSeq: number): number;
|
|
181
|
+
/**
|
|
182
|
+
* Rebases a (local) position from the perspective `{ seq: seqNumberFrom, localSeq }` to the perspective
|
|
183
|
+
* of the current sequence number. This is desirable when rebasing operations for reconnection.
|
|
184
|
+
*
|
|
185
|
+
* If the position refers to a segment/offset that was removed by some operation between `seqNumberFrom` and
|
|
186
|
+
* the current sequence number, the returned position will align with the position of a reference given
|
|
187
|
+
* `SlideOnRemove` semantics.
|
|
188
|
+
*/
|
|
189
|
+
rebasePosition(pos: number, seqNumberFrom: number, localSeq: number): number;
|
|
176
190
|
private resetPendingDeltaToOps;
|
|
177
191
|
private applyRemoteOp;
|
|
178
192
|
applyStashedOp(op: IMergeTreeDeltaOp): SegmentGroup;
|
|
@@ -210,6 +224,18 @@ export declare class Client {
|
|
|
210
224
|
segment: T | undefined;
|
|
211
225
|
offset: number | undefined;
|
|
212
226
|
};
|
|
227
|
+
/**
|
|
228
|
+
* Returns the position to slide a reference to if a slide is required.
|
|
229
|
+
* @param segoff - The segment and offset to slide from
|
|
230
|
+
* @returns - segment and offset to slide the reference to
|
|
231
|
+
*/
|
|
232
|
+
getSlideToSegment(segoff: {
|
|
233
|
+
segment: ISegment | undefined;
|
|
234
|
+
offset: number | undefined;
|
|
235
|
+
}): {
|
|
236
|
+
segment: ISegment | undefined;
|
|
237
|
+
offset: number | undefined;
|
|
238
|
+
};
|
|
213
239
|
getPropertiesAtPosition(pos: number): PropertySet | undefined;
|
|
214
240
|
getRangeExtentsOfPosition(pos: number): {
|
|
215
241
|
posStart: number | undefined;
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AACtE,OAAO,EAAE,yBAAyB,EAAe,MAAM,sCAAsC,CAAC;AAC9F,OAAO,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAC;AACvG,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAC5E,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAMtE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/client.js
CHANGED
|
@@ -13,11 +13,11 @@ const constants_1 = require("./constants");
|
|
|
13
13
|
const localReference_1 = require("./localReference");
|
|
14
14
|
const mergeTree_1 = require("./mergeTree");
|
|
15
15
|
const opBuilder_1 = require("./opBuilder");
|
|
16
|
+
const ops_1 = require("./ops");
|
|
16
17
|
const snapshotlegacy_1 = require("./snapshotlegacy");
|
|
17
18
|
const snapshotLoader_1 = require("./snapshotLoader");
|
|
18
19
|
const textSegment_1 = require("./textSegment");
|
|
19
20
|
const snapshotV1_1 = require("./snapshotV1");
|
|
20
|
-
const referencePositions_1 = require("./referencePositions");
|
|
21
21
|
function elapsedMicroseconds(trace) {
|
|
22
22
|
return trace.trace().duration * 1000;
|
|
23
23
|
}
|
|
@@ -224,11 +224,7 @@ class Client {
|
|
|
224
224
|
return this.mergeTree.removeLocalReferencePosition(lref);
|
|
225
225
|
}
|
|
226
226
|
localReferencePositionToPosition(lref) {
|
|
227
|
-
|
|
228
|
-
if (segment === undefined) {
|
|
229
|
-
return referencePositions_1.DetachedReferencePosition;
|
|
230
|
-
}
|
|
231
|
-
return this.getPosition(segment) + lref.getOffset();
|
|
227
|
+
return this.mergeTree.referencePositionToLocalPosition(lref);
|
|
232
228
|
}
|
|
233
229
|
/**
|
|
234
230
|
* Given a position specified relative to a marker id, lookup the marker
|
|
@@ -247,7 +243,7 @@ class Client {
|
|
|
247
243
|
* @returns True if the remove was applied. False if it could not be.
|
|
248
244
|
*/
|
|
249
245
|
applyRemoveRangeOp(opArgs) {
|
|
250
|
-
(0, common_utils_1.assert)(opArgs.op.type ===
|
|
246
|
+
(0, common_utils_1.assert)(opArgs.op.type === ops_1.MergeTreeDeltaType.REMOVE, 0x02d /* "Unexpected op type on range remove!" */);
|
|
251
247
|
const op = opArgs.op;
|
|
252
248
|
const clientArgs = this.getClientSequenceArgs(opArgs);
|
|
253
249
|
const range = this.getValidOpRange(op, clientArgs);
|
|
@@ -268,7 +264,7 @@ class Client {
|
|
|
268
264
|
* @returns True if the annotate was applied. False if it could not be.
|
|
269
265
|
*/
|
|
270
266
|
applyAnnotateRangeOp(opArgs) {
|
|
271
|
-
(0, common_utils_1.assert)(opArgs.op.type ===
|
|
267
|
+
(0, common_utils_1.assert)(opArgs.op.type === ops_1.MergeTreeDeltaType.ANNOTATE, 0x02e /* "Unexpected op type on range annotate!" */);
|
|
272
268
|
const op = opArgs.op;
|
|
273
269
|
const clientArgs = this.getClientSequenceArgs(opArgs);
|
|
274
270
|
const range = this.getValidOpRange(op, clientArgs);
|
|
@@ -289,7 +285,7 @@ class Client {
|
|
|
289
285
|
* @returns True if the insert was applied. False if it could not be.
|
|
290
286
|
*/
|
|
291
287
|
applyInsertOp(opArgs) {
|
|
292
|
-
(0, common_utils_1.assert)(opArgs.op.type ===
|
|
288
|
+
(0, common_utils_1.assert)(opArgs.op.type === ops_1.MergeTreeDeltaType.INSERT, 0x02f /* "Unexpected op type on range insert!" */);
|
|
293
289
|
const op = opArgs.op;
|
|
294
290
|
const clientArgs = this.getClientSequenceArgs(opArgs);
|
|
295
291
|
const range = this.getValidOpRange(op, clientArgs);
|
|
@@ -358,12 +354,12 @@ class Client {
|
|
|
358
354
|
if (start === undefined
|
|
359
355
|
|| start < 0
|
|
360
356
|
|| start > length
|
|
361
|
-
|| start === length && op.type !==
|
|
357
|
+
|| start === length && op.type !== ops_1.MergeTreeDeltaType.INSERT) {
|
|
362
358
|
invalidPositions.push("start");
|
|
363
359
|
}
|
|
364
360
|
// Validate end if not insert, or insert has end
|
|
365
361
|
//
|
|
366
|
-
if (op.type !==
|
|
362
|
+
if (op.type !== ops_1.MergeTreeDeltaType.INSERT || end !== undefined) {
|
|
367
363
|
if (end === undefined || end <= start) {
|
|
368
364
|
invalidPositions.push("end");
|
|
369
365
|
}
|
|
@@ -389,13 +385,13 @@ class Client {
|
|
|
389
385
|
}
|
|
390
386
|
/**
|
|
391
387
|
* Gets the client args from the op if remote, otherwise uses the local clients info
|
|
392
|
-
* @param
|
|
388
|
+
* @param sequencedMessage - The sequencedMessage to get the client sequence args for
|
|
393
389
|
*/
|
|
394
|
-
|
|
390
|
+
getClientSequenceArgsForMessage(sequencedMessage) {
|
|
395
391
|
// If there this no sequenced message, then the op is local
|
|
396
392
|
// and unacked, so use this clients sequenced args
|
|
397
393
|
//
|
|
398
|
-
if (!
|
|
394
|
+
if (!sequencedMessage) {
|
|
399
395
|
const segWindow = this.getCollabWindow();
|
|
400
396
|
return {
|
|
401
397
|
clientId: segWindow.clientId,
|
|
@@ -405,12 +401,19 @@ class Client {
|
|
|
405
401
|
}
|
|
406
402
|
else {
|
|
407
403
|
return {
|
|
408
|
-
clientId: this.
|
|
409
|
-
referenceSequenceNumber:
|
|
410
|
-
sequenceNumber:
|
|
404
|
+
clientId: this.getOrAddShortClientId(sequencedMessage.clientId),
|
|
405
|
+
referenceSequenceNumber: sequencedMessage.referenceSequenceNumber,
|
|
406
|
+
sequenceNumber: sequencedMessage.sequenceNumber,
|
|
411
407
|
};
|
|
412
408
|
}
|
|
413
409
|
}
|
|
410
|
+
/**
|
|
411
|
+
* Gets the client args from the op if remote, otherwise uses the local clients info
|
|
412
|
+
* @param opArgs - The op arg to get the client sequence args for
|
|
413
|
+
*/
|
|
414
|
+
getClientSequenceArgs(opArgs) {
|
|
415
|
+
return this.getClientSequenceArgsForMessage(opArgs.sequencedMessage);
|
|
416
|
+
}
|
|
414
417
|
ackPendingSegment(opArgs) {
|
|
415
418
|
const ackOp = (deltaOpArgs) => {
|
|
416
419
|
let trace;
|
|
@@ -418,7 +421,7 @@ class Client {
|
|
|
418
421
|
trace = common_utils_1.Trace.start();
|
|
419
422
|
}
|
|
420
423
|
this.mergeTree.ackPendingSegment(deltaOpArgs);
|
|
421
|
-
if (deltaOpArgs.op.type ===
|
|
424
|
+
if (deltaOpArgs.op.type === ops_1.MergeTreeDeltaType.ANNOTATE) {
|
|
422
425
|
if (deltaOpArgs.op.combiningOp && (deltaOpArgs.op.combiningOp.name === "consensus")) {
|
|
423
426
|
this.updateConsensusProperty(deltaOpArgs.op, deltaOpArgs.sequencedMessage);
|
|
424
427
|
}
|
|
@@ -429,7 +432,7 @@ class Client {
|
|
|
429
432
|
this.accumWindow += (this.getCurrentSeq() - this.getCollabWindow().minSeq);
|
|
430
433
|
}
|
|
431
434
|
};
|
|
432
|
-
if (opArgs.op.type ===
|
|
435
|
+
if (opArgs.op.type === ops_1.MergeTreeDeltaType.GROUP) {
|
|
433
436
|
for (const memberOp of opArgs.op.ops) {
|
|
434
437
|
ackOp({
|
|
435
438
|
groupOp: opArgs.op,
|
|
@@ -510,6 +513,47 @@ class Client {
|
|
|
510
513
|
});
|
|
511
514
|
return segmentPosition;
|
|
512
515
|
}
|
|
516
|
+
/**
|
|
517
|
+
* Rebases a (local) position from the perspective `{ seq: seqNumberFrom, localSeq }` to the perspective
|
|
518
|
+
* of the current sequence number. This is desirable when rebasing operations for reconnection.
|
|
519
|
+
*
|
|
520
|
+
* If the position refers to a segment/offset that was removed by some operation between `seqNumberFrom` and
|
|
521
|
+
* the current sequence number, the returned position will align with the position of a reference given
|
|
522
|
+
* `SlideOnRemove` semantics.
|
|
523
|
+
*/
|
|
524
|
+
rebasePosition(pos, seqNumberFrom, localSeq) {
|
|
525
|
+
(0, common_utils_1.assert)(localSeq <= this.mergeTree.collabWindow.localSeq, 0x300 /* localSeq greater than collab window */);
|
|
526
|
+
let segment;
|
|
527
|
+
let posAccumulated = 0;
|
|
528
|
+
let offset = pos;
|
|
529
|
+
const isInsertedInView = (seg) => (seg.seq !== undefined && seg.seq !== constants_1.UnassignedSequenceNumber && seg.seq <= seqNumberFrom)
|
|
530
|
+
|| (seg.localSeq !== undefined && seg.localSeq <= localSeq);
|
|
531
|
+
const isRemovedFromView = ({ removedSeq, localRemovedSeq }) => (removedSeq !== undefined && removedSeq !== constants_1.UnassignedSequenceNumber && removedSeq <= seqNumberFrom)
|
|
532
|
+
|| (localRemovedSeq !== undefined && localRemovedSeq <= localSeq);
|
|
533
|
+
this.mergeTree.walkAllSegments(this.mergeTree.root, (seg) => {
|
|
534
|
+
(0, common_utils_1.assert)(seg.seq !== undefined || seg.localSeq !== undefined, 0x301 /* Either seq or localSeq should be defined */);
|
|
535
|
+
segment = seg;
|
|
536
|
+
if (isInsertedInView(seg) && !isRemovedFromView(seg)) {
|
|
537
|
+
posAccumulated += seg.cachedLength;
|
|
538
|
+
if (offset >= seg.cachedLength) {
|
|
539
|
+
offset -= seg.cachedLength;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
// Keep going while we've yet to reach the segment at the desired position
|
|
543
|
+
return posAccumulated <= pos;
|
|
544
|
+
});
|
|
545
|
+
(0, common_utils_1.assert)(segment !== undefined, 0x302 /* No segment found */);
|
|
546
|
+
const seqNumberTo = this.getCollabWindow().currentSeq;
|
|
547
|
+
if ((segment.removedSeq !== undefined &&
|
|
548
|
+
segment.removedSeq !== constants_1.UnassignedSequenceNumber &&
|
|
549
|
+
segment.removedSeq <= seqNumberTo)
|
|
550
|
+
|| (segment.localRemovedSeq !== undefined && segment.localRemovedSeq <= localSeq)) {
|
|
551
|
+
// Segment that the position was in has been removed: null out offset.
|
|
552
|
+
offset = 0;
|
|
553
|
+
}
|
|
554
|
+
(0, common_utils_1.assert)(0 <= offset && offset < segment.cachedLength, 0x303 /* Invalid offset */);
|
|
555
|
+
return this.findReconnectionPosition(segment, localSeq) + offset;
|
|
556
|
+
}
|
|
513
557
|
resetPendingDeltaToOps(resetOp, segmentGroup) {
|
|
514
558
|
var _a, _b;
|
|
515
559
|
(0, common_utils_1.assert)(!!segmentGroup, 0x033 /* "Segment group undefined" */);
|
|
@@ -527,7 +571,7 @@ class Client {
|
|
|
527
571
|
const segmentPosition = this.findReconnectionPosition(segment, segmentGroup.localSeq);
|
|
528
572
|
let newOp;
|
|
529
573
|
switch (resetOp.type) {
|
|
530
|
-
case
|
|
574
|
+
case ops_1.MergeTreeDeltaType.ANNOTATE:
|
|
531
575
|
(0, common_utils_1.assert)(((_b = segment.propertyManager) === null || _b === void 0 ? void 0 : _b.hasPendingProperties()) === true, 0x036 /* "Segment has no pending properties" */);
|
|
532
576
|
// if the segment has been removed, there's no need to send the annotate op
|
|
533
577
|
// unless the remove was local, in which case the annotate must have come
|
|
@@ -536,11 +580,11 @@ class Client {
|
|
|
536
580
|
newOp = (0, opBuilder_1.createAnnotateRangeOp)(segmentPosition, segmentPosition + segment.cachedLength, resetOp.props, resetOp.combiningOp);
|
|
537
581
|
}
|
|
538
582
|
break;
|
|
539
|
-
case
|
|
583
|
+
case ops_1.MergeTreeDeltaType.INSERT:
|
|
540
584
|
(0, common_utils_1.assert)(segment.seq === constants_1.UnassignedSequenceNumber, 0x037 /* "Segment already has assigned sequence number" */);
|
|
541
585
|
newOp = (0, opBuilder_1.createInsertSegmentOp)(segmentPosition, segment);
|
|
542
586
|
break;
|
|
543
|
-
case
|
|
587
|
+
case ops_1.MergeTreeDeltaType.REMOVE:
|
|
544
588
|
if (segment.localRemovedSeq !== undefined) {
|
|
545
589
|
newOp = (0, opBuilder_1.createRemoveRangeOp)(segmentPosition, segmentPosition + segment.cachedLength);
|
|
546
590
|
}
|
|
@@ -562,16 +606,16 @@ class Client {
|
|
|
562
606
|
const msg = opArgs.sequencedMessage;
|
|
563
607
|
this.getOrAddShortClientId(msg.clientId);
|
|
564
608
|
switch (op.type) {
|
|
565
|
-
case
|
|
609
|
+
case ops_1.MergeTreeDeltaType.INSERT:
|
|
566
610
|
this.applyInsertOp(opArgs);
|
|
567
611
|
break;
|
|
568
|
-
case
|
|
612
|
+
case ops_1.MergeTreeDeltaType.REMOVE:
|
|
569
613
|
this.applyRemoveRangeOp(opArgs);
|
|
570
614
|
break;
|
|
571
|
-
case
|
|
615
|
+
case ops_1.MergeTreeDeltaType.ANNOTATE:
|
|
572
616
|
this.applyAnnotateRangeOp(opArgs);
|
|
573
617
|
break;
|
|
574
|
-
case
|
|
618
|
+
case ops_1.MergeTreeDeltaType.GROUP: {
|
|
575
619
|
for (const memberOp of op.ops) {
|
|
576
620
|
this.applyRemoteOp({
|
|
577
621
|
op: memberOp,
|
|
@@ -588,19 +632,19 @@ class Client {
|
|
|
588
632
|
applyStashedOp(op) {
|
|
589
633
|
let metadata;
|
|
590
634
|
switch (op.type) {
|
|
591
|
-
case
|
|
635
|
+
case ops_1.MergeTreeDeltaType.INSERT:
|
|
592
636
|
this.applyInsertOp({ op });
|
|
593
637
|
metadata = this.peekPendingSegmentGroups();
|
|
594
638
|
break;
|
|
595
|
-
case
|
|
639
|
+
case ops_1.MergeTreeDeltaType.REMOVE:
|
|
596
640
|
this.applyRemoveRangeOp({ op });
|
|
597
641
|
metadata = this.peekPendingSegmentGroups();
|
|
598
642
|
break;
|
|
599
|
-
case
|
|
643
|
+
case ops_1.MergeTreeDeltaType.ANNOTATE:
|
|
600
644
|
this.applyAnnotateRangeOp({ op });
|
|
601
645
|
metadata = this.peekPendingSegmentGroups();
|
|
602
646
|
break;
|
|
603
|
-
case
|
|
647
|
+
case ops_1.MergeTreeDeltaType.GROUP:
|
|
604
648
|
return op.ops.map((o) => this.applyStashedOp(o));
|
|
605
649
|
default:
|
|
606
650
|
(0, common_utils_1.unreachableCase)(op, "unrecognized op type");
|
|
@@ -655,7 +699,7 @@ class Client {
|
|
|
655
699
|
*/
|
|
656
700
|
regeneratePendingOp(resetOp, segmentGroup) {
|
|
657
701
|
const opList = [];
|
|
658
|
-
if (resetOp.type ===
|
|
702
|
+
if (resetOp.type === ops_1.MergeTreeDeltaType.GROUP) {
|
|
659
703
|
if (Array.isArray(segmentGroup)) {
|
|
660
704
|
(0, common_utils_1.assert)(resetOp.ops.length === segmentGroup.length, 0x03a /* "Number of ops in 'resetOp' must match the number of segment groups provided." */);
|
|
661
705
|
for (let i = 0; i < resetOp.ops.length; i++) {
|
|
@@ -670,7 +714,7 @@ class Client {
|
|
|
670
714
|
}
|
|
671
715
|
}
|
|
672
716
|
else {
|
|
673
|
-
(0, common_utils_1.assert)(resetOp.type !==
|
|
717
|
+
(0, common_utils_1.assert)(resetOp.type !== ops_1.MergeTreeDeltaType.GROUP, 0x03c /* "Reset op has 'group' delta type!" */);
|
|
674
718
|
(0, common_utils_1.assert)(!Array.isArray(segmentGroup), 0x03d /* "segmentGroup is array rather than singleton!" */);
|
|
675
719
|
opList.push(...this.resetPendingDeltaToOps(resetOp, segmentGroup));
|
|
676
720
|
}
|
|
@@ -727,13 +771,13 @@ class Client {
|
|
|
727
771
|
groupOp,
|
|
728
772
|
};
|
|
729
773
|
switch (op.type) {
|
|
730
|
-
case
|
|
774
|
+
case ops_1.MergeTreeDeltaType.INSERT:
|
|
731
775
|
this.applyInsertOp(opArgs);
|
|
732
776
|
break;
|
|
733
|
-
case
|
|
777
|
+
case ops_1.MergeTreeDeltaType.ANNOTATE:
|
|
734
778
|
this.applyAnnotateRangeOp(opArgs);
|
|
735
779
|
break;
|
|
736
|
-
case
|
|
780
|
+
case ops_1.MergeTreeDeltaType.REMOVE:
|
|
737
781
|
this.applyRemoveRangeOp(opArgs);
|
|
738
782
|
break;
|
|
739
783
|
default:
|
|
@@ -764,18 +808,16 @@ class Client {
|
|
|
764
808
|
}
|
|
765
809
|
}
|
|
766
810
|
getContainingSegment(pos, op) {
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
}
|
|
778
|
-
return this.mergeTree.getContainingSegment(pos, seq, clientId);
|
|
811
|
+
const args = this.getClientSequenceArgsForMessage(op);
|
|
812
|
+
return this.mergeTree.getContainingSegment(pos, args.referenceSequenceNumber, args.clientId);
|
|
813
|
+
}
|
|
814
|
+
/**
|
|
815
|
+
* Returns the position to slide a reference to if a slide is required.
|
|
816
|
+
* @param segoff - The segment and offset to slide from
|
|
817
|
+
* @returns - segment and offset to slide the reference to
|
|
818
|
+
*/
|
|
819
|
+
getSlideToSegment(segoff) {
|
|
820
|
+
return this.mergeTree._getSlideToSegment(segoff);
|
|
779
821
|
}
|
|
780
822
|
getPropertiesAtPosition(pos) {
|
|
781
823
|
let propertiesAtPosition;
|