@fluidframework/container-runtime 0.58.3000-61081 → 0.59.2000-61729

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 (93) hide show
  1. package/dist/blobManager.d.ts +13 -1
  2. package/dist/blobManager.d.ts.map +1 -1
  3. package/dist/blobManager.js +52 -0
  4. package/dist/blobManager.js.map +1 -1
  5. package/dist/connectionTelemetry.js +8 -8
  6. package/dist/connectionTelemetry.js.map +1 -1
  7. package/dist/containerRuntime.d.ts +27 -3
  8. package/dist/containerRuntime.d.ts.map +1 -1
  9. package/dist/containerRuntime.js +100 -14
  10. package/dist/containerRuntime.js.map +1 -1
  11. package/dist/dataStore.js +8 -1
  12. package/dist/dataStore.js.map +1 -1
  13. package/dist/dataStoreContext.d.ts +9 -3
  14. package/dist/dataStoreContext.d.ts.map +1 -1
  15. package/dist/dataStoreContext.js +22 -6
  16. package/dist/dataStoreContext.js.map +1 -1
  17. package/dist/dataStores.d.ts +13 -5
  18. package/dist/dataStores.d.ts.map +1 -1
  19. package/dist/dataStores.js +39 -18
  20. package/dist/dataStores.js.map +1 -1
  21. package/dist/deltaScheduler.d.ts +4 -5
  22. package/dist/deltaScheduler.d.ts.map +1 -1
  23. package/dist/deltaScheduler.js +54 -35
  24. package/dist/deltaScheduler.js.map +1 -1
  25. package/dist/garbageCollection.d.ts +31 -27
  26. package/dist/garbageCollection.d.ts.map +1 -1
  27. package/dist/garbageCollection.js +76 -75
  28. package/dist/garbageCollection.js.map +1 -1
  29. package/dist/orderedClientElection.d.ts.map +1 -1
  30. package/dist/orderedClientElection.js +2 -2
  31. package/dist/orderedClientElection.js.map +1 -1
  32. package/dist/packageVersion.d.ts +1 -1
  33. package/dist/packageVersion.js +1 -1
  34. package/dist/packageVersion.js.map +1 -1
  35. package/dist/summarizerClientElection.d.ts.map +1 -1
  36. package/dist/summarizerClientElection.js +8 -0
  37. package/dist/summarizerClientElection.js.map +1 -1
  38. package/dist/summaryGenerator.d.ts.map +1 -1
  39. package/dist/summaryGenerator.js +2 -3
  40. package/dist/summaryGenerator.js.map +1 -1
  41. package/lib/blobManager.d.ts +13 -1
  42. package/lib/blobManager.d.ts.map +1 -1
  43. package/lib/blobManager.js +52 -0
  44. package/lib/blobManager.js.map +1 -1
  45. package/lib/connectionTelemetry.js +8 -8
  46. package/lib/connectionTelemetry.js.map +1 -1
  47. package/lib/containerRuntime.d.ts +27 -3
  48. package/lib/containerRuntime.d.ts.map +1 -1
  49. package/lib/containerRuntime.js +101 -15
  50. package/lib/containerRuntime.js.map +1 -1
  51. package/lib/dataStore.js +8 -1
  52. package/lib/dataStore.js.map +1 -1
  53. package/lib/dataStoreContext.d.ts +9 -3
  54. package/lib/dataStoreContext.d.ts.map +1 -1
  55. package/lib/dataStoreContext.js +22 -6
  56. package/lib/dataStoreContext.js.map +1 -1
  57. package/lib/dataStores.d.ts +13 -5
  58. package/lib/dataStores.d.ts.map +1 -1
  59. package/lib/dataStores.js +39 -18
  60. package/lib/dataStores.js.map +1 -1
  61. package/lib/deltaScheduler.d.ts +4 -5
  62. package/lib/deltaScheduler.d.ts.map +1 -1
  63. package/lib/deltaScheduler.js +54 -35
  64. package/lib/deltaScheduler.js.map +1 -1
  65. package/lib/garbageCollection.d.ts +31 -27
  66. package/lib/garbageCollection.d.ts.map +1 -1
  67. package/lib/garbageCollection.js +75 -74
  68. package/lib/garbageCollection.js.map +1 -1
  69. package/lib/orderedClientElection.d.ts.map +1 -1
  70. package/lib/orderedClientElection.js +2 -2
  71. package/lib/orderedClientElection.js.map +1 -1
  72. package/lib/packageVersion.d.ts +1 -1
  73. package/lib/packageVersion.js +1 -1
  74. package/lib/packageVersion.js.map +1 -1
  75. package/lib/summarizerClientElection.d.ts.map +1 -1
  76. package/lib/summarizerClientElection.js +8 -0
  77. package/lib/summarizerClientElection.js.map +1 -1
  78. package/lib/summaryGenerator.d.ts.map +1 -1
  79. package/lib/summaryGenerator.js +2 -3
  80. package/lib/summaryGenerator.js.map +1 -1
  81. package/package.json +33 -21
  82. package/src/blobManager.ts +60 -1
  83. package/src/connectionTelemetry.ts +9 -9
  84. package/src/containerRuntime.ts +106 -17
  85. package/src/dataStore.ts +7 -1
  86. package/src/dataStoreContext.ts +22 -7
  87. package/src/dataStores.ts +40 -19
  88. package/src/deltaScheduler.ts +65 -39
  89. package/src/garbageCollection.ts +92 -78
  90. package/src/orderedClientElection.ts +2 -1
  91. package/src/packageVersion.ts +1 -1
  92. package/src/summarizerClientElection.ts +8 -0
  93. package/src/summaryGenerator.ts +1 -7
@@ -56,6 +56,7 @@ export class SummarizerClientElection extends TypedEventEmitter {
56
56
  this.lastReportedSeq = sequenceNumber;
57
57
  }
58
58
  if (this.electionEnabled) {
59
+ const previousParentId = this.electedParentId;
59
60
  this.clientElection.incrementElectedClient(sequenceNumber);
60
61
  // Verify that state incremented as expected. This should be reliable,
61
62
  // since all of OrderedClientElection is synchronous.
@@ -68,6 +69,13 @@ export class SummarizerClientElection extends TypedEventEmitter {
68
69
  lastSummaryAckSeqForClient: this.lastSummaryAckSeqForClient,
69
70
  // Expected to be same as op sequenceNumber
70
71
  electionSequenceNumber,
72
+ sequenceNumber,
73
+ previousClientId: electedClientId,
74
+ previousParentId,
75
+ electedParentId: this.electedParentId,
76
+ electedClientId: this.electedClientId,
77
+ opsSinceLastReport,
78
+ maxOpsSinceLastSummary,
71
79
  });
72
80
  }
73
81
  }
