@fluidframework/container-runtime 2.0.0-internal.3.0.2 → 2.0.0-internal.3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (474) hide show
  1. package/.eslintrc.js +19 -19
  2. package/.mocharc.js +2 -2
  3. package/api-extractor.json +2 -2
  4. package/dist/batchTracker.d.ts.map +1 -1
  5. package/dist/batchTracker.js +2 -1
  6. package/dist/batchTracker.js.map +1 -1
  7. package/dist/blobManager.d.ts +15 -2
  8. package/dist/blobManager.d.ts.map +1 -1
  9. package/dist/blobManager.js +109 -37
  10. package/dist/blobManager.js.map +1 -1
  11. package/dist/connectionTelemetry.d.ts.map +1 -1
  12. package/dist/connectionTelemetry.js +11 -9
  13. package/dist/connectionTelemetry.js.map +1 -1
  14. package/dist/containerHandleContext.d.ts.map +1 -1
  15. package/dist/containerHandleContext.js +3 -1
  16. package/dist/containerHandleContext.js.map +1 -1
  17. package/dist/containerRuntime.d.ts +23 -11
  18. package/dist/containerRuntime.d.ts.map +1 -1
  19. package/dist/containerRuntime.js +225 -132
  20. package/dist/containerRuntime.js.map +1 -1
  21. package/dist/dataStore.d.ts.map +1 -1
  22. package/dist/dataStore.js +11 -9
  23. package/dist/dataStore.js.map +1 -1
  24. package/dist/dataStoreContext.d.ts +27 -13
  25. package/dist/dataStoreContext.d.ts.map +1 -1
  26. package/dist/dataStoreContext.js +95 -56
  27. package/dist/dataStoreContext.js.map +1 -1
  28. package/dist/dataStoreContexts.d.ts.map +1 -1
  29. package/dist/dataStoreContexts.js +7 -3
  30. package/dist/dataStoreContexts.js.map +1 -1
  31. package/dist/dataStoreRegistry.d.ts.map +1 -1
  32. package/dist/dataStoreRegistry.js +3 -1
  33. package/dist/dataStoreRegistry.js.map +1 -1
  34. package/dist/dataStores.d.ts +28 -4
  35. package/dist/dataStores.d.ts.map +1 -1
  36. package/dist/dataStores.js +122 -44
  37. package/dist/dataStores.js.map +1 -1
  38. package/dist/deltaScheduler.d.ts.map +1 -1
  39. package/dist/deltaScheduler.js +8 -3
  40. package/dist/deltaScheduler.js.map +1 -1
  41. package/dist/{garbageCollection.d.ts → gc/garbageCollection.d.ts} +27 -203
  42. package/dist/gc/garbageCollection.d.ts.map +1 -0
  43. package/dist/{garbageCollection.js → gc/garbageCollection.js} +210 -400
  44. package/dist/gc/garbageCollection.js.map +1 -0
  45. package/dist/gc/gcDefinitions.d.ts +189 -0
  46. package/dist/gc/gcDefinitions.d.ts.map +1 -0
  47. package/dist/{garbageCollectionConstants.js → gc/gcDefinitions.js} +27 -2
  48. package/dist/gc/gcDefinitions.js.map +1 -0
  49. package/dist/gc/gcHelpers.d.ts +30 -0
  50. package/dist/gc/gcHelpers.d.ts.map +1 -0
  51. package/dist/gc/gcHelpers.js +65 -0
  52. package/dist/gc/gcHelpers.js.map +1 -0
  53. package/dist/gc/gcSummaryStateTracker.d.ts +86 -0
  54. package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -0
  55. package/dist/gc/gcSummaryStateTracker.js +246 -0
  56. package/dist/gc/gcSummaryStateTracker.js.map +1 -0
  57. package/{lib → dist/gc}/gcSweepReadyUsageDetection.d.ts +5 -5
  58. package/dist/gc/gcSweepReadyUsageDetection.d.ts.map +1 -0
  59. package/dist/{gcSweepReadyUsageDetection.js → gc/gcSweepReadyUsageDetection.js} +15 -11
  60. package/dist/gc/gcSweepReadyUsageDetection.js.map +1 -0
  61. package/dist/gc/gcUnreferencedStateTracker.d.ts +34 -0
  62. package/dist/gc/gcUnreferencedStateTracker.d.ts.map +1 -0
  63. package/dist/gc/gcUnreferencedStateTracker.js +94 -0
  64. package/dist/gc/gcUnreferencedStateTracker.js.map +1 -0
  65. package/dist/gc/index.d.ts +11 -0
  66. package/dist/gc/index.d.ts.map +1 -0
  67. package/dist/gc/index.js +40 -0
  68. package/dist/gc/index.js.map +1 -0
  69. package/dist/index.d.ts +2 -5
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +6 -9
  72. package/dist/index.js.map +1 -1
  73. package/dist/opLifecycle/batchManager.d.ts +2 -13
  74. package/dist/opLifecycle/batchManager.d.ts.map +1 -1
  75. package/dist/opLifecycle/batchManager.js +19 -41
  76. package/dist/opLifecycle/batchManager.js.map +1 -1
  77. package/dist/opLifecycle/definitions.d.ts +4 -0
  78. package/dist/opLifecycle/definitions.d.ts.map +1 -1
  79. package/dist/opLifecycle/definitions.js.map +1 -1
  80. package/dist/opLifecycle/index.d.ts.map +1 -1
  81. package/dist/opLifecycle/index.js.map +1 -1
  82. package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
  83. package/dist/opLifecycle/opCompressor.js +1 -0
  84. package/dist/opLifecycle/opCompressor.js.map +1 -1
  85. package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
  86. package/dist/opLifecycle/opDecompressor.js +5 -2
  87. package/dist/opLifecycle/opDecompressor.js.map +1 -1
  88. package/dist/opLifecycle/opSplitter.d.ts +1 -1
  89. package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
  90. package/dist/opLifecycle/opSplitter.js +24 -13
  91. package/dist/opLifecycle/opSplitter.js.map +1 -1
  92. package/dist/opLifecycle/outbox.d.ts +19 -3
  93. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  94. package/dist/opLifecycle/outbox.js +78 -45
  95. package/dist/opLifecycle/outbox.js.map +1 -1
  96. package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  97. package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
  98. package/dist/opProperties.d.ts.map +1 -1
  99. package/dist/opProperties.js +1 -3
  100. package/dist/opProperties.js.map +1 -1
  101. package/dist/packageVersion.d.ts +1 -1
  102. package/dist/packageVersion.js +1 -1
  103. package/dist/packageVersion.js.map +1 -1
  104. package/dist/pendingStateManager.d.ts +8 -2
  105. package/dist/pendingStateManager.d.ts.map +1 -1
  106. package/dist/pendingStateManager.js +21 -13
  107. package/dist/pendingStateManager.js.map +1 -1
  108. package/dist/scheduleManager.d.ts.map +1 -1
  109. package/dist/scheduleManager.js +3 -2
  110. package/dist/scheduleManager.js.map +1 -1
  111. package/dist/serializedSnapshotStorage.d.ts +2 -2
  112. package/dist/serializedSnapshotStorage.d.ts.map +1 -1
  113. package/dist/serializedSnapshotStorage.js +5 -3
  114. package/dist/serializedSnapshotStorage.js.map +1 -1
  115. package/dist/summary/index.d.ts +17 -0
  116. package/dist/summary/index.d.ts.map +1 -0
  117. package/dist/summary/index.js +47 -0
  118. package/dist/summary/index.js.map +1 -0
  119. package/dist/summary/orderedClientElection.d.ts.map +1 -0
  120. package/dist/{orderedClientElection.js → summary/orderedClientElection.js} +10 -4
  121. package/dist/summary/orderedClientElection.js.map +1 -0
  122. package/dist/summary/runWhileConnectedCoordinator.d.ts.map +1 -0
  123. package/dist/summary/runWhileConnectedCoordinator.js.map +1 -0
  124. package/{lib → dist/summary}/runningSummarizer.d.ts +19 -18
  125. package/dist/summary/runningSummarizer.d.ts.map +1 -0
  126. package/dist/{runningSummarizer.js → summary/runningSummarizer.js} +191 -76
  127. package/dist/summary/runningSummarizer.js.map +1 -0
  128. package/dist/{summarizer.d.ts → summary/summarizer.d.ts} +4 -6
  129. package/dist/summary/summarizer.d.ts.map +1 -0
  130. package/dist/{summarizer.js → summary/summarizer.js} +31 -71
  131. package/dist/summary/summarizer.js.map +1 -0
  132. package/dist/summary/summarizerClientElection.d.ts.map +1 -0
  133. package/dist/summary/summarizerClientElection.js.map +1 -0
  134. package/dist/summary/summarizerHandle.d.ts.map +1 -0
  135. package/dist/summary/summarizerHandle.js.map +1 -0
  136. package/{lib → dist/summary}/summarizerHeuristics.d.ts +1 -1
  137. package/dist/summary/summarizerHeuristics.d.ts.map +1 -0
  138. package/dist/{summarizerHeuristics.js → summary/summarizerHeuristics.js} +6 -9
  139. package/dist/summary/summarizerHeuristics.js.map +1 -0
  140. package/{lib → dist/summary}/summarizerTypes.d.ts +22 -22
  141. package/dist/summary/summarizerTypes.d.ts.map +1 -0
  142. package/dist/summary/summarizerTypes.js.map +1 -0
  143. package/dist/summary/summaryCollection.d.ts.map +1 -0
  144. package/dist/{summaryCollection.js → summary/summaryCollection.js} +18 -8
  145. package/dist/summary/summaryCollection.js.map +1 -0
  146. package/{lib → dist/summary}/summaryFormat.d.ts +1 -40
  147. package/dist/summary/summaryFormat.d.ts.map +1 -0
  148. package/dist/{summaryFormat.js → summary/summaryFormat.js} +19 -20
  149. package/dist/summary/summaryFormat.js.map +1 -0
  150. package/dist/summary/summaryGenerator.d.ts.map +1 -0
  151. package/dist/{summaryGenerator.js → summary/summaryGenerator.js} +33 -15
  152. package/dist/summary/summaryGenerator.js.map +1 -0
  153. package/dist/{summaryManager.d.ts → summary/summaryManager.d.ts} +1 -1
  154. package/dist/summary/summaryManager.d.ts.map +1 -0
  155. package/dist/{summaryManager.js → summary/summaryManager.js} +21 -9
  156. package/dist/summary/summaryManager.js.map +1 -0
  157. package/dist/throttler.d.ts +2 -2
  158. package/dist/throttler.d.ts.map +1 -1
  159. package/dist/throttler.js +4 -4
  160. package/dist/throttler.js.map +1 -1
  161. package/lib/batchTracker.d.ts.map +1 -1
  162. package/lib/batchTracker.js +2 -1
  163. package/lib/batchTracker.js.map +1 -1
  164. package/lib/blobManager.d.ts +15 -2
  165. package/lib/blobManager.d.ts.map +1 -1
  166. package/lib/blobManager.js +109 -37
  167. package/lib/blobManager.js.map +1 -1
  168. package/lib/connectionTelemetry.d.ts.map +1 -1
  169. package/lib/connectionTelemetry.js +11 -9
  170. package/lib/connectionTelemetry.js.map +1 -1
  171. package/lib/containerHandleContext.d.ts.map +1 -1
  172. package/lib/containerHandleContext.js +3 -1
  173. package/lib/containerHandleContext.js.map +1 -1
  174. package/lib/containerRuntime.d.ts +23 -11
  175. package/lib/containerRuntime.d.ts.map +1 -1
  176. package/lib/containerRuntime.js +201 -108
  177. package/lib/containerRuntime.js.map +1 -1
  178. package/lib/dataStore.d.ts.map +1 -1
  179. package/lib/dataStore.js +11 -9
  180. package/lib/dataStore.js.map +1 -1
  181. package/lib/dataStoreContext.d.ts +27 -13
  182. package/lib/dataStoreContext.d.ts.map +1 -1
  183. package/lib/dataStoreContext.js +84 -45
  184. package/lib/dataStoreContext.js.map +1 -1
  185. package/lib/dataStoreContexts.d.ts.map +1 -1
  186. package/lib/dataStoreContexts.js +7 -3
  187. package/lib/dataStoreContexts.js.map +1 -1
  188. package/lib/dataStoreRegistry.d.ts.map +1 -1
  189. package/lib/dataStoreRegistry.js +3 -1
  190. package/lib/dataStoreRegistry.js.map +1 -1
  191. package/lib/dataStores.d.ts +28 -4
  192. package/lib/dataStores.d.ts.map +1 -1
  193. package/lib/dataStores.js +120 -42
  194. package/lib/dataStores.js.map +1 -1
  195. package/lib/deltaScheduler.d.ts.map +1 -1
  196. package/lib/deltaScheduler.js +9 -4
  197. package/lib/deltaScheduler.js.map +1 -1
  198. package/lib/{garbageCollection.d.ts → gc/garbageCollection.d.ts} +27 -203
  199. package/lib/gc/garbageCollection.d.ts.map +1 -0
  200. package/lib/{garbageCollection.js → gc/garbageCollection.js} +190 -379
  201. package/lib/gc/garbageCollection.js.map +1 -0
  202. package/lib/gc/gcDefinitions.d.ts +189 -0
  203. package/lib/gc/gcDefinitions.d.ts.map +1 -0
  204. package/lib/{garbageCollectionConstants.js → gc/gcDefinitions.js} +26 -1
  205. package/lib/gc/gcDefinitions.js.map +1 -0
  206. package/lib/gc/gcHelpers.d.ts +30 -0
  207. package/lib/gc/gcHelpers.d.ts.map +1 -0
  208. package/lib/gc/gcHelpers.js +58 -0
  209. package/lib/gc/gcHelpers.js.map +1 -0
  210. package/lib/gc/gcSummaryStateTracker.d.ts +86 -0
  211. package/lib/gc/gcSummaryStateTracker.d.ts.map +1 -0
  212. package/lib/gc/gcSummaryStateTracker.js +242 -0
  213. package/lib/gc/gcSummaryStateTracker.js.map +1 -0
  214. package/{dist → lib/gc}/gcSweepReadyUsageDetection.d.ts +5 -5
  215. package/lib/gc/gcSweepReadyUsageDetection.d.ts.map +1 -0
  216. package/lib/{gcSweepReadyUsageDetection.js → gc/gcSweepReadyUsageDetection.js} +15 -11
  217. package/lib/gc/gcSweepReadyUsageDetection.js.map +1 -0
  218. package/lib/gc/gcUnreferencedStateTracker.d.ts +34 -0
  219. package/lib/gc/gcUnreferencedStateTracker.d.ts.map +1 -0
  220. package/lib/gc/gcUnreferencedStateTracker.js +90 -0
  221. package/lib/gc/gcUnreferencedStateTracker.js.map +1 -0
  222. package/lib/gc/index.d.ts +11 -0
  223. package/lib/gc/index.d.ts.map +1 -0
  224. package/lib/gc/index.js +11 -0
  225. package/lib/gc/index.js.map +1 -0
  226. package/lib/index.d.ts +2 -5
  227. package/lib/index.d.ts.map +1 -1
  228. package/lib/index.js +1 -4
  229. package/lib/index.js.map +1 -1
  230. package/lib/opLifecycle/batchManager.d.ts +2 -13
  231. package/lib/opLifecycle/batchManager.d.ts.map +1 -1
  232. package/lib/opLifecycle/batchManager.js +19 -41
  233. package/lib/opLifecycle/batchManager.js.map +1 -1
  234. package/lib/opLifecycle/definitions.d.ts +4 -0
  235. package/lib/opLifecycle/definitions.d.ts.map +1 -1
  236. package/lib/opLifecycle/definitions.js.map +1 -1
  237. package/lib/opLifecycle/index.d.ts.map +1 -1
  238. package/lib/opLifecycle/index.js.map +1 -1
  239. package/lib/opLifecycle/opCompressor.d.ts.map +1 -1
  240. package/lib/opLifecycle/opCompressor.js +1 -0
  241. package/lib/opLifecycle/opCompressor.js.map +1 -1
  242. package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
  243. package/lib/opLifecycle/opDecompressor.js +5 -2
  244. package/lib/opLifecycle/opDecompressor.js.map +1 -1
  245. package/lib/opLifecycle/opSplitter.d.ts +1 -1
  246. package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
  247. package/lib/opLifecycle/opSplitter.js +25 -14
  248. package/lib/opLifecycle/opSplitter.js.map +1 -1
  249. package/lib/opLifecycle/outbox.d.ts +19 -3
  250. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  251. package/lib/opLifecycle/outbox.js +79 -46
  252. package/lib/opLifecycle/outbox.js.map +1 -1
  253. package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  254. package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
  255. package/lib/opProperties.d.ts.map +1 -1
  256. package/lib/opProperties.js +1 -3
  257. package/lib/opProperties.js.map +1 -1
  258. package/lib/packageVersion.d.ts +1 -1
  259. package/lib/packageVersion.js +1 -1
  260. package/lib/packageVersion.js.map +1 -1
  261. package/lib/pendingStateManager.d.ts +8 -2
  262. package/lib/pendingStateManager.d.ts.map +1 -1
  263. package/lib/pendingStateManager.js +21 -13
  264. package/lib/pendingStateManager.js.map +1 -1
  265. package/lib/scheduleManager.d.ts.map +1 -1
  266. package/lib/scheduleManager.js +3 -2
  267. package/lib/scheduleManager.js.map +1 -1
  268. package/lib/serializedSnapshotStorage.d.ts +2 -2
  269. package/lib/serializedSnapshotStorage.d.ts.map +1 -1
  270. package/lib/serializedSnapshotStorage.js +5 -3
  271. package/lib/serializedSnapshotStorage.js.map +1 -1
  272. package/lib/summary/index.d.ts +17 -0
  273. package/lib/summary/index.d.ts.map +1 -0
  274. package/lib/summary/index.js +16 -0
  275. package/lib/summary/index.js.map +1 -0
  276. package/lib/summary/orderedClientElection.d.ts.map +1 -0
  277. package/lib/{orderedClientElection.js → summary/orderedClientElection.js} +10 -4
  278. package/lib/summary/orderedClientElection.js.map +1 -0
  279. package/lib/summary/runWhileConnectedCoordinator.d.ts.map +1 -0
  280. package/lib/summary/runWhileConnectedCoordinator.js.map +1 -0
  281. package/{dist → lib/summary}/runningSummarizer.d.ts +19 -18
  282. package/lib/summary/runningSummarizer.d.ts.map +1 -0
  283. package/lib/{runningSummarizer.js → summary/runningSummarizer.js} +193 -78
  284. package/lib/summary/runningSummarizer.js.map +1 -0
  285. package/lib/{summarizer.d.ts → summary/summarizer.d.ts} +4 -6
  286. package/lib/summary/summarizer.d.ts.map +1 -0
  287. package/lib/{summarizer.js → summary/summarizer.js} +33 -73
  288. package/lib/summary/summarizer.js.map +1 -0
  289. package/lib/summary/summarizerClientElection.d.ts.map +1 -0
  290. package/lib/summary/summarizerClientElection.js.map +1 -0
  291. package/lib/summary/summarizerHandle.d.ts.map +1 -0
  292. package/lib/summary/summarizerHandle.js.map +1 -0
  293. package/{dist → lib/summary}/summarizerHeuristics.d.ts +1 -1
  294. package/lib/summary/summarizerHeuristics.d.ts.map +1 -0
  295. package/lib/{summarizerHeuristics.js → summary/summarizerHeuristics.js} +6 -9
  296. package/lib/summary/summarizerHeuristics.js.map +1 -0
  297. package/{dist → lib/summary}/summarizerTypes.d.ts +22 -22
  298. package/lib/summary/summarizerTypes.d.ts.map +1 -0
  299. package/lib/summary/summarizerTypes.js.map +1 -0
  300. package/lib/summary/summaryCollection.d.ts.map +1 -0
  301. package/lib/{summaryCollection.js → summary/summaryCollection.js} +18 -8
  302. package/lib/summary/summaryCollection.js.map +1 -0
  303. package/{dist → lib/summary}/summaryFormat.d.ts +1 -40
  304. package/lib/summary/summaryFormat.d.ts.map +1 -0
  305. package/lib/{summaryFormat.js → summary/summaryFormat.js} +20 -20
  306. package/lib/summary/summaryFormat.js.map +1 -0
  307. package/lib/summary/summaryGenerator.d.ts.map +1 -0
  308. package/lib/{summaryGenerator.js → summary/summaryGenerator.js} +33 -15
  309. package/lib/summary/summaryGenerator.js.map +1 -0
  310. package/lib/{summaryManager.d.ts → summary/summaryManager.d.ts} +1 -1
  311. package/lib/summary/summaryManager.d.ts.map +1 -0
  312. package/lib/{summaryManager.js → summary/summaryManager.js} +21 -9
  313. package/lib/summary/summaryManager.js.map +1 -0
  314. package/lib/throttler.d.ts +2 -2
  315. package/lib/throttler.d.ts.map +1 -1
  316. package/lib/throttler.js +4 -4
  317. package/lib/throttler.js.map +1 -1
  318. package/package.json +60 -51
  319. package/prettier.config.cjs +1 -1
  320. package/src/batchTracker.ts +54 -49
  321. package/src/blobManager.ts +825 -674
  322. package/src/connectionTelemetry.ts +280 -249
  323. package/src/containerHandleContext.ts +27 -29
  324. package/src/containerRuntime.ts +3249 -2978
  325. package/src/dataStore.ts +172 -159
  326. package/src/dataStoreContext.ts +1141 -1057
  327. package/src/dataStoreContexts.ts +178 -161
  328. package/src/dataStoreRegistry.ts +25 -20
  329. package/src/dataStores.ts +880 -731
  330. package/src/deltaScheduler.ts +158 -150
  331. package/{garbageCollection.md → src/gc/garbageCollection.md} +16 -3
  332. package/src/gc/garbageCollection.ts +1506 -0
  333. package/src/gc/gcDefinitions.ts +244 -0
  334. package/src/gc/gcHelpers.ts +86 -0
  335. package/src/gc/gcSummaryStateTracker.ts +339 -0
  336. package/src/gc/gcSweepReadyUsageDetection.ts +145 -0
  337. package/src/gc/gcUnreferencedStateTracker.ts +114 -0
  338. package/src/gc/index.ts +40 -0
  339. package/src/index.ts +67 -70
  340. package/src/opLifecycle/README.md +152 -0
  341. package/src/opLifecycle/batchManager.ts +101 -144
  342. package/src/opLifecycle/definitions.ts +33 -29
  343. package/src/opLifecycle/index.ts +5 -5
  344. package/src/opLifecycle/opCompressor.ts +55 -53
  345. package/src/opLifecycle/opDecompressor.ts +100 -81
  346. package/src/opLifecycle/opSplitter.ts +233 -188
  347. package/src/opLifecycle/outbox.ts +251 -195
  348. package/src/opLifecycle/remoteMessageProcessor.ts +62 -62
  349. package/src/opProperties.ts +11 -9
  350. package/src/packageVersion.ts +1 -1
  351. package/src/pendingStateManager.ts +396 -338
  352. package/src/scheduleManager.ts +299 -269
  353. package/src/serializedSnapshotStorage.ts +126 -112
  354. package/src/summary/index.ts +99 -0
  355. package/src/summary/orderedClientElection.ts +564 -0
  356. package/src/summary/runWhileConnectedCoordinator.ts +113 -0
  357. package/src/summary/runningSummarizer.ts +788 -0
  358. package/src/summary/summarizer.ts +386 -0
  359. package/src/summary/summarizerClientElection.ts +139 -0
  360. package/src/{summarizerHandle.ts → summary/summarizerHandle.ts} +11 -9
  361. package/src/summary/summarizerHeuristics.ts +219 -0
  362. package/src/summary/summarizerTypes.ts +521 -0
  363. package/src/summary/summaryCollection.ts +450 -0
  364. package/src/summary/summaryFormat.ts +226 -0
  365. package/src/summary/summaryGenerator.ts +505 -0
  366. package/src/summary/summaryManager.ts +423 -0
  367. package/src/throttler.ts +131 -122
  368. package/tsconfig.esnext.json +6 -6
  369. package/tsconfig.json +9 -13
  370. package/dist/garbageCollection.d.ts.map +0 -1
  371. package/dist/garbageCollection.js.map +0 -1
  372. package/dist/garbageCollectionConstants.d.ts +0 -25
  373. package/dist/garbageCollectionConstants.d.ts.map +0 -1
  374. package/dist/garbageCollectionConstants.js.map +0 -1
  375. package/dist/garbageCollectionTombstoneUtils.d.ts +0 -14
  376. package/dist/garbageCollectionTombstoneUtils.d.ts.map +0 -1
  377. package/dist/garbageCollectionTombstoneUtils.js +0 -23
  378. package/dist/garbageCollectionTombstoneUtils.js.map +0 -1
  379. package/dist/gcSweepReadyUsageDetection.d.ts.map +0 -1
  380. package/dist/gcSweepReadyUsageDetection.js.map +0 -1
  381. package/dist/orderedClientElection.d.ts.map +0 -1
  382. package/dist/orderedClientElection.js.map +0 -1
  383. package/dist/runWhileConnectedCoordinator.d.ts.map +0 -1
  384. package/dist/runWhileConnectedCoordinator.js.map +0 -1
  385. package/dist/runningSummarizer.d.ts.map +0 -1
  386. package/dist/runningSummarizer.js.map +0 -1
  387. package/dist/summarizer.d.ts.map +0 -1
  388. package/dist/summarizer.js.map +0 -1
  389. package/dist/summarizerClientElection.d.ts.map +0 -1
  390. package/dist/summarizerClientElection.js.map +0 -1
  391. package/dist/summarizerHandle.d.ts.map +0 -1
  392. package/dist/summarizerHandle.js.map +0 -1
  393. package/dist/summarizerHeuristics.d.ts.map +0 -1
  394. package/dist/summarizerHeuristics.js.map +0 -1
  395. package/dist/summarizerTypes.d.ts.map +0 -1
  396. package/dist/summarizerTypes.js.map +0 -1
  397. package/dist/summaryCollection.d.ts.map +0 -1
  398. package/dist/summaryCollection.js.map +0 -1
  399. package/dist/summaryFormat.d.ts.map +0 -1
  400. package/dist/summaryFormat.js.map +0 -1
  401. package/dist/summaryGenerator.d.ts.map +0 -1
  402. package/dist/summaryGenerator.js.map +0 -1
  403. package/dist/summaryManager.d.ts.map +0 -1
  404. package/dist/summaryManager.js.map +0 -1
  405. package/lib/garbageCollection.d.ts.map +0 -1
  406. package/lib/garbageCollection.js.map +0 -1
  407. package/lib/garbageCollectionConstants.d.ts +0 -25
  408. package/lib/garbageCollectionConstants.d.ts.map +0 -1
  409. package/lib/garbageCollectionConstants.js.map +0 -1
  410. package/lib/garbageCollectionTombstoneUtils.d.ts +0 -14
  411. package/lib/garbageCollectionTombstoneUtils.d.ts.map +0 -1
  412. package/lib/garbageCollectionTombstoneUtils.js +0 -19
  413. package/lib/garbageCollectionTombstoneUtils.js.map +0 -1
  414. package/lib/gcSweepReadyUsageDetection.d.ts.map +0 -1
  415. package/lib/gcSweepReadyUsageDetection.js.map +0 -1
  416. package/lib/orderedClientElection.d.ts.map +0 -1
  417. package/lib/orderedClientElection.js.map +0 -1
  418. package/lib/runWhileConnectedCoordinator.d.ts.map +0 -1
  419. package/lib/runWhileConnectedCoordinator.js.map +0 -1
  420. package/lib/runningSummarizer.d.ts.map +0 -1
  421. package/lib/runningSummarizer.js.map +0 -1
  422. package/lib/summarizer.d.ts.map +0 -1
  423. package/lib/summarizer.js.map +0 -1
  424. package/lib/summarizerClientElection.d.ts.map +0 -1
  425. package/lib/summarizerClientElection.js.map +0 -1
  426. package/lib/summarizerHandle.d.ts.map +0 -1
  427. package/lib/summarizerHandle.js.map +0 -1
  428. package/lib/summarizerHeuristics.d.ts.map +0 -1
  429. package/lib/summarizerHeuristics.js.map +0 -1
  430. package/lib/summarizerTypes.d.ts.map +0 -1
  431. package/lib/summarizerTypes.js.map +0 -1
  432. package/lib/summaryCollection.d.ts.map +0 -1
  433. package/lib/summaryCollection.js.map +0 -1
  434. package/lib/summaryFormat.d.ts.map +0 -1
  435. package/lib/summaryFormat.js.map +0 -1
  436. package/lib/summaryGenerator.d.ts.map +0 -1
  437. package/lib/summaryGenerator.js.map +0 -1
  438. package/lib/summaryManager.d.ts.map +0 -1
  439. package/lib/summaryManager.js.map +0 -1
  440. package/src/garbageCollection.ts +0 -1800
  441. package/src/garbageCollectionConstants.ts +0 -41
  442. package/src/garbageCollectionTombstoneUtils.ts +0 -28
  443. package/src/gcSweepReadyUsageDetection.ts +0 -139
  444. package/src/orderedClientElection.ts +0 -532
  445. package/src/runWhileConnectedCoordinator.ts +0 -106
  446. package/src/runningSummarizer.ts +0 -610
  447. package/src/summarizer.ts +0 -421
  448. package/src/summarizerClientElection.ts +0 -132
  449. package/src/summarizerHeuristics.ts +0 -222
  450. package/src/summarizerTypes.ts +0 -507
  451. package/src/summaryCollection.ts +0 -421
  452. package/src/summaryFormat.ts +0 -256
  453. package/src/summaryGenerator.ts +0 -450
  454. package/src/summaryManager.ts +0 -394
  455. /package/dist/{orderedClientElection.d.ts → summary/orderedClientElection.d.ts} +0 -0
  456. /package/dist/{runWhileConnectedCoordinator.d.ts → summary/runWhileConnectedCoordinator.d.ts} +0 -0
  457. /package/dist/{runWhileConnectedCoordinator.js → summary/runWhileConnectedCoordinator.js} +0 -0
  458. /package/dist/{summarizerClientElection.d.ts → summary/summarizerClientElection.d.ts} +0 -0
  459. /package/dist/{summarizerClientElection.js → summary/summarizerClientElection.js} +0 -0
  460. /package/dist/{summarizerHandle.d.ts → summary/summarizerHandle.d.ts} +0 -0
  461. /package/dist/{summarizerHandle.js → summary/summarizerHandle.js} +0 -0
  462. /package/dist/{summarizerTypes.js → summary/summarizerTypes.js} +0 -0
  463. /package/dist/{summaryCollection.d.ts → summary/summaryCollection.d.ts} +0 -0
  464. /package/dist/{summaryGenerator.d.ts → summary/summaryGenerator.d.ts} +0 -0
  465. /package/lib/{orderedClientElection.d.ts → summary/orderedClientElection.d.ts} +0 -0
  466. /package/lib/{runWhileConnectedCoordinator.d.ts → summary/runWhileConnectedCoordinator.d.ts} +0 -0
  467. /package/lib/{runWhileConnectedCoordinator.js → summary/runWhileConnectedCoordinator.js} +0 -0
  468. /package/lib/{summarizerClientElection.d.ts → summary/summarizerClientElection.d.ts} +0 -0
  469. /package/lib/{summarizerClientElection.js → summary/summarizerClientElection.js} +0 -0
  470. /package/lib/{summarizerHandle.d.ts → summary/summarizerHandle.d.ts} +0 -0
  471. /package/lib/{summarizerHandle.js → summary/summarizerHandle.js} +0 -0
  472. /package/lib/{summarizerTypes.js → summary/summarizerTypes.js} +0 -0
  473. /package/lib/{summaryCollection.d.ts → summary/summaryCollection.d.ts} +0 -0
  474. /package/lib/{summaryGenerator.d.ts → summary/summaryGenerator.d.ts} +0 -0
