@fluidframework/container-runtime 0.54.2 → 0.56.0-49831
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 +1 -1
- package/dist/blobManager.js +1 -1
- package/dist/blobManager.js.map +1 -1
- package/dist/containerRuntime.d.ts +20 -14
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +51 -58
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStoreContext.d.ts +57 -33
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +44 -54
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStores.d.ts +12 -2
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/dataStores.js +106 -32
- package/dist/dataStores.js.map +1 -1
- package/dist/garbageCollection.d.ts +49 -14
- package/dist/garbageCollection.d.ts.map +1 -1
- package/dist/garbageCollection.js +122 -26
- package/dist/garbageCollection.js.map +1 -1
- package/dist/index.d.ts +7 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -17
- package/dist/index.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/runningSummarizer.d.ts.map +1 -1
- package/dist/runningSummarizer.js +2 -9
- package/dist/runningSummarizer.js.map +1 -1
- package/dist/summaryFormat.d.ts +2 -0
- package/dist/summaryFormat.d.ts.map +1 -1
- package/dist/summaryFormat.js +2 -4
- package/dist/summaryFormat.js.map +1 -1
- package/dist/summaryGenerator.d.ts +0 -5
- package/dist/summaryGenerator.d.ts.map +1 -1
- package/dist/summaryGenerator.js.map +1 -1
- package/dist/summaryManager.d.ts +1 -0
- package/dist/summaryManager.d.ts.map +1 -1
- package/dist/summaryManager.js +7 -2
- package/dist/summaryManager.js.map +1 -1
- package/garbageCollection.md +33 -0
- package/lib/blobManager.js +1 -1
- package/lib/blobManager.js.map +1 -1
- package/lib/containerRuntime.d.ts +20 -14
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +51 -58
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStoreContext.d.ts +57 -33
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +42 -52
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStores.d.ts +12 -2
- package/lib/dataStores.d.ts.map +1 -1
- package/lib/dataStores.js +107 -33
- package/lib/dataStores.js.map +1 -1
- package/lib/garbageCollection.d.ts +49 -14
- package/lib/garbageCollection.d.ts.map +1 -1
- package/lib/garbageCollection.js +122 -26
- package/lib/garbageCollection.js.map +1 -1
- package/lib/index.d.ts +7 -7
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +6 -7
- package/lib/index.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/runningSummarizer.d.ts.map +1 -1
- package/lib/runningSummarizer.js +2 -9
- package/lib/runningSummarizer.js.map +1 -1
- package/lib/summaryFormat.d.ts +2 -0
- package/lib/summaryFormat.d.ts.map +1 -1
- package/lib/summaryFormat.js +2 -4
- package/lib/summaryFormat.js.map +1 -1
- package/lib/summaryGenerator.d.ts +0 -5
- package/lib/summaryGenerator.d.ts.map +1 -1
- package/lib/summaryGenerator.js.map +1 -1
- package/lib/summaryManager.d.ts +1 -0
- package/lib/summaryManager.d.ts.map +1 -1
- package/lib/summaryManager.js +7 -2
- package/lib/summaryManager.js.map +1 -1
- package/package.json +24 -23
- package/src/blobManager.ts +1 -1
- package/src/containerRuntime.ts +69 -65
- package/src/dataStoreContext.ts +105 -129
- package/src/dataStores.ts +118 -68
- package/src/garbageCollection.ts +156 -31
- package/src/index.ts +52 -6
- package/src/packageVersion.ts +1 -1
- package/src/runningSummarizer.ts +2 -7
- package/src/summaryFormat.ts +4 -4
- package/src/summaryGenerator.ts +0 -5
- package/src/summaryManager.ts +9 -3
package/src/dataStores.ts
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
import { ITelemetryLogger, ITelemetryBaseLogger, IDisposable } from "@fluidframework/common-definitions";
|
|
7
7
|
import { DataCorruptionError, extractSafePropertiesFromMessage } from "@fluidframework/container-utils";
|
|
8
|
+
import { IFluidHandle } from "@fluidframework/core-interfaces";
|
|
9
|
+
import { FluidObjectHandle } from "@fluidframework/datastore";
|
|
8
10
|
import {
|
|
9
11
|
ISequencedDocumentMessage,
|
|
10
12
|
ISnapshotTree,
|
|
@@ -19,7 +21,7 @@ import {
|
|
|
19
21
|
IFluidDataStoreChannel,
|
|
20
22
|
IFluidDataStoreContextDetached,
|
|
21
23
|
IGarbageCollectionData,
|
|
22
|
-
|
|
24
|
+
IGarbageCollectionDetailsBase,
|
|
23
25
|
IInboundSignalMessage,
|
|
24
26
|
InboundAttachMessage,
|
|
25
27
|
ISummarizeResult,
|
|
@@ -42,7 +44,7 @@ import { DataStoreContexts } from "./dataStoreContexts";
|
|
|
42
44
|
import { ContainerRuntime } from "./containerRuntime";
|
|
43
45
|
import {
|
|
44
46
|
FluidDataStoreContext,
|
|
45
|
-
|
|
47
|
+
RemoteFluidDataStoreContext,
|
|
46
48
|
LocalFluidDataStoreContext,
|
|
47
49
|
createAttributesBlob,
|
|
48
50
|
LocalDetachedFluidDataStoreContext,
|
|
@@ -97,6 +99,13 @@ export class DataStores implements IDisposable {
|
|
|
97
99
|
readonly referencedDataStoreCount: number;
|
|
98
100
|
};
|
|
99
101
|
|
|
102
|
+
// Stores the ids of new data stores between two GC runs. This is used to notify the garbage collector of new
|
|
103
|
+
// root data stores that are added.
|
|
104
|
+
private dataStoresSinceLastGC: string[] = [];
|
|
105
|
+
// The handle to the container runtime. This is used mainly for GC purposes to represent outbound reference from
|
|
106
|
+
// the container runtime to other nodes.
|
|
107
|
+
private readonly containerRuntimeHandle: IFluidHandle;
|
|
108
|
+
|
|
100
109
|
constructor(
|
|
101
110
|
private readonly baseSnapshot: ISnapshotTree | undefined,
|
|
102
111
|
private readonly runtime: ContainerRuntime,
|
|
@@ -105,19 +114,21 @@ export class DataStores implements IDisposable {
|
|
|
105
114
|
(id: string, createParam: CreateChildSummarizerNodeParam) => CreateChildSummarizerNodeFn,
|
|
106
115
|
private readonly deleteChildSummarizerNodeFn: (id: string) => void,
|
|
107
116
|
baseLogger: ITelemetryBaseLogger,
|
|
108
|
-
|
|
117
|
+
getBaseGCDetails: () => Promise<Map<string, IGarbageCollectionDetailsBase>>,
|
|
109
118
|
private readonly dataStoreChanged: (id: string) => void,
|
|
110
119
|
private readonly aliasMap: Map<string, string>,
|
|
120
|
+
private readonly writeGCDataAtRoot: boolean,
|
|
111
121
|
private readonly contexts: DataStoreContexts = new DataStoreContexts(baseLogger),
|
|
112
122
|
) {
|
|
113
123
|
this.logger = ChildLogger.create(baseLogger);
|
|
124
|
+
this.containerRuntimeHandle = new FluidObjectHandle(this.runtime, "/", this.runtime.IFluidHandleContext);
|
|
114
125
|
|
|
115
|
-
const
|
|
116
|
-
return
|
|
126
|
+
const baseGCDetailsP = new LazyPromise(async () => {
|
|
127
|
+
return getBaseGCDetails();
|
|
117
128
|
});
|
|
118
|
-
// Returns the base
|
|
129
|
+
// Returns the base GC details for the data store with the given id.
|
|
119
130
|
const dataStoreBaseGCDetails = async (dataStoreId: string) => {
|
|
120
|
-
const baseGCDetails = await
|
|
131
|
+
const baseGCDetails = await baseGCDetailsP;
|
|
121
132
|
return baseGCDetails.get(dataStoreId);
|
|
122
133
|
};
|
|
123
134
|
|
|
@@ -140,30 +151,41 @@ export class DataStores implements IDisposable {
|
|
|
140
151
|
}
|
|
141
152
|
// If we have a detached container, then create local data store contexts.
|
|
142
153
|
if (this.runtime.attachState !== AttachState.Detached) {
|
|
143
|
-
dataStoreContext = new
|
|
144
|
-
key,
|
|
145
|
-
value,
|
|
146
|
-
async () => dataStoreBaseGCDetails(key),
|
|
147
|
-
this.runtime,
|
|
148
|
-
this.runtime.storage,
|
|
149
|
-
this.runtime.scope,
|
|
150
|
-
this.getCreateChildSummarizerNodeFn(
|
|
154
|
+
dataStoreContext = new RemoteFluidDataStoreContext({
|
|
155
|
+
id: key,
|
|
156
|
+
snapshotTree: value,
|
|
157
|
+
getBaseGCDetails: async () => dataStoreBaseGCDetails(key),
|
|
158
|
+
runtime: this.runtime,
|
|
159
|
+
storage: this.runtime.storage,
|
|
160
|
+
scope: this.runtime.scope,
|
|
161
|
+
createSummarizerNodeFn: this.getCreateChildSummarizerNodeFn(
|
|
162
|
+
key,
|
|
163
|
+
{ type: CreateSummarizerNodeSource.FromSummary },
|
|
164
|
+
),
|
|
165
|
+
writeGCDataAtRoot: this.writeGCDataAtRoot,
|
|
166
|
+
disableIsolatedChannels: this.runtime.disableIsolatedChannels,
|
|
167
|
+
});
|
|
151
168
|
} else {
|
|
152
169
|
if (typeof value !== "object") {
|
|
153
170
|
throw new Error("Snapshot should be there to load from!!");
|
|
154
171
|
}
|
|
155
172
|
const snapshotTree = value;
|
|
156
|
-
dataStoreContext = new LocalFluidDataStoreContext(
|
|
157
|
-
key,
|
|
158
|
-
undefined,
|
|
159
|
-
this.runtime,
|
|
160
|
-
this.runtime.storage,
|
|
161
|
-
this.runtime.scope,
|
|
162
|
-
this.getCreateChildSummarizerNodeFn(
|
|
163
|
-
|
|
173
|
+
dataStoreContext = new LocalFluidDataStoreContext({
|
|
174
|
+
id: key,
|
|
175
|
+
pkg: undefined,
|
|
176
|
+
runtime: this.runtime,
|
|
177
|
+
storage: this.runtime.storage,
|
|
178
|
+
scope: this.runtime.scope,
|
|
179
|
+
createSummarizerNodeFn: this.getCreateChildSummarizerNodeFn(
|
|
180
|
+
key,
|
|
181
|
+
{ type: CreateSummarizerNodeSource.FromSummary },
|
|
182
|
+
),
|
|
183
|
+
bindChannelFn: (cr: IFluidDataStoreChannel) => this.bindFluidDataStore(cr),
|
|
164
184
|
snapshotTree,
|
|
165
|
-
undefined,
|
|
166
|
-
|
|
185
|
+
isRootDataStore: undefined,
|
|
186
|
+
writeGCDataAtRoot: this.writeGCDataAtRoot,
|
|
187
|
+
disableIsolatedChannels: this.runtime.disableIsolatedChannels,
|
|
188
|
+
});
|
|
167
189
|
}
|
|
168
190
|
this.contexts.addBoundOrRemoted(dataStoreContext);
|
|
169
191
|
}
|
|
@@ -179,6 +201,9 @@ export class DataStores implements IDisposable {
|
|
|
179
201
|
|
|
180
202
|
public processAttachMessage(message: ISequencedDocumentMessage, local: boolean) {
|
|
181
203
|
const attachMessage = message.contents as InboundAttachMessage;
|
|
204
|
+
|
|
205
|
+
this.dataStoresSinceLastGC.push(attachMessage.id);
|
|
206
|
+
|
|
182
207
|
// The local object has already been attached
|
|
183
208
|
if (local) {
|
|
184
209
|
assert(this.pendingAttach.has(attachMessage.id),
|
|
@@ -189,7 +214,7 @@ export class DataStores implements IDisposable {
|
|
|
189
214
|
}
|
|
190
215
|
|
|
191
216
|
// If a non-local operation then go and create the object, otherwise mark it as officially attached.
|
|
192
|
-
if (this.
|
|
217
|
+
if (this.alreadyProcessed(attachMessage.id)) {
|
|
193
218
|
// TODO: dataStoreId may require a different tag from PackageData #7488
|
|
194
219
|
const error = new DataCorruptionError(
|
|
195
220
|
"duplicateDataStoreCreatedWithExistingId",
|
|
@@ -211,17 +236,17 @@ export class DataStores implements IDisposable {
|
|
|
211
236
|
}
|
|
212
237
|
|
|
213
238
|
// Include the type of attach message which is the pkg of the store to be
|
|
214
|
-
// used by
|
|
239
|
+
// used by RemoteFluidDataStoreContext in case it is not in the snapshot.
|
|
215
240
|
const pkg = [attachMessage.type];
|
|
216
|
-
const
|
|
217
|
-
attachMessage.id,
|
|
241
|
+
const remoteFluidDataStoreContext = new RemoteFluidDataStoreContext({
|
|
242
|
+
id: attachMessage.id,
|
|
218
243
|
snapshotTree,
|
|
219
244
|
// New data stores begin with empty GC details since GC hasn't run on them yet.
|
|
220
|
-
async () => { return {}; },
|
|
221
|
-
this.runtime,
|
|
222
|
-
new BlobCacheStorageService(this.runtime.storage, flatBlobs),
|
|
223
|
-
this.runtime.scope,
|
|
224
|
-
this.getCreateChildSummarizerNodeFn(
|
|
245
|
+
getBaseGCDetails: async () => { return {}; },
|
|
246
|
+
runtime: this.runtime,
|
|
247
|
+
storage: new BlobCacheStorageService(this.runtime.storage, flatBlobs),
|
|
248
|
+
scope: this.runtime.scope,
|
|
249
|
+
createSummarizerNodeFn: this.getCreateChildSummarizerNodeFn(
|
|
225
250
|
attachMessage.id,
|
|
226
251
|
{
|
|
227
252
|
type: CreateSummarizerNodeSource.FromAttach,
|
|
@@ -233,14 +258,14 @@ export class DataStores implements IDisposable {
|
|
|
233
258
|
this.runtime.disableIsolatedChannels,
|
|
234
259
|
)],
|
|
235
260
|
},
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
261
|
+
},
|
|
262
|
+
),
|
|
263
|
+
writeGCDataAtRoot: this.writeGCDataAtRoot,
|
|
264
|
+
disableIsolatedChannels: this.runtime.disableIsolatedChannels,
|
|
265
|
+
pkg,
|
|
266
|
+
});
|
|
240
267
|
|
|
241
|
-
|
|
242
|
-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
243
|
-
Promise.resolve().then(async () => remotedFluidDataStoreContext.realize());
|
|
268
|
+
this.contexts.addBoundOrRemoted(remoteFluidDataStoreContext);
|
|
244
269
|
}
|
|
245
270
|
|
|
246
271
|
public processAliasMessage(
|
|
@@ -266,15 +291,7 @@ export class DataStores implements IDisposable {
|
|
|
266
291
|
}
|
|
267
292
|
|
|
268
293
|
private processAliasMessageCore(aliasMessage: IDataStoreAliasMessage): boolean {
|
|
269
|
-
|
|
270
|
-
if (existingMapping !== undefined) {
|
|
271
|
-
return false;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
// Unlikely scenario, but we may receive an alias OP with the alias value
|
|
275
|
-
// equal to one of the ids supplied to `createRootDataStore` in the past
|
|
276
|
-
const maybeContextWithAliasAsId = this.contexts.get(aliasMessage.alias);
|
|
277
|
-
if (maybeContextWithAliasAsId !== undefined) {
|
|
294
|
+
if (this.alreadyProcessed(aliasMessage.alias)) {
|
|
278
295
|
return false;
|
|
279
296
|
}
|
|
280
297
|
|
|
@@ -292,6 +309,10 @@ export class DataStores implements IDisposable {
|
|
|
292
309
|
return true;
|
|
293
310
|
}
|
|
294
311
|
|
|
312
|
+
private alreadyProcessed(id: string): boolean {
|
|
313
|
+
return this.aliasMap.get(id) !== undefined || this.contexts.get(id) !== undefined;
|
|
314
|
+
}
|
|
315
|
+
|
|
295
316
|
public bindFluidDataStore(fluidDataStoreRuntime: IFluidDataStoreChannel): void {
|
|
296
317
|
const id = fluidDataStoreRuntime.id;
|
|
297
318
|
const localContext = this.contexts.getUnbound(id);
|
|
@@ -317,33 +338,44 @@ export class DataStores implements IDisposable {
|
|
|
317
338
|
isRoot: boolean,
|
|
318
339
|
id = uuid()): IFluidDataStoreContextDetached
|
|
319
340
|
{
|
|
320
|
-
const context = new LocalDetachedFluidDataStoreContext(
|
|
341
|
+
const context = new LocalDetachedFluidDataStoreContext({
|
|
321
342
|
id,
|
|
322
343
|
pkg,
|
|
323
|
-
this.runtime,
|
|
324
|
-
this.runtime.storage,
|
|
325
|
-
this.runtime.scope,
|
|
326
|
-
this.getCreateChildSummarizerNodeFn(
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
344
|
+
runtime: this.runtime,
|
|
345
|
+
storage: this.runtime.storage,
|
|
346
|
+
scope: this.runtime.scope,
|
|
347
|
+
createSummarizerNodeFn: this.getCreateChildSummarizerNodeFn(
|
|
348
|
+
id,
|
|
349
|
+
{ type: CreateSummarizerNodeSource.Local },
|
|
350
|
+
),
|
|
351
|
+
bindChannelFn: (cr: IFluidDataStoreChannel) => this.bindFluidDataStore(cr),
|
|
352
|
+
snapshotTree: undefined,
|
|
353
|
+
isRootDataStore: isRoot,
|
|
354
|
+
writeGCDataAtRoot: this.writeGCDataAtRoot,
|
|
355
|
+
disableIsolatedChannels: this.runtime.disableIsolatedChannels,
|
|
356
|
+
});
|
|
330
357
|
this.contexts.addUnbound(context);
|
|
331
358
|
return context;
|
|
332
359
|
}
|
|
333
360
|
|
|
334
361
|
public _createFluidDataStoreContext(pkg: string[], id: string, isRoot: boolean, props?: any) {
|
|
335
|
-
const context = new LocalFluidDataStoreContext(
|
|
362
|
+
const context = new LocalFluidDataStoreContext({
|
|
336
363
|
id,
|
|
337
364
|
pkg,
|
|
338
|
-
this.runtime,
|
|
339
|
-
this.runtime.storage,
|
|
340
|
-
this.runtime.scope,
|
|
341
|
-
this.getCreateChildSummarizerNodeFn(
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
365
|
+
runtime: this.runtime,
|
|
366
|
+
storage: this.runtime.storage,
|
|
367
|
+
scope: this.runtime.scope,
|
|
368
|
+
createSummarizerNodeFn: this.getCreateChildSummarizerNodeFn(
|
|
369
|
+
id,
|
|
370
|
+
{ type: CreateSummarizerNodeSource.Local },
|
|
371
|
+
),
|
|
372
|
+
bindChannelFn: (cr: IFluidDataStoreChannel) => this.bindFluidDataStore(cr),
|
|
373
|
+
snapshotTree: undefined,
|
|
374
|
+
isRootDataStore: isRoot,
|
|
375
|
+
writeGCDataAtRoot: this.writeGCDataAtRoot,
|
|
376
|
+
disableIsolatedChannels: this.runtime.disableIsolatedChannels,
|
|
377
|
+
createProps: props,
|
|
378
|
+
});
|
|
347
379
|
this.contexts.addUnbound(context);
|
|
348
380
|
return context;
|
|
349
381
|
}
|
|
@@ -498,6 +530,24 @@ export class DataStores implements IDisposable {
|
|
|
498
530
|
return builder.getSummaryTree();
|
|
499
531
|
}
|
|
500
532
|
|
|
533
|
+
/**
|
|
534
|
+
* Before GC runs, called by the garbage collector to update any pending GC state.
|
|
535
|
+
* The garbage collector needs to know all outbound references that are added. Since root data stores are not
|
|
536
|
+
* explicitly marked as referenced, notify GC of new root data stores that were added since the last GC run.
|
|
537
|
+
*/
|
|
538
|
+
public async updateStateBeforeGC(): Promise<void> {
|
|
539
|
+
for (const id of this.dataStoresSinceLastGC) {
|
|
540
|
+
const context = this.contexts.get(id);
|
|
541
|
+
assert(context !== undefined, 0x2b6 /* `Missing data store context with id ${id}` */);
|
|
542
|
+
if (await context.isRoot()) {
|
|
543
|
+
// A root data store is basically a reference from the container runtime to the data store.
|
|
544
|
+
const handle = new FluidObjectHandle(context, id, this.runtime.IFluidHandleContext);
|
|
545
|
+
this.runtime.addedGCOutboundReference(this.containerRuntimeHandle, handle);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
this.dataStoresSinceLastGC = [];
|
|
549
|
+
}
|
|
550
|
+
|
|
501
551
|
/**
|
|
502
552
|
* Generates data used for garbage collection. It does the following:
|
|
503
553
|
* 1. Calls into each child data store context to get its GC data.
|