@fluidframework/container-runtime 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/containerRuntime.d.ts +1 -1
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +8 -8
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStore.d.ts +2 -2
- package/dist/dataStore.d.ts.map +1 -1
- package/dist/dataStore.js +2 -2
- package/dist/dataStore.js.map +1 -1
- package/dist/dataStoreContext.d.ts +4 -4
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStores.d.ts +2 -2
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/dataStores.js +6 -5
- package/dist/dataStores.js.map +1 -1
- package/dist/garbageCollection.d.ts +33 -14
- package/dist/garbageCollection.d.ts.map +1 -1
- package/dist/garbageCollection.js +243 -122
- package/dist/garbageCollection.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/summarizerTypes.d.ts +5 -2
- package/dist/summarizerTypes.d.ts.map +1 -1
- package/dist/summarizerTypes.js.map +1 -1
- package/dist/summaryFormat.d.ts +6 -3
- package/dist/summaryFormat.d.ts.map +1 -1
- package/dist/summaryFormat.js +6 -3
- package/dist/summaryFormat.js.map +1 -1
- package/dist/summaryGenerator.d.ts.map +1 -1
- package/dist/summaryGenerator.js +0 -1
- package/dist/summaryGenerator.js.map +1 -1
- package/garbageCollection.md +7 -7
- package/lib/containerRuntime.d.ts +1 -1
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +9 -9
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStore.d.ts +2 -2
- package/lib/dataStore.d.ts.map +1 -1
- package/lib/dataStore.js +2 -2
- package/lib/dataStore.js.map +1 -1
- package/lib/dataStoreContext.d.ts +4 -4
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStores.d.ts +2 -2
- package/lib/dataStores.d.ts.map +1 -1
- package/lib/dataStores.js +6 -5
- package/lib/dataStores.js.map +1 -1
- package/lib/garbageCollection.d.ts +33 -14
- package/lib/garbageCollection.d.ts.map +1 -1
- package/lib/garbageCollection.js +242 -121
- package/lib/garbageCollection.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/summarizerTypes.d.ts +5 -2
- package/lib/summarizerTypes.d.ts.map +1 -1
- package/lib/summarizerTypes.js.map +1 -1
- package/lib/summaryFormat.d.ts +6 -3
- package/lib/summaryFormat.d.ts.map +1 -1
- package/lib/summaryFormat.js +6 -3
- package/lib/summaryFormat.js.map +1 -1
- package/lib/summaryGenerator.d.ts.map +1 -1
- package/lib/summaryGenerator.js +0 -1
- package/lib/summaryGenerator.js.map +1 -1
- package/package.json +16 -16
- package/src/containerRuntime.ts +60 -58
- package/src/dataStore.ts +4 -4
- package/src/dataStoreContext.ts +4 -4
- package/src/dataStores.ts +5 -5
- package/src/garbageCollection.ts +308 -167
- package/src/packageVersion.ts +1 -1
- package/src/summarizerTypes.ts +6 -3
- package/src/summaryFormat.ts +6 -3
- package/src/summaryGenerator.ts +0 -2
package/src/containerRuntime.ts
CHANGED
|
@@ -46,7 +46,7 @@ import {
|
|
|
46
46
|
TelemetryDataTag,
|
|
47
47
|
} from "@fluidframework/telemetry-utils";
|
|
48
48
|
import { DriverHeader, IDocumentStorageService, ISummaryContext } from "@fluidframework/driver-definitions";
|
|
49
|
-
import { readAndParse } from "@fluidframework/driver-utils";
|
|
49
|
+
import { readAndParse, isUnpackedRuntimeMessage } from "@fluidframework/driver-utils";
|
|
50
50
|
import {
|
|
51
51
|
DataCorruptionError,
|
|
52
52
|
DataProcessingError,
|
|
@@ -253,9 +253,9 @@ export interface ISummaryConfigurationDisableHeuristics extends ISummaryBaseConf
|
|
|
253
253
|
}
|
|
254
254
|
|
|
255
255
|
export type ISummaryConfiguration =
|
|
256
|
-
| ISummaryConfigurationDisableSummarizer
|
|
257
|
-
| ISummaryConfigurationDisableHeuristics
|
|
258
|
-
| ISummaryConfigurationHeuristics;
|
|
256
|
+
| ISummaryConfigurationDisableSummarizer
|
|
257
|
+
| ISummaryConfigurationDisableHeuristics
|
|
258
|
+
| ISummaryConfigurationHeuristics;
|
|
259
259
|
|
|
260
260
|
export const DefaultSummaryConfiguration: ISummaryConfiguration = {
|
|
261
261
|
state: "enabled",
|
|
@@ -341,11 +341,11 @@ export interface ISummaryRuntimeOptions {
|
|
|
341
341
|
*/
|
|
342
342
|
maxOpsSinceLastSummary?: number;
|
|
343
343
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
344
|
+
/**
|
|
345
|
+
* @deprecated - use `summaryConfigOverrides.summarizerClientElection` instead.
|
|
346
|
+
* Flag that will enable changing elected summarizer client after maxOpsSinceLastSummary.
|
|
347
|
+
* This defaults to false (disabled) and must be explicitly set to true to enable.
|
|
348
|
+
*/
|
|
349
349
|
summarizerClientElection?: boolean;
|
|
350
350
|
|
|
351
351
|
/**
|
|
@@ -502,7 +502,7 @@ export function unpackRuntimeMessage(message: ISequencedDocumentMessage) {
|
|
|
502
502
|
message.type = innerContents.type;
|
|
503
503
|
message.contents = innerContents.contents;
|
|
504
504
|
}
|
|
505
|
-
assert(
|
|
505
|
+
assert(isUnpackedRuntimeMessage(message), 0x122 /* "Message to unpack is not proper runtime message" */);
|
|
506
506
|
} else {
|
|
507
507
|
// Legacy format, but it's already "unpacked",
|
|
508
508
|
// i.e. message.type is actually ContainerMessageType.
|
|
@@ -574,7 +574,7 @@ class ScheduleManagerCore {
|
|
|
574
574
|
* The only public function in this class - called when we processed an op,
|
|
575
575
|
* to make decision if op processing should be paused or not afer that.
|
|
576
576
|
*/
|
|
577
|
-
|
|
577
|
+
public afterOpProcessing(sequenceNumber: number) {
|
|
578
578
|
assert(!this.localPaused, 0x294 /* "can't have op processing paused if we are processing an op" */);
|
|
579
579
|
|
|
580
580
|
// If the inbound queue is ever empty, nothing to do!
|
|
@@ -659,7 +659,7 @@ class ScheduleManagerCore {
|
|
|
659
659
|
const batchMetadata = metadata?.batch;
|
|
660
660
|
|
|
661
661
|
// Protocol messages are never part of a runtime batch of messages
|
|
662
|
-
if (!
|
|
662
|
+
if (!isUnpackedRuntimeMessage(message)) {
|
|
663
663
|
// Protocol messages should never show up in the middle of the batch!
|
|
664
664
|
assert(this.currentBatchClientId === undefined, 0x29a /* "System message in the middle of batch!" */);
|
|
665
665
|
assert(batchMetadata === undefined, 0x29b /* "system op in a batch?" */);
|
|
@@ -681,6 +681,7 @@ class ScheduleManagerCore {
|
|
|
681
681
|
throw new DataCorruptionError(
|
|
682
682
|
"OpBatchIncomplete",
|
|
683
683
|
{
|
|
684
|
+
runtimeVersion: pkgVersion,
|
|
684
685
|
batchClientId: this.currentBatchClientId,
|
|
685
686
|
...extractSafePropertiesFromMessage(message),
|
|
686
687
|
});
|
|
@@ -812,11 +813,11 @@ export function getDeviceSpec() {
|
|
|
812
813
|
*/
|
|
813
814
|
export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
814
815
|
implements
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
816
|
+
IContainerRuntime,
|
|
817
|
+
IGarbageCollectionRuntime,
|
|
818
|
+
IRuntime,
|
|
819
|
+
ISummarizerRuntime,
|
|
820
|
+
ISummarizerInternalsProvider {
|
|
820
821
|
public get IContainerRuntime() { return this; }
|
|
821
822
|
public get IFluidRouter() { return this; }
|
|
822
823
|
|
|
@@ -905,7 +906,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
905
906
|
const error = new DataCorruptionError(
|
|
906
907
|
// pre-0.58 error message: SummaryMetadataMismatch
|
|
907
908
|
"Summary metadata mismatch",
|
|
908
|
-
{ runtimeSequenceNumber, protocolSequenceNumber },
|
|
909
|
+
{ runtimeVersion: pkgVersion, runtimeSequenceNumber, protocolSequenceNumber },
|
|
909
910
|
);
|
|
910
911
|
|
|
911
912
|
if (loadSequenceNumberVerification === "log") {
|
|
@@ -1177,9 +1178,9 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
1177
1178
|
private readonly requestHandler?: (request: IRequest, runtime: IContainerRuntime) => Promise<IResponse>,
|
|
1178
1179
|
private readonly summaryConfiguration: ISummaryConfiguration = {
|
|
1179
1180
|
// the defaults
|
|
1180
|
-
...
|
|
1181
|
+
...DefaultSummaryConfiguration,
|
|
1181
1182
|
// the runtime configuration overrides
|
|
1182
|
-
...
|
|
1183
|
+
...runtimeOptions.summaryOptions?.summaryConfigOverrides,
|
|
1183
1184
|
},
|
|
1184
1185
|
) {
|
|
1185
1186
|
super();
|
|
@@ -1223,7 +1224,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
1223
1224
|
existing,
|
|
1224
1225
|
metadata,
|
|
1225
1226
|
isSummarizerClient: this.context.clientDetails.type === summarizerClientType,
|
|
1226
|
-
getNodePackagePath: (nodePath: string) => this.getGCNodePackagePath(nodePath),
|
|
1227
|
+
getNodePackagePath: async (nodePath: string) => this.getGCNodePackagePath(nodePath),
|
|
1227
1228
|
getLastSummaryTimestampMs: () => this.messageAtLastSummary?.timestamp,
|
|
1228
1229
|
readAndParseBlob: async <T>(id: string) => readAndParse<T>(this.storage, id),
|
|
1229
1230
|
});
|
|
@@ -1259,17 +1260,17 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
1259
1260
|
this,
|
|
1260
1261
|
(attachMsg) => this.submit(ContainerMessageType.Attach, attachMsg),
|
|
1261
1262
|
(id: string, createParam: CreateChildSummarizerNodeParam) => (
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1263
|
+
summarizeInternal: SummarizeInternalFn,
|
|
1264
|
+
getGCDataFn: (fullGC?: boolean) => Promise<IGarbageCollectionData>,
|
|
1265
|
+
getBaseGCDetailsFn: () => Promise<IGarbageCollectionDetailsBase>,
|
|
1266
|
+
) => this.summarizerNode.createChild(
|
|
1267
|
+
summarizeInternal,
|
|
1268
|
+
id,
|
|
1269
|
+
createParam,
|
|
1270
|
+
undefined,
|
|
1271
|
+
getGCDataFn,
|
|
1272
|
+
getBaseGCDetailsFn,
|
|
1273
|
+
),
|
|
1273
1274
|
(id: string) => this.summarizerNode.deleteChild(id),
|
|
1274
1275
|
this.mc.logger,
|
|
1275
1276
|
async () => this.garbageCollector.getBaseGCDetails(),
|
|
@@ -1801,7 +1802,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
1801
1802
|
this.verifyNotClosed();
|
|
1802
1803
|
|
|
1803
1804
|
// If it's not message for runtime, bail out right away.
|
|
1804
|
-
if (!
|
|
1805
|
+
if (!isUnpackedRuntimeMessage(messageArg)) {
|
|
1805
1806
|
return;
|
|
1806
1807
|
}
|
|
1807
1808
|
|
|
@@ -2249,7 +2250,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
2249
2250
|
|
|
2250
2251
|
public submitDataStoreSignal(address: string, type: string, content: any) {
|
|
2251
2252
|
const envelope = this.createNewSignalEnvelope(address, type, content);
|
|
2252
|
-
|
|
2253
|
+
return this.context.submitSignalFn(envelope);
|
|
2253
2254
|
}
|
|
2254
2255
|
|
|
2255
2256
|
public setAttachState(attachState: AttachState.Attaching | AttachState.Attached): void {
|
|
@@ -2348,7 +2349,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
2348
2349
|
const {
|
|
2349
2350
|
fullTree = false,
|
|
2350
2351
|
trackState = true,
|
|
2351
|
-
summaryLogger = this.logger,
|
|
2352
|
+
summaryLogger = this.mc.logger,
|
|
2352
2353
|
runGC = this.garbageCollector.shouldRunGC,
|
|
2353
2354
|
runSweep,
|
|
2354
2355
|
fullGC,
|
|
@@ -2462,7 +2463,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
2462
2463
|
* Called by GC to retrieve the package path of the node with the given path. The node should belong to a
|
|
2463
2464
|
* data store or an attachment blob.
|
|
2464
2465
|
*/
|
|
2465
|
-
public getGCNodePackagePath(nodePath: string): readonly string[] | undefined {
|
|
2466
|
+
public async getGCNodePackagePath(nodePath: string): Promise<readonly string[] | undefined> {
|
|
2466
2467
|
switch (this.getNodeType(nodePath)) {
|
|
2467
2468
|
case GCNodeType.Blob:
|
|
2468
2469
|
return ["_blobs"];
|
|
@@ -2675,16 +2676,16 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
2675
2676
|
const lastAck = this.summaryCollection.latestAck;
|
|
2676
2677
|
const summaryContext: ISummaryContext =
|
|
2677
2678
|
lastAck === undefined
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2679
|
+
? {
|
|
2680
|
+
proposalHandle: undefined,
|
|
2681
|
+
ackHandle: this.context.getLoadedFromVersion()?.id,
|
|
2682
|
+
referenceSequenceNumber: summaryRefSeqNum,
|
|
2683
|
+
}
|
|
2684
|
+
: {
|
|
2685
|
+
proposalHandle: lastAck.summaryOp.contents.handle,
|
|
2686
|
+
ackHandle: lastAck.summaryAck.contents.handle,
|
|
2687
|
+
referenceSequenceNumber: summaryRefSeqNum,
|
|
2688
|
+
};
|
|
2688
2689
|
|
|
2689
2690
|
let handle: string;
|
|
2690
2691
|
try {
|
|
@@ -3091,20 +3092,21 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
3091
3092
|
end: (arg0: {
|
|
3092
3093
|
getVersionDuration?: number | undefined;
|
|
3093
3094
|
getSnapshotDuration?: number | undefined;
|
|
3094
|
-
}) => void;
|
|
3095
|
-
|
|
3096
|
-
|
|
3095
|
+
}) => void;
|
|
3096
|
+
}) => {
|
|
3097
|
+
const stats: { getVersionDuration?: number; getSnapshotDuration?: number; } = {};
|
|
3098
|
+
const trace = Trace.start();
|
|
3097
3099
|
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3100
|
+
const versions = await this.storage.getVersions(versionId, 1);
|
|
3101
|
+
assert(!!versions && !!versions[0], 0x137 /* "Failed to get version from storage" */);
|
|
3102
|
+
stats.getVersionDuration = trace.trace().duration;
|
|
3101
3103
|
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3104
|
+
const maybeSnapshot = await this.storage.getSnapshotTree(versions[0]);
|
|
3105
|
+
assert(!!maybeSnapshot, 0x138 /* "Failed to get snapshot from storage" */);
|
|
3106
|
+
stats.getSnapshotDuration = trace.trace().duration;
|
|
3105
3107
|
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
+
perfEvent.end(stats);
|
|
3109
|
+
return maybeSnapshot;
|
|
3108
3110
|
});
|
|
3109
3111
|
}
|
|
3110
3112
|
|
|
@@ -3173,7 +3175,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
3173
3175
|
// because it is a misuse of the API rather than an expected failure.
|
|
3174
3176
|
throw new UsageError(
|
|
3175
3177
|
`Can't summarize, disableSummaries: ${this.summariesDisabled}`,
|
|
3176
|
-
|
|
3178
|
+
);
|
|
3177
3179
|
}
|
|
3178
3180
|
};
|
|
3179
3181
|
|
package/src/dataStore.ts
CHANGED
|
@@ -26,11 +26,11 @@ export interface IDataStoreAliasMessage {
|
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* Type guard that returns true if the given alias message is actually an instance of
|
|
29
|
-
* a class which implements @
|
|
29
|
+
* a class which implements {@link IDataStoreAliasMessage}
|
|
30
30
|
* @param maybeDataStoreAliasMessage - message object to be validated
|
|
31
|
-
* @returns True if the @
|
|
31
|
+
* @returns True if the {@link IDataStoreAliasMessage} is fully implemented, false otherwise
|
|
32
32
|
*/
|
|
33
|
-
|
|
33
|
+
export const isDataStoreAliasMessage = (
|
|
34
34
|
maybeDataStoreAliasMessage: any,
|
|
35
35
|
): maybeDataStoreAliasMessage is IDataStoreAliasMessage => {
|
|
36
36
|
return typeof maybeDataStoreAliasMessage?.internalId === "string"
|
|
@@ -153,7 +153,7 @@ class DataStore implements IDataStore {
|
|
|
153
153
|
|
|
154
154
|
private async ackBasedPromise<T>(
|
|
155
155
|
executor: (resolve: (value: T | PromiseLike<T>) => void,
|
|
156
|
-
|
|
156
|
+
reject: (reason?: any) => void) => void,
|
|
157
157
|
): Promise<T> {
|
|
158
158
|
let rejectBecauseDispose: () => void;
|
|
159
159
|
return new Promise<T>((resolve, reject) => {
|
package/src/dataStoreContext.ts
CHANGED
|
@@ -704,7 +704,7 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
|
|
|
704
704
|
|
|
705
705
|
public abstract generateAttachMessage(): IAttachMessage;
|
|
706
706
|
|
|
707
|
-
|
|
707
|
+
public abstract getInitialSnapshotDetails(): Promise<ISnapshotDetails>;
|
|
708
708
|
|
|
709
709
|
/**
|
|
710
710
|
* @deprecated - Sets the datastore as root, for aliasing purposes: #7948
|
|
@@ -858,7 +858,7 @@ export class RemoteFluidDataStoreContext extends FluidDataStoreContext {
|
|
|
858
858
|
};
|
|
859
859
|
});
|
|
860
860
|
|
|
861
|
-
|
|
861
|
+
public async getInitialSnapshotDetails(): Promise<ISnapshotDetails> {
|
|
862
862
|
return this.initialSnapshotDetailsP;
|
|
863
863
|
}
|
|
864
864
|
|
|
@@ -947,7 +947,7 @@ export class LocalFluidDataStoreContextBase extends FluidDataStoreContext {
|
|
|
947
947
|
return message;
|
|
948
948
|
}
|
|
949
949
|
|
|
950
|
-
|
|
950
|
+
public async getInitialSnapshotDetails(): Promise<ISnapshotDetails> {
|
|
951
951
|
let snapshot = this.snapshotTree;
|
|
952
952
|
let attributes: ReadFluidDataStoreAttributes;
|
|
953
953
|
let isRootDataStore = false;
|
|
@@ -1050,7 +1050,7 @@ export class LocalDetachedFluidDataStoreContext
|
|
|
1050
1050
|
}
|
|
1051
1051
|
}
|
|
1052
1052
|
|
|
1053
|
-
|
|
1053
|
+
public async getInitialSnapshotDetails(): Promise<ISnapshotDetails> {
|
|
1054
1054
|
if (this.detachedRuntimeCreation) {
|
|
1055
1055
|
throw new Error("Detached Fluid Data Store context can't be realized! Please attach runtime first!");
|
|
1056
1056
|
}
|
package/src/dataStores.ts
CHANGED
|
@@ -647,13 +647,13 @@ export class DataStores implements IDisposable {
|
|
|
647
647
|
}
|
|
648
648
|
|
|
649
649
|
/**
|
|
650
|
-
* Called
|
|
650
|
+
* Called by GC to retrieve the package path of a data store node with the given path.
|
|
651
651
|
*/
|
|
652
|
-
public getDataStorePackagePath(nodePath: string): readonly string[] | undefined {
|
|
653
|
-
// If the node belongs to a data store, return its package path
|
|
654
|
-
//
|
|
652
|
+
public async getDataStorePackagePath(nodePath: string): Promise<readonly string[] | undefined> {
|
|
653
|
+
// If the node belongs to a data store, return its package path. For DDSes, we return the package path of the
|
|
654
|
+
// data store that contains it.
|
|
655
655
|
const context = this.contexts.get(nodePath.split("/")[1]);
|
|
656
|
-
return context?.
|
|
656
|
+
return (await context?.getInitialSnapshotDetails())?.pkg;
|
|
657
657
|
}
|
|
658
658
|
|
|
659
659
|
/**
|