@fluidframework/merge-tree 2.23.0 → 2.30.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 +4 -0
- package/dist/mergeTree.d.ts +2 -0
- package/dist/mergeTree.d.ts.map +1 -1
- package/dist/mergeTree.js +15 -10
- package/dist/mergeTree.js.map +1 -1
- package/dist/perspective.d.ts +92 -54
- package/dist/perspective.d.ts.map +1 -1
- package/dist/perspective.js +145 -84
- package/dist/perspective.js.map +1 -1
- package/dist/stamps.d.ts +90 -0
- package/dist/stamps.d.ts.map +1 -0
- package/dist/stamps.js +90 -0
- package/dist/stamps.js.map +1 -0
- package/dist/test/perspective.spec.d.ts +6 -0
- package/dist/test/perspective.spec.d.ts.map +1 -0
- package/dist/test/perspective.spec.js +119 -0
- package/dist/test/perspective.spec.js.map +1 -0
- package/dist/test/stamps.spec.d.ts +6 -0
- package/dist/test/stamps.spec.d.ts.map +1 -0
- package/dist/test/stamps.spec.js +130 -0
- package/dist/test/stamps.spec.js.map +1 -0
- package/dist/test/testClientLogger.d.ts +9 -0
- package/dist/test/testClientLogger.d.ts.map +1 -1
- package/dist/test/testClientLogger.js +64 -45
- package/dist/test/testClientLogger.js.map +1 -1
- package/lib/mergeTree.d.ts +2 -0
- package/lib/mergeTree.d.ts.map +1 -1
- package/lib/mergeTree.js +16 -11
- package/lib/mergeTree.js.map +1 -1
- package/lib/perspective.d.ts +92 -54
- package/lib/perspective.d.ts.map +1 -1
- package/lib/perspective.js +119 -80
- package/lib/perspective.js.map +1 -1
- package/lib/stamps.d.ts +90 -0
- package/lib/stamps.d.ts.map +1 -0
- package/lib/stamps.js +77 -0
- package/lib/stamps.js.map +1 -0
- package/lib/test/perspective.spec.d.ts +6 -0
- package/lib/test/perspective.spec.d.ts.map +1 -0
- package/lib/test/perspective.spec.js +117 -0
- package/lib/test/perspective.spec.js.map +1 -0
- package/lib/test/stamps.spec.d.ts +6 -0
- package/lib/test/stamps.spec.d.ts.map +1 -0
- package/lib/test/stamps.spec.js +105 -0
- package/lib/test/stamps.spec.js.map +1 -0
- package/lib/test/testClientLogger.d.ts +9 -0
- package/lib/test/testClientLogger.d.ts.map +1 -1
- package/lib/test/testClientLogger.js +65 -46
- package/lib/test/testClientLogger.js.map +1 -1
- package/package.json +17 -17
- package/src/mergeTree.ts +32 -11
- package/src/perspective.ts +184 -108
- package/src/stamps.ts +164 -0
package/dist/perspective.d.ts
CHANGED
|
@@ -4,86 +4,124 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { type MergeTree } from "./mergeTree.js";
|
|
6
6
|
import { type ISegmentLeaf } from "./mergeTreeNodes.js";
|
|
7
|
-
import
|
|
7
|
+
import type { OperationStamp, InsertOperationStamp, RemoveOperationStamp } from "./stamps.js";
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
9
|
+
* A perspective which includes some subset of operations known to the local client.
|
|
10
|
+
*
|
|
11
|
+
* This helps the local client reason about the state of other clients when they issued an operation.
|
|
10
12
|
*/
|
|
11
13
|
export interface Perspective {
|
|
12
|
-
nextSegment(segment: ISegmentLeaf, forward?: boolean): ISegmentLeaf;
|
|
13
|
-
previousSegment(segment: ISegmentLeaf): ISegmentLeaf;
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Represents a point in time inside the collaboration window.
|
|
17
|
-
*/
|
|
18
|
-
export interface SeqTime {
|
|
19
|
-
refSeq: number;
|
|
20
|
-
localSeq?: number;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Implementation of {@link Perspective}.
|
|
24
|
-
* @privateRemarks
|
|
25
|
-
* TODO:AB#29765: This class does not support non-local-client perspectives, but should.
|
|
26
|
-
*/
|
|
27
|
-
export declare class PerspectiveImpl implements Perspective {
|
|
28
|
-
private readonly _mergeTree;
|
|
29
|
-
private readonly _seqTime;
|
|
30
14
|
/**
|
|
31
|
-
*
|
|
32
|
-
* @
|
|
15
|
+
* The sequence number last seen from this perspective. Same concept as `ISequencedDocumentMessage.referenceSequenceNumber`.
|
|
16
|
+
* @privateRemarks
|
|
17
|
+
* This currently allows inter-operation between MergeTree methods and the partial lengths implementation, which still depends
|
|
18
|
+
* on the (refSeq, clientId, localSeq?) representation of perspectives.
|
|
19
|
+
*/
|
|
20
|
+
readonly refSeq: number;
|
|
21
|
+
/**
|
|
22
|
+
* The client id for this perspective.
|
|
23
|
+
* @privateRemarks
|
|
24
|
+
* This currently allows inter-operation between MergeTree methods and the partial lengths implementation, which still depends
|
|
25
|
+
* on the (refSeq, clientId, localSeq?) representation of perspectives.
|
|
26
|
+
*/
|
|
27
|
+
readonly clientId: number;
|
|
28
|
+
/**
|
|
29
|
+
* When this is a local perspective, the local sequence number last seen from this perspective.
|
|
30
|
+
*
|
|
31
|
+
* Perspectives with defined `localSeq` values are useful in reconnection flows, where the local client may need to resend some
|
|
32
|
+
* of its ops after rederiving their new equivalents.
|
|
33
|
+
* @privateRemarks
|
|
34
|
+
* This currently allows inter-operation between MergeTree methods and the partial lengths implementation, which still depends
|
|
35
|
+
* on the (refSeq, clientId, localSeq?) representation of perspectives.
|
|
36
|
+
*/
|
|
37
|
+
readonly localSeq?: number;
|
|
38
|
+
/**
|
|
39
|
+
* @returns Whether the segment is present (visible) from this perspective
|
|
40
|
+
*/
|
|
41
|
+
isSegmentPresent(segment: ISegmentLeaf): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* @returns Whether this perspective has seen the given operation.
|
|
33
44
|
*/
|
|
34
|
-
|
|
45
|
+
hasOccurred(stamp: RemoveOperationStamp | InsertOperationStamp): boolean;
|
|
46
|
+
nextSegment(mergeTree: MergeTree, segment: ISegmentLeaf, forward?: boolean): ISegmentLeaf;
|
|
47
|
+
previousSegment(mergeTree: MergeTree, segment: ISegmentLeaf): ISegmentLeaf;
|
|
48
|
+
}
|
|
49
|
+
declare abstract class PerspectiveBase {
|
|
50
|
+
abstract hasOccurred(stamp: RemoveOperationStamp | InsertOperationStamp): boolean;
|
|
35
51
|
/**
|
|
36
52
|
* Returns the immediately adjacent segment in the specified direction from this perspective.
|
|
37
53
|
* There may actually be multiple segments between the given segment and the returned segment,
|
|
38
|
-
* but they were either inserted after this perspective, or have been removed
|
|
54
|
+
* but they were either inserted after this perspective, or have been removed before this perspective.
|
|
39
55
|
*
|
|
40
56
|
* @param segment - The segment to start from.
|
|
41
57
|
* @param forward - The direction to search.
|
|
42
58
|
* @returns the next segment in the specified direction, or the start or end of the tree if there is no next segment.
|
|
43
59
|
*/
|
|
44
|
-
nextSegment(segment: ISegmentLeaf, forward?: boolean): ISegmentLeaf;
|
|
60
|
+
nextSegment(mergeTree: MergeTree, segment: ISegmentLeaf, forward?: boolean): ISegmentLeaf;
|
|
45
61
|
/**
|
|
46
62
|
* Finds the segment prior to the given segment.
|
|
47
63
|
* @param segment - The segment to start from.
|
|
48
64
|
* @returns the previous segment, or the start of the tree if there is no previous segment.
|
|
49
65
|
* @remarks This is a convenient equivalent to calling `nextSegment(segment, false)`.
|
|
50
66
|
*/
|
|
51
|
-
previousSegment(segment: ISegmentLeaf): ISegmentLeaf;
|
|
67
|
+
previousSegment(mergeTree: MergeTree, segment: ISegmentLeaf): ISegmentLeaf;
|
|
68
|
+
isSegmentPresent(seg: ISegmentLeaf): boolean;
|
|
52
69
|
}
|
|
53
70
|
/**
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
* @
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* @privateRemarks
|
|
60
|
-
* TODO:AB#29765: This function does not support non-local-client perspectives, but should.
|
|
71
|
+
* A perspective which includes edits at or before some reference sequence number alongside all edits from some particular client.
|
|
72
|
+
*
|
|
73
|
+
* @remarks
|
|
74
|
+
* This works for both the local client as well as remote clients since refSeq-based checks disallow unacked edits, but the clientId check
|
|
75
|
+
* catches unacked edits from the local client.
|
|
61
76
|
*/
|
|
62
|
-
export declare
|
|
77
|
+
export declare class PriorPerspective extends PerspectiveBase implements Perspective {
|
|
78
|
+
readonly refSeq: number;
|
|
79
|
+
readonly clientId: number;
|
|
80
|
+
constructor(refSeq: number, clientId: number);
|
|
81
|
+
hasOccurred(stamp: OperationStamp): boolean;
|
|
82
|
+
}
|
|
63
83
|
/**
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* TODO:AB#29765: This function does not support non-local-client perspectives, but should.
|
|
84
|
+
* A perspective which includes edits which were either:
|
|
85
|
+
* - acked and at or before some reference sequence number
|
|
86
|
+
* - unacked, but at or before some local sequence number
|
|
87
|
+
*
|
|
88
|
+
* This is a useful perspective when the local client is in the process of reconnecting, since it must
|
|
89
|
+
* rederive positions for unacked ops while only considering a portion of its own edits as having been applied.
|
|
71
90
|
*/
|
|
72
|
-
export declare
|
|
91
|
+
export declare class LocalReconnectingPerspective extends PerspectiveBase implements Perspective {
|
|
92
|
+
readonly refSeq: number;
|
|
93
|
+
readonly clientId: number;
|
|
94
|
+
readonly localSeq: number;
|
|
95
|
+
constructor(refSeq: number, clientId: number, localSeq: number);
|
|
96
|
+
hasOccurred(stamp: OperationStamp): boolean;
|
|
97
|
+
}
|
|
73
98
|
/**
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
99
|
+
* A perspective which includes all known edits.
|
|
100
|
+
*
|
|
101
|
+
* This is the perspective that the application sees.
|
|
102
|
+
* @remarks
|
|
103
|
+
* This can be represented using {@link PriorPerspective} with a refSeq of `Number.MAX_SAFE_INTEGER`, but having an explicit
|
|
104
|
+
* variant of this perspective renders extra refSeq checks unnecessary and is a bit easier to read.
|
|
77
105
|
*/
|
|
78
|
-
export declare
|
|
106
|
+
export declare class LocalDefaultPerspective extends PerspectiveBase implements Perspective {
|
|
107
|
+
readonly clientId: number;
|
|
108
|
+
readonly refSeq: number;
|
|
109
|
+
constructor(clientId: number);
|
|
110
|
+
hasOccurred(_stamp: OperationStamp): boolean;
|
|
111
|
+
}
|
|
79
112
|
/**
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
* TODO:AB#29765: This function does not support non-local-client perspectives, but should.
|
|
113
|
+
* A perspective dictating whether segments are 'visible' to a remote obliterate operation.
|
|
114
|
+
*
|
|
115
|
+
* NOTE: Beware that partial lengths doesn't support this perspective, in the sense that consulting partial lengths' for the length of a block
|
|
116
|
+
* can give different results than summing the lengths of present segments in that block.
|
|
117
|
+
* This ends up not affecting the current obliterate implementation (which has some special casing in the mapRange calls it uses),
|
|
118
|
+
* but use with caution.
|
|
87
119
|
*/
|
|
88
|
-
export declare
|
|
120
|
+
export declare class RemoteObliteratePerspective extends PerspectiveBase implements Perspective {
|
|
121
|
+
readonly clientId: number;
|
|
122
|
+
readonly refSeq: number;
|
|
123
|
+
constructor(clientId: number);
|
|
124
|
+
hasOccurred(stamp: InsertOperationStamp | RemoveOperationStamp): boolean;
|
|
125
|
+
}
|
|
126
|
+
export {};
|
|
89
127
|
//# sourceMappingURL=perspective.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"perspective.d.ts","sourceRoot":"","sources":["../src/perspective.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,OAAO,EAAU,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"perspective.d.ts","sourceRoot":"","sources":["../src/perspective.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,OAAO,EAAU,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGhE,OAAO,KAAK,EAAE,cAAc,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAE9F;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC3B;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B;;;;;;;;OAQG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAE3B;;OAEG;IACH,gBAAgB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC;IAEjD;;OAEG;IACH,WAAW,CAAC,KAAK,EAAE,oBAAoB,GAAG,oBAAoB,GAAG,OAAO,CAAC;IAEzE,WAAW,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,YAAY,CAAC;IAC1F,eAAe,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,GAAG,YAAY,CAAC;CAC3E;AAED,uBAAe,eAAe;IAC7B,QAAQ,CAAC,WAAW,CAAC,KAAK,EAAE,oBAAoB,GAAG,oBAAoB,GAAG,OAAO;IAEjF;;;;;;;;OAQG;IACI,WAAW,CACjB,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,YAAY,EACrB,OAAO,GAAE,OAAc,GACrB,YAAY;IAYf;;;;;OAKG;IACI,eAAe,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,GAAG,YAAY;IAI1E,gBAAgB,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO;CAsDnD;AAED;;;;;;GAMG;AACH,qBAAa,gBAAiB,SAAQ,eAAgB,YAAW,WAAW;aAE1D,MAAM,EAAE,MAAM;aACd,QAAQ,EAAE,MAAM;gBADhB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM;IAK1B,WAAW,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO;CAKlD;AAED;;;;;;;GAOG;AACH,qBAAa,4BAA6B,SAAQ,eAAgB,YAAW,WAAW;aAEtE,MAAM,EAAE,MAAM;aACd,QAAQ,EAAE,MAAM;aAChB,QAAQ,EAAE,MAAM;gBAFhB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM;IAK1B,WAAW,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO;CAMlD;AAED;;;;;;;GAOG;AACH,qBAAa,uBAAwB,SAAQ,eAAgB,YAAW,WAAW;aAG/C,QAAQ,EAAE,MAAM;IAFnD,SAAgB,MAAM,SAA2B;gBAEd,QAAQ,EAAE,MAAM;IAI5C,WAAW,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO;CAGnD;AAED;;;;;;;GAOG;AACH,qBAAa,2BAA4B,SAAQ,eAAgB,YAAW,WAAW;aAG1D,QAAQ,EAAE,MAAM;IAF5C,SAAgB,MAAM,SAA2B;gBAErB,QAAQ,EAAE,MAAM;IAIrC,WAAW,CAAC,KAAK,EAAE,oBAAoB,GAAG,oBAAoB,GAAG,OAAO;CAY/E"}
|
package/dist/perspective.js
CHANGED
|
@@ -3,45 +3,56 @@
|
|
|
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
|
-
exports.
|
|
30
|
+
exports.RemoteObliteratePerspective = exports.LocalDefaultPerspective = exports.LocalReconnectingPerspective = exports.PriorPerspective = void 0;
|
|
8
31
|
const constants_js_1 = require("./constants.js");
|
|
9
32
|
const mergeTreeNodeWalk_js_1 = require("./mergeTreeNodeWalk.js");
|
|
10
33
|
const mergeTreeNodes_js_1 = require("./mergeTreeNodes.js");
|
|
11
34
|
const segmentInfos_js_1 = require("./segmentInfos.js");
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
* @privateRemarks
|
|
15
|
-
* TODO:AB#29765: This class does not support non-local-client perspectives, but should.
|
|
16
|
-
*/
|
|
17
|
-
class PerspectiveImpl {
|
|
18
|
-
/**
|
|
19
|
-
* @param _mergeTree - The {@link MergeTree} to view.
|
|
20
|
-
* @param _seqTime - The latest sequence number and local sequence number to consider.
|
|
21
|
-
*/
|
|
22
|
-
constructor(_mergeTree, _seqTime) {
|
|
23
|
-
this._mergeTree = _mergeTree;
|
|
24
|
-
this._seqTime = _seqTime;
|
|
25
|
-
}
|
|
35
|
+
const opstampUtils = __importStar(require("./stamps.js"));
|
|
36
|
+
class PerspectiveBase {
|
|
26
37
|
/**
|
|
27
38
|
* Returns the immediately adjacent segment in the specified direction from this perspective.
|
|
28
39
|
* There may actually be multiple segments between the given segment and the returned segment,
|
|
29
|
-
* but they were either inserted after this perspective, or have been removed
|
|
40
|
+
* but they were either inserted after this perspective, or have been removed before this perspective.
|
|
30
41
|
*
|
|
31
42
|
* @param segment - The segment to start from.
|
|
32
43
|
* @param forward - The direction to search.
|
|
33
44
|
* @returns the next segment in the specified direction, or the start or end of the tree if there is no next segment.
|
|
34
45
|
*/
|
|
35
|
-
nextSegment(segment, forward = true) {
|
|
46
|
+
nextSegment(mergeTree, segment, forward = true) {
|
|
36
47
|
let next;
|
|
37
48
|
const action = (seg) => {
|
|
38
|
-
if (isSegmentPresent(seg
|
|
49
|
+
if (this.isSegmentPresent(seg)) {
|
|
39
50
|
next = seg;
|
|
40
51
|
return mergeTreeNodeWalk_js_1.LeafAction.Exit;
|
|
41
52
|
}
|
|
42
53
|
};
|
|
43
54
|
(forward ? mergeTreeNodeWalk_js_1.forwardExcursion : mergeTreeNodeWalk_js_1.backwardExcursion)(segment, action);
|
|
44
|
-
return next ?? (forward ?
|
|
55
|
+
return next ?? (forward ? mergeTree.endOfTree : mergeTree.startOfTree);
|
|
45
56
|
}
|
|
46
57
|
/**
|
|
47
58
|
* Finds the segment prior to the given segment.
|
|
@@ -49,88 +60,138 @@ class PerspectiveImpl {
|
|
|
49
60
|
* @returns the previous segment, or the start of the tree if there is no previous segment.
|
|
50
61
|
* @remarks This is a convenient equivalent to calling `nextSegment(segment, false)`.
|
|
51
62
|
*/
|
|
52
|
-
previousSegment(segment) {
|
|
53
|
-
return this.nextSegment(segment, false);
|
|
63
|
+
previousSegment(mergeTree, segment) {
|
|
64
|
+
return this.nextSegment(mergeTree, segment, false);
|
|
65
|
+
}
|
|
66
|
+
isSegmentPresent(seg) {
|
|
67
|
+
const insert = {
|
|
68
|
+
type: "insert",
|
|
69
|
+
clientId: seg.clientId,
|
|
70
|
+
seq: seg.seq,
|
|
71
|
+
localSeq: seg.localSeq,
|
|
72
|
+
};
|
|
73
|
+
if ((0, segmentInfos_js_1.isInserted)(seg) && !this.hasOccurred(insert)) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
const removes = [];
|
|
77
|
+
const removalInfo = (0, segmentInfos_js_1.toRemovalInfo)(seg);
|
|
78
|
+
if (removalInfo !== undefined) {
|
|
79
|
+
removes.push(...removalInfo.removedClientIds.map((clientId) => (clientId === constants_js_1.LocalClientId || clientId === 0) &&
|
|
80
|
+
removalInfo.localRemovedSeq !== undefined
|
|
81
|
+
? {
|
|
82
|
+
type: "setRemove",
|
|
83
|
+
seq: constants_js_1.UnassignedSequenceNumber,
|
|
84
|
+
clientId,
|
|
85
|
+
localSeq: removalInfo.localRemovedSeq,
|
|
86
|
+
}
|
|
87
|
+
: // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
88
|
+
{ type: "setRemove", seq: removalInfo.removedSeq, clientId }));
|
|
89
|
+
}
|
|
90
|
+
const moveInfo = (0, segmentInfos_js_1.toMoveInfo)(seg);
|
|
91
|
+
if (moveInfo !== undefined) {
|
|
92
|
+
removes.push(...moveInfo.movedClientIds.map((clientId, index) => (clientId === constants_js_1.LocalClientId || clientId === 0) &&
|
|
93
|
+
moveInfo.localMovedSeq !== undefined
|
|
94
|
+
? {
|
|
95
|
+
type: "sliceRemove",
|
|
96
|
+
seq: constants_js_1.UnassignedSequenceNumber,
|
|
97
|
+
clientId,
|
|
98
|
+
localSeq: moveInfo.localMovedSeq,
|
|
99
|
+
}
|
|
100
|
+
: // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
101
|
+
{ type: "setRemove", seq: moveInfo.movedSeqs[index], clientId }));
|
|
102
|
+
}
|
|
103
|
+
if (removes.some((remove) => this.hasOccurred(remove))) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
return true;
|
|
54
107
|
}
|
|
55
108
|
}
|
|
56
|
-
exports.PerspectiveImpl = PerspectiveImpl;
|
|
57
109
|
/**
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
* @
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
* @privateRemarks
|
|
64
|
-
* TODO:AB#29765: This function does not support non-local-client perspectives, but should.
|
|
110
|
+
* A perspective which includes edits at or before some reference sequence number alongside all edits from some particular client.
|
|
111
|
+
*
|
|
112
|
+
* @remarks
|
|
113
|
+
* This works for both the local client as well as remote clients since refSeq-based checks disallow unacked edits, but the clientId check
|
|
114
|
+
* catches unacked edits from the local client.
|
|
65
115
|
*/
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
116
|
+
class PriorPerspective extends PerspectiveBase {
|
|
117
|
+
constructor(refSeq, clientId) {
|
|
118
|
+
super();
|
|
119
|
+
this.refSeq = refSeq;
|
|
120
|
+
this.clientId = clientId;
|
|
121
|
+
}
|
|
122
|
+
hasOccurred(stamp) {
|
|
123
|
+
const predatesViaRefSeq = (0, mergeTreeNodes_js_1.seqLTE)(stamp.seq, this.refSeq);
|
|
124
|
+
const predatesViaSameClient = stamp.clientId === this.clientId;
|
|
125
|
+
return predatesViaRefSeq || predatesViaSameClient;
|
|
71
126
|
}
|
|
72
|
-
return seg.removedSeq !== undefined && (0, mergeTreeNodes_js_1.seqLTE)(seg.removedSeq, refSeq);
|
|
73
127
|
}
|
|
74
|
-
exports.
|
|
128
|
+
exports.PriorPerspective = PriorPerspective;
|
|
75
129
|
/**
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
* TODO:AB#29765: This function does not support non-local-client perspectives, but should.
|
|
130
|
+
* A perspective which includes edits which were either:
|
|
131
|
+
* - acked and at or before some reference sequence number
|
|
132
|
+
* - unacked, but at or before some local sequence number
|
|
133
|
+
*
|
|
134
|
+
* This is a useful perspective when the local client is in the process of reconnecting, since it must
|
|
135
|
+
* rederive positions for unacked ops while only considering a portion of its own edits as having been applied.
|
|
83
136
|
*/
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
137
|
+
class LocalReconnectingPerspective extends PerspectiveBase {
|
|
138
|
+
constructor(refSeq, clientId, localSeq) {
|
|
139
|
+
super();
|
|
140
|
+
this.refSeq = refSeq;
|
|
141
|
+
this.clientId = clientId;
|
|
142
|
+
this.localSeq = localSeq;
|
|
143
|
+
}
|
|
144
|
+
hasOccurred(stamp) {
|
|
145
|
+
const predatesViaRefSeq = (0, mergeTreeNodes_js_1.seqLTE)(stamp.seq, this.refSeq);
|
|
146
|
+
const predatesViaLocalSeq = stamp.localSeq !== undefined && stamp.localSeq <= this.localSeq;
|
|
147
|
+
return predatesViaRefSeq || predatesViaLocalSeq;
|
|
89
148
|
}
|
|
90
|
-
return seg.movedSeq !== undefined && (0, mergeTreeNodes_js_1.seqLTE)(seg.movedSeq, refSeq);
|
|
91
149
|
}
|
|
92
|
-
exports.
|
|
150
|
+
exports.LocalReconnectingPerspective = LocalReconnectingPerspective;
|
|
93
151
|
/**
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
152
|
+
* A perspective which includes all known edits.
|
|
153
|
+
*
|
|
154
|
+
* This is the perspective that the application sees.
|
|
155
|
+
* @remarks
|
|
156
|
+
* This can be represented using {@link PriorPerspective} with a refSeq of `Number.MAX_SAFE_INTEGER`, but having an explicit
|
|
157
|
+
* variant of this perspective renders extra refSeq checks unnecessary and is a bit easier to read.
|
|
97
158
|
*/
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
(
|
|
101
|
-
|
|
159
|
+
class LocalDefaultPerspective extends PerspectiveBase {
|
|
160
|
+
constructor(clientId) {
|
|
161
|
+
super();
|
|
162
|
+
this.clientId = clientId;
|
|
163
|
+
this.refSeq = Number.MAX_SAFE_INTEGER;
|
|
164
|
+
}
|
|
165
|
+
hasOccurred(_stamp) {
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
102
168
|
}
|
|
103
|
-
exports.
|
|
169
|
+
exports.LocalDefaultPerspective = LocalDefaultPerspective;
|
|
104
170
|
/**
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
* TODO:AB#29765: This function does not support non-local-client perspectives, but should.
|
|
171
|
+
* A perspective dictating whether segments are 'visible' to a remote obliterate operation.
|
|
172
|
+
*
|
|
173
|
+
* NOTE: Beware that partial lengths doesn't support this perspective, in the sense that consulting partial lengths' for the length of a block
|
|
174
|
+
* can give different results than summing the lengths of present segments in that block.
|
|
175
|
+
* This ends up not affecting the current obliterate implementation (which has some special casing in the mapRange calls it uses),
|
|
176
|
+
* but use with caution.
|
|
112
177
|
*/
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
(localSeq === undefined || seg.localSeq > localSeq)) {
|
|
178
|
+
class RemoteObliteratePerspective extends PerspectiveBase {
|
|
179
|
+
constructor(clientId) {
|
|
180
|
+
super();
|
|
181
|
+
this.clientId = clientId;
|
|
182
|
+
this.refSeq = Number.MAX_SAFE_INTEGER;
|
|
183
|
+
}
|
|
184
|
+
hasOccurred(stamp) {
|
|
185
|
+
// Local-only removals are not visible to an obliterate operation, since this means the local removal was concurrent
|
|
186
|
+
// to a remote obliterate and we may need to mark the segment appropriately to reflect this overlapping remove.
|
|
187
|
+
// Every other type of operation is visible: obliterates do not affect segments that have already been removed and acked,
|
|
188
|
+
// and they always affect segments within their range that have not been removed, even if those segments were inserted
|
|
189
|
+
// after the obliterate's refSeq.
|
|
190
|
+
if (stamp.type !== "insert" && opstampUtils.isLocal(stamp)) {
|
|
127
191
|
return false;
|
|
128
192
|
}
|
|
193
|
+
return true;
|
|
129
194
|
}
|
|
130
|
-
if (wasRemovedOrMovedBefore(seg, seqTime)) {
|
|
131
|
-
return false;
|
|
132
|
-
}
|
|
133
|
-
return true;
|
|
134
195
|
}
|
|
135
|
-
exports.
|
|
196
|
+
exports.RemoteObliteratePerspective = RemoteObliteratePerspective;
|
|
136
197
|
//# sourceMappingURL=perspective.js.map
|
package/dist/perspective.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"perspective.js","sourceRoot":"","sources":["../src/perspective.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { UnassignedSequenceNumber } from \"./constants.js\";\nimport { type MergeTree } from \"./mergeTree.js\";\nimport { LeafAction, backwardExcursion, forwardExcursion } from \"./mergeTreeNodeWalk.js\";\nimport { seqLTE, type ISegmentLeaf } from \"./mergeTreeNodes.js\";\nimport {\n\tisInserted,\n\tisMoved,\n\tisRemoved,\n\ttype IInsertionInfo,\n\ttype IMoveInfo,\n\ttype IRemovalInfo,\n\ttype SegmentWithInfo,\n} from \"./segmentInfos.js\";\n\n/**\n * Provides a view of a MergeTree from the perspective of a specific client at a specific sequence number.\n */\nexport interface Perspective {\n\tnextSegment(segment: ISegmentLeaf, forward?: boolean): ISegmentLeaf;\n\tpreviousSegment(segment: ISegmentLeaf): ISegmentLeaf;\n}\n\n/**\n * Represents a point in time inside the collaboration window.\n */\nexport interface SeqTime {\n\trefSeq: number;\n\tlocalSeq?: number;\n}\n\n/**\n * Implementation of {@link Perspective}.\n * @privateRemarks\n * TODO:AB#29765: This class does not support non-local-client perspectives, but should.\n */\nexport class PerspectiveImpl implements Perspective {\n\t/**\n\t * @param _mergeTree - The {@link MergeTree} to view.\n\t * @param _seqTime - The latest sequence number and local sequence number to consider.\n\t */\n\tpublic constructor(\n\t\tprivate readonly _mergeTree: MergeTree,\n\t\tprivate readonly _seqTime: SeqTime,\n\t) {}\n\n\t/**\n\t * Returns the immediately adjacent segment in the specified direction from this perspective.\n\t * There may actually be multiple segments between the given segment and the returned segment,\n\t * but they were either inserted after this perspective, or have been removed or moved before this perspective.\n\t *\n\t * @param segment - The segment to start from.\n\t * @param forward - The direction to search.\n\t * @returns the next segment in the specified direction, or the start or end of the tree if there is no next segment.\n\t */\n\tpublic nextSegment(segment: ISegmentLeaf, forward: boolean = true): ISegmentLeaf {\n\t\tlet next: ISegmentLeaf | undefined;\n\t\tconst action = (seg: ISegmentLeaf): boolean | undefined => {\n\t\t\tif (isSegmentPresent(seg, this._seqTime)) {\n\t\t\t\tnext = seg;\n\t\t\t\treturn LeafAction.Exit;\n\t\t\t}\n\t\t};\n\t\t(forward ? forwardExcursion : backwardExcursion)(segment, action);\n\t\treturn next ?? (forward ? this._mergeTree.endOfTree : this._mergeTree.startOfTree);\n\t}\n\n\t/**\n\t * Finds the segment prior to the given segment.\n\t * @param segment - The segment to start from.\n\t * @returns the previous segment, or the start of the tree if there is no previous segment.\n\t * @remarks This is a convenient equivalent to calling `nextSegment(segment, false)`.\n\t */\n\tpublic previousSegment(segment: ISegmentLeaf): ISegmentLeaf {\n\t\treturn this.nextSegment(segment, false);\n\t}\n}\n\n/**\n * Determines if the given segment was removed before the given perspective.\n * @param seg - The segment to check.\n * @param seq - The latest sequence number to consider.\n * @param localSeq - The latest local sequence number to consider.\n * @returns true iff this segment was removed in the given perspective.\n * @privateRemarks\n * TODO:AB#29765: This function does not support non-local-client perspectives, but should.\n */\nexport function wasRemovedBefore(\n\tseg: SegmentWithInfo<IInsertionInfo & IRemovalInfo>,\n\t{ refSeq, localSeq }: SeqTime,\n): boolean {\n\tif (\n\t\tseg.removedSeq === UnassignedSequenceNumber &&\n\t\tlocalSeq !== undefined &&\n\t\tseg.localRemovedSeq !== undefined\n\t) {\n\t\treturn seg.localRemovedSeq <= localSeq;\n\t}\n\treturn seg.removedSeq !== undefined && seqLTE(seg.removedSeq, refSeq);\n}\n\n/**\n * Determines if the given segment was moved before the given perspective.\n * @param seg - The segment to check.\n * @param refSeq - The latest sequence number to consider.\n * @param localSeq - The latest local sequence number to consider.\n * @returns true iff this segment was moved (aka obliterated) in the given perspective.\n * @privateRemarks\n * TODO:AB#29765: This function does not support non-local-client perspectives, but should.\n */\nexport function wasMovedBefore(\n\tseg: SegmentWithInfo<IInsertionInfo & IMoveInfo>,\n\t{ refSeq, localSeq }: SeqTime,\n): boolean {\n\tif (\n\t\tseg.movedSeq === UnassignedSequenceNumber &&\n\t\tlocalSeq !== undefined &&\n\t\tseg.localMovedSeq !== undefined\n\t) {\n\t\treturn seg.localMovedSeq <= localSeq;\n\t}\n\treturn seg.movedSeq !== undefined && seqLTE(seg.movedSeq, refSeq);\n}\n\n/**\n * See {@link wasRemovedBefore} and {@link wasMovedBefore}.\n * @privateRemarks\n * TODO:AB#29765: This function does not support non-local-client perspectives, but should.\n */\nexport function wasRemovedOrMovedBefore(seg: ISegmentLeaf, seqTime: SeqTime): boolean {\n\treturn (\n\t\tisInserted(seg) &&\n\t\t((isRemoved(seg) && wasRemovedBefore(seg, seqTime)) ||\n\t\t\t(isMoved(seg) && wasMovedBefore(seg, seqTime)))\n\t);\n}\n\n/**\n * Determines if the given segment is present in the given perspective.\n * @param seg - The segment to check.\n * @param seqTime - The latest sequence number and local sequence number to consider.\n * @returns true iff this segment was inserted before the given perspective,\n * and it was not removed or moved in the given perspective.\n * @privateRemarks\n * TODO:AB#29765: This function does not support non-local-client perspectives, but should.\n */\nexport function isSegmentPresent(seg: ISegmentLeaf, seqTime: SeqTime): boolean {\n\tconst { refSeq, localSeq } = seqTime;\n\t// If seg.seq is undefined, then this segment has existed since minSeq.\n\t// It may have been moved or removed since.\n\tif (isInserted(seg)) {\n\t\tif (seg.seq !== UnassignedSequenceNumber) {\n\t\t\tif (!seqLTE(seg.seq, refSeq)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} else if (\n\t\t\tseg.localSeq !== undefined && // seg.seq === UnassignedSequenceNumber\n\t\t\t// If the current perspective does not include local sequence numbers,\n\t\t\t// then this segment does not exist yet.\n\t\t\t(localSeq === undefined || seg.localSeq > localSeq)\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\t}\n\tif (wasRemovedOrMovedBefore(seg, seqTime)) {\n\t\treturn false;\n\t}\n\treturn true;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"perspective.js","sourceRoot":"","sources":["../src/perspective.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { LocalClientId, UnassignedSequenceNumber } from \"./constants.js\";\nimport { type MergeTree } from \"./mergeTree.js\";\nimport { LeafAction, backwardExcursion, forwardExcursion } from \"./mergeTreeNodeWalk.js\";\nimport { seqLTE, type ISegmentLeaf } from \"./mergeTreeNodes.js\";\nimport { isInserted, toMoveInfo, toRemovalInfo } from \"./segmentInfos.js\";\nimport * as opstampUtils from \"./stamps.js\";\nimport type { OperationStamp, InsertOperationStamp, RemoveOperationStamp } from \"./stamps.js\";\n\n/**\n * A perspective which includes some subset of operations known to the local client.\n *\n * This helps the local client reason about the state of other clients when they issued an operation.\n */\nexport interface Perspective {\n\t/**\n\t * The sequence number last seen from this perspective. Same concept as `ISequencedDocumentMessage.referenceSequenceNumber`.\n\t * @privateRemarks\n\t * This currently allows inter-operation between MergeTree methods and the partial lengths implementation, which still depends\n\t * on the (refSeq, clientId, localSeq?) representation of perspectives.\n\t */\n\treadonly refSeq: number;\n\n\t/**\n\t * The client id for this perspective.\n\t * @privateRemarks\n\t * This currently allows inter-operation between MergeTree methods and the partial lengths implementation, which still depends\n\t * on the (refSeq, clientId, localSeq?) representation of perspectives.\n\t */\n\treadonly clientId: number;\n\n\t/**\n\t * When this is a local perspective, the local sequence number last seen from this perspective.\n\t *\n\t * Perspectives with defined `localSeq` values are useful in reconnection flows, where the local client may need to resend some\n\t * of its ops after rederiving their new equivalents.\n\t * @privateRemarks\n\t * This currently allows inter-operation between MergeTree methods and the partial lengths implementation, which still depends\n\t * on the (refSeq, clientId, localSeq?) representation of perspectives.\n\t */\n\treadonly localSeq?: number;\n\n\t/**\n\t * @returns Whether the segment is present (visible) from this perspective\n\t */\n\tisSegmentPresent(segment: ISegmentLeaf): boolean;\n\n\t/**\n\t * @returns Whether this perspective has seen the given operation.\n\t */\n\thasOccurred(stamp: RemoveOperationStamp | InsertOperationStamp): boolean;\n\n\tnextSegment(mergeTree: MergeTree, segment: ISegmentLeaf, forward?: boolean): ISegmentLeaf;\n\tpreviousSegment(mergeTree: MergeTree, segment: ISegmentLeaf): ISegmentLeaf;\n}\n\nabstract class PerspectiveBase {\n\tabstract hasOccurred(stamp: RemoveOperationStamp | InsertOperationStamp): boolean;\n\n\t/**\n\t * Returns the immediately adjacent segment in the specified direction from this perspective.\n\t * There may actually be multiple segments between the given segment and the returned segment,\n\t * but they were either inserted after this perspective, or have been removed before this perspective.\n\t *\n\t * @param segment - The segment to start from.\n\t * @param forward - The direction to search.\n\t * @returns the next segment in the specified direction, or the start or end of the tree if there is no next segment.\n\t */\n\tpublic nextSegment(\n\t\tmergeTree: MergeTree,\n\t\tsegment: ISegmentLeaf,\n\t\tforward: boolean = true,\n\t): ISegmentLeaf {\n\t\tlet next: ISegmentLeaf | undefined;\n\t\tconst action = (seg: ISegmentLeaf): boolean | undefined => {\n\t\t\tif (this.isSegmentPresent(seg)) {\n\t\t\t\tnext = seg;\n\t\t\t\treturn LeafAction.Exit;\n\t\t\t}\n\t\t};\n\t\t(forward ? forwardExcursion : backwardExcursion)(segment, action);\n\t\treturn next ?? (forward ? mergeTree.endOfTree : mergeTree.startOfTree);\n\t}\n\n\t/**\n\t * Finds the segment prior to the given segment.\n\t * @param segment - The segment to start from.\n\t * @returns the previous segment, or the start of the tree if there is no previous segment.\n\t * @remarks This is a convenient equivalent to calling `nextSegment(segment, false)`.\n\t */\n\tpublic previousSegment(mergeTree: MergeTree, segment: ISegmentLeaf): ISegmentLeaf {\n\t\treturn this.nextSegment(mergeTree, segment, false);\n\t}\n\n\tpublic isSegmentPresent(seg: ISegmentLeaf): boolean {\n\t\tconst insert: InsertOperationStamp = {\n\t\t\ttype: \"insert\",\n\t\t\tclientId: seg.clientId,\n\t\t\tseq: seg.seq,\n\t\t\tlocalSeq: seg.localSeq,\n\t\t};\n\t\tif (isInserted(seg) && !this.hasOccurred(insert)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst removes: RemoveOperationStamp[] = [];\n\t\tconst removalInfo = toRemovalInfo(seg);\n\t\tif (removalInfo !== undefined) {\n\t\t\tremoves.push(\n\t\t\t\t...removalInfo.removedClientIds.map((clientId) =>\n\t\t\t\t\t(clientId === LocalClientId || clientId === 0) &&\n\t\t\t\t\tremovalInfo.localRemovedSeq !== undefined\n\t\t\t\t\t\t? ({\n\t\t\t\t\t\t\t\ttype: \"setRemove\",\n\t\t\t\t\t\t\t\tseq: UnassignedSequenceNumber,\n\t\t\t\t\t\t\t\tclientId,\n\t\t\t\t\t\t\t\tlocalSeq: removalInfo.localRemovedSeq,\n\t\t\t\t\t\t\t} as const)\n\t\t\t\t\t\t: // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\t\t\t\t({ type: \"setRemove\", seq: removalInfo.removedSeq, clientId } as const),\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\tconst moveInfo = toMoveInfo(seg);\n\t\tif (moveInfo !== undefined) {\n\t\t\tremoves.push(\n\t\t\t\t...moveInfo.movedClientIds.map((clientId, index) =>\n\t\t\t\t\t(clientId === LocalClientId || clientId === 0) &&\n\t\t\t\t\tmoveInfo.localMovedSeq !== undefined\n\t\t\t\t\t\t? ({\n\t\t\t\t\t\t\t\ttype: \"sliceRemove\",\n\t\t\t\t\t\t\t\tseq: UnassignedSequenceNumber,\n\t\t\t\t\t\t\t\tclientId,\n\t\t\t\t\t\t\t\tlocalSeq: moveInfo.localMovedSeq,\n\t\t\t\t\t\t\t} as const)\n\t\t\t\t\t\t: // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\t\t\t\t({ type: \"setRemove\", seq: moveInfo.movedSeqs[index]!, clientId } as const),\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\tif (removes.some((remove) => this.hasOccurred(remove))) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n}\n\n/**\n * A perspective which includes edits at or before some reference sequence number alongside all edits from some particular client.\n *\n * @remarks\n * This works for both the local client as well as remote clients since refSeq-based checks disallow unacked edits, but the clientId check\n * catches unacked edits from the local client.\n */\nexport class PriorPerspective extends PerspectiveBase implements Perspective {\n\tpublic constructor(\n\t\tpublic readonly refSeq: number,\n\t\tpublic readonly clientId: number,\n\t) {\n\t\tsuper();\n\t}\n\n\tpublic hasOccurred(stamp: OperationStamp): boolean {\n\t\tconst predatesViaRefSeq = seqLTE(stamp.seq, this.refSeq);\n\t\tconst predatesViaSameClient = stamp.clientId === this.clientId;\n\t\treturn predatesViaRefSeq || predatesViaSameClient;\n\t}\n}\n\n/**\n * A perspective which includes edits which were either:\n * - acked and at or before some reference sequence number\n * - unacked, but at or before some local sequence number\n *\n * This is a useful perspective when the local client is in the process of reconnecting, since it must\n * rederive positions for unacked ops while only considering a portion of its own edits as having been applied.\n */\nexport class LocalReconnectingPerspective extends PerspectiveBase implements Perspective {\n\tpublic constructor(\n\t\tpublic readonly refSeq: number,\n\t\tpublic readonly clientId: number,\n\t\tpublic readonly localSeq: number,\n\t) {\n\t\tsuper();\n\t}\n\n\tpublic hasOccurred(stamp: OperationStamp): boolean {\n\t\tconst predatesViaRefSeq = seqLTE(stamp.seq, this.refSeq);\n\t\tconst predatesViaLocalSeq =\n\t\t\tstamp.localSeq !== undefined && stamp.localSeq <= this.localSeq;\n\t\treturn predatesViaRefSeq || predatesViaLocalSeq;\n\t}\n}\n\n/**\n * A perspective which includes all known edits.\n *\n * This is the perspective that the application sees.\n * @remarks\n * This can be represented using {@link PriorPerspective} with a refSeq of `Number.MAX_SAFE_INTEGER`, but having an explicit\n * variant of this perspective renders extra refSeq checks unnecessary and is a bit easier to read.\n */\nexport class LocalDefaultPerspective extends PerspectiveBase implements Perspective {\n\tpublic readonly refSeq = Number.MAX_SAFE_INTEGER;\n\n\tpublic constructor(public readonly clientId: number) {\n\t\tsuper();\n\t}\n\n\tpublic hasOccurred(_stamp: OperationStamp): boolean {\n\t\treturn true;\n\t}\n}\n\n/**\n * A perspective dictating whether segments are 'visible' to a remote obliterate operation.\n *\n * NOTE: Beware that partial lengths doesn't support this perspective, in the sense that consulting partial lengths' for the length of a block\n * can give different results than summing the lengths of present segments in that block.\n * This ends up not affecting the current obliterate implementation (which has some special casing in the mapRange calls it uses),\n * but use with caution.\n */\nexport class RemoteObliteratePerspective extends PerspectiveBase implements Perspective {\n\tpublic readonly refSeq = Number.MAX_SAFE_INTEGER;\n\n\tconstructor(public readonly clientId: number) {\n\t\tsuper();\n\t}\n\n\tpublic hasOccurred(stamp: InsertOperationStamp | RemoveOperationStamp): boolean {\n\t\t// Local-only removals are not visible to an obliterate operation, since this means the local removal was concurrent\n\t\t// to a remote obliterate and we may need to mark the segment appropriately to reflect this overlapping remove.\n\t\t// Every other type of operation is visible: obliterates do not affect segments that have already been removed and acked,\n\t\t// and they always affect segments within their range that have not been removed, even if those segments were inserted\n\t\t// after the obliterate's refSeq.\n\t\tif (stamp.type !== \"insert\" && opstampUtils.isLocal(stamp)) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n}\n"]}
|
package/dist/stamps.d.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* A stamp that identifies provenance of an operation performed on the MergeTree.
|
|
7
|
+
*
|
|
8
|
+
* Stamps identify a point in time (`seq`/`localSeq`) as well as the source (`clientId`) for the operation.
|
|
9
|
+
* This provides enough information to linearize all known applied operations: acked operations happen before
|
|
10
|
+
* local+unacked ones, with acked operations ordered by their sequence numbers and local+unacked operations
|
|
11
|
+
* ordered by their localSeq.
|
|
12
|
+
*
|
|
13
|
+
* By including `clientId`, it also provides enough information to resolve whether segments are visible
|
|
14
|
+
* from alternative perspectives: a remote client will have seen all of its own previous operations as well as
|
|
15
|
+
* those at or below the op's reference sequence number.
|
|
16
|
+
*
|
|
17
|
+
* @remarks - As the `readonly` identifies suggest, these stamps should be treated as immutable.
|
|
18
|
+
* New operations applied to a merge-tree should create new stamps rather than modify existing ones (e.g. when
|
|
19
|
+
* a change's ack happens).
|
|
20
|
+
* @internal
|
|
21
|
+
*/
|
|
22
|
+
export interface OperationStamp {
|
|
23
|
+
/**
|
|
24
|
+
* The sequence number at which this operation was applied.
|
|
25
|
+
*/
|
|
26
|
+
readonly seq: number;
|
|
27
|
+
/**
|
|
28
|
+
* Short clientId for the client that performed this operation.
|
|
29
|
+
*/
|
|
30
|
+
readonly clientId: number;
|
|
31
|
+
/**
|
|
32
|
+
* Local seq at which this operation was applied.
|
|
33
|
+
* This is defined if and only if the operation is pending an ack, i.e. `seq` is UnassignedSequenceNumber.
|
|
34
|
+
*
|
|
35
|
+
* @privateRemarks
|
|
36
|
+
* See {@link CollaborationWindow.localSeq} for more information on the semantics of localSeq.
|
|
37
|
+
*/
|
|
38
|
+
readonly localSeq?: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* {@link OperationStamp} for an 'insert' operation.
|
|
42
|
+
*/
|
|
43
|
+
export interface InsertOperationStamp extends OperationStamp {
|
|
44
|
+
readonly type: "insert";
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* {@link OperationStamp} for a 'set remove' operation. This aligns with the `markRangeRemoved` API in MergeTree.
|
|
48
|
+
*
|
|
49
|
+
* @remarks The terminology here comes from the fact that the removal should affect only the *set* of nodes that were
|
|
50
|
+
* specified at the time the local client issued the remove, and not any nodes that were inserted concurrently.
|
|
51
|
+
*
|
|
52
|
+
* Not using "remove" and "obliterate" here allows us to unambiguously use the term "remove" elsewhere in code to mean
|
|
53
|
+
* "removed from the tree, either by MergeTree.obliterateRange or MergeTree.removeRange". This is convenient as the vast majority
|
|
54
|
+
* of merge-tree code only cares about segment visibility and not the specific operation that caused a segment to be removed.
|
|
55
|
+
*/
|
|
56
|
+
export interface SetRemoveOperationStamp extends OperationStamp {
|
|
57
|
+
readonly type: "setRemove";
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* {@link OperationStamp} for a 'set remove' operation. This aligns with the `obliterateRange` API in MergeTree.
|
|
61
|
+
*
|
|
62
|
+
* @remarks The terminology here comes from the fact that the removal should affect the *slice* of nodes between the
|
|
63
|
+
* start and end point specified by the local client, which includes any nodes that were inserted concurrently.
|
|
64
|
+
*
|
|
65
|
+
* Not using "remove" and "obliterate" here allows us to unambiguously use the term "remove" elsewhere in code to mean
|
|
66
|
+
* "removed from the tree, either by MergeTree.obliterateRange or MergeTree.removeRange". This is convenient as the vast majority
|
|
67
|
+
* of merge-tree code only cares about segment visibility and not the specific operation that caused a segment to be removed.
|
|
68
|
+
*/
|
|
69
|
+
export interface SliceRemoveOperationStamp extends OperationStamp {
|
|
70
|
+
readonly type: "sliceRemove";
|
|
71
|
+
}
|
|
72
|
+
export type RemoveOperationStamp = SetRemoveOperationStamp | SliceRemoveOperationStamp;
|
|
73
|
+
export declare function lessThan(a: OperationStamp, b: OperationStamp): boolean;
|
|
74
|
+
export declare function gte(a: OperationStamp, b: OperationStamp): boolean;
|
|
75
|
+
export declare function greaterThan(a: OperationStamp, b: OperationStamp): boolean;
|
|
76
|
+
export declare function lte(a: OperationStamp, b: OperationStamp): boolean;
|
|
77
|
+
export declare function equal(a: OperationStamp, b: OperationStamp): boolean;
|
|
78
|
+
export declare function isLocal(a: OperationStamp): boolean;
|
|
79
|
+
export declare function isAcked(a: OperationStamp): boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Inserts a stamp into a sorted list of stamps in the correct (sorted) position.
|
|
82
|
+
*
|
|
83
|
+
* Beware that this uses Array.splice, thus requires asymptotics considerations.
|
|
84
|
+
* If inserting a variable number of timestamp, consider just pushing them and sorting the list
|
|
85
|
+
* after using {@link compare} instead.
|
|
86
|
+
*/
|
|
87
|
+
export declare function spliceIntoList(list: OperationStamp[], stamp: OperationStamp): void;
|
|
88
|
+
export declare function hasAnyAckedOperation(list: OperationStamp[]): boolean;
|
|
89
|
+
export declare function compare(a: OperationStamp, b: OperationStamp): number;
|
|
90
|
+
//# sourceMappingURL=stamps.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stamps.d.ts","sourceRoot":"","sources":["../src/stamps.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,cAAc;IAC9B;;OAEG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,cAAc;IAC3D,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;CACxB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,uBAAwB,SAAQ,cAAc;IAC9D,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;CAC3B;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,yBAA0B,SAAQ,cAAc;IAChE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;CAC7B;AAED,MAAM,MAAM,oBAAoB,GAAG,uBAAuB,GAAG,yBAAyB,CAAC;AAEvF,wBAAgB,QAAQ,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,cAAc,GAAG,OAAO,CAWtE;AAED,wBAAgB,GAAG,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,cAAc,GAAG,OAAO,CAEjE;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,cAAc,GAAG,OAAO,CAWzE;AAED,wBAAgB,GAAG,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,cAAc,GAAG,OAAO,CAEjE;AAED,wBAAgB,KAAK,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,cAAc,GAAG,OAAO,CAEnE;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,cAAc,GAAG,OAAO,CAElD;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,cAAc,GAAG,OAAO,CAElD;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,cAAc,EAAE,EAAE,KAAK,EAAE,cAAc,GAAG,IAAI,CAclF;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG,OAAO,CAEpE;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,cAAc,GAAG,MAAM,CAQpE"}
|