@fluidframework/container-runtime 2.0.0-dev-rc.5.0.0.268409 → 2.0.0-dev-rc.5.0.0.270401

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 (305) hide show
  1. package/api-report/container-runtime.alpha.api.md +3 -8
  2. package/api-report/container-runtime.beta.api.md +2 -2
  3. package/api-report/container-runtime.public.api.md +2 -2
  4. package/container-runtime.test-files.tar +0 -0
  5. package/dist/batchTracker.js +5 -1
  6. package/dist/batchTracker.js.map +1 -1
  7. package/dist/blobManager.d.ts +1 -18
  8. package/dist/blobManager.d.ts.map +1 -1
  9. package/dist/blobManager.js +39 -48
  10. package/dist/blobManager.js.map +1 -1
  11. package/dist/channelCollection.d.ts +2 -11
  12. package/dist/channelCollection.d.ts.map +1 -1
  13. package/dist/channelCollection.js +33 -48
  14. package/dist/channelCollection.js.map +1 -1
  15. package/dist/connectionTelemetry.d.ts +1 -2
  16. package/dist/connectionTelemetry.d.ts.map +1 -1
  17. package/dist/connectionTelemetry.js +32 -14
  18. package/dist/connectionTelemetry.js.map +1 -1
  19. package/dist/containerHandleContext.js +4 -0
  20. package/dist/containerHandleContext.js.map +1 -1
  21. package/dist/containerRuntime.d.ts +7 -18
  22. package/dist/containerRuntime.d.ts.map +1 -1
  23. package/dist/containerRuntime.js +145 -43
  24. package/dist/containerRuntime.js.map +1 -1
  25. package/dist/dataStore.js +9 -1
  26. package/dist/dataStore.js.map +1 -1
  27. package/dist/dataStoreContext.d.ts +2 -16
  28. package/dist/dataStoreContext.d.ts.map +1 -1
  29. package/dist/dataStoreContext.js +142 -120
  30. package/dist/dataStoreContext.js.map +1 -1
  31. package/dist/dataStoreContexts.js +29 -28
  32. package/dist/dataStoreContexts.js.map +1 -1
  33. package/dist/dataStoreRegistry.js +1 -0
  34. package/dist/dataStoreRegistry.js.map +1 -1
  35. package/dist/deltaManagerProxies.d.ts +4 -4
  36. package/dist/deltaManagerProxies.d.ts.map +1 -1
  37. package/dist/deltaManagerProxies.js +33 -28
  38. package/dist/deltaManagerProxies.js.map +1 -1
  39. package/dist/deltaScheduler.d.ts +1 -2
  40. package/dist/deltaScheduler.d.ts.map +1 -1
  41. package/dist/deltaScheduler.js +13 -9
  42. package/dist/deltaScheduler.js.map +1 -1
  43. package/dist/error.js +2 -1
  44. package/dist/error.js.map +1 -1
  45. package/dist/gc/garbageCollection.d.ts.map +1 -1
  46. package/dist/gc/garbageCollection.js +37 -17
  47. package/dist/gc/garbageCollection.js.map +1 -1
  48. package/dist/gc/gcDefinitions.d.ts +0 -4
  49. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  50. package/dist/gc/gcDefinitions.js +1 -3
  51. package/dist/gc/gcDefinitions.js.map +1 -1
  52. package/dist/gc/gcSummaryStateTracker.js +19 -14
  53. package/dist/gc/gcSummaryStateTracker.js.map +1 -1
  54. package/dist/gc/gcTelemetry.js +12 -5
  55. package/dist/gc/gcTelemetry.js.map +1 -1
  56. package/dist/gc/gcUnreferencedStateTracker.js +12 -1
  57. package/dist/gc/gcUnreferencedStateTracker.js.map +1 -1
  58. package/dist/gc/index.d.ts +1 -1
  59. package/dist/gc/index.d.ts.map +1 -1
  60. package/dist/gc/index.js +1 -2
  61. package/dist/gc/index.js.map +1 -1
  62. package/dist/messageTypes.d.ts +1 -1
  63. package/dist/messageTypes.d.ts.map +1 -1
  64. package/dist/messageTypes.js.map +1 -1
  65. package/dist/opLifecycle/batchManager.js +5 -3
  66. package/dist/opLifecycle/batchManager.js.map +1 -1
  67. package/dist/opLifecycle/opCompressor.js +1 -0
  68. package/dist/opLifecycle/opCompressor.js.map +1 -1
  69. package/dist/opLifecycle/opDecompressor.d.ts +1 -1
  70. package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
  71. package/dist/opLifecycle/opDecompressor.js +6 -4
  72. package/dist/opLifecycle/opDecompressor.js.map +1 -1
  73. package/dist/opLifecycle/opGroupingManager.d.ts +1 -1
  74. package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
  75. package/dist/opLifecycle/opGroupingManager.js +3 -1
  76. package/dist/opLifecycle/opGroupingManager.js.map +1 -1
  77. package/dist/opLifecycle/opSplitter.d.ts +1 -1
  78. package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
  79. package/dist/opLifecycle/opSplitter.js +6 -0
  80. package/dist/opLifecycle/opSplitter.js.map +1 -1
  81. package/dist/opLifecycle/outbox.js +15 -10
  82. package/dist/opLifecycle/outbox.js.map +1 -1
  83. package/dist/opLifecycle/remoteMessageProcessor.d.ts +1 -1
  84. package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  85. package/dist/opLifecycle/remoteMessageProcessor.js +3 -0
  86. package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
  87. package/dist/opProperties.d.ts +1 -1
  88. package/dist/opProperties.d.ts.map +1 -1
  89. package/dist/opProperties.js.map +1 -1
  90. package/dist/packageVersion.d.ts +1 -1
  91. package/dist/packageVersion.js +1 -1
  92. package/dist/packageVersion.js.map +1 -1
  93. package/dist/pendingStateManager.d.ts.map +1 -1
  94. package/dist/pendingStateManager.js +34 -18
  95. package/dist/pendingStateManager.js.map +1 -1
  96. package/dist/scheduleManager.d.ts +1 -2
  97. package/dist/scheduleManager.d.ts.map +1 -1
  98. package/dist/scheduleManager.js +15 -4
  99. package/dist/scheduleManager.js.map +1 -1
  100. package/dist/storageServiceWithAttachBlobs.js +1 -0
  101. package/dist/storageServiceWithAttachBlobs.js.map +1 -1
  102. package/dist/summary/documentSchema.js +17 -1
  103. package/dist/summary/documentSchema.js.map +1 -1
  104. package/dist/summary/orderedClientElection.js +19 -11
  105. package/dist/summary/orderedClientElection.js.map +1 -1
  106. package/dist/summary/runWhileConnectedCoordinator.js +4 -2
  107. package/dist/summary/runWhileConnectedCoordinator.js.map +1 -1
  108. package/dist/summary/runningSummarizer.d.ts +1 -1
  109. package/dist/summary/runningSummarizer.d.ts.map +1 -1
  110. package/dist/summary/runningSummarizer.js +56 -38
  111. package/dist/summary/runningSummarizer.js.map +1 -1
  112. package/dist/summary/summarizer.js +17 -8
  113. package/dist/summary/summarizer.js.map +1 -1
  114. package/dist/summary/summarizerClientElection.js +18 -7
  115. package/dist/summary/summarizerClientElection.js.map +1 -1
  116. package/dist/summary/summarizerHeuristics.js +30 -25
  117. package/dist/summary/summarizerHeuristics.js.map +1 -1
  118. package/dist/summary/summarizerNode/summarizerNode.d.ts +1 -2
  119. package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
  120. package/dist/summary/summarizerNode/summarizerNode.js +12 -3
  121. package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
  122. package/dist/summary/summarizerNode/summarizerNodeUtils.js +2 -0
  123. package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  124. package/dist/summary/summarizerNode/summarizerNodeWithGc.js +20 -6
  125. package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  126. package/dist/summary/summarizerTypes.d.ts +2 -2
  127. package/dist/summary/summarizerTypes.d.ts.map +1 -1
  128. package/dist/summary/summarizerTypes.js.map +1 -1
  129. package/dist/summary/summaryCollection.d.ts +1 -2
  130. package/dist/summary/summaryCollection.d.ts.map +1 -1
  131. package/dist/summary/summaryCollection.js +23 -11
  132. package/dist/summary/summaryCollection.js.map +1 -1
  133. package/dist/summary/summaryFormat.d.ts +1 -2
  134. package/dist/summary/summaryFormat.d.ts.map +1 -1
  135. package/dist/summary/summaryFormat.js.map +1 -1
  136. package/dist/summary/summaryGenerator.js +12 -5
  137. package/dist/summary/summaryGenerator.js.map +1 -1
  138. package/dist/summary/summaryManager.js +58 -48
  139. package/dist/summary/summaryManager.js.map +1 -1
  140. package/dist/throttler.js +4 -1
  141. package/dist/throttler.js.map +1 -1
  142. package/lib/batchTracker.js +5 -1
  143. package/lib/batchTracker.js.map +1 -1
  144. package/lib/blobManager.d.ts +1 -18
  145. package/lib/blobManager.d.ts.map +1 -1
  146. package/lib/blobManager.js +39 -48
  147. package/lib/blobManager.js.map +1 -1
  148. package/lib/channelCollection.d.ts +2 -11
  149. package/lib/channelCollection.d.ts.map +1 -1
  150. package/lib/channelCollection.js +34 -49
  151. package/lib/channelCollection.js.map +1 -1
  152. package/lib/connectionTelemetry.d.ts +1 -2
  153. package/lib/connectionTelemetry.d.ts.map +1 -1
  154. package/lib/connectionTelemetry.js +33 -15
  155. package/lib/connectionTelemetry.js.map +1 -1
  156. package/lib/containerHandleContext.js +4 -0
  157. package/lib/containerHandleContext.js.map +1 -1
  158. package/lib/containerRuntime.d.ts +7 -18
  159. package/lib/containerRuntime.d.ts.map +1 -1
  160. package/lib/containerRuntime.js +145 -43
  161. package/lib/containerRuntime.js.map +1 -1
  162. package/lib/dataStore.js +9 -1
  163. package/lib/dataStore.js.map +1 -1
  164. package/lib/dataStoreContext.d.ts +2 -16
  165. package/lib/dataStoreContext.d.ts.map +1 -1
  166. package/lib/dataStoreContext.js +144 -122
  167. package/lib/dataStoreContext.js.map +1 -1
  168. package/lib/dataStoreContexts.js +29 -28
  169. package/lib/dataStoreContexts.js.map +1 -1
  170. package/lib/dataStoreRegistry.js +1 -0
  171. package/lib/dataStoreRegistry.js.map +1 -1
  172. package/lib/deltaManagerProxies.d.ts +4 -4
  173. package/lib/deltaManagerProxies.d.ts.map +1 -1
  174. package/lib/deltaManagerProxies.js +33 -28
  175. package/lib/deltaManagerProxies.js.map +1 -1
  176. package/lib/deltaScheduler.d.ts +1 -2
  177. package/lib/deltaScheduler.d.ts.map +1 -1
  178. package/lib/deltaScheduler.js +13 -9
  179. package/lib/deltaScheduler.js.map +1 -1
  180. package/lib/error.js +2 -1
  181. package/lib/error.js.map +1 -1
  182. package/lib/gc/garbageCollection.d.ts.map +1 -1
  183. package/lib/gc/garbageCollection.js +37 -17
  184. package/lib/gc/garbageCollection.js.map +1 -1
  185. package/lib/gc/gcDefinitions.d.ts +0 -4
  186. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  187. package/lib/gc/gcDefinitions.js +0 -2
  188. package/lib/gc/gcDefinitions.js.map +1 -1
  189. package/lib/gc/gcSummaryStateTracker.js +19 -14
  190. package/lib/gc/gcSummaryStateTracker.js.map +1 -1
  191. package/lib/gc/gcTelemetry.js +12 -5
  192. package/lib/gc/gcTelemetry.js.map +1 -1
  193. package/lib/gc/gcUnreferencedStateTracker.js +12 -1
  194. package/lib/gc/gcUnreferencedStateTracker.js.map +1 -1
  195. package/lib/gc/index.d.ts +1 -1
  196. package/lib/gc/index.d.ts.map +1 -1
  197. package/lib/gc/index.js +1 -1
  198. package/lib/gc/index.js.map +1 -1
  199. package/lib/messageTypes.d.ts +1 -1
  200. package/lib/messageTypes.d.ts.map +1 -1
  201. package/lib/messageTypes.js.map +1 -1
  202. package/lib/opLifecycle/batchManager.js +5 -3
  203. package/lib/opLifecycle/batchManager.js.map +1 -1
  204. package/lib/opLifecycle/opCompressor.js +1 -0
  205. package/lib/opLifecycle/opCompressor.js.map +1 -1
  206. package/lib/opLifecycle/opDecompressor.d.ts +1 -1
  207. package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
  208. package/lib/opLifecycle/opDecompressor.js +6 -4
  209. package/lib/opLifecycle/opDecompressor.js.map +1 -1
  210. package/lib/opLifecycle/opGroupingManager.d.ts +1 -1
  211. package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -1
  212. package/lib/opLifecycle/opGroupingManager.js +3 -1
  213. package/lib/opLifecycle/opGroupingManager.js.map +1 -1
  214. package/lib/opLifecycle/opSplitter.d.ts +1 -1
  215. package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
  216. package/lib/opLifecycle/opSplitter.js +6 -0
  217. package/lib/opLifecycle/opSplitter.js.map +1 -1
  218. package/lib/opLifecycle/outbox.js +15 -10
  219. package/lib/opLifecycle/outbox.js.map +1 -1
  220. package/lib/opLifecycle/remoteMessageProcessor.d.ts +1 -1
  221. package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  222. package/lib/opLifecycle/remoteMessageProcessor.js +4 -1
  223. package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
  224. package/lib/opProperties.d.ts +1 -1
  225. package/lib/opProperties.d.ts.map +1 -1
  226. package/lib/opProperties.js.map +1 -1
  227. package/lib/packageVersion.d.ts +1 -1
  228. package/lib/packageVersion.js +1 -1
  229. package/lib/packageVersion.js.map +1 -1
  230. package/lib/pendingStateManager.d.ts.map +1 -1
  231. package/lib/pendingStateManager.js +34 -18
  232. package/lib/pendingStateManager.js.map +1 -1
  233. package/lib/scheduleManager.d.ts +1 -2
  234. package/lib/scheduleManager.d.ts.map +1 -1
  235. package/lib/scheduleManager.js +15 -4
  236. package/lib/scheduleManager.js.map +1 -1
  237. package/lib/storageServiceWithAttachBlobs.js +1 -0
  238. package/lib/storageServiceWithAttachBlobs.js.map +1 -1
  239. package/lib/summary/documentSchema.js +17 -1
  240. package/lib/summary/documentSchema.js.map +1 -1
  241. package/lib/summary/orderedClientElection.js +19 -11
  242. package/lib/summary/orderedClientElection.js.map +1 -1
  243. package/lib/summary/runWhileConnectedCoordinator.js +4 -2
  244. package/lib/summary/runWhileConnectedCoordinator.js.map +1 -1
  245. package/lib/summary/runningSummarizer.d.ts +1 -1
  246. package/lib/summary/runningSummarizer.d.ts.map +1 -1
  247. package/lib/summary/runningSummarizer.js +57 -39
  248. package/lib/summary/runningSummarizer.js.map +1 -1
  249. package/lib/summary/summarizer.js +17 -8
  250. package/lib/summary/summarizer.js.map +1 -1
  251. package/lib/summary/summarizerClientElection.js +18 -7
  252. package/lib/summary/summarizerClientElection.js.map +1 -1
  253. package/lib/summary/summarizerHeuristics.js +30 -25
  254. package/lib/summary/summarizerHeuristics.js.map +1 -1
  255. package/lib/summary/summarizerNode/summarizerNode.d.ts +1 -2
  256. package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
  257. package/lib/summary/summarizerNode/summarizerNode.js +12 -3
  258. package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
  259. package/lib/summary/summarizerNode/summarizerNodeUtils.js +2 -0
  260. package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  261. package/lib/summary/summarizerNode/summarizerNodeWithGc.js +20 -6
  262. package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  263. package/lib/summary/summarizerTypes.d.ts +2 -2
  264. package/lib/summary/summarizerTypes.d.ts.map +1 -1
  265. package/lib/summary/summarizerTypes.js.map +1 -1
  266. package/lib/summary/summaryCollection.d.ts +1 -2
  267. package/lib/summary/summaryCollection.d.ts.map +1 -1
  268. package/lib/summary/summaryCollection.js +23 -11
  269. package/lib/summary/summaryCollection.js.map +1 -1
  270. package/lib/summary/summaryFormat.d.ts +1 -2
  271. package/lib/summary/summaryFormat.d.ts.map +1 -1
  272. package/lib/summary/summaryFormat.js.map +1 -1
  273. package/lib/summary/summaryGenerator.js +12 -5
  274. package/lib/summary/summaryGenerator.js.map +1 -1
  275. package/lib/summary/summaryManager.js +58 -48
  276. package/lib/summary/summaryManager.js.map +1 -1
  277. package/lib/throttler.js +4 -1
  278. package/lib/throttler.js.map +1 -1
  279. package/package.json +17 -17
  280. package/src/batchTracker.ts +1 -1
  281. package/src/blobManager.ts +1 -39
  282. package/src/channelCollection.ts +19 -72
  283. package/src/connectionTelemetry.ts +5 -2
  284. package/src/containerRuntime.ts +9 -32
  285. package/src/dataStoreContext.ts +4 -38
  286. package/src/deltaManagerProxies.ts +3 -5
  287. package/src/deltaScheduler.ts +4 -2
  288. package/src/gc/garbageCollection.ts +0 -2
  289. package/src/gc/gcDefinitions.ts +0 -4
  290. package/src/gc/index.ts +0 -1
  291. package/src/messageTypes.ts +1 -1
  292. package/src/opLifecycle/opDecompressor.ts +1 -1
  293. package/src/opLifecycle/opGroupingManager.ts +1 -1
  294. package/src/opLifecycle/opSplitter.ts +1 -1
  295. package/src/opLifecycle/remoteMessageProcessor.ts +4 -2
  296. package/src/opProperties.ts +4 -2
  297. package/src/packageVersion.ts +1 -1
  298. package/src/pendingStateManager.ts +16 -5
  299. package/src/scheduleManager.ts +4 -2
  300. package/src/summary/runningSummarizer.ts +5 -2
  301. package/src/summary/summarizerNode/summarizerNode.ts +5 -2
  302. package/src/summary/summarizerTypes.ts +5 -2
  303. package/src/summary/summaryCollection.ts +1 -1
  304. package/src/summary/summaryFormat.ts +2 -1
  305. package/tsconfig.json +2 -0
