@fluidframework/container-runtime 0.58.2002 → 0.58.3000-61081

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 (83) hide show
  1. package/dist/blobManager.d.ts +3 -2
  2. package/dist/blobManager.d.ts.map +1 -1
  3. package/dist/blobManager.js +13 -9
  4. package/dist/blobManager.js.map +1 -1
  5. package/dist/connectionTelemetry.d.ts.map +1 -1
  6. package/dist/connectionTelemetry.js +63 -23
  7. package/dist/connectionTelemetry.js.map +1 -1
  8. package/dist/containerRuntime.d.ts +12 -4
  9. package/dist/containerRuntime.d.ts.map +1 -1
  10. package/dist/containerRuntime.js +61 -15
  11. package/dist/containerRuntime.js.map +1 -1
  12. package/dist/opTelemetry.d.ts +22 -0
  13. package/dist/opTelemetry.d.ts.map +1 -0
  14. package/dist/opTelemetry.js +59 -0
  15. package/dist/opTelemetry.js.map +1 -0
  16. package/dist/orderedClientElection.d.ts +57 -6
  17. package/dist/orderedClientElection.d.ts.map +1 -1
  18. package/dist/orderedClientElection.js +140 -25
  19. package/dist/orderedClientElection.js.map +1 -1
  20. package/dist/packageVersion.d.ts +1 -1
  21. package/dist/packageVersion.d.ts.map +1 -1
  22. package/dist/packageVersion.js +1 -1
  23. package/dist/packageVersion.js.map +1 -1
  24. package/dist/summarizerClientElection.d.ts +2 -0
  25. package/dist/summarizerClientElection.d.ts.map +1 -1
  26. package/dist/summarizerClientElection.js +7 -2
  27. package/dist/summarizerClientElection.js.map +1 -1
  28. package/dist/summarizerTypes.d.ts +9 -0
  29. package/dist/summarizerTypes.d.ts.map +1 -1
  30. package/dist/summarizerTypes.js.map +1 -1
  31. package/dist/summaryGenerator.d.ts.map +1 -1
  32. package/dist/summaryGenerator.js +1 -1
  33. package/dist/summaryGenerator.js.map +1 -1
  34. package/dist/summaryManager.d.ts.map +1 -1
  35. package/dist/summaryManager.js +14 -3
  36. package/dist/summaryManager.js.map +1 -1
  37. package/lib/blobManager.d.ts +3 -2
  38. package/lib/blobManager.d.ts.map +1 -1
  39. package/lib/blobManager.js +14 -10
  40. package/lib/blobManager.js.map +1 -1
  41. package/lib/connectionTelemetry.d.ts.map +1 -1
  42. package/lib/connectionTelemetry.js +63 -23
  43. package/lib/connectionTelemetry.js.map +1 -1
  44. package/lib/containerRuntime.d.ts +12 -4
  45. package/lib/containerRuntime.d.ts.map +1 -1
  46. package/lib/containerRuntime.js +62 -16
  47. package/lib/containerRuntime.js.map +1 -1
  48. package/lib/opTelemetry.d.ts +22 -0
  49. package/lib/opTelemetry.d.ts.map +1 -0
  50. package/lib/opTelemetry.js +55 -0
  51. package/lib/opTelemetry.js.map +1 -0
  52. package/lib/orderedClientElection.d.ts +57 -6
  53. package/lib/orderedClientElection.d.ts.map +1 -1
  54. package/lib/orderedClientElection.js +140 -25
  55. package/lib/orderedClientElection.js.map +1 -1
  56. package/lib/packageVersion.d.ts +1 -1
  57. package/lib/packageVersion.d.ts.map +1 -1
  58. package/lib/packageVersion.js +1 -1
  59. package/lib/packageVersion.js.map +1 -1
  60. package/lib/summarizerClientElection.d.ts +2 -0
  61. package/lib/summarizerClientElection.d.ts.map +1 -1
  62. package/lib/summarizerClientElection.js +7 -2
  63. package/lib/summarizerClientElection.js.map +1 -1
  64. package/lib/summarizerTypes.d.ts +9 -0
  65. package/lib/summarizerTypes.d.ts.map +1 -1
  66. package/lib/summarizerTypes.js.map +1 -1
  67. package/lib/summaryGenerator.d.ts.map +1 -1
  68. package/lib/summaryGenerator.js +1 -1
  69. package/lib/summaryGenerator.js.map +1 -1
  70. package/lib/summaryManager.d.ts.map +1 -1
  71. package/lib/summaryManager.js +14 -3
  72. package/lib/summaryManager.js.map +1 -1
  73. package/package.json +47 -15
  74. package/src/blobManager.ts +19 -11
  75. package/src/connectionTelemetry.ts +110 -19
  76. package/src/containerRuntime.ts +85 -19
  77. package/src/opTelemetry.ts +71 -0
  78. package/src/orderedClientElection.ts +154 -25
  79. package/src/packageVersion.ts +1 -1
  80. package/src/summarizerClientElection.ts +7 -2
  81. package/src/summarizerTypes.ts +9 -0
  82. package/src/summaryGenerator.ts +9 -1
  83. package/src/summaryManager.ts +15 -4
