@fluidframework/container-runtime 2.0.0-dev-rc.3.0.0.254866 → 2.0.0-dev-rc.4.0.0.261659
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/CHANGELOG.md +23 -0
- package/api-report/container-runtime.api.md +33 -19
- package/dist/batchTracker.d.ts +1 -1
- package/dist/batchTracker.d.ts.map +1 -1
- package/dist/batchTracker.js.map +1 -1
- package/dist/channelCollection.d.ts +5 -3
- package/dist/channelCollection.d.ts.map +1 -1
- package/dist/channelCollection.js +67 -15
- package/dist/channelCollection.js.map +1 -1
- package/dist/connectionTelemetry.d.ts +1 -1
- package/dist/connectionTelemetry.d.ts.map +1 -1
- package/dist/connectionTelemetry.js +54 -5
- package/dist/connectionTelemetry.js.map +1 -1
- package/dist/containerRuntime.d.ts +17 -27
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +174 -143
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStore.d.ts +1 -1
- package/dist/dataStore.d.ts.map +1 -1
- package/dist/dataStore.js.map +1 -1
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +1 -0
- package/dist/dataStoreContext.js.map +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/deltaManagerSummarizerProxy.d.ts +18 -6
- package/dist/deltaManagerSummarizerProxy.d.ts.map +1 -1
- package/dist/deltaManagerSummarizerProxy.js +38 -19
- package/dist/deltaManagerSummarizerProxy.js.map +1 -1
- package/dist/deltaScheduler.d.ts +1 -1
- package/dist/deltaScheduler.d.ts.map +1 -1
- package/dist/deltaScheduler.js.map +1 -1
- package/dist/gc/garbageCollection.d.ts +5 -12
- 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 +27 -6
- 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 +14 -4
- 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/{alpha.d.ts → legacy.d.ts} +3 -1
- 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 +0 -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/opDecompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opDecompressor.js +6 -6
- package/dist/opLifecycle/opDecompressor.js.map +1 -1
- package/dist/opLifecycle/opGroupingManager.js +2 -2
- package/dist/opLifecycle/opGroupingManager.js.map +1 -1
- package/dist/opLifecycle/opSplitter.js +1 -1
- package/dist/opLifecycle/opSplitter.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 +2 -34
- package/dist/opLifecycle/outbox.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/pendingStateManager.d.ts +3 -2
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +17 -10
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/public.d.ts +3 -0
- package/dist/scheduleManager.d.ts +1 -1
- package/dist/scheduleManager.d.ts.map +1 -1
- package/dist/scheduleManager.js.map +1 -1
- package/dist/summary/documentSchema.d.ts +3 -1
- package/dist/summary/documentSchema.d.ts.map +1 -1
- package/dist/summary/documentSchema.js +34 -16
- package/dist/summary/documentSchema.js.map +1 -1
- package/dist/summary/orderedClientElection.d.ts +1 -1
- package/dist/summary/orderedClientElection.d.ts.map +1 -1
- package/dist/summary/orderedClientElection.js.map +1 -1
- package/dist/summary/summarizer.d.ts +1 -2
- package/dist/summary/summarizer.d.ts.map +1 -1
- package/dist/summary/summarizer.js.map +1 -1
- package/dist/summary/summarizerClientElection.d.ts +1 -1
- package/dist/summary/summarizerClientElection.d.ts.map +1 -1
- package/dist/summary/summarizerClientElection.js.map +1 -1
- package/dist/summary/summarizerHeuristics.d.ts +1 -1
- package/dist/summary/summarizerHeuristics.d.ts.map +1 -1
- package/dist/summary/summarizerHeuristics.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.d.ts +4 -3
- package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.js +4 -10
- package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +2 -3
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +1 -2
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js +2 -9
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/dist/summary/summarizerTypes.d.ts +2 -3
- package/dist/summary/summarizerTypes.d.ts.map +1 -1
- package/dist/summary/summarizerTypes.js.map +1 -1
- package/dist/summary/summaryCollection.d.ts +1 -1
- package/dist/summary/summaryCollection.d.ts.map +1 -1
- package/dist/summary/summaryCollection.js.map +1 -1
- package/dist/summary/summaryGenerator.d.ts +1 -2
- package/dist/summary/summaryGenerator.d.ts.map +1 -1
- package/dist/summary/summaryGenerator.js +3 -2
- package/dist/summary/summaryGenerator.js.map +1 -1
- package/dist/summary/summaryManager.d.ts.map +1 -1
- package/dist/summary/summaryManager.js.map +1 -1
- package/{dist/beta.d.ts → internal.d.ts} +2 -0
- package/{lib/beta.d.ts → legacy.d.ts} +2 -0
- package/lib/batchTracker.d.ts +1 -1
- package/lib/batchTracker.d.ts.map +1 -1
- package/lib/batchTracker.js.map +1 -1
- package/lib/channelCollection.d.ts +5 -3
- package/lib/channelCollection.d.ts.map +1 -1
- package/lib/channelCollection.js +69 -17
- package/lib/channelCollection.js.map +1 -1
- package/lib/connectionTelemetry.d.ts +1 -1
- package/lib/connectionTelemetry.d.ts.map +1 -1
- package/lib/connectionTelemetry.js +49 -0
- package/lib/connectionTelemetry.js.map +1 -1
- package/lib/containerRuntime.d.ts +17 -27
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +174 -143
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStore.d.ts +1 -1
- package/lib/dataStore.d.ts.map +1 -1
- package/lib/dataStore.js +1 -1
- package/lib/dataStore.js.map +1 -1
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +1 -0
- package/lib/dataStoreContext.js.map +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/deltaManagerSummarizerProxy.d.ts +18 -6
- package/lib/deltaManagerSummarizerProxy.d.ts.map +1 -1
- package/lib/deltaManagerSummarizerProxy.js +36 -18
- package/lib/deltaManagerSummarizerProxy.js.map +1 -1
- package/lib/deltaScheduler.d.ts +1 -1
- package/lib/deltaScheduler.d.ts.map +1 -1
- package/lib/deltaScheduler.js.map +1 -1
- package/lib/gc/garbageCollection.d.ts +5 -12
- 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 +27 -6
- 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 +14 -4
- 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/{alpha.d.ts → legacy.d.ts} +3 -1
- 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 +0 -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/opDecompressor.d.ts.map +1 -1
- package/lib/opLifecycle/opDecompressor.js +6 -6
- package/lib/opLifecycle/opDecompressor.js.map +1 -1
- package/lib/opLifecycle/opGroupingManager.js +2 -2
- package/lib/opLifecycle/opGroupingManager.js.map +1 -1
- package/lib/opLifecycle/opSplitter.js +1 -1
- package/lib/opLifecycle/opSplitter.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 +2 -34
- package/lib/opLifecycle/outbox.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/pendingStateManager.d.ts +3 -2
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +18 -11
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/public.d.ts +3 -0
- package/lib/scheduleManager.d.ts +1 -1
- package/lib/scheduleManager.d.ts.map +1 -1
- package/lib/scheduleManager.js.map +1 -1
- package/lib/summary/documentSchema.d.ts +3 -1
- package/lib/summary/documentSchema.d.ts.map +1 -1
- package/lib/summary/documentSchema.js +34 -16
- package/lib/summary/documentSchema.js.map +1 -1
- package/lib/summary/orderedClientElection.d.ts +1 -1
- package/lib/summary/orderedClientElection.d.ts.map +1 -1
- package/lib/summary/orderedClientElection.js +1 -1
- package/lib/summary/orderedClientElection.js.map +1 -1
- package/lib/summary/summarizer.d.ts +1 -2
- package/lib/summary/summarizer.d.ts.map +1 -1
- package/lib/summary/summarizer.js.map +1 -1
- package/lib/summary/summarizerClientElection.d.ts +1 -1
- package/lib/summary/summarizerClientElection.d.ts.map +1 -1
- package/lib/summary/summarizerClientElection.js.map +1 -1
- package/lib/summary/summarizerHeuristics.d.ts +1 -1
- package/lib/summary/summarizerHeuristics.d.ts.map +1 -1
- package/lib/summary/summarizerHeuristics.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.d.ts +4 -3
- package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.js +4 -10
- package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +2 -3
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +1 -2
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js +2 -9
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/lib/summary/summarizerTypes.d.ts +2 -3
- package/lib/summary/summarizerTypes.d.ts.map +1 -1
- package/lib/summary/summarizerTypes.js.map +1 -1
- package/lib/summary/summaryCollection.d.ts +1 -1
- package/lib/summary/summaryCollection.d.ts.map +1 -1
- package/lib/summary/summaryCollection.js.map +1 -1
- package/lib/summary/summaryGenerator.d.ts +1 -2
- package/lib/summary/summaryGenerator.d.ts.map +1 -1
- package/lib/summary/summaryGenerator.js +4 -3
- package/lib/summary/summaryGenerator.js.map +1 -1
- package/lib/summary/summaryManager.d.ts.map +1 -1
- package/lib/summary/summaryManager.js +1 -1
- package/lib/summary/summaryManager.js.map +1 -1
- package/package.json +33 -57
- package/src/batchTracker.ts +1 -2
- package/src/channelCollection.ts +87 -35
- package/src/connectionTelemetry.ts +58 -3
- package/src/containerRuntime.ts +214 -222
- package/src/dataStore.ts +5 -2
- package/src/dataStoreContext.ts +1 -0
- package/src/dataStoreContexts.ts +13 -2
- package/src/deltaManagerSummarizerProxy.ts +43 -21
- package/src/deltaScheduler.ts +1 -2
- package/src/gc/garbageCollection.ts +64 -42
- package/src/gc/gcDefinitions.ts +22 -10
- package/src/gc/gcHelpers.ts +14 -1
- package/src/gc/gcTelemetry.ts +57 -50
- 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 +0 -14
- package/src/opLifecycle/opDecompressor.ts +12 -6
- package/src/opLifecycle/opGroupingManager.ts +2 -2
- package/src/opLifecycle/opSplitter.ts +1 -1
- package/src/opLifecycle/outbox.ts +2 -49
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +28 -15
- package/src/scheduleManager.ts +1 -1
- package/src/summary/documentSchema.ts +52 -18
- package/src/summary/orderedClientElection.ts +5 -2
- package/src/summary/summarizer.ts +1 -1
- package/src/summary/summarizerClientElection.ts +1 -1
- package/src/summary/summarizerHeuristics.ts +1 -1
- package/src/summary/summarizerNode/summarizerNode.ts +3 -12
- package/src/summary/summarizerNode/summarizerNodeUtils.ts +2 -3
- package/src/summary/summarizerNode/summarizerNodeWithGc.ts +1 -10
- package/src/summary/summarizerTypes.ts +5 -3
- package/src/summary/summaryCollection.ts +1 -1
- package/src/summary/summaryGenerator.ts +19 -8
- package/src/summary/summaryManager.ts +5 -2
package/src/gc/gcTelemetry.ts
CHANGED
|
@@ -5,15 +5,14 @@
|
|
|
5
5
|
|
|
6
6
|
import { IGarbageCollectionData } from "@fluidframework/runtime-definitions";
|
|
7
7
|
import {
|
|
8
|
-
type ITelemetryGenericEventExt,
|
|
9
8
|
ITelemetryLoggerExt,
|
|
10
|
-
} from "@fluidframework/telemetry-utils";
|
|
11
|
-
import {
|
|
12
9
|
MonitoringContext,
|
|
13
10
|
generateStack,
|
|
14
11
|
tagCodeArtifacts,
|
|
12
|
+
type ITelemetryGenericEventExt,
|
|
15
13
|
} from "@fluidframework/telemetry-utils/internal";
|
|
16
14
|
|
|
15
|
+
import type { Tagged } from "@fluidframework/core-interfaces";
|
|
17
16
|
import { RuntimeHeaderData } from "../containerRuntime.js";
|
|
18
17
|
import { ICreateContainerMetadata } from "../summary/index.js";
|
|
19
18
|
|
|
@@ -43,11 +42,12 @@ interface ICommonProps {
|
|
|
43
42
|
|
|
44
43
|
/** The event that is logged when unreferenced node is used after a certain time. */
|
|
45
44
|
interface IUnreferencedEventProps extends ICreateContainerMetadata, ICommonProps {
|
|
45
|
+
/** The id that GC uses to track the node. May or may not match id */
|
|
46
|
+
trackedId: string;
|
|
46
47
|
state: UnreferencedState;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
};
|
|
48
|
+
/** The full path (in GC Path format) to the node in question */
|
|
49
|
+
id: Tagged<string>;
|
|
50
|
+
fromId?: Tagged<string>;
|
|
51
51
|
type: GCNodeType;
|
|
52
52
|
unrefTime: number;
|
|
53
53
|
age: number;
|
|
@@ -56,19 +56,24 @@ interface IUnreferencedEventProps extends ICreateContainerMetadata, ICommonProps
|
|
|
56
56
|
[K in keyof GCFeatureMatrix]: GCFeatureMatrix[K];
|
|
57
57
|
};
|
|
58
58
|
timeout?: number;
|
|
59
|
-
fromId?: {
|
|
60
|
-
value: string;
|
|
61
|
-
tag: string;
|
|
62
|
-
};
|
|
63
59
|
}
|
|
64
60
|
|
|
65
61
|
/** Properties passed to nodeUsed function when a node is used. */
|
|
66
62
|
interface INodeUsageProps extends ICommonProps {
|
|
63
|
+
/** The full path (in GC Path format) to the node in question */
|
|
67
64
|
id: string;
|
|
65
|
+
/** Latest timestamp received from the server, as a baseline for computing GC state/age */
|
|
68
66
|
currentReferenceTimestampMs: number | undefined;
|
|
67
|
+
/** The package path of the node. This may not be available if the node hasn't been loaded yet */
|
|
69
68
|
packagePath: readonly string[] | undefined;
|
|
69
|
+
/** In case of Revived - what node added the reference? */
|
|
70
70
|
fromId?: string;
|
|
71
|
+
/** In case of Revived - was it revived due to autorecovery? */
|
|
71
72
|
autorecovery?: true;
|
|
73
|
+
/** URL (including query string) if this usage came from a request */
|
|
74
|
+
requestUrl?: string;
|
|
75
|
+
/** Original request headers if this usage came from a request or handle.get */
|
|
76
|
+
requestHeaders?: string;
|
|
72
77
|
}
|
|
73
78
|
|
|
74
79
|
/**
|
|
@@ -143,18 +148,34 @@ export class GCTelemetryTracker {
|
|
|
143
148
|
}
|
|
144
149
|
|
|
145
150
|
/**
|
|
146
|
-
* Called when a node is used. If the node is
|
|
151
|
+
* Called when a node is used. If the node is inactive or tombstoned, log telemetry indicating object is used
|
|
147
152
|
* when it should not have been.
|
|
153
|
+
* @param trackedId - The id that GC uses to track the node. For SubDataStore nodes, this should be the DataStore ID.
|
|
154
|
+
* @param INodeUsageProps - All kind of details about this event to be logged
|
|
148
155
|
*/
|
|
149
|
-
public nodeUsed(
|
|
156
|
+
public nodeUsed(
|
|
157
|
+
trackedId: string,
|
|
158
|
+
{
|
|
159
|
+
usageType,
|
|
160
|
+
currentReferenceTimestampMs,
|
|
161
|
+
packagePath,
|
|
162
|
+
id: untaggedId,
|
|
163
|
+
fromId: untaggedFromId,
|
|
164
|
+
isTombstoned,
|
|
165
|
+
...otherNodeUsageProps
|
|
166
|
+
}: INodeUsageProps,
|
|
167
|
+
) {
|
|
150
168
|
// If there is no reference timestamp to work with, no ops have been processed after creation. If so, skip
|
|
151
169
|
// logging as nothing interesting would have happened worth logging.
|
|
152
|
-
if (
|
|
170
|
+
if (currentReferenceTimestampMs === undefined) {
|
|
153
171
|
return;
|
|
154
172
|
}
|
|
155
173
|
|
|
156
|
-
|
|
157
|
-
|
|
174
|
+
// Note: For SubDataStore Load usage, trackedId will be the DataStore's id, not the full path in question.
|
|
175
|
+
// This is necessary because the SubDataStore path may be unrecognized by GC (if suited for a custom request handler)
|
|
176
|
+
const nodeStateTracker = this.getNodeStateTracker(trackedId);
|
|
177
|
+
const nodeType = this.getNodeType(untaggedId);
|
|
178
|
+
|
|
158
179
|
const timeout = (() => {
|
|
159
180
|
switch (nodeStateTracker?.state) {
|
|
160
181
|
case UnreferencedState.Inactive:
|
|
@@ -170,33 +191,27 @@ export class GCTelemetryTracker {
|
|
|
170
191
|
return undefined;
|
|
171
192
|
}
|
|
172
193
|
})();
|
|
173
|
-
const {
|
|
174
|
-
usageType,
|
|
175
|
-
currentReferenceTimestampMs,
|
|
176
|
-
packagePath,
|
|
177
|
-
id: untaggedId,
|
|
178
|
-
fromId: untaggedFromId,
|
|
179
|
-
...propsToLog
|
|
180
|
-
} = nodeUsageProps;
|
|
181
194
|
const { persistedGcFeatureMatrix, ...configs } = this.configs;
|
|
182
|
-
const unrefEventProps
|
|
195
|
+
const unrefEventProps = {
|
|
196
|
+
trackedId,
|
|
183
197
|
type: nodeType,
|
|
184
198
|
unrefTime: nodeStateTracker?.unreferencedTimestampMs ?? -1,
|
|
185
199
|
age:
|
|
186
200
|
nodeStateTracker !== undefined
|
|
187
|
-
?
|
|
188
|
-
nodeStateTracker.unreferencedTimestampMs
|
|
201
|
+
? currentReferenceTimestampMs - nodeStateTracker.unreferencedTimestampMs
|
|
189
202
|
: -1,
|
|
190
203
|
timeout,
|
|
204
|
+
isTombstoned,
|
|
191
205
|
...tagCodeArtifacts({ id: untaggedId, fromId: untaggedFromId }),
|
|
192
|
-
...
|
|
206
|
+
...otherNodeUsageProps,
|
|
193
207
|
...this.createContainerMetadata,
|
|
194
208
|
gcConfigs: { ...configs, ...persistedGcFeatureMatrix },
|
|
195
|
-
}
|
|
209
|
+
} satisfies Omit<IUnreferencedEventProps, "state" | "usageType"> &
|
|
210
|
+
typeof otherNodeUsageProps;
|
|
196
211
|
|
|
197
212
|
// If the node that is used is tombstoned, log a tombstone telemetry.
|
|
198
|
-
if (
|
|
199
|
-
this.logTombstoneUsageTelemetry(
|
|
213
|
+
if (isTombstoned) {
|
|
214
|
+
this.logTombstoneUsageTelemetry(unrefEventProps, nodeType, usageType, packagePath);
|
|
200
215
|
}
|
|
201
216
|
|
|
202
217
|
// After logging tombstone telemetry, if the node's unreferenced state is not tracked, there is nothing
|
|
@@ -206,16 +221,9 @@ export class GCTelemetryTracker {
|
|
|
206
221
|
}
|
|
207
222
|
|
|
208
223
|
const state = nodeStateTracker.state;
|
|
209
|
-
const uniqueEventId = `${state}-${
|
|
224
|
+
const uniqueEventId = `${state}-${untaggedId}-${usageType}`;
|
|
210
225
|
|
|
211
|
-
if (
|
|
212
|
-
!this.shouldLogNonActiveEvent(
|
|
213
|
-
nodeType,
|
|
214
|
-
nodeUsageProps.usageType,
|
|
215
|
-
nodeStateTracker,
|
|
216
|
-
uniqueEventId,
|
|
217
|
-
)
|
|
218
|
-
) {
|
|
226
|
+
if (!this.shouldLogNonActiveEvent(nodeType, usageType, nodeStateTracker, uniqueEventId)) {
|
|
219
227
|
return;
|
|
220
228
|
}
|
|
221
229
|
|
|
@@ -229,8 +237,8 @@ export class GCTelemetryTracker {
|
|
|
229
237
|
// SweepReady errors are usages of Objects that will be deleted by GC Sweep!
|
|
230
238
|
if (this.isSummarizerClient) {
|
|
231
239
|
this.pendingEventsQueue.push({
|
|
232
|
-
...unrefEventProps,
|
|
233
|
-
usageType
|
|
240
|
+
...unrefEventProps, // Note: Contains some properties from INodeUsageProps as well
|
|
241
|
+
usageType,
|
|
234
242
|
state,
|
|
235
243
|
});
|
|
236
244
|
} else {
|
|
@@ -238,11 +246,11 @@ export class GCTelemetryTracker {
|
|
|
238
246
|
// summarizer clients if they are based off of user actions (such as scrolling to content for these objects)
|
|
239
247
|
// Events generated:
|
|
240
248
|
// InactiveObject_Loaded, SweepReadyObject_Loaded
|
|
241
|
-
if (
|
|
249
|
+
if (usageType === "Loaded") {
|
|
242
250
|
const { id, fromId, headers, gcConfigs, ...detailedProps } = unrefEventProps;
|
|
243
251
|
const event = {
|
|
244
|
-
eventName: `${state}Object_${
|
|
245
|
-
...tagCodeArtifacts({ pkg:
|
|
252
|
+
eventName: `${state}Object_${usageType}`,
|
|
253
|
+
...tagCodeArtifacts({ pkg: packagePath?.join("/") }),
|
|
246
254
|
stack: generateStack(),
|
|
247
255
|
id,
|
|
248
256
|
fromId,
|
|
@@ -262,10 +270,10 @@ export class GCTelemetryTracker {
|
|
|
262
270
|
* Logs telemetry when a tombstoned object is changed, revived or loaded.
|
|
263
271
|
*/
|
|
264
272
|
private logTombstoneUsageTelemetry(
|
|
265
|
-
nodeUsageProps: INodeUsageProps,
|
|
266
273
|
unrefEventProps: Omit<IUnreferencedEventProps, "state" | "usageType">,
|
|
267
274
|
nodeType: GCNodeType,
|
|
268
275
|
usageType: NodeUsageType,
|
|
276
|
+
packagePath?: readonly string[],
|
|
269
277
|
) {
|
|
270
278
|
// This will log the following events:
|
|
271
279
|
// GC_Tombstone_DataStore_Requested, GC_Tombstone_DataStore_Changed, GC_Tombstone_DataStore_Revived
|
|
@@ -275,12 +283,12 @@ export class GCTelemetryTracker {
|
|
|
275
283
|
const eventUsageName = usageType === "Loaded" ? "Requested" : usageType;
|
|
276
284
|
const event = {
|
|
277
285
|
eventName: `GC_Tombstone_${nodeType}_${eventUsageName}`,
|
|
278
|
-
|
|
286
|
+
...tagCodeArtifacts({ pkg: packagePath?.join("/") }),
|
|
279
287
|
stack: generateStack(),
|
|
280
288
|
id,
|
|
281
289
|
fromId,
|
|
282
290
|
headers: { ...headers },
|
|
283
|
-
details: detailedProps,
|
|
291
|
+
details: detailedProps, // Also includes some properties from INodeUsageProps type
|
|
284
292
|
gcConfigs,
|
|
285
293
|
tombstoneFlags: {
|
|
286
294
|
DisableTombstone: this.mc.config.getBoolean(disableTombstoneKey),
|
|
@@ -372,7 +380,6 @@ export class GCTelemetryTracker {
|
|
|
372
380
|
// InactiveObject_Loaded, InactiveObject_Changed, InactiveObject_Revived
|
|
373
381
|
// SweepReadyObject_Loaded, SweepReadyObject_Changed, SweepReadyObject_Revived
|
|
374
382
|
for (const eventProps of this.pendingEventsQueue) {
|
|
375
|
-
// const { usageType, state, id, fromId, ...propsToLog } = eventProps;
|
|
376
383
|
const { usageType, state, id, fromId, headers, gcConfigs, ...detailedProps } =
|
|
377
384
|
eventProps;
|
|
378
385
|
/**
|
|
@@ -381,7 +388,7 @@ export class GCTelemetryTracker {
|
|
|
381
388
|
* Loaded and Changed events are logged only if the node is not active. If the node is active, it was
|
|
382
389
|
* revived and a Revived event will be logged for it.
|
|
383
390
|
*/
|
|
384
|
-
const nodeStateTracker = this.getNodeStateTracker(
|
|
391
|
+
const nodeStateTracker = this.getNodeStateTracker(detailedProps.trackedId); // Note: This is never SubDataStore path
|
|
385
392
|
const active =
|
|
386
393
|
nodeStateTracker === undefined ||
|
|
387
394
|
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,7 +9,6 @@ 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;
|
|
14
13
|
}
|
|
15
14
|
|
|
@@ -72,19 +71,6 @@ export class BatchManager {
|
|
|
72
71
|
// initially stored as base64, and that requires only 2 extra escape characters.
|
|
73
72
|
const socketMessageSize = contentSize + opOverhead * opCount;
|
|
74
73
|
|
|
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
74
|
if (socketMessageSize >= this.options.hardLimit) {
|
|
89
75
|
return false;
|
|
90
76
|
}
|
|
@@ -98,7 +98,10 @@ export class OpDecompressor {
|
|
|
98
98
|
message.compression === undefined || message.compression === CompressionAlgorithms.lz4,
|
|
99
99
|
0x511 /* Only lz4 compression is supported */,
|
|
100
100
|
);
|
|
101
|
-
assert(
|
|
101
|
+
assert(
|
|
102
|
+
this.isCompressedMessage(message),
|
|
103
|
+
0x940 /* provided message should be compressed */,
|
|
104
|
+
);
|
|
102
105
|
|
|
103
106
|
assert(this.activeBatch === false, 0x4b8 /* shouldn't have multiple active batches */);
|
|
104
107
|
this.activeBatch = true;
|
|
@@ -107,7 +110,7 @@ export class OpDecompressor {
|
|
|
107
110
|
if (batchMetadata === undefined) {
|
|
108
111
|
this.isSingleMessageBatch = true;
|
|
109
112
|
} else {
|
|
110
|
-
assert(batchMetadata === true,
|
|
113
|
+
assert(batchMetadata === true, 0x941 /* invalid batch metadata */);
|
|
111
114
|
}
|
|
112
115
|
|
|
113
116
|
const contents = IsoBuffer.from(
|
|
@@ -125,9 +128,12 @@ export class OpDecompressor {
|
|
|
125
128
|
* @returns the unrolled `ISequencedDocumentMessage`
|
|
126
129
|
*/
|
|
127
130
|
public unroll(message: ISequencedDocumentMessage): ISequencedDocumentMessage {
|
|
128
|
-
assert(this.currentlyUnrolling,
|
|
129
|
-
assert(this.rootMessageContents !== undefined,
|
|
130
|
-
assert(
|
|
131
|
+
assert(this.currentlyUnrolling, 0x942 /* not currently unrolling */);
|
|
132
|
+
assert(this.rootMessageContents !== undefined, 0x943 /* missing rootMessageContents */);
|
|
133
|
+
assert(
|
|
134
|
+
this.rootMessageContents.length > this.processedCount,
|
|
135
|
+
0x944 /* no more content to unroll */,
|
|
136
|
+
);
|
|
131
137
|
|
|
132
138
|
const batchMetadata = (message.metadata as IBatchMetadata | undefined)?.batch;
|
|
133
139
|
|
|
@@ -149,7 +155,7 @@ export class OpDecompressor {
|
|
|
149
155
|
return newMessage(message, this.rootMessageContents[this.processedCount++]);
|
|
150
156
|
}
|
|
151
157
|
|
|
152
|
-
assert(batchMetadata === undefined,
|
|
158
|
+
assert(batchMetadata === undefined, 0x945 /* invalid batch metadata */);
|
|
153
159
|
assert(message.contents === undefined, 0x512 /* Expecting empty message */);
|
|
154
160
|
|
|
155
161
|
// Continuation of compressed batch
|
|
@@ -50,7 +50,7 @@ export class OpGroupingManager {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
public groupBatch(batch: IBatch): IBatch {
|
|
53
|
-
assert(this.shouldGroup(batch),
|
|
53
|
+
assert(this.shouldGroup(batch), 0x946 /* cannot group the provided batch */);
|
|
54
54
|
|
|
55
55
|
if (batch.content.length >= 1000) {
|
|
56
56
|
this.logger.sendTelemetryEvent({
|
|
@@ -96,7 +96,7 @@ export class OpGroupingManager {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
public ungroupOp(op: ISequencedDocumentMessage): ISequencedDocumentMessage[] {
|
|
99
|
-
assert(isGroupContents(op.contents),
|
|
99
|
+
assert(isGroupContents(op.contents), 0x947 /* can only ungroup a grouped batch */);
|
|
100
100
|
const contents: IGroupedBatchMessageContents = op.contents;
|
|
101
101
|
|
|
102
102
|
let fakeCsn = 1;
|
|
@@ -182,7 +182,7 @@ export class OpSplitter {
|
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
public processChunk(message: ISequencedDocumentMessage): ProcessChunkResult {
|
|
185
|
-
assert(isChunkedContents(message.contents),
|
|
185
|
+
assert(isChunkedContents(message.contents), 0x948 /* message not of type ChunkedOp */);
|
|
186
186
|
const contents: IChunkedContents = message.contents;
|
|
187
187
|
|
|
188
188
|
// TODO: Verify whether this should be able to handle server-generated ops (with null clientId)
|
|
@@ -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.attachFlowBatch = new BatchManager({ hardLimit, softLimit });
|
|
119
115
|
this.mainBatch = new BatchManager({ hardLimit });
|
|
120
116
|
this.blobAttachBatch = new BatchManager({ hardLimit });
|
|
121
117
|
this.idAllocationBatch = new BatchManager({ hardLimit });
|
|
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
|
}
|
|
@@ -479,7 +433,6 @@ export class Outbox {
|
|
|
479
433
|
const mainBatch: IBatchCheckpoint = this.mainBatch.checkpoint();
|
|
480
434
|
return {
|
|
481
435
|
mainBatch,
|
|
482
|
-
attachFlowBatch: this.attachFlowBatch.checkpoint(),
|
|
483
436
|
blobAttachBatch: this.blobAttachBatch.checkpoint(),
|
|
484
437
|
};
|
|
485
438
|
}
|
package/src/packageVersion.ts
CHANGED
|
@@ -7,8 +7,11 @@ import { ICriticalContainerError } from "@fluidframework/container-definitions";
|
|
|
7
7
|
import { IDisposable } from "@fluidframework/core-interfaces";
|
|
8
8
|
import { assert, Lazy } from "@fluidframework/core-utils/internal";
|
|
9
9
|
import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
|
|
10
|
-
import {
|
|
11
|
-
|
|
10
|
+
import {
|
|
11
|
+
ITelemetryLoggerExt,
|
|
12
|
+
DataProcessingError,
|
|
13
|
+
LoggingError,
|
|
14
|
+
} from "@fluidframework/telemetry-utils/internal";
|
|
12
15
|
import Deque from "double-ended-queue";
|
|
13
16
|
|
|
14
17
|
import { InboundSequencedContainerRuntimeMessage } from "./messageTypes.js";
|
|
@@ -25,6 +28,7 @@ export interface IPendingMessage {
|
|
|
25
28
|
content: string;
|
|
26
29
|
localOpMetadata: unknown;
|
|
27
30
|
opMetadata: Record<string, unknown> | undefined;
|
|
31
|
+
sequenceNumber?: number;
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
export interface IPendingLocalState {
|
|
@@ -119,22 +123,31 @@ export class PendingStateManager implements IDisposable {
|
|
|
119
123
|
return this.pendingMessagesCount !== 0;
|
|
120
124
|
}
|
|
121
125
|
|
|
122
|
-
public getLocalState(): IPendingLocalState
|
|
126
|
+
public getLocalState(snapshotSequenceNumber?: number): IPendingLocalState {
|
|
123
127
|
assert(
|
|
124
128
|
this.initialMessages.isEmpty(),
|
|
125
129
|
0x2e9 /* "Must call getLocalState() after applying initial states" */,
|
|
126
130
|
);
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
131
|
+
const newSavedOps = [...this.savedOps].filter((message) => {
|
|
132
|
+
assert(
|
|
133
|
+
message.sequenceNumber !== undefined,
|
|
134
|
+
"saved op should already have a sequence number",
|
|
135
|
+
);
|
|
136
|
+
return message.sequenceNumber >= (snapshotSequenceNumber ?? 0);
|
|
137
|
+
});
|
|
138
|
+
this.pendingMessages.toArray().forEach((message) => {
|
|
139
|
+
if (
|
|
140
|
+
snapshotSequenceNumber !== undefined &&
|
|
141
|
+
message.referenceSequenceNumber < snapshotSequenceNumber
|
|
142
|
+
) {
|
|
143
|
+
throw new LoggingError("trying to stash ops older than our latest snapshot");
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
return {
|
|
147
|
+
pendingStates: [...newSavedOps, ...this.pendingMessages.toArray()].map((message) => {
|
|
148
|
+
return { ...message, localOpMetadata: undefined };
|
|
149
|
+
}),
|
|
150
|
+
};
|
|
138
151
|
}
|
|
139
152
|
|
|
140
153
|
constructor(
|
|
@@ -221,13 +234,13 @@ export class PendingStateManager implements IDisposable {
|
|
|
221
234
|
public processPendingLocalMessage(message: InboundSequencedContainerRuntimeMessage): unknown {
|
|
222
235
|
// Pre-processing part - This may be the start of a batch.
|
|
223
236
|
this.maybeProcessBatchBegin(message);
|
|
224
|
-
|
|
225
237
|
// Get the next message from the pending queue. Verify a message exists.
|
|
226
238
|
const pendingMessage = this.pendingMessages.peekFront();
|
|
227
239
|
assert(
|
|
228
240
|
pendingMessage !== undefined,
|
|
229
241
|
0x169 /* "No pending message found for this remote message" */,
|
|
230
242
|
);
|
|
243
|
+
pendingMessage.sequenceNumber = message.sequenceNumber;
|
|
231
244
|
this.savedOps.push(pendingMessage);
|
|
232
245
|
|
|
233
246
|
this.pendingMessages.shift();
|
package/src/scheduleManager.ts
CHANGED
|
@@ -9,8 +9,8 @@ import { IDeltaManager } from "@fluidframework/container-definitions";
|
|
|
9
9
|
import { assert } from "@fluidframework/core-utils/internal";
|
|
10
10
|
import { isRuntimeMessage } from "@fluidframework/driver-utils/internal";
|
|
11
11
|
import { IDocumentMessage, ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
|
|
12
|
-
import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
|
|
13
12
|
import {
|
|
13
|
+
ITelemetryLoggerExt,
|
|
14
14
|
DataCorruptionError,
|
|
15
15
|
DataProcessingError,
|
|
16
16
|
createChildLogger,
|