@fluidframework/container-runtime 2.0.0-internal.7.2.2 → 2.0.0-internal.7.3.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 (72) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +1 -2
  3. package/dist/batchTracker.d.ts +1 -0
  4. package/dist/batchTracker.d.ts.map +1 -1
  5. package/dist/connectionTelemetry.js +1 -1
  6. package/dist/connectionTelemetry.js.map +1 -1
  7. package/dist/containerRuntime.d.ts +5 -11
  8. package/dist/containerRuntime.d.ts.map +1 -1
  9. package/dist/containerRuntime.js +20 -30
  10. package/dist/containerRuntime.js.map +1 -1
  11. package/dist/messageTypes.d.ts +3 -6
  12. package/dist/messageTypes.d.ts.map +1 -1
  13. package/dist/messageTypes.js.map +1 -1
  14. package/dist/metadata.d.ts +6 -0
  15. package/dist/metadata.d.ts.map +1 -1
  16. package/dist/metadata.js.map +1 -1
  17. package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
  18. package/dist/opLifecycle/opGroupingManager.js +10 -1
  19. package/dist/opLifecycle/opGroupingManager.js.map +1 -1
  20. package/dist/opLifecycle/outbox.d.ts +2 -0
  21. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  22. package/dist/opLifecycle/outbox.js +21 -0
  23. package/dist/opLifecycle/outbox.js.map +1 -1
  24. package/dist/packageVersion.d.ts +1 -1
  25. package/dist/packageVersion.js +1 -1
  26. package/dist/packageVersion.js.map +1 -1
  27. package/dist/pendingStateManager.d.ts +0 -1
  28. package/dist/pendingStateManager.d.ts.map +1 -1
  29. package/dist/pendingStateManager.js +1 -11
  30. package/dist/pendingStateManager.js.map +1 -1
  31. package/dist/scheduleManager.d.ts +1 -0
  32. package/dist/scheduleManager.d.ts.map +1 -1
  33. package/dist/tsdoc-metadata.json +1 -1
  34. package/lib/batchTracker.d.ts +1 -0
  35. package/lib/batchTracker.d.ts.map +1 -1
  36. package/lib/connectionTelemetry.js +1 -1
  37. package/lib/connectionTelemetry.js.map +1 -1
  38. package/lib/containerRuntime.d.ts +5 -11
  39. package/lib/containerRuntime.d.ts.map +1 -1
  40. package/lib/containerRuntime.js +20 -30
  41. package/lib/containerRuntime.js.map +1 -1
  42. package/lib/messageTypes.d.ts +3 -6
  43. package/lib/messageTypes.d.ts.map +1 -1
  44. package/lib/messageTypes.js.map +1 -1
  45. package/lib/metadata.d.ts +6 -0
  46. package/lib/metadata.d.ts.map +1 -1
  47. package/lib/metadata.js.map +1 -1
  48. package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -1
  49. package/lib/opLifecycle/opGroupingManager.js +10 -1
  50. package/lib/opLifecycle/opGroupingManager.js.map +1 -1
  51. package/lib/opLifecycle/outbox.d.ts +2 -0
  52. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  53. package/lib/opLifecycle/outbox.js +21 -0
  54. package/lib/opLifecycle/outbox.js.map +1 -1
  55. package/lib/packageVersion.d.ts +1 -1
  56. package/lib/packageVersion.js +1 -1
  57. package/lib/packageVersion.js.map +1 -1
  58. package/lib/pendingStateManager.d.ts +0 -1
  59. package/lib/pendingStateManager.d.ts.map +1 -1
  60. package/lib/pendingStateManager.js +1 -11
  61. package/lib/pendingStateManager.js.map +1 -1
  62. package/lib/scheduleManager.d.ts +1 -0
  63. package/lib/scheduleManager.d.ts.map +1 -1
  64. package/package.json +29 -25
  65. package/src/connectionTelemetry.ts +1 -1
  66. package/src/containerRuntime.ts +30 -37
  67. package/src/messageTypes.ts +2 -7
  68. package/src/metadata.ts +7 -0
  69. package/src/opLifecycle/opGroupingManager.ts +10 -1
  70. package/src/opLifecycle/outbox.ts +34 -0
  71. package/src/packageVersion.ts +1 -1
  72. package/src/pendingStateManager.ts +2 -13
