@fluidframework/merge-tree 0.57.1 → 0.58.0-55561
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 +0 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +8 -29
- package/dist/client.js.map +1 -1
- package/dist/collections.d.ts +0 -3
- package/dist/collections.d.ts.map +1 -1
- package/dist/collections.js +6 -22
- 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 -26
- package/dist/mergeTree.d.ts.map +1 -1
- package/dist/mergeTree.js +16 -277
- package/dist/mergeTree.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 +0 -9
- 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/snapshotlegacy.d.ts.map +1 -1
- package/dist/snapshotlegacy.js +3 -6
- package/dist/snapshotlegacy.js.map +1 -1
- package/dist/textSegment.d.ts.map +1 -1
- package/dist/textSegment.js +0 -14
- 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 +0 -2
- package/lib/client.d.ts.map +1 -1
- package/lib/client.js +5 -26
- package/lib/client.js.map +1 -1
- package/lib/collections.d.ts +0 -3
- package/lib/collections.d.ts.map +1 -1
- package/lib/collections.js +6 -22
- 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 -26
- package/lib/mergeTree.d.ts.map +1 -1
- package/lib/mergeTree.js +15 -274
- package/lib/mergeTree.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 +0 -9
- 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/snapshotlegacy.d.ts.map +1 -1
- package/lib/snapshotlegacy.js +3 -6
- package/lib/snapshotlegacy.js.map +1 -1
- package/lib/textSegment.d.ts.map +1 -1
- package/lib/textSegment.js +1 -15
- package/lib/textSegment.js.map +1 -1
- package/package.json +10 -10
- package/src/base.ts +0 -1
- package/src/client.ts +5 -29
- package/src/collections.ts +7 -24
- package/src/index.ts +0 -1
- package/src/mergeTree.ts +31 -306
- package/src/ops.ts +0 -7
- package/src/partialLengths.ts +0 -10
- package/src/properties.ts +7 -15
- package/src/snapshotlegacy.ts +4 -6
- package/src/textSegment.ts +2 -17
- 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/lib/mergeTree.js
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
+
/* eslint-disable max-lines */
|
|
5
6
|
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
6
7
|
/* eslint-disable @typescript-eslint/consistent-type-assertions */
|
|
7
|
-
/* eslint-disable @typescript-eslint/no-shadow */
|
|
8
8
|
/* eslint-disable no-bitwise */
|
|
9
|
-
import { assert
|
|
9
|
+
import { assert } from "@fluidframework/common-utils";
|
|
10
10
|
import { Heap, ListMakeHead, Stack, } from "./collections";
|
|
11
11
|
import { LocalClientId, NonCollabClient, TreeMaintenanceSequenceNumber, UnassignedSequenceNumber, UniversalSequenceNumber, } from "./constants";
|
|
12
12
|
import { LocalReference, LocalReferenceCollection } from "./localReference";
|
|
@@ -26,7 +26,6 @@ export class MergeNode {
|
|
|
26
26
|
return false;
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
30
29
|
function addTile(tile, tiles) {
|
|
31
30
|
const tileLabels = tile.getTileLabels();
|
|
32
31
|
if (tileLabels) {
|
|
@@ -35,7 +34,6 @@ function addTile(tile, tiles) {
|
|
|
35
34
|
}
|
|
36
35
|
}
|
|
37
36
|
}
|
|
38
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
39
37
|
function addTileIfNotPresent(tile, tiles) {
|
|
40
38
|
const tileLabels = tile.getTileLabels();
|
|
41
39
|
if (tileLabels) {
|
|
@@ -47,7 +45,7 @@ function addTileIfNotPresent(tile, tiles) {
|
|
|
47
45
|
}
|
|
48
46
|
}
|
|
49
47
|
function applyStackDelta(currentStackMap, deltaStackMap) {
|
|
50
|
-
// eslint-disable-next-line guard-for-in
|
|
48
|
+
// eslint-disable-next-line guard-for-in
|
|
51
49
|
for (const label in deltaStackMap) {
|
|
52
50
|
const deltaStack = deltaStackMap[label];
|
|
53
51
|
if (!deltaStack.empty()) {
|
|
@@ -153,7 +151,6 @@ export function ordinalToArray(ord) {
|
|
|
153
151
|
// `MaxNodesInBlock`. (i.e., `MaxNodesInBlock` contains 1 extra slot for temporary storage to
|
|
154
152
|
// facilitate splits.)
|
|
155
153
|
export const MaxNodesInBlock = 8;
|
|
156
|
-
const traceOrdinals = false;
|
|
157
154
|
export class MergeBlock extends MergeNode {
|
|
158
155
|
constructor(childCount) {
|
|
159
156
|
super();
|
|
@@ -180,16 +177,9 @@ export class MergeBlock extends MergeNode {
|
|
|
180
177
|
localOrdinal = prevOrdCode + ordinalWidth;
|
|
181
178
|
}
|
|
182
179
|
child.ordinal = this.ordinal + String.fromCharCode(localOrdinal);
|
|
183
|
-
if (traceOrdinals) {
|
|
184
|
-
// eslint-disable-next-line max-len
|
|
185
|
-
console.log(`so: prnt chld prev ${ordinalToArray(this.ordinal)} ${ordinalToArray(child.ordinal)} ${(index > 0) ? ordinalToArray(this.children[index - 1].ordinal) : "NA"}`);
|
|
186
|
-
}
|
|
187
180
|
assert(child.ordinal.length === (this.ordinal.length + 1), 0x041 /* "Unexpected child ordinal length!" */);
|
|
188
181
|
if (index > 0) {
|
|
189
182
|
assert(child.ordinal > this.children[index - 1].ordinal, 0x042);
|
|
190
|
-
// eslint-disable-next-line max-len
|
|
191
|
-
// console.log(`${ordinalToArray(this.ordinal)} ${ordinalToArray(child.ordinal)} ${ordinalToArray(this.children[index - 1].ordinal)}`);
|
|
192
|
-
// console.log(`ord width ${ordinalWidth}`);
|
|
193
183
|
}
|
|
194
184
|
}
|
|
195
185
|
assignChild(child, index, updateOrdinal = true) {
|
|
@@ -216,7 +206,7 @@ class HierMergeBlock extends MergeBlock {
|
|
|
216
206
|
}
|
|
217
207
|
hierToString(indentCount) {
|
|
218
208
|
let strbuf = "";
|
|
219
|
-
// eslint-disable-next-line guard-for-in
|
|
209
|
+
// eslint-disable-next-line guard-for-in
|
|
220
210
|
for (const key in this.rangeStacks) {
|
|
221
211
|
const stack = this.rangeStacks[key];
|
|
222
212
|
strbuf += internedSpaces(indentCount);
|
|
@@ -289,7 +279,6 @@ export class BaseSegment extends MergeNode {
|
|
|
289
279
|
this.localSeq = undefined;
|
|
290
280
|
return true;
|
|
291
281
|
case 1 /* REMOVE */:
|
|
292
|
-
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
293
282
|
const removalInfo = this;
|
|
294
283
|
assert(!!removalInfo, 0x046 /* "On remove ack, missing removal info!" */);
|
|
295
284
|
assert(!!removalInfo.removedSeq, 0x047 /* "On remove ack, missing removed sequence number!" */);
|
|
@@ -298,11 +287,6 @@ export class BaseSegment extends MergeNode {
|
|
|
298
287
|
removalInfo.removedSeq = opArgs.sequencedMessage.sequenceNumber;
|
|
299
288
|
return true;
|
|
300
289
|
}
|
|
301
|
-
if (MergeTree.diagOverlappingRemove) {
|
|
302
|
-
console.log(`grump @seq ${opArgs.sequencedMessage.sequenceNumber} ` +
|
|
303
|
-
`cli ${glc(mergeTree, mergeTree.collabWindow.clientId)} ` +
|
|
304
|
-
`from ${removalInfo.removedSeq} text ${mergeTree.toString()}`);
|
|
305
|
-
}
|
|
306
290
|
return false;
|
|
307
291
|
default:
|
|
308
292
|
throw new Error(`${opArgs.op.type} is in unrecognized operation type`);
|
|
@@ -502,7 +486,6 @@ export class Marker extends BaseSegment {
|
|
|
502
486
|
// Avoid circular reference when stringifying makers containing handles.
|
|
503
487
|
// (Substitute a debug string instead.)
|
|
504
488
|
const handle = !!value && value.IFluidHandle;
|
|
505
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
506
489
|
return handle
|
|
507
490
|
? `#Handle(${handle.routeContext.path}/${handle.path})`
|
|
508
491
|
: value;
|
|
@@ -559,12 +542,6 @@ export class CollaborationWindow {
|
|
|
559
542
|
}
|
|
560
543
|
export const compareNumbers = (a, b) => a - b;
|
|
561
544
|
export const compareStrings = (a, b) => a.localeCompare(b);
|
|
562
|
-
export function clock() {
|
|
563
|
-
return Trace.start();
|
|
564
|
-
}
|
|
565
|
-
export function elapsedMicroseconds(trace) {
|
|
566
|
-
return trace.trace().duration * 1000;
|
|
567
|
-
}
|
|
568
545
|
const indentStrings = ["", " ", " "];
|
|
569
546
|
export function internedSpaces(n) {
|
|
570
547
|
if (indentStrings[n] === undefined) {
|
|
@@ -670,10 +647,6 @@ export class MergeTree {
|
|
|
670
647
|
// TODO: make and use interface describing options
|
|
671
648
|
constructor(options) {
|
|
672
649
|
this.options = options;
|
|
673
|
-
this.windowTime = 0;
|
|
674
|
-
this.packTime = 0;
|
|
675
|
-
this.ordTime = 0;
|
|
676
|
-
this.maxOrdTime = 0;
|
|
677
650
|
this.blockUpdateActions = MergeTree.initBlockUpdateActions;
|
|
678
651
|
this.collabWindow = new CollaborationWindow();
|
|
679
652
|
// TODO: add remove on segment remove
|
|
@@ -757,7 +730,6 @@ export class MergeTree {
|
|
|
757
730
|
// This code assumes that a later call to `startCollaboration()` will initialize partial lengths.
|
|
758
731
|
assert(!this.collabWindow.collaborating, 0x049 /* "Trying to reload from segments while collaborating!" */);
|
|
759
732
|
const maxChildren = MaxNodesInBlock - 1;
|
|
760
|
-
const measureReloadTime = false;
|
|
761
733
|
// Starting with the leaf segments, recursively builds the B-Tree layer by layer from the bottom up.
|
|
762
734
|
const buildMergeBlock = (nodes) => {
|
|
763
735
|
const blockCount = Math.ceil(nodes.length / maxChildren); // Compute # blocks require for this level of B-Tree
|
|
@@ -781,15 +753,10 @@ export class MergeTree {
|
|
|
781
753
|
// snapshot header. The bulk of the segments in long documents are inserted via `insertSegments()`.
|
|
782
754
|
this.blockUpdate(block);
|
|
783
755
|
}
|
|
784
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
785
756
|
return blocks.length === 1 // If there is only one block at this layer...
|
|
786
757
|
? blocks[0] // ...then we're done. Return the root.
|
|
787
758
|
: buildMergeBlock(blocks); // ...otherwise recursively build the next layer above blocks.
|
|
788
759
|
};
|
|
789
|
-
let clockStart;
|
|
790
|
-
if (measureReloadTime) {
|
|
791
|
-
clockStart = clock();
|
|
792
|
-
}
|
|
793
760
|
if (segments.length > 0) {
|
|
794
761
|
this.root = buildMergeBlock(segments);
|
|
795
762
|
this.nodeUpdateOrdinals(this.root);
|
|
@@ -797,9 +764,6 @@ export class MergeTree {
|
|
|
797
764
|
else {
|
|
798
765
|
this.root = this.makeBlock(0);
|
|
799
766
|
}
|
|
800
|
-
if (clockStart) {
|
|
801
|
-
console.log(`reload time ${elapsedMicroseconds(clockStart)}`);
|
|
802
|
-
}
|
|
803
767
|
}
|
|
804
768
|
/* eslint-enable max-len */
|
|
805
769
|
// For now assume min starts at zero
|
|
@@ -810,15 +774,7 @@ export class MergeTree {
|
|
|
810
774
|
this.collabWindow.currentSeq = currentSeq;
|
|
811
775
|
this.segmentsToScour = new Heap([], LRUSegmentComparer);
|
|
812
776
|
this.pendingSegments = ListMakeHead();
|
|
813
|
-
const measureFullCollab = false;
|
|
814
|
-
let clockStart;
|
|
815
|
-
if (measureFullCollab) {
|
|
816
|
-
clockStart = clock();
|
|
817
|
-
}
|
|
818
777
|
this.nodeUpdateLengthNewStructure(this.root, true);
|
|
819
|
-
if (clockStart) {
|
|
820
|
-
console.log(`update partial lengths at start ${elapsedMicroseconds(clockStart)}`);
|
|
821
|
-
}
|
|
822
778
|
}
|
|
823
779
|
addToLRUSet(segment, seq) {
|
|
824
780
|
// If the parent node has not yet been marked for scour (i.e., needsScour is not false or undefined),
|
|
@@ -848,10 +804,6 @@ export class MergeTree {
|
|
|
848
804
|
holdNodes.push(segment);
|
|
849
805
|
}
|
|
850
806
|
else {
|
|
851
|
-
if (MergeTree.traceZRemove) {
|
|
852
|
-
// eslint-disable-next-line @typescript-eslint/dot-notation, max-len
|
|
853
|
-
console.log(`${this.getLongClientId(this.collabWindow.clientId)}: Zremove ${segment["text"]}; cli ${this.getLongClientId(segment.clientId)}`);
|
|
854
|
-
}
|
|
855
807
|
// Notify maintenance event observers that the segment is being unlinked from the MergeTree
|
|
856
808
|
if (this.mergeTreeMaintenanceCallback) {
|
|
857
809
|
this.mergeTreeMaintenanceCallback({
|
|
@@ -871,10 +823,6 @@ export class MergeTree {
|
|
|
871
823
|
&& prevSegment.trackingCollection.matches(segment.trackingCollection)
|
|
872
824
|
&& this.localNetLength(segment) > 0;
|
|
873
825
|
if (canAppend) {
|
|
874
|
-
if (MergeTree.traceAppend) {
|
|
875
|
-
// eslint-disable-next-line @typescript-eslint/dot-notation, max-len
|
|
876
|
-
console.log(`${this.getLongClientId(this.collabWindow.clientId)}: append ${prevSegment["text"]} + ${segment["text"]}; cli ${this.getLongClientId(prevSegment.clientId)} + cli ${this.getLongClientId(segment.clientId)}`);
|
|
877
|
-
}
|
|
878
826
|
prevSegment.append(segment);
|
|
879
827
|
if (this.mergeTreeMaintenanceCallback) {
|
|
880
828
|
this.mergeTreeMaintenanceCallback({
|
|
@@ -950,9 +898,6 @@ export class MergeTree {
|
|
|
950
898
|
packedBlocks[nodeIndex] = packedBlock;
|
|
951
899
|
this.nodeUpdateLengthNewStructure(packedBlock);
|
|
952
900
|
}
|
|
953
|
-
if (readCount !== totalNodeCount) {
|
|
954
|
-
console.log(`total count ${totalNodeCount} readCount ${readCount}`);
|
|
955
|
-
}
|
|
956
901
|
parent.children = packedBlocks;
|
|
957
902
|
for (let j = 0; j < childCount; j++) {
|
|
958
903
|
parent.assignChild(packedBlocks[j], j, false);
|
|
@@ -970,10 +915,6 @@ export class MergeTree {
|
|
|
970
915
|
if (!this.collabWindow.collaborating) {
|
|
971
916
|
return;
|
|
972
917
|
}
|
|
973
|
-
let clockStart;
|
|
974
|
-
if (MergeTree.options.measureWindowTime) {
|
|
975
|
-
clockStart = clock();
|
|
976
|
-
}
|
|
977
918
|
for (let i = 0; i < zamboniSegmentsMaxCount; i++) {
|
|
978
919
|
let segmentToScour = this.segmentsToScour.peek();
|
|
979
920
|
if (!segmentToScour || segmentToScour.maxSeq > this.collabWindow.minSeq) {
|
|
@@ -984,7 +925,6 @@ export class MergeTree {
|
|
|
984
925
|
if (segmentToScour.segment.parent && segmentToScour.segment.parent.needsScour !== false) {
|
|
985
926
|
const block = segmentToScour.segment.parent;
|
|
986
927
|
const childrenCopy = [];
|
|
987
|
-
// console.log(`scouring from ${segmentToScour.segment.seq}`);
|
|
988
928
|
this.scourNode(block, childrenCopy);
|
|
989
929
|
// This will avoid the cost of re-scouring nodes
|
|
990
930
|
// that have recently been scoured
|
|
@@ -997,15 +937,7 @@ export class MergeTree {
|
|
|
997
937
|
block.assignChild(childrenCopy[j], j, false);
|
|
998
938
|
}
|
|
999
939
|
if (this.underflow(block) && block.parent) {
|
|
1000
|
-
// nodeUpdatePathLengths(node, UnassignedSequenceNumber, -1, true);
|
|
1001
|
-
let packClockStart;
|
|
1002
|
-
if (MergeTree.options.measureWindowTime) {
|
|
1003
|
-
packClockStart = clock();
|
|
1004
|
-
}
|
|
1005
940
|
this.packParent(block.parent);
|
|
1006
|
-
if (MergeTree.options.measureWindowTime) {
|
|
1007
|
-
this.packTime += elapsedMicroseconds(packClockStart);
|
|
1008
|
-
}
|
|
1009
941
|
}
|
|
1010
942
|
else {
|
|
1011
943
|
this.nodeUpdateOrdinals(block);
|
|
@@ -1014,9 +946,6 @@ export class MergeTree {
|
|
|
1014
946
|
}
|
|
1015
947
|
}
|
|
1016
948
|
}
|
|
1017
|
-
if (MergeTree.options.measureWindowTime) {
|
|
1018
|
-
this.windowTime += elapsedMicroseconds(clockStart);
|
|
1019
|
-
}
|
|
1020
949
|
}
|
|
1021
950
|
getCollabWindow() {
|
|
1022
951
|
return this.collabWindow;
|
|
@@ -1065,56 +994,8 @@ export class MergeTree {
|
|
|
1065
994
|
return stats;
|
|
1066
995
|
};
|
|
1067
996
|
const rootStats = nodeGetStats(this.root);
|
|
1068
|
-
if (MergeTree.options.measureWindowTime) {
|
|
1069
|
-
rootStats.windowTime = this.windowTime;
|
|
1070
|
-
rootStats.packTime = this.packTime;
|
|
1071
|
-
rootStats.ordTime = this.ordTime;
|
|
1072
|
-
rootStats.maxOrdTime = this.maxOrdTime;
|
|
1073
|
-
}
|
|
1074
997
|
return rootStats;
|
|
1075
998
|
}
|
|
1076
|
-
findHistorialPosition(pos, fromSeq, toSeq, clientId) {
|
|
1077
|
-
return this.findHistorialPositionFromClient(pos, fromSeq, toSeq, clientId);
|
|
1078
|
-
}
|
|
1079
|
-
findHistorialPositionFromClient(pos, fromSeq, toSeq, clientId) {
|
|
1080
|
-
assert(fromSeq < toSeq, 0x04a /* "Invalid range for historical position search!" */);
|
|
1081
|
-
if (pos < this.getLength(fromSeq, clientId)) {
|
|
1082
|
-
assert(toSeq <= this.collabWindow.currentSeq, 0x04b /* "Out-of-bounds end sequence number for historical position search!" */);
|
|
1083
|
-
const segoff = this.getContainingSegment(pos, fromSeq, clientId);
|
|
1084
|
-
assert(segoff.segment !== undefined, 0x04c /* "Containing segment for historical position search is undefined!" */);
|
|
1085
|
-
const toPos = this.getPosition(segoff.segment, toSeq, clientId);
|
|
1086
|
-
const ret = toPos + segoff.offset;
|
|
1087
|
-
assert(ret !== undefined, 0x04d /* "Return value for historical position search is undefined!" */);
|
|
1088
|
-
return ret;
|
|
1089
|
-
}
|
|
1090
|
-
else {
|
|
1091
|
-
return pos;
|
|
1092
|
-
}
|
|
1093
|
-
}
|
|
1094
|
-
findHistorialRangeFromClient(rangeStart, rangeEnd, fromSeq, toSeq, clientId) {
|
|
1095
|
-
const ranges = [];
|
|
1096
|
-
const recordRange = (segment, pos, refSeq, clientId, segStart, segEnd) => {
|
|
1097
|
-
var _a;
|
|
1098
|
-
let _segStart = segStart;
|
|
1099
|
-
let _segEnd = segEnd;
|
|
1100
|
-
if (((_a = this.nodeLength(segment, toSeq, clientId)) !== null && _a !== void 0 ? _a : 0) > 0) {
|
|
1101
|
-
const position = this.getPosition(segment, toSeq, clientId);
|
|
1102
|
-
if (_segStart < 0) {
|
|
1103
|
-
_segStart = 0;
|
|
1104
|
-
}
|
|
1105
|
-
if (_segEnd > segment.cachedLength) {
|
|
1106
|
-
_segEnd = segment.cachedLength;
|
|
1107
|
-
}
|
|
1108
|
-
ranges.push({ start: position + _segStart, end: position + _segEnd });
|
|
1109
|
-
}
|
|
1110
|
-
return true;
|
|
1111
|
-
};
|
|
1112
|
-
this.mapRange({ leaf: recordRange }, fromSeq, clientId, undefined, rangeStart, rangeEnd);
|
|
1113
|
-
return ranges;
|
|
1114
|
-
}
|
|
1115
|
-
findHistorialRange(rangeStart, rangeEnd, fromSeq, toSeq, clientId) {
|
|
1116
|
-
return this.findHistorialRangeFromClient(rangeStart, rangeEnd, fromSeq, toSeq, clientId);
|
|
1117
|
-
}
|
|
1118
999
|
getLength(refSeq, clientId) {
|
|
1119
1000
|
return this.blockLength(this.root, refSeq, clientId);
|
|
1120
1001
|
}
|
|
@@ -1384,15 +1265,12 @@ export class MergeTree {
|
|
|
1384
1265
|
* Assign sequence number to existing segment; update partial lengths to reflect the change
|
|
1385
1266
|
* @param seq - sequence number given by server to pending segment
|
|
1386
1267
|
*/
|
|
1387
|
-
ackPendingSegment(opArgs
|
|
1268
|
+
ackPendingSegment(opArgs) {
|
|
1388
1269
|
const seq = opArgs.sequencedMessage.sequenceNumber;
|
|
1389
1270
|
const pendingSegmentGroup = this.pendingSegments.dequeue();
|
|
1390
1271
|
const nodesToUpdate = [];
|
|
1391
1272
|
let overwrite = false;
|
|
1392
1273
|
if (pendingSegmentGroup !== undefined) {
|
|
1393
|
-
if (verboseOps) {
|
|
1394
|
-
console.log(`segment group has ${pendingSegmentGroup.segments.length} segments`);
|
|
1395
|
-
}
|
|
1396
1274
|
const deltaSegments = [];
|
|
1397
1275
|
pendingSegmentGroup.segments.map((pendingSegment) => {
|
|
1398
1276
|
overwrite = !pendingSegment.ack(pendingSegmentGroup, opArgs, this) || overwrite;
|
|
@@ -1466,12 +1344,7 @@ export class MergeTree {
|
|
|
1466
1344
|
return pos;
|
|
1467
1345
|
}
|
|
1468
1346
|
insertSegments(pos, segments, refSeq, clientId, seq, opArgs) {
|
|
1469
|
-
// const tt = MergeTree.traceTraversal;
|
|
1470
|
-
// MergeTree.traceTraversal = true;
|
|
1471
1347
|
this.ensureIntervalBoundary(pos, refSeq, clientId);
|
|
1472
|
-
if (MergeTree.traceOrdinals) {
|
|
1473
|
-
this.ordinalIntegrity();
|
|
1474
|
-
}
|
|
1475
1348
|
const localSeq = seq === UnassignedSequenceNumber ? ++this.collabWindow.localSeq : undefined;
|
|
1476
1349
|
this.blockInsert(pos, refSeq, clientId, seq, localSeq, segments);
|
|
1477
1350
|
// opArgs == undefined => loading snapshot or test code
|
|
@@ -1481,10 +1354,6 @@ export class MergeTree {
|
|
|
1481
1354
|
deltaSegments: segments.map((segment) => ({ segment })),
|
|
1482
1355
|
});
|
|
1483
1356
|
}
|
|
1484
|
-
// MergeTree.traceTraversal = tt;
|
|
1485
|
-
if (MergeTree.traceOrdinals) {
|
|
1486
|
-
this.ordinalIntegrity();
|
|
1487
|
-
}
|
|
1488
1357
|
if (this.collabWindow.collaborating && MergeTree.options.zamboniSegments &&
|
|
1489
1358
|
(seq !== UnassignedSequenceNumber)) {
|
|
1490
1359
|
this.zamboniSegments();
|
|
@@ -1594,12 +1463,21 @@ export class MergeTree {
|
|
|
1594
1463
|
/**
|
|
1595
1464
|
* Resolves a remote client's position against the local sequence
|
|
1596
1465
|
* and returns the remote client's position relative to the local
|
|
1597
|
-
* sequence
|
|
1466
|
+
* sequence. The client ref seq must be above the minimum sequence number
|
|
1467
|
+
* or the return value will be undefined.
|
|
1468
|
+
* Generally this method is used in conjunction with signals which provide
|
|
1469
|
+
* point in time values for the below parameters, and is useful for things
|
|
1470
|
+
* like displaying user position. It should not be used with persisted values
|
|
1471
|
+
* as persisted values will quickly become invalid as the remoteClientRefSeq
|
|
1472
|
+
* moves below the minimum sequence number
|
|
1598
1473
|
* @param remoteClientPosition - The remote client's position to resolve
|
|
1599
1474
|
* @param remoteClientRefSeq - The reference sequence number of the remote client
|
|
1600
1475
|
* @param remoteClientId - The client id of the remote client
|
|
1601
1476
|
*/
|
|
1602
1477
|
resolveRemoteClientPosition(remoteClientPosition, remoteClientRefSeq, remoteClientId) {
|
|
1478
|
+
if (remoteClientRefSeq < this.collabWindow.minSeq) {
|
|
1479
|
+
return undefined;
|
|
1480
|
+
}
|
|
1603
1481
|
const segmentInfo = this.getContainingSegment(remoteClientPosition, remoteClientRefSeq, remoteClientId);
|
|
1604
1482
|
const segwindow = this.getCollabWindow();
|
|
1605
1483
|
if (segmentInfo && segmentInfo.segment) {
|
|
@@ -1625,10 +1503,6 @@ export class MergeTree {
|
|
|
1625
1503
|
let segIsLocal = false;
|
|
1626
1504
|
const checkSegmentIsLocal = (segment, pos, refSeq, clientId) => {
|
|
1627
1505
|
if (segment.seq === UnassignedSequenceNumber) {
|
|
1628
|
-
if (MergeTree.diagInsertTie) {
|
|
1629
|
-
// eslint-disable-next-line max-len
|
|
1630
|
-
console.log(`@cli ${glc(this, this.collabWindow.clientId)}: promoting continue due to seq ${segment.seq} text ${segment.toString()} ref ${refSeq}`);
|
|
1631
|
-
}
|
|
1632
1506
|
segIsLocal = true;
|
|
1633
1507
|
}
|
|
1634
1508
|
// Only need to look at first segment that follows finished node
|
|
@@ -1637,10 +1511,6 @@ export class MergeTree {
|
|
|
1637
1511
|
const continueFrom = (node) => {
|
|
1638
1512
|
segIsLocal = false;
|
|
1639
1513
|
this.rightExcursion(node, checkSegmentIsLocal);
|
|
1640
|
-
if (MergeTree.diagInsertTie && segIsLocal) {
|
|
1641
|
-
// eslint-disable-next-line max-len
|
|
1642
|
-
console.log(`@cli ${glc(this, this.collabWindow.clientId)}: attempting continue with seq ${seq} ref ${refSeq} `);
|
|
1643
|
-
}
|
|
1644
1514
|
return segIsLocal;
|
|
1645
1515
|
};
|
|
1646
1516
|
let segmentGroup;
|
|
@@ -1796,7 +1666,6 @@ export class MergeTree {
|
|
|
1796
1666
|
let child;
|
|
1797
1667
|
let newNode;
|
|
1798
1668
|
let fromSplit;
|
|
1799
|
-
let found = false;
|
|
1800
1669
|
for (childIndex = 0; childIndex < block.childCount; childIndex++) {
|
|
1801
1670
|
child = children[childIndex];
|
|
1802
1671
|
const len = this.nodeLength(child, refSeq, clientId);
|
|
@@ -1805,23 +1674,8 @@ export class MergeTree {
|
|
|
1805
1674
|
// will be removed, so should just be skipped for now
|
|
1806
1675
|
continue;
|
|
1807
1676
|
}
|
|
1808
|
-
if (MergeTree.traceTraversal) {
|
|
1809
|
-
let segInfo;
|
|
1810
|
-
if ((!child.isLeaf()) && this.collabWindow.collaborating) {
|
|
1811
|
-
segInfo = `minLength: ${child.partialLengths.minLength}`;
|
|
1812
|
-
}
|
|
1813
|
-
else {
|
|
1814
|
-
const segment = child;
|
|
1815
|
-
segInfo = `cli: ${glc(this, segment.clientId)} seq: ${segment.seq} text: ${segment.toString()}`;
|
|
1816
|
-
if (segment.removedSeq !== undefined) {
|
|
1817
|
-
segInfo += ` rcli: ${glc(this, segment.removedClientId)} rseq: ${segment.removedSeq}`;
|
|
1818
|
-
}
|
|
1819
|
-
}
|
|
1820
|
-
console.log(`@tcli: ${glc(this, this.collabWindow.clientId)} len: ${len} pos: ${_pos} ${segInfo}`);
|
|
1821
|
-
}
|
|
1822
1677
|
if ((_pos < len) || ((_pos === len) && this.breakTie(_pos, child, seq))) {
|
|
1823
1678
|
// Found entry containing pos
|
|
1824
|
-
found = true;
|
|
1825
1679
|
if (!child.isLeaf()) {
|
|
1826
1680
|
const childBlock = child;
|
|
1827
1681
|
// Internal node
|
|
@@ -1836,10 +1690,6 @@ export class MergeTree {
|
|
|
1836
1690
|
return undefined;
|
|
1837
1691
|
}
|
|
1838
1692
|
else if (splitNode === MergeTree.theUnfinishedNode) {
|
|
1839
|
-
if (MergeTree.traceTraversal) {
|
|
1840
|
-
// eslint-disable-next-line max-len
|
|
1841
|
-
console.log(`@cli ${glc(this, this.collabWindow.clientId)} unfinished bus pos ${_pos} len ${len}`);
|
|
1842
|
-
}
|
|
1843
1693
|
_pos -= len; // Act as if shifted segment
|
|
1844
1694
|
continue;
|
|
1845
1695
|
}
|
|
@@ -1850,15 +1700,9 @@ export class MergeTree {
|
|
|
1850
1700
|
}
|
|
1851
1701
|
}
|
|
1852
1702
|
else {
|
|
1853
|
-
if (MergeTree.traceTraversal) {
|
|
1854
|
-
console.log(`@tcli: ${glc(this, this.collabWindow.clientId)}: leaf action`);
|
|
1855
|
-
}
|
|
1856
1703
|
const segment = child;
|
|
1857
1704
|
const segmentChanges = context.leaf(segment, _pos, context);
|
|
1858
1705
|
if (segmentChanges.replaceCurrent) {
|
|
1859
|
-
if (MergeTree.traceOrdinals) {
|
|
1860
|
-
console.log(`assign from leaf with block ord ${ordinalToArray(block.ordinal)}`);
|
|
1861
|
-
}
|
|
1862
1706
|
block.assignChild(segmentChanges.replaceCurrent, childIndex, false);
|
|
1863
1707
|
segmentChanges.replaceCurrent.ordinal = child.ordinal;
|
|
1864
1708
|
}
|
|
@@ -1880,12 +1724,6 @@ export class MergeTree {
|
|
|
1880
1724
|
_pos -= len;
|
|
1881
1725
|
}
|
|
1882
1726
|
}
|
|
1883
|
-
if (MergeTree.traceTraversal) {
|
|
1884
|
-
if ((!found) && (_pos > 0)) {
|
|
1885
|
-
// eslint-disable-next-line max-len
|
|
1886
|
-
console.log(`inserting walk fell through pos ${_pos} len: ${this.blockLength(this.root, refSeq, clientId)}`);
|
|
1887
|
-
}
|
|
1888
|
-
}
|
|
1889
1727
|
if (!newNode) {
|
|
1890
1728
|
if (_pos === 0) {
|
|
1891
1729
|
if ((seq !== UnassignedSequenceNumber) && context.continuePredicate &&
|
|
@@ -1893,9 +1731,6 @@ export class MergeTree {
|
|
|
1893
1731
|
return MergeTree.theUnfinishedNode;
|
|
1894
1732
|
}
|
|
1895
1733
|
else {
|
|
1896
|
-
if (MergeTree.traceTraversal) {
|
|
1897
|
-
console.log(`@tcli: ${glc(this, this.collabWindow.clientId)}: leaf action pos 0`);
|
|
1898
|
-
}
|
|
1899
1734
|
const segmentChanges = context.leaf(undefined, _pos, context);
|
|
1900
1735
|
newNode = segmentChanges.next;
|
|
1901
1736
|
// Assert segmentChanges.replaceCurrent === undefined
|
|
@@ -1912,9 +1747,6 @@ export class MergeTree {
|
|
|
1912
1747
|
block.setOrdinal(newNode, childIndex);
|
|
1913
1748
|
if (block.childCount < MaxNodesInBlock) {
|
|
1914
1749
|
if (fromSplit) {
|
|
1915
|
-
if (MergeTree.traceOrdinals) {
|
|
1916
|
-
console.log(`split ord ${ordinalToArray(fromSplit.ordinal)}`);
|
|
1917
|
-
}
|
|
1918
1750
|
this.nodeUpdateOrdinals(fromSplit);
|
|
1919
1751
|
}
|
|
1920
1752
|
if (context.structureChange) {
|
|
@@ -1948,43 +1780,7 @@ export class MergeTree {
|
|
|
1948
1780
|
this.nodeUpdateLengthNewStructure(newNode);
|
|
1949
1781
|
return newNode;
|
|
1950
1782
|
}
|
|
1951
|
-
ordinalIntegrity() {
|
|
1952
|
-
console.log("chk ordnls");
|
|
1953
|
-
this.nodeOrdinalIntegrity(this.root);
|
|
1954
|
-
}
|
|
1955
|
-
nodeOrdinalIntegrity(block) {
|
|
1956
|
-
const olen = block.ordinal.length;
|
|
1957
|
-
for (let i = 0; i < block.childCount; i++) {
|
|
1958
|
-
const child = block.children[i];
|
|
1959
|
-
if (child.ordinal) {
|
|
1960
|
-
if (olen !== (child.ordinal.length - 1)) {
|
|
1961
|
-
console.log("node integrity issue");
|
|
1962
|
-
}
|
|
1963
|
-
if (i > 0) {
|
|
1964
|
-
if (child.ordinal <= block.children[i - 1].ordinal) {
|
|
1965
|
-
console.log("node sib integrity issue");
|
|
1966
|
-
// eslint-disable-next-line max-len
|
|
1967
|
-
console.log(`??: prnt chld prev ${ordinalToArray(block.ordinal)} ${ordinalToArray(child.ordinal)} ${(i > 0) ? ordinalToArray(block.children[i - 1].ordinal) : "NA"}`);
|
|
1968
|
-
}
|
|
1969
|
-
}
|
|
1970
|
-
if (!child.isLeaf()) {
|
|
1971
|
-
this.nodeOrdinalIntegrity(child);
|
|
1972
|
-
}
|
|
1973
|
-
}
|
|
1974
|
-
else {
|
|
1975
|
-
console.log(`node child ordinal not set ${i}`);
|
|
1976
|
-
console.log(`??: prnt ${ordinalToArray(block.ordinal)}`);
|
|
1977
|
-
}
|
|
1978
|
-
}
|
|
1979
|
-
}
|
|
1980
1783
|
nodeUpdateOrdinals(block) {
|
|
1981
|
-
if (MergeTree.traceOrdinals) {
|
|
1982
|
-
console.log(`update ordinals for children of node with ordinal ${ordinalToArray(block.ordinal)}`);
|
|
1983
|
-
}
|
|
1984
|
-
let clockStart;
|
|
1985
|
-
if (MergeTree.options.measureOrdinalTime) {
|
|
1986
|
-
clockStart = clock();
|
|
1987
|
-
}
|
|
1988
1784
|
for (let i = 0; i < block.childCount; i++) {
|
|
1989
1785
|
const child = block.children[i];
|
|
1990
1786
|
block.setOrdinal(child, i);
|
|
@@ -1992,21 +1788,11 @@ export class MergeTree {
|
|
|
1992
1788
|
this.nodeUpdateOrdinals(child);
|
|
1993
1789
|
}
|
|
1994
1790
|
}
|
|
1995
|
-
if (clockStart) {
|
|
1996
|
-
const elapsed = elapsedMicroseconds(clockStart);
|
|
1997
|
-
if (elapsed > this.maxOrdTime) {
|
|
1998
|
-
this.maxOrdTime = elapsed;
|
|
1999
|
-
}
|
|
2000
|
-
this.ordTime += elapsed;
|
|
2001
|
-
}
|
|
2002
1791
|
}
|
|
2003
1792
|
addOverlappingClient(removalInfo, clientId) {
|
|
2004
1793
|
if (!removalInfo.removedClientOverlap) {
|
|
2005
1794
|
removalInfo.removedClientOverlap = [];
|
|
2006
1795
|
}
|
|
2007
|
-
if (MergeTree.diagOverlappingRemove) {
|
|
2008
|
-
console.log(`added cli ${glc(this, clientId)} to rseq: ${removalInfo.removedSeq}`);
|
|
2009
|
-
}
|
|
2010
1796
|
removalInfo.removedClientOverlap.push(clientId);
|
|
2011
1797
|
}
|
|
2012
1798
|
/**
|
|
@@ -2066,10 +1852,6 @@ export class MergeTree {
|
|
|
2066
1852
|
const markRemoved = (segment, pos, start, end) => {
|
|
2067
1853
|
const removalInfo = segment;
|
|
2068
1854
|
if (removalInfo.removedSeq !== undefined) {
|
|
2069
|
-
if (MergeTree.diagOverlappingRemove) {
|
|
2070
|
-
// eslint-disable-next-line max-len
|
|
2071
|
-
console.log(`yump @seq ${seq} cli ${glc(this, this.collabWindow.clientId)}: overlaps deleted segment ${removalInfo.removedSeq} text '${segment.toString()}'`);
|
|
2072
|
-
}
|
|
2073
1855
|
_overwrite = true;
|
|
2074
1856
|
if (removalInfo.removedSeq === UnassignedSequenceNumber) {
|
|
2075
1857
|
// replace because comes later
|
|
@@ -2104,7 +1886,6 @@ export class MergeTree {
|
|
|
2104
1886
|
this.addToLRUSet(segment, seq);
|
|
2105
1887
|
}
|
|
2106
1888
|
}
|
|
2107
|
-
// console.log(`saved local removed seg with text: ${textSegment.text}`);
|
|
2108
1889
|
}
|
|
2109
1890
|
return true;
|
|
2110
1891
|
};
|
|
@@ -2117,7 +1898,6 @@ export class MergeTree {
|
|
|
2117
1898
|
}
|
|
2118
1899
|
return true;
|
|
2119
1900
|
};
|
|
2120
|
-
// MergeTree.traceTraversal = true;
|
|
2121
1901
|
this.mapRange({ leaf: markRemoved, post: afterMarkRemoved }, refSeq, clientId, undefined, start, end);
|
|
2122
1902
|
if (savedLocalRefs.length > 0) {
|
|
2123
1903
|
const length = this.getLength(refSeq, clientId);
|
|
@@ -2163,7 +1943,6 @@ export class MergeTree {
|
|
|
2163
1943
|
this.zamboniSegments();
|
|
2164
1944
|
}
|
|
2165
1945
|
}
|
|
2166
|
-
// MergeTree.traceTraversal = false;
|
|
2167
1946
|
}
|
|
2168
1947
|
nodeUpdateLengthNewStructure(node, recur = false) {
|
|
2169
1948
|
this.blockUpdate(node);
|
|
@@ -2313,22 +2092,12 @@ export class MergeTree {
|
|
|
2313
2092
|
if ((state.op === IncrementalExecOp.Go) && (state.childIndex < state.block.childCount)) {
|
|
2314
2093
|
const child = state.block.children[state.childIndex];
|
|
2315
2094
|
const len = (_a = this.nodeLength(child, state.refSeq, state.clientId)) !== null && _a !== void 0 ? _a : 0;
|
|
2316
|
-
if (MergeTree.traceIncrTraversal) {
|
|
2317
|
-
if (child.isLeaf()) {
|
|
2318
|
-
// eslint-disable-next-line @typescript-eslint/dot-notation, max-len
|
|
2319
|
-
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)}`);
|
|
2320
|
-
}
|
|
2321
|
-
}
|
|
2322
2095
|
if ((len > 0) && (state.start < len) && (state.end > 0)) {
|
|
2323
2096
|
if (!child.isLeaf()) {
|
|
2324
2097
|
const childState = new IncrementalMapState(child, state.actions, state.pos, state.refSeq, state.clientId, state.context, state.start, state.end, 0);
|
|
2325
2098
|
stateStack.push(childState);
|
|
2326
2099
|
}
|
|
2327
2100
|
else {
|
|
2328
|
-
if (MergeTree.traceIncrTraversal) {
|
|
2329
|
-
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
2330
|
-
console.log(`action on seg with text ${child["text"]}`);
|
|
2331
|
-
}
|
|
2332
2101
|
state.actions.leaf(child, state);
|
|
2333
2102
|
}
|
|
2334
2103
|
}
|
|
@@ -2370,21 +2139,6 @@ export class MergeTree {
|
|
|
2370
2139
|
for (let childIndex = 0; childIndex < node.childCount; childIndex++) {
|
|
2371
2140
|
const child = children[childIndex];
|
|
2372
2141
|
const len = (_a = this.nodeLength(child, refSeq, clientId)) !== null && _a !== void 0 ? _a : 0;
|
|
2373
|
-
if (MergeTree.traceTraversal) {
|
|
2374
|
-
let segInfo;
|
|
2375
|
-
if ((!child.isLeaf()) && this.collabWindow.collaborating) {
|
|
2376
|
-
segInfo = `minLength: ${child.partialLengths.minLength}`;
|
|
2377
|
-
}
|
|
2378
|
-
else {
|
|
2379
|
-
const segment = child;
|
|
2380
|
-
segInfo = `cli: ${glc(this, segment.clientId)} seq: ${segment.seq} text: '${segment.toString()}'`;
|
|
2381
|
-
if (segment.removedSeq !== undefined) {
|
|
2382
|
-
segInfo += ` rcli: ${glc(this, segment.removedClientId)} rseq: ${segment.removedSeq}`;
|
|
2383
|
-
}
|
|
2384
|
-
}
|
|
2385
|
-
// eslint-disable-next-line max-len
|
|
2386
|
-
console.log(`@tcli ${glc(this, this.collabWindow.clientId)}: map len: ${len} start: ${_start} end: ${_end} ${segInfo}`);
|
|
2387
|
-
}
|
|
2388
2142
|
if (go && (_end > 0) && (len > 0) && (_start < len)) {
|
|
2389
2143
|
// Found entry containing pos
|
|
2390
2144
|
if (!child.isLeaf()) {
|
|
@@ -2393,9 +2147,6 @@ export class MergeTree {
|
|
|
2393
2147
|
}
|
|
2394
2148
|
}
|
|
2395
2149
|
else {
|
|
2396
|
-
if (MergeTree.traceTraversal) {
|
|
2397
|
-
console.log(`@tcli ${glc(this, this.collabWindow.clientId)}: map leaf action`);
|
|
2398
|
-
}
|
|
2399
2150
|
if (actions.leaf) {
|
|
2400
2151
|
go = actions.leaf(child, _pos, refSeq, clientId, _start, _end, accum);
|
|
2401
2152
|
}
|
|
@@ -2457,18 +2208,8 @@ MergeTree.zamboniSegmentsMaxCount = 2;
|
|
|
2457
2208
|
MergeTree.options = {
|
|
2458
2209
|
incrementalUpdate: true,
|
|
2459
2210
|
insertAfterRemovedSegs: true,
|
|
2460
|
-
measureOrdinalTime: true,
|
|
2461
|
-
measureWindowTime: true,
|
|
2462
2211
|
zamboniSegments: true,
|
|
2463
2212
|
};
|
|
2464
|
-
MergeTree.traceAppend = false;
|
|
2465
|
-
MergeTree.traceZRemove = false;
|
|
2466
|
-
MergeTree.traceOrdinals = false;
|
|
2467
|
-
MergeTree.traceGatherText = false;
|
|
2468
|
-
MergeTree.diagInsertTie = false;
|
|
2469
|
-
MergeTree.diagOverlappingRemove = false;
|
|
2470
|
-
MergeTree.traceTraversal = false;
|
|
2471
|
-
MergeTree.traceIncrTraversal = false;
|
|
2472
2213
|
MergeTree.theUnfinishedNode = { childCount: -1 };
|
|
2473
2214
|
// WARNING:
|
|
2474
2215
|
// Setting blockUpdateMarkers to false will result in eventual consistency issues
|