@@ -0,0 +1,788 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { IDisposable, ITelemetryLogger } from "@fluidframework/common-definitions";
7
+ import { assert, delay, Deferred, PromiseTimer } from "@fluidframework/common-utils";
8
+ import { UsageError } from "@fluidframework/container-utils";
9
+ import { DriverErrorType } from "@fluidframework/driver-definitions";
10
+ import { isRuntimeMessage } from "@fluidframework/driver-utils";
11
+ import { ISequencedDocumentMessage, MessageType } from "@fluidframework/protocol-definitions";
12
+ import {
13
+ ChildLogger,
14
+ isFluidError,
15
+ loggerToMonitoringContext,
16
+ MonitoringContext,
17
+ } from "@fluidframework/telemetry-utils";
18
+ import { ISummaryConfiguration } from "../containerRuntime";
19
+ import { opSize } from "../opProperties";
20
+ import { SummarizeHeuristicRunner } from "./summarizerHeuristics";
21
+ import {
22
+ IEnqueueSummarizeOptions,
23
+ ISummarizeOptions,
24
+ ISummarizeHeuristicData,
25
+ ISummarizeHeuristicRunner,
26
+ IOnDemandSummarizeOptions,
27
+ EnqueueSummarizeResult,
28
+ SummarizerStopReason,
29
+ ISubmitSummaryOptions,
30
+ SubmitSummaryResult,
31
+ ISummaryCancellationToken,
32
+ ISummarizeResults,
33
+ ISummarizeTelemetryProperties,
34
+ ISummarizerRuntime,
35
+ ISummarizeRunnerTelemetry,
36
+ IRefreshSummaryAckOptions,
37
+ } from "./summarizerTypes";
38
+ import { IAckedSummary, IClientSummaryWatcher, SummaryCollection } from "./summaryCollection";
39
+ import {
40
+ raceTimer,
41
+ SummarizeReason,
42
+ SummarizeResultBuilder,
43
+ SummaryGenerator,
44
+ } from "./summaryGenerator";
45
+
46
+ const maxSummarizeAckWaitTime = 10 * 60 * 1000; // 10 minutes
47
+
48
+ const defaultNumberSummarizationAttempts = 2; // only up to 2 attempts
49
+ /**
50
+ * An instance of RunningSummarizer manages the heuristics for summarizing.
51
+ * Until disposed, the instance of RunningSummarizer can assume that it is
52
+ * in a state of running, meaning it is connected and initialized. It keeps
53
+ * track of summaries that it is generating as they are broadcast and acked/nacked.
54
+ * This object is created and controlled by Summarizer object.
55
+ */
56
+ export class RunningSummarizer implements IDisposable {
57
+ public static async start(
58
+ logger: ITelemetryLogger,
59
+ summaryWatcher: IClientSummaryWatcher,
60
+ configuration: ISummaryConfiguration,
61
+ submitSummaryCallback: (options: ISubmitSummaryOptions) => Promise<SubmitSummaryResult>,
62
+ refreshLatestSummaryAckCallback: (options: IRefreshSummaryAckOptions) => Promise<void>,
63
+ heuristicData: ISummarizeHeuristicData,
64
+ raiseSummarizingError: (errorMessage: string) => void,
65
+ summaryCollection: SummaryCollection,
66
+ cancellationToken: ISummaryCancellationToken,
67
+ stopSummarizerCallback: (reason: SummarizerStopReason) => void,
68
+ runtime: ISummarizerRuntime,
69
+ ): Promise<RunningSummarizer> {
70
+ const summarizer = new RunningSummarizer(
71
+ logger,
72
+ summaryWatcher,
73
+ configuration,
74
+ submitSummaryCallback,
75
+ refreshLatestSummaryAckCallback,
76
+ heuristicData,
77
+ raiseSummarizingError,
78
+ summaryCollection,
79
+ cancellationToken,
80
+ stopSummarizerCallback,
81
+ runtime,
82
+ );
83
+
84
+ // Before doing any heuristics or proceeding with its refreshing, if there is a summary ack received while
85
+ // this summarizer catches up, let's refresh state before proceeding with the summarization.
86
+ const lastAckRefSeq = await summarizer.handleSummaryAck();
87
+
88
+ await summarizer.waitStart();
89
+
90
+ // Handle summary acks asynchronously
91
+ // Note: no exceptions are thrown from processIncomingSummaryAcks handler as it handles all exceptions
92
+ summarizer.processIncomingSummaryAcks(lastAckRefSeq).catch((error) => {
93
+ logger.sendErrorEvent({ eventName: "HandleSummaryAckFatalError" }, error);
94
+ });
95
+
96
+ // Update heuristic counts
97
+ // By the time we get here, there are potentially ops missing from the heuristic summary counts
98
+ // Examples of where this could happen:
99
+ // 1. Op is processed during the time that we are initiating the RunningSummarizer instance but before we
100
+ // listen for the op events (will get missed by the handlers in the current workflow)
101
+ // 2. Op was sequenced after the last time we summarized (op sequence number > summarize ref sequence number)
102
+ const diff =
103
+ runtime.deltaManager.lastSequenceNumber -
104
+ (heuristicData.lastSuccessfulSummary.refSequenceNumber +
105
+ heuristicData.numNonRuntimeOps +
106
+ heuristicData.numRuntimeOps);
107
+ heuristicData.hasMissingOpData = diff > 0;
108
+
109
+ if (heuristicData.hasMissingOpData) {
110
+ // Split the diff 50-50 and increment the counts appropriately
111
+ heuristicData.numNonRuntimeOps += Math.ceil(diff / 2);
112
+ heuristicData.numRuntimeOps += Math.floor(diff / 2);
113
+ }
114
+
115
+ // Update last seq number (in case the handlers haven't processed anything yet)
116
+ heuristicData.lastOpSequenceNumber = runtime.deltaManager.lastSequenceNumber;
117
+
118
+ // Start heuristics
119
+ summarizer.heuristicRunner?.start();
120
+ summarizer.heuristicRunner?.run();
121
+
122
+ return summarizer;
123
+ }
124
+
125
+ public get disposed() {
126
+ return this._disposed;
127
+ }
128
+ private stopping = false;
129
+ private _disposed = false;
130
+ private summarizingLock: Promise<void> | undefined;
131
+ private tryWhileSummarizing = false;
132
+ private readonly pendingAckTimer: PromiseTimer;
133
+ private heuristicRunner?: ISummarizeHeuristicRunner;
134
+ private readonly generator: SummaryGenerator;
135
+ private readonly mc: MonitoringContext;
136
+
137
+ private enqueuedSummary:
138
+ | {
139
+ reason: SummarizeReason;
140
+ afterSequenceNumber: number;
141
+ options: ISummarizeOptions;
142
+ readonly resultsBuilder: SummarizeResultBuilder;
143
+ }
144
+ | undefined;
145
+ private summarizeCount = 0;
146
+ private totalSuccessfulAttempts = 0;
147
+ private initialized = false;
148
+
149
+ private constructor(
150
+ baseLogger: ITelemetryLogger,
151
+ private readonly summaryWatcher: IClientSummaryWatcher,
152
+ private readonly configuration: ISummaryConfiguration,
153
+ private readonly submitSummaryCallback: (
154
+ options: ISubmitSummaryOptions,
155
+ ) => Promise<SubmitSummaryResult>,
156
+ private readonly refreshLatestSummaryAckCallback: (
157
+ options: IRefreshSummaryAckOptions,
158
+ ) => Promise<void>,
159
+ private readonly heuristicData: ISummarizeHeuristicData,
160
+ private readonly raiseSummarizingError: (errorMessage: string) => void,
161
+ private readonly summaryCollection: SummaryCollection,
162
+ private readonly cancellationToken: ISummaryCancellationToken,
163
+ private readonly stopSummarizerCallback: (reason: SummarizerStopReason) => void,
164
+ private readonly runtime: ISummarizerRuntime,
165
+ ) {
166
+ const telemetryProps: ISummarizeRunnerTelemetry = {
167
+ summarizeCount: () => this.summarizeCount,
168
+ summarizerSuccessfulAttempts: () => this.totalSuccessfulAttempts,
169
+ };
170
+
171
+ this.mc = loggerToMonitoringContext(
172
+ ChildLogger.create(baseLogger, "Running", {
173
+ all: telemetryProps,
174
+ }),
175
+ );
176
+
177
+ if (configuration.state !== "disableHeuristics") {
178
+ assert(
179
+ this.configuration.state === "enabled",
180
+ 0x2ea /* "Configuration state should be enabled" */,
181
+ );
182
+ this.heuristicRunner = new SummarizeHeuristicRunner(
183
+ heuristicData,
184
+ this.configuration,
185
+ (reason) => this.trySummarize(reason),
186
+ this.mc.logger,
187
+ );
188
+ }
189
+
190
+ assert(
191
+ this.configuration.state !== "disabled",
192
+ 0x2eb /* "Summary not supported with configuration disabled" */,
193
+ );
194
+
195
+ // Cap the maximum amount of time client will wait for a summarize op ack to maxSummarizeAckWaitTime
196
+ // configuration.maxAckWaitTime is composed from defaults, server values, and runtime overrides
197
+
198
+ const maxAckWaitTime = Math.min(this.configuration.maxAckWaitTime, maxSummarizeAckWaitTime);
199
+
200
+ this.pendingAckTimer = new PromiseTimer(maxAckWaitTime, () => {
201
+ // pre-0.58 error message: summaryAckWaitTimeout
202
+ this.raiseSummarizingError("Pending summary ack not received in time");
203
+ // Note: summarizeCount (from ChildLogger definition) may be 0,
204
+ // since this code path is hit when RunningSummarizer first starts up,
205
+ // before this instance has kicked off a new summarize run.
206
+ this.mc.logger.sendErrorEvent({
207
+ eventName: "SummaryAckWaitTimeout",
208
+ maxAckWaitTime,
209
+ referenceSequenceNumber: this.heuristicData.lastAttempt.refSequenceNumber,
210
+ summarySequenceNumber: this.heuristicData.lastAttempt.summarySequenceNumber,
211
+ timePending: Date.now() - this.heuristicData.lastAttempt.summaryTime,
212
+ });
213
+ });
214
+ // Set up pending ack timeout by op timestamp differences for previous summaries.
215
+ summaryCollection.setPendingAckTimerTimeoutCallback(maxAckWaitTime, () => {
216
+ if (this.pendingAckTimer.hasTimer) {
217
+ this.mc.logger.sendTelemetryEvent({
218
+ eventName: "MissingSummaryAckFoundByOps",
219
+ referenceSequenceNumber: this.heuristicData.lastAttempt.refSequenceNumber,
220
+ summarySequenceNumber: this.heuristicData.lastAttempt.summarySequenceNumber,
221
+ });
222
+ this.pendingAckTimer.clear();
223
+ }
224
+ });
225
+
226
+ this.generator = new SummaryGenerator(
227
+ this.pendingAckTimer,
228
+ this.heuristicData,
229
+ this.submitSummaryCallback,
230
+ this.raiseSummarizingError,
231
+ () => {
232
+ this.totalSuccessfulAttempts++;
233
+ },
234
+ this.summaryWatcher,
235
+ this.mc.logger,
236
+ );
237
+
238
+ // Listen for ops
239
+ this.runtime.deltaManager.on("op", (op) => {
240
+ this.handleOp(op);
241
+ });
242
+ }
243
+
244
+ private async handleSummaryAck(): Promise<number> {
245
+ const lastAck: IAckedSummary | undefined = this.summaryCollection.latestAck;
246
+ let refSequenceNumber = -1;
247
+ // In case we haven't received the lastestAck yet, just return.
248
+ if (lastAck !== undefined) {
249
+ refSequenceNumber = lastAck.summaryOp.referenceSequenceNumber;
250
+ const summaryLogger = this.tryGetCorrelatedLogger(refSequenceNumber) ?? this.mc.logger;
251
+ try {
252
+ const summaryOpHandle = lastAck.summaryOp.contents.handle;
253
+ const summaryAckHandle = lastAck.summaryAck.contents.handle;
254
+ while (this.summarizingLock !== undefined) {
255
+ summaryLogger.sendTelemetryEvent({
256
+ eventName: "RefreshAttemptWithSummarizerRunning",
257
+ referenceSequenceNumber: refSequenceNumber,
258
+ proposalHandle: summaryOpHandle,
259
+ ackHandle: summaryAckHandle,
260
+ });
261
+ await this.summarizingLock;
262
+ }
263
+
264
+ // Make sure we block any summarizer from being executed/enqueued while
265
+ // executing the refreshLatestSummaryAck.
266
+ // https://dev.azure.com/fluidframework/internal/_workitems/edit/779
267
+ await this.lockedSummaryAction(
268
+ () => {},
269
+ async () =>
270
+ this.refreshLatestSummaryAckCallback({
271
+ proposalHandle: summaryOpHandle,
272
+ ackHandle: summaryAckHandle,
273
+ summaryRefSeq: refSequenceNumber,
274
+ summaryLogger,
275
+ }).catch(async (error) => {
276
+ // If the error is 404, so maybe the fetched version no longer exists on server. We just
277
+ // ignore this error in that case, as that means we will have another summaryAck for the
278
+ // latest version with which we will refresh the state. However in case of single commit
279
+ // summary, we might me missing a summary ack, so in that case we are still fine as the
280
+ // code in `submitSummary` function in container runtime, will refresh the latest state
281
+ // by calling `refreshLatestSummaryAckFromServer` and we will be fine.
282
+ if (
283
+ isFluidError(error) &&
284
+ error.errorType === DriverErrorType.fileNotFoundOrAccessDeniedError
285
+ ) {
286
+ summaryLogger.sendTelemetryEvent(
287
+ {
288
+ eventName: "HandleSummaryAckErrorIgnored",
289
+ referenceSequenceNumber: refSequenceNumber,
290
+ proposalHandle: summaryOpHandle,
291
+ ackHandle: summaryAckHandle,
292
+ },
293
+ error,
294
+ );
295
+ } else {
296
+ throw error;
297
+ }
298
+ }),
299
+ () => {},
300
+ );
301
+ } catch (error) {
302
+ summaryLogger.sendErrorEvent(
303
+ {
304
+ eventName: "HandleLastSummaryAckError",
305
+ referenceSequenceNumber: refSequenceNumber,
306
+ handle: lastAck?.summaryOp?.contents?.handle,
307
+ ackHandle: lastAck?.summaryAck?.contents?.handle,
308
+ },
309
+ error,
310
+ );
311
+ }
312
+ refSequenceNumber++;
313
+ }
314
+ return refSequenceNumber;
315
+ }
316
+
317
+ /**
318
+ * Responsible for receiving and processing all the summaryAcks.
319
+ * In case there was a summary ack processed by the running summarizer before processIncomingSummaryAcks is called,
320
+ * it will wait for the summary ack that is newer than the one indicated by the lastAckRefSeq.
321
+ * @param lastAckRefSeq - Identifies the minimum reference sequence number the summarizer needs to wait for.
322
+ * In case of a negative number, the summarizer will wait for ANY summary ack that is greater than the deltaManager's initial sequence number,
323
+ * and, in case of a positive one, it will wait for a summary ack that is greater than this current reference sequence number.
324
+ */
325
+ private async processIncomingSummaryAcks(lastAckRefSeq: number) {
326
+ let refSequenceNumber =
327
+ lastAckRefSeq > 0 ? lastAckRefSeq : this.runtime.deltaManager.initialSequenceNumber;
328
+ while (!this.disposed) {
329
+ const summaryLogger = this.tryGetCorrelatedLogger(refSequenceNumber) ?? this.mc.logger;
330
+
331
+ // Initialize ack with undefined if exception happens inside of waitSummaryAck on second iteration,
332
+ // we record undefined, not previous handles.
333
+ await this.summaryCollection.waitSummaryAck(refSequenceNumber);
334
+
335
+ summaryLogger.sendTelemetryEvent({
336
+ eventName: "processIncomingSummaryAcks",
337
+ referenceSequenceNumber: refSequenceNumber,
338
+ lastAckRefSeq,
339
+ });
340
+
341
+ refSequenceNumber = await this.handleSummaryAck();
342
+ // A valid Summary Ack must have been processed.
343
+ assert(refSequenceNumber >= 0, 0x58f /* Invalid ref sequence number */);
344
+ }
345
+ }
346
+
347
+ public dispose(): void {
348
+ this.runtime.deltaManager.off("op", (op) => {
349
+ this.handleOp(op);
350
+ });
351
+ this.summaryWatcher.dispose();
352
+ this.heuristicRunner?.dispose();
353
+ this.heuristicRunner = undefined;
354
+ this.generator.dispose();
355
+ this.pendingAckTimer.clear();
356
+ this.disposeEnqueuedSummary();
357
+ this._disposed = true;
358
+ this.stopping = true;
359
+ }
360
+
361
+ /**
362
+ * RunningSummarizer's logger includes the sequenced index of the current summary on each event.
363
+ * If some other Summarizer code wants that event on their logs they can get it here,
364
+ * but only if they're logging about that same summary.
365
+ * @param summaryOpRefSeq - RefSeq number of the summary op, to ensure the log correlation will be correct
366
+ */
367
+ public tryGetCorrelatedLogger = (summaryOpRefSeq) =>
368
+ this.heuristicData.lastAttempt.refSequenceNumber === summaryOpRefSeq
369
+ ? this.mc.logger
370
+ : undefined;
371
+
372
+ /** We only want a single heuristic runner micro-task (will provide better optimized grouping of ops) */
373
+ private heuristicRunnerMicroTaskExists = false;
374
+
375
+ public handleOp(op: ISequencedDocumentMessage) {
376
+ this.heuristicData.lastOpSequenceNumber = op.sequenceNumber;
377
+
378
+ if (isRuntimeMessage(op)) {
379
+ this.heuristicData.numRuntimeOps++;
380
+ } else {
381
+ this.heuristicData.numNonRuntimeOps++;
382
+ }
383
+
384
+ this.heuristicData.totalOpsSize += opSize(op);
385
+
386
+ // Check for enqueued on-demand summaries; Intentionally do nothing otherwise
387
+ if (
388
+ this.initialized &&
389
+ this.opCanTriggerSummary(op) &&
390
+ !this.tryRunEnqueuedSummary() &&
391
+ !this.heuristicRunnerMicroTaskExists
392
+ ) {
393
+ this.heuristicRunnerMicroTaskExists = true;
394
+ Promise.resolve()
395
+ .then(() => {
396
+ this.heuristicRunner?.run();
397
+ })
398
+ .finally(() => {
399
+ this.heuristicRunnerMicroTaskExists = false;
400
+ });
401
+ }
402
+ }
403
+
404
+ /**
405
+ * Can the given op trigger a summary?
406
+ * # Currently always prevents summaries for Summarize and SummaryAck/Nack ops
407
+ * @param op - op to check
408
+ * @returns true if this op can trigger a summary
409
+ */
410
+ private opCanTriggerSummary(op: ISequencedDocumentMessage): boolean {
411
+ switch (op.type) {
412
+ case MessageType.Summarize:
413
+ case MessageType.SummaryAck:
414
+ case MessageType.SummaryNack:
415
+ return false;
416
+ default:
417
+ return isRuntimeMessage(op) || this.nonRuntimeOpCanTriggerSummary();
418
+ }
419
+ }
420
+
421
+ private nonRuntimeOpCanTriggerSummary(): boolean {
422
+ const opsSinceLastAck =
423
+ this.heuristicData.lastOpSequenceNumber -
424
+ this.heuristicData.lastSuccessfulSummary.refSequenceNumber;
425
+ return (
426
+ this.configuration.state === "enabled" &&
427
+ (this.configuration.nonRuntimeHeuristicThreshold === undefined ||
428
+ this.configuration.nonRuntimeHeuristicThreshold <= opsSinceLastAck)
429
+ );
430
+ }
431
+
432
+ public async waitStop(allowLastSummary: boolean): Promise<void> {
433
+ if (this.stopping) {
434
+ return;
435
+ }
436
+
437
+ this.stopping = true;
438
+
439
+ this.disposeEnqueuedSummary();
440
+
441
+ // This will try to run lastSummary if needed.
442
+ if (allowLastSummary && this.heuristicRunner?.shouldRunLastSummary()) {
443
+ if (this.summarizingLock === undefined) {
444
+ this.trySummarizeOnce(
445
+ // summarizeProps
446
+ { reason: "lastSummary" },
447
+ // ISummarizeOptions, using defaults: { refreshLatestAck: false, fullTree: false }
448
+ {},
449
+ );
450
+ }
451
+ }
452
+
453
+ // Note that trySummarizeOnce() call above returns right away, without waiting.
454
+ // So we need to wait for its completion, otherwise it would be destroyed right away.
455
+ // That said, if summary lock was taken upfront, this wait might wait on multiple retries to
456
+ // submit summary. We should reconsider this flow and make summarizer move to exit faster.
457
+ // This resolves when the current pending summary gets an ack or fails.
458
+ await this.summarizingLock;
459
+ }
460
+
461
+ private async waitStart() {
462
+ // Wait no longer than ack timeout for all pending
463
+ const waitStartResult = await raceTimer(
464
+ this.summaryWatcher.waitFlushed(),
465
+ this.pendingAckTimer.start(),
466
+ );
467
+ this.pendingAckTimer.clear();
468
+
469
+ // Remove pending ack wait timeout by op timestamp comparison, because
470
+ // it has race conditions with summaries submitted by this same client.
471
+ this.summaryCollection.unsetPendingAckTimerTimeoutCallback();
472
+
473
+ if (waitStartResult.result === "done" && waitStartResult.value !== undefined) {
474
+ this.heuristicData.updateWithLastSummaryAckInfo({
475
+ refSequenceNumber: waitStartResult.value.summaryOp.referenceSequenceNumber,
476
+ // This will be the Summarizer starting point so only use timestamps from client's machine.
477
+ summaryTime: Date.now(),
478
+ summarySequenceNumber: waitStartResult.value.summaryOp.sequenceNumber,
479
+ });
480
+ }
481
+ this.initialized = true;
482
+ }
483
+
484
+ private beforeSummaryAction() {
485
+ this.summarizeCount++;
486
+ }
487
+
488
+ private afterSummaryAction() {
489
+ const retry = this.tryWhileSummarizing;
490
+ this.tryWhileSummarizing = false;
491
+
492
+ // After summarizing, we should check to see if we need to summarize again.
493
+ // Rerun the heuristics and check for enqueued summaries.
494
+ if (!this.stopping && !this.tryRunEnqueuedSummary() && retry) {
495
+ this.heuristicRunner?.run();
496
+ }
497
+ }
498
+
499
+ /**
500
+ * Runs single summary action that prevents any other concurrent actions.
501
+ * Assumes that caller checked upfront for lack of concurrent action (this.summarizingLock)
502
+ * before calling this API. I.e. caller is responsible for either erroring out or waiting on this promise.
503
+ * @param before - set of instructions to run before running the action.
504
+ * @param action - action to perform.
505
+ * @param after - set of instructions to run after running the action.
506
+ * @returns - result of action.
507
+ */
508
+ private async lockedSummaryAction<T>(
509
+ before: () => void,
510
+ action: () => Promise<T>,
511
+ after: () => void,
512
+ ) {
513
+ assert(
514
+ this.summarizingLock === undefined,
515
+ 0x25b /* "Caller is responsible for checking lock" */,
516
+ );
517
+
518
+ const summarizingLock = new Deferred<void>();
519
+ this.summarizingLock = summarizingLock.promise;
520
+
521
+ before();
522
+
523
+ return action().finally(() => {
524
+ summarizingLock.resolve();
525
+ this.summarizingLock = undefined;
526
+ after();
527
+ });
528
+ }
529
+
530
+ /**
531
+ * Runs single summarize attempt
532
+ * @param summarizeProps - props to log with each telemetry event associated with this attempt
533
+ * @param options - summary options
534
+ * @param cancellationToken - cancellation token to use to be able to cancel this summary, if needed
535
+ * @param resultsBuilder - optional, result builder to use.
536
+ * @returns ISummarizeResult - result of running a summary.
537
+ */
538
+ private trySummarizeOnce(
539
+ summarizeProps: ISummarizeTelemetryProperties,
540
+ options: ISummarizeOptions,
541
+ cancellationToken = this.cancellationToken,
542
+ resultsBuilder = new SummarizeResultBuilder(),
543
+ ): ISummarizeResults {
544
+ this.lockedSummaryAction(
545
+ () => {
546
+ this.beforeSummaryAction();
547
+ },
548
+ async () => {
549
+ const summarizeResult = this.generator.summarize(
550
+ summarizeProps,
551
+ options,
552
+ cancellationToken,
553
+ resultsBuilder,
554
+ );
555
+ // ensure we wait till the end of the process
556
+ return summarizeResult.receivedSummaryAckOrNack;
557
+ },
558
+ () => {
559
+ this.afterSummaryAction();
560
+ },
561
+ ).catch((error) => {
562
+ // SummaryGenerator.summarize() does not throw exceptions - it converts them to failed result
563
+ // on resultsBuilder
564
+ // We do not care about exceptions on receivedSummaryAckOrNack - caller should check results
565
+ // and take a appropriate action.
566
+ });
567
+
568
+ return resultsBuilder.build();
569
+ }
570
+
571
+ /** Heuristics summarize attempt. */
572
+ private trySummarize(
573
+ reason: SummarizeReason,
574
+ cancellationToken = this.cancellationToken,
575
+ ): void {
576
+ if (this.summarizingLock !== undefined) {
577
+ // lockedSummaryAction() will retry heuristic-based summary at the end of current attempt
578
+ // if it's still needed
579
+ this.tryWhileSummarizing = true;
580
+ return;
581
+ }
582
+
583
+ this.lockedSummaryAction(
584
+ () => {
585
+ this.beforeSummaryAction();
586
+ },
587
+ async () => {
588
+ const attempts: (ISummarizeOptions & { delaySeconds?: number })[] = [
589
+ { refreshLatestAck: false, fullTree: false },
590
+ { refreshLatestAck: true, fullTree: false },
591
+ { refreshLatestAck: true, fullTree: false, delaySeconds: 2 * 60 },
592
+ { refreshLatestAck: true, fullTree: true, delaySeconds: 10 * 60 },
593
+ ];
594
+ let overrideDelaySeconds: number | undefined;
595
+ let summaryAttempts = 0;
596
+ let summaryAttemptsPerPhase = 0;
597
+ // Reducing the default number of attempts to defaultNumberofSummarizationAttempts.
598
+ let totalAttempts =
599
+ this.mc.config.getNumber("Fluid.Summarizer.Attempts") ??
600
+ defaultNumberSummarizationAttempts;
601
+
602
+ if (totalAttempts > attempts.length) {
603
+ this.mc.logger.sendTelemetryEvent({
604
+ eventName: "InvalidSummarizerAttempts",
605
+ attempts: totalAttempts,
606
+ });
607
+ totalAttempts = defaultNumberSummarizationAttempts;
608
+ } else if (totalAttempts < 1) {
609
+ throw new UsageError("Invalid number of attempts.");
610
+ }
611
+
612
+ let lastResult: { message: string; error: any } | undefined;
613
+
614
+ for (let summaryAttemptPhase = 0; summaryAttemptPhase < totalAttempts; ) {
615
+ if (this.cancellationToken.cancelled) {
616
+ return;
617
+ }
618
+
619
+ // We only want to attempt 1 summary when reason is "lastSummary"
620
+ if (++summaryAttempts > 1 && reason === "lastSummary") {
621
+ return;
622
+ }
623
+
624
+ summaryAttemptsPerPhase++;
625
+
626
+ const { delaySeconds: regularDelaySeconds = 0, ...options } =
627
+ attempts[summaryAttemptPhase];
628
+
629
+ const summarizeProps: ISummarizeTelemetryProperties = {
630
+ reason,
631
+ summaryAttempts,
632
+ summaryAttemptsPerPhase,
633
+ summaryAttemptPhase: summaryAttemptPhase + 1, // make everything 1-based
634
+ ...options,
635
+ };
636
+
637
+ // Note: no need to account for cancellationToken.waitCancelled here, as
638
+ // this is accounted SummaryGenerator.summarizeCore that controls receivedSummaryAckOrNack.
639
+ const resultSummarize = this.generator.summarize(
640
+ summarizeProps,
641
+ options,
642
+ cancellationToken,
643
+ );
644
+ const result = await resultSummarize.receivedSummaryAckOrNack;
645
+
646
+ if (result.success) {
647
+ return;
648
+ }
649
+ // Check for retryDelay that can come from summaryNack or upload summary flow.
650
+ // Retry the same step only once per retryAfter response.
651
+ overrideDelaySeconds = result.retryAfterSeconds;
652
+ if (overrideDelaySeconds === undefined || summaryAttemptsPerPhase > 1) {
653
+ summaryAttemptPhase++;
654
+ summaryAttemptsPerPhase = 0;
655
+ }
656
+ lastResult = result;
657
+
658
+ const delaySeconds = overrideDelaySeconds ?? regularDelaySeconds;
659
+
660
+ if (delaySeconds > 0) {
661
+ this.mc.logger.sendPerformanceEvent({
662
+ eventName: "SummarizeAttemptDelay",
663
+ duration: delaySeconds,
664
+ summaryNackDelay: overrideDelaySeconds !== undefined,
665
+ ...summarizeProps,
666
+ });
667
+ await delay(delaySeconds * 1000);
668
+ }
669
+ }
670
+
671
+ // If all attempts failed, log error (with last attempt info) and close the summarizer container
672
+ this.mc.logger.sendErrorEvent(
673
+ {
674
+ eventName: "FailToSummarize",
675
+ reason,
676
+ message: lastResult?.message,
677
+ },
678
+ lastResult?.error,
679
+ );
680
+
681
+ this.stopSummarizerCallback("failToSummarize");
682
+ },
683
+ () => {
684
+ this.afterSummaryAction();
685
+ },
686
+ ).catch((error) => {
687
+ this.mc.logger.sendErrorEvent({ eventName: "UnexpectedSummarizeError" }, error);
688
+ });
689
+ }
690
+
691
+ /** {@inheritdoc (ISummarizer:interface).summarizeOnDemand} */
692
+ public summarizeOnDemand(
693
+ resultsBuilder: SummarizeResultBuilder = new SummarizeResultBuilder(),
694
+ { reason, ...options }: IOnDemandSummarizeOptions,
695
+ ): ISummarizeResults {
696
+ if (this.stopping) {
697
+ resultsBuilder.fail("RunningSummarizer stopped or disposed", undefined);
698
+ return resultsBuilder.build();
699
+ }
700
+ // Check for concurrent summary attempts. If one is found,
701
+ // return a promise that caller can await before trying again.
702
+ if (this.summarizingLock !== undefined) {
703
+ // The heuristics are blocking concurrent summarize attempts.
704
+ throw new UsageError("Attempted to run an already-running summarizer on demand");
705
+ }
706
+
707
+ const result = this.trySummarizeOnce(
708
+ { reason: `onDemand/${reason}` },
709
+ options,
710
+ this.cancellationToken,
711
+ resultsBuilder,
712
+ );
713
+ return result;
714
+ }
715
+
716
+ /** {@inheritdoc (ISummarizer:interface).enqueueSummarize} */
717
+ public enqueueSummarize({
718
+ reason,
719
+ afterSequenceNumber = 0,
720
+ override = false,
721
+ ...options
722
+ }: IEnqueueSummarizeOptions): EnqueueSummarizeResult {
723
+ const onDemandReason = `enqueue;${reason}` as const;
724
+ let overridden = false;
725
+ if (this.enqueuedSummary !== undefined) {
726
+ if (!override) {
727
+ return { alreadyEnqueued: true };
728
+ }
729
+ // Override existing enqueued summarize attempt.
730
+ this.enqueuedSummary.resultsBuilder.fail(
731
+ "Aborted; overridden by another enqueue summarize attempt",
732
+ undefined,
733
+ );
734
+ this.enqueuedSummary = undefined;
735
+ overridden = true;
736
+ }
737
+ this.enqueuedSummary = {
738
+ reason: onDemandReason,
739
+ afterSequenceNumber,
740
+ options,
741
+ resultsBuilder: new SummarizeResultBuilder(),
742
+ };
743
+ const results = this.enqueuedSummary.resultsBuilder.build();
744
+ this.tryRunEnqueuedSummary();
745
+ return overridden
746
+ ? {
747
+ ...results,
748
+ alreadyEnqueued: true,
749
+ overridden: true,
750
+ }
751
+ : results;
752
+ }
753
+
754
+ private tryRunEnqueuedSummary() {
755
+ if (this.stopping) {
756
+ this.disposeEnqueuedSummary();
757
+ return false;
758
+ }
759
+ if (
760
+ this.enqueuedSummary === undefined ||
761
+ this.heuristicData.lastOpSequenceNumber < this.enqueuedSummary.afterSequenceNumber ||
762
+ this.summarizingLock !== undefined
763
+ ) {
764
+ // If no enqueued summary is ready or a summary is already in progress, take no action.
765
+ return false;
766
+ }
767
+ const { reason, resultsBuilder, options } = this.enqueuedSummary;
768
+ // Set to undefined first, so that subsequent enqueue attempt while summarize will occur later.
769
+ this.enqueuedSummary = undefined;
770
+ this.trySummarizeOnce(
771
+ { reason: `enqueuedSummary/${reason}` },
772
+ options,
773
+ this.cancellationToken,
774
+ resultsBuilder,
775
+ );
776
+ return true;
777
+ }
778
+
779
+ private disposeEnqueuedSummary() {
780
+ if (this.enqueuedSummary !== undefined) {
781
+ this.enqueuedSummary.resultsBuilder.fail(
782
+ "RunningSummarizer stopped or disposed",
783
+ undefined,
784
+ );
785
+ this.enqueuedSummary = undefined;
786
+ }
787
+ }
788
+ }