@fluidframework/container-runtime 2.0.0-internal.5.4.0 → 2.0.0-internal.6.1.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/CHANGELOG.md +75 -0
- package/dist/batchTracker.d.ts +2 -1
- package/dist/batchTracker.d.ts.map +1 -1
- package/dist/batchTracker.js.map +1 -1
- package/dist/blobManager.d.ts +4 -1
- package/dist/blobManager.d.ts.map +1 -1
- package/dist/blobManager.js +61 -26
- package/dist/blobManager.js.map +1 -1
- package/dist/connectionTelemetry.js +10 -2
- package/dist/connectionTelemetry.js.map +1 -1
- package/dist/containerRuntime.d.ts +26 -11
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +189 -131
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStore.js +8 -2
- package/dist/dataStore.js.map +1 -1
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +24 -26
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStores.d.ts +20 -4
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/dataStores.js +107 -53
- package/dist/dataStores.js.map +1 -1
- package/dist/deltaManagerProxyBase.d.ts +35 -0
- package/dist/deltaManagerProxyBase.d.ts.map +1 -0
- package/dist/deltaManagerProxyBase.js +77 -0
- package/dist/deltaManagerProxyBase.js.map +1 -0
- package/dist/deltaManagerSummarizerProxy.d.ts +1 -1
- package/dist/deltaManagerSummarizerProxy.d.ts.map +1 -1
- package/dist/deltaManagerSummarizerProxy.js +2 -2
- package/dist/deltaManagerSummarizerProxy.js.map +1 -1
- package/dist/gc/garbageCollection.js +17 -20
- package/dist/gc/garbageCollection.js.map +1 -1
- package/dist/gc/gcConfigs.js +13 -11
- package/dist/gc/gcConfigs.js.map +1 -1
- package/dist/gc/gcHelpers.js +4 -6
- package/dist/gc/gcHelpers.js.map +1 -1
- package/dist/gc/gcSummaryStateTracker.js +4 -6
- package/dist/gc/gcSummaryStateTracker.js.map +1 -1
- package/dist/gc/gcTelemetry.d.ts.map +1 -1
- package/dist/gc/gcTelemetry.js +55 -37
- package/dist/gc/gcTelemetry.js.map +1 -1
- package/dist/id-compressor/idCompressor.js +49 -51
- package/dist/id-compressor/idCompressor.js.map +1 -1
- package/dist/id-compressor/idRange.js +2 -2
- package/dist/id-compressor/idRange.js.map +1 -1
- package/dist/id-compressor/sessionIdNormalizer.js +11 -16
- package/dist/id-compressor/sessionIdNormalizer.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/opLifecycle/batchManager.js +10 -6
- package/dist/opLifecycle/batchManager.js.map +1 -1
- package/dist/opLifecycle/opCompressor.js +6 -1
- package/dist/opLifecycle/opCompressor.js.map +1 -1
- package/dist/opLifecycle/opDecompressor.js +11 -9
- package/dist/opLifecycle/opDecompressor.js.map +1 -1
- package/dist/opLifecycle/opGroupingManager.js +13 -5
- package/dist/opLifecycle/opGroupingManager.js.map +1 -1
- package/dist/opLifecycle/opSplitter.js +10 -6
- package/dist/opLifecycle/opSplitter.js.map +1 -1
- package/dist/opLifecycle/outbox.js +1 -2
- package/dist/opLifecycle/outbox.js.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.js +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/dist/opProperties.js +1 -2
- package/dist/opProperties.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/pendingStateManager.d.ts +2 -2
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +22 -22
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/scheduleManager.js +14 -10
- package/dist/scheduleManager.js.map +1 -1
- package/dist/summary/orderedClientElection.d.ts +2 -1
- package/dist/summary/orderedClientElection.d.ts.map +1 -1
- package/dist/summary/orderedClientElection.js +17 -18
- package/dist/summary/orderedClientElection.js.map +1 -1
- package/dist/summary/runningSummarizer.d.ts.map +1 -1
- package/dist/summary/runningSummarizer.js +35 -57
- package/dist/summary/runningSummarizer.js.map +1 -1
- package/dist/summary/summarizer.js +4 -7
- package/dist/summary/summarizer.js.map +1 -1
- package/dist/summary/summarizerClientElection.js +5 -9
- package/dist/summary/summarizerClientElection.js.map +1 -1
- package/dist/summary/summarizerHeuristics.js +8 -12
- package/dist/summary/summarizerHeuristics.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.js +22 -15
- package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.js +2 -4
- package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js +17 -16
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/dist/summary/summaryCollection.js +3 -5
- package/dist/summary/summaryCollection.js.map +1 -1
- package/dist/summary/summaryFormat.js +1 -2
- package/dist/summary/summaryFormat.js.map +1 -1
- package/dist/summary/summaryGenerator.d.ts.map +1 -1
- package/dist/summary/summaryGenerator.js +62 -21
- package/dist/summary/summaryGenerator.js.map +1 -1
- package/dist/summary/summaryManager.js +3 -5
- package/dist/summary/summaryManager.js.map +1 -1
- package/lib/batchTracker.d.ts +2 -1
- package/lib/batchTracker.d.ts.map +1 -1
- package/lib/batchTracker.js.map +1 -1
- package/lib/blobManager.d.ts +4 -1
- package/lib/blobManager.d.ts.map +1 -1
- package/lib/blobManager.js +61 -26
- package/lib/blobManager.js.map +1 -1
- package/lib/connectionTelemetry.js +10 -2
- package/lib/connectionTelemetry.js.map +1 -1
- package/lib/containerRuntime.d.ts +26 -11
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +189 -131
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStore.js +8 -2
- package/lib/dataStore.js.map +1 -1
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +24 -26
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStores.d.ts +20 -4
- package/lib/dataStores.d.ts.map +1 -1
- package/lib/dataStores.js +107 -53
- package/lib/dataStores.js.map +1 -1
- package/lib/deltaManagerProxyBase.d.ts +35 -0
- package/lib/deltaManagerProxyBase.d.ts.map +1 -0
- package/lib/deltaManagerProxyBase.js +73 -0
- package/lib/deltaManagerProxyBase.js.map +1 -0
- package/lib/deltaManagerSummarizerProxy.d.ts +1 -1
- package/lib/deltaManagerSummarizerProxy.d.ts.map +1 -1
- package/lib/deltaManagerSummarizerProxy.js +1 -1
- package/lib/deltaManagerSummarizerProxy.js.map +1 -1
- package/lib/gc/garbageCollection.js +17 -20
- package/lib/gc/garbageCollection.js.map +1 -1
- package/lib/gc/gcConfigs.js +13 -11
- package/lib/gc/gcConfigs.js.map +1 -1
- package/lib/gc/gcHelpers.js +4 -6
- package/lib/gc/gcHelpers.js.map +1 -1
- package/lib/gc/gcSummaryStateTracker.js +4 -6
- package/lib/gc/gcSummaryStateTracker.js.map +1 -1
- package/lib/gc/gcTelemetry.d.ts.map +1 -1
- package/lib/gc/gcTelemetry.js +55 -37
- package/lib/gc/gcTelemetry.js.map +1 -1
- package/lib/id-compressor/idCompressor.js +49 -51
- package/lib/id-compressor/idCompressor.js.map +1 -1
- package/lib/id-compressor/idRange.js +2 -2
- package/lib/id-compressor/idRange.js.map +1 -1
- package/lib/id-compressor/sessionIdNormalizer.js +11 -16
- package/lib/id-compressor/sessionIdNormalizer.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/opLifecycle/batchManager.js +10 -6
- package/lib/opLifecycle/batchManager.js.map +1 -1
- package/lib/opLifecycle/opCompressor.js +6 -1
- package/lib/opLifecycle/opCompressor.js.map +1 -1
- package/lib/opLifecycle/opDecompressor.js +11 -9
- package/lib/opLifecycle/opDecompressor.js.map +1 -1
- package/lib/opLifecycle/opGroupingManager.js +13 -5
- package/lib/opLifecycle/opGroupingManager.js.map +1 -1
- package/lib/opLifecycle/opSplitter.js +10 -6
- package/lib/opLifecycle/opSplitter.js.map +1 -1
- package/lib/opLifecycle/outbox.js +1 -2
- package/lib/opLifecycle/outbox.js.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.js +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/lib/opProperties.js +1 -2
- package/lib/opProperties.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/pendingStateManager.d.ts +2 -2
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +22 -22
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/scheduleManager.js +14 -10
- package/lib/scheduleManager.js.map +1 -1
- package/lib/summary/orderedClientElection.d.ts +2 -1
- package/lib/summary/orderedClientElection.d.ts.map +1 -1
- package/lib/summary/orderedClientElection.js +17 -18
- package/lib/summary/orderedClientElection.js.map +1 -1
- package/lib/summary/runningSummarizer.d.ts.map +1 -1
- package/lib/summary/runningSummarizer.js +35 -57
- package/lib/summary/runningSummarizer.js.map +1 -1
- package/lib/summary/summarizer.js +4 -7
- package/lib/summary/summarizer.js.map +1 -1
- package/lib/summary/summarizerClientElection.js +5 -9
- package/lib/summary/summarizerClientElection.js.map +1 -1
- package/lib/summary/summarizerHeuristics.js +8 -12
- package/lib/summary/summarizerHeuristics.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.js +22 -15
- package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.js +2 -4
- package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js +17 -16
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/lib/summary/summaryCollection.js +3 -5
- package/lib/summary/summaryCollection.js.map +1 -1
- package/lib/summary/summaryFormat.js +1 -2
- package/lib/summary/summaryFormat.js.map +1 -1
- package/lib/summary/summaryGenerator.d.ts.map +1 -1
- package/lib/summary/summaryGenerator.js +62 -21
- package/lib/summary/summaryGenerator.js.map +1 -1
- package/lib/summary/summaryManager.js +3 -5
- package/lib/summary/summaryManager.js.map +1 -1
- package/package.json +19 -19
- package/src/batchTracker.ts +2 -1
- package/src/blobManager.ts +43 -2
- package/src/containerRuntime.ts +95 -67
- package/src/dataStore.ts +7 -1
- package/src/dataStoreContext.ts +1 -2
- package/src/dataStores.ts +95 -55
- package/src/deltaManagerProxyBase.ts +111 -0
- package/src/deltaManagerSummarizerProxy.ts +2 -1
- package/src/gc/gcTelemetry.ts +1 -2
- package/src/index.ts +0 -1
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +12 -15
- package/src/summary/orderedClientElection.ts +2 -1
- package/src/summary/runningSummarizer.ts +9 -31
- package/src/summary/summaryGenerator.ts +0 -1
package/lib/containerRuntime.js
CHANGED
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
-
var t = {};
|
|
3
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
-
t[p] = s[p];
|
|
5
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
-
t[p[i]] = s[p[i]];
|
|
9
|
-
}
|
|
10
|
-
return t;
|
|
11
|
-
};
|
|
12
1
|
import { AttachState, LoaderHeader, } from "@fluidframework/container-definitions";
|
|
13
2
|
import { assert, delay, Trace, TypedEventEmitter, unreachableCase, } from "@fluidframework/common-utils";
|
|
14
3
|
import { LazyPromise } from "@fluidframework/core-utils";
|
|
@@ -151,7 +140,7 @@ export function getDeviceSpec() {
|
|
|
151
140
|
};
|
|
152
141
|
}
|
|
153
142
|
}
|
|
154
|
-
catch
|
|
143
|
+
catch { }
|
|
155
144
|
return {};
|
|
156
145
|
}
|
|
157
146
|
/**
|
|
@@ -176,9 +165,12 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
176
165
|
/**
|
|
177
166
|
* @internal
|
|
178
167
|
*/
|
|
179
|
-
constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, idCompressor, requestHandler, summaryConfiguration
|
|
180
|
-
|
|
181
|
-
|
|
168
|
+
constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, idCompressor, requestHandler, summaryConfiguration = {
|
|
169
|
+
// the defaults
|
|
170
|
+
...DefaultSummaryConfiguration,
|
|
171
|
+
// the runtime configuration overrides
|
|
172
|
+
...runtimeOptions.summaryOptions?.summaryConfigOverrides,
|
|
173
|
+
}, initializeEntryPoint) {
|
|
182
174
|
super();
|
|
183
175
|
this.registry = registry;
|
|
184
176
|
this.runtimeOptions = runtimeOptions;
|
|
@@ -248,7 +240,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
248
240
|
this.options = options;
|
|
249
241
|
this.clientDetails = clientDetails;
|
|
250
242
|
this.isSummarizerClient = this.clientDetails.type === summarizerClientType;
|
|
251
|
-
this.loadedFromVersionId =
|
|
243
|
+
this.loadedFromVersionId = context.getLoadedFromVersion()?.id;
|
|
252
244
|
this._getClientId = () => context.clientId;
|
|
253
245
|
this._getAttachState = () => context.attachState;
|
|
254
246
|
this.getAbsoluteUrl = async (relativeUrl) => {
|
|
@@ -265,15 +257,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
265
257
|
this.on("dirty", () => context.updateDirtyContainerState(true));
|
|
266
258
|
this.on("saved", () => context.updateDirtyContainerState(false));
|
|
267
259
|
// In old loaders without dispose functionality, closeFn is equivalent but will also switch container to readonly mode
|
|
268
|
-
this.disposeFn = disposeFn
|
|
260
|
+
this.disposeFn = disposeFn ?? closeFn;
|
|
269
261
|
// In cases of summarizer, we want to dispose instead since consumer doesn't interact with this container
|
|
270
|
-
this.closeFn = this.isSummarizerClient
|
|
271
|
-
? this.disposeFn
|
|
272
|
-
: (error) => {
|
|
273
|
-
closeFn(error);
|
|
274
|
-
// Also call disposeFn to retain functionality of runtime being disposed on close
|
|
275
|
-
disposeFn === null || disposeFn === void 0 ? void 0 : disposeFn(error);
|
|
276
|
-
};
|
|
262
|
+
this.closeFn = this.isSummarizerClient ? this.disposeFn : closeFn;
|
|
277
263
|
this.mc = createChildMonitoringContext({
|
|
278
264
|
logger: this.logger,
|
|
279
265
|
namespace: "ContainerRuntime",
|
|
@@ -283,15 +269,15 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
283
269
|
// get the values from the metadata blob.
|
|
284
270
|
if (existing) {
|
|
285
271
|
this.createContainerMetadata = {
|
|
286
|
-
createContainerRuntimeVersion: metadata
|
|
287
|
-
createContainerTimestamp: metadata
|
|
272
|
+
createContainerRuntimeVersion: metadata?.createContainerRuntimeVersion,
|
|
273
|
+
createContainerTimestamp: metadata?.createContainerTimestamp,
|
|
288
274
|
};
|
|
289
275
|
// summaryNumber was renamed from summaryCount. For older docs that haven't been opened for a long time,
|
|
290
276
|
// the count is reset to 0.
|
|
291
|
-
loadSummaryNumber =
|
|
277
|
+
loadSummaryNumber = metadata?.summaryNumber ?? 0;
|
|
292
278
|
// Enabling the IdCompressor is a one-way operation and we only want to
|
|
293
279
|
// allow new containers to turn it on
|
|
294
|
-
this.idCompressorEnabled =
|
|
280
|
+
this.idCompressorEnabled = metadata?.idCompressorEnabled ?? false;
|
|
295
281
|
}
|
|
296
282
|
else {
|
|
297
283
|
this.createContainerMetadata = {
|
|
@@ -300,22 +286,23 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
300
286
|
};
|
|
301
287
|
loadSummaryNumber = 0;
|
|
302
288
|
this.idCompressorEnabled =
|
|
303
|
-
|
|
289
|
+
this.mc.config.getBoolean("Fluid.ContainerRuntime.IdCompressorEnabled") ??
|
|
290
|
+
idCompressor !== undefined;
|
|
304
291
|
}
|
|
305
292
|
this.nextSummaryNumber = loadSummaryNumber + 1;
|
|
306
|
-
this.messageAtLastSummary = metadata
|
|
293
|
+
this.messageAtLastSummary = metadata?.message;
|
|
307
294
|
// Note that we only need to pull the *initial* connected state from the context.
|
|
308
295
|
// Later updates come through calls to setConnectionState.
|
|
309
296
|
this._connected = connected;
|
|
310
|
-
this.gcTombstoneEnforcementAllowed = shouldAllowGcTombstoneEnforcement(
|
|
297
|
+
this.gcTombstoneEnforcementAllowed = shouldAllowGcTombstoneEnforcement(metadata?.gcFeatureMatrix?.tombstoneGeneration /* persisted */, this.runtimeOptions.gcOptions[gcTombstoneGenerationOptionName] /* current */);
|
|
311
298
|
this.mc.logger.sendTelemetryEvent({
|
|
312
299
|
eventName: "GCFeatureMatrix",
|
|
313
|
-
metadataValue: JSON.stringify(metadata
|
|
300
|
+
metadataValue: JSON.stringify(metadata?.gcFeatureMatrix),
|
|
314
301
|
inputs: JSON.stringify({
|
|
315
302
|
gcOptions_gcTombstoneGeneration: this.runtimeOptions.gcOptions[gcTombstoneGenerationOptionName],
|
|
316
303
|
}),
|
|
317
304
|
});
|
|
318
|
-
this.telemetryDocumentId =
|
|
305
|
+
this.telemetryDocumentId = metadata?.telemetryDocumentId ?? uuid();
|
|
319
306
|
this.disableAttachReorder = this.mc.config.getBoolean("Fluid.ContainerRuntime.disableAttachOpReorder");
|
|
320
307
|
const disableChunking = this.mc.config.getBoolean("Fluid.ContainerRuntime.CompressionChunkingDisabled");
|
|
321
308
|
const opGroupingManager = new OpGroupingManager(this.groupedBatchingEnabled);
|
|
@@ -338,9 +325,10 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
338
325
|
this.idCompressor = idCompressor;
|
|
339
326
|
}
|
|
340
327
|
this.maxConsecutiveReconnects =
|
|
341
|
-
|
|
328
|
+
this.mc.config.getNumber(maxConsecutiveReconnectsKey) ??
|
|
329
|
+
this.defaultMaxConsecutiveReconnects;
|
|
342
330
|
if (runtimeOptions.flushMode === FlushModeExperimental.Async &&
|
|
343
|
-
|
|
331
|
+
supportedFeatures?.get("referenceSequenceNumbers") !== true) {
|
|
344
332
|
// The loader does not support reference sequence numbers, falling back on FlushMode.TurnBased
|
|
345
333
|
this.mc.logger.sendErrorEvent({ eventName: "FlushModeFallback" });
|
|
346
334
|
this._flushMode = FlushMode.TurnBased;
|
|
@@ -349,7 +337,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
349
337
|
this._flushMode = runtimeOptions.flushMode;
|
|
350
338
|
}
|
|
351
339
|
const pendingRuntimeState = pendingLocalState;
|
|
352
|
-
const maxSnapshotCacheDurationMs =
|
|
340
|
+
const maxSnapshotCacheDurationMs = this._storage?.policies?.maximumCacheDurationMs;
|
|
353
341
|
if (maxSnapshotCacheDurationMs !== undefined &&
|
|
354
342
|
maxSnapshotCacheDurationMs > 5 * 24 * 60 * 60 * 1000) {
|
|
355
343
|
// This is a runtime enforcement of what's already explicit in the policy's type itself,
|
|
@@ -367,7 +355,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
367
355
|
createContainerMetadata: this.createContainerMetadata,
|
|
368
356
|
isSummarizerClient: this.isSummarizerClient,
|
|
369
357
|
getNodePackagePath: async (nodePath) => this.getGCNodePackagePath(nodePath),
|
|
370
|
-
getLastSummaryTimestampMs: () =>
|
|
358
|
+
getLastSummaryTimestampMs: () => this.messageAtLastSummary?.timestamp,
|
|
371
359
|
readAndParseBlob: async (id) => readAndParse(this.storage, id),
|
|
372
360
|
// GC runs in summarizer client and needs access to the real (non-proxy) active information. The proxy
|
|
373
361
|
// delta manager would always return false for summarizer client.
|
|
@@ -405,7 +393,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
405
393
|
blobId,
|
|
406
394
|
});
|
|
407
395
|
}
|
|
408
|
-
}, (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"), (blobPath) => this.garbageCollector.isNodeDeleted(blobPath), this, pendingRuntimeState
|
|
396
|
+
}, (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"), (blobPath) => this.garbageCollector.isNodeDeleted(blobPath), this, pendingRuntimeState?.pendingAttachmentBlobs, (error) => this.closeFn(error));
|
|
409
397
|
this.scheduleManager = new ScheduleManager(this.innerDeltaManager, this, () => this.clientId, createChildLogger({ logger: this.logger, namespace: "ScheduleManager" }));
|
|
410
398
|
this.pendingStateManager = new PendingStateManager({
|
|
411
399
|
applyStashedOp: this.applyStashedOp.bind(this),
|
|
@@ -415,7 +403,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
415
403
|
reSubmit: this.reSubmit.bind(this),
|
|
416
404
|
reSubmitBatch: this.reSubmitBatch.bind(this),
|
|
417
405
|
isActiveConnection: () => this.innerDeltaManager.active,
|
|
418
|
-
}, pendingRuntimeState
|
|
406
|
+
}, pendingRuntimeState?.pending, this.logger);
|
|
419
407
|
const disableCompression = this.mc.config.getBoolean("Fluid.ContainerRuntime.CompressionDisabled");
|
|
420
408
|
const compressionOptions = disableCompression === true
|
|
421
409
|
? {
|
|
@@ -456,9 +444,10 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
456
444
|
this._audience = audience;
|
|
457
445
|
this.summaryStateUpdateMethod = this.mc.config.getString("Fluid.ContainerRuntime.Test.SummaryStateUpdateMethodV2");
|
|
458
446
|
const closeSummarizerDelayOverride = this.mc.config.getNumber("Fluid.ContainerRuntime.Test.CloseSummarizerDelayOverrideMs");
|
|
459
|
-
this.closeSummarizerDelayMs = closeSummarizerDelayOverride
|
|
447
|
+
this.closeSummarizerDelayMs = closeSummarizerDelayOverride ?? defaultCloseSummarizerDelayMs;
|
|
460
448
|
this.validateSummaryBeforeUpload =
|
|
461
|
-
|
|
449
|
+
this.mc.config.getBoolean("Fluid.ContainerRuntime.Test.ValidateSummaryBeforeUpload") ??
|
|
450
|
+
false;
|
|
462
451
|
this.summaryCollection = new SummaryCollection(this.deltaManager, this.logger);
|
|
463
452
|
this.dirtyContainer =
|
|
464
453
|
this.attachState !== AttachState.Attached ||
|
|
@@ -473,7 +462,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
473
462
|
namespace: "OrderedClientElection",
|
|
474
463
|
});
|
|
475
464
|
const orderedClientCollection = new OrderedClientCollection(orderedClientLogger, this.innerDeltaManager, this._quorum);
|
|
476
|
-
const orderedClientElectionForSummarizer = new OrderedClientElection(orderedClientLogger, orderedClientCollection, electedSummarizerData
|
|
465
|
+
const orderedClientElectionForSummarizer = new OrderedClientElection(orderedClientLogger, orderedClientCollection, electedSummarizerData ?? this.innerDeltaManager.lastSequenceNumber, SummarizerClientElection.isClientEligible);
|
|
477
466
|
this.summarizerClientElection = new SummarizerClientElection(orderedClientLogger, this.summaryCollection, orderedClientElectionForSummarizer, this.maxOpsSinceLastSummary);
|
|
478
467
|
if (this.isSummarizerClient) {
|
|
479
468
|
this._summarizer = new Summarizer(this /* ISummarizerRuntime */, () => this.summaryConfiguration, this /* ISummarizerInternalsProvider */, this.handleContext, this.summaryCollection, async (runtime) => RunWhileConnectedCoordinator.create(runtime,
|
|
@@ -534,8 +523,20 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
534
523
|
this.replayPendingStates();
|
|
535
524
|
});
|
|
536
525
|
// logging hardware telemetry
|
|
537
|
-
logger.sendTelemetryEvent(
|
|
538
|
-
|
|
526
|
+
logger.sendTelemetryEvent({
|
|
527
|
+
eventName: "DeviceSpec",
|
|
528
|
+
...getDeviceSpec(),
|
|
529
|
+
});
|
|
530
|
+
this.mc.logger.sendTelemetryEvent({
|
|
531
|
+
eventName: "ContainerLoadStats",
|
|
532
|
+
...this.createContainerMetadata,
|
|
533
|
+
...this.dataStores.containerLoadStats,
|
|
534
|
+
summaryNumber: loadSummaryNumber,
|
|
535
|
+
summaryFormatVersion: metadata?.summaryFormatVersion,
|
|
536
|
+
disableIsolatedChannels: metadata?.disableIsolatedChannels,
|
|
537
|
+
gcVersion: metadata?.gcFeature,
|
|
538
|
+
options: JSON.stringify(runtimeOptions),
|
|
539
|
+
featureGates: JSON.stringify({
|
|
539
540
|
disableCompression,
|
|
540
541
|
disableOpReentryCheck,
|
|
541
542
|
disableChunking,
|
|
@@ -544,7 +545,10 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
544
545
|
idCompressorEnabled: this.idCompressorEnabled,
|
|
545
546
|
summaryStateUpdateMethod: this.summaryStateUpdateMethod,
|
|
546
547
|
closeSummarizerDelayOverride,
|
|
547
|
-
}),
|
|
548
|
+
}),
|
|
549
|
+
telemetryDocumentId: this.telemetryDocumentId,
|
|
550
|
+
groupedBatchingEnabled: this.groupedBatchingEnabled,
|
|
551
|
+
});
|
|
548
552
|
ReportOpPerfTelemetry(this.clientId, this.deltaManager, this.logger);
|
|
549
553
|
BindBatchTracker(this, this.logger);
|
|
550
554
|
this.entryPoint = new LazyPromise(async () => {
|
|
@@ -552,9 +556,12 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
552
556
|
assert(this._summarizer !== undefined, 0x5bf /* Summarizer object is undefined in a summarizer client */);
|
|
553
557
|
return this._summarizer;
|
|
554
558
|
}
|
|
555
|
-
return initializeEntryPoint
|
|
559
|
+
return initializeEntryPoint?.(this);
|
|
556
560
|
});
|
|
557
561
|
}
|
|
562
|
+
/**
|
|
563
|
+
* @deprecated - Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
|
|
564
|
+
*/
|
|
558
565
|
get IFluidRouter() {
|
|
559
566
|
return this;
|
|
560
567
|
}
|
|
@@ -600,12 +607,12 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
600
607
|
* This object should provide all the functionality that the Container is expected to provide to the loader layer.
|
|
601
608
|
*/
|
|
602
609
|
static async loadRuntime(params) {
|
|
603
|
-
var _a, _b, _c, _d, _e, _f;
|
|
604
610
|
const { context, registryEntries, existing, requestHandler, runtimeOptions = {}, containerScope = {}, containerRuntimeCtor = ContainerRuntime, initializeEntryPoint, } = params;
|
|
605
611
|
// If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
|
|
606
612
|
// back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
|
|
607
613
|
const backCompatContext = context;
|
|
608
|
-
const passLogger =
|
|
614
|
+
const passLogger = backCompatContext.taggedLogger ??
|
|
615
|
+
new TaggedLoggerAdapter(backCompatContext.logger);
|
|
609
616
|
const logger = createChildLogger({
|
|
610
617
|
logger: passLogger,
|
|
611
618
|
properties: {
|
|
@@ -617,8 +624,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
617
624
|
const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, compressionOptions = defaultCompressionConfig, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, enableRuntimeIdCompressor = false, chunkSizeInBytes = defaultChunkSizeInBytes, enableOpReentryCheck = false, enableGroupedBatching = false, } = runtimeOptions;
|
|
618
625
|
const registry = new FluidDataStoreRegistry(registryEntries);
|
|
619
626
|
const tryFetchBlob = async (blobName) => {
|
|
620
|
-
|
|
621
|
-
const blobId = (_a = context.baseSnapshot) === null || _a === void 0 ? void 0 : _a.blobs[blobName];
|
|
627
|
+
const blobId = context.baseSnapshot?.blobs[blobName];
|
|
622
628
|
if (context.baseSnapshot && blobId) {
|
|
623
629
|
// IContainerContext storage api return type still has undefined in 0.39 package version.
|
|
624
630
|
// So once we release 0.40 container-defn package we can remove this check.
|
|
@@ -633,16 +639,15 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
633
639
|
tryFetchBlob(aliasBlobName),
|
|
634
640
|
tryFetchBlob(idCompressorBlobName),
|
|
635
641
|
]);
|
|
636
|
-
const loadExisting = existing === true || context.existing === true;
|
|
637
642
|
// read snapshot blobs needed for BlobManager to load
|
|
638
|
-
const blobManagerSnapshot = await BlobManager.load(
|
|
643
|
+
const blobManagerSnapshot = await BlobManager.load(context.baseSnapshot?.trees[blobsTreeName], async (id) => {
|
|
639
644
|
// IContainerContext storage api return type still has undefined in 0.39 package version.
|
|
640
645
|
// So once we release 0.40 container-defn package we can remove this check.
|
|
641
646
|
assert(context.storage !== undefined, 0x256 /* "storage undefined in attached container" */);
|
|
642
647
|
return readAndParse(context.storage, id);
|
|
643
648
|
});
|
|
644
649
|
// Verify summary runtime sequence number matches protocol sequence number.
|
|
645
|
-
const runtimeSequenceNumber =
|
|
650
|
+
const runtimeSequenceNumber = metadata?.message?.sequenceNumber;
|
|
646
651
|
// When we load with pending state, we reuse an old snapshot so we don't expect these numbers to match
|
|
647
652
|
if (!context.pendingLocalState && runtimeSequenceNumber !== undefined) {
|
|
648
653
|
const protocolSequenceNumber = context.deltaManager.initialSequenceNumber;
|
|
@@ -657,13 +662,11 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
657
662
|
logger.sendErrorEvent({ eventName: "SequenceNumberMismatch" }, error);
|
|
658
663
|
}
|
|
659
664
|
else {
|
|
660
|
-
// Call both close and dispose as closeFn implementation will no longer dispose runtime in future
|
|
661
665
|
context.closeFn(error);
|
|
662
|
-
(_d = context.disposeFn) === null || _d === void 0 ? void 0 : _d.call(context, error);
|
|
663
666
|
}
|
|
664
667
|
}
|
|
665
668
|
}
|
|
666
|
-
const idCompressorEnabled =
|
|
669
|
+
const idCompressorEnabled = metadata?.idCompressorEnabled ?? runtimeOptions.enableRuntimeIdCompressor ?? false;
|
|
667
670
|
let idCompressor;
|
|
668
671
|
if (idCompressorEnabled) {
|
|
669
672
|
const { IdCompressor, createSessionId } = await import("./id-compressor");
|
|
@@ -672,7 +675,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
672
675
|
? IdCompressor.deserialize(serializedIdCompressor, createSessionId())
|
|
673
676
|
: new IdCompressor(createSessionId(), logger);
|
|
674
677
|
}
|
|
675
|
-
const runtime = new containerRuntimeCtor(context, registry, metadata, electedSummarizerData, chunks
|
|
678
|
+
const runtime = new containerRuntimeCtor(context, registry, metadata, electedSummarizerData, chunks ?? [], aliases ?? [], {
|
|
676
679
|
summaryOptions,
|
|
677
680
|
gcOptions,
|
|
678
681
|
loadSequenceNumberVerification,
|
|
@@ -683,7 +686,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
683
686
|
enableRuntimeIdCompressor,
|
|
684
687
|
enableOpReentryCheck,
|
|
685
688
|
enableGroupedBatching,
|
|
686
|
-
}, containerScope, logger,
|
|
689
|
+
}, containerScope, logger, existing, blobManagerSnapshot, context.storage, idCompressor, requestHandler, undefined, // summaryConfiguration
|
|
687
690
|
initializeEntryPoint);
|
|
688
691
|
// It's possible to have ops with a reference sequence number of 0. Op sequence numbers start
|
|
689
692
|
// at 1, so we won't see a replayed saved op with a sequence number of 0.
|
|
@@ -739,8 +742,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
739
742
|
}
|
|
740
743
|
/** clientId of parent (non-summarizing) container that owns summarizer container */
|
|
741
744
|
get summarizerClientId() {
|
|
742
|
-
|
|
743
|
-
return (_a = this.summarizerClientElection) === null || _a === void 0 ? void 0 : _a.electedClientId;
|
|
745
|
+
return this.summarizerClientElection?.electedClientId;
|
|
744
746
|
}
|
|
745
747
|
get disposed() {
|
|
746
748
|
return this._disposed;
|
|
@@ -777,7 +779,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
777
779
|
await this.garbageCollector.initializeBaseState();
|
|
778
780
|
}
|
|
779
781
|
dispose(error) {
|
|
780
|
-
var _a;
|
|
781
782
|
if (this._disposed) {
|
|
782
783
|
return;
|
|
783
784
|
}
|
|
@@ -792,7 +793,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
792
793
|
this.summaryManager.dispose();
|
|
793
794
|
}
|
|
794
795
|
this.garbageCollector.dispose();
|
|
795
|
-
|
|
796
|
+
this._summarizer?.dispose();
|
|
796
797
|
this.dataStores.dispose();
|
|
797
798
|
this.pendingStateManager.dispose();
|
|
798
799
|
this.emit("dispose");
|
|
@@ -801,6 +802,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
801
802
|
/**
|
|
802
803
|
* Notifies this object about the request made to the container.
|
|
803
804
|
* @param request - Request made to the handler.
|
|
805
|
+
* @deprecated - Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
|
|
804
806
|
*/
|
|
805
807
|
async request(request) {
|
|
806
808
|
try {
|
|
@@ -867,19 +869,17 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
867
869
|
return this.entryPoint;
|
|
868
870
|
}
|
|
869
871
|
internalId(maybeAlias) {
|
|
870
|
-
|
|
871
|
-
return (_a = this.dataStores.aliases.get(maybeAlias)) !== null && _a !== void 0 ? _a : maybeAlias;
|
|
872
|
+
return this.dataStores.aliases.get(maybeAlias) ?? maybeAlias;
|
|
872
873
|
}
|
|
873
874
|
async getDataStoreFromRequest(id, request) {
|
|
874
|
-
var _a, _b, _c;
|
|
875
875
|
const headerData = {};
|
|
876
|
-
if (typeof
|
|
876
|
+
if (typeof request.headers?.[RuntimeHeaders.wait] === "boolean") {
|
|
877
877
|
headerData.wait = request.headers[RuntimeHeaders.wait];
|
|
878
878
|
}
|
|
879
|
-
if (typeof
|
|
879
|
+
if (typeof request.headers?.[RuntimeHeaders.viaHandle] === "boolean") {
|
|
880
880
|
headerData.viaHandle = request.headers[RuntimeHeaders.viaHandle];
|
|
881
881
|
}
|
|
882
|
-
if (typeof
|
|
882
|
+
if (typeof request.headers?.[AllowTombstoneRequestHeaderKey] === "boolean") {
|
|
883
883
|
headerData.allowTombstone = request.headers[AllowTombstoneRequestHeaderKey];
|
|
884
884
|
}
|
|
885
885
|
await this.dataStores.waitIfPendingAlias(id);
|
|
@@ -889,22 +889,27 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
889
889
|
// Remove query params, leading and trailing slashes from the url. This is done to make sure the format is
|
|
890
890
|
// the same as GC nodes id.
|
|
891
891
|
const urlWithoutQuery = trimLeadingAndTrailingSlashes(request.url.split("?")[0]);
|
|
892
|
-
this.garbageCollector.nodeUpdated(`/${urlWithoutQuery}`, "Loaded", undefined /* timestampMs */, dataStoreContext.packagePath, request
|
|
892
|
+
this.garbageCollector.nodeUpdated(`/${urlWithoutQuery}`, "Loaded", undefined /* timestampMs */, dataStoreContext.packagePath, request?.headers);
|
|
893
893
|
return dataStoreChannel;
|
|
894
894
|
}
|
|
895
895
|
/** Adds the container's metadata to the given summary tree. */
|
|
896
896
|
addMetadataToSummary(summaryTree) {
|
|
897
|
-
|
|
898
|
-
|
|
897
|
+
const metadata = {
|
|
898
|
+
...this.createContainerMetadata,
|
|
899
899
|
// Increment the summary number for the next summary that will be generated.
|
|
900
|
-
summaryNumber: this.nextSummaryNumber++,
|
|
900
|
+
summaryNumber: this.nextSummaryNumber++,
|
|
901
|
+
summaryFormatVersion: 1,
|
|
902
|
+
...this.garbageCollector.getMetadata(),
|
|
901
903
|
// The last message processed at the time of summary. If there are no new messages, use the message from the
|
|
902
904
|
// last summary.
|
|
903
|
-
message:
|
|
905
|
+
message: extractSummaryMetadataMessage(this.deltaManager.lastMessage) ??
|
|
906
|
+
this.messageAtLastSummary,
|
|
907
|
+
telemetryDocumentId: this.telemetryDocumentId,
|
|
908
|
+
idCompressorEnabled: this.idCompressorEnabled ? true : undefined,
|
|
909
|
+
};
|
|
904
910
|
addBlobToSummary(summaryTree, metadataBlobName, JSON.stringify(metadata));
|
|
905
911
|
}
|
|
906
912
|
addContainerStateToSummary(summaryTree, fullTree, trackState, telemetryContext) {
|
|
907
|
-
var _a;
|
|
908
913
|
this.addMetadataToSummary(summaryTree);
|
|
909
914
|
if (this.idCompressorEnabled) {
|
|
910
915
|
assert(this.idCompressor !== undefined, 0x67a /* IdCompressor should be defined if enabled */);
|
|
@@ -920,7 +925,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
920
925
|
addBlobToSummary(summaryTree, aliasBlobName, JSON.stringify([...dataStoreAliases]));
|
|
921
926
|
}
|
|
922
927
|
if (this.summarizerClientElection) {
|
|
923
|
-
const electedSummarizerContent = JSON.stringify(
|
|
928
|
+
const electedSummarizerContent = JSON.stringify(this.summarizerClientElection?.serialize());
|
|
924
929
|
addBlobToSummary(summaryTree, electedSummarizerBlobName, electedSummarizerContent);
|
|
925
930
|
}
|
|
926
931
|
const blobManagerSummary = this.blobManager.summarize();
|
|
@@ -967,7 +972,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
967
972
|
// in their own batches before the originating batch is sent.
|
|
968
973
|
// Therefore, receiving them while attempting to send the originating batch
|
|
969
974
|
// does not mean that the container is making any progress.
|
|
970
|
-
if (
|
|
975
|
+
if (message?.type !== ContainerMessageType.ChunkedOp) {
|
|
971
976
|
this.consecutiveReconnects = 0;
|
|
972
977
|
}
|
|
973
978
|
}
|
|
@@ -1122,7 +1127,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1122
1127
|
// or something different, like a system message.
|
|
1123
1128
|
const runtimeMessage = messageArg.type === MessageType.Operation;
|
|
1124
1129
|
// Do shallow copy of message, as the processing flow will modify it.
|
|
1125
|
-
const messageCopy =
|
|
1130
|
+
const messageCopy = { ...messageArg };
|
|
1126
1131
|
for (const message of this.remoteMessageProcessor.process(messageCopy)) {
|
|
1127
1132
|
this.processCore(message, local, runtimeMessage);
|
|
1128
1133
|
}
|
|
@@ -1134,7 +1139,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1134
1139
|
* @param runtimeMessage - Does this appear like a current ContainerRuntimeMessage? If true, certain validation will occur.
|
|
1135
1140
|
*/
|
|
1136
1141
|
processCore(message, local, runtimeMessage) {
|
|
1137
|
-
var _a;
|
|
1138
1142
|
// Surround the actual processing of the operation with messages to the schedule manager indicating
|
|
1139
1143
|
// the beginning and end. This allows it to emit appropriate events and/or pause the processing of new
|
|
1140
1144
|
// messages once a batch has been fully processed.
|
|
@@ -1179,7 +1183,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1179
1183
|
local,
|
|
1180
1184
|
type: message.type,
|
|
1181
1185
|
contentType: typeof message.contents,
|
|
1182
|
-
batch:
|
|
1186
|
+
batch: message.metadata?.batch,
|
|
1183
1187
|
compression: message.compression,
|
|
1184
1188
|
});
|
|
1185
1189
|
this.closeFn(error);
|
|
@@ -1256,6 +1260,12 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1256
1260
|
}
|
|
1257
1261
|
this.dataStores.processSignal(envelope.address, transformed, local);
|
|
1258
1262
|
}
|
|
1263
|
+
/**
|
|
1264
|
+
* Returns the runtime of the data store.
|
|
1265
|
+
* @param id - Id supplied during creating the data store.
|
|
1266
|
+
* @param wait - True if you want to wait for it.
|
|
1267
|
+
* @deprecated - Use getAliasedDataStoreEntryPoint instead to get an aliased data store's entry point.
|
|
1268
|
+
*/
|
|
1259
1269
|
async getRootDataStore(id, wait = true) {
|
|
1260
1270
|
return this.getRootDataStoreChannel(id, wait);
|
|
1261
1271
|
}
|
|
@@ -1317,9 +1327,25 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1317
1327
|
}
|
|
1318
1328
|
return result;
|
|
1319
1329
|
}
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1330
|
+
/**
|
|
1331
|
+
* Returns the aliased data store's entryPoint, given the alias.
|
|
1332
|
+
* @param alias - The alias for the data store.
|
|
1333
|
+
* @returns - The data store's entry point (IFluidHandle) if it exists and is aliased. Returns undefined if no
|
|
1334
|
+
* data store has been assigned the given alias.
|
|
1335
|
+
*/
|
|
1336
|
+
async getAliasedDataStoreEntryPoint(alias) {
|
|
1337
|
+
await this.dataStores.waitIfPendingAlias(alias);
|
|
1338
|
+
const internalId = this.internalId(alias);
|
|
1339
|
+
const context = await this.dataStores.getDataStoreIfAvailable(internalId, { wait: false });
|
|
1340
|
+
// If the data store is not available or not an alias, return undefined.
|
|
1341
|
+
if (context === undefined || !(await context.isRoot())) {
|
|
1342
|
+
return undefined;
|
|
1343
|
+
}
|
|
1344
|
+
const channel = await context.realize();
|
|
1345
|
+
if (channel.entryPoint === undefined) {
|
|
1346
|
+
throw new UsageError("entryPoint must be defined on data store runtime for using getAliasedDataStoreEntryPoint");
|
|
1347
|
+
}
|
|
1348
|
+
return channel.entryPoint;
|
|
1323
1349
|
}
|
|
1324
1350
|
createDetachedRootDataStore(pkg, rootDataStoreId) {
|
|
1325
1351
|
if (rootDataStoreId.includes("/")) {
|
|
@@ -1330,16 +1356,20 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1330
1356
|
createDetachedDataStore(pkg) {
|
|
1331
1357
|
return this.dataStores.createDetachedDataStoreCore(pkg, false);
|
|
1332
1358
|
}
|
|
1333
|
-
async
|
|
1334
|
-
const
|
|
1335
|
-
|
|
1336
|
-
.
|
|
1337
|
-
|
|
1359
|
+
async createDataStore(pkg) {
|
|
1360
|
+
const id = uuid();
|
|
1361
|
+
return channelToDataStore(await this.dataStores
|
|
1362
|
+
._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id)
|
|
1363
|
+
.realize(), id, this, this.dataStores, this.mc.logger);
|
|
1338
1364
|
}
|
|
1339
|
-
|
|
1340
|
-
|
|
1365
|
+
/**
|
|
1366
|
+
* @deprecated 0.16 Issue #1537, #3631
|
|
1367
|
+
* @internal
|
|
1368
|
+
*/
|
|
1369
|
+
async _createDataStoreWithProps(pkg, props, id = uuid()) {
|
|
1370
|
+
return channelToDataStore(await this.dataStores
|
|
1341
1371
|
._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, props)
|
|
1342
|
-
.realize();
|
|
1372
|
+
.realize(), id, this, this.dataStores, this.mc.logger);
|
|
1343
1373
|
}
|
|
1344
1374
|
canSendOps() {
|
|
1345
1375
|
// Note that the real (non-proxy) delta manager is needed here to get the readonly info. This is because
|
|
@@ -1448,7 +1478,11 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1448
1478
|
wrapSummaryInChannelsTree(summarizeResult);
|
|
1449
1479
|
const pathPartsForChildren = [channelsTreeName];
|
|
1450
1480
|
this.addContainerStateToSummary(summarizeResult, fullTree, trackState, telemetryContext);
|
|
1451
|
-
return
|
|
1481
|
+
return {
|
|
1482
|
+
...summarizeResult,
|
|
1483
|
+
id: "",
|
|
1484
|
+
pathPartsForChildren,
|
|
1485
|
+
};
|
|
1452
1486
|
}
|
|
1453
1487
|
/**
|
|
1454
1488
|
* Returns a summary of the runtime at the current sequence number.
|
|
@@ -1466,13 +1500,12 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1466
1500
|
runSweep,
|
|
1467
1501
|
});
|
|
1468
1502
|
try {
|
|
1469
|
-
let gcStats;
|
|
1470
1503
|
if (runGC) {
|
|
1471
|
-
|
|
1504
|
+
await this.collectGarbage({ logger: summaryLogger, runSweep, fullGC }, telemetryContext);
|
|
1472
1505
|
}
|
|
1473
1506
|
const { stats, summary } = await this.summarizerNode.summarize(fullTree, trackState, telemetryContext);
|
|
1474
1507
|
assert(summary.type === SummaryType.Tree, 0x12f /* "Container Runtime's summarize should always return a tree" */);
|
|
1475
|
-
return { stats, summary
|
|
1508
|
+
return { stats, summary };
|
|
1476
1509
|
}
|
|
1477
1510
|
finally {
|
|
1478
1511
|
this.mc.logger.sendTelemetryEvent({
|
|
@@ -1557,21 +1590,19 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1557
1590
|
* Returns a server generated referenced timestamp to be used to track unreferenced nodes by GC.
|
|
1558
1591
|
*/
|
|
1559
1592
|
getCurrentReferenceTimestampMs() {
|
|
1560
|
-
var _a, _b, _c;
|
|
1561
1593
|
// Use the timestamp of the last message seen by this client as that is server generated. If no messages have
|
|
1562
1594
|
// been processed, use the timestamp of the message from the last summary.
|
|
1563
|
-
return
|
|
1595
|
+
return this.deltaManager.lastMessage?.timestamp ?? this.messageAtLastSummary?.timestamp;
|
|
1564
1596
|
}
|
|
1565
1597
|
/**
|
|
1566
1598
|
* Returns the type of the GC node. Currently, there are nodes that belong to the root ("/"), data stores or
|
|
1567
1599
|
* blob manager.
|
|
1568
1600
|
*/
|
|
1569
1601
|
getNodeType(nodePath) {
|
|
1570
|
-
var _a;
|
|
1571
1602
|
if (this.isBlobPath(nodePath)) {
|
|
1572
1603
|
return GCNodeType.Blob;
|
|
1573
1604
|
}
|
|
1574
|
-
return
|
|
1605
|
+
return this.dataStores.getGCNodeType(nodePath) ?? GCNodeType.Other;
|
|
1575
1606
|
}
|
|
1576
1607
|
/**
|
|
1577
1608
|
* Called by GC to retrieve the package path of the node with the given path. The node should belong to a
|
|
@@ -1642,7 +1673,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1642
1673
|
* @param options - options controlling how the summary is generated or submitted
|
|
1643
1674
|
*/
|
|
1644
1675
|
async submitSummary(options) {
|
|
1645
|
-
var _a, _b;
|
|
1646
1676
|
const { fullTree = false, refreshLatestAck, summaryLogger } = options;
|
|
1647
1677
|
// The summary number for this summary. This will be updated during the summary process, so get it now and
|
|
1648
1678
|
// use it for all events logged during this summary.
|
|
@@ -1658,7 +1688,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1658
1688
|
if (refreshLatestAck) {
|
|
1659
1689
|
const latestSnapshotInfo = await this.refreshLatestSummaryAckFromServer(createChildLogger({
|
|
1660
1690
|
logger: summaryNumberLogger,
|
|
1661
|
-
namespace: undefined,
|
|
1662
1691
|
properties: { all: { safeSummary: true } },
|
|
1663
1692
|
}));
|
|
1664
1693
|
const latestSnapshotRefSeq = latestSnapshotInfo.latestSnapshotRefSeq;
|
|
@@ -1680,7 +1709,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1680
1709
|
this.summarizerNode.startSummary(summaryRefSeqNum, summaryNumberLogger);
|
|
1681
1710
|
// Helper function to check whether we should still continue between each async step.
|
|
1682
1711
|
const checkContinue = () => {
|
|
1683
|
-
var _a;
|
|
1684
1712
|
// Do not check for loss of connectivity directly! Instead leave it up to
|
|
1685
1713
|
// RunWhileConnectedCoordinator to control policy in a single place.
|
|
1686
1714
|
// This will allow easier change of design if we chose to. For example, we may chose to allow
|
|
@@ -1703,7 +1731,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1703
1731
|
error: `lastSequenceNumber changed before uploading to storage. ${this.deltaManager.lastSequenceNumber} !== ${summaryRefSeqNum}`,
|
|
1704
1732
|
};
|
|
1705
1733
|
}
|
|
1706
|
-
assert(summaryRefSeqNum ===
|
|
1734
|
+
assert(summaryRefSeqNum === this.deltaManager.lastMessage?.sequenceNumber, 0x395 /* it's one and the same thing */);
|
|
1707
1735
|
if (lastAck !== this.summaryCollection.latestAck) {
|
|
1708
1736
|
return {
|
|
1709
1737
|
continue: false,
|
|
@@ -1742,6 +1770,21 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1742
1770
|
error,
|
|
1743
1771
|
};
|
|
1744
1772
|
}
|
|
1773
|
+
// If validateSummaryBeforeUpload is true, validate that the summary generated by the summarizer nodes is
|
|
1774
|
+
// correct before this summary is uploaded.
|
|
1775
|
+
if (this.validateSummaryBeforeUpload) {
|
|
1776
|
+
const validateResult = this.summarizerNode.validateSummary();
|
|
1777
|
+
if (!validateResult.success) {
|
|
1778
|
+
const { success, ...loggingProps } = validateResult;
|
|
1779
|
+
const error = new RetriableSummaryError(validateResult.reason, validateResult.retryAfterSeconds, { ...loggingProps });
|
|
1780
|
+
return {
|
|
1781
|
+
stage: "base",
|
|
1782
|
+
referenceSequenceNumber: summaryRefSeqNum,
|
|
1783
|
+
minimumSequenceNumber,
|
|
1784
|
+
error,
|
|
1785
|
+
};
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1745
1788
|
const { summary: summaryTree, stats: partialStats } = summarizeResult;
|
|
1746
1789
|
// Now that we have generated the summary, update the message at last summary to the last message processed.
|
|
1747
1790
|
this.messageAtLastSummary = this.deltaManager.lastMessage;
|
|
@@ -1754,7 +1797,15 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1754
1797
|
const gcSummaryTreeStats = summaryTree.tree[gcTreeKey]
|
|
1755
1798
|
? calculateStats(summaryTree.tree[gcTreeKey])
|
|
1756
1799
|
: undefined;
|
|
1757
|
-
const summaryStats =
|
|
1800
|
+
const summaryStats = {
|
|
1801
|
+
dataStoreCount: this.dataStores.size,
|
|
1802
|
+
summarizedDataStoreCount: this.dataStores.size - handleCount,
|
|
1803
|
+
gcStateUpdatedDataStoreCount: this.garbageCollector.updatedDSCountSinceLastSummary,
|
|
1804
|
+
gcBlobNodeCount: gcSummaryTreeStats?.blobNodeCount,
|
|
1805
|
+
gcTotalBlobsSize: gcSummaryTreeStats?.totalBlobSize,
|
|
1806
|
+
summaryNumber,
|
|
1807
|
+
...partialStats,
|
|
1808
|
+
};
|
|
1758
1809
|
const generateSummaryData = {
|
|
1759
1810
|
referenceSequenceNumber: summaryRefSeqNum,
|
|
1760
1811
|
minimumSequenceNumber,
|
|
@@ -1763,19 +1814,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1763
1814
|
generateDuration: trace.trace().duration,
|
|
1764
1815
|
forcedFullTree,
|
|
1765
1816
|
};
|
|
1766
|
-
// If validateSummaryBeforeUpload is true, validate that the summary generated by the summarizer nodes is
|
|
1767
|
-
// correct before this summary is uploaded.
|
|
1768
|
-
if (this.validateSummaryBeforeUpload) {
|
|
1769
|
-
const validateResult = this.summarizerNode.validateSummary();
|
|
1770
|
-
if (!validateResult.success) {
|
|
1771
|
-
const { success } = validateResult, loggingProps = __rest(validateResult, ["success"]);
|
|
1772
|
-
const error = new RetriableSummaryError(validateResult.reason, validateResult.retryAfterSeconds, Object.assign({}, loggingProps));
|
|
1773
|
-
return Object.assign(Object.assign({ stage: "base" }, generateSummaryData), { error });
|
|
1774
|
-
}
|
|
1775
|
-
}
|
|
1776
1817
|
continueResult = checkContinue();
|
|
1777
1818
|
if (!continueResult.continue) {
|
|
1778
|
-
return
|
|
1819
|
+
return { stage: "generate", ...generateSummaryData, error: continueResult.error };
|
|
1779
1820
|
}
|
|
1780
1821
|
// It may happen that the lastAck it not correct due to missing summaryAck in case of single commit
|
|
1781
1822
|
// summary. So if the previous summarizer closes just after submitting the summary and before
|
|
@@ -1783,7 +1824,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1783
1824
|
// latestSnapshotVersionId from storage and it does not match with the lastAck ackHandle, then use
|
|
1784
1825
|
// the one fetched from storage as parent as that is the latest.
|
|
1785
1826
|
let summaryContext;
|
|
1786
|
-
if (
|
|
1827
|
+
if (lastAck?.summaryAck.contents.handle !== latestSnapshotVersionId &&
|
|
1787
1828
|
latestSnapshotVersionId !== undefined) {
|
|
1788
1829
|
summaryContext = {
|
|
1789
1830
|
proposalHandle: undefined,
|
|
@@ -1810,7 +1851,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1810
1851
|
handle = await this.storage.uploadSummaryWithContext(summarizeResult.summary, summaryContext);
|
|
1811
1852
|
}
|
|
1812
1853
|
catch (error) {
|
|
1813
|
-
return
|
|
1854
|
+
return { stage: "generate", ...generateSummaryData, error };
|
|
1814
1855
|
}
|
|
1815
1856
|
const parent = summaryContext.ackHandle;
|
|
1816
1857
|
const summaryMessage = {
|
|
@@ -1820,25 +1861,34 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1820
1861
|
message,
|
|
1821
1862
|
parents: parent ? [parent] : [],
|
|
1822
1863
|
};
|
|
1823
|
-
const uploadData =
|
|
1864
|
+
const uploadData = {
|
|
1865
|
+
...generateSummaryData,
|
|
1866
|
+
handle,
|
|
1867
|
+
uploadDuration: trace.trace().duration,
|
|
1868
|
+
};
|
|
1824
1869
|
continueResult = checkContinue();
|
|
1825
1870
|
if (!continueResult.continue) {
|
|
1826
|
-
return
|
|
1871
|
+
return { stage: "upload", ...uploadData, error: continueResult.error };
|
|
1827
1872
|
}
|
|
1828
1873
|
let clientSequenceNumber;
|
|
1829
1874
|
try {
|
|
1830
1875
|
clientSequenceNumber = this.submitSummaryMessage(summaryMessage, summaryRefSeqNum);
|
|
1831
1876
|
}
|
|
1832
1877
|
catch (error) {
|
|
1833
|
-
return
|
|
1878
|
+
return { stage: "upload", ...uploadData, error };
|
|
1834
1879
|
}
|
|
1835
|
-
const submitData =
|
|
1880
|
+
const submitData = {
|
|
1881
|
+
stage: "submit",
|
|
1882
|
+
...uploadData,
|
|
1883
|
+
clientSequenceNumber,
|
|
1884
|
+
submitOpDuration: trace.trace().duration,
|
|
1885
|
+
};
|
|
1836
1886
|
try {
|
|
1837
1887
|
// If validateSummaryBeforeUpload is false, the summary should be validated in this step.
|
|
1838
1888
|
this.summarizerNode.completeSummary(handle, !this.validateSummaryBeforeUpload /* validate */);
|
|
1839
1889
|
}
|
|
1840
1890
|
catch (error) {
|
|
1841
|
-
return
|
|
1891
|
+
return { stage: "upload", ...uploadData, error };
|
|
1842
1892
|
}
|
|
1843
1893
|
return submitData;
|
|
1844
1894
|
}
|
|
@@ -1846,7 +1896,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1846
1896
|
// Cleanup wip summary in case of failure
|
|
1847
1897
|
this.summarizerNode.clearSummary();
|
|
1848
1898
|
// ! This needs to happen before we resume inbound queues to ensure heuristics are tracked correctly
|
|
1849
|
-
|
|
1899
|
+
this._summarizer?.recordSummaryAttempt?.(summaryRefSeqNum);
|
|
1850
1900
|
// Restart the delta manager
|
|
1851
1901
|
this.deltaManager.inbound.resume();
|
|
1852
1902
|
if (shouldPauseInboundSignal) {
|
|
@@ -1892,7 +1942,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1892
1942
|
return this.blobManager.createBlob(blob, signal);
|
|
1893
1943
|
}
|
|
1894
1944
|
maybeSubmitIdAllocationOp(type) {
|
|
1895
|
-
var _a, _b;
|
|
1896
1945
|
if (type !== ContainerMessageType.IdAllocation) {
|
|
1897
1946
|
let idAllocationBatchMessage;
|
|
1898
1947
|
let idRange;
|
|
@@ -1900,7 +1949,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1900
1949
|
assert(this.idCompressor !== undefined, 0x67d /* IdCompressor should be defined if enabled */);
|
|
1901
1950
|
idRange = this.idCompressor.takeNextCreationRange();
|
|
1902
1951
|
// Don't include the idRange if there weren't any Ids allocated
|
|
1903
|
-
idRange =
|
|
1952
|
+
idRange = idRange?.ids?.first !== undefined ? idRange : undefined;
|
|
1904
1953
|
}
|
|
1905
1954
|
if (idRange !== undefined) {
|
|
1906
1955
|
const idAllocationMessage = {
|
|
@@ -1911,7 +1960,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1911
1960
|
contents: JSON.stringify(idAllocationMessage),
|
|
1912
1961
|
referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
1913
1962
|
metadata: undefined,
|
|
1914
|
-
localOpMetadata:
|
|
1963
|
+
localOpMetadata: this.idCompressor?.serialize(true),
|
|
1915
1964
|
type: ContainerMessageType.IdAllocation,
|
|
1916
1965
|
};
|
|
1917
1966
|
}
|
|
@@ -2189,7 +2238,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2189
2238
|
summaryRefSeq,
|
|
2190
2239
|
fetchedSnapshotRefSeq: fetchResult.latestSnapshotRefSeq,
|
|
2191
2240
|
});
|
|
2192
|
-
this.
|
|
2241
|
+
this.disposeFn(error);
|
|
2193
2242
|
throw error;
|
|
2194
2243
|
}
|
|
2195
2244
|
// In case we had to retrieve the latest snapshot and it is different than summaryRefSeq,
|
|
@@ -2228,7 +2277,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2228
2277
|
return this.fetchSnapshotFromStorageAndClose(logger, event, readAndParseBlob, null /* latest */);
|
|
2229
2278
|
}
|
|
2230
2279
|
async fetchSnapshotFromStorageAndClose(logger, event, readAndParseBlob, versionId) {
|
|
2231
|
-
var _a;
|
|
2232
2280
|
const snapshotResults = await PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
|
|
2233
2281
|
const stats = {};
|
|
2234
2282
|
const trace = Trace.start();
|
|
@@ -2252,26 +2300,36 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2252
2300
|
// situations which the main client (which is likely to be re-elected as the leader again)
|
|
2253
2301
|
// loads the summarizer from cache.
|
|
2254
2302
|
if (this.summaryStateUpdateMethod !== "refreshFromSnapshot") {
|
|
2255
|
-
this.mc.logger.sendTelemetryEvent(
|
|
2303
|
+
this.mc.logger.sendTelemetryEvent({
|
|
2304
|
+
...event,
|
|
2305
|
+
eventName: "ClosingSummarizerOnSummaryStale",
|
|
2306
|
+
codePath: event.eventName,
|
|
2307
|
+
message: "Stopping fetch from storage",
|
|
2308
|
+
versionId: versionId != null ? versionId : undefined,
|
|
2309
|
+
closeSummarizerDelayMs: this.closeSummarizerDelayMs,
|
|
2310
|
+
}, new GenericError("Restarting summarizer instead of refreshing"));
|
|
2256
2311
|
// Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
|
|
2257
2312
|
await delay(this.closeSummarizerDelayMs);
|
|
2258
|
-
|
|
2313
|
+
this._summarizer?.stop("latestSummaryStateStale");
|
|
2259
2314
|
this.disposeFn();
|
|
2260
2315
|
}
|
|
2261
2316
|
return snapshotResults;
|
|
2262
2317
|
}
|
|
2263
2318
|
notifyAttaching() { } // do nothing (deprecated method)
|
|
2264
|
-
getPendingLocalState() {
|
|
2319
|
+
async getPendingLocalState(props) {
|
|
2320
|
+
this.verifyNotClosed();
|
|
2321
|
+
const waitBlobsToAttach = props?.notifyImminentClosure;
|
|
2265
2322
|
if (this._orderSequentiallyCalls !== 0) {
|
|
2266
2323
|
throw new UsageError("can't get state during orderSequentially");
|
|
2267
2324
|
}
|
|
2325
|
+
const pendingAttachmentBlobs = await this.blobManager.getPendingBlobs(waitBlobsToAttach);
|
|
2268
2326
|
// Flush pending batch.
|
|
2269
2327
|
// getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
|
|
2270
2328
|
// to close current batch.
|
|
2271
2329
|
this.flush();
|
|
2272
2330
|
return {
|
|
2273
2331
|
pending: this.pendingStateManager.getLocalState(),
|
|
2274
|
-
pendingAttachmentBlobs
|
|
2332
|
+
pendingAttachmentBlobs,
|
|
2275
2333
|
};
|
|
2276
2334
|
}
|
|
2277
2335
|
/**
|