@fluidframework/container-runtime 2.0.0-rc.3.0.1 → 2.0.0-rc.3.0.11
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/api-report/container-runtime.api.md +30 -12
- package/dist/channelCollection.d.ts +5 -3
- package/dist/channelCollection.d.ts.map +1 -1
- package/dist/channelCollection.js +88 -29
- package/dist/channelCollection.js.map +1 -1
- package/dist/containerRuntime.d.ts +6 -1
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +55 -48
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStoreContext.d.ts +1 -1
- package/dist/dataStoreContexts.d.ts +2 -0
- package/dist/dataStoreContexts.d.ts.map +1 -1
- package/dist/dataStoreContexts.js +7 -0
- package/dist/dataStoreContexts.js.map +1 -1
- package/dist/gc/garbageCollection.d.ts +4 -11
- package/dist/gc/garbageCollection.d.ts.map +1 -1
- package/dist/gc/garbageCollection.js +45 -29
- package/dist/gc/garbageCollection.js.map +1 -1
- package/dist/gc/gcDefinitions.d.ts +26 -5
- package/dist/gc/gcDefinitions.d.ts.map +1 -1
- package/dist/gc/gcDefinitions.js.map +1 -1
- package/dist/gc/gcHelpers.d.ts +5 -4
- package/dist/gc/gcHelpers.d.ts.map +1 -1
- package/dist/gc/gcHelpers.js +14 -2
- package/dist/gc/gcHelpers.js.map +1 -1
- package/dist/gc/gcTelemetry.d.ts +13 -2
- package/dist/gc/gcTelemetry.d.ts.map +1 -1
- package/dist/gc/gcTelemetry.js +24 -21
- package/dist/gc/gcTelemetry.js.map +1 -1
- package/dist/gc/index.d.ts +2 -2
- package/dist/gc/index.d.ts.map +1 -1
- package/dist/gc/index.js +2 -2
- package/dist/gc/index.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/legacy.d.ts +1 -0
- package/dist/metadata.d.ts +2 -2
- package/dist/metadata.d.ts.map +1 -1
- package/dist/metadata.js.map +1 -1
- package/dist/opLifecycle/batchManager.d.ts +4 -1
- package/dist/opLifecycle/batchManager.d.ts.map +1 -1
- package/dist/opLifecycle/batchManager.js +0 -10
- package/dist/opLifecycle/batchManager.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts +0 -4
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +7 -38
- package/dist/opLifecycle/outbox.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.d.ts.map +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/summary/documentSchema.js +1 -1
- package/dist/summary/documentSchema.js.map +1 -1
- package/lib/channelCollection.d.ts +5 -3
- package/lib/channelCollection.d.ts.map +1 -1
- package/lib/channelCollection.js +90 -31
- package/lib/channelCollection.js.map +1 -1
- package/lib/containerRuntime.d.ts +6 -1
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +54 -47
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStoreContext.d.ts +1 -1
- package/lib/dataStoreContexts.d.ts +2 -0
- package/lib/dataStoreContexts.d.ts.map +1 -1
- package/lib/dataStoreContexts.js +7 -0
- package/lib/dataStoreContexts.js.map +1 -1
- package/lib/gc/garbageCollection.d.ts +4 -11
- package/lib/gc/garbageCollection.d.ts.map +1 -1
- package/lib/gc/garbageCollection.js +47 -31
- package/lib/gc/garbageCollection.js.map +1 -1
- package/lib/gc/gcDefinitions.d.ts +26 -5
- package/lib/gc/gcDefinitions.d.ts.map +1 -1
- package/lib/gc/gcDefinitions.js.map +1 -1
- package/lib/gc/gcHelpers.d.ts +5 -4
- package/lib/gc/gcHelpers.d.ts.map +1 -1
- package/lib/gc/gcHelpers.js +12 -1
- package/lib/gc/gcHelpers.js.map +1 -1
- package/lib/gc/gcTelemetry.d.ts +13 -2
- package/lib/gc/gcTelemetry.d.ts.map +1 -1
- package/lib/gc/gcTelemetry.js +24 -21
- package/lib/gc/gcTelemetry.js.map +1 -1
- package/lib/gc/index.d.ts +2 -2
- package/lib/gc/index.d.ts.map +1 -1
- package/lib/gc/index.js +1 -1
- package/lib/gc/index.js.map +1 -1
- package/lib/index.d.ts +2 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/legacy.d.ts +1 -0
- package/lib/metadata.d.ts +2 -2
- package/lib/metadata.d.ts.map +1 -1
- package/lib/metadata.js.map +1 -1
- package/lib/opLifecycle/batchManager.d.ts +4 -1
- package/lib/opLifecycle/batchManager.d.ts.map +1 -1
- package/lib/opLifecycle/batchManager.js +0 -10
- package/lib/opLifecycle/batchManager.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts +0 -4
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.js +7 -38
- package/lib/opLifecycle/outbox.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.d.ts.map +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/summary/documentSchema.js +1 -1
- package/lib/summary/documentSchema.js.map +1 -1
- package/package.json +20 -20
- package/src/channelCollection.ts +108 -49
- package/src/containerRuntime.ts +66 -80
- package/src/dataStoreContexts.ts +12 -0
- package/src/gc/garbageCollection.ts +63 -41
- package/src/gc/gcDefinitions.ts +21 -9
- package/src/gc/gcHelpers.ts +14 -1
- package/src/gc/gcTelemetry.ts +56 -47
- package/src/gc/index.ts +2 -1
- package/src/index.ts +2 -0
- package/src/metadata.ts +2 -2
- package/src/opLifecycle/README.md +4 -4
- package/src/opLifecycle/batchManager.ts +5 -14
- package/src/opLifecycle/outbox.ts +7 -53
- package/src/packageVersion.ts +1 -1
- package/src/summary/documentSchema.ts +1 -1
- package/dist/public.d.ts +0 -12
- package/lib/public.d.ts +0 -12
package/lib/containerRuntime.js
CHANGED
|
@@ -60,6 +60,11 @@ export const DefaultSummaryConfiguration = {
|
|
|
60
60
|
runtimeOpWeight: 1.0,
|
|
61
61
|
nonRuntimeHeuristicThreshold: 20,
|
|
62
62
|
};
|
|
63
|
+
/**
|
|
64
|
+
* Error responses when requesting a deleted object will have this header set to true
|
|
65
|
+
* @alpha
|
|
66
|
+
*/
|
|
67
|
+
export const DeletedResponseHeaderKey = "wasDeleted";
|
|
63
68
|
/**
|
|
64
69
|
* Tombstone error responses will have this header set to true
|
|
65
70
|
* @alpha
|
|
@@ -736,7 +741,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
736
741
|
const envelope2 = this.createNewSignalEnvelope(envelope1.address, type, envelope1.contents);
|
|
737
742
|
return this.submitSignalFn(envelope2, targetClientId);
|
|
738
743
|
};
|
|
739
|
-
this.channelCollection = new ChannelCollection(getSummaryForDatastores(baseSnapshot, metadata), parentContext, this.mc.logger, (
|
|
744
|
+
this.channelCollection = new ChannelCollection(getSummaryForDatastores(baseSnapshot, metadata), parentContext, this.mc.logger, (props) => this.garbageCollector.nodeUpdated(props), (path) => this.garbageCollector.isNodeDeleted(path), new Map(dataStoreAliasMap), async (runtime) => provideEntryPoint);
|
|
740
745
|
this.blobManager = new BlobManager({
|
|
741
746
|
routeContext: this.handleContext,
|
|
742
747
|
snapshot: blobManagerSnapshot,
|
|
@@ -749,7 +754,10 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
749
754
|
});
|
|
750
755
|
}
|
|
751
756
|
},
|
|
752
|
-
blobRequested: (blobPath) => this.garbageCollector.nodeUpdated(
|
|
757
|
+
blobRequested: (blobPath) => this.garbageCollector.nodeUpdated({
|
|
758
|
+
node: { type: "Blob", path: blobPath },
|
|
759
|
+
reason: "Loaded",
|
|
760
|
+
}),
|
|
753
761
|
isBlobDeleted: (blobPath) => this.garbageCollector.isNodeDeleted(blobPath),
|
|
754
762
|
runtime: this,
|
|
755
763
|
stashedBlobs: pendingRuntimeState?.pendingAttachmentBlobs,
|
|
@@ -1232,6 +1240,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1232
1240
|
this.emitDirtyDocumentEvent = false;
|
|
1233
1241
|
let newState;
|
|
1234
1242
|
try {
|
|
1243
|
+
this.submitIdAllocationOpIfNeeded(true);
|
|
1235
1244
|
// replay the ops
|
|
1236
1245
|
this.pendingStateManager.replayPendingStates();
|
|
1237
1246
|
}
|
|
@@ -1408,9 +1417,10 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1408
1417
|
// We do not need to make a deep copy. Each layer will just replace message.contents itself,
|
|
1409
1418
|
// but will not modify the contents object (likely it will replace it on the message).
|
|
1410
1419
|
const messageCopy = { ...messageArg };
|
|
1420
|
+
const savedOp = messageCopy.metadata?.savedOp;
|
|
1411
1421
|
for (const message of this.remoteMessageProcessor.process(messageCopy)) {
|
|
1412
|
-
|
|
1413
|
-
|
|
1422
|
+
const msg = modernRuntimeMessage
|
|
1423
|
+
? {
|
|
1414
1424
|
// Cast it since we expect it to be this based on modernRuntimeMessage computation above.
|
|
1415
1425
|
// There is nothing really ensuring that anytime original message.type is Operation that
|
|
1416
1426
|
// the result messages will be so. In the end modern bool being true only directs to
|
|
@@ -1418,12 +1428,16 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1418
1428
|
message: message,
|
|
1419
1429
|
local,
|
|
1420
1430
|
modernRuntimeMessage,
|
|
1421
|
-
}
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1431
|
+
}
|
|
1432
|
+
: // Unrecognized message will be ignored.
|
|
1433
|
+
{
|
|
1434
|
+
message,
|
|
1435
|
+
local,
|
|
1436
|
+
modernRuntimeMessage,
|
|
1437
|
+
};
|
|
1438
|
+
msg.savedOp = savedOp;
|
|
1439
|
+
// ensure that we observe any re-entrancy, and if needed, rebase ops
|
|
1440
|
+
this.ensureNoDataModelChanges(() => this.processCore(msg));
|
|
1427
1441
|
}
|
|
1428
1442
|
}
|
|
1429
1443
|
/**
|
|
@@ -1488,9 +1502,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1488
1502
|
// stashed ops flow. The compressor is stashed with these ops already processed.
|
|
1489
1503
|
// That said, in idCompressorMode === "delayed", we might not serialize ID compressor, and
|
|
1490
1504
|
// thus we need to process all the ops.
|
|
1491
|
-
if (!(this.skipSavedCompressorOps &&
|
|
1492
|
-
messageWithContext.message.metadata?.savedOp ===
|
|
1493
|
-
true)) {
|
|
1505
|
+
if (!(this.skipSavedCompressorOps && messageWithContext.savedOp === true)) {
|
|
1494
1506
|
const range = messageWithContext.message.contents;
|
|
1495
1507
|
// Some other client turned on the id compressor. If we have not turned it on,
|
|
1496
1508
|
// put it in a pending queue and delay finalization.
|
|
@@ -1619,9 +1631,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1619
1631
|
let checkpoint;
|
|
1620
1632
|
let result;
|
|
1621
1633
|
if (this.mc.config.getBoolean("Fluid.ContainerRuntime.EnableRollback")) {
|
|
1622
|
-
// Note: we are not touching
|
|
1623
|
-
// 1. It would not help, as
|
|
1624
|
-
// 2. There is no way to undo process of data store creation.
|
|
1634
|
+
// Note: we are not touching any batches other than mainBatch here, for two reasons:
|
|
1635
|
+
// 1. It would not help, as other batches are flushed independently from main batch.
|
|
1636
|
+
// 2. There is no way to undo process of data store creation, blob creation, ID compressor ops, or other things tracked by other batches.
|
|
1625
1637
|
checkpoint = this.outbox.checkpoint().mainBatch;
|
|
1626
1638
|
}
|
|
1627
1639
|
try {
|
|
@@ -1684,7 +1696,11 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1684
1696
|
if (channel.entryPoint === undefined) {
|
|
1685
1697
|
throw new UsageError("entryPoint must be defined on data store runtime for using getAliasedDataStoreEntryPoint");
|
|
1686
1698
|
}
|
|
1687
|
-
this.garbageCollector.nodeUpdated(
|
|
1699
|
+
this.garbageCollector.nodeUpdated({
|
|
1700
|
+
node: { type: "DataStore", path: `/${internalId}` },
|
|
1701
|
+
reason: "Loaded",
|
|
1702
|
+
packagePath: context.packagePath,
|
|
1703
|
+
});
|
|
1688
1704
|
return channel.entryPoint;
|
|
1689
1705
|
}
|
|
1690
1706
|
createDetachedDataStore(pkg, loadingGroupId) {
|
|
@@ -2079,9 +2095,17 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2079
2095
|
const message = `Summary @${summaryRefSeqNum}:${this.deltaManager.minimumSequenceNumber}`;
|
|
2080
2096
|
const lastAck = this.summaryCollection.latestAck;
|
|
2081
2097
|
const startSummaryResult = this.summarizerNode.startSummary(summaryRefSeqNum, summaryNumberLogger, latestSummaryRefSeqNum);
|
|
2098
|
+
/**
|
|
2099
|
+
* This was added to validate that the summarizer node tree has the same reference sequence number from the
|
|
2100
|
+
* top running summarizer down to the lowest summarizer node.
|
|
2101
|
+
*
|
|
2102
|
+
* The order of mismatch numbers goes (validate sequence number)-(node sequence number).
|
|
2103
|
+
* Generally the validate sequence number comes from the running summarizer and the node sequence number comes from the
|
|
2104
|
+
* summarizer nodes.
|
|
2105
|
+
*/
|
|
2082
2106
|
if (startSummaryResult.invalidNodes > 0 ||
|
|
2083
2107
|
startSummaryResult.mismatchNumbers.size > 0) {
|
|
2084
|
-
summaryLogger.
|
|
2108
|
+
summaryLogger.sendTelemetryEvent({
|
|
2085
2109
|
eventName: "LatestSummaryRefSeqNumMismatch",
|
|
2086
2110
|
details: {
|
|
2087
2111
|
...startSummaryResult,
|
|
@@ -2354,9 +2378,11 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2354
2378
|
this.verifyNotClosed();
|
|
2355
2379
|
return this.blobManager.createBlob(blob, signal);
|
|
2356
2380
|
}
|
|
2357
|
-
submitIdAllocationOpIfNeeded() {
|
|
2381
|
+
submitIdAllocationOpIfNeeded(resubmitOutstandingRanges = false) {
|
|
2358
2382
|
if (this._idCompressor) {
|
|
2359
|
-
const idRange =
|
|
2383
|
+
const idRange = resubmitOutstandingRanges
|
|
2384
|
+
? this.idCompressor?.takeUnfinalizedCreationRange()
|
|
2385
|
+
: this._idCompressor.takeNextCreationRange();
|
|
2360
2386
|
// Don't include the idRange if there weren't any Ids allocated
|
|
2361
2387
|
if (idRange?.ids !== undefined) {
|
|
2362
2388
|
const idAllocationMessage = {
|
|
@@ -2418,32 +2444,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2418
2444
|
referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
2419
2445
|
});
|
|
2420
2446
|
}
|
|
2421
|
-
|
|
2422
|
-
// Is it safe:
|
|
2423
|
-
// Yes, this should be safe reordering. Newly created data stores are not visible through API surface.
|
|
2424
|
-
// They become visible only when aliased, or handle to some sub-element of newly created datastore
|
|
2425
|
-
// is stored in some DDS, i.e. only after some other op.
|
|
2426
|
-
// Why:
|
|
2427
|
-
// Attach ops are large, and expensive to process. Plus there are scenarios where a lot of new data
|
|
2428
|
-
// stores are created, causing issues like relay service throttling (too many ops) and catastrophic
|
|
2429
|
-
// failure (batch is too large). Pushing them earlier and outside of main batch should alleviate
|
|
2430
|
-
// these issues.
|
|
2431
|
-
// Cons:
|
|
2432
|
-
// 1. With large batches, relay service may throttle clients. Clients may disconnect while throttled.
|
|
2433
|
-
// This change creates new possibility of a lot of newly created data stores never being referenced
|
|
2434
|
-
// because client died before it had a change to submit the rest of the ops. This will create more
|
|
2435
|
-
// garbage that needs to be collected leveraging GC (Garbage Collection) feature.
|
|
2436
|
-
// 2. Sending ops out of order means they are excluded from rollback functionality. This is not an issue
|
|
2437
|
-
// today as rollback can't undo creation of data store. To some extent not sending them is a bigger
|
|
2438
|
-
// issue than sending.
|
|
2439
|
-
// Please note that this does not change file format, so it can be disabled in the future if this
|
|
2440
|
-
// optimization no longer makes sense (for example, batch compression may make it less appealing).
|
|
2441
|
-
if (this.currentlyBatching() &&
|
|
2442
|
-
type === ContainerMessageType.Attach &&
|
|
2443
|
-
this.disableAttachReorder !== true) {
|
|
2444
|
-
this.outbox.submitAttach(message);
|
|
2445
|
-
}
|
|
2446
|
-
else if (type === ContainerMessageType.BlobAttach) {
|
|
2447
|
+
if (type === ContainerMessageType.BlobAttach) {
|
|
2447
2448
|
// BlobAttach ops must have their metadata visible and cannot be grouped (see opGroupingManager.ts)
|
|
2448
2449
|
this.outbox.submitBlobAttach(message);
|
|
2449
2450
|
}
|
|
@@ -2575,7 +2576,13 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2575
2576
|
this.channelCollection.reSubmit(message.type, message.contents, localOpMetadata);
|
|
2576
2577
|
break;
|
|
2577
2578
|
case ContainerMessageType.IdAllocation: {
|
|
2578
|
-
|
|
2579
|
+
// Allocation ops are never resubmitted/rebased. This is because they require special handling to
|
|
2580
|
+
// avoid being submitted out of order. For example, if the pending state manager contained
|
|
2581
|
+
// [idOp1, dataOp1, idOp2, dataOp2] and the resubmission of dataOp1 generated idOp3, that would be
|
|
2582
|
+
// placed into the outbox in the same batch as idOp1, but before idOp2 is resubmitted.
|
|
2583
|
+
// To avoid this, allocation ops are simply never resubmitted. Prior to invoking the pending state
|
|
2584
|
+
// manager to replay pending ops, the runtime will always submit a new allocation range that includes
|
|
2585
|
+
// all pending IDs. The resubmitted allocation ops are then ignored here.
|
|
2579
2586
|
break;
|
|
2580
2587
|
}
|
|
2581
2588
|
case ContainerMessageType.ChunkedOp:
|