@fluidframework/container-runtime 2.1.0-281041 → 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/CHANGELOG.md +4 -0
- package/README.md +4 -4
- 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 +50 -36
- package/dist/containerRuntime.js.map +1 -1
- package/dist/opLifecycle/batchManager.d.ts.map +1 -1
- package/dist/opLifecycle/batchManager.js +1 -1
- package/dist/opLifecycle/batchManager.js.map +1 -1
- package/dist/opLifecycle/index.d.ts +1 -1
- package/dist/opLifecycle/index.d.ts.map +1 -1
- package/dist/opLifecycle/index.js +2 -1
- package/dist/opLifecycle/index.js.map +1 -1
- package/dist/opLifecycle/outbox.js +1 -1
- package/dist/opLifecycle/outbox.js.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.d.ts +9 -7
- package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.js +24 -23
- package/dist/opLifecycle/remoteMessageProcessor.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/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 +51 -37
- package/lib/containerRuntime.js.map +1 -1
- package/lib/opLifecycle/batchManager.d.ts.map +1 -1
- package/lib/opLifecycle/batchManager.js +1 -1
- package/lib/opLifecycle/batchManager.js.map +1 -1
- package/lib/opLifecycle/index.d.ts +1 -1
- package/lib/opLifecycle/index.d.ts.map +1 -1
- package/lib/opLifecycle/index.js +1 -1
- package/lib/opLifecycle/index.js.map +1 -1
- package/lib/opLifecycle/outbox.js +1 -1
- package/lib/opLifecycle/outbox.js.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.d.ts +9 -7
- package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.js +22 -22
- package/lib/opLifecycle/remoteMessageProcessor.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/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 +22 -35
- package/src/containerRuntime.ts +62 -41
- package/src/opLifecycle/batchManager.ts +4 -1
- package/src/opLifecycle/index.ts +5 -1
- package/src/opLifecycle/outbox.ts +1 -1
- package/src/opLifecycle/remoteMessageProcessor.ts +32 -27
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +2 -21
|
@@ -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,19 +67,18 @@ 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
74
|
public process(remoteMessageCopy: ISequencedDocumentMessage):
|
|
74
75
|
| {
|
|
75
|
-
messages:
|
|
76
|
+
messages: InboundSequencedContainerRuntimeMessageOrSystemMessage[];
|
|
76
77
|
batchStartCsn: number;
|
|
77
78
|
}
|
|
78
79
|
| undefined {
|
|
79
80
|
let message = remoteMessageCopy;
|
|
80
81
|
|
|
81
|
-
ensureContentsDeserialized(message);
|
|
82
|
-
|
|
83
82
|
if (isChunkedMessage(message)) {
|
|
84
83
|
const chunkProcessingResult = this.opSplitter.processChunk(message);
|
|
85
84
|
// Only continue further if current chunk is the final chunk
|
|
@@ -104,10 +103,9 @@ export class RemoteMessageProcessor {
|
|
|
104
103
|
|
|
105
104
|
if (isGroupedBatch(message)) {
|
|
106
105
|
// We should be awaiting a new batch (batchStartCsn undefined)
|
|
107
|
-
assert(this.batchStartCsn === undefined, "Grouped batch interrupting another batch");
|
|
108
106
|
assert(
|
|
109
|
-
this.
|
|
110
|
-
|
|
107
|
+
this.batchStartCsn === undefined,
|
|
108
|
+
0x9d3 /* Grouped batch interrupting another batch */,
|
|
111
109
|
);
|
|
112
110
|
return {
|
|
113
111
|
messages: this.opGroupingManager.ungroupOp(message).map(unpack),
|
|
@@ -119,20 +117,8 @@ export class RemoteMessageProcessor {
|
|
|
119
117
|
|
|
120
118
|
// Do a final unpack of runtime messages in case the message was not grouped, compressed, or chunked
|
|
121
119
|
unpackRuntimeMessage(message);
|
|
122
|
-
this.processorBatch.push(message as InboundSequencedContainerRuntimeMessage);
|
|
123
|
-
|
|
124
|
-
// this.batchStartCsn is undefined only if we have processed all messages in the batch.
|
|
125
|
-
// If it's still defined, we're still in the middle of a batch, so we return nothing, letting
|
|
126
|
-
// containerRuntime know that we're waiting for more messages to complete the batch.
|
|
127
|
-
if (this.batchStartCsn !== undefined) {
|
|
128
|
-
// batch not yet complete
|
|
129
|
-
return undefined;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const messages = [...this.processorBatch];
|
|
133
|
-
this.processorBatch.length = 0;
|
|
134
120
|
return {
|
|
135
|
-
messages,
|
|
121
|
+
messages: [message as InboundSequencedContainerRuntimeMessageOrSystemMessage],
|
|
136
122
|
batchStartCsn,
|
|
137
123
|
};
|
|
138
124
|
}
|
|
@@ -146,7 +132,7 @@ export class RemoteMessageProcessor {
|
|
|
146
132
|
const batchMetadataFlag = asBatchMetadata(message.metadata)?.batch;
|
|
147
133
|
if (this.batchStartCsn === undefined) {
|
|
148
134
|
// We are waiting for a new batch
|
|
149
|
-
assert(batchMetadataFlag !== false,
|
|
135
|
+
assert(batchMetadataFlag !== false, 0x9d5 /* Unexpected batch end marker */);
|
|
150
136
|
|
|
151
137
|
// Start of a new multi-message batch
|
|
152
138
|
if (batchMetadataFlag === true) {
|
|
@@ -162,7 +148,7 @@ export class RemoteMessageProcessor {
|
|
|
162
148
|
// We are in the middle or end of an existing multi-message batch. Return the current batchStartCsn
|
|
163
149
|
const batchStartCsn = this.batchStartCsn;
|
|
164
150
|
|
|
165
|
-
assert(batchMetadataFlag !== true,
|
|
151
|
+
assert(batchMetadataFlag !== true, 0x9d6 /* Unexpected batch start marker */);
|
|
166
152
|
if (batchMetadataFlag === false) {
|
|
167
153
|
// Batch end? Then get ready for the next batch to start
|
|
168
154
|
this.batchStartCsn = undefined;
|
|
@@ -173,12 +159,27 @@ export class RemoteMessageProcessor {
|
|
|
173
159
|
}
|
|
174
160
|
|
|
175
161
|
/** Takes an incoming message and if the contents is a string, JSON.parse's it in place */
|
|
176
|
-
function ensureContentsDeserialized(
|
|
162
|
+
export function ensureContentsDeserialized(
|
|
163
|
+
mutableMessage: ISequencedDocumentMessage,
|
|
164
|
+
modernRuntimeMessage: boolean,
|
|
165
|
+
logLegacyCase: (codePath: string) => void,
|
|
166
|
+
): void {
|
|
177
167
|
// back-compat: ADO #1385: eventually should become unconditional, but only for runtime messages!
|
|
178
168
|
// System message may have no contents, or in some cases (mostly for back-compat) they may have actual objects.
|
|
179
169
|
// Old ops may contain empty string (I assume noops).
|
|
170
|
+
let parsedJsonContents: boolean;
|
|
180
171
|
if (typeof mutableMessage.contents === "string" && mutableMessage.contents !== "") {
|
|
181
172
|
mutableMessage.contents = JSON.parse(mutableMessage.contents);
|
|
173
|
+
parsedJsonContents = true;
|
|
174
|
+
} else {
|
|
175
|
+
parsedJsonContents = false;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// We expect Modern Runtime Messages to have JSON serialized contents,
|
|
179
|
+
// and all other messages not to (system messages and legacy runtime messages without outer "op" type envelope)
|
|
180
|
+
// Let's observe if we are wrong about this to learn about these cases.
|
|
181
|
+
if (modernRuntimeMessage !== parsedJsonContents) {
|
|
182
|
+
logLegacyCase("ensureContentsDeserialized_unexpectedContentsType");
|
|
182
183
|
}
|
|
183
184
|
}
|
|
184
185
|
|
|
@@ -214,7 +215,10 @@ function unpack(message: ISequencedDocumentMessage): InboundSequencedContainerRu
|
|
|
214
215
|
*
|
|
215
216
|
* @internal
|
|
216
217
|
*/
|
|
217
|
-
export function unpackRuntimeMessage(
|
|
218
|
+
export function unpackRuntimeMessage(
|
|
219
|
+
message: ISequencedDocumentMessage,
|
|
220
|
+
logLegacyCase: (codePath: string) => void = () => {},
|
|
221
|
+
): boolean {
|
|
218
222
|
if (message.type !== MessageType.Operation) {
|
|
219
223
|
// Legacy format, but it's already "unpacked",
|
|
220
224
|
// i.e. message.type is actually ContainerMessageType.
|
|
@@ -230,6 +234,7 @@ export function unpackRuntimeMessage(message: ISequencedDocumentMessage): boolea
|
|
|
230
234
|
(message.contents as { type?: unknown }).type === undefined
|
|
231
235
|
) {
|
|
232
236
|
message.type = ContainerMessageType.FluidDataStoreOp;
|
|
237
|
+
logLegacyCase("unpackRuntimeMessage_contentsWithAddress");
|
|
233
238
|
} else {
|
|
234
239
|
// new format
|
|
235
240
|
unpack(message);
|
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 {
|