@@ -1,3 +1,4 @@
1
+ /// <reference types="node" />
1
2
  /*!
2
3
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
4
  * Licensed under the MIT License.
@@ -1 +1 @@
1
- {"version":3,"file":"scheduleManager.d.ts","sourceRoot":"","sources":["../src/scheduleManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,uCAAuC,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AACnG,OAAO,EAKN,mBAAmB,EACnB,MAAM,iCAAiC,CAAC;AAczC;;;;;;;;GAQG;AACH,qBAAa,eAAe;IAM1B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,MAAM,GAAG,SAAS;IAC9C,OAAO,CAAC,QAAQ,CAAC,MAAM;IARxB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAiB;IAChD,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,QAAQ,CAAS;gBAGP,YAAY,EAAE,aAAa,CAAC,yBAAyB,EAAE,gBAAgB,CAAC,EACxE,OAAO,EAAE,YAAY,EAC7B,WAAW,EAAE,MAAM,MAAM,GAAG,SAAS,EAC7B,MAAM,EAAE,mBAAmB;IAStC,kBAAkB,CAAC,OAAO,EAAE,yBAAyB;IAkBrD,iBAAiB,CAAC,KAAK,EAAE,GAAG,GAAG,SAAS,EAAE,OAAO,EAAE,yBAAyB;CAwBnF"}
1
+ {"version":3,"file":"scheduleManager.d.ts","sourceRoot":"","sources":["../src/scheduleManager.ts"],"names":[],"mappings":";AAAA;;;GAGG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,uCAAuC,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AACnG,OAAO,EAKN,mBAAmB,EACnB,MAAM,iCAAiC,CAAC;AAczC;;;;;;;;GAQG;AACH,qBAAa,eAAe;IAM1B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,MAAM,GAAG,SAAS;IAC9C,OAAO,CAAC,QAAQ,CAAC,MAAM;IARxB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAiB;IAChD,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,QAAQ,CAAS;gBAGP,YAAY,EAAE,aAAa,CAAC,yBAAyB,EAAE,gBAAgB,CAAC,EACxE,OAAO,EAAE,YAAY,EAC7B,WAAW,EAAE,MAAM,MAAM,GAAG,SAAS,EAC7B,MAAM,EAAE,mBAAmB;IAStC,kBAAkB,CAAC,OAAO,EAAE,yBAAyB;IAkBrD,iBAAiB,CAAC,KAAK,EAAE,GAAG,GAAG,SAAS,EAAE,OAAO,EAAE,yBAAyB;CAwBnF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/container-runtime",
3
- "version": "2.0.0-internal.7.2.2",
3
+ "version": "2.0.0-internal.7.3.0",
4
4
  "description": "Fluid container runtime",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -35,18 +35,18 @@
35
35
  "temp-directory": "nyc/.nyc_output"
36
36
  },
37
37
  "dependencies": {
38
- "@fluid-internal/client-utils": ">=2.0.0-internal.7.2.2 <2.0.0-internal.7.3.0",
39
- "@fluidframework/container-definitions": ">=2.0.0-internal.7.2.2 <2.0.0-internal.7.3.0",
40
- "@fluidframework/container-runtime-definitions": ">=2.0.0-internal.7.2.2 <2.0.0-internal.7.3.0",
41
- "@fluidframework/core-interfaces": ">=2.0.0-internal.7.2.2 <2.0.0-internal.7.3.0",
42
- "@fluidframework/core-utils": ">=2.0.0-internal.7.2.2 <2.0.0-internal.7.3.0",
43
- "@fluidframework/datastore": ">=2.0.0-internal.7.2.2 <2.0.0-internal.7.3.0",
44
- "@fluidframework/driver-definitions": ">=2.0.0-internal.7.2.2 <2.0.0-internal.7.3.0",
45
- "@fluidframework/driver-utils": ">=2.0.0-internal.7.2.2 <2.0.0-internal.7.3.0",
38
+ "@fluid-internal/client-utils": ">=2.0.0-internal.7.3.0 <2.0.0-internal.7.4.0",
39
+ "@fluidframework/container-definitions": ">=2.0.0-internal.7.3.0 <2.0.0-internal.7.4.0",
40
+ "@fluidframework/container-runtime-definitions": ">=2.0.0-internal.7.3.0 <2.0.0-internal.7.4.0",
41
+ "@fluidframework/core-interfaces": ">=2.0.0-internal.7.3.0 <2.0.0-internal.7.4.0",
42
+ "@fluidframework/core-utils": ">=2.0.0-internal.7.3.0 <2.0.0-internal.7.4.0",
43
+ "@fluidframework/datastore": ">=2.0.0-internal.7.3.0 <2.0.0-internal.7.4.0",
44
+ "@fluidframework/driver-definitions": ">=2.0.0-internal.7.3.0 <2.0.0-internal.7.4.0",
45
+ "@fluidframework/driver-utils": ">=2.0.0-internal.7.3.0 <2.0.0-internal.7.4.0",
46
46
  "@fluidframework/protocol-definitions": "^3.0.0",
47
- "@fluidframework/runtime-definitions": ">=2.0.0-internal.7.2.2 <2.0.0-internal.7.3.0",
48
- "@fluidframework/runtime-utils": ">=2.0.0-internal.7.2.2 <2.0.0-internal.7.3.0",
49
- "@fluidframework/telemetry-utils": ">=2.0.0-internal.7.2.2 <2.0.0-internal.7.3.0",
47
+ "@fluidframework/runtime-definitions": ">=2.0.0-internal.7.3.0 <2.0.0-internal.7.4.0",
48
+ "@fluidframework/runtime-utils": ">=2.0.0-internal.7.3.0 <2.0.0-internal.7.4.0",
49
+ "@fluidframework/telemetry-utils": ">=2.0.0-internal.7.3.0 <2.0.0-internal.7.4.0",
50
50
  "double-ended-queue": "^2.1.0-0",
51
51
  "events": "^3.1.0",
52
52
  "lz4js": "^0.2.0",
@@ -54,16 +54,16 @@
54
54
  "uuid": "^9.0.0"
55
55
  },
56
56
  "devDependencies": {
57
- "@fluid-internal/stochastic-test-utils": ">=2.0.0-internal.7.2.2 <2.0.0-internal.7.3.0",
57
+ "@fluid-private/stochastic-test-utils": ">=2.0.0-internal.7.3.0 <2.0.0-internal.7.4.0",
58
58
  "@fluid-tools/benchmark": "^0.48.0",
59
- "@fluid-tools/build-cli": "^0.26.1",
59
+ "@fluid-tools/build-cli": "^0.28.0",
60
60
  "@fluidframework/build-common": "^2.0.3",
61
- "@fluidframework/build-tools": "^0.26.1",
62
- "@fluidframework/container-runtime-previous": "npm:@fluidframework/container-runtime@2.0.0-internal.7.2.1",
63
- "@fluidframework/eslint-config-fluid": "^3.0.0",
64
- "@fluidframework/mocha-test-setup": ">=2.0.0-internal.7.2.2 <2.0.0-internal.7.3.0",
65
- "@fluidframework/test-runtime-utils": ">=2.0.0-internal.7.2.2 <2.0.0-internal.7.3.0",
66
- "@microsoft/api-extractor": "^7.37.0",
61
+ "@fluidframework/build-tools": "^0.28.0",
62
+ "@fluidframework/container-runtime-previous": "npm:@fluidframework/container-runtime@2.0.0-internal.7.2.0",
63
+ "@fluidframework/eslint-config-fluid": "^3.1.0",
64
+ "@fluidframework/mocha-test-setup": ">=2.0.0-internal.7.3.0 <2.0.0-internal.7.4.0",
65
+ "@fluidframework/test-runtime-utils": ">=2.0.0-internal.7.3.0 <2.0.0-internal.7.4.0",
66
+ "@microsoft/api-extractor": "^7.38.3",
67
67
  "@types/double-ended-queue": "^2.1.0",
68
68
  "@types/events": "^3.0.0",
69
69
  "@types/mocha": "^9.1.1",
@@ -82,7 +82,11 @@
82
82
  "typescript": "~5.1.6"
83
83
  },
84
84
  "typeValidation": {
85
- "broken": {}
85
+ "broken": {
86
+ "ClassDeclaration_ContainerRuntime": {
87
+ "backCompat": false
88
+ }
89
+ }
86
90
  },
87
91
  "scripts": {
88
92
  "build": "fluid-build . --task build",
@@ -93,18 +97,18 @@
93
97
  "build:genver": "gen-version",
94
98
  "build:test": "tsc --project ./src/test/tsconfig.json",
95
99
  "ci:build:docs": "api-extractor run",
96
- "clean": "rimraf --glob dist lib \"*.tsbuildinfo\" \"*.build.log\" _api-extractor-temp nyc",
100
+ "clean": "rimraf --glob dist lib \"**/*.tsbuildinfo\" \"**/*.build.log\" _api-extractor-temp nyc",
97
101
  "eslint": "eslint --format stylish src",
