@fluidframework/container-loader 2.0.0-rc.1.0.4 → 2.0.0-rc.2.0.0
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 +219 -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} +179 -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 +63 -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 +297 -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
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
4
4
|
* Licensed under the MIT License.
|
|
5
5
|
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
6
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
10
|
exports.Container = exports.ReportIfTooLong = exports.waitContainerToCatchUp = void 0;
|
|
8
11
|
const uuid_1 = require("uuid");
|
|
@@ -13,25 +16,27 @@ const container_definitions_1 = require("@fluidframework/container-definitions")
|
|
|
13
16
|
const driver_utils_1 = require("@fluidframework/driver-utils");
|
|
14
17
|
const protocol_definitions_1 = require("@fluidframework/protocol-definitions");
|
|
15
18
|
const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
const
|
|
19
|
+
const structured_clone_1 = __importDefault(require("@ungap/structured-clone"));
|
|
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");
|
|
30
36
|
const detachedContainerRefSeqNumber = 0;
|
|
31
37
|
const dirtyContainerEvent = "dirty";
|
|
32
38
|
const savedContainerEvent = "saved";
|
|
33
39
|
const packageNotFactoryError = "Code package does not implement IRuntimeFactory";
|
|
34
|
-
const hasBlobsSummaryTree = ".hasAttachmentBlobs";
|
|
35
40
|
/**
|
|
36
41
|
* Waits until container connects to delta storage and gets up-to-date.
|
|
37
42
|
*
|
|
@@ -69,8 +74,8 @@ async function waitContainerToCatchUp(container) {
|
|
|
69
74
|
// Waiting for "connected" state in either case gets us at least to our own Join op
|
|
70
75
|
// which is a reasonable approximation of "caught up"
|
|
71
76
|
const waitForOps = () => {
|
|
72
|
-
(0, core_utils_1.assert)(container.connectionState ===
|
|
73
|
-
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!" */);
|
|
74
79
|
const hasCheckpointSequenceNumber = deltaManager.hasCheckpointSequenceNumber;
|
|
75
80
|
const connectionOpSeqNumber = deltaManager.lastKnownSeqNumber;
|
|
76
81
|
(0, core_utils_1.assert)(deltaManager.lastSequenceNumber <= connectionOpSeqNumber, 0x266 /* "lastKnownSeqNumber should never be below last processed sequence number" */);
|
|
@@ -92,7 +97,7 @@ async function waitContainerToCatchUp(container) {
|
|
|
92
97
|
// But that works only if service provides us checkPointSequenceNumber
|
|
93
98
|
// Our internal testing is based on R11S that does not, but almost all tests connect as "write" and
|
|
94
99
|
// use this function to catch up, so leveraging our own join op as a fence/barrier
|
|
95
|
-
if (container.connectionState ===
|
|
100
|
+
if (container.connectionState === connectionState_js_1.ConnectionState.Connected) {
|
|
96
101
|
waitForOps();
|
|
97
102
|
return;
|
|
98
103
|
}
|
|
@@ -101,15 +106,13 @@ async function waitContainerToCatchUp(container) {
|
|
|
101
106
|
waitForOps();
|
|
102
107
|
};
|
|
103
108
|
container.on(telemetry_utils_1.connectedEventName, callback);
|
|
104
|
-
if (container.connectionState ===
|
|
109
|
+
if (container.connectionState === connectionState_js_1.ConnectionState.Disconnected) {
|
|
105
110
|
container.connect();
|
|
106
111
|
}
|
|
107
112
|
});
|
|
108
113
|
}
|
|
109
114
|
exports.waitContainerToCatchUp = waitContainerToCatchUp;
|
|
110
|
-
const getCodeProposal =
|
|
111
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
112
|
-
(quorum) => quorum.get("code") ?? quorum.get("code2");
|
|
115
|
+
const getCodeProposal = (quorum) => quorum.get("code") ?? quorum.get("code2");
|
|
113
116
|
/**
|
|
114
117
|
* Helper function to report to telemetry cases where operation takes longer than expected (200ms)
|
|
115
118
|
* @param logger - logger to use
|
|
@@ -128,7 +131,6 @@ const summarizerClientType = "summarizer";
|
|
|
128
131
|
class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
129
132
|
/**
|
|
130
133
|
* Load an existing container.
|
|
131
|
-
* @internal
|
|
132
134
|
*/
|
|
133
135
|
static async load(loadProps, createProps) {
|
|
134
136
|
const { version, pendingLocalState, loadMode, resolvedUrl, loadToSequenceNumber } = loadProps;
|
|
@@ -185,11 +187,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
185
187
|
static async rehydrateDetachedFromSnapshot(createProps, snapshot) {
|
|
186
188
|
const container = new Container(createProps);
|
|
187
189
|
return telemetry_utils_1.PerformanceEvent.timedExecAsync(container.mc.logger, { eventName: "RehydrateDetachedFromSnapshot" }, async (_event) => {
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
throw new telemetry_utils_1.UsageError("Cannot rehydrate detached container. Incorrect format");
|
|
191
|
-
}
|
|
192
|
-
await container.rehydrateDetachedFromSnapshot(deserializedSummary);
|
|
190
|
+
const detachedContainerState = (0, utils_js_1.getDetachedContainerStateFromSerializedContainer)(snapshot);
|
|
191
|
+
await container.rehydrateDetachedFromSnapshot(detachedContainerState);
|
|
193
192
|
return container;
|
|
194
193
|
}, { start: true, end: true, cancel: "generic" });
|
|
195
194
|
}
|
|
@@ -240,6 +239,9 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
240
239
|
get readOnlyInfo() {
|
|
241
240
|
return this._deltaManager.readOnlyInfo;
|
|
242
241
|
}
|
|
242
|
+
get containerMetadata() {
|
|
243
|
+
return this._containerMetadata;
|
|
244
|
+
}
|
|
243
245
|
/**
|
|
244
246
|
* Sends signal to runtime (and data stores) to be read-only.
|
|
245
247
|
* Hosts may have read only views, indicating to data stores that no edits are allowed.
|
|
@@ -267,7 +269,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
267
269
|
return this.connectionStateHandler.connectionState;
|
|
268
270
|
}
|
|
269
271
|
get connected() {
|
|
270
|
-
return this.connectionStateHandler.connectionState ===
|
|
272
|
+
return this.connectionStateHandler.connectionState === connectionState_js_1.ConnectionState.Connected;
|
|
271
273
|
}
|
|
272
274
|
/**
|
|
273
275
|
* The server provided id of the client.
|
|
@@ -276,11 +278,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
276
278
|
get clientId() {
|
|
277
279
|
return this._clientId;
|
|
278
280
|
}
|
|
279
|
-
get
|
|
280
|
-
|
|
281
|
-
this.options?.enableOfflineLoad === true;
|
|
282
|
-
// summarizer will not have any pending state we want to save
|
|
283
|
-
return enabled && this.deltaManager.clientDetails.capabilities.interactive;
|
|
281
|
+
get isInteractiveClient() {
|
|
282
|
+
return this.deltaManager.clientDetails.capabilities.interactive;
|
|
284
283
|
}
|
|
285
284
|
/**
|
|
286
285
|
* Get the code details that are currently specified for the container.
|
|
@@ -335,9 +334,6 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
335
334
|
this._lifecycleEvents.once("disposed", disposedHandler);
|
|
336
335
|
});
|
|
337
336
|
}
|
|
338
|
-
/**
|
|
339
|
-
* @internal
|
|
340
|
-
*/
|
|
341
337
|
constructor(createProps, loadProps) {
|
|
342
338
|
super((name, error) => {
|
|
343
339
|
this.mc.logger.sendErrorEvent({
|
|
@@ -361,23 +357,101 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
361
357
|
* disposed: Container has been disposed
|
|
362
358
|
*/
|
|
363
359
|
this._lifecycleState = "loading";
|
|
364
|
-
this._attachState = container_definitions_1.AttachState.Detached;
|
|
365
360
|
/** During initialization we pause the inbound queues. We track this state to ensure we only call resume once */
|
|
366
361
|
this.inboundQueuePausedFromInit = true;
|
|
367
362
|
this.firstConnection = true;
|
|
368
363
|
this.connectionTransitionTimes = [];
|
|
369
|
-
this.attachStarted = false;
|
|
370
364
|
this._dirtyContainer = false;
|
|
371
|
-
this.
|
|
365
|
+
this.attachmentData = { state: container_definitions_1.AttachState.Detached };
|
|
372
366
|
this.clientsWhoShouldHaveLeft = new Set();
|
|
367
|
+
this._containerMetadata = {};
|
|
373
368
|
this.setAutoReconnectTime = client_utils_1.performance.now();
|
|
374
369
|
this._lifecycleEvents = new client_utils_1.TypedEventEmitter();
|
|
375
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
|
+
});
|
|
376
446
|
this.getAbsoluteUrl = async (relativeUrl) => {
|
|
377
447
|
if (this.resolvedUrl === undefined) {
|
|
378
448
|
return undefined;
|
|
379
449
|
}
|
|
380
|
-
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);
|
|
381
455
|
};
|
|
382
456
|
this.updateDirtyContainerState = (dirty) => {
|
|
383
457
|
if (this._dirtyContainer === dirty) {
|
|
@@ -387,7 +461,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
387
461
|
this.emit(dirty ? dirtyContainerEvent : savedContainerEvent);
|
|
388
462
|
};
|
|
389
463
|
const { canReconnect, clientDetailsOverride, urlResolver, documentServiceFactory, codeLoader, options, scope, subLogger, detachedBlobStorage, protocolHandlerBuilder, } = createProps;
|
|
390
|
-
this.connectionTransitionTimes[
|
|
464
|
+
this.connectionTransitionTimes[connectionState_js_1.ConnectionState.Disconnected] = client_utils_1.performance.now();
|
|
391
465
|
const pendingLocalState = loadProps?.pendingLocalState;
|
|
392
466
|
this._clientId = pendingLocalState?.clientId;
|
|
393
467
|
this._canReconnect = canReconnect ?? true;
|
|
@@ -403,7 +477,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
403
477
|
this.detachedBlobStorage = detachedBlobStorage;
|
|
404
478
|
this.protocolHandlerBuilder =
|
|
405
479
|
protocolHandlerBuilder ??
|
|
406
|
-
((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)));
|
|
407
481
|
// Note that we capture the createProps here so we can replicate the creation call when we want to clone.
|
|
408
482
|
this.clone = async (_loadProps, createParamOverrides) => {
|
|
409
483
|
return Container.load(_loadProps, {
|
|
@@ -412,7 +486,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
412
486
|
});
|
|
413
487
|
};
|
|
414
488
|
this._containerId = (0, uuid_1.v4)();
|
|
415
|
-
this.client = Container.setupClient(this._containerId,
|
|
489
|
+
this.client = Container.setupClient(this._containerId, options.client, this.clientDetailsOverride);
|
|
416
490
|
// Create logger for data stores to use
|
|
417
491
|
const type = this.client.details.type;
|
|
418
492
|
const interactive = this.client.details.capabilities.interactive;
|
|
@@ -426,9 +500,9 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
426
500
|
clientType,
|
|
427
501
|
containerId: this._containerId,
|
|
428
502
|
docId: () => this.resolvedUrl?.id,
|
|
429
|
-
containerAttachState: () => this.
|
|
503
|
+
containerAttachState: () => this.attachState,
|
|
430
504
|
containerLifecycleState: () => this._lifecycleState,
|
|
431
|
-
containerConnectionState: () =>
|
|
505
|
+
containerConnectionState: () => connectionState_js_1.ConnectionState[this.connectionState],
|
|
432
506
|
serializedContainer: pendingLocalState !== undefined,
|
|
433
507
|
},
|
|
434
508
|
// we need to be judicious with our logging here to avoid generating too much data
|
|
@@ -456,15 +530,15 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
456
530
|
// Prefix all events in this file with container-loader
|
|
457
531
|
this.mc = (0, telemetry_utils_1.createChildMonitoringContext)({ logger: this.subLogger, namespace: "Container" });
|
|
458
532
|
this._deltaManager = this.createDeltaManager();
|
|
459
|
-
this.connectionStateHandler = (0,
|
|
533
|
+
this.connectionStateHandler = (0, connectionStateHandler_js_1.createConnectionStateHandler)({
|
|
460
534
|
logger: this.mc.logger,
|
|
461
535
|
connectionStateChanged: (value, oldState, reason) => {
|
|
462
|
-
if (value ===
|
|
536
|
+
if (value === connectionState_js_1.ConnectionState.Connected) {
|
|
463
537
|
this._clientId = this.connectionStateHandler.pendingClientId;
|
|
464
538
|
}
|
|
465
539
|
this.logConnectionStateChangeTelemetry(value, oldState, reason);
|
|
466
540
|
if (this._lifecycleState === "loaded") {
|
|
467
|
-
this.propagateConnectionState(false /* initial transition */, value ===
|
|
541
|
+
this.propagateConnectionState(false /* initial transition */, value === connectionState_js_1.ConnectionState.Disconnected
|
|
468
542
|
? reason
|
|
469
543
|
: undefined /* disconnectedReason */);
|
|
470
544
|
}
|
|
@@ -483,7 +557,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
483
557
|
mode,
|
|
484
558
|
category: this._lifecycleState === "loading" ? "generic" : category,
|
|
485
559
|
duration: client_utils_1.performance.now() -
|
|
486
|
-
this.connectionTransitionTimes[
|
|
560
|
+
this.connectionTransitionTimes[connectionState_js_1.ConnectionState.CatchingUp],
|
|
487
561
|
...(details === undefined ? {} : { details: JSON.stringify(details) }),
|
|
488
562
|
});
|
|
489
563
|
// If this is "write" connection, it took too long to receive join op. But in most cases that's due
|
|
@@ -512,12 +586,16 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
512
586
|
// using this callback and fix them up.
|
|
513
587
|
const addProtocolSummaryIfMissing = (summaryTree) => (0, driver_utils_1.isCombinedAppAndProtocolSummary)(summaryTree) === true
|
|
514
588
|
? summaryTree
|
|
515
|
-
: (0,
|
|
589
|
+
: (0, utils_js_1.combineAppAndProtocolSummary)(summaryTree, this.captureProtocolSummary());
|
|
516
590
|
// Whether the combined summary tree has been forced on by either the loader option or the monitoring context.
|
|
517
591
|
// Even if not forced on via this flag, combined summaries may still be enabled by service policy.
|
|
518
592
|
const forceEnableSummarizeProtocolTree = this.mc.config.getBoolean("Fluid.Container.summarizeProtocolTree2") ??
|
|
519
593
|
options.summarizeProtocolTree;
|
|
520
|
-
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);
|
|
521
599
|
const isDomAvailable = typeof document === "object" &&
|
|
522
600
|
document !== null &&
|
|
523
601
|
typeof document.addEventListener === "function" &&
|
|
@@ -558,7 +636,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
558
636
|
this.verifyClosed();
|
|
559
637
|
}
|
|
560
638
|
verifyClosed() {
|
|
561
|
-
(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!" */);
|
|
562
640
|
(0, core_utils_1.assert)(this._lifecycleState === "closed" || this._lifecycleState === "disposed", 0x314 /* Container properly closed */);
|
|
563
641
|
}
|
|
564
642
|
closeCore(error) {
|
|
@@ -577,6 +655,10 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
577
655
|
: "generic",
|
|
578
656
|
}, error);
|
|
579
657
|
this._lifecycleState = "closing";
|
|
658
|
+
// Back-compat for Old driver
|
|
659
|
+
if (this.service?.off !== undefined) {
|
|
660
|
+
this.service?.off("metadataUpdate", this.metadataUpdateHandler);
|
|
661
|
+
}
|
|
580
662
|
this._protocolHandler?.close();
|
|
581
663
|
this.connectionStateHandler.dispose();
|
|
582
664
|
}
|
|
@@ -652,149 +734,35 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
652
734
|
return this.getPendingLocalStateCore({ notifyImminentClosure: false });
|
|
653
735
|
}
|
|
654
736
|
async getPendingLocalStateCore(props) {
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
throw new telemetry_utils_1.UsageError("Can't get pending local state unless offline load is enabled");
|
|
663
|
-
}
|
|
664
|
-
if (this.closed || this._disposed) {
|
|
665
|
-
throw new telemetry_utils_1.UsageError("Pending state cannot be retried if the container is closed or disposed");
|
|
666
|
-
}
|
|
667
|
-
(0, core_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attached, 0x0d1 /* "Container should be attached before close" */);
|
|
668
|
-
(0, core_utils_1.assert)(this.resolvedUrl !== undefined && this.resolvedUrl.type === "fluid", 0x0d2 /* "resolved url should be valid Fluid url" */);
|
|
669
|
-
(0, core_utils_1.assert)(!!this.baseSnapshot, 0x5d4 /* no base snapshot */);
|
|
670
|
-
(0, core_utils_1.assert)(!!this.baseSnapshotBlobs, 0x5d5 /* no snapshot blobs */);
|
|
671
|
-
const pendingRuntimeState = await this.runtime.getPendingLocalState(props);
|
|
672
|
-
const pendingState = {
|
|
673
|
-
pendingRuntimeState,
|
|
674
|
-
baseSnapshot: this.baseSnapshot,
|
|
675
|
-
snapshotBlobs: this.baseSnapshotBlobs,
|
|
676
|
-
savedOps: this.savedOps,
|
|
677
|
-
url: this.resolvedUrl.url,
|
|
678
|
-
// no need to save this if there is no pending runtime state
|
|
679
|
-
clientId: pendingRuntimeState !== undefined ? this.clientId : undefined,
|
|
680
|
-
};
|
|
681
|
-
return JSON.stringify(pendingState);
|
|
682
|
-
});
|
|
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;
|
|
683
744
|
}
|
|
684
745
|
get attachState() {
|
|
685
|
-
return this.
|
|
746
|
+
return this.attachmentData.state;
|
|
686
747
|
}
|
|
687
748
|
serialize() {
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
const protocolSummary = this.captureProtocolSummary();
|
|
691
|
-
const combinedSummary = (0, utils_1.combineAppAndProtocolSummary)(appSummary, protocolSummary);
|
|
692
|
-
if (this.detachedBlobStorage && this.detachedBlobStorage.size > 0) {
|
|
693
|
-
combinedSummary.tree[hasBlobsSummaryTree] = {
|
|
694
|
-
type: protocol_definitions_1.SummaryType.Blob,
|
|
695
|
-
content: "true",
|
|
696
|
-
};
|
|
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.");
|
|
697
751
|
}
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
(0, core_utils_1.assert)(this.deltaManager.inbound.length === 0, 0x0d6 /* "Inbound queue should be empty when attaching" */);
|
|
713
|
-
let summary;
|
|
714
|
-
if (!hasAttachmentBlobs) {
|
|
715
|
-
// Get the document state post attach - possibly can just call attach but we need to change the
|
|
716
|
-
// semantics around what the attach means as far as async code goes.
|
|
717
|
-
const appSummary = this.runtime.createSummary();
|
|
718
|
-
const protocolSummary = this.captureProtocolSummary();
|
|
719
|
-
summary = (0, utils_1.combineAppAndProtocolSummary)(appSummary, protocolSummary);
|
|
720
|
-
// Set the state as attaching as we are starting the process of attaching container.
|
|
721
|
-
// This should be fired after taking the summary because it is the place where we are
|
|
722
|
-
// starting to attach the container to storage.
|
|
723
|
-
// Also, this should only be fired in detached container.
|
|
724
|
-
this._attachState = container_definitions_1.AttachState.Attaching;
|
|
725
|
-
this.runtime.setAttachState(container_definitions_1.AttachState.Attaching);
|
|
726
|
-
this.emit("attaching");
|
|
727
|
-
if (this.offlineLoadEnabled) {
|
|
728
|
-
const snapshot = (0, utils_1.getSnapshotTreeFromSerializedContainer)(summary);
|
|
729
|
-
this.baseSnapshot = snapshot;
|
|
730
|
-
this.baseSnapshotBlobs =
|
|
731
|
-
(0, containerStorageAdapter_1.getBlobContentsFromTreeWithBlobContents)(snapshot);
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
// Actually go and create the resolved document
|
|
735
|
-
if (this.service === undefined) {
|
|
736
|
-
const createNewResolvedUrl = await this.urlResolver.resolve(request);
|
|
737
|
-
(0, core_utils_1.assert)(this.client.details.type !== summarizerClientType &&
|
|
738
|
-
createNewResolvedUrl !== undefined, 0x2c4 /* "client should not be summarizer before container is created" */);
|
|
739
|
-
this.service = await (0, driver_utils_1.runWithRetry)(async () => this.serviceFactory.createContainer(summary, createNewResolvedUrl, this.subLogger, false), "containerAttach", this.mc.logger, {
|
|
740
|
-
cancel: this._deltaManager.closeAbortController.signal,
|
|
741
|
-
});
|
|
742
|
-
}
|
|
743
|
-
this.storageAdapter.connectToService(this.service);
|
|
744
|
-
if (hasAttachmentBlobs) {
|
|
745
|
-
// upload blobs to storage
|
|
746
|
-
(0, core_utils_1.assert)(!!this.detachedBlobStorage, 0x24e /* "assertion for type narrowing" */);
|
|
747
|
-
// build a table mapping IDs assigned locally to IDs assigned by storage and pass it to runtime to
|
|
748
|
-
// support blob handles that only know about the local IDs
|
|
749
|
-
const redirectTable = new Map();
|
|
750
|
-
// if new blobs are added while uploading, upload them too
|
|
751
|
-
while (redirectTable.size < this.detachedBlobStorage.size) {
|
|
752
|
-
const newIds = this.detachedBlobStorage
|
|
753
|
-
.getBlobIds()
|
|
754
|
-
.filter((id) => !redirectTable.has(id));
|
|
755
|
-
for (const id of newIds) {
|
|
756
|
-
const blob = await this.detachedBlobStorage.readBlob(id);
|
|
757
|
-
const response = await this.storageAdapter.createBlob(blob);
|
|
758
|
-
redirectTable.set(id, response.id);
|
|
759
|
-
}
|
|
760
|
-
}
|
|
761
|
-
// take summary and upload
|
|
762
|
-
const appSummary = this.runtime.createSummary(redirectTable);
|
|
763
|
-
const protocolSummary = this.captureProtocolSummary();
|
|
764
|
-
summary = (0, utils_1.combineAppAndProtocolSummary)(appSummary, protocolSummary);
|
|
765
|
-
this._attachState = container_definitions_1.AttachState.Attaching;
|
|
766
|
-
this.runtime.setAttachState(container_definitions_1.AttachState.Attaching);
|
|
767
|
-
this.emit("attaching");
|
|
768
|
-
if (this.offlineLoadEnabled) {
|
|
769
|
-
const snapshot = (0, utils_1.getSnapshotTreeFromSerializedContainer)(summary);
|
|
770
|
-
this.baseSnapshot = snapshot;
|
|
771
|
-
this.baseSnapshotBlobs =
|
|
772
|
-
(0, containerStorageAdapter_1.getBlobContentsFromTreeWithBlobContents)(snapshot);
|
|
773
|
-
}
|
|
774
|
-
await this.storageAdapter.uploadSummaryWithContext(summary, {
|
|
775
|
-
referenceSequenceNumber: 0,
|
|
776
|
-
ackHandle: undefined,
|
|
777
|
-
proposalHandle: undefined,
|
|
778
|
-
});
|
|
779
|
-
}
|
|
780
|
-
this._attachState = container_definitions_1.AttachState.Attached;
|
|
781
|
-
this.runtime.setAttachState(container_definitions_1.AttachState.Attached);
|
|
782
|
-
this.emit("attached");
|
|
783
|
-
if (!this.closed) {
|
|
784
|
-
this.handleDeltaConnectionArg({
|
|
785
|
-
fetchOpsFromStorage: false,
|
|
786
|
-
reason: { text: "createDetached" },
|
|
787
|
-
}, attachProps?.deltaConnection);
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
catch (error) {
|
|
791
|
-
// add resolved URL on error object so that host has the ability to find this document and delete it
|
|
792
|
-
const newError = (0, telemetry_utils_1.normalizeError)(error);
|
|
793
|
-
newError.addTelemetryProperties({ resolvedUrl: this.resolvedUrl?.url });
|
|
794
|
-
this.close(newError);
|
|
795
|
-
throw newError;
|
|
796
|
-
}
|
|
797
|
-
}, { 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);
|
|
798
766
|
}
|
|
799
767
|
setAutoReconnectInternal(mode, reason) {
|
|
800
768
|
const currentMode = this._deltaManager.connectionManager.reconnectMode;
|
|
@@ -805,9 +773,9 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
805
773
|
const duration = now - this.setAutoReconnectTime;
|
|
806
774
|
this.setAutoReconnectTime = now;
|
|
807
775
|
this.mc.logger.sendTelemetryEvent({
|
|
808
|
-
eventName: mode ===
|
|
776
|
+
eventName: mode === contracts_js_1.ReconnectMode.Enabled ? "AutoReconnectEnabled" : "AutoReconnectDisabled",
|
|
809
777
|
connectionMode: this.connectionMode,
|
|
810
|
-
connectionState:
|
|
778
|
+
connectionState: connectionState_js_1.ConnectionState[this.connectionState],
|
|
811
779
|
duration,
|
|
812
780
|
});
|
|
813
781
|
this._deltaManager.connectionManager.setAutoReconnect(mode, reason);
|
|
@@ -816,7 +784,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
816
784
|
if (this.closed) {
|
|
817
785
|
throw new telemetry_utils_1.UsageError(`The Container is closed and cannot be connected`);
|
|
818
786
|
}
|
|
819
|
-
else if (this.
|
|
787
|
+
else if (this.attachState !== container_definitions_1.AttachState.Attached) {
|
|
820
788
|
throw new telemetry_utils_1.UsageError(`The Container is not attached and cannot be connected`);
|
|
821
789
|
}
|
|
822
790
|
else if (!this.connected) {
|
|
@@ -831,11 +799,11 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
831
799
|
}
|
|
832
800
|
connectInternal(args) {
|
|
833
801
|
(0, core_utils_1.assert)(!this.closed, 0x2c5 /* "Attempting to connect() a closed Container" */);
|
|
834
|
-
(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" */);
|
|
835
803
|
// Resume processing ops and connect to delta stream
|
|
836
804
|
this.resumeInternal(args);
|
|
837
805
|
// Set Auto Reconnect Mode
|
|
838
|
-
const mode =
|
|
806
|
+
const mode = contracts_js_1.ReconnectMode.Enabled;
|
|
839
807
|
this.setAutoReconnectInternal(mode, args.reason);
|
|
840
808
|
}
|
|
841
809
|
disconnect() {
|
|
@@ -849,7 +817,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
849
817
|
disconnectInternal(reason) {
|
|
850
818
|
(0, core_utils_1.assert)(!this.closed, 0x2c7 /* "Attempting to disconnect() a closed Container" */);
|
|
851
819
|
// Set Auto Reconnect Mode
|
|
852
|
-
const mode =
|
|
820
|
+
const mode = contracts_js_1.ReconnectMode.Disabled;
|
|
853
821
|
this.setAutoReconnectInternal(mode, reason);
|
|
854
822
|
}
|
|
855
823
|
resumeInternal(args) {
|
|
@@ -924,10 +892,6 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
924
892
|
}
|
|
925
893
|
return true;
|
|
926
894
|
}
|
|
927
|
-
async getVersion(version) {
|
|
928
|
-
const versions = await this.storageAdapter.getVersions(version, 1);
|
|
929
|
-
return versions[0];
|
|
930
|
-
}
|
|
931
895
|
connectToDeltaStream(args) {
|
|
932
896
|
// All agents need "write" access, including summarizer.
|
|
933
897
|
if (!this._canReconnect || !this.client.details.capabilities.interactive) {
|
|
@@ -935,6 +899,14 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
935
899
|
}
|
|
936
900
|
this._deltaManager.connect(args);
|
|
937
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
|
+
}
|
|
938
910
|
/**
|
|
939
911
|
* Load container.
|
|
940
912
|
*
|
|
@@ -942,7 +914,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
942
914
|
*/
|
|
943
915
|
async load(specifiedVersion, loadMode, resolvedUrl, pendingLocalState, loadToSequenceNumber) {
|
|
944
916
|
const timings = { phase1: client_utils_1.performance.now() };
|
|
945
|
-
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));
|
|
946
918
|
// Except in cases where it has stashed ops or requested by feature gate, the container will connect in "read" mode
|
|
947
919
|
const mode = this.mc.config.getBoolean("Fluid.Container.ForceWriteConnection") === true ||
|
|
948
920
|
(pendingLocalState?.savedOps.length ?? 0) > 0
|
|
@@ -959,25 +931,14 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
959
931
|
this.connectToDeltaStream(connectionArgs);
|
|
960
932
|
}
|
|
961
933
|
this.storageAdapter.connectToService(this.service);
|
|
962
|
-
this.
|
|
934
|
+
this.attachmentData = {
|
|
935
|
+
state: container_definitions_1.AttachState.Attached,
|
|
936
|
+
};
|
|
963
937
|
timings.phase2 = client_utils_1.performance.now();
|
|
964
938
|
// Fetch specified snapshot.
|
|
965
|
-
const {
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
if (pendingLocalState) {
|
|
969
|
-
this.baseSnapshot = pendingLocalState.baseSnapshot;
|
|
970
|
-
this.baseSnapshotBlobs = pendingLocalState.snapshotBlobs;
|
|
971
|
-
}
|
|
972
|
-
else {
|
|
973
|
-
(0, core_utils_1.assert)(snapshot !== undefined, 0x237 /* "Snapshot should exist" */);
|
|
974
|
-
if (this.offlineLoadEnabled) {
|
|
975
|
-
this.baseSnapshot = snapshot;
|
|
976
|
-
// Save contents of snapshot now, otherwise closeAndGetPendingLocalState() must be async
|
|
977
|
-
this.baseSnapshotBlobs = await (0, containerStorageAdapter_1.getBlobContentsFromTree)(snapshot, this.storageAdapter);
|
|
978
|
-
}
|
|
979
|
-
}
|
|
980
|
-
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);
|
|
981
942
|
// If we saved ops, we will replay them and don't need DeltaManager to fetch them
|
|
982
943
|
const sequenceNumber = pendingLocalState?.savedOps[pendingLocalState.savedOps.length - 1]?.sequenceNumber;
|
|
983
944
|
const dmAttributes = sequenceNumber !== undefined ? { ...attributes, sequenceNumber } : attributes;
|
|
@@ -1042,12 +1003,12 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1042
1003
|
}
|
|
1043
1004
|
// ...load in the existing quorum
|
|
1044
1005
|
// Initialize the protocol handler
|
|
1045
|
-
await this.initializeProtocolStateFromSnapshot(attributes, this.storageAdapter,
|
|
1006
|
+
await this.initializeProtocolStateFromSnapshot(attributes, this.storageAdapter, snapshotTree);
|
|
1046
1007
|
timings.phase3 = client_utils_1.performance.now();
|
|
1047
1008
|
const codeDetails = this.getCodeDetailsFromQuorum();
|
|
1048
|
-
await this.instantiateRuntime(codeDetails,
|
|
1009
|
+
await this.instantiateRuntime(codeDetails, snapshotTree,
|
|
1049
1010
|
// give runtime a dummy value so it knows we're loading from a stash blob
|
|
1050
|
-
pendingLocalState ? pendingLocalState?.pendingRuntimeState ?? {} : undefined);
|
|
1011
|
+
pendingLocalState ? pendingLocalState?.pendingRuntimeState ?? {} : undefined, (0, driver_utils_1.isInstanceOfISnapshot)(snapshotTree) ? snapshotTree : undefined);
|
|
1051
1012
|
// replay saved ops
|
|
1052
1013
|
if (pendingLocalState) {
|
|
1053
1014
|
for (const message of pendingLocalState.savedOps) {
|
|
@@ -1102,7 +1063,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1102
1063
|
}, undefined, core_interfaces_1.LogLevel.verbose);
|
|
1103
1064
|
return {
|
|
1104
1065
|
sequenceNumber: attributes.sequenceNumber,
|
|
1105
|
-
version:
|
|
1066
|
+
version: version?.id,
|
|
1106
1067
|
dmLastProcessedSeqNumber: this._deltaManager.lastSequenceNumber,
|
|
1107
1068
|
dmLastKnownSeqNumber: this._deltaManager.lastKnownSeqNumber,
|
|
1108
1069
|
};
|
|
@@ -1114,7 +1075,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1114
1075
|
};
|
|
1115
1076
|
await this.attachDeltaManagerOpHandler(attributes);
|
|
1116
1077
|
// Need to just seed the source data in the code quorum. Quorum itself is empty
|
|
1117
|
-
const qValues = (0,
|
|
1078
|
+
const qValues = (0, quorum_js_1.initQuorumValuesFromCodeDetails)(codeDetails);
|
|
1118
1079
|
this.initializeProtocolState(attributes, {
|
|
1119
1080
|
members: [],
|
|
1120
1081
|
proposals: [],
|
|
@@ -1123,18 +1084,16 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1123
1084
|
await this.instantiateRuntime(codeDetails, undefined);
|
|
1124
1085
|
this.setLoaded();
|
|
1125
1086
|
}
|
|
1126
|
-
async rehydrateDetachedFromSnapshot(
|
|
1127
|
-
if (
|
|
1087
|
+
async rehydrateDetachedFromSnapshot({ baseSnapshot, snapshotBlobs, hasAttachmentBlobs, pendingRuntimeState, }) {
|
|
1088
|
+
if (hasAttachmentBlobs) {
|
|
1128
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" */);
|
|
1129
|
-
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
|
1130
|
-
delete detachedContainerSnapshot.tree[hasBlobsSummaryTree];
|
|
1131
1090
|
}
|
|
1132
|
-
const
|
|
1133
|
-
this.storageAdapter.
|
|
1134
|
-
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);
|
|
1135
1094
|
await this.attachDeltaManagerOpHandler(attributes);
|
|
1136
1095
|
// Initialize the protocol handler
|
|
1137
|
-
const baseTree = (0,
|
|
1096
|
+
const baseTree = (0, utils_js_1.getProtocolSnapshotTree)(snapshotTreeWithBlobContents);
|
|
1138
1097
|
const qValues = await (0, driver_utils_1.readAndParse)(this.storageAdapter, baseTree.blobs.quorumValues);
|
|
1139
1098
|
this.initializeProtocolState(attributes, {
|
|
1140
1099
|
members: [],
|
|
@@ -1142,7 +1101,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1142
1101
|
values: qValues,
|
|
1143
1102
|
});
|
|
1144
1103
|
const codeDetails = this.getCodeDetailsFromQuorum();
|
|
1145
|
-
await this.instantiateRuntime(codeDetails,
|
|
1104
|
+
await this.instantiateRuntime(codeDetails, snapshotTreeWithBlobContents, pendingRuntimeState);
|
|
1146
1105
|
this.setLoaded();
|
|
1147
1106
|
}
|
|
1148
1107
|
async getDocumentAttributes(storage, tree) {
|
|
@@ -1166,7 +1125,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1166
1125
|
values: [],
|
|
1167
1126
|
};
|
|
1168
1127
|
if (snapshot !== undefined) {
|
|
1169
|
-
const baseTree = (0,
|
|
1128
|
+
const baseTree = (0, utils_js_1.getProtocolSnapshotTree)(snapshot);
|
|
1170
1129
|
[quorumSnapshot.members, quorumSnapshot.proposals, quorumSnapshot.values] =
|
|
1171
1130
|
await Promise.all([
|
|
1172
1131
|
(0, driver_utils_1.readAndParse)(storage, baseTree.blobs.quorumMembers),
|
|
@@ -1242,10 +1201,9 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1242
1201
|
const pkg = getCodeProposal(quorum);
|
|
1243
1202
|
return pkg;
|
|
1244
1203
|
}
|
|
1245
|
-
static setupClient(containerId,
|
|
1246
|
-
const loaderOptionsClient = structuredClone(options?.client);
|
|
1204
|
+
static setupClient(containerId, loaderOptionsClient, clientDetailsOverride) {
|
|
1247
1205
|
const client = loaderOptionsClient !== undefined
|
|
1248
|
-
? loaderOptionsClient
|
|
1206
|
+
? (0, structured_clone_1.default)(loaderOptionsClient)
|
|
1249
1207
|
: {
|
|
1250
1208
|
details: {
|
|
1251
1209
|
capabilities: { interactive: true },
|
|
@@ -1267,7 +1225,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1267
1225
|
}
|
|
1268
1226
|
client.details.environment = [
|
|
1269
1227
|
client.details.environment,
|
|
1270
|
-
` loaderVersion:${
|
|
1228
|
+
` loaderVersion:${packageVersion_js_1.pkgVersion}`,
|
|
1271
1229
|
` containerId:${containerId}`,
|
|
1272
1230
|
].join(";");
|
|
1273
1231
|
return client;
|
|
@@ -1279,11 +1237,11 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1279
1237
|
* If it's not true, runtime is not in position to send ops.
|
|
1280
1238
|
*/
|
|
1281
1239
|
activeConnection() {
|
|
1282
|
-
return (this.connectionState ===
|
|
1240
|
+
return (this.connectionState === connectionState_js_1.ConnectionState.Connected && this.connectionMode === "write");
|
|
1283
1241
|
}
|
|
1284
1242
|
createDeltaManager() {
|
|
1285
1243
|
const serviceProvider = () => this.service;
|
|
1286
|
-
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));
|
|
1287
1245
|
// Disable inbound queues as Container is not ready to accept any ops until we are fully loaded!
|
|
1288
1246
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
1289
1247
|
deltaManager.inbound.pause();
|
|
@@ -1299,10 +1257,10 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1299
1257
|
deltaManager.on("cancelEstablishingConnection", (reason) => {
|
|
1300
1258
|
this.connectionStateHandler.cancelEstablishingConnection(reason);
|
|
1301
1259
|
});
|
|
1302
|
-
deltaManager.on("disconnect", (
|
|
1260
|
+
deltaManager.on("disconnect", (text, error) => {
|
|
1303
1261
|
this.noopHeuristic?.notifyDisconnect();
|
|
1304
1262
|
if (!this.closed) {
|
|
1305
|
-
this.connectionStateHandler.receivedDisconnectEvent(
|
|
1263
|
+
this.connectionStateHandler.receivedDisconnectEvent({ text, error });
|
|
1306
1264
|
}
|
|
1307
1265
|
});
|
|
1308
1266
|
deltaManager.on("throttled", (warning) => {
|
|
@@ -1315,7 +1273,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1315
1273
|
this.emit("warning", warn);
|
|
1316
1274
|
});
|
|
1317
1275
|
deltaManager.on("readonly", (readonly) => {
|
|
1318
|
-
this.setContextConnectedState(this.connectionState ===
|
|
1276
|
+
this.setContextConnectedState(this.connectionState === connectionState_js_1.ConnectionState.Connected, readonly);
|
|
1319
1277
|
this.emit("readonly", readonly);
|
|
1320
1278
|
});
|
|
1321
1279
|
deltaManager.on("closed", (error) => {
|
|
@@ -1344,16 +1302,16 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1344
1302
|
let autoReconnect;
|
|
1345
1303
|
let checkpointSequenceNumber;
|
|
1346
1304
|
let opsBehind;
|
|
1347
|
-
if (value ===
|
|
1305
|
+
if (value === connectionState_js_1.ConnectionState.Disconnected) {
|
|
1348
1306
|
autoReconnect = this._deltaManager.connectionManager.reconnectMode;
|
|
1349
1307
|
}
|
|
1350
1308
|
else {
|
|
1351
|
-
if (value ===
|
|
1309
|
+
if (value === connectionState_js_1.ConnectionState.Connected) {
|
|
1352
1310
|
durationFromDisconnected =
|
|
1353
|
-
time - this.connectionTransitionTimes[
|
|
1311
|
+
time - this.connectionTransitionTimes[connectionState_js_1.ConnectionState.Disconnected];
|
|
1354
1312
|
durationFromDisconnected = (0, telemetry_utils_1.formatTick)(durationFromDisconnected);
|
|
1355
1313
|
}
|
|
1356
|
-
else if (value ===
|
|
1314
|
+
else if (value === connectionState_js_1.ConnectionState.CatchingUp) {
|
|
1357
1315
|
// This info is of most interesting while Catching Up.
|
|
1358
1316
|
checkpointSequenceNumber = this.deltaManager.lastKnownSeqNumber;
|
|
1359
1317
|
// Need to check that we have already loaded and fetched the snapshot.
|
|
@@ -1365,8 +1323,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1365
1323
|
connectionInitiationReason = this.firstConnection ? "InitialConnect" : "AutoReconnect";
|
|
1366
1324
|
}
|
|
1367
1325
|
this.mc.logger.sendPerformanceEvent({
|
|
1368
|
-
eventName: `ConnectionStateChange_${
|
|
1369
|
-
from:
|
|
1326
|
+
eventName: `ConnectionStateChange_${connectionState_js_1.ConnectionState[value]}`,
|
|
1327
|
+
from: connectionState_js_1.ConnectionState[oldState],
|
|
1370
1328
|
duration,
|
|
1371
1329
|
durationFromDisconnected,
|
|
1372
1330
|
reason: reason?.text,
|
|
@@ -1384,7 +1342,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1384
1342
|
isDirty: this.isDirty,
|
|
1385
1343
|
...this._deltaManager.connectionProps,
|
|
1386
1344
|
}, reason?.error);
|
|
1387
|
-
if (value ===
|
|
1345
|
+
if (value === connectionState_js_1.ConnectionState.Connected) {
|
|
1388
1346
|
this.firstConnection = false;
|
|
1389
1347
|
}
|
|
1390
1348
|
}
|
|
@@ -1393,11 +1351,11 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1393
1351
|
// After that, we communicate only transitions to Connected & Disconnected states, skipping all other states.
|
|
1394
1352
|
// This can be changed in the future, for example we likely should add "CatchingUp" event on Container.
|
|
1395
1353
|
if (!initialTransition &&
|
|
1396
|
-
this.connectionState !==
|
|
1397
|
-
this.connectionState !==
|
|
1354
|
+
this.connectionState !== connectionState_js_1.ConnectionState.Connected &&
|
|
1355
|
+
this.connectionState !== connectionState_js_1.ConnectionState.Disconnected) {
|
|
1398
1356
|
return;
|
|
1399
1357
|
}
|
|
1400
|
-
const state = this.connectionState ===
|
|
1358
|
+
const state = this.connectionState === connectionState_js_1.ConnectionState.Connected;
|
|
1401
1359
|
// Both protocol and context should not be undefined if we got so far.
|
|
1402
1360
|
this.setContextConnectedState(state, this.readOnlyInfo.readonly ?? false);
|
|
1403
1361
|
this.protocolHandler.setConnectionState(state, this.clientId);
|
|
@@ -1439,7 +1397,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1439
1397
|
return this.submitMessage(protocol_definitions_1.MessageType.Summarize, JSON.stringify(summary), false /* batch */, undefined /* metadata */, undefined /* compression */, referenceSequenceNumber);
|
|
1440
1398
|
}
|
|
1441
1399
|
submitMessage(type, contents, batch, metadata, compression, referenceSequenceNumber) {
|
|
1442
|
-
if (this.connectionState !==
|
|
1400
|
+
if (this.connectionState !== connectionState_js_1.ConnectionState.Connected) {
|
|
1443
1401
|
this.mc.logger.sendErrorEvent({ eventName: "SubmitMessageWithNoConnection", type });
|
|
1444
1402
|
return -1;
|
|
1445
1403
|
}
|
|
@@ -1447,14 +1405,12 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1447
1405
|
return this._deltaManager.submit(type, contents, batch, metadata, compression, referenceSequenceNumber);
|
|
1448
1406
|
}
|
|
1449
1407
|
processRemoteMessage(message) {
|
|
1450
|
-
if (this.offlineLoadEnabled) {
|
|
1451
|
-
this.savedOps.push(message);
|
|
1452
|
-
}
|
|
1453
1408
|
const local = this.clientId === message.clientId;
|
|
1454
1409
|
// Allow the protocol handler to process the message
|
|
1455
1410
|
const result = this.protocolHandler.processMessage(message, local);
|
|
1456
1411
|
// Forward messages to the loaded runtime for processing
|
|
1457
1412
|
this.runtime.process(message, local);
|
|
1413
|
+
this.serializedStateManager.addProcessedOp(message);
|
|
1458
1414
|
// Inactive (not in quorum or not writers) clients don't take part in the minimum sequence number calculation.
|
|
1459
1415
|
if (this.activeConnection()) {
|
|
1460
1416
|
if (this.noopHeuristic === undefined) {
|
|
@@ -1464,7 +1420,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1464
1420
|
// clients.
|
|
1465
1421
|
// All existing will continue to use settings they got earlier.
|
|
1466
1422
|
(0, core_utils_1.assert)(serviceConfiguration !== undefined, 0x2e4 /* "there should be service config for active connection" */);
|
|
1467
|
-
this.noopHeuristic = new
|
|
1423
|
+
this.noopHeuristic = new noopHeuristic_js_1.NoopHeuristic(serviceConfiguration.noopTimeFrequency, serviceConfiguration.noopCountFrequency);
|
|
1468
1424
|
this.noopHeuristic.on("wantsNoop", () => {
|
|
1469
1425
|
// On disconnect we notify the heuristic which should prevent it from wanting a noop.
|
|
1470
1426
|
// Hitting this assert would imply we lost activeConnection between notifying the heuristic of a processed message and
|
|
@@ -1487,7 +1443,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1487
1443
|
}
|
|
1488
1444
|
processSignal(message) {
|
|
1489
1445
|
// No clientId indicates a system signal message.
|
|
1490
|
-
if ((0,
|
|
1446
|
+
if ((0, protocol_js_1.protocolHandlerShouldProcessSignal)(message)) {
|
|
1491
1447
|
this.protocolHandler.processSignal(message);
|
|
1492
1448
|
}
|
|
1493
1449
|
else {
|
|
@@ -1495,33 +1451,12 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1495
1451
|
this.runtime.processSignal(message, local);
|
|
1496
1452
|
}
|
|
1497
1453
|
}
|
|
1498
|
-
|
|
1499
|
-
* Get the most recent snapshot, or a specific version.
|
|
1500
|
-
* @param specifiedVersion - The specific version of the snapshot to retrieve
|
|
1501
|
-
* @returns The snapshot requested, or the latest snapshot if no version was specified, plus version ID
|
|
1502
|
-
*/
|
|
1503
|
-
async fetchSnapshotTree(specifiedVersion) {
|
|
1504
|
-
const version = await this.getVersion(specifiedVersion ?? null);
|
|
1505
|
-
if (version === undefined && specifiedVersion !== undefined) {
|
|
1506
|
-
// We should have a defined version to load from if specified version requested
|
|
1507
|
-
this.mc.logger.sendErrorEvent({
|
|
1508
|
-
eventName: "NoVersionFoundWhenSpecified",
|
|
1509
|
-
id: specifiedVersion,
|
|
1510
|
-
});
|
|
1511
|
-
}
|
|
1512
|
-
this._loadedFromVersion = version;
|
|
1513
|
-
const snapshot = (await this.storageAdapter.getSnapshotTree(version)) ?? undefined;
|
|
1514
|
-
if (snapshot === undefined && version !== undefined) {
|
|
1515
|
-
this.mc.logger.sendErrorEvent({ eventName: "getSnapshotTreeFailed", id: version.id });
|
|
1516
|
-
}
|
|
1517
|
-
return { snapshot, versionId: version?.id };
|
|
1518
|
-
}
|
|
1519
|
-
async instantiateRuntime(codeDetails, snapshot, pendingLocalState) {
|
|
1454
|
+
async instantiateRuntime(codeDetails, snapshotTree, pendingLocalState, snapshot) {
|
|
1520
1455
|
(0, core_utils_1.assert)(this._runtime?.disposed !== false, 0x0dd /* "Existing runtime not disposed" */);
|
|
1521
1456
|
// The relative loader will proxy requests to '/' to the loader itself assuming no non-cache flags
|
|
1522
1457
|
// are set. Global requests will still go directly to the loader
|
|
1523
1458
|
const maybeLoader = this.scope;
|
|
1524
|
-
const loader = new
|
|
1459
|
+
const loader = new loader_js_1.RelativeLoader(this, maybeLoader.ILoader);
|
|
1525
1460
|
const loadCodeResult = await telemetry_utils_1.PerformanceEvent.timedExecAsync(this.subLogger, { eventName: "CodeLoad" }, async () => this.codeLoader.load(codeDetails));
|
|
1526
1461
|
this._loadedModule = {
|
|
1527
1462
|
module: loadCodeResult.module,
|
|
@@ -1537,8 +1472,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1537
1472
|
}
|
|
1538
1473
|
const getSpecifiedCodeDetails = () => (this.protocolHandler.quorum.get("code") ??
|
|
1539
1474
|
this.protocolHandler.quorum.get("code2"));
|
|
1540
|
-
const existing =
|
|
1541
|
-
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);
|
|
1542
1477
|
this._runtime = await telemetry_utils_1.PerformanceEvent.timedExecAsync(this.subLogger, { eventName: "InstantiateRuntime" }, async () => runtimeFactory.instantiateRuntime(context, existing));
|
|
1543
1478
|
this._lifecycleEvents.emit("runtimeInstantiated");
|
|
1544
1479
|
this._loadedCodeDetails = codeDetails;
|