@fluidframework/container-runtime 2.1.0 → 2.1.1
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/container-runtime.test-files.tar +0 -0
- package/dist/containerRuntime.d.ts +1 -0
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +40 -34
- package/dist/containerRuntime.js.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.d.ts +7 -7
- package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.js +7 -18
- package/dist/opLifecycle/remoteMessageProcessor.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 +2 -12
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +0 -12
- package/dist/pendingStateManager.js.map +1 -1
- package/lib/containerRuntime.d.ts +1 -0
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +40 -34
- package/lib/containerRuntime.js.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.d.ts +7 -7
- package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.js +7 -18
- package/lib/opLifecycle/remoteMessageProcessor.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 +2 -12
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +0 -12
- package/lib/pendingStateManager.js.map +1 -1
- package/package.json +19 -32
- package/src/containerRuntime.ts +48 -39
- package/src/opLifecycle/remoteMessageProcessor.ts +9 -27
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +2 -21
package/src/containerRuntime.ts
CHANGED
|
@@ -695,7 +695,7 @@ export const makeLegacySendBatchFn =
|
|
|
695
695
|
type MessageWithContext = {
|
|
696
696
|
local: boolean;
|
|
697
697
|
savedOp?: boolean;
|
|
698
|
-
|
|
698
|
+
batchStartCsn: number;
|
|
699
699
|
} & (
|
|
700
700
|
| {
|
|
701
701
|
message: InboundSequencedContainerRuntimeMessage;
|
|
@@ -1267,6 +1267,7 @@ export class ContainerRuntime
|
|
|
1267
1267
|
private dirtyContainer: boolean;
|
|
1268
1268
|
private emitDirtyDocumentEvent = true;
|
|
1269
1269
|
private readonly disableAttachReorder: boolean | undefined;
|
|
1270
|
+
private readonly useDeltaManagerOpsProxy: boolean;
|
|
1270
1271
|
private readonly closeSummarizerDelayMs: number;
|
|
1271
1272
|
private readonly defaultTelemetrySignalSampleCount = 100;
|
|
1272
1273
|
private readonly _perfSignalData: IPerfSignalReport = {
|
|
@@ -1558,8 +1559,8 @@ export class ContainerRuntime
|
|
|
1558
1559
|
);
|
|
1559
1560
|
|
|
1560
1561
|
let outerDeltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>;
|
|
1561
|
-
|
|
1562
|
-
this.mc.config.getBoolean("Fluid.ContainerRuntime.DeltaManagerOpsProxy")
|
|
1562
|
+
this.useDeltaManagerOpsProxy =
|
|
1563
|
+
this.mc.config.getBoolean("Fluid.ContainerRuntime.DeltaManagerOpsProxy") === true;
|
|
1563
1564
|
// The summarizerDeltaManager Proxy is used to lie to the summarizer to convince it is in the right state as a summarizer client.
|
|
1564
1565
|
const summarizerDeltaManagerProxy = new DeltaManagerSummarizerProxy(
|
|
1565
1566
|
this.innerDeltaManager,
|
|
@@ -1568,7 +1569,7 @@ export class ContainerRuntime
|
|
|
1568
1569
|
|
|
1569
1570
|
// The DeltaManagerPendingOpsProxy is used to control the minimum sequence number
|
|
1570
1571
|
// It allows us to lie to the layers below so that they can maintain enough local state for rebasing ops.
|
|
1571
|
-
if (useDeltaManagerOpsProxy) {
|
|
1572
|
+
if (this.useDeltaManagerOpsProxy) {
|
|
1572
1573
|
const pendingOpsDeltaManagerProxy = new DeltaManagerPendingOpsProxy(
|
|
1573
1574
|
summarizerDeltaManagerProxy,
|
|
1574
1575
|
this.pendingStateManager,
|
|
@@ -2634,38 +2635,34 @@ export class ContainerRuntime
|
|
|
2634
2635
|
const messageCopy = { ...messageArg };
|
|
2635
2636
|
// We expect runtime messages to have JSON contents - deserialize it in place.
|
|
2636
2637
|
ensureContentsDeserialized(messageCopy, modernRuntimeMessage, logLegacyCase);
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
const
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
local,
|
|
2666
|
-
modernRuntimeMessage,
|
|
2667
|
-
savedOp,
|
|
2668
|
-
};
|
|
2638
|
+
const processResult = this.remoteMessageProcessor.process(messageCopy);
|
|
2639
|
+
if (processResult === undefined) {
|
|
2640
|
+
// This means the incoming message is an incomplete part of a message or batch
|
|
2641
|
+
// and we need to process more messages before the rest of the system can understand it.
|
|
2642
|
+
return;
|
|
2643
|
+
}
|
|
2644
|
+
for (const message of processResult.messages) {
|
|
2645
|
+
const msg: MessageWithContext = modernRuntimeMessage
|
|
2646
|
+
? {
|
|
2647
|
+
// Cast it since we expect it to be this based on modernRuntimeMessage computation above.
|
|
2648
|
+
// There is nothing really ensuring that anytime original message.type is Operation that
|
|
2649
|
+
// the result messages will be so. In the end modern bool being true only directs to
|
|
2650
|
+
// throw error if ultimately unrecognized without compat details saying otherwise.
|
|
2651
|
+
message: message as InboundSequencedContainerRuntimeMessage,
|
|
2652
|
+
local,
|
|
2653
|
+
modernRuntimeMessage,
|
|
2654
|
+
batchStartCsn: processResult.batchStartCsn,
|
|
2655
|
+
}
|
|
2656
|
+
: // Unrecognized message will be ignored.
|
|
2657
|
+
{
|
|
2658
|
+
message,
|
|
2659
|
+
local,
|
|
2660
|
+
modernRuntimeMessage,
|
|
2661
|
+
batchStartCsn: processResult.batchStartCsn,
|
|
2662
|
+
};
|
|
2663
|
+
msg.savedOp = savedOp;
|
|
2664
|
+
|
|
2665
|
+
// ensure that we observe any re-entrancy, and if needed, rebase ops
|
|
2669
2666
|
this.ensureNoDataModelChanges(() => this.processCore(msg));
|
|
2670
2667
|
}
|
|
2671
2668
|
}
|
|
@@ -2676,13 +2673,14 @@ export class ContainerRuntime
|
|
|
2676
2673
|
* Direct the message to the correct subsystem for processing, and implement other side effects
|
|
2677
2674
|
*/
|
|
2678
2675
|
private processCore(messageWithContext: MessageWithContext) {
|
|
2679
|
-
const { message, local
|
|
2676
|
+
const { message, local } = messageWithContext;
|
|
2680
2677
|
|
|
2681
2678
|
// Intercept to reduce minimum sequence number to the delta manager's minimum sequence number.
|
|
2682
2679
|
// Sequence numbers are not guaranteed to follow any sort of order. Re-entrancy is one of those situations
|
|
2683
2680
|
if (
|
|
2681
|
+
this.useDeltaManagerOpsProxy &&
|
|
2684
2682
|
this.deltaManager.minimumSequenceNumber <
|
|
2685
|
-
|
|
2683
|
+
messageWithContext.message.minimumSequenceNumber
|
|
2686
2684
|
) {
|
|
2687
2685
|
messageWithContext.message.minimumSequenceNumber =
|
|
2688
2686
|
this.deltaManager.minimumSequenceNumber;
|
|
@@ -2696,12 +2694,23 @@ export class ContainerRuntime
|
|
|
2696
2694
|
this._processedClientSequenceNumber = message.clientSequenceNumber;
|
|
2697
2695
|
|
|
2698
2696
|
try {
|
|
2699
|
-
//
|
|
2697
|
+
// See commit that added this assert for more details.
|
|
2698
|
+
// These calls should be made for all but chunked ops:
|
|
2699
|
+
// 1) this.pendingStateManager.processPendingLocalMessage() below
|
|
2700
|
+
// 2) this.resetReconnectCount() below
|
|
2700
2701
|
assert(
|
|
2701
2702
|
message.type !== ContainerMessageType.ChunkedOp,
|
|
2702
2703
|
0x93b /* we should never get here with chunked ops */,
|
|
2703
2704
|
);
|
|
2704
2705
|
|
|
2706
|
+
let localOpMetadata: unknown;
|
|
2707
|
+
if (local && messageWithContext.modernRuntimeMessage) {
|
|
2708
|
+
localOpMetadata = this.pendingStateManager.processPendingLocalMessage(
|
|
2709
|
+
messageWithContext.message,
|
|
2710
|
+
messageWithContext.batchStartCsn,
|
|
2711
|
+
);
|
|
2712
|
+
}
|
|
2713
|
+
|
|
2705
2714
|
// If there are no more pending messages after processing a local message,
|
|
2706
2715
|
// the document is no longer dirty.
|
|
2707
2716
|
if (!this.hasPendingMessages()) {
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
ContainerMessageType,
|
|
14
14
|
type InboundContainerRuntimeMessage,
|
|
15
15
|
type InboundSequencedContainerRuntimeMessage,
|
|
16
|
+
type InboundSequencedContainerRuntimeMessageOrSystemMessage,
|
|
16
17
|
type InboundSequencedRecentlyAddedContainerRuntimeMessage,
|
|
17
18
|
} from "../messageTypes.js";
|
|
18
19
|
import { asBatchMetadata } from "../metadata.js";
|
|
@@ -35,7 +36,6 @@ export class RemoteMessageProcessor {
|
|
|
35
36
|
* @remarks For chunked batches, this is the CSN of the "representative" chunk (the final chunk)
|
|
36
37
|
*/
|
|
37
38
|
private batchStartCsn: number | undefined;
|
|
38
|
-
private readonly processorBatch: InboundSequencedContainerRuntimeMessage[] = [];
|
|
39
39
|
|
|
40
40
|
constructor(
|
|
41
41
|
private readonly opSplitter: OpSplitter,
|
|
@@ -52,7 +52,7 @@ export class RemoteMessageProcessor {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
|
-
* Ungroups and Unchunks the runtime ops
|
|
55
|
+
* Ungroups and Unchunks the runtime ops encapsulated by the single remoteMessage received over the wire
|
|
56
56
|
* @param remoteMessageCopy - A shallow copy of a message from another client, possibly virtualized
|
|
57
57
|
* (grouped, compressed, and/or chunked).
|
|
58
58
|
* Being a shallow copy, it's considered mutable, meaning no other Container or other parallel procedure
|
|
@@ -67,15 +67,13 @@ export class RemoteMessageProcessor {
|
|
|
67
67
|
* 3. If grouped, ungroup the message
|
|
68
68
|
* For more details, see https://github.com/microsoft/FluidFramework/blob/main/packages/runtime/container-runtime/src/opLifecycle/README.md#inbound
|
|
69
69
|
*
|
|
70
|
-
* @returns
|
|
71
|
-
*
|
|
70
|
+
* @returns the unchunked, decompressed, ungrouped, unpacked SequencedContainerRuntimeMessages encapsulated in the remote message.
|
|
71
|
+
* For ops that weren't virtualized (e.g. System ops that the ContainerRuntime will ultimately ignore),
|
|
72
|
+
* a singleton array [remoteMessageCopy] is returned
|
|
72
73
|
*/
|
|
73
|
-
public process(
|
|
74
|
-
remoteMessageCopy: ISequencedDocumentMessage,
|
|
75
|
-
logLegacyCase: (codePath: string) => void,
|
|
76
|
-
):
|
|
74
|
+
public process(remoteMessageCopy: ISequencedDocumentMessage):
|
|
77
75
|
| {
|
|
78
|
-
messages:
|
|
76
|
+
messages: InboundSequencedContainerRuntimeMessageOrSystemMessage[];
|
|
79
77
|
batchStartCsn: number;
|
|
80
78
|
}
|
|
81
79
|
| undefined {
|
|
@@ -109,10 +107,6 @@ export class RemoteMessageProcessor {
|
|
|
109
107
|
this.batchStartCsn === undefined,
|
|
110
108
|
0x9d3 /* Grouped batch interrupting another batch */,
|
|
111
109
|
);
|
|
112
|
-
assert(
|
|
113
|
-
this.processorBatch.length === 0,
|
|
114
|
-
0x9d4 /* Processor batch should be empty on grouped batch */,
|
|
115
|
-
);
|
|
116
110
|
return {
|
|
117
111
|
messages: this.opGroupingManager.ungroupOp(message).map(unpack),
|
|
118
112
|
batchStartCsn: message.clientSequenceNumber,
|
|
@@ -122,21 +116,9 @@ export class RemoteMessageProcessor {
|
|
|
122
116
|
const batchStartCsn = this.getAndUpdateBatchStartCsn(message);
|
|
123
117
|
|
|
124
118
|
// Do a final unpack of runtime messages in case the message was not grouped, compressed, or chunked
|
|
125
|
-
unpackRuntimeMessage(message
|
|
126
|
-
this.processorBatch.push(message as InboundSequencedContainerRuntimeMessage);
|
|
127
|
-
|
|
128
|
-
// this.batchStartCsn is undefined only if we have processed all messages in the batch.
|
|
129
|
-
// If it's still defined, we're still in the middle of a batch, so we return nothing, letting
|
|
130
|
-
// containerRuntime know that we're waiting for more messages to complete the batch.
|
|
131
|
-
if (this.batchStartCsn !== undefined) {
|
|
132
|
-
// batch not yet complete
|
|
133
|
-
return undefined;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
const messages = [...this.processorBatch];
|
|
137
|
-
this.processorBatch.length = 0;
|
|
119
|
+
unpackRuntimeMessage(message);
|
|
138
120
|
return {
|
|
139
|
-
messages,
|
|
121
|
+
messages: [message as InboundSequencedContainerRuntimeMessageOrSystemMessage],
|
|
140
122
|
batchStartCsn,
|
|
141
123
|
};
|
|
142
124
|
}
|
package/src/packageVersion.ts
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
import Deque from "double-ended-queue";
|
|
17
17
|
import { v4 as uuid } from "uuid";
|
|
18
18
|
|
|
19
|
-
import {
|
|
19
|
+
import { InboundSequencedContainerRuntimeMessage } from "./messageTypes.js";
|
|
20
20
|
import { asBatchMetadata, IBatchMetadata } from "./metadata.js";
|
|
21
21
|
import { BatchId, BatchMessage, generateBatchId } from "./opLifecycle/index.js";
|
|
22
22
|
import { pkgVersion } from "./packageVersion.js";
|
|
@@ -293,25 +293,6 @@ export class PendingStateManager implements IDisposable {
|
|
|
293
293
|
}
|
|
294
294
|
}
|
|
295
295
|
|
|
296
|
-
/**
|
|
297
|
-
* Processes the incoming batch from the server. It verifies that messages are received in the right order and
|
|
298
|
-
* that the batch information is correct.
|
|
299
|
-
* @param batch - The batch that is being processed.
|
|
300
|
-
* @param batchStartCsn - The clientSequenceNumber of the start of this message's batch
|
|
301
|
-
*/
|
|
302
|
-
public processPendingLocalBatch(
|
|
303
|
-
batch: InboundSequencedContainerRuntimeMessage[],
|
|
304
|
-
batchStartCsn: number,
|
|
305
|
-
): {
|
|
306
|
-
message: InboundSequencedContainerRuntimeMessage;
|
|
307
|
-
localOpMetadata: unknown;
|
|
308
|
-
}[] {
|
|
309
|
-
return batch.map((message) => ({
|
|
310
|
-
message,
|
|
311
|
-
localOpMetadata: this.processPendingLocalMessage(message, batchStartCsn),
|
|
312
|
-
}));
|
|
313
|
-
}
|
|
314
|
-
|
|
315
296
|
/**
|
|
316
297
|
* Processes a local message once its ack'd by the server. It verifies that there was no data corruption and that
|
|
317
298
|
* the batch information was preserved for batch messages.
|
|
@@ -319,7 +300,7 @@ export class PendingStateManager implements IDisposable {
|
|
|
319
300
|
* @param batchStartCsn - The clientSequenceNumber of the start of this message's batch (assigned during submit)
|
|
320
301
|
* (not to be confused with message.clientSequenceNumber - the overwritten value in case of grouped batching)
|
|
321
302
|
*/
|
|
322
|
-
|
|
303
|
+
public processPendingLocalMessage(
|
|
323
304
|
message: InboundSequencedContainerRuntimeMessage,
|
|
324
305
|
batchStartCsn: number,
|
|
325
306
|
): unknown {
|