@fluidframework/container-runtime 2.92.0 → 2.93.0

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.
Files changed (51) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +1 -1
  3. package/container-runtime.test-files.tar +0 -0
  4. package/dist/containerRuntime.d.ts +2 -2
  5. package/dist/containerRuntime.d.ts.map +1 -1
  6. package/dist/containerRuntime.js +25 -36
  7. package/dist/containerRuntime.js.map +1 -1
  8. package/dist/opLifecycle/batchManager.d.ts +3 -9
  9. package/dist/opLifecycle/batchManager.d.ts.map +1 -1
  10. package/dist/opLifecycle/batchManager.js +3 -2
  11. package/dist/opLifecycle/batchManager.js.map +1 -1
  12. package/dist/opLifecycle/outbox.d.ts +8 -5
  13. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  14. package/dist/opLifecycle/outbox.js +40 -57
  15. package/dist/opLifecycle/outbox.js.map +1 -1
  16. package/dist/packageVersion.d.ts +1 -1
  17. package/dist/packageVersion.js +1 -1
  18. package/dist/packageVersion.js.map +1 -1
  19. package/dist/pendingStateManager.d.ts +1 -6
  20. package/dist/pendingStateManager.d.ts.map +1 -1
  21. package/dist/pendingStateManager.js +6 -16
  22. package/dist/pendingStateManager.js.map +1 -1
  23. package/dist/runtimeLayerCompatState.d.ts +2 -2
  24. package/eslint.config.mts +1 -1
  25. package/lib/containerRuntime.d.ts +2 -2
  26. package/lib/containerRuntime.d.ts.map +1 -1
  27. package/lib/containerRuntime.js +25 -36
  28. package/lib/containerRuntime.js.map +1 -1
  29. package/lib/opLifecycle/batchManager.d.ts +3 -9
  30. package/lib/opLifecycle/batchManager.d.ts.map +1 -1
  31. package/lib/opLifecycle/batchManager.js +3 -2
  32. package/lib/opLifecycle/batchManager.js.map +1 -1
  33. package/lib/opLifecycle/outbox.d.ts +8 -5
  34. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  35. package/lib/opLifecycle/outbox.js +41 -58
  36. package/lib/opLifecycle/outbox.js.map +1 -1
  37. package/lib/packageVersion.d.ts +1 -1
  38. package/lib/packageVersion.js +1 -1
  39. package/lib/packageVersion.js.map +1 -1
  40. package/lib/pendingStateManager.d.ts +1 -6
  41. package/lib/pendingStateManager.d.ts.map +1 -1
  42. package/lib/pendingStateManager.js +6 -16
  43. package/lib/pendingStateManager.js.map +1 -1
  44. package/lib/runtimeLayerCompatState.d.ts +2 -2
  45. package/lib/tsdoc-metadata.json +1 -1
  46. package/package.json +24 -29
  47. package/src/containerRuntime.ts +25 -46
  48. package/src/opLifecycle/batchManager.ts +4 -12
  49. package/src/opLifecycle/outbox.ts +51 -69
  50. package/src/packageVersion.ts +1 -1
  51. package/src/pendingStateManager.ts +5 -23
@@ -2069,6 +2069,24 @@ export class ContainerRuntime
2069
2069
  }),
2070
2070
  reSubmit: this.reSubmit.bind(this),
2071
2071
  opReentrancy: () => this.dataModelChangeRunner.running,
2072
+ generateIdAllocationOp: (): LocalBatchMessage | undefined => {
2073
+ if (this._idCompressor === undefined) {
2074
+ return undefined;
2075
+ }
2076
+ const idRange = this._idCompressor.takeNextCreationRange();
2077
+ if (idRange.ids === undefined) {
2078
+ return undefined;
2079
+ }
2080
+ const idAllocationMessage: ContainerRuntimeIdAllocationMessage = {
2081
+ type: ContainerMessageType.IdAllocation,
2082
+ contents: idRange,
2083
+ };
2084
+ return {
2085
+ runtimeOp: idAllocationMessage,
2086
+ referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
2087
+ staged: false,
2088
+ };
2089
+ },
2072
2090
  });
2073
2091
 
2074
2092
  this._quorum = quorum;
@@ -3687,9 +3705,6 @@ export class ContainerRuntime
3687
3705
 
3688
3706
  this.stageControls = undefined;
3689
3707
 
