@fluidframework/container-runtime 2.0.0-rc.3.0.3 → 2.0.0-rc.3.0.5

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 (46) hide show
  1. package/dist/channelCollection.js +1 -1
  2. package/dist/channelCollection.js.map +1 -1
  3. package/dist/containerRuntime.d.ts.map +1 -1
  4. package/dist/containerRuntime.js +30 -43
  5. package/dist/containerRuntime.js.map +1 -1
  6. package/dist/metadata.d.ts +2 -2
  7. package/dist/metadata.d.ts.map +1 -1
  8. package/dist/metadata.js.map +1 -1
  9. package/dist/opLifecycle/batchManager.d.ts +4 -1
  10. package/dist/opLifecycle/batchManager.d.ts.map +1 -1
  11. package/dist/opLifecycle/batchManager.js +0 -10
  12. package/dist/opLifecycle/batchManager.js.map +1 -1
  13. package/dist/opLifecycle/outbox.d.ts +0 -4
  14. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  15. package/dist/opLifecycle/outbox.js +7 -38
  16. package/dist/opLifecycle/outbox.js.map +1 -1
  17. package/dist/packageVersion.d.ts +1 -1
  18. package/dist/packageVersion.js +1 -1
  19. package/dist/packageVersion.js.map +1 -1
  20. package/lib/channelCollection.js +1 -1
  21. package/lib/channelCollection.js.map +1 -1
  22. package/lib/containerRuntime.d.ts.map +1 -1
  23. package/lib/containerRuntime.js +30 -43
  24. package/lib/containerRuntime.js.map +1 -1
  25. package/lib/metadata.d.ts +2 -2
  26. package/lib/metadata.d.ts.map +1 -1
  27. package/lib/metadata.js.map +1 -1
  28. package/lib/opLifecycle/batchManager.d.ts +4 -1
  29. package/lib/opLifecycle/batchManager.d.ts.map +1 -1
  30. package/lib/opLifecycle/batchManager.js +0 -10
  31. package/lib/opLifecycle/batchManager.js.map +1 -1
  32. package/lib/opLifecycle/outbox.d.ts +0 -4
  33. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  34. package/lib/opLifecycle/outbox.js +7 -38
  35. package/lib/opLifecycle/outbox.js.map +1 -1
  36. package/lib/packageVersion.d.ts +1 -1
  37. package/lib/packageVersion.js +1 -1
  38. package/lib/packageVersion.js.map +1 -1
  39. package/package.json +17 -17
  40. package/src/channelCollection.ts +1 -1
  41. package/src/containerRuntime.ts +42 -56
  42. package/src/metadata.ts +2 -2
  43. package/src/opLifecycle/README.md +4 -4
  44. package/src/opLifecycle/batchManager.ts +5 -14
  45. package/src/opLifecycle/outbox.ts +7 -53
  46. package/src/packageVersion.ts +1 -1
@@ -1240,6 +1240,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1240
1240
  this.emitDirtyDocumentEvent = false;
1241
1241
  let newState;
1242
1242
  try {
1243
+ this.submitIdAllocationOpIfNeeded(true);
1243
1244
  // replay the ops
1244
1245
  this.pendingStateManager.replayPendingStates();
1245
1246
  }
