@fluidframework/container-loader 2.0.0-rc.1.0.6 → 2.0.0-rc.2.0.1
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 → .eslintrc.cjs} +5 -6
- package/{.mocharc.js → .mocharc.cjs} +1 -1
- package/CHANGELOG.md +48 -0
- package/README.md +3 -3
- package/{api-extractor-esm.json → api-extractor-cjs.json} +5 -1
- package/api-extractor-lint.json +1 -1
- package/api-extractor.json +1 -1
- package/api-report/container-loader.api.md +2 -2
- package/dist/attachment.d.ts +115 -0
- package/dist/attachment.d.ts.map +1 -0
- package/dist/attachment.js +83 -0
- package/dist/attachment.js.map +1 -0
- package/dist/audience.d.ts +9 -4
- package/dist/audience.d.ts.map +1 -1
- package/dist/audience.js +10 -4
- package/dist/audience.js.map +1 -1
- package/dist/connectionManager.d.ts +3 -3
- package/dist/connectionManager.d.ts.map +1 -1
- package/dist/connectionManager.js +17 -18
- package/dist/connectionManager.js.map +1 -1
- package/dist/connectionState.d.ts +1 -0
- package/dist/connectionState.d.ts.map +1 -1
- package/dist/connectionState.js +1 -0
- package/dist/connectionState.js.map +1 -1
- package/dist/connectionStateHandler.d.ts +7 -7
- package/dist/connectionStateHandler.d.ts.map +1 -1
- package/dist/connectionStateHandler.js +32 -32
- package/dist/connectionStateHandler.js.map +1 -1
- package/dist/container-loader-alpha.d.ts +2 -1
- package/dist/container-loader-beta.d.ts +3 -0
- package/dist/container-loader-public.d.ts +3 -0
- package/dist/container-loader-untrimmed.d.ts +5 -5
- package/dist/container.d.ts +29 -27
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +215 -284
- package/dist/container.js.map +1 -1
- package/dist/containerContext.d.ts +3 -2
- package/dist/containerContext.d.ts.map +1 -1
- package/dist/containerContext.js +2 -1
- package/dist/containerContext.js.map +1 -1
- package/dist/containerStorageAdapter.d.ts +5 -6
- package/dist/containerStorageAdapter.d.ts.map +1 -1
- package/dist/containerStorageAdapter.js +14 -21
- package/dist/containerStorageAdapter.js.map +1 -1
- package/dist/contracts.d.ts +3 -3
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js.map +1 -1
- package/dist/debugLogger.js.map +1 -1
- package/dist/deltaManager.d.ts +5 -5
- package/dist/deltaManager.d.ts.map +1 -1
- package/dist/deltaManager.js +6 -6
- package/dist/deltaManager.js.map +1 -1
- package/dist/error.d.ts.map +1 -1
- package/dist/error.js.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -11
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +3 -3
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +13 -17
- package/dist/loader.js.map +1 -1
- package/dist/location-redirection-utilities/index.d.ts +1 -1
- package/dist/location-redirection-utilities/index.d.ts.map +1 -1
- package/dist/location-redirection-utilities/index.js +3 -3
- package/dist/location-redirection-utilities/index.js.map +1 -1
- package/dist/package.json +3 -0
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/protocolTreeDocumentStorageService.d.ts +1 -1
- package/dist/protocolTreeDocumentStorageService.d.ts.map +1 -1
- package/dist/protocolTreeDocumentStorageService.js +1 -3
- package/dist/protocolTreeDocumentStorageService.js.map +1 -1
- package/dist/retriableDocumentStorageService.d.ts +2 -2
- package/dist/retriableDocumentStorageService.d.ts.map +1 -1
- package/dist/retriableDocumentStorageService.js +8 -6
- package/dist/retriableDocumentStorageService.js.map +1 -1
- package/dist/serializedStateManager.d.ts +44 -0
- package/dist/serializedStateManager.d.ts.map +1 -0
- package/dist/serializedStateManager.js +149 -0
- package/dist/serializedStateManager.js.map +1 -0
- package/dist/tsdoc-metadata.json +1 -1
- package/dist/utils.d.ts +16 -11
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +107 -32
- package/dist/utils.js.map +1 -1
- package/lib/attachment.d.ts +115 -0
- package/lib/attachment.d.ts.map +1 -0
- package/lib/attachment.js +79 -0
- package/lib/attachment.js.map +1 -0
- package/lib/{audience.d.mts → audience.d.ts} +14 -5
- package/lib/audience.d.ts.map +1 -0
- package/lib/{audience.mjs → audience.js} +14 -4
- package/lib/audience.js.map +1 -0
- package/lib/{catchUpMonitor.d.mts → catchUpMonitor.d.ts} +1 -1
- package/lib/catchUpMonitor.d.ts.map +1 -0
- package/lib/{catchUpMonitor.mjs → catchUpMonitor.js} +1 -1
- package/lib/catchUpMonitor.js.map +1 -0
- package/lib/{connectionManager.d.mts → connectionManager.d.ts} +4 -4
- package/lib/connectionManager.d.ts.map +1 -0
- package/lib/{connectionManager.mjs → connectionManager.js} +7 -10
- package/lib/connectionManager.js.map +1 -0
- package/lib/{connectionState.d.mts → connectionState.d.ts} +2 -1
- package/lib/connectionState.d.ts.map +1 -0
- package/lib/{connectionState.mjs → connectionState.js} +2 -1
- package/lib/connectionState.js.map +1 -0
- package/lib/{connectionStateHandler.d.mts → connectionStateHandler.d.ts} +8 -8
- package/lib/connectionStateHandler.d.ts.map +1 -0
- package/lib/{connectionStateHandler.mjs → connectionStateHandler.js} +3 -3
- package/lib/connectionStateHandler.js.map +1 -0
- package/lib/{container-loader-alpha.d.mts → container-loader-alpha.d.ts} +2 -1
- package/lib/{container-loader-beta.d.mts → container-loader-beta.d.ts} +3 -0
- package/lib/{container-loader-public.d.mts → container-loader-public.d.ts} +3 -0
- package/lib/{container-loader-untrimmed.d.mts → container-loader-untrimmed.d.ts} +5 -5
- package/lib/{container.d.mts → container.d.ts} +30 -28
- package/lib/container.d.ts.map +1 -0
- package/lib/{container.mjs → container.js} +178 -247
- package/lib/container.js.map +1 -0
- package/lib/{containerContext.d.mts → containerContext.d.ts} +4 -3
- package/lib/containerContext.d.ts.map +1 -0
- package/lib/{containerContext.mjs → containerContext.js} +3 -2
- package/lib/containerContext.js.map +1 -0
- package/lib/{containerStorageAdapter.d.mts → containerStorageAdapter.d.ts} +6 -7
- package/lib/containerStorageAdapter.d.ts.map +1 -0
- package/lib/{containerStorageAdapter.mjs → containerStorageAdapter.js} +13 -20
- package/lib/containerStorageAdapter.js.map +1 -0
- package/lib/{contracts.d.mts → contracts.d.ts} +4 -4
- package/lib/contracts.d.ts.map +1 -0
- package/lib/{contracts.mjs → contracts.js} +1 -1
- package/lib/contracts.js.map +1 -0
- package/lib/{debugLogger.d.mts → debugLogger.d.ts} +1 -1
- package/lib/debugLogger.d.ts.map +1 -0
- package/lib/{debugLogger.mjs → debugLogger.js} +2 -1
- package/lib/debugLogger.js.map +1 -0
- package/lib/{deltaManager.d.mts → deltaManager.d.ts} +6 -6
- package/lib/deltaManager.d.ts.map +1 -0
- package/lib/{deltaManager.mjs → deltaManager.js} +4 -4
- package/lib/deltaManager.js.map +1 -0
- package/lib/{deltaQueue.d.mts → deltaQueue.d.ts} +1 -1
- package/lib/deltaQueue.d.ts.map +1 -0
- package/lib/{deltaQueue.mjs → deltaQueue.js} +1 -1
- package/lib/deltaQueue.js.map +1 -0
- package/lib/{disposal.d.mts → disposal.d.ts} +1 -1
- package/lib/disposal.d.ts.map +1 -0
- package/lib/{disposal.mjs → disposal.js} +1 -1
- package/lib/disposal.js.map +1 -0
- package/lib/{error.d.mts → error.d.ts} +1 -1
- package/lib/error.d.ts.map +1 -0
- package/lib/{error.mjs → error.js} +1 -1
- package/lib/error.js.map +1 -0
- package/lib/{index.d.mts → index.d.ts} +7 -7
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +10 -0
- package/lib/index.js.map +1 -0
- package/lib/{loader.d.mts → loader.d.ts} +4 -4
- package/lib/loader.d.ts.map +1 -0
- package/lib/{loader.mjs → loader.js} +7 -11
- package/lib/loader.js.map +1 -0
- package/lib/location-redirection-utilities/{index.mjs → index.d.ts} +2 -2
- package/lib/location-redirection-utilities/index.d.ts.map +1 -0
- package/lib/location-redirection-utilities/{index.d.mts → index.js} +2 -2
- package/lib/location-redirection-utilities/index.js.map +1 -0
- package/lib/location-redirection-utilities/{resolveWithLocationRedirection.d.mts → resolveWithLocationRedirection.d.ts} +1 -1
- package/lib/location-redirection-utilities/resolveWithLocationRedirection.d.ts.map +1 -0
- package/lib/location-redirection-utilities/{resolveWithLocationRedirection.mjs → resolveWithLocationRedirection.js} +1 -1
- package/lib/location-redirection-utilities/resolveWithLocationRedirection.js.map +1 -0
- package/lib/{noopHeuristic.d.mts → noopHeuristic.d.ts} +1 -1
- package/lib/noopHeuristic.d.ts.map +1 -0
- package/lib/{noopHeuristic.mjs → noopHeuristic.js} +1 -1
- package/lib/noopHeuristic.js.map +1 -0
- package/lib/{packageVersion.d.mts → packageVersion.d.ts} +2 -2
- package/lib/packageVersion.d.ts.map +1 -0
- package/lib/{packageVersion.mjs → packageVersion.js} +2 -2
- package/lib/packageVersion.js.map +1 -0
- package/lib/{protocol.d.mts → protocol.d.ts} +1 -1
- package/lib/protocol.d.ts.map +1 -0
- package/lib/{protocol.mjs → protocol.js} +1 -1
- package/lib/protocol.js.map +1 -0
- package/lib/{protocolTreeDocumentStorageService.d.mts → protocolTreeDocumentStorageService.d.ts} +2 -2
- package/lib/protocolTreeDocumentStorageService.d.ts.map +1 -0
- package/lib/{protocolTreeDocumentStorageService.mjs → protocolTreeDocumentStorageService.js} +2 -4
- package/lib/protocolTreeDocumentStorageService.js.map +1 -0
- package/lib/{quorum.d.mts → quorum.d.ts} +5 -1
- package/lib/quorum.d.ts.map +1 -0
- package/lib/{quorum.mjs → quorum.js} +1 -1
- package/lib/quorum.js.map +1 -0
- package/lib/{retriableDocumentStorageService.d.mts → retriableDocumentStorageService.d.ts} +3 -3
- package/lib/retriableDocumentStorageService.d.ts.map +1 -0
- package/lib/{retriableDocumentStorageService.mjs → retriableDocumentStorageService.js} +10 -8
- package/lib/retriableDocumentStorageService.js.map +1 -0
- package/lib/serializedStateManager.d.ts +44 -0
- package/lib/serializedStateManager.d.ts.map +1 -0
- package/lib/serializedStateManager.js +145 -0
- package/lib/serializedStateManager.js.map +1 -0
- package/lib/test/attachment.spec.js +380 -0
- package/lib/test/attachment.spec.js.map +1 -0
- package/lib/test/catchUpMonitor.spec.js +88 -0
- package/lib/test/catchUpMonitor.spec.js.map +1 -0
- package/lib/test/connectionManager.spec.js +201 -0
- package/lib/test/connectionManager.spec.js.map +1 -0
- package/lib/test/connectionStateHandler.spec.js +555 -0
- package/lib/test/connectionStateHandler.spec.js.map +1 -0
- package/lib/test/container.spec.js +64 -0
- package/lib/test/container.spec.js.map +1 -0
- package/lib/test/deltaManager.spec.js +405 -0
- package/lib/test/deltaManager.spec.js.map +1 -0
- package/lib/test/loader.spec.js +212 -0
- package/lib/test/loader.spec.js.map +1 -0
- package/lib/test/locationRedirectionTests.spec.js +44 -0
- package/lib/test/locationRedirectionTests.spec.js.map +1 -0
- package/lib/test/serializedStateManager.spec.js +148 -0
- package/lib/test/serializedStateManager.spec.js.map +1 -0
- package/lib/test/snapshotConversionTest.spec.js +79 -0
- package/lib/test/snapshotConversionTest.spec.js.map +1 -0
- package/lib/test/types/validateContainerLoaderPrevious.generated.js +38 -0
- package/lib/test/types/validateContainerLoaderPrevious.generated.js.map +1 -0
- package/lib/test/utils.spec.js +31 -0
- package/lib/test/utils.spec.js.map +1 -0
- package/lib/{utils.d.mts → utils.d.ts} +17 -12
- package/lib/utils.d.ts.map +1 -0
- package/lib/utils.js +206 -0
- package/lib/utils.js.map +1 -0
- package/package.json +61 -63
- package/src/attachment.ts +222 -0
- package/src/audience.ts +9 -3
- package/src/connectionManager.ts +9 -11
- package/src/connectionState.ts +1 -0
- package/src/connectionStateHandler.ts +8 -7
- package/src/container.ts +296 -323
- package/src/containerContext.ts +2 -1
- package/src/containerStorageAdapter.ts +21 -26
- package/src/contracts.ts +3 -3
- package/src/debugLogger.ts +2 -2
- package/src/deltaManager.ts +8 -8
- package/src/error.ts +2 -2
- package/src/index.ts +6 -6
- package/src/loader.ts +9 -13
- package/src/location-redirection-utilities/index.ts +1 -1
- package/src/packageVersion.ts +1 -1
- package/src/protocolTreeDocumentStorageService.ts +1 -3
- package/src/retriableDocumentStorageService.ts +18 -8
- package/src/serializedStateManager.ts +217 -0
- package/src/utils.ts +140 -43
- package/tsconfig.cjs.json +7 -0
- package/tsconfig.json +2 -5
- package/lib/audience.d.mts.map +0 -1
- package/lib/audience.mjs.map +0 -1
- package/lib/catchUpMonitor.d.mts.map +0 -1
- package/lib/catchUpMonitor.mjs.map +0 -1
- package/lib/connectionManager.d.mts.map +0 -1
- package/lib/connectionManager.mjs.map +0 -1
- package/lib/connectionState.d.mts.map +0 -1
- package/lib/connectionState.mjs.map +0 -1
- package/lib/connectionStateHandler.d.mts.map +0 -1
- package/lib/connectionStateHandler.mjs.map +0 -1
- package/lib/container.d.mts.map +0 -1
- package/lib/container.mjs.map +0 -1
- package/lib/containerContext.d.mts.map +0 -1
- package/lib/containerContext.mjs.map +0 -1
- package/lib/containerStorageAdapter.d.mts.map +0 -1
- package/lib/containerStorageAdapter.mjs.map +0 -1
- package/lib/contracts.d.mts.map +0 -1
- package/lib/contracts.mjs.map +0 -1
- package/lib/debugLogger.d.mts.map +0 -1
- package/lib/debugLogger.mjs.map +0 -1
- package/lib/deltaManager.d.mts.map +0 -1
- package/lib/deltaManager.mjs.map +0 -1
- package/lib/deltaQueue.d.mts.map +0 -1
- package/lib/deltaQueue.mjs.map +0 -1
- package/lib/disposal.d.mts.map +0 -1
- package/lib/disposal.mjs.map +0 -1
- package/lib/error.d.mts.map +0 -1
- package/lib/error.mjs.map +0 -1
- package/lib/index.d.mts.map +0 -1
- package/lib/index.mjs +0 -10
- package/lib/index.mjs.map +0 -1
- package/lib/loader.d.mts.map +0 -1
- package/lib/loader.mjs.map +0 -1
- package/lib/location-redirection-utilities/index.d.mts.map +0 -1
- package/lib/location-redirection-utilities/index.mjs.map +0 -1
- package/lib/location-redirection-utilities/resolveWithLocationRedirection.d.mts.map +0 -1
- package/lib/location-redirection-utilities/resolveWithLocationRedirection.mjs.map +0 -1
- package/lib/noopHeuristic.d.mts.map +0 -1
- package/lib/noopHeuristic.mjs.map +0 -1
- package/lib/packageVersion.d.mts.map +0 -1
- package/lib/packageVersion.mjs.map +0 -1
- package/lib/protocol.d.mts.map +0 -1
- package/lib/protocol.mjs.map +0 -1
- package/lib/protocolTreeDocumentStorageService.d.mts.map +0 -1
- package/lib/protocolTreeDocumentStorageService.mjs.map +0 -1
- package/lib/quorum.d.mts.map +0 -1
- package/lib/quorum.mjs.map +0 -1
- package/lib/retriableDocumentStorageService.d.mts.map +0 -1
- package/lib/retriableDocumentStorageService.mjs.map +0 -1
- package/lib/utils.d.mts.map +0 -1
- package/lib/utils.mjs +0 -133
- package/lib/utils.mjs.map +0 -1
package/dist/container.js
CHANGED
|
@@ -17,25 +17,26 @@ const driver_utils_1 = require("@fluidframework/driver-utils");
|
|
|
17
17
|
const protocol_definitions_1 = require("@fluidframework/protocol-definitions");
|
|
18
18
|
const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
|
|
19
19
|
const structured_clone_1 = __importDefault(require("@ungap/structured-clone"));
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
const
|
|
33
|
-
const
|
|
20
|
+
const audience_js_1 = require("./audience.js");
|
|
21
|
+
const containerContext_js_1 = require("./containerContext.js");
|
|
22
|
+
const contracts_js_1 = require("./contracts.js");
|
|
23
|
+
const deltaManager_js_1 = require("./deltaManager.js");
|
|
24
|
+
const loader_js_1 = require("./loader.js");
|
|
25
|
+
const packageVersion_js_1 = require("./packageVersion.js");
|
|
26
|
+
const containerStorageAdapter_js_1 = require("./containerStorageAdapter.js");
|
|
27
|
+
const connectionStateHandler_js_1 = require("./connectionStateHandler.js");
|
|
28
|
+
const utils_js_1 = require("./utils.js");
|
|
29
|
+
const quorum_js_1 = require("./quorum.js");
|
|
30
|
+
const noopHeuristic_js_1 = require("./noopHeuristic.js");
|
|
31
|
+
const connectionManager_js_1 = require("./connectionManager.js");
|
|
32
|
+
const connectionState_js_1 = require("./connectionState.js");
|
|
33
|
+
const protocol_js_1 = require("./protocol.js");
|
|
34
|
+
const attachment_js_1 = require("./attachment.js");
|
|
35
|
+
const serializedStateManager_js_1 = require("./serializedStateManager.js");
|
|
34
36
|
const detachedContainerRefSeqNumber = 0;
|
|
35
37
|
const dirtyContainerEvent = "dirty";
|
|
36
38
|
const savedContainerEvent = "saved";
|
|
37
39
|
const packageNotFactoryError = "Code package does not implement IRuntimeFactory";
|
|
38
|
-
const hasBlobsSummaryTree = ".hasAttachmentBlobs";
|
|
39
40
|
/**
|
|
40
41
|
* Waits until container connects to delta storage and gets up-to-date.
|
|
41
42
|
*
|
|
@@ -73,8 +74,8 @@ async function waitContainerToCatchUp(container) {
|
|
|
73
74
|
// Waiting for "connected" state in either case gets us at least to our own Join op
|
|
74
75
|
// which is a reasonable approximation of "caught up"
|
|
75
76
|
const waitForOps = () => {
|
|
76
|
-
(0, core_utils_1.assert)(container.connectionState ===
|
|
77
|
-
container.connectionState ===
|
|
77
|
+
(0, core_utils_1.assert)(container.connectionState === connectionState_js_1.ConnectionState.CatchingUp ||
|
|
78
|
+
container.connectionState === connectionState_js_1.ConnectionState.Connected, 0x0cd /* "Container disconnected while waiting for ops!" */);
|
|
78
79
|
const hasCheckpointSequenceNumber = deltaManager.hasCheckpointSequenceNumber;
|
|
79
80
|
const connectionOpSeqNumber = deltaManager.lastKnownSeqNumber;
|
|
80
81
|
(0, core_utils_1.assert)(deltaManager.lastSequenceNumber <= connectionOpSeqNumber, 0x266 /* "lastKnownSeqNumber should never be below last processed sequence number" */);
|
|
@@ -96,7 +97,7 @@ async function waitContainerToCatchUp(container) {
|
|
|
96
97
|
// But that works only if service provides us checkPointSequenceNumber
|
|
97
98
|
// Our internal testing is based on R11S that does not, but almost all tests connect as "write" and
|
|
98
99
|
// use this function to catch up, so leveraging our own join op as a fence/barrier
|
|
99
|
-
if (container.connectionState ===
|
|
100
|
+
if (container.connectionState === connectionState_js_1.ConnectionState.Connected) {
|
|
100
101
|
waitForOps();
|
|
101
102
|
return;
|
|
102
103
|
}
|
|
@@ -105,15 +106,13 @@ async function waitContainerToCatchUp(container) {
|
|
|
105
106
|
waitForOps();
|
|
106
107
|
};
|
|
107
108
|
container.on(telemetry_utils_1.connectedEventName, callback);
|
|
108
|
-
if (container.connectionState ===
|
|
109
|
+
if (container.connectionState === connectionState_js_1.ConnectionState.Disconnected) {
|
|
109
110
|
container.connect();
|
|
110
111
|
}
|
|
111
112
|
});
|
|
112
113
|
}
|
|
113
114
|
exports.waitContainerToCatchUp = waitContainerToCatchUp;
|
|
114
|
-
const getCodeProposal =
|
|
115
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
116
|
-
(quorum) => quorum.get("code") ?? quorum.get("code2");
|
|
115
|
+
const getCodeProposal = (quorum) => quorum.get("code") ?? quorum.get("code2");
|
|
117
116
|
/**
|
|
118
117
|
* Helper function to report to telemetry cases where operation takes longer than expected (200ms)
|
|
119
118
|
* @param logger - logger to use
|
|
@@ -132,7 +131,6 @@ const summarizerClientType = "summarizer";
|
|
|
132
131
|
class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
133
132
|
/**
|
|
134
133
|
* Load an existing container.
|
|
135
|
-
* @internal
|
|
136
134
|
*/
|
|
137
135
|
static async load(loadProps, createProps) {
|
|
138
136
|
const { version, pendingLocalState, loadMode, resolvedUrl, loadToSequenceNumber } = loadProps;
|
|
@@ -189,11 +187,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
189
187
|
static async rehydrateDetachedFromSnapshot(createProps, snapshot) {
|
|
190
188
|
const container = new Container(createProps);
|
|
191
189
|
return telemetry_utils_1.PerformanceEvent.timedExecAsync(container.mc.logger, { eventName: "RehydrateDetachedFromSnapshot" }, async (_event) => {
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
throw new telemetry_utils_1.UsageError("Cannot rehydrate detached container. Incorrect format");
|
|
195
|
-
}
|
|
196
|
-
await container.rehydrateDetachedFromSnapshot(deserializedSummary);
|
|
190
|
+
const detachedContainerState = (0, utils_js_1.getDetachedContainerStateFromSerializedContainer)(snapshot);
|
|
191
|
+
await container.rehydrateDetachedFromSnapshot(detachedContainerState);
|
|
197
192
|
return container;
|
|
198
193
|
}, { start: true, end: true, cancel: "generic" });
|
|
199
194
|
}
|
|
@@ -244,6 +239,9 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
244
239
|
get readOnlyInfo() {
|
|
245
240
|
return this._deltaManager.readOnlyInfo;
|
|
246
241
|
}
|
|
242
|
+
get containerMetadata() {
|
|
243
|
+
return this._containerMetadata;
|
|
244
|
+
}
|
|
247
245
|
/**
|
|
248
246
|
* Sends signal to runtime (and data stores) to be read-only.
|
|
249
247
|
* Hosts may have read only views, indicating to data stores that no edits are allowed.
|
|
@@ -271,7 +269,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
271
269
|
return this.connectionStateHandler.connectionState;
|
|
272
270
|
}
|
|
273
271
|
get connected() {
|
|
274
|
-
return this.connectionStateHandler.connectionState ===
|
|
272
|
+
return this.connectionStateHandler.connectionState === connectionState_js_1.ConnectionState.Connected;
|
|
275
273
|
}
|
|
276
274
|
/**
|
|
277
275
|
* The server provided id of the client.
|
|
@@ -280,11 +278,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
280
278
|
get clientId() {
|
|
281
279
|
return this._clientId;
|
|
282
280
|
}
|
|
283
|
-
get
|
|
284
|
-
|
|
285
|
-
this.options?.enableOfflineLoad === true;
|
|
286
|
-
// summarizer will not have any pending state we want to save
|
|
287
|
-
return enabled && this.deltaManager.clientDetails.capabilities.interactive;
|
|
281
|
+
get isInteractiveClient() {
|
|
282
|
+
return this.deltaManager.clientDetails.capabilities.interactive;
|
|
288
283
|
}
|
|
289
284
|
/**
|
|
290
285
|
* Get the code details that are currently specified for the container.
|
|
@@ -339,9 +334,6 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
339
334
|
this._lifecycleEvents.once("disposed", disposedHandler);
|
|
340
335
|
});
|
|
341
336
|
}
|
|
342
|
-
/**
|
|
343
|
-
* @internal
|
|
344
|
-
*/
|
|
345
337
|
constructor(createProps, loadProps) {
|
|
346
338
|
super((name, error) => {
|
|
347
339
|
this.mc.logger.sendErrorEvent({
|
|
@@ -365,23 +357,101 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
365
357
|
* disposed: Container has been disposed
|
|
366
358
|
*/
|
|
367
359
|
this._lifecycleState = "loading";
|
|
368
|
-
this._attachState = container_definitions_1.AttachState.Detached;
|
|
369
360
|
/** During initialization we pause the inbound queues. We track this state to ensure we only call resume once */
|
|
370
361
|
this.inboundQueuePausedFromInit = true;
|
|
371
362
|
this.firstConnection = true;
|
|
372
363
|
this.connectionTransitionTimes = [];
|
|
373
|
-
this.attachStarted = false;
|
|
374
364
|
this._dirtyContainer = false;
|
|
375
|
-
this.
|
|
365
|
+
this.attachmentData = { state: container_definitions_1.AttachState.Detached };
|
|
376
366
|
this.clientsWhoShouldHaveLeft = new Set();
|
|
367
|
+
this._containerMetadata = {};
|
|
377
368
|
this.setAutoReconnectTime = client_utils_1.performance.now();
|
|
378
369
|
this._lifecycleEvents = new client_utils_1.TypedEventEmitter();
|
|
379
370
|
this._disposed = false;
|
|
371
|
+
this.attach = (0, utils_js_1.runSingle)(async (request, attachProps) => {
|
|
372
|
+
await telemetry_utils_1.PerformanceEvent.timedExecAsync(this.mc.logger, { eventName: "Attach" }, async () => {
|
|
373
|
+
if (this._lifecycleState !== "loaded" ||
|
|
374
|
+
this.attachmentData.state === container_definitions_1.AttachState.Attached) {
|
|
375
|
+
// pre-0.58 error message: containerNotValidForAttach
|
|
376
|
+
throw new telemetry_utils_1.UsageError(`The Container is not in a valid state for attach [${this._lifecycleState}] and [${this.attachState}]`);
|
|
377
|
+
}
|
|
378
|
+
const normalizeErrorAndClose = (error) => {
|
|
379
|
+
const newError = (0, telemetry_utils_1.normalizeError)(error);
|
|
380
|
+
this.close(newError);
|
|
381
|
+
// add resolved URL on error object so that host has the ability to find this document and delete it
|
|
382
|
+
newError.addTelemetryProperties({
|
|
383
|
+
resolvedUrl: this.service?.resolvedUrl?.url,
|
|
384
|
+
});
|
|
385
|
+
return newError;
|
|
386
|
+
};
|
|
387
|
+
const setAttachmentData = (attachmentData) => {
|
|
388
|
+
const previousState = this.attachmentData.state;
|
|
389
|
+
this.attachmentData = attachmentData;
|
|
390
|
+
const state = this.attachmentData.state;
|
|
391
|
+
if (state !== previousState && state !== container_definitions_1.AttachState.Detached) {
|
|
392
|
+
try {
|
|
393
|
+
this.runtime.setAttachState(state);
|
|
394
|
+
this.emit(state.toLocaleLowerCase());
|
|
395
|
+
}
|
|
396
|
+
catch (error) {
|
|
397
|
+
throw normalizeErrorAndClose(error);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
const createAttachmentSummary = (redirectTable) => {
|
|
402
|
+
try {
|
|
403
|
+
(0, core_utils_1.assert)(this.deltaManager.inbound.length === 0, 0x0d6 /* "Inbound queue should be empty when attaching" */);
|
|
404
|
+
return (0, utils_js_1.combineAppAndProtocolSummary)(this.runtime.createSummary(redirectTable), this.captureProtocolSummary());
|
|
405
|
+
}
|
|
406
|
+
catch (error) {
|
|
407
|
+
throw normalizeErrorAndClose(error);
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
const createOrGetStorageService = async (summary) => {
|
|
411
|
+
// Actually go and create the resolved document
|
|
412
|
+
if (this.service === undefined) {
|
|
413
|
+
const createNewResolvedUrl = await this.urlResolver.resolve(request);
|
|
414
|
+
(0, core_utils_1.assert)(this.client.details.type !== summarizerClientType &&
|
|
415
|
+
createNewResolvedUrl !== undefined, 0x2c4 /* "client should not be summarizer before container is created" */);
|
|
416
|
+
this.service = await (0, driver_utils_1.runWithRetry)(async () => this.serviceFactory.createContainer(summary, createNewResolvedUrl, this.subLogger, false), "containerAttach", this.mc.logger, {
|
|
417
|
+
cancel: this._deltaManager.closeAbortController.signal,
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
this.storageAdapter.connectToService(this.service);
|
|
421
|
+
return this.storageAdapter;
|
|
422
|
+
};
|
|
423
|
+
let attachP = (0, attachment_js_1.runRetriableAttachProcess)({
|
|
424
|
+
initialAttachmentData: this.attachmentData,
|
|
425
|
+
offlineLoadEnabled: this.serializedStateManager.offlineLoadEnabled,
|
|
426
|
+
detachedBlobStorage: this.detachedBlobStorage,
|
|
427
|
+
setAttachmentData,
|
|
428
|
+
createAttachmentSummary,
|
|
429
|
+
createOrGetStorageService,
|
|
430
|
+
});
|
|
431
|
+
// only enable the new behavior if the config is set
|
|
432
|
+
if (this.mc.config.getBoolean("Fluid.Container.RetryOnAttachFailure") !== true) {
|
|
433
|
+
attachP = attachP.catch((error) => {
|
|
434
|
+
throw normalizeErrorAndClose(error);
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
this.serializedStateManager.setSnapshot(await attachP);
|
|
438
|
+
if (!this.closed) {
|
|
439
|
+
this.handleDeltaConnectionArg({
|
|
440
|
+
fetchOpsFromStorage: false,
|
|
441
|
+
reason: { text: "createDetached" },
|
|
442
|
+
}, attachProps?.deltaConnection);
|
|
443
|
+
}
|
|
444
|
+
}, { start: true, end: true, cancel: "generic" });
|
|
445
|
+
});
|
|
380
446
|
this.getAbsoluteUrl = async (relativeUrl) => {
|
|
381
447
|
if (this.resolvedUrl === undefined) {
|
|
382
448
|
return undefined;
|
|
383
449
|
}
|
|
384
|
-
return this.urlResolver.getAbsoluteUrl(this.resolvedUrl, relativeUrl, (0,
|
|
450
|
+
return this.urlResolver.getAbsoluteUrl(this.resolvedUrl, relativeUrl, (0, contracts_js_1.getPackageName)(this._loadedCodeDetails));
|
|
451
|
+
};
|
|
452
|
+
this.metadataUpdateHandler = (metadata) => {
|
|
453
|
+
this._containerMetadata = { ...this._containerMetadata, ...metadata };
|
|
454
|
+
this.emit("metadataUpdate", metadata);
|
|
385
455
|
};
|
|
386
456
|
this.updateDirtyContainerState = (dirty) => {
|
|
387
457
|
if (this._dirtyContainer === dirty) {
|
|
@@ -391,7 +461,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
391
461
|
this.emit(dirty ? dirtyContainerEvent : savedContainerEvent);
|
|
392
462
|
};
|
|
393
463
|
const { canReconnect, clientDetailsOverride, urlResolver, documentServiceFactory, codeLoader, options, scope, subLogger, detachedBlobStorage, protocolHandlerBuilder, } = createProps;
|
|
394
|
-
this.connectionTransitionTimes[
|
|
464
|
+
this.connectionTransitionTimes[connectionState_js_1.ConnectionState.Disconnected] = client_utils_1.performance.now();
|
|
395
465
|
const pendingLocalState = loadProps?.pendingLocalState;
|
|
396
466
|
this._clientId = pendingLocalState?.clientId;
|
|
397
467
|
this._canReconnect = canReconnect ?? true;
|
|
@@ -407,7 +477,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
407
477
|
this.detachedBlobStorage = detachedBlobStorage;
|
|
408
478
|
this.protocolHandlerBuilder =
|
|
409
479
|
protocolHandlerBuilder ??
|
|
410
|
-
((attributes, quorumSnapshot, sendProposal) => new
|
|
480
|
+
((attributes, quorumSnapshot, sendProposal) => new protocol_js_1.ProtocolHandler(attributes, quorumSnapshot, sendProposal, new audience_js_1.Audience(), (clientId) => this.clientsWhoShouldHaveLeft.has(clientId)));
|
|
411
481
|
// Note that we capture the createProps here so we can replicate the creation call when we want to clone.
|
|
412
482
|
this.clone = async (_loadProps, createParamOverrides) => {
|
|
413
483
|
return Container.load(_loadProps, {
|
|
@@ -416,7 +486,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
416
486
|
});
|
|
417
487
|
};
|
|
418
488
|
this._containerId = (0, uuid_1.v4)();
|
|
419
|
-
this.client = Container.setupClient(this._containerId,
|
|
489
|
+
this.client = Container.setupClient(this._containerId, options.client, this.clientDetailsOverride);
|
|
420
490
|
// Create logger for data stores to use
|
|
421
491
|
const type = this.client.details.type;
|
|
422
492
|
const interactive = this.client.details.capabilities.interactive;
|
|
@@ -430,9 +500,9 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
430
500
|
clientType,
|
|
431
501
|
containerId: this._containerId,
|
|
432
502
|
docId: () => this.resolvedUrl?.id,
|
|
433
|
-
containerAttachState: () => this.
|
|
503
|
+
containerAttachState: () => this.attachState,
|
|
434
504
|
containerLifecycleState: () => this._lifecycleState,
|
|
435
|
-
containerConnectionState: () =>
|
|
505
|
+
containerConnectionState: () => connectionState_js_1.ConnectionState[this.connectionState],
|
|
436
506
|
serializedContainer: pendingLocalState !== undefined,
|
|
437
507
|
},
|
|
438
508
|
// we need to be judicious with our logging here to avoid generating too much data
|
|
@@ -460,15 +530,15 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
460
530
|
// Prefix all events in this file with container-loader
|
|
461
531
|
this.mc = (0, telemetry_utils_1.createChildMonitoringContext)({ logger: this.subLogger, namespace: "Container" });
|
|
462
532
|
this._deltaManager = this.createDeltaManager();
|
|
463
|
-
this.connectionStateHandler = (0,
|
|
533
|
+
this.connectionStateHandler = (0, connectionStateHandler_js_1.createConnectionStateHandler)({
|
|
464
534
|
logger: this.mc.logger,
|
|
465
535
|
connectionStateChanged: (value, oldState, reason) => {
|
|
466
|
-
if (value ===
|
|
536
|
+
if (value === connectionState_js_1.ConnectionState.Connected) {
|
|
467
537
|
this._clientId = this.connectionStateHandler.pendingClientId;
|
|
468
538
|
}
|
|
469
539
|
this.logConnectionStateChangeTelemetry(value, oldState, reason);
|
|
470
540
|
if (this._lifecycleState === "loaded") {
|
|
471
|
-
this.propagateConnectionState(false /* initial transition */, value ===
|
|
541
|
+
this.propagateConnectionState(false /* initial transition */, value === connectionState_js_1.ConnectionState.Disconnected
|
|
472
542
|
? reason
|
|
473
543
|
: undefined /* disconnectedReason */);
|
|
474
544
|
}
|
|
@@ -487,7 +557,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
487
557
|
mode,
|
|
488
558
|
category: this._lifecycleState === "loading" ? "generic" : category,
|
|
489
559
|
duration: client_utils_1.performance.now() -
|
|
490
|
-
this.connectionTransitionTimes[
|
|
560
|
+
this.connectionTransitionTimes[connectionState_js_1.ConnectionState.CatchingUp],
|
|
491
561
|
...(details === undefined ? {} : { details: JSON.stringify(details) }),
|
|
492
562
|
});
|
|
493
563
|
// If this is "write" connection, it took too long to receive join op. But in most cases that's due
|
|
@@ -516,12 +586,16 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
516
586
|
// using this callback and fix them up.
|
|
517
587
|
const addProtocolSummaryIfMissing = (summaryTree) => (0, driver_utils_1.isCombinedAppAndProtocolSummary)(summaryTree) === true
|
|
518
588
|
? summaryTree
|
|
519
|
-
: (0,
|
|
589
|
+
: (0, utils_js_1.combineAppAndProtocolSummary)(summaryTree, this.captureProtocolSummary());
|
|
520
590
|
// Whether the combined summary tree has been forced on by either the loader option or the monitoring context.
|
|
521
591
|
// Even if not forced on via this flag, combined summaries may still be enabled by service policy.
|
|
522
592
|
const forceEnableSummarizeProtocolTree = this.mc.config.getBoolean("Fluid.Container.summarizeProtocolTree2") ??
|
|
523
593
|
options.summarizeProtocolTree;
|
|
524
|
-
this.storageAdapter = new
|
|
594
|
+
this.storageAdapter = new containerStorageAdapter_js_1.ContainerStorageAdapter(detachedBlobStorage, this.mc.logger, pendingLocalState?.snapshotBlobs, addProtocolSummaryIfMissing, forceEnableSummarizeProtocolTree);
|
|
595
|
+
const offlineLoadEnabled = (this.isInteractiveClient &&
|
|
596
|
+
this.mc.config.getBoolean("Fluid.Container.enableOfflineLoad")) ??
|
|
597
|
+
options.enableOfflineLoad === true;
|
|
598
|
+
this.serializedStateManager = new serializedStateManager_js_1.SerializedStateManager(pendingLocalState, this.subLogger, this.storageAdapter, offlineLoadEnabled);
|
|
525
599
|
const isDomAvailable = typeof document === "object" &&
|
|
526
600
|
document !== null &&
|
|
527
601
|
typeof document.addEventListener === "function" &&
|
|
@@ -562,7 +636,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
562
636
|
this.verifyClosed();
|
|
563
637
|
}
|
|
564
638
|
verifyClosed() {
|
|
565
|
-
(0, core_utils_1.assert)(this.connectionState ===
|
|
639
|
+
(0, core_utils_1.assert)(this.connectionState === connectionState_js_1.ConnectionState.Disconnected, 0x0cf /* "disconnect event was not raised!" */);
|
|
566
640
|
(0, core_utils_1.assert)(this._lifecycleState === "closed" || this._lifecycleState === "disposed", 0x314 /* Container properly closed */);
|
|
567
641
|
}
|
|
568
642
|
closeCore(error) {
|
|
@@ -581,6 +655,10 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
581
655
|
: "generic",
|
|
582
656
|
}, error);
|
|
583
657
|
this._lifecycleState = "closing";
|
|
658
|
+
// Back-compat for Old driver
|
|
659
|
+
if (this.service?.off !== undefined) {
|
|
660
|
+
this.service?.off("metadataUpdate", this.metadataUpdateHandler);
|
|
661
|
+
}
|
|
584
662
|
this._protocolHandler?.close();
|
|
585
663
|
this.connectionStateHandler.dispose();
|
|
586
664
|
}
|
|
@@ -656,149 +734,35 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
656
734
|
return this.getPendingLocalStateCore({ notifyImminentClosure: false });
|
|
657
735
|
}
|
|
658
736
|
async getPendingLocalStateCore(props) {
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
throw new telemetry_utils_1.UsageError("Can't get pending local state unless offline load is enabled");
|
|
667
|
-
}
|
|
668
|
-
if (this.closed || this._disposed) {
|
|
669
|
-
throw new telemetry_utils_1.UsageError("Pending state cannot be retried if the container is closed or disposed");
|
|
670
|
-
}
|
|
671
|
-
(0, core_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attached, 0x0d1 /* "Container should be attached before close" */);
|
|
672
|
-
(0, core_utils_1.assert)(this.resolvedUrl !== undefined && this.resolvedUrl.type === "fluid", 0x0d2 /* "resolved url should be valid Fluid url" */);
|
|
673
|
-
(0, core_utils_1.assert)(!!this.baseSnapshot, 0x5d4 /* no base snapshot */);
|
|
674
|
-
(0, core_utils_1.assert)(!!this.baseSnapshotBlobs, 0x5d5 /* no snapshot blobs */);
|
|
675
|
-
const pendingRuntimeState = await this.runtime.getPendingLocalState(props);
|
|
676
|
-
const pendingState = {
|
|
677
|
-
pendingRuntimeState,
|
|
678
|
-
baseSnapshot: this.baseSnapshot,
|
|
679
|
-
snapshotBlobs: this.baseSnapshotBlobs,
|
|
680
|
-
savedOps: this.savedOps,
|
|
681
|
-
url: this.resolvedUrl.url,
|
|
682
|
-
// no need to save this if there is no pending runtime state
|
|
683
|
-
clientId: pendingRuntimeState !== undefined ? this.clientId : undefined,
|
|
684
|
-
};
|
|
685
|
-
return JSON.stringify(pendingState);
|
|
686
|
-
});
|
|
737
|
+
if (this.closed || this._disposed) {
|
|
738
|
+
throw new telemetry_utils_1.UsageError("Pending state cannot be retried if the container is closed or disposed");
|
|
739
|
+
}
|
|
740
|
+
(0, core_utils_1.assert)(this.attachmentData.state === container_definitions_1.AttachState.Attached, 0x0d1 /* "Container should be attached before close" */);
|
|
741
|
+
(0, core_utils_1.assert)(this.resolvedUrl !== undefined && this.resolvedUrl.type === "fluid", 0x0d2 /* "resolved url should be valid Fluid url" */);
|
|
742
|
+
const pendingState = await this.serializedStateManager.getPendingLocalStateCore(props, this.clientId, this.runtime, this.resolvedUrl);
|
|
743
|
+
return pendingState;
|
|
687
744
|
}
|
|
688
745
|
get attachState() {
|
|
689
|
-
return this.
|
|
746
|
+
return this.attachmentData.state;
|
|
690
747
|
}
|
|
691
748
|
serialize() {
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
const protocolSummary = this.captureProtocolSummary();
|
|
695
|
-
const combinedSummary = (0, utils_1.combineAppAndProtocolSummary)(appSummary, protocolSummary);
|
|
696
|
-
if (this.detachedBlobStorage && this.detachedBlobStorage.size > 0) {
|
|
697
|
-
combinedSummary.tree[hasBlobsSummaryTree] = {
|
|
698
|
-
type: protocol_definitions_1.SummaryType.Blob,
|
|
699
|
-
content: "true",
|
|
700
|
-
};
|
|
749
|
+
if (this.attachmentData.state === container_definitions_1.AttachState.Attached || this.closed) {
|
|
750
|
+
throw new telemetry_utils_1.UsageError("Container must not be attached or closed.");
|
|
701
751
|
}
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
(0, core_utils_1.assert)(this.deltaManager.inbound.length === 0, 0x0d6 /* "Inbound queue should be empty when attaching" */);
|
|
717
|
-
let summary;
|
|
718
|
-
if (!hasAttachmentBlobs) {
|
|
719
|
-
// Get the document state post attach - possibly can just call attach but we need to change the
|
|
720
|
-
// semantics around what the attach means as far as async code goes.
|
|
721
|
-
const appSummary = this.runtime.createSummary();
|
|
722
|
-
const protocolSummary = this.captureProtocolSummary();
|
|
723
|
-
summary = (0, utils_1.combineAppAndProtocolSummary)(appSummary, protocolSummary);
|
|
724
|
-
// Set the state as attaching as we are starting the process of attaching container.
|
|
725
|
-
// This should be fired after taking the summary because it is the place where we are
|
|
726
|
-
// starting to attach the container to storage.
|
|
727
|
-
// Also, this should only be fired in detached container.
|
|
728
|
-
this._attachState = container_definitions_1.AttachState.Attaching;
|
|
729
|
-
this.runtime.setAttachState(container_definitions_1.AttachState.Attaching);
|
|
730
|
-
this.emit("attaching");
|
|
731
|
-
if (this.offlineLoadEnabled) {
|
|
732
|
-
const snapshot = (0, utils_1.getSnapshotTreeFromSerializedContainer)(summary);
|
|
733
|
-
this.baseSnapshot = snapshot;
|
|
734
|
-
this.baseSnapshotBlobs =
|
|
735
|
-
(0, containerStorageAdapter_1.getBlobContentsFromTreeWithBlobContents)(snapshot);
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
// Actually go and create the resolved document
|
|
739
|
-
if (this.service === undefined) {
|
|
740
|
-
const createNewResolvedUrl = await this.urlResolver.resolve(request);
|
|
741
|
-
(0, core_utils_1.assert)(this.client.details.type !== summarizerClientType &&
|
|
742
|
-
createNewResolvedUrl !== undefined, 0x2c4 /* "client should not be summarizer before container is created" */);
|
|
743
|
-
this.service = await (0, driver_utils_1.runWithRetry)(async () => this.serviceFactory.createContainer(summary, createNewResolvedUrl, this.subLogger, false), "containerAttach", this.mc.logger, {
|
|
744
|
-
cancel: this._deltaManager.closeAbortController.signal,
|
|
745
|
-
});
|
|
746
|
-
}
|
|
747
|
-
this.storageAdapter.connectToService(this.service);
|
|
748
|
-
if (hasAttachmentBlobs) {
|
|
749
|
-
// upload blobs to storage
|
|
750
|
-
(0, core_utils_1.assert)(!!this.detachedBlobStorage, 0x24e /* "assertion for type narrowing" */);
|
|
751
|
-
// build a table mapping IDs assigned locally to IDs assigned by storage and pass it to runtime to
|
|
752
|
-
// support blob handles that only know about the local IDs
|
|
753
|
-
const redirectTable = new Map();
|
|
754
|
-
// if new blobs are added while uploading, upload them too
|
|
755
|
-
while (redirectTable.size < this.detachedBlobStorage.size) {
|
|
756
|
-
const newIds = this.detachedBlobStorage
|
|
757
|
-
.getBlobIds()
|
|
758
|
-
.filter((id) => !redirectTable.has(id));
|
|
759
|
-
for (const id of newIds) {
|
|
760
|
-
const blob = await this.detachedBlobStorage.readBlob(id);
|
|
761
|
-
const response = await this.storageAdapter.createBlob(blob);
|
|
762
|
-
redirectTable.set(id, response.id);
|
|
763
|
-
}
|
|
764
|
-
}
|
|
765
|
-
// take summary and upload
|
|
766
|
-
const appSummary = this.runtime.createSummary(redirectTable);
|
|
767
|
-
const protocolSummary = this.captureProtocolSummary();
|
|
768
|
-
summary = (0, utils_1.combineAppAndProtocolSummary)(appSummary, protocolSummary);
|
|
769
|
-
this._attachState = container_definitions_1.AttachState.Attaching;
|
|
770
|
-
this.runtime.setAttachState(container_definitions_1.AttachState.Attaching);
|
|
771
|
-
this.emit("attaching");
|
|
772
|
-
if (this.offlineLoadEnabled) {
|
|
773
|
-
const snapshot = (0, utils_1.getSnapshotTreeFromSerializedContainer)(summary);
|
|
774
|
-
this.baseSnapshot = snapshot;
|
|
775
|
-
this.baseSnapshotBlobs =
|
|
776
|
-
(0, containerStorageAdapter_1.getBlobContentsFromTreeWithBlobContents)(snapshot);
|
|
777
|
-
}
|
|
778
|
-
await this.storageAdapter.uploadSummaryWithContext(summary, {
|
|
779
|
-
referenceSequenceNumber: 0,
|
|
780
|
-
ackHandle: undefined,
|
|
781
|
-
proposalHandle: undefined,
|
|
782
|
-
});
|
|
783
|
-
}
|
|
784
|
-
this._attachState = container_definitions_1.AttachState.Attached;
|
|
785
|
-
this.runtime.setAttachState(container_definitions_1.AttachState.Attached);
|
|
786
|
-
this.emit("attached");
|
|
787
|
-
if (!this.closed) {
|
|
788
|
-
this.handleDeltaConnectionArg({
|
|
789
|
-
fetchOpsFromStorage: false,
|
|
790
|
-
reason: { text: "createDetached" },
|
|
791
|
-
}, attachProps?.deltaConnection);
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
catch (error) {
|
|
795
|
-
// add resolved URL on error object so that host has the ability to find this document and delete it
|
|
796
|
-
const newError = (0, telemetry_utils_1.normalizeError)(error);
|
|
797
|
-
newError.addTelemetryProperties({ resolvedUrl: this.resolvedUrl?.url });
|
|
798
|
-
this.close(newError);
|
|
799
|
-
throw newError;
|
|
800
|
-
}
|
|
801
|
-
}, { start: true, end: true, cancel: "generic" });
|
|
752
|
+
const attachingData = this.attachmentData.state === container_definitions_1.AttachState.Attaching ? this.attachmentData : undefined;
|
|
753
|
+
const combinedSummary = attachingData?.summary ??
|
|
754
|
+
(0, utils_js_1.combineAppAndProtocolSummary)(this.runtime.createSummary(), this.captureProtocolSummary());
|
|
755
|
+
const { tree: snapshot, blobs } = (0, utils_js_1.getSnapshotTreeAndBlobsFromSerializedContainer)(combinedSummary);
|
|
756
|
+
const pendingRuntimeState = attachingData !== undefined ? this.runtime.getPendingLocalState() : undefined;
|
|
757
|
+
(0, core_utils_1.assert)(!(0, core_utils_1.isPromiseLike)(pendingRuntimeState), 0x8e3 /* should not be a promise */);
|
|
758
|
+
const detachedContainerState = {
|
|
759
|
+
attached: false,
|
|
760
|
+
baseSnapshot: snapshot,
|
|
761
|
+
snapshotBlobs: blobs,
|
|
762
|
+
pendingRuntimeState,
|
|
763
|
+
hasAttachmentBlobs: !!this.detachedBlobStorage && this.detachedBlobStorage.size > 0,
|
|
764
|
+
};
|
|
765
|
+
return JSON.stringify(detachedContainerState);
|
|
802
766
|
}
|
|
803
767
|
setAutoReconnectInternal(mode, reason) {
|
|
804
768
|
const currentMode = this._deltaManager.connectionManager.reconnectMode;
|
|
@@ -809,9 +773,9 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
809
773
|
const duration = now - this.setAutoReconnectTime;
|
|
810
774
|
this.setAutoReconnectTime = now;
|
|
811
775
|
this.mc.logger.sendTelemetryEvent({
|
|
812
|
-
eventName: mode ===
|
|
776
|
+
eventName: mode === contracts_js_1.ReconnectMode.Enabled ? "AutoReconnectEnabled" : "AutoReconnectDisabled",
|
|
813
777
|
connectionMode: this.connectionMode,
|
|
814
|
-
connectionState:
|
|
778
|
+
connectionState: connectionState_js_1.ConnectionState[this.connectionState],
|
|
815
779
|
duration,
|
|
816
780
|
});
|
|
817
781
|
this._deltaManager.connectionManager.setAutoReconnect(mode, reason);
|
|
@@ -820,7 +784,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
820
784
|
if (this.closed) {
|
|
821
785
|
throw new telemetry_utils_1.UsageError(`The Container is closed and cannot be connected`);
|
|
822
786
|
}
|
|
823
|
-
else if (this.
|
|
787
|
+
else if (this.attachState !== container_definitions_1.AttachState.Attached) {
|
|
824
788
|
throw new telemetry_utils_1.UsageError(`The Container is not attached and cannot be connected`);
|
|
825
789
|
}
|
|
826
790
|
else if (!this.connected) {
|
|
@@ -835,11 +799,11 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
835
799
|
}
|
|
836
800
|
connectInternal(args) {
|
|
837
801
|
(0, core_utils_1.assert)(!this.closed, 0x2c5 /* "Attempting to connect() a closed Container" */);
|
|
838
|
-
(0, core_utils_1.assert)(this.
|
|
802
|
+
(0, core_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attached, 0x2c6 /* "Attempting to connect() a container that is not attached" */);
|
|
839
803
|
// Resume processing ops and connect to delta stream
|
|
840
804
|
this.resumeInternal(args);
|
|
841
805
|
// Set Auto Reconnect Mode
|
|
842
|
-
const mode =
|
|
806
|
+
const mode = contracts_js_1.ReconnectMode.Enabled;
|
|
843
807
|
this.setAutoReconnectInternal(mode, args.reason);
|
|
844
808
|
}
|
|
845
809
|
disconnect() {
|
|
@@ -853,7 +817,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
853
817
|
disconnectInternal(reason) {
|
|
854
818
|
(0, core_utils_1.assert)(!this.closed, 0x2c7 /* "Attempting to disconnect() a closed Container" */);
|
|
855
819
|
// Set Auto Reconnect Mode
|
|
856
|
-
const mode =
|
|
820
|
+
const mode = contracts_js_1.ReconnectMode.Disabled;
|
|
857
821
|
this.setAutoReconnectInternal(mode, reason);
|
|
858
822
|
}
|
|
859
823
|
resumeInternal(args) {
|
|
@@ -928,10 +892,6 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
928
892
|
}
|
|
929
893
|
return true;
|
|
930
894
|
}
|
|
931
|
-
async getVersion(version) {
|
|
932
|
-
const versions = await this.storageAdapter.getVersions(version, 1);
|
|
933
|
-
return versions[0];
|
|
934
|
-
}
|
|
935
895
|
connectToDeltaStream(args) {
|
|
936
896
|
// All agents need "write" access, including summarizer.
|
|
937
897
|
if (!this._canReconnect || !this.client.details.capabilities.interactive) {
|
|
@@ -939,6 +899,14 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
939
899
|
}
|
|
940
900
|
this._deltaManager.connect(args);
|
|
941
901
|
}
|
|
902
|
+
async createDocumentService(serviceProvider) {
|
|
903
|
+
const service = await serviceProvider();
|
|
904
|
+
// Back-compat for Old driver
|
|
905
|
+
if (service.on !== undefined) {
|
|
906
|
+
service.on("metadataUpdate", this.metadataUpdateHandler);
|
|
907
|
+
}
|
|
908
|
+
return service;
|
|
909
|
+
}
|
|
942
910
|
/**
|
|
943
911
|
* Load container.
|
|
944
912
|
*
|
|
@@ -946,7 +914,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
946
914
|
*/
|
|
947
915
|
async load(specifiedVersion, loadMode, resolvedUrl, pendingLocalState, loadToSequenceNumber) {
|
|
948
916
|
const timings = { phase1: client_utils_1.performance.now() };
|
|
949
|
-
this.service = await this.serviceFactory.createDocumentService(resolvedUrl, this.subLogger, this.client.details.type === summarizerClientType);
|
|
917
|
+
this.service = await this.createDocumentService(async () => this.serviceFactory.createDocumentService(resolvedUrl, this.subLogger, this.client.details.type === summarizerClientType));
|
|
950
918
|
// Except in cases where it has stashed ops or requested by feature gate, the container will connect in "read" mode
|
|
951
919
|
const mode = this.mc.config.getBoolean("Fluid.Container.ForceWriteConnection") === true ||
|
|
952
920
|
(pendingLocalState?.savedOps.length ?? 0) > 0
|
|
@@ -963,25 +931,14 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
963
931
|
this.connectToDeltaStream(connectionArgs);
|
|
964
932
|
}
|
|
965
933
|
this.storageAdapter.connectToService(this.service);
|
|
966
|
-
this.
|
|
934
|
+
this.attachmentData = {
|
|
935
|
+
state: container_definitions_1.AttachState.Attached,
|
|
936
|
+
};
|
|
967
937
|
timings.phase2 = client_utils_1.performance.now();
|
|
968
938
|
// Fetch specified snapshot.
|
|
969
|
-
const {
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
if (pendingLocalState) {
|
|
973
|
-
this.baseSnapshot = pendingLocalState.baseSnapshot;
|
|
974
|
-
this.baseSnapshotBlobs = pendingLocalState.snapshotBlobs;
|
|
975
|
-
}
|
|
976
|
-
else {
|
|
977
|
-
(0, core_utils_1.assert)(snapshot !== undefined, 0x237 /* "Snapshot should exist" */);
|
|
978
|
-
if (this.offlineLoadEnabled) {
|
|
979
|
-
this.baseSnapshot = snapshot;
|
|
980
|
-
// Save contents of snapshot now, otherwise closeAndGetPendingLocalState() must be async
|
|
981
|
-
this.baseSnapshotBlobs = await (0, containerStorageAdapter_1.getBlobContentsFromTree)(snapshot, this.storageAdapter);
|
|
982
|
-
}
|
|
983
|
-
}
|
|
984
|
-
const attributes = await this.getDocumentAttributes(this.storageAdapter, snapshot);
|
|
939
|
+
const { snapshotTree, version } = await this.serializedStateManager.fetchSnapshot(specifiedVersion, this.service?.policies?.supportGetSnapshotApi);
|
|
940
|
+
this._loadedFromVersion = version;
|
|
941
|
+
const attributes = await this.getDocumentAttributes(this.storageAdapter, snapshotTree);
|
|
985
942
|
// If we saved ops, we will replay them and don't need DeltaManager to fetch them
|
|
986
943
|
const sequenceNumber = pendingLocalState?.savedOps[pendingLocalState.savedOps.length - 1]?.sequenceNumber;
|
|
987
944
|
const dmAttributes = sequenceNumber !== undefined ? { ...attributes, sequenceNumber } : attributes;
|
|
@@ -1046,12 +1003,12 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1046
1003
|
}
|
|
1047
1004
|
// ...load in the existing quorum
|
|
1048
1005
|
// Initialize the protocol handler
|
|
1049
|
-
await this.initializeProtocolStateFromSnapshot(attributes, this.storageAdapter,
|
|
1006
|
+
await this.initializeProtocolStateFromSnapshot(attributes, this.storageAdapter, snapshotTree);
|
|
1050
1007
|
timings.phase3 = client_utils_1.performance.now();
|
|
1051
1008
|
const codeDetails = this.getCodeDetailsFromQuorum();
|
|
1052
|
-
await this.instantiateRuntime(codeDetails,
|
|
1009
|
+
await this.instantiateRuntime(codeDetails, snapshotTree,
|
|
1053
1010
|
// give runtime a dummy value so it knows we're loading from a stash blob
|
|
1054
|
-
pendingLocalState ? pendingLocalState?.pendingRuntimeState ?? {} : undefined);
|
|
1011
|
+
pendingLocalState ? pendingLocalState?.pendingRuntimeState ?? {} : undefined, (0, driver_utils_1.isInstanceOfISnapshot)(snapshotTree) ? snapshotTree : undefined);
|
|
1055
1012
|
// replay saved ops
|
|
1056
1013
|
if (pendingLocalState) {
|
|
1057
1014
|
for (const message of pendingLocalState.savedOps) {
|
|
@@ -1106,7 +1063,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1106
1063
|
}, undefined, core_interfaces_1.LogLevel.verbose);
|
|
1107
1064
|
return {
|
|
1108
1065
|
sequenceNumber: attributes.sequenceNumber,
|
|
1109
|
-
version:
|
|
1066
|
+
version: version?.id,
|
|
1110
1067
|
dmLastProcessedSeqNumber: this._deltaManager.lastSequenceNumber,
|
|
1111
1068
|
dmLastKnownSeqNumber: this._deltaManager.lastKnownSeqNumber,
|
|
1112
1069
|
};
|
|
@@ -1118,7 +1075,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1118
1075
|
};
|
|
1119
1076
|
await this.attachDeltaManagerOpHandler(attributes);
|
|
1120
1077
|
// Need to just seed the source data in the code quorum. Quorum itself is empty
|
|
1121
|
-
const qValues = (0,
|
|
1078
|
+
const qValues = (0, quorum_js_1.initQuorumValuesFromCodeDetails)(codeDetails);
|
|
1122
1079
|
this.initializeProtocolState(attributes, {
|
|
1123
1080
|
members: [],
|
|
1124
1081
|
proposals: [],
|
|
@@ -1127,18 +1084,16 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1127
1084
|
await this.instantiateRuntime(codeDetails, undefined);
|
|
1128
1085
|
this.setLoaded();
|
|
1129
1086
|
}
|
|
1130
|
-
async rehydrateDetachedFromSnapshot(
|
|
1131
|
-
if (
|
|
1087
|
+
async rehydrateDetachedFromSnapshot({ baseSnapshot, snapshotBlobs, hasAttachmentBlobs, pendingRuntimeState, }) {
|
|
1088
|
+
if (hasAttachmentBlobs) {
|
|
1132
1089
|
(0, core_utils_1.assert)(!!this.detachedBlobStorage && this.detachedBlobStorage.size > 0, 0x250 /* "serialized container with attachment blobs must be rehydrated with detached blob storage" */);
|
|
1133
|
-
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
|
1134
|
-
delete detachedContainerSnapshot.tree[hasBlobsSummaryTree];
|
|
1135
1090
|
}
|
|
1136
|
-
const
|
|
1137
|
-
this.storageAdapter.
|
|
1138
|
-
const attributes = await this.getDocumentAttributes(this.storageAdapter,
|
|
1091
|
+
const snapshotTreeWithBlobContents = (0, utils_js_1.combineSnapshotTreeAndSnapshotBlobs)(baseSnapshot, snapshotBlobs);
|
|
1092
|
+
this.storageAdapter.loadSnapshotFromSnapshotBlobs(snapshotBlobs);
|
|
1093
|
+
const attributes = await this.getDocumentAttributes(this.storageAdapter, snapshotTreeWithBlobContents);
|
|
1139
1094
|
await this.attachDeltaManagerOpHandler(attributes);
|
|
1140
1095
|
// Initialize the protocol handler
|
|
1141
|
-
const baseTree = (0,
|
|
1096
|
+
const baseTree = (0, utils_js_1.getProtocolSnapshotTree)(snapshotTreeWithBlobContents);
|
|
1142
1097
|
const qValues = await (0, driver_utils_1.readAndParse)(this.storageAdapter, baseTree.blobs.quorumValues);
|
|
1143
1098
|
this.initializeProtocolState(attributes, {
|
|
1144
1099
|
members: [],
|
|
@@ -1146,7 +1101,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1146
1101
|
values: qValues,
|
|
1147
1102
|
});
|
|
1148
1103
|
const codeDetails = this.getCodeDetailsFromQuorum();
|
|
1149
|
-
await this.instantiateRuntime(codeDetails,
|
|
1104
|
+
await this.instantiateRuntime(codeDetails, snapshotTreeWithBlobContents, pendingRuntimeState);
|
|
1150
1105
|
this.setLoaded();
|
|
1151
1106
|
}
|
|
1152
1107
|
async getDocumentAttributes(storage, tree) {
|
|
@@ -1170,7 +1125,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1170
1125
|
values: [],
|
|
1171
1126
|
};
|
|
1172
1127
|
if (snapshot !== undefined) {
|
|
1173
|
-
const baseTree = (0,
|
|
1128
|
+
const baseTree = (0, utils_js_1.getProtocolSnapshotTree)(snapshot);
|
|
1174
1129
|
[quorumSnapshot.members, quorumSnapshot.proposals, quorumSnapshot.values] =
|
|
1175
1130
|
await Promise.all([
|
|
1176
1131
|
(0, driver_utils_1.readAndParse)(storage, baseTree.blobs.quorumMembers),
|
|
@@ -1246,10 +1201,9 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1246
1201
|
const pkg = getCodeProposal(quorum);
|
|
1247
1202
|
return pkg;
|
|
1248
1203
|
}
|
|
1249
|
-
static setupClient(containerId,
|
|
1250
|
-
const loaderOptionsClient = (0, structured_clone_1.default)(options?.client);
|
|
1204
|
+
static setupClient(containerId, loaderOptionsClient, clientDetailsOverride) {
|
|
1251
1205
|
const client = loaderOptionsClient !== undefined
|
|
1252
|
-
? loaderOptionsClient
|
|
1206
|
+
? (0, structured_clone_1.default)(loaderOptionsClient)
|
|
1253
1207
|
: {
|
|
1254
1208
|
details: {
|
|
1255
1209
|
capabilities: { interactive: true },
|
|
@@ -1271,7 +1225,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1271
1225
|
}
|
|
1272
1226
|
client.details.environment = [
|
|
1273
1227
|
client.details.environment,
|
|
1274
|
-
` loaderVersion:${
|
|
1228
|
+
` loaderVersion:${packageVersion_js_1.pkgVersion}`,
|
|
1275
1229
|
` containerId:${containerId}`,
|
|
1276
1230
|
].join(";");
|
|
1277
1231
|
return client;
|
|
@@ -1283,11 +1237,11 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1283
1237
|
* If it's not true, runtime is not in position to send ops.
|
|
1284
1238
|
*/
|
|
1285
1239
|
activeConnection() {
|
|
1286
|
-
return (this.connectionState ===
|
|
1240
|
+
return (this.connectionState === connectionState_js_1.ConnectionState.Connected && this.connectionMode === "write");
|
|
1287
1241
|
}
|
|
1288
1242
|
createDeltaManager() {
|
|
1289
1243
|
const serviceProvider = () => this.service;
|
|
1290
|
-
const deltaManager = new
|
|
1244
|
+
const deltaManager = new deltaManager_js_1.DeltaManager(serviceProvider, (0, telemetry_utils_1.createChildLogger)({ logger: this.subLogger, namespace: "DeltaManager" }), () => this.activeConnection(), (props) => new connectionManager_js_1.ConnectionManager(serviceProvider, () => this.isDirty, this.client, this._canReconnect, (0, telemetry_utils_1.createChildLogger)({ logger: this.subLogger, namespace: "ConnectionManager" }), props));
|
|
1291
1245
|
// Disable inbound queues as Container is not ready to accept any ops until we are fully loaded!
|
|
1292
1246
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
1293
1247
|
deltaManager.inbound.pause();
|
|
@@ -1303,10 +1257,10 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1303
1257
|
deltaManager.on("cancelEstablishingConnection", (reason) => {
|
|
1304
1258
|
this.connectionStateHandler.cancelEstablishingConnection(reason);
|
|
1305
1259
|
});
|
|
1306
|
-
deltaManager.on("disconnect", (
|
|
1260
|
+
deltaManager.on("disconnect", (text, error) => {
|
|
1307
1261
|
this.noopHeuristic?.notifyDisconnect();
|
|
1308
1262
|
if (!this.closed) {
|
|
1309
|
-
this.connectionStateHandler.receivedDisconnectEvent(
|
|
1263
|
+
this.connectionStateHandler.receivedDisconnectEvent({ text, error });
|
|
1310
1264
|
}
|
|
1311
1265
|
});
|
|
1312
1266
|
deltaManager.on("throttled", (warning) => {
|
|
@@ -1319,7 +1273,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1319
1273
|
this.emit("warning", warn);
|
|
1320
1274
|
});
|
|
1321
1275
|
deltaManager.on("readonly", (readonly) => {
|
|
1322
|
-
this.setContextConnectedState(this.connectionState ===
|
|
1276
|
+
this.setContextConnectedState(this.connectionState === connectionState_js_1.ConnectionState.Connected, readonly);
|
|
1323
1277
|
this.emit("readonly", readonly);
|
|
1324
1278
|
});
|
|
1325
1279
|
deltaManager.on("closed", (error) => {
|
|
@@ -1348,16 +1302,16 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1348
1302
|
let autoReconnect;
|
|
1349
1303
|
let checkpointSequenceNumber;
|
|
1350
1304
|
let opsBehind;
|
|
1351
|
-
if (value ===
|
|
1305
|
+
if (value === connectionState_js_1.ConnectionState.Disconnected) {
|
|
1352
1306
|
autoReconnect = this._deltaManager.connectionManager.reconnectMode;
|
|
1353
1307
|
}
|
|
1354
1308
|
else {
|
|
1355
|
-
if (value ===
|
|
1309
|
+
if (value === connectionState_js_1.ConnectionState.Connected) {
|
|
1356
1310
|
durationFromDisconnected =
|
|
1357
|
-
time - this.connectionTransitionTimes[
|
|
1311
|
+
time - this.connectionTransitionTimes[connectionState_js_1.ConnectionState.Disconnected];
|
|
1358
1312
|
durationFromDisconnected = (0, telemetry_utils_1.formatTick)(durationFromDisconnected);
|
|
1359
1313
|
}
|
|
1360
|
-
else if (value ===
|
|
1314
|
+
else if (value === connectionState_js_1.ConnectionState.CatchingUp) {
|
|
1361
1315
|
// This info is of most interesting while Catching Up.
|
|
1362
1316
|
checkpointSequenceNumber = this.deltaManager.lastKnownSeqNumber;
|
|
1363
1317
|
// Need to check that we have already loaded and fetched the snapshot.
|
|
@@ -1369,8 +1323,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1369
1323
|
connectionInitiationReason = this.firstConnection ? "InitialConnect" : "AutoReconnect";
|
|
1370
1324
|
}
|
|
1371
1325
|
this.mc.logger.sendPerformanceEvent({
|
|
1372
|
-
eventName: `ConnectionStateChange_${
|
|
1373
|
-
from:
|
|
1326
|
+
eventName: `ConnectionStateChange_${connectionState_js_1.ConnectionState[value]}`,
|
|
1327
|
+
from: connectionState_js_1.ConnectionState[oldState],
|
|
1374
1328
|
duration,
|
|
1375
1329
|
durationFromDisconnected,
|
|
1376
1330
|
reason: reason?.text,
|
|
@@ -1388,7 +1342,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1388
1342
|
isDirty: this.isDirty,
|
|
1389
1343
|
...this._deltaManager.connectionProps,
|
|
1390
1344
|
}, reason?.error);
|
|
1391
|
-
if (value ===
|
|
1345
|
+
if (value === connectionState_js_1.ConnectionState.Connected) {
|
|
1392
1346
|
this.firstConnection = false;
|
|
1393
1347
|
}
|
|
1394
1348
|
}
|
|
@@ -1397,11 +1351,11 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1397
1351
|
// After that, we communicate only transitions to Connected & Disconnected states, skipping all other states.
|
|
1398
1352
|
// This can be changed in the future, for example we likely should add "CatchingUp" event on Container.
|
|
1399
1353
|
if (!initialTransition &&
|
|
1400
|
-
this.connectionState !==
|
|
1401
|
-
this.connectionState !==
|
|
1354
|
+
this.connectionState !== connectionState_js_1.ConnectionState.Connected &&
|
|
1355
|
+
this.connectionState !== connectionState_js_1.ConnectionState.Disconnected) {
|
|
1402
1356
|
return;
|
|
1403
1357
|
}
|
|
1404
|
-
const state = this.connectionState ===
|
|
1358
|
+
const state = this.connectionState === connectionState_js_1.ConnectionState.Connected;
|
|
1405
1359
|
// Both protocol and context should not be undefined if we got so far.
|
|
1406
1360
|
this.setContextConnectedState(state, this.readOnlyInfo.readonly ?? false);
|
|
1407
1361
|
this.protocolHandler.setConnectionState(state, this.clientId);
|
|
@@ -1443,7 +1397,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1443
1397
|
return this.submitMessage(protocol_definitions_1.MessageType.Summarize, JSON.stringify(summary), false /* batch */, undefined /* metadata */, undefined /* compression */, referenceSequenceNumber);
|
|
1444
1398
|
}
|
|
1445
1399
|
submitMessage(type, contents, batch, metadata, compression, referenceSequenceNumber) {
|
|
1446
|
-
if (this.connectionState !==
|
|
1400
|
+
if (this.connectionState !== connectionState_js_1.ConnectionState.Connected) {
|
|
1447
1401
|
this.mc.logger.sendErrorEvent({ eventName: "SubmitMessageWithNoConnection", type });
|
|
1448
1402
|
return -1;
|
|
1449
1403
|
}
|
|
@@ -1451,14 +1405,12 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1451
1405
|
return this._deltaManager.submit(type, contents, batch, metadata, compression, referenceSequenceNumber);
|
|
1452
1406
|
}
|
|
1453
1407
|
processRemoteMessage(message) {
|
|
1454
|
-
if (this.offlineLoadEnabled) {
|
|
1455
|
-
this.savedOps.push(message);
|
|
1456
|
-
}
|
|
1457
1408
|
const local = this.clientId === message.clientId;
|
|
1458
1409
|
// Allow the protocol handler to process the message
|
|
1459
1410
|
const result = this.protocolHandler.processMessage(message, local);
|
|
1460
1411
|
// Forward messages to the loaded runtime for processing
|
|
1461
1412
|
this.runtime.process(message, local);
|
|
1413
|
+
this.serializedStateManager.addProcessedOp(message);
|
|
1462
1414
|
// Inactive (not in quorum or not writers) clients don't take part in the minimum sequence number calculation.
|
|
1463
1415
|
if (this.activeConnection()) {
|
|
1464
1416
|
if (this.noopHeuristic === undefined) {
|
|
@@ -1468,7 +1420,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1468
1420
|
// clients.
|
|
1469
1421
|
// All existing will continue to use settings they got earlier.
|
|
1470
1422
|
(0, core_utils_1.assert)(serviceConfiguration !== undefined, 0x2e4 /* "there should be service config for active connection" */);
|
|
1471
|
-
this.noopHeuristic = new
|
|
1423
|
+
this.noopHeuristic = new noopHeuristic_js_1.NoopHeuristic(serviceConfiguration.noopTimeFrequency, serviceConfiguration.noopCountFrequency);
|
|
1472
1424
|
this.noopHeuristic.on("wantsNoop", () => {
|
|
1473
1425
|
// On disconnect we notify the heuristic which should prevent it from wanting a noop.
|
|
1474
1426
|
// Hitting this assert would imply we lost activeConnection between notifying the heuristic of a processed message and
|
|
@@ -1491,7 +1443,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1491
1443
|
}
|
|
1492
1444
|
processSignal(message) {
|
|
1493
1445
|
// No clientId indicates a system signal message.
|
|
1494
|
-
if ((0,
|
|
1446
|
+
if ((0, protocol_js_1.protocolHandlerShouldProcessSignal)(message)) {
|
|
1495
1447
|
this.protocolHandler.processSignal(message);
|
|
1496
1448
|
}
|
|
1497
1449
|
else {
|
|
@@ -1499,33 +1451,12 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1499
1451
|
this.runtime.processSignal(message, local);
|
|
1500
1452
|
}
|
|
1501
1453
|
}
|
|
1502
|
-
|
|
1503
|
-
* Get the most recent snapshot, or a specific version.
|
|
1504
|
-
* @param specifiedVersion - The specific version of the snapshot to retrieve
|
|
1505
|
-
* @returns The snapshot requested, or the latest snapshot if no version was specified, plus version ID
|
|
1506
|
-
*/
|
|
1507
|
-
async fetchSnapshotTree(specifiedVersion) {
|
|
1508
|
-
const version = await this.getVersion(specifiedVersion ?? null);
|
|
1509
|
-
if (version === undefined && specifiedVersion !== undefined) {
|
|
1510
|
-
// We should have a defined version to load from if specified version requested
|
|
1511
|
-
this.mc.logger.sendErrorEvent({
|
|
1512
|
-
eventName: "NoVersionFoundWhenSpecified",
|
|
1513
|
-
id: specifiedVersion,
|
|
1514
|
-
});
|
|
1515
|
-
}
|
|
1516
|
-
this._loadedFromVersion = version;
|
|
1517
|
-
const snapshot = (await this.storageAdapter.getSnapshotTree(version)) ?? undefined;
|
|
1518
|
-
if (snapshot === undefined && version !== undefined) {
|
|
1519
|
-
this.mc.logger.sendErrorEvent({ eventName: "getSnapshotTreeFailed", id: version.id });
|
|
1520
|
-
}
|
|
1521
|
-
return { snapshot, versionId: version?.id };
|
|
1522
|
-
}
|
|
1523
|
-
async instantiateRuntime(codeDetails, snapshot, pendingLocalState) {
|
|
1454
|
+
async instantiateRuntime(codeDetails, snapshotTree, pendingLocalState, snapshot) {
|
|
1524
1455
|
(0, core_utils_1.assert)(this._runtime?.disposed !== false, 0x0dd /* "Existing runtime not disposed" */);
|
|
1525
1456
|
// The relative loader will proxy requests to '/' to the loader itself assuming no non-cache flags
|
|
1526
1457
|
// are set. Global requests will still go directly to the loader
|
|
1527
1458
|
const maybeLoader = this.scope;
|
|
1528
|
-
const loader = new
|
|
1459
|
+
const loader = new loader_js_1.RelativeLoader(this, maybeLoader.ILoader);
|
|
1529
1460
|
const loadCodeResult = await telemetry_utils_1.PerformanceEvent.timedExecAsync(this.subLogger, { eventName: "CodeLoad" }, async () => this.codeLoader.load(codeDetails));
|
|
1530
1461
|
this._loadedModule = {
|
|
1531
1462
|
module: loadCodeResult.module,
|
|
@@ -1541,8 +1472,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1541
1472
|
}
|
|
1542
1473
|
const getSpecifiedCodeDetails = () => (this.protocolHandler.quorum.get("code") ??
|
|
1543
1474
|
this.protocolHandler.quorum.get("code2"));
|
|
1544
|
-
const existing =
|
|
1545
|
-
const context = new
|
|
1475
|
+
const existing = snapshotTree !== undefined;
|
|
1476
|
+
const context = new containerContext_js_1.ContainerContext(this.options, this.scope, snapshotTree, this._loadedFromVersion, this._deltaManager, this.storageAdapter, this.protocolHandler.quorum, this.protocolHandler.audience, loader, (type, contents, batch, metadata) => this.submitContainerMessage(type, contents, batch, metadata), (summaryOp, referenceSequenceNumber) => this.submitSummaryMessage(summaryOp, referenceSequenceNumber), (batch, referenceSequenceNumber) => this.submitBatch(batch, referenceSequenceNumber), (content, targetClientId) => this.submitSignal(content, targetClientId), (error) => this.dispose(error), (error) => this.close(error), this.updateDirtyContainerState, this.getAbsoluteUrl, () => this.resolvedUrl?.id, () => this.clientId, () => this.attachState, () => this.connected, getSpecifiedCodeDetails, this._deltaManager.clientDetails, existing, this.subLogger, pendingLocalState, snapshot);
|
|
1546
1477
|
this._runtime = await telemetry_utils_1.PerformanceEvent.timedExecAsync(this.subLogger, { eventName: "InstantiateRuntime" }, async () => runtimeFactory.instantiateRuntime(context, existing));
|
|
1547
1478
|
this._lifecycleEvents.emit("runtimeInstantiated");
|
|
1548
1479
|
this._loadedCodeDetails = codeDetails;
|