3690
- // During Staging Mode, we avoid submitting any ID Allocation ops (apart from resubmitting pre-staging ops).
3691
- // Now that we've exited, we need to submit an ID Allocation op for any IDs that were generated while in Staging Mode.
3692
- this.submitIdAllocationOpIfNeeded({ staged: false });
3693
3708
  const batchInfos = discardOrCommit();
3694
3709
  event.reportProgress({
3695
3710
  details: {
@@ -4272,7 +4287,6 @@ export class ContainerRuntime
4272
4287
  outboxLength: this.outbox.messageCount,
4273
4288
  mainBatchLength: this.outbox.mainBatchMessageCount,
4274
4289
  blobAttachBatchLength: this.outbox.blobAttachBatchMessageCount,
4275
- idAllocationBatchLength: this.outbox.idAllocationBatchMessageCount,
4276
4290
  },
4277
4291
  );
4278
4292
  }
@@ -4605,7 +4619,8 @@ export class ContainerRuntime
4605
4619
 
4606
4620
  /**
4607
4621
  * This helper is called during summarization. If the container is dirty, it will return a failed summarize result
4608
- * (IBaseSummarizeResult) unless this is the final summarize attempt and SkipFailingIncorrectSummary option is set.
4622
+ * (IBaseSummarizeResult) unless this is the final summarize attempt, in which case the summary is allowed to
4623
+ * proceed to make progress in documents where there are consistently pending ops in the summarizer.
4609
4624
  * @param logger - The logger to be used for sending telemetry.
4610
4625
  * @param referenceSequenceNumber - The reference sequence number of the summary attempt.
4611
4626
  * @param minimumSequenceNumber - The minimum sequence number of the summary attempt.
@@ -4624,13 +4639,9 @@ export class ContainerRuntime
4624
4639
  return;
4625
4640
  }
4626
4641
 
4627
- // If "SkipFailingIncorrectSummary" option is true, don't fail the summary in the last attempt.
4628
- // This is a fallback to make progress in documents where there are consistently pending ops in
4629
- // the summarizer.
4630
- if (
4631
- finalAttempt &&
4632
- this.mc.config.getBoolean("Fluid.Summarizer.SkipFailingIncorrectSummary") === true
4633
- ) {
4642
+ // Don't fail the summary in the last attempt. This is a fallback to make progress in
4643
+ // documents where there are consistently pending ops in the summarizer.
4644
+ if (finalAttempt) {
4634
4645
  const error = DataProcessingError.create(
4635
4646
  "Pending ops during summarization",
4636
4647
  "submitSummary",
@@ -4639,7 +4650,7 @@ export class ContainerRuntime
4639
4650
  );
4640
4651
  logger.sendErrorEvent(
4641
4652
  {
4642
- eventName: "SkipFailingIncorrectSummary",
4653
+ eventName: "PendingOpsDuringSummaryFinalAttempt",
4643
4654
  referenceSequenceNumber,
4644
4655
  minimumSequenceNumber,
4645
4656
  beforeGenerate: beforeSummaryGeneration,
@@ -4733,33 +4744,6 @@ export class ContainerRuntime
4733
4744
  return this.blobManager.lookupTemporaryBlobStorageId(localId);
4734
4745
  }
4735
4746
 
4736
- private submitIdAllocationOpIfNeeded({
4737
- resubmitOutstandingRanges = false,
4738
- staged,
4739
- }: {
4740
- resubmitOutstandingRanges?: boolean;
4741
- staged: boolean;
4742
- }): void {
4743
- if (this._idCompressor) {
4744
- const idRange = resubmitOutstandingRanges
4745
- ? this._idCompressor.takeUnfinalizedCreationRange()
4746
- : this._idCompressor.takeNextCreationRange();
4747
- // Don't include the idRange if there weren't any Ids allocated
4748
- if (idRange.ids !== undefined) {
4749
- const idAllocationMessage: ContainerRuntimeIdAllocationMessage = {
4750
- type: ContainerMessageType.IdAllocation,
4751
- contents: idRange,
4752
- };
4753
- const idAllocationBatchMessage: LocalBatchMessage = {
4754
- runtimeOp: idAllocationMessage,
4755
- referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
4756
- staged,
4757
- };
4758
- this.outbox.submitIdAllocation(idAllocationBatchMessage);
4759
- }
4760
- }
4761
- }
4762
-
4763
4747
  private submit(
4764
4748
  containerRuntimeMessage: LocalContainerRuntimeMessage,
4765
4749
  localOpMetadata: unknown = undefined,
@@ -4803,11 +4787,6 @@ export class ContainerRuntime
4803
4787
  0xbba /* Unexpected message type submitted in Staging Mode */,
