@fluidframework/merge-tree 2.22.0 → 2.22.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/merge-tree",
3
- "version": "2.22.0",
3
+ "version": "2.22.1",
4
4
  "description": "Merge tree",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -81,30 +81,30 @@
81
81
  "temp-directory": "nyc/.nyc_output"
82
82
  },
83
83
  "dependencies": {
84
- "@fluid-internal/client-utils": "~2.22.0",
85
- "@fluidframework/container-definitions": "~2.22.0",
86
- "@fluidframework/core-interfaces": "~2.22.0",
87
- "@fluidframework/core-utils": "~2.22.0",
88
- "@fluidframework/datastore-definitions": "~2.22.0",
89
- "@fluidframework/driver-definitions": "~2.22.0",
90
- "@fluidframework/runtime-definitions": "~2.22.0",
91
- "@fluidframework/runtime-utils": "~2.22.0",
92
- "@fluidframework/shared-object-base": "~2.22.0",
93
- "@fluidframework/telemetry-utils": "~2.22.0"
84
+ "@fluid-internal/client-utils": "~2.22.1",
85
+ "@fluidframework/container-definitions": "~2.22.1",
86
+ "@fluidframework/core-interfaces": "~2.22.1",
87
+ "@fluidframework/core-utils": "~2.22.1",
88
+ "@fluidframework/datastore-definitions": "~2.22.1",
89
+ "@fluidframework/driver-definitions": "~2.22.1",
90
+ "@fluidframework/runtime-definitions": "~2.22.1",
91
+ "@fluidframework/runtime-utils": "~2.22.1",
92
+ "@fluidframework/shared-object-base": "~2.22.1",
93
+ "@fluidframework/telemetry-utils": "~2.22.1"
94
94
  },
95
95
  "devDependencies": {
96
96
  "@arethetypeswrong/cli": "^0.17.1",
97
97
  "@biomejs/biome": "~1.9.3",
98
- "@fluid-internal/mocha-test-setup": "~2.22.0",
99
- "@fluid-private/stochastic-test-utils": "~2.22.0",
100
- "@fluid-private/test-pairwise-generator": "~2.22.0",
98
+ "@fluid-internal/mocha-test-setup": "~2.22.1",
99
+ "@fluid-private/stochastic-test-utils": "~2.22.1",
100
+ "@fluid-private/test-pairwise-generator": "~2.22.1",
101
101
  "@fluid-tools/benchmark": "^0.50.0",
102
102
  "@fluid-tools/build-cli": "^0.51.0",
103
103
  "@fluidframework/build-common": "^2.0.3",
104
104
  "@fluidframework/build-tools": "^0.51.0",
105
105
  "@fluidframework/eslint-config-fluid": "^5.7.3",
106
- "@fluidframework/merge-tree-previous": "npm:@fluidframework/merge-tree@2.21.0",
107
- "@fluidframework/test-runtime-utils": "~2.22.0",
106
+ "@fluidframework/merge-tree-previous": "npm:@fluidframework/merge-tree@2.22.0",
107
+ "@fluidframework/test-runtime-utils": "~2.22.1",
108
108
  "@microsoft/api-extractor": "7.47.8",
109
109
  "@types/diff": "^3.5.1",
110
110
  "@types/mocha": "^10.0.10",
package/src/mergeTree.ts CHANGED
@@ -1611,6 +1611,8 @@ export class MergeTree {
1611
1611
  let normalizedNewestSeq: number = 0;
1612
1612
  const movedClientIds: number[] = [];
1613
1613
  const movedSeqs: number[] = [];
1614
+ let newestAcked: ObliterateInfo | undefined;
1615
+ let oldestUnacked: ObliterateInfo | undefined;
1614
1616
  for (const ob of this.obliterates.findOverlapping(newSegment)) {
1615
1617
  // compute a normalized seq that takes into account local seqs
1616
1618
  // but is still comparable to remote seqs to keep the checks below easy
@@ -1641,6 +1643,23 @@ export class MergeTree {
1641
1643
  normalizedNewestSeq = normalizedObSeq;
1642
1644
  newest = ob;
1643
1645
  }
1646
+
1647
+ if (
1648
+ ob.seq !== UnassignedSequenceNumber &&
1649
+ (newestAcked === undefined || newestAcked.seq < ob.seq)
1650
+ ) {
1651
+ newestAcked = ob;
1652
+ }
1653
+
1654
+ if (
1655
+ ob.seq === UnassignedSequenceNumber &&
1656
+ (oldestUnacked === undefined || oldestUnacked.localSeq! > ob.localSeq!)
1657
+ ) {
1658
+ // There can be one local obliterate surrounding a segment if a client repeatedly obliterates
1659
+ // a region (ex: in the text ABCDEFG, obliterate D, then obliterate CE, then BF). In this case,
1660
+ // the first one that's applied will be the one that actually removes the segment.
1661
+ oldestUnacked = ob;
1662
+ }
1644
1663
  }
1645
1664
  }
1646
1665
 
@@ -1649,23 +1668,41 @@ export class MergeTree {
1649
1668
  // by the same client that's inserting this segment, we let them insert into this range and therefore don't
1650
1669
  // mark it obliterated.
1651
1670
  if (oldest && newest?.clientId !== clientId) {
1652
- const moveInfo: IMoveInfo = {
1653
- movedClientIds,
1654
- movedSeq: oldest.seq,
1655
- movedSeqs,
1656
- localMovedSeq: oldest.localSeq,
1657
- wasMovedOnInsert: oldest.seq !== UnassignedSequenceNumber,
1658
- };
1671
+ let moveInfo: IMoveInfo;
1672
+ if (newestAcked === newest || newestAcked?.clientId !== clientId) {
1673
+ moveInfo = {
1674
+ movedClientIds,
1675
+ movedSeq: oldest.seq,
1676
+ movedSeqs,
1677
+ localMovedSeq: oldestUnacked?.localSeq,
1678
+ wasMovedOnInsert: oldest.seq !== UnassignedSequenceNumber,
1679
+ };
1680
+ } else {
1681
+ assert(
1682
+ oldestUnacked !== undefined,
1683
+ "Expected local obliterate to be defined if newestAcked is not equal to newest",
1684
+ );
1685
+ // There's a pending local obliterate for this range, so it will be marked as obliterated by us. However,
1686
+ // all other clients are under the impression that the most recent acked obliterate won the right to insert
1687
+ // in this range.
1688
+ moveInfo = {
1689
+ movedClientIds: [oldestUnacked.clientId],
1690
+ movedSeq: oldestUnacked.seq,
1691
+ movedSeqs: [oldestUnacked.seq],
1692
+ localMovedSeq: oldestUnacked.localSeq,
1693
+ wasMovedOnInsert: false,
1694
+ };
1695
+ }
1659
1696
 
1660
1697
  overwriteInfo(newSegment, moveInfo);
1661
1698
 
1662
1699
  if (moveInfo.localMovedSeq !== undefined) {
1663
1700
  assert(
1664
- oldest.segmentGroup !== undefined,
1701
+ oldestUnacked?.segmentGroup !== undefined,
1665
1702
  0x86c /* expected segment group to exist */,
1666
1703
  );
1667
1704
 
1668
- this.addToPendingList(newSegment, oldest.segmentGroup);
1705
+ this.addToPendingList(newSegment, oldestUnacked?.segmentGroup);
1669
1706
  }
1670
1707
 
1671
1708
  if (newSegment.parent) {