@@ -1 +1 @@
1
- {"version":3,"file":"opProperties.js","sourceRoot":"","sources":["../src/opProperties.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAKI,MAAM,MAAM,GAAG,CAAC,EAA6B,EAAU,EAAE;IAC/D,kDAAkD;IAClD,2DAA2D;IAC3D,MAAM,OAAO,GACZ,OAAO,EAAE,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;IACnF,MAAM,IAAI,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1C,OAAO,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;AACrC,CAAC,CAAC;AAPW,QAAA,MAAM,UAOjB;AAEF,MAAM,SAAS,GAAG,CAAC,EAA6B,EAAyC,EAAE,CACzF,EAAsC,CAAC,IAAI,KAAK,SAAS,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ISequencedDocumentMessage } from \"@fluidframework/driver-definitions\";\nimport { ISequencedDocumentSystemMessage } from \"@fluidframework/driver-definitions/internal\";\n\nexport const opSize = (op: ISequencedDocumentMessage): number => {\n\t// Some messages may already have string contents,\n\t// so stringifying them again will add inaccurate overhead.\n\tconst content =\n\t\ttypeof op.contents === \"string\" ? op.contents : JSON.stringify(op.contents) ?? \"\";\n\tconst data = opHasData(op) ? op.data : \"\";\n\treturn content.length + data.length;\n};\n\nconst opHasData = (op: ISequencedDocumentMessage): op is ISequencedDocumentSystemMessage =>\n\t(op as ISequencedDocumentSystemMessage).data !== undefined;\n"]}
1
+ {"version":3,"file":"opProperties.js","sourceRoot":"","sources":["../src/opProperties.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAOI,MAAM,MAAM,GAAG,CAAC,EAA6B,EAAU,EAAE;IAC/D,kDAAkD;IAClD,2DAA2D;IAC3D,MAAM,OAAO,GACZ,OAAO,EAAE,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;IACnF,MAAM,IAAI,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1C,OAAO,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;AACrC,CAAC,CAAC;AAPW,QAAA,MAAM,UAOjB;AAEF,MAAM,SAAS,GAAG,CAAC,EAA6B,EAAyC,EAAE,CACzF,EAAsC,CAAC,IAAI,KAAK,SAAS,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tISequencedDocumentSystemMessage,\n\tISequencedDocumentMessage,\n} from \"@fluidframework/driver-definitions/internal\";\n\nexport const opSize = (op: ISequencedDocumentMessage): number => {\n\t// Some messages may already have string contents,\n\t// so stringifying them again will add inaccurate overhead.\n\tconst content =\n\t\ttypeof op.contents === \"string\" ? op.contents : JSON.stringify(op.contents) ?? \"\";\n\tconst data = opHasData(op) ? op.data : \"\";\n\treturn content.length + data.length;\n};\n\nconst opHasData = (op: ISequencedDocumentMessage): op is ISequencedDocumentSystemMessage =>\n\t(op as ISequencedDocumentSystemMessage).data !== undefined;\n"]}
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export declare const pkgName = "@fluidframework/container-runtime";
8
- export declare const pkgVersion = "2.0.0-dev-rc.5.0.0.268409";
8
+ export declare const pkgVersion = "2.0.0-dev-rc.5.0.0.270401";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -8,5 +8,5 @@
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.pkgVersion = exports.pkgName = void 0;
10
10
  exports.pkgName = "@fluidframework/container-runtime";
11
- exports.pkgVersion = "2.0.0-dev-rc.5.0.0.268409";
11
+ exports.pkgVersion = "2.0.0-dev-rc.5.0.0.270401";
12
12
  //# sourceMappingURL=packageVersion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,mCAAmC,CAAC;AAC9C,QAAA,UAAU,GAAG,2BAA2B,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/container-runtime\";\nexport const pkgVersion = \"2.0.0-dev-rc.5.0.0.268409\";\n"]}
1
+ {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,mCAAmC,CAAC;AAC9C,QAAA,UAAU,GAAG,2BAA2B,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/container-runtime\";\nexport const pkgVersion = \"2.0.0-dev-rc.5.0.0.270401\";\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"pendingStateManager.d.ts","sourceRoot":"","sources":["../src/pendingStateManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pendingStateManager.d.ts","sourceRoot":"","sources":["../src/pendingStateManager.ts"],"names":[],"mappings":"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"}
@@ -22,6 +22,12 @@ message) {
22
22
  // Any properties that are not defined, won't be emitted by stringify.
23
23
  return JSON.stringify({ type, contents, compatDetails });
24
24
  }
25
+ function withoutLocalOpMetadata(message) {
26
+ return {
27
+ ...message,
28
+ localOpMetadata: undefined,
29
+ };
30
+ }
25
31
  /**
26
32
  * PendingStateManager is responsible for maintaining the messages that have not been sent or have not yet been
27
33
  * acknowledged by the server. It also maintains the batch information for both automatically and manually flushed
@@ -32,6 +38,25 @@ message) {
32
38
  * It verifies that all the ops are acked, are received in the right order and batch information is correct.
33
39
  */
34
40
  class PendingStateManager {
41
+ stateHandler;
42
+ logger;
43
+ pendingMessages = new double_ended_queue_1.default();
44
+ // This queue represents already acked messages.
45
+ initialMessages = new double_ended_queue_1.default();
46
+ /**
47
+ * Sequenced local ops that are saved when stashing since pending ops may depend on them
48
+ */
49
+ savedOps = [];
50
+ disposeOnce = new internal_1.Lazy(() => {
51
+ this.initialMessages.clear();
52
+ this.pendingMessages.clear();
53
+ });
54
+ // Indicates whether we are processing a batch.
55
+ isProcessingBatch = false;
56
+ // This stores the first message in the batch that we are processing. This is used to verify that we get
57
+ // the correct batch metadata.
58
+ pendingBatchBeginMessage;
59
+ clientId;
35
60
  /**
36
61
  * The pending messages count. Includes `pendingMessages` and `initialMessages` to keep in sync with
37
62
  * 'hasPendingMessages'.
@@ -56,6 +81,9 @@ class PendingStateManager {
56
81
  }
57
82
  getLocalState(snapshotSequenceNumber) {
58
83
  (0, internal_1.assert)(this.initialMessages.isEmpty(), 0x2e9 /* "Must call getLocalState() after applying initial states" */);
84
+ // Using snapshot sequence number to filter ops older than our latest snapshot.
85
+ // Such ops should not be declared in pending/stashed state. Snapshot seq num will not
86
+ // be available when the container is not attached. Therefore, no filtering is needed.
59
87
  const newSavedOps = [...this.savedOps].filter((message) => {
60
88
  (0, internal_1.assert)(message.sequenceNumber !== undefined, 0x97c /* saved op should already have a sequence number */);
61
89
  return message.sequenceNumber >= (snapshotSequenceNumber ?? 0);
@@ -67,28 +95,15 @@ class PendingStateManager {
67
95
  }
68
96
  });
69
97
  return {
70
- pendingStates: [...newSavedOps, ...this.pendingMessages.toArray()].map((message) => {
71
- return { ...message, localOpMetadata: undefined };
72
- }),
98
+ pendingStates: [
99
+ ...newSavedOps,
100
+ ...this.pendingMessages.toArray().map(withoutLocalOpMetadata),
101
+ ],
73
102
  };
74
103
  }
