@fluidframework/matrix 2.41.0 → 2.43.0-343119
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/handlecache.js +1 -1
- package/dist/handlecache.js.map +1 -1
- package/dist/matrix.d.ts +1 -9
- package/dist/matrix.d.ts.map +1 -1
- package/dist/matrix.js +118 -78
- package/dist/matrix.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.d.ts.map +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/permutationvector.d.ts +4 -1
- package/dist/permutationvector.d.ts.map +1 -1
- package/dist/permutationvector.js +36 -14
- package/dist/permutationvector.js.map +1 -1
- package/lib/handlecache.js +1 -1
- package/lib/handlecache.js.map +1 -1
- package/lib/matrix.d.ts +1 -9
- package/lib/matrix.d.ts.map +1 -1
- package/lib/matrix.js +118 -78
- package/lib/matrix.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.d.ts.map +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/permutationvector.d.ts +4 -1
- package/lib/permutationvector.d.ts.map +1 -1
- package/lib/permutationvector.js +36 -14
- package/lib/permutationvector.js.map +1 -1
- package/package.json +19 -18
- package/src/handlecache.ts +3 -3
- package/src/matrix.ts +170 -105
- package/src/packageVersion.ts +1 -1
- package/src/permutationvector.ts +47 -20
package/lib/handlecache.js
CHANGED
|
@@ -64,9 +64,9 @@ export class HandleCache {
|
|
|
64
64
|
// is that
|
|
65
65
|
const { vector } = this;
|
|
66
66
|
for (let pos = start; pos < end; pos++) {
|
|
67
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
67
68
|
const { segment, offset } = vector.getContainingSegment(pos);
|
|
68
69
|
const asPerm = segment;
|
|
69
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
70
70
|
handles.push(asPerm.start + offset);
|
|
71
71
|
}
|
|
72
72
|
}
|
package/lib/handlecache.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handlecache.js","sourceRoot":"","sources":["../src/handlecache.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,+BAA+B;AAE/B,OAAO,EAAE,MAAM,EAAE,MAAM,qCAAqC,CAAC;AAG7D,OAAO,EAAU,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEzD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC;;;;;GAKG;AACH,MAAM,OAAO,WAAW;IAIvB,YAA4B,MAAyB;QAAzB,WAAM,GAAN,MAAM,CAAmB;QAH7C,YAAO,GAAa,EAAE,CAAC;QACvB,UAAK,GAAG,CAAC,CAAC;IAEsC,CAAC;IAEzD;;;OAGG;IACK,QAAQ,CAAC,QAAgB;QAChC,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACtC,CAAC;IAED;;;;;;;OAOG;IACI,SAAS,CAAC,QAAgB;QAChC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAEtC,uFAAuF;QACvF,8BAA8B;QAE9B,oFAAoF;QACpF,qFAAqF;QACrF,uEAAuE;QAEvE,OAAO,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACrF,CAAC;IAED;;OAEG;IACI,SAAS,CAAC,QAAgB,EAAE,MAAc;QAChD,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,qCAAqC,CAAC,CAAC;QAE3E,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACtC,IAAI,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YACjC,MAAM,CACL,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EACnC,KAAK,CAAC,wEAAwE,CAC9E,CAAC;YACF,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC;QAC9B,CAAC;IACF,CAAC;IAED;;;;;OAKG;IACK,UAAU,CAAC,KAAa,EAAE,GAAW,EAAE,OAAiB;QAC/D,sFAAsF;QACtF,gBAAgB;QAEhB,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;QAExB,KAAK,IAAI,GAAG,GAAG,KAAK,EAAE,GAAG,GAAG,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC;YACxC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,oBAAoB,CAAC,GAAG,
|
|
1
|
+
{"version":3,"file":"handlecache.js","sourceRoot":"","sources":["../src/handlecache.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\n/* eslint-disable no-bitwise */\n\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport { IVectorConsumer } from \"@tiny-calc/nano\";\n\nimport { Handle, isHandleValid } from \"./handletable.js\";\nimport { PermutationSegment, PermutationVector } from \"./permutationvector.js\";\nimport { ensureRange } from \"./range.js\";\n\n/**\n * Used by PermutationVector to cache position -\\> handle lookups.\n *\n * Perf: Possibly, this should eventually be inlined into PermutationVector itself, but\n * so far there's no measurable perf penalty for being a separate object (node 12 x64)\n */\nexport class HandleCache implements IVectorConsumer<Handle> {\n\tprivate handles: Handle[] = [];\n\tprivate start = 0;\n\n\tconstructor(public readonly vector: PermutationVector) {}\n\n\t/**\n\t * Returns the index of the given position in the 'handles' array as a Uint32.\n\t * (If the position is not in the array, returns an integer greater than 'handles.length').\n\t */\n\tprivate getIndex(position: number): number {\n\t\treturn (position - this.start) >>> 0;\n\t}\n\n\t/**\n\t * Returns the handle currently assigned to the given 'position' (if any). Check\n\t * the result with 'isValidHandle(..)' to see if a handle has been allocated for\n\t * the given position.\n\t *\n\t * @throws A 'RangeError' if the provided 'position' is out-of-bounds with regards to the\n\t * PermutationVector's length.\n\t */\n\tpublic getHandle(position: number): Handle {\n\t\tconst index = this.getIndex(position);\n\n\t\t// Perf: To encourage inlining, handling of the 'cacheMiss(..)' case has been extracted\n\t\t// to a separate method.\n\n\t\t// Perf: A cache hit implies that 'position' was in bounds. Therefore, we can defer\n\t\t// checking that 'position' is in bounds until 'cacheMiss(..)'. This yields an\n\t\t// ~40% speedup when the position is in the cache (node v12 x64).\n\n\t\treturn index < this.handles.length ? this.handles[index] : this.cacheMiss(position);\n\t}\n\n\t/**\n\t * Update the cache when a handle has been allocated for a given position.\n\t */\n\tpublic addHandle(position: number, handle: Handle): void {\n\t\tassert(isHandleValid(handle), 0x017 /* \"Trying to add invalid handle!\" */);\n\n\t\tconst index = this.getIndex(position);\n\t\tif (index < this.handles.length) {\n\t\t\tassert(\n\t\t\t\t!isHandleValid(this.handles[index]),\n\t\t\t\t0x018 /* \"Trying to insert handle into position with already valid handle!\" */,\n\t\t\t);\n\t\t\tthis.handles[index] = handle;\n\t\t}\n\t}\n\n\t/**\n\t * Used by {@link HandleCache.cacheMiss} to retrieve handles for a range of positions.\n\t * @param start - The start position (inclusive).\n\t * @param end - The end position (exclusive).\n\t * @param handles - The array to populate with handles. Note that it is mutated in place.\n\t */\n\tprivate getHandles(start: number, end: number, handles: Handle[]): void {\n\t\t// TODO: This can be accelerated substantially using 'walkSegments()'. The only catch\n\t\t// is that\n\n\t\tconst { vector } = this;\n\n\t\tfor (let pos = start; pos < end; pos++) {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\tconst { segment, offset } = vector.getContainingSegment(pos)!;\n\t\t\tconst asPerm = segment as PermutationSegment;\n\t\t\thandles.push(asPerm.start + offset);\n\t\t}\n\t}\n\n\tprivate cacheMiss(position: number): Handle {\n\t\t// Coercing 'position' to an Uint32 allows us to handle a negative 'position' value\n\t\t// with the same logic that handles 'position' >= length.\n\t\tconst _position = position >>> 0;\n\n\t\t// TODO: To bound memory usage, there should be a limit on the maximum size of\n\t\t// handle[].\n\n\t\t// TODO: To reduce MergeTree lookups, this code should opportunistically grow\n\t\t// the cache to the next MergeTree segment boundary (within the limits of\n\t\t// the handle cache).\n\n\t\tif (_position < this.start) {\n\t\t\tconst handles: Handle[] = [];\n\t\t\tthis.getHandles(_position, this.start, handles);\n\t\t\thandles.push(...this.handles);\n\t\t\tthis.handles = handles;\n\t\t\tthis.start = _position;\n\t\t\treturn this.handles[0];\n\t\t} else {\n\t\t\tensureRange(_position, this.vector.getLength());\n\t\t\tthis.getHandles(this.start + this.handles.length, _position + 1, this.handles);\n\t\t\treturn this.handles[this.handles.length - 1];\n\t\t}\n\t}\n\n\t// #region IVectorConsumer\n\n\titemsChanged(start: number, removedCount: number, insertedCount: number): void {\n\t\t// If positions were inserted/removed, our current policy is to trim the array\n\t\t// at the beginning of the invalidate range and lazily repopulate the handles\n\t\t// on demand.\n\t\t//\n\t\t// Some alternatives to consider that preserve the previously cached handles\n\t\t// that are still valid:\n\t\t//\n\t\t// * Eagerly populate the 'handles[]' with the newly insert values (currently guaranteed\n\t\t// to be Handle.unallocated, so we don't even need to look them up.)\n\t\t//\n\t\t// * Use a sentinel value or other mechanism to allow \"holes\" in the cache.\n\n\t\tconst index = this.getIndex(start);\n\t\tif (index < this.handles.length) {\n\t\t\tthis.handles.length = index;\n\t\t}\n\t}\n\n\t// #endregion IVectorConsumer\n}\n"]}
|
package/lib/matrix.d.ts
CHANGED
|
@@ -206,6 +206,7 @@ export declare class SharedMatrix<T = any> extends SharedObject<ISharedMatrixEve
|
|
|
206
206
|
protected onConnect(): void;
|
|
207
207
|
private rebasePosition;
|
|
208
208
|
protected reSubmitCore(incoming: unknown, localOpMetadata: unknown): void;
|
|
209
|
+
protected rollback(content: unknown, localOpMetadata: unknown): void;
|
|
209
210
|
protected onDisconnect(): void;
|
|
210
211
|
/**
|
|
211
212
|
* {@inheritDoc @fluidframework/shared-object-base#SharedObject.loadCore}
|
|
@@ -222,15 +223,6 @@ export declare class SharedMatrix<T = any> extends SharedObject<ISharedMatrixEve
|
|
|
222
223
|
private readonly onRowHandlesRecycled;
|
|
223
224
|
private readonly onColHandlesRecycled;
|
|
224
225
|
switchSetCellPolicy(): void;
|
|
225
|
-
/**
|
|
226
|
-
* Returns true if the latest pending write to the cell indicated by the given row/col handles
|
|
227
|
-
* matches the given 'localSeq'.
|
|
228
|
-
*
|
|
229
|
-
* A return value of `true` indicates that there are no later local operations queued that will
|
|
230
|
-
* clobber the write op at the given 'localSeq'. This includes later ops that overwrite the cell
|
|
231
|
-
* with a different value as well as row/col removals that might recycled the given row/col handles.
|
|
232
|
-
*/
|
|
233
|
-
private isLatestPendingWrite;
|
|
234
226
|
toString(): string;
|
|
235
227
|
/**
|
|
236
228
|
* {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.applyStashedOp}
|
package/lib/matrix.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"matrix.d.ts","sourceRoot":"","sources":["../src/matrix.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,MAAM,EACN,qBAAqB,EACrB,KAAK,cAAc,EACnB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EACN,kBAAkB,EAClB,sBAAsB,EACtB,KAAK,QAAQ,EACb,sBAAsB,EACtB,MAAM,gDAAgD,CAAC;AACxD,OAAO,EAAE,yBAAyB,EAAE,MAAM,6CAA6C,CAAC;AACxF,OAAO,EAEN,YAAY,EAOZ,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAAE,qBAAqB,EAAE,MAAM,8CAA8C,CAAC;AAKrF,OAAO,EACN,gBAAgB,EAChB,mBAAmB,EACnB,YAAY,EACZ,MAAM,6CAA6C,CAAC;AAErD,OAAO,EACN,eAAe,EACf,eAAe,EACf,aAAa,EACb,aAAa,EACb,MAAM,iBAAiB,CAAC;AAKzB,OAAO,EAEN,UAAU,EAKV,MAAM,UAAU,CAAC;AAKlB,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAY3C;;;;GAIG;AACH,MAAM,WAAW,mBAAmB,CAAC,CAAC,CAAE,SAAQ,MAAM;IACrD;;;;;;;;;;;;;;;;;;OAkBG;IACH,CACC,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,CACT,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,UAAU,CAAC,CAAC,CAAC,EAC3B,gBAAgB,EAAE,UAAU,CAAC,CAAC,CAAC,EAC/B,MAAM,EAAE,qBAAqB,KACzB,IAAI,GACP,IAAI,CAAC;CACR;AAUD;;;GAGG;AAIH,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,GAAG,CACrC,SAAQ,cAAc,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,EAC7C,eAAe,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAC9B,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAC5B,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAC5B,QAAQ;IACT;;;;;;OAMG;IACH,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAClD;;;;;;OAMG;IACH,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAClD;;;;;;OAMG;IACH,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAClD;;;;;;OAMG;IACH,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAElD;;;;;;;;;;;OAWG;IACH,QAAQ,CACP,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,SAAS,UAAU,CAAC,CAAC,CAAC,EAAE,GAC9B,IAAI,CAAC;IAER;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;IAExC;;;OAGG;IACH,oCAAoC,IAAI,OAAO,CAAC;IAEhD;;;;;;;OAOG;IACH,mBAAmB,IAAI,IAAI,CAAC;CAC5B;
|
|
1
|
+
{"version":3,"file":"matrix.d.ts","sourceRoot":"","sources":["../src/matrix.ts"],"names":[],"mappings":"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"}
|
package/lib/matrix.js
CHANGED
|
@@ -182,18 +182,18 @@ export class SharedMatrix extends SharedObject {
|
|
|
182
182
|
}
|
|
183
183
|
}
|
|
184
184
|
}
|
|
185
|
-
setCellCore(row, col, value, rowHandle = this.rows.getAllocatedHandle(row), colHandle = this.cols.getAllocatedHandle(col)) {
|
|
185
|
+
setCellCore(row, col, value, rowHandle = this.rows.getAllocatedHandle(row), colHandle = this.cols.getAllocatedHandle(col), rollback) {
|
|
186
186
|
this.protectAgainstReentrancy(() => {
|
|
187
|
+
const oldValue = this.cells.getCell(rowHandle, colHandle) ?? undefined;
|
|
187
188
|
if (this.undo !== undefined) {
|
|
188
|
-
let oldValue = this.cells.getCell(rowHandle, colHandle);
|
|
189
|
-
if (oldValue === null) {
|
|
190
|
-
oldValue = undefined;
|
|
191
|
-
}
|
|
192
189
|
this.undo.cellSet(rowHandle, colHandle, oldValue);
|
|
193
190
|
}
|
|
194
191
|
this.cells.setCell(rowHandle, colHandle, value);
|
|
195
|
-
if (this.isAttached()) {
|
|
196
|
-
this.sendSetCellOp(row, col, value, rowHandle, colHandle);
|
|
192
|
+
if (this.isAttached() && rollback !== true) {
|
|
193
|
+
const pending = this.sendSetCellOp(row, col, value, rowHandle, colHandle);
|
|
194
|
+
if (pending.local.length === 1) {
|
|
195
|
+
pending.consensus ??= oldValue;
|
|
196
|
+
}
|
|
197
197
|
}
|
|
198
198
|
// Avoid reentrancy by raising change notifications after the op is queued.
|
|
199
199
|
for (const consumer of this.consumers.values()) {
|
|
@@ -203,7 +203,7 @@ export class SharedMatrix extends SharedObject {
|
|
|
203
203
|
}
|
|
204
204
|
createOpMetadataLocalRef(vector, pos, localSeq) {
|
|
205
205
|
const segoff = vector.getContainingSegment(pos, undefined, localSeq);
|
|
206
|
-
assert(segoff
|
|
206
|
+
assert(segoff !== undefined, 0x8b3 /* expected valid position */);
|
|
207
207
|
return vector.createLocalReferencePosition(segoff.segment, segoff.offset, ReferenceType.StayOnRemove, undefined);
|
|
208
208
|
}
|
|
209
209
|
sendSetCellOp(row, col, value, rowHandle, colHandle, localSeq = this.nextLocalSeq()) {
|
|
@@ -226,7 +226,12 @@ export class SharedMatrix extends SharedObject {
|
|
|
226
226
|
referenceSeqNumber: this.deltaManager.lastSequenceNumber,
|
|
227
227
|
};
|
|
228
228
|
this.submitLocalMessage(op, metadata);
|
|
229
|
-
this.pending.
|
|
229
|
+
const pendingCell = this.pending.getCell(rowHandle, colHandle) ?? {
|
|
230
|
+
local: [],
|
|
231
|
+
};
|
|
232
|
+
pendingCell.local.push({ localSeq, value });
|
|
233
|
+
this.pending.setCell(rowHandle, colHandle, pendingCell);
|
|
234
|
+
return pendingCell;
|
|
230
235
|
}
|
|
231
236
|
/**
|
|
232
237
|
* This makes sure that the code inside the callback is not reentrant. We need to do that because we raise notifications
|
|
@@ -364,7 +369,16 @@ export class SharedMatrix extends SharedObject {
|
|
|
364
369
|
const builder = new SummaryTreeBuilder();
|
|
365
370
|
builder.addWithStats(SnapshotPath.rows, this.rows.summarize(this.runtime, this.handle, serializer));
|
|
366
371
|
builder.addWithStats(SnapshotPath.cols, this.cols.summarize(this.runtime, this.handle, serializer));
|
|
367
|
-
const artifactsToSummarize = [
|
|
372
|
+
const artifactsToSummarize = [
|
|
373
|
+
this.cells.snapshot(),
|
|
374
|
+
/**
|
|
375
|
+
* we used to write this.pending.snapshot(). this should have never been done, as pending is only for local
|
|
376
|
+
* changes, and there should never be local changes in the summarizer. This was also never used on load
|
|
377
|
+
* as there is no way to understand a previous clients pending changes. so we just set this to a constant
|
|
378
|
+
* which matches an empty this.pending.snapshot() for back-compat in terms of the array length
|
|
379
|
+
*/
|
|
380
|
+
[undefined],
|
|
381
|
+
];
|
|
368
382
|
// Only need to store it in the snapshot if we have switched the policy already.
|
|
369
383
|
if (this.fwwPolicy.state === "on") {
|
|
370
384
|
artifactsToSummarize.push(this.fwwPolicy.switchOpSeqNumber, this.fwwPolicy.cellLastWriteTracker.snapshot());
|
|
@@ -446,31 +460,36 @@ export class SharedMatrix extends SharedObject {
|
|
|
446
460
|
const col = this.rebasePosition(this.cols, colsRef, localSeq);
|
|
447
461
|
this.rows.removeLocalReferencePosition(rowsRef);
|
|
448
462
|
this.cols.removeLocalReferencePosition(colsRef);
|
|
449
|
-
|
|
450
|
-
|
|
463
|
+
const pendingCell = this.pending.getCell(rowHandle, colHandle);
|
|
464
|
+
assert(pendingCell !== undefined, 0xba4 /* local operation must have a pending array */);
|
|
465
|
+
const { local } = pendingCell;
|
|
466
|
+
assert(local !== undefined, 0xba5 /* local operation must have a pending array */);
|
|
467
|
+
const localSeqIndex = local.findIndex((p) => p.localSeq === localSeq);
|
|
468
|
+
assert(localSeqIndex >= 0, 0xba6 /* local operation must have a pending entry */);
|
|
469
|
+
const [change] = local.splice(localSeqIndex, 1);
|
|
470
|
+
assert(change.localSeq === localSeq, 0xba7 /* must match */);
|
|
471
|
+
if (row !== undefined &&
|
|
472
|
+
col !== undefined &&
|
|
473
|
+
row >= 0 &&
|
|
474
|
+
col >= 0 && // If the mode is LWW, then send the op.
|
|
451
475
|
// Otherwise if the current mode is FWW and if we generated this op, after seeing the
|
|
452
476
|
// last set op, or it is the first set op for the cell, then regenerate the op,
|
|
453
477
|
// otherwise raise conflict. We want to check the current mode here and not that
|
|
454
478
|
// whether op was made in FWW or not.
|
|
455
|
-
|
|
479
|
+
(this.fwwPolicy.state !== "on" ||
|
|
456
480
|
referenceSeqNumber >=
|
|
457
|
-
(this.fwwPolicy.cellLastWriteTracker.getCell(rowHandle, colHandle)?.seqNum ?? 0)) {
|
|
458
|
-
|
|
459
|
-
}
|
|
460
|
-
else if (this.pending.getCell(rowHandle, colHandle) !== undefined) {
|
|
461
|
-
// Clear the pending changes if any as we are not sending the op.
|
|
462
|
-
this.pending.setCell(rowHandle, colHandle, undefined);
|
|
463
|
-
}
|
|
481
|
+
(this.fwwPolicy.cellLastWriteTracker.getCell(rowHandle, colHandle)?.seqNum ?? 0))) {
|
|
482
|
+
this.sendSetCellOp(row, col, setOp.value, rowHandle, colHandle, localSeq);
|
|
464
483
|
}
|
|
465
484
|
}
|
|
466
485
|
else {
|
|
467
486
|
switch (content.target) {
|
|
468
487
|
case SnapshotPath.cols: {
|
|
469
|
-
this.submitColMessage(this.cols.regeneratePendingOp(content, localOpMetadata));
|
|
488
|
+
this.submitColMessage(this.cols.regeneratePendingOp(content, localOpMetadata, false));
|
|
470
489
|
break;
|
|
471
490
|
}
|
|
472
491
|
case SnapshotPath.rows: {
|
|
473
|
-
this.submitRowMessage(this.rows.regeneratePendingOp(content, localOpMetadata));
|
|
492
|
+
this.submitRowMessage(this.rows.regeneratePendingOp(content, localOpMetadata, false));
|
|
474
493
|
break;
|
|
475
494
|
}
|
|
476
495
|
default: {
|
|
@@ -479,6 +498,33 @@ export class SharedMatrix extends SharedObject {
|
|
|
479
498
|
}
|
|
480
499
|
}
|
|
481
500
|
}
|
|
501
|
+
rollback(content, localOpMetadata) {
|
|
502
|
+
const contents = content;
|
|
503
|
+
const target = contents.target;
|
|
504
|
+
switch (target) {
|
|
505
|
+
case SnapshotPath.cols: {
|
|
506
|
+
this.cols.rollback(content, localOpMetadata);
|
|
507
|
+
break;
|
|
508
|
+
}
|
|
509
|
+
case SnapshotPath.rows: {
|
|
510
|
+
this.rows.rollback(content, localOpMetadata);
|
|
511
|
+
break;
|
|
512
|
+
}
|
|
513
|
+
case undefined: {
|
|
514
|
+
assert(contents.type === MatrixOp.set, 0xba8 /* only sets supported */);
|
|
515
|
+
const setMetadata = localOpMetadata;
|
|
516
|
+
const pendingCell = this.pending.getCell(setMetadata.rowHandle, setMetadata.colHandle);
|
|
517
|
+
assert(pendingCell !== undefined, 0xba9 /* must have pending */);
|
|
518
|
+
const change = pendingCell.local.pop();
|
|
519
|
+
assert(change?.localSeq === setMetadata.localSeq, 0xbaa /* must have change */);
|
|
520
|
+
const previous = pendingCell.local.length > 0
|
|
521
|
+
? pendingCell.local[pendingCell.local.length - 1].value
|
|
522
|
+
: pendingCell.consensus;
|
|
523
|
+
this.setCellCore(contents.row, contents.col, previous, setMetadata.rowHandle, setMetadata.colHandle, true);
|
|
524
|
+
}
|
|
525
|
+
default:
|
|
526
|
+
}
|
|
527
|
+
}
|
|
482
528
|
onDisconnect() { }
|
|
483
529
|
/**
|
|
484
530
|
* {@inheritDoc @fluidframework/shared-object-base#SharedObject.loadCore}
|
|
@@ -562,63 +608,76 @@ export class SharedMatrix extends SharedObject {
|
|
|
562
608
|
if (local) {
|
|
563
609
|
// We are receiving the ACK for a local pending set operation.
|
|
564
610
|
const { rowHandle, colHandle, localSeq, rowsRef, colsRef } = localOpMetadata;
|
|
565
|
-
const isLatestPendingOp = this.isLatestPendingWrite(rowHandle, colHandle, localSeq);
|
|
566
611
|
this.rows.removeLocalReferencePosition(rowsRef);
|
|
567
612
|
this.cols.removeLocalReferencePosition(colsRef);
|
|
613
|
+
const pendingCell = this.pending.getCell(rowHandle, colHandle);
|
|
614
|
+
const ackedChange = pendingCell?.local.shift();
|
|
615
|
+
assert(ackedChange?.localSeq === localSeq, 0xbab /* must match */);
|
|
616
|
+
if (pendingCell?.local.length === 0) {
|
|
617
|
+
this.pending.setCell(rowHandle, colHandle, undefined);
|
|
618
|
+
}
|
|
568
619
|
// If policy is switched and cell should be modified too based on policy, then update the tracker.
|
|
569
620
|
// If policy is not switched, then also update the tracker in case it is the latest.
|
|
570
621
|
if (this.fwwPolicy.state === "on" &&
|
|
571
622
|
this.shouldSetCellBasedOnFWW(rowHandle, colHandle, msg)) {
|
|
623
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
624
|
+
pendingCell.consensus = ackedChange.value;
|
|
572
625
|
this.fwwPolicy.cellLastWriteTracker.setCell(rowHandle, colHandle, {
|
|
573
626
|
seqNum: msg.sequenceNumber,
|
|
574
627
|
clientId: msg.clientId,
|
|
575
628
|
});
|
|
576
629
|
}
|
|
577
|
-
if (isLatestPendingOp) {
|
|
578
|
-
this.pending.setCell(rowHandle, colHandle, undefined);
|
|
579
|
-
}
|
|
580
630
|
}
|
|
581
631
|
else {
|
|
582
632
|
const adjustedRow = this.rows.adjustPosition(row, msg);
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
633
|
+
const adjustedCol = this.cols.adjustPosition(col, msg);
|
|
634
|
+
const rowHandle = adjustedRow.handle;
|
|
635
|
+
const colHandle = adjustedCol.handle;
|
|
636
|
+
assert(isHandleValid(rowHandle) && isHandleValid(colHandle), 0x022 /* "SharedMatrix row and/or col handles are invalid!" */);
|
|
637
|
+
const pendingCell = this.pending.getCell(rowHandle, colHandle);
|
|
638
|
+
if (this.fwwPolicy.state === "on") {
|
|
639
|
+
// If someone tried to Overwrite the cell value or first write on this cell or
|
|
640
|
+
// same client tried to modify the cell or if the previous mode was LWW, then we need to still
|
|
641
|
+
// overwrite the cell and raise conflict if we have pending changes as our change is going to be lost.
|
|
642
|
+
if (this.shouldSetCellBasedOnFWW(rowHandle, colHandle, msg)) {
|
|
643
|
+
const previousValue = this.cells.getCell(rowHandle, colHandle);
|
|
644
|
+
this.cells.setCell(rowHandle, colHandle, value);
|
|
645
|
+
this.fwwPolicy.cellLastWriteTracker.setCell(rowHandle, colHandle, {
|
|
646
|
+
seqNum: msg.sequenceNumber,
|
|
647
|
+
clientId: msg.clientId,
|
|
648
|
+
});
|
|
649
|
+
if (pendingCell !== undefined) {
|
|
650
|
+
pendingCell.consensus = value;
|
|
651
|
+
}
|
|
652
|
+
if (adjustedRow.pos !== undefined && adjustedCol.pos !== undefined) {
|
|
653
|
+
for (const consumer of this.consumers.values()) {
|
|
654
|
+
consumer.cellsChanged(adjustedRow.pos, adjustedCol.pos, 1, 1, this);
|
|
655
|
+
}
|
|
656
|
+
// Check is there are any pending changes, which will be rejected. If so raise conflict.
|
|
657
|
+
if (pendingCell !== undefined && pendingCell.local.length > 0) {
|
|
658
|
+
// Don't reset the pending value yet, as there maybe more fww op from same client, so we want
|
|
659
|
+
// to raise conflict event for that op also.
|
|
660
|
+
this.emit("conflict", row, col, value, // Current value
|
|
661
|
+
previousValue, // Ignored local value
|
|
662
|
+
this);
|
|
611
663
|
}
|
|
612
664
|
}
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
else {
|
|
668
|
+
if (pendingCell === undefined || pendingCell.local.length === 0) {
|
|
669
|
+
// If there is a pending (unACKed) local write to the same cell, skip the current op
|
|
670
|
+
// since it "happened before" the pending write.
|
|
671
|
+
this.cells.setCell(rowHandle, colHandle, value);
|
|
672
|
+
if (adjustedRow.pos !== undefined && adjustedCol.pos !== undefined) {
|
|
617
673
|
for (const consumer of this.consumers.values()) {
|
|
618
|
-
consumer.cellsChanged(adjustedRow, adjustedCol, 1, 1, this);
|
|
674
|
+
consumer.cellsChanged(adjustedRow.pos, adjustedCol.pos, 1, 1, this);
|
|
619
675
|
}
|
|
620
676
|
}
|
|
621
677
|
}
|
|
678
|
+
else {
|
|
679
|
+
pendingCell.consensus = value;
|
|
680
|
+
}
|
|
622
681
|
}
|
|
623
682
|
}
|
|
624
683
|
break;
|
|
@@ -639,25 +698,6 @@ export class SharedMatrix extends SharedObject {
|
|
|
639
698
|
};
|
|
640
699
|
}
|
|
641
700
|
}
|
|
642
|
-
/**
|
|
643
|
-
* Returns true if the latest pending write to the cell indicated by the given row/col handles
|
|
644
|
-
* matches the given 'localSeq'.
|
|
645
|
-
*
|
|
646
|
-
* A return value of `true` indicates that there are no later local operations queued that will
|
|
647
|
-
* clobber the write op at the given 'localSeq'. This includes later ops that overwrite the cell
|
|
648
|
-
* with a different value as well as row/col removals that might recycled the given row/col handles.
|
|
649
|
-
*/
|
|
650
|
-
isLatestPendingWrite(rowHandle, colHandle, localSeq) {
|
|
651
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
652
|
-
const pendingLocalSeq = this.pending.getCell(rowHandle, colHandle);
|
|
653
|
-
// Note while we're awaiting the ACK for a local set, it's possible for the row/col to be
|
|
654
|
-
// locally removed and the row/col handles recycled. If this happens, the pendingLocalSeq will
|
|
655
|
-
// be 'undefined' or > 'localSeq'.
|
|
656
|
-
assert(!(pendingLocalSeq < localSeq), 0x023 /* "The 'localSeq' of pending write (if any) must be <= the localSeq of the currently processed op." */);
|
|
657
|
-
// If this is the most recent write to the cell by the local client, the stored localSeq
|
|
658
|
-
// will be an exact match for the given 'localSeq'.
|
|
659
|
-
return pendingLocalSeq === localSeq;
|
|
660
|
-
}
|
|
661
701
|
toString() {
|
|
662
702
|
let s = `client:${this.runtime.clientId}\nrows: ${this.rows.toString()}\ncols: ${this.cols.toString()}\n\n`;
|
|
663
703
|
for (let r = 0; r < this.rowCount; r++) {
|