98
102
  "eslint:fix": "eslint --format stylish src --fix --fix-type problem,suggestion,layout",
99
103
  "format": "npm run prettier:fix",
100
104
  "lint": "npm run prettier && npm run eslint",
101
- "lint:fix": "npm run prettier:fix &&npm run eslint:fix",
105
+ "lint:fix": "npm run prettier:fix && npm run eslint:fix",
102
106
  "prettier": "prettier --check . --ignore-path ../../../.prettierignore",
103
107
  "prettier:fix": "prettier --write . --ignore-path ../../../.prettierignore",
104
108
  "test": "npm run test:mocha",
105
- "test:benchmark:report": "mocha --timeout 999999 --perfMode --parentProcess --fgrep @Benchmark --reporter @fluid-tools/benchmark/dist/MochaReporter.js ./dist/**/*.perf.spec.js",
109
+ "test:benchmark:report": "mocha --timeout 999999 --perfMode --parentProcess --fgrep @Benchmark --reporter @fluid-tools/benchmark/dist/MochaReporter.js \"./dist/**/*.perf.spec.js\"",
106
110
  "test:coverage": "c8 npm test",
107
- "test:mocha": "mocha --ignore 'dist/test/types/*' --recursive dist/test -r node_modules/@fluidframework/mocha-test-setup",
111
+ "test:mocha": "mocha --ignore \"dist/test/types/*\" --recursive dist/test -r node_modules/@fluidframework/mocha-test-setup",
108
112
  "test:mocha:verbose": "cross-env FLUID_TEST_VERBOSE=1 npm run test:mocha",