75
104
  constructor(stateHandler, initialLocalState, logger) {
76
105
  this.stateHandler = stateHandler;
77
106
  this.logger = logger;
78
- this.pendingMessages = new double_ended_queue_1.default();
79
- // This queue represents already acked messages.
80
- this.initialMessages = new double_ended_queue_1.default();
81
- /**
82
- * Sequenced local ops that are saved when stashing since pending ops may depend on them
83
- */
84
- this.savedOps = [];
85
- this.disposeOnce = new internal_1.Lazy(() => {
86
- this.initialMessages.clear();
87
- this.pendingMessages.clear();
88
- });
89
- // Indicates whether we are processing a batch.
90
- this.isProcessingBatch = false;
91
- this.dispose = () => this.disposeOnce.value;
92
107
  if (initialLocalState?.pendingStates) {
93
108
  this.initialMessages.push(...initialLocalState.pendingStates);
94
109
  }
@@ -96,6 +111,7 @@ class PendingStateManager {
96
111
  get disposed() {
97
112
  return this.disposeOnce.evaluated;
98
113
  }
114
+ dispose = () => this.disposeOnce.value;
99
115
  /**
100
116
  * Called when a message is submitted locally. Adds the message and the associated details to the pending state
101
117
  * queue.
@@ -163,7 +179,7 @@ class PendingStateManager {
163
179
  const pendingMessage = this.pendingMessages.peekFront();
164
180
  (0, internal_1.assert)(pendingMessage !== undefined, 0x169 /* "No pending message found for this remote message" */);
165
181
  pendingMessage.sequenceNumber = message.sequenceNumber;
166
- this.savedOps.push(pendingMessage);
182
+ this.savedOps.push(withoutLocalOpMetadata(pendingMessage));
167
183
  this.pendingMessages.shift();
168
184
  const messageContent = buildPendingMessageContent(message);
169
185
  // Stringified content should match
@@ -1 +1 @@
1
- {"version":3,"file":"pendingStateManager.js","sourceRoot":"","sources":["../src/pendingStateManager.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 { ICriticalContainerError } from \"@fluidframework/container-definitions\";\nimport { IDisposable } from \"@fluidframework/core-interfaces\";\nimport { assert, Lazy } from \"@fluidframework/core-utils/internal\";\nimport { ISequencedDocumentMessage } from \"@fluidframework/driver-definitions\";\nimport {\n\tITelemetryLoggerExt,\n\tDataProcessingError,\n\tLoggingError,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport Deque from \"double-ended-queue\";\n\nimport { InboundSequencedContainerRuntimeMessage } from \"./messageTypes.js\";\nimport { IBatchMetadata } from \"./metadata.js\";\nimport { pkgVersion } from \"./packageVersion.js\";\n\n/**\n * This represents a message that has been submitted and is added to the pending queue when `submit` is called on the\n * ContainerRuntime. This message has either not been ack'd by the server or has not been submitted to the server yet.\n */\nexport interface IPendingMessage {\n\ttype: \"message\";\n\treferenceSequenceNumber: number;\n\tcontent: string;\n\tlocalOpMetadata: unknown;\n\topMetadata: Record<string, unknown> | undefined;\n\tsequenceNumber?: number;\n}\n\nexport interface IPendingLocalState {\n\t/**\n\t * list of pending states, including ops and batch information\n\t */\n\tpendingStates: IPendingMessage[];\n}\n\nexport interface IPendingBatchMessage {\n\tcontent: string;\n\tlocalOpMetadata: unknown;\n\topMetadata: Record<string, unknown> | undefined;\n}\n\nexport interface IRuntimeStateHandler {\n\tconnected(): boolean;\n\tclientId(): string | undefined;\n\tclose(error?: ICriticalContainerError): void;\n\tapplyStashedOp(content: string): Promise<unknown>;\n\treSubmit(message: IPendingBatchMessage): void;\n\treSubmitBatch(batch: IPendingBatchMessage[]): void;\n\tisActiveConnection: () => boolean;\n\tisAttached: () => boolean;\n}\n\n/** Union of keys of T */\ntype KeysOfUnion<T extends object> = T extends T ? keyof T : never;\n/** *Partial* type all possible combinations of properties and values of union T.\n * This loosens typing allowing access to all possible properties without\n * narrowing.\n */\ntype AnyComboFromUnion<T extends object> = { [P in KeysOfUnion<T>]?: T[P] };\n\nfunction buildPendingMessageContent(\n\t// AnyComboFromUnion is needed need to gain access to compatDetails that\n\t// is only defined for some cases.\n\tmessage: AnyComboFromUnion<InboundSequencedContainerRuntimeMessage>,\n): string {\n\t// IMPORTANT: Order matters here, this must match the order of the properties used\n\t// when submitting the message.\n\tconst { type, contents, compatDetails } = message;\n\t// Any properties that are not defined, won't be emitted by stringify.\n\treturn JSON.stringify({ type, contents, compatDetails });\n}\n\n/**\n * PendingStateManager is responsible for maintaining the messages that have not been sent or have not yet been\n * acknowledged by the server. It also maintains the batch information for both automatically and manually flushed\n * batches along with the messages.\n * When the Container reconnects, it replays the pending states, which includes manual flushing\n * of messages and triggering resubmission of unacked ops.\n *\n * It verifies that all the ops are acked, are received in the right order and batch information is correct.\n */\nexport class PendingStateManager implements IDisposable {\n\tprivate readonly pendingMessages = new Deque<IPendingMessage>();\n\t// This queue represents already acked messages.\n\tprivate readonly initialMessages = new Deque<IPendingMessage>();\n\n\t/**\n\t * Sequenced local ops that are saved when stashing since pending ops may depend on them\n\t */\n\tprivate savedOps: IPendingMessage[] = [];\n\n\tprivate readonly disposeOnce = new Lazy<void>(() => {\n\t\tthis.initialMessages.clear();\n\t\tthis.pendingMessages.clear();\n\t});\n\n\t// Indicates whether we are processing a batch.\n\tprivate isProcessingBatch: boolean = false;\n\n\t// This stores the first message in the batch that we are processing. This is used to verify that we get\n\t// the correct batch metadata.\n\tprivate pendingBatchBeginMessage: ISequencedDocumentMessage | undefined;\n\n\tprivate clientId: string | undefined;\n\n\t/**\n\t * The pending messages count. Includes `pendingMessages` and `initialMessages` to keep in sync with\n\t * 'hasPendingMessages'.\n\t */\n\tpublic get pendingMessagesCount(): number {\n\t\treturn this.pendingMessages.length + this.initialMessages.length;\n\t}\n\n\t/**\n\t * The minimumPendingMessageSequenceNumber is the minimum of the first pending message and the first initial message.\n\t *\n\t * We need this so that we can properly keep local data and maintain the correct sequence window.\n\t */\n\tpublic get minimumPendingMessageSequenceNumber(): number | undefined {\n\t\treturn this.pendingMessages.peekFront()?.referenceSequenceNumber;\n\t}\n\n\t/**\n\t * Called to check if there are any pending messages in the pending message queue.\n\t * @returns A boolean indicating whether there are messages or not.\n\t */\n\tpublic hasPendingMessages(): boolean {\n\t\treturn this.pendingMessagesCount !== 0;\n\t}\n\n\tpublic getLocalState(snapshotSequenceNumber?: number): IPendingLocalState {\n\t\tassert(\n\t\t\tthis.initialMessages.isEmpty(),\n\t\t\t0x2e9 /* \"Must call getLocalState() after applying initial states\" */,\n\t\t);\n\t\tconst newSavedOps = [...this.savedOps].filter((message) => {\n\t\t\tassert(\n\t\t\t\tmessage.sequenceNumber !== undefined,\n\t\t\t\t0x97c /* saved op should already have a sequence number */,\n\t\t\t);\n\t\t\treturn message.sequenceNumber >= (snapshotSequenceNumber ?? 0);\n\t\t});\n\t\tthis.pendingMessages.toArray().forEach((message) => {\n\t\t\tif (\n\t\t\t\tsnapshotSequenceNumber !== undefined &&\n\t\t\t\tmessage.referenceSequenceNumber < snapshotSequenceNumber\n\t\t\t) {\n\t\t\t\tthrow new LoggingError(\"trying to stash ops older than our latest snapshot\");\n\t\t\t}\n\t\t});\n\t\treturn {\n\t\t\tpendingStates: [...newSavedOps, ...this.pendingMessages.toArray()].map((message) => {\n\t\t\t\treturn { ...message, localOpMetadata: undefined };\n\t\t\t}),\n\t\t};\n\t}\n\n\tconstructor(\n\t\tprivate readonly stateHandler: IRuntimeStateHandler,\n\t\tinitialLocalState: IPendingLocalState | undefined,\n\t\tprivate readonly logger: ITelemetryLoggerExt | undefined,\n\t) {\n\t\tif (initialLocalState?.pendingStates) {\n\t\t\tthis.initialMessages.push(...initialLocalState.pendingStates);\n\t\t}\n\t}\n\n\tpublic get disposed() {\n\t\treturn this.disposeOnce.evaluated;\n\t}\n\tpublic readonly dispose = () => this.disposeOnce.value;\n\n\t/**\n\t * Called when a message is submitted locally. Adds the message and the associated details to the pending state\n\t * queue.\n\t * @param type - The container message type.\n\t * @param content - The message content.\n\t * @param localOpMetadata - The local metadata associated with the message.\n\t */\n\tpublic onSubmitMessage(\n\t\tcontent: string,\n\t\treferenceSequenceNumber: number,\n\t\tlocalOpMetadata: unknown,\n\t\topMetadata: Record<string, unknown> | undefined,\n\t) {\n\t\tconst pendingMessage: IPendingMessage = {\n\t\t\ttype: \"message\",\n\t\t\treferenceSequenceNumber,\n\t\t\tcontent,\n\t\t\tlocalOpMetadata,\n\t\t\topMetadata,\n\t\t};\n\n\t\tthis.pendingMessages.push(pendingMessage);\n\t}\n\n\t/**\n\t * Applies stashed ops at their reference sequence number so they are ready to be ACKed or resubmitted\n\t * @param seqNum - Sequence number at which to apply ops. Will apply all ops if seqNum is undefined.\n\t */\n\tpublic async applyStashedOpsAt(seqNum?: number) {\n\t\t// apply stashed ops at sequence number\n\t\twhile (!this.initialMessages.isEmpty()) {\n\t\t\tif (seqNum !== undefined) {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\tconst peekMessage = this.initialMessages.peekFront()!;\n\t\t\t\tif (peekMessage.referenceSequenceNumber > seqNum) {\n\t\t\t\t\tbreak; // nothing left to do at this sequence number\n\t\t\t\t}\n\t\t\t\tif (peekMessage.referenceSequenceNumber < seqNum) {\n\t\t\t\t\tthrow new Error(\"loaded from snapshot too recent to apply stashed ops\");\n\t\t\t\t}\n\t\t\t}\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\tconst nextMessage = this.initialMessages.shift()!;\n\t\t\ttry {\n\t\t\t\t// applyStashedOp will cause the DDS to behave as if it has sent the op but not actually send it\n\t\t\t\tconst localOpMetadata = await this.stateHandler.applyStashedOp(nextMessage.content);\n\t\t\t\tif (!this.stateHandler.isAttached()) {\n\t\t\t\t\tif (localOpMetadata !== undefined) {\n\t\t\t\t\t\tthrow new Error(\"Local Op Metadata must be undefined when not attached\");\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tnextMessage.localOpMetadata = localOpMetadata;\n\t\t\t\t\t// then we push onto pendingMessages which will cause PendingStateManager to resubmit when we connect\n\t\t\t\t\tthis.pendingMessages.push(nextMessage);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthrow DataProcessingError.wrapIfUnrecognized(error, \"applyStashedOp\", nextMessage);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Processes a local message once its ack'd by the server. It verifies that there was no data corruption and that\n\t * the batch information was preserved for batch messages.\n\t * @param message - The message that got ack'd and needs to be processed.\n\t */\n\tpublic processPendingLocalMessage(message: InboundSequencedContainerRuntimeMessage): unknown {\n\t\t// Pre-processing part - This may be the start of a batch.\n\t\tthis.maybeProcessBatchBegin(message);\n\t\t// Get the next message from the pending queue. Verify a message exists.\n\t\tconst pendingMessage = this.pendingMessages.peekFront();\n\t\tassert(\n\t\t\tpendingMessage !== undefined,\n\t\t\t0x169 /* \"No pending message found for this remote message\" */,\n\t\t);\n\t\tpendingMessage.sequenceNumber = message.sequenceNumber;\n\t\tthis.savedOps.push(pendingMessage);\n\n\t\tthis.pendingMessages.shift();\n\n\t\tconst messageContent = buildPendingMessageContent(message);\n\n\t\t// Stringified content should match\n\t\tif (pendingMessage.content !== messageContent) {\n\t\t\tthis.stateHandler.close(\n\t\t\t\tDataProcessingError.create(\n\t\t\t\t\t\"pending local message content mismatch\",\n\t\t\t\t\t\"unexpectedAckReceived\",\n\t\t\t\t\tmessage,\n\t\t\t\t\t{\n\t\t\t\t\t\texpectedMessageType: JSON.parse(pendingMessage.content).type,\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// Post-processing part - If we are processing a batch then this could be the last message in the batch.\n\t\tthis.maybeProcessBatchEnd(message);\n\n\t\treturn pendingMessage.localOpMetadata;\n\t}\n\n\t/**\n\t * This message could be the first message in batch. If so, set batch state marking the beginning of a batch.\n\t * @param message - The message that is being processed.\n\t */\n\tprivate maybeProcessBatchBegin(message: ISequencedDocumentMessage) {\n\t\t// This message is the first in a batch if the \"batch\" property on the metadata is set to true\n\t\tif ((message.metadata as IBatchMetadata | undefined)?.batch) {\n\t\t\t// We should not already be processing a batch and there should be no pending batch begin message.\n\t\t\tassert(\n\t\t\t\t!this.isProcessingBatch && this.pendingBatchBeginMessage === undefined,\n\t\t\t\t0x16b /* \"The pending batch state indicates we are already processing a batch\" */,\n\t\t\t);\n\n\t\t\t// Set the pending batch state indicating we have started processing a batch.\n\t\t\tthis.pendingBatchBeginMessage = message;\n\t\t\tthis.isProcessingBatch = true;\n\t\t}\n\t}\n\n\t/**\n\t * This message could be the last message in batch. If so, clear batch state since the batch is complete.\n\t * @param message - The message that is being processed.\n\t */\n\tprivate maybeProcessBatchEnd(message: ISequencedDocumentMessage) {\n\t\tif (!this.isProcessingBatch) {\n\t\t\treturn;\n\t\t}\n\n\t\t// There should be a pending batch begin message.\n\t\tassert(\n\t\t\tthis.pendingBatchBeginMessage !== undefined,\n\t\t\t0x16d /* \"There is no pending batch begin message\" */,\n\t\t);\n\n\t\tconst batchEndMetadata = (message.metadata as IBatchMetadata | undefined)?.batch;\n\t\tif (this.pendingMessages.isEmpty() || batchEndMetadata === false) {\n\t\t\t// Get the batch begin metadata from the first message in the batch.\n\t\t\tconst batchBeginMetadata = (\n\t\t\t\tthis.pendingBatchBeginMessage.metadata as IBatchMetadata | undefined\n\t\t\t)?.batch;\n\n\t\t\t// There could be just a single message in the batch. If so, it should not have any batch metadata. If there\n\t\t\t// are multiple messages in the batch, verify that we got the correct batch begin and end metadata.\n\t\t\tif (this.pendingBatchBeginMessage === message) {\n\t\t\t\tassert(\n\t\t\t\t\tbatchBeginMetadata === undefined,\n\t\t\t\t\t0x16e /* \"Batch with single message should not have batch metadata\" */,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tif (batchBeginMetadata !== true || batchEndMetadata !== false) {\n\t\t\t\t\tthis.stateHandler.close(\n\t\t\t\t\t\tDataProcessingError.create(\n\t\t\t\t\t\t\t\"Pending batch inconsistency\", // Formerly known as asserts 0x16f and 0x170\n\t\t\t\t\t\t\t\"processPendingLocalMessage\",\n\t\t\t\t\t\t\tmessage,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\truntimeVersion: pkgVersion,\n\t\t\t\t\t\t\t\tbatchClientId:\n\t\t\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing\n\t\t\t\t\t\t\t\t\tthis.pendingBatchBeginMessage.clientId === null\n\t\t\t\t\t\t\t\t\t\t? \"null\"\n\t\t\t\t\t\t\t\t\t\t: this.pendingBatchBeginMessage.clientId,\n\t\t\t\t\t\t\t\tclientId: this.stateHandler.clientId(),\n\t\t\t\t\t\t\t\thasBatchStart: batchBeginMetadata === true,\n\t\t\t\t\t\t\t\thasBatchEnd: batchEndMetadata === false,\n\t\t\t\t\t\t\t\tmessageType: message.type,\n\t\t\t\t\t\t\t\tpendingMessagesCount: this.pendingMessagesCount,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Clear the pending batch state now that we have processed the entire batch.\n\t\t\tthis.pendingBatchBeginMessage = undefined;\n\t\t\tthis.isProcessingBatch = false;\n\t\t}\n\t}\n\n\t/**\n\t * Called when the Container's connection state changes. If the Container gets connected, it replays all the pending\n\t * states in its queue. This includes triggering resubmission of unacked ops.\n\t * ! Note: successfully resubmitting an op that has been successfully sequenced is not possible due to checks in the ConnectionStateHandler (Loader layer)\n\t */\n\tpublic replayPendingStates() {\n\t\tassert(\n\t\t\tthis.stateHandler.connected(),\n\t\t\t0x172 /* \"The connection state is not consistent with the runtime\" */,\n\t\t);\n\n\t\t// This assert suggests we are about to send same ops twice, which will result in data loss.\n\t\tassert(\n\t\t\tthis.clientId !== this.stateHandler.clientId(),\n\t\t\t0x173 /* \"replayPendingStates called twice for same clientId!\" */,\n\t\t);\n\t\tthis.clientId = this.stateHandler.clientId();\n\n\t\tassert(\n\t\t\tthis.initialMessages.isEmpty(),\n\t\t\t0x174 /* \"initial states should be empty before replaying pending\" */,\n\t\t);\n\n\t\tconst initialPendingMessagesCount = this.pendingMessages.length;\n\t\tlet remainingPendingMessagesCount = this.pendingMessages.length;\n\n\t\t// Process exactly `pendingMessagesCount` items in the queue as it represents the number of messages that were\n\t\t// pending when we connected. This is important because the `reSubmitFn` might add more items in the queue\n\t\t// which must not be replayed.\n\t\twhile (remainingPendingMessagesCount > 0) {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\tlet pendingMessage = this.pendingMessages.shift()!;\n\t\t\tremainingPendingMessagesCount--;\n\t\t\tassert(\n\t\t\t\tpendingMessage.opMetadata?.batch !== false,\n\t\t\t\t0x41b /* We cannot process batches in chunks */,\n\t\t\t);\n\n\t\t\t/**\n\t\t\t * We want to ensure grouped messages get processed in a batch.\n\t\t\t * Note: It is not possible for the PendingStateManager to receive a partially acked batch. It will\n\t\t\t * either receive the whole batch ack or nothing at all.\n\t\t\t */\n\t\t\tif (pendingMessage.opMetadata?.batch) {\n\t\t\t\tassert(\n\t\t\t\t\tremainingPendingMessagesCount > 0,\n\t\t\t\t\t0x554 /* Last pending message cannot be a batch begin */,\n\t\t\t\t);\n\n\t\t\t\tconst batch: IPendingBatchMessage[] = [];\n\n\t\t\t\t// check is >= because batch end may be last pending message\n\t\t\t\twhile (remainingPendingMessagesCount >= 0) {\n\t\t\t\t\tbatch.push({\n\t\t\t\t\t\tcontent: pendingMessage.content,\n\t\t\t\t\t\tlocalOpMetadata: pendingMessage.localOpMetadata,\n\t\t\t\t\t\topMetadata: pendingMessage.opMetadata,\n\t\t\t\t\t});\n\n\t\t\t\t\tif (pendingMessage.opMetadata?.batch === false) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tassert(remainingPendingMessagesCount > 0, 0x555 /* No batch end found */);\n\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\t\tpendingMessage = this.pendingMessages.shift()!;\n\t\t\t\t\tremainingPendingMessagesCount--;\n\t\t\t\t\tassert(\n\t\t\t\t\t\tpendingMessage.opMetadata?.batch !== true,\n\t\t\t\t\t\t0x556 /* Batch start needs a corresponding batch end */,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tthis.stateHandler.reSubmitBatch(batch);\n\t\t\t} else {\n\t\t\t\tthis.stateHandler.reSubmit({\n\t\t\t\t\tcontent: pendingMessage.content,\n\t\t\t\t\tlocalOpMetadata: pendingMessage.localOpMetadata,\n\t\t\t\t\topMetadata: pendingMessage.opMetadata,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// pending ops should no longer depend on previous sequenced local ops after resubmit\n\t\tthis.savedOps = [];\n\n\t\t// We replayPendingStates on read connections too - we expect these to get nack'd though, and to then reconnect\n\t\t// on a write connection and replay again. This filters out the replay that happens on the read connection so\n\t\t// we only see the replays on write connections (that have a chance to go through).\n\t\tif (this.stateHandler.isActiveConnection()) {\n\t\t\tthis.logger?.sendTelemetryEvent({\n\t\t\t\teventName: \"PendingStatesReplayed\",\n\t\t\t\tcount: initialPendingMessagesCount,\n\t\t\t\tclientId: this.stateHandler.clientId(),\n\t\t\t});\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"pendingStateManager.js","sourceRoot":"","sources":["../src/pendingStateManager.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 { ICriticalContainerError } from \"@fluidframework/container-definitions\";\nimport { IDisposable } from \"@fluidframework/core-interfaces\";\nimport { assert, Lazy } from \"@fluidframework/core-utils/internal\";\nimport { ISequencedDocumentMessage } from \"@fluidframework/driver-definitions/internal\";\nimport {\n\tITelemetryLoggerExt,\n\tDataProcessingError,\n\tLoggingError,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport Deque from \"double-ended-queue\";\n\nimport { InboundSequencedContainerRuntimeMessage } from \"./messageTypes.js\";\nimport { IBatchMetadata } from \"./metadata.js\";\nimport { pkgVersion } from \"./packageVersion.js\";\n\n/**\n * This represents a message that has been submitted and is added to the pending queue when `submit` is called on the\n * ContainerRuntime. This message has either not been ack'd by the server or has not been submitted to the server yet.\n */\nexport interface IPendingMessage {\n\ttype: \"message\";\n\treferenceSequenceNumber: number;\n\tcontent: string;\n\tlocalOpMetadata: unknown;\n\topMetadata: Record<string, unknown> | undefined;\n\tsequenceNumber?: number;\n}\n\nexport interface IPendingLocalState {\n\t/**\n\t * list of pending states, including ops and batch information\n\t */\n\tpendingStates: IPendingMessage[];\n}\n\nexport interface IPendingBatchMessage {\n\tcontent: string;\n\tlocalOpMetadata: unknown;\n\topMetadata: Record<string, unknown> | undefined;\n}\n\nexport interface IRuntimeStateHandler {\n\tconnected(): boolean;\n\tclientId(): string | undefined;\n\tclose(error?: ICriticalContainerError): void;\n\tapplyStashedOp(content: string): Promise<unknown>;\n\treSubmit(message: IPendingBatchMessage): void;\n\treSubmitBatch(batch: IPendingBatchMessage[]): void;\n\tisActiveConnection: () => boolean;\n\tisAttached: () => boolean;\n}\n\n/** Union of keys of T */\ntype KeysOfUnion<T extends object> = T extends T ? keyof T : never;\n/** *Partial* type all possible combinations of properties and values of union T.\n * This loosens typing allowing access to all possible properties without\n * narrowing.\n */\ntype AnyComboFromUnion<T extends object> = { [P in KeysOfUnion<T>]?: T[P] };\n\nfunction buildPendingMessageContent(\n\t// AnyComboFromUnion is needed need to gain access to compatDetails that\n\t// is only defined for some cases.\n\tmessage: AnyComboFromUnion<InboundSequencedContainerRuntimeMessage>,\n): string {\n\t// IMPORTANT: Order matters here, this must match the order of the properties used\n\t// when submitting the message.\n\tconst { type, contents, compatDetails } = message;\n\t// Any properties that are not defined, won't be emitted by stringify.\n\treturn JSON.stringify({ type, contents, compatDetails });\n}\n\nfunction withoutLocalOpMetadata(message: IPendingMessage): IPendingMessage {\n\treturn {\n\t\t...message,\n\t\tlocalOpMetadata: undefined,\n\t};\n}\n\n/**\n * PendingStateManager is responsible for maintaining the messages that have not been sent or have not yet been\n * acknowledged by the server. It also maintains the batch information for both automatically and manually flushed\n * batches along with the messages.\n * When the Container reconnects, it replays the pending states, which includes manual flushing\n * of messages and triggering resubmission of unacked ops.\n *\n * It verifies that all the ops are acked, are received in the right order and batch information is correct.\n */\nexport class PendingStateManager implements IDisposable {\n\tprivate readonly pendingMessages = new Deque<IPendingMessage>();\n\t// This queue represents already acked messages.\n\tprivate readonly initialMessages = new Deque<IPendingMessage>();\n\n\t/**\n\t * Sequenced local ops that are saved when stashing since pending ops may depend on them\n\t */\n\tprivate savedOps: IPendingMessage[] = [];\n\n\tprivate readonly disposeOnce = new Lazy<void>(() => {\n\t\tthis.initialMessages.clear();\n\t\tthis.pendingMessages.clear();\n\t});\n\n\t// Indicates whether we are processing a batch.\n\tprivate isProcessingBatch: boolean = false;\n\n\t// This stores the first message in the batch that we are processing. This is used to verify that we get\n\t// the correct batch metadata.\n\tprivate pendingBatchBeginMessage: ISequencedDocumentMessage | undefined;\n\n\tprivate clientId: string | undefined;\n\n\t/**\n\t * The pending messages count. Includes `pendingMessages` and `initialMessages` to keep in sync with\n\t * 'hasPendingMessages'.\n\t */\n\tpublic get pendingMessagesCount(): number {\n\t\treturn this.pendingMessages.length + this.initialMessages.length;\n\t}\n\n\t/**\n\t * The minimumPendingMessageSequenceNumber is the minimum of the first pending message and the first initial message.\n\t *\n\t * We need this so that we can properly keep local data and maintain the correct sequence window.\n\t */\n\tpublic get minimumPendingMessageSequenceNumber(): number | undefined {\n\t\treturn this.pendingMessages.peekFront()?.referenceSequenceNumber;\n\t}\n\n\t/**\n\t * Called to check if there are any pending messages in the pending message queue.\n\t * @returns A boolean indicating whether there are messages or not.\n\t */\n\tpublic hasPendingMessages(): boolean {\n\t\treturn this.pendingMessagesCount !== 0;\n\t}\n\n\tpublic getLocalState(snapshotSequenceNumber?: number): IPendingLocalState {\n\t\tassert(\n\t\t\tthis.initialMessages.isEmpty(),\n\t\t\t0x2e9 /* \"Must call getLocalState() after applying initial states\" */,\n\t\t);\n\t\t// Using snapshot sequence number to filter ops older than our latest snapshot.\n\t\t// Such ops should not be declared in pending/stashed state. Snapshot seq num will not\n\t\t// be available when the container is not attached. Therefore, no filtering is needed.\n\t\tconst newSavedOps = [...this.savedOps].filter((message) => {\n\t\t\tassert(\n\t\t\t\tmessage.sequenceNumber !== undefined,\n\t\t\t\t0x97c /* saved op should already have a sequence number */,\n\t\t\t);\n\t\t\treturn message.sequenceNumber >= (snapshotSequenceNumber ?? 0);\n\t\t});\n\t\tthis.pendingMessages.toArray().forEach((message) => {\n\t\t\tif (\n\t\t\t\tsnapshotSequenceNumber !== undefined &&\n\t\t\t\tmessage.referenceSequenceNumber < snapshotSequenceNumber\n\t\t\t) {\n\t\t\t\tthrow new LoggingError(\"trying to stash ops older than our latest snapshot\");\n\t\t\t}\n\t\t});\n\t\treturn {\n\t\t\tpendingStates: [\n\t\t\t\t...newSavedOps,\n\t\t\t\t...this.pendingMessages.toArray().map(withoutLocalOpMetadata),\n\t\t\t],\n\t\t};\n\t}\n\n\tconstructor(\n\t\tprivate readonly stateHandler: IRuntimeStateHandler,\n\t\tinitialLocalState: IPendingLocalState | undefined,\n\t\tprivate readonly logger: ITelemetryLoggerExt | undefined,\n\t) {\n\t\tif (initialLocalState?.pendingStates) {\n\t\t\tthis.initialMessages.push(...initialLocalState.pendingStates);\n\t\t}\n\t}\n\n\tpublic get disposed() {\n\t\treturn this.disposeOnce.evaluated;\n\t}\n\tpublic readonly dispose = () => this.disposeOnce.value;\n\n\t/**\n\t * Called when a message is submitted locally. Adds the message and the associated details to the pending state\n\t * queue.\n\t * @param type - The container message type.\n\t * @param content - The message content.\n\t * @param localOpMetadata - The local metadata associated with the message.\n\t */\n\tpublic onSubmitMessage(\n\t\tcontent: string,\n\t\treferenceSequenceNumber: number,\n\t\tlocalOpMetadata: unknown,\n\t\topMetadata: Record<string, unknown> | undefined,\n\t) {\n\t\tconst pendingMessage: IPendingMessage = {\n\t\t\ttype: \"message\",\n\t\t\treferenceSequenceNumber,\n\t\t\tcontent,\n\t\t\tlocalOpMetadata,\n\t\t\topMetadata,\n\t\t};\n\n\t\tthis.pendingMessages.push(pendingMessage);\n\t}\n\n\t/**\n\t * Applies stashed ops at their reference sequence number so they are ready to be ACKed or resubmitted\n\t * @param seqNum - Sequence number at which to apply ops. Will apply all ops if seqNum is undefined.\n\t */\n\tpublic async applyStashedOpsAt(seqNum?: number) {\n\t\t// apply stashed ops at sequence number\n\t\twhile (!this.initialMessages.isEmpty()) {\n\t\t\tif (seqNum !== undefined) {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\tconst peekMessage = this.initialMessages.peekFront()!;\n\t\t\t\tif (peekMessage.referenceSequenceNumber > seqNum) {\n\t\t\t\t\tbreak; // nothing left to do at this sequence number\n\t\t\t\t}\n\t\t\t\tif (peekMessage.referenceSequenceNumber < seqNum) {\n\t\t\t\t\tthrow new Error(\"loaded from snapshot too recent to apply stashed ops\");\n\t\t\t\t}\n\t\t\t}\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\tconst nextMessage = this.initialMessages.shift()!;\n\t\t\ttry {\n\t\t\t\t// applyStashedOp will cause the DDS to behave as if it has sent the op but not actually send it\n\t\t\t\tconst localOpMetadata = await this.stateHandler.applyStashedOp(nextMessage.content);\n\t\t\t\tif (!this.stateHandler.isAttached()) {\n\t\t\t\t\tif (localOpMetadata !== undefined) {\n\t\t\t\t\t\tthrow new Error(\"Local Op Metadata must be undefined when not attached\");\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tnextMessage.localOpMetadata = localOpMetadata;\n\t\t\t\t\t// then we push onto pendingMessages which will cause PendingStateManager to resubmit when we connect\n\t\t\t\t\tthis.pendingMessages.push(nextMessage);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthrow DataProcessingError.wrapIfUnrecognized(error, \"applyStashedOp\", nextMessage);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Processes a local message once its ack'd by the server. It verifies that there was no data corruption and that\n\t * the batch information was preserved for batch messages.\n\t * @param message - The message that got ack'd and needs to be processed.\n\t */\n\tpublic processPendingLocalMessage(message: InboundSequencedContainerRuntimeMessage): unknown {\n\t\t// Pre-processing part - This may be the start of a batch.\n\t\tthis.maybeProcessBatchBegin(message);\n\t\t// Get the next message from the pending queue. Verify a message exists.\n\t\tconst pendingMessage = this.pendingMessages.peekFront();\n\t\tassert(\n\t\t\tpendingMessage !== undefined,\n\t\t\t0x169 /* \"No pending message found for this remote message\" */,\n\t\t);\n\t\tpendingMessage.sequenceNumber = message.sequenceNumber;\n\t\tthis.savedOps.push(withoutLocalOpMetadata(pendingMessage));\n\n\t\tthis.pendingMessages.shift();\n\n\t\tconst messageContent = buildPendingMessageContent(message);\n\n\t\t// Stringified content should match\n\t\tif (pendingMessage.content !== messageContent) {\n\t\t\tthis.stateHandler.close(\n\t\t\t\tDataProcessingError.create(\n\t\t\t\t\t\"pending local message content mismatch\",\n\t\t\t\t\t\"unexpectedAckReceived\",\n\t\t\t\t\tmessage,\n\t\t\t\t\t{\n\t\t\t\t\t\texpectedMessageType: JSON.parse(pendingMessage.content).type,\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// Post-processing part - If we are processing a batch then this could be the last message in the batch.\n\t\tthis.maybeProcessBatchEnd(message);\n\n\t\treturn pendingMessage.localOpMetadata;\n\t}\n\n\t/**\n\t * This message could be the first message in batch. If so, set batch state marking the beginning of a batch.\n\t * @param message - The message that is being processed.\n\t */\n\tprivate maybeProcessBatchBegin(message: ISequencedDocumentMessage) {\n\t\t// This message is the first in a batch if the \"batch\" property on the metadata is set to true\n\t\tif ((message.metadata as IBatchMetadata | undefined)?.batch) {\n\t\t\t// We should not already be processing a batch and there should be no pending batch begin message.\n\t\t\tassert(\n\t\t\t\t!this.isProcessingBatch && this.pendingBatchBeginMessage === undefined,\n\t\t\t\t0x16b /* \"The pending batch state indicates we are already processing a batch\" */,\n\t\t\t);\n\n\t\t\t// Set the pending batch state indicating we have started processing a batch.\n\t\t\tthis.pendingBatchBeginMessage = message;\n\t\t\tthis.isProcessingBatch = true;\n\t\t}\n\t}\n\n\t/**\n\t * This message could be the last message in batch. If so, clear batch state since the batch is complete.\n\t * @param message - The message that is being processed.\n\t */\n\tprivate maybeProcessBatchEnd(message: ISequencedDocumentMessage) {\n\t\tif (!this.isProcessingBatch) {\n\t\t\treturn;\n\t\t}\n\n\t\t// There should be a pending batch begin message.\n\t\tassert(\n\t\t\tthis.pendingBatchBeginMessage !== undefined,\n\t\t\t0x16d /* \"There is no pending batch begin message\" */,\n\t\t);\n\n\t\tconst batchEndMetadata = (message.metadata as IBatchMetadata | undefined)?.batch;\n\t\tif (this.pendingMessages.isEmpty() || batchEndMetadata === false) {\n\t\t\t// Get the batch begin metadata from the first message in the batch.\n\t\t\tconst batchBeginMetadata = (\n\t\t\t\tthis.pendingBatchBeginMessage.metadata as IBatchMetadata | undefined\n\t\t\t)?.batch;\n\n\t\t\t// There could be just a single message in the batch. If so, it should not have any batch metadata. If there\n\t\t\t// are multiple messages in the batch, verify that we got the correct batch begin and end metadata.\n\t\t\tif (this.pendingBatchBeginMessage === message) {\n\t\t\t\tassert(\n\t\t\t\t\tbatchBeginMetadata === undefined,\n\t\t\t\t\t0x16e /* \"Batch with single message should not have batch metadata\" */,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tif (batchBeginMetadata !== true || batchEndMetadata !== false) {\n\t\t\t\t\tthis.stateHandler.close(\n\t\t\t\t\t\tDataProcessingError.create(\n\t\t\t\t\t\t\t\"Pending batch inconsistency\", // Formerly known as asserts 0x16f and 0x170\n\t\t\t\t\t\t\t\"processPendingLocalMessage\",\n\t\t\t\t\t\t\tmessage,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\truntimeVersion: pkgVersion,\n\t\t\t\t\t\t\t\tbatchClientId:\n\t\t\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing\n\t\t\t\t\t\t\t\t\tthis.pendingBatchBeginMessage.clientId === null\n\t\t\t\t\t\t\t\t\t\t? \"null\"\n\t\t\t\t\t\t\t\t\t\t: this.pendingBatchBeginMessage.clientId,\n\t\t\t\t\t\t\t\tclientId: this.stateHandler.clientId(),\n\t\t\t\t\t\t\t\thasBatchStart: batchBeginMetadata === true,\n\t\t\t\t\t\t\t\thasBatchEnd: batchEndMetadata === false,\n\t\t\t\t\t\t\t\tmessageType: message.type,\n\t\t\t\t\t\t\t\tpendingMessagesCount: this.pendingMessagesCount,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Clear the pending batch state now that we have processed the entire batch.\n\t\t\tthis.pendingBatchBeginMessage = undefined;\n\t\t\tthis.isProcessingBatch = false;\n\t\t}\n\t}\n\n\t/**\n\t * Called when the Container's connection state changes. If the Container gets connected, it replays all the pending\n\t * states in its queue. This includes triggering resubmission of unacked ops.\n\t * ! Note: successfully resubmitting an op that has been successfully sequenced is not possible due to checks in the ConnectionStateHandler (Loader layer)\n\t */\n\tpublic replayPendingStates() {\n\t\tassert(\n\t\t\tthis.stateHandler.connected(),\n\t\t\t0x172 /* \"The connection state is not consistent with the runtime\" */,\n\t\t);\n\n\t\t// This assert suggests we are about to send same ops twice, which will result in data loss.\n\t\tassert(\n\t\t\tthis.clientId !== this.stateHandler.clientId(),\n\t\t\t0x173 /* \"replayPendingStates called twice for same clientId!\" */,\n\t\t);\n\t\tthis.clientId = this.stateHandler.clientId();\n\n\t\tassert(\n\t\t\tthis.initialMessages.isEmpty(),\n\t\t\t0x174 /* \"initial states should be empty before replaying pending\" */,\n\t\t);\n\n\t\tconst initialPendingMessagesCount = this.pendingMessages.length;\n\t\tlet remainingPendingMessagesCount = this.pendingMessages.length;\n\n\t\t// Process exactly `pendingMessagesCount` items in the queue as it represents the number of messages that were\n\t\t// pending when we connected. This is important because the `reSubmitFn` might add more items in the queue\n\t\t// which must not be replayed.\n\t\twhile (remainingPendingMessagesCount > 0) {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\tlet pendingMessage = this.pendingMessages.shift()!;\n\t\t\tremainingPendingMessagesCount--;\n\t\t\tassert(\n\t\t\t\tpendingMessage.opMetadata?.batch !== false,\n\t\t\t\t0x41b /* We cannot process batches in chunks */,\n\t\t\t);\n\n\t\t\t/**\n\t\t\t * We want to ensure grouped messages get processed in a batch.\n\t\t\t * Note: It is not possible for the PendingStateManager to receive a partially acked batch. It will\n\t\t\t * either receive the whole batch ack or nothing at all.\n\t\t\t */\n\t\t\tif (pendingMessage.opMetadata?.batch) {\n\t\t\t\tassert(\n\t\t\t\t\tremainingPendingMessagesCount > 0,\n\t\t\t\t\t0x554 /* Last pending message cannot be a batch begin */,\n\t\t\t\t);\n\n\t\t\t\tconst batch: IPendingBatchMessage[] = [];\n\n\t\t\t\t// check is >= because batch end may be last pending message\n\t\t\t\twhile (remainingPendingMessagesCount >= 0) {\n\t\t\t\t\tbatch.push({\n\t\t\t\t\t\tcontent: pendingMessage.content,\n\t\t\t\t\t\tlocalOpMetadata: pendingMessage.localOpMetadata,\n\t\t\t\t\t\topMetadata: pendingMessage.opMetadata,\n\t\t\t\t\t});\n\n\t\t\t\t\tif (pendingMessage.opMetadata?.batch === false) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tassert(remainingPendingMessagesCount > 0, 0x555 /* No batch end found */);\n\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\t\tpendingMessage = this.pendingMessages.shift()!;\n\t\t\t\t\tremainingPendingMessagesCount--;\n\t\t\t\t\tassert(\n\t\t\t\t\t\tpendingMessage.opMetadata?.batch !== true,\n\t\t\t\t\t\t0x556 /* Batch start needs a corresponding batch end */,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tthis.stateHandler.reSubmitBatch(batch);\n\t\t\t} else {\n\t\t\t\tthis.stateHandler.reSubmit({\n\t\t\t\t\tcontent: pendingMessage.content,\n\t\t\t\t\tlocalOpMetadata: pendingMessage.localOpMetadata,\n\t\t\t\t\topMetadata: pendingMessage.opMetadata,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// pending ops should no longer depend on previous sequenced local ops after resubmit\n\t\tthis.savedOps = [];\n\n\t\t// We replayPendingStates on read connections too - we expect these to get nack'd though, and to then reconnect\n\t\t// on a write connection and replay again. This filters out the replay that happens on the read connection so\n\t\t// we only see the replays on write connections (that have a chance to go through).\n\t\tif (this.stateHandler.isActiveConnection()) {\n\t\t\tthis.logger?.sendTelemetryEvent({\n\t\t\t\teventName: \"PendingStatesReplayed\",\n\t\t\t\tcount: initialPendingMessagesCount,\n\t\t\t\tclientId: this.stateHandler.clientId(),\n\t\t\t});\n\t\t}\n\t}\n}\n"]}
@@ -4,8 +4,7 @@
4
4
  */
5
5
  import type { EventEmitter } from "@fluid-internal/client-utils";
6
6
  import { IDeltaManager } from "@fluidframework/container-definitions/internal";
7
- import { ISequencedDocumentMessage } from "@fluidframework/driver-definitions";
8
- import { IDocumentMessage } from "@fluidframework/driver-definitions/internal";
7
+ import { IDocumentMessage, ISequencedDocumentMessage } from "@fluidframework/driver-definitions/internal";
9
8
  import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils/internal";
10
9
  /**
11
10
  * This class has the following responsibilities:
@@ -1 +1 @@
1
- {"version":3,"file":"scheduleManager.d.ts","sourceRoot":"","sources":["../src/scheduleManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAEjE,OAAO,EAAE,aAAa,EAAE,MAAM,gDAAgD,CAAC;AAE/E,OAAO,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AAC/E,OAAO,EAAE,gBAAgB,EAAE,MAAM,6CAA6C,CAAC;AAE/E,OAAO,EACN,mBAAmB,EAKnB,MAAM,0CAA0C,CAAC;AAYlD;;;;;;;;GAQG;AACH,qBAAa,eAAe;IAM1B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,MAAM,GAAG,SAAS;IAC9C,OAAO,CAAC,QAAQ,CAAC,MAAM;IARxB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAiB;IAChD,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,QAAQ,CAAS;gBAGP,YAAY,EAAE,aAAa,CAAC,yBAAyB,EAAE,gBAAgB,CAAC,EACxE,OAAO,EAAE,YAAY,EAC7B,WAAW,EAAE,MAAM,MAAM,GAAG,SAAS,EAC7B,MAAM,EAAE,mBAAmB;IAStC,kBAAkB,CAAC,OAAO,EAAE,yBAAyB;IAkBrD,iBAAiB,CAAC,KAAK,EAAE,GAAG,GAAG,SAAS,EAAE,OAAO,EAAE,yBAAyB;CAwBnF"}
1
+ {"version":3,"file":"scheduleManager.d.ts","sourceRoot":"","sources":["../src/scheduleManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAEjE,OAAO,EAAE,aAAa,EAAE,MAAM,gDAAgD,CAAC;AAE/E,OAAO,EACN,gBAAgB,EAChB,yBAAyB,EACzB,MAAM,6CAA6C,CAAC;AAErD,OAAO,EACN,mBAAmB,EAKnB,MAAM,0CAA0C,CAAC;AAYlD;;;;;;;;GAQG;AACH,qBAAa,eAAe;IAM1B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,MAAM,GAAG,SAAS;IAC9C,OAAO,CAAC,QAAQ,CAAC,MAAM;IARxB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAiB;IAChD,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,QAAQ,CAAS;gBAGP,YAAY,EAAE,aAAa,CAAC,yBAAyB,EAAE,gBAAgB,CAAC,EACxE,OAAO,EAAE,YAAY,EAC7B,WAAW,EAAE,MAAM,MAAM,GAAG,SAAS,EAC7B,MAAM,EAAE,mBAAmB;IAStC,kBAAkB,CAAC,OAAO,EAAE,yBAAyB;IAkBrD,iBAAiB,CAAC,KAAK,EAAE,GAAG,GAAG,SAAS,EAAE,OAAO,EAAE,yBAAyB;CAwBnF"}
@@ -21,12 +21,18 @@ const packageVersion_js_1 = require("./packageVersion.js");
21
21
  * unless all ops of the batch are in.
22
22
  */
23
23
  class ScheduleManager {
24
+ deltaManager;
25
+ emitter;
26
+ getClientId;
27
+ logger;
28
+ deltaScheduler;
29
+ batchClientId;
30
+ hitError = false;
24
31
  constructor(deltaManager, emitter, getClientId, logger) {
25
32
  this.deltaManager = deltaManager;
26
33
  this.emitter = emitter;
27
34
  this.getClientId = getClientId;
28
35
  this.logger = logger;
29
- this.hitError = false;
30
36
  this.deltaScheduler = new deltaScheduler_js_1.DeltaScheduler(this.deltaManager, (0, internal_3.createChildLogger)({ logger: this.logger, namespace: "DeltaScheduler" }));
31
37
  void new ScheduleManagerCore(deltaManager, getClientId, logger);
32
38
  }
@@ -71,13 +77,18 @@ exports.ScheduleManager = ScheduleManager;
71
77
  * start processing ops in a batch IF we do not have all ops in the batch.
72
78
  */
73
79
  class ScheduleManagerCore {
80
+ deltaManager;
81
+ getClientId;
82
+ logger;
83
+ pauseSequenceNumber;
84
+ currentBatchClientId;
85
+ localPaused = false;
86
+ timePaused = 0;
87
+ batchCount = 0;
74
88
  constructor(deltaManager, getClientId, logger) {
75
89
  this.deltaManager = deltaManager;
76
90
  this.getClientId = getClientId;
77
91
  this.logger = logger;
78
- this.localPaused = false;
79
- this.timePaused = 0;
80
- this.batchCount = 0;
81
92
  // Listen for delta manager sends and add batch metadata to messages
82
93
  this.deltaManager.on("prepareSend", (messages) => {
83
94
  if (messages.length === 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"scheduleManager.js","sourceRoot":"","sources":["../src/scheduleManager.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 type { EventEmitter } from \"@fluid-internal/client-utils\";\nimport { performance } from \"@fluid-internal/client-utils\";\nimport { IDeltaManager } from \"@fluidframework/container-definitions/internal\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport { ISequencedDocumentMessage } from \"@fluidframework/driver-definitions\";\nimport { IDocumentMessage } from \"@fluidframework/driver-definitions/internal\";\nimport { isRuntimeMessage } from \"@fluidframework/driver-utils/internal\";\nimport {\n\tITelemetryLoggerExt,\n\tDataCorruptionError,\n\tDataProcessingError,\n\tcreateChildLogger,\n\textractSafePropertiesFromMessage,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nimport { DeltaScheduler } from \"./deltaScheduler.js\";\nimport { IBatchMetadata } from \"./metadata.js\";\nimport { pkgVersion } from \"./packageVersion.js\";\n\ntype IRuntimeMessageMetadata =\n\t| undefined\n\t| {\n\t\t\tbatch?: boolean;\n\t };\n\n/**\n * This class has the following responsibilities:\n *\n * 1. It tracks batches as we process ops and raises \"batchBegin\" and \"batchEnd\" events.\n * As part of it, it validates batch correctness (i.e. no system ops in the middle of batch)\n *\n * 2. It creates instance of ScheduleManagerCore that ensures we never start processing ops from batch\n * unless all ops of the batch are in.\n */\nexport class ScheduleManager {\n\tprivate readonly deltaScheduler: DeltaScheduler;\n\tprivate batchClientId: string | undefined;\n\tprivate hitError = false;\n\n\tconstructor(\n\t\tprivate readonly deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>,\n\t\tprivate readonly emitter: EventEmitter,\n\t\treadonly getClientId: () => string | undefined,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t) {\n\t\tthis.deltaScheduler = new DeltaScheduler(\n\t\t\tthis.deltaManager,\n\t\t\tcreateChildLogger({ logger: this.logger, namespace: \"DeltaScheduler\" }),\n\t\t);\n\t\tvoid new ScheduleManagerCore(deltaManager, getClientId, logger);\n\t}\n\n\tpublic beforeOpProcessing(message: ISequencedDocumentMessage) {\n\t\tif (this.batchClientId !== message.clientId) {\n\t\t\tassert(\n\t\t\t\tthis.batchClientId === undefined,\n\t\t\t\t0x2a2 /* \"Batch is interrupted by other client op. Should be caught by trackPending()\" */,\n\t\t\t);\n\n\t\t\t// This could be the beginning of a new batch or an individual message.\n\t\t\tthis.emitter.emit(\"batchBegin\", message);\n\t\t\tthis.deltaScheduler.batchBegin(message);\n\n\t\t\tconst batch = (message?.metadata as IRuntimeMessageMetadata)?.batch;\n\t\t\t// TODO: Verify whether this should be able to handle server-generated ops (with null clientId)\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n\t\t\tthis.batchClientId = batch ? (message.clientId as string) : undefined;\n\t\t}\n\t}\n\n\tpublic afterOpProcessing(error: any | undefined, message: ISequencedDocumentMessage) {\n\t\t// If this is no longer true, we need to revisit what we do where we set this.hitError.\n\t\tassert(!this.hitError, 0x2a3 /* \"container should be closed on any error\" */);\n\n\t\tif (error) {\n\t\t\t// We assume here that loader will close container and stop processing all future ops.\n\t\t\t// This is implicit dependency. If this flow changes, this code might no longer be correct.\n\t\t\tthis.hitError = true;\n\t\t\tthis.batchClientId = undefined;\n\t\t\tthis.emitter.emit(\"batchEnd\", error, message);\n\t\t\tthis.deltaScheduler.batchEnd(message);\n\t\t\treturn;\n\t\t}\n\n\t\tconst batch = (message?.metadata as IRuntimeMessageMetadata)?.batch;\n\t\t// If no batchClientId has been set then we're in an individual batch. Else, if we get\n\t\t// batch end metadata, this is end of the current batch.\n\t\tif (this.batchClientId === undefined || batch === false) {\n\t\t\tthis.batchClientId = undefined;\n\t\t\tthis.emitter.emit(\"batchEnd\", undefined, message);\n\t\t\tthis.deltaScheduler.batchEnd(message);\n\t\t\treturn;\n\t\t}\n\t}\n}\n\n/**\n * This class controls pausing and resuming of inbound queue to ensure that we never\n * start processing ops in a batch IF we do not have all ops in the batch.\n */\nclass ScheduleManagerCore {\n\tprivate pauseSequenceNumber: number | undefined;\n\tprivate currentBatchClientId: string | undefined;\n\tprivate localPaused = false;\n\tprivate timePaused = 0;\n\tprivate batchCount = 0;\n\n\tconstructor(\n\t\tprivate readonly deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>,\n\t\tprivate readonly getClientId: () => string | undefined,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t) {\n\t\t// Listen for delta manager sends and add batch metadata to messages\n\t\tthis.deltaManager.on(\"prepareSend\", (messages: IDocumentMessage[]) => {\n\t\t\tif (messages.length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// First message will have the batch flag set to true if doing a batched send\n\t\t\tconst firstMessageMetadata = messages[0].metadata as IRuntimeMessageMetadata;\n\t\t\tif (!firstMessageMetadata?.batch) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If the batch contains only a single op, clear the batch flag.\n\t\t\tif (messages.length === 1) {\n\t\t\t\tdelete firstMessageMetadata.batch;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Set the batch flag to false on the last message to indicate the end of the send batch\n\t\t\tconst lastMessage = messages[messages.length - 1];\n\t\t\t// TODO: It's not clear if this shallow clone is required, as opposed to just setting \"batch\" to false.\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n\t\t\tlastMessage.metadata = { ...(lastMessage.metadata as any), batch: false };\n\t\t});\n\n\t\t// Listen for updates and peek at the inbound\n\t\tthis.deltaManager.inbound.on(\"push\", (message: ISequencedDocumentMessage) => {\n\t\t\tthis.trackPending(message);\n\t\t});\n\n\t\t// Start with baseline - empty inbound queue.\n\t\tassert(!this.localPaused, 0x293 /* \"initial state\" */);\n\n\t\tconst allPending = this.deltaManager.inbound.toArray();\n\t\tfor (const pending of allPending) {\n\t\t\tthis.trackPending(pending);\n\t\t}\n\n\t\t// We are intentionally directly listening to the \"op\" to inspect system ops as well.\n\t\t// If we do not observe system ops, we are likely to hit 0x296 assert when system ops\n\t\t// precedes start of incomplete batch.\n\t\tthis.deltaManager.on(\"op\", (message) => this.afterOpProcessing(message));\n\t}\n\n\t/**\n\t * The only public function in this class - called when we processed an op,\n\t * to make decision if op processing should be paused or not after that.\n\t */\n\tpublic afterOpProcessing(message: ISequencedDocumentMessage) {\n\t\tassert(\n\t\t\t!this.localPaused,\n\t\t\t0x294 /* \"can't have op processing paused if we are processing an op\" */,\n\t\t);\n\n\t\t// If the inbound queue is ever empty, nothing to do!\n\t\tif (this.deltaManager.inbound.length === 0) {\n\t\t\tassert(\n\t\t\t\tthis.pauseSequenceNumber === undefined,\n\t\t\t\t0x295 /* \"there should be no pending batch if we have no ops\" */,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// The queue is\n\t\t// 1. paused only when the next message to be processed is the beginning of a batch. Done in two places:\n\t\t// - here (processing ops until reaching start of incomplete batch)\n\t\t// - in trackPending(), when queue was empty and start of batch showed up.\n\t\t// 2. resumed when batch end comes in (in trackPending())\n\n\t\t// do we have incomplete batch to worry about?\n\t\tif (this.pauseSequenceNumber !== undefined) {\n\t\t\tif (message.sequenceNumber >= this.pauseSequenceNumber) {\n\t\t\t\tthrow DataProcessingError.create(\n\t\t\t\t\t// Former assert 0x296\n\t\t\t\t\t\"Incomplete batch\",\n\t\t\t\t\t\"ScheduleManager\",\n\t\t\t\t\tmessage,\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: message.type,\n\t\t\t\t\t\tcontentType: typeof message.contents,\n\t\t\t\t\t\tbatch: (message.metadata as IBatchMetadata | undefined)?.batch,\n\t\t\t\t\t\tcompression: message.compression,\n\t\t\t\t\t\tpauseSeqNum: this.pauseSequenceNumber,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// If the next op is the start of incomplete batch, then we can't process it until it's fully in - pause!\n\t\t\tif (message.sequenceNumber + 1 === this.pauseSequenceNumber) {\n\t\t\t\tthis.pauseQueue();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate pauseQueue() {\n\t\tassert(!this.localPaused, 0x297 /* \"always called from resumed state\" */);\n\t\tthis.localPaused = true;\n\t\tthis.timePaused = performance.now();\n\t\t// eslint-disable-next-line @typescript-eslint/no-floating-promises\n\t\tthis.deltaManager.inbound.pause();\n\t}\n\n\tprivate resumeQueue(startBatch: number, messageEndBatch: ISequencedDocumentMessage) {\n\t\tconst endBatch = messageEndBatch.sequenceNumber;\n\t\tconst duration = this.localPaused ? performance.now() - this.timePaused : undefined;\n\n\t\tthis.batchCount++;\n\t\tif (this.batchCount % 1000 === 1) {\n\t\t\tthis.logger.sendTelemetryEvent({\n\t\t\t\teventName: \"BatchStats\",\n\t\t\t\tsequenceNumber: endBatch,\n\t\t\t\tlength: endBatch - startBatch + 1,\n\t\t\t\tmsnDistance: endBatch - messageEndBatch.minimumSequenceNumber,\n\t\t\t\tduration,\n\t\t\t\tbatchCount: this.batchCount,\n\t\t\t\tinterrupted: this.localPaused,\n\t\t\t});\n\t\t}\n\n\t\t// Return early if no change in value\n\t\tif (!this.localPaused) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.localPaused = false;\n\n\t\tthis.deltaManager.inbound.resume();\n\t}\n\n\t/**\n\t * Called for each incoming op (i.e. inbound \"push\" notification)\n\t */\n\tprivate trackPending(message: ISequencedDocumentMessage) {\n\t\tassert(\n\t\t\tthis.deltaManager.inbound.length !== 0,\n\t\t\t0x298 /* \"we have something in the queue that generates this event\" */,\n\t\t);\n\n\t\tassert(\n\t\t\t(this.currentBatchClientId === undefined) === (this.pauseSequenceNumber === undefined),\n\t\t\t0x299 /* \"non-synchronized state\" */,\n\t\t);\n\n\t\tconst metadata = message.metadata as IRuntimeMessageMetadata;\n\t\t// batchMetadata will be true for the message that starts a batch, false for the one that ends it, and\n\t\t// undefined for all other messages.\n\t\tconst batchMetadata = metadata?.batch;\n\n\t\t// Protocol messages are never part of a runtime batch of messages\n\t\tif (!isRuntimeMessage(message)) {\n\t\t\t// Protocol messages should never show up in the middle of the batch!\n\t\t\tif (this.currentBatchClientId !== undefined) {\n\t\t\t\tthrow DataProcessingError.create(\n\t\t\t\t\t\"Received a system message during batch processing\", // Formerly known as assert 0x29a\n\t\t\t\t\t\"trackPending\",\n\t\t\t\t\tmessage,\n\t\t\t\t\t{\n\t\t\t\t\t\truntimeVersion: pkgVersion,\n\t\t\t\t\t\tbatchClientId:\n\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing\n\t\t\t\t\t\t\tthis.currentBatchClientId === null ? \"null\" : this.currentBatchClientId,\n\t\t\t\t\t\tpauseSequenceNumber: this.pauseSequenceNumber,\n\t\t\t\t\t\tlocalBatch: this.currentBatchClientId === this.getClientId(),\n\t\t\t\t\t\tmessageType: message.type,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tassert(batchMetadata === undefined, 0x29b /* \"system op in a batch?\" */);\n\t\t\tassert(\n\t\t\t\t!this.localPaused,\n\t\t\t\t0x29c /* \"we should be processing ops when there is no active batch\" */,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.currentBatchClientId === undefined && batchMetadata === undefined) {\n\t\t\tassert(\n\t\t\t\t!this.localPaused,\n\t\t\t\t0x29d /* \"we should be processing ops when there is no active batch\" */,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// If we got here, the message is part of a batch. Either starting, in progress, or ending.\n\n\t\t// If this is not the start of the batch, error out if the message was sent by a client other than the one that\n\t\t// started the current batch (it should not be possible for ops from other clients to get interleaved with a batch).\n\t\tif (\n\t\t\tthis.currentBatchClientId !== undefined &&\n\t\t\tthis.currentBatchClientId !== message.clientId\n\t\t) {\n\t\t\tthrow new DataCorruptionError(\"OpBatchIncomplete\", {\n\t\t\t\truntimeVersion: pkgVersion,\n\t\t\t\tbatchClientId:\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing\n\t\t\t\t\tthis.currentBatchClientId === null ? \"null\" : this.currentBatchClientId,\n\t\t\t\tpauseSequenceNumber: this.pauseSequenceNumber,\n\t\t\t\tlocalBatch: this.currentBatchClientId === this.getClientId(),\n\t\t\t\tlocalMessage: message.clientId === this.getClientId(),\n\t\t\t\t...extractSafePropertiesFromMessage(message),\n\t\t\t});\n\t\t}\n\n\t\t// The queue is\n\t\t// 1. paused only when the next message to be processed is the beginning of a batch. Done in two places:\n\t\t// - in afterOpProcessing() - processing ops until reaching start of incomplete batch\n\t\t// - here, when queue was empty and start of batch showed up (batchMetadata === true below).\n\t\t// 2. resumed when batch end comes in (batchMetadata === false below)\n\n\t\tif (batchMetadata) {\n\t\t\tassert(\n\t\t\t\tthis.currentBatchClientId === undefined,\n\t\t\t\t0x29e /* \"there can't be active batch\" */,\n\t\t\t);\n\t\t\tassert(\n\t\t\t\t!this.localPaused,\n\t\t\t\t0x29f /* \"we should be processing ops when there is no active batch\" */,\n\t\t\t);\n\t\t\tthis.pauseSequenceNumber = message.sequenceNumber;\n\t\t\t// TODO: Verify whether this should be able to handle server-generated ops (with null clientId)\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n\t\t\tthis.currentBatchClientId = message.clientId as string;\n\t\t\t// Start of the batch\n\t\t\t// Only pause processing if queue has no other ops!\n\t\t\t// If there are any other ops in the queue, processing will be stopped when they are processed!\n\t\t\tif (this.deltaManager.inbound.length === 1) {\n\t\t\t\tthis.pauseQueue();\n\t\t\t}\n\t\t} else if (batchMetadata === false) {\n\t\t\tassert(\n\t\t\t\tthis.pauseSequenceNumber !== undefined,\n\t\t\t\t0x2a0 /* \"batch presence was validated above\" */,\n\t\t\t);\n\t\t\t// Batch is complete, we can process it!\n\t\t\tthis.resumeQueue(this.pauseSequenceNumber, message);\n\t\t\tthis.pauseSequenceNumber = undefined;\n\t\t\tthis.currentBatchClientId = undefined;\n\t\t} else {\n\t\t\t// Continuation of current batch. Do nothing\n\t\t\tassert(this.currentBatchClientId !== undefined, 0x2a1 /* \"logic error\" */);\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"scheduleManager.js","sourceRoot":"","sources":["../src/scheduleManager.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 type { EventEmitter } from \"@fluid-internal/client-utils\";\nimport { performance } from \"@fluid-internal/client-utils\";\nimport { IDeltaManager } from \"@fluidframework/container-definitions/internal\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport {\n\tIDocumentMessage,\n\tISequencedDocumentMessage,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { isRuntimeMessage } from \"@fluidframework/driver-utils/internal\";\nimport {\n\tITelemetryLoggerExt,\n\tDataCorruptionError,\n\tDataProcessingError,\n\tcreateChildLogger,\n\textractSafePropertiesFromMessage,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nimport { DeltaScheduler } from \"./deltaScheduler.js\";\nimport { IBatchMetadata } from \"./metadata.js\";\nimport { pkgVersion } from \"./packageVersion.js\";\n\ntype IRuntimeMessageMetadata =\n\t| undefined\n\t| {\n\t\t\tbatch?: boolean;\n\t };\n\n/**\n * This class has the following responsibilities:\n *\n * 1. It tracks batches as we process ops and raises \"batchBegin\" and \"batchEnd\" events.\n * As part of it, it validates batch correctness (i.e. no system ops in the middle of batch)\n *\n * 2. It creates instance of ScheduleManagerCore that ensures we never start processing ops from batch\n * unless all ops of the batch are in.\n */\nexport class ScheduleManager {\n\tprivate readonly deltaScheduler: DeltaScheduler;\n\tprivate batchClientId: string | undefined;\n\tprivate hitError = false;\n\n\tconstructor(\n\t\tprivate readonly deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>,\n\t\tprivate readonly emitter: EventEmitter,\n\t\treadonly getClientId: () => string | undefined,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t) {\n\t\tthis.deltaScheduler = new DeltaScheduler(\n\t\t\tthis.deltaManager,\n\t\t\tcreateChildLogger({ logger: this.logger, namespace: \"DeltaScheduler\" }),\n\t\t);\n\t\tvoid new ScheduleManagerCore(deltaManager, getClientId, logger);\n\t}\n\n\tpublic beforeOpProcessing(message: ISequencedDocumentMessage) {\n\t\tif (this.batchClientId !== message.clientId) {\n\t\t\tassert(\n\t\t\t\tthis.batchClientId === undefined,\n\t\t\t\t0x2a2 /* \"Batch is interrupted by other client op. Should be caught by trackPending()\" */,\n\t\t\t);\n\n\t\t\t// This could be the beginning of a new batch or an individual message.\n\t\t\tthis.emitter.emit(\"batchBegin\", message);\n\t\t\tthis.deltaScheduler.batchBegin(message);\n\n\t\t\tconst batch = (message?.metadata as IRuntimeMessageMetadata)?.batch;\n\t\t\t// TODO: Verify whether this should be able to handle server-generated ops (with null clientId)\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n\t\t\tthis.batchClientId = batch ? (message.clientId as string) : undefined;\n\t\t}\n\t}\n\n\tpublic afterOpProcessing(error: any | undefined, message: ISequencedDocumentMessage) {\n\t\t// If this is no longer true, we need to revisit what we do where we set this.hitError.\n\t\tassert(!this.hitError, 0x2a3 /* \"container should be closed on any error\" */);\n\n\t\tif (error) {\n\t\t\t// We assume here that loader will close container and stop processing all future ops.\n\t\t\t// This is implicit dependency. If this flow changes, this code might no longer be correct.\n\t\t\tthis.hitError = true;\n\t\t\tthis.batchClientId = undefined;\n\t\t\tthis.emitter.emit(\"batchEnd\", error, message);\n\t\t\tthis.deltaScheduler.batchEnd(message);\n\t\t\treturn;\n\t\t}\n\n\t\tconst batch = (message?.metadata as IRuntimeMessageMetadata)?.batch;\n\t\t// If no batchClientId has been set then we're in an individual batch. Else, if we get\n\t\t// batch end metadata, this is end of the current batch.\n\t\tif (this.batchClientId === undefined || batch === false) {\n\t\t\tthis.batchClientId = undefined;\n\t\t\tthis.emitter.emit(\"batchEnd\", undefined, message);\n\t\t\tthis.deltaScheduler.batchEnd(message);\n\t\t\treturn;\n\t\t}\n\t}\n}\n\n/**\n * This class controls pausing and resuming of inbound queue to ensure that we never\n * start processing ops in a batch IF we do not have all ops in the batch.\n */\nclass ScheduleManagerCore {\n\tprivate pauseSequenceNumber: number | undefined;\n\tprivate currentBatchClientId: string | undefined;\n\tprivate localPaused = false;\n\tprivate timePaused = 0;\n\tprivate batchCount = 0;\n\n\tconstructor(\n\t\tprivate readonly deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>,\n\t\tprivate readonly getClientId: () => string | undefined,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t) {\n\t\t// Listen for delta manager sends and add batch metadata to messages\n\t\tthis.deltaManager.on(\"prepareSend\", (messages: IDocumentMessage[]) => {\n\t\t\tif (messages.length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// First message will have the batch flag set to true if doing a batched send\n\t\t\tconst firstMessageMetadata = messages[0].metadata as IRuntimeMessageMetadata;\n\t\t\tif (!firstMessageMetadata?.batch) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If the batch contains only a single op, clear the batch flag.\n\t\t\tif (messages.length === 1) {\n\t\t\t\tdelete firstMessageMetadata.batch;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Set the batch flag to false on the last message to indicate the end of the send batch\n\t\t\tconst lastMessage = messages[messages.length - 1];\n\t\t\t// TODO: It's not clear if this shallow clone is required, as opposed to just setting \"batch\" to false.\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n\t\t\tlastMessage.metadata = { ...(lastMessage.metadata as any), batch: false };\n\t\t});\n\n\t\t// Listen for updates and peek at the inbound\n\t\tthis.deltaManager.inbound.on(\"push\", (message: ISequencedDocumentMessage) => {\n\t\t\tthis.trackPending(message);\n\t\t});\n\n\t\t// Start with baseline - empty inbound queue.\n\t\tassert(!this.localPaused, 0x293 /* \"initial state\" */);\n\n\t\tconst allPending = this.deltaManager.inbound.toArray();\n\t\tfor (const pending of allPending) {\n\t\t\tthis.trackPending(pending);\n\t\t}\n\n\t\t// We are intentionally directly listening to the \"op\" to inspect system ops as well.\n\t\t// If we do not observe system ops, we are likely to hit 0x296 assert when system ops\n\t\t// precedes start of incomplete batch.\n\t\tthis.deltaManager.on(\"op\", (message) => this.afterOpProcessing(message));\n\t}\n\n\t/**\n\t * The only public function in this class - called when we processed an op,\n\t * to make decision if op processing should be paused or not after that.\n\t */\n\tpublic afterOpProcessing(message: ISequencedDocumentMessage) {\n\t\tassert(\n\t\t\t!this.localPaused,\n\t\t\t0x294 /* \"can't have op processing paused if we are processing an op\" */,\n\t\t);\n\n\t\t// If the inbound queue is ever empty, nothing to do!\n\t\tif (this.deltaManager.inbound.length === 0) {\n\t\t\tassert(\n\t\t\t\tthis.pauseSequenceNumber === undefined,\n\t\t\t\t0x295 /* \"there should be no pending batch if we have no ops\" */,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// The queue is\n\t\t// 1. paused only when the next message to be processed is the beginning of a batch. Done in two places:\n\t\t// - here (processing ops until reaching start of incomplete batch)\n\t\t// - in trackPending(), when queue was empty and start of batch showed up.\n\t\t// 2. resumed when batch end comes in (in trackPending())\n\n\t\t// do we have incomplete batch to worry about?\n\t\tif (this.pauseSequenceNumber !== undefined) {\n\t\t\tif (message.sequenceNumber >= this.pauseSequenceNumber) {\n\t\t\t\tthrow DataProcessingError.create(\n\t\t\t\t\t// Former assert 0x296\n\t\t\t\t\t\"Incomplete batch\",\n\t\t\t\t\t\"ScheduleManager\",\n\t\t\t\t\tmessage,\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: message.type,\n\t\t\t\t\t\tcontentType: typeof message.contents,\n\t\t\t\t\t\tbatch: (message.metadata as IBatchMetadata | undefined)?.batch,\n\t\t\t\t\t\tcompression: message.compression,\n\t\t\t\t\t\tpauseSeqNum: this.pauseSequenceNumber,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// If the next op is the start of incomplete batch, then we can't process it until it's fully in - pause!\n\t\t\tif (message.sequenceNumber + 1 === this.pauseSequenceNumber) {\n\t\t\t\tthis.pauseQueue();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate pauseQueue() {\n\t\tassert(!this.localPaused, 0x297 /* \"always called from resumed state\" */);\n\t\tthis.localPaused = true;\n\t\tthis.timePaused = performance.now();\n\t\t// eslint-disable-next-line @typescript-eslint/no-floating-promises\n\t\tthis.deltaManager.inbound.pause();\n\t}\n\n\tprivate resumeQueue(startBatch: number, messageEndBatch: ISequencedDocumentMessage) {\n\t\tconst endBatch = messageEndBatch.sequenceNumber;\n\t\tconst duration = this.localPaused ? performance.now() - this.timePaused : undefined;\n\n\t\tthis.batchCount++;\n\t\tif (this.batchCount % 1000 === 1) {\n\t\t\tthis.logger.sendTelemetryEvent({\n\t\t\t\teventName: \"BatchStats\",\n\t\t\t\tsequenceNumber: endBatch,\n\t\t\t\tlength: endBatch - startBatch + 1,\n\t\t\t\tmsnDistance: endBatch - messageEndBatch.minimumSequenceNumber,\n\t\t\t\tduration,\n\t\t\t\tbatchCount: this.batchCount,\n\t\t\t\tinterrupted: this.localPaused,\n\t\t\t});\n\t\t}\n\n\t\t// Return early if no change in value\n\t\tif (!this.localPaused) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.localPaused = false;\n\n\t\tthis.deltaManager.inbound.resume();\n\t}\n\n\t/**\n\t * Called for each incoming op (i.e. inbound \"push\" notification)\n\t */\n\tprivate trackPending(message: ISequencedDocumentMessage) {\n\t\tassert(\n\t\t\tthis.deltaManager.inbound.length !== 0,\n\t\t\t0x298 /* \"we have something in the queue that generates this event\" */,\n\t\t);\n\n\t\tassert(\n\t\t\t(this.currentBatchClientId === undefined) === (this.pauseSequenceNumber === undefined),\n\t\t\t0x299 /* \"non-synchronized state\" */,\n\t\t);\n\n\t\tconst metadata = message.metadata as IRuntimeMessageMetadata;\n\t\t// batchMetadata will be true for the message that starts a batch, false for the one that ends it, and\n\t\t// undefined for all other messages.\n\t\tconst batchMetadata = metadata?.batch;\n\n\t\t// Protocol messages are never part of a runtime batch of messages\n\t\tif (!isRuntimeMessage(message)) {\n\t\t\t// Protocol messages should never show up in the middle of the batch!\n\t\t\tif (this.currentBatchClientId !== undefined) {\n\t\t\t\tthrow DataProcessingError.create(\n\t\t\t\t\t\"Received a system message during batch processing\", // Formerly known as assert 0x29a\n\t\t\t\t\t\"trackPending\",\n\t\t\t\t\tmessage,\n\t\t\t\t\t{\n\t\t\t\t\t\truntimeVersion: pkgVersion,\n\t\t\t\t\t\tbatchClientId:\n\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing\n\t\t\t\t\t\t\tthis.currentBatchClientId === null ? \"null\" : this.currentBatchClientId,\n\t\t\t\t\t\tpauseSequenceNumber: this.pauseSequenceNumber,\n\t\t\t\t\t\tlocalBatch: this.currentBatchClientId === this.getClientId(),\n\t\t\t\t\t\tmessageType: message.type,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tassert(batchMetadata === undefined, 0x29b /* \"system op in a batch?\" */);\n\t\t\tassert(\n\t\t\t\t!this.localPaused,\n\t\t\t\t0x29c /* \"we should be processing ops when there is no active batch\" */,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.currentBatchClientId === undefined && batchMetadata === undefined) {\n\t\t\tassert(\n\t\t\t\t!this.localPaused,\n\t\t\t\t0x29d /* \"we should be processing ops when there is no active batch\" */,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// If we got here, the message is part of a batch. Either starting, in progress, or ending.\n\n\t\t// If this is not the start of the batch, error out if the message was sent by a client other than the one that\n\t\t// started the current batch (it should not be possible for ops from other clients to get interleaved with a batch).\n\t\tif (\n\t\t\tthis.currentBatchClientId !== undefined &&\n\t\t\tthis.currentBatchClientId !== message.clientId\n\t\t) {\n\t\t\tthrow new DataCorruptionError(\"OpBatchIncomplete\", {\n\t\t\t\truntimeVersion: pkgVersion,\n\t\t\t\tbatchClientId:\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing\n\t\t\t\t\tthis.currentBatchClientId === null ? \"null\" : this.currentBatchClientId,\n\t\t\t\tpauseSequenceNumber: this.pauseSequenceNumber,\n\t\t\t\tlocalBatch: this.currentBatchClientId === this.getClientId(),\n\t\t\t\tlocalMessage: message.clientId === this.getClientId(),\n\t\t\t\t...extractSafePropertiesFromMessage(message),\n\t\t\t});\n\t\t}\n\n\t\t// The queue is\n\t\t// 1. paused only when the next message to be processed is the beginning of a batch. Done in two places:\n\t\t// - in afterOpProcessing() - processing ops until reaching start of incomplete batch\n\t\t// - here, when queue was empty and start of batch showed up (batchMetadata === true below).\n\t\t// 2. resumed when batch end comes in (batchMetadata === false below)\n\n\t\tif (batchMetadata) {\n\t\t\tassert(\n\t\t\t\tthis.currentBatchClientId === undefined,\n\t\t\t\t0x29e /* \"there can't be active batch\" */,\n\t\t\t);\n\t\t\tassert(\n\t\t\t\t!this.localPaused,\n\t\t\t\t0x29f /* \"we should be processing ops when there is no active batch\" */,\n\t\t\t);\n\t\t\tthis.pauseSequenceNumber = message.sequenceNumber;\n\t\t\t// TODO: Verify whether this should be able to handle server-generated ops (with null clientId)\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n\t\t\tthis.currentBatchClientId = message.clientId as string;\n\t\t\t// Start of the batch\n\t\t\t// Only pause processing if queue has no other ops!\n\t\t\t// If there are any other ops in the queue, processing will be stopped when they are processed!\n\t\t\tif (this.deltaManager.inbound.length === 1) {\n\t\t\t\tthis.pauseQueue();\n\t\t\t}\n\t\t} else if (batchMetadata === false) {\n\t\t\tassert(\n\t\t\t\tthis.pauseSequenceNumber !== undefined,\n\t\t\t\t0x2a0 /* \"batch presence was validated above\" */,\n\t\t\t);\n\t\t\t// Batch is complete, we can process it!\n\t\t\tthis.resumeQueue(this.pauseSequenceNumber, message);\n\t\t\tthis.pauseSequenceNumber = undefined;\n\t\t\tthis.currentBatchClientId = undefined;\n\t\t} else {\n\t\t\t// Continuation of current batch. Do nothing\n\t\t\tassert(this.currentBatchClientId !== undefined, 0x2a1 /* \"logic error\" */);\n\t\t}\n\t}\n}\n"]}
@@ -11,6 +11,7 @@ const internal_1 = require("@fluidframework/driver-utils/internal");
11
11
  * attach message. We use this to avoid an unnecessary request to the storage service.
12
12
  */
13
13
  class StorageServiceWithAttachBlobs extends internal_1.DocumentStorageServiceProxy {
14
+ attachBlobs;
14
15
  constructor(internalStorageService, attachBlobs) {
15
16
  super(internalStorageService);
16
17
  this.attachBlobs = attachBlobs;
@@ -1 +1 @@
1
- {"version":3,"file":"storageServiceWithAttachBlobs.js","sourceRoot":"","sources":["../src/storageServiceWithAttachBlobs.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAMH,oEAAoF;AAEpF;;;GAGG;AACH,MAAa,6BAA8B,SAAQ,sCAA2B;IAC7E,YACC,sBAA+C,EAC9B,WAAyC;QAE1D,KAAK,CAAC,sBAAsB,CAAC,CAAC;QAFb,gBAAW,GAAX,WAAW,CAA8B;IAG3D,CAAC;IAED,IAAW,QAAQ;QAClB,OAAO,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC;IAC7C,CAAC;IAEM,KAAK,CAAC,QAAQ,CAAC,EAAU;QAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACtC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC;QACb,CAAC;QAED,8FAA8F;QAC9F,2EAA2E;QAC3E,OAAO,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACjD,CAAC;CACD;AAtBD,sEAsBC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tIDocumentStorageService,\n\tIDocumentStorageServicePolicies,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { DocumentStorageServiceProxy } from \"@fluidframework/driver-utils/internal\";\n\n/**\n * IDocumentStorageService proxy which intercepts requests if they can be satisfied by the blobs received in the\n * attach message. We use this to avoid an unnecessary request to the storage service.\n */\nexport class StorageServiceWithAttachBlobs extends DocumentStorageServiceProxy {\n\tconstructor(\n\t\tinternalStorageService: IDocumentStorageService,\n\t\tprivate readonly attachBlobs: Map<string, ArrayBufferLike>,\n\t) {\n\t\tsuper(internalStorageService);\n\t}\n\n\tpublic get policies(): IDocumentStorageServicePolicies | undefined {\n\t\treturn this.internalStorageService.policies;\n\t}\n\n\tpublic async readBlob(id: string): Promise<ArrayBufferLike> {\n\t\tconst blob = this.attachBlobs.get(id);\n\t\tif (blob !== undefined) {\n\t\t\treturn blob;\n\t\t}\n\n\t\t// Note that it is intentional not to cache the result of this readBlob - we'll trust the real\n\t\t// IDocumentStorageService to cache appropriately, no need to double-cache.\n\t\treturn this.internalStorageService.readBlob(id);\n\t}\n}\n"]}
1
+ {"version":3,"file":"storageServiceWithAttachBlobs.js","sourceRoot":"","sources":["../src/storageServiceWithAttachBlobs.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAMH,oEAAoF;AAEpF;;;GAGG;AACH,MAAa,6BAA8B,SAAQ,sCAA2B;IAG3D;IAFlB,YACC,sBAA+C,EAC9B,WAAyC;QAE1D,KAAK,CAAC,sBAAsB,CAAC,CAAC;QAFb,gBAAW,GAAX,WAAW,CAA8B;IAG3D,CAAC;IAED,IAAW,QAAQ;QAClB,OAAO,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC;IAC7C,CAAC;IAEM,KAAK,CAAC,QAAQ,CAAC,EAAU;QAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACtC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC;QACb,CAAC;QAED,8FAA8F;QAC9F,2EAA2E;QAC3E,OAAO,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACjD,CAAC;CACD;AAtBD,sEAsBC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tIDocumentStorageService,\n\tIDocumentStorageServicePolicies,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { DocumentStorageServiceProxy } from \"@fluidframework/driver-utils/internal\";\n\n/**\n * IDocumentStorageService proxy which intercepts requests if they can be satisfied by the blobs received in the\n * attach message. We use this to avoid an unnecessary request to the storage service.\n */\nexport class StorageServiceWithAttachBlobs extends DocumentStorageServiceProxy {\n\tconstructor(\n\t\tinternalStorageService: IDocumentStorageService,\n\t\tprivate readonly attachBlobs: Map<string, ArrayBufferLike>,\n\t) {\n\t\tsuper(internalStorageService);\n\t}\n\n\tpublic get policies(): IDocumentStorageServicePolicies | undefined {\n\t\treturn this.internalStorageService.policies;\n\t}\n\n\tpublic async readBlob(id: string): Promise<ArrayBufferLike> {\n\t\tconst blob = this.attachBlobs.get(id);\n\t\tif (blob !== undefined) {\n\t\t\treturn blob;\n\t\t}\n\n\t\t// Note that it is intentional not to cache the result of this readBlob - we'll trust the real\n\t\t// IDocumentStorageService to cache appropriately, no need to double-cache.\n\t\treturn this.internalStorageService.readBlob(id);\n\t}\n}\n"]}
@@ -33,6 +33,7 @@ class TrueOrUndefinedMax extends TrueOrUndefined {
33
33
  }
34
34
  }
35
35
  class MultiChoice {
36
+ choices;
36
37
  constructor(choices) {
37
38
  this.choices = choices;
38
39
  }
@@ -247,6 +248,22 @@ function arrayToProp(arr) {
247
248
  * @alpha
248
249
  */
249
250
  class DocumentsSchemaController {
251
+ onSchemaChange;
252
+ explicitSchemaControl;
253
+ sendOp = true;
254
+ // schema coming from document metadata (snapshot we loaded from)
255
+ documentSchema;
256
+ // desired schema, based on feature gates / runtime options.
257
+ // This includes requests to enable to disable functionality
258
+ desiredSchema;
259
+ // OR() of document schema and desired schema. It enables all the features that are enabled in either of schemas.
260
+ futureSchema;
261
+ // Current schema this session operates with.
262
+ // 1) Legacy mode (explicitSchemaControl === false): this is same as desired schema - all options that were requested to be on are on, and all options requested to be off are off.
263
+ // 2) Non-legacy mode (explicitSchemaControl === true): this is AND() of document schema and desired schema. Only options that are enabled in both are enabled here.
264
+ // If there are any options that are not enabled in document schema, but are enabled in desired schema, then attempt to change schema
265
+ // (and enable such options) will be made through the session.
266
+ sessionSchema;
250
267
  /**
251
268
  * Constructs DocumentsSchemaController that controls current schema and processes around it, including changes in schema.
252
269
  * @param existing - Is the document existing document, or a new doc.
@@ -256,7 +273,6 @@ class DocumentsSchemaController {
256
273
  */
257
274
  constructor(existing, snapshotSequenceNumber, documentMetadataSchema, features, onSchemaChange) {
258
275
  this.onSchemaChange = onSchemaChange;
259
- this.sendOp = true;
260
276
  // For simplicity, let's only support new schema features for explicit schema control mode
261
277
  (0, internal_1.assert)(features.disallowedVersions.length === 0 || features.explicitSchemaControl, 0x949 /* not supported */);
262
278
  // Desired schema by this session - almost all props are coming from arguments