@fluidframework/merge-tree 0.57.0-51086 → 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.
Files changed (90) hide show
  1. package/dist/base.d.ts +0 -1
  2. package/dist/base.d.ts.map +1 -1
  3. package/dist/base.js.map +1 -1
  4. package/dist/client.d.ts +0 -2
  5. package/dist/client.d.ts.map +1 -1
  6. package/dist/client.js +8 -29
  7. package/dist/client.js.map +1 -1
  8. package/dist/collections.d.ts +0 -3
  9. package/dist/collections.d.ts.map +1 -1
  10. package/dist/collections.js +6 -22
  11. package/dist/collections.js.map +1 -1
  12. package/dist/index.d.ts +0 -1
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +0 -3
  15. package/dist/index.js.map +1 -1
  16. package/dist/mergeTree.d.ts +8 -26
  17. package/dist/mergeTree.d.ts.map +1 -1
  18. package/dist/mergeTree.js +16 -277
  19. package/dist/mergeTree.js.map +1 -1
  20. package/dist/ops.d.ts +0 -6
  21. package/dist/ops.d.ts.map +1 -1
  22. package/dist/ops.js +1 -8
  23. package/dist/ops.js.map +1 -1
  24. package/dist/partialLengths.d.ts.map +1 -1
  25. package/dist/partialLengths.js +0 -9
  26. package/dist/partialLengths.js.map +1 -1
  27. package/dist/properties.d.ts.map +1 -1
  28. package/dist/properties.js +2 -15
  29. package/dist/properties.js.map +1 -1
  30. package/dist/snapshotlegacy.d.ts.map +1 -1
  31. package/dist/snapshotlegacy.js +3 -6
  32. package/dist/snapshotlegacy.js.map +1 -1
  33. package/dist/textSegment.d.ts.map +1 -1
  34. package/dist/textSegment.js +0 -14
  35. package/dist/textSegment.js.map +1 -1
  36. package/lib/base.d.ts +0 -1
  37. package/lib/base.d.ts.map +1 -1
  38. package/lib/base.js.map +1 -1
  39. package/lib/client.d.ts +0 -2
  40. package/lib/client.d.ts.map +1 -1
  41. package/lib/client.js +5 -26
  42. package/lib/client.js.map +1 -1
  43. package/lib/collections.d.ts +0 -3
  44. package/lib/collections.d.ts.map +1 -1
  45. package/lib/collections.js +6 -22
  46. package/lib/collections.js.map +1 -1
  47. package/lib/index.d.ts +0 -1
  48. package/lib/index.d.ts.map +1 -1
  49. package/lib/index.js +0 -1
  50. package/lib/index.js.map +1 -1
  51. package/lib/mergeTree.d.ts +8 -26
  52. package/lib/mergeTree.d.ts.map +1 -1
  53. package/lib/mergeTree.js +15 -274
  54. package/lib/mergeTree.js.map +1 -1
  55. package/lib/ops.d.ts +0 -6
  56. package/lib/ops.d.ts.map +1 -1
  57. package/lib/ops.js +0 -7
  58. package/lib/ops.js.map +1 -1
  59. package/lib/partialLengths.d.ts.map +1 -1
  60. package/lib/partialLengths.js +0 -9
  61. package/lib/partialLengths.js.map +1 -1
  62. package/lib/properties.d.ts.map +1 -1
  63. package/lib/properties.js +2 -15
  64. package/lib/properties.js.map +1 -1
  65. package/lib/snapshotlegacy.d.ts.map +1 -1
  66. package/lib/snapshotlegacy.js +3 -6
  67. package/lib/snapshotlegacy.js.map +1 -1
  68. package/lib/textSegment.d.ts.map +1 -1
  69. package/lib/textSegment.js +1 -15
  70. package/lib/textSegment.js.map +1 -1
  71. package/package.json +8 -8
  72. package/src/base.ts +0 -1
  73. package/src/client.ts +5 -29
  74. package/src/collections.ts +7 -24
  75. package/src/index.ts +0 -1
  76. package/src/mergeTree.ts +31 -306
  77. package/src/ops.ts +0 -7
  78. package/src/partialLengths.ts +0 -10
  79. package/src/properties.ts +7 -15
  80. package/src/snapshotlegacy.ts +4 -6
  81. package/src/textSegment.ts +2 -17
  82. package/dist/text.d.ts +0 -8
  83. package/dist/text.d.ts.map +0 -1
  84. package/dist/text.js +0 -78
  85. package/dist/text.js.map +0 -1
  86. package/lib/text.d.ts +0 -8
  87. package/lib/text.d.ts.map +0 -1
  88. package/lib/text.js +0 -73
  89. package/lib/text.js.map +0 -1
  90. 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
