@fluidframework/matrix 2.0.0-dev.7.4.0.217212 → 2.0.0-dev.7.4.0.221926

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.
Files changed (67) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +39 -0
  3. package/api-extractor.json +0 -3
  4. package/api-report/matrix.api.md +17 -7
  5. package/dist/index.cjs.map +1 -1
  6. package/dist/index.d.ts +1 -1
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/matrix-alpha.d.ts +207 -34
  9. package/dist/matrix-beta.d.ts +20 -0
  10. package/dist/matrix-public.d.ts +20 -0
  11. package/dist/matrix-untrimmed.d.ts +69 -8
  12. package/dist/matrix.cjs +173 -43
  13. package/dist/matrix.cjs.map +1 -1
  14. package/dist/matrix.d.ts +65 -6
  15. package/dist/matrix.d.ts.map +1 -1
  16. package/dist/ops.cjs +1 -0
  17. package/dist/ops.cjs.map +1 -1
  18. package/dist/ops.d.ts +5 -1
  19. package/dist/ops.d.ts.map +1 -1
  20. package/dist/packageVersion.cjs +1 -1
  21. package/dist/packageVersion.cjs.map +1 -1
  22. package/dist/packageVersion.d.ts +1 -1
  23. package/dist/runtime.cjs +1 -1
  24. package/dist/runtime.cjs.map +1 -1
  25. package/dist/runtime.d.ts +1 -1
  26. package/dist/types.cjs.map +1 -1
  27. package/dist/types.d.ts +2 -2
  28. package/lib/handlecache.d.ts +2 -2
  29. package/lib/handlecache.d.ts.map +1 -1
  30. package/lib/index.d.ts +3 -3
  31. package/lib/index.d.ts.map +1 -1
  32. package/lib/index.mjs.map +1 -1
  33. package/lib/matrix-alpha.d.ts +207 -34
  34. package/lib/matrix-beta.d.ts +20 -0
  35. package/lib/matrix-public.d.ts +20 -0
  36. package/lib/matrix-untrimmed.d.ts +69 -8
  37. package/lib/matrix.d.ts +67 -8
  38. package/lib/matrix.d.ts.map +1 -1
  39. package/lib/matrix.mjs +173 -43
  40. package/lib/matrix.mjs.map +1 -1
  41. package/lib/ops.d.ts +5 -1
  42. package/lib/ops.d.ts.map +1 -1
  43. package/lib/ops.mjs +1 -0
  44. package/lib/ops.mjs.map +1 -1
  45. package/lib/packageVersion.d.ts +1 -1
  46. package/lib/packageVersion.mjs +1 -1
  47. package/lib/packageVersion.mjs.map +1 -1
  48. package/lib/permutationvector.d.ts +3 -3
  49. package/lib/permutationvector.d.ts.map +1 -1
  50. package/lib/runtime.d.ts +1 -1
  51. package/lib/runtime.d.ts.map +1 -1
  52. package/lib/runtime.mjs +1 -1
  53. package/lib/runtime.mjs.map +1 -1
  54. package/lib/serialization.d.ts.map +1 -1
  55. package/lib/sparsearray2d.d.ts.map +1 -1
  56. package/lib/types.d.ts +2 -2
  57. package/lib/types.mjs.map +1 -1
  58. package/lib/undoprovider.d.ts +4 -4
  59. package/lib/undoprovider.d.ts.map +1 -1
  60. package/matrix.test-files.tar +0 -0
  61. package/package.json +22 -28
  62. package/src/index.ts +1 -1
  63. package/src/matrix.ts +280 -57
  64. package/src/ops.ts +5 -0
  65. package/src/packageVersion.ts +1 -1
  66. package/src/runtime.ts +1 -1
  67. package/src/types.ts +2 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # @fluidframework/matrix
2
2
 
3
+ ## 2.0.0-internal.7.4.0
4
+
5
+ Dependency updates only.
6
+
3
7
  ## 2.0.0-internal.7.3.0
4
8
 
5
9
  Dependency updates only.