@@ -1416,9 +1417,10 @@ export class ContainerRuntime extends TypedEventEmitter {
1416
1417
  // We do not need to make a deep copy. Each layer will just replace message.contents itself,
1417
1418
  // but will not modify the contents object (likely it will replace it on the message).
1418
1419
  const messageCopy = { ...messageArg };
1420
+ const savedOp = messageCopy.metadata?.savedOp;
1419
1421
  for (const message of this.remoteMessageProcessor.process(messageCopy)) {
1420
- if (modernRuntimeMessage) {
1421
- this.processCore({
1422
+ const msg = modernRuntimeMessage
1423
+ ? {
1422
1424
  // Cast it since we expect it to be this based on modernRuntimeMessage computation above.
1423
1425
  // There is nothing really ensuring that anytime original message.type is Operation that
1424
1426
  // the result messages will be so. In the end modern bool being true only directs to
@@ -1426,12 +1428,16 @@ export class ContainerRuntime extends TypedEventEmitter {
1426
1428
  message: message,
1427
1429
  local,
1428
1430
  modernRuntimeMessage,
1429
- });
1430
- }
1431
- else {
1432
- // Unrecognized message will be ignored.
1433
- this.processCore({ message, local, modernRuntimeMessage });
1434
- }
1431
+ }
1432
+ : // Unrecognized message will be ignored.
1433
+ {
1434
+ message,
1435
+ local,
1436
+ modernRuntimeMessage,
1437
+ };
1438
+ msg.savedOp = savedOp;
1439
+ // ensure that we observe any re-entrancy, and if needed, rebase ops
1440
+ this.ensureNoDataModelChanges(() => this.processCore(msg));
1435
1441
  }
1436
1442
  }
1437
1443
  /**
@@ -1496,9 +1502,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1496
1502
  // stashed ops flow. The compressor is stashed with these ops already processed.
1497
1503
  // That said, in idCompressorMode === "delayed", we might not serialize ID compressor, and
1498
1504
  // thus we need to process all the ops.
1499
- if (!(this.skipSavedCompressorOps &&
1500
- messageWithContext.message.metadata?.savedOp ===
1501
- true)) {
1505
+ if (!(this.skipSavedCompressorOps && messageWithContext.savedOp === true)) {
1502
1506
  const range = messageWithContext.message.contents;
1503
1507
  // Some other client turned on the id compressor. If we have not turned it on,
1504
1508
  // put it in a pending queue and delay finalization.
@@ -1627,9 +1631,9 @@ export class ContainerRuntime extends TypedEventEmitter {
1627
1631
  let checkpoint;
1628
1632
  let result;
1629
1633
  if (this.mc.config.getBoolean("Fluid.ContainerRuntime.EnableRollback")) {
1630
- // Note: we are not touching this.pendingAttachBatch here, for two reasons:
1631
- // 1. It would not help, as we flush attach ops as they become available.
1632
- // 2. There is no way to undo process of data store creation.
1634
+ // Note: we are not touching any batches other than mainBatch here, for two reasons:
1635
+ // 1. It would not help, as other batches are flushed independently from main batch.
1636
+ // 2. There is no way to undo process of data store creation, blob creation, ID compressor ops, or other things tracked by other batches.
1633
1637
  checkpoint = this.outbox.checkpoint().mainBatch;
1634
1638
  }
1635
1639
  try {
@@ -2374,9 +2378,11 @@ export class ContainerRuntime extends TypedEventEmitter {
2374
2378
  this.verifyNotClosed();
2375
2379
  return this.blobManager.createBlob(blob, signal);
2376
2380
  }
2377
- submitIdAllocationOpIfNeeded() {
2381
+ submitIdAllocationOpIfNeeded(resubmitOutstandingRanges = false) {
2378
2382
  if (this._idCompressor) {
2379
- const idRange = this._idCompressor.takeNextCreationRange();
2383
+ const idRange = resubmitOutstandingRanges
2384
+ ? this.idCompressor?.takeUnfinalizedCreationRange()
2385
+ : this._idCompressor.takeNextCreationRange();
2380
2386
  // Don't include the idRange if there weren't any Ids allocated
2381
2387
  if (idRange?.ids !== undefined) {
2382
2388
  const idAllocationMessage = {
@@ -2438,32 +2444,7 @@ export class ContainerRuntime extends TypedEventEmitter {
2438
2444
  referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
2439
2445
  });
2440
2446
  }
2441
- // If this is attach message for new data store, and we are in a batch, send this op out of order
2442
- // Is it safe:
2443
- // Yes, this should be safe reordering. Newly created data stores are not visible through API surface.
2444
- // They become visible only when aliased, or handle to some sub-element of newly created datastore
2445
- // is stored in some DDS, i.e. only after some other op.
2446
- // Why:
2447
- // Attach ops are large, and expensive to process. Plus there are scenarios where a lot of new data
2448
- // stores are created, causing issues like relay service throttling (too many ops) and catastrophic
2449
- // failure (batch is too large). Pushing them earlier and outside of main batch should alleviate
2450
- // these issues.
2451
- // Cons:
2452
- // 1. With large batches, relay service may throttle clients. Clients may disconnect while throttled.
2453
- // This change creates new possibility of a lot of newly created data stores never being referenced
2454
- // because client died before it had a change to submit the rest of the ops. This will create more
2455
- // garbage that needs to be collected leveraging GC (Garbage Collection) feature.
2456
- // 2. Sending ops out of order means they are excluded from rollback functionality. This is not an issue
2457
- // today as rollback can't undo creation of data store. To some extent not sending them is a bigger
2458
- // issue than sending.
2459
- // Please note that this does not change file format, so it can be disabled in the future if this
2460
- // optimization no longer makes sense (for example, batch compression may make it less appealing).
2461
- if (this.currentlyBatching() &&
2462
- type === ContainerMessageType.Attach &&
2463
- this.disableAttachReorder !== true) {
2464
- this.outbox.submitAttach(message);
2465
- }
2466
- else if (type === ContainerMessageType.BlobAttach) {
2447
+ if (type === ContainerMessageType.BlobAttach) {
2467
2448
  // BlobAttach ops must have their metadata visible and cannot be grouped (see opGroupingManager.ts)
2468
2449
  this.outbox.submitBlobAttach(message);
2469
2450
  }
@@ -2595,7 +2576,13 @@ export class ContainerRuntime extends TypedEventEmitter {
2595
2576
  this.channelCollection.reSubmit(message.type, message.contents, localOpMetadata);
2596
2577
  break;
2597
2578
  case ContainerMessageType.IdAllocation: {
2598
- this.submit(message, localOpMetadata);
2579
+ // Allocation ops are never resubmitted/rebased. This is because they require special handling to
2580
+ // avoid being submitted out of order. For example, if the pending state manager contained
2581
+ // [idOp1, dataOp1, idOp2, dataOp2] and the resubmission of dataOp1 generated idOp3, that would be
2582
+ // placed into the outbox in the same batch as idOp1, but before idOp2 is resubmitted.
2583
+ // To avoid this, allocation ops are simply never resubmitted. Prior to invoking the pending state
2584
+ // manager to replay pending ops, the runtime will always submit a new allocation range that includes
2585
+ // all pending IDs. The resubmitted allocation ops are then ignored here.
2599
2586
  break;
2600
2587
  }
2601
2588
  case ContainerMessageType.ChunkedOp: