@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 CHANGED
@@ -1,5 +1,9 @@
1
1
  # @fluidframework/matrix
2
2
 
3
+ ## 2.42.0
4
+
5
+ Dependency updates only.
6
+
3
7
  ## 2.41.0
4
8
 
5
9
  Dependency updates only.
@@ -67,9 +67,9 @@ class HandleCache {
67
67
  // is that
68
68
  const { vector } = this;
69
69
  for (let pos = start; pos < end; pos++) {
70
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
70
71
  const { segment, offset } = vector.getContainingSegment(pos);
71
72
  const asPerm = segment;
72
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
73
73
  handles.push(asPerm.start + offset);
74
74
  }
75
75
  }
@@ -1 +1 @@
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\tconst { segment, offset } = vector.getContainingSegment(pos);\n\t\t\tconst asPerm = segment as PermutationSegment;\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\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"]}
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/dist/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}
@@ -1 +1 @@
1
- {"version":3,"file":"matrix.d.ts","sourceRoot":"","sources":["../src/matrix.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"matrix.d.ts","sourceRoot":"","sources":["../src/matrix.ts"],"names":[],"mappings":"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"}
package/dist/matrix.js CHANGED
@@ -188,18 +188,18 @@ class SharedMatrix extends internal_4.SharedObject {
188
188
  }
189
189
  }
190
190
  }
