@fluidframework/container-runtime 2.32.0 → 2.33.0-333010
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.map +1 -1
- package/dist/opLifecycle/batchManager.d.ts +2 -14
- package/dist/opLifecycle/batchManager.d.ts.map +1 -1
- package/dist/opLifecycle/batchManager.js +1 -38
- package/dist/opLifecycle/batchManager.js.map +1 -1
- package/dist/opLifecycle/definitions.d.ts +9 -7
- package/dist/opLifecycle/definitions.d.ts.map +1 -1
- package/dist/opLifecycle/definitions.js.map +1 -1
- package/dist/opLifecycle/index.d.ts +2 -2
- package/dist/opLifecycle/index.d.ts.map +1 -1
- package/dist/opLifecycle/index.js +3 -2
- package/dist/opLifecycle/index.js.map +1 -1
- package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opCompressor.js +2 -2
- package/dist/opLifecycle/opCompressor.js.map +1 -1
- package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
- package/dist/opLifecycle/opSplitter.js +2 -2
- package/dist/opLifecycle/opSplitter.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts +20 -1
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +69 -44
- 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/lib/containerRuntime.d.ts.map +1 -1
- package/lib/opLifecycle/batchManager.d.ts +2 -14
- package/lib/opLifecycle/batchManager.d.ts.map +1 -1
- package/lib/opLifecycle/batchManager.js +0 -36
- package/lib/opLifecycle/batchManager.js.map +1 -1
- package/lib/opLifecycle/definitions.d.ts +9 -7
- package/lib/opLifecycle/definitions.d.ts.map +1 -1
- package/lib/opLifecycle/definitions.js.map +1 -1
- package/lib/opLifecycle/index.d.ts +2 -2
- package/lib/opLifecycle/index.d.ts.map +1 -1
- package/lib/opLifecycle/index.js +2 -2
- package/lib/opLifecycle/index.js.map +1 -1
- package/lib/opLifecycle/opCompressor.d.ts.map +1 -1
- package/lib/opLifecycle/opCompressor.js +1 -1
- package/lib/opLifecycle/opCompressor.js.map +1 -1
- package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
- package/lib/opLifecycle/opSplitter.js +1 -1
- package/lib/opLifecycle/opSplitter.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts +20 -1
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.js +67 -44
- 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/package.json +17 -17
- package/src/opLifecycle/batchManager.ts +2 -48
- package/src/opLifecycle/definitions.ts +11 -7
- package/src/opLifecycle/index.ts +6 -2
- package/src/opLifecycle/opCompressor.ts +1 -1
- package/src/opLifecycle/opSplitter.ts +1 -1
- package/src/opLifecycle/outbox.ts +92 -58
- package/src/packageVersion.ts +1 -1
|
@@ -4,13 +4,16 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { IBatchMessage } from "@fluidframework/container-definitions/internal";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
ITelemetryBaseLogger,
|
|
9
|
+
type ITelemetryBaseProperties,
|
|
10
|
+
} from "@fluidframework/core-interfaces";
|
|
8
11
|
import { assert, Lazy } from "@fluidframework/core-utils/internal";
|
|
9
12
|
import {
|
|
10
13
|
DataProcessingError,
|
|
11
|
-
GenericError,
|
|
12
14
|
UsageError,
|
|
13
15
|
createChildLogger,
|
|
16
|
+
type IFluidErrorBase,
|
|
14
17
|
type ITelemetryLoggerExt,
|
|
15
18
|
} from "@fluidframework/telemetry-utils/internal";
|
|
16
19
|
|
|
@@ -20,7 +23,6 @@ import { PendingMessageResubmitData, PendingStateManager } from "../pendingState
|
|
|
20
23
|
import {
|
|
21
24
|
BatchManager,
|
|
22
25
|
BatchSequenceNumbers,
|
|
23
|
-
estimateSocketSize,
|
|
24
26
|
sequenceNumbersMatch,
|
|
25
27
|
type BatchId,
|
|
26
28
|
} from "./batchManager.js";
|
|
@@ -106,6 +108,55 @@ export function getLongStack<T>(action: () => T, length: number = 50): T {
|
|
|
106
108
|
}
|
|
107
109
|
}
|
|
108
110
|
|
|
111
|
+
/**
|
|
112
|
+
* Convert from local batch to outbound batch, including computing contentSizeInBytes.
|
|
113
|
+
*/
|
|
114
|
+
export function localBatchToOutboundBatch(localBatch: LocalBatch): OutboundBatch {
|
|
115
|
+
// Shallow copy each message as we switch types
|
|
116
|
+
const outboundMessages = localBatch.messages.map<OutboundBatchMessage>(
|
|
117
|
+
({ serializedOp, ...message }) => ({
|
|
118
|
+
contents: serializedOp,
|
|
119
|
+
...message,
|
|
120
|
+
}),
|
|
121
|
+
);
|
|
122
|
+
const contentSizeInBytes = outboundMessages.reduce(
|
|
123
|
+
(acc, message) => acc + (message.contents?.length ?? 0),
|
|
124
|
+
0,
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
// Shallow copy the local batch, updating the messages to be outbound messages and adding contentSizeInBytes
|
|
128
|
+
const outboundBatch: OutboundBatch = {
|
|
129
|
+
...localBatch,
|
|
130
|
+
messages: outboundMessages,
|
|
131
|
+
contentSizeInBytes,
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
return outboundBatch;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Estimated size of the stringification overhead for an op accumulated
|
|
139
|
+
* from runtime to loader to the service.
|
|
140
|
+
*/
|
|
141
|
+
const opOverhead = 200;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Estimates the real size in bytes on the socket for a given batch. It assumes that
|
|
145
|
+
* the envelope size (and the size of an empty op) is 200 bytes, taking into account
|
|
146
|
+
* extra overhead from stringification.
|
|
147
|
+
*
|
|
148
|
+
* @remarks
|
|
149
|
+
* Also content will be stringified, and that adds a lot of overhead due to a lot of escape characters.
|
|
150
|
+
* Not taking it into account, as compression work should help there - compressed payload will be
|
|
151
|
+
* initially stored as base64, and that requires only 2 extra escape characters.
|
|
152
|
+
*
|
|
153
|
+
* @param batch - the batch to inspect
|
|
154
|
+
* @returns An estimate of the payload size in bytes which will be produced when the batch is sent over the wire
|
|
155
|
+
*/
|
|
156
|
+
export const estimateSocketSize = (batch: OutboundBatch): number => {
|
|
157
|
+
return batch.contentSizeInBytes + opOverhead * batch.messages.length;
|
|
158
|
+
};
|
|
159
|
+
|
|
109
160
|
/**
|
|
110
161
|
* The Outbox collects messages submitted by the ContainerRuntime into a batch,
|
|
111
162
|
* and then flushes the batch when requested.
|
|
@@ -133,18 +184,9 @@ export class Outbox {
|
|
|
133
184
|
constructor(private readonly params: IOutboxParameters) {
|
|
134
185
|
this.logger = createChildLogger({ logger: params.logger, namespace: "Outbox" });
|
|
135
186
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
Number.POSITIVE_INFINITY;
|
|
139
|
-
// We need to allow infinite size batches if we enable compression
|
|
140
|
-
const hardLimit = isCompressionEnabled
|
|
141
|
-
? Number.POSITIVE_INFINITY
|
|
142
|
-
: this.params.config.maxBatchSizeInBytes;
|
|
143
|
-
|
|
144
|
-
this.mainBatch = new BatchManager({ hardLimit, canRebase: true });
|
|
145
|
-
this.blobAttachBatch = new BatchManager({ hardLimit, canRebase: true });
|
|
187
|
+
this.mainBatch = new BatchManager({ canRebase: true });
|
|
188
|
+
this.blobAttachBatch = new BatchManager({ canRebase: true });
|
|
146
189
|
this.idAllocationBatch = new BatchManager({
|
|
147
|
-
hardLimit,
|
|
148
190
|
canRebase: false,
|
|
149
191
|
ignoreBatchId: true,
|
|
150
192
|
});
|
|
@@ -274,20 +316,11 @@ export class Outbox {
|
|
|
274
316
|
batchManager: BatchManager,
|
|
275
317
|
message: LocalBatchMessage,
|
|
276
318
|
): void {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
)
|
|
283
|
-
) {
|
|
284
|
-
throw new GenericError("BatchTooLarge", /* error */ undefined, {
|
|
285
|
-
opSize: message.serializedOp?.length ?? 0,
|
|
286
|
-
batchSize: batchManager.contentSizeInBytes,
|
|
287
|
-
count: batchManager.length,
|
|
288
|
-
limit: batchManager.options.hardLimit,
|
|
289
|
-
});
|
|
290
|
-
}
|
|
319
|
+
batchManager.push(
|
|
320
|
+
message,
|
|
321
|
+
this.isContextReentrant(),
|
|
322
|
+
this.params.getCurrentSequenceNumbers().clientSequenceNumber,
|
|
323
|
+
);
|
|
291
324
|
}
|
|
292
325
|
|
|
293
326
|
/**
|
|
@@ -465,15 +498,7 @@ export class Outbox {
|
|
|
465
498
|
*/
|
|
466
499
|
private virtualizeBatch(localBatch: LocalBatch, groupingEnabled: boolean): OutboundBatch {
|
|
467
500
|
// Shallow copy the local batch, updating the messages to be outbound messages
|
|
468
|
-
const originalBatch
|
|
469
|
-
...localBatch,
|
|
470
|
-
messages: localBatch.messages.map<OutboundBatchMessage>(
|
|
471
|
-
({ serializedOp, ...message }) => ({
|
|
472
|
-
contents: serializedOp,
|
|
473
|
-
...message,
|
|
474
|
-
}),
|
|
475
|
-
),
|
|
476
|
-
};
|
|
501
|
+
const originalBatch = localBatchToOutboundBatch(localBatch);
|
|
477
502
|
|
|
478
503
|
const originalOrGroupedBatch = groupingEnabled
|
|
479
504
|
? this.params.groupingManager.groupBatch(originalBatch)
|
|
@@ -489,7 +514,6 @@ export class Outbox {
|
|
|
489
514
|
const singletonBatch = originalOrGroupedBatch as OutboundSingletonBatch;
|
|
490
515
|
|
|
491
516
|
if (
|
|
492
|
-
this.params.config.compressionOptions === undefined ||
|
|
493
517
|
this.params.config.compressionOptions.minimumBatchSizeInBytes >
|
|
494
518
|
singletonBatch.contentSizeInBytes ||
|
|
495
519
|
this.params.submitBatchFn === undefined
|
|
@@ -506,21 +530,11 @@ export class Outbox {
|
|
|
506
530
|
: this.params.splitter.splitSingletonBatchMessage(compressedBatch);
|
|
507
531
|
}
|
|
508
532
|
|
|
533
|
+
// We want to distinguish this "BatchTooLarge" case from the generic "BatchTooLarge" case in sendBatch
|
|
509
534
|
if (compressedBatch.contentSizeInBytes >= this.params.config.maxBatchSizeInBytes) {
|
|
510
|
-
throw
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
/* sequencedMessage */ undefined,
|
|
514
|
-
{
|
|
515
|
-
batchSize: singletonBatch.contentSizeInBytes,
|
|
516
|
-
compressedBatchSize: compressedBatch.contentSizeInBytes,
|
|
517
|
-
count: compressedBatch.messages.length,
|
|
518
|
-
limit: this.params.config.maxBatchSizeInBytes,
|
|
519
|
-
chunkingEnabled: this.params.splitter.isBatchChunkingEnabled,
|
|
520
|
-
compressionOptions: JSON.stringify(this.params.config.compressionOptions),
|
|
521
|
-
socketSize: estimateSocketSize(singletonBatch),
|
|
522
|
-
},
|
|
523
|
-
);
|
|
535
|
+
throw this.makeBatchTooLargeError(compressedBatch, "CompressionInsufficient", {
|
|
536
|
+
uncompressedSizeInBytes: singletonBatch.contentSizeInBytes,
|
|
537
|
+
});
|
|
524
538
|
}
|
|
525
539
|
|
|
526
540
|
return compressedBatch;
|
|
@@ -540,12 +554,7 @@ export class Outbox {
|
|
|
540
554
|
|
|
541
555
|
const socketSize = estimateSocketSize(batch);
|
|
542
556
|
if (socketSize >= this.params.config.maxBatchSizeInBytes) {
|
|
543
|
-
this.
|
|
544
|
-
eventName: "LargeBatch",
|
|
545
|
-
length: batch.messages.length,
|
|
546
|
-
sizeInBytes: batch.contentSizeInBytes,
|
|
547
|
-
socketSize,
|
|
548
|
-
});
|
|
557
|
+
throw this.makeBatchTooLargeError(batch, "CannotSend");
|
|
549
558
|
}
|
|
550
559
|
|
|
551
560
|
let clientSequenceNumber: number;
|
|
@@ -577,6 +586,31 @@ export class Outbox {
|
|
|
577
586
|
return clientSequenceNumber;
|
|
578
587
|
}
|
|
579
588
|
|
|
589
|
+
private makeBatchTooLargeError(
|
|
590
|
+
batch: OutboundBatch,
|
|
591
|
+
codepath: string,
|
|
592
|
+
moreDetails?: ITelemetryBaseProperties,
|
|
593
|
+
): IFluidErrorBase {
|
|
594
|
+
return DataProcessingError.create(
|
|
595
|
+
"BatchTooLarge",
|
|
596
|
+
codepath,
|
|
597
|
+
/* sequencedMessage */ undefined,
|
|
598
|
+
{
|
|
599
|
+
errorDetails: {
|
|
600
|
+
opCount: batch.messages.length,
|
|
601
|
+
contentSizeInBytes: batch.contentSizeInBytes,
|
|
602
|
+
socketSize: estimateSocketSize(batch),
|
|
603
|
+
maxBatchSizeInBytes: this.params.config.maxBatchSizeInBytes,
|
|
604
|
+
groupedBatchingEnabled: this.params.groupingManager.groupedBatchingEnabled(),
|
|
605
|
+
compressionOptions: JSON.stringify(this.params.config.compressionOptions),
|
|
606
|
+
chunkingEnabled: this.params.splitter.isBatchChunkingEnabled,
|
|
607
|
+
chunkSizeInBytes: this.params.splitter.chunkSizeInBytes,
|
|
608
|
+
...moreDetails,
|
|
609
|
+
},
|
|
610
|
+
},
|
|
611
|
+
);
|
|
612
|
+
}
|
|
613
|
+
|
|
580
614
|
/**
|
|
581
615
|
* Gets a checkpoint object per batch that facilitates iterating over the batch messages when rolling back.
|
|
582
616
|
*/
|
package/src/packageVersion.ts
CHANGED