package/README.md CHANGED
@@ -119,3 +119,42 @@ return undefined; // Empty region
119
119
  A benefit of storing the cell data in [Z-order](https://en.wikipedia.org/wiki/Z-order_curve) is that both row-major and
120
120
  col-major traversal benefit from prefetching and cache coherence. Reading/writing to the physical storage along either
121
121
  axis is typically within an order of magnitude compared to sequentially accessing a cache hot native JavaScript array.
122
+
123
+ ### Switching From Last Write Win(LWW) to First Write Win(FWW) mode
124
+
125
+ Shared Matrix allows to make to make one way switch from LWW to FWW. This is introduced in order to handle conflict
126
+ when multiple clients at once initialize a cell. Using FWW, will help clients to receive a `conflict` event in case
127
+ their change was rejected. They can resolve conflict with the new information that they received in the event.
128
+ This event is only emitted when the SetCell Resolution Policy is First Write Win(FWW). This is emitted when two clients
129
+ race and send changes without observing each other changes, the changes that gets sequenced last would be rejected, and
130
+ only client who's changes rejected would be notified via this event, with expectation that it will merge its changes
131
+ back by accounting new information (state from winner of the race).
132
+
133
+ Some cases which documents how the Set op changes are applied or rejected during LWW -> FWW switch as some clients will
134
+ be in FWW mode and some will in LWW mode. When app calls `switchSetCellPolicy` the policy is changed to FWW mode
135
+ immediately and then later communicated to other clients via next SetOp which is made on the matrix.
136
+
137
+ **Case 1:** When all clients have switched to FWW mode, then any race between 2 Set Op, will result in a `conflict` event
138
+ at the loser client until it receives its own latest Set op. For example, client has sent op for cell C1. It receives remote
139
+ ops R1 and R2 for cell C1. It will first raise `conflict` event when it receives R1 and then another `conflict` event when
140
+ it receives R2. This will keep happening until it receives its own op, so that its changes are not lost due to conflict.
141
+
142
+ **Case 2:** Client switches policy to FWW locally. No SetOp is made yet. This client has no pending changes yet. On receiving
143
+ remote Set ops, this client will apply them all.
144
+
145
+ **Case 3:** Client switches policy to FWW locally. This client has pending changes for cell C1. On
146
+ receiving remote LWW Set op for C1, this client will reject it as its own op will finally be applied. So the first FWW
147
+ SetOp is still treated as LWW op in a way. Now lets say it has received a remote FWW op for C1 instead of a LWW op, then
148
+ the remote op would have been applied causing client's policy to shift to FWW with that op. It will also raise a conflict
149
+ event locally as its Op for cell c1 will be rejected by other clients as it is a loser op.
150
+
151
+ **Case 4:** In FWW mode, when there is no conflict, clients will still be able to overwrite cells. We track the sequence
152
+ number for each cell when it was last edited and also track the clientId which made that change. If the receive a Op for
153
+ cell C1, and its ref Sequence number is >= to sequence number at which it was last edited, then the cell would be
154
+ overwritten. Otherwise, if the same client made the changes, then the op will still be applied as the client knew about
155
+ the previous edit.
156
+
157
+ **Case 5: Reconnection:** When a client makes an op in LWW mode in disconnected state for cell C1, then when it comes online
158
+ later on, and catches up it sees a FWW op for C1, it will raise a `conflict` event for C1 and will not send it own op.
159
+ It can receive many ops for C1 during catchup and will raise `conflict` event for each of those in case they are winner
160
+ ops for C1.
@@ -1,9 +1,6 @@
1
1
  {
2
2
  "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
3
3
  "extends": "../../../common/build/build-common/api-extractor-base.json",
4
- "dtsRollup": {
5
- "enabled": true
6
- },
7
4
  "messages": {
8
5
  "extractorMessageReporting": {
9
6
  // TODO: Add missing documentation and remove this rule override
@@ -9,6 +9,7 @@ import { IChannelAttributes } from '@fluidframework/datastore-definitions';
9
9
  import { IChannelFactory } from '@fluidframework/datastore-definitions';
10
10
  import { IChannelServices } from '@fluidframework/datastore-definitions';
11
11
  import { IChannelStorageService } from '@fluidframework/datastore-definitions';
12
+ import { IEventThisPlaceHolder } from '@fluidframework/core-interfaces';
12
13
  import { IFluidDataStoreRuntime } from '@fluidframework/datastore-definitions';
13
14
  import { IFluidSerializer } from '@fluidframework/shared-object-base';
14
15
  import { IJSONSegment } from '@fluidframework/merge-tree';
@@ -17,12 +18,13 @@ import { IMatrixProducer } from '@tiny-calc/nano';
17
18
  import { IMatrixReader } from '@tiny-calc/nano';
18
19
  import { IMatrixWriter } from '@tiny-calc/nano';
19
20
  import { ISequencedDocumentMessage } from '@fluidframework/protocol-definitions';
21
+ import { ISharedObjectEvents } from '@fluidframework/shared-object-base';
20
22
  import { ISummaryTreeWithStats } from '@fluidframework/runtime-definitions';
21
23
  import { Serializable } from '@fluidframework/datastore-definitions';
22
24
  import { SharedObject } from '@fluidframework/shared-object-base';
23
25
  import { SummarySerializer } from '@fluidframework/shared-object-base';
24
26
 
25
- // @internal (undocumented)
27
+ // @alpha (undocumented)
26
28
  export interface IRevertible {
27
29
  // (undocumented)
28
30
  discard(): any;
@@ -30,18 +32,23 @@ export interface IRevertible {
30
32
  revert(): any;
31
33
  }
32
34
 
33
- // @internal (undocumented)
35
+ // @alpha
36
+ export interface ISharedMatrixEvents<T> extends ISharedObjectEvents {
37
+ (event: "conflict", listener: (row: number, col: number, currentValue: MatrixItem<T>, conflictingValue: MatrixItem<T>, target: IEventThisPlaceHolder) => void): any;
38
+ }
39
+
40
+ // @alpha (undocumented)
34
41
  export interface IUndoConsumer {
35
42
  // (undocumented)
36
43
  pushToCurrentOperation(revertible: IRevertible): any;
37
44
  }
38
45
 
39
- // @internal
46
+ // @alpha
40
47
  export type MatrixItem<T> = Serializable<Exclude<T, null>> | undefined;
41
48
 
42
- // @internal
43
- export class SharedMatrix<T = any> extends SharedObject implements IMatrixProducer<MatrixItem<T>>, IMatrixReader<MatrixItem<T>>, IMatrixWriter<MatrixItem<T>> {
44
- constructor(runtime: IFluidDataStoreRuntime, id: string, attributes: IChannelAttributes);
49
+ // @alpha
50
+ export class SharedMatrix<T = any> extends SharedObject<ISharedMatrixEvents<T>> implements IMatrixProducer<MatrixItem<T>>, IMatrixReader<MatrixItem<T>>, IMatrixWriter<MatrixItem<T>> {
51
+ constructor(runtime: IFluidDataStoreRuntime, id: string, attributes: IChannelAttributes, _isSetCellConflictResolutionPolicyFWW?: boolean);
45
52
  // (undocumented)
46
53
  protected applyStashedOp(content: any): unknown;
47
54
  // (undocumented)
@@ -63,6 +70,8 @@ export class SharedMatrix<T = any> extends SharedObject implements IMatrixProduc
63
70
  // (undocumented)
64
71
  insertRows(rowStart: number, count: number): void;
65
72
  // (undocumented)
73
+ isSetCellConflictResolutionPolicyFWW(): boolean;
74
+ // (undocumented)
66
75
  protected loadCore(storage: IChannelStorageService): Promise<void>;
67
76
  // (undocumented)
68
77
  get matrixProducer(): IMatrixProducer<MatrixItem<T>>;
@@ -92,6 +101,7 @@ export class SharedMatrix<T = any> extends SharedObject implements IMatrixProduc
92
101
  protected submitLocalMessage(message: any, localOpMetadata?: any): void;
93
102
  // (undocumented)
94
103
  protected summarizeCore(serializer: IFluidSerializer): ISummaryTreeWithStats;
104
+ switchSetCellPolicy(): void;
95
105
  // (undocumented)
96
106
  toString(): string;
97
107
  // (undocumented)
@@ -100,7 +110,7 @@ export class SharedMatrix<T = any> extends SharedObject implements IMatrixProduc
100
110
  _undoRemoveRows(rowStart: number, spec: IJSONSegment): void;
101
111
  }
102
112
 
103
- // @internal
113
+ // @alpha
104
114
  export class SharedMatrixFactory implements IChannelFactory {
105
115
  // (undocumented)
106
116
  static readonly Attributes: IChannelAttributes;
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,uCAAoD;AAA3C,sGAAA,YAAY,OAAA;AACrB,yCAAgD;AAAvC,8GAAA,mBAAmB,OAAA","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport { SharedMatrix, MatrixItem } from \"./matrix\";\nexport { SharedMatrixFactory } from \"./runtime\";\n\n// TODO: We temporarily duplicate these contracts from 'framework/undo-redo' to unblock development\n// of SharedMatrix undo while we decide on the correct layering for undo.\nexport { IUndoConsumer, IRevertible } from \"./types\";\n"]}
1
+ {"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,uCAAyE;AAA3C,sGAAA,YAAY,OAAA;AAC1C,yCAAgD;AAAvC,8GAAA,mBAAmB,OAAA","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport { ISharedMatrixEvents, SharedMatrix, MatrixItem } from \"./matrix\";\nexport { SharedMatrixFactory } from \"./runtime\";\n\n// TODO: We temporarily duplicate these contracts from 'framework/undo-redo' to unblock development\n// of SharedMatrix undo while we decide on the correct layering for undo.\nexport { IUndoConsumer, IRevertible } from \"./types\";\n"]}
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- export { SharedMatrix, MatrixItem } from "./matrix";
5
+ export { ISharedMatrixEvents, SharedMatrix, MatrixItem } from "./matrix";
6
6
  export { SharedMatrixFactory } from "./runtime";
7
7
  export { IUndoConsumer, IRevertible } from "./types";
8
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAIhD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAIhD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC"}
@@ -1,41 +1,214 @@
1
+ import { IChannel } from '@fluidframework/datastore-definitions';
2
+ import { IChannelAttributes } from '@fluidframework/datastore-definitions';
3
+ import { IChannelFactory } from '@fluidframework/datastore-definitions';
4
+ import { IChannelServices } from '@fluidframework/datastore-definitions';
5
+ import { IChannelStorageService } from '@fluidframework/datastore-definitions';
6
+ import { IEventThisPlaceHolder } from '@fluidframework/core-interfaces';
7
+ import { IFluidDataStoreRuntime } from '@fluidframework/datastore-definitions';
8
+ import { IFluidSerializer } from '@fluidframework/shared-object-base';
9
+ import { IJSONSegment } from '@fluidframework/merge-tree';
1
10
  import { IMatrixConsumer } from '@tiny-calc/nano';
2
11
  import { IMatrixProducer } from '@tiny-calc/nano';
3
12
  import { IMatrixReader } from '@tiny-calc/nano';
4
13
  import { IMatrixWriter } from '@tiny-calc/nano';
5
14
  import { ISequencedDocumentMessage } from '@fluidframework/protocol-definitions';
6
-
7
- /* Excluded from this release type: IChannel */
8
-
9
- /* Excluded from this release type: IChannelAttributes */
10
-
11
- /* Excluded from this release type: IChannelFactory */
12
-
13
- /* Excluded from this release type: IChannelServices */
14
-
15
- /* Excluded from this release type: IChannelStorageService */
16
-
17
- /* Excluded from this release type: IFluidDataStoreRuntime */
18
-
19
- /* Excluded from this release type: IFluidSerializer */
20
-
21
- /* Excluded from this release type: IJSONSegment */
22
-
23
- /* Excluded from this release type: IRevertible */
24
-
25
- /* Excluded from this release type: ISummaryTreeWithStats */
26
-
27
- /* Excluded from this release type: IUndoConsumer */
28
-
29
- /* Excluded from this release type: MatrixItem */
30
-
31
- /* Excluded from this release type: Serializable */
32
-
33
- /* Excluded from this release type: SharedMatrix */
34
-
35
- /* Excluded from this release type: SharedMatrixFactory */
36
-
37
- /* Excluded from this release type: SharedObject */
38
-
39
- /* Excluded from this release type: SummarySerializer */
15
+ import { ISharedObjectEvents } from '@fluidframework/shared-object-base';
16
+ import { ISummaryTreeWithStats } from '@fluidframework/runtime-definitions';
17
+ import { Serializable } from '@fluidframework/datastore-definitions';
18
+ import { SharedObject } from '@fluidframework/shared-object-base';
19
+ import { SummarySerializer } from '@fluidframework/shared-object-base';
20
+
21
+ /**
22
+ * @alpha
23
+ */
24
+ export declare interface IRevertible {
25
+ revert(): any;
26
+ discard(): any;
27
+ }
28
+
29
+ /**
30
+ * Events emitted by Shared Matrix.
31
+ * @alpha
32
+ */
33
+ export declare interface ISharedMatrixEvents<T> extends ISharedObjectEvents {
34
+ /**
35
+ * This event is only emitted when the SetCell Resolution Policy is First Write Win(FWW).
36
+ * This is emitted when two clients race and send changes without observing each other changes,
37
+ * the changes that gets sequenced last would be rejected, and only client who's changes rejected
38
+ * would be notified via this event, with expectation that it will merge its changes back by
39
+ * accounting new information (state from winner of the race).
40
+ *
41
+ * @remarks Listener parameters:
42
+ *
43
+ * - `row` - Row number at which conflict happened.
44
+ *
45
+ * - `col` - Col number at which conflict happened.
46
+ *
47
+ * - `currentValue` - The current value of the cell.
48
+ *
49
+ * - `conflictingValue` - The value that this client tried to set in the cell and got ignored due to conflict.
50
+ *
51
+ * - `target` - The {@link SharedMatrix} itself.
52
+ */
53
+ (event: "conflict", listener: (row: number, col: number, currentValue: MatrixItem<T>, conflictingValue: MatrixItem<T>, target: IEventThisPlaceHolder) => void): any;
54
+ }
55
+
56
+ /**
57
+ * @alpha
58
+ */
59
+ export declare interface IUndoConsumer {
60
+ pushToCurrentOperation(revertible: IRevertible): any;
61
+ }
62
+
63
+ /**
64
+ * A matrix cell value may be undefined (indicating an empty cell) or any serializable type,
65
+ * excluding null. (However, nulls may be embedded inside objects and arrays.)
66
+ * @alpha
67
+ */
68
+ export declare type MatrixItem<T> = Serializable<Exclude<T, null>> | undefined;
69
+
70
+ /**
71
+ * A SharedMatrix holds a rectangular 2D array of values. Supported operations
72
+ * include setting values and inserting/removing rows and columns.
73
+ *
74
+ * Matrix values may be any Fluid serializable type, which is the set of JSON
75
+ * serializable types extended to include IFluidHandles.
76
+ *
77
+ * Fluid's SharedMatrix implementation works equally well for dense and sparse
78
+ * matrix data and physically stores data in Z-order to leverage CPU caches and
79
+ * prefetching when reading in either row or column major order. (See README.md
80
+ * for more details.)
81
+ * @alpha
82
+ */
83
+ export declare class SharedMatrix<T = any> extends SharedObject<ISharedMatrixEvents<T>> implements IMatrixProducer<MatrixItem<T>>, IMatrixReader<MatrixItem<T>>, IMatrixWriter<MatrixItem<T>> {
84
+ id: string;
85
+ private readonly consumers;
86
+ static getFactory(): SharedMatrixFactory;
87
+ private readonly rows;
88
+ private readonly cols;
89
+ private cells;
90
+ private readonly pending;
91
+ private cellLastWriteTracker;
92
+ private setCellLwwToFwwPolicySwitchOpSeqNumber;
93
+ private userSwitchedSetCellPolicy;
94
+ private reentrantCount;
95
+ /**
96
+ * Constructor for the Shared Matrix
97
+ * @param runtime - DataStore runtime.
98
+ * @param id - id of the dds
99
+ * @param attributes - channel attributes
100
+ * @param _isSetCellConflictResolutionPolicyFWW - Conflict resolution for Matrix set op is First Writer Win in case of
101
+ * race condition. Client can still overwrite values in case of no race.
102
+ */
103
+ constructor(runtime: IFluidDataStoreRuntime, id: string, attributes: IChannelAttributes, _isSetCellConflictResolutionPolicyFWW?: boolean);
104
+ private undo?;
105
+ /**
106
+ * Subscribes the given IUndoConsumer to the matrix.
107
+ */
108
+ openUndo(consumer: IUndoConsumer): void;
109
+ private get rowHandles();
110
+ private get colHandles();
111
+ /**
112
+ * {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory.create}
113
+ */
114
+ static create<T>(runtime: IFluidDataStoreRuntime, id?: string): SharedMatrix<T>;
115
+ openMatrix(consumer: IMatrixConsumer<MatrixItem<T>>): IMatrixReader<MatrixItem<T>>;
116
+ closeMatrix(consumer: IMatrixConsumer<MatrixItem<T>>): void;
117
+ get rowCount(): number;
118
+ get colCount(): number;
119
+ isSetCellConflictResolutionPolicyFWW(): boolean;
120
+ getCell(row: number, col: number): MatrixItem<T>;
121
+ get matrixProducer(): IMatrixProducer<MatrixItem<T>>;
122
+ setCell(row: number, col: number, value: MatrixItem<T>): void;
123
+ setCells(rowStart: number, colStart: number, colCount: number, values: readonly MatrixItem<T>[]): void;
124
+ private setCellCore;
125
+ private sendSetCellOp;
126
+ /**
127
+ * This makes sure that the code inside the callback is not reentrant. We need to do that because we raise notifications
128
+ * to the consumers telling about these changes and they can try to change the matrix while listening to those notifications
129
+ * which can make the shared matrix to be in bad state. For example, we are raising notification for a setCell changes and
130
+ * a consumer tries to delete that row/col on receiving that notification which can lead to this matrix trying to setCell in
131
+ * a deleted row/col.
132
+ * @param callback - code that needs to protected against reentrancy.
133
+ */
134
+ private protectAgainstReentrancy;
135
+ private submitVectorMessage;
136
+ private submitColMessage;
137
+ insertCols(colStart: number, count: number): void;
138
+ removeCols(colStart: number, count: number): void;
139
+ private submitRowMessage;
140
+ insertRows(rowStart: number, count: number): void;
141
+ removeRows(rowStart: number, count: number): void;
142
+ /***/ _undoRemoveRows(rowStart: number, spec: IJSONSegment): void;
143
+ /***/ _undoRemoveCols(colStart: number, spec: IJSONSegment): void;
144
+ protected summarizeCore(serializer: IFluidSerializer): ISummaryTreeWithStats;
145
+ /**
146
+ * Runs serializer on the GC data for this SharedMatrix.
147
+ * All the IFluidHandle's stored in the cells represent routes to other objects.
148
+ */
149
+ protected processGCDataCore(serializer: SummarySerializer): void;
150
+ /**
151
+ * Advances the 'localSeq' counter for the cell data operation currently being queued.
152
+ *
153
+ * Do not use with 'submitColMessage()/submitRowMessage()' as these helpers + the MergeTree will
154
+ * automatically advance 'localSeq'.
155
+ */
156
+ private nextLocalSeq;
157
+ protected submitLocalMessage(message: any, localOpMetadata?: any): void;
158
+ protected didAttach(): void;
159
+ protected onConnect(): void;
160
+ private rebasePosition;
161
+ protected reSubmitCore(content: any, localOpMetadata: unknown): void;
162
+ protected onDisconnect(): void;
163
+ /**
164
+ * {@inheritDoc @fluidframework/shared-object-base#SharedObject.loadCore}
165
+ */
166
+ protected loadCore(storage: IChannelStorageService): Promise<void>;
167
+ /**
168
+ * Tells whether the setCell op should be applied or not based on First Write Win policy. It assumes
169
+ * we are in FWW mode.
170
+ */
171
+ private shouldSetCellBasedOnFWW;
172
+ protected processCore(rawMessage: ISequencedDocumentMessage, local: boolean, localOpMetadata: unknown): void;
173
+ private readonly onRowDelta;
174
+ private readonly onColDelta;
175
+ private readonly onRowHandlesRecycled;
176
+ private readonly onColHandlesRecycled;
177
+ /**
178
+ * Api to switch Set Op policy from Last Writer Win to First Writer Win. It only switches from LWW to FWW
179
+ * and not from FWW to LWW. The next SetOp which is sent will communicate this policy to other clients.
180
+ */
181
+ switchSetCellPolicy(): void;
182
+ /**
183
+ * Returns true if the latest pending write to the cell indicated by the given row/col handles
184
+ * matches the given 'localSeq'.
185
+ *
186
+ * A return value of `true` indicates that there are no later local operations queued that will
187
+ * clobber the write op at the given 'localSeq'. This includes later ops that overwrite the cell
188
+ * with a different value as well as row/col removals that might recycled the given row/col handles.
189
+ */
190
+ private isLatestPendingWrite;
191
+ toString(): string;
192
+ /**
193
+ * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.applyStashedOp}
194
+ */
195
+ protected applyStashedOp(content: any): unknown;
196
+ }
197
+
198
+ /**
199
+ * {@link @fluidframework/datastore-definitions#IChannelFactory} for {@link SharedMatrix}.
200
+ * @alpha
201
+ */
202
+ export declare class SharedMatrixFactory implements IChannelFactory {
203
+ static Type: string;
204
+ static readonly Attributes: IChannelAttributes;
205
+ get type(): string;
206
+ get attributes(): IChannelAttributes;
207
+ /**
208
+ * {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory.load}
209
+ */
210
+ load(runtime: IFluidDataStoreRuntime, id: string, services: IChannelServices, attributes: IChannelAttributes): Promise<IChannel>;
211
+ create(document: IFluidDataStoreRuntime, id: string): IChannel;
212
+ }
40
213
 
41
214
  export { }
@@ -1,8 +1,22 @@
1
+ import { IChannel } from '@fluidframework/datastore-definitions';
2
+ import { IChannelAttributes } from '@fluidframework/datastore-definitions';
3
+ import { IChannelFactory } from '@fluidframework/datastore-definitions';
4
+ import { IChannelServices } from '@fluidframework/datastore-definitions';
5
+ import { IChannelStorageService } from '@fluidframework/datastore-definitions';
6
+ import { IEventThisPlaceHolder } from '@fluidframework/core-interfaces';
7
+ import { IFluidDataStoreRuntime } from '@fluidframework/datastore-definitions';
8
+ import { IFluidSerializer } from '@fluidframework/shared-object-base';
9
+ import { IJSONSegment } from '@fluidframework/merge-tree';
1
10
  import { IMatrixConsumer } from '@tiny-calc/nano';
2
11
  import { IMatrixProducer } from '@tiny-calc/nano';
3
12
  import { IMatrixReader } from '@tiny-calc/nano';
4
13
  import { IMatrixWriter } from '@tiny-calc/nano';
5
14
  import { ISequencedDocumentMessage } from '@fluidframework/protocol-definitions';
15
+ import { ISharedObjectEvents } from '@fluidframework/shared-object-base';
16
+ import { ISummaryTreeWithStats } from '@fluidframework/runtime-definitions';
17
+ import { Serializable } from '@fluidframework/datastore-definitions';
18
+ import { SharedObject } from '@fluidframework/shared-object-base';
19
+ import { SummarySerializer } from '@fluidframework/shared-object-base';
6
20
 
7
21
  /* Excluded from this release type: IChannel */
8
22
 
@@ -14,6 +28,8 @@ import { ISequencedDocumentMessage } from '@fluidframework/protocol-definitions'
14
28
 
15
29
  /* Excluded from this release type: IChannelStorageService */
16
30
 
31
+ /* Excluded from this release type: IEventThisPlaceHolder */
32
+
17
33
  /* Excluded from this release type: IFluidDataStoreRuntime */
18
34
 
19
35
  /* Excluded from this release type: IFluidSerializer */
@@ -22,6 +38,10 @@ import { ISequencedDocumentMessage } from '@fluidframework/protocol-definitions'
22
38
 
23
39
  /* Excluded from this release type: IRevertible */
24
40
 
41
+ /* Excluded from this release type: ISharedMatrixEvents */
42
+
43
+ /* Excluded from this release type: ISharedObjectEvents */
44
+
25
45
  /* Excluded from this release type: ISummaryTreeWithStats */
26
46
 
27
47
  /* Excluded from this release type: IUndoConsumer */
@@ -1,8 +1,22 @@
1
+ import { IChannel } from '@fluidframework/datastore-definitions';
2
+ import { IChannelAttributes } from '@fluidframework/datastore-definitions';
3
+ import { IChannelFactory } from '@fluidframework/datastore-definitions';
4
+ import { IChannelServices } from '@fluidframework/datastore-definitions';
5
+ import { IChannelStorageService } from '@fluidframework/datastore-definitions';
6
+ import { IEventThisPlaceHolder } from '@fluidframework/core-interfaces';
7
+ import { IFluidDataStoreRuntime } from '@fluidframework/datastore-definitions';
8
+ import { IFluidSerializer } from '@fluidframework/shared-object-base';
9
+ import { IJSONSegment } from '@fluidframework/merge-tree';
1
10
  import { IMatrixConsumer } from '@tiny-calc/nano';
2
11
  import { IMatrixProducer } from '@tiny-calc/nano';
3
12
  import { IMatrixReader } from '@tiny-calc/nano';
4
13
  import { IMatrixWriter } from '@tiny-calc/nano';
5
14
  import { ISequencedDocumentMessage } from '@fluidframework/protocol-definitions';
15
+ import { ISharedObjectEvents } from '@fluidframework/shared-object-base';
16
+ import { ISummaryTreeWithStats } from '@fluidframework/runtime-definitions';
17
+ import { Serializable } from '@fluidframework/datastore-definitions';
18
+ import { SharedObject } from '@fluidframework/shared-object-base';
19
+ import { SummarySerializer } from '@fluidframework/shared-object-base';
6
20
 
7
21
  /* Excluded from this release type: IChannel */
8
22
 
@@ -14,6 +28,8 @@ import { ISequencedDocumentMessage } from '@fluidframework/protocol-definitions'
14
28
 
15
29
  /* Excluded from this release type: IChannelStorageService */
16
30
 
31
+ /* Excluded from this release type: IEventThisPlaceHolder */
32
+
17
33
  /* Excluded from this release type: IFluidDataStoreRuntime */
18
34
 
19
35
  /* Excluded from this release type: IFluidSerializer */
@@ -22,6 +38,10 @@ import { ISequencedDocumentMessage } from '@fluidframework/protocol-definitions'
22
38
 
23
39
  /* Excluded from this release type: IRevertible */
24
40
 
41
+ /* Excluded from this release type: ISharedMatrixEvents */
42
+
43
+ /* Excluded from this release type: ISharedObjectEvents */
44
+
25
45
  /* Excluded from this release type: ISummaryTreeWithStats */
26
46
 
27
47
  /* Excluded from this release type: IUndoConsumer */
@@ -3,6 +3,7 @@ import { IChannelAttributes } from '@fluidframework/datastore-definitions';
3
3
  import { IChannelFactory } from '@fluidframework/datastore-definitions';
4
4
  import { IChannelServices } from '@fluidframework/datastore-definitions';
5
5
  import { IChannelStorageService } from '@fluidframework/datastore-definitions';
6
+ import { IEventThisPlaceHolder } from '@fluidframework/core-interfaces';
6
7
  import { IFluidDataStoreRuntime } from '@fluidframework/datastore-definitions';
7
8
  import { IFluidSerializer } from '@fluidframework/shared-object-base';
8
9
  import { IJSONSegment } from '@fluidframework/merge-tree';
@@ -11,13 +12,14 @@ import { IMatrixProducer } from '@tiny-calc/nano';
11
12
  import { IMatrixReader } from '@tiny-calc/nano';
12
13
  import { IMatrixWriter } from '@tiny-calc/nano';
13
14
  import { ISequencedDocumentMessage } from '@fluidframework/protocol-definitions';
15
+ import { ISharedObjectEvents } from '@fluidframework/shared-object-base';
14
16
  import { ISummaryTreeWithStats } from '@fluidframework/runtime-definitions';
15
17
  import { Serializable } from '@fluidframework/datastore-definitions';
16
18
  import { SharedObject } from '@fluidframework/shared-object-base';
17
19
  import { SummarySerializer } from '@fluidframework/shared-object-base';
18
20
 
19
21
  /**
20
- * @internal
22
+ * @alpha
21
23
  */
22
24
  export declare interface IRevertible {
23
25
  revert(): any;
@@ -25,7 +27,34 @@ export declare interface IRevertible {
25
27
  }
26
28
 
27
29
  /**
28
- * @internal
30
+ * Events emitted by Shared Matrix.
31
+ * @alpha
32
+ */
33
+ export declare interface ISharedMatrixEvents<T> extends ISharedObjectEvents {
34
+ /**
35
+ * This event is only emitted when the SetCell Resolution Policy is First Write Win(FWW).
36
+ * This is emitted when two clients race and send changes without observing each other changes,
37
+ * the changes that gets sequenced last would be rejected, and only client who's changes rejected
38
+ * would be notified via this event, with expectation that it will merge its changes back by
39
+ * accounting new information (state from winner of the race).
40
+ *
41
+ * @remarks Listener parameters:
42
+ *
43
+ * - `row` - Row number at which conflict happened.
44
+ *
45
+ * - `col` - Col number at which conflict happened.
46
+ *
47
+ * - `currentValue` - The current value of the cell.
48
+ *
49
+ * - `conflictingValue` - The value that this client tried to set in the cell and got ignored due to conflict.
50
+ *
51
+ * - `target` - The {@link SharedMatrix} itself.
52
+ */
53
+ (event: "conflict", listener: (row: number, col: number, currentValue: MatrixItem<T>, conflictingValue: MatrixItem<T>, target: IEventThisPlaceHolder) => void): any;
54
+ }
55
+
56
+ /**
57
+ * @alpha
29
58
  */
30
59
  export declare interface IUndoConsumer {
31
60
  pushToCurrentOperation(revertible: IRevertible): any;
@@ -34,7 +63,7 @@ export declare interface IUndoConsumer {
34
63
  /**
35
64
  * A matrix cell value may be undefined (indicating an empty cell) or any serializable type,
36
65
  * excluding null. (However, nulls may be embedded inside objects and arrays.)
37
- * @internal
66
+ * @alpha
38
67
  */
39
68
  export declare type MatrixItem<T> = Serializable<Exclude<T, null>> | undefined;
40
69
 
@@ -49,17 +78,29 @@ export declare type MatrixItem<T> = Serializable<Exclude<T, null>> | undefined;
49
78
  * matrix data and physically stores data in Z-order to leverage CPU caches and
50
79
  * prefetching when reading in either row or column major order. (See README.md
51
80
  * for more details.)
52
- * @internal
81
+ * @alpha
53
82
  */
54
- export declare class SharedMatrix<T = any> extends SharedObject implements IMatrixProducer<MatrixItem<T>>, IMatrixReader<MatrixItem<T>>, IMatrixWriter<MatrixItem<T>> {
83
+ export declare class SharedMatrix<T = any> extends SharedObject<ISharedMatrixEvents<T>> implements IMatrixProducer<MatrixItem<T>>, IMatrixReader<MatrixItem<T>>, IMatrixWriter<MatrixItem<T>> {
55
84
  id: string;
56
85
  private readonly consumers;
57
86
  static getFactory(): SharedMatrixFactory;
58
87
  private readonly rows;
59
88
  private readonly cols;
60
89
  private cells;
61
- private pending;
62
- constructor(runtime: IFluidDataStoreRuntime, id: string, attributes: IChannelAttributes);
90
+ private readonly pending;
91
+ private cellLastWriteTracker;
92
+ private setCellLwwToFwwPolicySwitchOpSeqNumber;
93
+ private userSwitchedSetCellPolicy;
94
+ private reentrantCount;
95
+ /**
96
+ * Constructor for the Shared Matrix
97
+ * @param runtime - DataStore runtime.
98
+ * @param id - id of the dds
99
+ * @param attributes - channel attributes
100
+ * @param _isSetCellConflictResolutionPolicyFWW - Conflict resolution for Matrix set op is First Writer Win in case of
101
+ * race condition. Client can still overwrite values in case of no race.
102
+ */
103
+ constructor(runtime: IFluidDataStoreRuntime, id: string, attributes: IChannelAttributes, _isSetCellConflictResolutionPolicyFWW?: boolean);
63
104
  private undo?;
64
105
  /**
65
106
  * Subscribes the given IUndoConsumer to the matrix.
@@ -75,12 +116,22 @@ export declare class SharedMatrix<T = any> extends SharedObject implements IMatr
75
116
  closeMatrix(consumer: IMatrixConsumer<MatrixItem<T>>): void;
76
117
  get rowCount(): number;
77
118
  get colCount(): number;
119
+ isSetCellConflictResolutionPolicyFWW(): boolean;
78
120
  getCell(row: number, col: number): MatrixItem<T>;
79
121
  get matrixProducer(): IMatrixProducer<MatrixItem<T>>;
80
122
  setCell(row: number, col: number, value: MatrixItem<T>): void;
81
123
  setCells(rowStart: number, colStart: number, colCount: number, values: readonly MatrixItem<T>[]): void;
82
124
  private setCellCore;
83
125
  private sendSetCellOp;
126
+ /**
127
+ * This makes sure that the code inside the callback is not reentrant. We need to do that because we raise notifications
128
+ * to the consumers telling about these changes and they can try to change the matrix while listening to those notifications
129
+ * which can make the shared matrix to be in bad state. For example, we are raising notification for a setCell changes and
130
+ * a consumer tries to delete that row/col on receiving that notification which can lead to this matrix trying to setCell in
131
+ * a deleted row/col.
132
+ * @param callback - code that needs to protected against reentrancy.
133
+ */
134
+ private protectAgainstReentrancy;
84
135
  private submitVectorMessage;
85
136
  private submitColMessage;
86
137
  insertCols(colStart: number, count: number): void;
@@ -113,11 +164,21 @@ export declare class SharedMatrix<T = any> extends SharedObject implements IMatr
113
164
  * {@inheritDoc @fluidframework/shared-object-base#SharedObject.loadCore}
114
165
  */
115
166
  protected loadCore(storage: IChannelStorageService): Promise<void>;
167
+ /**
168
+ * Tells whether the setCell op should be applied or not based on First Write Win policy. It assumes
169
+ * we are in FWW mode.
170
+ */
171
+ private shouldSetCellBasedOnFWW;
116
172
  protected processCore(rawMessage: ISequencedDocumentMessage, local: boolean, localOpMetadata: unknown): void;
117
173
  private readonly onRowDelta;
118
174
  private readonly onColDelta;
119
175
  private readonly onRowHandlesRecycled;
120
176
  private readonly onColHandlesRecycled;
177
+ /**
178
+ * Api to switch Set Op policy from Last Writer Win to First Writer Win. It only switches from LWW to FWW
179
+ * and not from FWW to LWW. The next SetOp which is sent will communicate this policy to other clients.
180
+ */
181
+ switchSetCellPolicy(): void;
121
182
  /**
122
183
  * Returns true if the latest pending write to the cell indicated by the given row/col handles
123
184
  * matches the given 'localSeq'.
@@ -136,7 +197,7 @@ export declare class SharedMatrix<T = any> extends SharedObject implements IMatr
136
197
 
137
198
  /**
138
199
  * {@link @fluidframework/datastore-definitions#IChannelFactory} for {@link SharedMatrix}.
139
- * @internal
200
+ * @alpha
140
201
  */
141
202
  export declare class SharedMatrixFactory implements IChannelFactory {
142
203
  static Type: string;