@@ -1 +1 @@
1
- {"version":3,"file":"summarizerClientElection.js","sourceRoot":"","sources":["../src/summarizerClientElection.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAkB,WAAW,EAAE,MAAM,sCAAsC,CAAC;AAInF,MAAM,CAAC,MAAM,oBAAoB,GAAG,YAAY,CAAC;AAWjD;;;;GAIG;AACH,MAAM,OAAO,wBACT,SAAQ,iBAAkD;IAuB1D,YACqB,MAAwB,EACxB,iBAA6D,EAC9D,cAAsC,EACrC,sBAA8B,EAC9B,eAAwB;QAEzC,KAAK,EAAE,CAAC;QANS,WAAM,GAAN,MAAM,CAAkB;QACxB,sBAAiB,GAAjB,iBAAiB,CAA4C;QAC9D,mBAAc,GAAd,cAAc,CAAwB;QACrC,2BAAsB,GAAtB,sBAAsB,CAAQ;QAC9B,oBAAe,GAAf,eAAe,CAAS;QAnB7C;;;;WAIG;QACK,oBAAe,GAAG,CAAC,CAAC;QAiBxB,6FAA6F;QAC7F,2CAA2C;QAC3C,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,EAAE,cAAc,EAAE,EAAE,EAAE;;YACxD,MAAM,eAAe,GAAG,IAAI,CAAC,eAAe,CAAC;YAC7C,IAAI,eAAe,KAAK,SAAS,EAAE;gBAC/B,2EAA2E;gBAC3E,uEAAuE;gBACvE,2EAA2E;gBAC3E,yDAAyD;gBACzD,IAAI,IAAI,CAAC,cAAc,CAAC,aAAa,GAAG,CAAC,EAAE;oBACvC,IAAI,CAAC,cAAc,CAAC,kBAAkB,CAAC,cAAc,CAAC,CAAC;iBAC1D;gBACD,OAAO;aACV;YACD,IAAI,sBAAsB,GAAG,IAAI,CAAC,cAAc,CAAC,sBAAsB,CAAC;YACxE,MAAM,iBAAiB,GAAG,cAAc,GAAG,OAAC,IAAI,CAAC,0BAA0B,mCAAI,sBAAsB,CAAC,CAAC;YACvG,IAAI,iBAAiB,GAAG,IAAI,CAAC,sBAAsB,EAAE;gBACjD,yCAAyC;gBACzC,MAAM,kBAAkB,GAAG,cAAc,GAAG,IAAI,CAAC,eAAe,CAAC;gBACjE,IAAI,kBAAkB,GAAG,IAAI,CAAC,sBAAsB,EAAE;oBAClD,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC;wBACvB,SAAS,EAAE,6BAA6B;wBACxC,eAAe;wBACf,0BAA0B,EAAE,IAAI,CAAC,0BAA0B;wBAC3D,sBAAsB;wBACtB,mBAAmB,QAAE,IAAI,CAAC,cAAc,CAAC,qBAAqB,EAAE,0CAAE,QAAQ;wBAC1E,eAAe,EAAE,IAAI,CAAC,eAAe;qBACxC,CAAC,CAAC;oBACH,IAAI,CAAC,eAAe,GAAG,cAAc,CAAC;iBACzC;gBAED,IAAI,IAAI,CAAC,eAAe,EAAE;oBACtB,IAAI,CAAC,cAAc,CAAC,sBAAsB,CAAC,cAAc,CAAC,CAAC;oBAE3D,sEAAsE;oBACtE,qDAAqD;oBACrD,sBAAsB,GAAG,IAAI,CAAC,cAAc,CAAC,sBAAsB,CAAC;oBACpE,IAAI,cAAc,GAAG,OAAC,IAAI,CAAC,0BAA0B,mCAAI,sBAAsB,CAAC,EAAE;wBAC9E,IAAI,kBAAkB,GAAG,IAAI,CAAC,sBAAsB,EAAE;4BAClD,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC;gCACvB,SAAS,EAAE,kCAAkC;gCAC7C,2BAA2B;gCAC3B,0BAA0B,EAAE,IAAI,CAAC,0BAA0B;gCAC3D,2CAA2C;gCAC3C,sBAAsB;6BACzB,CAAC,CAAC;yBACN;qBACJ;iBACJ;aACJ;QACL,CAAC,CAAC,CAAC;QAEH,yDAAyD;QACzD,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC,WAAW,CAAC,UAAU,EAAE,CAAC,EAAE,EAAE,EAAE;YACrD,IAAI,CAAC,0BAA0B,GAAG,EAAE,CAAC,cAAc,CAAC;QACxD,CAAC,CAAC,CAAC;QAEH,4EAA4E;QAC5E,iCAAiC;QACjC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,cAAc,EAAE,EAAE;YAC1D,IAAI,CAAC,0BAA0B,GAAG,SAAS,CAAC;YAC5C,IAAI,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,cAAc,CAAC,aAAa,GAAG,CAAC,EAAE;gBAC/D,iEAAiE;gBACjE,kEAAkE;gBAClE,mEAAmE;gBACnE,4BAA4B;gBAC5B,IAAI,CAAC,cAAc,CAAC,kBAAkB,CAAC,cAAc,CAAC,CAAC;aAC1D;YACD,yDAAyD;YACzD,IAAI,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;QAC1C,CAAC,CAAC,CAAC;IACP,CAAC;IAtFD,IAAW,eAAe;;QACtB,aAAO,IAAI,CAAC,cAAc,CAAC,aAAa,0CAAE,QAAQ,CAAC;IACvD,CAAC;IACD,IAAW,eAAe;;QACtB,aAAO,IAAI,CAAC,cAAc,CAAC,aAAa,0CAAE,QAAQ,CAAC;IACvD,CAAC;IAmFM,SAAS;;QACZ,MAAM,EAAE,eAAe,EAAE,eAAe,EAAE,sBAAsB,EAAE,GAAG,IAAI,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC;QACrG,OAAO;YACH,eAAe;YACf,eAAe;YACf,sBAAsB,QAAE,IAAI,CAAC,0BAA0B,mCAAI,sBAAsB;SACpF,CAAC;IACN,CAAC;IAEM,MAAM,CAAC,gBAAgB,CAAC,MAAsB;QACjD,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;QACtC,IAAI,OAAO,KAAK,SAAS,EAAE;YACvB,+BAA+B;YAC/B,OAAO,IAAI,CAAC;SACf;QACD,OAAO,wBAAwB,CAAC,2BAA2B,CAAC,OAAO,CAAC,CAAC;IACzE,CAAC;;AAEsB,oDAA2B,GAAG,CAAC,OAAuB,EAAW,EAAE,CACtF,OAAO,CAAC,YAAY,CAAC,WAAW,IAAI,OAAO,CAAC,IAAI,KAAK,oBAAoB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { IEvent, IEventProvider, ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { TypedEventEmitter } from \"@fluidframework/common-utils\";\nimport { IClientDetails, MessageType } from \"@fluidframework/protocol-definitions\";\nimport { IOrderedClientElection, ISerializedElection, ITrackedClient } from \"./orderedClientElection\";\nimport { ISummaryCollectionOpEvents } from \"./summaryCollection\";\n\nexport const summarizerClientType = \"summarizer\";\n\nexport interface ISummarizerClientElectionEvents extends IEvent {\n (event: \"electedSummarizerChanged\", handler: () => void): void;\n}\n\nexport interface ISummarizerClientElection extends IEventProvider<ISummarizerClientElectionEvents> {\n readonly electedClientId: string | undefined;\n readonly electedParentId: string | undefined;\n}\n\n/**\n * This class encapsulates logic around tracking the elected summarizer client.\n * It will handle updating the elected client when a summary ack hasn't been seen\n * for some configured number of ops.\n */\nexport class SummarizerClientElection\n extends TypedEventEmitter<ISummarizerClientElectionEvents>\n implements ISummarizerClientElection {\n /**\n * Used to calculate number of ops since last summary ack for the current elected client.\n * This will be undefined if there is no elected summarizer, or no summary ack has been\n * observed since this client was elected.\n * When a summary ack comes in, this will be set to the sequence number of the summary ack.\n */\n private lastSummaryAckSeqForClient: number | undefined;\n /**\n * Used to prevent excess logging by recording the sequence number that we last reported at,\n * and making sure we don't report another event to telemetry. If things work as intended,\n * this is not needed, otherwise it could report an event on every op in worst case scenario.\n */\n private lastReportedSeq = 0;\n\n public get electedClientId() {\n return this.clientElection.electedClient?.clientId;\n }\n public get electedParentId() {\n return this.clientElection.electedParent?.clientId;\n }\n\n constructor(\n private readonly logger: ITelemetryLogger,\n private readonly summaryCollection: IEventProvider<ISummaryCollectionOpEvents>,\n public readonly clientElection: IOrderedClientElection,\n private readonly maxOpsSinceLastSummary: number,\n private readonly electionEnabled: boolean,\n ) {\n super();\n // On every inbound op, if enough ops pass without seeing a summary ack (per elected client),\n // elect a new client and log to telemetry.\n this.summaryCollection.on(\"default\", ({ sequenceNumber }) => {\n const electedClientId = this.electedClientId;\n if (electedClientId === undefined) {\n // Reset election if no elected client, but eligible clients are connected.\n // This should be uncommon, but is possible if the initial state of the\n // ordered client election contains an undefined client id or one not found\n // in the quorum (the latter would already log an error).\n if (this.clientElection.eligibleCount > 0) {\n this.clientElection.resetElectedClient(sequenceNumber);\n }\n return;\n }\n let electionSequenceNumber = this.clientElection.electionSequenceNumber;\n const opsWithoutSummary = sequenceNumber - (this.lastSummaryAckSeqForClient ?? electionSequenceNumber);\n if (opsWithoutSummary > this.maxOpsSinceLastSummary) {\n // Log and elect a new summarizer client.\n const opsSinceLastReport = sequenceNumber - this.lastReportedSeq;\n if (opsSinceLastReport > this.maxOpsSinceLastSummary) {\n this.logger.sendErrorEvent({\n eventName: \"ElectedClientNotSummarizing\",\n electedClientId,\n lastSummaryAckSeqForClient: this.lastSummaryAckSeqForClient,\n electionSequenceNumber,\n nextElectedClientId: this.clientElection.peekNextElectedClient()?.clientId,\n electionEnabled: this.electionEnabled,\n });\n this.lastReportedSeq = sequenceNumber;\n }\n\n if (this.electionEnabled) {\n this.clientElection.incrementElectedClient(sequenceNumber);\n\n // Verify that state incremented as expected. This should be reliable,\n // since all of OrderedClientElection is synchronous.\n electionSequenceNumber = this.clientElection.electionSequenceNumber;\n if (sequenceNumber > (this.lastSummaryAckSeqForClient ?? electionSequenceNumber)) {\n if (opsSinceLastReport > this.maxOpsSinceLastSummary) {\n this.logger.sendErrorEvent({\n eventName: \"UnexpectedElectionSequenceNumber\",\n // Expected to be undefined\n lastSummaryAckSeqForClient: this.lastSummaryAckSeqForClient,\n // Expected to be same as op sequenceNumber\n electionSequenceNumber,\n });\n }\n }\n }\n }\n });\n\n // When a summary ack comes in, reset our op seq counter.\n this.summaryCollection.on(MessageType.SummaryAck, (op) => {\n this.lastSummaryAckSeqForClient = op.sequenceNumber;\n });\n\n // Use oldest client election for unanimously and deterministically deciding\n // which client should summarize.\n this.clientElection.on(\"election\", (client, sequenceNumber) => {\n this.lastSummaryAckSeqForClient = undefined;\n if (client === undefined && this.clientElection.eligibleCount > 0) {\n // If no client is valid for election, reset to the oldest again.\n // Also make extra sure not to get stuck in an infinite loop here:\n // If there are no eligible clients, just wait until a client joins\n // and will be auto-elected.\n this.clientElection.resetElectedClient(sequenceNumber);\n }\n // Election can trigger a change in SummaryManager state.\n this.emit(\"electedSummarizerChanged\");\n });\n }\n\n public serialize(): ISerializedElection {\n const { electedClientId, electedParentId, electionSequenceNumber } = this.clientElection.serialize();\n return {\n electedClientId,\n electedParentId,\n electionSequenceNumber: this.lastSummaryAckSeqForClient ?? electionSequenceNumber,\n };\n }\n\n public static isClientEligible(client: ITrackedClient): boolean {\n const details = client.client.details;\n if (details === undefined) {\n // Very old clients back-compat\n return true;\n }\n return SummarizerClientElection.clientDetailsPermitElection(details);\n }\n\n public static readonly clientDetailsPermitElection = (details: IClientDetails): boolean =>\n details.capabilities.interactive || details.type === summarizerClientType;\n}\n"]}
1
+ {"version":3,"file":"summarizerClientElection.js","sourceRoot":"","sources":["../src/summarizerClientElection.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { IEvent, IEventProvider, ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { TypedEventEmitter } from \"@fluidframework/common-utils\";\nimport { IClientDetails, MessageType } from \"@fluidframework/protocol-definitions\";\nimport { IOrderedClientElection, ISerializedElection, ITrackedClient } from \"./orderedClientElection\";\nimport { ISummaryCollectionOpEvents } from \"./summaryCollection\";\n\nexport const summarizerClientType = \"summarizer\";\n\nexport interface ISummarizerClientElectionEvents extends IEvent {\n (event: \"electedSummarizerChanged\", handler: () => void): void;\n}\n\nexport interface ISummarizerClientElection extends IEventProvider<ISummarizerClientElectionEvents> {\n readonly electedClientId: string | undefined;\n readonly electedParentId: string | undefined;\n}\n\n/**\n * This class encapsulates logic around tracking the elected summarizer client.\n * It will handle updating the elected client when a summary ack hasn't been seen\n * for some configured number of ops.\n */\nexport class SummarizerClientElection\n extends TypedEventEmitter<ISummarizerClientElectionEvents>\n implements ISummarizerClientElection {\n /**\n * Used to calculate number of ops since last summary ack for the current elected client.\n * This will be undefined if there is no elected summarizer, or no summary ack has been\n * observed since this client was elected.\n * When a summary ack comes in, this will be set to the sequence number of the summary ack.\n */\n private lastSummaryAckSeqForClient: number | undefined;\n /**\n * Used to prevent excess logging by recording the sequence number that we last reported at,\n * and making sure we don't report another event to telemetry. If things work as intended,\n * this is not needed, otherwise it could report an event on every op in worst case scenario.\n */\n private lastReportedSeq = 0;\n\n public get electedClientId() {\n return this.clientElection.electedClient?.clientId;\n }\n public get electedParentId() {\n return this.clientElection.electedParent?.clientId;\n }\n\n constructor(\n private readonly logger: ITelemetryLogger,\n private readonly summaryCollection: IEventProvider<ISummaryCollectionOpEvents>,\n public readonly clientElection: IOrderedClientElection,\n private readonly maxOpsSinceLastSummary: number,\n private readonly electionEnabled: boolean,\n ) {\n super();\n // On every inbound op, if enough ops pass without seeing a summary ack (per elected client),\n // elect a new client and log to telemetry.\n this.summaryCollection.on(\"default\", ({ sequenceNumber }) => {\n const electedClientId = this.electedClientId;\n if (electedClientId === undefined) {\n // Reset election if no elected client, but eligible clients are connected.\n // This should be uncommon, but is possible if the initial state of the\n // ordered client election contains an undefined client id or one not found\n // in the quorum (the latter would already log an error).\n if (this.clientElection.eligibleCount > 0) {\n this.clientElection.resetElectedClient(sequenceNumber);\n }\n return;\n }\n let electionSequenceNumber = this.clientElection.electionSequenceNumber;\n const opsWithoutSummary = sequenceNumber - (this.lastSummaryAckSeqForClient ?? electionSequenceNumber);\n if (opsWithoutSummary > this.maxOpsSinceLastSummary) {\n // Log and elect a new summarizer client.\n const opsSinceLastReport = sequenceNumber - this.lastReportedSeq;\n if (opsSinceLastReport > this.maxOpsSinceLastSummary) {\n this.logger.sendErrorEvent({\n eventName: \"ElectedClientNotSummarizing\",\n electedClientId,\n lastSummaryAckSeqForClient: this.lastSummaryAckSeqForClient,\n electionSequenceNumber,\n nextElectedClientId: this.clientElection.peekNextElectedClient()?.clientId,\n electionEnabled: this.electionEnabled,\n });\n this.lastReportedSeq = sequenceNumber;\n }\n\n if (this.electionEnabled) {\n const previousParentId = this.electedParentId;\n this.clientElection.incrementElectedClient(sequenceNumber);\n\n // Verify that state incremented as expected. This should be reliable,\n // since all of OrderedClientElection is synchronous.\n electionSequenceNumber = this.clientElection.electionSequenceNumber;\n if (sequenceNumber > (this.lastSummaryAckSeqForClient ?? electionSequenceNumber)) {\n if (opsSinceLastReport > this.maxOpsSinceLastSummary) {\n this.logger.sendErrorEvent({\n eventName: \"UnexpectedElectionSequenceNumber\",\n // Expected to be undefined\n lastSummaryAckSeqForClient: this.lastSummaryAckSeqForClient,\n // Expected to be same as op sequenceNumber\n electionSequenceNumber,\n sequenceNumber,\n previousClientId: electedClientId,\n previousParentId,\n electedParentId: this.electedParentId,\n electedClientId: this.electedClientId,\n opsSinceLastReport,\n maxOpsSinceLastSummary,\n });\n }\n }\n }\n }\n });\n\n // When a summary ack comes in, reset our op seq counter.\n this.summaryCollection.on(MessageType.SummaryAck, (op) => {\n this.lastSummaryAckSeqForClient = op.sequenceNumber;\n });\n\n // Use oldest client election for unanimously and deterministically deciding\n // which client should summarize.\n this.clientElection.on(\"election\", (client, sequenceNumber) => {\n this.lastSummaryAckSeqForClient = undefined;\n if (client === undefined && this.clientElection.eligibleCount > 0) {\n // If no client is valid for election, reset to the oldest again.\n // Also make extra sure not to get stuck in an infinite loop here:\n // If there are no eligible clients, just wait until a client joins\n // and will be auto-elected.\n this.clientElection.resetElectedClient(sequenceNumber);\n }\n // Election can trigger a change in SummaryManager state.\n this.emit(\"electedSummarizerChanged\");\n });\n }\n\n public serialize(): ISerializedElection {\n const { electedClientId, electedParentId, electionSequenceNumber } = this.clientElection.serialize();\n return {\n electedClientId,\n electedParentId,\n electionSequenceNumber: this.lastSummaryAckSeqForClient ?? electionSequenceNumber,\n };\n }\n\n public static isClientEligible(client: ITrackedClient): boolean {\n const details = client.client.details;\n if (details === undefined) {\n // Very old clients back-compat\n return true;\n }\n return SummarizerClientElection.clientDetailsPermitElection(details);\n }\n\n public static readonly clientDetailsPermitElection = (details: IClientDetails): boolean =>\n details.capabilities.interactive || details.type === summarizerClientType;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"summaryGenerator.d.ts","sourceRoot":"","sources":["../src/summaryGenerator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAwB,MAAM,oCAAoC,CAAC;AAC5F,OAAO,EAEH,QAAQ,EACR,aAAa,EACb,mBAAmB,EAEtB,MAAM,8BAA8B,CAAC;AAKtC,OAAO,EACH,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,uBAAuB,EACvB,iBAAiB,EACjB,uBAAuB,EACvB,qBAAqB,EACrB,mBAAmB,EACnB,mBAAmB,EACnB,yBAAyB,EACzB,6BAA6B,EAChC,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,oBAAY,eAAe,CAAC,CAAC,IACzB;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GAC5B;IAAE,MAAM,EAAE,mBAAmB,CAAC,aAAa,CAAC,CAAA;CAAE,GAC9C;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,CAAC;AAE5B,uEAAuE;AACvE,wBAAsB,SAAS,CAAC,CAAC,EAC7B,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,KAAK,EAAE,OAAO,CAAC,mBAAmB,CAAC,EACnC,iBAAiB,CAAC,EAAE,yBAAyB,GAC9C,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAS7B;AA+CD,oBAAY,eAAe;AACvB;;;;;GAKG;AACD,MAAM;AACR;;;;GAIG;GACD,SAAS;AACX;;;;;;GAMG;GACD,QAAQ;AACV;;;;;;GAMG;GACD,aAAa;AACf,4DAA4D;GAC1D,QAAQ,MAAM,EAAE;AAClB,yDAAyD;GACvD,YAAY,MAAM,EAAE;AACtB,uDAAuD;GACrD,WAAW,MAAM,EAAE,CAAC;AA6B1B,qBAAa,sBAAsB;IAC/B,SAAgB,gBAAgB,gEAA4D;IAC5F,SAAgB,oBAAoB,oEAAgE;IACpG,SAAgB,wBAAwB,uEACuC;IAExE,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,iBAAiB,CAAC,EAAE,kBAAkB,EAAE,iBAAiB,CAAC,EAAE,MAAM;IAUpG,KAAK,IAAI,iBAAiB;CAOpC;AAED;;GAEG;AACH,qBAAa,gBAAgB;IAGrB,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IACtC,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IACtC,OAAO,CAAC,QAAQ,CAAC,yBAAyB;IAC1C,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,MAAM;IAR3B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAQ;gBAElB,eAAe,EAAE,aAAa,EAC9B,aAAa,EAAE,uBAAuB,EACtC,qBAAqB,EAAE,CAAC,OAAO,EAAE,qBAAqB,KAAK,OAAO,CAAC,mBAAmB,CAAC,EACvF,qBAAqB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,EACrD,yBAAyB,EAAE,MAAM,IAAI,EACrC,cAAc,EAAE,IAAI,CAAC,qBAAqB,EAAE,cAAc,CAAC,EAC3D,MAAM,EAAE,gBAAgB;IAQ7C;;;;;;OAMG;IACI,SAAS,CACZ,cAAc,EAAE,6BAA6B,EAC7C,OAAO,EAAE,iBAAiB,EAC1B,iBAAiB,EAAE,yBAAyB,EAC5C,cAAc,yBAA+B,GAC9C,iBAAiB;YAWN,aAAa;IAoO3B,OAAO,CAAC,qBAAqB;IAatB,OAAO;CAGjB"}
1
+ {"version":3,"file":"summaryGenerator.d.ts","sourceRoot":"","sources":["../src/summaryGenerator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAwB,MAAM,oCAAoC,CAAC;AAC5F,OAAO,EAEH,QAAQ,EACR,aAAa,EACb,mBAAmB,EAEtB,MAAM,8BAA8B,CAAC;AAKtC,OAAO,EACH,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,uBAAuB,EACvB,iBAAiB,EACjB,uBAAuB,EACvB,qBAAqB,EACrB,mBAAmB,EACnB,mBAAmB,EACnB,yBAAyB,EACzB,6BAA6B,EAChC,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,oBAAY,eAAe,CAAC,CAAC,IACzB;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GAC5B;IAAE,MAAM,EAAE,mBAAmB,CAAC,aAAa,CAAC,CAAA;CAAE,GAC9C;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,CAAC;AAE5B,uEAAuE;AACvE,wBAAsB,SAAS,CAAC,CAAC,EAC7B,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,KAAK,EAAE,OAAO,CAAC,mBAAmB,CAAC,EACnC,iBAAiB,CAAC,EAAE,yBAAyB,GAC9C,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAS7B;AA+CD,oBAAY,eAAe;AACvB;;;;;GAKG;AACD,MAAM;AACR;;;;GAIG;GACD,SAAS;AACX;;;;;;GAMG;GACD,QAAQ;AACV;;;;;;GAMG;GACD,aAAa;AACf,4DAA4D;GAC1D,QAAQ,MAAM,EAAE;AAClB,yDAAyD;GACvD,YAAY,MAAM,EAAE;AACtB,uDAAuD;GACrD,WAAW,MAAM,EAAE,CAAC;AA6B1B,qBAAa,sBAAsB;IAC/B,SAAgB,gBAAgB,gEAA4D;IAC5F,SAAgB,oBAAoB,oEAAgE;IACpG,SAAgB,wBAAwB,uEACuC;IAExE,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,iBAAiB,CAAC,EAAE,kBAAkB,EAAE,iBAAiB,CAAC,EAAE,MAAM;IAUpG,KAAK,IAAI,iBAAiB;CAOpC;AAED;;GAEG;AACH,qBAAa,gBAAgB;IAGrB,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IACtC,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IACtC,OAAO,CAAC,QAAQ,CAAC,yBAAyB;IAC1C,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,MAAM;IAR3B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAQ;gBAElB,eAAe,EAAE,aAAa,EAC9B,aAAa,EAAE,uBAAuB,EACtC,qBAAqB,EAAE,CAAC,OAAO,EAAE,qBAAqB,KAAK,OAAO,CAAC,mBAAmB,CAAC,EACvF,qBAAqB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,EACrD,yBAAyB,EAAE,MAAM,IAAI,EACrC,cAAc,EAAE,IAAI,CAAC,qBAAqB,EAAE,cAAc,CAAC,EAC3D,MAAM,EAAE,gBAAgB;IAQ7C;;;;;;OAMG;IACI,SAAS,CACZ,cAAc,EAAE,6BAA6B,EAC7C,OAAO,EAAE,iBAAiB,EAC1B,iBAAiB,EAAE,yBAAyB,EAC5C,cAAc,yBAA+B,GAC9C,iBAAiB;YAWN,aAAa;IA8N3B,OAAO,CAAC,qBAAqB;IAatB,OAAO;CAGjB"}
@@ -129,7 +129,6 @@ export class SummaryGenerator {
129
129
  // Use record type to prevent unexpected value types
130
130
  let summaryData;
131
131
  try {
132
- const generateSummaryEvent = PerformanceEvent.start(logger, Object.assign({ eventName: "Summarize" }, summarizeTelemetryProps));
133
132
  summaryData = await this.submitSummaryCallback({
134
133
  fullTree,
135
134
  refreshLatestAck,
@@ -174,7 +173,7 @@ export class SummaryGenerator {
174
173
  }
175
174
  }
176
175
  // Log event here on summary success only, as Summarize_cancel duplicates failure logging.
177
- generateSummaryEvent.reportEvent("generate", Object.assign({}, summarizeTelemetryProps));
176
+ summarizeEvent.reportEvent("generate", Object.assign({}, summarizeTelemetryProps));
178
177
  resultsBuilder.summarySubmitted.resolve({ success: true, data: summaryData });
179
178
  }
180
179
  catch (error) {
@@ -226,7 +225,7 @@ export class SummaryGenerator {
226
225
  if (ackNackOp.type === MessageType.SummaryAck) {
227
226
  this.heuristicData.markLastAttemptAsSuccessful();
228
227
  this.successfulSummaryCallback();
229
- summarizeEvent.end(Object.assign(Object.assign({}, summarizeTelemetryProps), { handle: ackNackOp.contents.handle, message: "summaryAck" }));
228
+ summarizeEvent.end(Object.assign(Object.assign({}, summarizeTelemetryProps), { handle: ackNackOp.contents.handle }));
230
229
  resultsBuilder.receivedSummaryAckOrNack.resolve({ success: true, data: {
231
230
  summaryAckOp: ackNackOp,
232
231
  ackNackDuration,
@@ -1 +1 @@
1
- {"version":3,"file":"summaryGenerator.js","sourceRoot":"","sources":["../src/summaryGenerator.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger, ITelemetryProperties } from \"@fluidframework/common-definitions\";\nimport {\n assert,\n Deferred,\n IPromiseTimer,\n IPromiseTimerResult,\n Timer,\n} from \"@fluidframework/common-utils\";\nimport { MessageType } from \"@fluidframework/protocol-definitions\";\nimport { PerformanceEvent, LoggingError, ChildLogger } from \"@fluidframework/telemetry-utils\";\nimport { getRetryDelaySecondsFromError } from \"@fluidframework/driver-utils\";\nimport { DriverErrorType } from \"@fluidframework/driver-definitions\";\nimport {\n IAckSummaryResult,\n INackSummaryResult,\n ISummarizeOptions,\n IBroadcastSummaryResult,\n ISummarizeResults,\n ISummarizeHeuristicData,\n ISubmitSummaryOptions,\n SubmitSummaryResult,\n SummarizeResultPart,\n ISummaryCancellationToken,\n ISummarizeTelemetryProperties,\n} from \"./summarizerTypes\";\nimport { IClientSummaryWatcher } from \"./summaryCollection\";\n\nexport type raceTimerResult<T> =\n { result: \"done\"; value: T } |\n { result: IPromiseTimerResult[\"timerResult\"] } |\n { result: \"cancelled\" };\n\n/** Helper function to wait for a promise or PromiseTimer to elapse. */\nexport async function raceTimer<T>(\n promise: Promise<T>,\n timer: Promise<IPromiseTimerResult>,\n cancellationToken?: ISummaryCancellationToken,\n): Promise<raceTimerResult<T>> {\n const promises: Promise<raceTimerResult<T>>[] = [\n promise.then((value) => ({ result: \"done\", value } as const)),\n timer.then(({ timerResult: result }) => ({ result } as const)),\n ];\n if (cancellationToken !== undefined) {\n promises.push(cancellationToken.waitCancelled.then(() => ({ result: \"cancelled\" } as const)));\n }\n return Promise.race(promises);\n}\n\n// Send some telemetry if generate summary takes too long\nconst maxSummarizeTimeoutTime = 20000; // 20 sec\nconst maxSummarizeTimeoutCount = 5; // Double and resend 5 times\n\ntype SummaryGeneratorRequiredTelemetryProperties =\n /** True to generate the full tree with no handle reuse optimizations */\n \"fullTree\" |\n /** Time since we last attempted to generate a summary */\n \"timeSinceLastAttempt\" |\n /** Time since we last successfully generated a summary */\n \"timeSinceLastSummary\";\ntype SummaryGeneratorOptionalTelemetryProperties =\n /** Reference sequence number as of the generate summary attempt. */\n \"referenceSequenceNumber\" |\n /** minimum sequence number (at the reference sequence number) */\n \"minimumSequenceNumber\" |\n /** Delta between the current reference sequence number and the reference sequence number of the last attempt */\n \"opsSinceLastAttempt\" |\n /** Delta between the current reference sequence number and the reference sequence number of the last summary */\n \"opsSinceLastSummary\" |\n /** Delta in sum of op sizes between the current reference sequence number and the reference\n * sequence number of the last summary */\n \"opsSizesSinceLastSummary\" |\n /** Delta between the number of non-system ops since the last summary @see isSystemMessage */\n \"nonSystemOpsSinceLastSummary\" |\n /** Time it took to generate the summary tree and stats. */\n \"generateDuration\" |\n /** The handle returned by storage pointing to the uploaded summary tree. */\n \"handle\" |\n /** Time it took to upload the summary tree to storage. */\n \"uploadDuration\" |\n /** The client sequence number of the summarize op submitted for the summary. */\n \"clientSequenceNumber\" |\n /** Time it took for this summary to be acked after it was generated */\n \"ackWaitDuration\" |\n /** Reference sequence number of the ack/nack message */\n \"ackNackSequenceNumber\" |\n /** Actual sequence number of the summary op proposal. */\n \"summarySequenceNumber\" |\n /** Optional Retry-After time in seconds. If specified, the client should wait this many seconds before retrying. */\n \"nackRetryAfter\";\ntype SummaryGeneratorTelemetry =\n Pick<ITelemetryProperties, SummaryGeneratorRequiredTelemetryProperties> &\n Partial<Pick<ITelemetryProperties, SummaryGeneratorOptionalTelemetryProperties>>;\n\nexport type SummarizeReason =\n /**\n * Attempt to summarize after idle timeout has elapsed.\n * Idle timer restarts whenever an op is received. So this\n * triggers only after some amount of time has passed with\n * no ops being received.\n */\n | \"idle\"\n /**\n * Attempt to summarize after a maximum time since last\n * successful summary has passed. This measures time since\n * last summary ack op was processed.\n */\n | \"maxTime\"\n /**\n * Attempt to summarize after a maximum number of ops have\n * passed since the last successful summary. This compares\n * op sequence numbers with the reference sequence number\n * of the summarize op corresponding to the last summary\n * ack op.\n */\n | \"maxOps\"\n /**\n * Special case to attempt to summarize one last time before the\n * summarizer client closes itself. This is to prevent cases where\n * the summarizer client never gets a chance to summarize, because\n * there are too many outstanding ops and/or parent client cannot\n * stay connected long enough for summarizer client to catch up.\n */\n | \"lastSummary\"\n /** Previous summary attempt failed, and we are retrying. */\n | `retry${number}`\n /** On-demand summary requested with specified reason. */\n | `onDemand;${string}`\n /** Enqueue summarize attempt with specified reason. */\n | `enqueue;${string}`;\n\nconst summarizeErrors = {\n /**\n * Error encountered while generating the summary tree, uploading\n * it to storage, or submitting the op. It could be a result of\n * the client becoming disconnected while generating or an actual error.\n */\n submitSummaryFailure: \"Error while generating, uploading, or submitting summary\",\n /**\n * The summaryAckWaitTimeout time has elapsed before receiving the summarize op\n * sent by this summarize attempt. It is expected to be broadcast quickly.\n */\n summaryOpWaitTimeout: \"Timeout while waiting for summarize op broadcast\",\n /**\n * The summaryAckWaitTimeout time has elapsed before receiving either a\n * summaryAck or summaryNack op from the server in response to this\n * summarize attempt. It is expected that the server should respond.\n */\n summaryAckWaitTimeout: \"Timeout while waiting for summaryAck/summaryNack op\",\n /**\n * The server responded with a summaryNack op, thus rejecting this\n * summarize attempt.\n */\n summaryNack: \"Server rejected summary via summaryNack op\",\n\n disconnect: \"Summary cancelled due to summarizer or main client disconnect\",\n} as const;\n\nexport class SummarizeResultBuilder {\n public readonly summarySubmitted = new Deferred<SummarizeResultPart<SubmitSummaryResult>>();\n public readonly summaryOpBroadcasted = new Deferred<SummarizeResultPart<IBroadcastSummaryResult>>();\n public readonly receivedSummaryAckOrNack =\n new Deferred<SummarizeResultPart<IAckSummaryResult, INackSummaryResult>>();\n\n public fail(message: string, error: any, nackSummaryResult?: INackSummaryResult, retryAfterSeconds?: number) {\n assert(!this.receivedSummaryAckOrNack.isCompleted,\n 0x25e /* \"no reason to call fail if all promises have been completed\" */);\n\n const result: SummarizeResultPart<undefined> =\n { success: false, message, data: undefined, error, retryAfterSeconds } as const;\n this.summarySubmitted.resolve(result);\n this.summaryOpBroadcasted.resolve(result);\n this.receivedSummaryAckOrNack.resolve({ ...result, data: nackSummaryResult });\n }\n public build(): ISummarizeResults {\n return {\n summarySubmitted: this.summarySubmitted.promise,\n summaryOpBroadcasted: this.summaryOpBroadcasted.promise,\n receivedSummaryAckOrNack: this.receivedSummaryAckOrNack.promise,\n } as const;\n }\n}\n\n/**\n * This class generates and tracks a summary attempt.\n */\nexport class SummaryGenerator {\n private readonly summarizeTimer: Timer;\n constructor(\n private readonly pendingAckTimer: IPromiseTimer,\n private readonly heuristicData: ISummarizeHeuristicData,\n private readonly submitSummaryCallback: (options: ISubmitSummaryOptions) => Promise<SubmitSummaryResult>,\n private readonly raiseSummarizingError: (errorMessage: string) => void,\n private readonly successfulSummaryCallback: () => void,\n private readonly summaryWatcher: Pick<IClientSummaryWatcher, \"watchSummary\">,\n private readonly logger: ITelemetryLogger,\n ) {\n this.summarizeTimer = new Timer(\n maxSummarizeTimeoutTime,\n () => this.summarizeTimerHandler(maxSummarizeTimeoutTime, 1),\n );\n }\n\n /**\n * Generates summary and listens for broadcast and ack/nack.\n * Returns true for ack, false for nack, and undefined for failure or timeout.\n * @param reason - reason for summarizing\n * @param options - refreshLatestAck to fetch summary ack info from server,\n * fullTree to generate tree without any summary handles even if unchanged\n */\n public summarize(\n summarizeProps: ISummarizeTelemetryProperties,\n options: ISummarizeOptions,\n cancellationToken: ISummaryCancellationToken,\n resultsBuilder = new SummarizeResultBuilder(),\n ): ISummarizeResults {\n this.summarizeCore(summarizeProps, options, resultsBuilder, cancellationToken)\n .catch((error) => {\n const message = \"UnexpectedSummarizeError\";\n this.logger.sendErrorEvent({ eventName: message, ...summarizeProps }, error);\n resultsBuilder.fail(message, error);\n });\n\n return resultsBuilder.build();\n }\n\n private async summarizeCore(\n summarizeProps: ISummarizeTelemetryProperties,\n options: ISummarizeOptions,\n resultsBuilder: SummarizeResultBuilder,\n cancellationToken: ISummaryCancellationToken,\n ): Promise<void> {\n const { refreshLatestAck, fullTree } = options;\n const logger = ChildLogger.create(this.logger, undefined, { all: summarizeProps });\n\n const timeSinceLastAttempt = Date.now() - this.heuristicData.lastAttempt.summaryTime;\n const timeSinceLastSummary = Date.now() - this.heuristicData.lastSuccessfulSummary.summaryTime;\n let summarizeTelemetryProps: SummaryGeneratorTelemetry = {\n fullTree,\n timeSinceLastAttempt,\n timeSinceLastSummary,\n };\n\n const summarizeEvent = PerformanceEvent.start(logger, {\n eventName: \"Summarize\",\n refreshLatestAck,\n ...summarizeTelemetryProps,\n });\n\n // Helper functions to report failures and return.\n const getFailMessage =\n (errorCode: keyof typeof summarizeErrors) => `${errorCode}: ${summarizeErrors[errorCode]}`;\n const fail = (\n errorCode: keyof typeof summarizeErrors,\n error?: any,\n properties?: SummaryGeneratorTelemetry,\n nackSummaryResult?: INackSummaryResult,\n ) => {\n this.raiseSummarizingError(summarizeErrors[errorCode]);\n // UploadSummary may fail with 429 and retryAfter - respect that\n // Summary Nack also can have retryAfter, it's parsed below and comes as a property.\n const retryAfterSeconds = getRetryDelaySecondsFromError(error);\n\n // Report any failure as an error unless it was due to cancellation (like \"disconnected\" error)\n // If failure happened on upload, we may not yet realized that socket disconnected, so check\n // offlineError too.\n const category = cancellationToken.cancelled || error?.errorType === DriverErrorType.offlineError ?\n \"generic\" : \"error\";\n\n summarizeEvent.cancel({\n ...properties,\n reason: errorCode,\n category,\n retryAfterSeconds,\n }, error);\n resultsBuilder.fail(getFailMessage(errorCode), error, nackSummaryResult, retryAfterSeconds);\n };\n\n // Wait to generate and send summary\n this.summarizeTimer.start();\n\n // Use record type to prevent unexpected value types\n let summaryData: SubmitSummaryResult | undefined;\n try {\n const generateSummaryEvent = PerformanceEvent.start(logger, {\n eventName: \"Summarize\",\n ...summarizeTelemetryProps,\n });\n\n summaryData = await this.submitSummaryCallback({\n fullTree,\n refreshLatestAck,\n summaryLogger: logger,\n cancellationToken,\n });\n\n // Cumulatively add telemetry properties based on how far generateSummary went.\n const referenceSequenceNumber = summaryData.referenceSequenceNumber;\n const opsSinceLastSummary =\n referenceSequenceNumber - this.heuristicData.lastSuccessfulSummary.refSequenceNumber;\n summarizeTelemetryProps = {\n ...summarizeTelemetryProps,\n referenceSequenceNumber,\n minimumSequenceNumber: summaryData.minimumSequenceNumber,\n opsSinceLastAttempt: referenceSequenceNumber - this.heuristicData.lastAttempt.refSequenceNumber,\n opsSinceLastSummary,\n };\n if (summaryData.stage !== \"base\") {\n summarizeTelemetryProps = {\n ...summarizeTelemetryProps,\n ...summaryData.summaryStats,\n generateDuration: summaryData.generateDuration,\n };\n\n if (summaryData.stage !== \"generate\") {\n summarizeTelemetryProps = {\n ...summarizeTelemetryProps,\n handle: summaryData.handle,\n uploadDuration: summaryData.uploadDuration,\n };\n\n if (summaryData.stage !== \"upload\") {\n summarizeTelemetryProps = {\n ...summarizeTelemetryProps,\n clientSequenceNumber: summaryData.clientSequenceNumber,\n };\n }\n }\n }\n\n if (summaryData.stage !== \"submit\") {\n return fail(\"submitSummaryFailure\", summaryData.error, summarizeTelemetryProps);\n }\n\n /**\n * With incremental summaries, if the full tree was not summarized, only data stores that changed should\n * be summarized. A data store is considered changed if either or both of the following is true:\n * - It has received an op.\n * - Its reference state changed, i.e., it went from referenced to unreferenced or vice-versa.\n *\n * In the extreme case, every op can be for a different data store and each op can result in the reference\n * state change of multiple data stores. So, the total number of data stores that are summarized should not\n * exceed the number of ops since last summary + number of data store whose reference state changed.\n */\n if (!fullTree && !summaryData.forcedFullTree) {\n const { summarizedDataStoreCount, gcStateUpdatedDataStoreCount = 0 } = summaryData.summaryStats;\n if (summarizedDataStoreCount > gcStateUpdatedDataStoreCount + opsSinceLastSummary) {\n logger.sendErrorEvent({\n eventName: \"IncrementalSummaryViolation\",\n summarizedDataStoreCount,\n gcStateUpdatedDataStoreCount,\n opsSinceLastSummary,\n });\n }\n }\n\n // Log event here on summary success only, as Summarize_cancel duplicates failure logging.\n generateSummaryEvent.reportEvent(\"generate\", {...summarizeTelemetryProps});\n resultsBuilder.summarySubmitted.resolve({ success: true, data: summaryData });\n } catch (error) {\n return fail(\"submitSummaryFailure\", error);\n } finally {\n this.heuristicData.recordAttempt(summaryData?.referenceSequenceNumber);\n this.summarizeTimer.clear();\n }\n\n try {\n const pendingTimeoutP = this.pendingAckTimer.start();\n const summary = this.summaryWatcher.watchSummary(summaryData.clientSequenceNumber);\n\n // Wait for broadcast\n const waitBroadcastResult = await raceTimer(summary.waitBroadcast(), pendingTimeoutP, cancellationToken);\n if (waitBroadcastResult.result === \"cancelled\") {\n return fail(\"disconnect\");\n }\n if (waitBroadcastResult.result !== \"done\") {\n return fail(\"summaryOpWaitTimeout\");\n }\n const summarizeOp = waitBroadcastResult.value;\n\n const broadcastDuration = Date.now() - this.heuristicData.lastAttempt.summaryTime;\n resultsBuilder.summaryOpBroadcasted.resolve({\n success: true,\n data: { summarizeOp, broadcastDuration },\n });\n\n this.heuristicData.lastAttempt.summarySequenceNumber = summarizeOp.sequenceNumber;\n logger.sendTelemetryEvent({\n eventName: \"Summarize_Op\",\n duration: broadcastDuration,\n referenceSequenceNumber: summarizeOp.referenceSequenceNumber,\n summarySequenceNumber: summarizeOp.sequenceNumber,\n handle: summarizeOp.contents.handle,\n });\n\n // Wait for ack/nack\n const waitAckNackResult = await raceTimer(summary.waitAckNack(), pendingTimeoutP, cancellationToken);\n if (waitAckNackResult.result === \"cancelled\") {\n return fail(\"disconnect\");\n }\n if (waitAckNackResult.result !== \"done\") {\n return fail(\"summaryAckWaitTimeout\");\n }\n const ackNackOp = waitAckNackResult.value;\n this.pendingAckTimer.clear();\n\n // Update for success/failure\n const ackNackDuration = Date.now() - this.heuristicData.lastAttempt.summaryTime;\n\n // adding new properties\n summarizeTelemetryProps = {\n ackWaitDuration: ackNackDuration,\n ackNackSequenceNumber: ackNackOp.sequenceNumber,\n summarySequenceNumber: ackNackOp.contents.summaryProposal.summarySequenceNumber,\n ...summarizeTelemetryProps,\n };\n if (ackNackOp.type === MessageType.SummaryAck) {\n this.heuristicData.markLastAttemptAsSuccessful();\n this.successfulSummaryCallback();\n summarizeEvent.end({\n ...summarizeTelemetryProps,\n handle: ackNackOp.contents.handle,\n message: \"summaryAck\",\n });\n resultsBuilder.receivedSummaryAckOrNack.resolve({ success: true, data: {\n summaryAckOp: ackNackOp,\n ackNackDuration,\n }});\n } else {\n // Check for retryDelay in summaryNack response.\n assert(ackNackOp.type === MessageType.SummaryNack, 0x274 /* \"type check\" */);\n const summaryNack = ackNackOp.contents;\n const message = summaryNack?.message;\n const retryAfterSeconds = summaryNack?.retryAfter;\n\n // pre-0.58 error message prefix: summaryNack\n const error = new LoggingError(`Received summaryNack: ${message}`, { retryAfterSeconds });\n logger.sendErrorEvent(\n { eventName: \"SummaryNack\", ...summarizeTelemetryProps, retryAfterSeconds }, error);\n\n assert(getRetryDelaySecondsFromError(error) === retryAfterSeconds, 0x25f /* \"retryAfterSeconds\" */);\n // This will only set resultsBuilder.receivedSummaryAckOrNack, as other promises are already set.\n return fail(\n \"summaryNack\",\n error,\n { ...summarizeTelemetryProps, nackRetryAfter: retryAfterSeconds },\n { summaryNackOp: ackNackOp, ackNackDuration },\n );\n }\n } finally {\n this.pendingAckTimer.clear();\n }\n }\n\n private summarizeTimerHandler(time: number, count: number) {\n this.logger.sendPerformanceEvent({\n eventName: \"SummarizeTimeout\",\n timeoutTime: time,\n timeoutCount: count,\n });\n if (count < maxSummarizeTimeoutCount) {\n // Double and start a new timer\n const nextTime = time * 2;\n this.summarizeTimer.start(nextTime, () => this.summarizeTimerHandler(nextTime, count + 1));\n }\n }\n\n public dispose() {\n this.summarizeTimer.clear();\n }\n}\n"]}
1
+ {"version":3,"file":"summaryGenerator.js","sourceRoot":"","sources":["../src/summaryGenerator.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger, ITelemetryProperties } from \"@fluidframework/common-definitions\";\nimport {\n assert,\n Deferred,\n IPromiseTimer,\n IPromiseTimerResult,\n Timer,\n} from \"@fluidframework/common-utils\";\nimport { MessageType } from \"@fluidframework/protocol-definitions\";\nimport { PerformanceEvent, LoggingError, ChildLogger } from \"@fluidframework/telemetry-utils\";\nimport { getRetryDelaySecondsFromError } from \"@fluidframework/driver-utils\";\nimport { DriverErrorType } from \"@fluidframework/driver-definitions\";\nimport {\n IAckSummaryResult,\n INackSummaryResult,\n ISummarizeOptions,\n IBroadcastSummaryResult,\n ISummarizeResults,\n ISummarizeHeuristicData,\n ISubmitSummaryOptions,\n SubmitSummaryResult,\n SummarizeResultPart,\n ISummaryCancellationToken,\n ISummarizeTelemetryProperties,\n} from \"./summarizerTypes\";\nimport { IClientSummaryWatcher } from \"./summaryCollection\";\n\nexport type raceTimerResult<T> =\n { result: \"done\"; value: T } |\n { result: IPromiseTimerResult[\"timerResult\"] } |\n { result: \"cancelled\" };\n\n/** Helper function to wait for a promise or PromiseTimer to elapse. */\nexport async function raceTimer<T>(\n promise: Promise<T>,\n timer: Promise<IPromiseTimerResult>,\n cancellationToken?: ISummaryCancellationToken,\n): Promise<raceTimerResult<T>> {\n const promises: Promise<raceTimerResult<T>>[] = [\n promise.then((value) => ({ result: \"done\", value } as const)),\n timer.then(({ timerResult: result }) => ({ result } as const)),\n ];\n if (cancellationToken !== undefined) {\n promises.push(cancellationToken.waitCancelled.then(() => ({ result: \"cancelled\" } as const)));\n }\n return Promise.race(promises);\n}\n\n// Send some telemetry if generate summary takes too long\nconst maxSummarizeTimeoutTime = 20000; // 20 sec\nconst maxSummarizeTimeoutCount = 5; // Double and resend 5 times\n\ntype SummaryGeneratorRequiredTelemetryProperties =\n /** True to generate the full tree with no handle reuse optimizations */\n \"fullTree\" |\n /** Time since we last attempted to generate a summary */\n \"timeSinceLastAttempt\" |\n /** Time since we last successfully generated a summary */\n \"timeSinceLastSummary\";\ntype SummaryGeneratorOptionalTelemetryProperties =\n /** Reference sequence number as of the generate summary attempt. */\n \"referenceSequenceNumber\" |\n /** minimum sequence number (at the reference sequence number) */\n \"minimumSequenceNumber\" |\n /** Delta between the current reference sequence number and the reference sequence number of the last attempt */\n \"opsSinceLastAttempt\" |\n /** Delta between the current reference sequence number and the reference sequence number of the last summary */\n \"opsSinceLastSummary\" |\n /** Delta in sum of op sizes between the current reference sequence number and the reference\n * sequence number of the last summary */\n \"opsSizesSinceLastSummary\" |\n /** Delta between the number of non-system ops since the last summary @see isSystemMessage */\n \"nonSystemOpsSinceLastSummary\" |\n /** Time it took to generate the summary tree and stats. */\n \"generateDuration\" |\n /** The handle returned by storage pointing to the uploaded summary tree. */\n \"handle\" |\n /** Time it took to upload the summary tree to storage. */\n \"uploadDuration\" |\n /** The client sequence number of the summarize op submitted for the summary. */\n \"clientSequenceNumber\" |\n /** Time it took for this summary to be acked after it was generated */\n \"ackWaitDuration\" |\n /** Reference sequence number of the ack/nack message */\n \"ackNackSequenceNumber\" |\n /** Actual sequence number of the summary op proposal. */\n \"summarySequenceNumber\" |\n /** Optional Retry-After time in seconds. If specified, the client should wait this many seconds before retrying. */\n \"nackRetryAfter\";\ntype SummaryGeneratorTelemetry =\n Pick<ITelemetryProperties, SummaryGeneratorRequiredTelemetryProperties> &\n Partial<Pick<ITelemetryProperties, SummaryGeneratorOptionalTelemetryProperties>>;\n\nexport type SummarizeReason =\n /**\n * Attempt to summarize after idle timeout has elapsed.\n * Idle timer restarts whenever an op is received. So this\n * triggers only after some amount of time has passed with\n * no ops being received.\n */\n | \"idle\"\n /**\n * Attempt to summarize after a maximum time since last\n * successful summary has passed. This measures time since\n * last summary ack op was processed.\n */\n | \"maxTime\"\n /**\n * Attempt to summarize after a maximum number of ops have\n * passed since the last successful summary. This compares\n * op sequence numbers with the reference sequence number\n * of the summarize op corresponding to the last summary\n * ack op.\n */\n | \"maxOps\"\n /**\n * Special case to attempt to summarize one last time before the\n * summarizer client closes itself. This is to prevent cases where\n * the summarizer client never gets a chance to summarize, because\n * there are too many outstanding ops and/or parent client cannot\n * stay connected long enough for summarizer client to catch up.\n */\n | \"lastSummary\"\n /** Previous summary attempt failed, and we are retrying. */\n | `retry${number}`\n /** On-demand summary requested with specified reason. */\n | `onDemand;${string}`\n /** Enqueue summarize attempt with specified reason. */\n | `enqueue;${string}`;\n\nconst summarizeErrors = {\n /**\n * Error encountered while generating the summary tree, uploading\n * it to storage, or submitting the op. It could be a result of\n * the client becoming disconnected while generating or an actual error.\n */\n submitSummaryFailure: \"Error while generating, uploading, or submitting summary\",\n /**\n * The summaryAckWaitTimeout time has elapsed before receiving the summarize op\n * sent by this summarize attempt. It is expected to be broadcast quickly.\n */\n summaryOpWaitTimeout: \"Timeout while waiting for summarize op broadcast\",\n /**\n * The summaryAckWaitTimeout time has elapsed before receiving either a\n * summaryAck or summaryNack op from the server in response to this\n * summarize attempt. It is expected that the server should respond.\n */\n summaryAckWaitTimeout: \"Timeout while waiting for summaryAck/summaryNack op\",\n /**\n * The server responded with a summaryNack op, thus rejecting this\n * summarize attempt.\n */\n summaryNack: \"Server rejected summary via summaryNack op\",\n\n disconnect: \"Summary cancelled due to summarizer or main client disconnect\",\n} as const;\n\nexport class SummarizeResultBuilder {\n public readonly summarySubmitted = new Deferred<SummarizeResultPart<SubmitSummaryResult>>();\n public readonly summaryOpBroadcasted = new Deferred<SummarizeResultPart<IBroadcastSummaryResult>>();\n public readonly receivedSummaryAckOrNack =\n new Deferred<SummarizeResultPart<IAckSummaryResult, INackSummaryResult>>();\n\n public fail(message: string, error: any, nackSummaryResult?: INackSummaryResult, retryAfterSeconds?: number) {\n assert(!this.receivedSummaryAckOrNack.isCompleted,\n 0x25e /* \"no reason to call fail if all promises have been completed\" */);\n\n const result: SummarizeResultPart<undefined> =\n { success: false, message, data: undefined, error, retryAfterSeconds } as const;\n this.summarySubmitted.resolve(result);\n this.summaryOpBroadcasted.resolve(result);\n this.receivedSummaryAckOrNack.resolve({ ...result, data: nackSummaryResult });\n }\n public build(): ISummarizeResults {\n return {\n summarySubmitted: this.summarySubmitted.promise,\n summaryOpBroadcasted: this.summaryOpBroadcasted.promise,\n receivedSummaryAckOrNack: this.receivedSummaryAckOrNack.promise,\n } as const;\n }\n}\n\n/**\n * This class generates and tracks a summary attempt.\n */\nexport class SummaryGenerator {\n private readonly summarizeTimer: Timer;\n constructor(\n private readonly pendingAckTimer: IPromiseTimer,\n private readonly heuristicData: ISummarizeHeuristicData,\n private readonly submitSummaryCallback: (options: ISubmitSummaryOptions) => Promise<SubmitSummaryResult>,\n private readonly raiseSummarizingError: (errorMessage: string) => void,\n private readonly successfulSummaryCallback: () => void,\n private readonly summaryWatcher: Pick<IClientSummaryWatcher, \"watchSummary\">,\n private readonly logger: ITelemetryLogger,\n ) {\n this.summarizeTimer = new Timer(\n maxSummarizeTimeoutTime,\n () => this.summarizeTimerHandler(maxSummarizeTimeoutTime, 1),\n );\n }\n\n /**\n * Generates summary and listens for broadcast and ack/nack.\n * Returns true for ack, false for nack, and undefined for failure or timeout.\n * @param reason - reason for summarizing\n * @param options - refreshLatestAck to fetch summary ack info from server,\n * fullTree to generate tree without any summary handles even if unchanged\n */\n public summarize(\n summarizeProps: ISummarizeTelemetryProperties,\n options: ISummarizeOptions,\n cancellationToken: ISummaryCancellationToken,\n resultsBuilder = new SummarizeResultBuilder(),\n ): ISummarizeResults {\n this.summarizeCore(summarizeProps, options, resultsBuilder, cancellationToken)\n .catch((error) => {\n const message = \"UnexpectedSummarizeError\";\n this.logger.sendErrorEvent({ eventName: message, ...summarizeProps }, error);\n resultsBuilder.fail(message, error);\n });\n\n return resultsBuilder.build();\n }\n\n private async summarizeCore(\n summarizeProps: ISummarizeTelemetryProperties,\n options: ISummarizeOptions,\n resultsBuilder: SummarizeResultBuilder,\n cancellationToken: ISummaryCancellationToken,\n ): Promise<void> {\n const { refreshLatestAck, fullTree } = options;\n const logger = ChildLogger.create(this.logger, undefined, { all: summarizeProps });\n\n const timeSinceLastAttempt = Date.now() - this.heuristicData.lastAttempt.summaryTime;\n const timeSinceLastSummary = Date.now() - this.heuristicData.lastSuccessfulSummary.summaryTime;\n let summarizeTelemetryProps: SummaryGeneratorTelemetry = {\n fullTree,\n timeSinceLastAttempt,\n timeSinceLastSummary,\n };\n\n const summarizeEvent = PerformanceEvent.start(logger, {\n eventName: \"Summarize\",\n refreshLatestAck,\n ...summarizeTelemetryProps,\n });\n\n // Helper functions to report failures and return.\n const getFailMessage =\n (errorCode: keyof typeof summarizeErrors) => `${errorCode}: ${summarizeErrors[errorCode]}`;\n const fail = (\n errorCode: keyof typeof summarizeErrors,\n error?: any,\n properties?: SummaryGeneratorTelemetry,\n nackSummaryResult?: INackSummaryResult,\n ) => {\n this.raiseSummarizingError(summarizeErrors[errorCode]);\n // UploadSummary may fail with 429 and retryAfter - respect that\n // Summary Nack also can have retryAfter, it's parsed below and comes as a property.\n const retryAfterSeconds = getRetryDelaySecondsFromError(error);\n\n // Report any failure as an error unless it was due to cancellation (like \"disconnected\" error)\n // If failure happened on upload, we may not yet realized that socket disconnected, so check\n // offlineError too.\n const category = cancellationToken.cancelled || error?.errorType === DriverErrorType.offlineError ?\n \"generic\" : \"error\";\n\n summarizeEvent.cancel({\n ...properties,\n reason: errorCode,\n category,\n retryAfterSeconds,\n }, error);\n resultsBuilder.fail(getFailMessage(errorCode), error, nackSummaryResult, retryAfterSeconds);\n };\n\n // Wait to generate and send summary\n this.summarizeTimer.start();\n\n // Use record type to prevent unexpected value types\n let summaryData: SubmitSummaryResult | undefined;\n try {\n summaryData = await this.submitSummaryCallback({\n fullTree,\n refreshLatestAck,\n summaryLogger: logger,\n cancellationToken,\n });\n\n // Cumulatively add telemetry properties based on how far generateSummary went.\n const referenceSequenceNumber = summaryData.referenceSequenceNumber;\n const opsSinceLastSummary =\n referenceSequenceNumber - this.heuristicData.lastSuccessfulSummary.refSequenceNumber;\n summarizeTelemetryProps = {\n ...summarizeTelemetryProps,\n referenceSequenceNumber,\n minimumSequenceNumber: summaryData.minimumSequenceNumber,\n opsSinceLastAttempt: referenceSequenceNumber - this.heuristicData.lastAttempt.refSequenceNumber,\n opsSinceLastSummary,\n };\n if (summaryData.stage !== \"base\") {\n summarizeTelemetryProps = {\n ...summarizeTelemetryProps,\n ...summaryData.summaryStats,\n generateDuration: summaryData.generateDuration,\n };\n\n if (summaryData.stage !== \"generate\") {\n summarizeTelemetryProps = {\n ...summarizeTelemetryProps,\n handle: summaryData.handle,\n uploadDuration: summaryData.uploadDuration,\n };\n\n if (summaryData.stage !== \"upload\") {\n summarizeTelemetryProps = {\n ...summarizeTelemetryProps,\n clientSequenceNumber: summaryData.clientSequenceNumber,\n };\n }\n }\n }\n\n if (summaryData.stage !== \"submit\") {\n return fail(\"submitSummaryFailure\", summaryData.error, summarizeTelemetryProps);\n }\n\n /**\n * With incremental summaries, if the full tree was not summarized, only data stores that changed should\n * be summarized. A data store is considered changed if either or both of the following is true:\n * - It has received an op.\n * - Its reference state changed, i.e., it went from referenced to unreferenced or vice-versa.\n *\n * In the extreme case, every op can be for a different data store and each op can result in the reference\n * state change of multiple data stores. So, the total number of data stores that are summarized should not\n * exceed the number of ops since last summary + number of data store whose reference state changed.\n */\n if (!fullTree && !summaryData.forcedFullTree) {\n const { summarizedDataStoreCount, gcStateUpdatedDataStoreCount = 0 } = summaryData.summaryStats;\n if (summarizedDataStoreCount > gcStateUpdatedDataStoreCount + opsSinceLastSummary) {\n logger.sendErrorEvent({\n eventName: \"IncrementalSummaryViolation\",\n summarizedDataStoreCount,\n gcStateUpdatedDataStoreCount,\n opsSinceLastSummary,\n });\n }\n }\n\n // Log event here on summary success only, as Summarize_cancel duplicates failure logging.\n summarizeEvent.reportEvent(\"generate\", {...summarizeTelemetryProps});\n resultsBuilder.summarySubmitted.resolve({ success: true, data: summaryData });\n } catch (error) {\n return fail(\"submitSummaryFailure\", error);\n } finally {\n this.heuristicData.recordAttempt(summaryData?.referenceSequenceNumber);\n this.summarizeTimer.clear();\n }\n\n try {\n const pendingTimeoutP = this.pendingAckTimer.start();\n const summary = this.summaryWatcher.watchSummary(summaryData.clientSequenceNumber);\n\n // Wait for broadcast\n const waitBroadcastResult = await raceTimer(summary.waitBroadcast(), pendingTimeoutP, cancellationToken);\n if (waitBroadcastResult.result === \"cancelled\") {\n return fail(\"disconnect\");\n }\n if (waitBroadcastResult.result !== \"done\") {\n return fail(\"summaryOpWaitTimeout\");\n }\n const summarizeOp = waitBroadcastResult.value;\n\n const broadcastDuration = Date.now() - this.heuristicData.lastAttempt.summaryTime;\n resultsBuilder.summaryOpBroadcasted.resolve({\n success: true,\n data: { summarizeOp, broadcastDuration },\n });\n\n this.heuristicData.lastAttempt.summarySequenceNumber = summarizeOp.sequenceNumber;\n logger.sendTelemetryEvent({\n eventName: \"Summarize_Op\",\n duration: broadcastDuration,\n referenceSequenceNumber: summarizeOp.referenceSequenceNumber,\n summarySequenceNumber: summarizeOp.sequenceNumber,\n handle: summarizeOp.contents.handle,\n });\n\n // Wait for ack/nack\n const waitAckNackResult = await raceTimer(summary.waitAckNack(), pendingTimeoutP, cancellationToken);\n if (waitAckNackResult.result === \"cancelled\") {\n return fail(\"disconnect\");\n }\n if (waitAckNackResult.result !== \"done\") {\n return fail(\"summaryAckWaitTimeout\");\n }\n const ackNackOp = waitAckNackResult.value;\n this.pendingAckTimer.clear();\n\n // Update for success/failure\n const ackNackDuration = Date.now() - this.heuristicData.lastAttempt.summaryTime;\n\n // adding new properties\n summarizeTelemetryProps = {\n ackWaitDuration: ackNackDuration,\n ackNackSequenceNumber: ackNackOp.sequenceNumber,\n summarySequenceNumber: ackNackOp.contents.summaryProposal.summarySequenceNumber,\n ...summarizeTelemetryProps,\n };\n if (ackNackOp.type === MessageType.SummaryAck) {\n this.heuristicData.markLastAttemptAsSuccessful();\n this.successfulSummaryCallback();\n summarizeEvent.end({\n ...summarizeTelemetryProps,\n handle: ackNackOp.contents.handle,\n });\n resultsBuilder.receivedSummaryAckOrNack.resolve({ success: true, data: {\n summaryAckOp: ackNackOp,\n ackNackDuration,\n }});\n } else {\n // Check for retryDelay in summaryNack response.\n assert(ackNackOp.type === MessageType.SummaryNack, 0x274 /* \"type check\" */);\n const summaryNack = ackNackOp.contents;\n const message = summaryNack?.message;\n const retryAfterSeconds = summaryNack?.retryAfter;\n\n // pre-0.58 error message prefix: summaryNack\n const error = new LoggingError(`Received summaryNack: ${message}`, { retryAfterSeconds });\n logger.sendErrorEvent(\n { eventName: \"SummaryNack\", ...summarizeTelemetryProps, retryAfterSeconds }, error);\n\n assert(getRetryDelaySecondsFromError(error) === retryAfterSeconds, 0x25f /* \"retryAfterSeconds\" */);\n // This will only set resultsBuilder.receivedSummaryAckOrNack, as other promises are already set.\n return fail(\n \"summaryNack\",\n error,\n { ...summarizeTelemetryProps, nackRetryAfter: retryAfterSeconds },\n { summaryNackOp: ackNackOp, ackNackDuration },\n );\n }\n } finally {\n this.pendingAckTimer.clear();\n }\n }\n\n private summarizeTimerHandler(time: number, count: number) {\n this.logger.sendPerformanceEvent({\n eventName: \"SummarizeTimeout\",\n timeoutTime: time,\n timeoutCount: count,\n });\n if (count < maxSummarizeTimeoutCount) {\n // Double and start a new timer\n const nextTime = time * 2;\n this.summarizeTimer.start(nextTime, () => this.summarizeTimerHandler(nextTime, count + 1));\n }\n }\n\n public dispose() {\n this.summarizeTimer.clear();\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/container-runtime",
3
- "version": "0.58.3000-61081",
3
+ "version": "0.59.2000-61729",
4
4
  "description": "Fluid container runtime",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -64,29 +64,29 @@
64
64
  "dependencies": {
65
65
  "@fluidframework/common-definitions": "^0.20.1",
66
66
  "@fluidframework/common-utils": "^0.32.1",
67
- "@fluidframework/container-definitions": "^0.47.1000",
68
- "@fluidframework/container-runtime-definitions": "0.58.3000-61081",
69
- "@fluidframework/container-utils": "0.58.3000-61081",
70
- "@fluidframework/core-interfaces": "^0.42.0",
71
- "@fluidframework/datastore": "0.58.3000-61081",
72
- "@fluidframework/driver-definitions": "^0.45.2000-0",
73
- "@fluidframework/driver-utils": "0.58.3000-61081",
74
- "@fluidframework/garbage-collector": "0.58.3000-61081",
75
- "@fluidframework/protocol-base": "^0.1035.1000",
76
- "@fluidframework/protocol-definitions": "^0.1027.1000",
77
- "@fluidframework/runtime-definitions": "0.58.3000-61081",
78
- "@fluidframework/runtime-utils": "0.58.3000-61081",
79
- "@fluidframework/telemetry-utils": "0.58.3000-61081",
67
+ "@fluidframework/container-definitions": "^0.48.1000-0",
68
+ "@fluidframework/container-runtime-definitions": "0.59.2000-61729",
69
+ "@fluidframework/container-utils": "0.59.2000-61729",
70
+ "@fluidframework/core-interfaces": "^0.43.1000-0",
71
+ "@fluidframework/datastore": "0.59.2000-61729",
72
+ "@fluidframework/driver-definitions": "^0.46.1000-0",
73
+ "@fluidframework/driver-utils": "0.59.2000-61729",
74
+ "@fluidframework/garbage-collector": "0.59.2000-61729",
75
+ "@fluidframework/protocol-base": "^0.1036.1000-0",
76
+ "@fluidframework/protocol-definitions": "^0.1028.1000-0",
77
+ "@fluidframework/runtime-definitions": "0.59.2000-61729",
78
+ "@fluidframework/runtime-utils": "0.59.2000-61729",
79
+ "@fluidframework/telemetry-utils": "0.59.2000-61729",
80
80
  "double-ended-queue": "^2.1.0-0",
81
81
  "uuid": "^8.3.1"
82
82
  },
83
83
  "devDependencies": {
84
84
  "@fluidframework/build-common": "^0.23.0",
85
- "@fluidframework/build-tools": "^0.2.60108",
86
- "@fluidframework/container-runtime-previous": "npm:@fluidframework/container-runtime@0.58.2000",
87
- "@fluidframework/eslint-config-fluid": "^0.27.2000-59622",
88
- "@fluidframework/mocha-test-setup": "0.58.3000-61081",
89
- "@fluidframework/test-runtime-utils": "0.58.3000-61081",
85
+ "@fluidframework/build-tools": "^0.2.61288",
86
+ "@fluidframework/container-runtime-previous": "npm:@fluidframework/container-runtime@^0.58.0",
87
+ "@fluidframework/eslint-config-fluid": "^0.28.1000-61189",
88
+ "@fluidframework/mocha-test-setup": "0.59.2000-61729",
89
+ "@fluidframework/test-runtime-utils": "0.59.2000-61729",
90
90
  "@microsoft/api-extractor": "^7.16.1",
91
91
  "@rushstack/eslint-config": "^2.5.1",
92
92
  "@types/double-ended-queue": "^2.1.0",
@@ -114,9 +114,9 @@
114
114
  "typescript-formatter": "7.1.0"
115
115
  },
116
116
  "typeValidation": {
117
- "version": "0.58.3000",
117
+ "version": "0.59.1000",
118
118
  "broken": {
119
- "0.58.2000": {
119
+ "0.58.2002": {
120
120
  "InterfaceDeclaration_IBaseSummarizeResult": {
121
121
  "forwardCompat": false
122
122
  },
@@ -137,6 +137,18 @@
137
137
  },
138
138
  "InterfaceDeclaration_IGeneratedSummaryStats": {
139
139
  "forwardCompat": false
140
+ },
141
+ "ClassDeclaration_ContainerRuntime": {
142
+ "forwardCompat": false
143
+ },
144
+ "InterfaceDeclaration_IGarbageCollectionRuntime": {
145
+ "forwardCompat": false
146
+ },
147
+ "InterfaceDeclaration_IGCStats": {
148
+ "forwardCompat": false
149
+ },
150
+ "InterfaceDeclaration_IRootSummaryTreeWithStats": {
151
+ "forwardCompat": false
140
152
  }
141
153
  }
142
154
  }
@@ -11,7 +11,7 @@ import { ITelemetryLogger } from "@fluidframework/common-definitions";
11
11
  import { assert, Deferred } from "@fluidframework/common-utils";
12
12
  import { IContainerRuntime } from "@fluidframework/container-runtime-definitions";
13
13
  import { AttachState } from "@fluidframework/container-definitions";
14
- import { ISummaryTreeWithStats } from "@fluidframework/runtime-definitions";
14
+ import { IGarbageCollectionData, ISummaryTreeWithStats } from "@fluidframework/runtime-definitions";
15
15
 
16
16
  /**
17
17
  * This class represents blob (long string)
@@ -205,6 +205,65 @@ export class BlobManager {
205
205
  });
206
206
  }
207
207
 
208
+ /**
209
+ * Generates data used for garbage collection. Each blob uploaded represents a node in the GC graph as it can be
210
+ * individually referenced by storing its handle in a referenced DDS. Returns the list of blob ids as GC nodes.
211
+ * @param fullGC - true to bypass optimizations and force full generation of GC data. BlobManager doesn't care
212
+ * about this for now because the data is a simple list of blob ids.
213
+ */
214
+ public getGCData(fullGC: boolean = false): IGarbageCollectionData {
215
+ const getGCNodePath = (blobId: string) => { return `/${BlobManager.basePath}/${blobId}`; };
216
+ const gcData: IGarbageCollectionData = { gcNodes: {} };
217
+ /**
218
+ * The node path is of the format `/_blobs/blobId`. This path must match the path of the blob handle returned
219
+ * by the createBlob API because blobs are marked referenced by storing these handles in a referenced DDS.
220
+ */
221
+ this.blobIds.forEach((blobId: string) => {
222
+ gcData.gcNodes[getGCNodePath(blobId)] = [];
223
+ });
224
+
225
+ /**
226
+ * For all blobs in the redirect table, the handle returned on creation is based off of the localId. So, these
227
+ * nodes can be referenced by storing the localId handle. When that happens, the corresponding storageId node
228
+ * must also be marked referenced. So, we add a route from the localId node to the storageId node.
229
+ * Note that because of de-duping, there can be multiple localIds that all redirect to the same storageId or
230
+ * a blob may be referenced via its storageId handle.
231
+ */
232
+ if (this.redirectTable !== undefined) {
233
+ for (const [localId, storageId] of this.redirectTable) {
234
+ // Add node for the localId and add a route to the storageId node. The storageId node will have been
235
+ // added above when adding nodes for this.blobIds.
236
+ gcData.gcNodes[getGCNodePath(localId)] = [getGCNodePath(storageId)];
237
+ }
238
+ }
239
+
240
+ return gcData;
241
+ }
242
+
243
+ /**
244
+ * When running GC in test mode, this is called to delete blobs that are unused.
245
+ * @param unusedRoutes - These are the blob node ids that are unused and should be deleted.
246
+ */
247
+ public deleteUnusedRoutes(unusedRoutes: string[]): void {
248
+ // The routes or blob node paths are in the same format as returned in getGCData - `/_blobs/blobId`.
249
+ for (const route of unusedRoutes) {
250
+ const pathParts = route.split("/");
251
+ assert(
252
+ pathParts.length === 3 && pathParts[1] === BlobManager.basePath,
253
+ 0x2d5 /* "Invalid blob node id in unused routes." */,
254
+ );
255
+ const blobId = pathParts[2];
256
+
257
+ // The unused blobId could be a localId. If so, remove it from the redirect table and continue. The
258
+ // corresponding storageId may still be used either directly or via other localIds.
259
+ if (this.redirectTable?.has(blobId)) {
260
+ this.redirectTable.delete(blobId);
261
+ continue;
262
+ }
263
+ this.blobIds.delete(blobId);
264
+ }
265
+ }
266
+
208
267
  public summarize(): ISummaryTreeWithStats {
209
268
  // If we have a redirect table it means the container is about to transition to "Attaching" state, so we need
210
269
  // to return an actual snapshot containing all the real storage IDs we know about.
@@ -33,7 +33,7 @@ interface IOpPerfTelemetryProperties {
33
33
  /** Measure time between (3) and (4) - Time between DM's inbound "push" event until DM's "op" event */
34
34
  durationInboundToProcessing: number;
35
35
  /** Length of the DeltaManager's inbound queue at the time of the DM's inbound "push" event (3) */
36
- lenghtInboundQueue: number;
36
+ lengthInboundQueue: number;
37
37
  }
38
38
 
39
39
  /**
@@ -109,16 +109,16 @@ class OpPerfTelemetry {
109
109
  if (msg.type === MessageType.Operation &&
110
110
  this.clientSequenceNumberForLatencyStatistics === msg.clientSequenceNumber) {
111
111
  assert(this.opProcessingTimes.opStartTimeSittingInboundQueue === undefined,
112
- "opStartTimeSittingInboundQueue should be undefined");
112
+ 0x2c8 /* "opStartTimeSittingInboundQueue should be undefined" */);
113
113
  assert(this.opPerfData.durationInboundQueue === undefined,
114
- "durationInboundQueue should be undefined");
114
+ 0x2c9 /* "durationInboundQueue should be undefined" */);
115
115
  this.opProcessingTimes.opStartTimeSittingInboundQueue = Date.now();
116
116
 
117
117
  assert(this.opPerfData.durationOutboundQueue === undefined,
118
- "durationOutboundQueue should be undefined");
118
+ 0x2ca /* "durationOutboundQueue should be undefined" */);
119
119
 
120
120
  assert(this.opProcessingTimes.opStartTimeForLatencyStatistics !== undefined,
121
- "opStartTimeForLatencyStatistics should be undefined");
121
+ 0x2cb /* "opStartTimeForLatencyStatistics should be undefined" */);
122
122
 
123
123
  this.opPerfData.durationOutboundQueue = this.opProcessingTimes.opStartTimeSittingInboundQueue
124
124
  - this.opProcessingTimes.opStartTimeForLatencyStatistics;
@@ -135,7 +135,7 @@ class OpPerfTelemetry {
135
135
  this.opPerfData.durationInboundQueue = this.opProcessingTimes.opStartTimeInboundPushEvent
136
136
  - this.opProcessingTimes.opStartTimeSittingInboundQueue;
137
137
  this.opProcessingTimes.opStartTimeSittingInboundQueue = undefined;
138
- this.opPerfData.lenghtInboundQueue = this.deltaManager.inbound.length;
138
+ this.opPerfData.lengthInboundQueue = this.deltaManager.inbound.length;
139
139
  }
140
140
  });
141
141
 
@@ -188,9 +188,9 @@ class OpPerfTelemetry {
188
188
  if (this.clientSequenceNumberForLatencyStatistics === undefined &&
189
189
  message.clientSequenceNumber % 500 === 1) {
190
190
  assert(this.opProcessingTimes.opStartTimeSittingInboundQueue === undefined,
191
- "OpTimeSittingInboundQueue should be undefined");
191
+ 0x2cc /* "OpTimeSittingInboundQueue should be undefined" */);
192
192
  assert(this.opPerfData.durationInboundQueue === undefined,
193
- "durationInboundQueue should be undefined");
193
+ 0x2cd /* "durationInboundQueue should be undefined" */);
194
194
  this.opProcessingTimes.opStartTimeForLatencyStatistics = Date.now();
195
195
  this.clientSequenceNumberForLatencyStatistics = message.clientSequenceNumber;
196
196
  }
@@ -211,7 +211,7 @@ class OpPerfTelemetry {
211
211
  if (this.sequenceNumberForMsnTracking !== undefined &&
212
212
  message.minimumSequenceNumber >= this.sequenceNumberForMsnTracking) {
213
213
  assert(this.msnTrackingTimestamp !== undefined,
214
- "msnTrackingTimestamp should not be undefined");
214
+ 0x2ce /* "msnTrackingTimestamp should not be undefined" */);
215
215
  this.logger.sendPerformanceEvent({
216
216
  eventName: "MsnStatistics",
217
217
  sequenceNumber,