- /* eslint-disable @typescript-eslint/no-shadow */
8
+
9
9
  /* eslint-disable no-bitwise */
10
10
 
11
- import { assert, Trace } from "@fluidframework/common-utils";
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
- // eslint-disable-next-line @typescript-eslint/prefer-function-type
152
+
154
153
  (marker: Marker): void;
155
154
  }
156
155
 
157
156
  export interface ISegmentAction<TClientData> {
158
- // eslint-disable-next-line @typescript-eslint/prefer-function-type
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
- // eslint-disable-next-line @typescript-eslint/prefer-function-type
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
- // eslint-disable-next-line @typescript-eslint/prefer-function-type
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
- // eslint-disable-next-line @typescript-eslint/ban-types
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
- // eslint-disable-next-line @typescript-eslint/ban-types
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, no-restricted-syntax
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, no-restricted-syntax
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
- // eslint-disable-next-line @typescript-eslint/no-this-alias
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
- if (MergeTree.diagOverlappingRemove) {
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
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
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) {
@@ -1060,18 +1039,9 @@ export class MergeTree {
1060
1039
  public static readonly options = {
1061
1040
  incrementalUpdate: true,
1062
1041
  insertAfterRemovedSegs: true,
1063
- measureOrdinalTime: true,
1064
- measureWindowTime: true,
1065
1042
  zamboniSegments: true,
1066
1043
  };
1067
- private static readonly traceAppend = false;
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;
1044
+
1075
1045
  private static readonly initBlockUpdateActions: BlockUpdateActions;
1076
1046
  private static readonly theUnfinishedNode = <IMergeBlock>{ childCount: -1 };
1077
1047
  // WARNING:
@@ -1079,11 +1049,6 @@ export class MergeTree {
1079
1049
  // for property updates on markers when loading from snapshots
1080
1050
  private static readonly blockUpdateMarkers = true;
1081
1051
 
1082
- private windowTime = 0;
1083
- private packTime = 0;
1084
- private ordTime = 0;
1085
- private maxOrdTime = 0;
1086
-
1087
1052
  root: IMergeBlock;
1088
1053
  private readonly blockUpdateActions: BlockUpdateActions = MergeTree.initBlockUpdateActions;
1089
1054
  public readonly collabWindow = new CollaborationWindow();
@@ -1171,7 +1136,6 @@ export class MergeTree {
1171
1136
  assert(!this.collabWindow.collaborating, 0x049 /* "Trying to reload from segments while collaborating!" */);
1172
1137
 
1173
1138
  const maxChildren = MaxNodesInBlock - 1;
1174
- const measureReloadTime = false;
1175
1139
 
1176
1140
  // Starting with the leaf segments, recursively builds the B-Tree layer by layer from the bottom up.
1177
1141
  const buildMergeBlock = (nodes: IMergeNode[]) => {
@@ -1201,26 +1165,16 @@ export class MergeTree {
1201
1165
  this.blockUpdate(block);
1202
1166
  }
1203
1167
 
1204
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
1205
1168
  return blocks.length === 1 // If there is only one block at this layer...
1206
1169
  ? blocks[0] // ...then we're done. Return the root.
1207
1170
  : buildMergeBlock(blocks); // ...otherwise recursively build the next layer above blocks.
1208
1171
  };
1209
-
1210
- let clockStart: Trace | undefined;
1211
- if (measureReloadTime) {
1212
- clockStart = clock();
1213
- }
1214
1172
  if (segments.length > 0) {
1215
1173
  this.root = buildMergeBlock(segments);
1216
1174
  this.nodeUpdateOrdinals(this.root);
1217
1175
  } else {
1218
1176
  this.root = this.makeBlock(0);
1219
1177
  }
1220
-
1221
- if (clockStart) {
1222
- console.log(`reload time ${elapsedMicroseconds(clockStart)}`);
1223
- }
1224
1178
  }
1225
1179
  /* eslint-enable max-len */
1226
1180
 
@@ -1232,15 +1186,7 @@ export class MergeTree {
1232
1186
  this.collabWindow.currentSeq = currentSeq;
1233
1187
  this.segmentsToScour = new Heap<LRUSegment>([], LRUSegmentComparer);
1234
1188
  this.pendingSegments = ListMakeHead<SegmentGroup>();
1235
- const measureFullCollab = false;
1236
- let clockStart: Trace | undefined;
1237
- if (measureFullCollab) {
1238
- clockStart = clock();
1239
- }
1240
1189
  this.nodeUpdateLengthNewStructure(this.root, true);
1241
- if (clockStart) {
1242
- console.log(`update partial lengths at start ${elapsedMicroseconds(clockStart)}`);
1243
- }
1244
1190
  }
1245
1191
 
1246
1192
  private addToLRUSet(segment: ISegment, seq: number) {
@@ -1272,11 +1218,6 @@ export class MergeTree {
1272
1218
  } else if (!segment.trackingCollection.empty) {
1273
1219
  holdNodes.push(segment);
1274
1220
  } 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
1221
  // Notify maintenance event observers that the segment is being unlinked from the MergeTree
1281
1222
  if (this.mergeTreeMaintenanceCallback) {
1282
1223
  this.mergeTreeMaintenanceCallback({
@@ -1298,10 +1239,6 @@ export class MergeTree {
1298
1239
  && this.localNetLength(segment) > 0;
1299
1240
 
1300
1241
  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
1242
  prevSegment!.append(segment);
1306
1243
  if (this.mergeTreeMaintenanceCallback) {
1307
1244
  this.mergeTreeMaintenanceCallback({
@@ -1374,9 +1311,6 @@ export class MergeTree {
1374
1311
  packedBlocks[nodeIndex] = packedBlock;
1375
1312
  this.nodeUpdateLengthNewStructure(packedBlock);
1376
1313
  }
1377
- if (readCount !== totalNodeCount) {
1378
- console.log(`total count ${totalNodeCount} readCount ${readCount}`);
1379
- }
1380
1314
  parent.children = packedBlocks;
1381
1315
  for (let j = 0; j < childCount; j++) {
1382
1316
  parent.assignChild(packedBlocks[j], j, false);
@@ -1394,10 +1328,6 @@ export class MergeTree {
1394
1328
  if (!this.collabWindow.collaborating) {
1395
1329
  return;
1396
1330
  }
1397
- let clockStart;
1398
- if (MergeTree.options.measureWindowTime) {
1399
- clockStart = clock();
1400
- }
1401
1331
 
1402
1332
  for (let i = 0; i < zamboniSegmentsMaxCount; i++) {
1403
1333
  let segmentToScour = this.segmentsToScour!.peek();
@@ -1409,7 +1339,6 @@ export class MergeTree {
1409
1339
  if (segmentToScour.segment!.parent && segmentToScour.segment!.parent.needsScour !== false) {
1410
1340
  const block = segmentToScour.segment!.parent;
1411
1341
  const childrenCopy: IMergeNode[] = [];
1412
- // console.log(`scouring from ${segmentToScour.segment.seq}`);
1413
1342
  this.scourNode(block, childrenCopy);
1414
1343
  // This will avoid the cost of re-scouring nodes
1415
1344
  // that have recently been scoured
@@ -1425,16 +1354,9 @@ export class MergeTree {
1425
1354
  }
1426
1355
 
1427
1356
  if (this.underflow(block) && block.parent) {
1428
- // nodeUpdatePathLengths(node, UnassignedSequenceNumber, -1, true);
1429
- let packClockStart;
1430
- if (MergeTree.options.measureWindowTime) {
1431
- packClockStart = clock();
1432
- }
1357
+
1433
1358
  this.packParent(block.parent);
1434
1359
 
1435
- if (MergeTree.options.measureWindowTime) {
1436
- this.packTime += elapsedMicroseconds(packClockStart);
1437
- }
1438
1360
  } else {
1439
1361
  this.nodeUpdateOrdinals(block);
1440
1362
  this.blockUpdatePathLengths(block, UnassignedSequenceNumber, -1, true);
@@ -1442,10 +1364,6 @@ export class MergeTree {
1442
1364
  }
1443
1365
  }
1444
1366
  }
1445
-
1446
- if (MergeTree.options.measureWindowTime) {
1447
- this.windowTime += elapsedMicroseconds(clockStart);
1448
- }
1449
1367
  }
1450
1368
 
1451
1369
  public getCollabWindow() {
@@ -1495,74 +1413,9 @@ export class MergeTree {
1495
1413
  return stats;
1496
1414
  };
1497
1415
  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
1416
  return rootStats;
1505
1417
  }
1506
1418
 
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
1419
  public getLength(refSeq: number, clientId: number) {
1567
1420
  return this.blockLength(this.root, refSeq, clientId);
1568
1421
  }
@@ -1862,16 +1715,12 @@ export class MergeTree {
1862
1715
  * Assign sequence number to existing segment; update partial lengths to reflect the change
1863
1716
  * @param seq - sequence number given by server to pending segment
1864
1717
  */
1865
- public ackPendingSegment(opArgs: IMergeTreeDeltaOpArgs, verboseOps = false) {
1718
+ public ackPendingSegment(opArgs: IMergeTreeDeltaOpArgs) {
1866
1719
  const seq = opArgs.sequencedMessage!.sequenceNumber;
1867
1720
  const pendingSegmentGroup = this.pendingSegments!.dequeue();
1868
1721
  const nodesToUpdate: IMergeBlock[] = [];
1869
1722
  let overwrite = false;
1870
1723
  if (pendingSegmentGroup !== undefined) {
1871
- if (verboseOps) {
1872
- console.log(`segment group has ${pendingSegmentGroup.segments.length} segments`);
1873
- }
1874
-
1875
1724
  const deltaSegments: IMergeTreeSegmentDelta[] = [];
1876
1725
  pendingSegmentGroup.segments.map((pendingSegment) => {
1877
1726
  overwrite = !pendingSegment.ack(pendingSegmentGroup, opArgs, this) || overwrite;
@@ -1961,13 +1810,8 @@ export class MergeTree {
1961
1810
  seq: number,
1962
1811
  opArgs: IMergeTreeDeltaOpArgs | undefined,
1963
1812
  ) {
1964
- // const tt = MergeTree.traceTraversal;
1965
- // MergeTree.traceTraversal = true;
1966
1813
  this.ensureIntervalBoundary(pos, refSeq, clientId);
1967
1814
 
1968
- if (MergeTree.traceOrdinals) {
1969
- this.ordinalIntegrity();
1970
- }
1971
1815
  const localSeq = seq === UnassignedSequenceNumber ? ++this.collabWindow.localSeq : undefined;
1972
1816
 
1973
1817
  this.blockInsert(pos, refSeq, clientId, seq, localSeq, segments);
@@ -1982,10 +1826,6 @@ export class MergeTree {
1982
1826
  });
1983
1827
  }
1984
1828
 
1985
- // MergeTree.traceTraversal = tt;
1986
- if (MergeTree.traceOrdinals) {
1987
- this.ordinalIntegrity();
1988
- }
1989
1829
  if (this.collabWindow.collaborating && MergeTree.options.zamboniSegments &&
1990
1830
  (seq !== UnassignedSequenceNumber)) {
1991
1831
  this.zamboniSegments();
@@ -2109,7 +1949,13 @@ export class MergeTree {
2109
1949
  /**
2110
1950
  * Resolves a remote client's position against the local sequence
2111
1951
  * and returns the remote client's position relative to the local
2112
- * sequence
1952
+ * sequence. The client ref seq must be above the minimum sequence number
1953
+ * or the return value will be undefined.
1954
+ * Generally this method is used in conjunction with signals which provide
1955
+ * point in time values for the below parameters, and is useful for things
1956
+ * like displaying user position. It should not be used with persisted values
1957
+ * as persisted values will quickly become invalid as the remoteClientRefSeq
1958
+ * moves below the minimum sequence number
2113
1959
  * @param remoteClientPosition - The remote client's position to resolve
2114
1960
  * @param remoteClientRefSeq - The reference sequence number of the remote client
2115
1961
  * @param remoteClientId - The client id of the remote client
@@ -2118,6 +1964,11 @@ export class MergeTree {
2118
1964
  remoteClientPosition: number,
2119
1965
  remoteClientRefSeq: number,
2120
1966
  remoteClientId: number): number | undefined {
1967
+
1968
+ if(remoteClientRefSeq < this.collabWindow.minSeq){
1969
+ return undefined;
1970
+ }
1971
+
2121
1972
  const segmentInfo = this.getContainingSegment(
2122
1973
  remoteClientPosition,
2123
1974
  remoteClientRefSeq,
@@ -2159,10 +2010,6 @@ export class MergeTree {
2159
2010
  let segIsLocal = false;
2160
2011
  const checkSegmentIsLocal = (segment: ISegment, pos: number, refSeq: number, clientId: number) => {
2161
2012
  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
2013
  segIsLocal = true;
2167
2014
  }
2168
2015
  // Only need to look at first segment that follows finished node
@@ -2172,10 +2019,6 @@ export class MergeTree {
2172
2019
  const continueFrom = (node: IMergeBlock) => {
2173
2020
  segIsLocal = false;
2174
2021
  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
2022
  return segIsLocal;
2180
2023
  };
2181
2024
 
@@ -2357,7 +2200,6 @@ export class MergeTree {
2357
2200
  let child: IMergeNode;
2358
2201
  let newNode: IMergeNode | undefined;
2359
2202
  let fromSplit: IMergeBlock | undefined;
2360
- let found = false;
2361
2203
  for (childIndex = 0; childIndex < block.childCount; childIndex++) {
2362
2204
  child = children[childIndex];
2363
2205
  const len = this.nodeLength(child, refSeq, clientId);
@@ -2366,23 +2208,9 @@ export class MergeTree {
2366
2208
  // will be removed, so should just be skipped for now
2367
2209
  continue;
2368
2210
  }
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
2211
 
2383
2212
  if ((_pos < len) || ((_pos === len) && this.breakTie(_pos, child, seq))) {
2384
2213
  // Found entry containing pos
2385
- found = true;
2386
2214
  if (!child.isLeaf()) {
2387
2215
  const childBlock = child;
2388
2216
  // Internal node
@@ -2396,10 +2224,6 @@ export class MergeTree {
2396
2224
  }
2397
2225
  return undefined;
2398
2226
  } 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
2227
  _pos -= len; // Act as if shifted segment
2404
2228
  continue;
2405
2229
  } else {
@@ -2408,15 +2232,9 @@ export class MergeTree {
2408
2232
  childIndex++; // Insert after
2409
2233
  }
2410
2234
  } else {
2411
- if (MergeTree.traceTraversal) {
2412
- console.log(`@tcli: ${glc(this, this.collabWindow.clientId)}: leaf action`);
2413
- }
2414
2235
  const segment = child;
2415
2236
  const segmentChanges = context.leaf(segment, _pos, context);
2416
2237
  if (segmentChanges.replaceCurrent) {
2417
- if (MergeTree.traceOrdinals) {
2418
- console.log(`assign from leaf with block ord ${ordinalToArray(block.ordinal)}`);
2419
- }
2420
2238
  block.assignChild(segmentChanges.replaceCurrent, childIndex, false);
2421
2239
  segmentChanges.replaceCurrent.ordinal = child.ordinal;
2422
2240
  }
@@ -2436,21 +2254,12 @@ export class MergeTree {
2436
2254
  _pos -= len;
2437
2255
  }
2438
2256
  }
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
2257
  if (!newNode) {
2446
2258
  if (_pos === 0) {
2447
2259
  if ((seq !== UnassignedSequenceNumber) && context.continuePredicate &&
2448
2260
  context.continuePredicate(block)) {
2449
2261
  return MergeTree.theUnfinishedNode;
2450
2262
  } else {
2451
- if (MergeTree.traceTraversal) {
2452
- console.log(`@tcli: ${glc(this, this.collabWindow.clientId)}: leaf action pos 0`);
2453
- }
2454
2263
  const segmentChanges = context.leaf(undefined, _pos, context);
2455
2264
  newNode = segmentChanges.next;
2456
2265
  // Assert segmentChanges.replaceCurrent === undefined
@@ -2467,9 +2276,6 @@ export class MergeTree {
2467
2276
  block.setOrdinal(newNode, childIndex);
2468
2277
  if (block.childCount < MaxNodesInBlock) {
2469
2278
  if (fromSplit) {
2470
- if (MergeTree.traceOrdinals) {
2471
- console.log(`split ord ${ordinalToArray(fromSplit.ordinal)}`);
2472
- }
2473
2279
  this.nodeUpdateOrdinals(fromSplit);
2474
2280
  }
2475
2281
  if (context.structureChange) {
@@ -2502,44 +2308,7 @@ export class MergeTree {
2502
2308
  return newNode;
2503
2309
  }
2504
2310
 
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
2311
  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
2312
  for (let i = 0; i < block.childCount; i++) {
2544
2313
  const child = block.children[i];
2545
2314
  block.setOrdinal(child, i);
@@ -2547,22 +2316,12 @@ export class MergeTree {
2547
2316
  this.nodeUpdateOrdinals(child);
2548
2317
  }
2549
2318
  }
2550
- if (clockStart) {
2551
- const elapsed = elapsedMicroseconds(clockStart);
2552
- if (elapsed > this.maxOrdTime) {
2553
- this.maxOrdTime = elapsed;
2554
- }
2555
- this.ordTime += elapsed;
2556
- }
2557
2319
  }
2558
2320
 
2559
2321
  private addOverlappingClient(removalInfo: IRemovalInfo, clientId: number) {
2560
2322
  if (!removalInfo.removedClientOverlap) {
2561
2323
  removalInfo.removedClientOverlap = <number[]>[];
2562
2324
  }
2563
- if (MergeTree.diagOverlappingRemove) {
2564
- console.log(`added cli ${glc(this, clientId)} to rseq: ${removalInfo.removedSeq}`);
2565
- }
2566
2325
  removalInfo.removedClientOverlap.push(clientId);
2567
2326
  }
2568
2327
 
@@ -2638,10 +2397,6 @@ export class MergeTree {
2638
2397
  const markRemoved = (segment: ISegment, pos: number, start: number, end: number) => {
2639
2398
  const removalInfo: IRemovalInfo = segment;
2640
2399
  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
2400
  _overwrite = true;
2646
2401
  if (removalInfo.removedSeq === UnassignedSequenceNumber) {
2647
2402
  // replace because comes later
@@ -2675,7 +2430,6 @@ export class MergeTree {
2675
2430
  this.addToLRUSet(segment, seq);
2676
2431
  }
2677
2432
  }
2678
- // console.log(`saved local removed seg with text: ${textSegment.text}`);
2679
2433
  }
2680
2434
  return true;
2681
2435
  };
@@ -2687,7 +2441,6 @@ export class MergeTree {
2687
2441
  }
2688
2442
  return true;
2689
2443
  };
2690
- // MergeTree.traceTraversal = true;
2691
2444
  this.mapRange({ leaf: markRemoved, post: afterMarkRemoved }, refSeq, clientId, undefined, start, end);
2692
2445
  if (savedLocalRefs.length > 0) {
2693
2446
  const length = this.getLength(refSeq, clientId);
@@ -2736,7 +2489,6 @@ export class MergeTree {
2736
2489
  this.zamboniSegments();
2737
2490
  }
2738
2491
  }
2739
- // MergeTree.traceTraversal = false;
2740
2492
  }
2741
2493
 
2742
2494
  private nodeUpdateLengthNewStructure(node: IMergeBlock, recur = false) {
@@ -2917,22 +2669,12 @@ export class MergeTree {
2917
2669
  if ((state.op === IncrementalExecOp.Go) && (state.childIndex < state.block.childCount)) {
2918
2670
  const child = state.block.children[state.childIndex];
2919
2671
  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
2672
  if ((len > 0) && (state.start < len) && (state.end > 0)) {
2927
2673
  if (!child.isLeaf()) {
2928
2674
  const childState = new IncrementalMapState(child, state.actions, state.pos,
2929
2675
  state.refSeq, state.clientId, state.context, state.start, state.end, 0);
2930
2676
  stateStack.push(childState);
2931
2677
  } 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
2678
  state.actions.leaf(child, state);
2937
2679
  }
2938
2680
  }
@@ -2975,20 +2717,6 @@ export class MergeTree {
2975
2717
  for (let childIndex = 0; childIndex < node.childCount; childIndex++) {
2976
2718
  const child = children[childIndex];
2977
2719
  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
2720
  if (go && (_end > 0) && (len > 0) && (_start < len)) {
2993
2721
  // Found entry containing pos
2994
2722
  if (!child.isLeaf()) {
@@ -2996,14 +2724,11 @@ export class MergeTree {
2996
2724
  go = this.nodeMap(child, actions, _pos, refSeq, clientId, accum, _start, _end);
2997
2725
  }
2998
2726
  } else {
2999
- if (MergeTree.traceTraversal) {
3000
- console.log(`@tcli ${glc(this, this.collabWindow.clientId)}: map leaf action`);
3001
- }
3002
2727
  if (actions.leaf) {
3003
- go = actions.leaf(child, _pos, refSeq, clientId, _start, _end, accum);
2728
+ go = actions.leaf(child, _pos, refSeq, clientId, _start, _end, accum);
2729
+ }
3004
2730
  }
3005
2731
  }
3006
- }
3007
2732
  if (!go) {
3008
2733
  break;
3009
2734
  }