@fluidframework/merge-tree 0.57.0 → 0.58.0-55983
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/base.d.ts +0 -1
- package/dist/base.d.ts.map +1 -1
- package/dist/base.js.map +1 -1
- package/dist/client.d.ts +3 -5
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +14 -36
- package/dist/client.js.map +1 -1
- package/dist/collections.d.ts +1 -4
- package/dist/collections.d.ts.map +1 -1
- package/dist/collections.js +8 -24
- package/dist/collections.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -3
- package/dist/index.js.map +1 -1
- package/dist/mergeTree.d.ts +8 -30
- package/dist/mergeTree.d.ts.map +1 -1
- package/dist/mergeTree.js +17 -326
- package/dist/mergeTree.js.map +1 -1
- package/dist/mergeTreeDeltaCallback.d.ts.map +1 -1
- package/dist/mergeTreeDeltaCallback.js.map +1 -1
- package/dist/ops.d.ts +0 -6
- package/dist/ops.d.ts.map +1 -1
- package/dist/ops.js +1 -8
- package/dist/ops.js.map +1 -1
- package/dist/partialLengths.d.ts.map +1 -1
- package/dist/partialLengths.js +14 -26
- package/dist/partialLengths.js.map +1 -1
- package/dist/properties.d.ts.map +1 -1
- package/dist/properties.js +2 -15
- package/dist/properties.js.map +1 -1
- package/dist/segmentPropertiesManager.js +1 -5
- package/dist/segmentPropertiesManager.js.map +1 -1
- package/dist/snapshotChunks.js +3 -3
- package/dist/snapshotChunks.js.map +1 -1
- package/dist/snapshotV1.d.ts +2 -1
- package/dist/snapshotV1.d.ts.map +1 -1
- package/dist/snapshotV1.js +4 -4
- package/dist/snapshotV1.js.map +1 -1
- package/dist/snapshotlegacy.d.ts.map +1 -1
- package/dist/snapshotlegacy.js +3 -6
- package/dist/snapshotlegacy.js.map +1 -1
- package/dist/sortedSegmentSet.d.ts +3 -3
- package/dist/sortedSegmentSet.d.ts.map +1 -1
- package/dist/sortedSegmentSet.js +12 -12
- package/dist/sortedSegmentSet.js.map +1 -1
- package/dist/textSegment.d.ts.map +1 -1
- package/dist/textSegment.js +3 -17
- package/dist/textSegment.js.map +1 -1
- package/lib/base.d.ts +0 -1
- package/lib/base.d.ts.map +1 -1
- package/lib/base.js.map +1 -1
- package/lib/client.d.ts +3 -5
- package/lib/client.d.ts.map +1 -1
- package/lib/client.js +11 -33
- package/lib/client.js.map +1 -1
- package/lib/collections.d.ts +1 -4
- package/lib/collections.d.ts.map +1 -1
- package/lib/collections.js +8 -24
- package/lib/collections.js.map +1 -1
- package/lib/index.d.ts +0 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +0 -1
- package/lib/index.js.map +1 -1
- package/lib/mergeTree.d.ts +8 -30
- package/lib/mergeTree.d.ts.map +1 -1
- package/lib/mergeTree.js +16 -322
- package/lib/mergeTree.js.map +1 -1
- package/lib/mergeTreeDeltaCallback.d.ts.map +1 -1
- package/lib/mergeTreeDeltaCallback.js.map +1 -1
- package/lib/ops.d.ts +0 -6
- package/lib/ops.d.ts.map +1 -1
- package/lib/ops.js +0 -7
- package/lib/ops.js.map +1 -1
- package/lib/partialLengths.d.ts.map +1 -1
- package/lib/partialLengths.js +14 -26
- package/lib/partialLengths.js.map +1 -1
- package/lib/properties.d.ts.map +1 -1
- package/lib/properties.js +2 -15
- package/lib/properties.js.map +1 -1
- package/lib/segmentPropertiesManager.js +1 -5
- package/lib/segmentPropertiesManager.js.map +1 -1
- package/lib/snapshotChunks.js +3 -3
- package/lib/snapshotChunks.js.map +1 -1
- package/lib/snapshotV1.d.ts +2 -1
- package/lib/snapshotV1.d.ts.map +1 -1
- package/lib/snapshotV1.js +4 -4
- package/lib/snapshotV1.js.map +1 -1
- package/lib/snapshotlegacy.d.ts.map +1 -1
- package/lib/snapshotlegacy.js +3 -6
- package/lib/snapshotlegacy.js.map +1 -1
- package/lib/sortedSegmentSet.d.ts +3 -3
- package/lib/sortedSegmentSet.d.ts.map +1 -1
- package/lib/sortedSegmentSet.js +12 -12
- package/lib/sortedSegmentSet.js.map +1 -1
- package/lib/textSegment.d.ts.map +1 -1
- package/lib/textSegment.js +4 -18
- package/lib/textSegment.js.map +1 -1
- package/package.json +11 -11
- package/src/base.ts +2 -3
- package/src/client.ts +11 -36
- package/src/collections.ts +9 -26
- package/src/index.ts +0 -1
- package/src/mergeTree.ts +32 -357
- package/src/mergeTreeDeltaCallback.ts +0 -1
- package/src/ops.ts +0 -7
- package/src/partialLengths.ts +17 -27
- package/src/properties.ts +7 -15
- package/src/segmentPropertiesManager.ts +5 -5
- package/src/snapshotChunks.ts +3 -3
- package/src/snapshotV1.ts +3 -3
- package/src/snapshotlegacy.ts +4 -6
- package/src/sortedSegmentSet.ts +12 -12
- package/src/textSegment.ts +5 -20
- package/dist/text.d.ts +0 -8
- package/dist/text.d.ts.map +0 -1
- package/dist/text.js +0 -78
- package/dist/text.js.map +0 -1
- package/lib/text.d.ts +0 -8
- package/lib/text.d.ts.map +0 -1
- package/lib/text.js +0 -73
- package/lib/text.js.map +0 -1
- package/src/text.ts +0 -83
package/src/mergeTree.ts
CHANGED
|
@@ -2,14 +2,13 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
-
|
|
5
|
+
/* eslint-disable max-lines */
|
|
6
6
|
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
7
7
|
/* eslint-disable @typescript-eslint/consistent-type-assertions */
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
/* eslint-disable no-bitwise */
|
|
10
10
|
|
|
11
|
-
import { assert
|
|
12
|
-
import { IIntegerRange } from "./base";
|
|
11
|
+
import { assert } from "@fluidframework/common-utils";
|
|
13
12
|
import {
|
|
14
13
|
Comparer,
|
|
15
14
|
Heap,
|
|
@@ -150,12 +149,12 @@ export interface ISegment extends IMergeNodeCommon, IRemovalInfo {
|
|
|
150
149
|
}
|
|
151
150
|
|
|
152
151
|
export interface IMarkerModifiedAction {
|
|
153
|
-
|
|
152
|
+
|
|
154
153
|
(marker: Marker): void;
|
|
155
154
|
}
|
|
156
155
|
|
|
157
156
|
export interface ISegmentAction<TClientData> {
|
|
158
|
-
|
|
157
|
+
|
|
159
158
|
(segment: ISegment, pos: number, refSeq: number, clientId: number, start: number,
|
|
160
159
|
end: number, accum: TClientData): boolean;
|
|
161
160
|
}
|
|
@@ -166,7 +165,7 @@ export interface ISegmentChanges {
|
|
|
166
165
|
}
|
|
167
166
|
|
|
168
167
|
export interface BlockAction<TClientData> {
|
|
169
|
-
|
|
168
|
+
|
|
170
169
|
(
|
|
171
170
|
block: IMergeBlock,
|
|
172
171
|
pos: number,
|
|
@@ -179,7 +178,7 @@ export interface BlockAction<TClientData> {
|
|
|
179
178
|
}
|
|
180
179
|
|
|
181
180
|
export interface NodeAction<TClientData> {
|
|
182
|
-
|
|
181
|
+
|
|
183
182
|
(
|
|
184
183
|
node: IMergeNode,
|
|
185
184
|
pos: number,
|
|
@@ -259,7 +258,7 @@ export class MergeNode implements IMergeNodeCommon {
|
|
|
259
258
|
}
|
|
260
259
|
}
|
|
261
260
|
|
|
262
|
-
|
|
261
|
+
|
|
263
262
|
function addTile(tile: ReferencePosition, tiles: object) {
|
|
264
263
|
const tileLabels = tile.getTileLabels();
|
|
265
264
|
if (tileLabels) {
|
|
@@ -269,7 +268,7 @@ function addTile(tile: ReferencePosition, tiles: object) {
|
|
|
269
268
|
}
|
|
270
269
|
}
|
|
271
270
|
|
|
272
|
-
|
|
271
|
+
|
|
273
272
|
function addTileIfNotPresent(tile: ReferencePosition, tiles: object) {
|
|
274
273
|
const tileLabels = tile.getTileLabels();
|
|
275
274
|
if (tileLabels) {
|
|
@@ -282,7 +281,7 @@ function addTileIfNotPresent(tile: ReferencePosition, tiles: object) {
|
|
|
282
281
|
}
|
|
283
282
|
|
|
284
283
|
function applyStackDelta(currentStackMap: RangeStackMap, deltaStackMap: RangeStackMap) {
|
|
285
|
-
// eslint-disable-next-line guard-for-in
|
|
284
|
+
// eslint-disable-next-line guard-for-in
|
|
286
285
|
for (const label in deltaStackMap) {
|
|
287
286
|
const deltaStack = deltaStackMap[label];
|
|
288
287
|
if (!deltaStack.empty()) {
|
|
@@ -390,7 +389,6 @@ export function ordinalToArray(ord: string) {
|
|
|
390
389
|
// `MaxNodesInBlock`. (i.e., `MaxNodesInBlock` contains 1 extra slot for temporary storage to
|
|
391
390
|
// facilitate splits.)
|
|
392
391
|
export const MaxNodesInBlock = 8;
|
|
393
|
-
const traceOrdinals = false;
|
|
394
392
|
|
|
395
393
|
export class MergeBlock extends MergeNode implements IMergeBlock {
|
|
396
394
|
public children: IMergeNode[];
|
|
@@ -419,19 +417,12 @@ export class MergeBlock extends MergeNode implements IMergeBlock {
|
|
|
419
417
|
localOrdinal = prevOrdCode + ordinalWidth;
|
|
420
418
|
}
|
|
421
419
|
child.ordinal = this.ordinal + String.fromCharCode(localOrdinal);
|
|
422
|
-
if (traceOrdinals) {
|
|
423
|
-
// eslint-disable-next-line max-len
|
|
424
|
-
console.log(`so: prnt chld prev ${ordinalToArray(this.ordinal)} ${ordinalToArray(child.ordinal)} ${(index > 0) ? ordinalToArray(this.children[index - 1].ordinal) : "NA"}`);
|
|
425
|
-
}
|
|
426
420
|
assert(child.ordinal.length === (this.ordinal.length + 1), 0x041 /* "Unexpected child ordinal length!" */);
|
|
427
421
|
if (index > 0) {
|
|
428
422
|
assert(
|
|
429
423
|
child.ordinal > this.children[index - 1].ordinal,
|
|
430
424
|
0x042, /* "Child ordinal <= previous sibling ordinal!" */
|
|
431
425
|
);
|
|
432
|
-
// eslint-disable-next-line max-len
|
|
433
|
-
// console.log(`${ordinalToArray(this.ordinal)} ${ordinalToArray(child.ordinal)} ${ordinalToArray(this.children[index - 1].ordinal)}`);
|
|
434
|
-
// console.log(`ord width ${ordinalWidth}`);
|
|
435
426
|
}
|
|
436
427
|
}
|
|
437
428
|
|
|
@@ -468,7 +459,7 @@ class HierMergeBlock extends MergeBlock implements IMergeBlock {
|
|
|
468
459
|
|
|
469
460
|
public hierToString(indentCount: number) {
|
|
470
461
|
let strbuf = "";
|
|
471
|
-
// eslint-disable-next-line guard-for-in
|
|
462
|
+
// eslint-disable-next-line guard-for-in
|
|
472
463
|
for (const key in this.rangeStacks) {
|
|
473
464
|
const stack = this.rangeStacks[key];
|
|
474
465
|
strbuf += internedSpaces(indentCount);
|
|
@@ -566,7 +557,7 @@ export abstract class BaseSegment extends MergeNode implements ISegment {
|
|
|
566
557
|
return true;
|
|
567
558
|
|
|
568
559
|
case MergeTreeDeltaType.REMOVE:
|
|
569
|
-
|
|
560
|
+
|
|
570
561
|
const removalInfo: IRemovalInfo = this;
|
|
571
562
|
assert(!!removalInfo, 0x046 /* "On remove ack, missing removal info!" */);
|
|
572
563
|
assert(!!removalInfo.removedSeq, 0x047 /* "On remove ack, missing removed sequence number!" */);
|
|
@@ -575,11 +566,7 @@ export abstract class BaseSegment extends MergeNode implements ISegment {
|
|
|
575
566
|
removalInfo.removedSeq = opArgs.sequencedMessage!.sequenceNumber;
|
|
576
567
|
return true;
|
|
577
568
|
}
|
|
578
|
-
|
|
579
|
-
console.log(`grump @seq ${opArgs.sequencedMessage!.sequenceNumber} ` +
|
|
580
|
-
`cli ${glc(mergeTree, mergeTree.collabWindow.clientId)} ` +
|
|
581
|
-
`from ${removalInfo.removedSeq} text ${mergeTree.toString()}`);
|
|
582
|
-
}
|
|
569
|
+
|
|
583
570
|
return false;
|
|
584
571
|
|
|
585
572
|
default:
|
|
@@ -824,7 +811,7 @@ export class Marker extends BaseSegment implements ReferencePosition {
|
|
|
824
811
|
// Avoid circular reference when stringifying makers containing handles.
|
|
825
812
|
// (Substitute a debug string instead.)
|
|
826
813
|
const handle = !!value && value.IFluidHandle;
|
|
827
|
-
|
|
814
|
+
|
|
828
815
|
return handle
|
|
829
816
|
? `#Handle(${handle.routeContext.path}/${handle.path})`
|
|
830
817
|
: value;
|
|
@@ -889,14 +876,6 @@ export const compareNumbers = (a: number, b: number) => a - b;
|
|
|
889
876
|
|
|
890
877
|
export const compareStrings = (a: string, b: string) => a.localeCompare(b);
|
|
891
878
|
|
|
892
|
-
export function clock() {
|
|
893
|
-
return Trace.start();
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
export function elapsedMicroseconds(trace: Trace) {
|
|
897
|
-
return trace.trace().duration * 1000;
|
|
898
|
-
}
|
|
899
|
-
|
|
900
879
|
const indentStrings = ["", " ", " "];
|
|
901
880
|
export function internedSpaces(n: number) {
|
|
902
881
|
if (indentStrings[n] === undefined) {
|
|
@@ -933,14 +912,6 @@ const LRUSegmentComparer: Comparer<LRUSegment> = {
|
|
|
933
912
|
compare: (a, b) => a.maxSeq - b.maxSeq,
|
|
934
913
|
};
|
|
935
914
|
|
|
936
|
-
export function glc(mergeTree: MergeTree, id: number) {
|
|
937
|
-
if (mergeTree.getLongClientId) {
|
|
938
|
-
return mergeTree.getLongClientId(id);
|
|
939
|
-
} else {
|
|
940
|
-
return id.toString();
|
|
941
|
-
}
|
|
942
|
-
}
|
|
943
|
-
|
|
944
915
|
export interface SegmentAccumulator {
|
|
945
916
|
segments: ISegment[];
|
|
946
917
|
}
|
|
@@ -1060,18 +1031,9 @@ export class MergeTree {
|
|
|
1060
1031
|
public static readonly options = {
|
|
1061
1032
|
incrementalUpdate: true,
|
|
1062
1033
|
insertAfterRemovedSegs: true,
|
|
1063
|
-
measureOrdinalTime: true,
|
|
1064
|
-
measureWindowTime: true,
|
|
1065
1034
|
zamboniSegments: true,
|
|
1066
1035
|
};
|
|
1067
|
-
|
|
1068
|
-
private static readonly traceZRemove = false;
|
|
1069
|
-
private static readonly traceOrdinals = false;
|
|
1070
|
-
public static readonly traceGatherText = false;
|
|
1071
|
-
private static readonly diagInsertTie = false;
|
|
1072
|
-
public static readonly diagOverlappingRemove = false;
|
|
1073
|
-
private static readonly traceTraversal = false;
|
|
1074
|
-
private static readonly traceIncrTraversal = false;
|
|
1036
|
+
|
|
1075
1037
|
private static readonly initBlockUpdateActions: BlockUpdateActions;
|
|
1076
1038
|
private static readonly theUnfinishedNode = <IMergeBlock>{ childCount: -1 };
|
|
1077
1039
|
// WARNING:
|
|
@@ -1079,11 +1041,6 @@ export class MergeTree {
|
|
|
1079
1041
|
// for property updates on markers when loading from snapshots
|
|
1080
1042
|
private static readonly blockUpdateMarkers = true;
|
|
1081
1043
|
|
|
1082
|
-
private windowTime = 0;
|
|
1083
|
-
private packTime = 0;
|
|
1084
|
-
private ordTime = 0;
|
|
1085
|
-
private maxOrdTime = 0;
|
|
1086
|
-
|
|
1087
1044
|
root: IMergeBlock;
|
|
1088
1045
|
private readonly blockUpdateActions: BlockUpdateActions = MergeTree.initBlockUpdateActions;
|
|
1089
1046
|
public readonly collabWindow = new CollaborationWindow();
|
|
@@ -1094,8 +1051,6 @@ export class MergeTree {
|
|
|
1094
1051
|
// if we need to have pointers to non-markers, we can change to point at local refs
|
|
1095
1052
|
private readonly idToSegment = new Map<string, ISegment>();
|
|
1096
1053
|
private minSeqListeners: Heap<MinListener> | undefined;
|
|
1097
|
-
// For diagnostics
|
|
1098
|
-
public getLongClientId?: (id: number) => string;
|
|
1099
1054
|
public mergeTreeDeltaCallback?: MergeTreeDeltaCallback;
|
|
1100
1055
|
public mergeTreeMaintenanceCallback?: MergeTreeMaintenanceCallback;
|
|
1101
1056
|
|
|
@@ -1171,7 +1126,6 @@ export class MergeTree {
|
|
|
1171
1126
|
assert(!this.collabWindow.collaborating, 0x049 /* "Trying to reload from segments while collaborating!" */);
|
|
1172
1127
|
|
|
1173
1128
|
const maxChildren = MaxNodesInBlock - 1;
|
|
1174
|
-
const measureReloadTime = false;
|
|
1175
1129
|
|
|
1176
1130
|
// Starting with the leaf segments, recursively builds the B-Tree layer by layer from the bottom up.
|
|
1177
1131
|
const buildMergeBlock = (nodes: IMergeNode[]) => {
|
|
@@ -1201,26 +1155,16 @@ export class MergeTree {
|
|
|
1201
1155
|
this.blockUpdate(block);
|
|
1202
1156
|
}
|
|
1203
1157
|
|
|
1204
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
1205
1158
|
return blocks.length === 1 // If there is only one block at this layer...
|
|
1206
1159
|
? blocks[0] // ...then we're done. Return the root.
|
|
1207
1160
|
: buildMergeBlock(blocks); // ...otherwise recursively build the next layer above blocks.
|
|
1208
1161
|
};
|
|
1209
|
-
|
|
1210
|
-
let clockStart: Trace | undefined;
|
|
1211
|
-
if (measureReloadTime) {
|
|
1212
|
-
clockStart = clock();
|
|
1213
|
-
}
|
|
1214
1162
|
if (segments.length > 0) {
|
|
1215
1163
|
this.root = buildMergeBlock(segments);
|
|
1216
1164
|
this.nodeUpdateOrdinals(this.root);
|
|
1217
1165
|
} else {
|
|
1218
1166
|
this.root = this.makeBlock(0);
|
|
1219
1167
|
}
|
|
1220
|
-
|
|
1221
|
-
if (clockStart) {
|
|
1222
|
-
console.log(`reload time ${elapsedMicroseconds(clockStart)}`);
|
|
1223
|
-
}
|
|
1224
1168
|
}
|
|
1225
1169
|
/* eslint-enable max-len */
|
|
1226
1170
|
|
|
@@ -1232,15 +1176,7 @@ export class MergeTree {
|
|
|
1232
1176
|
this.collabWindow.currentSeq = currentSeq;
|
|
1233
1177
|
this.segmentsToScour = new Heap<LRUSegment>([], LRUSegmentComparer);
|
|
1234
1178
|
this.pendingSegments = ListMakeHead<SegmentGroup>();
|
|
1235
|
-
const measureFullCollab = false;
|
|
1236
|
-
let clockStart: Trace | undefined;
|
|
1237
|
-
if (measureFullCollab) {
|
|
1238
|
-
clockStart = clock();
|
|
1239
|
-
}
|
|
1240
1179
|
this.nodeUpdateLengthNewStructure(this.root, true);
|
|
1241
|
-
if (clockStart) {
|
|
1242
|
-
console.log(`update partial lengths at start ${elapsedMicroseconds(clockStart)}`);
|
|
1243
|
-
}
|
|
1244
1180
|
}
|
|
1245
1181
|
|
|
1246
1182
|
private addToLRUSet(segment: ISegment, seq: number) {
|
|
@@ -1272,11 +1208,6 @@ export class MergeTree {
|
|
|
1272
1208
|
} else if (!segment.trackingCollection.empty) {
|
|
1273
1209
|
holdNodes.push(segment);
|
|
1274
1210
|
} else {
|
|
1275
|
-
if (MergeTree.traceZRemove) {
|
|
1276
|
-
// eslint-disable-next-line @typescript-eslint/dot-notation, max-len
|
|
1277
|
-
console.log(`${this.getLongClientId!(this.collabWindow.clientId)}: Zremove ${segment["text"]}; cli ${this.getLongClientId!(segment.clientId)}`);
|
|
1278
|
-
}
|
|
1279
|
-
|
|
1280
1211
|
// Notify maintenance event observers that the segment is being unlinked from the MergeTree
|
|
1281
1212
|
if (this.mergeTreeMaintenanceCallback) {
|
|
1282
1213
|
this.mergeTreeMaintenanceCallback({
|
|
@@ -1298,10 +1229,6 @@ export class MergeTree {
|
|
|
1298
1229
|
&& this.localNetLength(segment) > 0;
|
|
1299
1230
|
|
|
1300
1231
|
if (canAppend) {
|
|
1301
|
-
if (MergeTree.traceAppend) {
|
|
1302
|
-
// eslint-disable-next-line @typescript-eslint/dot-notation, max-len
|
|
1303
|
-
console.log(`${this.getLongClientId!(this.collabWindow.clientId)}: append ${prevSegment!["text"]} + ${segment["text"]}; cli ${this.getLongClientId!(prevSegment!.clientId)} + cli ${this.getLongClientId!(segment.clientId)}`);
|
|
1304
|
-
}
|
|
1305
1232
|
prevSegment!.append(segment);
|
|
1306
1233
|
if (this.mergeTreeMaintenanceCallback) {
|
|
1307
1234
|
this.mergeTreeMaintenanceCallback({
|
|
@@ -1374,9 +1301,6 @@ export class MergeTree {
|
|
|
1374
1301
|
packedBlocks[nodeIndex] = packedBlock;
|
|
1375
1302
|
this.nodeUpdateLengthNewStructure(packedBlock);
|
|
1376
1303
|
}
|
|
1377
|
-
if (readCount !== totalNodeCount) {
|
|
1378
|
-
console.log(`total count ${totalNodeCount} readCount ${readCount}`);
|
|
1379
|
-
}
|
|
1380
1304
|
parent.children = packedBlocks;
|
|
1381
1305
|
for (let j = 0; j < childCount; j++) {
|
|
1382
1306
|
parent.assignChild(packedBlocks[j], j, false);
|
|
@@ -1394,10 +1318,6 @@ export class MergeTree {
|
|
|
1394
1318
|
if (!this.collabWindow.collaborating) {
|
|
1395
1319
|
return;
|
|
1396
1320
|
}
|
|
1397
|
-
let clockStart;
|
|
1398
|
-
if (MergeTree.options.measureWindowTime) {
|
|
1399
|
-
clockStart = clock();
|
|
1400
|
-
}
|
|
1401
1321
|
|
|
1402
1322
|
for (let i = 0; i < zamboniSegmentsMaxCount; i++) {
|
|
1403
1323
|
let segmentToScour = this.segmentsToScour!.peek();
|
|
@@ -1409,7 +1329,6 @@ export class MergeTree {
|
|
|
1409
1329
|
if (segmentToScour.segment!.parent && segmentToScour.segment!.parent.needsScour !== false) {
|
|
1410
1330
|
const block = segmentToScour.segment!.parent;
|
|
1411
1331
|
const childrenCopy: IMergeNode[] = [];
|
|
1412
|
-
// console.log(`scouring from ${segmentToScour.segment.seq}`);
|
|
1413
1332
|
this.scourNode(block, childrenCopy);
|
|
1414
1333
|
// This will avoid the cost of re-scouring nodes
|
|
1415
1334
|
// that have recently been scoured
|
|
@@ -1425,16 +1344,9 @@ export class MergeTree {
|
|
|
1425
1344
|
}
|
|
1426
1345
|
|
|
1427
1346
|
if (this.underflow(block) && block.parent) {
|
|
1428
|
-
|
|
1429
|
-
let packClockStart;
|
|
1430
|
-
if (MergeTree.options.measureWindowTime) {
|
|
1431
|
-
packClockStart = clock();
|
|
1432
|
-
}
|
|
1347
|
+
|
|
1433
1348
|
this.packParent(block.parent);
|
|
1434
1349
|
|
|
1435
|
-
if (MergeTree.options.measureWindowTime) {
|
|
1436
|
-
this.packTime += elapsedMicroseconds(packClockStart);
|
|
1437
|
-
}
|
|
1438
1350
|
} else {
|
|
1439
1351
|
this.nodeUpdateOrdinals(block);
|
|
1440
1352
|
this.blockUpdatePathLengths(block, UnassignedSequenceNumber, -1, true);
|
|
@@ -1442,10 +1354,6 @@ export class MergeTree {
|
|
|
1442
1354
|
}
|
|
1443
1355
|
}
|
|
1444
1356
|
}
|
|
1445
|
-
|
|
1446
|
-
if (MergeTree.options.measureWindowTime) {
|
|
1447
|
-
this.windowTime += elapsedMicroseconds(clockStart);
|
|
1448
|
-
}
|
|
1449
1357
|
}
|
|
1450
1358
|
|
|
1451
1359
|
public getCollabWindow() {
|
|
@@ -1495,74 +1403,9 @@ export class MergeTree {
|
|
|
1495
1403
|
return stats;
|
|
1496
1404
|
};
|
|
1497
1405
|
const rootStats = nodeGetStats(this.root);
|
|
1498
|
-
if (MergeTree.options.measureWindowTime) {
|
|
1499
|
-
rootStats.windowTime = this.windowTime;
|
|
1500
|
-
rootStats.packTime = this.packTime;
|
|
1501
|
-
rootStats.ordTime = this.ordTime;
|
|
1502
|
-
rootStats.maxOrdTime = this.maxOrdTime;
|
|
1503
|
-
}
|
|
1504
1406
|
return rootStats;
|
|
1505
1407
|
}
|
|
1506
1408
|
|
|
1507
|
-
public findHistorialPosition(pos: number, fromSeq: number, toSeq: number, clientId: number) {
|
|
1508
|
-
return this.findHistorialPositionFromClient(pos, fromSeq, toSeq, clientId);
|
|
1509
|
-
}
|
|
1510
|
-
|
|
1511
|
-
private findHistorialPositionFromClient(pos: number, fromSeq: number, toSeq: number, clientId: number) {
|
|
1512
|
-
assert(fromSeq < toSeq, 0x04a /* "Invalid range for historical position search!" */);
|
|
1513
|
-
if (pos < this.getLength(fromSeq, clientId)) {
|
|
1514
|
-
assert(toSeq <= this.collabWindow.currentSeq,
|
|
1515
|
-
0x04b /* "Out-of-bounds end sequence number for historical position search!" */);
|
|
1516
|
-
const segoff = this.getContainingSegment(pos, fromSeq, clientId);
|
|
1517
|
-
assert(segoff.segment !== undefined,
|
|
1518
|
-
0x04c /* "Containing segment for historical position search is undefined!" */);
|
|
1519
|
-
const toPos = this.getPosition(segoff.segment, toSeq, clientId);
|
|
1520
|
-
const ret = toPos + segoff.offset!;
|
|
1521
|
-
assert(ret !== undefined,
|
|
1522
|
-
0x04d /* "Return value for historical position search is undefined!" */);
|
|
1523
|
-
return ret;
|
|
1524
|
-
} else {
|
|
1525
|
-
return pos;
|
|
1526
|
-
}
|
|
1527
|
-
}
|
|
1528
|
-
|
|
1529
|
-
public findHistorialRangeFromClient(
|
|
1530
|
-
rangeStart: number,
|
|
1531
|
-
rangeEnd: number,
|
|
1532
|
-
fromSeq: number,
|
|
1533
|
-
toSeq: number,
|
|
1534
|
-
clientId: number,
|
|
1535
|
-
) {
|
|
1536
|
-
const ranges: IIntegerRange[] = [];
|
|
1537
|
-
const recordRange = (
|
|
1538
|
-
segment: ISegment,
|
|
1539
|
-
pos: number,
|
|
1540
|
-
refSeq: number,
|
|
1541
|
-
clientId: number,
|
|
1542
|
-
segStart: number,
|
|
1543
|
-
segEnd: number) => {
|
|
1544
|
-
let _segStart = segStart;
|
|
1545
|
-
let _segEnd = segEnd;
|
|
1546
|
-
if ((this.nodeLength(segment, toSeq, clientId) ?? 0) > 0) {
|
|
1547
|
-
const position = this.getPosition(segment, toSeq, clientId);
|
|
1548
|
-
if (_segStart < 0) {
|
|
1549
|
-
_segStart = 0;
|
|
1550
|
-
}
|
|
1551
|
-
if (_segEnd > segment.cachedLength) {
|
|
1552
|
-
_segEnd = segment.cachedLength;
|
|
1553
|
-
}
|
|
1554
|
-
ranges.push({ start: position + _segStart, end: position + _segEnd });
|
|
1555
|
-
}
|
|
1556
|
-
return true;
|
|
1557
|
-
};
|
|
1558
|
-
this.mapRange({ leaf: recordRange }, fromSeq, clientId, undefined, rangeStart, rangeEnd);
|
|
1559
|
-
return ranges;
|
|
1560
|
-
}
|
|
1561
|
-
|
|
1562
|
-
public findHistorialRange(rangeStart: number, rangeEnd: number, fromSeq: number, toSeq: number, clientId: number) {
|
|
1563
|
-
return this.findHistorialRangeFromClient(rangeStart, rangeEnd, fromSeq, toSeq, clientId);
|
|
1564
|
-
}
|
|
1565
|
-
|
|
1566
1409
|
public getLength(refSeq: number, clientId: number) {
|
|
1567
1410
|
return this.blockLength(this.root, refSeq, clientId);
|
|
1568
1411
|
}
|
|
@@ -1862,16 +1705,12 @@ export class MergeTree {
|
|
|
1862
1705
|
* Assign sequence number to existing segment; update partial lengths to reflect the change
|
|
1863
1706
|
* @param seq - sequence number given by server to pending segment
|
|
1864
1707
|
*/
|
|
1865
|
-
public ackPendingSegment(opArgs: IMergeTreeDeltaOpArgs
|
|
1708
|
+
public ackPendingSegment(opArgs: IMergeTreeDeltaOpArgs) {
|
|
1866
1709
|
const seq = opArgs.sequencedMessage!.sequenceNumber;
|
|
1867
1710
|
const pendingSegmentGroup = this.pendingSegments!.dequeue();
|
|
1868
1711
|
const nodesToUpdate: IMergeBlock[] = [];
|
|
1869
1712
|
let overwrite = false;
|
|
1870
1713
|
if (pendingSegmentGroup !== undefined) {
|
|
1871
|
-
if (verboseOps) {
|
|
1872
|
-
console.log(`segment group has ${pendingSegmentGroup.segments.length} segments`);
|
|
1873
|
-
}
|
|
1874
|
-
|
|
1875
1714
|
const deltaSegments: IMergeTreeSegmentDelta[] = [];
|
|
1876
1715
|
pendingSegmentGroup.segments.map((pendingSegment) => {
|
|
1877
1716
|
overwrite = !pendingSegment.ack(pendingSegmentGroup, opArgs, this) || overwrite;
|
|
@@ -1961,13 +1800,8 @@ export class MergeTree {
|
|
|
1961
1800
|
seq: number,
|
|
1962
1801
|
opArgs: IMergeTreeDeltaOpArgs | undefined,
|
|
1963
1802
|
) {
|
|
1964
|
-
// const tt = MergeTree.traceTraversal;
|
|
1965
|
-
// MergeTree.traceTraversal = true;
|
|
1966
1803
|
this.ensureIntervalBoundary(pos, refSeq, clientId);
|
|
1967
1804
|
|
|
1968
|
-
if (MergeTree.traceOrdinals) {
|
|
1969
|
-
this.ordinalIntegrity();
|
|
1970
|
-
}
|
|
1971
1805
|
const localSeq = seq === UnassignedSequenceNumber ? ++this.collabWindow.localSeq : undefined;
|
|
1972
1806
|
|
|
1973
1807
|
this.blockInsert(pos, refSeq, clientId, seq, localSeq, segments);
|
|
@@ -1982,10 +1816,6 @@ export class MergeTree {
|
|
|
1982
1816
|
});
|
|
1983
1817
|
}
|
|
1984
1818
|
|
|
1985
|
-
// MergeTree.traceTraversal = tt;
|
|
1986
|
-
if (MergeTree.traceOrdinals) {
|
|
1987
|
-
this.ordinalIntegrity();
|
|
1988
|
-
}
|
|
1989
1819
|
if (this.collabWindow.collaborating && MergeTree.options.zamboniSegments &&
|
|
1990
1820
|
(seq !== UnassignedSequenceNumber)) {
|
|
1991
1821
|
this.zamboniSegments();
|
|
@@ -2109,7 +1939,13 @@ export class MergeTree {
|
|
|
2109
1939
|
/**
|
|
2110
1940
|
* Resolves a remote client's position against the local sequence
|
|
2111
1941
|
* and returns the remote client's position relative to the local
|
|
2112
|
-
* sequence
|
|
1942
|
+
* sequence. The client ref seq must be above the minimum sequence number
|
|
1943
|
+
* or the return value will be undefined.
|
|
1944
|
+
* Generally this method is used in conjunction with signals which provide
|
|
1945
|
+
* point in time values for the below parameters, and is useful for things
|
|
1946
|
+
* like displaying user position. It should not be used with persisted values
|
|
1947
|
+
* as persisted values will quickly become invalid as the remoteClientRefSeq
|
|
1948
|
+
* moves below the minimum sequence number
|
|
2113
1949
|
* @param remoteClientPosition - The remote client's position to resolve
|
|
2114
1950
|
* @param remoteClientRefSeq - The reference sequence number of the remote client
|
|
2115
1951
|
* @param remoteClientId - The client id of the remote client
|
|
@@ -2118,6 +1954,11 @@ export class MergeTree {
|
|
|
2118
1954
|
remoteClientPosition: number,
|
|
2119
1955
|
remoteClientRefSeq: number,
|
|
2120
1956
|
remoteClientId: number): number | undefined {
|
|
1957
|
+
|
|
1958
|
+
if(remoteClientRefSeq < this.collabWindow.minSeq){
|
|
1959
|
+
return undefined;
|
|
1960
|
+
}
|
|
1961
|
+
|
|
2121
1962
|
const segmentInfo = this.getContainingSegment(
|
|
2122
1963
|
remoteClientPosition,
|
|
2123
1964
|
remoteClientRefSeq,
|
|
@@ -2159,10 +2000,6 @@ export class MergeTree {
|
|
|
2159
2000
|
let segIsLocal = false;
|
|
2160
2001
|
const checkSegmentIsLocal = (segment: ISegment, pos: number, refSeq: number, clientId: number) => {
|
|
2161
2002
|
if (segment.seq === UnassignedSequenceNumber) {
|
|
2162
|
-
if (MergeTree.diagInsertTie) {
|
|
2163
|
-
// eslint-disable-next-line max-len
|
|
2164
|
-
console.log(`@cli ${glc(this, this.collabWindow.clientId)}: promoting continue due to seq ${segment.seq} text ${segment.toString()} ref ${refSeq}`);
|
|
2165
|
-
}
|
|
2166
2003
|
segIsLocal = true;
|
|
2167
2004
|
}
|
|
2168
2005
|
// Only need to look at first segment that follows finished node
|
|
@@ -2172,10 +2009,6 @@ export class MergeTree {
|
|
|
2172
2009
|
const continueFrom = (node: IMergeBlock) => {
|
|
2173
2010
|
segIsLocal = false;
|
|
2174
2011
|
this.rightExcursion(node, checkSegmentIsLocal);
|
|
2175
|
-
if (MergeTree.diagInsertTie && segIsLocal) {
|
|
2176
|
-
// eslint-disable-next-line max-len
|
|
2177
|
-
console.log(`@cli ${glc(this, this.collabWindow.clientId)}: attempting continue with seq ${seq} ref ${refSeq} `);
|
|
2178
|
-
}
|
|
2179
2012
|
return segIsLocal;
|
|
2180
2013
|
};
|
|
2181
2014
|
|
|
@@ -2270,7 +2103,7 @@ export class MergeTree {
|
|
|
2270
2103
|
if (pos === 0) {
|
|
2271
2104
|
// normalize the seq numbers
|
|
2272
2105
|
// if the new seg is local (UnassignedSequenceNumber) give it the highest possible
|
|
2273
|
-
// seq for
|
|
2106
|
+
// seq for comparison, as it will get a seq higher than any other seq once sequences
|
|
2274
2107
|
// if the current seg is local (UnassignedSequenceNumber) give it the second highest
|
|
2275
2108
|
// possible seq, as the highest is reserved for the previous.
|
|
2276
2109
|
const newSeq = seq === UnassignedSequenceNumber ? Number.MAX_SAFE_INTEGER : seq;
|
|
@@ -2357,7 +2190,6 @@ export class MergeTree {
|
|
|
2357
2190
|
let child: IMergeNode;
|
|
2358
2191
|
let newNode: IMergeNode | undefined;
|
|
2359
2192
|
let fromSplit: IMergeBlock | undefined;
|
|
2360
|
-
let found = false;
|
|
2361
2193
|
for (childIndex = 0; childIndex < block.childCount; childIndex++) {
|
|
2362
2194
|
child = children[childIndex];
|
|
2363
2195
|
const len = this.nodeLength(child, refSeq, clientId);
|
|
@@ -2366,23 +2198,9 @@ export class MergeTree {
|
|
|
2366
2198
|
// will be removed, so should just be skipped for now
|
|
2367
2199
|
continue;
|
|
2368
2200
|
}
|
|
2369
|
-
if (MergeTree.traceTraversal) {
|
|
2370
|
-
let segInfo: string;
|
|
2371
|
-
if ((!child.isLeaf()) && this.collabWindow.collaborating) {
|
|
2372
|
-
segInfo = `minLength: ${child.partialLengths!.minLength}`;
|
|
2373
|
-
} else {
|
|
2374
|
-
const segment = <ISegment>child;
|
|
2375
|
-
segInfo = `cli: ${glc(this, segment.clientId)} seq: ${segment.seq} text: ${segment.toString()}`;
|
|
2376
|
-
if (segment.removedSeq !== undefined) {
|
|
2377
|
-
segInfo += ` rcli: ${glc(this, segment.removedClientId!)} rseq: ${segment.removedSeq}`;
|
|
2378
|
-
}
|
|
2379
|
-
}
|
|
2380
|
-
console.log(`@tcli: ${glc(this, this.collabWindow.clientId)} len: ${len} pos: ${_pos} ${segInfo}`);
|
|
2381
|
-
}
|
|
2382
2201
|
|
|
2383
2202
|
if ((_pos < len) || ((_pos === len) && this.breakTie(_pos, child, seq))) {
|
|
2384
2203
|
// Found entry containing pos
|
|
2385
|
-
found = true;
|
|
2386
2204
|
if (!child.isLeaf()) {
|
|
2387
2205
|
const childBlock = child;
|
|
2388
2206
|
// Internal node
|
|
@@ -2396,10 +2214,6 @@ export class MergeTree {
|
|
|
2396
2214
|
}
|
|
2397
2215
|
return undefined;
|
|
2398
2216
|
} else if (splitNode === MergeTree.theUnfinishedNode) {
|
|
2399
|
-
if (MergeTree.traceTraversal) {
|
|
2400
|
-
// eslint-disable-next-line max-len
|
|
2401
|
-
console.log(`@cli ${glc(this, this.collabWindow.clientId)} unfinished bus pos ${_pos} len ${len}`);
|
|
2402
|
-
}
|
|
2403
2217
|
_pos -= len; // Act as if shifted segment
|
|
2404
2218
|
continue;
|
|
2405
2219
|
} else {
|
|
@@ -2408,15 +2222,9 @@ export class MergeTree {
|
|
|
2408
2222
|
childIndex++; // Insert after
|
|
2409
2223
|
}
|
|
2410
2224
|
} else {
|
|
2411
|
-
if (MergeTree.traceTraversal) {
|
|
2412
|
-
console.log(`@tcli: ${glc(this, this.collabWindow.clientId)}: leaf action`);
|
|
2413
|
-
}
|
|
2414
2225
|
const segment = child;
|
|
2415
2226
|
const segmentChanges = context.leaf(segment, _pos, context);
|
|
2416
2227
|
if (segmentChanges.replaceCurrent) {
|
|
2417
|
-
if (MergeTree.traceOrdinals) {
|
|
2418
|
-
console.log(`assign from leaf with block ord ${ordinalToArray(block.ordinal)}`);
|
|
2419
|
-
}
|
|
2420
2228
|
block.assignChild(segmentChanges.replaceCurrent, childIndex, false);
|
|
2421
2229
|
segmentChanges.replaceCurrent.ordinal = child.ordinal;
|
|
2422
2230
|
}
|
|
@@ -2436,21 +2244,12 @@ export class MergeTree {
|
|
|
2436
2244
|
_pos -= len;
|
|
2437
2245
|
}
|
|
2438
2246
|
}
|
|
2439
|
-
if (MergeTree.traceTraversal) {
|
|
2440
|
-
if ((!found) && (_pos > 0)) {
|
|
2441
|
-
// eslint-disable-next-line max-len
|
|
2442
|
-
console.log(`inserting walk fell through pos ${_pos} len: ${this.blockLength(this.root, refSeq, clientId)}`);
|
|
2443
|
-
}
|
|
2444
|
-
}
|
|
2445
2247
|
if (!newNode) {
|
|
2446
2248
|
if (_pos === 0) {
|
|
2447
2249
|
if ((seq !== UnassignedSequenceNumber) && context.continuePredicate &&
|
|
2448
2250
|
context.continuePredicate(block)) {
|
|
2449
2251
|
return MergeTree.theUnfinishedNode;
|
|
2450
2252
|
} else {
|
|
2451
|
-
if (MergeTree.traceTraversal) {
|
|
2452
|
-
console.log(`@tcli: ${glc(this, this.collabWindow.clientId)}: leaf action pos 0`);
|
|
2453
|
-
}
|
|
2454
2253
|
const segmentChanges = context.leaf(undefined, _pos, context);
|
|
2455
2254
|
newNode = segmentChanges.next;
|
|
2456
2255
|
// Assert segmentChanges.replaceCurrent === undefined
|
|
@@ -2467,9 +2266,6 @@ export class MergeTree {
|
|
|
2467
2266
|
block.setOrdinal(newNode, childIndex);
|
|
2468
2267
|
if (block.childCount < MaxNodesInBlock) {
|
|
2469
2268
|
if (fromSplit) {
|
|
2470
|
-
if (MergeTree.traceOrdinals) {
|
|
2471
|
-
console.log(`split ord ${ordinalToArray(fromSplit.ordinal)}`);
|
|
2472
|
-
}
|
|
2473
2269
|
this.nodeUpdateOrdinals(fromSplit);
|
|
2474
2270
|
}
|
|
2475
2271
|
if (context.structureChange) {
|
|
@@ -2502,44 +2298,7 @@ export class MergeTree {
|
|
|
2502
2298
|
return newNode;
|
|
2503
2299
|
}
|
|
2504
2300
|
|
|
2505
|
-
private ordinalIntegrity() {
|
|
2506
|
-
console.log("chk ordnls");
|
|
2507
|
-
this.nodeOrdinalIntegrity(this.root);
|
|
2508
|
-
}
|
|
2509
|
-
|
|
2510
|
-
private nodeOrdinalIntegrity(block: IMergeBlock) {
|
|
2511
|
-
const olen = block.ordinal.length;
|
|
2512
|
-
for (let i = 0; i < block.childCount; i++) {
|
|
2513
|
-
const child = block.children[i];
|
|
2514
|
-
if (child.ordinal) {
|
|
2515
|
-
if (olen !== (child.ordinal.length - 1)) {
|
|
2516
|
-
console.log("node integrity issue");
|
|
2517
|
-
}
|
|
2518
|
-
if (i > 0) {
|
|
2519
|
-
if (child.ordinal <= block.children[i - 1].ordinal) {
|
|
2520
|
-
console.log("node sib integrity issue");
|
|
2521
|
-
// eslint-disable-next-line max-len
|
|
2522
|
-
console.log(`??: prnt chld prev ${ordinalToArray(block.ordinal)} ${ordinalToArray(child.ordinal)} ${(i > 0) ? ordinalToArray(block.children[i - 1].ordinal) : "NA"}`);
|
|
2523
|
-
}
|
|
2524
|
-
}
|
|
2525
|
-
if (!child.isLeaf()) {
|
|
2526
|
-
this.nodeOrdinalIntegrity(child);
|
|
2527
|
-
}
|
|
2528
|
-
} else {
|
|
2529
|
-
console.log(`node child ordinal not set ${i}`);
|
|
2530
|
-
console.log(`??: prnt ${ordinalToArray(block.ordinal)}`);
|
|
2531
|
-
}
|
|
2532
|
-
}
|
|
2533
|
-
}
|
|
2534
|
-
|
|
2535
2301
|
private nodeUpdateOrdinals(block: IMergeBlock) {
|
|
2536
|
-
if (MergeTree.traceOrdinals) {
|
|
2537
|
-
console.log(`update ordinals for children of node with ordinal ${ordinalToArray(block.ordinal)}`);
|
|
2538
|
-
}
|
|
2539
|
-
let clockStart: Trace | undefined;
|
|
2540
|
-
if (MergeTree.options.measureOrdinalTime) {
|
|
2541
|
-
clockStart = clock();
|
|
2542
|
-
}
|
|
2543
2302
|
for (let i = 0; i < block.childCount; i++) {
|
|
2544
2303
|
const child = block.children[i];
|
|
2545
2304
|
block.setOrdinal(child, i);
|
|
@@ -2547,22 +2306,12 @@ export class MergeTree {
|
|
|
2547
2306
|
this.nodeUpdateOrdinals(child);
|
|
2548
2307
|
}
|
|
2549
2308
|
}
|
|
2550
|
-
if (clockStart) {
|
|
2551
|
-
const elapsed = elapsedMicroseconds(clockStart);
|
|
2552
|
-
if (elapsed > this.maxOrdTime) {
|
|
2553
|
-
this.maxOrdTime = elapsed;
|
|
2554
|
-
}
|
|
2555
|
-
this.ordTime += elapsed;
|
|
2556
|
-
}
|
|
2557
2309
|
}
|
|
2558
2310
|
|
|
2559
2311
|
private addOverlappingClient(removalInfo: IRemovalInfo, clientId: number) {
|
|
2560
2312
|
if (!removalInfo.removedClientOverlap) {
|
|
2561
2313
|
removalInfo.removedClientOverlap = <number[]>[];
|
|
2562
2314
|
}
|
|
2563
|
-
if (MergeTree.diagOverlappingRemove) {
|
|
2564
|
-
console.log(`added cli ${glc(this, clientId)} to rseq: ${removalInfo.removedSeq}`);
|
|
2565
|
-
}
|
|
2566
2315
|
removalInfo.removedClientOverlap.push(clientId);
|
|
2567
2316
|
}
|
|
2568
2317
|
|
|
@@ -2638,10 +2387,6 @@ export class MergeTree {
|
|
|
2638
2387
|
const markRemoved = (segment: ISegment, pos: number, start: number, end: number) => {
|
|
2639
2388
|
const removalInfo: IRemovalInfo = segment;
|
|
2640
2389
|
if (removalInfo.removedSeq !== undefined) {
|
|
2641
|
-
if (MergeTree.diagOverlappingRemove) {
|
|
2642
|
-
// eslint-disable-next-line max-len
|
|
2643
|
-
console.log(`yump @seq ${seq} cli ${glc(this, this.collabWindow.clientId)}: overlaps deleted segment ${removalInfo.removedSeq} text '${segment.toString()}'`);
|
|
2644
|
-
}
|
|
2645
2390
|
_overwrite = true;
|
|
2646
2391
|
if (removalInfo.removedSeq === UnassignedSequenceNumber) {
|
|
2647
2392
|
// replace because comes later
|
|
@@ -2675,7 +2420,6 @@ export class MergeTree {
|
|
|
2675
2420
|
this.addToLRUSet(segment, seq);
|
|
2676
2421
|
}
|
|
2677
2422
|
}
|
|
2678
|
-
// console.log(`saved local removed seg with text: ${textSegment.text}`);
|
|
2679
2423
|
}
|
|
2680
2424
|
return true;
|
|
2681
2425
|
};
|
|
@@ -2687,7 +2431,6 @@ export class MergeTree {
|
|
|
2687
2431
|
}
|
|
2688
2432
|
return true;
|
|
2689
2433
|
};
|
|
2690
|
-
// MergeTree.traceTraversal = true;
|
|
2691
2434
|
this.mapRange({ leaf: markRemoved, post: afterMarkRemoved }, refSeq, clientId, undefined, start, end);
|
|
2692
2435
|
if (savedLocalRefs.length > 0) {
|
|
2693
2436
|
const length = this.getLength(refSeq, clientId);
|
|
@@ -2736,7 +2479,6 @@ export class MergeTree {
|
|
|
2736
2479
|
this.zamboniSegments();
|
|
2737
2480
|
}
|
|
2738
2481
|
}
|
|
2739
|
-
// MergeTree.traceTraversal = false;
|
|
2740
2482
|
}
|
|
2741
2483
|
|
|
2742
2484
|
private nodeUpdateLengthNewStructure(node: IMergeBlock, recur = false) {
|
|
@@ -2855,46 +2597,6 @@ export class MergeTree {
|
|
|
2855
2597
|
this.nodeMap(this.root, actions, 0, refSeq, clientId, accum, start, end);
|
|
2856
2598
|
}
|
|
2857
2599
|
|
|
2858
|
-
public nodeToString(block: IMergeBlock, strbuf: string, indentCount = 0) {
|
|
2859
|
-
let _strbuf = strbuf;
|
|
2860
|
-
_strbuf += internedSpaces(indentCount);
|
|
2861
|
-
// eslint-disable-next-line max-len
|
|
2862
|
-
_strbuf += `Node (len ${block.cachedLength}) p len (${block.parent ? block.parent.cachedLength : 0}) ord ${ordinalToArray(block.ordinal)} with ${block.childCount} segs:\n`;
|
|
2863
|
-
if (MergeTree.blockUpdateMarkers) {
|
|
2864
|
-
_strbuf += internedSpaces(indentCount);
|
|
2865
|
-
_strbuf += (<IHierBlock>block).hierToString(indentCount);
|
|
2866
|
-
}
|
|
2867
|
-
if (this.collabWindow.collaborating) {
|
|
2868
|
-
_strbuf += internedSpaces(indentCount);
|
|
2869
|
-
_strbuf += `${block.partialLengths!.toString((id) => glc(this, id), indentCount)}\n`;
|
|
2870
|
-
}
|
|
2871
|
-
const children = block.children;
|
|
2872
|
-
for (let childIndex = 0; childIndex < block.childCount; childIndex++) {
|
|
2873
|
-
const child = children[childIndex];
|
|
2874
|
-
if (!child.isLeaf()) {
|
|
2875
|
-
_strbuf = this.nodeToString(child, _strbuf, indentCount + 4);
|
|
2876
|
-
} else {
|
|
2877
|
-
const segment = child;
|
|
2878
|
-
_strbuf += internedSpaces(indentCount + 4);
|
|
2879
|
-
// eslint-disable-next-line max-len
|
|
2880
|
-
_strbuf += `cli: ${glc(this, segment.clientId)} seq: ${segment.seq} ord: ${ordinalToArray(segment.ordinal)}`;
|
|
2881
|
-
const removalInfo: IRemovalInfo = segment;
|
|
2882
|
-
if (removalInfo.removedSeq !== undefined) {
|
|
2883
|
-
_strbuf += ` rcli: ${glc(this, removalInfo.removedClientId!)} rseq: ${removalInfo.removedSeq}`;
|
|
2884
|
-
}
|
|
2885
|
-
_strbuf += "\n";
|
|
2886
|
-
_strbuf += internedSpaces(indentCount + 4);
|
|
2887
|
-
_strbuf += segment.toString();
|
|
2888
|
-
_strbuf += "\n";
|
|
2889
|
-
}
|
|
2890
|
-
}
|
|
2891
|
-
return _strbuf;
|
|
2892
|
-
}
|
|
2893
|
-
|
|
2894
|
-
public toString() {
|
|
2895
|
-
return this.nodeToString(this.root, "", 0);
|
|
2896
|
-
}
|
|
2897
|
-
|
|
2898
2600
|
public incrementalBlockMap<TContext>(stateStack: Stack<IncrementalMapState<TContext>>) {
|
|
2899
2601
|
while (!stateStack.empty()) {
|
|
2900
2602
|
// We already check the stack is not empty
|
|
@@ -2917,22 +2619,12 @@ export class MergeTree {
|
|
|
2917
2619
|
if ((state.op === IncrementalExecOp.Go) && (state.childIndex < state.block.childCount)) {
|
|
2918
2620
|
const child = state.block.children[state.childIndex];
|
|
2919
2621
|
const len = this.nodeLength(child, state.refSeq, state.clientId) ?? 0;
|
|
2920
|
-
if (MergeTree.traceIncrTraversal) {
|
|
2921
|
-
if (child.isLeaf()) {
|
|
2922
|
-
// eslint-disable-next-line @typescript-eslint/dot-notation, max-len
|
|
2923
|
-
console.log(`considering (r ${state.refSeq} c ${glc(this, state.clientId)}) seg with text ${child["text"]} len ${len} seq ${child.seq} rseq ${child.removedSeq} cli ${glc(this, child.clientId)}`);
|
|
2924
|
-
}
|
|
2925
|
-
}
|
|
2926
2622
|
if ((len > 0) && (state.start < len) && (state.end > 0)) {
|
|
2927
2623
|
if (!child.isLeaf()) {
|
|
2928
2624
|
const childState = new IncrementalMapState(child, state.actions, state.pos,
|
|
2929
2625
|
state.refSeq, state.clientId, state.context, state.start, state.end, 0);
|
|
2930
2626
|
stateStack.push(childState);
|
|
2931
2627
|
} else {
|
|
2932
|
-
if (MergeTree.traceIncrTraversal) {
|
|
2933
|
-
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
2934
|
-
console.log(`action on seg with text ${child["text"]}`);
|
|
2935
|
-
}
|
|
2936
2628
|
state.actions.leaf(child, state);
|
|
2937
2629
|
}
|
|
2938
2630
|
}
|
|
@@ -2975,20 +2667,6 @@ export class MergeTree {
|
|
|
2975
2667
|
for (let childIndex = 0; childIndex < node.childCount; childIndex++) {
|
|
2976
2668
|
const child = children[childIndex];
|
|
2977
2669
|
const len = this.nodeLength(child, refSeq, clientId) ?? 0;
|
|
2978
|
-
if (MergeTree.traceTraversal) {
|
|
2979
|
-
let segInfo: string;
|
|
2980
|
-
if ((!child.isLeaf()) && this.collabWindow.collaborating) {
|
|
2981
|
-
segInfo = `minLength: ${child.partialLengths!.minLength}`;
|
|
2982
|
-
} else {
|
|
2983
|
-
const segment = <ISegment>child;
|
|
2984
|
-
segInfo = `cli: ${glc(this, segment.clientId)} seq: ${segment.seq} text: '${segment.toString()}'`;
|
|
2985
|
-
if (segment.removedSeq !== undefined) {
|
|
2986
|
-
segInfo += ` rcli: ${glc(this, segment.removedClientId!)} rseq: ${segment.removedSeq}`;
|
|
2987
|
-
}
|
|
2988
|
-
}
|
|
2989
|
-
// eslint-disable-next-line max-len
|
|
2990
|
-
console.log(`@tcli ${glc(this, this.collabWindow.clientId)}: map len: ${len} start: ${_start} end: ${_end} ${segInfo}`);
|
|
2991
|
-
}
|
|
2992
2670
|
if (go && (_end > 0) && (len > 0) && (_start < len)) {
|
|
2993
2671
|
// Found entry containing pos
|
|
2994
2672
|
if (!child.isLeaf()) {
|
|
@@ -2996,14 +2674,11 @@ export class MergeTree {
|
|
|
2996
2674
|
go = this.nodeMap(child, actions, _pos, refSeq, clientId, accum, _start, _end);
|
|
2997
2675
|
}
|
|
2998
2676
|
} else {
|
|
2999
|
-
if (MergeTree.traceTraversal) {
|
|
3000
|
-
console.log(`@tcli ${glc(this, this.collabWindow.clientId)}: map leaf action`);
|
|
3001
|
-
}
|
|
3002
2677
|
if (actions.leaf) {
|
|
3003
|
-
|
|
2678
|
+
go = actions.leaf(child, _pos, refSeq, clientId, _start, _end, accum);
|
|
2679
|
+
}
|
|
3004
2680
|
}
|
|
3005
2681
|
}
|
|
3006
|
-
}
|
|
3007
2682
|
if (!go) {
|
|
3008
2683
|
break;
|
|
3009
2684
|
}
|