@fluidframework/matrix 2.0.0-internal.7.2.2 → 2.0.0-internal.7.4.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/CHANGELOG.md +8 -0
- package/README.md +39 -0
- package/api-extractor-lint.json +13 -0
- package/api-extractor.json +3 -7
- package/api-report/matrix.api.md +19 -9
- package/dist/{handlecache.js → handlecache.cjs} +3 -3
- package/dist/handlecache.cjs.map +1 -0
- package/dist/{handletable.js → handletable.cjs} +1 -1
- package/dist/handletable.cjs.map +1 -0
- package/dist/{index.js → index.cjs} +3 -3
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/matrix-alpha.d.ts +214 -0
- package/dist/matrix-beta.d.ts +61 -0
- package/dist/matrix-public.d.ts +61 -0
- package/dist/matrix-untrimmed.d.ts +214 -0
- package/dist/{matrix.js → matrix.cjs} +185 -55
- package/dist/matrix.cjs.map +1 -0
- package/dist/matrix.d.ts +67 -8
- package/dist/matrix.d.ts.map +1 -1
- package/dist/{ops.js → ops.cjs} +2 -1
- package/dist/ops.cjs.map +1 -0
- package/dist/ops.d.ts +5 -1
- package/dist/ops.d.ts.map +1 -1
- package/dist/{packageVersion.js → packageVersion.cjs} +2 -2
- package/dist/packageVersion.cjs.map +1 -0
- package/dist/packageVersion.d.ts +1 -1
- package/dist/{permutationvector.js → permutationvector.cjs} +5 -4
- package/dist/permutationvector.cjs.map +1 -0
- package/dist/permutationvector.d.ts.map +1 -1
- package/dist/{range.js → range.cjs} +1 -1
- package/dist/range.cjs.map +1 -0
- package/dist/{runtime.js → runtime.cjs} +7 -3
- package/dist/runtime.cjs.map +1 -0
- package/dist/runtime.d.ts +4 -0
- package/dist/runtime.d.ts.map +1 -1
- package/dist/{serialization.js → serialization.cjs} +1 -1
- package/dist/serialization.cjs.map +1 -0
- package/dist/{sparsearray2d.js → sparsearray2d.cjs} +1 -1
- package/dist/sparsearray2d.cjs.map +1 -0
- package/dist/tsdoc-metadata.json +1 -1
- package/dist/{types.js → types.cjs} +1 -1
- package/dist/types.cjs.map +1 -0
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/{undoprovider.js → undoprovider.cjs} +2 -2
- package/dist/undoprovider.cjs.map +1 -0
- package/lib/handlecache.d.ts +2 -2
- package/lib/handlecache.d.ts.map +1 -1
- package/lib/{handlecache.js → handlecache.mjs} +3 -4
- package/lib/handlecache.mjs.map +1 -0
- package/lib/{handletable.js → handletable.mjs} +1 -1
- package/lib/handletable.mjs.map +1 -0
- package/lib/index.d.ts +3 -3
- package/lib/index.d.ts.map +1 -1
- package/lib/index.mjs +7 -0
- package/lib/index.mjs.map +1 -0
- package/lib/matrix-alpha.d.ts +214 -0
- package/lib/matrix-beta.d.ts +61 -0
- package/lib/matrix-public.d.ts +61 -0
- package/lib/matrix-untrimmed.d.ts +214 -0
- package/lib/matrix.d.ts +69 -10
- package/lib/matrix.d.ts.map +1 -1
- package/lib/{matrix.js → matrix.mjs} +184 -55
- package/lib/matrix.mjs.map +1 -0
- package/lib/ops.d.ts +5 -1
- package/lib/ops.d.ts.map +1 -1
- package/lib/{ops.js → ops.mjs} +2 -1
- package/lib/ops.mjs.map +1 -0
- package/lib/packageVersion.d.ts +1 -1
- package/lib/{packageVersion.js → packageVersion.mjs} +2 -2
- package/lib/packageVersion.mjs.map +1 -0
- package/lib/permutationvector.d.ts +3 -3
- package/lib/permutationvector.d.ts.map +1 -1
- package/lib/{permutationvector.js → permutationvector.mjs} +4 -4
- package/lib/permutationvector.mjs.map +1 -0
- package/lib/{range.js → range.mjs} +1 -1
- package/lib/range.mjs.map +1 -0
- package/lib/runtime.d.ts +4 -0
- package/lib/runtime.d.ts.map +1 -1
- package/lib/{runtime.js → runtime.mjs} +7 -3
- package/lib/runtime.mjs.map +1 -0
- package/lib/serialization.d.ts.map +1 -1
- package/lib/{serialization.js → serialization.mjs} +1 -1
- package/lib/serialization.mjs.map +1 -0
- package/lib/sparsearray2d.d.ts.map +1 -1
- package/lib/{sparsearray2d.js → sparsearray2d.mjs} +1 -1
- package/lib/sparsearray2d.mjs.map +1 -0
- package/lib/types.d.ts +6 -0
- package/lib/types.d.ts.map +1 -1
- package/lib/{types.js → types.mjs} +1 -1
- package/lib/types.mjs.map +1 -0
- package/lib/undoprovider.d.ts +4 -4
- package/lib/undoprovider.d.ts.map +1 -1
- package/lib/{undoprovider.js → undoprovider.mjs} +2 -2
- package/lib/undoprovider.mjs.map +1 -0
- package/matrix.test-files.tar +0 -0
- package/package.json +59 -35
- package/src/index.ts +1 -1
- package/src/matrix.ts +284 -59
- package/src/ops.ts +5 -0
- package/src/packageVersion.ts +1 -1
- package/src/permutationvector.ts +2 -0
- package/src/runtime.ts +4 -0
- package/src/types.ts +6 -0
- package/tsc-multi.test.json +4 -0
- package/tsconfig.json +6 -4
- package/dist/handlecache.js.map +0 -1
- package/dist/handletable.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/matrix.js.map +0 -1
- package/dist/ops.js.map +0 -1
- package/dist/packageVersion.js.map +0 -1
- package/dist/permutationvector.js.map +0 -1
- package/dist/range.js.map +0 -1
- package/dist/runtime.js.map +0 -1
- package/dist/serialization.js.map +0 -1
- package/dist/sparsearray2d.js.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/undoprovider.js.map +0 -1
- package/lib/handlecache.js.map +0 -1
- package/lib/handletable.js.map +0 -1
- package/lib/index.js +0 -7
- package/lib/index.js.map +0 -1
- package/lib/matrix.js.map +0 -1
- package/lib/ops.js.map +0 -1
- package/lib/packageVersion.js.map +0 -1
- package/lib/permutationvector.js.map +0 -1
- package/lib/range.js.map +0 -1
- package/lib/runtime.js.map +0 -1
- package/lib/serialization.js.map +0 -1
- package/lib/sparsearray2d.js.map +0 -1
- package/lib/types.js.map +0 -1
- package/lib/undoprovider.js.map +0 -1
- package/tsconfig.esnext.json +0 -7
|
@@ -0,0 +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';
|
|
10
|
+
import { IMatrixConsumer } from '@tiny-calc/nano';
|
|
11
|
+
import { IMatrixProducer } from '@tiny-calc/nano';
|
|
12
|
+
import { IMatrixReader } from '@tiny-calc/nano';
|
|
13
|
+
import { IMatrixWriter } from '@tiny-calc/nano';
|
|
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';
|
|
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
|
+
}
|
|
213
|
+
|
|
214
|
+
export { }
|
|
@@ -5,18 +5,19 @@
|
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.SharedMatrix = void 0;
|
|
8
|
+
/* eslint-disable import/no-deprecated */
|
|
8
9
|
const core_utils_1 = require("@fluidframework/core-utils");
|
|
9
10
|
const shared_object_base_1 = require("@fluidframework/shared-object-base");
|
|
10
11
|
const runtime_utils_1 = require("@fluidframework/runtime-utils");
|
|
11
12
|
const merge_tree_1 = require("@fluidframework/merge-tree");
|
|
12
|
-
const ops_1 = require("./ops");
|
|
13
|
-
const permutationvector_1 = require("./permutationvector");
|
|
14
|
-
const sparsearray2d_1 = require("./sparsearray2d");
|
|
15
|
-
const runtime_1 = require("./runtime");
|
|
16
|
-
const handletable_1 = require("./handletable");
|
|
17
|
-
const serialization_1 = require("./serialization");
|
|
18
|
-
const range_1 = require("./range");
|
|
19
|
-
const undoprovider_1 = require("./undoprovider");
|
|
13
|
+
const ops_1 = require("./ops.cjs");
|
|
14
|
+
const permutationvector_1 = require("./permutationvector.cjs");
|
|
15
|
+
const sparsearray2d_1 = require("./sparsearray2d.cjs");
|
|
16
|
+
const runtime_1 = require("./runtime.cjs");
|
|
17
|
+
const handletable_1 = require("./handletable.cjs");
|
|
18
|
+
const serialization_1 = require("./serialization.cjs");
|
|
19
|
+
const range_1 = require("./range.cjs");
|
|
20
|
+
const undoprovider_1 = require("./undoprovider.cjs");
|
|
20
21
|
/**
|
|
21
22
|
* A SharedMatrix holds a rectangular 2D array of values. Supported operations
|
|
22
23
|
* include setting values and inserting/removing rows and columns.
|
|
@@ -28,19 +29,30 @@ const undoprovider_1 = require("./undoprovider");
|
|
|
28
29
|
* matrix data and physically stores data in Z-order to leverage CPU caches and
|
|
29
30
|
* prefetching when reading in either row or column major order. (See README.md
|
|
30
31
|
* for more details.)
|
|
31
|
-
*
|
|
32
|
-
* @public
|
|
32
|
+
* @alpha
|
|
33
33
|
*/
|
|
34
34
|
class SharedMatrix extends shared_object_base_1.SharedObject {
|
|
35
35
|
static getFactory() {
|
|
36
36
|
return new runtime_1.SharedMatrixFactory();
|
|
37
37
|
}
|
|
38
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Constructor for the Shared Matrix
|
|
40
|
+
* @param runtime - DataStore runtime.
|
|
41
|
+
* @param id - id of the dds
|
|
42
|
+
* @param attributes - channel attributes
|
|
43
|
+
* @param _isSetCellConflictResolutionPolicyFWW - Conflict resolution for Matrix set op is First Writer Win in case of
|
|
44
|
+
* race condition. Client can still overwrite values in case of no race.
|
|
45
|
+
*/
|
|
46
|
+
constructor(runtime, id, attributes, _isSetCellConflictResolutionPolicyFWW) {
|
|
39
47
|
super(id, runtime, attributes, "fluid_matrix_");
|
|
40
48
|
this.id = id;
|
|
41
49
|
this.consumers = new Set();
|
|
42
50
|
this.cells = new sparsearray2d_1.SparseArray2D(); // Stores cell values.
|
|
43
51
|
this.pending = new sparsearray2d_1.SparseArray2D(); // Tracks pending writes.
|
|
52
|
+
this.cellLastWriteTracker = new sparsearray2d_1.SparseArray2D(); // Tracks last writes sequence number and clientId in a cell.
|
|
53
|
+
this.userSwitchedSetCellPolicy = false; // Set to true when the user calls switchPolicy.
|
|
54
|
+
// Used to track if there is any reentrancy in setCell code.
|
|
55
|
+
this.reentrantCount = 0;
|
|
44
56
|
// Invoked by PermutationVector to notify IMatrixConsumers of row insertion/deletions.
|
|
45
57
|
this.onRowDelta = (position, removedCount, insertedCount) => {
|
|
46
58
|
for (const consumer of this.consumers) {
|
|
@@ -57,14 +69,18 @@ class SharedMatrix extends shared_object_base_1.SharedObject {
|
|
|
57
69
|
for (const rowHandle of rowHandles) {
|
|
58
70
|
this.cells.clearRows(/* rowStart: */ rowHandle, /* rowCount: */ 1);
|
|
59
71
|
this.pending.clearRows(/* rowStart: */ rowHandle, /* rowCount: */ 1);
|
|
72
|
+
this.cellLastWriteTracker.clearRows(/* rowStart: */ rowHandle, /* rowCount: */ 1);
|
|
60
73
|
}
|
|
61
74
|
};
|
|
62
75
|
this.onColHandlesRecycled = (colHandles) => {
|
|
63
76
|
for (const colHandle of colHandles) {
|
|
64
77
|
this.cells.clearCols(/* colStart: */ colHandle, /* colCount: */ 1);
|
|
65
78
|
this.pending.clearCols(/* colStart: */ colHandle, /* colCount: */ 1);
|
|
79
|
+
this.cellLastWriteTracker.clearCols(/* colStart: */ colHandle, /* colCount: */ 1);
|
|
66
80
|
}
|
|
67
81
|
};
|
|
82
|
+
this.setCellLwwToFwwPolicySwitchOpSeqNumber =
|
|
83
|
+
_isSetCellConflictResolutionPolicyFWW === true ? 0 : -1;
|
|
68
84
|
this.rows = new permutationvector_1.PermutationVector("rows" /* SnapshotPath.rows */, this.logger, runtime, this.onRowDelta, this.onRowHandlesRecycled);
|
|
69
85
|
this.cols = new permutationvector_1.PermutationVector("cols" /* SnapshotPath.cols */, this.logger, runtime, this.onColDelta, this.onColHandlesRecycled);
|
|
70
86
|
}
|
|
@@ -104,6 +120,9 @@ class SharedMatrix extends shared_object_base_1.SharedObject {
|
|
|
104
120
|
get colCount() {
|
|
105
121
|
return this.cols.getLength();
|
|
106
122
|
}
|
|
123
|
+
isSetCellConflictResolutionPolicyFWW() {
|
|
124
|
+
return this.setCellLwwToFwwPolicySwitchOpSeqNumber > -1 || this.userSwitchedSetCellPolicy;
|
|
125
|
+
}
|
|
107
126
|
getCell(row, col) {
|
|
108
127
|
// Perf: When possible, bounds checking is performed inside the implementation for
|
|
109
128
|
// 'getHandle()' so that it can be elided in the case of a cache hit. This
|
|
@@ -130,10 +149,6 @@ class SharedMatrix extends shared_object_base_1.SharedObject {
|
|
|
130
149
|
setCell(row, col, value) {
|
|
131
150
|
(0, core_utils_1.assert)(0 <= row && row < this.rowCount && 0 <= col && col < this.colCount, 0x01a /* "Trying to set out-of-bounds cell!" */);
|
|
132
151
|
this.setCellCore(row, col, value);
|
|
133
|
-
// Avoid reentrancy by raising change notifications after the op is queued.
|
|
134
|
-
for (const consumer of this.consumers.values()) {
|
|
135
|
-
consumer.cellsChanged(row, col, 1, 1, this);
|
|
136
|
-
}
|
|
137
152
|
}
|
|
138
153
|
setCells(rowStart, colStart, colCount, values) {
|
|
139
154
|
const rowCount = Math.ceil(values.length / colCount);
|
|
@@ -154,23 +169,25 @@ class SharedMatrix extends shared_object_base_1.SharedObject {
|
|
|
154
169
|
r++;
|
|
155
170
|
}
|
|
156
171
|
}
|
|
157
|
-
// Avoid reentrancy by raising change notifications after the op is queued.
|
|
158
|
-
for (const consumer of this.consumers.values()) {
|
|
159
|
-
consumer.cellsChanged(rowStart, colStart, rowCount, colCount, this);
|
|
160
|
-
}
|
|
161
172
|
}
|
|
162
173
|
setCellCore(row, col, value, rowHandle = this.rows.getAllocatedHandle(row), colHandle = this.cols.getAllocatedHandle(col)) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
oldValue
|
|
174
|
+
this.protectAgainstReentrancy(() => {
|
|
175
|
+
if (this.undo !== undefined) {
|
|
176
|
+
let oldValue = this.cells.getCell(rowHandle, colHandle);
|
|
177
|
+
if (oldValue === null) {
|
|
178
|
+
oldValue = undefined;
|
|
179
|
+
}
|
|
180
|
+
this.undo.cellSet(rowHandle, colHandle, oldValue);
|
|
167
181
|
}
|
|
168
|
-
this.
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
182
|
+
this.cells.setCell(rowHandle, colHandle, value);
|
|
183
|
+
if (this.isAttached()) {
|
|
184
|
+
this.sendSetCellOp(row, col, value, rowHandle, colHandle);
|
|
185
|
+
}
|
|
186
|
+
// Avoid reentrancy by raising change notifications after the op is queued.
|
|
187
|
+
for (const consumer of this.consumers.values()) {
|
|
188
|
+
consumer.cellsChanged(row, col, 1, 1, this);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
174
191
|
}
|
|
175
192
|
sendSetCellOp(row, col, value, rowHandle, colHandle, localSeq = this.nextLocalSeq(), rowsRefSeq = this.rows.getCollabWindow().currentSeq, colsRefSeq = this.cols.getCollabWindow().currentSeq) {
|
|
176
193
|
(0, core_utils_1.assert)(this.isAttached(), 0x1e2 /* "Caller must ensure 'isAttached()' before calling 'sendSetCellOp'." */);
|
|
@@ -179,6 +196,7 @@ class SharedMatrix extends shared_object_base_1.SharedObject {
|
|
|
179
196
|
row,
|
|
180
197
|
col,
|
|
181
198
|
value,
|
|
199
|
+
fwwMode: this.userSwitchedSetCellPolicy || this.setCellLwwToFwwPolicySwitchOpSeqNumber > -1,
|
|
182
200
|
};
|
|
183
201
|
const metadata = {
|
|
184
202
|
rowHandle,
|
|
@@ -186,10 +204,26 @@ class SharedMatrix extends shared_object_base_1.SharedObject {
|
|
|
186
204
|
localSeq,
|
|
187
205
|
rowsRefSeq,
|
|
188
206
|
colsRefSeq,
|
|
207
|
+
referenceSeqNumber: this.runtime.deltaManager.lastSequenceNumber,
|
|
189
208
|
};
|
|
190
209
|
this.submitLocalMessage(op, metadata);
|
|
191
210
|
this.pending.setCell(rowHandle, colHandle, localSeq);
|
|
192
211
|
}
|
|
212
|
+
/**
|
|
213
|
+
* This makes sure that the code inside the callback is not reentrant. We need to do that because we raise notifications
|
|
214
|
+
* to the consumers telling about these changes and they can try to change the matrix while listening to those notifications
|
|
215
|
+
* which can make the shared matrix to be in bad state. For example, we are raising notification for a setCell changes and
|
|
216
|
+
* a consumer tries to delete that row/col on receiving that notification which can lead to this matrix trying to setCell in
|
|
217
|
+
* a deleted row/col.
|
|
218
|
+
* @param callback - code that needs to protected against reentrancy.
|
|
219
|
+
*/
|
|
220
|
+
protectAgainstReentrancy(callback) {
|
|
221
|
+
(0, core_utils_1.assert)(this.reentrantCount === 0, 0x85d /* reentrant code */);
|
|
222
|
+
this.reentrantCount++;
|
|
223
|
+
callback();
|
|
224
|
+
this.reentrantCount--;
|
|
225
|
+
(0, core_utils_1.assert)(this.reentrantCount === 0, 0x85e /* reentrant code on exit */);
|
|
226
|
+
}
|
|
193
227
|
submitVectorMessage(currentVector, oppositeVector, dimension, message) {
|
|
194
228
|
// Ideally, we would have a single 'localSeq' counter that is shared between both PermutationVectors
|
|
195
229
|
// and the SharedMatrix's cell data. Instead, we externally advance each MergeTree's 'localSeq' counter
|
|
@@ -212,21 +246,21 @@ class SharedMatrix extends shared_object_base_1.SharedObject {
|
|
|
212
246
|
this.submitVectorMessage(this.cols, this.rows, "cols" /* SnapshotPath.cols */, message);
|
|
213
247
|
}
|
|
214
248
|
insertCols(colStart, count) {
|
|
215
|
-
this.submitColMessage(this.cols.insert(colStart, count));
|
|
249
|
+
this.protectAgainstReentrancy(() => this.submitColMessage(this.cols.insert(colStart, count)));
|
|
216
250
|
}
|
|
217
251
|
removeCols(colStart, count) {
|
|
218
|
-
this.submitColMessage(this.cols.remove(colStart, count));
|
|
252
|
+
this.protectAgainstReentrancy(() => this.submitColMessage(this.cols.remove(colStart, count)));
|
|
219
253
|
}
|
|
220
254
|
submitRowMessage(message) {
|
|
221
255
|
this.submitVectorMessage(this.rows, this.cols, "rows" /* SnapshotPath.rows */, message);
|
|
222
256
|
}
|
|
223
257
|
insertRows(rowStart, count) {
|
|
224
|
-
this.submitRowMessage(this.rows.insert(rowStart, count));
|
|
258
|
+
this.protectAgainstReentrancy(() => this.submitRowMessage(this.rows.insert(rowStart, count)));
|
|
225
259
|
}
|
|
226
260
|
removeRows(rowStart, count) {
|
|
227
|
-
this.submitRowMessage(this.rows.remove(rowStart, count));
|
|
261
|
+
this.protectAgainstReentrancy(() => this.submitRowMessage(this.rows.remove(rowStart, count)));
|
|
228
262
|
}
|
|
229
|
-
|
|
263
|
+
/***/ _undoRemoveRows(rowStart, spec) {
|
|
230
264
|
const { op, inserted } = (0, permutationvector_1.reinsertSegmentIntoVector)(this.rows, rowStart, spec);
|
|
231
265
|
this.submitRowMessage(op);
|
|
232
266
|
// Generate setCell ops for each populated cell in the reinserted rows.
|
|
@@ -246,7 +280,7 @@ class SharedMatrix extends shared_object_base_1.SharedObject {
|
|
|
246
280
|
consumer.cellsChanged(rowStart, /* colStart: */ 0, rowCount, this.colCount, this);
|
|
247
281
|
}
|
|
248
282
|
}
|
|
249
|
-
|
|
283
|
+
/***/ _undoRemoveCols(colStart, spec) {
|
|
250
284
|
const { op, inserted } = (0, permutationvector_1.reinsertSegmentIntoVector)(this.cols, colStart, spec);
|
|
251
285
|
this.submitColMessage(op);
|
|
252
286
|
// Generate setCell ops for each populated cell in the reinserted cols.
|
|
@@ -270,7 +304,16 @@ class SharedMatrix extends shared_object_base_1.SharedObject {
|
|
|
270
304
|
const builder = new runtime_utils_1.SummaryTreeBuilder();
|
|
271
305
|
builder.addWithStats("rows" /* SnapshotPath.rows */, this.rows.summarize(this.runtime, this.handle, serializer));
|
|
272
306
|
builder.addWithStats("cols" /* SnapshotPath.cols */, this.cols.summarize(this.runtime, this.handle, serializer));
|
|
273
|
-
|
|
307
|
+
const artifactsToSummarize = [
|
|
308
|
+
this.cells.snapshot(),
|
|
309
|
+
this.pending.snapshot(),
|
|
310
|
+
this.setCellLwwToFwwPolicySwitchOpSeqNumber,
|
|
311
|
+
];
|
|
312
|
+
// Only need to store it in the snapshot if we have switched the policy already.
|
|
313
|
+
if (this.setCellLwwToFwwPolicySwitchOpSeqNumber > -1) {
|
|
314
|
+
artifactsToSummarize.push(this.cellLastWriteTracker.snapshot());
|
|
315
|
+
}
|
|
316
|
+
builder.addBlob("cells" /* SnapshotPath.cells */, serializer.stringify(artifactsToSummarize, this.handle));
|
|
274
317
|
return builder.getSummaryTree();
|
|
275
318
|
}
|
|
276
319
|
/**
|
|
@@ -339,16 +382,27 @@ class SharedMatrix extends shared_object_base_1.SharedObject {
|
|
|
339
382
|
default: {
|
|
340
383
|
(0, core_utils_1.assert)(content.type === ops_1.MatrixOp.set, 0x020 /* "Unknown SharedMatrix 'op' type." */);
|
|
341
384
|
const setOp = content;
|
|
342
|
-
const { rowHandle, colHandle, localSeq, rowsRefSeq, colsRefSeq } = localOpMetadata;
|
|
343
|
-
// If
|
|
344
|
-
//
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
const
|
|
349
|
-
|
|
385
|
+
const { rowHandle, colHandle, localSeq, rowsRefSeq, colsRefSeq, referenceSeqNumber, } = localOpMetadata;
|
|
386
|
+
// If after rebasing the op, we get a valid row/col number, that means the row/col
|
|
387
|
+
// handles have not been recycled and we can safely use them.
|
|
388
|
+
const row = this.rebasePosition(this.rows, setOp.row, rowsRefSeq, localSeq);
|
|
389
|
+
const col = this.rebasePosition(this.cols, setOp.col, colsRefSeq, localSeq);
|
|
390
|
+
if (row !== undefined && col !== undefined && row >= 0 && col >= 0) {
|
|
391
|
+
const lastCellModificationDetails = this.cellLastWriteTracker.getCell(rowHandle, colHandle);
|
|
392
|
+
// If the mode is LWW, then send the op.
|
|
393
|
+
// Otherwise if the current mode is FWW and if we generated this op, after seeing the
|
|
394
|
+
// last set op, or it is the first set op for the cell, then regenerate the op,
|
|
395
|
+
// otherwise raise conflict. We want to check the current mode here and not that
|
|
396
|
+
// whether op was made in FWW or not.
|
|
397
|
+
if (this.setCellLwwToFwwPolicySwitchOpSeqNumber === -1 ||
|
|
398
|
+
lastCellModificationDetails === undefined ||
|
|
399
|
+
referenceSeqNumber >= lastCellModificationDetails.seqNum) {
|
|
350
400
|
this.sendSetCellOp(row, col, setOp.value, rowHandle, colHandle, localSeq, rowsRefSeq, colsRefSeq);
|
|
351
401
|
}
|
|
402
|
+
else if (this.pending.getCell(rowHandle, colHandle) !== undefined) {
|
|
403
|
+
// Clear the pending changes if any as we are not sending the op.
|
|
404
|
+
this.pending.setCell(rowHandle, colHandle, undefined);
|
|
405
|
+
}
|
|
352
406
|
}
|
|
353
407
|
break;
|
|
354
408
|
}
|
|
@@ -362,14 +416,32 @@ class SharedMatrix extends shared_object_base_1.SharedObject {
|
|
|
362
416
|
try {
|
|
363
417
|
await this.rows.load(this.runtime, new runtime_utils_1.ObjectStoragePartition(storage, "rows" /* SnapshotPath.rows */), this.serializer);
|
|
364
418
|
await this.cols.load(this.runtime, new runtime_utils_1.ObjectStoragePartition(storage, "cols" /* SnapshotPath.cols */), this.serializer);
|
|
365
|
-
const [cellData,
|
|
419
|
+
const [cellData, _pendingCliSeqData, setCellLwwToFwwPolicySwitchOpSeqNumber, cellLastWriteTracker,] = await (0, serialization_1.deserializeBlob)(storage, "cells" /* SnapshotPath.cells */, this.serializer);
|
|
366
420
|
this.cells = sparsearray2d_1.SparseArray2D.load(cellData);
|
|
367
|
-
this.
|
|
421
|
+
this.setCellLwwToFwwPolicySwitchOpSeqNumber =
|
|
422
|
+
setCellLwwToFwwPolicySwitchOpSeqNumber ?? -1;
|
|
423
|
+
if (cellLastWriteTracker !== undefined) {
|
|
424
|
+
this.cellLastWriteTracker = sparsearray2d_1.SparseArray2D.load(cellLastWriteTracker);
|
|
425
|
+
}
|
|
368
426
|
}
|
|
369
427
|
catch (error) {
|
|
370
428
|
this.logger.sendErrorEvent({ eventName: "MatrixLoadFailed" }, error);
|
|
371
429
|
}
|
|
372
430
|
}
|
|
431
|
+
/**
|
|
432
|
+
* Tells whether the setCell op should be applied or not based on First Write Win policy. It assumes
|
|
433
|
+
* we are in FWW mode.
|
|
434
|
+
*/
|
|
435
|
+
shouldSetCellBasedOnFWW(rowHandle, colHandle, message) {
|
|
436
|
+
(0, core_utils_1.assert)(this.setCellLwwToFwwPolicySwitchOpSeqNumber > -1, 0x85f /* should be in Fww mode when calling this method */);
|
|
437
|
+
(0, core_utils_1.assert)(message.clientId !== null, 0x860 /* clientId should not be null */);
|
|
438
|
+
const lastCellModificationDetails = this.cellLastWriteTracker.getCell(rowHandle, colHandle);
|
|
439
|
+
// If someone tried to Overwrite the cell value or first write on this cell or
|
|
440
|
+
// same client tried to modify the cell.
|
|
441
|
+
return (lastCellModificationDetails === undefined ||
|
|
442
|
+
lastCellModificationDetails.clientId === message.clientId ||
|
|
443
|
+
message.referenceSequenceNumber >= lastCellModificationDetails.seqNum);
|
|
444
|
+
}
|
|
373
445
|
processCore(rawMessage, local, localOpMetadata) {
|
|
374
446
|
const msg = (0, shared_object_base_1.parseHandles)(rawMessage, this.serializer);
|
|
375
447
|
const contents = msg.contents;
|
|
@@ -382,13 +454,28 @@ class SharedMatrix extends shared_object_base_1.SharedObject {
|
|
|
382
454
|
break;
|
|
383
455
|
default: {
|
|
384
456
|
(0, core_utils_1.assert)(contents.type === ops_1.MatrixOp.set, 0x021 /* "SharedMatrix message contents have unexpected type!" */);
|
|
385
|
-
const { row, col } = contents;
|
|
457
|
+
const { row, col, value, fwwMode } = contents;
|
|
458
|
+
const isPreviousSetCellPolicyModeFWW = this.setCellLwwToFwwPolicySwitchOpSeqNumber > -1;
|
|
459
|
+
// If this is the first op notifying us of the policy change, then set the policy change seq number.
|
|
460
|
+
if (this.setCellLwwToFwwPolicySwitchOpSeqNumber === -1 && fwwMode === true) {
|
|
461
|
+
this.setCellLwwToFwwPolicySwitchOpSeqNumber = rawMessage.sequenceNumber;
|
|
462
|
+
}
|
|
463
|
+
(0, core_utils_1.assert)(rawMessage.clientId !== null, 0x861 /* clientId should not be null!! */);
|
|
386
464
|
if (local) {
|
|
387
465
|
// We are receiving the ACK for a local pending set operation.
|
|
388
466
|
const { rowHandle, colHandle, localSeq } = localOpMetadata;
|
|
389
|
-
|
|
390
|
-
//
|
|
391
|
-
|
|
467
|
+
const isLatestPendingOp = this.isLatestPendingWrite(rowHandle, colHandle, localSeq);
|
|
468
|
+
// If policy is switched and cell should be modified too based on policy, then update the tracker.
|
|
469
|
+
// If policy is not switched, then also update the tracker in case it is the latest.
|
|
470
|
+
if ((this.setCellLwwToFwwPolicySwitchOpSeqNumber > -1 &&
|
|
471
|
+
this.shouldSetCellBasedOnFWW(rowHandle, colHandle, rawMessage)) ||
|
|
472
|
+
(this.setCellLwwToFwwPolicySwitchOpSeqNumber === -1 && isLatestPendingOp)) {
|
|
473
|
+
this.cellLastWriteTracker.setCell(rowHandle, colHandle, {
|
|
474
|
+
seqNum: rawMessage.sequenceNumber,
|
|
475
|
+
clientId: rawMessage.clientId,
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
if (isLatestPendingOp) {
|
|
392
479
|
this.pending.setCell(rowHandle, colHandle, undefined);
|
|
393
480
|
}
|
|
394
481
|
}
|
|
@@ -400,11 +487,39 @@ class SharedMatrix extends shared_object_base_1.SharedObject {
|
|
|
400
487
|
const rowHandle = this.rows.getAllocatedHandle(adjustedRow);
|
|
401
488
|
const colHandle = this.cols.getAllocatedHandle(adjustedCol);
|
|
402
489
|
(0, core_utils_1.assert)((0, handletable_1.isHandleValid)(rowHandle) && (0, handletable_1.isHandleValid)(colHandle), 0x022 /* "SharedMatrix row and/or col handles are invalid!" */);
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
490
|
+
if (this.setCellLwwToFwwPolicySwitchOpSeqNumber > -1) {
|
|
491
|
+
// If someone tried to Overwrite the cell value or first write on this cell or
|
|
492
|
+
// same client tried to modify the cell or if the previous mode was LWW, then we need to still
|
|
493
|
+
// overwrite the cell and raise conflict if we have pending changes as our change is going to be lost.
|
|
494
|
+
if (!isPreviousSetCellPolicyModeFWW ||
|
|
495
|
+
this.shouldSetCellBasedOnFWW(rowHandle, colHandle, rawMessage)) {
|
|
496
|
+
const previousValue = this.cells.getCell(rowHandle, colHandle);
|
|
497
|
+
this.cells.setCell(rowHandle, colHandle, value);
|
|
498
|
+
this.cellLastWriteTracker.setCell(rowHandle, colHandle, {
|
|
499
|
+
seqNum: rawMessage.sequenceNumber,
|
|
500
|
+
clientId: rawMessage.clientId,
|
|
501
|
+
});
|
|
502
|
+
for (const consumer of this.consumers.values()) {
|
|
503
|
+
consumer.cellsChanged(adjustedRow, adjustedCol, 1, 1, this);
|
|
504
|
+
}
|
|
505
|
+
// Check is there are any pending changes, which will be rejected. If so raise conflict.
|
|
506
|
+
if (this.pending.getCell(rowHandle, colHandle) !== undefined) {
|
|
507
|
+
// Don't reset the pending value yet, as there maybe more fww op from same client, so we want
|
|
508
|
+
// to raise conflict event for that op also.
|
|
509
|
+
this.emit("conflict", row, col, value, // Current value
|
|
510
|
+
previousValue, // Ignored local value
|
|
511
|
+
this);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
else if (this.pending.getCell(rowHandle, colHandle) === undefined) {
|
|
516
|
+
// If there is a pending (unACKed) local write to the same cell, skip the current op
|
|
517
|
+
// since it "happened before" the pending write.
|
|
407
518
|
this.cells.setCell(rowHandle, colHandle, value);
|
|
519
|
+
this.cellLastWriteTracker.setCell(rowHandle, colHandle, {
|
|
520
|
+
seqNum: rawMessage.sequenceNumber,
|
|
521
|
+
clientId: rawMessage.clientId,
|
|
522
|
+
});
|
|
408
523
|
for (const consumer of this.consumers.values()) {
|
|
409
524
|
consumer.cellsChanged(adjustedRow, adjustedCol, 1, 1, this);
|
|
410
525
|
}
|
|
@@ -415,6 +530,20 @@ class SharedMatrix extends shared_object_base_1.SharedObject {
|
|
|
415
530
|
}
|
|
416
531
|
}
|
|
417
532
|
}
|
|
533
|
+
/**
|
|
534
|
+
* Api to switch Set Op policy from Last Writer Win to First Writer Win. It only switches from LWW to FWW
|
|
535
|
+
* and not from FWW to LWW. The next SetOp which is sent will communicate this policy to other clients.
|
|
536
|
+
*/
|
|
537
|
+
switchSetCellPolicy() {
|
|
538
|
+
if (this.setCellLwwToFwwPolicySwitchOpSeqNumber === -1) {
|
|
539
|
+
if (this.isAttached()) {
|
|
540
|
+
this.userSwitchedSetCellPolicy = true;
|
|
541
|
+
}
|
|
542
|
+
else {
|
|
543
|
+
this.setCellLwwToFwwPolicySwitchOpSeqNumber = 0;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
418
547
|
/**
|
|
419
548
|
* Returns true if the latest pending write to the cell indicated by the given row/col handles
|
|
420
549
|
* matches the given 'localSeq'.
|
|
@@ -487,6 +616,7 @@ class SharedMatrix extends shared_object_base_1.SharedObject {
|
|
|
487
616
|
localSeq,
|
|
488
617
|
rowsRefSeq,
|
|
489
618
|
colsRefSeq,
|
|
619
|
+
referenceSeqNumber: this.runtime.deltaManager.lastSequenceNumber,
|
|
490
620
|
};
|
|
491
621
|
this.pending.setCell(rowHandle, colHandle, localSeq);
|
|
492
622
|
return metadata;
|
|
@@ -494,4 +624,4 @@ class SharedMatrix extends shared_object_base_1.SharedObject {
|
|
|
494
624
|
}
|
|
495
625
|
}
|
|
496
626
|
exports.SharedMatrix = SharedMatrix;
|
|
497
|
-
//# sourceMappingURL=matrix.
|
|
627
|
+
//# sourceMappingURL=matrix.cjs.map
|