@@ -6,7 +6,7 @@ import { readAndParse, BlobAggregationStorage } from "@fluidframework/driver-uti
6
6
  import { DataCorruptionError, GenericError, UsageError, extractSafePropertiesFromMessage, } from "@fluidframework/container-utils";
7
7
  import { MessageType, SummaryType, } from "@fluidframework/protocol-definitions";
8
8
  import { FlushMode, channelsTreeName, } from "@fluidframework/runtime-definitions";
9
- import { addBlobToSummary, addTreeToSummary, convertToSummaryTree, createRootSummarizerNodeWithGC, RequestParser, create404Response, exceptionToResponse, requestFluidObject, responseToException, seqFromTree, } from "@fluidframework/runtime-utils";
9
+ import { addBlobToSummary, addTreeToSummary, createRootSummarizerNodeWithGC, RequestParser, create404Response, exceptionToResponse, requestFluidObject, responseToException, seqFromTree, calculateStats, } from "@fluidframework/runtime-utils";
10
10
  import { v4 as uuid } from "uuid";
11
11
  import { ContainerFluidHandleContext } from "./containerHandleContext";
12
12
  import { FluidDataStoreRegistry } from "./dataStoreRegistry";
@@ -27,6 +27,7 @@ import { RunWhileConnectedCoordinator } from "./runWhileConnectedCoordinator";
27
27
  import { GarbageCollector, gcTreeKey, } from "./garbageCollection";
28
28
  import { channelToDataStore, isDataStoreAliasMessage, } from "./dataStore";
29
29
  import { BindBatchTracker } from "./batchTracker";
30
+ import { OpTracker } from "./opTelemetry";
30
31
  export var ContainerMessageType;
