/*! * Copyright (c) Microsoft Corporation and contributors. All rights reserved. * Licensed under the MIT License. */ import type { IEvent, IEventThisPlaceHolder, IEventProvider } from "@fluidframework/core-interfaces"; import type { IChannelAttributes, IFluidDataStoreRuntime, IChannel, IChannelStorageService } from "@fluidframework/datastore-definitions/internal"; import { type IJSONSegment } from "@fluidframework/merge-tree/internal"; import type { ISummaryTreeWithStats, IRuntimeMessageCollection } from "@fluidframework/runtime-definitions/internal"; import { type IFluidSerializer, type ISharedObjectEvents, SharedObject } from "@fluidframework/shared-object-base/internal"; import type { IMatrixConsumer, IMatrixProducer, IMatrixReader, IMatrixWriter } from "@tiny-calc/nano"; import { type MatrixItem } from "./ops.js"; import type { IUndoConsumer } from "./types.js"; /** * Events emitted by Shared Matrix. * @legacy @beta */ export interface ISharedMatrixEvents extends IEvent { /** * This event is only emitted when the SetCell Resolution Policy is First Write Win(FWW). * This is emitted when two clients race and send changes without observing each other changes, * the changes that gets sequenced last would be rejected, and only client who's changes rejected * would be notified via this event, with expectation that it will merge its changes back by * accounting new information (state from winner of the race). * * @remarks Listener parameters: * * - `row` - Row number at which conflict happened. * * - `col` - Col number at which conflict happened. * * - `currentValue` - The current value of the cell. * * - `conflictingValue` - The value that this client tried to set in the cell and got ignored due to conflict. * * - `target` - The {@link ISharedMatrix} itself. */ (event: "conflict", listener: (row: number, col: number, currentValue: MatrixItem, conflictingValue: MatrixItem, target: IEventThisPlaceHolder) => void): void; } /** * @legacy @beta */ export interface ISharedMatrix extends IEventProvider>, IMatrixProducer>, IMatrixReader>, IMatrixWriter>, IChannel { /** * Inserts columns into the matrix. * @param colStart - Index of the first column to insert. * @param count - Number of columns to insert. * @remarks * Inserting 0 columns is a noop. */ insertCols(colStart: number, count: number): void; /** * Removes columns from the matrix. * @param colStart - Index of the first column to remove. * @param count - Number of columns to remove. * @remarks * Removing 0 columns is a noop. */ removeCols(colStart: number, count: number): void; /** * Inserts rows into the matrix. * @param rowStart - Index of the first row to insert. * @param count - Number of rows to insert. * @remarks * Inserting 0 rows is a noop. */ insertRows(rowStart: number, count: number): void; /** * Removes rows from the matrix. * @param rowStart - Index of the first row to remove. * @param count - Number of rows to remove. * @remarks * Removing 0 rows is a noop. */ removeRows(rowStart: number, count: number): void; /** * Sets a range of cells in the matrix. * Cells are set in consecutive columns between `colStart` and `colStart + colCount - 1`. * When `values` has larger size than `colCount`, the extra values are inserted in subsequent rows * a la text-wrapping. * @param rowStart - Index of the row to start setting cells. * @param colStart - Index of the column to start setting cells. * @param colCount - Number of columns to set before wrapping to subsequent rows (if `values` has more items) * @param values - Values to insert. * @remarks * This is not currently more efficient than calling `setCell` for each cell. */ setCells(rowStart: number, colStart: number, colCount: number, values: readonly MatrixItem[]): void; /** * Attach an {@link IUndoConsumer} to the matrix. * @param consumer - Undo consumer which will receive revertibles from the matrix. */ openUndo(consumer: IUndoConsumer): void; /** * Whether the current conflict resolution policy is first-write win (FWW). * See {@link ISharedMatrix.switchSetCellPolicy} for more details. */ isSetCellConflictResolutionPolicyFWW(): boolean; /** * Change the conflict resolution policy for setCell operations to first-write win (FWW). * * This API only switches from LWW to FWW and not from FWW to LWW. * * @privateRemarks * The next SetOp which is sent will communicate this policy to other clients. */ switchSetCellPolicy(): void; } /** * A SharedMatrix holds a rectangular 2D array of values. Supported operations * include setting values and inserting/removing rows and columns. * * Matrix values may be any Fluid serializable type, which is the set of JSON * serializable types extended to include IFluidHandles. * * Fluid's SharedMatrix implementation works equally well for dense and sparse * matrix data and physically stores data in Z-order to leverage CPU caches and * prefetching when reading in either row or column major order. (See README.md * for more details.) * @legacy @beta */ export declare class SharedMatrix extends SharedObject & ISharedObjectEvents> implements ISharedMatrix { id: string; private readonly consumers; /** * Note: this field only provides a lower-bound on the reference sequence numbers for in-flight ops. * The exact reason isn't understood, but some e2e tests suggest that the runtime may sometimes process * incoming leave/join ops before putting an op that this DDS submits over the wire. * * E.g. SharedMatrix submits an op while deltaManager has lastSequenceNumber = 10, but before the runtime * puts this op over the wire, it processes a client join/leave op with sequence number 11, so the referenceSequenceNumber * on the SharedMatrix op is 11. */ private readonly inFlightRefSeqs; readonly getMinInFlightRefSeq: () => number | undefined; private readonly rows; private readonly cols; private cells; private readonly pending; private fwwPolicy; private reentrantCount; /** * Constructor for the Shared Matrix * @param runtime - DataStore runtime. * @param id - id of the dds * @param attributes - channel attributes * @param _isSetCellConflictResolutionPolicyFWW - Conflict resolution for Matrix set op is First Writer Win in case of * race condition. Client can still overwrite values in case of no race. */ constructor(runtime: IFluidDataStoreRuntime, id: string, attributes: IChannelAttributes); private undo?; /** * Subscribes the given IUndoConsumer to the matrix. */ openUndo(consumer: IUndoConsumer): void; private get rowHandles(); private get colHandles(); openMatrix(consumer: IMatrixConsumer>): IMatrixReader>; closeMatrix(consumer: IMatrixConsumer>): void; get rowCount(): number; get colCount(): number; isSetCellConflictResolutionPolicyFWW(): boolean; getCell(row: number, col: number): MatrixItem; get matrixProducer(): IMatrixProducer>; setCell(row: number, col: number, value: MatrixItem): void; setCells(rowStart: number, colStart: number, colCount: number, values: readonly MatrixItem[]): void; private setCellCore; private createOpMetadataLocalRef; private sendSetCellOp; /** * This makes sure that the code inside the callback is not reentrant. We need to do that because we raise notifications * to the consumers telling about these changes and they can try to change the matrix while listening to those notifications * which can make the shared matrix to be in bad state. For example, we are raising notification for a setCell changes and * a consumer tries to delete that row/col on receiving that notification which can lead to this matrix trying to setCell in * a deleted row/col. * @param callback - code that needs to protected against reentrancy. */ private protectAgainstReentrancy; private submitVectorMessage; private submitColMessage; insertCols(colStart: number, count: number): void; removeCols(colStart: number, count: number): void; private submitRowMessage; insertRows(rowStart: number, count: number): void; removeRows(rowStart: number, count: number): void; _undoRemoveRows(rowStart: number, spec: IJSONSegment): void; /***/ _undoRemoveCols(colStart: number, spec: IJSONSegment): void; protected summarizeCore(serializer: IFluidSerializer): ISummaryTreeWithStats; /** * Runs serializer on the GC data for this SharedMatrix. * All the IFluidHandle's stored in the cells represent routes to other objects. */ protected processGCDataCore(serializer: IFluidSerializer): void; /** * Advances the 'localSeq' counter for the cell data operation currently being queued. * * Do not use with 'submitColMessage()/submitRowMessage()' as these helpers + the MergeTree will * automatically advance 'localSeq'. */ private nextLocalSeq; protected submitLocalMessage(message: unknown, localOpMetadata?: unknown): void; protected didAttach(): void; protected onConnect(): void; private rebasePosition; protected reSubmitCore(incoming: unknown, localOpMetadata: unknown): void; protected rollback(content: unknown, localOpMetadata: unknown): void; protected onDisconnect(): void; /** * {@inheritDoc @fluidframework/shared-object-base#SharedObject.loadCore} */ protected loadCore(storage: IChannelStorageService): Promise; /** * Tells whether the setCell op should be applied or not based on First Write Win policy. It assumes * we are in FWW mode. */ private shouldSetCellBasedOnFWW; protected processMessagesCore(messagesCollection: IRuntimeMessageCollection): void; private processMessage; private readonly onRowDelta; private readonly onColDelta; private readonly onRowHandlesRecycled; private readonly onColHandlesRecycled; switchSetCellPolicy(): void; toString(): string; /** * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.applyStashedOp} */ protected applyStashedOp(_content: unknown): void; } //# sourceMappingURL=matrix.d.ts.map