@fluidframework/sequence 2.0.0-dev.5.3.2.178189 → 2.0.0-dev.6.4.0.191457
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 +114 -0
- package/README.md +4 -3
- package/dist/defaultMap.d.ts +1 -1
- package/dist/defaultMap.d.ts.map +1 -1
- package/dist/defaultMap.js +9 -10
- package/dist/defaultMap.js.map +1 -1
- package/dist/defaultMapInterfaces.d.ts +1 -1
- package/dist/defaultMapInterfaces.d.ts.map +1 -1
- package/dist/defaultMapInterfaces.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -9
- package/dist/index.js.map +1 -1
- package/dist/intervalCollection.d.ts +11 -424
- package/dist/intervalCollection.d.ts.map +1 -1
- package/dist/intervalCollection.js +74 -815
- package/dist/intervalCollection.js.map +1 -1
- package/dist/intervalIndex/endpointInRangeIndex.d.ts +20 -0
- package/dist/intervalIndex/endpointInRangeIndex.d.ts.map +1 -0
- package/dist/intervalIndex/endpointInRangeIndex.js +60 -0
- package/dist/intervalIndex/endpointInRangeIndex.js.map +1 -0
- package/dist/intervalIndex/endpointIndex.d.ts +21 -0
- package/dist/intervalIndex/endpointIndex.d.ts.map +1 -0
- package/dist/intervalIndex/endpointIndex.js +42 -0
- package/dist/intervalIndex/endpointIndex.js.map +1 -0
- package/dist/intervalIndex/idIntervalIndex.d.ts +12 -0
- package/dist/intervalIndex/idIntervalIndex.d.ts.map +1 -0
- package/dist/intervalIndex/idIntervalIndex.js +41 -0
- package/dist/intervalIndex/idIntervalIndex.js.map +1 -0
- package/dist/intervalIndex/index.d.ts +5 -0
- package/dist/intervalIndex/index.d.ts.map +1 -1
- package/dist/intervalIndex/index.js +9 -1
- package/dist/intervalIndex/index.js.map +1 -1
- package/dist/intervalIndex/intervalIndex.d.ts +29 -0
- package/dist/intervalIndex/intervalIndex.d.ts.map +1 -0
- package/dist/intervalIndex/intervalIndex.js +7 -0
- package/dist/intervalIndex/intervalIndex.js.map +1 -0
- package/dist/intervalIndex/intervalIndexUtils.d.ts +17 -0
- package/dist/intervalIndex/intervalIndexUtils.d.ts.map +1 -0
- package/dist/intervalIndex/intervalIndexUtils.js +22 -0
- package/dist/intervalIndex/intervalIndexUtils.js.map +1 -0
- package/dist/intervalIndex/overlappingIntervalsIndex.d.ts +2 -1
- package/dist/intervalIndex/overlappingIntervalsIndex.d.ts.map +1 -1
- package/dist/intervalIndex/overlappingIntervalsIndex.js +3 -3
- package/dist/intervalIndex/overlappingIntervalsIndex.js.map +1 -1
- package/dist/intervalIndex/overlappingSequenceIntervalsIndex.js +5 -5
- package/dist/intervalIndex/overlappingSequenceIntervalsIndex.js.map +1 -1
- package/dist/intervalIndex/sequenceIntervalIndexes.d.ts +1 -1
- package/dist/intervalIndex/sequenceIntervalIndexes.d.ts.map +1 -1
- package/dist/intervalIndex/sequenceIntervalIndexes.js.map +1 -1
- package/dist/intervalIndex/startpointInRangeIndex.d.ts +20 -0
- package/dist/intervalIndex/startpointInRangeIndex.d.ts.map +1 -0
- package/dist/intervalIndex/startpointInRangeIndex.js +62 -0
- package/dist/intervalIndex/startpointInRangeIndex.js.map +1 -0
- package/dist/intervalTree.d.ts +2 -56
- package/dist/intervalTree.d.ts.map +1 -1
- package/dist/intervalTree.js +2 -11
- package/dist/intervalTree.js.map +1 -1
- package/dist/intervals/index.d.ts +8 -0
- package/dist/intervals/index.d.ts.map +1 -0
- package/dist/intervals/index.js +23 -0
- package/dist/intervals/index.js.map +1 -0
- package/dist/intervals/interval.d.ts +88 -0
- package/dist/intervals/interval.d.ts.map +1 -0
- package/dist/intervals/interval.js +180 -0
- package/dist/intervals/interval.js.map +1 -0
- package/dist/intervals/intervalUtils.d.ts +200 -0
- package/dist/intervals/intervalUtils.d.ts.map +1 -0
- package/dist/intervals/intervalUtils.js +79 -0
- package/dist/intervals/intervalUtils.js.map +1 -0
- package/dist/intervals/sequenceInterval.d.ts +132 -0
- package/dist/intervals/sequenceInterval.d.ts.map +1 -0
- package/dist/intervals/sequenceInterval.js +313 -0
- package/dist/intervals/sequenceInterval.js.map +1 -0
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/revertibles.d.ts +1 -1
- package/dist/revertibles.d.ts.map +1 -1
- package/dist/revertibles.js +45 -52
- package/dist/revertibles.js.map +1 -1
- package/dist/sequence.d.ts +33 -4
- package/dist/sequence.d.ts.map +1 -1
- package/dist/sequence.js +91 -47
- package/dist/sequence.js.map +1 -1
- package/dist/sequenceDeltaEvent.d.ts +8 -3
- package/dist/sequenceDeltaEvent.d.ts.map +1 -1
- package/dist/sequenceDeltaEvent.js +3 -4
- package/dist/sequenceDeltaEvent.js.map +1 -1
- package/dist/sharedIntervalCollection.d.ts +2 -1
- package/dist/sharedIntervalCollection.d.ts.map +1 -1
- package/dist/sharedIntervalCollection.js +2 -2
- package/dist/sharedIntervalCollection.js.map +1 -1
- package/dist/sharedSequence.d.ts +9 -0
- package/dist/sharedSequence.d.ts.map +1 -1
- package/dist/sharedSequence.js +9 -6
- package/dist/sharedSequence.js.map +1 -1
- package/dist/sharedString.d.ts.map +1 -1
- package/dist/sharedString.js +9 -29
- package/dist/sharedString.js.map +1 -1
- package/lib/defaultMap.d.ts +1 -1
- package/lib/defaultMap.d.ts.map +1 -1
- package/lib/defaultMap.js +5 -6
- package/lib/defaultMap.js.map +1 -1
- package/lib/defaultMapInterfaces.d.ts +1 -1
- package/lib/defaultMapInterfaces.d.ts.map +1 -1
- package/lib/defaultMapInterfaces.js.map +1 -1
- package/lib/index.d.ts +3 -3
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +3 -2
- package/lib/index.js.map +1 -1
- package/lib/intervalCollection.d.ts +11 -424
- package/lib/intervalCollection.d.ts.map +1 -1
- package/lib/intervalCollection.js +43 -776
- package/lib/intervalCollection.js.map +1 -1
- package/lib/intervalIndex/endpointInRangeIndex.d.ts +20 -0
- package/lib/intervalIndex/endpointInRangeIndex.d.ts.map +1 -0
- package/lib/intervalIndex/endpointInRangeIndex.js +56 -0
- package/lib/intervalIndex/endpointInRangeIndex.js.map +1 -0
- package/lib/intervalIndex/endpointIndex.d.ts +21 -0
- package/lib/intervalIndex/endpointIndex.d.ts.map +1 -0
- package/lib/intervalIndex/endpointIndex.js +38 -0
- package/lib/intervalIndex/endpointIndex.js.map +1 -0
- package/lib/intervalIndex/idIntervalIndex.d.ts +12 -0
- package/lib/intervalIndex/idIntervalIndex.d.ts.map +1 -0
- package/lib/intervalIndex/idIntervalIndex.js +37 -0
- package/lib/intervalIndex/idIntervalIndex.js.map +1 -0
- package/lib/intervalIndex/index.d.ts +5 -0
- package/lib/intervalIndex/index.d.ts.map +1 -1
- package/lib/intervalIndex/index.js +4 -0
- package/lib/intervalIndex/index.js.map +1 -1
- package/lib/intervalIndex/intervalIndex.d.ts +29 -0
- package/lib/intervalIndex/intervalIndex.d.ts.map +1 -0
- package/lib/intervalIndex/intervalIndex.js +6 -0
- package/lib/intervalIndex/intervalIndex.js.map +1 -0
- package/lib/intervalIndex/intervalIndexUtils.d.ts +17 -0
- package/lib/intervalIndex/intervalIndexUtils.d.ts.map +1 -0
- package/lib/intervalIndex/intervalIndexUtils.js +18 -0
- package/lib/intervalIndex/intervalIndexUtils.js.map +1 -0
- package/lib/intervalIndex/overlappingIntervalsIndex.d.ts +2 -1
- package/lib/intervalIndex/overlappingIntervalsIndex.d.ts.map +1 -1
- package/lib/intervalIndex/overlappingIntervalsIndex.js +1 -1
- package/lib/intervalIndex/overlappingIntervalsIndex.js.map +1 -1
- package/lib/intervalIndex/overlappingSequenceIntervalsIndex.js +1 -1
- package/lib/intervalIndex/overlappingSequenceIntervalsIndex.js.map +1 -1
- package/lib/intervalIndex/sequenceIntervalIndexes.d.ts +1 -1
- package/lib/intervalIndex/sequenceIntervalIndexes.d.ts.map +1 -1
- package/lib/intervalIndex/sequenceIntervalIndexes.js.map +1 -1
- package/lib/intervalIndex/startpointInRangeIndex.d.ts +20 -0
- package/lib/intervalIndex/startpointInRangeIndex.d.ts.map +1 -0
- package/lib/intervalIndex/startpointInRangeIndex.js +58 -0
- package/lib/intervalIndex/startpointInRangeIndex.js.map +1 -0
- package/lib/intervalTree.d.ts +2 -56
- package/lib/intervalTree.d.ts.map +1 -1
- package/lib/intervalTree.js +2 -11
- package/lib/intervalTree.js.map +1 -1
- package/lib/intervals/index.d.ts +8 -0
- package/lib/intervals/index.d.ts.map +1 -0
- package/lib/intervals/index.js +8 -0
- package/lib/intervals/index.js.map +1 -0
- package/lib/intervals/interval.d.ts +88 -0
- package/lib/intervals/interval.d.ts.map +1 -0
- package/lib/intervals/interval.js +175 -0
- package/lib/intervals/interval.js.map +1 -0
- package/lib/intervals/intervalUtils.d.ts +200 -0
- package/lib/intervals/intervalUtils.d.ts.map +1 -0
- package/lib/intervals/intervalUtils.js +74 -0
- package/lib/intervals/intervalUtils.js.map +1 -0
- package/lib/intervals/sequenceInterval.d.ts +132 -0
- package/lib/intervals/sequenceInterval.d.ts.map +1 -0
- package/lib/intervals/sequenceInterval.js +305 -0
- package/lib/intervals/sequenceInterval.js.map +1 -0
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/revertibles.d.ts +1 -1
- package/lib/revertibles.d.ts.map +1 -1
- package/lib/revertibles.js +28 -35
- package/lib/revertibles.js.map +1 -1
- package/lib/sequence.d.ts +33 -4
- package/lib/sequence.d.ts.map +1 -1
- package/lib/sequence.js +86 -41
- package/lib/sequence.js.map +1 -1
- package/lib/sequenceDeltaEvent.d.ts +8 -3
- package/lib/sequenceDeltaEvent.d.ts.map +1 -1
- package/lib/sequenceDeltaEvent.js +2 -3
- package/lib/sequenceDeltaEvent.js.map +1 -1
- package/lib/sharedIntervalCollection.d.ts +2 -1
- package/lib/sharedIntervalCollection.d.ts.map +1 -1
- package/lib/sharedIntervalCollection.js +1 -1
- package/lib/sharedIntervalCollection.js.map +1 -1
- package/lib/sharedSequence.d.ts +9 -0
- package/lib/sharedSequence.d.ts.map +1 -1
- package/lib/sharedSequence.js +8 -5
- package/lib/sharedSequence.js.map +1 -1
- package/lib/sharedString.d.ts.map +1 -1
- package/lib/sharedString.js +9 -29
- package/lib/sharedString.js.map +1 -1
- package/package.json +29 -32
- package/src/defaultMap.ts +2 -1
- package/src/defaultMapInterfaces.ts +1 -1
- package/src/index.ts +18 -12
- package/src/intervalCollection.ts +42 -1225
- package/src/intervalIndex/endpointInRangeIndex.ts +104 -0
- package/src/intervalIndex/endpointIndex.ts +78 -0
- package/src/intervalIndex/idIntervalIndex.ts +58 -0
- package/src/intervalIndex/index.ts +5 -0
- package/src/intervalIndex/intervalIndex.ts +31 -0
- package/src/intervalIndex/intervalIndexUtils.ts +27 -0
- package/src/intervalIndex/overlappingIntervalsIndex.ts +2 -6
- package/src/intervalIndex/overlappingSequenceIntervalsIndex.ts +1 -1
- package/src/intervalIndex/sequenceIntervalIndexes.ts +1 -1
- package/src/intervalIndex/startpointInRangeIndex.ts +109 -0
- package/src/intervalTree.ts +3 -75
- package/src/intervals/index.ts +25 -0
- package/src/intervals/interval.ts +230 -0
- package/src/intervals/intervalUtils.ts +256 -0
- package/src/intervals/sequenceInterval.ts +494 -0
- package/src/packageVersion.ts +1 -1
- package/src/revertibles.ts +24 -13
- package/src/sequence.ts +100 -35
- package/src/sequenceDeltaEvent.ts +12 -4
- package/src/sharedIntervalCollection.ts +2 -3
- package/src/sharedSequence.ts +11 -5
- package/src/sharedString.ts +8 -25
package/src/sequence.ts
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { assert, Deferred } from "@fluidframework/core-utils";
|
|
6
|
+
import { bufferToString } from "@fluid-internal/client-utils";
|
|
7
|
+
import { LoggingError, createChildLogger } from "@fluidframework/telemetry-utils";
|
|
7
8
|
import { ISequencedDocumentMessage, MessageType } from "@fluidframework/protocol-definitions";
|
|
8
9
|
import {
|
|
9
10
|
IChannelAttributes,
|
|
@@ -13,6 +14,7 @@ import {
|
|
|
13
14
|
import {
|
|
14
15
|
Client,
|
|
15
16
|
createAnnotateRangeOp,
|
|
17
|
+
// eslint-disable-next-line import/no-deprecated
|
|
16
18
|
createGroupOp,
|
|
17
19
|
createInsertOp,
|
|
18
20
|
createRemoveRangeOp,
|
|
@@ -46,15 +48,14 @@ import {
|
|
|
46
48
|
ISharedObjectEvents,
|
|
47
49
|
SummarySerializer,
|
|
48
50
|
} from "@fluidframework/shared-object-base";
|
|
49
|
-
import { IEventThisPlaceHolder } from "@fluidframework/
|
|
51
|
+
import { IEventThisPlaceHolder } from "@fluidframework/core-interfaces";
|
|
50
52
|
import { ISummaryTreeWithStats, ITelemetryContext } from "@fluidframework/runtime-definitions";
|
|
51
|
-
|
|
52
53
|
import { DefaultMap, IMapOperation } from "./defaultMap";
|
|
53
54
|
import { IMapMessageLocalMetadata, IValueChanged } from "./defaultMapInterfaces";
|
|
55
|
+
import { SequenceInterval } from "./intervals";
|
|
54
56
|
import {
|
|
55
57
|
IIntervalCollection,
|
|
56
58
|
IntervalCollection,
|
|
57
|
-
SequenceInterval,
|
|
58
59
|
SequenceIntervalCollectionValueType,
|
|
59
60
|
} from "./intervalCollection";
|
|
60
61
|
import { SequenceDeltaEvent, SequenceMaintenanceEvent } from "./sequenceDeltaEvent";
|
|
@@ -119,6 +120,21 @@ export abstract class SharedSegmentSequence<T extends ISegment>
|
|
|
119
120
|
return this.loadedDeferred.promise;
|
|
120
121
|
}
|
|
121
122
|
|
|
123
|
+
/**
|
|
124
|
+
* This is a safeguard to avoid problematic reentrancy of local ops. This type of scenario occurs if the user of SharedString subscribes
|
|
125
|
+
* to the `sequenceDelta` event and uses the callback for a local op to submit further local ops.
|
|
126
|
+
* Historically (before 2.0.0-internal.6.1.0), doing so would result in eventual consistency issues or a corrupted document.
|
|
127
|
+
* These issues were fixed in #16815 which makes such reentrancy no different from applying the ops in order but not from within the change events,
|
|
128
|
+
* but there is still little test coverage for reentrant scenarios.
|
|
129
|
+
* Additionally, applications submitting ops from inside change events need to take extreme care that their data models also support reentrancy.
|
|
130
|
+
* Since this is likely not the case, by default SharedString throws when encountering reentrant ops.
|
|
131
|
+
*
|
|
132
|
+
* An application using SharedString which explicitly wants to opt in to allowing reentrancy anyway can set `sharedStringPreventReentrancy`
|
|
133
|
+
* on the data store options to `false`.
|
|
134
|
+
* @internal
|
|
135
|
+
*/
|
|
136
|
+
protected guardReentrancy: <TRet>(callback: () => TRet) => TRet;
|
|
137
|
+
|
|
122
138
|
private static createOpsFromDelta(event: SequenceDeltaEvent): IMergeTreeDeltaOp[] {
|
|
123
139
|
const ops: IMergeTreeDeltaOp[] = [];
|
|
124
140
|
for (const r of event.ranges) {
|
|
@@ -194,22 +210,38 @@ export abstract class SharedSegmentSequence<T extends ISegment>
|
|
|
194
210
|
) {
|
|
195
211
|
super(id, dataStoreRuntime, attributes, "fluid_sequence_");
|
|
196
212
|
|
|
213
|
+
this.guardReentrancy =
|
|
214
|
+
dataStoreRuntime.options.sharedStringPreventReentrancy ?? true
|
|
215
|
+
? ensureNoReentrancy
|
|
216
|
+
: createReentrancyDetector((depth) => {
|
|
217
|
+
if (totalReentrancyLogs > 0) {
|
|
218
|
+
totalReentrancyLogs--;
|
|
219
|
+
this.logger.sendTelemetryEvent(
|
|
220
|
+
{ eventName: "LocalOpReentry", depth },
|
|
221
|
+
new LoggingError(reentrancyErrorMessage),
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
|
|
197
226
|
this.loadedDeferred.promise.catch((error) => {
|
|
198
227
|
this.logger.sendErrorEvent({ eventName: "SequenceLoadFailed" }, error);
|
|
199
228
|
});
|
|
200
229
|
|
|
201
230
|
this.client = new Client(
|
|
202
231
|
segmentFromSpec,
|
|
203
|
-
|
|
232
|
+
createChildLogger({
|
|
233
|
+
logger: this.logger,
|
|
234
|
+
namespace: "SharedSegmentSequence.MergeTreeClient",
|
|
235
|
+
}),
|
|
204
236
|
dataStoreRuntime.options,
|
|
205
237
|
);
|
|
206
238
|
|
|
207
|
-
this.client.
|
|
208
|
-
this.
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
);
|
|
239
|
+
this.client.prependListener("delta", (opArgs, deltaArgs) => {
|
|
240
|
+
const event = new SequenceDeltaEvent(opArgs, deltaArgs, this.client);
|
|
241
|
+
if (opArgs.stashed !== true && event.isLocal) {
|
|
242
|
+
this.submitSequenceMessage(opArgs.op);
|
|
243
|
+
}
|
|
244
|
+
this.emit("sequenceDelta", event, this);
|
|
213
245
|
});
|
|
214
246
|
|
|
215
247
|
this.client.on("maintenance", (args, opArgs) => {
|
|
@@ -230,14 +262,14 @@ export abstract class SharedSegmentSequence<T extends ISegment>
|
|
|
230
262
|
* @param end - The exclusive end of the range to remove
|
|
231
263
|
*/
|
|
232
264
|
public removeRange(start: number, end: number): IMergeTreeRemoveMsg {
|
|
233
|
-
|
|
234
|
-
this.submitSequenceMessage(removeOp);
|
|
235
|
-
return removeOp;
|
|
265
|
+
return this.guardReentrancy(() => this.client.removeRangeLocal(start, end));
|
|
236
266
|
}
|
|
237
267
|
|
|
268
|
+
/**
|
|
269
|
+
* @deprecated - The ability to create group ops will be removed in an upcoming release, as group ops are redundant with the native batching capabilities of the runtime
|
|
270
|
+
*/
|
|
238
271
|
public groupOperation(groupOp: IMergeTreeGroupMsg) {
|
|
239
|
-
this.client.localTransaction(groupOp);
|
|
240
|
-
this.submitSequenceMessage(groupOp);
|
|
272
|
+
this.guardReentrancy(() => this.client.localTransaction(groupOp));
|
|
241
273
|
}
|
|
242
274
|
|
|
243
275
|
/**
|
|
@@ -283,10 +315,7 @@ export abstract class SharedSegmentSequence<T extends ISegment>
|
|
|
283
315
|
props: PropertySet,
|
|
284
316
|
combiningOp?: ICombiningOp,
|
|
285
317
|
) {
|
|
286
|
-
|
|
287
|
-
if (annotateOp) {
|
|
288
|
-
this.submitSequenceMessage(annotateOp);
|
|
289
|
-
}
|
|
318
|
+
this.guardReentrancy(() => this.client.annotateRangeLocal(start, end, props, combiningOp));
|
|
290
319
|
}
|
|
291
320
|
|
|
292
321
|
public getPropertiesAtPosition(pos: number) {
|
|
@@ -361,6 +390,9 @@ export abstract class SharedSegmentSequence<T extends ISegment>
|
|
|
361
390
|
);
|
|
362
391
|
}
|
|
363
392
|
|
|
393
|
+
/**
|
|
394
|
+
* @deprecated - This method will no longer be public in an upcoming release as it is not safe to use outside of this class
|
|
395
|
+
*/
|
|
364
396
|
public submitSequenceMessage(message: IMergeTreeOp) {
|
|
365
397
|
if (!this.isAttached()) {
|
|
366
398
|
return;
|
|
@@ -412,12 +444,15 @@ export abstract class SharedSegmentSequence<T extends ISegment>
|
|
|
412
444
|
this.client.walkSegments(handler, start, end, accum as TClientData, splitRange);
|
|
413
445
|
}
|
|
414
446
|
|
|
447
|
+
/**
|
|
448
|
+
* @deprecated - this functionality is no longer supported and will be removed
|
|
449
|
+
*/
|
|
415
450
|
public getStackContext(startPos: number, rangeLabels: string[]): RangeStackMap {
|
|
416
451
|
return this.client.getStackContext(startPos, rangeLabels);
|
|
417
452
|
}
|
|
418
453
|
|
|
419
454
|
/**
|
|
420
|
-
* @returns
|
|
455
|
+
* @returns The most recent sequence number which has been acked by the server and processed by this
|
|
421
456
|
* SharedSegmentSequence.
|
|
422
457
|
*/
|
|
423
458
|
public getCurrentSeq() {
|
|
@@ -430,10 +465,7 @@ export abstract class SharedSegmentSequence<T extends ISegment>
|
|
|
430
465
|
* @param segment - The segment to insert
|
|
431
466
|
*/
|
|
432
467
|
public insertAtReferencePosition(pos: ReferencePosition, segment: T) {
|
|
433
|
-
|
|
434
|
-
if (insertOp) {
|
|
435
|
-
this.submitSequenceMessage(insertOp);
|
|
436
|
-
}
|
|
468
|
+
this.guardReentrancy(() => this.client.insertAtReferencePositionLocal(pos, segment));
|
|
437
469
|
}
|
|
438
470
|
/**
|
|
439
471
|
* Inserts a segment
|
|
@@ -442,10 +474,7 @@ export abstract class SharedSegmentSequence<T extends ISegment>
|
|
|
442
474
|
*/
|
|
443
475
|
public insertFromSpec(pos: number, spec: IJSONSegment) {
|
|
444
476
|
const segment = this.segmentFromSpec(spec);
|
|
445
|
-
|
|
446
|
-
if (insertOp) {
|
|
447
|
-
this.submitSequenceMessage(insertOp);
|
|
448
|
-
}
|
|
477
|
+
this.guardReentrancy(() => this.client.insertSegmentLocal(pos, segment));
|
|
449
478
|
}
|
|
450
479
|
|
|
451
480
|
/**
|
|
@@ -460,6 +489,7 @@ export abstract class SharedSegmentSequence<T extends ISegment>
|
|
|
460
489
|
* @returns An iterable object that enumerates the IntervalCollection labels.
|
|
461
490
|
*
|
|
462
491
|
* @example
|
|
492
|
+
*
|
|
463
493
|
* ```typescript
|
|
464
494
|
* const iter = this.getIntervalCollectionKeys();
|
|
465
495
|
* for (key of iter)
|
|
@@ -520,11 +550,7 @@ export abstract class SharedSegmentSequence<T extends ISegment>
|
|
|
520
550
|
const insert = this.client.insertSegmentLocal(insertIndex, segment);
|
|
521
551
|
if (insert) {
|
|
522
552
|
if (start < end) {
|
|
523
|
-
|
|
524
|
-
const op = remove ? createGroupOp(insert, remove) : insert;
|
|
525
|
-
this.submitSequenceMessage(op);
|
|
526
|
-
} else {
|
|
527
|
-
this.submitSequenceMessage(insert);
|
|
553
|
+
this.client.removeRangeLocal(start, end);
|
|
528
554
|
}
|
|
529
555
|
}
|
|
530
556
|
}
|
|
@@ -729,6 +755,7 @@ export abstract class SharedSegmentSequence<T extends ISegment>
|
|
|
729
755
|
stashMessage = {
|
|
730
756
|
...message,
|
|
731
757
|
referenceSequenceNumber: stashMessage.sequenceNumber - 1,
|
|
758
|
+
// eslint-disable-next-line import/no-deprecated
|
|
732
759
|
contents: ops.length !== 1 ? createGroupOp(...ops) : ops[0],
|
|
733
760
|
};
|
|
734
761
|
}
|
|
@@ -810,3 +837,41 @@ export abstract class SharedSegmentSequence<T extends ISegment>
|
|
|
810
837
|
}
|
|
811
838
|
}
|
|
812
839
|
}
|
|
840
|
+
|
|
841
|
+
function createReentrancyDetector(
|
|
842
|
+
onReentrancy: (depth: number) => void,
|
|
843
|
+
): <T>(callback: () => T) => T {
|
|
844
|
+
let depth = 0;
|
|
845
|
+
function detectReentrancy<T>(callback: () => T): T {
|
|
846
|
+
if (depth > 0) {
|
|
847
|
+
onReentrancy(depth);
|
|
848
|
+
}
|
|
849
|
+
depth++;
|
|
850
|
+
try {
|
|
851
|
+
return callback();
|
|
852
|
+
} finally {
|
|
853
|
+
depth--;
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
return detectReentrancy;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
/**
|
|
861
|
+
* Apps which generate reentrant behavior may do so at a high frequency.
|
|
862
|
+
* Logging even per-SharedSegmentSequence instance might be too noisy, and having a few logs from a session
|
|
863
|
+
* is likely enough.
|
|
864
|
+
*/
|
|
865
|
+
let totalReentrancyLogs = 3;
|
|
866
|
+
|
|
867
|
+
/**
|
|
868
|
+
* Resets the reentrancy log counter. Test-only API.
|
|
869
|
+
*/
|
|
870
|
+
export function resetReentrancyLogCounter() {
|
|
871
|
+
totalReentrancyLogs = 3;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
const reentrancyErrorMessage = "Reentrancy detected in sequence local ops";
|
|
875
|
+
const ensureNoReentrancy = createReentrancyDetector(() => {
|
|
876
|
+
throw new LoggingError(reentrancyErrorMessage);
|
|
877
|
+
});
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { assert } from "@fluidframework/
|
|
6
|
+
import { assert } from "@fluidframework/core-utils";
|
|
7
7
|
import {
|
|
8
8
|
Client,
|
|
9
9
|
IMergeTreeDeltaCallbackArgs,
|
|
@@ -147,25 +147,33 @@ export interface ISequenceDeltaRange<
|
|
|
147
147
|
> {
|
|
148
148
|
/**
|
|
149
149
|
* The type of operation that changed this range.
|
|
150
|
-
*
|
|
150
|
+
*
|
|
151
|
+
* @remarks Consuming code should typically compare this to the enum values defined in
|
|
151
152
|
* `MergeTreeDeltaOperationTypes`.
|
|
152
153
|
*/
|
|
153
154
|
operation: TOperation;
|
|
155
|
+
|
|
154
156
|
/**
|
|
155
157
|
* The index of the start of the range.
|
|
156
158
|
*/
|
|
157
159
|
position: number;
|
|
160
|
+
|
|
158
161
|
/**
|
|
159
162
|
* The segment that corresponds to the range.
|
|
160
163
|
*/
|
|
161
164
|
segment: ISegment;
|
|
165
|
+
|
|
162
166
|
/**
|
|
163
167
|
* Deltas object which contains all modified properties with their previous values.
|
|
164
168
|
* Since `undefined` doesn't survive a round-trip through JSON serialization, the old value being absent
|
|
165
169
|
* is instead encoded with `null`.
|
|
166
|
-
*
|
|
170
|
+
*
|
|
171
|
+
* @remarks This object is motivated by undo/redo scenarios, and provides a convenient "inverse op" to apply to
|
|
167
172
|
* undo a property change.
|
|
168
|
-
*
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
*
|
|
176
|
+
* If a segment initially had properties `{ foo: "1", bar: 2 }` and it was annotated with
|
|
169
177
|
* `{ foo: 3, baz: 5 }`, the corresponding event would have a `propertyDeltas` of `{ foo: "1", baz: null }`.
|
|
170
178
|
*/
|
|
171
179
|
propertyDeltas: PropertySet;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { bufferToString } from "@
|
|
6
|
+
import { bufferToString } from "@fluid-internal/client-utils";
|
|
7
7
|
import {
|
|
8
8
|
IChannelAttributes,
|
|
9
9
|
IFluidDataStoreRuntime,
|
|
@@ -18,12 +18,11 @@ import {
|
|
|
18
18
|
IFluidSerializer,
|
|
19
19
|
SharedObject,
|
|
20
20
|
} from "@fluidframework/shared-object-base";
|
|
21
|
+
import { Interval, ISerializableInterval } from "./intervals";
|
|
21
22
|
import {
|
|
22
|
-
Interval,
|
|
23
23
|
IntervalCollection,
|
|
24
24
|
IIntervalCollection,
|
|
25
25
|
IntervalCollectionValueType,
|
|
26
|
-
ISerializableInterval,
|
|
27
26
|
} from "./intervalCollection";
|
|
28
27
|
import { DefaultMap, IMapOperation } from "./defaultMap";
|
|
29
28
|
import { pkgVersion } from "./packageVersion";
|
package/src/sharedSequence.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { assert } from "@fluidframework/
|
|
6
|
+
import { assert } from "@fluidframework/core-utils";
|
|
7
7
|
import { BaseSegment, IJSONSegment, ISegment, PropertySet } from "@fluidframework/merge-tree";
|
|
8
8
|
import {
|
|
9
9
|
IChannelAttributes,
|
|
@@ -14,10 +14,16 @@ import { SharedSegmentSequence } from "./sequence";
|
|
|
14
14
|
|
|
15
15
|
const MaxRun = 128;
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* @deprecated - IJSONRunSegment will be removed in a upcoming release. It has been moved to the fluid-experimental/sequence-deprecated package
|
|
19
|
+
*/
|
|
17
20
|
export interface IJSONRunSegment<T> extends IJSONSegment {
|
|
18
21
|
items: Serializable<T>[];
|
|
19
22
|
}
|
|
20
23
|
|
|
24
|
+
/**
|
|
25
|
+
* @deprecated - SubSequence will be removed in a upcoming release. It has been moved to the fluid-experimental/sequence-deprecated package
|
|
26
|
+
*/
|
|
21
27
|
export class SubSequence<T> extends BaseSegment {
|
|
22
28
|
public static readonly typeString: string = "SubSequence";
|
|
23
29
|
public static is(segment: ISegment): segment is SubSequence<any> {
|
|
@@ -98,6 +104,9 @@ export class SubSequence<T> extends BaseSegment {
|
|
|
98
104
|
}
|
|
99
105
|
}
|
|
100
106
|
|
|
107
|
+
/**
|
|
108
|
+
* @deprecated - SharedSequence will be removed in a upcoming release. It has been moved to the fluid-experimental/sequence-deprecated package
|
|
109
|
+
*/
|
|
101
110
|
export class SharedSequence<T> extends SharedSegmentSequence<SubSequence<T>> {
|
|
102
111
|
constructor(
|
|
103
112
|
document: IFluidDataStoreRuntime,
|
|
@@ -118,10 +127,7 @@ export class SharedSequence<T> extends SharedSegmentSequence<SubSequence<T>> {
|
|
|
118
127
|
if (props) {
|
|
119
128
|
segment.addProperties(props);
|
|
120
129
|
}
|
|
121
|
-
|
|
122
|
-
if (insertOp) {
|
|
123
|
-
this.submitSequenceMessage(insertOp);
|
|
124
|
-
}
|
|
130
|
+
this.client.insertSegmentLocal(pos, segment);
|
|
125
131
|
}
|
|
126
132
|
|
|
127
133
|
/**
|
package/src/sharedString.ts
CHANGED
|
@@ -118,10 +118,7 @@ export class SharedString
|
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
const pos = this.posFromRelativePos(relativePos1);
|
|
121
|
-
|
|
122
|
-
if (insertOp) {
|
|
123
|
-
this.submitSequenceMessage(insertOp);
|
|
124
|
-
}
|
|
121
|
+
this.guardReentrancy(() => this.client.insertSegmentLocal(pos, segment));
|
|
125
122
|
}
|
|
126
123
|
|
|
127
124
|
/**
|
|
@@ -137,11 +134,7 @@ export class SharedString
|
|
|
137
134
|
segment.addProperties(props);
|
|
138
135
|
}
|
|
139
136
|
|
|
140
|
-
|
|
141
|
-
if (insertOp) {
|
|
142
|
-
this.submitSequenceMessage(insertOp);
|
|
143
|
-
}
|
|
144
|
-
return insertOp;
|
|
137
|
+
return this.guardReentrancy(() => this.client.insertSegmentLocal(pos, segment));
|
|
145
138
|
}
|
|
146
139
|
|
|
147
140
|
/**
|
|
@@ -157,10 +150,7 @@ export class SharedString
|
|
|
157
150
|
}
|
|
158
151
|
|
|
159
152
|
const pos = this.posFromRelativePos(relativePos1);
|
|
160
|
-
|
|
161
|
-
if (insertOp) {
|
|
162
|
-
this.submitSequenceMessage(insertOp);
|
|
163
|
-
}
|
|
153
|
+
this.guardReentrancy(() => this.client.insertSegmentLocal(pos, segment));
|
|
164
154
|
}
|
|
165
155
|
|
|
166
156
|
/**
|
|
@@ -172,10 +162,7 @@ export class SharedString
|
|
|
172
162
|
segment.addProperties(props);
|
|
173
163
|
}
|
|
174
164
|
|
|
175
|
-
|
|
176
|
-
if (insertOp) {
|
|
177
|
-
this.submitSequenceMessage(insertOp);
|
|
178
|
-
}
|
|
165
|
+
this.guardReentrancy(() => this.client.insertSegmentLocal(pos, segment));
|
|
179
166
|
}
|
|
180
167
|
|
|
181
168
|
/**
|
|
@@ -210,10 +197,9 @@ export class SharedString
|
|
|
210
197
|
props: PropertySet,
|
|
211
198
|
callback: (m: Marker) => void,
|
|
212
199
|
) {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
}
|
|
200
|
+
this.guardReentrancy(() =>
|
|
201
|
+
this.client.annotateMarkerNotifyConsensus(marker, props, callback),
|
|
202
|
+
);
|
|
217
203
|
}
|
|
218
204
|
|
|
219
205
|
/**
|
|
@@ -223,10 +209,7 @@ export class SharedString
|
|
|
223
209
|
* @param combiningOp - Optional. Specifies how to combine values for the property, such as "incr" for increment.
|
|
224
210
|
*/
|
|
225
211
|
public annotateMarker(marker: Marker, props: PropertySet, combiningOp?: ICombiningOp) {
|
|
226
|
-
|
|
227
|
-
if (annotateOp) {
|
|
228
|
-
this.submitSequenceMessage(annotateOp);
|
|
229
|
-
}
|
|
212
|
+
this.guardReentrancy(() => this.client.annotateMarker(marker, props, combiningOp));
|
|
230
213
|
}
|
|
231
214
|
|
|
232
215
|
/**
|