109
113
  "tsc": "tsc",
110
114
  "tsc:watch": "tsc --watch",
@@ -110,7 +110,7 @@ class OpPerfTelemetry {
110
110
 
111
111
  this.deltaLatencyLogger = createSampledLogger(logger, deltaLatencyEventSampler);
112
112
 
113
- // The SampledLogger here is used get access to the isSamplingDisabled property dervied from
113
+ // The SampledLogger here is used get access to the isSamplingDisabled property derived from
114
114
  // telemetry config properties. The actual sampling logic for op messages happens outside this SampledLogger
115
115
  // due to complexity of the different asynchronus scenarios of the op message lifecycle.
116
116
  this.opLatencyLogger = createSampledLogger(logger);
@@ -91,7 +91,7 @@ import {
91
91
  IIdCompressor,
92
92
  IIdCompressorCore,
93
93
  IdCreationRange,
94
- IdCreationRangeWithStashedState,
94
+ SerializedIdCompressorWithOngoingSession,
95
95
  } from "@fluidframework/runtime-definitions";
96
96
  import {
97
97
  addBlobToSummary,
@@ -185,13 +185,12 @@ import {
185
185
  getLongStack,
186
186
  } from "./opLifecycle";
187
187
  import { DeltaManagerSummarizerProxy } from "./deltaManagerSummarizerProxy";
188
- import { IBatchMetadata } from "./metadata";
188
+ import { IBatchMetadata, IIdAllocationMetadata } from "./metadata";
189
189
  import {
190
190
  ContainerMessageType,
191
191
  type InboundSequencedContainerRuntimeMessage,
192
192
  type InboundSequencedContainerRuntimeMessageOrSystemMessage,
193
193
  type ContainerRuntimeIdAllocationMessage,
194
- type LocalContainerRuntimeIdAllocationMessage,
195
194
  type LocalContainerRuntimeMessage,
196
195
  type OutboundContainerRuntimeMessage,
197
196
  type UnknownContainerRuntimeMessage,
@@ -213,15 +212,6 @@ function compatBehaviorAllowsMessageType(
213
212
  return compatBehavior === "Ignore";
214
213
  }
215
214
 
216
- function prepareLocalContainerRuntimeIdAllocationMessageForTransit(
217
- message: LocalContainerRuntimeIdAllocationMessage | ContainerRuntimeIdAllocationMessage,
218
- ): asserts message is ContainerRuntimeIdAllocationMessage {
219
- // Remove the stashedState from the op if it's a stashed op
220
- if ("stashedState" in message.contents) {
221
- delete message.contents.stashedState;
222
- }
223
- }
224
-
225
215
  /**
226
216
  * @public
227
217
  */
@@ -557,6 +547,10 @@ export interface IPendingRuntimeState {
557
547
  * Pending blobs from BlobManager
558
548
  */
559
549
  pendingAttachmentBlobs?: IPendingBlobs;
550
+ /**
551
+ * Pending idCompressor state
552
+ */
553
+ pendingIdCompressorState?: SerializedIdCompressorWithOngoingSession;
560
554
  }
561
555
 
562
556
  const maxConsecutiveReconnectsKey = "Fluid.ContainerRuntime.MaxConsecutiveReconnects";
@@ -916,10 +910,16 @@ export class ContainerRuntime
916
910
  let idCompressor: (IIdCompressor & IIdCompressorCore) | undefined;
917
911
  if (idCompressorEnabled) {
918
912
  const { IdCompressor, createSessionId } = await import("./id-compressor");
919
- idCompressor =
920
- serializedIdCompressor !== undefined
921
- ? IdCompressor.deserialize(serializedIdCompressor, createSessionId())
922
- : IdCompressor.create(logger);
913
+
914
+ const pendingLocalState = context.pendingLocalState as IPendingRuntimeState;
915
+
916
+ if (pendingLocalState?.pendingIdCompressorState !== undefined) {
917
+ idCompressor = IdCompressor.deserialize(pendingLocalState.pendingIdCompressorState);
918
+ } else if (serializedIdCompressor !== undefined) {
919
+ idCompressor = IdCompressor.deserialize(serializedIdCompressor, createSessionId());
920
+ } else {
921
+ idCompressor = IdCompressor.create(logger);
922
+ }
923
923
  }
924
924
 
925
925
  const runtime = new containerRuntimeCtor(
@@ -2050,20 +2050,6 @@ export class ContainerRuntime
2050
2050
  this.updateDocumentDirtyState(newState);
2051
2051
  }
2052
2052
 
2053
- /**
2054
- * Updates the runtime's IdCompressor with the stashed state present in the given op. This is a bit of a
2055
- * hack and is unnecessarily expensive. As it stands, every locally stashed op (all ops that get stored in
2056
- * the PendingStateManager) will store their serialized representation locally until ack'd. Upon receiving
2057
- * this stashed state, the IdCompressor blindly deserializes to the stashed state and assumes the session.
2058
- * Technically only the last stashed state is needed to do this correctly, but we would have to write some
2059
- * more hacky code to modify the batch before it gets sent out.
2060
- * @param content - An IdAllocationOp with "stashedState", which is a representation of un-ack'd local state.
2061
- */
2062
- private async applyStashedIdAllocationOp(op: IdCreationRangeWithStashedState) {
2063
- const { IdCompressor } = await import("./id-compressor");
2064
- this.idCompressor = IdCompressor.deserialize(op.stashedState);
2065
- }
2066
-
2067
2053
  /**
2068
2054
  * Parse an op's type and actual content from given serialized content
2069
2055
  * ! Note: this format needs to be in-line with what is set in the "ContainerRuntime.submit(...)" method
@@ -2089,7 +2075,7 @@ export class ContainerRuntime
2089
2075
  this.idCompressor !== undefined,
2090
2076
  0x67b /* IdCompressor should be defined if enabled */,
2091
2077
  );
2092
- return this.applyStashedIdAllocationOp(opContents.contents);
2078
+ return;
2093
2079
  case ContainerMessageType.Alias:
2094
2080
  case ContainerMessageType.BlobAttach:
2095
2081
  return;
@@ -2341,7 +2327,14 @@ export class ContainerRuntime
2341
2327
  this.idCompressor !== undefined,
2342
2328
  0x67c /* IdCompressor should be defined if enabled */,
2343
2329
  );
2344
- this.idCompressor.finalizeCreationRange(messageWithContext.message.contents);
2330
+
2331
+ // Don't re-finalize the range if we're processing a "savedOp" in
2332
+ // stashed ops flow. The compressor is stashed with these ops already processed.
2333
+ if (
2334
+ (messageWithContext.message.metadata as IIdAllocationMetadata)?.savedOp !== true
2335
+ ) {
2336
+ this.idCompressor.finalizeCreationRange(messageWithContext.message.contents);
2337
+ }
2345
2338
  break;
2346
2339
  case ContainerMessageType.ChunkedOp:
2347
2340
  case ContainerMessageType.Rejoin:
@@ -3516,13 +3509,13 @@ export class ContainerRuntime
3516
3509
  contents: JSON.stringify(idAllocationMessage),
3517
3510
  referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
3518
3511
  metadata: undefined,
3519
- localOpMetadata: this.idCompressor?.serialize(true),
3512
+ localOpMetadata: undefined,
3520
3513
  type: ContainerMessageType.IdAllocation,
3521
3514
  };