191
- setCellCore(row, col, value, rowHandle = this.rows.getAllocatedHandle(row), colHandle = this.cols.getAllocatedHandle(col)) {
191
+ setCellCore(row, col, value, rowHandle = this.rows.getAllocatedHandle(row), colHandle = this.cols.getAllocatedHandle(col), rollback) {
192
192
  this.protectAgainstReentrancy(() => {
193
+ const oldValue = this.cells.getCell(rowHandle, colHandle) ?? undefined;
193
194
  if (this.undo !== undefined) {
194
- let oldValue = this.cells.getCell(rowHandle, colHandle);
195
- if (oldValue === null) {
196
- oldValue = undefined;
197
- }
198
195
  this.undo.cellSet(rowHandle, colHandle, oldValue);
199
196
  }
200
197
  this.cells.setCell(rowHandle, colHandle, value);
201
- if (this.isAttached()) {
202
- this.sendSetCellOp(row, col, value, rowHandle, colHandle);
198
+ if (this.isAttached() && rollback !== true) {
199
+ const pending = this.sendSetCellOp(row, col, value, rowHandle, colHandle);
200
+ if (pending.local.length === 1) {
201
+ pending.consensus ??= oldValue;
202
+ }
203
203
  }
204
204
  // Avoid reentrancy by raising change notifications after the op is queued.
205
205
  for (const consumer of this.consumers.values()) {
@@ -209,7 +209,7 @@ class SharedMatrix extends internal_4.SharedObject {
209
209
  }
210
210
  createOpMetadataLocalRef(vector, pos, localSeq) {
211
211
  const segoff = vector.getContainingSegment(pos, undefined, localSeq);
212
- (0, internal_1.assert)(segoff.segment !== undefined && segoff.offset !== undefined, 0x8b3 /* expected valid position */);
212
+ (0, internal_1.assert)(segoff !== undefined, 0x8b3 /* expected valid position */);
213
213
  return vector.createLocalReferencePosition(segoff.segment, segoff.offset, internal_2.ReferenceType.StayOnRemove, undefined);
214
214
  }
215
215
  sendSetCellOp(row, col, value, rowHandle, colHandle, localSeq = this.nextLocalSeq()) {
@@ -232,7 +232,12 @@ class SharedMatrix extends internal_4.SharedObject {
232
232
  referenceSeqNumber: this.deltaManager.lastSequenceNumber,
233
233
  };
234
234
  this.submitLocalMessage(op, metadata);
235
- this.pending.setCell(rowHandle, colHandle, localSeq);
235
+ const pendingCell = this.pending.getCell(rowHandle, colHandle) ?? {
236
+ local: [],
237
+ };
238
+ pendingCell.local.push({ localSeq, value });
239
+ this.pending.setCell(rowHandle, colHandle, pendingCell);
240
+ return pendingCell;
236
241
  }
237
242
  /**
238
243
  * This makes sure that the code inside the callback is not reentrant. We need to do that because we raise notifications
@@ -370,7 +375,16 @@ class SharedMatrix extends internal_4.SharedObject {
370
375
  const builder = new internal_3.SummaryTreeBuilder();
371
376
  builder.addWithStats(ops_js_1.SnapshotPath.rows, this.rows.summarize(this.runtime, this.handle, serializer));
372
377
  builder.addWithStats(ops_js_1.SnapshotPath.cols, this.cols.summarize(this.runtime, this.handle, serializer));
373
- const artifactsToSummarize = [this.cells.snapshot(), this.pending.snapshot()];
378
+ const artifactsToSummarize = [
379
+ this.cells.snapshot(),
380
+ /**
381
+ * we used to write this.pending.snapshot(). this should have never been done, as pending is only for local
382
+ * changes, and there should never be local changes in the summarizer. This was also never used on load
383
+ * as there is no way to understand a previous clients pending changes. so we just set this to a constant
384
+ * which matches an empty this.pending.snapshot() for back-compat in terms of the array length
385
+ */
386
+ [undefined],
387
+ ];
374
388
  // Only need to store it in the snapshot if we have switched the policy already.
375
389
  if (this.fwwPolicy.state === "on") {
376
390
  artifactsToSummarize.push(this.fwwPolicy.switchOpSeqNumber, this.fwwPolicy.cellLastWriteTracker.snapshot());
@@ -452,31 +466,36 @@ class SharedMatrix extends internal_4.SharedObject {
452
466
  const col = this.rebasePosition(this.cols, colsRef, localSeq);
453
467
  this.rows.removeLocalReferencePosition(rowsRef);
454
468
  this.cols.removeLocalReferencePosition(colsRef);
455
- if (row !== undefined && col !== undefined && row >= 0 && col >= 0) {
456
- // If the mode is LWW, then send the op.
469
+ const pendingCell = this.pending.getCell(rowHandle, colHandle);
470
+ (0, internal_1.assert)(pendingCell !== undefined, 0xba4 /* local operation must have a pending array */);
471
+ const { local } = pendingCell;
472
+ (0, internal_1.assert)(local !== undefined, 0xba5 /* local operation must have a pending array */);
473
+ const localSeqIndex = local.findIndex((p) => p.localSeq === localSeq);
474
+ (0, internal_1.assert)(localSeqIndex >= 0, 0xba6 /* local operation must have a pending entry */);
475
+ const [change] = local.splice(localSeqIndex, 1);
476
+ (0, internal_1.assert)(change.localSeq === localSeq, 0xba7 /* must match */);
477
+ if (row !== undefined &&
478
+ col !== undefined &&
479
+ row >= 0 &&
480
+ col >= 0 && // If the mode is LWW, then send the op.
457
481
  // Otherwise if the current mode is FWW and if we generated this op, after seeing the
458
482
  // last set op, or it is the first set op for the cell, then regenerate the op,
459
483
  // otherwise raise conflict. We want to check the current mode here and not that
460
484
  // whether op was made in FWW or not.
461
- if (this.fwwPolicy.state !== "on" ||
485
+ (this.fwwPolicy.state !== "on" ||
462
486
  referenceSeqNumber >=
463
- (this.fwwPolicy.cellLastWriteTracker.getCell(rowHandle, colHandle)?.seqNum ?? 0)) {
464
- this.sendSetCellOp(row, col, setOp.value, rowHandle, colHandle, localSeq);
465
- }
466
- else if (this.pending.getCell(rowHandle, colHandle) !== undefined) {
467
- // Clear the pending changes if any as we are not sending the op.
468
- this.pending.setCell(rowHandle, colHandle, undefined);
469
- }
487
+ (this.fwwPolicy.cellLastWriteTracker.getCell(rowHandle, colHandle)?.seqNum ?? 0))) {
488
+ this.sendSetCellOp(row, col, setOp.value, rowHandle, colHandle, localSeq);
470
489
  }
471
490
  }
472
491
  else {
473
492
  switch (content.target) {
474
493
  case ops_js_1.SnapshotPath.cols: {
475
- this.submitColMessage(this.cols.regeneratePendingOp(content, localOpMetadata));
494
+ this.submitColMessage(this.cols.regeneratePendingOp(content, localOpMetadata, false));
476
495
  break;
477
496
  }
478
497
  case ops_js_1.SnapshotPath.rows: {
479
- this.submitRowMessage(this.rows.regeneratePendingOp(content, localOpMetadata));
498
+ this.submitRowMessage(this.rows.regeneratePendingOp(content, localOpMetadata, false));
480
499
  break;
481
500
  }
482
501
  default: {
@@ -485,6 +504,33 @@ class SharedMatrix extends internal_4.SharedObject {
485
504
  }
486
505
  }
487
506
  }
507
+ rollback(content, localOpMetadata) {
508
+ const contents = content;
509
+ const target = contents.target;
510
+ switch (target) {
511
+ case ops_js_1.SnapshotPath.cols: {
512
+ this.cols.rollback(content, localOpMetadata);
513
+ break;
514
+ }
515
+ case ops_js_1.SnapshotPath.rows: {
516
+ this.rows.rollback(content, localOpMetadata);
517
+ break;
518
+ }
519
+ case undefined: {
520
+ (0, internal_1.assert)(contents.type === ops_js_1.MatrixOp.set, 0xba8 /* only sets supported */);
521
+ const setMetadata = localOpMetadata;
522
+ const pendingCell = this.pending.getCell(setMetadata.rowHandle, setMetadata.colHandle);
523
+ (0, internal_1.assert)(pendingCell !== undefined, 0xba9 /* must have pending */);
524
+ const change = pendingCell.local.pop();
525
+ (0, internal_1.assert)(change?.localSeq === setMetadata.localSeq, 0xbaa /* must have change */);
526
+ const previous = pendingCell.local.length > 0
527
+ ? pendingCell.local[pendingCell.local.length - 1].value
528
+ : pendingCell.consensus;
529
+ this.setCellCore(contents.row, contents.col, previous, setMetadata.rowHandle, setMetadata.colHandle, true);
530
+ }
531
+ default:
532
+ }
533
+ }
488
534
  onDisconnect() { }
489
535
  /**
490
536
  * {@inheritDoc @fluidframework/shared-object-base#SharedObject.loadCore}
@@ -568,63 +614,76 @@ class SharedMatrix extends internal_4.SharedObject {
568
614
  if (local) {
569
615
  // We are receiving the ACK for a local pending set operation.
570
616
  const { rowHandle, colHandle, localSeq, rowsRef, colsRef } = localOpMetadata;
571
- const isLatestPendingOp = this.isLatestPendingWrite(rowHandle, colHandle, localSeq);
572
617
  this.rows.removeLocalReferencePosition(rowsRef);
573
618
  this.cols.removeLocalReferencePosition(colsRef);
619
+ const pendingCell = this.pending.getCell(rowHandle, colHandle);
620
+ const ackedChange = pendingCell?.local.shift();
621
+ (0, internal_1.assert)(ackedChange?.localSeq === localSeq, 0xbab /* must match */);
622
+ if (pendingCell?.local.length === 0) {
623
+ this.pending.setCell(rowHandle, colHandle, undefined);
624
+ }
574
625
  // If policy is switched and cell should be modified too based on policy, then update the tracker.
575
626
  // If policy is not switched, then also update the tracker in case it is the latest.
576
627
  if (this.fwwPolicy.state === "on" &&
577
628
  this.shouldSetCellBasedOnFWW(rowHandle, colHandle, msg)) {
629
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
630
+ pendingCell.consensus = ackedChange.value;
578
631
  this.fwwPolicy.cellLastWriteTracker.setCell(rowHandle, colHandle, {
579
632
  seqNum: msg.sequenceNumber,
580
633
  clientId: msg.clientId,
581
634
  });
582
635
  }
583
- if (isLatestPendingOp) {
584
- this.pending.setCell(rowHandle, colHandle, undefined);
585
- }
586
636
  }
587
637
  else {
588
638
  const adjustedRow = this.rows.adjustPosition(row, msg);
589
- if (adjustedRow !== undefined) {
590
- const adjustedCol = this.cols.adjustPosition(col, msg);
591
- if (adjustedCol !== undefined) {
592
- const rowHandle = this.rows.getAllocatedHandle(adjustedRow);
593
- const colHandle = this.cols.getAllocatedHandle(adjustedCol);
594
- (0, internal_1.assert)((0, handletable_js_1.isHandleValid)(rowHandle) && (0, handletable_js_1.isHandleValid)(colHandle), 0x022 /* "SharedMatrix row and/or col handles are invalid!" */);
595
- if (this.fwwPolicy.state === "on") {
596
- // If someone tried to Overwrite the cell value or first write on this cell or
597
- // same client tried to modify the cell or if the previous mode was LWW, then we need to still
598
- // overwrite the cell and raise conflict if we have pending changes as our change is going to be lost.
599
- if (this.shouldSetCellBasedOnFWW(rowHandle, colHandle, msg)) {
600
- const previousValue = this.cells.getCell(rowHandle, colHandle);
601
- this.cells.setCell(rowHandle, colHandle, value);
602
- this.fwwPolicy.cellLastWriteTracker.setCell(rowHandle, colHandle, {
603
- seqNum: msg.sequenceNumber,
604
- clientId: msg.clientId,
605
- });
606
- for (const consumer of this.consumers.values()) {
607
- consumer.cellsChanged(adjustedRow, adjustedCol, 1, 1, this);
608
- }
609
- // Check is there are any pending changes, which will be rejected. If so raise conflict.
610
- if (this.pending.getCell(rowHandle, colHandle) !== undefined) {
611
- // Don't reset the pending value yet, as there maybe more fww op from same client, so we want
612
- // to raise conflict event for that op also.
613
- this.emit("conflict", row, col, value, // Current value
614
- previousValue, // Ignored local value
615
- this);
616
- }
639
+ const adjustedCol = this.cols.adjustPosition(col, msg);
640
+ const rowHandle = adjustedRow.handle;
641
+ const colHandle = adjustedCol.handle;
642
+ (0, internal_1.assert)((0, handletable_js_1.isHandleValid)(rowHandle) && (0, handletable_js_1.isHandleValid)(colHandle), 0x022 /* "SharedMatrix row and/or col handles are invalid!" */);
643
+ const pendingCell = this.pending.getCell(rowHandle, colHandle);
644
+ if (this.fwwPolicy.state === "on") {
645
+ // If someone tried to Overwrite the cell value or first write on this cell or
646
+ // same client tried to modify the cell or if the previous mode was LWW, then we need to still
647
+ // overwrite the cell and raise conflict if we have pending changes as our change is going to be lost.
648
+ if (this.shouldSetCellBasedOnFWW(rowHandle, colHandle, msg)) {
649
+ const previousValue = this.cells.getCell(rowHandle, colHandle);
650
+ this.cells.setCell(rowHandle, colHandle, value);
651
+ this.fwwPolicy.cellLastWriteTracker.setCell(rowHandle, colHandle, {
652
+ seqNum: msg.sequenceNumber,
653
+ clientId: msg.clientId,
654
+ });
655
+ if (pendingCell !== undefined) {
656
+ pendingCell.consensus = value;
657
+ }
658
+ if (adjustedRow.pos !== undefined && adjustedCol.pos !== undefined) {
659
+ for (const consumer of this.consumers.values()) {
660
+ consumer.cellsChanged(adjustedRow.pos, adjustedCol.pos, 1, 1, this);
661
+ }
662
+ // Check is there are any pending changes, which will be rejected. If so raise conflict.
663
+ if (pendingCell !== undefined && pendingCell.local.length > 0) {
664
+ // Don't reset the pending value yet, as there maybe more fww op from same client, so we want
665
+ // to raise conflict event for that op also.
666
+ this.emit("conflict", row, col, value, // Current value
667
+ previousValue, // Ignored local value
668
+ this);
617
669
  }
618
670
  }
619
- else if (this.pending.getCell(rowHandle, colHandle) === undefined) {
620
- // If there is a pending (unACKed) local write to the same cell, skip the current op
621
- // since it "happened before" the pending write.
622
- this.cells.setCell(rowHandle, colHandle, value);
671
+ }
672
+ }
673
+ else {
674
+ if (pendingCell === undefined || pendingCell.local.length === 0) {
675
+ // If there is a pending (unACKed) local write to the same cell, skip the current op
676
+ // since it "happened before" the pending write.
677
+ this.cells.setCell(rowHandle, colHandle, value);
678
+ if (adjustedRow.pos !== undefined && adjustedCol.pos !== undefined) {
623
679
  for (const consumer of this.consumers.values()) {
624
- consumer.cellsChanged(adjustedRow, adjustedCol, 1, 1, this);
680
+ consumer.cellsChanged(adjustedRow.pos, adjustedCol.pos, 1, 1, this);
625
681
  }
626
682
  }
627
683
  }
684
+ else {
685
+ pendingCell.consensus = value;
686
+ }
628
687
  }
629
688
  }
630
689
  break;
@@ -645,25 +704,6 @@ class SharedMatrix extends internal_4.SharedObject {
645
704
  };
646
705
  }
647
706
  }
648
- /**
649
- * Returns true if the latest pending write to the cell indicated by the given row/col handles
650
- * matches the given 'localSeq'.
651
- *
652
- * A return value of `true` indicates that there are no later local operations queued that will
653
- * clobber the write op at the given 'localSeq'. This includes later ops that overwrite the cell
654
- * with a different value as well as row/col removals that might recycled the given row/col handles.
655
- */
656
- isLatestPendingWrite(rowHandle, colHandle, localSeq) {
657
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
658
- const pendingLocalSeq = this.pending.getCell(rowHandle, colHandle);
659
- // Note while we're awaiting the ACK for a local set, it's possible for the row/col to be
660
- // locally removed and the row/col handles recycled. If this happens, the pendingLocalSeq will
661
- // be 'undefined' or > 'localSeq'.
662
- (0, internal_1.assert)(!(pendingLocalSeq < localSeq), 0x023 /* "The 'localSeq' of pending write (if any) must be <= the localSeq of the currently processed op." */);
663
- // If this is the most recent write to the cell by the local client, the stored localSeq
664
- // will be an exact match for the given 'localSeq'.
665
- return pendingLocalSeq === localSeq;
666
- }
667
707
  toString() {
668
708
  let s = `client:${this.runtime.clientId}\nrows: ${this.rows.toString()}\ncols: ${this.cols.toString()}\n\n`;
669
709
  for (let r = 0; r < this.rowCount; r++) {