@fluidframework/container-loader 0.59.4000-71130 → 1.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 +1 -1
- package/README.md +1 -1
- package/dist/connectionState.d.ts +15 -3
- package/dist/connectionState.d.ts.map +1 -1
- package/dist/connectionState.js +15 -3
- package/dist/connectionState.js.map +1 -1
- package/dist/connectionStateHandler.d.ts +6 -4
- package/dist/connectionStateHandler.d.ts.map +1 -1
- package/dist/connectionStateHandler.js +21 -6
- package/dist/connectionStateHandler.js.map +1 -1
- package/dist/container.d.ts +18 -26
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +54 -88
- package/dist/container.js.map +1 -1
- package/dist/containerContext.d.ts +6 -4
- package/dist/containerContext.d.ts.map +1 -1
- package/dist/containerContext.js +8 -7
- package/dist/containerContext.js.map +1 -1
- package/dist/containerStorageAdapter.d.ts +2 -3
- package/dist/containerStorageAdapter.d.ts.map +1 -1
- package/dist/containerStorageAdapter.js +0 -3
- package/dist/containerStorageAdapter.js.map +1 -1
- package/dist/deltaManagerProxy.d.ts +0 -1
- package/dist/deltaManagerProxy.d.ts.map +1 -1
- package/dist/deltaManagerProxy.js +0 -3
- package/dist/deltaManagerProxy.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +1 -13
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +2 -3
- package/dist/loader.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.d.ts.map +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/protocolTreeDocumentStorageService.d.ts +0 -1
- package/dist/protocolTreeDocumentStorageService.d.ts.map +1 -1
- package/dist/protocolTreeDocumentStorageService.js +0 -1
- package/dist/protocolTreeDocumentStorageService.js.map +1 -1
- package/dist/retriableDocumentStorageService.d.ts +1 -2
- package/dist/retriableDocumentStorageService.d.ts.map +1 -1
- package/dist/retriableDocumentStorageService.js +0 -3
- package/dist/retriableDocumentStorageService.js.map +1 -1
- package/lib/connectionState.d.ts +15 -3
- package/lib/connectionState.d.ts.map +1 -1
- package/lib/connectionState.js +15 -3
- package/lib/connectionState.js.map +1 -1
- package/lib/connectionStateHandler.d.ts +6 -4
- package/lib/connectionStateHandler.d.ts.map +1 -1
- package/lib/connectionStateHandler.js +21 -6
- package/lib/connectionStateHandler.js.map +1 -1
- package/lib/container.d.ts +18 -26
- package/lib/container.d.ts.map +1 -1
- package/lib/container.js +54 -88
- package/lib/container.js.map +1 -1
- package/lib/containerContext.d.ts +6 -4
- package/lib/containerContext.d.ts.map +1 -1
- package/lib/containerContext.js +8 -7
- package/lib/containerContext.js.map +1 -1
- package/lib/containerStorageAdapter.d.ts +2 -3
- package/lib/containerStorageAdapter.d.ts.map +1 -1
- package/lib/containerStorageAdapter.js +0 -3
- package/lib/containerStorageAdapter.js.map +1 -1
- package/lib/deltaManagerProxy.d.ts +0 -1
- package/lib/deltaManagerProxy.d.ts.map +1 -1
- package/lib/deltaManagerProxy.js +0 -3
- package/lib/deltaManagerProxy.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/loader.d.ts +1 -13
- package/lib/loader.d.ts.map +1 -1
- package/lib/loader.js +2 -3
- package/lib/loader.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.d.ts.map +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/protocolTreeDocumentStorageService.d.ts +0 -1
- package/lib/protocolTreeDocumentStorageService.d.ts.map +1 -1
- package/lib/protocolTreeDocumentStorageService.js +0 -1
- package/lib/protocolTreeDocumentStorageService.js.map +1 -1
- package/lib/retriableDocumentStorageService.d.ts +1 -2
- package/lib/retriableDocumentStorageService.d.ts.map +1 -1
- package/lib/retriableDocumentStorageService.js +0 -3
- package/lib/retriableDocumentStorageService.js.map +1 -1
- package/package.json +27 -27
- package/src/connectionState.ts +20 -6
- package/src/connectionStateHandler.ts +29 -8
- package/src/container.ts +77 -100
- package/src/containerContext.ts +10 -10
- package/src/containerStorageAdapter.ts +1 -6
- package/src/deltaManagerProxy.ts +0 -4
- package/src/index.ts +1 -0
- package/src/loader.ts +4 -21
- package/src/packageVersion.ts +1 -1
- package/src/protocolTreeDocumentStorageService.ts +0 -1
- package/src/retriableDocumentStorageService.ts +0 -8
package/src/container.ts
CHANGED
|
@@ -25,7 +25,6 @@ import {
|
|
|
25
25
|
ContainerWarning,
|
|
26
26
|
AttachState,
|
|
27
27
|
IThrottlingWarning,
|
|
28
|
-
IPendingLocalState,
|
|
29
28
|
ReadOnlyInfo,
|
|
30
29
|
IContainerLoadMode,
|
|
31
30
|
IFluidCodeDetails,
|
|
@@ -64,6 +63,7 @@ import {
|
|
|
64
63
|
IDocumentAttributes,
|
|
65
64
|
IDocumentMessage,
|
|
66
65
|
IProcessMessageResult,
|
|
66
|
+
IProtocolState,
|
|
67
67
|
IQuorumClients,
|
|
68
68
|
IQuorumProposals,
|
|
69
69
|
ISequencedClient,
|
|
@@ -140,6 +140,10 @@ export interface IContainerConfig {
|
|
|
140
140
|
* Client details provided in the override will be merged over the default client.
|
|
141
141
|
*/
|
|
142
142
|
clientDetailsOverride?: IClientDetails;
|
|
143
|
+
/**
|
|
144
|
+
* Serialized state from a previous instance of this container
|
|
145
|
+
*/
|
|
146
|
+
serializedContainerState?: IPendingContainerState;
|
|
143
147
|
}
|
|
144
148
|
|
|
145
149
|
/**
|
|
@@ -147,7 +151,7 @@ export interface IContainerConfig {
|
|
|
147
151
|
* Useful when resolving URIs and hitting 404, due to container being loaded from (stale) snapshot and not being
|
|
148
152
|
* up to date. Host may chose to wait in such case and retry resolving URI.
|
|
149
153
|
* Warning: Will wait infinitely for connection to establish if there is no connection.
|
|
150
|
-
* May result in deadlock if Container.
|
|
154
|
+
* May result in deadlock if Container.disconnect() is called and never followed by a call to Container.connect().
|
|
151
155
|
* @returns true: container is up to date, it processed all the ops that were know at the time of first connection
|
|
152
156
|
* false: storage does not provide indication of how far the client is. Container processed
|
|
153
157
|
* all the ops known to it, but it maybe still behind.
|
|
@@ -174,7 +178,8 @@ export async function waitContainerToCatchUp(container: IContainer) {
|
|
|
174
178
|
container.on("closed", closedCallback);
|
|
175
179
|
|
|
176
180
|
const waitForOps = () => {
|
|
177
|
-
assert(container.connectionState
|
|
181
|
+
assert(container.connectionState === ConnectionState.CatchingUp
|
|
182
|
+
|| container.connectionState === ConnectionState.Connected,
|
|
178
183
|
0x0cd /* "Container disconnected while waiting for ops!" */);
|
|
179
184
|
const hasCheckpointSequenceNumber = deltaManager.hasCheckpointSequenceNumber;
|
|
180
185
|
|
|
@@ -211,9 +216,7 @@ export async function waitContainerToCatchUp(container: IContainer) {
|
|
|
211
216
|
};
|
|
212
217
|
container.on(connectedEventName, callback);
|
|
213
218
|
|
|
214
|
-
|
|
215
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
216
|
-
container.resume!();
|
|
219
|
+
container.connect();
|
|
217
220
|
});
|
|
218
221
|
}
|
|
219
222
|
|
|
@@ -221,6 +224,18 @@ const getCodeProposal =
|
|
|
221
224
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
222
225
|
(quorum: IQuorumProposals) => quorum.get("code") ?? quorum.get("code2");
|
|
223
226
|
|
|
227
|
+
/**
|
|
228
|
+
* State saved by a container at close time, to be used to load a new instance
|
|
229
|
+
* of the container to the same state
|
|
230
|
+
*/
|
|
231
|
+
export interface IPendingContainerState {
|
|
232
|
+
pendingRuntimeState: unknown;
|
|
233
|
+
url: string;
|
|
234
|
+
protocol: IProtocolState;
|
|
235
|
+
term: number;
|
|
236
|
+
clientId?: string;
|
|
237
|
+
}
|
|
238
|
+
|
|
224
239
|
const summarizerClientType = "summarizer";
|
|
225
240
|
|
|
226
241
|
export class Container extends EventEmitterWithErrorHandling<IContainerEvents> implements IContainer {
|
|
@@ -232,7 +247,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
232
247
|
public static async load(
|
|
233
248
|
loader: Loader,
|
|
234
249
|
loadOptions: IContainerLoadOptions,
|
|
235
|
-
pendingLocalState?:
|
|
250
|
+
pendingLocalState?: IPendingContainerState,
|
|
236
251
|
): Promise<Container> {
|
|
237
252
|
const container = new Container(
|
|
238
253
|
loader,
|
|
@@ -240,6 +255,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
240
255
|
clientDetailsOverride: loadOptions.clientDetailsOverride,
|
|
241
256
|
resolvedUrl: loadOptions.resolvedUrl,
|
|
242
257
|
canReconnect: loadOptions.canReconnect,
|
|
258
|
+
serializedContainerState: pendingLocalState,
|
|
243
259
|
});
|
|
244
260
|
|
|
245
261
|
return PerformanceEvent.timedExecAsync(
|
|
@@ -249,12 +265,12 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
249
265
|
container._lifecycleState = "loading";
|
|
250
266
|
const version = loadOptions.version;
|
|
251
267
|
|
|
252
|
-
// always load unpaused with pending ops!
|
|
253
|
-
// It is also default mode in general.
|
|
254
268
|
const defaultMode: IContainerLoadMode = { opsBeforeReturn: "cached" };
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
const mode: IContainerLoadMode =
|
|
269
|
+
// if we have pendingLocalState, anything we cached is not useful and we shouldn't wait for connection
|
|
270
|
+
// to return container, so ignore this value and use undefined for opsBeforeReturn
|
|
271
|
+
const mode: IContainerLoadMode = pendingLocalState
|
|
272
|
+
? { ...(loadOptions.loadMode ?? defaultMode), opsBeforeReturn: undefined }
|
|
273
|
+
: loadOptions.loadMode ?? defaultMode;
|
|
258
274
|
|
|
259
275
|
const onClosed = (err?: ICriticalContainerError) => {
|
|
260
276
|
// pre-0.58 error message: containerClosedWithoutErrorDuringLoad
|
|
@@ -597,7 +613,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
597
613
|
// its own join op. Attempt recovery option.
|
|
598
614
|
this._deltaManager.logConnectionIssue({
|
|
599
615
|
eventName,
|
|
600
|
-
duration: performance.now() - this.connectionTransitionTimes[ConnectionState.
|
|
616
|
+
duration: performance.now() - this.connectionTransitionTimes[ConnectionState.CatchingUp],
|
|
601
617
|
});
|
|
602
618
|
},
|
|
603
619
|
connectionStateChanged: () => {
|
|
@@ -607,6 +623,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
607
623
|
},
|
|
608
624
|
},
|
|
609
625
|
this.mc.logger,
|
|
626
|
+
config.serializedContainerState?.clientId,
|
|
610
627
|
);
|
|
611
628
|
|
|
612
629
|
this.on(savedContainerEvent, () => {
|
|
@@ -748,9 +765,13 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
748
765
|
assert(this.attachState === AttachState.Attached, 0x0d1 /* "Container should be attached before close" */);
|
|
749
766
|
assert(this.resolvedUrl !== undefined && this.resolvedUrl.type === "fluid",
|
|
750
767
|
0x0d2 /* "resolved url should be valid Fluid url" */);
|
|
751
|
-
|
|
768
|
+
assert(!!this._protocolHandler, 0x2e3 /* "Must have a valid protocol handler instance" */);
|
|
769
|
+
const pendingState: IPendingContainerState = {
|
|
752
770
|
pendingRuntimeState: this.context.getPendingLocalState(),
|
|
753
771
|
url: this.resolvedUrl.url,
|
|
772
|
+
protocol: this._protocolHandler.getProtocolState(),
|
|
773
|
+
term: this._protocolHandler.term,
|
|
774
|
+
clientId: this.clientId,
|
|
754
775
|
};
|
|
755
776
|
|
|
756
777
|
this.close();
|
|
@@ -808,7 +829,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
808
829
|
// starting to attach the container to storage.
|
|
809
830
|
// Also, this should only be fired in detached container.
|
|
810
831
|
this._attachState = AttachState.Attaching;
|
|
811
|
-
this.context.notifyAttaching();
|
|
832
|
+
this.context.notifyAttaching(getSnapshotTreeFromSerializedContainer(summary));
|
|
812
833
|
}
|
|
813
834
|
|
|
814
835
|
// Actually go and create the resolved document
|
|
@@ -860,7 +881,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
860
881
|
summary = combineAppAndProtocolSummary(appSummary, protocolSummary);
|
|
861
882
|
|
|
862
883
|
this._attachState = AttachState.Attaching;
|
|
863
|
-
this.context.notifyAttaching();
|
|
884
|
+
this.context.notifyAttaching(getSnapshotTreeFromSerializedContainer(summary));
|
|
864
885
|
|
|
865
886
|
await this.storageService.uploadSummaryWithContext(summary, {
|
|
866
887
|
referenceSequenceNumber: 0,
|
|
@@ -900,30 +921,6 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
900
921
|
);
|
|
901
922
|
}
|
|
902
923
|
|
|
903
|
-
/**
|
|
904
|
-
* Dictates whether or not the current container will automatically attempt to reconnect to the delta stream
|
|
905
|
-
* after receiving a disconnect event
|
|
906
|
-
* @param reconnect - Boolean indicating if reconnect should automatically occur
|
|
907
|
-
* @deprecated - 0.58, This API will be removed in 1.0
|
|
908
|
-
* Use `connect()` and `disconnect()` instead of `setAutoReconnect(true)` and `setAutoReconnect(false)` respectively
|
|
909
|
-
* See https://github.com/microsoft/FluidFramework/issues/9167 for context
|
|
910
|
-
*/
|
|
911
|
-
public setAutoReconnect(reconnect: boolean) {
|
|
912
|
-
if (this.closed) {
|
|
913
|
-
throw new Error("Attempting to setAutoReconnect() a closed Container");
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
const mode = reconnect ? ReconnectMode.Enabled : ReconnectMode.Disabled;
|
|
917
|
-
this.setAutoReconnectInternal(mode);
|
|
918
|
-
|
|
919
|
-
// If container state is not attached and resumed, then don't connect to delta stream. Also don't set the
|
|
920
|
-
// manual reconnection flag to true as we haven't made the initial connection yet.
|
|
921
|
-
if (reconnect && this._attachState === AttachState.Attached && this.resumedOpProcessingAfterLoad) {
|
|
922
|
-
// Ensure connection to web socket
|
|
923
|
-
this.connectToDeltaStream({ reason: "autoReconnect" });
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
|
|
927
924
|
private setAutoReconnectInternal(mode: ReconnectMode) {
|
|
928
925
|
const currentMode = this._deltaManager.connectionManager.reconnectMode;
|
|
929
926
|
|
|
@@ -987,23 +984,8 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
987
984
|
this.setAutoReconnectInternal(mode);
|
|
988
985
|
}
|
|
989
986
|
|
|
990
|
-
/**
|
|
991
|
-
* Have the container attempt to resume processing ops
|
|
992
|
-
* @deprecated - 0.58, This API will be removed in 1.0
|
|
993
|
-
* Use `connect()` instead
|
|
994
|
-
* See https://github.com/microsoft/FluidFramework/issues/9167 for context
|
|
995
|
-
*/
|
|
996
|
-
public resume() {
|
|
997
|
-
if (!this.closed) {
|
|
998
|
-
// Note: no need to fetch ops as we do it preemptively as part of DeltaManager.attachOpHandler().
|
|
999
|
-
// If there is gap, we will learn about it once connected, but the gap should be small (if any),
|
|
1000
|
-
// assuming that resume() is called quickly after initial container boot.
|
|
1001
|
-
this.resumeInternal({ reason: "DocumentOpenResume", fetchOpsFromStorage: false });
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
1004
|
-
|
|
1005
987
|
private resumeInternal(args: IConnectionArgs) {
|
|
1006
|
-
assert(!this.closed, 0x0d9 /* "Attempting to
|
|
988
|
+
assert(!this.closed, 0x0d9 /* "Attempting to connect() a closed DeltaManager" */);
|
|
1007
989
|
|
|
1008
990
|
// Resume processing ops
|
|
1009
991
|
if (!this.resumedOpProcessingAfterLoad) {
|
|
@@ -1095,7 +1077,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1095
1077
|
private async load(
|
|
1096
1078
|
specifiedVersion: string | undefined,
|
|
1097
1079
|
loadMode: IContainerLoadMode,
|
|
1098
|
-
pendingLocalState?:
|
|
1080
|
+
pendingLocalState?: IPendingContainerState,
|
|
1099
1081
|
) {
|
|
1100
1082
|
if (this._resolvedUrl === undefined) {
|
|
1101
1083
|
throw new Error("Attempting to load without a resolved url");
|
|
@@ -1123,14 +1105,28 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1123
1105
|
this.connectToDeltaStream(connectionArgs);
|
|
1124
1106
|
}
|
|
1125
1107
|
|
|
1126
|
-
|
|
1108
|
+
if (!pendingLocalState) {
|
|
1109
|
+
await this.connectStorageService();
|
|
1110
|
+
} else {
|
|
1111
|
+
// if we have pendingLocalState we can load without storage; don't wait for connection
|
|
1112
|
+
this.connectStorageService().catch((error) => this.close(error));
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1127
1115
|
this._attachState = AttachState.Attached;
|
|
1128
1116
|
|
|
1129
1117
|
// Fetch specified snapshot.
|
|
1130
|
-
const { snapshot, versionId } =
|
|
1131
|
-
|
|
1118
|
+
const { snapshot, versionId } = pendingLocalState === undefined
|
|
1119
|
+
? await this.fetchSnapshotTree(specifiedVersion)
|
|
1120
|
+
: { snapshot: undefined, versionId: undefined };
|
|
1121
|
+
assert(snapshot !== undefined || pendingLocalState !== undefined, 0x237 /* "Snapshot should exist" */);
|
|
1132
1122
|
|
|
1133
|
-
const attributes =
|
|
1123
|
+
const attributes: IDocumentAttributes = pendingLocalState === undefined
|
|
1124
|
+
? await this.getDocumentAttributes(this.storageService, snapshot)
|
|
1125
|
+
: {
|
|
1126
|
+
sequenceNumber: pendingLocalState.protocol.sequenceNumber,
|
|
1127
|
+
minimumSequenceNumber: pendingLocalState.protocol.minimumSequenceNumber,
|
|
1128
|
+
term: pendingLocalState.term,
|
|
1129
|
+
};
|
|
1134
1130
|
|
|
1135
1131
|
let opsBeforeReturnP: Promise<void> | undefined;
|
|
1136
1132
|
|
|
@@ -1154,15 +1150,21 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1154
1150
|
|
|
1155
1151
|
// ...load in the existing quorum
|
|
1156
1152
|
// Initialize the protocol handler
|
|
1157
|
-
this._protocolHandler =
|
|
1158
|
-
await this.initializeProtocolStateFromSnapshot(attributes, this.storageService, snapshot)
|
|
1153
|
+
this._protocolHandler = pendingLocalState === undefined
|
|
1154
|
+
? await this.initializeProtocolStateFromSnapshot(attributes, this.storageService, snapshot)
|
|
1155
|
+
: await this.initializeProtocolState(
|
|
1156
|
+
attributes,
|
|
1157
|
+
pendingLocalState.protocol.members,
|
|
1158
|
+
pendingLocalState.protocol.proposals,
|
|
1159
|
+
pendingLocalState.protocol.values,
|
|
1160
|
+
);
|
|
1159
1161
|
|
|
1160
1162
|
const codeDetails = this.getCodeDetailsFromQuorum();
|
|
1161
1163
|
await this.instantiateContext(
|
|
1162
1164
|
true, // existing
|
|
1163
1165
|
codeDetails,
|
|
1164
1166
|
snapshot,
|
|
1165
|
-
pendingLocalState,
|
|
1167
|
+
pendingLocalState?.pendingRuntimeState,
|
|
1166
1168
|
);
|
|
1167
1169
|
|
|
1168
1170
|
// Propagate current connection state through the system.
|
|
@@ -1186,7 +1188,10 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1186
1188
|
|
|
1187
1189
|
switch (loadMode.deltaConnection) {
|
|
1188
1190
|
case undefined:
|
|
1189
|
-
|
|
1191
|
+
// Note: no need to fetch ops as we do it preemptively as part of DeltaManager.attachOpHandler().
|
|
1192
|
+
// If there is gap, we will learn about it once connected, but the gap should be small (if any),
|
|
1193
|
+
// assuming that resumeInternal() is called quickly after initial container boot.
|
|
1194
|
+
this.resumeInternal({ reason: "DocumentLoad", fetchOpsFromStorage: false });
|
|
1190
1195
|
break;
|
|
1191
1196
|
case "delayed":
|
|
1192
1197
|
this.resumedOpProcessingAfterLoad = true;
|
|
@@ -1379,13 +1384,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1379
1384
|
});
|
|
1380
1385
|
|
|
1381
1386
|
// Track membership changes and update connection state accordingly
|
|
1382
|
-
|
|
1383
|
-
this.connectionStateHandler.receivedAddMemberEvent(clientId);
|
|
1384
|
-
});
|
|
1385
|
-
|
|
1386
|
-
protocol.quorum.on("removeMember", (clientId) => {
|
|
1387
|
-
this.connectionStateHandler.receivedRemoveMemberEvent(clientId);
|
|
1388
|
-
});
|
|
1387
|
+
this.connectionStateHandler.initProtocol(protocol);
|
|
1389
1388
|
|
|
1390
1389
|
protocol.quorum.on("addProposal", (proposal: ISequencedProposal) => {
|
|
1391
1390
|
if (proposal.key === "code" || proposal.key === "code2") {
|
|
@@ -1611,6 +1610,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1611
1610
|
online: OnlineStatus[isOnline()],
|
|
1612
1611
|
lastVisible: this.lastVisible !== undefined ? performance.now() - this.lastVisible : undefined,
|
|
1613
1612
|
checkpointSequenceNumber,
|
|
1613
|
+
quorumSize: this._protocolHandler?.quorum.getMembers().size,
|
|
1614
1614
|
...this._deltaManager.connectionProps,
|
|
1615
1615
|
});
|
|
1616
1616
|
|
|
@@ -1719,15 +1719,17 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1719
1719
|
// That means that if relay service changes settings, such changes will impact only newly booted
|
|
1720
1720
|
// clients.
|
|
1721
1721
|
// All existing will continue to use settings they got earlier.
|
|
1722
|
-
|
|
1722
|
+
assert(
|
|
1723
|
+
this.serviceConfiguration !== undefined,
|
|
1724
|
+
0x2e4 /* "there should be service config for active connection" */);
|
|
1723
1725
|
this.collabWindowTracker = new CollabWindowTracker(
|
|
1724
1726
|
(type, contents) => {
|
|
1725
1727
|
assert(this.activeConnection(),
|
|
1726
1728
|
0x241 /* "disconnect should result in stopSequenceNumberUpdate() call" */);
|
|
1727
1729
|
this.submitMessage(type, contents);
|
|
1728
1730
|
},
|
|
1729
|
-
noopTimeFrequency,
|
|
1730
|
-
noopCountFrequency,
|
|
1731
|
+
this.serviceConfiguration?.noopTimeFrequency,
|
|
1732
|
+
this.serviceConfiguration?.noopCountFrequency,
|
|
1731
1733
|
);
|
|
1732
1734
|
}
|
|
1733
1735
|
this.collabWindowTracker.scheduleSequenceNumberUpdate(message, result.immediateNoOp === true);
|
|
@@ -1738,29 +1740,6 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1738
1740
|
return result;
|
|
1739
1741
|
}
|
|
1740
1742
|
|
|
1741
|
-
/**
|
|
1742
|
-
* #260 (ADO)
|
|
1743
|
-
* back-compat: noopTimeFrequency & noopCountFrequency properties were added to
|
|
1744
|
-
* IClientConfiguration in 0.59.3000. During the integration, we must read the
|
|
1745
|
-
* available configuration from the loader options.
|
|
1746
|
-
*/
|
|
1747
|
-
private getNoopConfig(): [number | undefined, number | undefined] {
|
|
1748
|
-
assert(
|
|
1749
|
-
this.serviceConfiguration !== undefined,
|
|
1750
|
-
0x2e2, /* "there should be service config for active connection" */
|
|
1751
|
-
);
|
|
1752
|
-
|
|
1753
|
-
if (this.serviceConfiguration.noopTimeFrequency !== undefined ||
|
|
1754
|
-
this.serviceConfiguration.noopCountFrequency !== undefined) {
|
|
1755
|
-
return [
|
|
1756
|
-
this.serviceConfiguration.noopTimeFrequency as number,
|
|
1757
|
-
this.serviceConfiguration.noopCountFrequency as number,
|
|
1758
|
-
];
|
|
1759
|
-
}
|
|
1760
|
-
|
|
1761
|
-
return [this.loader.services.options?.noopTimeFrequency, this.loader.services.options?.noopCountFrequency];
|
|
1762
|
-
}
|
|
1763
|
-
|
|
1764
1743
|
private submitSignal(message: any) {
|
|
1765
1744
|
this._deltaManager.submitSignal(JSON.stringify(message));
|
|
1766
1745
|
}
|
|
@@ -1807,7 +1786,6 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1807
1786
|
private async instantiateContextDetached(
|
|
1808
1787
|
existing: boolean,
|
|
1809
1788
|
snapshot?: ISnapshotTree,
|
|
1810
|
-
pendingLocalState?: unknown,
|
|
1811
1789
|
) {
|
|
1812
1790
|
const codeDetails = this.getCodeDetailsFromQuorum();
|
|
1813
1791
|
if (codeDetails === undefined) {
|
|
@@ -1818,7 +1796,6 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1818
1796
|
existing,
|
|
1819
1797
|
codeDetails,
|
|
1820
1798
|
snapshot,
|
|
1821
|
-
pendingLocalState,
|
|
1822
1799
|
);
|
|
1823
1800
|
}
|
|
1824
1801
|
|
package/src/containerContext.ts
CHANGED
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
IProvideFluidCodeDetailsComparer,
|
|
22
22
|
ICodeDetailsLoader,
|
|
23
23
|
IFluidModuleWithDetails,
|
|
24
|
-
|
|
24
|
+
ISnapshotTreeWithBlobContents,
|
|
25
25
|
} from "@fluidframework/container-definitions";
|
|
26
26
|
import {
|
|
27
27
|
IRequest,
|
|
@@ -92,7 +92,9 @@ export class ContainerContext implements IContainerContext {
|
|
|
92
92
|
return this.container.clientId;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
/**
|
|
95
|
+
/**
|
|
96
|
+
* DISCLAIMER: this id is only for telemetry purposes. Not suitable for any other usages.
|
|
97
|
+
*/
|
|
96
98
|
public get id(): string {
|
|
97
99
|
const resolvedUrl = this.container.resolvedUrl;
|
|
98
100
|
if (isFluidResolvedUrl(resolvedUrl)) {
|
|
@@ -159,7 +161,7 @@ export class ContainerContext implements IContainerContext {
|
|
|
159
161
|
public readonly scope: FluidObject,
|
|
160
162
|
private readonly codeLoader: ICodeDetailsLoader,
|
|
161
163
|
private readonly _codeDetails: IFluidCodeDetails,
|
|
162
|
-
private
|
|
164
|
+
private _baseSnapshot: ISnapshotTree | undefined,
|
|
163
165
|
public readonly deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>,
|
|
164
166
|
quorum: IQuorum,
|
|
165
167
|
public readonly loader: ILoader,
|
|
@@ -287,7 +289,9 @@ export class ContainerContext implements IContainerContext {
|
|
|
287
289
|
return true;
|
|
288
290
|
}
|
|
289
291
|
|
|
290
|
-
public notifyAttaching() {
|
|
292
|
+
public notifyAttaching(snapshot: ISnapshotTreeWithBlobContents) {
|
|
293
|
+
this._baseSnapshot = snapshot;
|
|
294
|
+
this.runtime.notifyAttaching?.(snapshot);
|
|
291
295
|
this.runtime.setAttachState(AttachState.Attaching);
|
|
292
296
|
}
|
|
293
297
|
|
|
@@ -316,11 +320,7 @@ export class ContainerContext implements IContainerContext {
|
|
|
316
320
|
}
|
|
317
321
|
|
|
318
322
|
private async loadCodeModule(codeDetails: IFluidCodeDetails): Promise<IFluidModuleWithDetails> {
|
|
319
|
-
|
|
320
|
-
// Because the type system currently does not capture this in load,
|
|
321
|
-
// explicitly declare the type here to support both cases.
|
|
322
|
-
// See also comment about this below.
|
|
323
|
-
const loadCodeResult: IFluidModuleWithDetails | IFluidModule = await PerformanceEvent.timedExecAsync(
|
|
323
|
+
const loadCodeResult = await PerformanceEvent.timedExecAsync(
|
|
324
324
|
this.taggedLogger,
|
|
325
325
|
{ eventName: "CodeLoad" },
|
|
326
326
|
async () => this.codeLoader.load(codeDetails),
|
|
@@ -336,7 +336,7 @@ export class ContainerContext implements IContainerContext {
|
|
|
336
336
|
// If "module" is not in the result, we are using a legacy ICodeLoader. Fix the result up with details.
|
|
337
337
|
// Once usage drops to 0 we can remove this compat path.
|
|
338
338
|
this.taggedLogger.sendTelemetryEvent({ eventName: "LegacyCodeLoader" });
|
|
339
|
-
return
|
|
339
|
+
return loadCodeResult;
|
|
340
340
|
}
|
|
341
341
|
}
|
|
342
342
|
// #endregion
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
7
|
+
import { ISnapshotTreeWithBlobContents } from "@fluidframework/container-definitions";
|
|
7
8
|
import {
|
|
8
9
|
IDocumentStorageService,
|
|
9
10
|
IDocumentStorageServicePolicies,
|
|
@@ -14,11 +15,9 @@ import {
|
|
|
14
15
|
ISnapshotTree,
|
|
15
16
|
ISummaryHandle,
|
|
16
17
|
ISummaryTree,
|
|
17
|
-
ITree,
|
|
18
18
|
IVersion,
|
|
19
19
|
} from "@fluidframework/protocol-definitions";
|
|
20
20
|
import { IDetachedBlobStorage } from "./loader";
|
|
21
|
-
import { ISnapshotTreeWithBlobContents } from "./utils";
|
|
22
21
|
|
|
23
22
|
/**
|
|
24
23
|
* This class wraps the actual storage and make sure no wrong apis are called according to
|
|
@@ -70,10 +69,6 @@ export class ContainerStorageAdapter implements IDocumentStorageService {
|
|
|
70
69
|
return this.storageGetter().getVersions(versionId, count);
|
|
71
70
|
}
|
|
72
71
|
|
|
73
|
-
public async write(tree: ITree, parents: string[], message: string, ref: string): Promise<IVersion> {
|
|
74
|
-
return this.storageGetter().write(tree, parents, message, ref);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
72
|
public async uploadSummaryWithContext(summary: ISummaryTree, context: ISummaryContext): Promise<string> {
|
|
78
73
|
return this.storageGetter().uploadSummaryWithContext(summary, context);
|
|
79
74
|
}
|
package/src/deltaManagerProxy.ts
CHANGED
package/src/index.ts
CHANGED
package/src/loader.ts
CHANGED
|
@@ -17,9 +17,7 @@ import {
|
|
|
17
17
|
IFluidModule,
|
|
18
18
|
IHostLoader,
|
|
19
19
|
ILoader,
|
|
20
|
-
IPendingLocalState,
|
|
21
20
|
ILoaderOptions as ILoaderOptions1,
|
|
22
|
-
IProxyLoaderFactory,
|
|
23
21
|
LoaderHeader,
|
|
24
22
|
IProvideFluidCodeDetailsComparer,
|
|
25
23
|
IFluidCodeDetails,
|
|
@@ -47,7 +45,7 @@ import {
|
|
|
47
45
|
MultiUrlResolver,
|
|
48
46
|
MultiDocumentServiceFactory,
|
|
49
47
|
} from "@fluidframework/driver-utils";
|
|
50
|
-
import { Container } from "./container";
|
|
48
|
+
import { Container, IPendingContainerState } from "./container";
|
|
51
49
|
import { IParsedUrl, parseUrl } from "./utils";
|
|
52
50
|
import { pkgVersion } from "./packageVersion";
|
|
53
51
|
|
|
@@ -200,13 +198,6 @@ export interface ILoaderProps {
|
|
|
200
198
|
*/
|
|
201
199
|
readonly scope?: FluidObject;
|
|
202
200
|
|
|
203
|
-
/**
|
|
204
|
-
* Proxy loader factories for loading containers via proxy in other contexts,
|
|
205
|
-
* like web workers, or worker threads.
|
|
206
|
-
* @deprecated Not recommended for general use and will be removed in an upcoming release.
|
|
207
|
-
*/
|
|
208
|
-
readonly proxyLoaderFactories?: Map<string, IProxyLoaderFactory>;
|
|
209
|
-
|
|
210
201
|
/**
|
|
211
202
|
* The logger that all telemetry should be pushed to.
|
|
212
203
|
*/
|
|
@@ -257,13 +248,6 @@ export interface ILoaderServices {
|
|
|
257
248
|
*/
|
|
258
249
|
readonly scope: FluidObject;
|
|
259
250
|
|
|
260
|
-
/**
|
|
261
|
-
* Proxy loader factories for loading containers via proxy in other contexts,
|
|
262
|
-
* like web workers, or worker threads.
|
|
263
|
-
* @deprecated Not recommended for general use and will be removed in an upcoming release.
|
|
264
|
-
*/
|
|
265
|
-
readonly proxyLoaderFactories: Map<string, IProxyLoaderFactory>;
|
|
266
|
-
|
|
267
251
|
/**
|
|
268
252
|
* The logger downstream consumers should construct their loggers from
|
|
269
253
|
*/
|
|
@@ -318,7 +302,6 @@ export class Loader implements IHostLoader {
|
|
|
318
302
|
options: loaderProps.options ?? {},
|
|
319
303
|
scope,
|
|
320
304
|
subLogger: subMc.logger,
|
|
321
|
-
proxyLoaderFactories: loaderProps.proxyLoaderFactories ?? new Map<string, IProxyLoaderFactory>(),
|
|
322
305
|
detachedBlobStorage: loaderProps.detachedBlobStorage,
|
|
323
306
|
};
|
|
324
307
|
this.mc = loggerToMonitoringContext(
|
|
@@ -394,7 +377,7 @@ export class Loader implements IHostLoader {
|
|
|
394
377
|
|
|
395
378
|
private async resolveCore(
|
|
396
379
|
request: IRequest,
|
|
397
|
-
pendingLocalState?:
|
|
380
|
+
pendingLocalState?: IPendingContainerState,
|
|
398
381
|
): Promise<{ container: Container; parsed: IParsedUrl; }> {
|
|
399
382
|
const resolvedAsFluid = await this.services.urlResolver.resolve(request);
|
|
400
383
|
ensureFluidResolvedUrl(resolvedAsFluid);
|
|
@@ -436,7 +419,7 @@ export class Loader implements IHostLoader {
|
|
|
436
419
|
await this.loadContainer(
|
|
437
420
|
request,
|
|
438
421
|
resolvedAsFluid,
|
|
439
|
-
pendingLocalState
|
|
422
|
+
pendingLocalState);
|
|
440
423
|
}
|
|
441
424
|
|
|
442
425
|
if (container.deltaManager.lastSequenceNumber <= fromSequenceNumber) {
|
|
@@ -487,7 +470,7 @@ export class Loader implements IHostLoader {
|
|
|
487
470
|
private async loadContainer(
|
|
488
471
|
request: IRequest,
|
|
489
472
|
resolved: IFluidResolvedUrl,
|
|
490
|
-
pendingLocalState?:
|
|
473
|
+
pendingLocalState?: IPendingContainerState,
|
|
491
474
|
): Promise<Container> {
|
|
492
475
|
return Container.load(
|
|
493
476
|
this,
|
package/src/packageVersion.ts
CHANGED
|
@@ -31,7 +31,6 @@ export class ProtocolTreeStorageService implements IDocumentStorageService, IDis
|
|
|
31
31
|
|
|
32
32
|
getSnapshotTree = this.internalStorageService.getSnapshotTree.bind(this.internalStorageService);
|
|
33
33
|
getVersions = this.internalStorageService.getVersions.bind(this.internalStorageService);
|
|
34
|
-
write = this.internalStorageService.write.bind(this.internalStorageService);
|
|
35
34
|
createBlob = this.internalStorageService.createBlob.bind(this.internalStorageService);
|
|
36
35
|
readBlob = this.internalStorageService.readBlob.bind(this.internalStorageService);
|
|
37
36
|
downloadSummary = this.internalStorageService.downloadSummary.bind(this.internalStorageService);
|
|
@@ -15,7 +15,6 @@ import {
|
|
|
15
15
|
ISnapshotTree,
|
|
16
16
|
ISummaryHandle,
|
|
17
17
|
ISummaryTree,
|
|
18
|
-
ITree,
|
|
19
18
|
IVersion,
|
|
20
19
|
} from "@fluidframework/protocol-definitions";
|
|
21
20
|
import { IDisposable, ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
@@ -62,13 +61,6 @@ export class RetriableDocumentStorageService implements IDocumentStorageService,
|
|
|
62
61
|
);
|
|
63
62
|
}
|
|
64
63
|
|
|
65
|
-
public async write(tree: ITree, parents: string[], message: string, ref: string): Promise<IVersion> {
|
|
66
|
-
return this.runWithRetry(
|
|
67
|
-
async () => this.internalStorageService.write(tree, parents, message, ref),
|
|
68
|
-
"storage_write",
|
|
69
|
-
);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
64
|
public async uploadSummaryWithContext(summary: ISummaryTree, context: ISummaryContext): Promise<string> {
|
|
73
65
|
// Not using retry loop here. Couple reasons:
|
|
74
66
|
// 1. If client lost connectivity, then retry loop will result in uploading stale summary
|