3522
3515
  }
3523
3516
 
3524
3517
  if (idAllocationBatchMessage !== undefined) {
3525
- this.outbox.submit(idAllocationBatchMessage);
3518
+ this.outbox.submitIdAllocation(idAllocationBatchMessage);
3526
3519
  }
3527
3520
  }
3528
3521
  }
@@ -3747,10 +3740,7 @@ export class ContainerRuntime
3747
3740
  break;
3748
3741
  case ContainerMessageType.Attach:
3749
3742
  case ContainerMessageType.Alias:
3750
- this.submit(message, localOpMetadata);
3751
- break;
3752
3743
  case ContainerMessageType.IdAllocation: {
3753
- prepareLocalContainerRuntimeIdAllocationMessageForTransit(message);
3754
3744
  this.submit(message, localOpMetadata);
3755
3745
  break;
3756
3746
  }
@@ -3990,9 +3980,12 @@ export class ContainerRuntime
3990
3980
  return; // no pending state to save
3991
3981
  }
3992
3982
 
3983
+ const pendingIdCompressorState = this.idCompressor?.serialize(true);
3984
+
3993
3985
  const pendingState: IPendingRuntimeState = {
3994
3986
  pending,
3995
3987
  pendingAttachmentBlobs,
3988
+ pendingIdCompressorState,
3996
3989
  };
