@fluidframework/container-runtime 0.58.2001 → 0.59.2000-61729
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/blobManager.d.ts +15 -2
- package/dist/blobManager.d.ts.map +1 -1
- package/dist/blobManager.js +65 -9
- package/dist/blobManager.js.map +1 -1
- package/dist/connectionTelemetry.d.ts.map +1 -1
- package/dist/connectionTelemetry.js +63 -23
- package/dist/connectionTelemetry.js.map +1 -1
- package/dist/containerRuntime.d.ts +39 -7
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +161 -29
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStore.js +8 -1
- package/dist/dataStore.js.map +1 -1
- package/dist/dataStoreContext.d.ts +9 -3
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +22 -6
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStores.d.ts +13 -5
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/dataStores.js +39 -18
- package/dist/dataStores.js.map +1 -1
- package/dist/deltaScheduler.d.ts +4 -5
- package/dist/deltaScheduler.d.ts.map +1 -1
- package/dist/deltaScheduler.js +54 -35
- package/dist/deltaScheduler.js.map +1 -1
- package/dist/garbageCollection.d.ts +31 -27
- package/dist/garbageCollection.d.ts.map +1 -1
- package/dist/garbageCollection.js +76 -75
- package/dist/garbageCollection.js.map +1 -1
- package/dist/opTelemetry.d.ts +22 -0
- package/dist/opTelemetry.d.ts.map +1 -0
- package/dist/opTelemetry.js +59 -0
- package/dist/opTelemetry.js.map +1 -0
- package/dist/orderedClientElection.d.ts +57 -6
- package/dist/orderedClientElection.d.ts.map +1 -1
- package/dist/orderedClientElection.js +141 -26
- 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/summarizerClientElection.d.ts +2 -0
- package/dist/summarizerClientElection.d.ts.map +1 -1
- package/dist/summarizerClientElection.js +15 -2
- package/dist/summarizerClientElection.js.map +1 -1
- package/dist/summarizerTypes.d.ts +9 -0
- package/dist/summarizerTypes.d.ts.map +1 -1
- package/dist/summarizerTypes.js.map +1 -1
- package/dist/summaryGenerator.d.ts.map +1 -1
- package/dist/summaryGenerator.js +3 -4
- package/dist/summaryGenerator.js.map +1 -1
- package/dist/summaryManager.d.ts.map +1 -1
- package/dist/summaryManager.js +14 -3
- package/dist/summaryManager.js.map +1 -1
- package/lib/blobManager.d.ts +15 -2
- package/lib/blobManager.d.ts.map +1 -1
- package/lib/blobManager.js +66 -10
- package/lib/blobManager.js.map +1 -1
- package/lib/connectionTelemetry.d.ts.map +1 -1
- package/lib/connectionTelemetry.js +63 -23
- package/lib/connectionTelemetry.js.map +1 -1
- package/lib/containerRuntime.d.ts +39 -7
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +163 -31
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStore.js +8 -1
- package/lib/dataStore.js.map +1 -1
- package/lib/dataStoreContext.d.ts +9 -3
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +22 -6
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStores.d.ts +13 -5
- package/lib/dataStores.d.ts.map +1 -1
- package/lib/dataStores.js +39 -18
- package/lib/dataStores.js.map +1 -1
- package/lib/deltaScheduler.d.ts +4 -5
- package/lib/deltaScheduler.d.ts.map +1 -1
- package/lib/deltaScheduler.js +54 -35
- package/lib/deltaScheduler.js.map +1 -1
- package/lib/garbageCollection.d.ts +31 -27
- package/lib/garbageCollection.d.ts.map +1 -1
- package/lib/garbageCollection.js +75 -74
- package/lib/garbageCollection.js.map +1 -1
- package/lib/opTelemetry.d.ts +22 -0
- package/lib/opTelemetry.d.ts.map +1 -0
- package/lib/opTelemetry.js +55 -0
- package/lib/opTelemetry.js.map +1 -0
- package/lib/orderedClientElection.d.ts +57 -6
- package/lib/orderedClientElection.d.ts.map +1 -1
- package/lib/orderedClientElection.js +141 -26
- 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/summarizerClientElection.d.ts +2 -0
- package/lib/summarizerClientElection.d.ts.map +1 -1
- package/lib/summarizerClientElection.js +15 -2
- package/lib/summarizerClientElection.js.map +1 -1
- package/lib/summarizerTypes.d.ts +9 -0
- package/lib/summarizerTypes.d.ts.map +1 -1
- package/lib/summarizerTypes.js.map +1 -1
- package/lib/summaryGenerator.d.ts.map +1 -1
- package/lib/summaryGenerator.js +3 -4
- package/lib/summaryGenerator.js.map +1 -1
- package/lib/summaryManager.d.ts.map +1 -1
- package/lib/summaryManager.js +14 -3
- package/lib/summaryManager.js.map +1 -1
- package/package.json +63 -19
- package/src/blobManager.ts +78 -11
- package/src/connectionTelemetry.ts +110 -19
- package/src/containerRuntime.ts +191 -36
- package/src/dataStore.ts +7 -1
- package/src/dataStoreContext.ts +22 -7
- package/src/dataStores.ts +40 -19
- package/src/deltaScheduler.ts +65 -39
- package/src/garbageCollection.ts +92 -78
- package/src/opTelemetry.ts +71 -0
- package/src/orderedClientElection.ts +155 -25
- package/src/packageVersion.ts +1 -1
- package/src/summarizerClientElection.ts +15 -2
- package/src/summarizerTypes.ts +9 -0
- package/src/summaryGenerator.ts +10 -8
- package/src/summaryManager.ts +15 -4
package/src/dataStores.ts
CHANGED
|
@@ -18,7 +18,6 @@ import {
|
|
|
18
18
|
CreateSummarizerNodeSource,
|
|
19
19
|
IAttachMessage,
|
|
20
20
|
IEnvelope,
|
|
21
|
-
IFluidDataStoreChannel,
|
|
22
21
|
IFluidDataStoreContextDetached,
|
|
23
22
|
IGarbageCollectionData,
|
|
24
23
|
IGarbageCollectionDetailsBase,
|
|
@@ -157,7 +156,7 @@ export class DataStores implements IDisposable {
|
|
|
157
156
|
key,
|
|
158
157
|
{ type: CreateSummarizerNodeSource.FromSummary },
|
|
159
158
|
),
|
|
160
|
-
|
|
159
|
+
makeLocallyVisibleFn: () => this.makeDataStoreLocallyVisible(key),
|
|
161
160
|
snapshotTree,
|
|
162
161
|
isRootDataStore: undefined,
|
|
163
162
|
writeGCDataAtRoot: this.writeGCDataAtRoot,
|
|
@@ -291,14 +290,20 @@ export class DataStores implements IDisposable {
|
|
|
291
290
|
return this.aliasMap.get(id) !== undefined || this.contexts.get(id) !== undefined;
|
|
292
291
|
}
|
|
293
292
|
|
|
294
|
-
|
|
295
|
-
|
|
293
|
+
/**
|
|
294
|
+
* Make the data stores locally visible in the container graph by moving the data store context from unbound to
|
|
295
|
+
* bound list. This data store can now be reached from the root.
|
|
296
|
+
* @param id - The id of the data store context to make visible.
|
|
297
|
+
*/
|
|
298
|
+
private makeDataStoreLocallyVisible(id: string): void {
|
|
296
299
|
const localContext = this.contexts.getUnbound(id);
|
|
297
300
|
assert(!!localContext, 0x15f /* "Could not find unbound context to bind" */);
|
|
298
301
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
+
/**
|
|
303
|
+
* If the container is not detached, it is globally visible to all clients. This data store should also be
|
|
304
|
+
* globally visible. Move it to attaching state and send an "attach" op for it.
|
|
305
|
+
* If the container is detached, this data store will be part of the summary that makes the container attached.
|
|
306
|
+
*/
|
|
302
307
|
if (this.runtime.attachState !== AttachState.Detached) {
|
|
303
308
|
localContext.emit("attaching");
|
|
304
309
|
const message = localContext.generateAttachMessage();
|
|
@@ -308,7 +313,7 @@ export class DataStores implements IDisposable {
|
|
|
308
313
|
this.attachOpFiredForDataStore.add(id);
|
|
309
314
|
}
|
|
310
315
|
|
|
311
|
-
this.contexts.bind(
|
|
316
|
+
this.contexts.bind(id);
|
|
312
317
|
}
|
|
313
318
|
|
|
314
319
|
public createDetachedDataStoreCore(
|
|
@@ -326,7 +331,7 @@ export class DataStores implements IDisposable {
|
|
|
326
331
|
id,
|
|
327
332
|
{ type: CreateSummarizerNodeSource.Local },
|
|
328
333
|
),
|
|
329
|
-
|
|
334
|
+
makeLocallyVisibleFn: () => this.makeDataStoreLocallyVisible(id),
|
|
330
335
|
snapshotTree: undefined,
|
|
331
336
|
isRootDataStore: isRoot,
|
|
332
337
|
writeGCDataAtRoot: this.writeGCDataAtRoot,
|
|
@@ -347,7 +352,7 @@ export class DataStores implements IDisposable {
|
|
|
347
352
|
id,
|
|
348
353
|
{ type: CreateSummarizerNodeSource.Local },
|
|
349
354
|
),
|
|
350
|
-
|
|
355
|
+
makeLocallyVisibleFn: () => this.makeDataStoreLocallyVisible(id),
|
|
351
356
|
snapshotTree: undefined,
|
|
352
357
|
isRootDataStore: isRoot,
|
|
353
358
|
writeGCDataAtRoot: this.writeGCDataAtRoot,
|
|
@@ -587,7 +592,14 @@ export class DataStores implements IDisposable {
|
|
|
587
592
|
*/
|
|
588
593
|
public deleteUnusedRoutes(unusedRoutes: string[]) {
|
|
589
594
|
for (const route of unusedRoutes) {
|
|
590
|
-
const
|
|
595
|
+
const pathParts = route.split("/");
|
|
596
|
+
// Delete data store only if its route (/datastoreId) is in unusedRoutes. We don't want to delete a data
|
|
597
|
+
// store based on its DDS being unused.
|
|
598
|
+
if (pathParts.length > 2) {
|
|
599
|
+
continue;
|
|
600
|
+
}
|
|
601
|
+
const dataStoreId = pathParts[1];
|
|
602
|
+
assert(this.contexts.has(dataStoreId), 0x2d7 /* `${dataStoreId} is not a data store` */);
|
|
591
603
|
// Delete the contexts of unused data stores.
|
|
592
604
|
this.contexts.delete(dataStoreId);
|
|
593
605
|
// Delete the summarizer node of the unused data stores.
|
|
@@ -611,15 +623,24 @@ export class DataStores implements IDisposable {
|
|
|
611
623
|
}
|
|
612
624
|
|
|
613
625
|
/**
|
|
614
|
-
*
|
|
615
|
-
|
|
626
|
+
* Called during GC to retrieve the package path of a data store node with the given path.
|
|
627
|
+
*/
|
|
628
|
+
public getDataStorePackagePath(nodePath: string): readonly string[] | undefined {
|
|
629
|
+
// If the node belongs to a data store, return its package path if the data store is loaded. For DDSs, we return
|
|
630
|
+
// the package path of the data store that contains it.
|
|
631
|
+
const context = this.contexts.get(nodePath.split("/")[1]);
|
|
632
|
+
return context?.isLoaded ? context.packagePath : undefined;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* Called by GC to know if a node is a data store or not. Data store ids are of the format "/dataStoreId".
|
|
616
637
|
*/
|
|
617
|
-
public
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
return
|
|
638
|
+
public isDataStoreNode(nodePath: string): boolean {
|
|
639
|
+
const pathParts = nodePath.split("/");
|
|
640
|
+
if (pathParts.length === 2 && this.contexts.has(pathParts[1])) {
|
|
641
|
+
return true;
|
|
642
|
+
}
|
|
643
|
+
return false;
|
|
623
644
|
}
|
|
624
645
|
}
|
|
625
646
|
|
package/src/deltaScheduler.ts
CHANGED
|
@@ -11,6 +11,9 @@ import {
|
|
|
11
11
|
ISequencedDocumentMessage,
|
|
12
12
|
} from "@fluidframework/protocol-definitions";
|
|
13
13
|
|
|
14
|
+
import {
|
|
15
|
+
TelemetryLogger,
|
|
16
|
+
} from "@fluidframework/telemetry-utils";
|
|
14
17
|
/**
|
|
15
18
|
* DeltaScheduler is responsible for the scheduling of inbound delta queue in cases where there
|
|
16
19
|
* is more than one op a particular run of the queue. It does not schedule if there is just one
|
|
@@ -25,18 +28,13 @@ import {
|
|
|
25
28
|
export class DeltaScheduler {
|
|
26
29
|
private readonly deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>;
|
|
27
30
|
// The time for processing ops in a single turn.
|
|
28
|
-
public static readonly processingTime =
|
|
31
|
+
public static readonly processingTime = 50;
|
|
29
32
|
|
|
30
33
|
// The increase in time for processing ops after each turn.
|
|
31
34
|
private readonly processingTimeIncrement = 10;
|
|
32
35
|
|
|
33
36
|
private processingStartTime: number | undefined;
|
|
34
|
-
private
|
|
35
|
-
|
|
36
|
-
// This keeps track of whether the delta scheduler is scheduling a particular run of the
|
|
37
|
-
// the inbound delta queue. Basically, every time the delta queue starts processing with
|
|
38
|
-
// more than one op, this will be set to true until the run completes.
|
|
39
|
-
private isScheduling: boolean = false;
|
|
37
|
+
private currentAllowedProcessingTimeForTurn: number = DeltaScheduler.processingTime;
|
|
40
38
|
|
|
41
39
|
// This keeps track of the number of times inbound queue has been scheduled. After a particular
|
|
42
40
|
// count, we log telemetry for the number of ops processed, the time and number of turns it took
|
|
@@ -44,9 +42,13 @@ export class DeltaScheduler {
|
|
|
44
42
|
private schedulingCount: number = 0;
|
|
45
43
|
|
|
46
44
|
private schedulingLog: {
|
|
47
|
-
|
|
45
|
+
opsRemainingToProcess: number;
|
|
48
46
|
totalProcessingTime: number;
|
|
49
47
|
numberOfTurns: number;
|
|
48
|
+
numberOfBatchesProcessed: number;
|
|
49
|
+
lastSequenceNumber: number;
|
|
50
|
+
firstSequenceNumber: number;
|
|
51
|
+
startTime: number;
|
|
50
52
|
} | undefined;
|
|
51
53
|
|
|
52
54
|
constructor(
|
|
@@ -57,50 +59,72 @@ export class DeltaScheduler {
|
|
|
57
59
|
this.deltaManager.inbound.on("idle", () => { this.inboundQueueIdle(); });
|
|
58
60
|
}
|
|
59
61
|
|
|
60
|
-
public batchBegin() {
|
|
62
|
+
public batchBegin(message: ISequencedDocumentMessage) {
|
|
61
63
|
if (!this.processingStartTime) {
|
|
62
64
|
this.processingStartTime = performance.now();
|
|
63
65
|
}
|
|
66
|
+
if (this.schedulingLog === undefined && this.schedulingCount % 500 === 0) {
|
|
67
|
+
// Every 500th time we are scheduling the inbound queue, we log telemetry for the
|
|
68
|
+
// number of ops processed, the time and number of turns it took to process the ops.
|
|
69
|
+
this.schedulingLog = {
|
|
70
|
+
opsRemainingToProcess: 0,
|
|
71
|
+
numberOfTurns: 1,
|
|
72
|
+
totalProcessingTime: 0,
|
|
73
|
+
numberOfBatchesProcessed: 0,
|
|
74
|
+
firstSequenceNumber: message.sequenceNumber,
|
|
75
|
+
lastSequenceNumber: message.sequenceNumber,
|
|
76
|
+
startTime: performance.now(),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
64
79
|
}
|
|
65
80
|
|
|
66
|
-
public batchEnd() {
|
|
67
|
-
if (this.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if (this.schedulingCount % 2000 === 0) {
|
|
73
|
-
this.schedulingLog = {
|
|
74
|
-
numberOfOps: this.deltaManager.inbound.length,
|
|
75
|
-
numberOfTurns: 1,
|
|
76
|
-
totalProcessingTime: 0,
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
}
|
|
81
|
+
public batchEnd(message: ISequencedDocumentMessage) {
|
|
82
|
+
if (this.schedulingLog) {
|
|
83
|
+
this.schedulingLog.numberOfBatchesProcessed++;
|
|
84
|
+
this.schedulingLog.lastSequenceNumber = message.sequenceNumber;
|
|
85
|
+
this.schedulingLog.opsRemainingToProcess = this.deltaManager.inbound.length;
|
|
86
|
+
}
|
|
80
87
|
|
|
88
|
+
if (this.shouldRunScheduler()) {
|
|
89
|
+
const currentTime = performance.now();
|
|
81
90
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
82
|
-
const elapsedTime =
|
|
83
|
-
if (elapsedTime > this.
|
|
91
|
+
const elapsedTime = currentTime - this.processingStartTime!;
|
|
92
|
+
if (elapsedTime > this.currentAllowedProcessingTimeForTurn) {
|
|
84
93
|
// We have processed ops for more than the total processing time. So, pause the
|
|
85
94
|
// queue, yield the thread and schedule a resume.
|
|
86
95
|
|
|
87
96
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
88
97
|
this.deltaManager.inbound.pause();
|
|
89
|
-
setTimeout(() => {
|
|
90
|
-
this.deltaManager.inbound.resume();
|
|
91
|
-
});
|
|
92
98
|
|
|
93
|
-
|
|
94
|
-
// Increase the total processing time. Keep doing this after each turn until all the ops have
|
|
99
|
+
// Increase the total processing time. Keep doing this after each turn until all the ops have
|
|
95
100
|
// been processed. This way we keep the responsiveness at the beginning while also making sure
|
|
96
101
|
// that all the ops process fairly quickly.
|
|
97
|
-
this.
|
|
102
|
+
this.currentAllowedProcessingTimeForTurn += this.processingTimeIncrement;
|
|
98
103
|
|
|
99
104
|
// If we are logging the telemetry this time, update the telemetry log object.
|
|
100
105
|
if (this.schedulingLog) {
|
|
101
106
|
this.schedulingLog.numberOfTurns++;
|
|
102
107
|
this.schedulingLog.totalProcessingTime += elapsedTime;
|
|
103
108
|
}
|
|
109
|
+
|
|
110
|
+
setTimeout(() => {
|
|
111
|
+
if (this.schedulingLog) {
|
|
112
|
+
this.logger.sendTelemetryEvent({
|
|
113
|
+
eventName: "InboundOpsPartialProcessingTime",
|
|
114
|
+
duration: TelemetryLogger.formatTick(elapsedTime),
|
|
115
|
+
opsProcessed: this.schedulingLog.lastSequenceNumber -
|
|
116
|
+
this.schedulingLog.firstSequenceNumber + 1,
|
|
117
|
+
opsRemainingToProcess: this.deltaManager.inbound.length,
|
|
118
|
+
processingTime: TelemetryLogger.formatTick(this.schedulingLog.totalProcessingTime),
|
|
119
|
+
numberOfTurns: this.schedulingLog.numberOfTurns,
|
|
120
|
+
batchesProcessed: this.schedulingLog.numberOfBatchesProcessed,
|
|
121
|
+
timeToResume: TelemetryLogger.formatTick(performance.now() - currentTime),
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
this.deltaManager.inbound.resume();
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
this.processingStartTime = undefined;
|
|
104
128
|
}
|
|
105
129
|
}
|
|
106
130
|
}
|
|
@@ -109,14 +133,19 @@ export class DeltaScheduler {
|
|
|
109
133
|
if (this.schedulingLog) {
|
|
110
134
|
// Add the time taken for processing the final ops to the total processing time in the
|
|
111
135
|
// telemetry log object.
|
|
136
|
+
const currentTime = performance.now();
|
|
112
137
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
113
|
-
this.schedulingLog.totalProcessingTime +=
|
|
138
|
+
this.schedulingLog.totalProcessingTime += currentTime - this.processingStartTime!;
|
|
114
139
|
|
|
115
140
|
this.logger.sendTelemetryEvent({
|
|
116
141
|
eventName: "InboundOpsProcessingTime",
|
|
117
|
-
|
|
142
|
+
opsRemainingToProcess: this.schedulingLog.opsRemainingToProcess,
|
|
118
143
|
numberOfTurns: this.schedulingLog.numberOfTurns,
|
|
119
|
-
processingTime: this.schedulingLog.totalProcessingTime,
|
|
144
|
+
processingTime: TelemetryLogger.formatTick(this.schedulingLog.totalProcessingTime),
|
|
145
|
+
opsProcessed: this.schedulingLog.lastSequenceNumber - this.schedulingLog.firstSequenceNumber + 1,
|
|
146
|
+
batchesProcessed: this.schedulingLog.numberOfBatchesProcessed,
|
|
147
|
+
duration: TelemetryLogger.formatTick(currentTime - this.schedulingLog.startTime),
|
|
148
|
+
schedulingCount: this.schedulingCount,
|
|
120
149
|
});
|
|
121
150
|
|
|
122
151
|
this.schedulingLog = undefined;
|
|
@@ -124,14 +153,11 @@ export class DeltaScheduler {
|
|
|
124
153
|
|
|
125
154
|
// If we scheduled this batch of the inbound queue, increment the counter that tracks the
|
|
126
155
|
// number of times we have done this.
|
|
127
|
-
|
|
128
|
-
this.isScheduling = false;
|
|
129
|
-
this.schedulingCount++;
|
|
130
|
-
}
|
|
156
|
+
this.schedulingCount++;
|
|
131
157
|
|
|
132
158
|
// Reset the processing times.
|
|
133
159
|
this.processingStartTime = undefined;
|
|
134
|
-
this.
|
|
160
|
+
this.currentAllowedProcessingTimeForTurn = DeltaScheduler.processingTime;
|
|
135
161
|
}
|
|
136
162
|
|
|
137
163
|
/**
|