@fluidframework/matrix 2.41.0 → 2.42.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/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}
@@ -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/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()) {
@@ -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.setCell(rowHandle, colHandle, localSeq);
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 = [this.cells.snapshot(), this.pending.snapshot()];
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
- if (row !== undefined && col !== undefined && row >= 0 && col >= 0) {
450
- // If the mode is LWW, then send the op.
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
- if (this.fwwPolicy.state !== "on" ||
479
+ (this.fwwPolicy.state !== "on" ||
456
480
  referenceSeqNumber >=
457
- (this.fwwPolicy.cellLastWriteTracker.getCell(rowHandle, colHandle)?.seqNum ?? 0)) {
458
- this.sendSetCellOp(row, col, setOp.value, rowHandle, colHandle, localSeq);
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
- if (adjustedRow !== undefined) {
584
- const adjustedCol = this.cols.adjustPosition(col, msg);
585
- if (adjustedCol !== undefined) {
586
- const rowHandle = this.rows.getAllocatedHandle(adjustedRow);
587
- const colHandle = this.cols.getAllocatedHandle(adjustedCol);
588
- assert(isHandleValid(rowHandle) && isHandleValid(colHandle), 0x022 /* "SharedMatrix row and/or col handles are invalid!" */);
589
- if (this.fwwPolicy.state === "on") {
590
- // If someone tried to Overwrite the cell value or first write on this cell or
591
- // same client tried to modify the cell or if the previous mode was LWW, then we need to still
592
- // overwrite the cell and raise conflict if we have pending changes as our change is going to be lost.
593
- if (this.shouldSetCellBasedOnFWW(rowHandle, colHandle, msg)) {
594
- const previousValue = this.cells.getCell(rowHandle, colHandle);
595
- this.cells.setCell(rowHandle, colHandle, value);
596
- this.fwwPolicy.cellLastWriteTracker.setCell(rowHandle, colHandle, {
597
- seqNum: msg.sequenceNumber,
598
- clientId: msg.clientId,
599
- });
600
- for (const consumer of this.consumers.values()) {
601
- consumer.cellsChanged(adjustedRow, adjustedCol, 1, 1, this);
602
- }
603
- // Check is there are any pending changes, which will be rejected. If so raise conflict.
604
- if (this.pending.getCell(rowHandle, colHandle) !== undefined) {
605
- // Don't reset the pending value yet, as there maybe more fww op from same client, so we want
606
- // to raise conflict event for that op also.
607
- this.emit("conflict", row, col, value, // Current value
608
- previousValue, // Ignored local value
609
- this);
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
- else if (this.pending.getCell(rowHandle, colHandle) === undefined) {
614
- // If there is a pending (unACKed) local write to the same cell, skip the current op
615
- // since it "happened before" the pending write.
616
- this.cells.setCell(rowHandle, colHandle, value);
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++) {