@fluidframework/container-loader 2.0.0-internal.1.1.2 → 2.0.0-internal.1.2.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/dist/catchUpMonitor.d.ts +6 -17
- package/dist/catchUpMonitor.d.ts.map +1 -1
- package/dist/catchUpMonitor.js +5 -36
- package/dist/catchUpMonitor.js.map +1 -1
- package/dist/collabWindowTracker.d.ts +1 -1
- package/dist/collabWindowTracker.d.ts.map +1 -1
- package/dist/collabWindowTracker.js +2 -1
- package/dist/collabWindowTracker.js.map +1 -1
- package/dist/connectionManager.d.ts +1 -1
- package/dist/connectionManager.d.ts.map +1 -1
- package/dist/connectionManager.js +8 -11
- package/dist/connectionManager.js.map +1 -1
- package/dist/connectionStateHandler.d.ts +80 -26
- package/dist/connectionStateHandler.d.ts.map +1 -1
- package/dist/connectionStateHandler.js +170 -89
- package/dist/connectionStateHandler.js.map +1 -1
- package/dist/container.d.ts +22 -11
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +130 -142
- package/dist/container.js.map +1 -1
- package/dist/containerContext.d.ts +18 -7
- package/dist/containerContext.d.ts.map +1 -1
- package/dist/containerContext.js +18 -8
- package/dist/containerContext.js.map +1 -1
- package/dist/containerStorageAdapter.d.ts +10 -24
- package/dist/containerStorageAdapter.d.ts.map +1 -1
- package/dist/containerStorageAdapter.js +50 -16
- package/dist/containerStorageAdapter.js.map +1 -1
- package/dist/deltaManager.d.ts +1 -1
- package/dist/deltaManager.d.ts.map +1 -1
- package/dist/deltaManager.js +18 -6
- package/dist/deltaManager.js.map +1 -1
- package/dist/loader.d.ts +1 -1
- package/dist/loader.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +2 -1
- package/dist/protocol.js.map +1 -1
- package/lib/catchUpMonitor.d.ts +6 -17
- package/lib/catchUpMonitor.d.ts.map +1 -1
- package/lib/catchUpMonitor.js +5 -35
- package/lib/catchUpMonitor.js.map +1 -1
- package/lib/collabWindowTracker.d.ts +1 -1
- package/lib/collabWindowTracker.d.ts.map +1 -1
- package/lib/collabWindowTracker.js +3 -2
- package/lib/collabWindowTracker.js.map +1 -1
- package/lib/connectionManager.d.ts +1 -1
- package/lib/connectionManager.d.ts.map +1 -1
- package/lib/connectionManager.js +9 -14
- package/lib/connectionManager.js.map +1 -1
- package/lib/connectionStateHandler.d.ts +80 -26
- package/lib/connectionStateHandler.d.ts.map +1 -1
- package/lib/connectionStateHandler.js +170 -90
- package/lib/connectionStateHandler.js.map +1 -1
- package/lib/container.d.ts +22 -11
- package/lib/container.d.ts.map +1 -1
- package/lib/container.js +133 -145
- package/lib/container.js.map +1 -1
- package/lib/containerContext.d.ts +18 -7
- package/lib/containerContext.d.ts.map +1 -1
- package/lib/containerContext.js +19 -9
- package/lib/containerContext.js.map +1 -1
- package/lib/containerStorageAdapter.d.ts +10 -24
- package/lib/containerStorageAdapter.d.ts.map +1 -1
- package/lib/containerStorageAdapter.js +50 -15
- package/lib/containerStorageAdapter.js.map +1 -1
- package/lib/deltaManager.d.ts +1 -1
- package/lib/deltaManager.d.ts.map +1 -1
- package/lib/deltaManager.js +18 -6
- package/lib/deltaManager.js.map +1 -1
- package/lib/loader.d.ts +1 -1
- package/lib/loader.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/protocol.d.ts.map +1 -1
- package/lib/protocol.js +2 -1
- package/lib/protocol.js.map +1 -1
- package/package.json +13 -13
- package/src/catchUpMonitor.ts +7 -47
- package/src/collabWindowTracker.ts +4 -3
- package/src/connectionManager.ts +9 -11
- package/src/connectionStateHandler.ts +231 -106
- package/src/container.ts +156 -168
- package/src/containerContext.ts +22 -8
- package/src/containerStorageAdapter.ts +64 -15
- package/src/deltaManager.ts +20 -7
- package/src/loader.ts +1 -1
- package/src/packageVersion.ts +1 -1
- package/src/protocol.ts +2 -1
package/dist/container.js
CHANGED
|
@@ -24,10 +24,8 @@ const deltaManager_1 = require("./deltaManager");
|
|
|
24
24
|
const deltaManagerProxy_1 = require("./deltaManagerProxy");
|
|
25
25
|
const loader_1 = require("./loader");
|
|
26
26
|
const packageVersion_1 = require("./packageVersion");
|
|
27
|
-
const connectionStateHandler_1 = require("./connectionStateHandler");
|
|
28
|
-
const retriableDocumentStorageService_1 = require("./retriableDocumentStorageService");
|
|
29
|
-
const protocolTreeDocumentStorageService_1 = require("./protocolTreeDocumentStorageService");
|
|
30
27
|
const containerStorageAdapter_1 = require("./containerStorageAdapter");
|
|
28
|
+
const connectionStateHandler_1 = require("./connectionStateHandler");
|
|
31
29
|
const utils_1 = require("./utils");
|
|
32
30
|
const quorum_1 = require("./quorum");
|
|
33
31
|
const collabWindowTracker_1 = require("./collabWindowTracker");
|
|
@@ -38,14 +36,19 @@ const detachedContainerRefSeqNumber = 0;
|
|
|
38
36
|
const dirtyContainerEvent = "dirty";
|
|
39
37
|
const savedContainerEvent = "saved";
|
|
40
38
|
/**
|
|
41
|
-
* Waits until container connects to delta storage and gets up-to-date
|
|
39
|
+
* Waits until container connects to delta storage and gets up-to-date.
|
|
40
|
+
*
|
|
42
41
|
* Useful when resolving URIs and hitting 404, due to container being loaded from (stale) snapshot and not being
|
|
43
42
|
* up to date. Host may chose to wait in such case and retry resolving URI.
|
|
43
|
+
*
|
|
44
44
|
* Warning: Will wait infinitely for connection to establish if there is no connection.
|
|
45
45
|
* May result in deadlock if Container.disconnect() is called and never followed by a call to Container.connect().
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
46
|
+
*
|
|
47
|
+
* @returns `true`: container is up to date, it processed all the ops that were know at the time of first connection.
|
|
48
|
+
*
|
|
49
|
+
* `false`: storage does not provide indication of how far the client is. Container processed all the ops known to it,
|
|
50
|
+
* but it maybe still behind.
|
|
51
|
+
*
|
|
49
52
|
* @throws an error beginning with `"Container closed"` if the container is closed before it catches up.
|
|
50
53
|
*/
|
|
51
54
|
async function waitContainerToCatchUp(container) {
|
|
@@ -190,9 +193,19 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
190
193
|
this.mc = (0, telemetry_utils_1.loggerToMonitoringContext)(telemetry_utils_1.ChildLogger.create(this.subLogger, "Container"));
|
|
191
194
|
const summarizeProtocolTree = (_a = this.mc.config.getBoolean("Fluid.Container.summarizeProtocolTree")) !== null && _a !== void 0 ? _a : this.loader.services.options.summarizeProtocolTree;
|
|
192
195
|
this.options = Object.assign(Object.assign({}, this.loader.services.options), { summarizeProtocolTree });
|
|
193
|
-
this.
|
|
194
|
-
|
|
195
|
-
|
|
196
|
+
this._deltaManager = this.createDeltaManager();
|
|
197
|
+
this._clientId = (_b = config.serializedContainerState) === null || _b === void 0 ? void 0 : _b.clientId;
|
|
198
|
+
this.connectionStateHandler = (0, connectionStateHandler_1.createConnectionStateHandler)({
|
|
199
|
+
logger: this.mc.logger,
|
|
200
|
+
connectionStateChanged: (value, oldState, reason) => {
|
|
201
|
+
if (value === connectionState_1.ConnectionState.Connected) {
|
|
202
|
+
this._clientId = this.connectionStateHandler.pendingClientId;
|
|
203
|
+
}
|
|
204
|
+
this.logConnectionStateChangeTelemetry(value, oldState, reason);
|
|
205
|
+
if (this._lifecycleState === "loaded") {
|
|
206
|
+
this.propagateConnectionState(false /* initial transition */);
|
|
207
|
+
}
|
|
208
|
+
},
|
|
196
209
|
shouldClientJoinWrite: () => this._deltaManager.connectionManager.shouldJoinWrite(),
|
|
197
210
|
maxClientLeaveWaitTime: this.loader.services.options.maxClientLeaveWaitTime,
|
|
198
211
|
logConnectionIssue: (eventName, details) => {
|
|
@@ -200,29 +213,13 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
200
213
|
// its own join op. Attempt recovery option.
|
|
201
214
|
this._deltaManager.logConnectionIssue(Object.assign({ eventName, duration: common_utils_1.performance.now() - this.connectionTransitionTimes[connectionState_1.ConnectionState.CatchingUp] }, (details === undefined ? {} : { details: JSON.stringify(details) })));
|
|
202
215
|
},
|
|
203
|
-
|
|
204
|
-
// Fire events only if container is fully loaded and not closed
|
|
205
|
-
if (this._lifecycleState === "loaded") {
|
|
206
|
-
this.propagateConnectionState();
|
|
207
|
-
}
|
|
208
|
-
},
|
|
209
|
-
}, this.mc.logger, (_b = config.serializedContainerState) === null || _b === void 0 ? void 0 : _b.clientId);
|
|
216
|
+
}, this.deltaManager, this._clientId);
|
|
210
217
|
this.on(savedContainerEvent, () => {
|
|
211
218
|
this.connectionStateHandler.containerSaved();
|
|
212
219
|
});
|
|
213
|
-
this.
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
if (this.loader.services.detachedBlobStorage !== undefined) {
|
|
217
|
-
return new containerStorageAdapter_1.BlobOnlyStorage(this.loader.services.detachedBlobStorage, this.mc.logger);
|
|
218
|
-
}
|
|
219
|
-
this.mc.logger.sendErrorEvent({
|
|
220
|
-
eventName: "NoRealStorageInDetachedContainer",
|
|
221
|
-
});
|
|
222
|
-
throw new Error("Real storage calls not allowed in Unattached container");
|
|
223
|
-
}
|
|
224
|
-
return this.storageService;
|
|
225
|
-
});
|
|
220
|
+
this.storageService = new containerStorageAdapter_1.ContainerStorageAdapter(this.loader.services.detachedBlobStorage, this.mc.logger, this.options.summarizeProtocolTree === true
|
|
221
|
+
? () => this.captureProtocolSummary()
|
|
222
|
+
: undefined);
|
|
226
223
|
const isDomAvailable = typeof document === "object" &&
|
|
227
224
|
document !== null &&
|
|
228
225
|
typeof document.addEventListener === "function" &&
|
|
@@ -343,7 +340,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
343
340
|
// Only transition states if currently loading
|
|
344
341
|
if (this._lifecycleState === "loading") {
|
|
345
342
|
// Propagate current connection state through the system.
|
|
346
|
-
this.propagateConnectionState();
|
|
343
|
+
this.propagateConnectionState(true /* initial transition */);
|
|
347
344
|
this._lifecycleState = "loaded";
|
|
348
345
|
}
|
|
349
346
|
}
|
|
@@ -351,13 +348,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
351
348
|
return (this._lifecycleState === "closing" || this._lifecycleState === "closed");
|
|
352
349
|
}
|
|
353
350
|
get storage() {
|
|
354
|
-
return this.
|
|
355
|
-
}
|
|
356
|
-
get storageService() {
|
|
357
|
-
if (this._storageService === undefined) {
|
|
358
|
-
throw new Error("Attempted to access storageService before it was defined");
|
|
359
|
-
}
|
|
360
|
-
return this._storageService;
|
|
351
|
+
return this.storageService;
|
|
361
352
|
}
|
|
362
353
|
get context() {
|
|
363
354
|
if (this._context === undefined) {
|
|
@@ -398,7 +389,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
398
389
|
return this.connectionStateHandler.connectionState;
|
|
399
390
|
}
|
|
400
391
|
get connected() {
|
|
401
|
-
return this.connectionStateHandler.
|
|
392
|
+
return this.connectionStateHandler.connectionState === connectionState_1.ConnectionState.Connected;
|
|
402
393
|
}
|
|
403
394
|
/**
|
|
404
395
|
* Service configuration details. If running in offline mode will be undefined otherwise will contain service
|
|
@@ -412,7 +403,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
412
403
|
* Set once this.connected is true, otherwise undefined
|
|
413
404
|
*/
|
|
414
405
|
get clientId() {
|
|
415
|
-
return this.
|
|
406
|
+
return this._clientId;
|
|
416
407
|
}
|
|
417
408
|
/**
|
|
418
409
|
* The server provided claims of the client.
|
|
@@ -474,7 +465,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
474
465
|
(0, common_utils_1.assert)(this._lifecycleState === "closed", 0x314 /* Container properly closed */);
|
|
475
466
|
}
|
|
476
467
|
closeCore(error) {
|
|
477
|
-
var _a, _b, _c
|
|
468
|
+
var _a, _b, _c;
|
|
478
469
|
(0, common_utils_1.assert)(!this.closed, 0x315 /* re-entrancy */);
|
|
479
470
|
try {
|
|
480
471
|
// Ensure that we raise all key events even if one of these throws
|
|
@@ -489,11 +480,11 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
489
480
|
(_a = this._protocolHandler) === null || _a === void 0 ? void 0 : _a.close();
|
|
490
481
|
this.connectionStateHandler.dispose();
|
|
491
482
|
(_b = this._context) === null || _b === void 0 ? void 0 : _b.dispose(error !== undefined ? new Error(error.message) : undefined);
|
|
492
|
-
|
|
483
|
+
this.storageService.dispose();
|
|
493
484
|
// Notify storage about critical errors. They may be due to disconnect between client & server knowledge
|
|
494
485
|
// about file, like file being overwritten in storage, but client having stale local cache.
|
|
495
486
|
// Driver need to ensure all caches are cleared on critical errors
|
|
496
|
-
(
|
|
487
|
+
(_c = this.service) === null || _c === void 0 ? void 0 : _c.dispose(error);
|
|
497
488
|
}
|
|
498
489
|
catch (exception) {
|
|
499
490
|
this.mc.logger.sendErrorEvent({ eventName: "ContainerCloseException" }, exception);
|
|
@@ -580,7 +571,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
580
571
|
const resolvedUrl = this.service.resolvedUrl;
|
|
581
572
|
(0, driver_utils_1.ensureFluidResolvedUrl)(resolvedUrl);
|
|
582
573
|
this._resolvedUrl = resolvedUrl;
|
|
583
|
-
await this.
|
|
574
|
+
await this.storageService.connectToService(this.service);
|
|
584
575
|
if (hasAttachmentBlobs) {
|
|
585
576
|
// upload blobs to storage
|
|
586
577
|
(0, common_utils_1.assert)(!!this.loader.services.detachedBlobStorage, 0x24e /* "assertion for type narrowing" */);
|
|
@@ -610,8 +601,6 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
610
601
|
}
|
|
611
602
|
this._attachState = container_definitions_1.AttachState.Attached;
|
|
612
603
|
this.emit("attached");
|
|
613
|
-
// Propagate current connection state through the system.
|
|
614
|
-
this.propagateConnectionState();
|
|
615
604
|
if (!this.closed) {
|
|
616
605
|
this.resumeInternal({ fetchOpsFromStorage: false, reason: "createDetached" });
|
|
617
606
|
}
|
|
@@ -750,9 +739,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
750
739
|
/**
|
|
751
740
|
* Load container.
|
|
752
741
|
*
|
|
753
|
-
* @param specifiedVersion -
|
|
754
|
-
* - undefined - fetch latest snapshot
|
|
755
|
-
* - otherwise, version sha to load snapshot
|
|
742
|
+
* @param specifiedVersion - Version SHA to load snapshot. If not specified, will fetch the latest snapshot.
|
|
756
743
|
*/
|
|
757
744
|
async load(specifiedVersion, loadMode, pendingLocalState) {
|
|
758
745
|
if (this._resolvedUrl === undefined) {
|
|
@@ -775,11 +762,11 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
775
762
|
this.connectToDeltaStream(connectionArgs);
|
|
776
763
|
}
|
|
777
764
|
if (!pendingLocalState) {
|
|
778
|
-
await this.
|
|
765
|
+
await this.storageService.connectToService(this.service);
|
|
779
766
|
}
|
|
780
767
|
else {
|
|
781
768
|
// if we have pendingLocalState we can load without storage; don't wait for connection
|
|
782
|
-
this.
|
|
769
|
+
this.storageService.connectToService(this.service).catch((error) => this.close(error));
|
|
783
770
|
}
|
|
784
771
|
this._attachState = container_definitions_1.AttachState.Attached;
|
|
785
772
|
// Fetch specified snapshot.
|
|
@@ -814,12 +801,16 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
814
801
|
}
|
|
815
802
|
// ...load in the existing quorum
|
|
816
803
|
// Initialize the protocol handler
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
804
|
+
if (pendingLocalState === undefined) {
|
|
805
|
+
await this.initializeProtocolStateFromSnapshot(attributes, this.storageService, snapshot);
|
|
806
|
+
}
|
|
807
|
+
else {
|
|
808
|
+
this.initializeProtocolState(attributes, {
|
|
809
|
+
members: pendingLocalState.protocol.members,
|
|
810
|
+
proposals: pendingLocalState.protocol.proposals,
|
|
811
|
+
values: pendingLocalState.protocol.values,
|
|
812
|
+
});
|
|
813
|
+
}
|
|
823
814
|
const codeDetails = this.getCodeDetailsFromQuorum();
|
|
824
815
|
await this.instantiateContext(true, // existing
|
|
825
816
|
codeDetails, snapshot, pendingLocalState === null || pendingLocalState === void 0 ? void 0 : pendingLocalState.pendingRuntimeState);
|
|
@@ -873,7 +864,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
873
864
|
await this.attachDeltaManagerOpHandler(attributes);
|
|
874
865
|
// Need to just seed the source data in the code quorum. Quorum itself is empty
|
|
875
866
|
const qValues = (0, quorum_1.initQuorumValuesFromCodeDetails)(source);
|
|
876
|
-
this.
|
|
867
|
+
this.initializeProtocolState(attributes, {
|
|
877
868
|
members: [],
|
|
878
869
|
proposals: [],
|
|
879
870
|
values: qValues,
|
|
@@ -888,40 +879,22 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
888
879
|
delete detachedContainerSnapshot.tree[".hasAttachmentBlobs"];
|
|
889
880
|
}
|
|
890
881
|
const snapshotTree = (0, utils_1.getSnapshotTreeFromSerializedContainer)(detachedContainerSnapshot);
|
|
891
|
-
this.
|
|
892
|
-
const attributes = await this.getDocumentAttributes(this.
|
|
882
|
+
this.storageService.loadSnapshotForRehydratingContainer(snapshotTree);
|
|
883
|
+
const attributes = await this.getDocumentAttributes(this.storageService, snapshotTree);
|
|
893
884
|
await this.attachDeltaManagerOpHandler(attributes);
|
|
894
885
|
// Initialize the protocol handler
|
|
895
886
|
const baseTree = (0, utils_1.getProtocolSnapshotTree)(snapshotTree);
|
|
896
|
-
const qValues = await (0, driver_utils_1.readAndParse)(this.
|
|
887
|
+
const qValues = await (0, driver_utils_1.readAndParse)(this.storageService, baseTree.blobs.quorumValues);
|
|
897
888
|
const codeDetails = (0, quorum_1.getCodeDetailsFromQuorumValues)(qValues);
|
|
898
|
-
this.
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
});
|
|
889
|
+
this.initializeProtocolState(attributes, {
|
|
890
|
+
members: [],
|
|
891
|
+
proposals: [],
|
|
892
|
+
values: codeDetails !== undefined ? (0, quorum_1.initQuorumValuesFromCodeDetails)(codeDetails) : [],
|
|
893
|
+
});
|
|
904
894
|
await this.instantiateContextDetached(true, // existing
|
|
905
895
|
snapshotTree);
|
|
906
896
|
this.setLoaded();
|
|
907
897
|
}
|
|
908
|
-
async connectStorageService() {
|
|
909
|
-
var _a, _b;
|
|
910
|
-
if (this._storageService !== undefined) {
|
|
911
|
-
return;
|
|
912
|
-
}
|
|
913
|
-
(0, common_utils_1.assert)(this.service !== undefined, 0x1ef /* "services must be defined" */);
|
|
914
|
-
const storageService = await this.service.connectToStorage();
|
|
915
|
-
this._storageService =
|
|
916
|
-
new retriableDocumentStorageService_1.RetriableDocumentStorageService(storageService, this.mc.logger);
|
|
917
|
-
if (this.options.summarizeProtocolTree === true) {
|
|
918
|
-
this.mc.logger.sendTelemetryEvent({ eventName: "summarizeProtocolTreeEnabled" });
|
|
919
|
-
this._storageService =
|
|
920
|
-
new protocolTreeDocumentStorageService_1.ProtocolTreeStorageService(this._storageService, () => this.captureProtocolSummary());
|
|
921
|
-
}
|
|
922
|
-
// ensure we did not lose that policy in the process of wrapping
|
|
923
|
-
(0, common_utils_1.assert)(((_a = storageService.policies) === null || _a === void 0 ? void 0 : _a.minBlobSize) === ((_b = this.storageService.policies) === null || _b === void 0 ? void 0 : _b.minBlobSize), 0x0e0 /* "lost minBlobSize policy" */);
|
|
924
|
-
}
|
|
925
898
|
async getDocumentAttributes(storage, tree) {
|
|
926
899
|
if (tree === undefined) {
|
|
927
900
|
return {
|
|
@@ -955,13 +928,12 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
955
928
|
(0, driver_utils_1.readAndParse)(storage, baseTree.blobs.quorumValues),
|
|
956
929
|
]);
|
|
957
930
|
}
|
|
958
|
-
|
|
959
|
-
return protocolHandler;
|
|
931
|
+
this.initializeProtocolState(attributes, quorumSnapshot);
|
|
960
932
|
}
|
|
961
|
-
|
|
933
|
+
initializeProtocolState(attributes, quorumSnapshot) {
|
|
962
934
|
var _a, _b;
|
|
963
935
|
const protocolHandlerBuilder = (_a = this.protocolHandlerBuilder) !== null && _a !== void 0 ? _a : ((...args) => new protocol_1.ProtocolHandler(...args, new audience_1.Audience()));
|
|
964
|
-
const protocol = protocolHandlerBuilder(attributes, quorumSnapshot, (key, value) => this.submitMessage(protocol_definitions_1.MessageType.Propose, { key, value }), (_b = this._initialClients) !== null && _b !== void 0 ? _b : []);
|
|
936
|
+
const protocol = protocolHandlerBuilder(attributes, quorumSnapshot, (key, value) => this.submitMessage(protocol_definitions_1.MessageType.Propose, JSON.stringify({ key, value })), (_b = this._initialClients) !== null && _b !== void 0 ? _b : []);
|
|
965
937
|
this._initialClients = undefined;
|
|
966
938
|
const protocolLogger = telemetry_utils_1.ChildLogger.create(this.subLogger, "ProtocolHandler");
|
|
967
939
|
protocol.quorum.on("error", (error) => {
|
|
@@ -987,7 +959,11 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
987
959
|
});
|
|
988
960
|
}
|
|
989
961
|
});
|
|
990
|
-
|
|
962
|
+
// we need to make sure this member get set in a synchronous context,
|
|
963
|
+
// or other things can happen after the object that will be set is created, but not yet set
|
|
964
|
+
// this was breaking this._initialClients handling
|
|
965
|
+
//
|
|
966
|
+
this._protocolHandler = protocol;
|
|
991
967
|
}
|
|
992
968
|
captureProtocolSummary() {
|
|
993
969
|
const quorumSnapshot = this.protocolHandler.snapshot();
|
|
@@ -1071,10 +1047,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1071
1047
|
this._protocolHandler.audience.addMember(priorClient.clientId, priorClient.client);
|
|
1072
1048
|
}
|
|
1073
1049
|
}
|
|
1074
|
-
|
|
1075
|
-
this.deltaManager
|
|
1076
|
-
: undefined;
|
|
1077
|
-
this.connectionStateHandler.receivedConnectEvent(this.connectionMode, details, deltaManagerForCatchingUp);
|
|
1050
|
+
this.connectionStateHandler.receivedConnectEvent(this.connectionMode, details);
|
|
1078
1051
|
});
|
|
1079
1052
|
deltaManager.on("disconnect", (reason) => {
|
|
1080
1053
|
var _a;
|
|
@@ -1091,6 +1064,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1091
1064
|
this.emit("warning", warn);
|
|
1092
1065
|
});
|
|
1093
1066
|
deltaManager.on("readonly", (readonly) => {
|
|
1067
|
+
this.setContextConnectedState(this.connectionState === connectionState_1.ConnectionState.Connected, readonly);
|
|
1094
1068
|
this.emit("readonly", readonly);
|
|
1095
1069
|
});
|
|
1096
1070
|
deltaManager.on("closed", (error) => {
|
|
@@ -1133,12 +1107,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1133
1107
|
opsBehind = checkpointSequenceNumber - this.deltaManager.lastSequenceNumber;
|
|
1134
1108
|
}
|
|
1135
1109
|
}
|
|
1136
|
-
|
|
1137
|
-
connectionInitiationReason = "InitialConnect";
|
|
1138
|
-
}
|
|
1139
|
-
else {
|
|
1140
|
-
connectionInitiationReason = "AutoReconnect";
|
|
1141
|
-
}
|
|
1110
|
+
connectionInitiationReason = this.firstConnection ? "InitialConnect" : "AutoReconnect";
|
|
1142
1111
|
}
|
|
1143
1112
|
this.mc.logger.sendPerformanceEvent(Object.assign({ eventName: `ConnectionStateChange_${connectionState_1.ConnectionState[value]}`, from: connectionState_1.ConnectionState[oldState], duration,
|
|
1144
1113
|
durationFromDisconnected,
|
|
@@ -1149,49 +1118,64 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1149
1118
|
this.firstConnection = false;
|
|
1150
1119
|
}
|
|
1151
1120
|
}
|
|
1152
|
-
propagateConnectionState() {
|
|
1121
|
+
propagateConnectionState(initialTransition) {
|
|
1153
1122
|
var _a;
|
|
1123
|
+
// When container loaded, we want to propagate initial connection state.
|
|
1124
|
+
// After that, we communicate only transitions to Connected & Disconnected states, skipping all other states.
|
|
1125
|
+
// This can be changed in the future, for example we likely should add "CatchingUp" event on Container.
|
|
1126
|
+
if (!initialTransition &&
|
|
1127
|
+
this.connectionState !== connectionState_1.ConnectionState.Connected &&
|
|
1128
|
+
this.connectionState !== connectionState_1.ConnectionState.Disconnected) {
|
|
1129
|
+
return;
|
|
1130
|
+
}
|
|
1131
|
+
const state = this.connectionState === connectionState_1.ConnectionState.Connected;
|
|
1154
1132
|
const logOpsOnReconnect = this.connectionState === connectionState_1.ConnectionState.Connected &&
|
|
1155
1133
|
!this.firstConnection &&
|
|
1156
1134
|
this.connectionMode === "write";
|
|
1157
1135
|
if (logOpsOnReconnect) {
|
|
1158
1136
|
this.messageCountAfterDisconnection = 0;
|
|
1159
1137
|
}
|
|
1160
|
-
const state = this.connectionState === connectionState_1.ConnectionState.Connected;
|
|
1161
1138
|
// Both protocol and context should not be undefined if we got so far.
|
|
1162
|
-
|
|
1163
|
-
this.context.setConnectionState(state, this.clientId);
|
|
1164
|
-
}
|
|
1139
|
+
this.setContextConnectedState(state, (_a = this._deltaManager.connectionManager.readOnlyInfo.readonly) !== null && _a !== void 0 ? _a : false);
|
|
1165
1140
|
this.protocolHandler.setConnectionState(state, this.clientId);
|
|
1166
1141
|
(0, telemetry_utils_1.raiseConnectedEvent)(this.mc.logger, this, state, this.clientId);
|
|
1167
1142
|
if (logOpsOnReconnect) {
|
|
1168
1143
|
this.mc.logger.sendTelemetryEvent({ eventName: "OpsSentOnReconnect", count: this.messageCountAfterDisconnection });
|
|
1169
1144
|
}
|
|
1170
1145
|
}
|
|
1146
|
+
// back-compat: ADO #1385: Remove in the future, summary op should come through submitSummaryMessage()
|
|
1171
1147
|
submitContainerMessage(type, contents, batch, metadata) {
|
|
1172
|
-
|
|
1173
|
-
switch (outboundMessageType) {
|
|
1148
|
+
switch (type) {
|
|
1174
1149
|
case protocol_definitions_1.MessageType.Operation:
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
// github #6451: this is only needed for staging so the server
|
|
1179
|
-
// know when the protocol tree is included
|
|
1180
|
-
// this can be removed once all clients send
|
|
1181
|
-
// protocol tree by default
|
|
1182
|
-
const summary = contents;
|
|
1183
|
-
if (summary.details === undefined) {
|
|
1184
|
-
summary.details = {};
|
|
1185
|
-
}
|
|
1186
|
-
summary.details.includesProtocolTree =
|
|
1187
|
-
this.options.summarizeProtocolTree === true;
|
|
1188
|
-
break;
|
|
1189
|
-
}
|
|
1150
|
+
return this.submitMessage(type, JSON.stringify(contents), batch, metadata);
|
|
1151
|
+
case protocol_definitions_1.MessageType.Summarize:
|
|
1152
|
+
return this.submitSummaryMessage(contents);
|
|
1190
1153
|
default:
|
|
1191
1154
|
this.close(new container_utils_1.GenericError("invalidContainerSubmitOpType", undefined /* error */, { messageType: type }));
|
|
1192
1155
|
return -1;
|
|
1193
1156
|
}
|
|
1194
|
-
|
|
1157
|
+
}
|
|
1158
|
+
/** @returns clientSequenceNumber of last message in a batch */
|
|
1159
|
+
submitBatch(batch) {
|
|
1160
|
+
let clientSequenceNumber = -1;
|
|
1161
|
+
for (const message of batch) {
|
|
1162
|
+
clientSequenceNumber = this.submitMessage(protocol_definitions_1.MessageType.Operation, message.contents, true, // batch
|
|
1163
|
+
message.metadata);
|
|
1164
|
+
}
|
|
1165
|
+
this._deltaManager.flush();
|
|
1166
|
+
return clientSequenceNumber;
|
|
1167
|
+
}
|
|
1168
|
+
submitSummaryMessage(summary) {
|
|
1169
|
+
// github #6451: this is only needed for staging so the server
|
|
1170
|
+
// know when the protocol tree is included
|
|
1171
|
+
// this can be removed once all clients send
|
|
1172
|
+
// protocol tree by default
|
|
1173
|
+
if (summary.details === undefined) {
|
|
1174
|
+
summary.details = {};
|
|
1175
|
+
}
|
|
1176
|
+
summary.details.includesProtocolTree =
|
|
1177
|
+
this.options.summarizeProtocolTree === true;
|
|
1178
|
+
return this.submitMessage(protocol_definitions_1.MessageType.Summarize, JSON.stringify(summary), false /* batch */);
|
|
1195
1179
|
}
|
|
1196
1180
|
submitMessage(type, contents, batch, metadata) {
|
|
1197
1181
|
var _a;
|
|
@@ -1206,22 +1190,9 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1206
1190
|
processRemoteMessage(message) {
|
|
1207
1191
|
const local = this.clientId === message.clientId;
|
|
1208
1192
|
// Allow the protocol handler to process the message
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
}
|
|
1213
|
-
catch (error) {
|
|
1214
|
-
this.close((0, telemetry_utils_1.wrapError)(error, (errorMessage) => new container_utils_1.DataCorruptionError(errorMessage, (0, container_utils_1.extractSafePropertiesFromMessage)(message))));
|
|
1215
|
-
}
|
|
1216
|
-
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
|
1217
|
-
if ((0, driver_utils_1.isUnpackedRuntimeMessage)(message) && !(0, driver_utils_1.isRuntimeMessage)(message)) {
|
|
1218
|
-
this.mc.logger.sendTelemetryEvent({ eventName: "UnpackedRuntimeMessage", type: message.type });
|
|
1219
|
-
}
|
|
1220
|
-
// Forward non system messages to the loaded runtime for processing
|
|
1221
|
-
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
|
1222
|
-
if ((0, driver_utils_1.isRuntimeMessage)(message) || (0, driver_utils_1.isUnpackedRuntimeMessage)(message)) {
|
|
1223
|
-
this.context.process(message, local, undefined);
|
|
1224
|
-
}
|
|
1193
|
+
const result = this.protocolHandler.processMessage(message, local);
|
|
1194
|
+
// Forward messages to the loaded runtime for processing
|
|
1195
|
+
this.context.process(message, local, undefined);
|
|
1225
1196
|
// Inactive (not in quorum or not writers) clients don't take part in the minimum sequence number calculation.
|
|
1226
1197
|
if (this.activeConnection()) {
|
|
1227
1198
|
if (this.collabWindowTracker === undefined) {
|
|
@@ -1230,15 +1201,14 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1230
1201
|
// clients.
|
|
1231
1202
|
// All existing will continue to use settings they got earlier.
|
|
1232
1203
|
(0, common_utils_1.assert)(this.serviceConfiguration !== undefined, 0x2e4 /* "there should be service config for active connection" */);
|
|
1233
|
-
this.collabWindowTracker = new collabWindowTracker_1.CollabWindowTracker((type
|
|
1204
|
+
this.collabWindowTracker = new collabWindowTracker_1.CollabWindowTracker((type) => {
|
|
1234
1205
|
(0, common_utils_1.assert)(this.activeConnection(), 0x241 /* "disconnect should result in stopSequenceNumberUpdate() call" */);
|
|
1235
|
-
this.submitMessage(type
|
|
1206
|
+
this.submitMessage(type);
|
|
1236
1207
|
}, this.serviceConfiguration.noopTimeFrequency, this.serviceConfiguration.noopCountFrequency);
|
|
1237
1208
|
}
|
|
1238
1209
|
this.collabWindowTracker.scheduleSequenceNumberUpdate(message, result.immediateNoOp === true);
|
|
1239
1210
|
}
|
|
1240
1211
|
this.emit("op", message);
|
|
1241
|
-
return result;
|
|
1242
1212
|
}
|
|
1243
1213
|
submitSignal(message) {
|
|
1244
1214
|
this._deltaManager.submitSignal(JSON.stringify(message));
|
|
@@ -1285,7 +1255,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1285
1255
|
// The relative loader will proxy requests to '/' to the loader itself assuming no non-cache flags
|
|
1286
1256
|
// are set. Global requests will still go directly to the loader
|
|
1287
1257
|
const loader = new loader_1.RelativeLoader(this, this.loader);
|
|
1288
|
-
this._context = await containerContext_1.ContainerContext.createOrLoad(this, this.scope, this.codeLoader, codeDetails, snapshot, new deltaManagerProxy_1.DeltaManagerProxy(this._deltaManager), new quorum_1.QuorumProxy(this.protocolHandler.quorum), loader, (type, contents, batch, metadata) => this.submitContainerMessage(type, contents, batch, metadata), (message) => this.submitSignal(message), (error) => this.close(error), Container.version, (dirty) => this.updateDirtyContainerState(dirty), existing, pendingLocalState);
|
|
1258
|
+
this._context = await containerContext_1.ContainerContext.createOrLoad(this, this.scope, this.codeLoader, codeDetails, snapshot, new deltaManagerProxy_1.DeltaManagerProxy(this._deltaManager), new quorum_1.QuorumProxy(this.protocolHandler.quorum), loader, (type, contents, batch, metadata) => this.submitContainerMessage(type, contents, batch, metadata), (summaryOp) => this.submitSummaryMessage(summaryOp), (batch) => this.submitBatch(batch), (message) => this.submitSignal(message), (error) => this.close(error), Container.version, (dirty) => this.updateDirtyContainerState(dirty), existing, pendingLocalState);
|
|
1289
1259
|
this.emit("contextChanged", codeDetails);
|
|
1290
1260
|
}
|
|
1291
1261
|
updateDirtyContainerState(dirty) {
|
|
@@ -1298,6 +1268,24 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1298
1268
|
logContainerError(warning) {
|
|
1299
1269
|
this.mc.logger.sendErrorEvent({ eventName: "ContainerWarning" }, warning);
|
|
1300
1270
|
}
|
|
1271
|
+
/**
|
|
1272
|
+
* Set the connected state of the ContainerContext
|
|
1273
|
+
* This controls the "connected" state of the ContainerRuntime as well
|
|
1274
|
+
* @param state - Is the container currently connected?
|
|
1275
|
+
* @param readonly - Is the container in readonly mode?
|
|
1276
|
+
*/
|
|
1277
|
+
setContextConnectedState(state, readonly) {
|
|
1278
|
+
var _a;
|
|
1279
|
+
if (((_a = this._context) === null || _a === void 0 ? void 0 : _a.disposed) === false) {
|
|
1280
|
+
/**
|
|
1281
|
+
* We want to lie to the ContainerRuntime when we are in readonly mode to prevent issues with pending
|
|
1282
|
+
* ops getting through to the DeltaManager.
|
|
1283
|
+
* The ContainerRuntime's "connected" state simply means it is ok to send ops
|
|
1284
|
+
* See https://dev.azure.com/fluidframework/internal/_workitems/edit/1246
|
|
1285
|
+
*/
|
|
1286
|
+
this.context.setConnectionState(state && !readonly, this.clientId);
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1301
1289
|
}
|
|
1302
1290
|
exports.Container = Container;
|
|
1303
1291
|
Container.version = "^0.1.0";
|