@fluidframework/datastore
Advanced tools
@@ -6,3 +6,3 @@ /*! | ||
import { IDocumentStorageService } from "@fluidframework/driver-definitions"; | ||
import { ISequencedDocumentMessage, ISnapshotTree, ITree } from "@fluidframework/protocol-definitions"; | ||
import { ISequencedDocumentMessage, ISnapshotTree } from "@fluidframework/protocol-definitions"; | ||
import { IChannel } from "@fluidframework/datastore-definitions"; | ||
@@ -16,5 +16,3 @@ import { ISummarizeResult } from "@fluidframework/runtime-definitions"; | ||
processOp(message: ISequencedDocumentMessage, local: boolean, localOpMetadata?: unknown): void; | ||
/** @deprecated in 0.22 summarizerNode */ | ||
snapshot(fullTree?: boolean): Promise<ITree>; | ||
summarize(fullTree?: boolean): Promise<ISummarizeResult>; | ||
summarize(fullTree?: boolean, trackState?: boolean): Promise<ISummarizeResult>; | ||
reSubmit(content: any, localOpMetadata: unknown): void; | ||
@@ -26,3 +24,3 @@ } | ||
}; | ||
export declare function snapshotChannel(channel: IChannel): ITree; | ||
export declare function snapshotChannel(channel: IChannel): import("@fluidframework/protocol-definitions").ITree; | ||
//# sourceMappingURL=channelContext.d.ts.map |
@@ -5,10 +5,10 @@ /*! | ||
*/ | ||
import { EventEmitter } from "events"; | ||
import { ITelemetryLogger } from "@fluidframework/common-definitions"; | ||
import { IFluidHandle, IFluidHandleContext, IRequest, IResponse } from "@fluidframework/core-interfaces"; | ||
import { IAudience, IDeltaManager, ContainerWarning, ILoader, AttachState } from "@fluidframework/container-definitions"; | ||
import { TypedEventEmitter } from "@fluidframework/common-utils"; | ||
import { IClientDetails, IDocumentMessage, IQuorum, ISequencedDocumentMessage, ITreeEntry } from "@fluidframework/protocol-definitions"; | ||
import { IFluidDataStoreContext, IFluidDataStoreChannel, IInboundSignalMessage, ISummaryTreeWithStats } from "@fluidframework/runtime-definitions"; | ||
import { FluidSerializer } from "@fluidframework/runtime-utils"; | ||
import { IChannel, IFluidDataStoreRuntime, IChannelFactory } from "@fluidframework/datastore-definitions"; | ||
import { IChannel, IFluidDataStoreRuntime, IFluidDataStoreRuntimeEvents, IChannelFactory } from "@fluidframework/datastore-definitions"; | ||
export declare enum DataStoreMessageType { | ||
@@ -24,3 +24,3 @@ Attach = "attach", | ||
*/ | ||
export declare class FluidDataStoreRuntime extends EventEmitter implements IFluidDataStoreChannel, IFluidDataStoreRuntime, IFluidHandleContext { | ||
export declare class FluidDataStoreRuntime extends TypedEventEmitter<IFluidDataStoreRuntimeEvents> implements IFluidDataStoreChannel, IFluidDataStoreRuntime, IFluidHandleContext { | ||
private readonly dataStoreContext; | ||
@@ -77,3 +77,2 @@ private readonly sharedObjectRegistry; | ||
private readonly audience; | ||
private readonly snapshotFn; | ||
readonly logger: ITelemetryLogger; | ||
@@ -84,2 +83,7 @@ constructor(dataStoreContext: IFluidDataStoreContext, sharedObjectRegistry: ISharedObjectRegistry); | ||
request(request: IRequest): Promise<IResponse>; | ||
/** | ||
* @deprecated | ||
* Please use mixinRequestHandler() to override default behavior or request() | ||
* // back-compat: remove in 0.30+ | ||
*/ | ||
registerRequestHandler(handler: (request: IRequest) => Promise<IResponse>): void; | ||
@@ -106,3 +110,2 @@ getChannel(id: string): Promise<IChannel>; | ||
getAudience(): IAudience; | ||
snapshot(message: string): Promise<void>; | ||
uploadBlob(blob: ArrayBufferLike): Promise<IFluidHandle<ArrayBufferLike>>; | ||
@@ -113,4 +116,14 @@ process(message: ISequencedDocumentMessage, local: boolean, localOpMetadata: unknown): void; | ||
snapshotInternal(fullTree?: boolean): Promise<ITreeEntry[]>; | ||
summarize(fullTree?: boolean): Promise<ISummaryTreeWithStats>; | ||
/** | ||
* 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. | ||
*/ | ||
summarize(fullTree?: boolean, trackState?: boolean): Promise<ISummaryTreeWithStats>; | ||
/** | ||
* back-compat 0.28 - snapshot is being removed and replaced with summary. | ||
* So, getAttachSnapshot has been deprecated and getAttachSummary should be used instead. | ||
*/ | ||
getAttachSnapshot(): ITreeEntry[]; | ||
getAttachSummary(): ISummaryTreeWithStats; | ||
submitMessage(type: DataStoreMessageType, content: any, localOpMetadata: unknown): void; | ||
@@ -144,12 +157,15 @@ submitSignal(type: string, content: any): void; | ||
* Mixin class that adds request handler to FluidDataStoreRuntime | ||
* Request handler is only called when data store can't resolve request, i.e. for custom requests. | ||
* @param Base - base class, inherits from FluidDataStoreRuntime | ||
* @param requestHandler - request handler to mix in | ||
*/ | ||
export declare function requestFluidDataStoreMixin(Base: typeof FluidDataStoreRuntime, requestHandler: (request: IRequest, runtime: FluidDataStoreRuntime) => Promise<IResponse>): typeof FluidDataStoreRuntime; | ||
export declare function mixinRequestHandler(requestHandler: (request: IRequest, runtime: FluidDataStoreRuntime) => Promise<IResponse>, Base?: typeof FluidDataStoreRuntime): typeof FluidDataStoreRuntime; | ||
/** | ||
* Mixin class that adds await for DataObject to finish initialization before we proceed to summary. | ||
* @param Base - base class, inherits from FluidDataStoreRuntime | ||
* @param init - async callback to wait before proceeding with summary | ||
*/ | ||
export declare function summaryWaitFluidDataStoreMixin(Base: typeof FluidDataStoreRuntime, init: () => Promise<void>): typeof FluidDataStoreRuntime; | ||
export declare function mixinSummaryHandler(handler: (runtime: FluidDataStoreRuntime) => Promise<{ | ||
path: string[]; | ||
content: string; | ||
}>, Base?: typeof FluidDataStoreRuntime): typeof FluidDataStoreRuntime; | ||
//# sourceMappingURL=dataStoreRuntime.d.ts.map |
@@ -7,3 +7,2 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const events_1 = require("events"); | ||
const container_definitions_1 = require("@fluidframework/container-definitions"); | ||
@@ -13,3 +12,2 @@ const common_utils_1 = require("@fluidframework/common-utils"); | ||
const driver_utils_1 = require("@fluidframework/driver-utils"); | ||
const protocol_base_1 = require("@fluidframework/protocol-base"); | ||
const runtime_definitions_1 = require("@fluidframework/runtime-definitions"); | ||
@@ -21,3 +19,2 @@ const runtime_utils_1 = require("@fluidframework/runtime-utils"); | ||
const remoteChannelContext_1 = require("./remoteChannelContext"); | ||
const utils_1 = require("./utils"); | ||
var DataStoreMessageType; | ||
@@ -32,3 +29,3 @@ (function (DataStoreMessageType) { | ||
*/ | ||
class FluidDataStoreRuntime extends events_1.EventEmitter { | ||
class FluidDataStoreRuntime extends common_utils_1.TypedEventEmitter { | ||
constructor(dataStoreContext, sharedObjectRegistry) { | ||
@@ -58,3 +55,2 @@ var _a; | ||
this.audience = dataStoreContext.getAudience(); | ||
this.snapshotFn = dataStoreContext.snapshotFn; | ||
const tree = dataStoreContext.baseSnapshot; | ||
@@ -163,3 +159,3 @@ // Must always receive the data store type inside of the attributes | ||
const id = parser.pathParts[0]; | ||
if (id === "_channels" || id === "_objects") { | ||
if (id === "_channels" || id === "_custom") { | ||
return this.request(parser.createSubRequest(1)); | ||
@@ -192,2 +188,7 @@ } | ||
} | ||
/** | ||
* @deprecated | ||
* Please use mixinRequestHandler() to override default behavior or request() | ||
* // back-compat: remove in 0.30+ | ||
*/ | ||
registerRequestHandler(handler) { | ||
@@ -281,2 +282,3 @@ this.requestHandler = handler; | ||
// Attach the runtime to the container via this callback | ||
// back-compat: remove argument ans cast in 0.30. | ||
this.dataStoreContext.bindToContext(this); | ||
@@ -310,7 +312,2 @@ this.bindState = container_definitions_1.BindState.Bound; | ||
} | ||
// eslint-disable-next-line @typescript-eslint/promise-function-async | ||
snapshot(message) { | ||
this.verifyNotClosed(); | ||
return this.snapshotFn(message); | ||
} | ||
async uploadBlob(blob) { | ||
@@ -383,20 +380,14 @@ this.verifyNotClosed(); | ||
} | ||
// back-compat for N-2 <= 0.28, remove when N-2 >= 0.29 | ||
async snapshotInternal(fullTree = false) { | ||
// Craft the .attributes file for each shared object | ||
const entries = await Promise.all(Array.from(this.contexts) | ||
.filter(([key, _]) => { | ||
const isAttached = this.isChannelAttached(key); | ||
// We are not expecting local dds! Summary may not capture local state. | ||
common_utils_1.assert(isAttached, "Not expecting detached channels during summarize"); | ||
// If the object is registered - and we have received the sequenced op creating the object | ||
// (i.e. it has a base mapping) - then we go ahead and snapshot | ||
return isAttached; | ||
}).map(async ([key, value]) => { | ||
const snapshot = await value.snapshot(fullTree); | ||
// And then store the tree | ||
return new protocol_base_1.TreeTreeEntry(key, snapshot); | ||
})); | ||
return entries; | ||
const summaryTree = await this.summarize(fullTree); | ||
const tree = runtime_utils_1.convertSummaryTreeToITree(summaryTree.summary); | ||
return tree.entries; | ||
} | ||
async summarize(fullTree = false) { | ||
/** | ||
* 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. | ||
*/ | ||
async summarize(fullTree = false, trackState = true) { | ||
const builder = new runtime_utils_1.SummaryTreeBuilder(); | ||
@@ -413,3 +404,3 @@ // Iterate over each data store and ask it to snapshot | ||
}).map(async ([key, value]) => { | ||
const channelSummary = await value.summarize(fullTree); | ||
const channelSummary = await value.summarize(fullTree, trackState); | ||
builder.addWithStats(key, channelSummary); | ||
@@ -419,5 +410,14 @@ })); | ||
} | ||
/** | ||
* back-compat 0.28 - snapshot is being removed and replaced with summary. | ||
* So, getAttachSnapshot has been deprecated and getAttachSummary should be used instead. | ||
*/ | ||
getAttachSnapshot() { | ||
const entries = []; | ||
const summaryTree = this.getAttachSummary(); | ||
const tree = runtime_utils_1.convertSummaryTreeToITree(summaryTree.summary); | ||
return tree.entries; | ||
} | ||
getAttachSummary() { | ||
this.attachGraph(); | ||
const builder = new runtime_utils_1.SummaryTreeBuilder(); | ||
// Craft the .attributes file for each shared object | ||
@@ -429,5 +429,5 @@ for (const [objectId, value] of this.contexts) { | ||
if (!this.notBoundedChannelContextSet.has(objectId)) { | ||
let snapshot; | ||
let summary; | ||
if (value.isLoaded) { | ||
snapshot = value.getAttachSnapshot(); | ||
summary = value.getAttachSummary(); | ||
} | ||
@@ -438,9 +438,8 @@ else { | ||
common_utils_1.assert(!!this.dataStoreContext.baseSnapshot, "BaseSnapshot should be there as detached container loaded from snapshot"); | ||
snapshot = utils_1.convertSnapshotToITree(this.dataStoreContext.baseSnapshot.trees[objectId]); | ||
summary = runtime_utils_1.convertSnapshotTreeToSummaryTree(this.dataStoreContext.baseSnapshot.trees[objectId]); | ||
} | ||
// And then store the tree | ||
entries.push(new protocol_base_1.TreeTreeEntry(objectId, snapshot)); | ||
builder.addWithStats(objectId, summary); | ||
} | ||
} | ||
return entries; | ||
return builder.getSummaryTree(); | ||
} | ||
@@ -567,2 +566,3 @@ submitMessage(type, content, localOpMetadata) { | ||
* Mixin class that adds request handler to FluidDataStoreRuntime | ||
* Request handler is only called when data store can't resolve request, i.e. for custom requests. | ||
* @param Base - base class, inherits from FluidDataStoreRuntime | ||
@@ -572,3 +572,3 @@ * @param requestHandler - request handler to mix in | ||
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions | ||
function requestFluidDataStoreMixin(Base, requestHandler) { | ||
function mixinRequestHandler(requestHandler, Base = FluidDataStoreRuntime) { | ||
return class RuntimeWithRequestHandler extends Base { | ||
@@ -584,18 +584,39 @@ async request(request) { | ||
} | ||
exports.requestFluidDataStoreMixin = requestFluidDataStoreMixin; | ||
exports.mixinRequestHandler = mixinRequestHandler; | ||
/** | ||
* Mixin class that adds await for DataObject to finish initialization before we proceed to summary. | ||
* @param Base - base class, inherits from FluidDataStoreRuntime | ||
* @param init - async callback to wait before proceeding with summary | ||
*/ | ||
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions | ||
function summaryWaitFluidDataStoreMixin(Base, init) { | ||
function mixinSummaryHandler(handler, Base = FluidDataStoreRuntime) { | ||
return class RuntimeWithSummarizerHandler extends Base { | ||
addBlob(summary, path, content) { | ||
const firstName = path.shift(); | ||
if (firstName === undefined) { | ||
throw new Error("Path can't be empty"); | ||
} | ||
let blob = { | ||
type: 2 /* Blob */, | ||
content, | ||
}; | ||
summary.stats.blobNodeCount++; | ||
summary.stats.totalBlobSize += content.length; | ||
for (const name of path.reverse()) { | ||
blob = { | ||
type: 1 /* Tree */, | ||
tree: { [name]: blob }, | ||
}; | ||
summary.stats.treeNodeCount++; | ||
} | ||
summary.summary.tree[firstName] = blob; | ||
} | ||
async summarize(...args) { | ||
await init(); | ||
return super.summarize(...args); | ||
const summary = await super.summarize(...args); | ||
const content = await handler(this); | ||
this.addBlob(summary, content.path, content.content); | ||
return summary; | ||
} | ||
}; | ||
} | ||
exports.summaryWaitFluidDataStoreMixin = summaryWaitFluidDataStoreMixin; | ||
exports.mixinSummaryHandler = mixinSummaryHandler; | ||
//# sourceMappingURL=dataStoreRuntime.js.map |
@@ -6,5 +6,5 @@ /*! | ||
import { IDocumentStorageService } from "@fluidframework/driver-definitions"; | ||
import { ISequencedDocumentMessage, ITree, ISnapshotTree } from "@fluidframework/protocol-definitions"; | ||
import { ISequencedDocumentMessage, ISnapshotTree } from "@fluidframework/protocol-definitions"; | ||
import { IChannel, IFluidDataStoreRuntime } from "@fluidframework/datastore-definitions"; | ||
import { IFluidDataStoreContext, ISummarizeResult } from "@fluidframework/runtime-definitions"; | ||
import { IFluidDataStoreContext, ISummarizeResult, ISummaryTreeWithStats } from "@fluidframework/runtime-definitions"; | ||
import { IChannelContext } from "./channelContext"; | ||
@@ -34,5 +34,9 @@ import { ISharedObjectRegistry } from "./dataStoreRuntime"; | ||
reSubmit(content: any, localOpMetadata: unknown): void; | ||
snapshot(fullTree?: boolean): Promise<ITree>; | ||
summarize(fullTree?: boolean): Promise<ISummarizeResult>; | ||
getAttachSnapshot(): ITree; | ||
/** | ||
* 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. | ||
*/ | ||
summarize(fullTree?: boolean, trackState?: boolean): Promise<ISummarizeResult>; | ||
getAttachSummary(): ISummaryTreeWithStats; | ||
private loadChannel; | ||
@@ -39,0 +43,0 @@ markAttached(): void; |
@@ -82,13 +82,22 @@ "use strict"; | ||
} | ||
async snapshot(fullTree = false) { | ||
return this.getAttachSnapshot(); | ||
} | ||
async summarize(fullTree = false) { | ||
const snapshot = this.getAttachSnapshot(); | ||
/** | ||
* 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. | ||
*/ | ||
async summarize(fullTree = false, trackState = false) { | ||
common_utils_1.assert(this.isLoaded && this.channel !== undefined, "Channel should be loaded to take summary"); | ||
const snapshot = channelContext_1.snapshotChannel(this.channel); | ||
const summary = runtime_utils_1.convertToSummaryTree(snapshot, fullTree); | ||
return summary; | ||
} | ||
getAttachSnapshot() { | ||
getAttachSummary() { | ||
common_utils_1.assert(this.isLoaded && this.channel !== undefined, "Channel should be loaded to take snapshot"); | ||
return channelContext_1.snapshotChannel(this.channel); | ||
const snapshot = channelContext_1.snapshotChannel(this.channel); | ||
const summaryTree = runtime_utils_1.convertToSummaryTree(snapshot, true /* fullTree */); | ||
common_utils_1.assert(summaryTree.summary.type === 1 /* Tree */, "summarize should always return a tree when fullTree is true"); | ||
return { | ||
stats: summaryTree.stats, | ||
summary: summaryTree.summary, | ||
}; | ||
} | ||
@@ -95,0 +104,0 @@ async loadChannel() { |
@@ -8,3 +8,3 @@ /*! | ||
export declare const pkgName = "@fluidframework/datastore"; | ||
export declare const pkgVersion = "0.28.7"; | ||
export declare const pkgVersion = "0.29.0"; | ||
//# sourceMappingURL=packageVersion.d.ts.map |
@@ -10,3 +10,3 @@ "use strict"; | ||
exports.pkgName = "@fluidframework/datastore"; | ||
exports.pkgVersion = "0.28.7"; | ||
exports.pkgVersion = "0.29.0"; | ||
//# sourceMappingURL=packageVersion.js.map |
@@ -6,3 +6,3 @@ /*! | ||
import { IDocumentStorageService } from "@fluidframework/driver-definitions"; | ||
import { ISequencedDocumentMessage, ISnapshotTree, ITree } from "@fluidframework/protocol-definitions"; | ||
import { ISequencedDocumentMessage, ISnapshotTree } from "@fluidframework/protocol-definitions"; | ||
import { IChannel, IFluidDataStoreRuntime } from "@fluidframework/datastore-definitions"; | ||
@@ -31,4 +31,8 @@ import { IFluidDataStoreContext, ISummaryTracker, ISummarizeResult, CreateChildSummarizerNodeFn } from "@fluidframework/runtime-definitions"; | ||
reSubmit(content: any, localOpMetadata: unknown): void; | ||
snapshot(fullTree?: boolean): Promise<ITree>; | ||
summarize(fullTree?: boolean): Promise<ISummarizeResult>; | ||
/** | ||
* 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. | ||
*/ | ||
summarize(fullTree?: boolean, trackState?: boolean): Promise<ISummarizeResult>; | ||
private summarizeInternal; | ||
@@ -35,0 +39,0 @@ private loadChannel; |
@@ -25,3 +25,4 @@ "use strict"; | ||
this.services = channelContext_1.createServiceEndpoints(this.id, this.dataStoreContext.connected, submitFn, () => dirtyFn(this.id), storageService, Promise.resolve(baseSnapshot), extraBlobs); | ||
const thisSummarizeInternal = async (fullTree) => this.summarizeInternal(fullTree); | ||
// Summarizer node always tracks summary state. Set trackState to true. | ||
const thisSummarizeInternal = async (fullTree) => this.summarizeInternal(fullTree, true /* trackState */); | ||
this.summarizerNode = createSummarizerNode(thisSummarizeInternal); | ||
@@ -59,16 +60,15 @@ } | ||
} | ||
async snapshot(fullTree = false) { | ||
if (!fullTree) { | ||
const id = await this.summaryTracker.getId(); | ||
if (id !== undefined) { | ||
return { id, entries: [] }; | ||
} | ||
} | ||
const channel = await this.getChannel(); | ||
return channelContext_1.snapshotChannel(channel); | ||
/** | ||
* 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. | ||
*/ | ||
async summarize(fullTree = false, trackState = true) { | ||
// Summarizer node tracks the state from the summary. If trackState is true, use summarizer node to get | ||
// the summary. Else, get the summary tree directly. | ||
return trackState | ||
? this.summarizerNode.summarize(fullTree) | ||
: this.summarizeInternal(fullTree, false /* trackState */); | ||
} | ||
async summarize(fullTree = false) { | ||
return this.summarizerNode.summarize(fullTree); | ||
} | ||
async summarizeInternal(fullTree) { | ||
async summarizeInternal(fullTree, trackState) { | ||
const channel = await this.getChannel(); | ||
@@ -75,0 +75,0 @@ const snapshotTree = channelContext_1.snapshotChannel(channel); |
@@ -6,3 +6,3 @@ /*! | ||
import { IDocumentStorageService } from "@fluidframework/driver-definitions"; | ||
import { ISequencedDocumentMessage, ISnapshotTree, ITree } from "@fluidframework/protocol-definitions"; | ||
import { ISequencedDocumentMessage, ISnapshotTree } from "@fluidframework/protocol-definitions"; | ||
import { IChannel } from "@fluidframework/datastore-definitions"; | ||
@@ -16,5 +16,3 @@ import { ISummarizeResult } from "@fluidframework/runtime-definitions"; | ||
processOp(message: ISequencedDocumentMessage, local: boolean, localOpMetadata?: unknown): void; | ||
/** @deprecated in 0.22 summarizerNode */ | ||
snapshot(fullTree?: boolean): Promise<ITree>; | ||
summarize(fullTree?: boolean): Promise<ISummarizeResult>; | ||
summarize(fullTree?: boolean, trackState?: boolean): Promise<ISummarizeResult>; | ||
reSubmit(content: any, localOpMetadata: unknown): void; | ||
@@ -26,3 +24,3 @@ } | ||
}; | ||
export declare function snapshotChannel(channel: IChannel): ITree; | ||
export declare function snapshotChannel(channel: IChannel): import("@fluidframework/protocol-definitions").ITree; | ||
//# sourceMappingURL=channelContext.d.ts.map |
@@ -5,10 +5,10 @@ /*! | ||
*/ | ||
import { EventEmitter } from "events"; | ||
import { ITelemetryLogger } from "@fluidframework/common-definitions"; | ||
import { IFluidHandle, IFluidHandleContext, IRequest, IResponse } from "@fluidframework/core-interfaces"; | ||
import { IAudience, IDeltaManager, ContainerWarning, ILoader, AttachState } from "@fluidframework/container-definitions"; | ||
import { TypedEventEmitter } from "@fluidframework/common-utils"; | ||
import { IClientDetails, IDocumentMessage, IQuorum, ISequencedDocumentMessage, ITreeEntry } from "@fluidframework/protocol-definitions"; | ||
import { IFluidDataStoreContext, IFluidDataStoreChannel, IInboundSignalMessage, ISummaryTreeWithStats } from "@fluidframework/runtime-definitions"; | ||
import { FluidSerializer } from "@fluidframework/runtime-utils"; | ||
import { IChannel, IFluidDataStoreRuntime, IChannelFactory } from "@fluidframework/datastore-definitions"; | ||
import { IChannel, IFluidDataStoreRuntime, IFluidDataStoreRuntimeEvents, IChannelFactory } from "@fluidframework/datastore-definitions"; | ||
export declare enum DataStoreMessageType { | ||
@@ -24,3 +24,3 @@ Attach = "attach", | ||
*/ | ||
export declare class FluidDataStoreRuntime extends EventEmitter implements IFluidDataStoreChannel, IFluidDataStoreRuntime, IFluidHandleContext { | ||
export declare class FluidDataStoreRuntime extends TypedEventEmitter<IFluidDataStoreRuntimeEvents> implements IFluidDataStoreChannel, IFluidDataStoreRuntime, IFluidHandleContext { | ||
private readonly dataStoreContext; | ||
@@ -77,3 +77,2 @@ private readonly sharedObjectRegistry; | ||
private readonly audience; | ||
private readonly snapshotFn; | ||
readonly logger: ITelemetryLogger; | ||
@@ -84,2 +83,7 @@ constructor(dataStoreContext: IFluidDataStoreContext, sharedObjectRegistry: ISharedObjectRegistry); | ||
request(request: IRequest): Promise<IResponse>; | ||
/** | ||
* @deprecated | ||
* Please use mixinRequestHandler() to override default behavior or request() | ||
* // back-compat: remove in 0.30+ | ||
*/ | ||
registerRequestHandler(handler: (request: IRequest) => Promise<IResponse>): void; | ||
@@ -106,3 +110,2 @@ getChannel(id: string): Promise<IChannel>; | ||
getAudience(): IAudience; | ||
snapshot(message: string): Promise<void>; | ||
uploadBlob(blob: ArrayBufferLike): Promise<IFluidHandle<ArrayBufferLike>>; | ||
@@ -113,4 +116,14 @@ process(message: ISequencedDocumentMessage, local: boolean, localOpMetadata: unknown): void; | ||
snapshotInternal(fullTree?: boolean): Promise<ITreeEntry[]>; | ||
summarize(fullTree?: boolean): Promise<ISummaryTreeWithStats>; | ||
/** | ||
* 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. | ||
*/ | ||
summarize(fullTree?: boolean, trackState?: boolean): Promise<ISummaryTreeWithStats>; | ||
/** | ||
* back-compat 0.28 - snapshot is being removed and replaced with summary. | ||
* So, getAttachSnapshot has been deprecated and getAttachSummary should be used instead. | ||
*/ | ||
getAttachSnapshot(): ITreeEntry[]; | ||
getAttachSummary(): ISummaryTreeWithStats; | ||
submitMessage(type: DataStoreMessageType, content: any, localOpMetadata: unknown): void; | ||
@@ -144,12 +157,15 @@ submitSignal(type: string, content: any): void; | ||
* Mixin class that adds request handler to FluidDataStoreRuntime | ||
* Request handler is only called when data store can't resolve request, i.e. for custom requests. | ||
* @param Base - base class, inherits from FluidDataStoreRuntime | ||
* @param requestHandler - request handler to mix in | ||
*/ | ||
export declare function requestFluidDataStoreMixin(Base: typeof FluidDataStoreRuntime, requestHandler: (request: IRequest, runtime: FluidDataStoreRuntime) => Promise<IResponse>): typeof FluidDataStoreRuntime; | ||
export declare function mixinRequestHandler(requestHandler: (request: IRequest, runtime: FluidDataStoreRuntime) => Promise<IResponse>, Base?: typeof FluidDataStoreRuntime): typeof FluidDataStoreRuntime; | ||
/** | ||
* Mixin class that adds await for DataObject to finish initialization before we proceed to summary. | ||
* @param Base - base class, inherits from FluidDataStoreRuntime | ||
* @param init - async callback to wait before proceeding with summary | ||
*/ | ||
export declare function summaryWaitFluidDataStoreMixin(Base: typeof FluidDataStoreRuntime, init: () => Promise<void>): typeof FluidDataStoreRuntime; | ||
export declare function mixinSummaryHandler(handler: (runtime: FluidDataStoreRuntime) => Promise<{ | ||
path: string[]; | ||
content: string; | ||
}>, Base?: typeof FluidDataStoreRuntime): typeof FluidDataStoreRuntime; | ||
//# sourceMappingURL=dataStoreRuntime.d.ts.map |
@@ -5,10 +5,8 @@ /*! | ||
*/ | ||
import { EventEmitter } from "events"; | ||
import { BindState, AttachState, } from "@fluidframework/container-definitions"; | ||
import { assert, Deferred, unreachableCase, } from "@fluidframework/common-utils"; | ||
import { assert, Deferred, TypedEventEmitter, unreachableCase, } from "@fluidframework/common-utils"; | ||
import { ChildLogger, raiseConnectedEvent, } from "@fluidframework/telemetry-utils"; | ||
import { buildSnapshotTree, readAndParseFromBlobs } from "@fluidframework/driver-utils"; | ||
import { TreeTreeEntry } from "@fluidframework/protocol-base"; | ||
import { CreateSummarizerNodeSource, } from "@fluidframework/runtime-definitions"; | ||
import { generateHandleContextPath, RequestParser, SummaryTreeBuilder, FluidSerializer, } from "@fluidframework/runtime-utils"; | ||
import { convertSnapshotTreeToSummaryTree, generateHandleContextPath, RequestParser, SummaryTreeBuilder, FluidSerializer, convertSummaryTreeToITree, } from "@fluidframework/runtime-utils"; | ||
import { v4 as uuid } from "uuid"; | ||
@@ -18,3 +16,2 @@ import { snapshotChannel } from "./channelContext"; | ||
import { RemoteChannelContext } from "./remoteChannelContext"; | ||
import { convertSnapshotToITree } from "./utils"; | ||
export var DataStoreMessageType; | ||
@@ -29,3 +26,3 @@ (function (DataStoreMessageType) { | ||
*/ | ||
export class FluidDataStoreRuntime extends EventEmitter { | ||
export class FluidDataStoreRuntime extends TypedEventEmitter { | ||
constructor(dataStoreContext, sharedObjectRegistry) { | ||
@@ -55,3 +52,2 @@ var _a; | ||
this.audience = dataStoreContext.getAudience(); | ||
this.snapshotFn = dataStoreContext.snapshotFn; | ||
const tree = dataStoreContext.baseSnapshot; | ||
@@ -160,3 +156,3 @@ // Must always receive the data store type inside of the attributes | ||
const id = parser.pathParts[0]; | ||
if (id === "_channels" || id === "_objects") { | ||
if (id === "_channels" || id === "_custom") { | ||
return this.request(parser.createSubRequest(1)); | ||
@@ -189,2 +185,7 @@ } | ||
} | ||
/** | ||
* @deprecated | ||
* Please use mixinRequestHandler() to override default behavior or request() | ||
* // back-compat: remove in 0.30+ | ||
*/ | ||
registerRequestHandler(handler) { | ||
@@ -278,2 +279,3 @@ this.requestHandler = handler; | ||
// Attach the runtime to the container via this callback | ||
// back-compat: remove argument ans cast in 0.30. | ||
this.dataStoreContext.bindToContext(this); | ||
@@ -307,7 +309,2 @@ this.bindState = BindState.Bound; | ||
} | ||
// eslint-disable-next-line @typescript-eslint/promise-function-async | ||
snapshot(message) { | ||
this.verifyNotClosed(); | ||
return this.snapshotFn(message); | ||
} | ||
async uploadBlob(blob) { | ||
@@ -380,20 +377,14 @@ this.verifyNotClosed(); | ||
} | ||
// back-compat for N-2 <= 0.28, remove when N-2 >= 0.29 | ||
async snapshotInternal(fullTree = false) { | ||
// Craft the .attributes file for each shared object | ||
const entries = await Promise.all(Array.from(this.contexts) | ||
.filter(([key, _]) => { | ||
const isAttached = this.isChannelAttached(key); | ||
// We are not expecting local dds! Summary may not capture local state. | ||
assert(isAttached, "Not expecting detached channels during summarize"); | ||
// If the object is registered - and we have received the sequenced op creating the object | ||
// (i.e. it has a base mapping) - then we go ahead and snapshot | ||
return isAttached; | ||
}).map(async ([key, value]) => { | ||
const snapshot = await value.snapshot(fullTree); | ||
// And then store the tree | ||
return new TreeTreeEntry(key, snapshot); | ||
})); | ||
return entries; | ||
const summaryTree = await this.summarize(fullTree); | ||
const tree = convertSummaryTreeToITree(summaryTree.summary); | ||
return tree.entries; | ||
} | ||
async summarize(fullTree = false) { | ||
/** | ||
* 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. | ||
*/ | ||
async summarize(fullTree = false, trackState = true) { | ||
const builder = new SummaryTreeBuilder(); | ||
@@ -410,3 +401,3 @@ // Iterate over each data store and ask it to snapshot | ||
}).map(async ([key, value]) => { | ||
const channelSummary = await value.summarize(fullTree); | ||
const channelSummary = await value.summarize(fullTree, trackState); | ||
builder.addWithStats(key, channelSummary); | ||
@@ -416,5 +407,14 @@ })); | ||
} | ||
/** | ||
* back-compat 0.28 - snapshot is being removed and replaced with summary. | ||
* So, getAttachSnapshot has been deprecated and getAttachSummary should be used instead. | ||
*/ | ||
getAttachSnapshot() { | ||
const entries = []; | ||
const summaryTree = this.getAttachSummary(); | ||
const tree = convertSummaryTreeToITree(summaryTree.summary); | ||
return tree.entries; | ||
} | ||
getAttachSummary() { | ||
this.attachGraph(); | ||
const builder = new SummaryTreeBuilder(); | ||
// Craft the .attributes file for each shared object | ||
@@ -426,5 +426,5 @@ for (const [objectId, value] of this.contexts) { | ||
if (!this.notBoundedChannelContextSet.has(objectId)) { | ||
let snapshot; | ||
let summary; | ||
if (value.isLoaded) { | ||
snapshot = value.getAttachSnapshot(); | ||
summary = value.getAttachSummary(); | ||
} | ||
@@ -435,9 +435,8 @@ else { | ||
assert(!!this.dataStoreContext.baseSnapshot, "BaseSnapshot should be there as detached container loaded from snapshot"); | ||
snapshot = convertSnapshotToITree(this.dataStoreContext.baseSnapshot.trees[objectId]); | ||
summary = convertSnapshotTreeToSummaryTree(this.dataStoreContext.baseSnapshot.trees[objectId]); | ||
} | ||
// And then store the tree | ||
entries.push(new TreeTreeEntry(objectId, snapshot)); | ||
builder.addWithStats(objectId, summary); | ||
} | ||
} | ||
return entries; | ||
return builder.getSummaryTree(); | ||
} | ||
@@ -563,2 +562,3 @@ submitMessage(type, content, localOpMetadata) { | ||
* Mixin class that adds request handler to FluidDataStoreRuntime | ||
* Request handler is only called when data store can't resolve request, i.e. for custom requests. | ||
* @param Base - base class, inherits from FluidDataStoreRuntime | ||
@@ -568,3 +568,3 @@ * @param requestHandler - request handler to mix in | ||
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions | ||
export function requestFluidDataStoreMixin(Base, requestHandler) { | ||
export function mixinRequestHandler(requestHandler, Base = FluidDataStoreRuntime) { | ||
return class RuntimeWithRequestHandler extends Base { | ||
@@ -583,10 +583,31 @@ async request(request) { | ||
* @param Base - base class, inherits from FluidDataStoreRuntime | ||
* @param init - async callback to wait before proceeding with summary | ||
*/ | ||
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions | ||
export function summaryWaitFluidDataStoreMixin(Base, init) { | ||
export function mixinSummaryHandler(handler, Base = FluidDataStoreRuntime) { | ||
return class RuntimeWithSummarizerHandler extends Base { | ||
addBlob(summary, path, content) { | ||
const firstName = path.shift(); | ||
if (firstName === undefined) { | ||
throw new Error("Path can't be empty"); | ||
} | ||
let blob = { | ||
type: 2 /* Blob */, | ||
content, | ||
}; | ||
summary.stats.blobNodeCount++; | ||
summary.stats.totalBlobSize += content.length; | ||
for (const name of path.reverse()) { | ||
blob = { | ||
type: 1 /* Tree */, | ||
tree: { [name]: blob }, | ||
}; | ||
summary.stats.treeNodeCount++; | ||
} | ||
summary.summary.tree[firstName] = blob; | ||
} | ||
async summarize(...args) { | ||
await init(); | ||
return super.summarize(...args); | ||
const summary = await super.summarize(...args); | ||
const content = await handler(this); | ||
this.addBlob(summary, content.path, content.content); | ||
return summary; | ||
} | ||
@@ -593,0 +614,0 @@ }; |
@@ -6,5 +6,5 @@ /*! | ||
import { IDocumentStorageService } from "@fluidframework/driver-definitions"; | ||
import { ISequencedDocumentMessage, ITree, ISnapshotTree } from "@fluidframework/protocol-definitions"; | ||
import { ISequencedDocumentMessage, ISnapshotTree } from "@fluidframework/protocol-definitions"; | ||
import { IChannel, IFluidDataStoreRuntime } from "@fluidframework/datastore-definitions"; | ||
import { IFluidDataStoreContext, ISummarizeResult } from "@fluidframework/runtime-definitions"; | ||
import { IFluidDataStoreContext, ISummarizeResult, ISummaryTreeWithStats } from "@fluidframework/runtime-definitions"; | ||
import { IChannelContext } from "./channelContext"; | ||
@@ -34,5 +34,9 @@ import { ISharedObjectRegistry } from "./dataStoreRuntime"; | ||
reSubmit(content: any, localOpMetadata: unknown): void; | ||
snapshot(fullTree?: boolean): Promise<ITree>; | ||
summarize(fullTree?: boolean): Promise<ISummarizeResult>; | ||
getAttachSnapshot(): ITree; | ||
/** | ||
* 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. | ||
*/ | ||
summarize(fullTree?: boolean, trackState?: boolean): Promise<ISummarizeResult>; | ||
getAttachSummary(): ISummaryTreeWithStats; | ||
private loadChannel; | ||
@@ -39,0 +43,0 @@ markAttached(): void; |
@@ -77,13 +77,22 @@ /*! | ||
} | ||
async snapshot(fullTree = false) { | ||
return this.getAttachSnapshot(); | ||
} | ||
async summarize(fullTree = false) { | ||
const snapshot = this.getAttachSnapshot(); | ||
/** | ||
* 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. | ||
*/ | ||
async summarize(fullTree = false, trackState = false) { | ||
assert(this.isLoaded && this.channel !== undefined, "Channel should be loaded to take summary"); | ||
const snapshot = snapshotChannel(this.channel); | ||
const summary = convertToSummaryTree(snapshot, fullTree); | ||
return summary; | ||
} | ||
getAttachSnapshot() { | ||
getAttachSummary() { | ||
assert(this.isLoaded && this.channel !== undefined, "Channel should be loaded to take snapshot"); | ||
return snapshotChannel(this.channel); | ||
const snapshot = snapshotChannel(this.channel); | ||
const summaryTree = convertToSummaryTree(snapshot, true /* fullTree */); | ||
assert(summaryTree.summary.type === 1 /* Tree */, "summarize should always return a tree when fullTree is true"); | ||
return { | ||
stats: summaryTree.stats, | ||
summary: summaryTree.summary, | ||
}; | ||
} | ||
@@ -90,0 +99,0 @@ async loadChannel() { |
@@ -8,3 +8,3 @@ /*! | ||
export declare const pkgName = "@fluidframework/datastore"; | ||
export declare const pkgVersion = "0.28.7"; | ||
export declare const pkgVersion = "0.29.0"; | ||
//# sourceMappingURL=packageVersion.d.ts.map |
@@ -8,3 +8,3 @@ /*! | ||
export const pkgName = "@fluidframework/datastore"; | ||
export const pkgVersion = "0.28.7"; | ||
export const pkgVersion = "0.29.0"; | ||
//# sourceMappingURL=packageVersion.js.map |
@@ -6,3 +6,3 @@ /*! | ||
import { IDocumentStorageService } from "@fluidframework/driver-definitions"; | ||
import { ISequencedDocumentMessage, ISnapshotTree, ITree } from "@fluidframework/protocol-definitions"; | ||
import { ISequencedDocumentMessage, ISnapshotTree } from "@fluidframework/protocol-definitions"; | ||
import { IChannel, IFluidDataStoreRuntime } from "@fluidframework/datastore-definitions"; | ||
@@ -31,4 +31,8 @@ import { IFluidDataStoreContext, ISummaryTracker, ISummarizeResult, CreateChildSummarizerNodeFn } from "@fluidframework/runtime-definitions"; | ||
reSubmit(content: any, localOpMetadata: unknown): void; | ||
snapshot(fullTree?: boolean): Promise<ITree>; | ||
summarize(fullTree?: boolean): Promise<ISummarizeResult>; | ||
/** | ||
* 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. | ||
*/ | ||
summarize(fullTree?: boolean, trackState?: boolean): Promise<ISummarizeResult>; | ||
private summarizeInternal; | ||
@@ -35,0 +39,0 @@ private loadChannel; |
@@ -23,3 +23,4 @@ /*! | ||
this.services = createServiceEndpoints(this.id, this.dataStoreContext.connected, submitFn, () => dirtyFn(this.id), storageService, Promise.resolve(baseSnapshot), extraBlobs); | ||
const thisSummarizeInternal = async (fullTree) => this.summarizeInternal(fullTree); | ||
// Summarizer node always tracks summary state. Set trackState to true. | ||
const thisSummarizeInternal = async (fullTree) => this.summarizeInternal(fullTree, true /* trackState */); | ||
this.summarizerNode = createSummarizerNode(thisSummarizeInternal); | ||
@@ -57,16 +58,15 @@ } | ||
} | ||
async snapshot(fullTree = false) { | ||
if (!fullTree) { | ||
const id = await this.summaryTracker.getId(); | ||
if (id !== undefined) { | ||
return { id, entries: [] }; | ||
} | ||
} | ||
const channel = await this.getChannel(); | ||
return snapshotChannel(channel); | ||
/** | ||
* 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. | ||
*/ | ||
async summarize(fullTree = false, trackState = true) { | ||
// Summarizer node tracks the state from the summary. If trackState is true, use summarizer node to get | ||
// the summary. Else, get the summary tree directly. | ||
return trackState | ||
? this.summarizerNode.summarize(fullTree) | ||
: this.summarizeInternal(fullTree, false /* trackState */); | ||
} | ||
async summarize(fullTree = false) { | ||
return this.summarizerNode.summarize(fullTree); | ||
} | ||
async summarizeInternal(fullTree) { | ||
async summarizeInternal(fullTree, trackState) { | ||
const channel = await this.getChannel(); | ||
@@ -73,0 +73,0 @@ const snapshotTree = snapshotChannel(channel); |
{ | ||
"name": "@fluidframework/datastore", | ||
"version": "0.28.7", | ||
"version": "0.29.0", | ||
"description": "Fluid data store implementation", | ||
"homepage": "https://fluidframework.com", | ||
"repository": "microsoft/FluidFramework", | ||
"repository": "https://github.com/microsoft/FluidFramework", | ||
"license": "MIT", | ||
"author": "Microsoft", | ||
"sideEffects": "false", | ||
"sideEffects": false, | ||
"main": "dist/index.js", | ||
@@ -58,13 +58,13 @@ "module": "lib/index.js", | ||
"@fluidframework/common-utils": "^0.25.0", | ||
"@fluidframework/container-definitions": "^0.28.7", | ||
"@fluidframework/container-utils": "^0.28.7", | ||
"@fluidframework/core-interfaces": "^0.28.7", | ||
"@fluidframework/datastore-definitions": "^0.28.7", | ||
"@fluidframework/driver-definitions": "^0.28.7", | ||
"@fluidframework/driver-utils": "^0.28.7", | ||
"@fluidframework/protocol-base": "^0.1014.1", | ||
"@fluidframework/protocol-definitions": "^0.1014.1", | ||
"@fluidframework/runtime-definitions": "^0.28.7", | ||
"@fluidframework/runtime-utils": "^0.28.7", | ||
"@fluidframework/telemetry-utils": "^0.28.7", | ||
"@fluidframework/container-definitions": "^0.29.0", | ||
"@fluidframework/container-utils": "^0.29.0", | ||
"@fluidframework/core-interfaces": "^0.29.0", | ||
"@fluidframework/datastore-definitions": "^0.29.0", | ||
"@fluidframework/driver-definitions": "^0.29.0", | ||
"@fluidframework/driver-utils": "^0.29.0", | ||
"@fluidframework/protocol-base": "^0.1015.0", | ||
"@fluidframework/protocol-definitions": "^0.1015.0", | ||
"@fluidframework/runtime-definitions": "^0.29.0", | ||
"@fluidframework/runtime-utils": "^0.29.0", | ||
"@fluidframework/telemetry-utils": "^0.29.0", | ||
"assert": "^2.0.0", | ||
@@ -77,4 +77,4 @@ "debug": "^4.1.1", | ||
"@fluidframework/build-common": "^0.19.2", | ||
"@fluidframework/eslint-config-fluid": "^0.20.0", | ||
"@fluidframework/mocha-test-setup": "^0.28.7", | ||
"@fluidframework/eslint-config-fluid": "^0.21.0", | ||
"@fluidframework/mocha-test-setup": "^0.29.0", | ||
"@microsoft/api-extractor": "^7.7.2", | ||
@@ -81,0 +81,0 @@ "@types/assert": "^1.5.1", |
@@ -8,7 +8,3 @@ /*! | ||
import { BlobTreeEntry } from "@fluidframework/protocol-base"; | ||
import { | ||
ISequencedDocumentMessage, | ||
ISnapshotTree, | ||
ITree, | ||
} from "@fluidframework/protocol-definitions"; | ||
import { ISequencedDocumentMessage, ISnapshotTree } from "@fluidframework/protocol-definitions"; | ||
import { IChannel } from "@fluidframework/datastore-definitions"; | ||
@@ -26,7 +22,4 @@ import { ISummarizeResult } from "@fluidframework/runtime-definitions"; | ||
/** @deprecated in 0.22 summarizerNode */ | ||
snapshot(fullTree?: boolean): Promise<ITree>; | ||
summarize(fullTree?: boolean, trackState?: boolean): Promise<ISummarizeResult>; | ||
summarize(fullTree?: boolean): Promise<ISummarizeResult>; | ||
reSubmit(content: any, localOpMetadata: unknown): void; | ||
@@ -33,0 +26,0 @@ } |
@@ -6,3 +6,2 @@ /*! | ||
import { EventEmitter } from "events"; | ||
import { ITelemetryLogger } from "@fluidframework/common-definitions"; | ||
@@ -26,2 +25,3 @@ import { | ||
Deferred, | ||
TypedEventEmitter, | ||
unreachableCase, | ||
@@ -34,3 +34,2 @@ } from "@fluidframework/common-utils"; | ||
import { buildSnapshotTree, readAndParseFromBlobs } from "@fluidframework/driver-utils"; | ||
import { TreeTreeEntry } from "@fluidframework/protocol-base"; | ||
import { | ||
@@ -42,3 +41,5 @@ IClientDetails, | ||
ITreeEntry, | ||
ITree, | ||
SummaryType, | ||
ISummaryBlob, | ||
ISummaryTree, | ||
} from "@fluidframework/protocol-definitions"; | ||
@@ -55,2 +56,3 @@ import { | ||
import { | ||
convertSnapshotTreeToSummaryTree, | ||
generateHandleContextPath, | ||
@@ -60,2 +62,3 @@ RequestParser, | ||
FluidSerializer, | ||
convertSummaryTreeToITree, | ||
} from "@fluidframework/runtime-utils"; | ||
@@ -65,2 +68,3 @@ import { | ||
IFluidDataStoreRuntime, | ||
IFluidDataStoreRuntimeEvents, | ||
IChannelFactory, | ||
@@ -73,3 +77,2 @@ IChannelAttributes, | ||
import { RemoteChannelContext } from "./remoteChannelContext"; | ||
import { convertSnapshotToITree } from "./utils"; | ||
@@ -91,4 +94,5 @@ export enum DataStoreMessageType { | ||
*/ | ||
export class FluidDataStoreRuntime extends EventEmitter implements IFluidDataStoreChannel, | ||
IFluidDataStoreRuntime, IFluidHandleContext { | ||
export class FluidDataStoreRuntime extends | ||
TypedEventEmitter<IFluidDataStoreRuntimeEvents> implements | ||
IFluidDataStoreChannel, IFluidDataStoreRuntime, IFluidHandleContext { | ||
/** | ||
@@ -186,3 +190,2 @@ * Loads the data store runtime | ||
private readonly audience: IAudience; | ||
private readonly snapshotFn: (message: string) => Promise<void>; | ||
public readonly logger: ITelemetryLogger; | ||
@@ -205,3 +208,2 @@ | ||
this.audience = dataStoreContext.getAudience(); | ||
this.snapshotFn = dataStoreContext.snapshotFn; | ||
@@ -296,3 +298,3 @@ const tree = dataStoreContext.baseSnapshot; | ||
if (id === "_channels" || id === "_objects") { | ||
if (id === "_channels" || id === "_custom") { | ||
return this.request(parser.createSubRequest(1)); | ||
@@ -328,2 +330,7 @@ } | ||
/** | ||
* @deprecated | ||
* Please use mixinRequestHandler() to override default behavior or request() | ||
* // back-compat: remove in 0.30+ | ||
*/ | ||
public registerRequestHandler(handler: (request: IRequest) => Promise<IResponse>) { | ||
@@ -438,3 +445,4 @@ this.requestHandler = handler; | ||
// Attach the runtime to the container via this callback | ||
this.dataStoreContext.bindToContext(this); | ||
// back-compat: remove argument ans cast in 0.30. | ||
(this.dataStoreContext as any).bindToContext(this); | ||
@@ -476,8 +484,2 @@ this.bindState = BindState.Bound; | ||
// eslint-disable-next-line @typescript-eslint/promise-function-async | ||
public snapshot(message: string): Promise<void> { | ||
this.verifyNotClosed(); | ||
return this.snapshotFn(message); | ||
} | ||
public async uploadBlob(blob: ArrayBufferLike): Promise<IFluidHandle<ArrayBufferLike>> { | ||
@@ -579,23 +581,15 @@ this.verifyNotClosed(); | ||
// back-compat for N-2 <= 0.28, remove when N-2 >= 0.29 | ||
public async snapshotInternal(fullTree: boolean = false): Promise<ITreeEntry[]> { | ||
// Craft the .attributes file for each shared object | ||
const entries = await Promise.all(Array.from(this.contexts) | ||
.filter(([key, _]) => { | ||
const isAttached = this.isChannelAttached(key); | ||
// We are not expecting local dds! Summary may not capture local state. | ||
assert(isAttached, "Not expecting detached channels during summarize"); | ||
// If the object is registered - and we have received the sequenced op creating the object | ||
// (i.e. it has a base mapping) - then we go ahead and snapshot | ||
return isAttached; | ||
}).map(async ([key, value]) => { | ||
const snapshot = await value.snapshot(fullTree); | ||
// And then store the tree | ||
return new TreeTreeEntry(key, snapshot); | ||
})); | ||
return entries; | ||
const summaryTree = await this.summarize(fullTree); | ||
const tree = convertSummaryTreeToITree(summaryTree.summary); | ||
return tree.entries; | ||
} | ||
public async summarize(fullTree = false): Promise<ISummaryTreeWithStats> { | ||
/** | ||
* 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. | ||
*/ | ||
public async summarize(fullTree: boolean = false, trackState: boolean = true): Promise<ISummaryTreeWithStats> { | ||
const builder = new SummaryTreeBuilder(); | ||
@@ -613,3 +607,3 @@ | ||
}).map(async ([key, value]) => { | ||
const channelSummary = await value.summarize(fullTree); | ||
const channelSummary = await value.summarize(fullTree, trackState); | ||
builder.addWithStats(key, channelSummary); | ||
@@ -621,6 +615,17 @@ })); | ||
/** | ||
* back-compat 0.28 - snapshot is being removed and replaced with summary. | ||
* So, getAttachSnapshot has been deprecated and getAttachSummary should be used instead. | ||
*/ | ||
public getAttachSnapshot(): ITreeEntry[] { | ||
const entries: ITreeEntry[] = []; | ||
const summaryTree = this.getAttachSummary(); | ||
const tree = convertSummaryTreeToITree(summaryTree.summary); | ||
return tree.entries; | ||
} | ||
public getAttachSummary(): ISummaryTreeWithStats { | ||
this.attachGraph(); | ||
const builder = new SummaryTreeBuilder(); | ||
// Craft the .attributes file for each shared object | ||
@@ -633,5 +638,5 @@ for (const [objectId, value] of this.contexts) { | ||
if (!this.notBoundedChannelContextSet.has(objectId)) { | ||
let snapshot: ITree; | ||
let summary: ISummaryTreeWithStats; | ||
if (value.isLoaded) { | ||
snapshot = value.getAttachSnapshot(); | ||
summary = value.getAttachSummary(); | ||
} else { | ||
@@ -642,11 +647,10 @@ // If this channel is not yet loaded, then there should be no changes in the snapshot from which | ||
"BaseSnapshot should be there as detached container loaded from snapshot"); | ||
snapshot = convertSnapshotToITree(this.dataStoreContext.baseSnapshot.trees[objectId]); | ||
summary = convertSnapshotTreeToSummaryTree(this.dataStoreContext.baseSnapshot.trees[objectId]); | ||
} | ||
// And then store the tree | ||
entries.push(new TreeTreeEntry(objectId, snapshot)); | ||
builder.addWithStats(objectId, summary); | ||
} | ||
} | ||
return entries; | ||
return builder.getSummaryTree(); | ||
} | ||
@@ -800,2 +804,3 @@ | ||
* Mixin class that adds request handler to FluidDataStoreRuntime | ||
* Request handler is only called when data store can't resolve request, i.e. for custom requests. | ||
* @param Base - base class, inherits from FluidDataStoreRuntime | ||
@@ -805,5 +810,5 @@ * @param requestHandler - request handler to mix in | ||
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions | ||
export function requestFluidDataStoreMixin( | ||
Base: typeof FluidDataStoreRuntime, | ||
requestHandler: (request: IRequest, runtime: FluidDataStoreRuntime) => Promise<IResponse>) | ||
export function mixinRequestHandler( | ||
requestHandler: (request: IRequest, runtime: FluidDataStoreRuntime) => Promise<IResponse>, | ||
Base: typeof FluidDataStoreRuntime = FluidDataStoreRuntime) | ||
{ | ||
@@ -824,15 +829,40 @@ return class RuntimeWithRequestHandler extends Base { | ||
* @param Base - base class, inherits from FluidDataStoreRuntime | ||
* @param init - async callback to wait before proceeding with summary | ||
*/ | ||
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions | ||
export function summaryWaitFluidDataStoreMixin( | ||
Base: typeof FluidDataStoreRuntime, | ||
init: () => Promise<void>) | ||
export function mixinSummaryHandler( | ||
handler: (runtime: FluidDataStoreRuntime) => Promise<{ path: string[], content: string }>, | ||
Base: typeof FluidDataStoreRuntime = FluidDataStoreRuntime, | ||
) | ||
{ | ||
return class RuntimeWithSummarizerHandler extends Base { | ||
public async summarize(...args) { | ||
await init(); | ||
return super.summarize(...args); | ||
private addBlob(summary: ISummaryTreeWithStats, path: string[], content: string) { | ||
const firstName = path.shift(); | ||
if (firstName === undefined) { | ||
throw new Error("Path can't be empty"); | ||
} | ||
let blob: ISummaryTree | ISummaryBlob = { | ||
type: SummaryType.Blob, | ||
content, | ||
}; | ||
summary.stats.blobNodeCount++; | ||
summary.stats.totalBlobSize += content.length; | ||
for (const name of path.reverse()) { | ||
blob = { | ||
type: SummaryType.Tree, | ||
tree: { [name]: blob }, | ||
}; | ||
summary.stats.treeNodeCount++; | ||
} | ||
summary.summary.tree[firstName] = blob; | ||
} | ||
async summarize(...args: any[]) { | ||
const summary = await super.summarize(...args); | ||
const content = await handler(this); | ||
this.addBlob(summary, content.path, content.content); | ||
return summary; | ||
} | ||
} as typeof FluidDataStoreRuntime; | ||
} |
@@ -11,4 +11,4 @@ /*! | ||
ISequencedDocumentMessage, | ||
ITree, | ||
ISnapshotTree, | ||
SummaryType, | ||
} from "@fluidframework/protocol-definitions"; | ||
@@ -21,3 +21,3 @@ import { | ||
} from "@fluidframework/datastore-definitions"; | ||
import { IFluidDataStoreContext, ISummarizeResult } from "@fluidframework/runtime-definitions"; | ||
import { IFluidDataStoreContext, ISummarizeResult, ISummaryTreeWithStats } from "@fluidframework/runtime-definitions"; | ||
import { readAndParse } from "@fluidframework/driver-utils"; | ||
@@ -124,8 +124,10 @@ import { CreateContainerError } from "@fluidframework/container-utils"; | ||
public async snapshot(fullTree: boolean = false): Promise<ITree> { | ||
return this.getAttachSnapshot(); | ||
} | ||
public async summarize(fullTree: boolean = false): Promise<ISummarizeResult> { | ||
const snapshot = this.getAttachSnapshot(); | ||
/** | ||
* 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. | ||
*/ | ||
public async summarize(fullTree: boolean = false, trackState: boolean = false): Promise<ISummarizeResult> { | ||
assert(this.isLoaded && this.channel !== undefined, "Channel should be loaded to take summary"); | ||
const snapshot = snapshotChannel(this.channel); | ||
const summary = convertToSummaryTree(snapshot, fullTree); | ||
@@ -135,5 +137,13 @@ return summary; | ||
public getAttachSnapshot(): ITree { | ||
public getAttachSummary(): ISummaryTreeWithStats { | ||
assert(this.isLoaded && this.channel !== undefined, "Channel should be loaded to take snapshot"); | ||
return snapshotChannel(this.channel); | ||
const snapshot = snapshotChannel(this.channel); | ||
const summaryTree = convertToSummaryTree(snapshot, true /* fullTree */); | ||
assert( | ||
summaryTree.summary.type === SummaryType.Tree, | ||
"summarize should always return a tree when fullTree is true"); | ||
return { | ||
stats: summaryTree.stats, | ||
summary: summaryTree.summary, | ||
}; | ||
} | ||
@@ -140,0 +150,0 @@ |
@@ -9,2 +9,2 @@ /*! | ||
export const pkgName = "@fluidframework/datastore"; | ||
export const pkgVersion = "0.28.7"; | ||
export const pkgVersion = "0.29.0"; |
@@ -13,3 +13,2 @@ /*! | ||
ISnapshotTree, | ||
ITree, | ||
} from "@fluidframework/protocol-definitions"; | ||
@@ -70,3 +69,6 @@ import { | ||
extraBlobs); | ||
const thisSummarizeInternal = async (fullTree: boolean) => this.summarizeInternal(fullTree); | ||
// Summarizer node always tracks summary state. Set trackState to true. | ||
const thisSummarizeInternal = | ||
async (fullTree: boolean) => this.summarizeInternal(fullTree, true /* trackState */); | ||
this.summarizerNode = createSummarizerNode(thisSummarizeInternal); | ||
@@ -112,19 +114,16 @@ } | ||
public async snapshot(fullTree: boolean = false): Promise<ITree> { | ||
if (!fullTree) { | ||
const id = await this.summaryTracker.getId(); | ||
if (id !== undefined) { | ||
return { id, entries: [] }; | ||
} | ||
} | ||
const channel = await this.getChannel(); | ||
return snapshotChannel(channel); | ||
/** | ||
* 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. | ||
*/ | ||
public async summarize(fullTree: boolean = false, trackState: boolean = true): Promise<ISummarizeResult> { | ||
// Summarizer node tracks the state from the summary. If trackState is true, use summarizer node to get | ||
// the summary. Else, get the summary tree directly. | ||
return trackState | ||
? this.summarizerNode.summarize(fullTree) | ||
: this.summarizeInternal(fullTree, false /* trackState */); | ||
} | ||
public async summarize(fullTree: boolean = false): Promise<ISummarizeResult> { | ||
return this.summarizerNode.summarize(fullTree); | ||
} | ||
private async summarizeInternal(fullTree: boolean): Promise<ISummarizeInternalResult> { | ||
private async summarizeInternal(fullTree: boolean, trackState: boolean): Promise<ISummarizeInternalResult> { | ||
const channel = await this.getChannel(); | ||
@@ -131,0 +130,0 @@ const snapshotTree = snapshotChannel(channel); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
478904
0.67%4989
0.69%124
-6.77%