@fluidframework/container-runtime 2.0.0-internal.2.2.1 → 2.0.0-internal.2.3.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 +19 -8
- package/dist/batchTracker.d.ts +1 -2
- package/dist/batchTracker.d.ts.map +1 -1
- package/dist/batchTracker.js.map +1 -1
- package/dist/blobManager.d.ts +44 -33
- package/dist/blobManager.d.ts.map +1 -1
- package/dist/blobManager.js +130 -97
- package/dist/blobManager.js.map +1 -1
- package/dist/containerRuntime.d.ts +39 -8
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +117 -61
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStoreContext.d.ts +1 -1
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +4 -3
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStores.d.ts +9 -6
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/dataStores.js +30 -24
- package/dist/dataStores.js.map +1 -1
- package/dist/garbageCollection.d.ts +41 -20
- package/dist/garbageCollection.d.ts.map +1 -1
- package/dist/garbageCollection.js +205 -151
- package/dist/garbageCollection.js.map +1 -1
- package/dist/garbageCollectionConstants.d.ts +6 -3
- package/dist/garbageCollectionConstants.d.ts.map +1 -1
- package/dist/garbageCollectionConstants.js +7 -7
- package/dist/garbageCollectionConstants.js.map +1 -1
- package/dist/garbageCollectionTombstoneUtils.d.ts +13 -0
- package/dist/garbageCollectionTombstoneUtils.d.ts.map +1 -0
- package/dist/garbageCollectionTombstoneUtils.js +28 -0
- package/dist/garbageCollectionTombstoneUtils.js.map +1 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -5
- package/dist/index.js.map +1 -1
- package/dist/opLifecycle/batchManager.d.ts +13 -1
- package/dist/opLifecycle/batchManager.d.ts.map +1 -1
- package/dist/opLifecycle/batchManager.js +35 -1
- package/dist/opLifecycle/batchManager.js.map +1 -1
- package/dist/opLifecycle/definitions.d.ts +25 -1
- package/dist/opLifecycle/definitions.d.ts.map +1 -1
- package/dist/opLifecycle/definitions.js.map +1 -1
- package/dist/opLifecycle/index.d.ts +2 -2
- package/dist/opLifecycle/index.d.ts.map +1 -1
- package/dist/opLifecycle/index.js +2 -1
- package/dist/opLifecycle/index.js.map +1 -1
- package/dist/opLifecycle/opCompressor.d.ts +1 -1
- package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opCompressor.js +24 -10
- package/dist/opLifecycle/opCompressor.js.map +1 -1
- package/dist/opLifecycle/opDecompressor.d.ts +2 -1
- package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opDecompressor.js +30 -17
- package/dist/opLifecycle/opDecompressor.js.map +1 -1
- package/dist/opLifecycle/opSplitter.d.ts +34 -2
- package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
- package/dist/opLifecycle/opSplitter.js +114 -5
- package/dist/opLifecycle/opSplitter.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts +5 -0
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +24 -14
- package/dist/opLifecycle/outbox.js.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.js +17 -2
- package/dist/opLifecycle/remoteMessageProcessor.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/runningSummarizer.d.ts.map +1 -1
- package/dist/runningSummarizer.js +0 -1
- package/dist/runningSummarizer.js.map +1 -1
- package/dist/scheduleManager.d.ts +0 -1
- package/dist/scheduleManager.d.ts.map +1 -1
- package/dist/scheduleManager.js +9 -20
- package/dist/scheduleManager.js.map +1 -1
- package/dist/summarizer.d.ts +0 -1
- package/dist/summarizer.d.ts.map +1 -1
- package/dist/summarizer.js +2 -1
- package/dist/summarizer.js.map +1 -1
- package/dist/summarizerTypes.d.ts +1 -0
- package/dist/summarizerTypes.d.ts.map +1 -1
- package/dist/summarizerTypes.js.map +1 -1
- package/dist/summaryFormat.d.ts.map +1 -1
- package/dist/summaryFormat.js +1 -2
- package/dist/summaryFormat.js.map +1 -1
- package/lib/batchTracker.d.ts +1 -2
- package/lib/batchTracker.d.ts.map +1 -1
- package/lib/batchTracker.js.map +1 -1
- package/lib/blobManager.d.ts +44 -33
- package/lib/blobManager.d.ts.map +1 -1
- package/lib/blobManager.js +131 -98
- package/lib/blobManager.js.map +1 -1
- package/lib/containerRuntime.d.ts +39 -8
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +115 -59
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStoreContext.d.ts +1 -1
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +5 -4
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStores.d.ts +9 -6
- package/lib/dataStores.d.ts.map +1 -1
- package/lib/dataStores.js +32 -26
- package/lib/dataStores.js.map +1 -1
- package/lib/garbageCollection.d.ts +41 -20
- package/lib/garbageCollection.d.ts.map +1 -1
- package/lib/garbageCollection.js +201 -147
- package/lib/garbageCollection.js.map +1 -1
- package/lib/garbageCollectionConstants.d.ts +6 -3
- package/lib/garbageCollectionConstants.d.ts.map +1 -1
- package/lib/garbageCollectionConstants.js +6 -6
- package/lib/garbageCollectionConstants.js.map +1 -1
- package/lib/garbageCollectionTombstoneUtils.d.ts +13 -0
- package/lib/garbageCollectionTombstoneUtils.d.ts.map +1 -0
- package/lib/garbageCollectionTombstoneUtils.js +24 -0
- package/lib/garbageCollectionTombstoneUtils.js.map +1 -0
- package/lib/index.d.ts +0 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +0 -1
- package/lib/index.js.map +1 -1
- package/lib/opLifecycle/batchManager.d.ts +13 -1
- package/lib/opLifecycle/batchManager.d.ts.map +1 -1
- package/lib/opLifecycle/batchManager.js +35 -1
- package/lib/opLifecycle/batchManager.js.map +1 -1
- package/lib/opLifecycle/definitions.d.ts +25 -1
- package/lib/opLifecycle/definitions.d.ts.map +1 -1
- package/lib/opLifecycle/definitions.js.map +1 -1
- package/lib/opLifecycle/index.d.ts +2 -2
- package/lib/opLifecycle/index.d.ts.map +1 -1
- package/lib/opLifecycle/index.js +1 -1
- package/lib/opLifecycle/index.js.map +1 -1
- package/lib/opLifecycle/opCompressor.d.ts +1 -1
- package/lib/opLifecycle/opCompressor.d.ts.map +1 -1
- package/lib/opLifecycle/opCompressor.js +24 -10
- package/lib/opLifecycle/opCompressor.js.map +1 -1
- package/lib/opLifecycle/opDecompressor.d.ts +2 -1
- package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/lib/opLifecycle/opDecompressor.js +30 -17
- package/lib/opLifecycle/opDecompressor.js.map +1 -1
- package/lib/opLifecycle/opSplitter.d.ts +34 -2
- package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
- package/lib/opLifecycle/opSplitter.js +112 -4
- package/lib/opLifecycle/opSplitter.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts +5 -0
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.js +24 -14
- package/lib/opLifecycle/outbox.js.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.js +17 -2
- package/lib/opLifecycle/remoteMessageProcessor.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/runningSummarizer.d.ts.map +1 -1
- package/lib/runningSummarizer.js +0 -1
- package/lib/runningSummarizer.js.map +1 -1
- package/lib/scheduleManager.d.ts +0 -1
- package/lib/scheduleManager.d.ts.map +1 -1
- package/lib/scheduleManager.js +9 -20
- package/lib/scheduleManager.js.map +1 -1
- package/lib/summarizer.d.ts +0 -1
- package/lib/summarizer.d.ts.map +1 -1
- package/lib/summarizer.js +2 -1
- package/lib/summarizer.js.map +1 -1
- package/lib/summarizerTypes.d.ts +1 -0
- package/lib/summarizerTypes.d.ts.map +1 -1
- package/lib/summarizerTypes.js.map +1 -1
- package/lib/summaryFormat.d.ts.map +1 -1
- package/lib/summaryFormat.js +1 -2
- package/lib/summaryFormat.js.map +1 -1
- package/package.json +37 -19
- package/src/batchTracker.ts +1 -1
- package/src/blobManager.ts +146 -103
- package/src/containerRuntime.ts +166 -65
- package/src/dataStoreContext.ts +5 -5
- package/src/dataStores.ts +40 -30
- package/src/garbageCollection.ts +254 -183
- package/src/garbageCollectionConstants.ts +7 -6
- package/src/garbageCollectionTombstoneUtils.ts +31 -0
- package/src/index.ts +0 -5
- package/src/opLifecycle/batchManager.ts +59 -1
- package/src/opLifecycle/definitions.ts +27 -1
- package/src/opLifecycle/index.ts +2 -1
- package/src/opLifecycle/opCompressor.ts +29 -12
- package/src/opLifecycle/opDecompressor.ts +39 -18
- package/src/opLifecycle/opSplitter.ts +141 -7
- package/src/opLifecycle/outbox.ts +32 -16
- package/src/opLifecycle/remoteMessageProcessor.ts +19 -3
- package/src/packageVersion.ts +1 -1
- package/src/runningSummarizer.ts +0 -1
- package/src/scheduleManager.ts +19 -30
- package/src/summarizer.ts +1 -1
- package/src/summarizerTypes.ts +1 -0
- package/src/summaryFormat.ts +1 -2
package/lib/containerRuntime.js
CHANGED
|
@@ -5,7 +5,7 @@ import { DriverHeader, FetchSource, } from "@fluidframework/driver-definitions";
|
|
|
5
5
|
import { readAndParse } from "@fluidframework/driver-utils";
|
|
6
6
|
import { DataCorruptionError, DataProcessingError, GenericError, UsageError, } from "@fluidframework/container-utils";
|
|
7
7
|
import { MessageType, SummaryType, } from "@fluidframework/protocol-definitions";
|
|
8
|
-
import { FlushMode, channelsTreeName, } from "@fluidframework/runtime-definitions";
|
|
8
|
+
import { FlushMode, gcTreeKey, channelsTreeName, } from "@fluidframework/runtime-definitions";
|
|
9
9
|
import { addBlobToSummary, addSummarizeResultToSummary, addTreeToSummary, createRootSummarizerNodeWithGC, RequestParser, create404Response, exceptionToResponse, requestFluidObject, responseToException, seqFromTree, calculateStats, TelemetryContext, } from "@fluidframework/runtime-utils";
|
|
10
10
|
import { GCDataBuilder, trimLeadingAndTrailingSlashes } from "@fluidframework/garbage-collector";
|
|
11
11
|
import { v4 as uuid } from "uuid";
|
|
@@ -25,7 +25,6 @@ import { SummarizerClientElection, summarizerClientType } from "./summarizerClie
|
|
|
25
25
|
import { formExponentialFn, Throttler } from "./throttler";
|
|
26
26
|
import { RunWhileConnectedCoordinator } from "./runWhileConnectedCoordinator";
|
|
27
27
|
import { GarbageCollector, GCNodeType, } from "./garbageCollection";
|
|
28
|
-
import { gcTreeKey, } from "./garbageCollectionConstants";
|
|
29
28
|
import { channelToDataStore, isDataStoreAliasMessage, } from "./dataStore";
|
|
30
29
|
import { BindBatchTracker } from "./batchTracker";
|
|
31
30
|
import { SerializedSnapshotStorage } from "./serializedSnapshotStorage";
|
|
@@ -213,12 +212,17 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
213
212
|
this.nextSummaryNumber = loadSummaryNumber + 1;
|
|
214
213
|
this.messageAtLastSummary = metadata === null || metadata === void 0 ? void 0 : metadata.message;
|
|
215
214
|
this._connected = this.context.connected;
|
|
216
|
-
this.remoteMessageProcessor = new RemoteMessageProcessor(new OpSplitter(chunks), new OpDecompressor());
|
|
217
|
-
this.handleContext = new ContainerFluidHandleContext("", this);
|
|
218
215
|
this.mc = loggerToMonitoringContext(ChildLogger.create(this.logger, "ContainerRuntime"));
|
|
216
|
+
const opSplitter = new OpSplitter(chunks, this.context.submitBatchFn, this.mc.config.getBoolean("Fluid.ContainerRuntime.DisableCompressionChunking") === true ?
|
|
217
|
+
Number.POSITIVE_INFINITY : runtimeOptions.chunkSizeInBytes, runtimeOptions.maxBatchSizeInBytes, this.mc.logger);
|
|
218
|
+
this.remoteMessageProcessor = new RemoteMessageProcessor(opSplitter, new OpDecompressor());
|
|
219
|
+
this.handleContext = new ContainerFluidHandleContext("", this);
|
|
219
220
|
if (this.summaryConfiguration.state === "enabled") {
|
|
220
221
|
this.validateSummaryHeuristicConfiguration(this.summaryConfiguration);
|
|
221
222
|
}
|
|
223
|
+
this.enableOpReentryCheck = runtimeOptions.enableOpReentryCheck === true
|
|
224
|
+
// Allow for a break-glass config to override the options
|
|
225
|
+
&& this.mc.config.getBoolean("Fluid.ContainerRuntime.DisableOpReentryCheck") !== true;
|
|
222
226
|
this.summariesDisabled = this.isSummariesDisabled();
|
|
223
227
|
this.heuristicsDisabled = this.isHeuristicsDisabled();
|
|
224
228
|
this.summarizerClientElectionEnabled = this.isSummarizerClientElectionEnabled();
|
|
@@ -267,16 +271,20 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
267
271
|
throwOnFailure: true,
|
|
268
272
|
// If GC should not run, let the summarizer node know so that it does not track GC state.
|
|
269
273
|
gcDisabled: !this.garbageCollector.shouldRunGC,
|
|
270
|
-
}
|
|
274
|
+
},
|
|
275
|
+
// Function to get GC data if needed. This will always be called by the root summarizer node to get GC data.
|
|
276
|
+
async (fullGC) => this.getGCDataInternal(fullGC),
|
|
277
|
+
// Function to get the GC details from the base snapshot we loaded from.
|
|
278
|
+
async () => this.garbageCollector.getBaseGCDetails());
|
|
271
279
|
if (baseSnapshot) {
|
|
272
280
|
this.summarizerNode.updateBaseSummaryState(baseSnapshot);
|
|
273
281
|
}
|
|
274
282
|
this.dataStores = new DataStores(getSummaryForDatastores(baseSnapshot, metadata), this, (attachMsg) => this.submit(ContainerMessageType.Attach, attachMsg), (id, createParam) => (summarizeInternal, getGCDataFn, getBaseGCDetailsFn) => this.summarizerNode.createChild(summarizeInternal, id, createParam, undefined, getGCDataFn, getBaseGCDetailsFn), (id) => this.summarizerNode.deleteChild(id), this.mc.logger, async () => this.garbageCollector.getBaseGCDetails(), (path, timestampMs, packagePath) => this.garbageCollector.nodeUpdated(path, "Changed", timestampMs, packagePath), new Map(dataStoreAliasMap));
|
|
275
|
-
this.blobManager = new BlobManager(this.handleContext, blobManagerSnapshot, () => this.storage, (
|
|
283
|
+
this.blobManager = new BlobManager(this.handleContext, blobManagerSnapshot, () => this.storage, (localId, blobId) => {
|
|
276
284
|
if (!this.disposed) {
|
|
277
|
-
this.submit(ContainerMessageType.BlobAttach, undefined, undefined, {
|
|
285
|
+
this.submit(ContainerMessageType.BlobAttach, undefined, undefined, { localId, blobId });
|
|
278
286
|
}
|
|
279
|
-
}, (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"), this, pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.pendingAttachmentBlobs);
|
|
287
|
+
}, (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"), (fromPath, toPath) => this.garbageCollector.addedOutboundReference(fromPath, toPath), this, pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.pendingAttachmentBlobs);
|
|
280
288
|
this.scheduleManager = new ScheduleManager(context.deltaManager, this, () => this.clientId, ChildLogger.create(this.logger, "ScheduleManager"));
|
|
281
289
|
this.pendingStateManager = new PendingStateManager({
|
|
282
290
|
applyStashedOp: this.applyStashedOp.bind(this),
|
|
@@ -288,15 +296,23 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
288
296
|
rollback: this.rollback.bind(this),
|
|
289
297
|
orderSequentially: this.orderSequentially.bind(this),
|
|
290
298
|
}, pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.pending);
|
|
299
|
+
const compressionOptions = this.mc.config.getBoolean("Fluid.ContainerRuntime.DisableCompression") === true ?
|
|
300
|
+
{
|
|
301
|
+
minimumBatchSizeInBytes: Number.POSITIVE_INFINITY,
|
|
302
|
+
compressionAlgorithm: CompressionAlgorithms.lz4
|
|
303
|
+
} : runtimeOptions.compressionOptions;
|
|
291
304
|
this.outbox = new Outbox({
|
|
292
305
|
shouldSend: () => this.canSendOps(),
|
|
293
306
|
pendingStateManager: this.pendingStateManager,
|
|
294
307
|
containerContext: this.context,
|
|
295
308
|
compressor: new OpCompressor(this.mc.logger),
|
|
309
|
+
splitter: opSplitter,
|
|
296
310
|
config: {
|
|
297
|
-
compressionOptions
|
|
311
|
+
compressionOptions,
|
|
298
312
|
maxBatchSizeInBytes: runtimeOptions.maxBatchSizeInBytes,
|
|
313
|
+
enableOpReentryCheck: this.enableOpReentryCheck,
|
|
299
314
|
},
|
|
315
|
+
logger: this.mc.logger,
|
|
300
316
|
});
|
|
301
317
|
this.context.quorum.on("removeMember", (clientId) => {
|
|
302
318
|
this.remoteMessageProcessor.clearPartialMessagesFor(clientId);
|
|
@@ -384,7 +400,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
384
400
|
* allows mixin classes to leverage this method to define their own async initializer.
|
|
385
401
|
*/
|
|
386
402
|
static async load(context, registryEntries, requestHandler, runtimeOptions = {}, containerScope = context.scope, existing, containerRuntimeCtor = ContainerRuntime) {
|
|
387
|
-
var _a, _b, _c;
|
|
403
|
+
var _a, _b, _c, _d;
|
|
388
404
|
// If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
|
|
389
405
|
// back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
|
|
390
406
|
const backCompatContext = context;
|
|
@@ -397,7 +413,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
397
413
|
const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, enableOfflineLoad = false, compressionOptions = {
|
|
398
414
|
minimumBatchSizeInBytes: Number.POSITIVE_INFINITY,
|
|
399
415
|
compressionAlgorithm: CompressionAlgorithms.lz4
|
|
400
|
-
}, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, } = runtimeOptions;
|
|
416
|
+
}, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, chunkSizeInBytes = Number.POSITIVE_INFINITY, enableOpReentryCheck = false, } = runtimeOptions;
|
|
401
417
|
const pendingRuntimeState = context.pendingLocalState;
|
|
402
418
|
const baseSnapshot = (_b = pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.baseSnapshot) !== null && _b !== void 0 ? _b : context.baseSnapshot;
|
|
403
419
|
const storage = !pendingRuntimeState ?
|
|
@@ -442,7 +458,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
442
458
|
logger.sendErrorEvent({ eventName: "SequenceNumberMismatch" }, error);
|
|
443
459
|
}
|
|
444
460
|
else {
|
|
461
|
+
// Call both close and dispose as close implementation will no longer dispose runtime in future (2.0.0-internal.3.0.0)
|
|
445
462
|
context.closeFn(error);
|
|
463
|
+
(_d = context.disposeFn) === null || _d === void 0 ? void 0 : _d.call(context, error);
|
|
446
464
|
}
|
|
447
465
|
}
|
|
448
466
|
}
|
|
@@ -454,6 +472,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
454
472
|
enableOfflineLoad,
|
|
455
473
|
compressionOptions,
|
|
456
474
|
maxBatchSizeInBytes,
|
|
475
|
+
chunkSizeInBytes,
|
|
476
|
+
enableOpReentryCheck,
|
|
457
477
|
}, containerScope, logger, loadExisting, blobManagerSnapshot, storage, requestHandler);
|
|
458
478
|
if (pendingRuntimeState) {
|
|
459
479
|
await runtime.processSavedOps(pendingRuntimeState);
|
|
@@ -483,8 +503,18 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
483
503
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
484
504
|
return this.reSubmit;
|
|
485
505
|
}
|
|
506
|
+
get disposeFn() {
|
|
507
|
+
var _a;
|
|
508
|
+
// In old loaders without dispose functionality, closeFn is equivalent but will also switch container to readonly mode
|
|
509
|
+
return (_a = this.context.disposeFn) !== null && _a !== void 0 ? _a : this.context.closeFn;
|
|
510
|
+
}
|
|
486
511
|
get closeFn() {
|
|
487
|
-
|
|
512
|
+
// Also call disposeFn to retain functionality of runtime being disposed on close
|
|
513
|
+
return (error) => {
|
|
514
|
+
var _a, _b;
|
|
515
|
+
this.context.closeFn(error);
|
|
516
|
+
(_b = (_a = this.context).disposeFn) === null || _b === void 0 ? void 0 : _b.call(_a, error);
|
|
517
|
+
};
|
|
488
518
|
}
|
|
489
519
|
get flushMode() {
|
|
490
520
|
return this._flushMode;
|
|
@@ -862,9 +892,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
862
892
|
if (reconnection) {
|
|
863
893
|
this.consecutiveReconnects++;
|
|
864
894
|
if (!this.shouldContinueReconnecting()) {
|
|
865
|
-
this.closeFn(DataProcessingError.create(
|
|
866
|
-
// eslint-disable-next-line max-len
|
|
867
|
-
"Runtime detected too many reconnects with no progress syncing local ops. Batch of ops is likely too large (over 1Mb)", "setConnectionState", undefined, {
|
|
895
|
+
this.closeFn(DataProcessingError.create("Runtime detected too many reconnects with no progress syncing local ops. Batch of ops is likely too large (over 1Mb)", "setConnectionState", undefined, {
|
|
868
896
|
dataLoss: 1,
|
|
869
897
|
attempts: this.consecutiveReconnects,
|
|
870
898
|
pendingMessages: this.pendingStateManager.pendingMessagesCount,
|
|
@@ -898,7 +926,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
898
926
|
this.scheduleManager.beforeOpProcessing(message);
|
|
899
927
|
try {
|
|
900
928
|
let localOpMetadata;
|
|
901
|
-
if (local && runtimeMessage) {
|
|
929
|
+
if (local && runtimeMessage && message.type !== ContainerMessageType.ChunkedOp) {
|
|
902
930
|
localOpMetadata = this.pendingStateManager.processPendingLocalMessage(message);
|
|
903
931
|
}
|
|
904
932
|
// If there are no more pending messages after processing a local message,
|
|
@@ -1015,6 +1043,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1015
1043
|
}
|
|
1016
1044
|
orderSequentially(callback) {
|
|
1017
1045
|
let checkpoint;
|
|
1046
|
+
let result;
|
|
1018
1047
|
if (this.mc.config.getBoolean("Fluid.ContainerRuntime.EnableRollback")) {
|
|
1019
1048
|
// Note: we are not touching this.pendingAttachBatch here, for two reasons:
|
|
1020
1049
|
// 1. It would not help, as we flush attach ops as they become available.
|
|
@@ -1023,7 +1052,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1023
1052
|
}
|
|
1024
1053
|
try {
|
|
1025
1054
|
this._orderSequentiallyCalls++;
|
|
1026
|
-
callback();
|
|
1055
|
+
result = callback();
|
|
1027
1056
|
}
|
|
1028
1057
|
catch (error) {
|
|
1029
1058
|
if (checkpoint) {
|
|
@@ -1051,6 +1080,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1051
1080
|
if (this.flushMode === FlushMode.Immediate && this._orderSequentiallyCalls === 0) {
|
|
1052
1081
|
this.flush();
|
|
1053
1082
|
}
|
|
1083
|
+
return result;
|
|
1054
1084
|
}
|
|
1055
1085
|
async createDataStore(pkg) {
|
|
1056
1086
|
const internalId = uuid();
|
|
@@ -1216,6 +1246,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1216
1246
|
async updateStateBeforeGC() {
|
|
1217
1247
|
return this.dataStores.updateStateBeforeGC();
|
|
1218
1248
|
}
|
|
1249
|
+
async getGCDataInternal(fullGC) {
|
|
1250
|
+
return this.dataStores.getGCData(fullGC);
|
|
1251
|
+
}
|
|
1219
1252
|
/**
|
|
1220
1253
|
* Implementation of IGarbageCollectionRuntime::getGCData.
|
|
1221
1254
|
* Generates and returns the GC data for this container.
|
|
@@ -1223,7 +1256,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1223
1256
|
*/
|
|
1224
1257
|
async getGCData(fullGC) {
|
|
1225
1258
|
const builder = new GCDataBuilder();
|
|
1226
|
-
const dsGCData = await this.
|
|
1259
|
+
const dsGCData = await this.summarizerNode.getGCData(fullGC);
|
|
1227
1260
|
builder.addNodes(dsGCData.gcNodes);
|
|
1228
1261
|
const blobsGCData = this.blobManager.getGCData(fullGC);
|
|
1229
1262
|
builder.addNodes(blobsGCData.gcNodes);
|
|
@@ -1239,39 +1272,26 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1239
1272
|
// summarizing is required and asserted by the the summarizer node. We are the root and are
|
|
1240
1273
|
// always referenced, so the used routes is only self-route (empty string).
|
|
1241
1274
|
this.summarizerNode.updateUsedRoutes([""]);
|
|
1242
|
-
const
|
|
1243
|
-
|
|
1244
|
-
for (const route of usedRoutes) {
|
|
1245
|
-
if (this.isBlobPath(route)) {
|
|
1246
|
-
blobManagerUsedRoutes.push(route);
|
|
1247
|
-
}
|
|
1248
|
-
else {
|
|
1249
|
-
dataStoreUsedRoutes.push(route);
|
|
1250
|
-
}
|
|
1251
|
-
}
|
|
1252
|
-
this.blobManager.updateUsedRoutes(blobManagerUsedRoutes);
|
|
1253
|
-
this.dataStores.updateUsedRoutes(dataStoreUsedRoutes);
|
|
1275
|
+
const { dataStoreRoutes } = this.getDataStoreAndBlobManagerRoutes(usedRoutes);
|
|
1276
|
+
this.dataStores.updateUsedRoutes(dataStoreRoutes);
|
|
1254
1277
|
}
|
|
1255
1278
|
/**
|
|
1256
|
-
* This is called to update objects whose routes are unused.
|
|
1257
|
-
*
|
|
1258
|
-
* @param unusedRoutes - The routes that are unused in all data stores and attachment blobs in this Container.
|
|
1259
|
-
* @param tombstone - if true, the objects corresponding to unused routes are marked tombstones. Otherwise, they
|
|
1260
|
-
* are deleted.
|
|
1279
|
+
* This is called to update objects whose routes are unused.
|
|
1280
|
+
* @param unusedRoutes - Data store and attachment blob routes that are unused in this Container.
|
|
1261
1281
|
*/
|
|
1262
|
-
updateUnusedRoutes(unusedRoutes
|
|
1263
|
-
const
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
}
|
|
1273
|
-
this.blobManager.
|
|
1274
|
-
this.dataStores.
|
|
1282
|
+
updateUnusedRoutes(unusedRoutes) {
|
|
1283
|
+
const { blobManagerRoutes, dataStoreRoutes } = this.getDataStoreAndBlobManagerRoutes(unusedRoutes);
|
|
1284
|
+
this.blobManager.updateUnusedRoutes(blobManagerRoutes);
|
|
1285
|
+
this.dataStores.updateUnusedRoutes(dataStoreRoutes);
|
|
1286
|
+
}
|
|
1287
|
+
/**
|
|
1288
|
+
* This is called to update objects that are tombstones.
|
|
1289
|
+
* @param tombstonedRoutes - Data store and attachment blob routes that are tombstones in this Container.
|
|
1290
|
+
*/
|
|
1291
|
+
updateTombstonedRoutes(tombstonedRoutes) {
|
|
1292
|
+
const { blobManagerRoutes, dataStoreRoutes } = this.getDataStoreAndBlobManagerRoutes(tombstonedRoutes);
|
|
1293
|
+
this.blobManager.updateTombstonedRoutes(blobManagerRoutes);
|
|
1294
|
+
this.dataStores.updateTombstonedRoutes(dataStoreRoutes);
|
|
1275
1295
|
}
|
|
1276
1296
|
/**
|
|
1277
1297
|
* Returns a server generated referenced timestamp to be used to track unreferenced nodes by GC.
|
|
@@ -1300,7 +1320,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1300
1320
|
async getGCNodePackagePath(nodePath) {
|
|
1301
1321
|
switch (this.getNodeType(nodePath)) {
|
|
1302
1322
|
case GCNodeType.Blob:
|
|
1303
|
-
return [
|
|
1323
|
+
return [BlobManager.basePath];
|
|
1304
1324
|
case GCNodeType.DataStore:
|
|
1305
1325
|
case GCNodeType.SubDataStore:
|
|
1306
1326
|
return this.dataStores.getDataStorePackagePath(nodePath);
|
|
@@ -1318,6 +1338,25 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1318
1338
|
}
|
|
1319
1339
|
return true;
|
|
1320
1340
|
}
|
|
1341
|
+
/**
|
|
1342
|
+
* From a given list of routes, separate and return routes that belong to blob manager and data stores.
|
|
1343
|
+
* @param routes - A list of routes that can belong to data stores or blob manager.
|
|
1344
|
+
* @returns - Two route lists - One that contains routes for blob manager and another one that contains routes
|
|
1345
|
+
* for data stores.
|
|
1346
|
+
*/
|
|
1347
|
+
getDataStoreAndBlobManagerRoutes(routes) {
|
|
1348
|
+
const blobManagerRoutes = [];
|
|
1349
|
+
const dataStoreRoutes = [];
|
|
1350
|
+
for (const route of routes) {
|
|
1351
|
+
if (this.isBlobPath(route)) {
|
|
1352
|
+
blobManagerRoutes.push(route);
|
|
1353
|
+
}
|
|
1354
|
+
else {
|
|
1355
|
+
dataStoreRoutes.push(route);
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
return { blobManagerRoutes, dataStoreRoutes };
|
|
1359
|
+
}
|
|
1321
1360
|
/**
|
|
1322
1361
|
* Runs garbage collection and updates the reference / used state of the nodes in the container.
|
|
1323
1362
|
* @returns the statistics of the garbage collection run; undefined if GC did not run.
|
|
@@ -1389,7 +1428,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1389
1428
|
if (this.deltaManager.lastSequenceNumber !== summaryRefSeqNum) {
|
|
1390
1429
|
return {
|
|
1391
1430
|
continue: false,
|
|
1392
|
-
// eslint-disable-next-line max-len
|
|
1393
1431
|
error: `lastSequenceNumber changed before uploading to storage. ${this.deltaManager.lastSequenceNumber} !== ${summaryRefSeqNum}`,
|
|
1394
1432
|
};
|
|
1395
1433
|
}
|
|
@@ -1397,7 +1435,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1397
1435
|
if (lastAck !== this.summaryCollection.latestAck) {
|
|
1398
1436
|
return {
|
|
1399
1437
|
continue: false,
|
|
1400
|
-
// eslint-disable-next-line max-len
|
|
1401
1438
|
error: `Last summary changed while summarizing. ${this.summaryCollection.latestAck} !== ${lastAck}`,
|
|
1402
1439
|
};
|
|
1403
1440
|
}
|
|
@@ -1612,7 +1649,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1612
1649
|
else if (!this.flushMicroTaskExists) {
|
|
1613
1650
|
this.flushMicroTaskExists = true;
|
|
1614
1651
|
// Queue a microtask to detect the end of the turn and force a flush.
|
|
1615
|
-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
1616
1652
|
Promise.resolve().then(() => {
|
|
1617
1653
|
this.flushMicroTaskExists = false;
|
|
1618
1654
|
this.flush();
|
|
@@ -1705,13 +1741,32 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1705
1741
|
// It should only be done by the summarizerNode, if required.
|
|
1706
1742
|
// When fetching from storage we will always get the latest version and do not use the ackHandle.
|
|
1707
1743
|
const snapshotTreeFetcher = async () => {
|
|
1708
|
-
const fetchResult = await this.
|
|
1744
|
+
const fetchResult = await this.fetchLatestSnapshotFromStorage(summaryLogger, {
|
|
1709
1745
|
eventName: "RefreshLatestSummaryGetSnapshot",
|
|
1710
1746
|
ackHandle,
|
|
1711
1747
|
summaryRefSeq,
|
|
1712
1748
|
fetchLatest: true,
|
|
1713
1749
|
});
|
|
1714
1750
|
const latestSnapshotRefSeq = await seqFromTree(fetchResult.snapshotTree, readAndParseBlob);
|
|
1751
|
+
/**
|
|
1752
|
+
* If the fetched snapshot is older than the one for which the ack was received, close the container.
|
|
1753
|
+
* This should never happen because an ack should be sent after the latest summary is updated in the server.
|
|
1754
|
+
* However, there are couple of scenarios where it's possible:
|
|
1755
|
+
* 1. A file was modified externally resulting in modifying the snapshot's sequence number. This can lead to
|
|
1756
|
+
* the document being unusable and we should not proceed.
|
|
1757
|
+
* 2. The server DB failed after the ack was sent which may delete the corresponding snapshot. Ideally, in
|
|
1758
|
+
* such cases, the file will be rolled back along with the ack and we will eventually reach a consistent
|
|
1759
|
+
* state.
|
|
1760
|
+
*/
|
|
1761
|
+
if (latestSnapshotRefSeq < summaryRefSeq) {
|
|
1762
|
+
const error = DataProcessingError.create("Fetched snapshot is older than the received ack", "RefreshLatestSummaryAck", undefined /* sequencedMessage */, {
|
|
1763
|
+
ackHandle,
|
|
1764
|
+
summaryRefSeq,
|
|
1765
|
+
latestSnapshotRefSeq,
|
|
1766
|
+
});
|
|
1767
|
+
this.closeFn(error);
|
|
1768
|
+
throw error;
|
|
1769
|
+
}
|
|
1715
1770
|
summaryLogger.sendTelemetryEvent({
|
|
1716
1771
|
eventName: "LatestSummaryRetrieved",
|
|
1717
1772
|
ackHandle,
|
|
@@ -1725,7 +1780,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1725
1780
|
};
|
|
1726
1781
|
const result = await this.summarizerNode.refreshLatestSummary(proposalHandle, summaryRefSeq, snapshotTreeFetcher, readAndParseBlob, summaryLogger);
|
|
1727
1782
|
// Notify the garbage collector so it can update its latest summary state.
|
|
1728
|
-
await this.garbageCollector.
|
|
1783
|
+
await this.garbageCollector.refreshLatestSummary(result, proposalHandle, summaryRefSeq, readAndParseBlob);
|
|
1729
1784
|
}
|
|
1730
1785
|
/**
|
|
1731
1786
|
* Fetches the latest snapshot from storage and uses it to refresh SummarizerNode's
|
|
@@ -1734,22 +1789,22 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1734
1789
|
* @returns downloaded snapshot's reference sequence number
|
|
1735
1790
|
*/
|
|
1736
1791
|
async refreshLatestSummaryAckFromServer(summaryLogger) {
|
|
1737
|
-
const { snapshotTree, versionId } = await this.
|
|
1792
|
+
const { snapshotTree, versionId } = await this.fetchLatestSnapshotFromStorage(summaryLogger, {
|
|
1738
1793
|
eventName: "RefreshLatestSummaryGetSnapshot",
|
|
1739
1794
|
fetchLatest: true,
|
|
1740
|
-
}
|
|
1795
|
+
});
|
|
1741
1796
|
const readAndParseBlob = async (id) => readAndParse(this.storage, id);
|
|
1742
1797
|
const latestSnapshotRefSeq = await seqFromTree(snapshotTree, readAndParseBlob);
|
|
1743
1798
|
const result = await this.summarizerNode.refreshLatestSummary(undefined, latestSnapshotRefSeq, async () => snapshotTree, readAndParseBlob, summaryLogger);
|
|
1744
1799
|
// Notify the garbage collector so it can update its latest summary state.
|
|
1745
|
-
await this.garbageCollector.
|
|
1800
|
+
await this.garbageCollector.refreshLatestSummary(result, undefined, latestSnapshotRefSeq, readAndParseBlob);
|
|
1746
1801
|
return { latestSnapshotRefSeq, latestSnapshotVersionId: versionId };
|
|
1747
1802
|
}
|
|
1748
|
-
async
|
|
1803
|
+
async fetchLatestSnapshotFromStorage(logger, event) {
|
|
1749
1804
|
return PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
|
|
1750
1805
|
const stats = {};
|
|
1751
1806
|
const trace = Trace.start();
|
|
1752
|
-
const versions = await this.storage.getVersions(
|
|
1807
|
+
const versions = await this.storage.getVersions(null, 1, "refreshLatestSummaryAckFromServer", FetchSource.noCache);
|
|
1753
1808
|
assert(!!versions && !!versions[0], 0x137 /* "Failed to get version from storage" */);
|
|
1754
1809
|
stats.getVersionDuration = trace.trace().duration;
|
|
1755
1810
|
const maybeSnapshot = await this.storage.getSnapshotTree(versions[0]);
|
|
@@ -1865,6 +1920,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1865
1920
|
const waitForSeq = async (deltaManager, targetSeq) => new Promise((resolve, reject) => {
|
|
1866
1921
|
// TODO: remove cast to any when actual event is determined
|
|
1867
1922
|
deltaManager.on("closed", reject);
|
|
1923
|
+
deltaManager.on("disposed", reject);
|
|
1868
1924
|
// If we already reached target sequence number, simply resolve the promise.
|
|
1869
1925
|
if (deltaManager.lastSequenceNumber >= targetSeq) {
|
|
1870
1926
|
resolve();
|