@fluidframework/container-runtime 1.3.0 → 2.0.0-dev.1.4.5.105745
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 +8 -22
- package/.mocharc.js +12 -0
- package/dist/batchManager.d.ts +37 -0
- package/dist/batchManager.d.ts.map +1 -0
- package/dist/batchManager.js +73 -0
- package/dist/batchManager.js.map +1 -0
- package/dist/batchTracker.d.ts +1 -2
- package/dist/batchTracker.d.ts.map +1 -1
- package/dist/batchTracker.js +2 -3
- package/dist/batchTracker.js.map +1 -1
- package/dist/blobManager.d.ts +87 -25
- package/dist/blobManager.d.ts.map +1 -1
- package/dist/blobManager.js +317 -99
- package/dist/blobManager.js.map +1 -1
- package/dist/containerRuntime.d.ts +110 -125
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +360 -549
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStore.js +29 -24
- package/dist/dataStore.js.map +1 -1
- package/dist/dataStoreContext.d.ts +20 -14
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +49 -58
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStores.d.ts +12 -5
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/dataStores.js +21 -20
- package/dist/dataStores.js.map +1 -1
- package/dist/deltaScheduler.d.ts +6 -4
- package/dist/deltaScheduler.d.ts.map +1 -1
- package/dist/deltaScheduler.js +6 -4
- package/dist/deltaScheduler.js.map +1 -1
- package/dist/garbageCollection.d.ts +74 -14
- package/dist/garbageCollection.d.ts.map +1 -1
- package/dist/garbageCollection.js +248 -169
- package/dist/garbageCollection.js.map +1 -1
- package/dist/gcSweepReadyUsageDetection.d.ts +53 -0
- package/dist/gcSweepReadyUsageDetection.d.ts.map +1 -0
- package/dist/gcSweepReadyUsageDetection.js +135 -0
- package/dist/gcSweepReadyUsageDetection.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/opProperties.d.ts +7 -0
- package/dist/opProperties.d.ts.map +1 -0
- package/dist/opProperties.js +20 -0
- package/dist/opProperties.js.map +1 -0
- package/dist/orderedClientElection.d.ts +28 -10
- package/dist/orderedClientElection.d.ts.map +1 -1
- package/dist/orderedClientElection.js +14 -4
- package/dist/orderedClientElection.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/pendingStateManager.d.ts +0 -11
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +24 -46
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/runningSummarizer.d.ts +14 -4
- package/dist/runningSummarizer.d.ts.map +1 -1
- package/dist/runningSummarizer.js +69 -27
- package/dist/runningSummarizer.js.map +1 -1
- package/dist/scheduleManager.d.ts +31 -0
- package/dist/scheduleManager.d.ts.map +1 -0
- package/dist/scheduleManager.js +243 -0
- package/dist/scheduleManager.js.map +1 -0
- package/dist/summarizer.d.ts +0 -2
- package/dist/summarizer.d.ts.map +1 -1
- package/dist/summarizer.js +1 -12
- package/dist/summarizer.js.map +1 -1
- package/dist/summarizerHeuristics.d.ts +26 -4
- package/dist/summarizerHeuristics.d.ts.map +1 -1
- package/dist/summarizerHeuristics.js +98 -18
- package/dist/summarizerHeuristics.js.map +1 -1
- package/dist/summarizerTypes.d.ts +45 -18
- package/dist/summarizerTypes.d.ts.map +1 -1
- package/dist/summarizerTypes.js +1 -1
- package/dist/summarizerTypes.js.map +1 -1
- package/dist/summaryCollection.d.ts +1 -0
- package/dist/summaryCollection.d.ts.map +1 -1
- package/dist/summaryCollection.js +31 -15
- package/dist/summaryCollection.js.map +1 -1
- package/dist/summaryFormat.d.ts +0 -5
- package/dist/summaryFormat.d.ts.map +1 -1
- package/dist/summaryFormat.js.map +1 -1
- package/dist/summaryGenerator.d.ts +1 -0
- package/dist/summaryGenerator.d.ts.map +1 -1
- package/dist/summaryGenerator.js +11 -9
- package/dist/summaryGenerator.js.map +1 -1
- package/dist/summaryManager.d.ts +2 -2
- package/dist/summaryManager.d.ts.map +1 -1
- package/dist/summaryManager.js +22 -7
- package/dist/summaryManager.js.map +1 -1
- package/lib/batchManager.d.ts +37 -0
- package/lib/batchManager.d.ts.map +1 -0
- package/lib/batchManager.js +69 -0
- package/lib/batchManager.js.map +1 -0
- package/lib/batchTracker.d.ts +1 -2
- package/lib/batchTracker.d.ts.map +1 -1
- package/lib/batchTracker.js +2 -3
- package/lib/batchTracker.js.map +1 -1
- package/lib/blobManager.d.ts +87 -25
- package/lib/blobManager.d.ts.map +1 -1
- package/lib/blobManager.js +319 -101
- package/lib/blobManager.js.map +1 -1
- package/lib/containerRuntime.d.ts +110 -125
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +366 -554
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStore.js +29 -24
- package/lib/dataStore.js.map +1 -1
- package/lib/dataStoreContext.d.ts +20 -14
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +46 -55
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStores.d.ts +12 -5
- package/lib/dataStores.d.ts.map +1 -1
- package/lib/dataStores.js +21 -20
- package/lib/dataStores.js.map +1 -1
- package/lib/deltaScheduler.d.ts +6 -4
- package/lib/deltaScheduler.d.ts.map +1 -1
- package/lib/deltaScheduler.js +6 -4
- package/lib/deltaScheduler.js.map +1 -1
- package/lib/garbageCollection.d.ts +74 -14
- package/lib/garbageCollection.d.ts.map +1 -1
- package/lib/garbageCollection.js +237 -159
- package/lib/garbageCollection.js.map +1 -1
- package/lib/gcSweepReadyUsageDetection.d.ts +53 -0
- package/lib/gcSweepReadyUsageDetection.d.ts.map +1 -0
- package/lib/gcSweepReadyUsageDetection.js +130 -0
- package/lib/gcSweepReadyUsageDetection.js.map +1 -0
- package/lib/index.d.ts +2 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -1
- package/lib/index.js.map +1 -1
- package/lib/opProperties.d.ts +7 -0
- package/lib/opProperties.d.ts.map +1 -0
- package/lib/opProperties.js +16 -0
- package/lib/opProperties.js.map +1 -0
- package/lib/orderedClientElection.d.ts +28 -10
- package/lib/orderedClientElection.d.ts.map +1 -1
- package/lib/orderedClientElection.js +14 -4
- package/lib/orderedClientElection.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/pendingStateManager.d.ts +0 -11
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +24 -46
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/runningSummarizer.d.ts +14 -4
- package/lib/runningSummarizer.d.ts.map +1 -1
- package/lib/runningSummarizer.js +69 -27
- package/lib/runningSummarizer.js.map +1 -1
- package/lib/scheduleManager.d.ts +31 -0
- package/lib/scheduleManager.d.ts.map +1 -0
- package/lib/scheduleManager.js +239 -0
- package/lib/scheduleManager.js.map +1 -0
- package/lib/summarizer.d.ts +0 -2
- package/lib/summarizer.d.ts.map +1 -1
- package/lib/summarizer.js +1 -12
- package/lib/summarizer.js.map +1 -1
- package/lib/summarizerHeuristics.d.ts +26 -4
- package/lib/summarizerHeuristics.d.ts.map +1 -1
- package/lib/summarizerHeuristics.js +98 -18
- package/lib/summarizerHeuristics.js.map +1 -1
- package/lib/summarizerTypes.d.ts +45 -18
- package/lib/summarizerTypes.d.ts.map +1 -1
- package/lib/summarizerTypes.js +1 -1
- package/lib/summarizerTypes.js.map +1 -1
- package/lib/summaryCollection.d.ts +1 -0
- package/lib/summaryCollection.d.ts.map +1 -1
- package/lib/summaryCollection.js +31 -15
- package/lib/summaryCollection.js.map +1 -1
- package/lib/summaryFormat.d.ts +0 -5
- package/lib/summaryFormat.d.ts.map +1 -1
- package/lib/summaryFormat.js.map +1 -1
- package/lib/summaryGenerator.d.ts +1 -0
- package/lib/summaryGenerator.d.ts.map +1 -1
- package/lib/summaryGenerator.js +11 -9
- package/lib/summaryGenerator.js.map +1 -1
- package/lib/summaryManager.d.ts +2 -2
- package/lib/summaryManager.d.ts.map +1 -1
- package/lib/summaryManager.js +22 -7
- package/lib/summaryManager.js.map +1 -1
- package/package.json +68 -25
- package/src/batchManager.ts +91 -0
- package/src/batchTracker.ts +2 -3
- package/src/blobManager.ts +385 -118
- package/src/containerRuntime.ts +523 -732
- package/src/dataStore.ts +49 -37
- package/src/dataStoreContext.ts +44 -56
- package/src/dataStores.ts +34 -30
- package/src/deltaScheduler.ts +6 -4
- package/src/garbageCollection.ts +296 -205
- package/src/gcSweepReadyUsageDetection.ts +147 -0
- package/src/index.ts +1 -2
- package/src/opProperties.ts +19 -0
- package/src/orderedClientElection.ts +31 -10
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +27 -59
- package/src/runningSummarizer.ts +76 -23
- package/src/scheduleManager.ts +314 -0
- package/src/summarizer.ts +1 -18
- package/src/summarizerHeuristics.ts +136 -19
- package/src/summarizerTypes.ts +53 -18
- package/src/summaryCollection.ts +33 -18
- package/src/summaryFormat.ts +0 -6
- package/src/summaryGenerator.ts +40 -22
- package/src/summaryManager.ts +22 -7
- package/dist/opTelemetry.d.ts +0 -22
- package/dist/opTelemetry.d.ts.map +0 -1
- package/dist/opTelemetry.js +0 -59
- package/dist/opTelemetry.js.map +0 -1
- package/lib/opTelemetry.d.ts +0 -22
- package/lib/opTelemetry.d.ts.map +0 -1
- package/lib/opTelemetry.js +0 -55
- package/lib/opTelemetry.js.map +0 -1
- package/src/opTelemetry.ts +0 -71
package/src/dataStore.ts
CHANGED
|
@@ -54,6 +54,7 @@ enum AliasState {
|
|
|
54
54
|
class DataStore implements IDataStore {
|
|
55
55
|
private aliasState: AliasState = AliasState.None;
|
|
56
56
|
private alias: string | undefined;
|
|
57
|
+
private readonly pendingAliases: Map<string, Promise<AliasResult>>;
|
|
57
58
|
private aliasResult: Promise<AliasResult> | undefined;
|
|
58
59
|
|
|
59
60
|
async trySetAlias(alias: string): Promise<AliasResult> {
|
|
@@ -75,14 +76,25 @@ class DataStore implements IDataStore {
|
|
|
75
76
|
case AliasState.Aliased:
|
|
76
77
|
return this.alias === alias ? "Success" : "AlreadyAliased";
|
|
77
78
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
case AliasState.None: {
|
|
80
|
+
const existingAlias = this.pendingAliases.get(alias);
|
|
81
|
+
if (existingAlias !== undefined) {
|
|
82
|
+
// There is already another datastore which will be aliased
|
|
83
|
+
// to the same name
|
|
84
|
+
return "Conflict";
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// There is no current or past alias operation for this datastore,
|
|
88
|
+
// or for this alias, so it is safe to continue execution
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
|
|
81
92
|
default: unreachableCase(this.aliasState);
|
|
82
93
|
}
|
|
83
94
|
|
|
84
95
|
this.aliasState = AliasState.Aliasing;
|
|
85
96
|
this.aliasResult = this.trySetAliasInternal(alias);
|
|
97
|
+
this.pendingAliases.set(alias, this.aliasResult);
|
|
86
98
|
return this.aliasResult;
|
|
87
99
|
}
|
|
88
100
|
|
|
@@ -92,13 +104,7 @@ class DataStore implements IDataStore {
|
|
|
92
104
|
alias,
|
|
93
105
|
};
|
|
94
106
|
|
|
95
|
-
|
|
96
|
-
// older versions, we still have to call bindToContext.
|
|
97
|
-
if (this.fluidDataStoreChannel.makeVisibleAndAttachGraph !== undefined) {
|
|
98
|
-
this.fluidDataStoreChannel.makeVisibleAndAttachGraph();
|
|
99
|
-
} else {
|
|
100
|
-
this.fluidDataStoreChannel.bindToContext();
|
|
101
|
-
}
|
|
107
|
+
this.fluidDataStoreChannel.makeVisibleAndAttachGraph();
|
|
102
108
|
|
|
103
109
|
if (this.runtime.attachState === AttachState.Detached) {
|
|
104
110
|
const localResult = this.datastores.processAliasMessageCore(message);
|
|
@@ -108,34 +114,37 @@ class DataStore implements IDataStore {
|
|
|
108
114
|
return localResult ? "Success" : "Conflict";
|
|
109
115
|
}
|
|
110
116
|
|
|
111
|
-
const aliased = await this
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
117
|
+
const aliased = await this
|
|
118
|
+
.ackBasedPromise<boolean>((resolve) => {
|
|
119
|
+
this.runtime.submitDataStoreAliasOp(message, resolve);
|
|
120
|
+
})
|
|
121
|
+
.catch((error) => {
|
|
122
|
+
this.logger.sendErrorEvent({
|
|
123
|
+
eventName: "AliasingException",
|
|
124
|
+
alias: {
|
|
125
|
+
value: alias,
|
|
126
|
+
tag: TelemetryDataTag.UserData,
|
|
127
|
+
},
|
|
128
|
+
internalId: {
|
|
129
|
+
value: this.internalId,
|
|
130
|
+
tag: TelemetryDataTag.CodeArtifact,
|
|
131
|
+
},
|
|
132
|
+
}, error);
|
|
133
|
+
|
|
134
|
+
return false;
|
|
135
|
+
}).finally(() => {
|
|
136
|
+
this.pendingAliases.delete(alias);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
if (!aliased) {
|
|
134
140
|
this.aliasState = AliasState.None;
|
|
135
|
-
|
|
136
|
-
|
|
141
|
+
this.aliasResult = undefined;
|
|
142
|
+
return "Conflict";
|
|
143
|
+
}
|
|
137
144
|
|
|
138
|
-
|
|
145
|
+
this.alias = alias;
|
|
146
|
+
this.aliasState = AliasState.Aliased;
|
|
147
|
+
return "Success";
|
|
139
148
|
}
|
|
140
149
|
|
|
141
150
|
async request(request: IRequest): Promise<IResponse> {
|
|
@@ -148,7 +157,10 @@ class DataStore implements IDataStore {
|
|
|
148
157
|
private readonly runtime: ContainerRuntime,
|
|
149
158
|
private readonly datastores: DataStores,
|
|
150
159
|
private readonly logger: ITelemetryLogger,
|
|
151
|
-
) {
|
|
160
|
+
) {
|
|
161
|
+
this.pendingAliases = datastores.pendingAliases;
|
|
162
|
+
}
|
|
163
|
+
|
|
152
164
|
public get IFluidRouter() { return this.fluidDataStoreChannel; }
|
|
153
165
|
|
|
154
166
|
private async ackBasedPromise<T>(
|
package/src/dataStoreContext.ts
CHANGED
|
@@ -13,7 +13,6 @@ import {
|
|
|
13
13
|
import {
|
|
14
14
|
IAudience,
|
|
15
15
|
IDeltaManager,
|
|
16
|
-
BindState,
|
|
17
16
|
AttachState,
|
|
18
17
|
ILoaderOptions,
|
|
19
18
|
} from "@fluidframework/container-definitions";
|
|
@@ -38,6 +37,7 @@ import {
|
|
|
38
37
|
IContainerRuntime,
|
|
39
38
|
} from "@fluidframework/container-runtime-definitions";
|
|
40
39
|
import {
|
|
40
|
+
BindState,
|
|
41
41
|
channelsTreeName,
|
|
42
42
|
CreateChildSummarizerNodeFn,
|
|
43
43
|
CreateChildSummarizerNodeParam,
|
|
@@ -83,14 +83,9 @@ import {
|
|
|
83
83
|
function createAttributes(
|
|
84
84
|
pkg: readonly string[],
|
|
85
85
|
isRootDataStore: boolean,
|
|
86
|
-
disableIsolatedChannels: boolean,
|
|
87
86
|
): WriteFluidDataStoreAttributes {
|
|
88
87
|
const stringifiedPkg = JSON.stringify(pkg);
|
|
89
|
-
return
|
|
90
|
-
pkg: stringifiedPkg,
|
|
91
|
-
snapshotFormatVersion: "0.1",
|
|
92
|
-
isRootDataStore,
|
|
93
|
-
} : {
|
|
88
|
+
return {
|
|
94
89
|
pkg: stringifiedPkg,
|
|
95
90
|
summaryFormatVersion: 2,
|
|
96
91
|
isRootDataStore,
|
|
@@ -99,9 +94,8 @@ function createAttributes(
|
|
|
99
94
|
export function createAttributesBlob(
|
|
100
95
|
pkg: readonly string[],
|
|
101
96
|
isRootDataStore: boolean,
|
|
102
|
-
disableIsolatedChannels: boolean,
|
|
103
97
|
): ITreeEntry {
|
|
104
|
-
const attributes = createAttributes(pkg, isRootDataStore
|
|
98
|
+
const attributes = createAttributes(pkg, isRootDataStore);
|
|
105
99
|
return new BlobTreeEntry(dataStoreAttributesBlobName, JSON.stringify(attributes));
|
|
106
100
|
}
|
|
107
101
|
|
|
@@ -124,7 +118,6 @@ export interface IFluidDataStoreContextProps {
|
|
|
124
118
|
readonly scope: FluidObject;
|
|
125
119
|
readonly createSummarizerNodeFn: CreateChildSummarizerNodeFn;
|
|
126
120
|
readonly writeGCDataAtRoot: boolean;
|
|
127
|
-
readonly disableIsolatedChannels: boolean;
|
|
128
121
|
readonly pkg?: Readonly<string[]>;
|
|
129
122
|
}
|
|
130
123
|
|
|
@@ -232,6 +225,7 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
|
|
|
232
225
|
protected registry: IFluidDataStoreRegistry | undefined;
|
|
233
226
|
|
|
234
227
|
protected detachedRuntimeCreation = false;
|
|
228
|
+
/** @deprecated - To be replaced by calling makeLocallyVisible directly */
|
|
235
229
|
public readonly bindToContext: () => void;
|
|
236
230
|
protected channel: IFluidDataStoreChannel | undefined;
|
|
237
231
|
private loaded = false;
|
|
@@ -254,13 +248,12 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
|
|
|
254
248
|
public readonly storage: IDocumentStorageService;
|
|
255
249
|
public readonly scope: FluidObject;
|
|
256
250
|
private readonly writeGCDataAtRoot: boolean;
|
|
257
|
-
protected readonly disableIsolatedChannels: boolean;
|
|
258
251
|
protected pkg?: readonly string[];
|
|
259
252
|
|
|
260
253
|
constructor(
|
|
261
254
|
props: IFluidDataStoreContextProps,
|
|
262
255
|
private readonly existing: boolean,
|
|
263
|
-
private bindState: BindState,
|
|
256
|
+
private bindState: BindState, // Used to assert for state tracking purposes
|
|
264
257
|
public readonly isLocalDataStore: boolean,
|
|
265
258
|
private readonly makeLocallyVisibleFn: () => void,
|
|
266
259
|
) {
|
|
@@ -271,7 +264,6 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
|
|
|
271
264
|
this.storage = props.storage;
|
|
272
265
|
this.scope = props.scope;
|
|
273
266
|
this.writeGCDataAtRoot = props.writeGCDataAtRoot;
|
|
274
|
-
this.disableIsolatedChannels = props.disableIsolatedChannels;
|
|
275
267
|
this.pkg = props.pkg;
|
|
276
268
|
|
|
277
269
|
// URIs use slashes as delimiters. Handles use URIs.
|
|
@@ -319,7 +311,7 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
|
|
|
319
311
|
}
|
|
320
312
|
|
|
321
313
|
private rejectDeferredRealize(reason: string, packageName?: string): never {
|
|
322
|
-
throw new LoggingError(reason, { packageName: { value: packageName, tag: TelemetryDataTag.
|
|
314
|
+
throw new LoggingError(reason, { packageName: { value: packageName, tag: TelemetryDataTag.CodeArtifact } });
|
|
323
315
|
}
|
|
324
316
|
|
|
325
317
|
public async realize(): Promise<IFluidDataStoreChannel> {
|
|
@@ -328,7 +320,12 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
|
|
|
328
320
|
this.channelDeferred = new Deferred<IFluidDataStoreChannel>();
|
|
329
321
|
this.realizeCore(this.existing).catch((error) => {
|
|
330
322
|
const errorWrapped = DataProcessingError.wrapIfUnrecognized(error, "realizeFluidDataStoreContext");
|
|
331
|
-
errorWrapped.addTelemetryProperties({
|
|
323
|
+
errorWrapped.addTelemetryProperties({
|
|
324
|
+
fluidDataStoreId: {
|
|
325
|
+
value: this.id,
|
|
326
|
+
tag: TelemetryDataTag.CodeArtifact,
|
|
327
|
+
},
|
|
328
|
+
});
|
|
332
329
|
this.channelDeferred?.reject(errorWrapped);
|
|
333
330
|
this.logger.sendErrorEvent({ eventName: "RealizeError" }, errorWrapped);
|
|
334
331
|
});
|
|
@@ -385,8 +382,8 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
|
|
|
385
382
|
/**
|
|
386
383
|
* Notifies this object about changes in the connection state.
|
|
387
384
|
* @param value - New connection state.
|
|
388
|
-
* @param clientId - ID of the client.
|
|
389
|
-
*
|
|
385
|
+
* @param clientId - ID of the client. Its old ID when in disconnected state and
|
|
386
|
+
* its new client ID when we are connecting or connected.
|
|
390
387
|
*/
|
|
391
388
|
public setConnectionState(connected: boolean, clientId?: string) {
|
|
392
389
|
this.verifyNotClosed();
|
|
@@ -466,18 +463,15 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
|
|
|
466
463
|
|
|
467
464
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
468
465
|
const summarizeResult = await this.channel!.summarize(fullTree, trackState, telemetryContext);
|
|
469
|
-
let pathPartsForChildren: string[] | undefined;
|
|
470
466
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
pathPartsForChildren = [channelsTreeName];
|
|
475
|
-
}
|
|
467
|
+
// Wrap dds summaries in .channels subtree.
|
|
468
|
+
wrapSummaryInChannelsTree(summarizeResult);
|
|
469
|
+
const pathPartsForChildren = [channelsTreeName];
|
|
476
470
|
|
|
477
471
|
// Add data store's attributes to the summary.
|
|
478
472
|
const { pkg } = await this.getInitialSnapshotDetails();
|
|
479
473
|
const isRoot = await this.isRoot();
|
|
480
|
-
const attributes = createAttributes(pkg, isRoot
|
|
474
|
+
const attributes = createAttributes(pkg, isRoot);
|
|
481
475
|
addBlobToSummary(summarizeResult, dataStoreAttributesBlobName, JSON.stringify(attributes));
|
|
482
476
|
|
|
483
477
|
// Add GC data to the summary if it's not written at the root.
|
|
@@ -525,12 +519,18 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
|
|
|
525
519
|
|
|
526
520
|
/**
|
|
527
521
|
* After GC has run, called to notify the data store of routes used in it. These are used for the following:
|
|
522
|
+
*
|
|
528
523
|
* 1. To identify if this data store is being referenced in the document or not.
|
|
524
|
+
*
|
|
529
525
|
* 2. To determine if it needs to re-summarize in case used routes changed since last summary.
|
|
526
|
+
*
|
|
530
527
|
* 3. These are added to the summary generated by the data store.
|
|
531
|
-
*
|
|
532
|
-
*
|
|
528
|
+
*
|
|
529
|
+
* 4. To notify child contexts of their used routes. This is done immediately if the data store is loaded.
|
|
530
|
+
* Else, it is done when realizing the data store.
|
|
531
|
+
*
|
|
533
532
|
* 5. To update the timestamp when this data store or any children are marked as unreferenced.
|
|
533
|
+
*
|
|
534
534
|
* @param usedRoutes - The routes that are used in this data store.
|
|
535
535
|
* @param gcTimestamp - The time when GC was run that generated these used routes. If any node becomes unreferenced
|
|
536
536
|
* as part of this GC run, this should be used to update the time when it happens.
|
|
@@ -690,7 +690,10 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
|
|
|
690
690
|
} catch (error) {
|
|
691
691
|
this.channelDeferred?.reject(error);
|
|
692
692
|
this.logger.sendErrorEvent(
|
|
693
|
-
{ eventName: "BindRuntimeError", fluidDataStoreId: {
|
|
693
|
+
{ eventName: "BindRuntimeError", fluidDataStoreId: {
|
|
694
|
+
value: this.id,
|
|
695
|
+
tag: TelemetryDataTag.CodeArtifact,
|
|
696
|
+
} },
|
|
694
697
|
error);
|
|
695
698
|
}
|
|
696
699
|
}
|
|
@@ -707,7 +710,7 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
|
|
|
707
710
|
public abstract getInitialSnapshotDetails(): Promise<ISnapshotDetails>;
|
|
708
711
|
|
|
709
712
|
/**
|
|
710
|
-
* @deprecated
|
|
713
|
+
* @deprecated Sets the datastore as root, for aliasing purposes: #7948
|
|
711
714
|
* This method should not be used outside of the aliasing context.
|
|
712
715
|
* It will be removed, as the source of truth for this flag will be the aliasing blob.
|
|
713
716
|
*/
|
|
@@ -716,7 +719,7 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
|
|
|
716
719
|
}
|
|
717
720
|
|
|
718
721
|
/**
|
|
719
|
-
* @deprecated
|
|
722
|
+
* @deprecated Renamed to `{@link FluidDataStoreContext.getBaseGCDetails}()`.
|
|
720
723
|
*/
|
|
721
724
|
public abstract getInitialGCSummaryDetails(): Promise<IGarbageCollectionSummaryDetails>;
|
|
722
725
|
|
|
@@ -809,11 +812,7 @@ export class RemoteFluidDataStoreContext extends FluidDataStoreContext {
|
|
|
809
812
|
|
|
810
813
|
const localReadAndParse = async <T>(id: string) => readAndParse<T>(this.storage, id);
|
|
811
814
|
if (tree) {
|
|
812
|
-
|
|
813
|
-
tree = loadedSummary.baseSummary;
|
|
814
|
-
// Prepend outstanding ops to pending queue of ops to process.
|
|
815
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
816
|
-
this.pending = loadedSummary.outstandingOps.concat(this.pending!);
|
|
815
|
+
tree = await this.summarizerNode.loadBaseSummary(tree, localReadAndParse);
|
|
817
816
|
}
|
|
818
817
|
|
|
819
818
|
if (!!tree && tree.blobs[dataStoreAttributesBlobName] !== undefined) {
|
|
@@ -826,11 +825,9 @@ export class RemoteFluidDataStoreContext extends FluidDataStoreContext {
|
|
|
826
825
|
// For snapshotFormatVersion = "0.1" (1) or above, pkg is jsonified, otherwise it is just a string.
|
|
827
826
|
const formatVersion = getAttributesFormatVersion(attributes);
|
|
828
827
|
if (formatVersion < 1) {
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
pkgFromSnapshot = [attributes.pkg];
|
|
833
|
-
}
|
|
828
|
+
pkgFromSnapshot = attributes.pkg.startsWith("[\"") && attributes.pkg.endsWith("\"]")
|
|
829
|
+
? JSON.parse(attributes.pkg) as string[]
|
|
830
|
+
: [attributes.pkg];
|
|
834
831
|
} else {
|
|
835
832
|
pkgFromSnapshot = JSON.parse(attributes.pkg) as string[];
|
|
836
833
|
}
|
|
@@ -863,7 +860,7 @@ export class RemoteFluidDataStoreContext extends FluidDataStoreContext {
|
|
|
863
860
|
}
|
|
864
861
|
|
|
865
862
|
/**
|
|
866
|
-
* @deprecated
|
|
863
|
+
* @deprecated Renamed to {@link RemoteFluidDataStoreContext.getBaseGCDetails}.
|
|
867
864
|
*/
|
|
868
865
|
public async getInitialGCSummaryDetails(): Promise<IGarbageCollectionSummaryDetails> {
|
|
869
866
|
return this.getBaseGCDetails();
|
|
@@ -922,16 +919,13 @@ export class LocalFluidDataStoreContextBase extends FluidDataStoreContext {
|
|
|
922
919
|
|
|
923
920
|
const summarizeResult = this.channel.getAttachSummary();
|
|
924
921
|
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
wrapSummaryInChannelsTree(summarizeResult);
|
|
928
|
-
}
|
|
922
|
+
// Wrap dds summaries in .channels subtree.
|
|
923
|
+
wrapSummaryInChannelsTree(summarizeResult);
|
|
929
924
|
|
|
930
925
|
// Add data store's attributes to the summary.
|
|
931
926
|
const attributes = createAttributes(
|
|
932
927
|
this.pkg,
|
|
933
928
|
this.isInMemoryRoot(),
|
|
934
|
-
this.disableIsolatedChannels,
|
|
935
929
|
);
|
|
936
930
|
addBlobToSummary(summarizeResult, dataStoreAttributesBlobName, JSON.stringify(attributes));
|
|
937
931
|
|
|
@@ -981,7 +975,7 @@ export class LocalFluidDataStoreContextBase extends FluidDataStoreContext {
|
|
|
981
975
|
}
|
|
982
976
|
|
|
983
977
|
/**
|
|
984
|
-
* @deprecated
|
|
978
|
+
* @deprecated Renamed to {@link LocalFluidDataStoreContextBase.getBaseGCDetails}.
|
|
985
979
|
*/
|
|
986
980
|
public async getInitialGCSummaryDetails(): Promise<IGarbageCollectionSummaryDetails> {
|
|
987
981
|
// Local data store does not have initial summary.
|
|
@@ -1024,7 +1018,10 @@ export class LocalDetachedFluidDataStoreContext
|
|
|
1024
1018
|
registry: IProvideFluidDataStoreFactory,
|
|
1025
1019
|
dataStoreChannel: IFluidDataStoreChannel) {
|
|
1026
1020
|
assert(this.detachedRuntimeCreation, 0x154 /* "runtime creation is already attached" */);
|
|
1021
|
+
this.detachedRuntimeCreation = false;
|
|
1022
|
+
|
|
1027
1023
|
assert(this.channelDeferred === undefined, 0x155 /* "channel deferral is already set" */);
|
|
1024
|
+
this.channelDeferred = new Deferred<IFluidDataStoreChannel>();
|
|
1028
1025
|
|
|
1029
1026
|
const factory = registry.IFluidDataStoreFactory;
|
|
1030
1027
|
|
|
@@ -1034,19 +1031,10 @@ export class LocalDetachedFluidDataStoreContext
|
|
|
1034
1031
|
assert(this.registry === undefined, 0x157 /* "datastore registry already attached" */);
|
|
1035
1032
|
this.registry = entry.registry;
|
|
1036
1033
|
|
|
1037
|
-
this.detachedRuntimeCreation = false;
|
|
1038
|
-
this.channelDeferred = new Deferred<IFluidDataStoreChannel>();
|
|
1039
|
-
|
|
1040
1034
|
super.bindRuntime(dataStoreChannel);
|
|
1041
1035
|
|
|
1042
1036
|
if (await this.isRoot()) {
|
|
1043
|
-
|
|
1044
|
-
// For older versions, we still have to call bindToContext.
|
|
1045
|
-
if (dataStoreChannel.makeVisibleAndAttachGraph !== undefined) {
|
|
1046
|
-
dataStoreChannel.makeVisibleAndAttachGraph();
|
|
1047
|
-
} else {
|
|
1048
|
-
dataStoreChannel.bindToContext();
|
|
1049
|
-
}
|
|
1037
|
+
dataStoreChannel.makeVisibleAndAttachGraph();
|
|
1050
1038
|
}
|
|
1051
1039
|
}
|
|
1052
1040
|
|
package/src/dataStores.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
ISnapshotTree,
|
|
13
13
|
} from "@fluidframework/protocol-definitions";
|
|
14
14
|
import {
|
|
15
|
+
AliasResult,
|
|
15
16
|
channelsTreeName,
|
|
16
17
|
CreateChildSummarizerNodeFn,
|
|
17
18
|
CreateChildSummarizerNodeParam,
|
|
@@ -28,11 +29,11 @@ import {
|
|
|
28
29
|
ITelemetryContext,
|
|
29
30
|
} from "@fluidframework/runtime-definitions";
|
|
30
31
|
import {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
convertSnapshotTreeToSummaryTree,
|
|
33
|
+
convertToSummaryTree,
|
|
34
|
+
create404Response,
|
|
35
|
+
responseToException,
|
|
36
|
+
SummaryTreeBuilder,
|
|
36
37
|
} from "@fluidframework/runtime-utils";
|
|
37
38
|
import { ChildLogger, LoggingError, TelemetryDataTag } from "@fluidframework/telemetry-utils";
|
|
38
39
|
import { AttachState } from "@fluidframework/container-definitions";
|
|
@@ -55,10 +56,10 @@ import { GCNodeType } from "./garbageCollection";
|
|
|
55
56
|
|
|
56
57
|
type PendingAliasResolve = (success: boolean) => void;
|
|
57
58
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
/**
|
|
60
|
+
* This class encapsulates data store handling. Currently it is only used by the container runtime,
|
|
61
|
+
* but eventually could be hosted on any channel once we formalize the channel api boundary.
|
|
62
|
+
*/
|
|
62
63
|
export class DataStores implements IDisposable {
|
|
63
64
|
// Stores tracked by the Domain
|
|
64
65
|
private readonly pendingAttach = new Map<string, IAttachMessage>();
|
|
@@ -82,6 +83,7 @@ export class DataStores implements IDisposable {
|
|
|
82
83
|
// The handle to the container runtime. This is used mainly for GC purposes to represent outbound reference from
|
|
83
84
|
// the container runtime to other nodes.
|
|
84
85
|
private readonly containerRuntimeHandle: IFluidHandle;
|
|
86
|
+
private readonly pendingAliasMap: Map<string, Promise<AliasResult>> = new Map<string, Promise<AliasResult>>();
|
|
85
87
|
|
|
86
88
|
constructor(
|
|
87
89
|
private readonly baseSnapshot: ISnapshotTree | undefined,
|
|
@@ -141,7 +143,6 @@ export class DataStores implements IDisposable {
|
|
|
141
143
|
{ type: CreateSummarizerNodeSource.FromSummary },
|
|
142
144
|
),
|
|
143
145
|
writeGCDataAtRoot: this.writeGCDataAtRoot,
|
|
144
|
-
disableIsolatedChannels: this.runtime.disableIsolatedChannels,
|
|
145
146
|
});
|
|
146
147
|
} else {
|
|
147
148
|
if (typeof value !== "object") {
|
|
@@ -162,7 +163,6 @@ export class DataStores implements IDisposable {
|
|
|
162
163
|
snapshotTree,
|
|
163
164
|
isRootDataStore: undefined,
|
|
164
165
|
writeGCDataAtRoot: this.writeGCDataAtRoot,
|
|
165
|
-
disableIsolatedChannels: this.runtime.disableIsolatedChannels,
|
|
166
166
|
});
|
|
167
167
|
}
|
|
168
168
|
this.contexts.addBoundOrRemoted(dataStoreContext);
|
|
@@ -173,10 +173,19 @@ export class DataStores implements IDisposable {
|
|
|
173
173
|
};
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
-
public aliases(): ReadonlyMap<string, string> {
|
|
176
|
+
public get aliases(): ReadonlyMap<string, string> {
|
|
177
177
|
return this.aliasMap;
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
+
public get pendingAliases(): Map<string, Promise<AliasResult>> {
|
|
181
|
+
return this.pendingAliasMap;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
public async waitIfPendingAlias(maybeAlias: string): Promise<AliasResult> {
|
|
185
|
+
const pendingAliasPromise = this.pendingAliases.get(maybeAlias);
|
|
186
|
+
return pendingAliasPromise === undefined ? "Success" : pendingAliasPromise;
|
|
187
|
+
}
|
|
188
|
+
|
|
180
189
|
public processAttachMessage(message: ISequencedDocumentMessage, local: boolean) {
|
|
181
190
|
const attachMessage = message.contents as InboundAttachMessage;
|
|
182
191
|
|
|
@@ -191,7 +200,7 @@ export class DataStores implements IDisposable {
|
|
|
191
200
|
return;
|
|
192
201
|
}
|
|
193
202
|
|
|
194
|
-
|
|
203
|
+
// If a non-local operation then go and create the object, otherwise mark it as officially attached.
|
|
195
204
|
if (this.alreadyProcessed(attachMessage.id)) {
|
|
196
205
|
// TODO: dataStoreId may require a different tag from PackageData #7488
|
|
197
206
|
const error = new DataCorruptionError(
|
|
@@ -201,7 +210,7 @@ export class DataStores implements IDisposable {
|
|
|
201
210
|
...extractSafePropertiesFromMessage(message),
|
|
202
211
|
dataStoreId: {
|
|
203
212
|
value: attachMessage.id,
|
|
204
|
-
tag: TelemetryDataTag.
|
|
213
|
+
tag: TelemetryDataTag.CodeArtifact,
|
|
205
214
|
},
|
|
206
215
|
},
|
|
207
216
|
);
|
|
@@ -234,13 +243,11 @@ export class DataStores implements IDisposable {
|
|
|
234
243
|
entries: [createAttributesBlob(
|
|
235
244
|
pkg,
|
|
236
245
|
true /* isRootDataStore */,
|
|
237
|
-
this.runtime.disableIsolatedChannels,
|
|
238
246
|
)],
|
|
239
247
|
},
|
|
240
248
|
},
|
|
241
249
|
),
|
|
242
250
|
writeGCDataAtRoot: this.writeGCDataAtRoot,
|
|
243
|
-
disableIsolatedChannels: this.runtime.disableIsolatedChannels,
|
|
244
251
|
pkg,
|
|
245
252
|
});
|
|
246
253
|
|
|
@@ -345,13 +352,12 @@ export class DataStores implements IDisposable {
|
|
|
345
352
|
snapshotTree: undefined,
|
|
346
353
|
isRootDataStore: isRoot,
|
|
347
354
|
writeGCDataAtRoot: this.writeGCDataAtRoot,
|
|
348
|
-
disableIsolatedChannels: this.runtime.disableIsolatedChannels,
|
|
349
355
|
});
|
|
350
356
|
this.contexts.addUnbound(context);
|
|
351
357
|
return context;
|
|
352
358
|
}
|
|
353
359
|
|
|
354
|
-
public _createFluidDataStoreContext(pkg: string[], id: string,
|
|
360
|
+
public _createFluidDataStoreContext(pkg: string[], id: string, props?: any) {
|
|
355
361
|
assert(!id.includes("/"), 0x30d /* Id cannot contain slashes */);
|
|
356
362
|
const context = new LocalFluidDataStoreContext({
|
|
357
363
|
id,
|
|
@@ -365,9 +371,8 @@ export class DataStores implements IDisposable {
|
|
|
365
371
|
),
|
|
366
372
|
makeLocallyVisibleFn: () => this.makeDataStoreLocallyVisible(id),
|
|
367
373
|
snapshotTree: undefined,
|
|
368
|
-
isRootDataStore:
|
|
374
|
+
isRootDataStore: false,
|
|
369
375
|
writeGCDataAtRoot: this.writeGCDataAtRoot,
|
|
370
|
-
disableIsolatedChannels: this.runtime.disableIsolatedChannels,
|
|
371
376
|
createProps: props,
|
|
372
377
|
});
|
|
373
378
|
this.contexts.addUnbound(context);
|
|
@@ -440,7 +445,7 @@ export class DataStores implements IDisposable {
|
|
|
440
445
|
eventName: "SignalFluidDataStoreNotFound",
|
|
441
446
|
fluidDataStoreId: {
|
|
442
447
|
value: address,
|
|
443
|
-
tag: TelemetryDataTag.
|
|
448
|
+
tag: TelemetryDataTag.CodeArtifact,
|
|
444
449
|
},
|
|
445
450
|
});
|
|
446
451
|
return;
|
|
@@ -464,13 +469,8 @@ export class DataStores implements IDisposable {
|
|
|
464
469
|
}
|
|
465
470
|
|
|
466
471
|
public setAttachState(attachState: AttachState.Attaching | AttachState.Attached): void {
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
eventName = "attaching";
|
|
470
|
-
} else {
|
|
471
|
-
eventName = "attached";
|
|
472
|
-
}
|
|
473
|
-
for (const [,context] of this.contexts) {
|
|
472
|
+
const eventName = attachState === AttachState.Attaching ? "attaching" : "attached";
|
|
473
|
+
for (const [, context] of this.contexts) {
|
|
474
474
|
// Fire only for bounded stores.
|
|
475
475
|
if (!this.contexts.isNotBound(context.id)) {
|
|
476
476
|
context.emit(eventName);
|
|
@@ -561,11 +561,15 @@ export class DataStores implements IDisposable {
|
|
|
561
561
|
|
|
562
562
|
/**
|
|
563
563
|
* Generates data used for garbage collection. It does the following:
|
|
564
|
+
*
|
|
564
565
|
* 1. Calls into each child data store context to get its GC data.
|
|
566
|
+
*
|
|
565
567
|
* 2. Prefixes the child context's id to the GC nodes in the child's GC data. This makes sure that the node can be
|
|
566
|
-
*
|
|
568
|
+
* identified as belonging to the child.
|
|
569
|
+
*
|
|
567
570
|
* 3. Adds a GC node for this channel to the nodes received from the children. All these nodes together represent
|
|
568
|
-
*
|
|
571
|
+
* the GC data of this channel.
|
|
572
|
+
*
|
|
569
573
|
* @param fullGC - true to bypass optimizations and force full generation of GC data.
|
|
570
574
|
*/
|
|
571
575
|
public async getGCData(fullGC: boolean = false): Promise<IGarbageCollectionData> {
|
package/src/deltaScheduler.ts
CHANGED
|
@@ -18,12 +18,14 @@ import {
|
|
|
18
18
|
* DeltaScheduler is responsible for the scheduling of inbound delta queue in cases where there
|
|
19
19
|
* is more than one op a particular run of the queue. It does not schedule if there is just one
|
|
20
20
|
* op or just one batch in the run. It does the following two things:
|
|
21
|
+
*
|
|
21
22
|
* 1. If the ops have been processed for more than a specific amount of time, it pauses the queue
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
23
|
+
* and calls setTimeout to schedule a resume of the queue. This ensures that we don't block
|
|
24
|
+
* the JS thread for a long time processing ops synchronously (for example, when catching up
|
|
25
|
+
* ops right after boot or catching up ops / delayed realizing data stores by summarizer).
|
|
26
|
+
*
|
|
25
27
|
* 2. If we scheduled a particular run of the queue, it logs telemetry for the number of ops
|
|
26
|
-
*
|
|
28
|
+
* processed, the time and number of turns it took to process the ops.
|
|
27
29
|
*/
|
|
28
30
|
export class DeltaScheduler {
|
|
29
31
|
private readonly deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>;
|