@fluidframework/merge-tree 2.21.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/.eslintrc.cjs +0 -1
- package/CHANGELOG.md +4 -0
- package/README.md +1 -0
- package/dist/attributionCollection.js +5 -7
- package/dist/attributionCollection.js.map +1 -1
- package/dist/localReference.js +6 -8
- package/dist/localReference.js.map +1 -1
- package/dist/mergeTree.d.ts.map +1 -1
- package/dist/mergeTree.js +107 -43
- package/dist/mergeTree.js.map +1 -1
- package/dist/mergeTreeNodes.d.ts +15 -4
- package/dist/mergeTreeNodes.d.ts.map +1 -1
- package/dist/mergeTreeNodes.js +1 -1
- package/dist/mergeTreeNodes.js.map +1 -1
- package/dist/partialLengths.d.ts +114 -144
- package/dist/partialLengths.d.ts.map +1 -1
- package/dist/partialLengths.js +431 -525
- package/dist/partialLengths.js.map +1 -1
- package/dist/perspective.d.ts +10 -1
- package/dist/perspective.d.ts.map +1 -1
- package/dist/perspective.js +10 -1
- package/dist/perspective.js.map +1 -1
- package/dist/properties.d.ts.map +1 -1
- package/dist/properties.js +2 -3
- package/dist/properties.js.map +1 -1
- package/dist/revertibles.js +3 -3
- package/dist/revertibles.js.map +1 -1
- package/dist/segmentInfos.d.ts +3 -0
- package/dist/segmentInfos.d.ts.map +1 -1
- package/dist/segmentInfos.js.map +1 -1
- package/dist/segmentPropertiesManager.js +3 -3
- package/dist/segmentPropertiesManager.js.map +1 -1
- package/dist/snapshotLoader.js +2 -2
- package/dist/snapshotLoader.js.map +1 -1
- package/dist/sortedSegmentSet.d.ts +5 -3
- package/dist/sortedSegmentSet.d.ts.map +1 -1
- package/dist/sortedSegmentSet.js +33 -41
- package/dist/sortedSegmentSet.js.map +1 -1
- package/dist/sortedSet.d.ts +20 -3
- package/dist/sortedSet.d.ts.map +1 -1
- package/dist/sortedSet.js +23 -14
- package/dist/sortedSet.js.map +1 -1
- package/dist/test/Snapshot.perf.spec.js +1 -1
- package/dist/test/Snapshot.perf.spec.js.map +1 -1
- package/dist/test/client.applyMsg.spec.js +20 -0
- package/dist/test/client.applyMsg.spec.js.map +1 -1
- package/dist/test/client.applyStashedOpFarm.spec.js +1 -1
- package/dist/test/client.applyStashedOpFarm.spec.js.map +1 -1
- package/dist/test/client.attributionFarm.spec.js +1 -1
- package/dist/test/client.attributionFarm.spec.js.map +1 -1
- package/dist/test/client.localReference.spec.js +48 -0
- package/dist/test/client.localReference.spec.js.map +1 -1
- package/dist/test/client.obliterateFarm.spec.d.ts.map +1 -1
- package/dist/test/client.obliterateFarm.spec.js +12 -3
- package/dist/test/client.obliterateFarm.spec.js.map +1 -1
- package/dist/test/client.reconnectFarm.spec.js +1 -1
- package/dist/test/client.reconnectFarm.spec.js.map +1 -1
- package/dist/test/client.searchForMarker.spec.js +2 -2
- package/dist/test/client.searchForMarker.spec.js.map +1 -1
- package/dist/test/mergeTreeOperationRunner.d.ts +1 -1
- package/dist/test/mergeTreeOperationRunner.d.ts.map +1 -1
- package/dist/test/mergeTreeOperationRunner.js +23 -11
- package/dist/test/mergeTreeOperationRunner.js.map +1 -1
- package/dist/test/obliterate.concurrent.spec.js +97 -1
- package/dist/test/obliterate.concurrent.spec.js.map +1 -1
- package/dist/test/obliterate.rangeExpansion.spec.js +81 -5
- package/dist/test/obliterate.rangeExpansion.spec.js.map +1 -1
- package/dist/test/obliterate.spec.js +3 -3
- package/dist/test/obliterate.spec.js.map +1 -1
- package/dist/test/obliterateOperations.d.ts.map +1 -1
- package/dist/test/obliterateOperations.js +29 -18
- package/dist/test/obliterateOperations.js.map +1 -1
- package/dist/test/partialSyncHelper.d.ts +42 -0
- package/dist/test/partialSyncHelper.d.ts.map +1 -0
- package/dist/test/partialSyncHelper.js +96 -0
- package/dist/test/partialSyncHelper.js.map +1 -0
- package/dist/test/revertibles.spec.js +3 -3
- package/dist/test/revertibles.spec.js.map +1 -1
- package/dist/test/sortedSegmentSet.spec.js +21 -0
- package/dist/test/sortedSegmentSet.spec.js.map +1 -1
- package/dist/test/testClient.d.ts +1 -1
- package/dist/test/testClient.d.ts.map +1 -1
- package/dist/test/testClient.js +1 -0
- package/dist/test/testClient.js.map +1 -1
- package/dist/test/testUtils.js +2 -2
- package/dist/test/testUtils.js.map +1 -1
- package/lib/attributionCollection.js +5 -7
- package/lib/attributionCollection.js.map +1 -1
- package/lib/localReference.js +6 -8
- package/lib/localReference.js.map +1 -1
- package/lib/mergeTree.d.ts.map +1 -1
- package/lib/mergeTree.js +107 -43
- package/lib/mergeTree.js.map +1 -1
- package/lib/mergeTreeNodes.d.ts +15 -4
- package/lib/mergeTreeNodes.d.ts.map +1 -1
- package/lib/mergeTreeNodes.js +1 -1
- package/lib/mergeTreeNodes.js.map +1 -1
- package/lib/partialLengths.d.ts +114 -144
- package/lib/partialLengths.d.ts.map +1 -1
- package/lib/partialLengths.js +432 -525
- package/lib/partialLengths.js.map +1 -1
- package/lib/perspective.d.ts +10 -1
- package/lib/perspective.d.ts.map +1 -1
- package/lib/perspective.js +10 -1
- package/lib/perspective.js.map +1 -1
- package/lib/properties.d.ts.map +1 -1
- package/lib/properties.js +2 -3
- package/lib/properties.js.map +1 -1
- package/lib/revertibles.js +3 -3
- package/lib/revertibles.js.map +1 -1
- package/lib/segmentInfos.d.ts +3 -0
- package/lib/segmentInfos.d.ts.map +1 -1
- package/lib/segmentInfos.js.map +1 -1
- package/lib/segmentPropertiesManager.js +3 -3
- package/lib/segmentPropertiesManager.js.map +1 -1
- package/lib/snapshotLoader.js +2 -2
- package/lib/snapshotLoader.js.map +1 -1
- package/lib/sortedSegmentSet.d.ts +5 -3
- package/lib/sortedSegmentSet.d.ts.map +1 -1
- package/lib/sortedSegmentSet.js +33 -41
- package/lib/sortedSegmentSet.js.map +1 -1
- package/lib/sortedSet.d.ts +20 -3
- package/lib/sortedSet.d.ts.map +1 -1
- package/lib/sortedSet.js +23 -14
- package/lib/sortedSet.js.map +1 -1
- package/lib/test/Snapshot.perf.spec.js +1 -1
- package/lib/test/Snapshot.perf.spec.js.map +1 -1
- package/lib/test/client.applyMsg.spec.js +20 -0
- package/lib/test/client.applyMsg.spec.js.map +1 -1
- package/lib/test/client.applyStashedOpFarm.spec.js +1 -1
- package/lib/test/client.applyStashedOpFarm.spec.js.map +1 -1
- package/lib/test/client.attributionFarm.spec.js +1 -1
- package/lib/test/client.attributionFarm.spec.js.map +1 -1
- package/lib/test/client.localReference.spec.js +48 -0
- package/lib/test/client.localReference.spec.js.map +1 -1
- package/lib/test/client.obliterateFarm.spec.d.ts.map +1 -1
- package/lib/test/client.obliterateFarm.spec.js +16 -5
- package/lib/test/client.obliterateFarm.spec.js.map +1 -1
- package/lib/test/client.reconnectFarm.spec.js +1 -1
- package/lib/test/client.reconnectFarm.spec.js.map +1 -1
- package/lib/test/client.searchForMarker.spec.js +2 -2
- package/lib/test/client.searchForMarker.spec.js.map +1 -1
- package/lib/test/mergeTreeOperationRunner.d.ts +1 -1
- package/lib/test/mergeTreeOperationRunner.d.ts.map +1 -1
- package/lib/test/mergeTreeOperationRunner.js +23 -11
- package/lib/test/mergeTreeOperationRunner.js.map +1 -1
- package/lib/test/obliterate.concurrent.spec.js +97 -1
- package/lib/test/obliterate.concurrent.spec.js.map +1 -1
- package/lib/test/obliterate.rangeExpansion.spec.js +81 -5
- package/lib/test/obliterate.rangeExpansion.spec.js.map +1 -1
- package/lib/test/obliterate.spec.js +3 -3
- package/lib/test/obliterate.spec.js.map +1 -1
- package/lib/test/obliterateOperations.d.ts.map +1 -1
- package/lib/test/obliterateOperations.js +29 -18
- package/lib/test/obliterateOperations.js.map +1 -1
- package/lib/test/partialSyncHelper.d.ts +42 -0
- package/lib/test/partialSyncHelper.d.ts.map +1 -0
- package/lib/test/partialSyncHelper.js +92 -0
- package/lib/test/partialSyncHelper.js.map +1 -0
- package/lib/test/revertibles.spec.js +3 -3
- package/lib/test/revertibles.spec.js.map +1 -1
- package/lib/test/sortedSegmentSet.spec.js +21 -0
- package/lib/test/sortedSegmentSet.spec.js.map +1 -1
- package/lib/test/testClient.d.ts +1 -1
- package/lib/test/testClient.d.ts.map +1 -1
- package/lib/test/testClient.js +1 -0
- package/lib/test/testClient.js.map +1 -1
- package/lib/test/testUtils.js +2 -2
- package/lib/test/testUtils.js.map +1 -1
- package/package.json +18 -18
- package/src/mergeTree.ts +126 -37
- package/src/mergeTreeNodes.ts +15 -4
- package/src/partialLengths.ts +559 -776
- package/src/perspective.ts +10 -1
- package/src/properties.ts +2 -3
- package/src/segmentInfos.ts +3 -0
- package/src/snapshotLoader.ts +1 -1
- package/src/sortedSegmentSet.ts +41 -50
- package/src/sortedSet.ts +32 -16
|
@@ -7,6 +7,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
const node_assert_1 = require("node:assert");
|
|
8
8
|
const internal_1 = require("@fluidframework/telemetry-utils/internal");
|
|
9
9
|
const mergeTree_js_1 = require("../mergeTree.js");
|
|
10
|
+
const sequencePlace_js_1 = require("../sequencePlace.js");
|
|
11
|
+
const partialSyncHelper_js_1 = require("./partialSyncHelper.js");
|
|
10
12
|
const reconnectHelper_js_1 = require("./reconnectHelper.js");
|
|
11
13
|
const testUtils_js_1 = require("./testUtils.js");
|
|
12
14
|
/**
|
|
@@ -1193,7 +1195,6 @@ for (const incremental of [true, false]) {
|
|
|
1193
1195
|
node_assert_1.strict.equal(helper.clients.A.getText(), "BR");
|
|
1194
1196
|
helper.logger.validate();
|
|
1195
1197
|
});
|
|
1196
|
-
// fails only for incremental
|
|
1197
1198
|
it("combines remote obliterated length ", () => {
|
|
1198
1199
|
const helper = new reconnectHelper_js_1.ReconnectTestHelper();
|
|
1199
1200
|
// R-XYZ12-STUVW-LMNOP-DEFGHIJK-A-34567890-Q-BC
|
|
@@ -1455,6 +1456,101 @@ for (const incremental of [true, false]) {
|
|
|
1455
1456
|
node_assert_1.strict.equal(helper.clients.A.getText(), "jihagSCdfeD");
|
|
1456
1457
|
helper.logger.validate();
|
|
1457
1458
|
});
|
|
1459
|
+
it("Fuzz regression for negative partial lengths", () => {
|
|
1460
|
+
// This is a regression test for AB#15630.
|
|
1461
|
+
// Strict partial lengths checks reported an inconsistency when B applies A's
|
|
1462
|
+
// obliterateRange op for the length of the string at refSeq 4.
|
|
1463
|
+
// With strict partial lengths disabled, this manifested in 0x4bc on the subsequent op application.
|
|
1464
|
+
const helper = new partialSyncHelper_js_1.PartialSyncTestHelper();
|
|
1465
|
+
helper.insertText("D", 0, "ABCDEFGH");
|
|
1466
|
+
helper.processAllOps();
|
|
1467
|
+
helper.insertText("B", 0, "123456xxxxx7890");
|
|
1468
|
+
helper.advanceClients("C");
|
|
1469
|
+
helper.obliterateRange("B", 15, 20);
|
|
1470
|
+
helper.advanceClients("A", "B");
|
|
1471
|
+
helper.insertText("A", 4, "a");
|
|
1472
|
+
helper.advanceClients("A");
|
|
1473
|
+
helper.insertText("C", 0, "c");
|
|
1474
|
+
helper.obliterateRange("C", { pos: 4, side: sequencePlace_js_1.Side.After }, { pos: 10, side: sequencePlace_js_1.Side.After });
|
|
1475
|
+
helper.obliterateRange("A", { pos: 0, side: sequencePlace_js_1.Side.Before }, { pos: 7, side: sequencePlace_js_1.Side.After });
|
|
1476
|
+
helper.removeRange("A", 0, 1);
|
|
1477
|
+
helper.processAllOps();
|
|
1478
|
+
helper.logger.validate({ baseText: "cx7890FGH" });
|
|
1479
|
+
});
|
|
1480
|
+
it("Avoids adding entries for insert with subsequent removal", () => {
|
|
1481
|
+
const helper = new partialSyncHelper_js_1.PartialSyncTestHelper();
|
|
1482
|
+
helper.insertText("D", 0, "bZL4aQd");
|
|
1483
|
+
helper.processAllOps();
|
|
1484
|
+
helper.insertText("A", 0, "8mvaLcEa4nwhELu");
|
|
1485
|
+
helper.processAllOps();
|
|
1486
|
+
// These 3 ops are the crux of the test: A's inserted segment is both obliterated by C as soon as it is inserted
|
|
1487
|
+
// as well as removed by A before the insertion is acked.
|
|
1488
|
+
// This is an interesting case for partial lengths of observing clients, as:
|
|
1489
|
+
// - obliteration by C on insertion means the segment would normally only be visible to the inserting client
|
|
1490
|
+
// - ... but after some client receives the notice of A's removal, it shouldn't be visible there either!
|
|
1491
|
+
helper.obliterateRange("C", { pos: 2, side: sequencePlace_js_1.Side.After }, { pos: 21, side: sequencePlace_js_1.Side.After });
|
|
1492
|
+
helper.insertText("A", 3, "Y");
|
|
1493
|
+
helper.removeRange("A", 2, 4);
|
|
1494
|
+
// The subsequent operations forced failure at the time the code was defective, since clients with incorrect
|
|
1495
|
+
// partial lengths adjustments for A would misinterpret where these ops should go.
|
|
1496
|
+
helper.obliterateRange("A", { pos: 2, side: sequencePlace_js_1.Side.After }, { pos: 6, side: sequencePlace_js_1.Side.After });
|
|
1497
|
+
helper.obliterateRange("A", 2, 3);
|
|
1498
|
+
helper.insertText("A", 3, "X");
|
|
1499
|
+
helper.processAllOps();
|
|
1500
|
+
helper.logger.validate({ baseText: "8m" });
|
|
1501
|
+
});
|
|
1502
|
+
// See 'Local obliterate wins post-insertion of segment previously thought to have won' (below) for a simpler
|
|
1503
|
+
// to understand version of this test. This test is the original partial synchronization fuzz variant which
|
|
1504
|
+
// demonstrated that issue, and has been preserved for now in case it catches additional related problems.
|
|
1505
|
+
// Once fuzz testing more meaninfully leverages ops being sent to different clients at different types (partial
|
|
1506
|
+
// synchronization), it's probably fine to remove this.
|
|
1507
|
+
it("fuzz regression: Local obliterate wins post-insertion of segment previously thought to have won", () => {
|
|
1508
|
+
const helper = new partialSyncHelper_js_1.PartialSyncTestHelper();
|
|
1509
|
+
helper.insertText("A", 0, "Hx15J");
|
|
1510
|
+
helper.processAllOps();
|
|
1511
|
+
helper.insertText("A", 0, "9T");
|
|
1512
|
+
helper.insertText("B", 0, "c8v");
|
|
1513
|
+
helper.advanceClients("A", "C");
|
|
1514
|
+
helper.removeRange("A", 2, 5);
|
|
1515
|
+
helper.removeRange("A", 0, 1);
|
|
1516
|
+
helper.obliterateRange("A", 0, 3);
|
|
1517
|
+
helper.obliterateRange("C", { pos: 1, side: sequencePlace_js_1.Side.After }, { pos: 4, side: sequencePlace_js_1.Side.Before });
|
|
1518
|
+
helper.insertText("B", 0, "4qpo");
|
|
1519
|
+
helper.insertText("C", 2, "fP");
|
|
1520
|
+
helper.insertText("A", 0, "hn");
|
|
1521
|
+
helper.advanceClients("A", "C");
|
|
1522
|
+
helper.obliterateRange("A", { pos: 5, side: sequencePlace_js_1.Side.After }, { pos: 9, side: sequencePlace_js_1.Side.After });
|
|
1523
|
+
helper.obliterateRange("B", { pos: 3, side: sequencePlace_js_1.Side.Before }, { pos: 9, side: sequencePlace_js_1.Side.After });
|
|
1524
|
+
// At the time of the original bug, this would hit 0xa3f.
|
|
1525
|
+
helper.processAllOps();
|
|
1526
|
+
helper.logger.validate({ baseText: "hn4qpJ" });
|
|
1527
|
+
});
|
|
1528
|
+
// Simpler version of the above test which has the same root cause but reproduces a slightly different failure mode.
|
|
1529
|
+
it("Local obliterate wins post-insertion of segment previously thought to have won", () => {
|
|
1530
|
+
const helper = new partialSyncHelper_js_1.PartialSyncTestHelper();
|
|
1531
|
+
helper.insertText("A", 0, "1xx2");
|
|
1532
|
+
helper.processAllOps();
|
|
1533
|
+
// A and B both obliterate the 'xx' segment with an expanding obliterate, then try to insert
|
|
1534
|
+
// into the gap that it leaves.
|
|
1535
|
+
helper.obliterateRange("A", { pos: 0, side: sequencePlace_js_1.Side.After }, { pos: 3, side: sequencePlace_js_1.Side.Before });
|
|
1536
|
+
helper.insertText("A", 1, "aaaa");
|
|
1537
|
+
helper.obliterateRange("B", { pos: 0, side: sequencePlace_js_1.Side.After }, { pos: 3, side: sequencePlace_js_1.Side.Before });
|
|
1538
|
+
helper.insertText("B", 1, "bbb");
|
|
1539
|
+
helper.advanceClients("A", "B");
|
|
1540
|
+
// Meanwhile, C attempts the same thing without seeing A or B's obliterate & insertions
|
|
1541
|
+
helper.obliterateRange("C", { pos: 0, side: sequencePlace_js_1.Side.After }, { pos: 3, side: sequencePlace_js_1.Side.Before });
|
|
1542
|
+
helper.insertText("C", 1, "ccc");
|
|
1543
|
+
// Before seeing C's ops, B attempts to insert more content. Since B hasn't yet seen C's obliterate,
|
|
1544
|
+
// A and B are under the impression that B's obliterate has won and the string contents are '1bbb2'.
|
|
1545
|
+
helper.insertText("B", 5, "B");
|
|
1546
|
+
helper.insertText("A", 5, "A");
|
|
1547
|
+
helper.processAllOps();
|
|
1548
|
+
// By now, all clients realize C actually won the obliterate and should have additionally applied B's
|
|
1549
|
+
// op correctly as it was outside of the obliterated range.
|
|
1550
|
+
// At the time this test was written, client C had trouble recognizing that A and B think that B has won
|
|
1551
|
+
// and merged incorrectly, hitting 'MergeTree insert failed'.
|
|
1552
|
+
helper.logger.validate({ baseText: "1ccc2AB" });
|
|
1553
|
+
});
|
|
1458
1554
|
});
|
|
1459
1555
|
});
|
|
1460
1556
|
}
|