3997
3990
  event.end({
3998
3991
  attachmentBlobsSize: Object.keys(pendingAttachmentBlobs ?? {}).length,
@@ -8,7 +8,6 @@ import {
8
8
  IEnvelope,
9
9
  InboundAttachMessage,
10
10
  IAttachMessage,
11
- IdCreationRangeWithStashedState,
12
11
  IdCreationRange,
13
12
  } from "@fluidframework/runtime-definitions";
14
13
  import { IDataStoreAliasMessage } from "./dataStore";
@@ -116,13 +115,9 @@ export type ContainerRuntimeAliasMessage = TypedContainerRuntimeMessage<
116
115
  ContainerMessageType.Alias,
117
116
  IDataStoreAliasMessage
118
117
  >;
119
- export type LocalContainerRuntimeIdAllocationMessage = TypedContainerRuntimeMessage<
120
- ContainerMessageType.IdAllocation,
121
- IdCreationRangeWithStashedState
122
- >;
123
118
  export type ContainerRuntimeIdAllocationMessage = TypedContainerRuntimeMessage<
124
119
  ContainerMessageType.IdAllocation,
125
- IdCreationRange & { stashedState?: never }
120
+ IdCreationRange
126
121
  >;
127
122
 
128
123
  /**
@@ -163,7 +158,7 @@ export type LocalContainerRuntimeMessage =
163
158
  | ContainerRuntimeBlobAttachMessage
164
159
  | ContainerRuntimeRejoinMessage
165
160
  | ContainerRuntimeAliasMessage
166
- | LocalContainerRuntimeIdAllocationMessage
161
+ | ContainerRuntimeIdAllocationMessage
167
162
  // In rare cases (e.g. related to stashed ops) we could have a local message of an unknown type
168
163
  | UnknownContainerRuntimeMessage;
169
164
 
package/src/metadata.ts CHANGED
@@ -17,3 +17,10 @@ export interface IBlobMetadata {
17
17
  blobId?: string;
18
18
  localId?: string;
19
19
  }
20
+
21
+ /**
22
+ * The IdCompressor needs to know if this is a replayed savedOp as those need to be skipped in stashed ops scenarios.
23
+ */
24
+ export interface IIdAllocationMetadata {
25
+ savedOp?: boolean;
26
+ }
@@ -96,12 +96,21 @@ export class OpGroupingManager {
96
96
  }
97
97
 
98
98
  public ungroupOp(op: ISequencedDocumentMessage): ISequencedDocumentMessage[] {
99
+ let fakeCsn = 1;
99
100
  if (!isGroupContents(op.contents)) {
101
+ // Align the worlds of what clientSequenceNumber represents when grouped batching is enabled
102
+ if (this.config.groupedBatchingEnabled) {
103
+ return [
104
+ {
105
+ ...op,
106
+ clientSequenceNumber: fakeCsn,
107
+ },
108
+ ];
109
+ }
100
110
  return [op];
101
111
  }
102
112
 
103
113
  const messages = op.contents.contents;
104
- let fakeCsn = 1;
105
114
  return messages.map((subMessage) => ({
106
115
  ...op,
107
116
  clientSequenceNumber: fakeCsn++,
@@ -89,6 +89,7 @@ export class Outbox {
89
89
  private readonly attachFlowBatch: BatchManager;
90
90
  private readonly mainBatch: BatchManager;
91
91
  private readonly blobAttachBatch: BatchManager;
92
+ private readonly idAllocationBatch: BatchManager;
92
93
  private readonly defaultAttachFlowSoftLimitInBytes = 320 * 1024;
93
94
  private batchRebasesToReport = 5;
94
95
  private rebasing = false;
@@ -114,6 +115,7 @@ export class Outbox {
114
115
  this.attachFlowBatch = new BatchManager({ hardLimit, softLimit });
115
116
  this.mainBatch = new BatchManager({ hardLimit });
116
117
  this.blobAttachBatch = new BatchManager({ hardLimit });
118
+ this.idAllocationBatch = new BatchManager({ hardLimit });
117
119
  }
118
120
 
119
121
  public get messageCount(): number {
@@ -230,6 +232,37 @@ export class Outbox {
230
232
  }
231
233
  }
232
234
 
235
+ public submitIdAllocation(message: BatchMessage) {
236
+ this.maybeFlushPartialBatch();
237
+
238
+ if (
239
+ !this.idAllocationBatch.push(
240
+ message,
241
+ this.isContextReentrant(),
242
+ this.params.getCurrentSequenceNumbers().clientSequenceNumber,
243
+ )
244
+ ) {
245
+ // BatchManager has two limits - soft limit & hard limit. Soft limit is only engaged
246
+ // when queue is not empty.
247
+ // Flush queue & retry. Failure on retry would mean - single message is bigger than hard limit
248
+ this.flushInternal(this.idAllocationBatch);
249
+
250
+ this.addMessageToBatchManager(this.idAllocationBatch, message);
251
+ }
252
+
253
+ // If compression is enabled, we will always successfully receive
254
+ // attach ops and compress then send them at the next JS turn, regardless
255
+ // of the overall size of the accumulated ops in the batch.
256
+ // However, it is more efficient to flush these ops faster, preferably
257
+ // after they reach a size which would benefit from compression.
258
+ if (
259
+ this.idAllocationBatch.contentSizeInBytes >=
260
+ this.params.config.compressionOptions.minimumBatchSizeInBytes
261
+ ) {
262
+ this.flushInternal(this.idAllocationBatch);
263
+ }
264
+ }
265
+
233
266
  private addMessageToBatchManager(batchManager: BatchManager, message: BatchMessage) {
234
267
  if (
235
268
  !batchManager.push(
@@ -258,6 +291,7 @@ export class Outbox {
258
291
  }
259
292
 
260
293
  private flushAll() {
294
+ this.flushInternal(this.idAllocationBatch);
261
295
  this.flushInternal(this.attachFlowBatch);
262
296
  this.flushInternal(this.blobAttachBatch, true /* disableGroupedBatching */);
263
297
  this.flushInternal(this.mainBatch);
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/container-runtime";
9
- export const pkgVersion = "2.0.0-internal.7.2.2";
9
+ export const pkgVersion = "2.0.0-internal.7.3.0";
@@ -11,7 +11,7 @@ import { ICriticalContainerError } from "@fluidframework/container-definitions";
11
11
  import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
12
12
  import { DataProcessingError, ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
13
13
 
14
- import { ContainerMessageType, InboundSequencedContainerRuntimeMessage } from "./messageTypes";
14
+ import { InboundSequencedContainerRuntimeMessage } from "./messageTypes";
15
15
  import { pkgVersion } from "./packageVersion";
16
16
  import { IBatchMetadata } from "./metadata";
17
17
 
@@ -21,7 +21,6 @@ import { IBatchMetadata } from "./metadata";
21
21
  */
22
22
  export interface IPendingMessage {
23
23
  type: "message";
24
- clientSequenceNumber: number;
25
24
  referenceSequenceNumber: number;
26
25
  content: string;
27
26
  localOpMetadata: unknown;
@@ -128,18 +127,9 @@ export class PendingStateManager implements IDisposable {
128
127
  return {
129
128
  pendingStates: [...this.savedOps, ...this.pendingMessages.toArray()].map(
130
129
  (message) => {
131
- let content = message.content;
132
- const parsedContent = JSON.parse(content);
133
- // IdAllocations need their localOpMetadata stashed in the contents
134
- // of the op to correctly resume the session when processing stashed ops
135
- if (parsedContent.type === ContainerMessageType.IdAllocation) {
136
- parsedContent.contents.stashedState = message.localOpMetadata;
137
- content = JSON.stringify(parsedContent);
138
- }
139
-
140
130
  // delete localOpMetadata since it may not be serializable
141
131
  // and will be regenerated by applyStashedOp()
142
- return { ...message, content, localOpMetadata: undefined };
132
+ return { ...message, localOpMetadata: undefined };
143
133
  },
144
134
  ),
145
135
  };
@@ -176,7 +166,6 @@ export class PendingStateManager implements IDisposable {
176
166
  ) {
177
167
  const pendingMessage: IPendingMessage = {
178
168
  type: "message",
179
- clientSequenceNumber: -1, // dummy value (not to be used anywhere)
180
169
  referenceSequenceNumber,
181
170
  content,
182
171
  localOpMetadata,