@fluidframework/container-runtime 0.54.0-47413 → 0.55.0-48551
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/.eslintrc.js +1 -1
- package/dist/blobManager.js +1 -1
- package/dist/blobManager.js.map +1 -1
- package/dist/containerRuntime.d.ts +17 -2
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +31 -21
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStoreContext.d.ts +16 -5
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +20 -8
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStores.d.ts +11 -2
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/dataStores.js +33 -17
- package/dist/dataStores.js.map +1 -1
- package/dist/garbageCollection.d.ts +28 -6
- package/dist/garbageCollection.d.ts.map +1 -1
- package/dist/garbageCollection.js +80 -7
- package/dist/garbageCollection.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/summaryFormat.d.ts +2 -0
- package/dist/summaryFormat.d.ts.map +1 -1
- package/dist/summaryFormat.js +0 -3
- package/dist/summaryFormat.js.map +1 -1
- package/dist/summaryManager.d.ts +1 -0
- package/dist/summaryManager.d.ts.map +1 -1
- package/dist/summaryManager.js +7 -2
- package/dist/summaryManager.js.map +1 -1
- package/lib/blobManager.js +1 -1
- package/lib/blobManager.js.map +1 -1
- package/lib/containerRuntime.d.ts +17 -2
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +30 -20
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStoreContext.d.ts +16 -5
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +20 -8
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStores.d.ts +11 -2
- package/lib/dataStores.d.ts.map +1 -1
- package/lib/dataStores.js +33 -17
- package/lib/dataStores.js.map +1 -1
- package/lib/garbageCollection.d.ts +28 -6
- package/lib/garbageCollection.d.ts.map +1 -1
- package/lib/garbageCollection.js +80 -7
- package/lib/garbageCollection.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/summaryFormat.d.ts +2 -0
- package/lib/summaryFormat.d.ts.map +1 -1
- package/lib/summaryFormat.js +0 -3
- package/lib/summaryFormat.js.map +1 -1
- package/lib/summaryManager.d.ts +1 -0
- package/lib/summaryManager.d.ts.map +1 -1
- package/lib/summaryManager.js +7 -2
- package/lib/summaryManager.js.map +1 -1
- package/package.json +22 -21
- package/src/blobManager.ts +1 -1
- package/src/containerRuntime.ts +34 -23
- package/src/dataStoreContext.ts +31 -9
- package/src/dataStores.ts +43 -20
- package/src/garbageCollection.ts +108 -10
- package/src/index.ts +1 -0
- package/src/packageVersion.ts +1 -1
- package/src/summaryFormat.ts +2 -3
- package/src/summaryManager.ts +9 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summaryManager.js","sourceRoot":"","sources":["../src/summaryManager.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { IDisposable, IEvent, IEventProvider, ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { TypedEventEmitter, assert } from \"@fluidframework/common-utils\";\nimport { ChildLogger, PerformanceEvent } from \"@fluidframework/telemetry-utils\";\nimport { DriverErrorType } from \"@fluidframework/driver-definitions\";\nimport { createSummarizingWarning } from \"./summarizer\";\nimport { ISummarizerClientElection } from \"./summarizerClientElection\";\nimport { IThrottler } from \"./throttler\";\nimport {\n ISummarizer,\n ISummarizerOptions,\n ISummarizingWarning,\n SummarizerStopReason,\n} from \"./summarizerTypes\";\nimport { SummaryCollection } from \"./summaryCollection\";\n\nconst defaultInitialDelayMs = 5000;\nconst defaultOpsToBypassInitialDelay = 4000;\n\nexport enum SummaryManagerState {\n Off = 0,\n Starting = 1,\n Running = 2,\n Stopping = 3,\n}\n\n// Please note that all reasons in this list are not errors,\n// and thus they are not raised today to parent container as error.\n// If this needs to be changed in future, we should re-evaluate what and how we raise to summarizer\ntype StopReason = Extract<SummarizerStopReason, \"parentNotConnected\" | \"parentShouldNotSummarize\">;\ntype ShouldSummarizeState =\n | { shouldSummarize: true; }\n | { shouldSummarize: false; stopReason: StopReason; };\n\nexport interface IConnectedEvents extends IEvent {\n (event: \"connected\", listener: (clientId: string) => void);\n (event: \"disconnected\", listener: () => void);\n}\n\n/**\n * IConnectedState describes an object that SummaryManager can watch to observe connection/disconnection.\n *\n * Under current implementation, its role will be fulfilled by the ContainerRuntime, but this could be replaced\n * with anything else that fulfills the contract if we want to shift the layer that the SummaryManager lives at.\n */\nexport interface IConnectedState extends IEventProvider<IConnectedEvents> {\n readonly connected: boolean;\n\n /**\n * Under current implementation this is undefined if we've never connected, otherwise it's the clientId from our\n * latest connection (even if we've since disconnected!). Although this happens to be the behavior we want in\n * SummaryManager, I suspect that globally we may eventually want to modify this behavior (e.g. make clientId\n * undefined while disconnected). To protect against this, let's assume this field can't be trusted while\n * disconnected and instead separately track \"latest clientId\" in SummaryManager.\n */\n readonly clientId: string | undefined;\n}\n\nexport interface ISummaryManagerEvents extends IEvent {\n (event: \"summarizerWarning\", listener: (warning: ISummarizingWarning) => void);\n}\n\nexport interface ISummaryManagerConfig {\n initialDelayMs: number;\n opsToBypassInitialDelay: number;\n}\n\n/**\n * SummaryManager is created by parent container (i.e. interactive container with clientType !== \"summarizer\") only.\n * It observes changes in calculated summarizer and reacts to changes by either creating summarizer client or\n * stopping existing summarizer client.\n */\nexport class SummaryManager extends TypedEventEmitter<ISummaryManagerEvents> implements IDisposable {\n private readonly logger: ITelemetryLogger;\n private readonly opsToBypassInitialDelay: number;\n private readonly initialDelayMs: number;\n private latestClientId: string | undefined;\n private state = SummaryManagerState.Off;\n private summarizer?: ISummarizer;\n private _disposed = false;\n\n public get disposed() {\n return this._disposed;\n }\n\n public get currentState() { return this.state; }\n\n constructor(\n private readonly clientElection: ISummarizerClientElection,\n private readonly connectedState: IConnectedState,\n private readonly summaryCollection:\n Pick<SummaryCollection, \"opsSinceLastAck\" | \"addOpListener\" | \"removeOpListener\">,\n parentLogger: ITelemetryLogger,\n /** Creates summarizer by asking interactive container to spawn summarizing container and\n * get back its Summarizer instance. */\n private readonly requestSummarizerFn: () => Promise<ISummarizer>,\n private readonly startThrottler: IThrottler,\n {\n initialDelayMs = defaultInitialDelayMs,\n opsToBypassInitialDelay = defaultOpsToBypassInitialDelay,\n }: Readonly<Partial<ISummaryManagerConfig>> = {},\n private readonly summarizerOptions?: Readonly<Partial<ISummarizerOptions>>,\n ) {\n super();\n\n this.logger = ChildLogger.create(\n parentLogger,\n \"SummaryManager\",\n {all:{ clientId: () => this.latestClientId }});\n\n this.connectedState.on(\"connected\", this.handleConnected);\n this.connectedState.on(\"disconnected\", this.handleDisconnected);\n this.latestClientId = this.connectedState.clientId;\n\n this.opsToBypassInitialDelay = opsToBypassInitialDelay;\n this.initialDelayMs = initialDelayMs;\n }\n\n /**\n * Until start is called, the SummaryManager won't begin attempting to start summarization. This ensures there's\n * a window between construction and starting where the caller can attach listeners.\n */\n public start(): void {\n this.clientElection.on(\"electedSummarizerChanged\", this.refreshSummarizer);\n this.refreshSummarizer();\n }\n\n private readonly handleConnected = (clientId: string) => {\n this.latestClientId = clientId;\n // If we have a summarizer, it should have been either cancelled on disconnected by now.\n // But because of lastSummary process, it can still hang around, so there is not much we can\n // check or assert.\n this.refreshSummarizer();\n };\n\n private readonly handleDisconnected = () => {\n this.refreshSummarizer();\n };\n\n private getShouldSummarizeState(): ShouldSummarizeState {\n if (!this.connectedState.connected) {\n return { shouldSummarize: false, stopReason: \"parentNotConnected\" };\n } else if (this.connectedState.clientId !== this.clientElection.electedClientId) {\n return { shouldSummarize: false, stopReason: \"parentShouldNotSummarize\" };\n } else if (this.disposed) {\n assert(false, 0x260 /* \"Disposed should mean disconnected!\" */);\n } else {\n return { shouldSummarize: true };\n }\n }\n\n private readonly refreshSummarizer = () => {\n // Transition states depending on shouldSummarize, which is a calculated property\n // that is only true if this client is connected and is the elected summarizer.\n const shouldSummarizeState = this.getShouldSummarizeState();\n switch (this.state) {\n case SummaryManagerState.Off: {\n if (shouldSummarizeState.shouldSummarize) {\n this.startSummarization();\n }\n return;\n }\n case SummaryManagerState.Starting: {\n // Cannot take any action until summarizer is created\n // state transition will occur after creation\n return;\n }\n case SummaryManagerState.Running: {\n if (shouldSummarizeState.shouldSummarize === false) {\n this.stop(shouldSummarizeState.stopReason);\n }\n return;\n }\n case SummaryManagerState.Stopping: {\n // Cannot take any action until running summarizer finishes\n // state transition will occur after it stops\n return;\n }\n default: {\n return;\n }\n }\n };\n\n private startSummarization() {\n assert(this.state === SummaryManagerState.Off, 0x261 /* \"Expected: off\" */);\n this.state = SummaryManagerState.Starting;\n\n assert(this.summarizer === undefined, 0x262 /* \"Old summarizer is still working!\" */);\n\n let reason = \"unknown\";\n\n this.delayBeforeCreatingSummarizer().then(async (startWithInitialDelay: boolean) => {\n // Re-validate that it need to be running. Due to asynchrony, it may be not the case anymore\n // but only if creation was delayed. If it was not, then we want to ensure we always create\n // a summarizer to kick off lastSummary. Without that, we would not be able to summarize and get\n // document out of broken state if it has too many ops and ordering service keeps nacking main\n // container (and thus it goes into cycle of reconnects)\n if (startWithInitialDelay && this.getShouldSummarizeState().shouldSummarize === false) {\n return;\n }\n\n const summarizer = await this.requestSummarizerFn();\n\n // Re-validate that it need to be running. Due to asynchrony, it may be not the case anymore\n const shouldSummarizeState = this.getShouldSummarizeState();\n if (shouldSummarizeState.shouldSummarize === false) {\n summarizer.stop(shouldSummarizeState.stopReason);\n return;\n }\n\n assert(this.state === SummaryManagerState.Starting, 0x263 /* \"Expected: starting\" */);\n this.state = SummaryManagerState.Running;\n\n summarizer.on(\"summarizingError\",\n (warning: ISummarizingWarning) => this.emit(\"summarizerWarning\", warning));\n this.summarizer = summarizer;\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const clientId = this.latestClientId!;\n\n reason = await PerformanceEvent.timedExecAsync(\n this.logger,\n { eventName: \"RunningSummarizer\", attempt: this.startThrottler.numAttempts },\n async () => summarizer.run(clientId, this.summarizerOptions),\n );\n }).catch((error) => {\n // Most of exceptions happen due to container being closed while loading it, due to\n // summarizer container loosing connection while load.\n // Not worth reporting such errors as errors. That said, we might miss some real errors if\n // we ignore blindly, so try to narrow signature we are looking for - skip logging\n // error only if this client should no longer be a summarizer (which in practice\n // means it also lost connection), and error happened on load (we do not have summarizer).\n // We could add error.fluidErrorCode !== \"containerClosedWithoutErrorDuringLoad\" check to narrow it down,\n // but that does not seem to be necessary.\n if (this.getShouldSummarizeState().shouldSummarize || this.summarizer !== undefined) {\n // Report any failure as an error unless it was due to cancellation (like \"disconnected\" error)\n // If failure happened on container load, we may not yet realized that socket disconnected, so check\n // offlineError.\n const category = error?.errorType === DriverErrorType.offlineError ? \"generic\" : \"error\";\n this.logger.sendTelemetryEvent(\n {\n eventName: \"SummarizerException\",\n category,\n },\n error);\n this.emit(\"summarizerWarning\", error);\n\n // Note that summarizer may keep going (like doing last summary).\n // Ideally we await stopping process, but this code path is due to a bug\n // that needs to be fixed either way.\n this.stop(\"summarizerException\");\n }\n }).finally(() => {\n assert(this.state !== SummaryManagerState.Off, 0x264 /* \"Expected: Not Off\" */);\n this.state = SummaryManagerState.Off;\n\n this.summarizer = undefined;\n\n this.logger.sendTelemetryEvent({\n eventName: \"EndingSummarizer\",\n reason,\n });\n\n if (this.getShouldSummarizeState().shouldSummarize) {\n this.startSummarization();\n }\n });\n }\n\n private stop(reason: SummarizerStopReason) {\n assert(this.state === SummaryManagerState.Running || this.state === SummaryManagerState.Starting,\n 0x265 /* \"Expected: Starting or Running\" */);\n this.state = SummaryManagerState.Stopping;\n\n // Stopping the running summarizer client should trigger a change\n // in states when the running summarizer closes\n this.summarizer?.stop(reason);\n }\n\n /**\n * Implements initial delay before creating summarizer\n * @returns true, if creation is delayed due to heuristics (not many ops to summarize).\n * False if summarizer should start immediately due to too many unsummarized ops.\n */\n private async delayBeforeCreatingSummarizer(): Promise<boolean> {\n // throttle creation of new summarizer containers to prevent spamming the server with websocket connections\n let delayMs = this.startThrottler.getDelay();\n if (delayMs > 0 && delayMs > this.startThrottler.maxDelayMs) {\n this.emit(\n \"summarizerWarning\",\n createSummarizingWarning(\"summaryManagerCreateSummarizerMaxThrottleDelay\", false),\n );\n }\n\n // We have been elected the summarizer. Some day we may be able to summarize with a live document but for\n // now we play it safe and launch a second copy.\n this.logger.sendTelemetryEvent({\n eventName: \"CreatingSummarizer\",\n throttlerDelay: delayMs,\n initialDelay: this.initialDelayMs,\n opsSinceLastAck: this.summaryCollection.opsSinceLastAck,\n opsToBypassInitialDelay: this.opsToBypassInitialDelay,\n });\n\n // This delay helps ensure that last summarizer that might be left from previous client\n // has enough time to complete its last summary and thus new summarizer not conflict with previous one.\n // If, however, there are too many unsummarized ops, try to resolve it as quickly as possible, with\n // understanding that we may see nacks because of such quick action.\n // A better design would be for summarizer election logic to always select current summarizer as\n // summarizing client (i.e. clientType === \"summarizer\" can be elected) to ensure that nobody else can\n // summarizer while it finishes its work and moves to exit.\n // It also helps with pure boot scenario (single client) to offset expensive work a bit out from\n // critical boot sequence.\n let startWithInitialDelay = false;\n if (this.summaryCollection.opsSinceLastAck < this.opsToBypassInitialDelay) {\n startWithInitialDelay = true;\n delayMs = Math.max(delayMs, this.initialDelayMs);\n }\n\n if (delayMs > 0) {\n let timer;\n let resolveOpPromiseFn;\n // Create a listener that will break the delay if we've exceeded the initial delay ops count.\n const opsListenerFn = () => {\n if (this.summaryCollection.opsSinceLastAck >= this.opsToBypassInitialDelay) {\n clearTimeout(timer);\n resolveOpPromiseFn();\n }\n };\n // Create a Promise that will resolve when the delay expires.\n const delayPromise = new Promise<void>((resolve) => {\n timer = setTimeout(() => resolve(), delayMs);\n });\n // Create a Promise that will resolve if the ops count passes the threshold.\n const opPromise = new Promise<void>((resolve) => { resolveOpPromiseFn = resolve; });\n this.summaryCollection.addOpListener(opsListenerFn);\n await Promise.race([ delayPromise, opPromise ]);\n this.summaryCollection.removeOpListener(opsListenerFn);\n }\n return startWithInitialDelay;\n }\n\n public readonly summarizeOnDemand: ISummarizer[\"summarizeOnDemand\"] = (...args) => {\n if (this.summarizer === undefined) {\n throw Error(\"No running summarizer client\");\n // TODO: could spawn a summarizer client temporarily.\n }\n return this.summarizer.summarizeOnDemand(...args);\n };\n\n public readonly enqueueSummarize: ISummarizer[\"enqueueSummarize\"] = (...args) => {\n if (this.summarizer === undefined) {\n throw Error(\"No running summarizer client\");\n // TODO: could spawn a summarizer client temporarily.\n }\n return this.summarizer.enqueueSummarize(...args);\n };\n\n public dispose() {\n this.clientElection.off(\"electedSummarizerChanged\", this.refreshSummarizer);\n this.connectedState.off(\"connected\", this.handleConnected);\n this.connectedState.off(\"disconnected\", this.handleDisconnected);\n this._disposed = true;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"summaryManager.js","sourceRoot":"","sources":["../src/summaryManager.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { IDisposable, IEvent, IEventProvider, ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { TypedEventEmitter, assert } from \"@fluidframework/common-utils\";\nimport { ChildLogger, PerformanceEvent } from \"@fluidframework/telemetry-utils\";\nimport { DriverErrorType } from \"@fluidframework/driver-definitions\";\nimport { createSummarizingWarning } from \"./summarizer\";\nimport { ISummarizerClientElection } from \"./summarizerClientElection\";\nimport { IThrottler } from \"./throttler\";\nimport {\n ISummarizer,\n ISummarizerOptions,\n ISummarizingWarning,\n SummarizerStopReason,\n} from \"./summarizerTypes\";\nimport { SummaryCollection } from \"./summaryCollection\";\n\nconst defaultInitialDelayMs = 5000;\nconst defaultOpsToBypassInitialDelay = 4000;\n\nexport enum SummaryManagerState {\n Off = 0,\n Starting = 1,\n Running = 2,\n Stopping = 3,\n}\n\n// Please note that all reasons in this list are not errors,\n// and thus they are not raised today to parent container as error.\n// If this needs to be changed in future, we should re-evaluate what and how we raise to summarizer\ntype StopReason = Extract<SummarizerStopReason, \"parentNotConnected\" | \"parentShouldNotSummarize\">;\ntype ShouldSummarizeState =\n | { shouldSummarize: true; }\n | { shouldSummarize: false; stopReason: StopReason; };\n\nexport interface IConnectedEvents extends IEvent {\n (event: \"connected\", listener: (clientId: string) => void);\n (event: \"disconnected\", listener: () => void);\n}\n\n/**\n * IConnectedState describes an object that SummaryManager can watch to observe connection/disconnection.\n *\n * Under current implementation, its role will be fulfilled by the ContainerRuntime, but this could be replaced\n * with anything else that fulfills the contract if we want to shift the layer that the SummaryManager lives at.\n */\nexport interface IConnectedState extends IEventProvider<IConnectedEvents> {\n readonly connected: boolean;\n\n /**\n * Under current implementation this is undefined if we've never connected, otherwise it's the clientId from our\n * latest connection (even if we've since disconnected!). Although this happens to be the behavior we want in\n * SummaryManager, I suspect that globally we may eventually want to modify this behavior (e.g. make clientId\n * undefined while disconnected). To protect against this, let's assume this field can't be trusted while\n * disconnected and instead separately track \"latest clientId\" in SummaryManager.\n */\n readonly clientId: string | undefined;\n}\n\nexport interface ISummaryManagerEvents extends IEvent {\n (event: \"summarizerWarning\", listener: (warning: ISummarizingWarning) => void);\n}\n\nexport interface ISummaryManagerConfig {\n initialDelayMs: number;\n opsToBypassInitialDelay: number;\n}\n\n/**\n * SummaryManager is created by parent container (i.e. interactive container with clientType !== \"summarizer\") only.\n * It observes changes in calculated summarizer and reacts to changes by either creating summarizer client or\n * stopping existing summarizer client.\n */\nexport class SummaryManager extends TypedEventEmitter<ISummaryManagerEvents> implements IDisposable {\n private readonly logger: ITelemetryLogger;\n private readonly opsToBypassInitialDelay: number;\n private readonly initialDelayMs: number;\n private latestClientId: string | undefined;\n private state = SummaryManagerState.Off;\n private summarizer?: ISummarizer;\n private _disposed = false;\n\n public get disposed() {\n return this._disposed;\n }\n\n public get currentState() { return this.state; }\n\n constructor(\n private readonly clientElection: ISummarizerClientElection,\n private readonly connectedState: IConnectedState,\n private readonly summaryCollection:\n Pick<SummaryCollection, \"opsSinceLastAck\" | \"addOpListener\" | \"removeOpListener\">,\n parentLogger: ITelemetryLogger,\n /** Creates summarizer by asking interactive container to spawn summarizing container and\n * get back its Summarizer instance. */\n private readonly requestSummarizerFn: () => Promise<ISummarizer>,\n private readonly startThrottler: IThrottler,\n {\n initialDelayMs = defaultInitialDelayMs,\n opsToBypassInitialDelay = defaultOpsToBypassInitialDelay,\n }: Readonly<Partial<ISummaryManagerConfig>> = {},\n private readonly summarizerOptions?: Readonly<Partial<ISummarizerOptions>>,\n ) {\n super();\n\n this.logger = ChildLogger.create(\n parentLogger,\n \"SummaryManager\",\n {all:{ clientId: () => this.latestClientId }});\n\n this.connectedState.on(\"connected\", this.handleConnected);\n this.connectedState.on(\"disconnected\", this.handleDisconnected);\n this.latestClientId = this.connectedState.clientId;\n\n this.opsToBypassInitialDelay = opsToBypassInitialDelay;\n this.initialDelayMs = initialDelayMs;\n }\n\n /**\n * Until start is called, the SummaryManager won't begin attempting to start summarization. This ensures there's\n * a window between construction and starting where the caller can attach listeners.\n */\n public start(): void {\n this.clientElection.on(\"electedSummarizerChanged\", this.refreshSummarizer);\n this.refreshSummarizer();\n }\n\n private readonly handleConnected = (clientId: string) => {\n this.latestClientId = clientId;\n // If we have a summarizer, it should have been either cancelled on disconnected by now.\n // But because of lastSummary process, it can still hang around, so there is not much we can\n // check or assert.\n this.refreshSummarizer();\n };\n\n private readonly handleDisconnected = () => {\n this.refreshSummarizer();\n };\n\n private static readonly isStartingOrRunning = (state: SummaryManagerState) =>\n state === SummaryManagerState.Starting || state === SummaryManagerState.Running;\n\n private getShouldSummarizeState(): ShouldSummarizeState {\n if (!this.connectedState.connected) {\n return { shouldSummarize: false, stopReason: \"parentNotConnected\" };\n } else if (this.connectedState.clientId !== this.clientElection.electedClientId) {\n return { shouldSummarize: false, stopReason: \"parentShouldNotSummarize\" };\n } else if (this.disposed) {\n assert(false, 0x260 /* \"Disposed should mean disconnected!\" */);\n } else {\n return { shouldSummarize: true };\n }\n }\n\n private readonly refreshSummarizer = () => {\n // Transition states depending on shouldSummarize, which is a calculated property\n // that is only true if this client is connected and is the elected summarizer.\n const shouldSummarizeState = this.getShouldSummarizeState();\n switch (this.state) {\n case SummaryManagerState.Off: {\n if (shouldSummarizeState.shouldSummarize) {\n this.startSummarization();\n }\n return;\n }\n case SummaryManagerState.Starting: {\n // Cannot take any action until summarizer is created\n // state transition will occur after creation\n return;\n }\n case SummaryManagerState.Running: {\n if (shouldSummarizeState.shouldSummarize === false) {\n this.stop(shouldSummarizeState.stopReason);\n }\n return;\n }\n case SummaryManagerState.Stopping: {\n // Cannot take any action until running summarizer finishes\n // state transition will occur after it stops\n return;\n }\n default: {\n return;\n }\n }\n };\n\n private startSummarization() {\n assert(this.state === SummaryManagerState.Off, 0x261 /* \"Expected: off\" */);\n this.state = SummaryManagerState.Starting;\n\n assert(this.summarizer === undefined, 0x262 /* \"Old summarizer is still working!\" */);\n\n let reason = \"unknown\";\n\n this.delayBeforeCreatingSummarizer().then(async (startWithInitialDelay: boolean) => {\n // Re-validate that it need to be running. Due to asynchrony, it may be not the case anymore\n // but only if creation was delayed. If it was not, then we want to ensure we always create\n // a summarizer to kick off lastSummary. Without that, we would not be able to summarize and get\n // document out of broken state if it has too many ops and ordering service keeps nacking main\n // container (and thus it goes into cycle of reconnects)\n if (startWithInitialDelay && this.getShouldSummarizeState().shouldSummarize === false) {\n return;\n }\n\n const summarizer = await this.requestSummarizerFn();\n\n // Re-validate that it need to be running. Due to asynchrony, it may be not the case anymore\n const shouldSummarizeState = this.getShouldSummarizeState();\n if (shouldSummarizeState.shouldSummarize === false) {\n summarizer.stop(shouldSummarizeState.stopReason);\n return;\n }\n\n assert(this.state === SummaryManagerState.Starting, 0x263 /* \"Expected: starting\" */);\n this.state = SummaryManagerState.Running;\n\n summarizer.on(\"summarizingError\",\n (warning: ISummarizingWarning) => this.emit(\"summarizerWarning\", warning));\n this.summarizer = summarizer;\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const clientId = this.latestClientId!;\n\n reason = await PerformanceEvent.timedExecAsync(\n this.logger,\n { eventName: \"RunningSummarizer\", attempt: this.startThrottler.numAttempts },\n async () => summarizer.run(clientId, this.summarizerOptions),\n );\n }).catch((error) => {\n // Most of exceptions happen due to container being closed while loading it, due to\n // summarizer container loosing connection while load.\n // Not worth reporting such errors as errors. That said, we might miss some real errors if\n // we ignore blindly, so try to narrow signature we are looking for - skip logging\n // error only if this client should no longer be a summarizer (which in practice\n // means it also lost connection), and error happened on load (we do not have summarizer).\n // We could add error.fluidErrorCode !== \"containerClosedWithoutErrorDuringLoad\" check to narrow it down,\n // but that does not seem to be necessary.\n if (this.getShouldSummarizeState().shouldSummarize || this.summarizer !== undefined) {\n // Report any failure as an error unless it was due to cancellation (like \"disconnected\" error)\n // If failure happened on container load, we may not yet realized that socket disconnected, so check\n // offlineError.\n const category = error?.errorType === DriverErrorType.offlineError ? \"generic\" : \"error\";\n this.logger.sendTelemetryEvent(\n {\n eventName: \"SummarizerException\",\n category,\n },\n error);\n this.emit(\"summarizerWarning\", error);\n\n // Note that summarizer may keep going (like doing last summary).\n // Ideally we await stopping process, but this code path is due to a bug\n // that needs to be fixed either way.\n if (SummaryManager.isStartingOrRunning(this.state)) {\n this.stop(\"summarizerException\");\n }\n }\n }).finally(() => {\n assert(this.state !== SummaryManagerState.Off, 0x264 /* \"Expected: Not Off\" */);\n this.state = SummaryManagerState.Off;\n\n this.summarizer = undefined;\n\n this.logger.sendTelemetryEvent({\n eventName: \"EndingSummarizer\",\n reason,\n });\n\n if (this.getShouldSummarizeState().shouldSummarize) {\n this.startSummarization();\n }\n });\n }\n\n private stop(reason: SummarizerStopReason) {\n if (!SummaryManager.isStartingOrRunning(this.state)) {\n return;\n }\n this.state = SummaryManagerState.Stopping;\n\n // Stopping the running summarizer client should trigger a change\n // in states when the running summarizer closes\n this.summarizer?.stop(reason);\n }\n\n /**\n * Implements initial delay before creating summarizer\n * @returns true, if creation is delayed due to heuristics (not many ops to summarize).\n * False if summarizer should start immediately due to too many unsummarized ops.\n */\n private async delayBeforeCreatingSummarizer(): Promise<boolean> {\n // throttle creation of new summarizer containers to prevent spamming the server with websocket connections\n let delayMs = this.startThrottler.getDelay();\n if (delayMs > 0 && delayMs > this.startThrottler.maxDelayMs) {\n this.emit(\n \"summarizerWarning\",\n createSummarizingWarning(\"summaryManagerCreateSummarizerMaxThrottleDelay\", false),\n );\n }\n\n // We have been elected the summarizer. Some day we may be able to summarize with a live document but for\n // now we play it safe and launch a second copy.\n this.logger.sendTelemetryEvent({\n eventName: \"CreatingSummarizer\",\n throttlerDelay: delayMs,\n initialDelay: this.initialDelayMs,\n opsSinceLastAck: this.summaryCollection.opsSinceLastAck,\n opsToBypassInitialDelay: this.opsToBypassInitialDelay,\n });\n\n // This delay helps ensure that last summarizer that might be left from previous client\n // has enough time to complete its last summary and thus new summarizer not conflict with previous one.\n // If, however, there are too many unsummarized ops, try to resolve it as quickly as possible, with\n // understanding that we may see nacks because of such quick action.\n // A better design would be for summarizer election logic to always select current summarizer as\n // summarizing client (i.e. clientType === \"summarizer\" can be elected) to ensure that nobody else can\n // summarizer while it finishes its work and moves to exit.\n // It also helps with pure boot scenario (single client) to offset expensive work a bit out from\n // critical boot sequence.\n let startWithInitialDelay = false;\n if (this.summaryCollection.opsSinceLastAck < this.opsToBypassInitialDelay) {\n startWithInitialDelay = true;\n delayMs = Math.max(delayMs, this.initialDelayMs);\n }\n\n if (delayMs > 0) {\n let timer;\n let resolveOpPromiseFn;\n // Create a listener that will break the delay if we've exceeded the initial delay ops count.\n const opsListenerFn = () => {\n if (this.summaryCollection.opsSinceLastAck >= this.opsToBypassInitialDelay) {\n clearTimeout(timer);\n resolveOpPromiseFn();\n }\n };\n // Create a Promise that will resolve when the delay expires.\n const delayPromise = new Promise<void>((resolve) => {\n timer = setTimeout(() => resolve(), delayMs);\n });\n // Create a Promise that will resolve if the ops count passes the threshold.\n const opPromise = new Promise<void>((resolve) => { resolveOpPromiseFn = resolve; });\n this.summaryCollection.addOpListener(opsListenerFn);\n await Promise.race([ delayPromise, opPromise ]);\n this.summaryCollection.removeOpListener(opsListenerFn);\n }\n return startWithInitialDelay;\n }\n\n public readonly summarizeOnDemand: ISummarizer[\"summarizeOnDemand\"] = (...args) => {\n if (this.summarizer === undefined) {\n throw Error(\"No running summarizer client\");\n // TODO: could spawn a summarizer client temporarily.\n }\n return this.summarizer.summarizeOnDemand(...args);\n };\n\n public readonly enqueueSummarize: ISummarizer[\"enqueueSummarize\"] = (...args) => {\n if (this.summarizer === undefined) {\n throw Error(\"No running summarizer client\");\n // TODO: could spawn a summarizer client temporarily.\n }\n return this.summarizer.enqueueSummarize(...args);\n };\n\n public dispose() {\n this.clientElection.off(\"electedSummarizerChanged\", this.refreshSummarizer);\n this.connectedState.off(\"connected\", this.handleConnected);\n this.connectedState.off(\"disconnected\", this.handleDisconnected);\n this._disposed = true;\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/container-runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.55.0-48551",
|
|
4
4
|
"description": "Fluid container runtime",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": "https://github.com/microsoft/FluidFramework",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"ci:build:docs": "api-extractor run --typescript-compiler-folder ../../../node_modules/typescript && copyfiles -u 1 ./_api-extractor-temp/doc-models/* ../../../_api-extractor-temp/",
|
|
24
24
|
"clean": "rimraf dist lib *.tsbuildinfo *.build.log",
|
|
25
25
|
"eslint": "eslint --format stylish src",
|
|
26
|
-
"eslint:fix": "eslint --format stylish src --fix",
|
|
26
|
+
"eslint:fix": "eslint --format stylish src --fix --fix-type problem,suggestion,layout",
|
|
27
27
|
"lint": "npm run eslint",
|
|
28
28
|
"lint:fix": "npm run eslint:fix",
|
|
29
29
|
"test": "npm run test:mocha",
|
|
@@ -58,45 +58,46 @@
|
|
|
58
58
|
"dependencies": {
|
|
59
59
|
"@fluidframework/common-definitions": "^0.20.1",
|
|
60
60
|
"@fluidframework/common-utils": "^0.32.1",
|
|
61
|
-
"@fluidframework/container-definitions": "^0.44.0
|
|
62
|
-
"@fluidframework/container-runtime-definitions": "0.
|
|
63
|
-
"@fluidframework/container-utils": "0.
|
|
61
|
+
"@fluidframework/container-definitions": "^0.44.0",
|
|
62
|
+
"@fluidframework/container-runtime-definitions": "0.55.0-48551",
|
|
63
|
+
"@fluidframework/container-utils": "0.55.0-48551",
|
|
64
64
|
"@fluidframework/core-interfaces": "^0.41.0",
|
|
65
|
-
"@fluidframework/datastore": "0.
|
|
65
|
+
"@fluidframework/datastore": "0.55.0-48551",
|
|
66
66
|
"@fluidframework/driver-definitions": "^0.43.0",
|
|
67
|
-
"@fluidframework/driver-utils": "0.
|
|
68
|
-
"@fluidframework/garbage-collector": "0.
|
|
67
|
+
"@fluidframework/driver-utils": "0.55.0-48551",
|
|
68
|
+
"@fluidframework/garbage-collector": "0.55.0-48551",
|
|
69
69
|
"@fluidframework/protocol-base": "^0.1034.0",
|
|
70
70
|
"@fluidframework/protocol-definitions": "^0.1026.0",
|
|
71
|
-
"@fluidframework/runtime-definitions": "0.
|
|
72
|
-
"@fluidframework/runtime-utils": "0.
|
|
73
|
-
"@fluidframework/telemetry-utils": "0.
|
|
71
|
+
"@fluidframework/runtime-definitions": "0.55.0-48551",
|
|
72
|
+
"@fluidframework/runtime-utils": "0.55.0-48551",
|
|
73
|
+
"@fluidframework/telemetry-utils": "0.55.0-48551",
|
|
74
74
|
"double-ended-queue": "^2.1.0-0",
|
|
75
75
|
"uuid": "^8.3.1"
|
|
76
76
|
},
|
|
77
77
|
"devDependencies": {
|
|
78
78
|
"@fluidframework/build-common": "^0.23.0",
|
|
79
|
-
"@fluidframework/eslint-config-fluid": "^0.
|
|
80
|
-
"@fluidframework/mocha-test-setup": "0.
|
|
81
|
-
"@fluidframework/test-runtime-utils": "0.
|
|
79
|
+
"@fluidframework/eslint-config-fluid": "^0.25.0-0",
|
|
80
|
+
"@fluidframework/mocha-test-setup": "0.55.0-48551",
|
|
81
|
+
"@fluidframework/test-runtime-utils": "0.55.0-48551",
|
|
82
82
|
"@microsoft/api-extractor": "^7.16.1",
|
|
83
|
+
"@rushstack/eslint-config": "^2.5.1",
|
|
83
84
|
"@types/double-ended-queue": "^2.1.0",
|
|
84
85
|
"@types/mocha": "^8.2.2",
|
|
85
86
|
"@types/node": "^14.18.0",
|
|
86
87
|
"@types/sinon": "^7.0.13",
|
|
87
88
|
"@types/uuid": "^8.3.0",
|
|
88
|
-
"@typescript-eslint/eslint-plugin": "~
|
|
89
|
-
"@typescript-eslint/parser": "~
|
|
89
|
+
"@typescript-eslint/eslint-plugin": "~5.9.0",
|
|
90
|
+
"@typescript-eslint/parser": "~5.9.0",
|
|
90
91
|
"concurrently": "^6.2.0",
|
|
91
92
|
"copyfiles": "^2.1.0",
|
|
92
93
|
"cross-env": "^7.0.2",
|
|
93
|
-
"eslint": "~
|
|
94
|
+
"eslint": "~8.6.0",
|
|
95
|
+
"eslint-plugin-editorconfig": "~3.2.0",
|
|
94
96
|
"eslint-plugin-eslint-comments": "~3.2.0",
|
|
95
|
-
"eslint-plugin-import": "~2.
|
|
97
|
+
"eslint-plugin-import": "~2.25.4",
|
|
96
98
|
"eslint-plugin-no-null": "~1.0.2",
|
|
97
|
-
"eslint-plugin-
|
|
98
|
-
"eslint-plugin-
|
|
99
|
-
"eslint-plugin-unicorn": "~26.0.1",
|
|
99
|
+
"eslint-plugin-react": "~7.28.0",
|
|
100
|
+
"eslint-plugin-unicorn": "~40.0.0",
|
|
100
101
|
"mocha": "^8.4.0",
|
|
101
102
|
"nyc": "^15.0.0",
|
|
102
103
|
"rimraf": "^2.6.2",
|
package/src/blobManager.ts
CHANGED
|
@@ -104,7 +104,7 @@ export class BlobManager {
|
|
|
104
104
|
if (this.runtime.attachState === AttachState.Attaching) {
|
|
105
105
|
// blob upload is not supported in "Attaching" state
|
|
106
106
|
this.logger.sendTelemetryEvent({ eventName: "CreateBlobWhileAttaching" });
|
|
107
|
-
await new Promise<void>((
|
|
107
|
+
await new Promise<void>((resolve) => this.runtime.once("attached", resolve));
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
const response = await this.getStorage().createBlob(blob);
|
package/src/containerRuntime.ts
CHANGED
|
@@ -7,7 +7,6 @@ import { EventEmitter } from "events";
|
|
|
7
7
|
import { ITelemetryGenericEvent, ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
8
8
|
import {
|
|
9
9
|
FluidObject,
|
|
10
|
-
IFluidConfiguration,
|
|
11
10
|
IFluidHandle,
|
|
12
11
|
IFluidHandleContext,
|
|
13
12
|
IFluidObject,
|
|
@@ -77,7 +76,7 @@ import {
|
|
|
77
76
|
IFluidDataStoreRegistry,
|
|
78
77
|
IFluidDataStoreChannel,
|
|
79
78
|
IGarbageCollectionData,
|
|
80
|
-
|
|
79
|
+
IGarbageCollectionDetailsBase,
|
|
81
80
|
IEnvelope,
|
|
82
81
|
IInboundSignalMessage,
|
|
83
82
|
ISignalEnvelope,
|
|
@@ -294,19 +293,21 @@ type IRuntimeMessageMetadata = undefined | {
|
|
|
294
293
|
// Local storage key to set the default flush mode to TurnBased
|
|
295
294
|
const turnBasedFlushModeKey = "Fluid.ContainerRuntime.FlushModeTurnBased";
|
|
296
295
|
|
|
296
|
+
export enum RuntimeMessage {
|
|
297
|
+
FluidDataStoreOp = "component",
|
|
298
|
+
Attach = "attach",
|
|
299
|
+
ChunkedOp = "chunkedOp",
|
|
300
|
+
BlobAttach = "blobAttach",
|
|
301
|
+
Rejoin = "rejoin",
|
|
302
|
+
Alias = "alias",
|
|
303
|
+
Operation = "op",
|
|
304
|
+
}
|
|
305
|
+
|
|
297
306
|
export function isRuntimeMessage(message: ISequencedDocumentMessage): boolean {
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
case ContainerMessageType.ChunkedOp:
|
|
301
|
-
case ContainerMessageType.Attach:
|
|
302
|
-
case ContainerMessageType.Alias:
|
|
303
|
-
case ContainerMessageType.BlobAttach:
|
|
304
|
-
case ContainerMessageType.Rejoin:
|
|
305
|
-
case MessageType.Operation:
|
|
306
|
-
return true;
|
|
307
|
-
default:
|
|
308
|
-
return false;
|
|
307
|
+
if ((Object.values(RuntimeMessage) as string[]).includes(message.type)) {
|
|
308
|
+
return true;
|
|
309
309
|
}
|
|
310
|
+
return false;
|
|
310
311
|
}
|
|
311
312
|
|
|
312
313
|
export function unpackRuntimeMessage(message: ISequencedDocumentMessage) {
|
|
@@ -608,6 +609,7 @@ export function getDeviceSpec() {
|
|
|
608
609
|
}
|
|
609
610
|
return {};
|
|
610
611
|
}
|
|
612
|
+
|
|
611
613
|
/**
|
|
612
614
|
* Represents the runtime of the container. Contains helper functions/state of the container.
|
|
613
615
|
* It will define the store level mappings.
|
|
@@ -995,6 +997,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
995
997
|
this.runtimeOptions.gcOptions,
|
|
996
998
|
(unusedRoutes: string[]) => this.dataStores.deleteUnusedRoutes(unusedRoutes),
|
|
997
999
|
getCurrentTimestamp,
|
|
1000
|
+
this.closeFn,
|
|
998
1001
|
context.baseSnapshot,
|
|
999
1002
|
async <T>(id: string) => readAndParse<T>(this.storage, id),
|
|
1000
1003
|
this.mc.logger,
|
|
@@ -1034,14 +1037,14 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
1034
1037
|
(id: string, createParam: CreateChildSummarizerNodeParam) => (
|
|
1035
1038
|
summarizeInternal: SummarizeInternalFn,
|
|
1036
1039
|
getGCDataFn: (fullGC?: boolean) => Promise<IGarbageCollectionData>,
|
|
1037
|
-
|
|
1040
|
+
getBaseGCDetailsFn: () => Promise<IGarbageCollectionDetailsBase>,
|
|
1038
1041
|
) => this.summarizerNode.createChild(
|
|
1039
1042
|
summarizeInternal,
|
|
1040
1043
|
id,
|
|
1041
1044
|
createParam,
|
|
1042
1045
|
undefined,
|
|
1043
1046
|
getGCDataFn,
|
|
1044
|
-
|
|
1047
|
+
getBaseGCDetailsFn,
|
|
1045
1048
|
),
|
|
1046
1049
|
(id: string) => this.summarizerNode.deleteChild(id),
|
|
1047
1050
|
this.mc.logger,
|
|
@@ -1231,10 +1234,10 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
1231
1234
|
this.summaryManager.off("summarizerWarning", this.raiseContainerWarning);
|
|
1232
1235
|
this.summaryManager.dispose();
|
|
1233
1236
|
}
|
|
1237
|
+
this.garbageCollector.dispose();
|
|
1234
1238
|
this._summarizer?.dispose();
|
|
1235
1239
|
this.dataStores.dispose();
|
|
1236
1240
|
this.pendingStateManager.dispose();
|
|
1237
|
-
|
|
1238
1241
|
this.emit("dispose");
|
|
1239
1242
|
this.removeAllListeners();
|
|
1240
1243
|
}
|
|
@@ -1249,10 +1252,6 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
1249
1252
|
return undefined;
|
|
1250
1253
|
}
|
|
1251
1254
|
|
|
1252
|
-
public get IFluidConfiguration(): IFluidConfiguration {
|
|
1253
|
-
return this.context.configuration;
|
|
1254
|
-
}
|
|
1255
|
-
|
|
1256
1255
|
/**
|
|
1257
1256
|
* Notifies this object about the request made to the container.
|
|
1258
1257
|
* @param request - Request made to the handler.
|
|
@@ -1343,6 +1342,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
1343
1342
|
// The last message processed at the time of summary. If there are no messages, nothing has changed from
|
|
1344
1343
|
// the base summary we loaded from. So, use the message from its metadata blob.
|
|
1345
1344
|
message: extractSummaryMetadataMessage(this.deltaManager.lastMessage) ?? this.baseSummaryMessage,
|
|
1345
|
+
sessionExpiryTimeoutMs: this.garbageCollector.sessionExpiryTimeoutMs,
|
|
1346
1346
|
};
|
|
1347
1347
|
}
|
|
1348
1348
|
|
|
@@ -1358,7 +1358,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
1358
1358
|
const dataStoreContext = await this.dataStores.getDataStore(id, wait);
|
|
1359
1359
|
// The data store is referenced if used routes in the initial summary has a route to self.
|
|
1360
1360
|
// Older documents may not have used routes in the summary. They are considered referenced.
|
|
1361
|
-
const usedRoutes = (await dataStoreContext.
|
|
1361
|
+
const usedRoutes = (await dataStoreContext.getBaseGCDetails()).usedRoutes;
|
|
1362
1362
|
if (usedRoutes === undefined || usedRoutes.includes("") || usedRoutes.includes("/")) {
|
|
1363
1363
|
return dataStoreContext.realize();
|
|
1364
1364
|
}
|
|
@@ -1666,6 +1666,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
1666
1666
|
this.setFlushMode(savedFlushMode);
|
|
1667
1667
|
} catch(error) {
|
|
1668
1668
|
this.closeFn(CreateProcessingError(error, "orderSequentially"));
|
|
1669
|
+
throw error; // throw the original error for the consumer of the runtime
|
|
1669
1670
|
}
|
|
1670
1671
|
}
|
|
1671
1672
|
|
|
@@ -1870,6 +1871,16 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
1870
1871
|
return summarizeResult as ISummaryTreeWithStats;
|
|
1871
1872
|
}
|
|
1872
1873
|
|
|
1874
|
+
/**
|
|
1875
|
+
* Implementation of IGarbageCollectionRuntime::updateStateBeforeGC.
|
|
1876
|
+
* Before GC runs, called by the garbage collector to update any pending GC state. This is mainly used to notify
|
|
1877
|
+
* the garbage collector of references detected since the last GC run. Most references are notified immediately
|
|
1878
|
+
* but there can be some for which async operation is required (such as detecting new root data stores).
|
|
1879
|
+
*/
|
|
1880
|
+
public async updateStateBeforeGC() {
|
|
1881
|
+
return this.dataStores.updateStateBeforeGC();
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1873
1884
|
/**
|
|
1874
1885
|
* Implementation of IGarbageCollectionRuntime::getGCData.
|
|
1875
1886
|
* Generates and returns the GC data for this container.
|
|
@@ -2487,13 +2498,13 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
2487
2498
|
const waitForSeq = async (
|
|
2488
2499
|
deltaManager: IDeltaManager<Pick<ISequencedDocumentMessage, "sequenceNumber">, unknown>,
|
|
2489
2500
|
targetSeq: number,
|
|
2490
|
-
): Promise<void> => new Promise<void>((
|
|
2501
|
+
): Promise<void> => new Promise<void>((resolve, reject) => {
|
|
2491
2502
|
// TODO: remove cast to any when actual event is determined
|
|
2492
2503
|
deltaManager.on("closed" as any, reject);
|
|
2493
2504
|
|
|
2494
2505
|
const handleOp = (message: Pick<ISequencedDocumentMessage, "sequenceNumber">) => {
|
|
2495
2506
|
if (message.sequenceNumber >= targetSeq) {
|
|
2496
|
-
|
|
2507
|
+
resolve();
|
|
2497
2508
|
deltaManager.off("op", handleOp);
|
|
2498
2509
|
}
|
|
2499
2510
|
};
|
package/src/dataStoreContext.ts
CHANGED
|
@@ -51,6 +51,7 @@ import {
|
|
|
51
51
|
IFluidDataStoreContextEvents,
|
|
52
52
|
IFluidDataStoreRegistry,
|
|
53
53
|
IGarbageCollectionData,
|
|
54
|
+
IGarbageCollectionDetailsBase,
|
|
54
55
|
IGarbageCollectionSummaryDetails,
|
|
55
56
|
IInboundSignalMessage,
|
|
56
57
|
IProvideFluidDataStoreFactory,
|
|
@@ -248,7 +249,7 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
|
|
|
248
249
|
this.summarizerNode = createSummarizerNode(
|
|
249
250
|
thisSummarizeInternal,
|
|
250
251
|
async (fullGC?: boolean) => this.getGCDataInternal(fullGC),
|
|
251
|
-
async () => this.
|
|
252
|
+
async () => this.getBaseGCDetails(),
|
|
252
253
|
);
|
|
253
254
|
|
|
254
255
|
this.subLogger = ChildLogger.create(this.logger, "FluidDataStoreContext");
|
|
@@ -652,8 +653,13 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
|
|
|
652
653
|
*/
|
|
653
654
|
public abstract setRoot(): void;
|
|
654
655
|
|
|
656
|
+
/**
|
|
657
|
+
* @deprecated - Renamed to getBaseGCDetails().
|
|
658
|
+
*/
|
|
655
659
|
public abstract getInitialGCSummaryDetails(): Promise<IGarbageCollectionSummaryDetails>;
|
|
656
660
|
|
|
661
|
+
public abstract getBaseGCDetails(): Promise<IGarbageCollectionDetailsBase>;
|
|
662
|
+
|
|
657
663
|
public reSubmit(contents: any, localOpMetadata: unknown) {
|
|
658
664
|
assert(!!this.channel, 0x14b /* "Channel must exist when resubmitting ops" */);
|
|
659
665
|
const innerContents = contents as FluidDataStoreMessage;
|
|
@@ -679,7 +685,7 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
|
|
|
679
685
|
return (
|
|
680
686
|
summarizeInternal: SummarizeInternalFn,
|
|
681
687
|
getGCDataFn: (fullGC?: boolean) => Promise<IGarbageCollectionData>,
|
|
682
|
-
|
|
688
|
+
getBaseGCDetailsFn: () => Promise<IGarbageCollectionDetailsBase>,
|
|
683
689
|
) => this.summarizerNode.createChild(
|
|
684
690
|
summarizeInternal,
|
|
685
691
|
id,
|
|
@@ -687,7 +693,7 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
|
|
|
687
693
|
// DDS will not create failure summaries
|
|
688
694
|
{ throwOnFailure: true },
|
|
689
695
|
getGCDataFn,
|
|
690
|
-
|
|
696
|
+
getBaseGCDetailsFn,
|
|
691
697
|
);
|
|
692
698
|
}
|
|
693
699
|
|
|
@@ -698,11 +704,12 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
|
|
|
698
704
|
|
|
699
705
|
export class RemotedFluidDataStoreContext extends FluidDataStoreContext {
|
|
700
706
|
private isRootDataStore: boolean | undefined;
|
|
707
|
+
private readonly baseGCDetailsP: Promise<IGarbageCollectionDetailsBase>;
|
|
701
708
|
|
|
702
709
|
constructor(
|
|
703
710
|
id: string,
|
|
704
711
|
private readonly initSnapshotValue: ISnapshotTree | string | undefined,
|
|
705
|
-
|
|
712
|
+
getBaseGCDetails: () => Promise<IGarbageCollectionDetailsBase | undefined>,
|
|
706
713
|
runtime: ContainerRuntime,
|
|
707
714
|
storage: IDocumentStorageService,
|
|
708
715
|
scope: FluidObject,
|
|
@@ -723,6 +730,10 @@ export class RemotedFluidDataStoreContext extends FluidDataStoreContext {
|
|
|
723
730
|
},
|
|
724
731
|
pkg,
|
|
725
732
|
);
|
|
733
|
+
|
|
734
|
+
this.baseGCDetailsP = new LazyPromise<IGarbageCollectionDetailsBase>(async () => {
|
|
735
|
+
return (await getBaseGCDetails()) ?? {};
|
|
736
|
+
});
|
|
726
737
|
}
|
|
727
738
|
|
|
728
739
|
private readonly initialSnapshotDetailsP = new LazyPromise<ISnapshotDetails>(async () => {
|
|
@@ -787,16 +798,19 @@ export class RemotedFluidDataStoreContext extends FluidDataStoreContext {
|
|
|
787
798
|
};
|
|
788
799
|
});
|
|
789
800
|
|
|
790
|
-
private readonly gcDetailsInInitialSummaryP = new LazyPromise<IGarbageCollectionSummaryDetails>(async () => {
|
|
791
|
-
return (await this.getBaseSummaryGCDetails()) ?? {};
|
|
792
|
-
});
|
|
793
|
-
|
|
794
801
|
protected async getInitialSnapshotDetails(): Promise<ISnapshotDetails> {
|
|
795
802
|
return this.initialSnapshotDetailsP;
|
|
796
803
|
}
|
|
797
804
|
|
|
805
|
+
/**
|
|
806
|
+
* @deprecated - Renamed to getBaseGCDetails.
|
|
807
|
+
*/
|
|
798
808
|
public async getInitialGCSummaryDetails(): Promise<IGarbageCollectionSummaryDetails> {
|
|
799
|
-
return this.
|
|
809
|
+
return this.getBaseGCDetails();
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
public async getBaseGCDetails(): Promise<IGarbageCollectionDetailsBase> {
|
|
813
|
+
return this.baseGCDetailsP;
|
|
800
814
|
}
|
|
801
815
|
|
|
802
816
|
public generateAttachMessage(): IAttachMessage {
|
|
@@ -926,11 +940,19 @@ export class LocalFluidDataStoreContextBase extends FluidDataStoreContext {
|
|
|
926
940
|
};
|
|
927
941
|
}
|
|
928
942
|
|
|
943
|
+
/**
|
|
944
|
+
* @deprecated - Renamed to getBaseGCDetails.
|
|
945
|
+
*/
|
|
929
946
|
public async getInitialGCSummaryDetails(): Promise<IGarbageCollectionSummaryDetails> {
|
|
930
947
|
// Local data store does not have initial summary.
|
|
931
948
|
return {};
|
|
932
949
|
}
|
|
933
950
|
|
|
951
|
+
public async getBaseGCDetails(): Promise<IGarbageCollectionDetailsBase> {
|
|
952
|
+
// Local data store does not have initial summary.
|
|
953
|
+
return {};
|
|
954
|
+
}
|
|
955
|
+
|
|
934
956
|
/**
|
|
935
957
|
* @deprecated - Sets the datastore as root, for aliasing purposes: #7948
|
|
936
958
|
* This method should not be used outside of the aliasing context.
|
package/src/dataStores.ts
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
import { ITelemetryLogger, ITelemetryBaseLogger, IDisposable } from "@fluidframework/common-definitions";
|
|
7
7
|
import { DataCorruptionError, extractSafePropertiesFromMessage } from "@fluidframework/container-utils";
|
|
8
|
+
import { IFluidHandle } from "@fluidframework/core-interfaces";
|
|
9
|
+
import { FluidObjectHandle } from "@fluidframework/datastore";
|
|
8
10
|
import {
|
|
9
11
|
ISequencedDocumentMessage,
|
|
10
12
|
ISnapshotTree,
|
|
@@ -19,7 +21,7 @@ import {
|
|
|
19
21
|
IFluidDataStoreChannel,
|
|
20
22
|
IFluidDataStoreContextDetached,
|
|
21
23
|
IGarbageCollectionData,
|
|
22
|
-
|
|
24
|
+
IGarbageCollectionDetailsBase,
|
|
23
25
|
IInboundSignalMessage,
|
|
24
26
|
InboundAttachMessage,
|
|
25
27
|
ISummarizeResult,
|
|
@@ -97,6 +99,13 @@ export class DataStores implements IDisposable {
|
|
|
97
99
|
readonly referencedDataStoreCount: number;
|
|
98
100
|
};
|
|
99
101
|
|
|
102
|
+
// Stores the ids of new data stores between two GC runs. This is used to notify the garbage collector of new
|
|
103
|
+
// root data stores that are added.
|
|
104
|
+
private dataStoresSinceLastGC: string[] = [];
|
|
105
|
+
// The handle to the container runtime. This is used mainly for GC purposes to represent outbound reference from
|
|
106
|
+
// the container runtime to other nodes.
|
|
107
|
+
private readonly containerRuntimeHandle: IFluidHandle;
|
|
108
|
+
|
|
100
109
|
constructor(
|
|
101
110
|
private readonly baseSnapshot: ISnapshotTree | undefined,
|
|
102
111
|
private readonly runtime: ContainerRuntime,
|
|
@@ -105,19 +114,20 @@ export class DataStores implements IDisposable {
|
|
|
105
114
|
(id: string, createParam: CreateChildSummarizerNodeParam) => CreateChildSummarizerNodeFn,
|
|
106
115
|
private readonly deleteChildSummarizerNodeFn: (id: string) => void,
|
|
107
116
|
baseLogger: ITelemetryBaseLogger,
|
|
108
|
-
|
|
117
|
+
getBaseGCDetails: () => Promise<Map<string, IGarbageCollectionDetailsBase>>,
|
|
109
118
|
private readonly dataStoreChanged: (id: string) => void,
|
|
110
119
|
private readonly aliasMap: Map<string, string>,
|
|
111
120
|
private readonly contexts: DataStoreContexts = new DataStoreContexts(baseLogger),
|
|
112
121
|
) {
|
|
113
122
|
this.logger = ChildLogger.create(baseLogger);
|
|
123
|
+
this.containerRuntimeHandle = new FluidObjectHandle(this.runtime, "/", this.runtime.IFluidHandleContext);
|
|
114
124
|
|
|
115
|
-
const
|
|
116
|
-
return
|
|
125
|
+
const baseGCDetailsP = new LazyPromise(async () => {
|
|
126
|
+
return getBaseGCDetails();
|
|
117
127
|
});
|
|
118
|
-
// Returns the base
|
|
128
|
+
// Returns the base GC details for the data store with the given id.
|
|
119
129
|
const dataStoreBaseGCDetails = async (dataStoreId: string) => {
|
|
120
|
-
const baseGCDetails = await
|
|
130
|
+
const baseGCDetails = await baseGCDetailsP;
|
|
121
131
|
return baseGCDetails.get(dataStoreId);
|
|
122
132
|
};
|
|
123
133
|
|
|
@@ -179,6 +189,9 @@ export class DataStores implements IDisposable {
|
|
|
179
189
|
|
|
180
190
|
public processAttachMessage(message: ISequencedDocumentMessage, local: boolean) {
|
|
181
191
|
const attachMessage = message.contents as InboundAttachMessage;
|
|
192
|
+
|
|
193
|
+
this.dataStoresSinceLastGC.push(attachMessage.id);
|
|
194
|
+
|
|
182
195
|
// The local object has already been attached
|
|
183
196
|
if (local) {
|
|
184
197
|
assert(this.pendingAttach.has(attachMessage.id),
|
|
@@ -189,7 +202,7 @@ export class DataStores implements IDisposable {
|
|
|
189
202
|
}
|
|
190
203
|
|
|
191
204
|
// If a non-local operation then go and create the object, otherwise mark it as officially attached.
|
|
192
|
-
if (this.
|
|
205
|
+
if (this.alreadyProcessed(attachMessage.id)) {
|
|
193
206
|
// TODO: dataStoreId may require a different tag from PackageData #7488
|
|
194
207
|
const error = new DataCorruptionError(
|
|
195
208
|
"duplicateDataStoreCreatedWithExistingId",
|
|
@@ -237,10 +250,6 @@ export class DataStores implements IDisposable {
|
|
|
237
250
|
pkg);
|
|
238
251
|
|
|
239
252
|
this.contexts.addBoundOrRemoted(remotedFluidDataStoreContext);
|
|
240
|
-
|
|
241
|
-
// Equivalent of nextTick() - Prefetch once all current ops have completed
|
|
242
|
-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
243
|
-
Promise.resolve().then(async () => remotedFluidDataStoreContext.realize());
|
|
244
253
|
}
|
|
245
254
|
|
|
246
255
|
public processAliasMessage(
|
|
@@ -266,15 +275,7 @@ export class DataStores implements IDisposable {
|
|
|
266
275
|
}
|
|
267
276
|
|
|
268
277
|
private processAliasMessageCore(aliasMessage: IDataStoreAliasMessage): boolean {
|
|
269
|
-
|
|
270
|
-
if (existingMapping !== undefined) {
|
|
271
|
-
return false;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
// Unlikely scenario, but we may receive an alias OP with the alias value
|
|
275
|
-
// equal to one of the ids supplied to `createRootDataStore` in the past
|
|
276
|
-
const maybeContextWithAliasAsId = this.contexts.get(aliasMessage.alias);
|
|
277
|
-
if (maybeContextWithAliasAsId !== undefined) {
|
|
278
|
+
if (this.alreadyProcessed(aliasMessage.alias)) {
|
|
278
279
|
return false;
|
|
279
280
|
}
|
|
280
281
|
|
|
@@ -292,6 +293,10 @@ export class DataStores implements IDisposable {
|
|
|
292
293
|
return true;
|
|
293
294
|
}
|
|
294
295
|
|
|
296
|
+
private alreadyProcessed(id: string): boolean {
|
|
297
|
+
return this.aliasMap.get(id) !== undefined || this.contexts.get(id) !== undefined;
|
|
298
|
+
}
|
|
299
|
+
|
|
295
300
|
public bindFluidDataStore(fluidDataStoreRuntime: IFluidDataStoreChannel): void {
|
|
296
301
|
const id = fluidDataStoreRuntime.id;
|
|
297
302
|
const localContext = this.contexts.getUnbound(id);
|
|
@@ -498,6 +503,24 @@ export class DataStores implements IDisposable {
|
|
|
498
503
|
return builder.getSummaryTree();
|
|
499
504
|
}
|
|
500
505
|
|
|
506
|
+
/**
|
|
507
|
+
* Before GC runs, called by the garbage collector to update any pending GC state.
|
|
508
|
+
* The garbage collector needs to know all outbound references that are added. Since root data stores are not
|
|
509
|
+
* explicitly marked as referenced, notify GC of new root data stores that were added since the last GC run.
|
|
510
|
+
*/
|
|
511
|
+
public async updateStateBeforeGC(): Promise<void> {
|
|
512
|
+
for (const id of this.dataStoresSinceLastGC) {
|
|
513
|
+
const context = this.contexts.get(id);
|
|
514
|
+
assert(context !== undefined, 0x2b6 /* `Missing data store context with id ${id}` */);
|
|
515
|
+
if (await context.isRoot()) {
|
|
516
|
+
// A root data store is basically a reference from the container runtime to the data store.
|
|
517
|
+
const handle = new FluidObjectHandle(context, id, this.runtime.IFluidHandleContext);
|
|
518
|
+
this.runtime.addedGCOutboundReference(this.containerRuntimeHandle, handle);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
this.dataStoresSinceLastGC = [];
|
|
522
|
+
}
|
|
523
|
+
|
|
501
524
|
/**
|
|
502
525
|
* Generates data used for garbage collection. It does the following:
|
|
503
526
|
* 1. Calls into each child data store context to get its GC data.
|