@fluidframework/container-runtime 2.0.0-internal.2.1.1 → 2.0.0-internal.2.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/.eslintrc.js +1 -1
- package/dist/blobManager.d.ts +20 -5
- package/dist/blobManager.d.ts.map +1 -1
- package/dist/blobManager.js +57 -15
- package/dist/blobManager.js.map +1 -1
- package/dist/containerRuntime.d.ts +39 -40
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +115 -278
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStoreContext.d.ts +3 -1
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +21 -3
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStores.d.ts +8 -5
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/dataStores.js +26 -13
- package/dist/dataStores.js.map +1 -1
- package/dist/garbageCollection.d.ts +15 -17
- package/dist/garbageCollection.d.ts.map +1 -1
- package/dist/garbageCollection.js +92 -106
- package/dist/garbageCollection.js.map +1 -1
- package/dist/garbageCollectionConstants.d.ts +19 -0
- package/dist/garbageCollectionConstants.d.ts.map +1 -0
- package/dist/garbageCollectionConstants.js +34 -0
- package/dist/garbageCollectionConstants.js.map +1 -0
- package/dist/gcSweepReadyUsageDetection.js +2 -2
- package/dist/gcSweepReadyUsageDetection.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -6
- package/dist/index.js.map +1 -1
- package/dist/opLifecycle/batchManager.d.ts +30 -0
- package/dist/opLifecycle/batchManager.d.ts.map +1 -0
- package/dist/{batchManager.js → opLifecycle/batchManager.js} +25 -10
- package/dist/opLifecycle/batchManager.js.map +1 -0
- package/dist/opLifecycle/definitions.d.ts +40 -0
- package/dist/opLifecycle/definitions.d.ts.map +1 -0
- package/dist/opLifecycle/definitions.js +7 -0
- package/dist/opLifecycle/definitions.js.map +1 -0
- package/dist/opLifecycle/index.d.ts +12 -0
- package/dist/opLifecycle/index.d.ts.map +1 -0
- package/dist/opLifecycle/index.js +21 -0
- package/dist/opLifecycle/index.js.map +1 -0
- package/dist/opLifecycle/opCompressor.d.ts +18 -0
- package/dist/opLifecycle/opCompressor.d.ts.map +1 -0
- package/dist/opLifecycle/opCompressor.js +53 -0
- package/dist/opLifecycle/opCompressor.js.map +1 -0
- package/dist/opLifecycle/opDecompressor.d.ts +20 -0
- package/dist/opLifecycle/opDecompressor.d.ts.map +1 -0
- package/dist/opLifecycle/opDecompressor.js +72 -0
- package/dist/opLifecycle/opDecompressor.js.map +1 -0
- package/dist/opLifecycle/opSplitter.d.ts +17 -0
- package/dist/opLifecycle/opSplitter.d.ts.map +1 -0
- package/dist/opLifecycle/opSplitter.js +61 -0
- package/dist/opLifecycle/opSplitter.js.map +1 -0
- package/dist/opLifecycle/outbox.d.ts +47 -0
- package/dist/opLifecycle/outbox.d.ts.map +1 -0
- package/dist/opLifecycle/outbox.js +153 -0
- package/dist/opLifecycle/outbox.js.map +1 -0
- package/dist/opLifecycle/remoteMessageProcessor.d.ts +26 -0
- package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -0
- package/dist/opLifecycle/remoteMessageProcessor.js +81 -0
- package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -0
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/summaryFormat.js +2 -2
- package/dist/summaryFormat.js.map +1 -1
- package/lib/blobManager.d.ts +20 -5
- package/lib/blobManager.d.ts.map +1 -1
- package/lib/blobManager.js +59 -17
- package/lib/blobManager.js.map +1 -1
- package/lib/containerRuntime.d.ts +39 -40
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +113 -275
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStoreContext.d.ts +3 -1
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +23 -5
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStores.d.ts +8 -5
- package/lib/dataStores.d.ts.map +1 -1
- package/lib/dataStores.js +28 -15
- package/lib/dataStores.js.map +1 -1
- package/lib/garbageCollection.d.ts +15 -17
- package/lib/garbageCollection.d.ts.map +1 -1
- package/lib/garbageCollection.js +72 -86
- package/lib/garbageCollection.js.map +1 -1
- package/lib/garbageCollectionConstants.d.ts +19 -0
- package/lib/garbageCollectionConstants.d.ts.map +1 -0
- package/lib/garbageCollectionConstants.js +31 -0
- package/lib/garbageCollectionConstants.js.map +1 -0
- package/lib/gcSweepReadyUsageDetection.js +1 -1
- package/lib/gcSweepReadyUsageDetection.js.map +1 -1
- package/lib/index.d.ts +4 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +3 -2
- package/lib/index.js.map +1 -1
- package/lib/opLifecycle/batchManager.d.ts +30 -0
- package/lib/opLifecycle/batchManager.d.ts.map +1 -0
- package/lib/{batchManager.js → opLifecycle/batchManager.js} +25 -10
- package/lib/opLifecycle/batchManager.js.map +1 -0
- package/lib/opLifecycle/definitions.d.ts +40 -0
- package/lib/opLifecycle/definitions.d.ts.map +1 -0
- package/lib/opLifecycle/definitions.js +6 -0
- package/lib/opLifecycle/definitions.js.map +1 -0
- package/lib/opLifecycle/index.d.ts +12 -0
- package/lib/opLifecycle/index.d.ts.map +1 -0
- package/lib/opLifecycle/index.js +11 -0
- package/lib/opLifecycle/index.js.map +1 -0
- package/lib/opLifecycle/opCompressor.d.ts +18 -0
- package/lib/opLifecycle/opCompressor.d.ts.map +1 -0
- package/lib/opLifecycle/opCompressor.js +49 -0
- package/lib/opLifecycle/opCompressor.js.map +1 -0
- package/lib/opLifecycle/opDecompressor.d.ts +20 -0
- package/lib/opLifecycle/opDecompressor.d.ts.map +1 -0
- package/lib/opLifecycle/opDecompressor.js +68 -0
- package/lib/opLifecycle/opDecompressor.js.map +1 -0
- package/lib/opLifecycle/opSplitter.d.ts +17 -0
- package/lib/opLifecycle/opSplitter.d.ts.map +1 -0
- package/lib/opLifecycle/opSplitter.js +57 -0
- package/lib/opLifecycle/opSplitter.js.map +1 -0
- package/lib/opLifecycle/outbox.d.ts +47 -0
- package/lib/opLifecycle/outbox.d.ts.map +1 -0
- package/lib/opLifecycle/outbox.js +149 -0
- package/lib/opLifecycle/outbox.js.map +1 -0
- package/lib/opLifecycle/remoteMessageProcessor.d.ts +26 -0
- package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -0
- package/lib/opLifecycle/remoteMessageProcessor.js +76 -0
- package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -0
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/summaryFormat.js +1 -1
- package/lib/summaryFormat.js.map +1 -1
- package/package.json +35 -21
- package/prettier.config.cjs +8 -0
- package/src/blobManager.ts +74 -19
- package/src/containerRuntime.ts +144 -341
- package/src/dataStoreContext.ts +33 -5
- package/src/dataStores.ts +32 -16
- package/src/garbageCollection.ts +106 -82
- package/src/garbageCollectionConstants.ts +35 -0
- package/src/gcSweepReadyUsageDetection.ts +1 -1
- package/src/index.ts +6 -4
- package/src/{batchManager.ts → opLifecycle/batchManager.ts} +41 -23
- package/src/opLifecycle/definitions.ts +44 -0
- package/src/opLifecycle/index.ts +17 -0
- package/src/opLifecycle/opCompressor.ts +64 -0
- package/src/opLifecycle/opDecompressor.ts +84 -0
- package/src/opLifecycle/opSplitter.ts +78 -0
- package/src/opLifecycle/outbox.ts +204 -0
- package/src/opLifecycle/remoteMessageProcessor.ts +90 -0
- package/src/packageVersion.ts +1 -1
- package/src/summaryFormat.ts +1 -1
- package/dist/batchManager.d.ts +0 -36
- package/dist/batchManager.d.ts.map +0 -1
- package/dist/batchManager.js.map +0 -1
- package/lib/batchManager.d.ts +0 -36
- package/lib/batchManager.d.ts.map +0 -1
- package/lib/batchManager.js.map +0 -1
package/src/blobManager.ts
CHANGED
|
@@ -7,18 +7,24 @@ import { v4 as uuid } from "uuid";
|
|
|
7
7
|
import { IFluidHandle, IFluidHandleContext } from "@fluidframework/core-interfaces";
|
|
8
8
|
import { IDocumentStorageService } from "@fluidframework/driver-definitions";
|
|
9
9
|
import { ICreateBlobResponse, ISequencedDocumentMessage, ISnapshotTree } from "@fluidframework/protocol-definitions";
|
|
10
|
-
import {
|
|
11
|
-
|
|
10
|
+
import {
|
|
11
|
+
createResponseError,
|
|
12
|
+
generateHandleContextPath,
|
|
13
|
+
responseToException,
|
|
14
|
+
SummaryTreeBuilder,
|
|
15
|
+
} from "@fluidframework/runtime-utils";
|
|
12
16
|
import { assert, bufferToString, Deferred, stringToBuffer, TypedEventEmitter } from "@fluidframework/common-utils";
|
|
13
17
|
import { IContainerRuntime, IContainerRuntimeEvents } from "@fluidframework/container-runtime-definitions";
|
|
14
18
|
import { AttachState } from "@fluidframework/container-definitions";
|
|
15
|
-
import { ChildLogger, PerformanceEvent } from "@fluidframework/telemetry-utils";
|
|
19
|
+
import { ChildLogger, loggerToMonitoringContext, MonitoringContext, PerformanceEvent } from "@fluidframework/telemetry-utils";
|
|
16
20
|
import {
|
|
17
21
|
IGarbageCollectionData,
|
|
18
22
|
ISummaryTreeWithStats,
|
|
19
23
|
ITelemetryContext,
|
|
20
24
|
} from "@fluidframework/runtime-definitions";
|
|
21
25
|
import { Throttler, formExponentialFn, IThrottler } from "./throttler";
|
|
26
|
+
import { summarizerClientType } from "./summarizerClientElection";
|
|
27
|
+
import { throwOnTombstoneUsageKey } from "./garbageCollectionConstants";
|
|
22
28
|
|
|
23
29
|
/**
|
|
24
30
|
* This class represents blob (long string)
|
|
@@ -83,7 +89,7 @@ export interface IBlobManagerLoadInfo {
|
|
|
83
89
|
// Restrict the IContainerRuntime interface to the subset required by BlobManager. This helps to make
|
|
84
90
|
// the contract explicit and reduces the amount of mocking required for tests.
|
|
85
91
|
export type IBlobManagerRuntime =
|
|
86
|
-
Pick<IContainerRuntime, "attachState" | "connected" | "logger"> & TypedEventEmitter<IContainerRuntimeEvents>;
|
|
92
|
+
Pick<IContainerRuntime, "attachState" | "connected" | "logger" | "clientDetails"> & TypedEventEmitter<IContainerRuntimeEvents>;
|
|
87
93
|
|
|
88
94
|
// Note that while offline we "submit" an op before uploading the blob, but we always
|
|
89
95
|
// expect blobs to be uploaded before we actually see the op round-trip
|
|
@@ -107,7 +113,7 @@ export interface IPendingBlobs { [id: string]: { blob: string; }; }
|
|
|
107
113
|
export class BlobManager {
|
|
108
114
|
public static readonly basePath = "_blobs";
|
|
109
115
|
private static readonly redirectTableBlobName = ".redirectTable";
|
|
110
|
-
private readonly
|
|
116
|
+
private readonly mc: MonitoringContext;
|
|
111
117
|
|
|
112
118
|
/**
|
|
113
119
|
* Map of local (offline/detached) IDs to storage IDs. Contains identity entries
|
|
@@ -137,6 +143,14 @@ export class BlobManager {
|
|
|
137
143
|
formExponentialFn({ coefficient: 20, initialDelay: 0 }),
|
|
138
144
|
));
|
|
139
145
|
|
|
146
|
+
/** If true, throw an error when a tombstone attachment blob is retrieved. */
|
|
147
|
+
private readonly throwOnTombstoneUsage: boolean;
|
|
148
|
+
/**
|
|
149
|
+
* This stores ides of tombstoned blobs.
|
|
150
|
+
* Tombstone is a temporary feature that imitates a blob getting swept by garbage collection.
|
|
151
|
+
*/
|
|
152
|
+
private readonly tombstonedBlobs: Set<string> = new Set();
|
|
153
|
+
|
|
140
154
|
constructor(
|
|
141
155
|
private readonly routeContext: IFluidHandleContext,
|
|
142
156
|
snapshot: IBlobManagerLoadInfo,
|
|
@@ -158,7 +172,12 @@ export class BlobManager {
|
|
|
158
172
|
private readonly runtime: IBlobManagerRuntime,
|
|
159
173
|
stashedBlobs: IPendingBlobs = {},
|
|
160
174
|
) {
|
|
161
|
-
this.
|
|
175
|
+
this.mc = loggerToMonitoringContext(ChildLogger.create(this.runtime.logger, "BlobManager"));
|
|
176
|
+
// Read the feature flag that tells whether to throw when a tombstone blob is requested.
|
|
177
|
+
this.throwOnTombstoneUsage =
|
|
178
|
+
this.mc.config.getBoolean(throwOnTombstoneUsageKey) === true &&
|
|
179
|
+
this.runtime.clientDetails.type !== summarizerClientType;
|
|
180
|
+
|
|
162
181
|
this.runtime.on("disconnected", () => this.onDisconnected());
|
|
163
182
|
this.redirectTable = this.load(snapshot);
|
|
164
183
|
|
|
@@ -189,7 +208,7 @@ export class BlobManager {
|
|
|
189
208
|
public async onConnected() {
|
|
190
209
|
this.retryThrottler.cancel();
|
|
191
210
|
const pendingUploads = this.pendingOfflineUploads.map(async (e) => e.uploadP);
|
|
192
|
-
await PerformanceEvent.timedExecAsync(this.logger, {
|
|
211
|
+
await PerformanceEvent.timedExecAsync(this.mc.logger, {
|
|
193
212
|
eventName: "BlobUploadOnConnected",
|
|
194
213
|
count: pendingUploads.length,
|
|
195
214
|
}, async () => Promise.all(pendingUploads),
|
|
@@ -239,6 +258,18 @@ export class BlobManager {
|
|
|
239
258
|
}
|
|
240
259
|
|
|
241
260
|
public async getBlob(blobId: string): Promise<ArrayBufferLike> {
|
|
261
|
+
const request = { url: blobId };
|
|
262
|
+
if (this.tombstonedBlobs.has(blobId) ) {
|
|
263
|
+
const error = responseToException(createResponseError(404, "Blob removed by gc", request), request);
|
|
264
|
+
this.mc.logger.sendErrorEvent({
|
|
265
|
+
eventName: "GC_Tombstone_Blob_Requested",
|
|
266
|
+
url: request.url,
|
|
267
|
+
}, error);
|
|
268
|
+
if (this.throwOnTombstoneUsage) {
|
|
269
|
+
throw error;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
242
273
|
const pending = this.pendingBlobs.get(blobId);
|
|
243
274
|
if (pending) {
|
|
244
275
|
return pending.blob;
|
|
@@ -259,7 +290,7 @@ export class BlobManager {
|
|
|
259
290
|
this.gcNodeUpdated(this.getBlobGCNodePath(blobId));
|
|
260
291
|
|
|
261
292
|
return PerformanceEvent.timedExecAsync(
|
|
262
|
-
this.logger,
|
|
293
|
+
this.mc.logger,
|
|
263
294
|
{ eventName: "AttachmentReadBlob", id: storageId },
|
|
264
295
|
async () => {
|
|
265
296
|
return this.getStorage().readBlob(storageId);
|
|
@@ -292,7 +323,7 @@ export class BlobManager {
|
|
|
292
323
|
}
|
|
293
324
|
if (this.runtime.attachState === AttachState.Attaching) {
|
|
294
325
|
// blob upload is not supported in "Attaching" state
|
|
295
|
-
this.logger.sendTelemetryEvent({ eventName: "CreateBlobWhileAttaching" });
|
|
326
|
+
this.mc.logger.sendTelemetryEvent({ eventName: "CreateBlobWhileAttaching" });
|
|
296
327
|
await new Promise<void>((resolve) => this.runtime.once("attached", resolve));
|
|
297
328
|
}
|
|
298
329
|
assert(this.runtime.attachState === AttachState.Attached,
|
|
@@ -314,7 +345,7 @@ export class BlobManager {
|
|
|
314
345
|
|
|
315
346
|
private async uploadBlob(localId: string, blob: ArrayBufferLike): Promise<ICreateBlobResponse> {
|
|
316
347
|
return PerformanceEvent.timedExecAsync(
|
|
317
|
-
this.logger,
|
|
348
|
+
this.mc.logger,
|
|
318
349
|
{ eventName: "createBlob" },
|
|
319
350
|
async () => this.getStorage().createBlob(blob),
|
|
320
351
|
{ end: true, cancel: this.runtime.connected ? "error" : "generic" },
|
|
@@ -351,7 +382,7 @@ export class BlobManager {
|
|
|
351
382
|
}
|
|
352
383
|
} else {
|
|
353
384
|
// connected to storage but not ordering service?
|
|
354
|
-
this.logger.sendTelemetryEvent({ eventName: "BlobUploadSuccessWhileDisconnected" });
|
|
385
|
+
this.mc.logger.sendTelemetryEvent({ eventName: "BlobUploadSuccessWhileDisconnected" });
|
|
355
386
|
if (entry.status === PendingBlobStatus.OnlinePendingUpload) {
|
|
356
387
|
this.transitionToOffline(localId);
|
|
357
388
|
}
|
|
@@ -477,7 +508,7 @@ export class BlobManager {
|
|
|
477
508
|
* Load a set of previously attached blob IDs and redirect table from a previous snapshot.
|
|
478
509
|
*/
|
|
479
510
|
private load(snapshot: IBlobManagerLoadInfo): Map<string, string | undefined> {
|
|
480
|
-
this.logger.sendTelemetryEvent({
|
|
511
|
+
this.mc.logger.sendTelemetryEvent({
|
|
481
512
|
eventName: "AttachmentBlobsLoaded",
|
|
482
513
|
count: snapshot.ids?.length ?? 0,
|
|
483
514
|
redirectTable: snapshot.redirectTable?.length,
|
|
@@ -524,10 +555,32 @@ export class BlobManager {
|
|
|
524
555
|
}
|
|
525
556
|
|
|
526
557
|
/**
|
|
527
|
-
*
|
|
528
|
-
* @param
|
|
558
|
+
* This is called to update blobs whose routes are used. The used blobs are removed from the tombstone list.
|
|
559
|
+
* @param usedRoutes - The routes of the blob nodes that are used.
|
|
529
560
|
*/
|
|
530
|
-
public
|
|
561
|
+
public updateUsedRoutes(usedRoutes: string[]) {
|
|
562
|
+
// The routes or blob node paths are in the same format as returned in getGCData -
|
|
563
|
+
// `/<BlobManager.basePath>/<blobId>`.
|
|
564
|
+
for (const route of usedRoutes) {
|
|
565
|
+
const pathParts = route.split("/");
|
|
566
|
+
assert(
|
|
567
|
+
pathParts.length === 3 && pathParts[1] === BlobManager.basePath,
|
|
568
|
+
0x4bc /* Invalid blob node id in used routes. */,
|
|
569
|
+
);
|
|
570
|
+
const blobId = pathParts[2];
|
|
571
|
+
// Un-tombstone the blob if it was marked tombstone.
|
|
572
|
+
this.tombstonedBlobs.delete(blobId);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* This is called to update blobs whose routes are unused. The unused blobs are either deleted or marked as
|
|
578
|
+
* tombstones.
|
|
579
|
+
* @param unusedRoutes - The routes of the blob nodes that are unused.
|
|
580
|
+
* @param tombstone - if true, the objects corresponding to unused routes are marked tombstones. Otherwise, they
|
|
581
|
+
* are deleted.
|
|
582
|
+
*/
|
|
583
|
+
public updateUnusedRoutes(unusedRoutes: string[], tombstone: boolean): void {
|
|
531
584
|
// The routes or blob node paths are in the same format as returned in getGCData -
|
|
532
585
|
// `/<BlobManager.basePath>/<blobId>`.
|
|
533
586
|
for (const route of unusedRoutes) {
|
|
@@ -538,11 +591,13 @@ export class BlobManager {
|
|
|
538
591
|
);
|
|
539
592
|
const blobId = pathParts[2];
|
|
540
593
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
594
|
+
if (tombstone) {
|
|
595
|
+
// If tombstone is set, add this blob to the tombstone list.
|
|
596
|
+
this.tombstonedBlobs.add(blobId);
|
|
597
|
+
} else {
|
|
598
|
+
// The unused blobId could be a localId. If so, remove it from the redirect table and continue. The
|
|
599
|
+
// corresponding storageId may still be used either directly or via other localIds.
|
|
544
600
|
this.redirectTable.delete(blobId);
|
|
545
|
-
continue;
|
|
546
601
|
}
|
|
547
602
|
}
|
|
548
603
|
}
|