/*! * Copyright (c) Microsoft Corporation and contributors. All rights reserved. * Licensed under the MIT License. */ import { TypedEventEmitter, type ILayerCompatDetails, type IProvideLayerCompatDetails } from "@fluid-internal/client-utils"; import { AttachState, type IAudience } from "@fluidframework/container-definitions"; import { type IDeltaManager } from "@fluidframework/container-definitions/internal"; import type { FluidObject, IDisposable, IEvent } from "@fluidframework/core-interfaces"; import type { IFluidHandleContext, IFluidHandleInternal, ITelemetryBaseLogger } from "@fluidframework/core-interfaces/internal"; import type { IClientDetails, IQuorumClients } from "@fluidframework/driver-definitions"; import type { ISnapshot, IDocumentMessage, ISnapshotTree, ITreeEntry, ISequencedDocumentMessage } from "@fluidframework/driver-definitions/internal"; import type { IIdCompressor } from "@fluidframework/id-compressor"; import type { FluidDataStoreMessage, ISummaryTreeWithStats, ITelemetryContext, IGarbageCollectionData, CreateChildSummarizerNodeFn, CreateChildSummarizerNodeParam, FluidDataStoreContextInternal, IContainerRuntimeBase, IDataStore, IFluidDataStoreChannel, IFluidDataStoreContextDetached, IFluidDataStoreRegistry, IGarbageCollectionDetailsBase, IProvideFluidDataStoreFactory, ISummarizeResult, ISummarizerNodeWithGC, SummarizeInternalFn, IInboundSignalMessage, IRuntimeMessageCollection, IFluidDataStoreFactory, PackagePath, IRuntimeStorageService, MinimumVersionForCollab, ContainerExtensionId, ContainerExtensionExpectations } from "@fluidframework/runtime-definitions/internal"; import { type MonitoringContext } from "@fluidframework/telemetry-utils/internal"; import type { IFluidParentContextPrivate } from "./channelCollection.js"; export declare function createAttributesBlob(pkg: readonly string[], isRootDataStore: boolean): ITreeEntry; export interface ISnapshotDetails { pkg: readonly string[]; isRootDataStore: boolean; snapshot?: ISnapshotTree; sequenceNumber?: number; } /** * This is interface that every context should implement. * This interface is used for context's parent - ChannelCollection. * It should not be exposed to any other users of context. */ export interface IFluidDataStoreContextPrivate extends FluidDataStoreContextInternal { getAttachSummary(telemetryContext?: ITelemetryContext): ISummaryTreeWithStats; getAttachGCData(telemetryContext?: ITelemetryContext): IGarbageCollectionData; getInitialSnapshotDetails(): Promise; realize(): Promise; isRoot(): Promise; } /** * Properties necessary for creating a FluidDataStoreContext */ export interface IFluidDataStoreContextProps { readonly id: string; readonly parentContext: IFluidParentContextPrivate; readonly storage: IRuntimeStorageService; readonly scope: FluidObject; readonly createSummarizerNodeFn: CreateChildSummarizerNodeFn; /** * See {@link FluidDataStoreContext.pkg}. */ readonly pkg?: PackagePath; /** * See {@link FluidDataStoreContext.loadingGroupId}. */ readonly loadingGroupId?: string; } /** * Properties necessary for creating a local FluidDataStoreContext */ export interface ILocalFluidDataStoreContextProps extends IFluidDataStoreContextProps { readonly pkg: readonly string[] | undefined; readonly snapshotTree: ISnapshotTree | undefined; readonly makeLocallyVisibleFn: () => void; } /** * Properties necessary for creating a local FluidDataStoreContext */ export interface ILocalDetachedFluidDataStoreContextProps extends ILocalFluidDataStoreContextProps { readonly channelToDataStoreFn: (channel: IFluidDataStoreChannel) => IDataStore; } /** * Properties necessary for creating a remote FluidDataStoreContext */ export interface IRemoteFluidDataStoreContextProps extends IFluidDataStoreContextProps { readonly snapshot: ISnapshotTree | ISnapshot | undefined; } export interface IFluidDataStoreContextEvents extends IEvent { (event: "attaching" | "attached", listener: () => void): any; } /** * {@link IFluidDataStoreContext} for the implementations of {@link IFluidDataStoreChannel} which powers the {@link IDataStore}s. */ export declare abstract class FluidDataStoreContext extends TypedEventEmitter implements IFluidDataStoreContextPrivate, IDisposable, IProvideLayerCompatDetails { private readonly existing; readonly isLocalDataStore: boolean; private readonly makeLocallyVisibleFn; get packagePath(): PackagePath; get options(): Record; get clientId(): string | undefined; get clientDetails(): IClientDetails; get baseLogger(): ITelemetryBaseLogger; private readonly _contextDeltaManagerProxy; get deltaManager(): IDeltaManager; private isStagingMode; isReadOnly: () => boolean; get connected(): boolean; get IFluidHandleContext(): IFluidHandleContext; get containerRuntime(): IContainerRuntimeBase; get isLoaded(): boolean; get baseSnapshot(): ISnapshotTree | undefined; get idCompressor(): IIdCompressor | undefined; private _disposed; get disposed(): boolean; /** * A Tombstoned object has been unreferenced long enough that GC knows it won't be referenced again. * Tombstoned objects are eventually deleted by GC. */ private _tombstoned; get tombstoned(): boolean; /** * If true, throw an error when a tombstone data store is used. * @deprecated NOT SUPPORTED - hardcoded to return false since it's deprecated. */ readonly gcThrowOnTombstoneUsage: boolean; /** * @deprecated NOT SUPPORTED - hardcoded to return false since it's deprecated. */ readonly gcTombstoneEnforcementAllowed: boolean; /** * If true, this means that this data store context and its children have been removed from the runtime */ protected deleted: boolean; get attachState(): AttachState; get IFluidDataStoreRegistry(): IFluidDataStoreRegistry | undefined; /** * The compatibility details of the Runtime layer that is exposed to the DataStore layer * for validating DataStore-Runtime compatibility. */ get ILayerCompatDetails(): ILayerCompatDetails; /** * {@inheritdoc IFluidDataStoreContext.minVersionForCollab} */ readonly minVersionForCollab: MinimumVersionForCollab; private baseSnapshotSequenceNumber; /** * A datastore is considered as root if it * 1. is root in memory - see isInMemoryRoot * 2. is root as part of the base snapshot that the datastore loaded from * @returns whether a datastore is root */ isRoot(aliasedDataStores?: Set): Promise; /** * There are 3 states where isInMemoryRoot needs to be true * 1. when a datastore becomes aliased. This can happen for both remote and local datastores * 2. when a datastore is created locally as root * 3. when a datastore is created locally as root and is rehydrated * @returns whether a datastore is root in memory */ protected isInMemoryRoot(): boolean; /** * Returns the count of pending messages that are stored until the data store is realized. */ get pendingCount(): number; protected registry: IFluidDataStoreRegistry | undefined; protected detachedRuntimeCreation: boolean; protected channel: IFluidDataStoreChannel | undefined; private loaded; /** * Tracks the messages for this data store that are sent while it's not loaded */ private pendingMessagesState; protected channelP: Promise | undefined; protected _baseSnapshot: ISnapshotTree | undefined; protected _attachState: AttachState; private _isInMemoryRoot; protected readonly summarizerNode: ISummarizerNodeWithGC; protected readonly mc: MonitoringContext; private readonly thresholdOpsCounter; private static readonly pendingOpsCountThreshold; /** * If the summarizer makes local changes, a telemetry event is logged. This has the potential to be very noisy. * So, adding a count of how many telemetry events are logged per data store context. This can be * controlled via feature flags. */ private localChangesTelemetryCount; readonly id: string; private readonly _containerRuntime; /** * Information for this data store from its parent. * * @remarks * The parent which provided this information currently can be the container runtime or a datastore (if the datastore this context is for is nested under another one). */ private readonly parentContext; readonly storage: IRuntimeStorageService; readonly scope: FluidObject; /** * The loading group to which the data store belongs to. */ readonly loadingGroupId: string | undefined; /** * {@link PackagePath} of this data store. * * This can be undefined when a data store is delay loaded, i.e., the attributes of this data store in the snapshot are not fetched until this data store is actually used. * At that time, the attributes blob is fetched and the pkg is updated from it. * * @see {@link PackagePath}. * @see {@link IFluidDataStoreContext.packagePath}. * @see {@link factoryFromPackagePath}. */ protected pkg?: PackagePath; constructor(props: IFluidDataStoreContextProps, existing: boolean, isLocalDataStore: boolean, makeLocallyVisibleFn: () => void); dispose(): void; /** * When delete is called, that means that the data store is permanently removed from the runtime, and will not show up in future summaries * This function is called to prevent ops from being generated from this data store once it has been deleted. Furthermore, this data store * should not receive any ops/signals. */ delete(): void; setTombstone(tombstone: boolean): void; abstract setAttachState(attachState: AttachState.Attaching | AttachState.Attached): void; /** * Throw a {@link LoggingError} indicating that {@link factoryFromPackagePath} failed. */ private factoryFromPackagePathError; realize(): Promise; /** * Gets the factory that would be used to instantiate this data store by calling `instantiateDataStore` based on {@link pkg}. * @remarks * Also populates {@link registry}. * * Must be called after {@link pkg} is set, and only called once. * * @see {@link @fluidframework/container-runtime-definitions#IContainerRuntimeBase.createDataStore}. * @see {@link FluidDataStoreContext.pkg}. */ protected factoryFromPackagePath(): Promise; createChildDataStore(childFactory: T): ReturnType>; private realizeCore; /** * Notifies this object about changes in the connection state. * @param value - New connection state. * @param clientId - ID of the client. Its old ID when in disconnected state and * its new client ID when we are connecting or connected. */ setConnectionState(connected: boolean, clientId?: string): void; notifyReadOnlyState(): void; /** * Updates the readonly state of the data store based on the staging mode. * * @param staging - A boolean indicating whether the container is in staging mode. * If true, the data store is set to readonly unless explicitly allowed by its policies. */ notifyStagingMode(staging: boolean): void; /** * Process messages for this data store. The messages here are contiguous messages for this data store in a batch. * @param messageCollection - The collection of messages to process. */ processMessages(messageCollection: IRuntimeMessageCollection): void; processSignal(message: IInboundSignalMessage, local: boolean): void; getQuorum(): IQuorumClients; getAudience(): IAudience; /** * Returns a summary at the current sequence number. * @param fullTree - true to bypass optimizations and force a full summary tree * @param trackState - This tells whether we should track state from this summary. * @param telemetryContext - summary data passed through the layers for telemetry purposes */ summarize(fullTree?: boolean, trackState?: boolean, telemetryContext?: ITelemetryContext): Promise; private summarizeInternal; /** * Returns the data used for garbage collection. This includes a list of GC nodes that represent this data store * including any of its child channel contexts. Each node has a set of outbound routes to other GC nodes in the * document. * If there is no new data in this data store since the last summary, previous GC data is used. * If there is new data, the GC data is generated again (by calling getGCDataInternal). * @param fullGC - true to bypass optimizations and force full generation of GC data. */ getGCData(fullGC?: boolean): Promise; /** * Generates data used for garbage collection. This is called when there is new data since last summary. It * realizes the data store and calls into each channel context to get its GC data. * @param fullGC - true to bypass optimizations and force full generation of GC data. */ private getGCDataInternal; /** * After GC has run, called to notify the data store of routes used in it. These are used for the following: * 1. To identify if this data store is being referenced in the document or not. * 2. To determine if it needs to re-summarize in case used routes changed since last summary. * 3. To notify child contexts of their used routes. This is done immediately if the data store is loaded. * Else, it is done by the data stores's summarizer node when child summarizer nodes are created. * * @param usedRoutes - The routes that are used in this data store. */ updateUsedRoutes(usedRoutes: string[]): void; /** * Called when a new outbound reference is added to another node. This is used by garbage collection to identify * all references added in the system. * * @param fromPath - The absolute path of the node that added the reference. * @param toPath - The absolute path of the outbound node that is referenced. * @param messageTimestampMs - The timestamp of the message that added the reference. */ addedGCOutboundRoute(fromPath: string, toPath: string, messageTimestampMs?: number): void; submitMessage(type: string, content: unknown, localOpMetadata: unknown): void; /** * This is called from a SharedSummaryBlock that does not generate ops but only wants to be part of the summary. * It indicates that there is data in the object that needs to be summarized. * We will update the latestSequenceNumber of the summary tracker of this * store and of the object's channel. * * @param address - The address of the channel that is dirty. * */ setChannelDirty(address: string): void; submitSignal(type: string, content: unknown, targetClientId?: string): void; /** * This is called by the data store channel when it becomes locally visible indicating that it is ready to become * globally visible now. */ makeLocallyVisible(): void; protected processPendingOps(channel: IFluidDataStoreChannel): void; protected completeBindingRuntime(channel: IFluidDataStoreChannel): void; protected bindRuntime(channel: IFluidDataStoreChannel, existing: boolean): Promise; getAbsoluteUrl(relativeUrl: string): Promise; /** * Get the summary required when attaching this context's DataStore. * Used for both Container Attach and DataStore Attach. */ abstract getAttachSummary(telemetryContext?: ITelemetryContext): ISummaryTreeWithStats; /** * Get the GC Data for the initial state being attached so remote clients can learn of this DataStore's * outbound routes. */ abstract getAttachGCData(telemetryContext?: ITelemetryContext): IGarbageCollectionData; abstract getInitialSnapshotDetails(): Promise; /** * @deprecated Sets the datastore as root, for aliasing purposes: #7948 * This method should not be used outside of the aliasing context. * It will be removed, as the source of truth for this flag will be the aliasing blob. */ setInMemoryRoot(): void; /** * @deprecated The functionality to get base GC details has been moved to summarizer node. */ getBaseGCDetails(): Promise; reSubmit(message: FluidDataStoreMessage, localOpMetadata: unknown, squash: boolean): void; rollback(message: FluidDataStoreMessage, localOpMetadata: unknown): void; applyStashedOp(contents: unknown): Promise; private verifyNotClosed; /** * Readonly client, including summarizer, should not have local changes. These changes can become part of the summary and can break * eventual consistency. For example, the next summary (say at ref seq# 100) may contain these changes whereas * other clients that are up-to-date till seq# 100 may not have them yet. */ protected identifyLocalChangeIfReadonly(eventName: string, type?: string): void; getCreateChildSummarizerNodeFn(id: string, createParam: CreateChildSummarizerNodeParam): (summarizeInternal: SummarizeInternalFn, getGCDataFn: (fullGC?: boolean) => Promise) => ISummarizerNodeWithGC; deleteChildSummarizerNode(id: string): void; uploadBlob(blob: ArrayBufferLike, signal?: AbortSignal): Promise>; getExtension(id: ContainerExtensionId, requirements: ContainerExtensionExpectations, ...context: TUseContext): TInterface; } /** * @internal */ export declare class RemoteFluidDataStoreContext extends FluidDataStoreContext { private snapshotFetchRequired; private readonly runtime; private readonly blobContents; private readonly isSnapshotInISnapshotFormat; constructor(props: IRemoteFluidDataStoreContextProps); /** * This API should not be called for RemoteFluidDataStoreContext. But here is one scenario where it's not the case: * The scenario (hit by stashedOps.spec.ts, "resends attach op" UT is the following (as far as I understand): * * 1. data store is being attached in attached container * * 2. container state is serialized (stashed ops feature) * * 3. new container instance is rehydrated (from stashed ops) - * As result, we create RemoteFluidDataStoreContext for this data store that is actually in "attaching" state * (as of # 2). * But its state is set to attached when loading container from stashed ops. * * 4. attach op for this data store is processed - setAttachState() is called. */ setAttachState(attachState: AttachState.Attaching | AttachState.Attached): void; private readonly initialSnapshotDetailsP; getInitialSnapshotDetails(): Promise; /** * {@inheritDoc FluidDataStoreContext.getAttachSummary} */ getAttachSummary(): ISummaryTreeWithStats; /** * {@inheritDoc FluidDataStoreContext.getAttachGCData} */ getAttachGCData(telemetryContext?: ITelemetryContext): IGarbageCollectionData; } /** * Base class for detached & attached context classes * @internal */ export declare class LocalFluidDataStoreContextBase extends FluidDataStoreContext { private readonly snapshotTree; constructor(props: ILocalFluidDataStoreContextProps); setAttachState(attachState: AttachState.Attaching | AttachState.Attached): void; /** * {@inheritDoc FluidDataStoreContext.getAttachSummary} */ getAttachSummary(telemetryContext?: ITelemetryContext): ISummaryTreeWithStats; /** * {@inheritDoc FluidDataStoreContext.getAttachGCData} */ getAttachGCData(telemetryContext?: ITelemetryContext): IGarbageCollectionData; private readonly initialSnapshotDetailsP; getInitialSnapshotDetails(): Promise; /** * A context should only be marked as deleted when its a remote context. * Session Expiry at the runtime level should have closed the container creating the local data store context * before delete is even possible. Session Expiry is at 30 days, and sweep is done 36+ days later from the time * it was unreferenced. Thus the sweeping container should have loaded from a snapshot and thus creating a remote * context. */ delete(): void; } /** * context implementation for "attached" data store runtime. * Various workflows (snapshot creation, requests) result in .realize() being called * on context, resulting in instantiation and attachment of runtime. * Runtime is created using data store factory that is associated with this context. * @internal */ export declare class LocalFluidDataStoreContext extends LocalFluidDataStoreContextBase { constructor(props: ILocalFluidDataStoreContextProps); } /** * Detached context. Data Store runtime will be attached to it by attachRuntime() call * Before attachment happens, this context is not associated with particular type of runtime * or factory, i.e. it's package path is undefined. * Attachment process provides all missing parts - package path, data store runtime, and data store factory */ export declare class LocalDetachedFluidDataStoreContext extends LocalFluidDataStoreContextBase implements IFluidDataStoreContextDetached { constructor(props: ILocalDetachedFluidDataStoreContextProps); private readonly channelToDataStoreFn; attachRuntime(registry: IProvideFluidDataStoreFactory, dataStoreChannel: IFluidDataStoreChannel): Promise; /** * This method provides a synchronous path for binding a runtime to the context. * * Due to its synchronous nature, it is unable to validate that the runtime * represents a datastore which is instantiable by remote clients. This could * happen if the runtime's package path does not return a factory when looked up * in the container runtime's registry, or if the runtime's entrypoint is not * properly initialized. As both of these validation's are asynchronous to preform. * * If used incorrectly, this function can result in permanent data corruption. */ unsafe_AttachRuntimeSync(channel: IFluidDataStoreChannel): IDataStore; getInitialSnapshotDetails(): Promise; } //# sourceMappingURL=dataStoreContext.d.ts.map