@fluidframework/container-runtime 2.0.0-internal.7.4.0 → 2.0.0-internal.8.0.1
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 +32 -0
- package/api-report/container-runtime.api.md +0 -17
- package/dist/container-runtime-alpha.d.ts +3 -32
- package/dist/container-runtime-beta.d.ts +0 -8
- package/dist/container-runtime-public.d.ts +0 -8
- package/dist/container-runtime-untrimmed.d.ts +3 -47
- package/dist/containerRuntime.d.ts +6 -36
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +6 -67
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStore.js +0 -12
- package/dist/dataStore.js.map +1 -1
- package/dist/gc/garbageCollection.d.ts +8 -12
- package/dist/gc/garbageCollection.d.ts.map +1 -1
- package/dist/gc/garbageCollection.js +71 -103
- package/dist/gc/garbageCollection.js.map +1 -1
- package/dist/gc/gcDefinitions.d.ts +0 -1
- package/dist/gc/gcDefinitions.d.ts.map +1 -1
- package/dist/gc/gcDefinitions.js.map +1 -1
- package/dist/gc/gcSummaryStateTracker.d.ts +1 -1
- package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -1
- package/dist/gc/gcSummaryStateTracker.js +3 -0
- package/dist/gc/gcSummaryStateTracker.js.map +1 -1
- package/dist/gc/gcTelemetry.d.ts.map +1 -1
- package/dist/gc/gcTelemetry.js +4 -14
- package/dist/gc/gcTelemetry.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.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/summary/summarizer.d.ts +0 -12
- package/dist/summary/summarizer.d.ts.map +1 -1
- package/dist/summary/summarizer.js +0 -46
- package/dist/summary/summarizer.js.map +1 -1
- package/lib/container-runtime-alpha.d.ts +3 -32
- package/lib/container-runtime-beta.d.ts +0 -8
- package/lib/container-runtime-public.d.ts +0 -8
- package/lib/container-runtime-untrimmed.d.ts +3 -47
- package/lib/containerRuntime.d.ts +6 -36
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +5 -65
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStore.js +0 -12
- package/lib/dataStore.js.map +1 -1
- package/lib/gc/garbageCollection.d.ts +8 -12
- package/lib/gc/garbageCollection.d.ts.map +1 -1
- package/lib/gc/garbageCollection.js +72 -104
- package/lib/gc/garbageCollection.js.map +1 -1
- package/lib/gc/gcDefinitions.d.ts +0 -1
- package/lib/gc/gcDefinitions.d.ts.map +1 -1
- package/lib/gc/gcDefinitions.js.map +1 -1
- package/lib/gc/gcSummaryStateTracker.d.ts +1 -1
- package/lib/gc/gcSummaryStateTracker.d.ts.map +1 -1
- package/lib/gc/gcSummaryStateTracker.js +3 -0
- package/lib/gc/gcSummaryStateTracker.js.map +1 -1
- package/lib/gc/gcTelemetry.d.ts.map +1 -1
- package/lib/gc/gcTelemetry.js +4 -14
- package/lib/gc/gcTelemetry.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.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/summary/summarizer.d.ts +0 -12
- package/lib/summary/summarizer.d.ts.map +1 -1
- package/lib/summary/summarizer.js +0 -46
- package/lib/summary/summarizer.js.map +1 -1
- package/package.json +20 -16
- package/src/containerRuntime.ts +7 -88
- package/src/dataStore.ts +1 -15
- package/src/gc/garbageCollection.ts +92 -119
- package/src/gc/gcDefinitions.ts +0 -1
- package/src/gc/gcSummaryStateTracker.ts +5 -1
- package/src/gc/gcTelemetry.ts +4 -13
- package/src/index.ts +0 -1
- package/src/packageVersion.ts +1 -1
- package/src/summary/summarizer.ts +1 -50
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/container-runtime",
|
|
3
|
-
"version": "2.0.0-internal.
|
|
3
|
+
"version": "2.0.0-internal.8.0.1",
|
|
4
4
|
"description": "Fluid container runtime",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -35,19 +35,19 @@
|
|
|
35
35
|
"temp-directory": "nyc/.nyc_output"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@fluid-internal/client-utils": ">=2.0.0-internal.
|
|
39
|
-
"@fluidframework/container-definitions": ">=2.0.0-internal.
|
|
40
|
-
"@fluidframework/container-runtime-definitions": ">=2.0.0-internal.
|
|
41
|
-
"@fluidframework/core-interfaces": ">=2.0.0-internal.
|
|
42
|
-
"@fluidframework/core-utils": ">=2.0.0-internal.
|
|
43
|
-
"@fluidframework/datastore": ">=2.0.0-internal.
|
|
44
|
-
"@fluidframework/driver-definitions": ">=2.0.0-internal.
|
|
45
|
-
"@fluidframework/driver-utils": ">=2.0.0-internal.
|
|
46
|
-
"@fluidframework/id-compressor": ">=2.0.0-internal.
|
|
38
|
+
"@fluid-internal/client-utils": ">=2.0.0-internal.8.0.1 <2.0.0-internal.8.1.0",
|
|
39
|
+
"@fluidframework/container-definitions": ">=2.0.0-internal.8.0.1 <2.0.0-internal.8.1.0",
|
|
40
|
+
"@fluidframework/container-runtime-definitions": ">=2.0.0-internal.8.0.1 <2.0.0-internal.8.1.0",
|
|
41
|
+
"@fluidframework/core-interfaces": ">=2.0.0-internal.8.0.1 <2.0.0-internal.8.1.0",
|
|
42
|
+
"@fluidframework/core-utils": ">=2.0.0-internal.8.0.1 <2.0.0-internal.8.1.0",
|
|
43
|
+
"@fluidframework/datastore": ">=2.0.0-internal.8.0.1 <2.0.0-internal.8.1.0",
|
|
44
|
+
"@fluidframework/driver-definitions": ">=2.0.0-internal.8.0.1 <2.0.0-internal.8.1.0",
|
|
45
|
+
"@fluidframework/driver-utils": ">=2.0.0-internal.8.0.1 <2.0.0-internal.8.1.0",
|
|
46
|
+
"@fluidframework/id-compressor": ">=2.0.0-internal.8.0.1 <2.0.0-internal.8.1.0",
|
|
47
47
|
"@fluidframework/protocol-definitions": "^3.0.0",
|
|
48
|
-
"@fluidframework/runtime-definitions": ">=2.0.0-internal.
|
|
49
|
-
"@fluidframework/runtime-utils": ">=2.0.0-internal.
|
|
50
|
-
"@fluidframework/telemetry-utils": ">=2.0.0-internal.
|
|
48
|
+
"@fluidframework/runtime-definitions": ">=2.0.0-internal.8.0.1 <2.0.0-internal.8.1.0",
|
|
49
|
+
"@fluidframework/runtime-utils": ">=2.0.0-internal.8.0.1 <2.0.0-internal.8.1.0",
|
|
50
|
+
"@fluidframework/telemetry-utils": ">=2.0.0-internal.8.0.1 <2.0.0-internal.8.1.0",
|
|
51
51
|
"double-ended-queue": "^2.1.0-0",
|
|
52
52
|
"events": "^3.1.0",
|
|
53
53
|
"lz4js": "^0.2.0",
|
|
@@ -56,15 +56,15 @@
|
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@arethetypeswrong/cli": "^0.13.3",
|
|
59
|
-
"@fluid-private/stochastic-test-utils": ">=2.0.0-internal.
|
|
59
|
+
"@fluid-private/stochastic-test-utils": ">=2.0.0-internal.8.0.1 <2.0.0-internal.8.1.0",
|
|
60
60
|
"@fluid-tools/benchmark": "^0.48.0",
|
|
61
61
|
"@fluid-tools/build-cli": "^0.28.0",
|
|
62
62
|
"@fluidframework/build-common": "^2.0.3",
|
|
63
63
|
"@fluidframework/build-tools": "^0.28.0",
|
|
64
64
|
"@fluidframework/container-runtime-previous": "npm:@fluidframework/container-runtime@2.0.0-internal.7.2.0",
|
|
65
65
|
"@fluidframework/eslint-config-fluid": "^3.1.0",
|
|
66
|
-
"@fluidframework/mocha-test-setup": ">=2.0.0-internal.
|
|
67
|
-
"@fluidframework/test-runtime-utils": ">=2.0.0-internal.
|
|
66
|
+
"@fluidframework/mocha-test-setup": ">=2.0.0-internal.8.0.1 <2.0.0-internal.8.1.0",
|
|
67
|
+
"@fluidframework/test-runtime-utils": ">=2.0.0-internal.8.0.1 <2.0.0-internal.8.1.0",
|
|
68
68
|
"@microsoft/api-extractor": "^7.38.3",
|
|
69
69
|
"@types/double-ended-queue": "^2.1.0",
|
|
70
70
|
"@types/events": "^3.0.0",
|
|
@@ -101,6 +101,10 @@
|
|
|
101
101
|
"ClassDeclaration_ContainerRuntime": {
|
|
102
102
|
"backCompat": false
|
|
103
103
|
},
|
|
104
|
+
"RemovedFunctionDeclaration_TEST_requestSummarizer": {
|
|
105
|
+
"forwardCompat": false,
|
|
106
|
+
"backCompat": false
|
|
107
|
+
},
|
|
104
108
|
"InterfaceDeclaration_IGCStats": {
|
|
105
109
|
"forwardCompat": false
|
|
106
110
|
}
|
package/src/containerRuntime.ts
CHANGED
|
@@ -8,8 +8,6 @@ import {
|
|
|
8
8
|
FluidObject,
|
|
9
9
|
IFluidHandle,
|
|
10
10
|
IFluidHandleContext,
|
|
11
|
-
// eslint-disable-next-line import/no-deprecated
|
|
12
|
-
IFluidRouter,
|
|
13
11
|
IRequest,
|
|
14
12
|
IResponse,
|
|
15
13
|
IProvideFluidHandleContext,
|
|
@@ -698,7 +696,9 @@ async function createSummarizer(loader: ILoader, url: string): Promise<ISummariz
|
|
|
698
696
|
if (resolvedContainer.getEntryPoint !== undefined) {
|
|
699
697
|
fluidObject = await resolvedContainer.getEntryPoint();
|
|
700
698
|
} else {
|
|
701
|
-
const response = await resolvedContainer.request({
|
|
699
|
+
const response = await (resolvedContainer as any).request({
|
|
700
|
+
url: `/${summarizerRequestUrl}`,
|
|
701
|
+
});
|
|
702
702
|
if (response.status !== 200 || response.mimeType !== "fluid/object") {
|
|
703
703
|
throw responseToException(response, request);
|
|
704
704
|
}
|
|
@@ -711,14 +711,6 @@ async function createSummarizer(loader: ILoader, url: string): Promise<ISummariz
|
|
|
711
711
|
return fluidObject.ISummarizer;
|
|
712
712
|
}
|
|
713
713
|
|
|
714
|
-
/**
|
|
715
|
-
* This function is not supported publicly and exists for e2e testing
|
|
716
|
-
* @internal
|
|
717
|
-
*/
|
|
718
|
-
export async function TEST_requestSummarizer(loader: ILoader, url: string): Promise<ISummarizer> {
|
|
719
|
-
return createSummarizer(loader, url);
|
|
720
|
-
}
|
|
721
|
-
|
|
722
714
|
/**
|
|
723
715
|
* Represents the runtime of the container. Contains helper functions/state of the container.
|
|
724
716
|
* It will define the store level mappings.
|
|
@@ -733,53 +725,6 @@ export class ContainerRuntime
|
|
|
733
725
|
ISummarizerInternalsProvider,
|
|
734
726
|
IProvideFluidHandleContext
|
|
735
727
|
{
|
|
736
|
-
/**
|
|
737
|
-
* @deprecated Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
|
|
738
|
-
*/
|
|
739
|
-
public get IFluidRouter() {
|
|
740
|
-
return this;
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
/**
|
|
744
|
-
* @deprecated use loadRuntime instead.
|
|
745
|
-
* Load the stores from a snapshot and returns the runtime.
|
|
746
|
-
* @param context - Context of the container.
|
|
747
|
-
* @param registryEntries - Mapping to the stores.
|
|
748
|
-
* @param requestHandler - Request handlers for the container runtime
|
|
749
|
-
* @param runtimeOptions - Additional options to be passed to the runtime
|
|
750
|
-
* @param existing - (optional) When loading from an existing snapshot. Precedes context.existing if provided
|
|
751
|
-
* @param containerRuntimeCtor - (optional) Constructor to use to create the ContainerRuntime instance. This
|
|
752
|
-
* allows mixin classes to leverage this method to define their own async initializer.
|
|
753
|
-
*/
|
|
754
|
-
public static async load(
|
|
755
|
-
context: IContainerContext,
|
|
756
|
-
registryEntries: NamedFluidDataStoreRegistryEntries,
|
|
757
|
-
requestHandler?: (request: IRequest, runtime: IContainerRuntime) => Promise<IResponse>,
|
|
758
|
-
runtimeOptions: IContainerRuntimeOptions = {},
|
|
759
|
-
containerScope: FluidObject = context.scope,
|
|
760
|
-
existing?: boolean,
|
|
761
|
-
containerRuntimeCtor: typeof ContainerRuntime = ContainerRuntime,
|
|
762
|
-
): Promise<ContainerRuntime> {
|
|
763
|
-
let existingFlag = true;
|
|
764
|
-
if (!existing) {
|
|
765
|
-
existingFlag = false;
|
|
766
|
-
}
|
|
767
|
-
return this.loadRuntime({
|
|
768
|
-
context,
|
|
769
|
-
registryEntries,
|
|
770
|
-
existing: existingFlag,
|
|
771
|
-
runtimeOptions,
|
|
772
|
-
containerScope,
|
|
773
|
-
containerRuntimeCtor,
|
|
774
|
-
requestHandler,
|
|
775
|
-
provideEntryPoint: () => {
|
|
776
|
-
throw new UsageError(
|
|
777
|
-
"ContainerRuntime.load is deprecated and should no longer be used",
|
|
778
|
-
);
|
|
779
|
-
},
|
|
780
|
-
});
|
|
781
|
-
}
|
|
782
|
-
|
|
783
728
|
/**
|
|
784
729
|
* Load the stores from a snapshot and returns the runtime.
|
|
785
730
|
* @param params - An object housing the runtime properties:
|
|
@@ -802,7 +747,7 @@ export class ContainerRuntime
|
|
|
802
747
|
runtimeOptions?: IContainerRuntimeOptions;
|
|
803
748
|
containerScope?: FluidObject;
|
|
804
749
|
containerRuntimeCtor?: typeof ContainerRuntime;
|
|
805
|
-
/** @deprecated Will be removed
|
|
750
|
+
/** @deprecated Will be removed once Loader LTS version is "2.0.0-internal.7.0.0". Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md */
|
|
806
751
|
requestHandler?: (request: IRequest, runtime: IContainerRuntime) => Promise<IResponse>;
|
|
807
752
|
provideEntryPoint: (containerRuntime: IContainerRuntime) => Promise<FluidObject>;
|
|
808
753
|
}): Promise<ContainerRuntime> {
|
|
@@ -1449,9 +1394,6 @@ export class ContainerRuntime
|
|
|
1449
1394
|
getNodePackagePath: async (nodePath: string) => this.getGCNodePackagePath(nodePath),
|
|
1450
1395
|
getLastSummaryTimestampMs: () => this.messageAtLastSummary?.timestamp,
|
|
1451
1396
|
readAndParseBlob: async <T>(id: string) => readAndParse<T>(this.storage, id),
|
|
1452
|
-
// GC runs in summarizer client and needs access to the real (non-proxy) active information. The proxy
|
|
1453
|
-
// delta manager would always return false for summarizer client.
|
|
1454
|
-
activeConnection: () => this.innerDeltaManager.active,
|
|
1455
1397
|
submitMessage: (message: ContainerRuntimeGCMessage) => this.submit(message),
|
|
1456
1398
|
});
|
|
1457
1399
|
|
|
@@ -1783,9 +1725,10 @@ export class ContainerRuntime
|
|
|
1783
1725
|
/**
|
|
1784
1726
|
* Notifies this object about the request made to the container.
|
|
1785
1727
|
* @param request - Request made to the handler.
|
|
1786
|
-
* @deprecated Will be removed in future major release.
|
|
1728
|
+
* @deprecated Will be removed in future major release. This method needs to stay private until LTS version of Loader moves to "2.0.0-internal.7.0.0".
|
|
1787
1729
|
*/
|
|
1788
|
-
|
|
1730
|
+
// @ts-expect-error expected to be used by LTS Loaders and Containers
|
|
1731
|
+
private async request(request: IRequest): Promise<IResponse> {
|
|
1789
1732
|
try {
|
|
1790
1733
|
const parser = RequestParser.create(request);
|
|
1791
1734
|
const id = parser.pathParts[0];
|
|
@@ -2450,28 +2393,6 @@ export class ContainerRuntime
|
|
|
2450
2393
|
this.dataStores.processSignal(envelope.address, transformed, local);
|
|
2451
2394
|
}
|
|
2452
2395
|
|
|
2453
|
-
/**
|
|
2454
|
-
* Returns the runtime of the data store.
|
|
2455
|
-
* @param id - Id supplied during creating the data store.
|
|
2456
|
-
* @param wait - True if you want to wait for it.
|
|
2457
|
-
* @deprecated Use getAliasedDataStoreEntryPoint instead to get an aliased data store's entry point.
|
|
2458
|
-
*/
|
|
2459
|
-
// eslint-disable-next-line import/no-deprecated
|
|
2460
|
-
public async getRootDataStore(id: string, wait = true): Promise<IFluidRouter> {
|
|
2461
|
-
return this.getRootDataStoreChannel(id, wait);
|
|
2462
|
-
}
|
|
2463
|
-
|
|
2464
|
-
private async getRootDataStoreChannel(
|
|
2465
|
-
id: string,
|
|
2466
|
-
wait = true,
|
|
2467
|
-
): Promise<IFluidDataStoreChannel> {
|
|
2468
|
-
await this.dataStores.waitIfPendingAlias(id);
|
|
2469
|
-
const internalId = this.internalId(id);
|
|
2470
|
-
const context = await this.dataStores.getDataStore(internalId, { wait });
|
|
2471
|
-
assert(await context.isRoot(), 0x12b /* "did not get root data store" */);
|
|
2472
|
-
return context.realize();
|
|
2473
|
-
}
|
|
2474
|
-
|
|
2475
2396
|
/**
|
|
2476
2397
|
* Flush the pending ops manually.
|
|
2477
2398
|
* This method is expected to be called at the end of a batch.
|
|
@@ -3978,8 +3899,6 @@ export class ContainerRuntime
|
|
|
3978
3899
|
);
|
|
3979
3900
|
}
|
|
3980
3901
|
|
|
3981
|
-
public notifyAttaching() {} // do nothing (deprecated method)
|
|
3982
|
-
|
|
3983
3902
|
public async getPendingLocalState(props?: IGetPendingLocalStateProps): Promise<unknown> {
|
|
3984
3903
|
return PerformanceEvent.timedExecAsync(
|
|
3985
3904
|
this.mc.logger,
|
package/src/dataStore.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import { ITelemetryLoggerExt, TelemetryDataTag, UsageError } from "@fluidframework/telemetry-utils";
|
|
7
7
|
import { assert, unreachableCase } from "@fluidframework/core-utils";
|
|
8
8
|
import { AttachState } from "@fluidframework/container-definitions";
|
|
9
|
-
import { FluidObject, IFluidHandle
|
|
9
|
+
import { FluidObject, IFluidHandle } from "@fluidframework/core-interfaces";
|
|
10
10
|
import {
|
|
11
11
|
AliasResult,
|
|
12
12
|
IDataStore,
|
|
@@ -160,13 +160,6 @@ class DataStore implements IDataStore {
|
|
|
160
160
|
return "Success";
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
-
/**
|
|
164
|
-
* @deprecated Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
|
|
165
|
-
*/
|
|
166
|
-
public async request(request: IRequest): Promise<IResponse> {
|
|
167
|
-
return this.fluidDataStoreChannel.request(request);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
163
|
/**
|
|
171
164
|
* {@inheritDoc @fluidframework/runtime-definitions#IDataStore.entryPoint}
|
|
172
165
|
*/
|
|
@@ -184,13 +177,6 @@ class DataStore implements IDataStore {
|
|
|
184
177
|
this.pendingAliases = datastores.pendingAliases;
|
|
185
178
|
}
|
|
186
179
|
|
|
187
|
-
/**
|
|
188
|
-
* @deprecated Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
|
|
189
|
-
*/
|
|
190
|
-
public get IFluidRouter() {
|
|
191
|
-
return this.fluidDataStoreChannel;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
180
|
private async ackBasedPromise<T>(
|
|
195
181
|
executor: (
|
|
196
182
|
resolve: (value: T | PromiseLike<T>) => void,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { LazyPromise, Timer } from "@fluidframework/core-utils";
|
|
6
|
+
import { assert, LazyPromise, Timer } from "@fluidframework/core-utils";
|
|
7
7
|
import { IRequest } from "@fluidframework/core-interfaces";
|
|
8
8
|
import {
|
|
9
9
|
gcTreeKey,
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
MonitoringContext,
|
|
22
22
|
PerformanceEvent,
|
|
23
23
|
} from "@fluidframework/telemetry-utils";
|
|
24
|
+
import { BlobManager } from "../blobManager";
|
|
24
25
|
import {
|
|
25
26
|
InactiveResponseHeaderKey,
|
|
26
27
|
RuntimeHeaderData,
|
|
@@ -141,8 +142,6 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
141
142
|
) => Promise<readonly string[] | undefined>;
|
|
142
143
|
/** Returns the timestamp of the last summary generated for this container. */
|
|
143
144
|
private readonly getLastSummaryTimestampMs: () => number | undefined;
|
|
144
|
-
/** Returns true if connection is active, i.e. it's "write" connection and the runtime is connected. */
|
|
145
|
-
private readonly activeConnection: () => boolean;
|
|
146
145
|
|
|
147
146
|
private readonly submitMessage: (message: ContainerRuntimeGCMessage) => void;
|
|
148
147
|
|
|
@@ -160,7 +159,6 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
160
159
|
this.isSummarizerClient = createParams.isSummarizerClient;
|
|
161
160
|
this.getNodePackagePath = createParams.getNodePackagePath;
|
|
162
161
|
this.getLastSummaryTimestampMs = createParams.getLastSummaryTimestampMs;
|
|
163
|
-
this.activeConnection = createParams.activeConnection;
|
|
164
162
|
this.submitMessage = createParams.submitMessage;
|
|
165
163
|
|
|
166
164
|
const baseSnapshot = createParams.baseSnapshot;
|
|
@@ -255,28 +253,18 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
255
253
|
);
|
|
256
254
|
|
|
257
255
|
/**
|
|
258
|
-
* Set up the initializer which initializes the GC state from the data in base snapshot.
|
|
259
|
-
*
|
|
260
|
-
*
|
|
256
|
+
* Set up the initializer which initializes the GC state from the data in base snapshot. It sets up GC data
|
|
257
|
+
* from the base GC state and starts tracking the state of unreferenced nodes.
|
|
258
|
+
*
|
|
259
|
+
* Must only be called if there is a current reference timestamp.
|
|
261
260
|
*/
|
|
262
261
|
this.initializeGCStateFromBaseSnapshotP = new LazyPromise<void>(async () => {
|
|
263
|
-
/**
|
|
264
|
-
* If there is no current reference timestamp, skip initialization. We need the current timestamp to track
|
|
265
|
-
* how long objects have been unreferenced and if they can be deleted.
|
|
266
|
-
*
|
|
267
|
-
* Note that the only scenario where there is no reference timestamp is when no ops have ever been processed
|
|
268
|
-
* for this container and it is in read mode. In this scenario, there is no point in running GC anyway
|
|
269
|
-
* because references in the container do not change without any ops, i.e., there is nothing to collect.
|
|
270
|
-
*/
|
|
271
262
|
const currentReferenceTimestampMs = this.runtime.getCurrentReferenceTimestampMs();
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
});
|
|
278
|
-
return;
|
|
279
|
-
}
|
|
263
|
+
assert(
|
|
264
|
+
currentReferenceTimestampMs !== undefined,
|
|
265
|
+
"Trying to initialize GC state without current timestamp",
|
|
266
|
+
);
|
|
267
|
+
|
|
280
268
|
/**
|
|
281
269
|
* The base snapshot data will not be present if the container is loaded from:
|
|
282
270
|
* 1. The first summary created by the detached container.
|
|
@@ -284,11 +272,31 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
284
272
|
* 3. A summary that was generated before GC even existed.
|
|
285
273
|
*/
|
|
286
274
|
const baseSnapshotData = await this.baseSnapshotDataP;
|
|
287
|
-
|
|
275
|
+
this.summaryStateTracker.initializeBaseState(baseSnapshotData);
|
|
276
|
+
|
|
277
|
+
if (baseSnapshotData?.gcState === undefined) {
|
|
288
278
|
return;
|
|
289
279
|
}
|
|
290
|
-
|
|
291
|
-
|
|
280
|
+
|
|
281
|
+
// Update unreferenced state tracking as per the GC state in the snapshot data and update gcDataFromLastRun
|
|
282
|
+
// to the GC data from the snapshot data.
|
|
283
|
+
const gcNodes: { [id: string]: string[] } = {};
|
|
284
|
+
for (const [nodeId, nodeData] of Object.entries(baseSnapshotData.gcState.gcNodes)) {
|
|
285
|
+
if (nodeData.unreferencedTimestampMs !== undefined) {
|
|
286
|
+
this.unreferencedNodesState.set(
|
|
287
|
+
nodeId,
|
|
288
|
+
new UnreferencedStateTracker(
|
|
289
|
+
nodeData.unreferencedTimestampMs,
|
|
290
|
+
this.configs.inactiveTimeoutMs,
|
|
291
|
+
currentReferenceTimestampMs,
|
|
292
|
+
this.configs.sweepTimeoutMs,
|
|
293
|
+
this.configs.sweepGracePeriodMs,
|
|
294
|
+
),
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
gcNodes[nodeId] = Array.from(nodeData.outboundRoutes);
|
|
298
|
+
}
|
|
299
|
+
this.gcDataFromLastRun = { gcNodes };
|
|
292
300
|
});
|
|
293
301
|
|
|
294
302
|
// Get the GC details from the GC state in the base summary. This is returned in getBaseGCDetails which is
|
|
@@ -322,8 +330,10 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
322
330
|
}
|
|
323
331
|
|
|
324
332
|
/**
|
|
325
|
-
* Called during container initialization.
|
|
326
|
-
*
|
|
333
|
+
* Called during container initialization. Initializes the tombstone and deleted nodes state from the base snapshot.
|
|
334
|
+
* Also, initializes the GC state including unreferenced nodes tracking if a current reference timestamp exists.
|
|
335
|
+
* Note that if there is any GC state in the base snapshot, then there will definitely be a reference timestamp
|
|
336
|
+
* to work with - The GC state would have been generated using a timestamp which is part of the snapshot.
|
|
327
337
|
*/
|
|
328
338
|
public async initializeBaseState(): Promise<void> {
|
|
329
339
|
const baseSnapshotData = await this.baseSnapshotDataP;
|
|
@@ -350,115 +360,59 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
350
360
|
this.tombstones = Array.from(baseSnapshotData.tombstones);
|
|
351
361
|
this.runtime.updateTombstonedRoutes(this.tombstones);
|
|
352
362
|
}
|
|
363
|
+
|
|
364
|
+
await this.initializeOrUpdateGCState();
|
|
353
365
|
}
|
|
354
366
|
|
|
355
367
|
/**
|
|
356
|
-
*
|
|
357
|
-
*
|
|
358
|
-
* @param snapshotData - The snapshot data to update state from. If this is undefined, all GC state and tracking
|
|
359
|
-
* is reset.
|
|
360
|
-
* @param currentReferenceTimestampMs - The current reference timestamp for marking unreferenced nodes' unreferenced
|
|
361
|
-
* timestamp.
|
|
368
|
+
* Initialize the GC state if not already initialized. If GC state is already initialized, update the unreferenced
|
|
369
|
+
* state tracking as per the current reference timestamp.
|
|
362
370
|
*/
|
|
363
|
-
private
|
|
364
|
-
|
|
365
|
-
currentReferenceTimestampMs
|
|
366
|
-
|
|
367
|
-
/**
|
|
368
|
-
* Note: "newReferencesSinceLastRun" is not reset here. This is done because there may be references since the
|
|
369
|
-
* snapshot that we are updating state from. For example, this client may have processed ops till seq#1000 and
|
|
370
|
-
* its refreshing state from a summary that happened at seq#900. In this case, there may be references between
|
|
371
|
-
* seq#901 and seq#1000 that we don't want to reset.
|
|
372
|
-
* Unfortunately, there is no way to track the seq# of ops that add references, so we choose to not reset any
|
|
373
|
-
* references here. This should be fine because, in the worst case, we may end up updating the unreferenced
|
|
374
|
-
* timestamp of a node which will delay its deletion. Although not ideal, this will only happen in rare
|
|
375
|
-
* scenarios, so it should be okay.
|
|
376
|
-
*/
|
|
377
|
-
|
|
378
|
-
// Clear all existing unreferenced state tracking.
|
|
379
|
-
for (const [, nodeStateTracker] of this.unreferencedNodesState) {
|
|
380
|
-
nodeStateTracker.stopTracking();
|
|
381
|
-
}
|
|
382
|
-
this.unreferencedNodesState.clear();
|
|
383
|
-
|
|
384
|
-
// If running sweep, the tombstone state represents the list of nodes that have been deleted during sweep.
|
|
385
|
-
// If running in tombstone mode, the tombstone state represents the list of nodes that have been marked as
|
|
386
|
-
// tombstones.
|
|
387
|
-
// If this call is because we are refreshing from a snapshot due to an ack, it is likely that the GC state
|
|
388
|
-
// in the snapshot is newer than this client's. And so, the deleted / tombstone nodes need to be updated.
|
|
389
|
-
if (this.configs.shouldRunSweep) {
|
|
390
|
-
const snapshotDeletedNodes = snapshotData?.deletedNodes
|
|
391
|
-
? new Set(snapshotData.deletedNodes)
|
|
392
|
-
: undefined;
|
|
393
|
-
// If the snapshot contains deleted nodes that are not yet deleted by this client, ask the runtime to
|
|
394
|
-
// delete them.
|
|
395
|
-
if (snapshotDeletedNodes !== undefined) {
|
|
396
|
-
const newDeletedNodes: string[] = [];
|
|
397
|
-
for (const nodeId of snapshotDeletedNodes) {
|
|
398
|
-
if (!this.deletedNodes.has(nodeId)) {
|
|
399
|
-
newDeletedNodes.push(nodeId);
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
if (newDeletedNodes.length > 0) {
|
|
403
|
-
// Call container runtime to delete these nodes and add deleted nodes to this.deletedNodes.
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
} else if (this.configs.tombstoneMode) {
|
|
407
|
-
// The snapshot may contain more or fewer tombstone nodes than this client. Update tombstone state and
|
|
408
|
-
// notify the runtime to update its state as well.
|
|
409
|
-
this.tombstones = snapshotData?.tombstones ? Array.from(snapshotData.tombstones) : [];
|
|
410
|
-
this.runtime.updateTombstonedRoutes(this.tombstones);
|
|
371
|
+
private async initializeOrUpdateGCState() {
|
|
372
|
+
const currentReferenceTimestampMs = this.runtime.getCurrentReferenceTimestampMs();
|
|
373
|
+
if (currentReferenceTimestampMs === undefined) {
|
|
374
|
+
return;
|
|
411
375
|
}
|
|
412
376
|
|
|
413
|
-
// If
|
|
414
|
-
if (
|
|
415
|
-
this.
|
|
377
|
+
// If the GC state hasn't been initialized yet, initialize it and return.
|
|
378
|
+
if (this.gcDataFromLastRun === undefined) {
|
|
379
|
+
await this.initializeGCStateFromBaseSnapshotP;
|
|
416
380
|
return;
|
|
417
381
|
}
|
|
418
382
|
|
|
419
|
-
//
|
|
420
|
-
//
|
|
421
|
-
const
|
|
422
|
-
|
|
423
|
-
if (nodeData.unreferencedTimestampMs !== undefined) {
|
|
424
|
-
this.unreferencedNodesState.set(
|
|
425
|
-
nodeId,
|
|
426
|
-
new UnreferencedStateTracker(
|
|
427
|
-
nodeData.unreferencedTimestampMs,
|
|
428
|
-
this.configs.inactiveTimeoutMs,
|
|
429
|
-
currentReferenceTimestampMs,
|
|
430
|
-
this.configs.sweepTimeoutMs,
|
|
431
|
-
this.configs.sweepGracePeriodMs,
|
|
432
|
-
),
|
|
433
|
-
);
|
|
434
|
-
}
|
|
435
|
-
gcNodes[nodeId] = Array.from(nodeData.outboundRoutes);
|
|
383
|
+
// If the GC state has been initialized, update the tracking of unreferenced nodes as per the current
|
|
384
|
+
// reference timestamp.
|
|
385
|
+
for (const [, nodeStateTracker] of this.unreferencedNodesState) {
|
|
386
|
+
nodeStateTracker.updateTracking(currentReferenceTimestampMs);
|
|
436
387
|
}
|
|
437
|
-
this.gcDataFromLastRun = { gcNodes };
|
|
438
388
|
}
|
|
439
389
|
|
|
440
390
|
/**
|
|
441
391
|
* Called when the connection state of the runtime changes, i.e., it connects or disconnects. GC subscribes to this
|
|
442
|
-
* to initialize the
|
|
392
|
+
* to initialize or update the unreference state tracking.
|
|
443
393
|
* @param connected - Whether the runtime connected / disconnected.
|
|
444
394
|
* @param clientId - The clientId of this runtime.
|
|
445
395
|
*/
|
|
446
396
|
public setConnectionState(connected: boolean, clientId?: string | undefined): void {
|
|
447
397
|
/**
|
|
448
|
-
*
|
|
449
|
-
*
|
|
450
|
-
* reference timestamp that will be used to update the state of unreferenced nodes. Also, all trailing ops which
|
|
451
|
-
* could affect the GC state will have been processed.
|
|
452
|
-
*
|
|
453
|
-
* If GC is up-to-date for the client and the summarizing client, there will be an doubling of both
|
|
454
|
-
* InactiveObject_Loaded and SweepReady_Loaded errors, as there will be one from the sending client and one from
|
|
455
|
-
* the receiving summarizer client.
|
|
398
|
+
* When the client connects (or reconnects), attempt to initialize or update the GC state. This will keep
|
|
399
|
+
* the unreferenced state tracking updated as per the reference timestamp at the time of connection.
|
|
456
400
|
*
|
|
457
|
-
*
|
|
458
|
-
*
|
|
401
|
+
* During GC initialization and during connections in read mode, it is possible that either no ops are
|
|
402
|
+
* processed or only trailing ops are processed. This means that the GC state is not initialized or initialized
|
|
403
|
+
* with an older reference timestamp. So, doing this on every connection will keep the unreferenced state
|
|
404
|
+
* tracking up-to-date.
|
|
459
405
|
*/
|
|
460
|
-
if (
|
|
461
|
-
this.
|
|
406
|
+
if (connected && this.configs.shouldRunGC) {
|
|
407
|
+
this.initializeOrUpdateGCState().catch((error) => {
|
|
408
|
+
this.mc.logger.sendErrorEvent(
|
|
409
|
+
{
|
|
410
|
+
eventName: "GCInitializationOrUpdateFailed",
|
|
411
|
+
gcConfigs: JSON.stringify(this.configs),
|
|
412
|
+
},
|
|
413
|
+
error,
|
|
414
|
+
);
|
|
415
|
+
});
|
|
462
416
|
}
|
|
463
417
|
}
|
|
464
418
|
|
|
@@ -536,8 +490,11 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
536
490
|
const gcStats = await this.runGC(fullGC, currentReferenceTimestampMs, logger);
|
|
537
491
|
event.end({
|
|
538
492
|
...gcStats,
|
|
539
|
-
|
|
540
|
-
|
|
493
|
+
details: {
|
|
494
|
+
timestamp: currentReferenceTimestampMs,
|
|
495
|
+
sweep: this.configs.shouldRunSweep,
|
|
496
|
+
tombstone: this.configs.throwOnTombstoneLoad,
|
|
497
|
+
},
|
|
541
498
|
});
|
|
542
499
|
|
|
543
500
|
/** Post-GC steps */
|
|
@@ -1163,9 +1120,25 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
1163
1120
|
deletedAttachmentBlobCount: 0,
|
|
1164
1121
|
};
|
|
1165
1122
|
|
|
1123
|
+
// The runtime can't reliably identify the type of deleted nodes. So, get the type here. This should
|
|
1124
|
+
// be good enough because the only types that participate in GC today are data stores, DDSes and blobs.
|
|
1125
|
+
const getDeletedNodeType = (nodeId: string): GCNodeType => {
|
|
1126
|
+
const pathParts = nodeId.split("/");
|
|
1127
|
+
if (pathParts[1] === BlobManager.basePath) {
|
|
1128
|
+
return GCNodeType.Blob;
|
|
1129
|
+
}
|
|
1130
|
+
if (pathParts.length === 2) {
|
|
1131
|
+
return GCNodeType.DataStore;
|
|
1132
|
+
}
|
|
1133
|
+
if (pathParts.length === 3) {
|
|
1134
|
+
return GCNodeType.SubDataStore;
|
|
1135
|
+
}
|
|
1136
|
+
return GCNodeType.Other;
|
|
1137
|
+
};
|
|
1138
|
+
|
|
1166
1139
|
for (const nodeId of deletedNodes) {
|
|
1167
1140
|
sweepPhaseStats.deletedNodeCount++;
|
|
1168
|
-
const nodeType =
|
|
1141
|
+
const nodeType = getDeletedNodeType(nodeId);
|
|
1169
1142
|
if (nodeType === GCNodeType.DataStore) {
|
|
1170
1143
|
sweepPhaseStats.deletedDataStoreCount++;
|
|
1171
1144
|
} else if (nodeType === GCNodeType.Blob) {
|
package/src/gc/gcDefinitions.ts
CHANGED
|
@@ -353,7 +353,6 @@ export interface IGarbageCollectorCreateParams {
|
|
|
353
353
|
readonly getNodePackagePath: (nodePath: string) => Promise<readonly string[] | undefined>;
|
|
354
354
|
readonly getLastSummaryTimestampMs: () => number | undefined;
|
|
355
355
|
readonly readAndParseBlob: ReadAndParseBlob;
|
|
356
|
-
readonly activeConnection: () => boolean;
|
|
357
356
|
readonly submitMessage: (message: ContainerRuntimeGCMessage) => void;
|
|
358
357
|
}
|
|
359
358
|
|
|
@@ -111,7 +111,11 @@ export class GCSummaryStateTracker {
|
|
|
111
111
|
/**
|
|
112
112
|
* Called during GC initialization. Initialize the latest summary data from the base snapshot data.
|
|
113
113
|
*/
|
|
114
|
-
public initializeBaseState(baseSnapshotData: IGarbageCollectionSnapshotData) {
|
|
114
|
+
public initializeBaseState(baseSnapshotData: IGarbageCollectionSnapshotData | undefined) {
|
|
115
|
+
if (baseSnapshotData === undefined) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
115
119
|
// If tracking state across summaries, update latest summary data from the snapshot's GC data.
|
|
116
120
|
this.latestSummaryData = {
|
|
117
121
|
serializedGCState: baseSnapshotData.gcState
|
package/src/gc/gcTelemetry.ts
CHANGED
|
@@ -240,13 +240,9 @@ export class GCTelemetryTracker {
|
|
|
240
240
|
gcConfigs,
|
|
241
241
|
};
|
|
242
242
|
|
|
243
|
-
//
|
|
244
|
-
//
|
|
245
|
-
|
|
246
|
-
this.mc.logger.sendTelemetryEvent(event);
|
|
247
|
-
} else {
|
|
248
|
-
this.mc.logger.sendErrorEvent(event);
|
|
249
|
-
}
|
|
243
|
+
// These are logged as generic events and not errors because there can be false positives. The Tombstone
|
|
244
|
+
// and Delete errors are separately logged and are reliable.
|
|
245
|
+
this.mc.logger.sendTelemetryEvent(event);
|
|
250
246
|
}
|
|
251
247
|
}
|
|
252
248
|
}
|
|
@@ -393,12 +389,7 @@ export class GCTelemetryTracker {
|
|
|
393
389
|
fromPkg: fromPkg?.join("/"),
|
|
394
390
|
}),
|
|
395
391
|
};
|
|
396
|
-
|
|
397
|
-
if (state === UnreferencedState.Inactive) {
|
|
398
|
-
logger.sendTelemetryEvent(event);
|
|
399
|
-
} else {
|
|
400
|
-
logger.sendErrorEvent(event);
|
|
401
|
-
}
|
|
392
|
+
logger.sendTelemetryEvent(event);
|
|
402
393
|
}
|
|
403
394
|
}
|
|
404
395
|
this.pendingEventsQueue = [];
|
package/src/index.ts
CHANGED
package/src/packageVersion.ts
CHANGED