@fluidframework/merge-tree 2.0.0-internal.2.4.0 → 2.0.0-internal.3.0.1
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/dist/client.d.ts +20 -50
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +29 -146
- package/dist/client.js.map +1 -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/mergeTree.d.ts +22 -1
- package/dist/mergeTree.d.ts.map +1 -1
- package/dist/mergeTree.js +131 -2
- package/dist/mergeTree.js.map +1 -1
- package/dist/mergeTreeNodes.d.ts +1 -12
- package/dist/mergeTreeNodes.d.ts.map +1 -1
- package/dist/mergeTreeNodes.js.map +1 -1
- package/lib/client.d.ts +20 -50
- package/lib/client.d.ts.map +1 -1
- package/lib/client.js +30 -147
- package/lib/client.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/mergeTree.d.ts +22 -1
- package/lib/mergeTree.d.ts.map +1 -1
- package/lib/mergeTree.js +131 -2
- package/lib/mergeTree.js.map +1 -1
- package/lib/mergeTreeNodes.d.ts +1 -12
- package/lib/mergeTreeNodes.d.ts.map +1 -1
- package/lib/mergeTreeNodes.js.map +1 -1
- package/package.json +33 -17
- package/src/client.ts +82 -217
- package/src/index.ts +0 -1
- package/src/mergeTree.ts +152 -2
- package/src/mergeTreeNodes.ts +1 -13
package/dist/client.d.ts
CHANGED
|
@@ -7,31 +7,32 @@ import { IFluidSerializer } from "@fluidframework/shared-object-base";
|
|
|
7
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
|
-
import { ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
10
|
+
import type { IEventThisPlaceHolder, ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
11
|
+
import { TypedEventEmitter } from "@fluidframework/common-utils";
|
|
11
12
|
import { LocalReferencePosition } from "./localReference";
|
|
12
13
|
import { CollaborationWindow, ISegment, ISegmentAction, Marker, SegmentGroup } from "./mergeTreeNodes";
|
|
13
|
-
import {
|
|
14
|
+
import { IMergeTreeDeltaCallbackArgs, IMergeTreeMaintenanceCallbackArgs } from "./mergeTreeDeltaCallback";
|
|
14
15
|
import { ICombiningOp, IJSONSegment, IMergeTreeAnnotateMsg, IMergeTreeDeltaOp, IMergeTreeGroupMsg, IMergeTreeInsertMsg, IMergeTreeRemoveMsg, IMergeTreeOp, IRelativePosition, ReferenceType } from "./ops";
|
|
15
16
|
import { PropertySet } from "./properties";
|
|
16
17
|
import { IMergeTreeTextHelper } from "./textSegment";
|
|
17
18
|
import { ReferencePosition, RangeStackMap } from "./referencePositions";
|
|
18
|
-
import {
|
|
19
|
-
|
|
19
|
+
import { IMergeTreeDeltaOpArgs } from "./index";
|
|
20
|
+
/**
|
|
21
|
+
* Emitted before this client's merge-tree normalizes its segments on reconnect, potentially
|
|
22
|
+
* ordering them. Useful for DDS-like consumers built atop the merge-tree to compute any information
|
|
23
|
+
* they need for rebasing their ops on reconnection.
|
|
24
|
+
*
|
|
25
|
+
* @internal
|
|
26
|
+
*/
|
|
27
|
+
export interface IClientEvents {
|
|
28
|
+
(event: "normalize", listener: (target: IEventThisPlaceHolder) => void): any;
|
|
29
|
+
(event: "delta", listener: (opArgs: IMergeTreeDeltaOpArgs, deltaArgs: IMergeTreeDeltaCallbackArgs, target: IEventThisPlaceHolder) => void): any;
|
|
30
|
+
(event: "maintenance", listener: (args: IMergeTreeMaintenanceCallbackArgs, deltaArgs: IMergeTreeDeltaOpArgs | undefined, target: IEventThisPlaceHolder) => void): any;
|
|
31
|
+
}
|
|
32
|
+
export declare class Client extends TypedEventEmitter<IClientEvents> {
|
|
20
33
|
readonly specToSegment: (spec: IJSONSegment) => ISegment;
|
|
21
34
|
readonly logger: ITelemetryLogger;
|
|
22
|
-
measureOps: boolean;
|
|
23
|
-
accumTime: number;
|
|
24
|
-
localTime: number;
|
|
25
|
-
localOps: number;
|
|
26
|
-
accumWindowTime: number;
|
|
27
|
-
accumWindow: number;
|
|
28
|
-
accumOps: number;
|
|
29
|
-
maxWindowTime: number;
|
|
30
35
|
longClientId: string | undefined;
|
|
31
|
-
get mergeTreeDeltaCallback(): MergeTreeDeltaCallback | undefined;
|
|
32
|
-
set mergeTreeDeltaCallback(callback: MergeTreeDeltaCallback | undefined);
|
|
33
|
-
get mergeTreeMaintenanceCallback(): MergeTreeMaintenanceCallback | undefined;
|
|
34
|
-
set mergeTreeMaintenanceCallback(callback: MergeTreeMaintenanceCallback | undefined);
|
|
35
36
|
private readonly _mergeTree;
|
|
36
37
|
private readonly clientNameToIds;
|
|
37
38
|
private readonly shortClientIdMap;
|
|
@@ -87,7 +88,6 @@ export declare class Client {
|
|
|
87
88
|
* @param segment - The segment to insert
|
|
88
89
|
*/
|
|
89
90
|
insertAtReferencePositionLocal(refPos: ReferencePosition, segment: ISegment): IMergeTreeInsertMsg | undefined;
|
|
90
|
-
private traceOp;
|
|
91
91
|
walkSegments<TClientData>(handler: ISegmentAction<TClientData>, start: number | undefined, end: number | undefined, accum: TClientData, splitRange?: boolean): void;
|
|
92
92
|
walkSegments<undefined>(handler: ISegmentAction<undefined>, start?: number, end?: number, accum?: undefined, splitRange?: boolean): void;
|
|
93
93
|
protected walkAllSegments<TClientData>(action: (segment: ISegment, accum?: TClientData) => boolean, accum?: TClientData): boolean;
|
|
@@ -150,14 +150,6 @@ export declare class Client {
|
|
|
150
150
|
* @returns True if the insert was applied. False if it could not be.
|
|
151
151
|
*/
|
|
152
152
|
private applyInsertOp;
|
|
153
|
-
/**
|
|
154
|
-
*
|
|
155
|
-
* @param opArgs - The op args of the op to complete
|
|
156
|
-
* @param clientArgs - The client args for the op
|
|
157
|
-
* @param range - The range the op applied to
|
|
158
|
-
* @param clockStart - Optional. The clock start if timing data should be updated.
|
|
159
|
-
*/
|
|
160
|
-
private completeAndLogOp;
|
|
161
153
|
/**
|
|
162
154
|
* Returns a valid range for the op, or undefined
|
|
163
155
|
* @param op - The op to generate the range for
|
|
@@ -189,30 +181,7 @@ export declare class Client {
|
|
|
189
181
|
* @param segment - The segment to find the position for
|
|
190
182
|
* @param localSeq - The localSeq to find the position of the segment at
|
|
191
183
|
*/
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Rebases a (local) position from the perspective `{ seq: seqNumberFrom, localSeq }` to the perspective
|
|
195
|
-
* of the current sequence number. This is desirable when rebasing operations for reconnection.
|
|
196
|
-
*
|
|
197
|
-
* If the position refers to a segment/offset that was removed by some operation between `seqNumberFrom` and
|
|
198
|
-
* the current sequence number, returns undefined.
|
|
199
|
-
*/
|
|
200
|
-
rebasePositionWithoutSegmentSlide(pos: number, seqNumberFrom: number, localSeq: number): number | undefined;
|
|
201
|
-
/**
|
|
202
|
-
* Rebases a (local) position from the perspective `{ seq: seqNumberFrom, localSeq }` to the perspective
|
|
203
|
-
* of the current sequence number. This is desirable when rebasing operations for reconnection.
|
|
204
|
-
*
|
|
205
|
-
* If the position refers to a segment/offset that was removed by some operation between `seqNumberFrom` and
|
|
206
|
-
* the current sequence number, the returned position will align with the position of a reference given
|
|
207
|
-
* `SlideOnRemove` semantics.
|
|
208
|
-
*
|
|
209
|
-
* If a reference was initially given `StayOnRemove` semantics, with intent to later change to `SlideOnRemove`,
|
|
210
|
-
* that isn't equivalent, and so local bookkeeping needs to be updated.
|
|
211
|
-
*
|
|
212
|
-
* If the position has slid off and there is no nearest position (i.e. the
|
|
213
|
-
* tree is empty), returns `DetachedReferencePosition`
|
|
214
|
-
*/
|
|
215
|
-
rebasePosition(pos: number, seqNumberFrom: number, localSeq: number): number;
|
|
184
|
+
findReconnectionPosition(segment: ISegment, localSeq: number): number;
|
|
216
185
|
private resetPendingDeltaToOps;
|
|
217
186
|
private applyRemoteOp;
|
|
218
187
|
applyStashedOp(op: IMergeTreeDeltaOp): SegmentGroup;
|
|
@@ -229,6 +198,7 @@ export declare class Client {
|
|
|
229
198
|
* @param remoteClientId - The client id of the remote client
|
|
230
199
|
*/
|
|
231
200
|
resolveRemoteClientPosition(remoteClientPosition: number, remoteClientRefSeq: number, remoteClientId: string): number | undefined;
|
|
201
|
+
private lastNormalizationRefSeq;
|
|
232
202
|
/**
|
|
233
203
|
* Given an pending operation and segment group, regenerate the op, so it
|
|
234
204
|
* can be resubmitted
|
|
@@ -246,7 +216,7 @@ export declare class Client {
|
|
|
246
216
|
localTransaction(groupOp: IMergeTreeGroupMsg): void;
|
|
247
217
|
updateConsensusProperty(op: IMergeTreeAnnotateMsg, msg: ISequencedDocumentMessage): void;
|
|
248
218
|
updateMinSeq(minSeq: number): void;
|
|
249
|
-
getContainingSegment<T extends ISegment>(pos: number,
|
|
219
|
+
getContainingSegment<T extends ISegment>(pos: number, sequenceArgs?: Pick<ISequencedDocumentMessage, "referenceSequenceNumber" | "clientId">, localSeq?: number): {
|
|
250
220
|
segment: T | undefined;
|
|
251
221
|
offset: number | undefined;
|
|
252
222
|
};
|
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;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/client.js
CHANGED
|
@@ -20,37 +20,24 @@ const referencePositions_1 = require("./referencePositions");
|
|
|
20
20
|
const mergeTree_1 = require("./mergeTree");
|
|
21
21
|
const MergeTreeTextHelper_1 = require("./MergeTreeTextHelper");
|
|
22
22
|
const mergeTreeNodeWalk_1 = require("./mergeTreeNodeWalk");
|
|
23
|
-
|
|
24
|
-
return trace.trace().duration * 1000;
|
|
25
|
-
}
|
|
26
|
-
class Client {
|
|
23
|
+
class Client extends common_utils_1.TypedEventEmitter {
|
|
27
24
|
constructor(
|
|
28
25
|
// Passing this callback would be unnecessary if Client were merged with SharedSegmentSequence
|
|
29
26
|
specToSegment, logger, options) {
|
|
27
|
+
super();
|
|
30
28
|
this.specToSegment = specToSegment;
|
|
31
29
|
this.logger = logger;
|
|
32
|
-
this.measureOps = false;
|
|
33
|
-
this.accumTime = 0;
|
|
34
|
-
this.localTime = 0;
|
|
35
|
-
this.localOps = 0;
|
|
36
|
-
this.accumWindowTime = 0;
|
|
37
|
-
this.accumWindow = 0;
|
|
38
|
-
this.accumOps = 0;
|
|
39
|
-
this.maxWindowTime = 0;
|
|
40
30
|
this.clientNameToIds = new collections_1.RedBlackTree(mergeTreeNodes_1.compareStrings);
|
|
41
31
|
this.shortClientIdMap = [];
|
|
42
32
|
this.pendingConsensus = new Map();
|
|
33
|
+
this.lastNormalizationRefSeq = 0;
|
|
43
34
|
this._mergeTree = new mergeTree_1.MergeTree(options);
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
this._mergeTree.
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
return this._mergeTree.mergeTreeMaintenanceCallback;
|
|
51
|
-
}
|
|
52
|
-
set mergeTreeMaintenanceCallback(callback) {
|
|
53
|
-
this._mergeTree.mergeTreeMaintenanceCallback = callback;
|
|
35
|
+
this._mergeTree.mergeTreeDeltaCallback = (opArgs, deltaArgs) => {
|
|
36
|
+
this.emit("delta", opArgs, deltaArgs, this);
|
|
37
|
+
};
|
|
38
|
+
this._mergeTree.mergeTreeMaintenanceCallback = (args, opArgs) => {
|
|
39
|
+
this.emit("maintenance", args, opArgs, this);
|
|
40
|
+
};
|
|
54
41
|
}
|
|
55
42
|
/**
|
|
56
43
|
* The merge tree maintains a queue of segment groups for each local operation.
|
|
@@ -158,17 +145,9 @@ class Client {
|
|
|
158
145
|
}
|
|
159
146
|
const op = (0, opBuilder_1.createInsertSegmentOp)(pos, segment);
|
|
160
147
|
const opArgs = { op };
|
|
161
|
-
this.
|
|
148
|
+
this._mergeTree.insertAtReferencePosition(refPos, segment, opArgs);
|
|
162
149
|
return op;
|
|
163
150
|
}
|
|
164
|
-
traceOp(opArgs, applyOp) {
|
|
165
|
-
let traceStart;
|
|
166
|
-
if (this.measureOps) {
|
|
167
|
-
traceStart = common_utils_1.Trace.start();
|
|
168
|
-
}
|
|
169
|
-
applyOp();
|
|
170
|
-
this.completeAndLogOp(opArgs, traceStart);
|
|
171
|
-
}
|
|
172
151
|
walkSegments(handler, start, end, accum, splitRange = false) {
|
|
173
152
|
this._mergeTree.mapRange(handler, this.getCurrentSeq(), this.getClientId(), accum, start, end, splitRange);
|
|
174
153
|
}
|
|
@@ -264,7 +243,7 @@ class Client {
|
|
|
264
243
|
const op = opArgs.op;
|
|
265
244
|
const clientArgs = this.getClientSequenceArgs(opArgs);
|
|
266
245
|
const range = this.getValidOpRange(op, clientArgs);
|
|
267
|
-
this.
|
|
246
|
+
this._mergeTree.markRangeRemoved(range.start, range.end, clientArgs.referenceSequenceNumber, clientArgs.clientId, clientArgs.sequenceNumber, false, opArgs);
|
|
268
247
|
return true;
|
|
269
248
|
}
|
|
270
249
|
/**
|
|
@@ -280,7 +259,7 @@ class Client {
|
|
|
280
259
|
if (!range) {
|
|
281
260
|
return false;
|
|
282
261
|
}
|
|
283
|
-
this.
|
|
262
|
+
this._mergeTree.annotateRange(range.start, range.end, op.props, op.combiningOp, clientArgs.referenceSequenceNumber, clientArgs.clientId, clientArgs.sequenceNumber, opArgs);
|
|
284
263
|
return true;
|
|
285
264
|
}
|
|
286
265
|
/**
|
|
@@ -303,35 +282,9 @@ class Client {
|
|
|
303
282
|
if (!segments || segments.length === 0) {
|
|
304
283
|
return false;
|
|
305
284
|
}
|
|
306
|
-
this.
|
|
285
|
+
this._mergeTree.insertSegments(range.start, segments, clientArgs.referenceSequenceNumber, clientArgs.clientId, clientArgs.sequenceNumber, opArgs);
|
|
307
286
|
return true;
|
|
308
287
|
}
|
|
309
|
-
/**
|
|
310
|
-
*
|
|
311
|
-
* @param opArgs - The op args of the op to complete
|
|
312
|
-
* @param clientArgs - The client args for the op
|
|
313
|
-
* @param range - The range the op applied to
|
|
314
|
-
* @param clockStart - Optional. The clock start if timing data should be updated.
|
|
315
|
-
*/
|
|
316
|
-
completeAndLogOp(opArgs, traceStart) {
|
|
317
|
-
if (!opArgs.sequencedMessage) {
|
|
318
|
-
if (traceStart) {
|
|
319
|
-
this.localTime += elapsedMicroseconds(traceStart);
|
|
320
|
-
this.localOps++;
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
else {
|
|
324
|
-
const { currentSeq, minSeq } = this.getCollabWindow();
|
|
325
|
-
const { minimumSequenceNumber, sequenceNumber } = opArgs.sequencedMessage;
|
|
326
|
-
(0, common_utils_1.assert)(currentSeq < sequenceNumber, 0x030 /* "Incoming remote op sequence# <= local collabWindow's currentSequence#" */);
|
|
327
|
-
(0, common_utils_1.assert)(minSeq <= minimumSequenceNumber, 0x031 /* "Incoming remote op minSequence# < local collabWindow's minSequence#" */);
|
|
328
|
-
if (traceStart) {
|
|
329
|
-
this.accumTime += elapsedMicroseconds(traceStart);
|
|
330
|
-
this.accumOps++;
|
|
331
|
-
this.accumWindow += (this.getCurrentSeq() - this.getCollabWindow().minSeq);
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
288
|
/**
|
|
336
289
|
* Returns a valid range for the op, or undefined
|
|
337
290
|
* @param op - The op to generate the range for
|
|
@@ -384,10 +337,6 @@ class Client {
|
|
|
384
337
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
385
338
|
return { start, end };
|
|
386
339
|
}
|
|
387
|
-
/**
|
|
388
|
-
* Gets the client args from the op if remote, otherwise uses the local clients info
|
|
389
|
-
* @param sequencedMessage - The sequencedMessage to get the client sequence args for
|
|
390
|
-
*/
|
|
391
340
|
getClientSequenceArgsForMessage(sequencedMessage) {
|
|
392
341
|
// If there this no sequenced message, then the op is local
|
|
393
342
|
// and unacked, so use this clients sequenced args
|
|
@@ -404,6 +353,8 @@ class Client {
|
|
|
404
353
|
return {
|
|
405
354
|
clientId: this.getOrAddShortClientId(sequencedMessage.clientId),
|
|
406
355
|
referenceSequenceNumber: sequencedMessage.referenceSequenceNumber,
|
|
356
|
+
// Note: return value satisfies overload signatures despite the cast, as if input argument doesn't contain sequenceNumber,
|
|
357
|
+
// return value isn't expected to have it either.
|
|
407
358
|
sequenceNumber: sequencedMessage.sequenceNumber,
|
|
408
359
|
};
|
|
409
360
|
}
|
|
@@ -417,21 +368,12 @@ class Client {
|
|
|
417
368
|
}
|
|
418
369
|
ackPendingSegment(opArgs) {
|
|
419
370
|
const ackOp = (deltaOpArgs) => {
|
|
420
|
-
let trace;
|
|
421
|
-
if (this.measureOps) {
|
|
422
|
-
trace = common_utils_1.Trace.start();
|
|
423
|
-
}
|
|
424
371
|
this._mergeTree.ackPendingSegment(deltaOpArgs);
|
|
425
372
|
if (deltaOpArgs.op.type === ops_1.MergeTreeDeltaType.ANNOTATE) {
|
|
426
373
|
if (deltaOpArgs.op.combiningOp && (deltaOpArgs.op.combiningOp.name === "consensus")) {
|
|
427
374
|
this.updateConsensusProperty(deltaOpArgs.op, deltaOpArgs.sequencedMessage);
|
|
428
375
|
}
|
|
429
376
|
}
|
|
430
|
-
if (trace) {
|
|
431
|
-
this.accumTime += elapsedMicroseconds(trace);
|
|
432
|
-
this.accumOps++;
|
|
433
|
-
this.accumWindow += (this.getCurrentSeq() - this.getCollabWindow().minSeq);
|
|
434
|
-
}
|
|
435
377
|
};
|
|
436
378
|
if (opArgs.op.type === ops_1.MergeTreeDeltaType.GROUP) {
|
|
437
379
|
for (const memberOp of opArgs.op.ops) {
|
|
@@ -484,64 +426,6 @@ class Client {
|
|
|
484
426
|
const { currentSeq, clientId } = this.getCollabWindow();
|
|
485
427
|
return this._mergeTree.getPosition(segment, currentSeq, clientId, localSeq);
|
|
486
428
|
}
|
|
487
|
-
/**
|
|
488
|
-
* Rebases a (local) position from the perspective `{ seq: seqNumberFrom, localSeq }` to the perspective
|
|
489
|
-
* of the current sequence number. This is desirable when rebasing operations for reconnection.
|
|
490
|
-
*
|
|
491
|
-
* If the position refers to a segment/offset that was removed by some operation between `seqNumberFrom` and
|
|
492
|
-
* the current sequence number, returns undefined.
|
|
493
|
-
*/
|
|
494
|
-
rebasePositionWithoutSegmentSlide(pos, seqNumberFrom, localSeq) {
|
|
495
|
-
(0, common_utils_1.assert)(localSeq <= this._mergeTree.collabWindow.localSeq, 0x424 /* localSeq greater than collab window */);
|
|
496
|
-
const { clientId } = this.getCollabWindow();
|
|
497
|
-
const { segment, offset } = this._mergeTree.getContainingSegment(pos, seqNumberFrom, clientId, localSeq);
|
|
498
|
-
if (segment === undefined && offset === undefined) {
|
|
499
|
-
return;
|
|
500
|
-
}
|
|
501
|
-
// if segment is undefined, it slid off the string
|
|
502
|
-
(0, common_utils_1.assert)(segment !== undefined, 0x425 /* No segment found */);
|
|
503
|
-
(0, common_utils_1.assert)(offset !== undefined && 0 <= offset && offset < segment.cachedLength, 0x426 /* Invalid offset */);
|
|
504
|
-
return this.findReconnectionPosition(segment, localSeq) + offset;
|
|
505
|
-
}
|
|
506
|
-
/**
|
|
507
|
-
* Rebases a (local) position from the perspective `{ seq: seqNumberFrom, localSeq }` to the perspective
|
|
508
|
-
* of the current sequence number. This is desirable when rebasing operations for reconnection.
|
|
509
|
-
*
|
|
510
|
-
* If the position refers to a segment/offset that was removed by some operation between `seqNumberFrom` and
|
|
511
|
-
* the current sequence number, the returned position will align with the position of a reference given
|
|
512
|
-
* `SlideOnRemove` semantics.
|
|
513
|
-
*
|
|
514
|
-
* If a reference was initially given `StayOnRemove` semantics, with intent to later change to `SlideOnRemove`,
|
|
515
|
-
* that isn't equivalent, and so local bookkeeping needs to be updated.
|
|
516
|
-
*
|
|
517
|
-
* If the position has slid off and there is no nearest position (i.e. the
|
|
518
|
-
* tree is empty), returns `DetachedReferencePosition`
|
|
519
|
-
*/
|
|
520
|
-
rebasePosition(pos, seqNumberFrom, localSeq) {
|
|
521
|
-
var _a;
|
|
522
|
-
(0, common_utils_1.assert)(localSeq <= this._mergeTree.collabWindow.localSeq, 0x300 /* localSeq greater than collab window */);
|
|
523
|
-
const { clientId } = this.getCollabWindow();
|
|
524
|
-
let { segment, offset } = this._mergeTree.getContainingSegment(pos, seqNumberFrom, clientId, localSeq);
|
|
525
|
-
if (segment === undefined && offset === undefined) {
|
|
526
|
-
// getContainingSegment will only return non-removed segments. This means the position was past
|
|
527
|
-
// all non-removed segments in the tree, so we take the last one instead as an approximation.
|
|
528
|
-
let finalSegment = this._mergeTree.root;
|
|
529
|
-
while (!finalSegment.isLeaf()) {
|
|
530
|
-
finalSegment = finalSegment.children[finalSegment.childCount - 1];
|
|
531
|
-
}
|
|
532
|
-
segment = finalSegment;
|
|
533
|
-
offset = 0;
|
|
534
|
-
}
|
|
535
|
-
// if segment is undefined, it slid off the string
|
|
536
|
-
(0, common_utils_1.assert)(segment !== undefined, 0x302 /* No segment found */);
|
|
537
|
-
const segoff = (_a = this.getSlideToSegment({ segment, offset })) !== null && _a !== void 0 ? _a : segment;
|
|
538
|
-
// case happens when rebasing op, but concurrently entire string has been deleted
|
|
539
|
-
if (segoff.segment === undefined || segoff.offset === undefined) {
|
|
540
|
-
return referencePositions_1.DetachedReferencePosition;
|
|
541
|
-
}
|
|
542
|
-
(0, common_utils_1.assert)(offset !== undefined && 0 <= offset && offset < segment.cachedLength, 0x303 /* Invalid offset */);
|
|
543
|
-
return this.findReconnectionPosition(segoff.segment, localSeq) + segoff.offset;
|
|
544
|
-
}
|
|
545
429
|
resetPendingDeltaToOps(resetOp, segmentGroup) {
|
|
546
430
|
var _a, _b, _c;
|
|
547
431
|
(0, common_utils_1.assert)(!!segmentGroup, 0x033 /* "Segment group undefined" */);
|
|
@@ -587,7 +471,11 @@ class Client {
|
|
|
587
471
|
throw new Error(`Invalid op type`);
|
|
588
472
|
}
|
|
589
473
|
if (newOp) {
|
|
590
|
-
const newSegmentGroup = {
|
|
474
|
+
const newSegmentGroup = {
|
|
475
|
+
segments: [],
|
|
476
|
+
localSeq: segmentGroup.localSeq,
|
|
477
|
+
refSeq: this.getCollabWindow().currentSeq,
|
|
478
|
+
};
|
|
591
479
|
segment.segmentGroups.enqueue(newSegmentGroup);
|
|
592
480
|
this._mergeTree.pendingSegments.push(newSegmentGroup);
|
|
593
481
|
opList.push(newOp);
|
|
@@ -692,6 +580,12 @@ class Client {
|
|
|
692
580
|
* @param segmentGroup - The segment group associated with the op
|
|
693
581
|
*/
|
|
694
582
|
regeneratePendingOp(resetOp, segmentGroup) {
|
|
583
|
+
const rebaseTo = this.getCollabWindow().currentSeq;
|
|
584
|
+
if (rebaseTo !== this.lastNormalizationRefSeq) {
|
|
585
|
+
this.emit("normalize", this);
|
|
586
|
+
this._mergeTree.normalizeSegmentsOnRebase();
|
|
587
|
+
this.lastNormalizationRefSeq = rebaseTo;
|
|
588
|
+
}
|
|
695
589
|
const opList = [];
|
|
696
590
|
if (resetOp.type === ops_1.MergeTreeDeltaType.GROUP) {
|
|
697
591
|
if (Array.isArray(segmentGroup)) {
|
|
@@ -783,22 +677,11 @@ class Client {
|
|
|
783
677
|
this._mergeTree.addMinSeqListener(msg.sequenceNumber, () => consensusInfo.callback(consensusInfo.marker));
|
|
784
678
|
}
|
|
785
679
|
updateMinSeq(minSeq) {
|
|
786
|
-
let trace;
|
|
787
|
-
if (this.measureOps) {
|
|
788
|
-
trace = common_utils_1.Trace.start();
|
|
789
|
-
}
|
|
790
680
|
this._mergeTree.setMinSeq(minSeq);
|
|
791
|
-
if (trace) {
|
|
792
|
-
const elapsed = elapsedMicroseconds(trace);
|
|
793
|
-
this.accumWindowTime += elapsed;
|
|
794
|
-
if (elapsed > this.maxWindowTime) {
|
|
795
|
-
this.maxWindowTime = elapsed;
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
681
|
}
|
|
799
|
-
getContainingSegment(pos,
|
|
800
|
-
const
|
|
801
|
-
return this._mergeTree.getContainingSegment(pos,
|
|
682
|
+
getContainingSegment(pos, sequenceArgs, localSeq) {
|
|
683
|
+
const { referenceSequenceNumber, clientId } = this.getClientSequenceArgsForMessage(sequenceArgs);
|
|
684
|
+
return this._mergeTree.getContainingSegment(pos, referenceSequenceNumber, clientId, localSeq);
|
|
802
685
|
}
|
|
803
686
|
/**
|
|
804
687
|
* Returns the position to slide a reference to if a slide is required.
|