31
32
  (function (ContainerMessageType) {
32
33
  // An op to be delivered to store
@@ -79,6 +80,11 @@ const maxOpSizeInBytesKey = "Fluid.ContainerRuntime.MaxOpSizeInBytes";
79
80
  // in order to account for some extra overhead from serialization
80
81
  // to not reach the 1MB limits in socket.io and Kafka.
81
82
  const defaultMaxOpSizeInBytes = 768000;
83
+ // By default, the size of the contents for the incoming ops is tracked.
84
+ // However, in certain situations, this may incur a performance hit.
85
+ // The feature-gate below can be used to disable this feature.
86
+ const disableOpTrackingKey = "Fluid.ContainerRuntime.DisableOpTracking";
87
+ const defaultFlushMode = FlushMode.TurnBased;
82
88
  export var RuntimeMessage;
83
89
  (function (RuntimeMessage) {
84
90
  RuntimeMessage["FluidDataStoreOp"] = "component";
@@ -127,6 +133,7 @@ class ScheduleManagerCore {
127
133
  this.logger = logger;
128
134
  this.localPaused = false;
129
135
  this.timePaused = 0;
136
+ this.batchCount = 0;
130
137
  // Listen for delta manager sends and add batch metadata to messages
131
138
  this.deltaManager.on("prepareSend", (messages) => {
132
139
  if (messages.length === 0) {
@@ -193,13 +200,26 @@ class ScheduleManagerCore {
193
200
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
194
201
  this.deltaManager.inbound.pause();
195
202
  }
196
- resumeQueue(startBatch, endBatch) {
203
+ resumeQueue(startBatch, messageEndBatch) {
204
+ const endBatch = messageEndBatch.sequenceNumber;
205
+ const duration = performance.now() - this.timePaused;
206
+ this.batchCount++;
207
+ if (this.batchCount % 1000 === 1) {
208
+ this.logger.sendTelemetryEvent({
209
+ eventName: "BatchStats",
210
+ sequenceNumber: endBatch,
211
+ length: endBatch - startBatch + 1,
212
+ msnDistance: endBatch - messageEndBatch.minimumSequenceNumber,
213
+ duration,
214
+ batchCount: this.batchCount,
215
+ interrupted: this.localPaused,
216
+ });
217
+ }
197
218
  // Return early if no change in value
198
219
  if (!this.localPaused) {
199
220
  return;
200
221
  }
201
222
  this.localPaused = false;
202
- const duration = performance.now() - this.timePaused;
203
223
  // Random round number - we want to know when batch waiting paused op processing.
204
224
  if (duration > latencyThreshold) {
205
225
  this.logger.sendErrorEvent({
@@ -260,7 +280,7 @@ class ScheduleManagerCore {
260
280
  else if (batchMetadata === false) {
261
281
  assert(this.pauseSequenceNumber !== undefined, 0x2a0 /* "batch presence was validated above" */);
262
282
  // Batch is complete, we can process it!
263
- this.resumeQueue(this.pauseSequenceNumber, message.sequenceNumber);
283
+ this.resumeQueue(this.pauseSequenceNumber, message);
264
284
  this.pauseSequenceNumber = undefined;
265
285
  this.currentBatchClientId = undefined;
266
286
  }
@@ -363,7 +383,6 @@ export class ContainerRuntime extends TypedEventEmitter {
363
383
  this._storage = _storage;
364
384
  this.defaultMaxConsecutiveReconnects = 15;
365
385
  this._orderSequentiallyCalls = 0;
366
- this._flushMode = FlushMode.TurnBased;
367
386
  this.needsFlush = false;
368
387
  this.flushTrigger = false;
369
388
  this.paused = false;
@@ -446,6 +465,7 @@ export class ContainerRuntime extends TypedEventEmitter {
446
465
  ((_c = runtimeOptions.useDataStoreAliasing) !== null && _c !== void 0 ? _c : false);
447
466
  this._maxOpSizeInBytes = ((_d = this.mc.config.getNumber(maxOpSizeInBytesKey)) !== null && _d !== void 0 ? _d : defaultMaxOpSizeInBytes);
448
467
  this.maxConsecutiveReconnects = (_e = this.mc.config.getNumber(maxConsecutiveReconnectsKey)) !== null && _e !== void 0 ? _e : this.defaultMaxConsecutiveReconnects;
468
+ this._flushMode = runtimeOptions.flushMode;
449
469
  this.garbageCollector = GarbageCollector.create(this, this.runtimeOptions.gcOptions, (unusedRoutes) => this.dataStores.deleteUnusedRoutes(unusedRoutes), (nodePath) => this.dataStores.getNodePackagePath(nodePath),
450
470
  /**
451
471
  * Returns the timestamp of the last message seen by this client. This is used by garbage collector as
@@ -560,6 +580,7 @@ export class ContainerRuntime extends TypedEventEmitter {
560
580
  this.logger.sendTelemetryEvent(Object.assign(Object.assign(Object.assign({ eventName: "ContainerLoadStats" }, this.createContainerMetadata), this.dataStores.containerLoadStats), { summaryCount: this.summaryCount, summaryFormatVersion: metadata === null || metadata === void 0 ? void 0 : metadata.summaryFormatVersion, disableIsolatedChannels: metadata === null || metadata === void 0 ? void 0 : metadata.disableIsolatedChannels, gcVersion: metadata === null || metadata === void 0 ? void 0 : metadata.gcFeature }));
561
581
  ReportOpPerfTelemetry(this.context.clientId, this.deltaManager, this.logger);
562
582
  BindBatchTracker(this, this.logger);
583
+ this.opTracker = new OpTracker(this.deltaManager, this.mc.config.getBoolean(disableOpTrackingKey) === true);
563
584
  }
564
585
  get IContainerRuntime() { return this; }
565
586
  get IFluidRouter() { return this; }
@@ -582,7 +603,7 @@ export class ContainerRuntime extends TypedEventEmitter {
582
603
  runtimeVersion: pkgVersion,
583
604
  },
584
605
  });
585
- const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", useDataStoreAliasing = false, } = runtimeOptions;
606
+ const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", useDataStoreAliasing = false, flushMode = defaultFlushMode, } = runtimeOptions;
586
607
  // We pack at data store level only. If isolated channels are disabled,
587
608
  // then there are no .channel layers, we pack at level 1, otherwise we pack at level 2
588
609
  const packingLevel = summaryOptions.disableIsolatedChannels ? 1 : 2;
@@ -653,6 +674,7 @@ export class ContainerRuntime extends TypedEventEmitter {
653
674
  gcOptions,
654
675
  loadSequenceNumberVerification,
655
676
  useDataStoreAliasing,
677
+ flushMode,
656
678
  }, containerScope, logger, loadExisting, blobManagerSnapshot, requestHandler, storage);
657
679
  return runtime;
658
680
  }
@@ -871,12 +893,11 @@ export class ContainerRuntime extends TypedEventEmitter {
871
893
  const electedSummarizerContent = JSON.stringify((_a = this.summarizerClientElection) === null || _a === void 0 ? void 0 : _a.serialize());
872
894
  addBlobToSummary(summaryTree, electedSummarizerBlobName, electedSummarizerContent);
873
895
  }
874
- const snapshot = this.blobManager.snapshot();
896
+ const summary = this.blobManager.summarize();
875
897
  // Some storage (like git) doesn't allow empty tree, so we can omit it.
876
898
  // and the blob manager can handle the tree not existing when loading
877
- if (snapshot.entries.length !== 0) {
878
- const blobsTree = convertToSummaryTree(snapshot, false);
879
- addTreeToSummary(summaryTree, blobsTreeName, blobsTree);
899
+ if (Object.keys(summary.summary.tree).length > 0) {
900
+ addTreeToSummary(summaryTree, blobsTreeName, summary);
880
901
  }
881
902
  if (this.garbageCollector.writeDataAtRoot) {
882
903
  const gcSummary = this.garbageCollector.summarize();
@@ -1065,6 +1086,11 @@ export class ContainerRuntime extends TypedEventEmitter {
1065
1086
  if (mode === this._flushMode) {
1066
1087
  return;
1067
1088
  }
1089
+ this.mc.logger.sendTelemetryEvent({
1090
+ eventName: "FlushMode Updated",
1091
+ old: this._flushMode,
1092
+ new: mode,
1093
+ });
1068
1094
  // Flush any pending batches if switching to immediate
1069
1095
  if (mode === FlushMode.Immediate) {
1070
1096
  this.flush();
@@ -1192,6 +1218,10 @@ export class ContainerRuntime extends TypedEventEmitter {
1192
1218
  const fluidDataStore = await this.dataStores._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, isRoot, props).realize();
1193
1219
  if (isRoot) {
1194
1220
  fluidDataStore.bindToContext();
1221
+ this.logger.sendTelemetryEvent({
1222
+ eventName: "Root datastore with props",
1223
+ hasProps: props !== undefined,
1224
+ });
1195
1225
  }
1196
1226
  return channelToDataStore(fluidDataStore, id, this, this.dataStores, this.mc.logger);
1197
1227
  }
@@ -1315,9 +1345,9 @@ export class ContainerRuntime extends TypedEventEmitter {
1315
1345
  if (runGC) {
1316
1346
  gcStats = await this.collectGarbage({ logger: summaryLogger, runSweep, fullGC });
1317
1347
  }
1318
- const summarizeResult = await this.summarizerNode.summarize(fullTree, trackState);
1319
- assert(summarizeResult.summary.type === SummaryType.Tree, 0x12f /* "Container Runtime's summarize should always return a tree" */);
1320
- return Object.assign(Object.assign({}, summarizeResult), { gcStats });
1348
+ const { stats, summary } = await this.summarizerNode.summarize(fullTree, trackState);
1349
+ assert(summary.type === SummaryType.Tree, 0x12f /* "Container Runtime's summarize should always return a tree" */);
1350
+ return { stats, summary, gcStats };
1321
1351
  }
1322
1352
  /**
1323
1353
  * Implementation of IGarbageCollectionRuntime::updateStateBeforeGC.
@@ -1392,6 +1422,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1392
1422
  try {
1393
1423
  await this.deltaManager.inbound.pause();
1394
1424
  const summaryRefSeqNum = this.deltaManager.lastSequenceNumber;
1425
+ const minimumSequenceNumber = this.deltaManager.minimumSequenceNumber;
1395
1426
  const message = `Summary @${summaryRefSeqNum}:${this.deltaManager.minimumSequenceNumber}`;
1396
1427
  // We should be here is we haven't processed be here. If we are of if the last message's sequence number
1397
1428
  // doesn't match the last processed sequence number, log an error.
@@ -1431,7 +1462,12 @@ export class ContainerRuntime extends TypedEventEmitter {
1431
1462
  };
1432
1463
  let continueResult = checkContinue();
1433
1464
  if (!continueResult.continue) {
1434
- return { stage: "base", referenceSequenceNumber: summaryRefSeqNum, error: continueResult.error };
1465
+ return {
1466
+ stage: "base",
1467
+ referenceSequenceNumber: summaryRefSeqNum,
1468
+ minimumSequenceNumber,
1469
+ error: continueResult.error,
1470
+ };
1435
1471
  }
1436
1472
  // increment summary count
1437
1473
  if (this.summaryCount !== undefined) {
@@ -1454,7 +1490,12 @@ export class ContainerRuntime extends TypedEventEmitter {
1454
1490
  });
1455
1491
  }
1456
1492
  catch (error) {
1457
- return { stage: "base", referenceSequenceNumber: summaryRefSeqNum, error };
1493
+ return {
1494
+ stage: "base",
1495
+ referenceSequenceNumber: summaryRefSeqNum,
1496
+ minimumSequenceNumber,
1497
+ error,
1498
+ };
1458
1499
  }
1459
1500
  const { summary: summaryTree, stats: partialStats } = summarizeResult;
1460
1501
  // Now that we have generated the summary, update the message at last summary to the last message processed.
@@ -1465,9 +1506,13 @@ export class ContainerRuntime extends TypedEventEmitter {
1465
1506
  const dataStoreTree = this.disableIsolatedChannels ? summaryTree : summaryTree.tree[channelsTreeName];
1466
1507
  assert(dataStoreTree.type === SummaryType.Tree, 0x1fc /* "summary is not a tree" */);
1467
1508
  const handleCount = Object.values(dataStoreTree.tree).filter((value) => value.type === SummaryType.Handle).length;
1468
- const summaryStats = Object.assign({ dataStoreCount: this.dataStores.size, summarizedDataStoreCount: this.dataStores.size - handleCount, gcStateUpdatedDataStoreCount: (_b = summarizeResult.gcStats) === null || _b === void 0 ? void 0 : _b.updatedDataStoreCount }, partialStats);
1509
+ const gcSummaryTreeStats = summaryTree.tree[gcTreeKey]
1510
+ ? calculateStats(summaryTree.tree[gcTreeKey])
1511
+ : undefined;
1512
+ const summaryStats = Object.assign({ dataStoreCount: this.dataStores.size, summarizedDataStoreCount: this.dataStores.size - handleCount, gcStateUpdatedDataStoreCount: (_b = summarizeResult.gcStats) === null || _b === void 0 ? void 0 : _b.updatedDataStoreCount, gcBlobNodeCount: gcSummaryTreeStats === null || gcSummaryTreeStats === void 0 ? void 0 : gcSummaryTreeStats.blobNodeCount, gcTotalBlobsSize: gcSummaryTreeStats === null || gcSummaryTreeStats === void 0 ? void 0 : gcSummaryTreeStats.totalBlobSize, opsSizesSinceLastSummary: this.opTracker.opsSizeAccumulator, nonSystemOpsSinceLastSummary: this.opTracker.nonSystemOpCount }, partialStats);
1469
1513
  const generateSummaryData = {
1470
1514
  referenceSequenceNumber: summaryRefSeqNum,
1515
+ minimumSequenceNumber,
1471
1516
  summaryTree,
1472
1517
  summaryStats,
1473
1518
  generateDuration: trace.trace().duration,
@@ -1518,6 +1563,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1518
1563
  }
1519
1564
  const submitData = Object.assign(Object.assign({ stage: "submit" }, uploadData), { clientSequenceNumber, submitOpDuration: trace.trace().duration });
1520
1565
  this.summarizerNode.completeSummary(handle);
1566
+ this.opTracker.reset();
1521
1567
  return submitData;
1522
1568
  }
1523
1569
  finally {