@fluidframework/container-runtime 2.0.0-internal.7.2.1 → 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 (108) 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 +26 -32
  10. package/dist/containerRuntime.js.map +1 -1
  11. package/dist/gc/gcConfigs.d.ts.map +1 -1
  12. package/dist/gc/gcConfigs.js +4 -1
  13. package/dist/gc/gcConfigs.js.map +1 -1
  14. package/dist/gc/gcDefinitions.d.ts +7 -2
  15. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  16. package/dist/gc/gcDefinitions.js +8 -3
  17. package/dist/gc/gcDefinitions.js.map +1 -1
  18. package/dist/gc/gcTelemetry.d.ts +1 -1
  19. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  20. package/dist/gc/gcTelemetry.js +20 -8
  21. package/dist/gc/gcTelemetry.js.map +1 -1
  22. package/dist/gc/index.d.ts +1 -1
  23. package/dist/gc/index.d.ts.map +1 -1
  24. package/dist/gc/index.js +3 -1
  25. package/dist/gc/index.js.map +1 -1
  26. package/dist/messageTypes.d.ts +3 -6
  27. package/dist/messageTypes.d.ts.map +1 -1
  28. package/dist/messageTypes.js.map +1 -1
  29. package/dist/metadata.d.ts +6 -0
  30. package/dist/metadata.d.ts.map +1 -1
  31. package/dist/metadata.js.map +1 -1
  32. package/dist/opLifecycle/opGroupingManager.d.ts +10 -2
  33. package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
  34. package/dist/opLifecycle/opGroupingManager.js +33 -4
  35. package/dist/opLifecycle/opGroupingManager.js.map +1 -1
  36. package/dist/opLifecycle/outbox.d.ts +2 -1
  37. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  38. package/dist/opLifecycle/outbox.js +23 -1
  39. package/dist/opLifecycle/outbox.js.map +1 -1
  40. package/dist/packageVersion.d.ts +1 -1
  41. package/dist/packageVersion.js +1 -1
  42. package/dist/packageVersion.js.map +1 -1
  43. package/dist/pendingStateManager.d.ts +0 -1
  44. package/dist/pendingStateManager.d.ts.map +1 -1
  45. package/dist/pendingStateManager.js +1 -11
  46. package/dist/pendingStateManager.js.map +1 -1
  47. package/dist/scheduleManager.d.ts +1 -0
  48. package/dist/scheduleManager.d.ts.map +1 -1
  49. package/dist/tsdoc-metadata.json +1 -1
  50. package/lib/batchTracker.d.ts +1 -0
  51. package/lib/batchTracker.d.ts.map +1 -1
  52. package/lib/connectionTelemetry.js +1 -1
  53. package/lib/connectionTelemetry.js.map +1 -1
  54. package/lib/containerRuntime.d.ts +5 -11
  55. package/lib/containerRuntime.d.ts.map +1 -1
  56. package/lib/containerRuntime.js +26 -32
  57. package/lib/containerRuntime.js.map +1 -1
  58. package/lib/gc/gcConfigs.d.ts.map +1 -1
  59. package/lib/gc/gcConfigs.js +5 -2
  60. package/lib/gc/gcConfigs.js.map +1 -1
  61. package/lib/gc/gcDefinitions.d.ts +7 -2
  62. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  63. package/lib/gc/gcDefinitions.js +7 -2
  64. package/lib/gc/gcDefinitions.js.map +1 -1
  65. package/lib/gc/gcTelemetry.d.ts +1 -1
  66. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  67. package/lib/gc/gcTelemetry.js +21 -9
  68. package/lib/gc/gcTelemetry.js.map +1 -1
  69. package/lib/gc/index.d.ts +1 -1
  70. package/lib/gc/index.d.ts.map +1 -1
  71. package/lib/gc/index.js +1 -1
  72. package/lib/gc/index.js.map +1 -1
  73. package/lib/messageTypes.d.ts +3 -6
  74. package/lib/messageTypes.d.ts.map +1 -1
  75. package/lib/messageTypes.js.map +1 -1
  76. package/lib/metadata.d.ts +6 -0
  77. package/lib/metadata.d.ts.map +1 -1
  78. package/lib/metadata.js.map +1 -1
  79. package/lib/opLifecycle/opGroupingManager.d.ts +10 -2
  80. package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -1
  81. package/lib/opLifecycle/opGroupingManager.js +33 -4
  82. package/lib/opLifecycle/opGroupingManager.js.map +1 -1
  83. package/lib/opLifecycle/outbox.d.ts +2 -1
  84. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  85. package/lib/opLifecycle/outbox.js +23 -1
  86. package/lib/opLifecycle/outbox.js.map +1 -1
  87. package/lib/packageVersion.d.ts +1 -1
  88. package/lib/packageVersion.js +1 -1
  89. package/lib/packageVersion.js.map +1 -1
  90. package/lib/pendingStateManager.d.ts +0 -1
  91. package/lib/pendingStateManager.d.ts.map +1 -1
  92. package/lib/pendingStateManager.js +1 -11
  93. package/lib/pendingStateManager.js.map +1 -1
  94. package/lib/scheduleManager.d.ts +1 -0
  95. package/lib/scheduleManager.d.ts.map +1 -1
  96. package/package.json +25 -25
  97. package/src/connectionTelemetry.ts +1 -1
  98. package/src/containerRuntime.ts +41 -39
  99. package/src/gc/gcConfigs.ts +8 -2
  100. package/src/gc/gcDefinitions.ts +10 -2
  101. package/src/gc/gcTelemetry.ts +28 -17
  102. package/src/gc/index.ts +2 -0
  103. package/src/messageTypes.ts +2 -7
  104. package/src/metadata.ts +7 -0
  105. package/src/opLifecycle/opGroupingManager.ts +47 -3
  106. package/src/opLifecycle/outbox.ts +38 -2
  107. package/src/packageVersion.ts +1 -1
  108. package/src/pendingStateManager.ts +2 -13
