@fluidframework/merge-tree 2.30.0 → 2.31.0
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/CHANGELOG.md +403 -399
- package/api-report/merge-tree.legacy.alpha.api.md +1 -0
- package/dist/MergeTreeTextHelper.d.ts +9 -3
- package/dist/MergeTreeTextHelper.d.ts.map +1 -1
- package/dist/MergeTreeTextHelper.js +5 -5
- package/dist/MergeTreeTextHelper.js.map +1 -1
- package/dist/client.d.ts +7 -13
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +136 -110
- package/dist/client.js.map +1 -1
- package/dist/endOfTreeSegment.d.ts +12 -8
- package/dist/endOfTreeSegment.d.ts.map +1 -1
- package/dist/endOfTreeSegment.js +2 -4
- package/dist/endOfTreeSegment.js.map +1 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -3
- package/dist/index.js.map +1 -1
- package/dist/mergeTree.d.ts +37 -23
- package/dist/mergeTree.d.ts.map +1 -1
- package/dist/mergeTree.js +400 -483
- package/dist/mergeTree.js.map +1 -1
- package/dist/mergeTreeDeltaCallback.d.ts +4 -8
- package/dist/mergeTreeDeltaCallback.d.ts.map +1 -1
- package/dist/mergeTreeDeltaCallback.js.map +1 -1
- package/dist/mergeTreeNodes.d.ts +32 -10
- package/dist/mergeTreeNodes.d.ts.map +1 -1
- package/dist/mergeTreeNodes.js +43 -28
- package/dist/mergeTreeNodes.js.map +1 -1
- package/dist/partialLengths.d.ts +2 -2
- package/dist/partialLengths.d.ts.map +1 -1
- package/dist/partialLengths.js +181 -109
- package/dist/partialLengths.js.map +1 -1
- package/dist/perspective.d.ts +8 -27
- package/dist/perspective.d.ts.map +1 -1
- package/dist/perspective.js +7 -67
- package/dist/perspective.js.map +1 -1
- package/dist/revertibles.d.ts.map +1 -1
- package/dist/revertibles.js +2 -2
- package/dist/revertibles.js.map +1 -1
- package/dist/segmentInfos.d.ts +20 -106
- package/dist/segmentInfos.d.ts.map +1 -1
- package/dist/segmentInfos.js +28 -42
- package/dist/segmentInfos.js.map +1 -1
- package/dist/segmentPropertiesManager.d.ts +1 -14
- package/dist/segmentPropertiesManager.d.ts.map +1 -1
- package/dist/segmentPropertiesManager.js +3 -17
- package/dist/segmentPropertiesManager.js.map +1 -1
- package/dist/snapshotLoader.d.ts.map +1 -1
- package/dist/snapshotLoader.js +62 -19
- package/dist/snapshotLoader.js.map +1 -1
- package/dist/snapshotV1.d.ts.map +1 -1
- package/dist/snapshotV1.js +55 -24
- package/dist/snapshotV1.js.map +1 -1
- package/dist/snapshotlegacy.d.ts.map +1 -1
- package/dist/snapshotlegacy.js +6 -9
- package/dist/snapshotlegacy.js.map +1 -1
- package/dist/stamps.d.ts +1 -1
- package/dist/stamps.js +1 -1
- package/dist/stamps.js.map +1 -1
- package/dist/test/Insertion.perf.spec.js +6 -51
- package/dist/test/Insertion.perf.spec.js.map +1 -1
- package/dist/test/PartialLengths.perf.spec.js +18 -25
- package/dist/test/PartialLengths.perf.spec.js.map +1 -1
- package/dist/test/Removal.perf.spec.js +13 -41
- package/dist/test/Removal.perf.spec.js.map +1 -1
- package/dist/test/beastTest.spec.d.ts.map +1 -1
- package/dist/test/beastTest.spec.js +41 -66
- package/dist/test/beastTest.spec.js.map +1 -1
- package/dist/test/client.annotateMarker.spec.js +1 -11
- package/dist/test/client.annotateMarker.spec.js.map +1 -1
- package/dist/test/client.applyMsg.spec.js +14 -14
- package/dist/test/client.applyMsg.spec.js.map +1 -1
- package/dist/test/client.getPosition.spec.js +1 -1
- package/dist/test/client.getPosition.spec.js.map +1 -1
- package/dist/test/client.localReference.spec.js +1 -1
- package/dist/test/client.localReference.spec.js.map +1 -1
- package/dist/test/client.rollback.spec.js +49 -58
- package/dist/test/client.rollback.spec.js.map +1 -1
- package/dist/test/client.rollbackFarm.spec.js +1 -1
- package/dist/test/client.rollbackFarm.spec.js.map +1 -1
- package/dist/test/client.searchForMarker.spec.js +4 -21
- package/dist/test/client.searchForMarker.spec.js.map +1 -1
- package/dist/test/index.d.ts +2 -2
- package/dist/test/index.d.ts.map +1 -1
- package/dist/test/index.js +2 -6
- package/dist/test/index.js.map +1 -1
- package/dist/test/mergeTree.annotate.deltaCallback.spec.js +14 -59
- package/dist/test/mergeTree.annotate.deltaCallback.spec.js.map +1 -1
- package/dist/test/mergeTree.annotate.spec.js +47 -63
- package/dist/test/mergeTree.annotate.spec.js.map +1 -1
- package/dist/test/mergeTree.insert.deltaCallback.spec.js +9 -62
- package/dist/test/mergeTree.insert.deltaCallback.spec.js.map +1 -1
- package/dist/test/mergeTree.insertingWalk.spec.js +59 -125
- package/dist/test/mergeTree.insertingWalk.spec.js.map +1 -1
- package/dist/test/mergeTree.markRangeRemoved.deltaCallback.spec.js +12 -93
- package/dist/test/mergeTree.markRangeRemoved.deltaCallback.spec.js.map +1 -1
- package/dist/test/mergeTree.markRangeRemoved.spec.js +10 -7
- package/dist/test/mergeTree.markRangeRemoved.spec.js.map +1 -1
- package/dist/test/mergeTree.walk.spec.js +2 -14
- package/dist/test/mergeTree.walk.spec.js.map +1 -1
- package/dist/test/mergeTreeOperationRunner.js +2 -2
- package/dist/test/mergeTreeOperationRunner.js.map +1 -1
- package/dist/test/obliterate.concurrent.spec.js +18 -23
- package/dist/test/obliterate.concurrent.spec.js.map +1 -1
- package/dist/test/obliterate.partialLength.spec.js +166 -136
- package/dist/test/obliterate.partialLength.spec.js.map +1 -1
- package/dist/test/obliterate.spec.js +16 -126
- package/dist/test/obliterate.spec.js.map +1 -1
- package/dist/test/partialLength.spec.js +28 -196
- package/dist/test/partialLength.spec.js.map +1 -1
- package/dist/test/perspective.spec.js +34 -0
- package/dist/test/perspective.spec.js.map +1 -1
- package/dist/test/propertyManager.spec.js +1 -1
- package/dist/test/propertyManager.spec.js.map +1 -1
- package/dist/test/resetPendingSegmentsToOp.spec.js +0 -2
- package/dist/test/resetPendingSegmentsToOp.spec.js.map +1 -1
- package/dist/test/segmentGroupCollection.spec.js +10 -4
- package/dist/test/segmentGroupCollection.spec.js.map +1 -1
- package/dist/test/testClient.d.ts +1 -0
- package/dist/test/testClient.d.ts.map +1 -1
- package/dist/test/testClient.js +16 -26
- package/dist/test/testClient.js.map +1 -1
- package/dist/test/testClientLogger.d.ts.map +1 -1
- package/dist/test/testClientLogger.js +3 -10
- package/dist/test/testClientLogger.js.map +1 -1
- package/dist/test/testServer.d.ts +2 -1
- package/dist/test/testServer.d.ts.map +1 -1
- package/dist/test/testServer.js +7 -5
- package/dist/test/testServer.js.map +1 -1
- package/dist/test/testUtils.d.ts +36 -56
- package/dist/test/testUtils.d.ts.map +1 -1
- package/dist/test/testUtils.js +68 -77
- package/dist/test/testUtils.js.map +1 -1
- package/dist/test/text.d.ts +2 -2
- package/dist/test/text.d.ts.map +1 -1
- package/dist/test/text.js +5 -2
- package/dist/test/text.js.map +1 -1
- package/dist/textSegment.d.ts +0 -6
- package/dist/textSegment.d.ts.map +1 -1
- package/dist/textSegment.js.map +1 -1
- package/dist/zamboni.d.ts.map +1 -1
- package/dist/zamboni.js +53 -26
- package/dist/zamboni.js.map +1 -1
- package/lib/MergeTreeTextHelper.d.ts +9 -3
- package/lib/MergeTreeTextHelper.d.ts.map +1 -1
- package/lib/MergeTreeTextHelper.js +5 -5
- package/lib/MergeTreeTextHelper.js.map +1 -1
- package/lib/client.d.ts +7 -13
- package/lib/client.d.ts.map +1 -1
- package/lib/client.js +117 -116
- package/lib/client.js.map +1 -1
- package/lib/endOfTreeSegment.d.ts +12 -8
- package/lib/endOfTreeSegment.d.ts.map +1 -1
- package/lib/endOfTreeSegment.js +2 -4
- package/lib/endOfTreeSegment.js.map +1 -1
- package/lib/index.d.ts +6 -3
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/mergeTree.d.ts +37 -23
- package/lib/mergeTree.d.ts.map +1 -1
- package/lib/mergeTree.js +381 -488
- package/lib/mergeTree.js.map +1 -1
- package/lib/mergeTreeDeltaCallback.d.ts +4 -8
- package/lib/mergeTreeDeltaCallback.d.ts.map +1 -1
- package/lib/mergeTreeDeltaCallback.js.map +1 -1
- package/lib/mergeTreeNodes.d.ts +32 -10
- package/lib/mergeTreeNodes.d.ts.map +1 -1
- package/lib/mergeTreeNodes.js +42 -29
- package/lib/mergeTreeNodes.js.map +1 -1
- package/lib/partialLengths.d.ts +2 -2
- package/lib/partialLengths.d.ts.map +1 -1
- package/lib/partialLengths.js +160 -111
- package/lib/partialLengths.js.map +1 -1
- package/lib/perspective.d.ts +8 -27
- package/lib/perspective.d.ts.map +1 -1
- package/lib/perspective.js +8 -68
- package/lib/perspective.js.map +1 -1
- package/lib/revertibles.d.ts.map +1 -1
- package/lib/revertibles.js +2 -2
- package/lib/revertibles.js.map +1 -1
- package/lib/segmentInfos.d.ts +20 -106
- package/lib/segmentInfos.d.ts.map +1 -1
- package/lib/segmentInfos.js +26 -37
- package/lib/segmentInfos.js.map +1 -1
- package/lib/segmentPropertiesManager.d.ts +1 -14
- package/lib/segmentPropertiesManager.d.ts.map +1 -1
- package/lib/segmentPropertiesManager.js +2 -16
- package/lib/segmentPropertiesManager.js.map +1 -1
- package/lib/snapshotLoader.d.ts.map +1 -1
- package/lib/snapshotLoader.js +39 -19
- package/lib/snapshotLoader.js.map +1 -1
- package/lib/snapshotV1.d.ts.map +1 -1
- package/lib/snapshotV1.js +34 -26
- package/lib/snapshotV1.js.map +1 -1
- package/lib/snapshotlegacy.d.ts.map +1 -1
- package/lib/snapshotlegacy.js +7 -10
- package/lib/snapshotlegacy.js.map +1 -1
- package/lib/stamps.d.ts +1 -1
- package/lib/stamps.js +1 -1
- package/lib/stamps.js.map +1 -1
- package/lib/test/Insertion.perf.spec.js +6 -51
- package/lib/test/Insertion.perf.spec.js.map +1 -1
- package/lib/test/PartialLengths.perf.spec.js +18 -25
- package/lib/test/PartialLengths.perf.spec.js.map +1 -1
- package/lib/test/Removal.perf.spec.js +13 -41
- package/lib/test/Removal.perf.spec.js.map +1 -1
- package/lib/test/beastTest.spec.d.ts.map +1 -1
- package/lib/test/beastTest.spec.js +42 -67
- package/lib/test/beastTest.spec.js.map +1 -1
- package/lib/test/client.annotateMarker.spec.js +1 -11
- package/lib/test/client.annotateMarker.spec.js.map +1 -1
- package/lib/test/client.applyMsg.spec.js +14 -14
- package/lib/test/client.applyMsg.spec.js.map +1 -1
- package/lib/test/client.getPosition.spec.js +1 -1
- package/lib/test/client.getPosition.spec.js.map +1 -1
- package/lib/test/client.localReference.spec.js +1 -1
- package/lib/test/client.localReference.spec.js.map +1 -1
- package/lib/test/client.rollback.spec.js +50 -59
- package/lib/test/client.rollback.spec.js.map +1 -1
- package/lib/test/client.rollbackFarm.spec.js +1 -1
- package/lib/test/client.rollbackFarm.spec.js.map +1 -1
- package/lib/test/client.searchForMarker.spec.js +4 -21
- package/lib/test/client.searchForMarker.spec.js.map +1 -1
- package/lib/test/index.d.ts +2 -2
- package/lib/test/index.d.ts.map +1 -1
- package/lib/test/index.js +1 -1
- package/lib/test/index.js.map +1 -1
- package/lib/test/mergeTree.annotate.deltaCallback.spec.js +15 -60
- package/lib/test/mergeTree.annotate.deltaCallback.spec.js.map +1 -1
- package/lib/test/mergeTree.annotate.spec.js +48 -64
- package/lib/test/mergeTree.annotate.spec.js.map +1 -1
- package/lib/test/mergeTree.insert.deltaCallback.spec.js +10 -63
- package/lib/test/mergeTree.insert.deltaCallback.spec.js.map +1 -1
- package/lib/test/mergeTree.insertingWalk.spec.js +61 -127
- package/lib/test/mergeTree.insertingWalk.spec.js.map +1 -1
- package/lib/test/mergeTree.markRangeRemoved.deltaCallback.spec.js +13 -94
- package/lib/test/mergeTree.markRangeRemoved.deltaCallback.spec.js.map +1 -1
- package/lib/test/mergeTree.markRangeRemoved.spec.js +10 -7
- package/lib/test/mergeTree.markRangeRemoved.spec.js.map +1 -1
- package/lib/test/mergeTree.walk.spec.js +2 -14
- package/lib/test/mergeTree.walk.spec.js.map +1 -1
- package/lib/test/mergeTreeOperationRunner.js +3 -3
- package/lib/test/mergeTreeOperationRunner.js.map +1 -1
- package/lib/test/obliterate.concurrent.spec.js +18 -23
- package/lib/test/obliterate.concurrent.spec.js.map +1 -1
- package/lib/test/obliterate.partialLength.spec.js +167 -137
- package/lib/test/obliterate.partialLength.spec.js.map +1 -1
- package/lib/test/obliterate.spec.js +17 -127
- package/lib/test/obliterate.spec.js.map +1 -1
- package/lib/test/partialLength.spec.js +29 -197
- package/lib/test/partialLength.spec.js.map +1 -1
- package/lib/test/perspective.spec.js +34 -0
- package/lib/test/perspective.spec.js.map +1 -1
- package/lib/test/propertyManager.spec.js +2 -2
- package/lib/test/propertyManager.spec.js.map +1 -1
- package/lib/test/resetPendingSegmentsToOp.spec.js +0 -2
- package/lib/test/resetPendingSegmentsToOp.spec.js.map +1 -1
- package/lib/test/segmentGroupCollection.spec.js +10 -4
- package/lib/test/segmentGroupCollection.spec.js.map +1 -1
- package/lib/test/testClient.d.ts +1 -0
- package/lib/test/testClient.d.ts.map +1 -1
- package/lib/test/testClient.js +18 -28
- package/lib/test/testClient.js.map +1 -1
- package/lib/test/testClientLogger.d.ts.map +1 -1
- package/lib/test/testClientLogger.js +3 -10
- package/lib/test/testClientLogger.js.map +1 -1
- package/lib/test/testServer.d.ts +2 -1
- package/lib/test/testServer.d.ts.map +1 -1
- package/lib/test/testServer.js +7 -5
- package/lib/test/testServer.js.map +1 -1
- package/lib/test/testUtils.d.ts +36 -56
- package/lib/test/testUtils.d.ts.map +1 -1
- package/lib/test/testUtils.js +66 -48
- package/lib/test/testUtils.js.map +1 -1
- package/lib/test/text.d.ts +2 -2
- package/lib/test/text.d.ts.map +1 -1
- package/lib/test/text.js +6 -3
- package/lib/test/text.js.map +1 -1
- package/lib/textSegment.d.ts +0 -6
- package/lib/textSegment.d.ts.map +1 -1
- package/lib/textSegment.js.map +1 -1
- package/lib/tsdoc-metadata.json +1 -1
- package/lib/zamboni.d.ts.map +1 -1
- package/lib/zamboni.js +32 -28
- package/lib/zamboni.js.map +1 -1
- package/package.json +17 -20
- package/src/MergeTreeTextHelper.ts +17 -12
- package/src/client.ts +141 -197
- package/src/endOfTreeSegment.ts +11 -8
- package/src/index.ts +4 -3
- package/src/mergeTree.ts +482 -633
- package/src/mergeTreeDeltaCallback.ts +4 -8
- package/src/mergeTreeNodes.ts +66 -45
- package/src/partialLengths.ts +181 -137
- package/src/perspective.ts +17 -95
- package/src/revertibles.ts +2 -7
- package/src/segmentInfos.ts +48 -141
- package/src/segmentPropertiesManager.ts +2 -16
- package/src/snapshotLoader.ts +62 -30
- package/src/snapshotV1.ts +36 -28
- package/src/snapshotlegacy.ts +7 -16
- package/src/stamps.ts +1 -1
- package/src/textSegment.ts +0 -13
- package/src/zamboni.ts +38 -32
- package/tsconfig.json +1 -0
- package/prettier.config.cjs +0 -8
package/dist/partialLengths.js
CHANGED
|
@@ -3,13 +3,37 @@
|
|
|
3
3
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
4
4
|
* Licensed under the MIT License.
|
|
5
5
|
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
23
|
+
if (mod && mod.__esModule) return mod;
|
|
24
|
+
var result = {};
|
|
25
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
26
|
+
__setModuleDefault(result, mod);
|
|
27
|
+
return result;
|
|
28
|
+
};
|
|
6
29
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
30
|
exports.verifyPartialLengths = exports.verifyExpectedPartialLengths = exports.PartialSequenceLengths = void 0;
|
|
8
31
|
const internal_1 = require("@fluidframework/core-utils/internal");
|
|
9
|
-
const constants_js_1 = require("./constants.js");
|
|
10
32
|
const mergeTreeNodes_js_1 = require("./mergeTreeNodes.js");
|
|
33
|
+
const perspective_js_1 = require("./perspective.js");
|
|
11
34
|
const segmentInfos_js_1 = require("./segmentInfos.js");
|
|
12
35
|
const sortedSet_js_1 = require("./sortedSet.js");
|
|
36
|
+
const opstampUtils = __importStar(require("./stamps.js"));
|
|
13
37
|
class PartialSequenceLengthsSet extends sortedSet_js_1.SortedSet {
|
|
14
38
|
compare(a, b) {
|
|
15
39
|
return a.seq - b.seq;
|
|
@@ -311,8 +335,8 @@ class PartialSequenceLengths {
|
|
|
311
335
|
if (child.isLeaf()) {
|
|
312
336
|
// Leaf segment
|
|
313
337
|
const segment = child;
|
|
314
|
-
if ((0, segmentInfos_js_1.
|
|
315
|
-
PartialSequenceLengths.
|
|
338
|
+
if ((0, segmentInfos_js_1.wasRemovedOnInsert)(segment)) {
|
|
339
|
+
PartialSequenceLengths.accountForRemoveOnInsert(combinedPartialLengths, segment, collabWindow);
|
|
316
340
|
}
|
|
317
341
|
else {
|
|
318
342
|
PartialSequenceLengths.accountForInsertion(combinedPartialLengths, segment, collabWindow);
|
|
@@ -324,22 +348,24 @@ class PartialSequenceLengths {
|
|
|
324
348
|
return combinedPartialLengths;
|
|
325
349
|
}
|
|
326
350
|
/**
|
|
327
|
-
* Assuming this segment was
|
|
351
|
+
* Assuming this segment was removed on insertion, inserts length information about that operation
|
|
328
352
|
* into the appropriate per-client adjustments (the overall view needs no such adjustment since
|
|
329
353
|
* from an observing client's perspective, the segment never exists).
|
|
330
354
|
*/
|
|
331
|
-
static
|
|
355
|
+
static accountForRemoveOnInsert(combinedPartialLengths, segment, collabWindow) {
|
|
332
356
|
(0, segmentInfos_js_1.assertInserted)(segment);
|
|
333
|
-
const
|
|
334
|
-
(0, internal_1.assert)(
|
|
335
|
-
|
|
357
|
+
const removeInfo = (0, segmentInfos_js_1.toRemovalInfo)(segment);
|
|
358
|
+
(0, internal_1.assert)(removeInfo !== undefined && (0, segmentInfos_js_1.wasRemovedOnInsert)(segment), 0xab7 /* Segment was not removed on insert */);
|
|
359
|
+
const firstRemove = removeInfo?.removes[0];
|
|
360
|
+
if (opstampUtils.lte(firstRemove, (0, mergeTreeNodes_js_1.getMinSeqStamp)(collabWindow))) {
|
|
336
361
|
// This segment was obliterated as soon as it was inserted, and everyone was aware of the obliterate.
|
|
337
362
|
// Thus every single client treats this segment as length 0 from every perspective, and no adjustments
|
|
338
363
|
// are necessary.
|
|
339
364
|
return;
|
|
340
365
|
}
|
|
341
|
-
const
|
|
342
|
-
const
|
|
366
|
+
const { insert, cachedLength } = segment;
|
|
367
|
+
const isLocal = opstampUtils.isLocal(insert);
|
|
368
|
+
const { clientId } = insert;
|
|
343
369
|
const partials = isLocal
|
|
344
370
|
? combinedPartialLengths.unsequencedRecords?.partialLengths
|
|
345
371
|
: combinedPartialLengths.partialLengths;
|
|
@@ -349,33 +375,51 @@ class PartialSequenceLengths {
|
|
|
349
375
|
}
|
|
350
376
|
if (isLocal) {
|
|
351
377
|
// Implication -> this is a local segment which will be obliterated as soon as it is acked.
|
|
352
|
-
// For refSeqs preceding that
|
|
378
|
+
// For refSeqs preceding that removedSeq and localSeqs following the localSeq, it will be visible.
|
|
353
379
|
// For the rest, it will not be visible.
|
|
354
380
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
355
|
-
const localSeq =
|
|
381
|
+
const localSeq = insert.localSeq;
|
|
356
382
|
partials.addOrUpdate({
|
|
357
383
|
seq: localSeq,
|
|
358
384
|
len: 0,
|
|
359
|
-
seglen:
|
|
385
|
+
seglen: cachedLength,
|
|
360
386
|
clientId,
|
|
361
387
|
});
|
|
362
388
|
combinedPartialLengths.addLocalAdjustment({
|
|
363
|
-
refSeq:
|
|
389
|
+
refSeq: firstRemove.seq,
|
|
364
390
|
localSeq,
|
|
365
|
-
seglen: -
|
|
391
|
+
seglen: -cachedLength,
|
|
366
392
|
});
|
|
393
|
+
const lastRemove = removeInfo.removes[removeInfo.removes.length - 1];
|
|
394
|
+
if (opstampUtils.isLocal(lastRemove)) {
|
|
395
|
+
// In addition to a remote sliceRemove causing this segment to be removed as soon as its insertion is acked,
|
|
396
|
+
// the local client has also removed it before its insertion was acked.
|
|
397
|
+
// It will therefore not be visible for a local reconnecting perspective beyond the removed localSeq.
|
|
398
|
+
partials.addOrUpdate({
|
|
399
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
400
|
+
seq: lastRemove.localSeq,
|
|
401
|
+
len: 0,
|
|
402
|
+
seglen: -cachedLength,
|
|
403
|
+
clientId,
|
|
404
|
+
});
|
|
405
|
+
combinedPartialLengths.addLocalAdjustment({
|
|
406
|
+
refSeq: firstRemove.seq,
|
|
407
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
408
|
+
localSeq: lastRemove.localSeq,
|
|
409
|
+
seglen: cachedLength,
|
|
410
|
+
});
|
|
411
|
+
}
|
|
367
412
|
}
|
|
368
413
|
else {
|
|
369
414
|
// Segment was obliterated on insert. Generally this means it should be visible only to the
|
|
370
415
|
// inserting client (in which case we add an adjustment to only that client's perspective),
|
|
371
416
|
// but if that client has also removed it, we don't need to add anything.
|
|
372
|
-
const
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
(
|
|
378
|
-
combinedPartialLengths.addClientAdjustment(clientId, moveSeq, segment.cachedLength);
|
|
417
|
+
const wasRemovedByInsertingClient = removeInfo !== undefined &&
|
|
418
|
+
removeInfo.removes.some((remove) => remove.clientId === clientId);
|
|
419
|
+
if (!wasRemovedByInsertingClient) {
|
|
420
|
+
const removeSeq = firstRemove?.seq;
|
|
421
|
+
(0, internal_1.assert)(removeSeq !== undefined, 0xab8 /* ObliterateOnInsertion implies removeSeq is defined */);
|
|
422
|
+
combinedPartialLengths.addClientAdjustment(clientId, removeSeq, cachedLength);
|
|
379
423
|
}
|
|
380
424
|
}
|
|
381
425
|
}
|
|
@@ -385,15 +429,15 @@ class PartialSequenceLengths {
|
|
|
385
429
|
*/
|
|
386
430
|
static accountForInsertion(combinedPartialLengths, segment, collabWindow) {
|
|
387
431
|
(0, segmentInfos_js_1.assertInserted)(segment);
|
|
388
|
-
if (segment.
|
|
432
|
+
if (opstampUtils.lte(segment.insert, (0, mergeTreeNodes_js_1.getMinSeqStamp)(collabWindow))) {
|
|
389
433
|
combinedPartialLengths.minLength += segment.cachedLength;
|
|
390
434
|
return;
|
|
391
435
|
}
|
|
392
|
-
const
|
|
436
|
+
const { insert, cachedLength: segmentLen } = segment;
|
|
437
|
+
const isLocal = opstampUtils.isLocal(insert);
|
|
393
438
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
394
|
-
const seqOrLocalSeq = isLocal ?
|
|
395
|
-
const
|
|
396
|
-
const clientId = segment.clientId;
|
|
439
|
+
const seqOrLocalSeq = isLocal ? insert.localSeq : insert.seq;
|
|
440
|
+
const clientId = insert.clientId;
|
|
397
441
|
const partials = isLocal
|
|
398
442
|
? combinedPartialLengths.unsequencedRecords?.partialLengths
|
|
399
443
|
: combinedPartialLengths.partialLengths;
|
|
@@ -426,55 +470,27 @@ class PartialSequenceLengths {
|
|
|
426
470
|
static accountForRemoval(combinedPartialLengths, segment, collabWindow) {
|
|
427
471
|
(0, segmentInfos_js_1.assertInserted)(segment);
|
|
428
472
|
const removalInfo = (0, segmentInfos_js_1.toRemovalInfo)(segment);
|
|
429
|
-
|
|
430
|
-
if (!removalInfo && !moveInfo) {
|
|
473
|
+
if (!removalInfo) {
|
|
431
474
|
return;
|
|
432
475
|
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
476
|
+
const firstRemove = removalInfo?.removes[0];
|
|
477
|
+
const minSeqStamp = (0, mergeTreeNodes_js_1.getMinSeqStamp)(collabWindow);
|
|
478
|
+
if (firstRemove !== undefined && opstampUtils.lte(firstRemove, minSeqStamp)) {
|
|
436
479
|
combinedPartialLengths.minLength -= segment.cachedLength;
|
|
437
480
|
return;
|
|
438
481
|
}
|
|
439
|
-
const removalIsLocal = !!
|
|
440
|
-
const
|
|
441
|
-
const
|
|
442
|
-
const
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
if (segment.seq === constants_js_1.UnassignedSequenceNumber &&
|
|
446
|
-
!(removalIsLocal && (!moveInfo || moveIsLocal)) &&
|
|
447
|
-
!(moveIsLocal && (!removalInfo || removalIsLocal))) {
|
|
448
|
-
throw new Error("Should have handled this codepath in wasMovedOnInsertion");
|
|
482
|
+
const removalIsLocal = !!firstRemove && opstampUtils.isLocal(firstRemove);
|
|
483
|
+
const isLocalInsertion = opstampUtils.isLocal(segment.insert);
|
|
484
|
+
const isOnlyLocalRemoval = removalIsLocal;
|
|
485
|
+
const isLocal = isLocalInsertion || isOnlyLocalRemoval;
|
|
486
|
+
if (isLocalInsertion && !removalIsLocal) {
|
|
487
|
+
throw new Error("Should have handled this codepath in wasRemovedOnInsertion");
|
|
449
488
|
}
|
|
450
489
|
const lenDelta = -segment.cachedLength;
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
(
|
|
455
|
-
const clientsWithRemoveOrObliterate = new Set([
|
|
456
|
-
...(removalInfo?.removedClientIds ?? []),
|
|
457
|
-
...(moveInfo?.movedClientIds ?? []),
|
|
458
|
-
]);
|
|
459
|
-
const removeHappenedFirst = removalInfo &&
|
|
460
|
-
(!moveInfo ||
|
|
461
|
-
moveIsLocal ||
|
|
462
|
-
(!removalIsLocal && moveInfo.movedSeq > removalInfo.removedSeq));
|
|
463
|
-
if (removeHappenedFirst) {
|
|
464
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
465
|
-
seqOrLocalSeq = removalIsLocal ? removalInfo.localRemovedSeq : removalInfo.removedSeq;
|
|
466
|
-
// The client who performed the remove is always stored
|
|
467
|
-
// in the first position of removalInfo.
|
|
468
|
-
clientId = removalInfo.removedClientIds[0];
|
|
469
|
-
}
|
|
470
|
-
else {
|
|
471
|
-
(0, internal_1.assert)(moveInfo !== undefined, 0xab9 /* Expected move to exist if remove either did not exist or didn't happen first */);
|
|
472
|
-
// The client who performed the move is always stored
|
|
473
|
-
// in the first position of moveInfo.
|
|
474
|
-
clientId = moveInfo.movedClientIds[0];
|
|
475
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
476
|
-
seqOrLocalSeq = moveIsLocal ? moveInfo.localMovedSeq : moveInfo.movedSeq;
|
|
477
|
-
}
|
|
490
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
491
|
+
const seqOrLocalSeq = removalIsLocal ? firstRemove.localSeq : firstRemove.seq;
|
|
492
|
+
const clientId = firstRemove.clientId;
|
|
493
|
+
const clientsWithRemoveOrObliterate = new Set(removalInfo?.removes.map((stamp) => stamp.clientId));
|
|
478
494
|
const partials = isLocal
|
|
479
495
|
? combinedPartialLengths.unsequencedRecords?.partialLengths
|
|
480
496
|
: combinedPartialLengths.partialLengths;
|
|
@@ -483,15 +499,30 @@ class PartialSequenceLengths {
|
|
|
483
499
|
return;
|
|
484
500
|
}
|
|
485
501
|
if (isLocal) {
|
|
486
|
-
// The segment is either inserted only locally or removed
|
|
502
|
+
// The segment is either inserted only locally or removed only locally.
|
|
487
503
|
// We already accounted for the insertion in the accountForInsertion codepath.
|
|
488
|
-
// Only thing left to do is account for the removal.
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
504
|
+
// Only thing left to do is account for the removal in local partial lengths.
|
|
505
|
+
// One thing to be careful about is that the removal should only apply to perspectives that saw
|
|
506
|
+
// the segment's insertion in the first place.
|
|
507
|
+
// When the segment's insertion was common knowledge (at or below minSeq) or also by the local client,
|
|
508
|
+
// all possible perspectives will have seen it.
|
|
509
|
+
if (opstampUtils.lte(segment.insert, minSeqStamp) ||
|
|
510
|
+
collabWindow.clientId === segment.insert.clientId) {
|
|
511
|
+
partials.addOrUpdate({
|
|
512
|
+
seq: seqOrLocalSeq,
|
|
513
|
+
clientId,
|
|
514
|
+
len: 0,
|
|
515
|
+
seglen: lenDelta,
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
else {
|
|
519
|
+
// ... otherwise, it's only visible to reconnecting perspectives above the seq of the insert.
|
|
520
|
+
combinedPartialLengths.addLocalAdjustment({
|
|
521
|
+
localSeq: seqOrLocalSeq,
|
|
522
|
+
refSeq: segment.insert.seq,
|
|
523
|
+
seglen: lenDelta,
|
|
524
|
+
});
|
|
525
|
+
}
|
|
495
526
|
}
|
|
496
527
|
else {
|
|
497
528
|
partials.addOrUpdate({
|
|
@@ -503,7 +534,7 @@ class PartialSequenceLengths {
|
|
|
503
534
|
for (const id of clientsWithRemoveOrObliterate) {
|
|
504
535
|
if (id === collabWindow.clientId) {
|
|
505
536
|
// The local client also removed or obliterated this segment.
|
|
506
|
-
const localSeq =
|
|
537
|
+
const { localSeq } = removalInfo.removes[removalInfo.removes.length - 1];
|
|
507
538
|
if (localSeq === undefined) {
|
|
508
539
|
// Sure, the local client did it--but that change was already acked.
|
|
509
540
|
// No need to account for it in the unsequenced records.
|
|
@@ -514,13 +545,50 @@ class PartialSequenceLengths {
|
|
|
514
545
|
// Local partial but its computation isn't required.
|
|
515
546
|
continue;
|
|
516
547
|
}
|
|
517
|
-
(0, internal_1.assert)(localSeq !== undefined, 0xaba /* Local client was in
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
548
|
+
(0, internal_1.assert)(localSeq !== undefined, 0xaba /* Local client was in removed client ids but segment has no local seq for either */);
|
|
549
|
+
// Here...
|
|
550
|
+
// - The segment was removed locally at `localSeq`
|
|
551
|
+
// - The segment was also removed remotely at `seqOrLocalSeq`
|
|
552
|
+
// - We're ensuring that partial lengths works for arbitrary `LocalReconnectingPerspective`s.
|
|
553
|
+
//
|
|
554
|
+
// Visualize an arbitrary local reconnecting perspective in 2d space, where the x-axis is `seq` and the y-axis is `localSeq`.
|
|
555
|
+
// The events that have occurred to this segment divide the space into up to 6 regions:
|
|
556
|
+
//
|
|
557
|
+
// (localSeq)
|
|
558
|
+
// | | |
|
|
559
|
+
// | 1 | 2 | 3
|
|
560
|
+
// local remove |-----------------------------
|
|
561
|
+
// | | |
|
|
562
|
+
// | 4 | 5 | 6
|
|
563
|
+
// |----------------------------- (seq)
|
|
564
|
+
// insert remove
|
|
565
|
+
// In all regions but region 5, the segment has length 0 (it was not inserted yet in regions 1 or 4, and removed locally and/or remotely
|
|
566
|
+
// in regions 2, 3, and 6).
|
|
567
|
+
// `accountForInsertion` already added a partial lengths adjustment of +segment.cachedLength for regions 2, 3, 5, and 6.
|
|
568
|
+
// Above in this function, we've added a partial lengths adjustment of -segment.cachedLength for regions 3 and 6.
|
|
569
|
+
//
|
|
570
|
+
// Note that in this picture:
|
|
571
|
+
// - Adding entries to `unsequencedRecords.partialLengths` is like adding adjustments that affect anything above a given Y value
|
|
572
|
+
// - Adding entries to `combinedPartialLengths.partialLengths` is like adding adjustments that affect anything above a given X value
|
|
573
|
+
// - Adding entries with `addLocalAdjustment` is like adding adjustments that affect anything above a given X *and* Y value
|
|
574
|
+
// The remainder this block adds the necessary adjustments to make the length appear 0 in region 2 as well, keeping in mind that
|
|
575
|
+
// region 1 may or may not exist depending on if the insertion is in the collab window.
|
|
576
|
+
if (opstampUtils.isAcked(segment.insert) &&
|
|
577
|
+
opstampUtils.greaterThan(segment.insert, minSeqStamp)) {
|
|
578
|
+
combinedPartialLengths.addLocalAdjustment({
|
|
579
|
+
refSeq: segment.insert.seq,
|
|
580
|
+
localSeq,
|
|
581
|
+
seglen: lenDelta,
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
else {
|
|
585
|
+
unsequencedRecords.partialLengths.addOrUpdate({
|
|
586
|
+
seq: localSeq,
|
|
587
|
+
clientId: collabWindow.clientId,
|
|
588
|
+
seglen: lenDelta,
|
|
589
|
+
len: 0,
|
|
590
|
+
});
|
|
591
|
+
}
|
|
524
592
|
// Because we've included deltas which take effect when either of localSeq or refSeq are high enough,
|
|
525
593
|
// we need to offset this with an adjustment that takes effect when both are high enough.
|
|
526
594
|
combinedPartialLengths.addLocalAdjustment({
|
|
@@ -536,15 +604,16 @@ class PartialSequenceLengths {
|
|
|
536
604
|
}
|
|
537
605
|
else {
|
|
538
606
|
// Note that all clients that have a remove or obliterate operation on this segment
|
|
539
|
-
// use the seq of the winning
|
|
607
|
+
// use the seq of the winning obliterate in their per-client adjustments!
|
|
540
608
|
combinedPartialLengths.addClientAdjustment(id, seqOrLocalSeq, lenDelta);
|
|
541
609
|
// Also ensure that all these clients have seen the segment as inserted before being removed
|
|
542
|
-
// This is technically not necessary for
|
|
610
|
+
// This is technically not necessary for setRemoves (we never ask for the length of this block with
|
|
543
611
|
// respect to a refSeq which this entry would affect), but it's simpler to just add it here.
|
|
544
612
|
// We already add this entry as part of the accountForInsertion codepath for the client that
|
|
545
613
|
// actually did insert the segment, hence not doing so [again] here.
|
|
546
|
-
if (segment.
|
|
547
|
-
|
|
614
|
+
if (opstampUtils.greaterThan(segment.insert, minSeqStamp) &&
|
|
615
|
+
id !== segment.insert.clientId) {
|
|
616
|
+
combinedPartialLengths.addClientAdjustment(id, segment.insert.seq, segment.cachedLength);
|
|
548
617
|
}
|
|
549
618
|
}
|
|
550
619
|
}
|
|
@@ -588,15 +657,14 @@ class PartialSequenceLengths {
|
|
|
588
657
|
if (child.isLeaf()) {
|
|
589
658
|
const segment = child;
|
|
590
659
|
const removalInfo = (0, segmentInfos_js_1.toRemovalInfo)(segment);
|
|
591
|
-
const
|
|
592
|
-
if (seq === segment.seq) {
|
|
593
|
-
// if this segment was
|
|
660
|
+
const firstRemove = removalInfo?.removes[0];
|
|
661
|
+
if (seq === segment.insert.seq) {
|
|
662
|
+
// if this segment was removed on insert, its length should
|
|
594
663
|
// only be visible to the inserting client
|
|
595
|
-
if (segment.seq !== undefined &&
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
(
|
|
599
|
-
this.addClientAdjustment(clientId, moveInfo.movedSeq, segment.cachedLength);
|
|
664
|
+
if (segment.insert.seq !== undefined &&
|
|
665
|
+
firstRemove !== undefined &&
|
|
666
|
+
(0, segmentInfos_js_1.wasRemovedOnInsert)(segment)) {
|
|
667
|
+
this.addClientAdjustment(clientId, firstRemove.seq, segment.cachedLength);
|
|
600
668
|
failIncrementalPropagation = true;
|
|
601
669
|
}
|
|
602
670
|
else {
|
|
@@ -604,13 +672,13 @@ class PartialSequenceLengths {
|
|
|
604
672
|
this.addClientAdjustment(clientId, seq, segment.cachedLength);
|
|
605
673
|
}
|
|
606
674
|
}
|
|
607
|
-
|
|
608
|
-
if (segment.seq !== constants_js_1.UnassignedSequenceNumber && seq === earlierDeletion) {
|
|
675
|
+
if (opstampUtils.isAcked(segment.insert) && seq === firstRemove?.seq) {
|
|
609
676
|
seqSeglen -= segment.cachedLength;
|
|
610
677
|
if (clientId !== collabWindow.clientId) {
|
|
611
678
|
this.addClientAdjustment(clientId, seq, -segment.cachedLength);
|
|
612
|
-
if (segment.
|
|
613
|
-
|
|
679
|
+
if (opstampUtils.greaterThan(segment.insert, (0, mergeTreeNodes_js_1.getMinSeqStamp)(collabWindow)) &&
|
|
680
|
+
segment.insert.clientId !== clientId) {
|
|
681
|
+
this.addClientAdjustment(clientId, segment.insert.seq, segment.cachedLength);
|
|
614
682
|
failIncrementalPropagation = true;
|
|
615
683
|
}
|
|
616
684
|
}
|
|
@@ -685,13 +753,12 @@ class PartialSequenceLengths {
|
|
|
685
753
|
(0, internal_1.assert)(this.unsequencedRecords !== undefined, 0x39f /* Local getPartialLength invoked without computing local partials. */);
|
|
686
754
|
const unsequencedPartialLengths = this.unsequencedRecords.partialLengths;
|
|
687
755
|
// Local segments at or before localSeq should also be included
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
}
|
|
756
|
+
length += unsequencedPartialLengths.latestLeq(localSeq)?.len ?? 0;
|
|
757
|
+
// Lastly, we must add in any additional adjustment that should only take effect when both
|
|
758
|
+
// refSeq AND localSeq are above some threshold. This accounts for things like double-counting
|
|
759
|
+
// local+remote removes, or only subtracting the length out of a local remove if we've also seen
|
|
760
|
+
// the insert of the segment it affects. (see addLocalAdjustment usages for examples)
|
|
761
|
+
length += this.computeOverallRefSeqAdjustment(refSeq, localSeq);
|
|
695
762
|
}
|
|
696
763
|
return length;
|
|
697
764
|
}
|
|
@@ -843,13 +910,18 @@ function verifyExpectedPartialLengths(mergeTree, node, refSeq, clientId, localSe
|
|
|
843
910
|
const partialLen = node.partialLengths?.getPartialLength(refSeq, clientId, localSeq);
|
|
844
911
|
let expected = 0;
|
|
845
912
|
const nodesToVisit = [node];
|
|
913
|
+
const perspective = clientId === mergeTree.collabWindow.clientId
|
|
914
|
+
? localSeq === undefined
|
|
915
|
+
? new perspective_js_1.LocalDefaultPerspective(clientId)
|
|
916
|
+
: new perspective_js_1.LocalReconnectingPerspective(refSeq, clientId, localSeq)
|
|
917
|
+
: new perspective_js_1.PriorPerspective(refSeq, clientId);
|
|
846
918
|
while (nodesToVisit.length > 0) {
|
|
847
919
|
const thisNode = nodesToVisit.pop();
|
|
848
920
|
if (!thisNode) {
|
|
849
921
|
continue;
|
|
850
922
|
}
|
|
851
923
|
if (thisNode.isLeaf()) {
|
|
852
|
-
expected += mergeTree["nodeLength"](thisNode,
|
|
924
|
+
expected += mergeTree["nodeLength"](thisNode, perspective) ?? 0;
|
|
853
925
|
}
|
|
854
926
|
else {
|
|
855
927
|
nodesToVisit.push(...thisNode.children.slice(0, thisNode.childCount));
|