4804
4788
  );
4805
4789
 
4806
- // Before submitting any non-staged change, submit the ID Allocation op to cover any compressed IDs included in the op.
4807
- if (!staged) {
4808
- this.submitIdAllocationOpIfNeeded({ staged: false });
4809
- }
4810
-
4811
4790
  // Allow document schema controller to send a message if it needs to propose change in document schema.
4812
4791
  // If it needs to send a message, it will call provided callback with payload of such message and rely
4813
4792
  // on this callback to do actual sending.
@@ -4867,7 +4846,7 @@ export class ContainerRuntime
4867
4846
  // Incoming ops still break the batch via direct this.flush() calls elsewhere
4868
4847
  // (deltaManager "op" handler, process(), connection changes, getPendingLocalState,
4869
4848
  // exitStagingMode). Those all bypass scheduleFlush(), so they're unaffected by this check.
4870
- // Additionally, outbox.maybeFlushPartialBatch() (called on every submit) detects
4849
+ // Additionally, outbox.outboxSequenceNumberCoherencyCheck() (called on every submit) detects
4871
4850
  // sequence number changes and throws if unexpected changes are detected.
4872
4851
  if (
4873
4852
  this.inStagingMode &&
@@ -20,17 +20,8 @@ import { serializeOp } from "./opSerialization.js";
20
20
  import type { BatchStartInfo } from "./remoteMessageProcessor.js";
21
21
 
22
22
  export interface IBatchManagerOptions {
23
+ readonly disableGroupedBatching: boolean;
23
24
  readonly compressionOptions?: ICompressionRuntimeOptions;
24
-
25
- /**
26
- * If true, the outbox is allowed to rebase the batch during flushing.
27
- */
28
- readonly canRebase: boolean;
29
-
30
- /**
31
- * If true, don't compare batchID of incoming batches to this. e.g. ID Allocation Batch IDs should be ignored
32
- */
33
- readonly ignoreBatchId?: boolean;
34
25
  }
35
26
 
36
27
  export interface BatchSequenceNumbers {
@@ -127,8 +118,9 @@ export class BatchManager {
127
118
 
128
119
  /**
129
120
  * Gets the pending batch and clears state for the next batch.
121
+ * The caller is responsible for calling {@link addBatchMetadata} after any modifications (e.g. prepending messages).
130
122
  */
131
- public popBatch(batchId?: BatchId): LocalBatch {
123
+ public popBatch(): LocalBatch {
132
124
  assert(this.pendingBatch[0] !== undefined, 0xb8a /* expected non-empty batch */);
133
125
  const batch: LocalBatch = {
134
126
  messages: this.pendingBatch,
@@ -141,7 +133,7 @@ export class BatchManager {
141
133
  this.clientSequenceNumber = undefined;
142
134
  this.hasReentrantOps = false;
143
135
 
144
- return addBatchMetadata(batch, batchId);
136
+ return batch;
145
137
  }
146
138
 
147
139
  /**
@@ -28,6 +28,7 @@ import {
28
28
  type BatchSequenceNumbers,
29
29
  sequenceNumbersMatch,
30
30
  type BatchId,
31
+ addBatchMetadata,
31
32
  } from "./batchManager.js";
32
33
  import type {
33
34
  LocalBatchMessage,
@@ -65,6 +66,13 @@ export interface IOutboxParameters {
65
66
  readonly getCurrentSequenceNumbers: () => BatchSequenceNumbers;
66
67
  readonly reSubmit: (message: PendingMessageResubmitData, squash: boolean) => void;
67
68
  readonly opReentrancy: () => boolean;
69
+ /**
70
+ * JIT callback to generate an ID allocation op at flush time.
71
+ * Called after rebase (if any), so the returned message has the correct refSeq.
72
+ *
73
+ * @returns A LocalBatchMessage for the ID allocation op, or undefined if no IDs need allocating.
74
+ */
75
+ readonly generateIdAllocationOp: () => LocalBatchMessage | undefined;
68
76
  }
69
77
 
70
78
  /**
@@ -189,7 +197,6 @@ export class Outbox {
189
197
  private readonly logger: ITelemetryLoggerExt;
190
198
  private readonly mainBatch: BatchManager;
191
199
  private readonly blobAttachBatch: BatchManager;
192
- private readonly idAllocationBatch: BatchManager;
193
200
  private batchRebasesToReport = 5;
194
201
  private rebasing = false;
195
202
 
@@ -205,16 +212,12 @@ export class Outbox {
205
212
  constructor(private readonly params: IOutboxParameters) {
206
213
  this.logger = createChildLogger({ logger: params.logger, namespace: "Outbox" });
207
214
 
208
- this.mainBatch = new BatchManager({ canRebase: true });
209
- this.blobAttachBatch = new BatchManager({ canRebase: true });
210
- this.idAllocationBatch = new BatchManager({
211
- canRebase: false,
212
- ignoreBatchId: true,
213
- });
215
+ this.mainBatch = new BatchManager({ disableGroupedBatching: false });
216
+ this.blobAttachBatch = new BatchManager({ disableGroupedBatching: true });
214
217
  }
215
218
 
216
219
  public get messageCount(): number {
217
- return this.mainBatch.length + this.blobAttachBatch.length + this.idAllocationBatch.length;
220
+ return this.mainBatch.length + this.blobAttachBatch.length;
218
221
  }
219
222
 
220
223
  public get mainBatchMessageCount(): number {
@@ -225,19 +228,12 @@ export class Outbox {
225
228
  return this.blobAttachBatch.length;
226
229
  }
227
230
 
228
- public get idAllocationBatchMessageCount(): number {
229
- return this.idAllocationBatch.length;
230
- }
231
-
232
231
  public get isEmpty(): boolean {
233
232
  return this.messageCount === 0;
234
233
  }
235
234
 
236
235
  public containsUserChanges(): boolean {
237
- return (
238
- this.mainBatch.containsUserChanges() || this.blobAttachBatch.containsUserChanges()
239
- // ID Allocation ops are not user changes
240
- );
236
+ return this.mainBatch.containsUserChanges() || this.blobAttachBatch.containsUserChanges();
241
237
  }
242
238
 
243
239
  /**
@@ -251,13 +247,11 @@ export class Outbox {
251
247
  * last message processed by the ContainerRuntime. In the absence of op reentrancy, this
252
248
  * pair will remain stable during a single JS turn during which the batch is being built up.
253
249
  */
254
- private maybeFlushPartialBatch(): void {
250
+ private outboxSequenceNumberCoherencyCheck(): void {
255
251
  const mainBatchSeqNums = this.mainBatch.sequenceNumbers;
256
252
  const blobAttachSeqNums = this.blobAttachBatch.sequenceNumbers;
257
- const idAllocSeqNums = this.idAllocationBatch.sequenceNumbers;
258
253
  assert(
259
- sequenceNumbersMatch(mainBatchSeqNums, blobAttachSeqNums) &&
260
- sequenceNumbersMatch(mainBatchSeqNums, idAllocSeqNums),
254
+ sequenceNumbersMatch(mainBatchSeqNums, blobAttachSeqNums),
261
255
  0x58d /* Reference sequence numbers from both batches must be in sync */,
262
256
  );
263
257
 
@@ -265,8 +259,7 @@ export class Outbox {
265
259
 
266
260
  if (
267
261
  sequenceNumbersMatch(mainBatchSeqNums, currentSequenceNumbers) &&
268
- sequenceNumbersMatch(blobAttachSeqNums, currentSequenceNumbers) &&
269
- sequenceNumbersMatch(idAllocSeqNums, currentSequenceNumbers)
262
+ sequenceNumbersMatch(blobAttachSeqNums, currentSequenceNumbers)
270
263
  ) {
271
264
  // The reference sequence numbers are stable, there is nothing to do
272
265
  return;
@@ -314,23 +307,17 @@ export class Outbox {
314
307
  }
315
308
 
316
309
  public submit(message: LocalBatchMessage): void {
317
- this.maybeFlushPartialBatch();
310
+ this.outboxSequenceNumberCoherencyCheck();
318
311
 
319
312
  this.addMessageToBatchManager(this.mainBatch, message);
320
313
  }
321
314
 
322
315
  public submitBlobAttach(message: LocalBatchMessage): void {
323
- this.maybeFlushPartialBatch();
316
+ this.outboxSequenceNumberCoherencyCheck();
324
317
 
325
318
  this.addMessageToBatchManager(this.blobAttachBatch, message);
326
319
  }
327
320
 
328
- public submitIdAllocation(message: LocalBatchMessage): void {
329
- this.maybeFlushPartialBatch();
330
-
331
- this.addMessageToBatchManager(this.idAllocationBatch, message);
332
- }
333
-
334
321
  private addMessageToBatchManager(
335
322
  batchManager: BatchManager,
336
323
  message: LocalBatchMessage,
@@ -352,11 +339,12 @@ export class Outbox {
352
339
  public flush(resubmitInfo?: BatchResubmitInfo): void {
353
340
  // We have nothing to flush if all batchManagers are empty, and we we're not needing to resubmit an empty batch placeholder
354
341
  if (
355
- this.idAllocationBatch.empty &&
356
342
  this.blobAttachBatch.empty &&
357
343
  this.mainBatch.empty &&
358
344
  resubmitInfo?.batchId === undefined
359
345
  ) {
346
+ // Note that it's possible that there are unfinalized ranges in the ID Compressor,
347
+ // but there's no urgency to flush those if they're not referenced in any messages.
360
348
  return;
361
349
  }
362
350
 
@@ -368,8 +356,7 @@ export class Outbox {
368
356
  }
369
357
 
370
358
  private flushAll(resubmitInfo?: BatchResubmitInfo): void {
371
- const allBatchesEmpty =
372
- this.idAllocationBatch.empty && this.blobAttachBatch.empty && this.mainBatch.empty;
359
+ const allBatchesEmpty = this.blobAttachBatch.empty && this.mainBatch.empty;
373
360
  if (allBatchesEmpty) {
374
361
  // If we're resubmitting with a batchId and all batches are empty, we need to flush an empty batch.
375
362
  // Note that we currently resubmit one batch at a time, so on resubmit, 1 of the 2 batches will *always* be empty.
@@ -382,22 +369,8 @@ export class Outbox {
382
369
  return;
383
370
  }
384
371
 
385
- // Don't use resubmittingBatchId for idAllocationBatch.
386
- // ID Allocation messages are not directly resubmitted so don't pass the resubmitInfo
387
- this.flushInternal({
388
- batchManager: this.idAllocationBatch,
389
- // Note: For now, we will never stage ID Allocation messages.
390
- // They won't contain personal info and no harm in extra allocations in case of discarding the staged changes
391
- });
392
- this.flushInternal({
393
- batchManager: this.blobAttachBatch,
394
- disableGroupedBatching: true,
395
- resubmitInfo,
396
- });
397
- this.flushInternal({
398
- batchManager: this.mainBatch,
399
- resubmitInfo,
400
- });
372
+ this.flushInternal(this.blobAttachBatch, resubmitInfo);
373
+ this.flushInternal(this.mainBatch, resubmitInfo);
401
374
  }
402
375
 
403
376
  private flushEmptyBatch(
@@ -429,17 +402,15 @@ export class Outbox {
429
402
  return;
430
403
  }
431
404
 
432
- private flushInternal(params: {
433
- batchManager: BatchManager;
434
- disableGroupedBatching?: boolean;
435
- resubmitInfo?: BatchResubmitInfo; // undefined if not resubmitting
436
- }): void {
437
- const { batchManager, disableGroupedBatching = false, resubmitInfo } = params;
405
+ private flushInternal(
406
+ batchManager: BatchManager,
407
+ resubmitInfo?: BatchResubmitInfo, // undefined if not resubmitting
408
+ ): void {
438
409
  if (batchManager.empty) {
439
410
  return;
440
411
  }
441
412
 
442
- const rawBatch = batchManager.popBatch(resubmitInfo?.batchId);
413
+ let rawBatch = batchManager.popBatch();
443
414
 
444
415
  // On resubmit we use the original batch's staged state, so these should match as well.
445
416
  const staged = rawBatch.staged === true;
@@ -449,13 +420,15 @@ export class Outbox {
449
420
  );
450
421
 
451
422
  const groupingEnabled =
452
- !disableGroupedBatching && this.params.groupingManager.groupedBatchingEnabled();
453
- if (
454
- batchManager.options.canRebase &&
455
- rawBatch.hasReentrantOps === true &&
456
- groupingEnabled
457
- ) {
423
+ !batchManager.options.disableGroupedBatching &&
424
+ this.params.groupingManager.groupedBatchingEnabled();
425
+ if (rawBatch.hasReentrantOps === true) {
426
+ assert(
427
+ resubmitInfo === undefined,
428
+ 0xcf2 /* Re-submitting a batch with reentrant ops is not supported */,
429
+ );
458
430
  assert(!this.rebasing, 0x6fa /* A rebased batch should never have reentrant ops */);
431
+ // Rebase the current batch (resubmit the ops one-by-one) and then reinvoke flushInternal.
459
432
  // If a batch contains reentrant ops (ops created as a result from processing another op)
460
433
  // it needs to be rebased so that we can ensure consistent reference sequence numbers
461
434
  // and eventual consistency at the DDS level.
@@ -466,11 +439,22 @@ export class Outbox {
466
439
  return;
467
440
  }
468
441
 
469
- let clientSequenceNumber: number | undefined;
470
442
  // Did we disconnect? (i.e. is shouldSend false?)
471
443
  // If so, do nothing, as pending state manager will resubmit it correctly on reconnect.
472
444
  // Because flush() is a task that executes async (on clean stack), we can get here in disconnected state.
473
- if (this.params.shouldSend() && !staged) {
445
+ const shouldSendNow = this.params.shouldSend() && !staged;
446
+ let clientSequenceNumber: number | undefined;
447
+ if (shouldSendNow) {
448
+ // Generate ID Allocation op just-in-time, after rebase (if any), and before addBatchMetadata,
449
+ // so that the prepended idAllocMsg is correctly marked as the first op in the batch.
450
+ // This ensures the refSeq is correct (matching the rest of the batch) and that
451
+ // ID ranges aren't lost during rebase (since reSubmit drops IdAllocation ops).
452
+ // Only generate for non-staged batches — ID alloc ops are always non-staged.
453
+ const idAllocMsg = this.params.generateIdAllocationOp();
454
+ if (idAllocMsg !== undefined) {
455
+ rawBatch = { ...rawBatch, messages: [idAllocMsg, ...rawBatch.messages] };
456
+ }
457
+ addBatchMetadata(rawBatch, resubmitInfo?.batchId);
474
458
  const virtualizedBatch = this.virtualizeBatch(rawBatch, groupingEnabled);
475
459
 
476
460
  clientSequenceNumber = this.sendBatch(virtualizedBatch);
@@ -478,13 +462,14 @@ export class Outbox {
478
462
  clientSequenceNumber === undefined || clientSequenceNumber >= 0,
479
463
  0x9d2 /* unexpected negative clientSequenceNumber (empty batch should yield undefined) */,
480
464
  );
465
+ } else {
466
+ addBatchMetadata(rawBatch, resubmitInfo?.batchId);
481
467
  }
482
468
 
483
469
  this.params.pendingStateManager.onFlushBatch(
484
470
  rawBatch.messages,
485
471
  clientSequenceNumber,
486
472
  staged,
487
- batchManager.options.ignoreBatchId,
488
473
  );
489
474
  }
490
475
 
@@ -496,7 +481,6 @@ export class Outbox {
496
481
  */
497
482
  private rebase(rawBatch: LocalBatch, batchManager: BatchManager): void {
498
483
  assert(!this.rebasing, 0x6fb /* Reentrancy */);
499
- assert(batchManager.options.canRebase, 0x9a7 /* BatchManager does not support rebase */);
500
484
 
501
485
  this.rebasing = true;
502
486
  const squash = false;
@@ -523,7 +507,7 @@ export class Outbox {
523
507
  this.batchRebasesToReport--;
524
508
  }
525
509
 
526
- this.flushInternal({ batchManager });
510
+ this.flushInternal(batchManager);
527
511
  this.rebasing = false;
528
512
  }
529
513
 
@@ -664,7 +648,6 @@ export class Outbox {
664
648
  */
665
649
  public getBatchCheckpoints(): {
666
650
  mainBatch: IBatchCheckpoint;
667
- idAllocationBatch: IBatchCheckpoint;
668
651
  blobAttachBatch: IBatchCheckpoint;
669
652
  } {
670
653
  // This variable is declared with a specific type so that we have a standard import of the IBatchCheckpoint type.
@@ -672,7 +655,6 @@ export class Outbox {
672
655
  const mainBatch: IBatchCheckpoint = this.mainBatch.checkpoint();
673
656
  return {
674
657
  mainBatch,
675
- idAllocationBatch: this.idAllocationBatch.checkpoint(),
676
658
  blobAttachBatch: this.blobAttachBatch.checkpoint(),
677
659
  };
678
660
  }
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/container-runtime";
9
- export const pkgVersion = "2.92.0";
9
+ export const pkgVersion = "2.93.0";
@@ -84,10 +84,6 @@ export interface IPendingMessage {
84
84
  * length of the batch (how many runtime messages here)
85
85
  */
86
86
  length: number;
87
- /**
88
- * If true, don't compare batchID of incoming batches to this. e.g. ID Allocation Batch IDs should be ignored
89
- */
90
- ignoreBatchId?: boolean;
91
87
  /**
92
88
  * If true, this batch is staged and should not actually be submitted on replayPendingStates.
93
89
  */
@@ -407,13 +403,11 @@ export class PendingStateManager implements IDisposable {
407
403
  * @param clientSequenceNumber - The CSN of the first message in the batch,
408
404
  * or undefined if the batch was not yet sent (e.g. by the time we flushed we lost the connection)
409
405
  * @param staged - Indicates whether batch is staged (not to be submitted while runtime is in Staging Mode)
410
- * @param ignoreBatchId - Whether to ignore the batchId in the batchStartInfo
411
406
  */
412
407
  public onFlushBatch(
413
408
  batch: LocalBatchMessage[] | [LocalEmptyBatchPlaceholder],
414
409
  clientSequenceNumber: number | undefined,
415
410
  staged: boolean,
416
- ignoreBatchId?: boolean,
417
411
  ): void {
418
412
  // clientId and batchStartCsn are used for generating the batchId so we can detect container forks
419
413
  // where this batch was submitted by two different clients rehydrating from the same local state.
@@ -431,7 +425,7 @@ export class PendingStateManager implements IDisposable {
431
425
  clientId !== undefined,
432
426
  0xa33 /* clientId (from stateHandler) could only be undefined if we've never connected, but we have a CSN so we know that's not the case */,
433
427
  );
434
- const batchInfo = { clientId, batchStartCsn, length: batch.length, ignoreBatchId, staged };
428
+ const batchInfo = { clientId, batchStartCsn, length: batch.length, staged };
435
429
  for (const message of batch) {
436
430
  const {
437
431
  runtimeOp,
@@ -512,23 +506,14 @@ export class PendingStateManager implements IDisposable {
512
506
  * @returns whether the batch IDs match
513
507
  */
514
508
  private remoteBatchMatchesPendingBatch(remoteBatchStart: BatchStartInfo): boolean {
515
- // Find the first pending message that uses Batch ID, to compare to the incoming remote batch.
516
- // If there is no such message, then the incoming remote batch doesn't have a match here and we can return.
517
- const firstIndexUsingBatchId = Array.from({
518
- length: this.pendingMessages.length,
519
- }).findIndex((_, i) => this.pendingMessages.get(i)?.batchInfo.ignoreBatchId !== true);
520
- const pendingMessageUsingBatchId =
521
- firstIndexUsingBatchId === -1
522
- ? undefined
523
- : this.pendingMessages.get(firstIndexUsingBatchId);
524
-
525
- if (pendingMessageUsingBatchId === undefined) {
509
+ const pendingMessage = this.pendingMessages.peekFront();
510
+ if (pendingMessage === undefined) {
526
511
  return false;
527
512
  }
528
513
 
529
514
  // We must compare the effective batch IDs, since one of these ops
530
515
  // may have been the original, not resubmitted, so wouldn't have its batch ID stamped yet.
531
- const pendingBatchId = getEffectiveBatchId(pendingMessageUsingBatchId);
516
+ const pendingBatchId = getEffectiveBatchId(pendingMessage);
532
517
  const inboundBatchId = getEffectiveBatchId(remoteBatchStart);
533
518
 
534
519
  return pendingBatchId === inboundBatchId;
@@ -810,10 +795,7 @@ export class PendingStateManager implements IDisposable {
810
795
  assert(batchMetadataFlag !== false, 0x41b /* We cannot process batches in chunks */);
811
796
 
812
797
  // The next message starts a batch (possibly single-message), and we'll need its batchId.
813
- const batchId =
814
- pendingMessage.batchInfo.ignoreBatchId === true
815
- ? undefined
816
- : getEffectiveBatchId(pendingMessage);
798
+ const batchId = getEffectiveBatchId(pendingMessage);
817
799
 
818
800
  const staged = pendingMessage.batchInfo.staged;
819
801