@fluidframework/container-runtime 2.0.0-rc.3.0.0 → 2.0.0-rc.3.0.10
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/api-report/container-runtime.api.md +30 -12
- package/dist/channelCollection.d.ts +5 -3
- package/dist/channelCollection.d.ts.map +1 -1
- package/dist/channelCollection.js +88 -29
- package/dist/channelCollection.js.map +1 -1
- package/dist/containerRuntime.d.ts +6 -1
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +55 -48
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStoreContext.d.ts +1 -1
- package/dist/dataStoreContexts.d.ts +2 -0
- package/dist/dataStoreContexts.d.ts.map +1 -1
- package/dist/dataStoreContexts.js +7 -0
- package/dist/dataStoreContexts.js.map +1 -1
- package/dist/gc/garbageCollection.d.ts +4 -11
- package/dist/gc/garbageCollection.d.ts.map +1 -1
- package/dist/gc/garbageCollection.js +45 -29
- package/dist/gc/garbageCollection.js.map +1 -1
- package/dist/gc/gcDefinitions.d.ts +26 -5
- package/dist/gc/gcDefinitions.d.ts.map +1 -1
- package/dist/gc/gcDefinitions.js.map +1 -1
- package/dist/gc/gcHelpers.d.ts +5 -4
- package/dist/gc/gcHelpers.d.ts.map +1 -1
- package/dist/gc/gcHelpers.js +14 -2
- package/dist/gc/gcHelpers.js.map +1 -1
- package/dist/gc/gcTelemetry.d.ts +13 -2
- package/dist/gc/gcTelemetry.d.ts.map +1 -1
- package/dist/gc/gcTelemetry.js +24 -21
- package/dist/gc/gcTelemetry.js.map +1 -1
- package/dist/gc/index.d.ts +2 -2
- package/dist/gc/index.d.ts.map +1 -1
- package/dist/gc/index.js +2 -2
- package/dist/gc/index.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/legacy.d.ts +1 -0
- package/dist/metadata.d.ts +2 -2
- package/dist/metadata.d.ts.map +1 -1
- package/dist/metadata.js.map +1 -1
- package/dist/opLifecycle/batchManager.d.ts +4 -1
- package/dist/opLifecycle/batchManager.d.ts.map +1 -1
- package/dist/opLifecycle/batchManager.js +0 -10
- package/dist/opLifecycle/batchManager.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts +0 -4
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +7 -38
- package/dist/opLifecycle/outbox.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/summary/documentSchema.js +1 -1
- package/dist/summary/documentSchema.js.map +1 -1
- package/lib/channelCollection.d.ts +5 -3
- package/lib/channelCollection.d.ts.map +1 -1
- package/lib/channelCollection.js +90 -31
- package/lib/channelCollection.js.map +1 -1
- package/lib/containerRuntime.d.ts +6 -1
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +54 -47
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStoreContext.d.ts +1 -1
- package/lib/dataStoreContexts.d.ts +2 -0
- package/lib/dataStoreContexts.d.ts.map +1 -1
- package/lib/dataStoreContexts.js +7 -0
- package/lib/dataStoreContexts.js.map +1 -1
- package/lib/gc/garbageCollection.d.ts +4 -11
- package/lib/gc/garbageCollection.d.ts.map +1 -1
- package/lib/gc/garbageCollection.js +47 -31
- package/lib/gc/garbageCollection.js.map +1 -1
- package/lib/gc/gcDefinitions.d.ts +26 -5
- package/lib/gc/gcDefinitions.d.ts.map +1 -1
- package/lib/gc/gcDefinitions.js.map +1 -1
- package/lib/gc/gcHelpers.d.ts +5 -4
- package/lib/gc/gcHelpers.d.ts.map +1 -1
- package/lib/gc/gcHelpers.js +12 -1
- package/lib/gc/gcHelpers.js.map +1 -1
- package/lib/gc/gcTelemetry.d.ts +13 -2
- package/lib/gc/gcTelemetry.d.ts.map +1 -1
- package/lib/gc/gcTelemetry.js +24 -21
- package/lib/gc/gcTelemetry.js.map +1 -1
- package/lib/gc/index.d.ts +2 -2
- package/lib/gc/index.d.ts.map +1 -1
- package/lib/gc/index.js +1 -1
- package/lib/gc/index.js.map +1 -1
- package/lib/index.d.ts +2 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/legacy.d.ts +1 -0
- package/lib/metadata.d.ts +2 -2
- package/lib/metadata.d.ts.map +1 -1
- package/lib/metadata.js.map +1 -1
- package/lib/opLifecycle/batchManager.d.ts +4 -1
- package/lib/opLifecycle/batchManager.d.ts.map +1 -1
- package/lib/opLifecycle/batchManager.js +0 -10
- package/lib/opLifecycle/batchManager.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts +0 -4
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.js +7 -38
- package/lib/opLifecycle/outbox.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/summary/documentSchema.js +1 -1
- package/lib/summary/documentSchema.js.map +1 -1
- package/package.json +20 -20
- package/src/channelCollection.ts +108 -49
- package/src/containerRuntime.ts +66 -80
- package/src/dataStoreContexts.ts +12 -0
- package/src/gc/garbageCollection.ts +63 -41
- package/src/gc/gcDefinitions.ts +21 -9
- package/src/gc/gcHelpers.ts +14 -1
- package/src/gc/gcTelemetry.ts +56 -47
- package/src/gc/index.ts +2 -1
- package/src/index.ts +2 -0
- package/src/metadata.ts +2 -2
- package/src/opLifecycle/README.md +4 -4
- package/src/opLifecycle/batchManager.ts +5 -14
- package/src/opLifecycle/outbox.ts +7 -53
- package/src/packageVersion.ts +1 -1
- package/src/summary/documentSchema.ts +1 -1
- package/dist/public.d.ts +0 -12
- package/lib/public.d.ts +0 -12
package/src/gc/gcTelemetry.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
tagCodeArtifacts,
|
|
15
15
|
} from "@fluidframework/telemetry-utils/internal";
|
|
16
16
|
|
|
17
|
+
import type { Tagged } from "@fluidframework/core-interfaces";
|
|
17
18
|
import { RuntimeHeaderData } from "../containerRuntime.js";
|
|
18
19
|
import { ICreateContainerMetadata } from "../summary/index.js";
|
|
19
20
|
|
|
@@ -43,11 +44,12 @@ interface ICommonProps {
|
|
|
43
44
|
|
|
44
45
|
/** The event that is logged when unreferenced node is used after a certain time. */
|
|
45
46
|
interface IUnreferencedEventProps extends ICreateContainerMetadata, ICommonProps {
|
|
47
|
+
/** The id that GC uses to track the node. May or may not match id */
|
|
48
|
+
trackedId: string;
|
|
46
49
|
state: UnreferencedState;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
};
|
|
50
|
+
/** The full path (in GC Path format) to the node in question */
|
|
51
|
+
id: Tagged<string>;
|
|
52
|
+
fromId?: Tagged<string>;
|
|
51
53
|
type: GCNodeType;
|
|
52
54
|
unrefTime: number;
|
|
53
55
|
age: number;
|
|
@@ -56,19 +58,24 @@ interface IUnreferencedEventProps extends ICreateContainerMetadata, ICommonProps
|
|
|
56
58
|
[K in keyof GCFeatureMatrix]: GCFeatureMatrix[K];
|
|
57
59
|
};
|
|
58
60
|
timeout?: number;
|
|
59
|
-
fromId?: {
|
|
60
|
-
value: string;
|
|
61
|
-
tag: string;
|
|
62
|
-
};
|
|
63
61
|
}
|
|
64
62
|
|
|
65
63
|
/** Properties passed to nodeUsed function when a node is used. */
|
|
66
64
|
interface INodeUsageProps extends ICommonProps {
|
|
65
|
+
/** The full path (in GC Path format) to the node in question */
|
|
67
66
|
id: string;
|
|
67
|
+
/** Latest timestamp received from the server, as a baseline for computing GC state/age */
|
|
68
68
|
currentReferenceTimestampMs: number | undefined;
|
|
69
|
+
/** The package path of the node. This may not be available if the node hasn't been loaded yet */
|
|
69
70
|
packagePath: readonly string[] | undefined;
|
|
71
|
+
/** In case of Revived - what node added the reference? */
|
|
70
72
|
fromId?: string;
|
|
73
|
+
/** In case of Revived - was it revived due to autorecovery? */
|
|
71
74
|
autorecovery?: true;
|
|
75
|
+
/** URL (including query string) if this usage came from a request */
|
|
76
|
+
requestUrl?: string;
|
|
77
|
+
/** Original request headers if this usage came from a request or handle.get */
|
|
78
|
+
requestHeaders?: string;
|
|
72
79
|
}
|
|
73
80
|
|
|
74
81
|
/**
|
|
@@ -143,18 +150,34 @@ export class GCTelemetryTracker {
|
|
|
143
150
|
}
|
|
144
151
|
|
|
145
152
|
/**
|
|
146
|
-
* Called when a node is used. If the node is
|
|
153
|
+
* Called when a node is used. If the node is inactive or tombstoned, log telemetry indicating object is used
|
|
147
154
|
* when it should not have been.
|
|
155
|
+
* @param trackedId - The id that GC uses to track the node. For SubDataStore nodes, this should be the DataStore ID.
|
|
156
|
+
* @param INodeUsageProps - All kind of details about this event to be logged
|
|
148
157
|
*/
|
|
149
|
-
public nodeUsed(
|
|
158
|
+
public nodeUsed(
|
|
159
|
+
trackedId: string,
|
|
160
|
+
{
|
|
161
|
+
usageType,
|
|
162
|
+
currentReferenceTimestampMs,
|
|
163
|
+
packagePath,
|
|
164
|
+
id: untaggedId,
|
|
165
|
+
fromId: untaggedFromId,
|
|
166
|
+
isTombstoned,
|
|
167
|
+
...otherNodeUsageProps
|
|
168
|
+
}: INodeUsageProps,
|
|
169
|
+
) {
|
|
150
170
|
// If there is no reference timestamp to work with, no ops have been processed after creation. If so, skip
|
|
151
171
|
// logging as nothing interesting would have happened worth logging.
|
|
152
|
-
if (
|
|
172
|
+
if (currentReferenceTimestampMs === undefined) {
|
|
153
173
|
return;
|
|
154
174
|
}
|
|
155
175
|
|
|
156
|
-
|
|
157
|
-
|
|
176
|
+
// Note: For SubDataStore Load usage, trackedId will be the DataStore's id, not the full path in question.
|
|
177
|
+
// This is necessary because the SubDataStore path may be unrecognized by GC (if suited for a custom request handler)
|
|
178
|
+
const nodeStateTracker = this.getNodeStateTracker(trackedId);
|
|
179
|
+
const nodeType = this.getNodeType(untaggedId);
|
|
180
|
+
|
|
158
181
|
const timeout = (() => {
|
|
159
182
|
switch (nodeStateTracker?.state) {
|
|
160
183
|
case UnreferencedState.Inactive:
|
|
@@ -170,33 +193,27 @@ export class GCTelemetryTracker {
|
|
|
170
193
|
return undefined;
|
|
171
194
|
}
|
|
172
195
|
})();
|
|
173
|
-
const {
|
|
174
|
-
usageType,
|
|
175
|
-
currentReferenceTimestampMs,
|
|
176
|
-
packagePath,
|
|
177
|
-
id: untaggedId,
|
|
178
|
-
fromId: untaggedFromId,
|
|
179
|
-
...propsToLog
|
|
180
|
-
} = nodeUsageProps;
|
|
181
196
|
const { persistedGcFeatureMatrix, ...configs } = this.configs;
|
|
182
|
-
const unrefEventProps
|
|
197
|
+
const unrefEventProps = {
|
|
198
|
+
trackedId,
|
|
183
199
|
type: nodeType,
|
|
184
200
|
unrefTime: nodeStateTracker?.unreferencedTimestampMs ?? -1,
|
|
185
201
|
age:
|
|
186
202
|
nodeStateTracker !== undefined
|
|
187
|
-
?
|
|
188
|
-
nodeStateTracker.unreferencedTimestampMs
|
|
203
|
+
? currentReferenceTimestampMs - nodeStateTracker.unreferencedTimestampMs
|
|
189
204
|
: -1,
|
|
190
205
|
timeout,
|
|
206
|
+
isTombstoned,
|
|
191
207
|
...tagCodeArtifacts({ id: untaggedId, fromId: untaggedFromId }),
|
|
192
|
-
...
|
|
208
|
+
...otherNodeUsageProps,
|
|
193
209
|
...this.createContainerMetadata,
|
|
194
210
|
gcConfigs: { ...configs, ...persistedGcFeatureMatrix },
|
|
195
|
-
}
|
|
211
|
+
} satisfies Omit<IUnreferencedEventProps, "state" | "usageType"> &
|
|
212
|
+
typeof otherNodeUsageProps;
|
|
196
213
|
|
|
197
214
|
// If the node that is used is tombstoned, log a tombstone telemetry.
|
|
198
|
-
if (
|
|
199
|
-
this.logTombstoneUsageTelemetry(
|
|
215
|
+
if (isTombstoned) {
|
|
216
|
+
this.logTombstoneUsageTelemetry(unrefEventProps, nodeType, usageType, packagePath);
|
|
200
217
|
}
|
|
201
218
|
|
|
202
219
|
// After logging tombstone telemetry, if the node's unreferenced state is not tracked, there is nothing
|
|
@@ -206,16 +223,9 @@ export class GCTelemetryTracker {
|
|
|
206
223
|
}
|
|
207
224
|
|
|
208
225
|
const state = nodeStateTracker.state;
|
|
209
|
-
const uniqueEventId = `${state}-${
|
|
226
|
+
const uniqueEventId = `${state}-${untaggedId}-${usageType}`;
|
|
210
227
|
|
|
211
|
-
if (
|
|
212
|
-
!this.shouldLogNonActiveEvent(
|
|
213
|
-
nodeType,
|
|
214
|
-
nodeUsageProps.usageType,
|
|
215
|
-
nodeStateTracker,
|
|
216
|
-
uniqueEventId,
|
|
217
|
-
)
|
|
218
|
-
) {
|
|
228
|
+
if (!this.shouldLogNonActiveEvent(nodeType, usageType, nodeStateTracker, uniqueEventId)) {
|
|
219
229
|
return;
|
|
220
230
|
}
|
|
221
231
|
|
|
@@ -229,8 +239,8 @@ export class GCTelemetryTracker {
|
|
|
229
239
|
// SweepReady errors are usages of Objects that will be deleted by GC Sweep!
|
|
230
240
|
if (this.isSummarizerClient) {
|
|
231
241
|
this.pendingEventsQueue.push({
|
|
232
|
-
...unrefEventProps,
|
|
233
|
-
usageType
|
|
242
|
+
...unrefEventProps, // Note: Contains some properties from INodeUsageProps as well
|
|
243
|
+
usageType,
|
|
234
244
|
state,
|
|
235
245
|
});
|
|
236
246
|
} else {
|
|
@@ -238,11 +248,11 @@ export class GCTelemetryTracker {
|
|
|
238
248
|
// summarizer clients if they are based off of user actions (such as scrolling to content for these objects)
|
|
239
249
|
// Events generated:
|
|
240
250
|
// InactiveObject_Loaded, SweepReadyObject_Loaded
|
|
241
|
-
if (
|
|
251
|
+
if (usageType === "Loaded") {
|
|
242
252
|
const { id, fromId, headers, gcConfigs, ...detailedProps } = unrefEventProps;
|
|
243
253
|
const event = {
|
|
244
|
-
eventName: `${state}Object_${
|
|
245
|
-
...tagCodeArtifacts({ pkg:
|
|
254
|
+
eventName: `${state}Object_${usageType}`,
|
|
255
|
+
...tagCodeArtifacts({ pkg: packagePath?.join("/") }),
|
|
246
256
|
stack: generateStack(),
|
|
247
257
|
id,
|
|
248
258
|
fromId,
|
|
@@ -262,10 +272,10 @@ export class GCTelemetryTracker {
|
|
|
262
272
|
* Logs telemetry when a tombstoned object is changed, revived or loaded.
|
|
263
273
|
*/
|
|
264
274
|
private logTombstoneUsageTelemetry(
|
|
265
|
-
nodeUsageProps: INodeUsageProps,
|
|
266
275
|
unrefEventProps: Omit<IUnreferencedEventProps, "state" | "usageType">,
|
|
267
276
|
nodeType: GCNodeType,
|
|
268
277
|
usageType: NodeUsageType,
|
|
278
|
+
packagePath?: readonly string[],
|
|
269
279
|
) {
|
|
270
280
|
// This will log the following events:
|
|
271
281
|
// GC_Tombstone_DataStore_Requested, GC_Tombstone_DataStore_Changed, GC_Tombstone_DataStore_Revived
|
|
@@ -275,12 +285,12 @@ export class GCTelemetryTracker {
|
|
|
275
285
|
const eventUsageName = usageType === "Loaded" ? "Requested" : usageType;
|
|
276
286
|
const event = {
|
|
277
287
|
eventName: `GC_Tombstone_${nodeType}_${eventUsageName}`,
|
|
278
|
-
|
|
288
|
+
...tagCodeArtifacts({ pkg: packagePath?.join("/") }),
|
|
279
289
|
stack: generateStack(),
|
|
280
290
|
id,
|
|
281
291
|
fromId,
|
|
282
292
|
headers: { ...headers },
|
|
283
|
-
details: detailedProps,
|
|
293
|
+
details: detailedProps, // Also includes some properties from INodeUsageProps type
|
|
284
294
|
gcConfigs,
|
|
285
295
|
tombstoneFlags: {
|
|
286
296
|
DisableTombstone: this.mc.config.getBoolean(disableTombstoneKey),
|
|
@@ -372,7 +382,6 @@ export class GCTelemetryTracker {
|
|
|
372
382
|
// InactiveObject_Loaded, InactiveObject_Changed, InactiveObject_Revived
|
|
373
383
|
// SweepReadyObject_Loaded, SweepReadyObject_Changed, SweepReadyObject_Revived
|
|
374
384
|
for (const eventProps of this.pendingEventsQueue) {
|
|
375
|
-
// const { usageType, state, id, fromId, ...propsToLog } = eventProps;
|
|
376
385
|
const { usageType, state, id, fromId, headers, gcConfigs, ...detailedProps } =
|
|
377
386
|
eventProps;
|
|
378
387
|
/**
|
|
@@ -381,7 +390,7 @@ export class GCTelemetryTracker {
|
|
|
381
390
|
* Loaded and Changed events are logged only if the node is not active. If the node is active, it was
|
|
382
391
|
* revived and a Revived event will be logged for it.
|
|
383
392
|
*/
|
|
384
|
-
const nodeStateTracker = this.getNodeStateTracker(
|
|
393
|
+
const nodeStateTracker = this.getNodeStateTracker(detailedProps.trackedId); // Note: This is never SubDataStore path
|
|
385
394
|
const active =
|
|
386
395
|
nodeStateTracker === undefined ||
|
|
387
396
|
nodeStateTracker.state === UnreferencedState.Active;
|
package/src/gc/index.ts
CHANGED
|
@@ -23,6 +23,7 @@ export {
|
|
|
23
23
|
IGarbageCollectorCreateParams,
|
|
24
24
|
IGCMetadata,
|
|
25
25
|
IGCMetadata_Deprecated,
|
|
26
|
+
IGCNodeUpdatedProps,
|
|
26
27
|
IGCResult,
|
|
27
28
|
IGCRuntimeOptions,
|
|
28
29
|
IMarkPhaseStats,
|
|
@@ -46,8 +47,8 @@ export {
|
|
|
46
47
|
cloneGCData,
|
|
47
48
|
concatGarbageCollectionStates,
|
|
48
49
|
getGCVersionInEffect,
|
|
49
|
-
trimLeadingAndTrailingSlashes,
|
|
50
50
|
unpackChildNodesGCDetails,
|
|
51
|
+
urlToGCNodePath,
|
|
51
52
|
} from "./gcHelpers.js";
|
|
52
53
|
export { runGarbageCollection } from "./gcReferenceGraphAlgorithm.js";
|
|
53
54
|
export {
|
package/src/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ export {
|
|
|
13
13
|
isRuntimeMessage,
|
|
14
14
|
agentSchedulerId,
|
|
15
15
|
ContainerRuntime,
|
|
16
|
+
DeletedResponseHeaderKey,
|
|
16
17
|
TombstoneResponseHeaderKey,
|
|
17
18
|
InactiveResponseHeaderKey,
|
|
18
19
|
ISummaryConfiguration,
|
|
@@ -47,6 +48,7 @@ export {
|
|
|
47
48
|
IGCRuntimeOptions,
|
|
48
49
|
IMarkPhaseStats,
|
|
49
50
|
ISweepPhaseStats,
|
|
51
|
+
IGCNodeUpdatedProps,
|
|
50
52
|
IGCStats,
|
|
51
53
|
} from "./gc/index.js";
|
|
52
54
|
export {
|
package/src/metadata.ts
CHANGED
|
@@ -19,8 +19,8 @@ export interface IBlobMetadata {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
*
|
|
22
|
+
* ContainerRuntime needs to know if this is a replayed savedOp as those need to be skipped in stashed ops scenarios.
|
|
23
23
|
*/
|
|
24
|
-
export interface
|
|
24
|
+
export interface ISavedOpMetadata {
|
|
25
25
|
savedOp?: boolean;
|
|
26
26
|
}
|
|
@@ -339,19 +339,19 @@ stateDiagram-v2
|
|
|
339
339
|
state "Store original (uncompressed, unchunked, ungrouped) batch locally" as store
|
|
340
340
|
state if_compression <<choice>>
|
|
341
341
|
[*] --> ContainerRuntime.submit
|
|
342
|
-
ContainerRuntime.submit --> outbox.
|
|
342
|
+
ContainerRuntime.submit --> outbox.submitIdAllocation
|
|
343
343
|
ContainerRuntime.submit --> outbox.submitBlobAttach
|
|
344
344
|
ContainerRuntime.submit --> outbox.submit
|
|
345
345
|
outbox.submit --> scheduleFlush
|
|
346
|
-
outbox.
|
|
346
|
+
outbox.submitIdAllocation --> scheduleFlush
|
|
347
347
|
outbox.submitBlobAttach --> scheduleFlush
|
|
348
348
|
scheduleFlush --> jsTurn
|
|
349
349
|
jsTurn --> flush
|
|
350
350
|
flush --> outbox.flushInternalMain
|
|
351
|
-
flush --> outbox.
|
|
351
|
+
flush --> outbox.flushInternalIdAllocation
|
|
352
352
|
flush --> outbox.flushInternalBlobAttach
|
|
353
353
|
outbox.flushInternalMain --> flushInternal
|
|
354
|
-
outbox.
|
|
354
|
+
outbox.flushInternalIdAllocation --> flushInternal
|
|
355
355
|
outbox.flushInternalBlobAttach --> flushInternal
|
|
356
356
|
flushInternal --> ContainerRuntime.reSubmit: if batch has reentrant ops and should group
|
|
357
357
|
ContainerRuntime.reSubmit --> flushInternal
|
|
@@ -9,8 +9,12 @@ import { BatchMessage, IBatch, IBatchCheckpoint } from "./definitions.js";
|
|
|
9
9
|
|
|
10
10
|
export interface IBatchManagerOptions {
|
|
11
11
|
readonly hardLimit: number;
|
|
12
|
-
readonly softLimit?: number;
|
|
13
12
|
readonly compressionOptions?: ICompressionRuntimeOptions;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* If true, the outbox is allowed to rebase the batch during flushing.
|
|
16
|
+
*/
|
|
17
|
+
readonly canRebase: boolean;
|
|
14
18
|
}
|
|
15
19
|
|
|
16
20
|
export interface BatchSequenceNumbers {
|
|
@@ -72,19 +76,6 @@ export class BatchManager {
|
|
|
72
76
|
// initially stored as base64, and that requires only 2 extra escape characters.
|
|
73
77
|
const socketMessageSize = contentSize + opOverhead * opCount;
|
|
74
78
|
|
|
75
|
-
// If we were provided soft limit, check for exceeding it.
|
|
76
|
-
// But only if we have any ops, as the intention here is to flush existing ops (on exceeding this limit)
|
|
77
|
-
// and start over. That's not an option if we have no ops.
|
|
78
|
-
// If compression is enabled, the soft and hard limit are ignored and the message will be pushed anyways.
|
|
79
|
-
// Cases where the message is still too large will be handled by the maxConsecutiveReconnects path.
|
|
80
|
-
if (
|
|
81
|
-
this.options.softLimit !== undefined &&
|
|
82
|
-
this.length > 0 &&
|
|
83
|
-
socketMessageSize >= this.options.softLimit
|
|
84
|
-
) {
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
79
|
if (socketMessageSize >= this.options.hardLimit) {
|
|
89
80
|
return false;
|
|
90
81
|
}
|
|
@@ -89,11 +89,9 @@ export function getLongStack<T>(action: () => T, length: number = 50): T {
|
|
|
89
89
|
|
|
90
90
|
export class Outbox {
|
|
91
91
|
private readonly mc: MonitoringContext;
|
|
92
|
-
private readonly attachFlowBatch: BatchManager;
|
|
93
92
|
private readonly mainBatch: BatchManager;
|
|
94
93
|
private readonly blobAttachBatch: BatchManager;
|
|
95
94
|
private readonly idAllocationBatch: BatchManager;
|
|
96
|
-
private readonly defaultAttachFlowSoftLimitInBytes = 320 * 1024;
|
|
97
95
|
private batchRebasesToReport = 5;
|
|
98
96
|
private rebasing = false;
|
|
99
97
|
|
|
@@ -113,21 +111,14 @@ export class Outbox {
|
|
|
113
111
|
Number.POSITIVE_INFINITY;
|
|
114
112
|
// We need to allow infinite size batches if we enable compression
|
|
115
113
|
const hardLimit = isCompressionEnabled ? Infinity : this.params.config.maxBatchSizeInBytes;
|
|
116
|
-
const softLimit = isCompressionEnabled ? Infinity : this.defaultAttachFlowSoftLimitInBytes;
|
|
117
114
|
|
|
118
|
-
this.
|
|
119
|
-
this.
|
|
120
|
-
this.
|
|
121
|
-
this.idAllocationBatch = new BatchManager({ hardLimit });
|
|
115
|
+
this.mainBatch = new BatchManager({ hardLimit, canRebase: true });
|
|
116
|
+
this.blobAttachBatch = new BatchManager({ hardLimit, canRebase: true });
|
|
117
|
+
this.idAllocationBatch = new BatchManager({ hardLimit, canRebase: false });
|
|
122
118
|
}
|
|
123
119
|
|
|
124
120
|
public get messageCount(): number {
|
|
125
|
-
return
|
|
126
|
-
this.attachFlowBatch.length +
|
|
127
|
-
this.mainBatch.length +
|
|
128
|
-
this.blobAttachBatch.length +
|
|
129
|
-
this.idAllocationBatch.length
|
|
130
|
-
);
|
|
121
|
+
return this.mainBatch.length + this.blobAttachBatch.length + this.idAllocationBatch.length;
|
|
131
122
|
}
|
|
132
123
|
|
|
133
124
|
public get isEmpty(): boolean {
|
|
@@ -142,13 +133,11 @@ export class Outbox {
|
|
|
142
133
|
*/
|
|
143
134
|
private maybeFlushPartialBatch() {
|
|
144
135
|
const mainBatchSeqNums = this.mainBatch.sequenceNumbers;
|
|
145
|
-
const attachFlowBatchSeqNums = this.attachFlowBatch.sequenceNumbers;
|
|
146
136
|
const blobAttachSeqNums = this.blobAttachBatch.sequenceNumbers;
|
|
147
137
|
const idAllocSeqNums = this.idAllocationBatch.sequenceNumbers;
|
|
148
138
|
assert(
|
|
149
139
|
this.params.config.disablePartialFlush ||
|
|
150
|
-
(sequenceNumbersMatch(mainBatchSeqNums,
|
|
151
|
-
sequenceNumbersMatch(mainBatchSeqNums, blobAttachSeqNums) &&
|
|
140
|
+
(sequenceNumbersMatch(mainBatchSeqNums, blobAttachSeqNums) &&
|
|
152
141
|
sequenceNumbersMatch(mainBatchSeqNums, idAllocSeqNums)),
|
|
153
142
|
0x58d /* Reference sequence numbers from both batches must be in sync */,
|
|
154
143
|
);
|
|
@@ -157,7 +146,6 @@ export class Outbox {
|
|
|
157
146
|
|
|
158
147
|
if (
|
|
159
148
|
sequenceNumbersMatch(mainBatchSeqNums, currentSequenceNumbers) &&
|
|
160
|
-
sequenceNumbersMatch(attachFlowBatchSeqNums, currentSequenceNumbers) &&
|
|
161
149
|
sequenceNumbersMatch(blobAttachSeqNums, currentSequenceNumbers) &&
|
|
162
150
|
sequenceNumbersMatch(idAllocSeqNums, currentSequenceNumbers)
|
|
163
151
|
) {
|
|
@@ -172,8 +160,6 @@ export class Outbox {
|
|
|
172
160
|
eventName: "ReferenceSequenceNumberMismatch",
|
|
173
161
|
mainReferenceSequenceNumber: mainBatchSeqNums.referenceSequenceNumber,
|
|
174
162
|
mainClientSequenceNumber: mainBatchSeqNums.clientSequenceNumber,
|
|
175
|
-
attachReferenceSequenceNumber: attachFlowBatchSeqNums.referenceSequenceNumber,
|
|
176
|
-
attachClientSequenceNumber: attachFlowBatchSeqNums.clientSequenceNumber,
|
|
177
163
|
blobAttachReferenceSequenceNumber: blobAttachSeqNums.referenceSequenceNumber,
|
|
178
164
|
blobAttachClientSequenceNumber: blobAttachSeqNums.clientSequenceNumber,
|
|
179
165
|
currentReferenceSequenceNumber: currentSequenceNumbers.referenceSequenceNumber,
|
|
@@ -194,37 +180,6 @@ export class Outbox {
|
|
|
194
180
|
this.addMessageToBatchManager(this.mainBatch, message);
|
|
195
181
|
}
|
|
196
182
|
|
|
197
|
-
public submitAttach(message: BatchMessage) {
|
|
198
|
-
this.maybeFlushPartialBatch();
|
|
199
|
-
|
|
200
|
-
if (
|
|
201
|
-
!this.attachFlowBatch.push(
|
|
202
|
-
message,
|
|
203
|
-
this.isContextReentrant(),
|
|
204
|
-
this.params.getCurrentSequenceNumbers().clientSequenceNumber,
|
|
205
|
-
)
|
|
206
|
-
) {
|
|
207
|
-
// BatchManager has two limits - soft limit & hard limit. Soft limit is only engaged
|
|
208
|
-
// when queue is not empty.
|
|
209
|
-
// Flush queue & retry. Failure on retry would mean - single message is bigger than hard limit
|
|
210
|
-
this.flushInternal(this.attachFlowBatch);
|
|
211
|
-
|
|
212
|
-
this.addMessageToBatchManager(this.attachFlowBatch, message);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// If compression is enabled, we will always successfully receive
|
|
216
|
-
// attach ops and compress then send them at the next JS turn, regardless
|
|
217
|
-
// of the overall size of the accumulated ops in the batch.
|
|
218
|
-
// However, it is more efficient to flush these ops faster, preferably
|
|
219
|
-
// after they reach a size which would benefit from compression.
|
|
220
|
-
if (
|
|
221
|
-
this.attachFlowBatch.contentSizeInBytes >=
|
|
222
|
-
this.params.config.compressionOptions.minimumBatchSizeInBytes
|
|
223
|
-
) {
|
|
224
|
-
this.flushInternal(this.attachFlowBatch);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
183
|
public submitBlobAttach(message: BatchMessage) {
|
|
229
184
|
this.maybeFlushPartialBatch();
|
|
230
185
|
|
|
@@ -303,7 +258,6 @@ export class Outbox {
|
|
|
303
258
|
|
|
304
259
|
private flushAll() {
|
|
305
260
|
this.flushInternal(this.idAllocationBatch);
|
|
306
|
-
this.flushInternal(this.attachFlowBatch);
|
|
307
261
|
this.flushInternal(this.blobAttachBatch, true /* disableGroupedBatching */);
|
|
308
262
|
this.flushInternal(this.mainBatch);
|
|
309
263
|
}
|
|
@@ -316,7 +270,7 @@ export class Outbox {
|
|
|
316
270
|
const rawBatch = batchManager.popBatch();
|
|
317
271
|
const shouldGroup =
|
|
318
272
|
!disableGroupedBatching && this.params.groupingManager.shouldGroup(rawBatch);
|
|
319
|
-
if (rawBatch.hasReentrantOps === true && shouldGroup) {
|
|
273
|
+
if (batchManager.options.canRebase && rawBatch.hasReentrantOps === true && shouldGroup) {
|
|
320
274
|
assert(!this.rebasing, 0x6fa /* A rebased batch should never have reentrant ops */);
|
|
321
275
|
// If a batch contains reentrant ops (ops created as a result from processing another op)
|
|
322
276
|
// it needs to be rebased so that we can ensure consistent reference sequence numbers
|
|
@@ -346,6 +300,7 @@ export class Outbox {
|
|
|
346
300
|
*/
|
|
347
301
|
private rebase(rawBatch: IBatch, batchManager: BatchManager) {
|
|
348
302
|
assert(!this.rebasing, 0x6fb /* Reentrancy */);
|
|
303
|
+
assert(batchManager.options.canRebase, "BatchManager does not support rebase");
|
|
349
304
|
|
|
350
305
|
this.rebasing = true;
|
|
351
306
|
for (const message of rawBatch.content) {
|
|
@@ -479,7 +434,6 @@ export class Outbox {
|
|
|
479
434
|
const mainBatch: IBatchCheckpoint = this.mainBatch.checkpoint();
|
|
480
435
|
return {
|
|
481
436
|
mainBatch,
|
|
482
|
-
attachFlowBatch: this.attachFlowBatch.checkpoint(),
|
|
483
437
|
blobAttachBatch: this.blobAttachBatch.checkpoint(),
|
|
484
438
|
};
|
|
485
439
|
}
|
package/src/packageVersion.ts
CHANGED
|
@@ -552,6 +552,7 @@ export class DocumentsSchemaController {
|
|
|
552
552
|
*/
|
|
553
553
|
public maybeSendSchemaMessage(): IDocumentSchemaChangeMessage | undefined {
|
|
554
554
|
if (this.sendOp && this.futureSchema !== undefined) {
|
|
555
|
+
this.sendOp = false;
|
|
555
556
|
assert(
|
|
556
557
|
this.explicitSchemaControl &&
|
|
557
558
|
this.futureSchema.runtime.explicitSchemaControl === true,
|
|
@@ -562,7 +563,6 @@ export class DocumentsSchemaController {
|
|
|
562
563
|
refSeq: this.documentSchema.refSeq,
|
|
563
564
|
};
|
|
564
565
|
}
|
|
565
|
-
this.sendOp = false;
|
|
566
566
|
}
|
|
567
567
|
|
|
568
568
|
/**
|
package/dist/public.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
-
* Licensed under the MIT License.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/*
|
|
7
|
-
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
8
|
-
* Generated by "flub generate entrypoints" in @fluidframework/build-tools.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
export {}
|
|
12
|
-
|
package/lib/public.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
-
* Licensed under the MIT License.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/*
|
|
7
|
-
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
8
|
-
* Generated by "flub generate entrypoints" in @fluidframework/build-tools.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
export {}
|
|
12
|
-
|