@@ -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
+ }
@@ -5,6 +5,8 @@
5
5
 
6
6
  import { assert } from "@fluidframework/core-utils";
7
7
  import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
8
+ import { createChildLogger } from "@fluidframework/telemetry-utils";
9
+ import { ITelemetryBaseLogger } from "@fluidframework/core-interfaces";
8
10
  import { ContainerMessageType } from "../messageTypes";
9
11
  import { IBatch } from "./definitions";
10
12
 
@@ -26,16 +28,38 @@ function isGroupContents(opContents: any): opContents is IGroupedBatchMessageCon
26
28
  return opContents?.type === OpGroupingManager.groupedBatchOp;
27
29
  }
28
30
 
31
+ export interface OpGroupingManagerConfig {
32
+ readonly groupedBatchingEnabled: boolean;
33
+ readonly opCountThreshold: number;
34
+ readonly reentrantBatchGroupingEnabled: boolean;
35
+ }
36
+
29
37
  export class OpGroupingManager {
30
38
  static readonly groupedBatchOp = "groupedBatch";
39
+ private readonly logger;
31
40
 
32
- constructor(private readonly groupedBatchingEnabled: boolean) {}
41
+ constructor(
42
+ private readonly config: OpGroupingManagerConfig,
43
+ logger: ITelemetryBaseLogger,
44
+ ) {
45
+ this.logger = createChildLogger({ logger, namespace: "OpGroupingManager" });
46
+ }
33
47
 
34
48
  public groupBatch(batch: IBatch): IBatch {
35
- if (batch.content.length < 2 || !this.groupedBatchingEnabled) {
49
+ if (!this.shouldGroup(batch)) {
36
50
  return batch;
37
51
  }
38
52
 
53
+ if (batch.content.length >= 1000) {
54
+ this.logger.sendTelemetryEvent({
55
+ eventName: "GroupLargeBatch",
56
+ length: batch.content.length,
57
+ threshold: this.config.opCountThreshold,
58
+ reentrant: batch.hasReentrantOps,
59
+ referenceSequenceNumber: batch.content[0].referenceSequenceNumber,
60
+ });
61
+ }
62
+
39
63
  for (const message of batch.content) {
40
64
  if (message.metadata) {
41
65
  const keys = Object.keys(message.metadata);
@@ -72,12 +96,21 @@ export class OpGroupingManager {
72
96
  }
73
97
 
74
98
  public ungroupOp(op: ISequencedDocumentMessage): ISequencedDocumentMessage[] {
99
+ let fakeCsn = 1;
75
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
+ }
76
110
  return [op];
77
111
  }
78
112
 
79
113
  const messages = op.contents.contents;
80
- let fakeCsn = 1;
81
114
  return messages.map((subMessage) => ({
82
115
  ...op,
83
116
  clientSequenceNumber: fakeCsn++,
@@ -86,4 +119,15 @@ export class OpGroupingManager {
86
119
  compression: subMessage.compression,
87
120
  }));
88
121
  }
122
+
123
+ public shouldGroup(batch: IBatch): boolean {
124
+ return (
125
+ // Grouped batching must be enabled
126
+ this.config.groupedBatchingEnabled &&
127
+ // The number of ops in the batch must surpass the configured threshold
128
+ batch.content.length >= this.config.opCountThreshold &&
129
+ // Support for reentrant batches must be explicitly enabled
130
+ (this.config.reentrantBatchGroupingEnabled || batch.hasReentrantOps !== true)
131
+ );
132
+ }
89
133
  }
@@ -30,7 +30,6 @@ export interface IOutboxConfig {
30
30
  // The maximum size of a batch that we can send over the wire.
31
31
  readonly maxBatchSizeInBytes: number;
32
32
  readonly disablePartialFlush: boolean;
33
- readonly enableGroupedBatching: boolean;
34
33
  }
35
34
 
36
35
  export interface IOutboxParameters {
@@ -90,6 +89,7 @@ export class Outbox {
90
89
  private readonly attachFlowBatch: BatchManager;
91
90
  private readonly mainBatch: BatchManager;
92
91
  private readonly blobAttachBatch: BatchManager;
92
+ private readonly idAllocationBatch: BatchManager;
93
93
  private readonly defaultAttachFlowSoftLimitInBytes = 320 * 1024;
94
94
  private batchRebasesToReport = 5;
95
95
  private rebasing = false;
@@ -115,6 +115,7 @@ export class Outbox {
115
115
  this.attachFlowBatch = new BatchManager({ hardLimit, softLimit });
116
116
  this.mainBatch = new BatchManager({ hardLimit });
117
117
  this.blobAttachBatch = new BatchManager({ hardLimit });
118
+ this.idAllocationBatch = new BatchManager({ hardLimit });
118
119
  }
119
120
 
120
121
  public get messageCount(): number {
@@ -231,6 +232,37 @@ export class Outbox {
231
232
  }
232
233
  }
233
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
+
234
266
  private addMessageToBatchManager(batchManager: BatchManager, message: BatchMessage) {
235
267
  if (
236
268
  !batchManager.push(
@@ -259,6 +291,7 @@ export class Outbox {
259
291
  }
260
292
 
261
293
  private flushAll() {
294
+ this.flushInternal(this.idAllocationBatch);
262
295
  this.flushInternal(this.attachFlowBatch);
263
296
  this.flushInternal(this.blobAttachBatch, true /* disableGroupedBatching */);
264
297
  this.flushInternal(this.mainBatch);
@@ -270,7 +303,10 @@ export class Outbox {
270
303
  }
271
304
 
272
305
  const rawBatch = batchManager.popBatch();
273
- if (rawBatch.hasReentrantOps === true && this.params.config.enableGroupedBatching) {
306
+ if (
307
+ rawBatch.hasReentrantOps === true &&
308
+ this.params.groupingManager.shouldGroup(rawBatch)
309
+ ) {
274
310
  assert(!this.rebasing, 0x6fa /* A rebased batch should never have reentrant ops */);
275
311
  // If a batch contains reentrant ops (ops created as a result from processing another op)
276
312
  // it needs to be rebased so that we can ensure consistent reference sequence numbers
@@ -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.1";
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,