@fluidframework/container-runtime 2.1.0-276326 → 2.1.0-281041

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 (236) hide show
  1. package/README.md +74 -21
  2. package/api-extractor/api-extractor.current.json +5 -0
  3. package/api-extractor/api-extractor.legacy.json +1 -1
  4. package/api-extractor.json +1 -1
  5. package/api-report/container-runtime.legacy.public.api.md +9 -0
  6. package/container-runtime.test-files.tar +0 -0
  7. package/dist/{blobManager.d.ts → blobManager/blobManager.d.ts} +19 -29
  8. package/dist/blobManager/blobManager.d.ts.map +1 -0
  9. package/dist/{blobManager.js → blobManager/blobManager.js} +42 -83
  10. package/dist/blobManager/blobManager.js.map +1 -0
  11. package/dist/blobManager/blobManagerSnapSum.d.ts +30 -0
  12. package/dist/blobManager/blobManagerSnapSum.d.ts.map +1 -0
  13. package/dist/blobManager/blobManagerSnapSum.js +82 -0
  14. package/dist/blobManager/blobManagerSnapSum.js.map +1 -0
  15. package/dist/blobManager/index.d.ts +7 -0
  16. package/dist/blobManager/index.d.ts.map +1 -0
  17. package/dist/blobManager/index.js +16 -0
  18. package/dist/blobManager/index.js.map +1 -0
  19. package/dist/channelCollection.d.ts +1 -1
  20. package/dist/channelCollection.d.ts.map +1 -1
  21. package/dist/channelCollection.js +40 -8
  22. package/dist/channelCollection.js.map +1 -1
  23. package/dist/containerRuntime.d.ts +15 -10
  24. package/dist/containerRuntime.d.ts.map +1 -1
  25. package/dist/containerRuntime.js +199 -162
  26. package/dist/containerRuntime.js.map +1 -1
  27. package/dist/dataStoreContext.d.ts +5 -0
  28. package/dist/dataStoreContext.d.ts.map +1 -1
  29. package/dist/dataStoreContext.js +16 -5
  30. package/dist/dataStoreContext.js.map +1 -1
  31. package/dist/gc/garbageCollection.d.ts +1 -1
  32. package/dist/gc/garbageCollection.d.ts.map +1 -1
  33. package/dist/gc/garbageCollection.js +16 -10
  34. package/dist/gc/garbageCollection.js.map +1 -1
  35. package/dist/gc/gcDefinitions.d.ts +4 -2
  36. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  37. package/dist/gc/gcDefinitions.js.map +1 -1
  38. package/dist/gc/gcHelpers.d.ts.map +1 -1
  39. package/dist/gc/gcHelpers.js +12 -0
  40. package/dist/gc/gcHelpers.js.map +1 -1
  41. package/dist/gc/gcTelemetry.d.ts +3 -2
  42. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  43. package/dist/gc/gcTelemetry.js +6 -6
  44. package/dist/gc/gcTelemetry.js.map +1 -1
  45. package/dist/index.d.ts +1 -1
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js.map +1 -1
  48. package/dist/legacy.d.ts +1 -1
  49. package/dist/metadata.d.ts +7 -1
  50. package/dist/metadata.d.ts.map +1 -1
  51. package/dist/metadata.js +6 -0
  52. package/dist/metadata.js.map +1 -1
  53. package/dist/opLifecycle/batchManager.d.ts +8 -1
  54. package/dist/opLifecycle/batchManager.d.ts.map +1 -1
  55. package/dist/opLifecycle/batchManager.js +37 -16
  56. package/dist/opLifecycle/batchManager.js.map +1 -1
  57. package/dist/opLifecycle/definitions.d.ts +1 -1
  58. package/dist/opLifecycle/definitions.d.ts.map +1 -1
  59. package/dist/opLifecycle/definitions.js.map +1 -1
  60. package/dist/opLifecycle/index.d.ts +1 -1
  61. package/dist/opLifecycle/index.d.ts.map +1 -1
  62. package/dist/opLifecycle/index.js +2 -1
  63. package/dist/opLifecycle/index.js.map +1 -1
  64. package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
  65. package/dist/opLifecycle/opCompressor.js +12 -8
  66. package/dist/opLifecycle/opCompressor.js.map +1 -1
  67. package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
  68. package/dist/opLifecycle/opGroupingManager.js +14 -11
  69. package/dist/opLifecycle/opGroupingManager.js.map +1 -1
  70. package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
  71. package/dist/opLifecycle/opSplitter.js +11 -6
  72. package/dist/opLifecycle/opSplitter.js.map +1 -1
  73. package/dist/opLifecycle/outbox.d.ts +22 -6
  74. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  75. package/dist/opLifecycle/outbox.js +43 -21
  76. package/dist/opLifecycle/outbox.js.map +1 -1
  77. package/dist/opLifecycle/remoteMessageProcessor.d.ts +22 -6
  78. package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  79. package/dist/opLifecycle/remoteMessageProcessor.js +59 -9
  80. package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
  81. package/dist/packageVersion.d.ts +1 -1
  82. package/dist/packageVersion.js +1 -1
  83. package/dist/packageVersion.js.map +1 -1
  84. package/dist/pendingStateManager.d.ts +39 -13
  85. package/dist/pendingStateManager.d.ts.map +1 -1
  86. package/dist/pendingStateManager.js +98 -33
  87. package/dist/pendingStateManager.js.map +1 -1
  88. package/dist/public.d.ts +1 -1
  89. package/dist/scheduleManager.js +4 -0
  90. package/dist/scheduleManager.js.map +1 -1
  91. package/dist/summary/index.d.ts +1 -1
  92. package/dist/summary/index.d.ts.map +1 -1
  93. package/dist/summary/index.js +1 -2
  94. package/dist/summary/index.js.map +1 -1
  95. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  96. package/dist/summary/summarizerNode/summarizerNodeUtils.js +2 -0
  97. package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  98. package/dist/summary/summaryFormat.d.ts +0 -1
  99. package/dist/summary/summaryFormat.d.ts.map +1 -1
  100. package/dist/summary/summaryFormat.js +7 -4
  101. package/dist/summary/summaryFormat.js.map +1 -1
  102. package/internal.d.ts +1 -1
  103. package/legacy.d.ts +1 -1
  104. package/lib/{blobManager.d.ts → blobManager/blobManager.d.ts} +19 -29
  105. package/lib/blobManager/blobManager.d.ts.map +1 -0
  106. package/lib/{blobManager.js → blobManager/blobManager.js} +40 -83
  107. package/lib/blobManager/blobManager.js.map +1 -0
  108. package/lib/blobManager/blobManagerSnapSum.d.ts +30 -0
  109. package/lib/blobManager/blobManagerSnapSum.d.ts.map +1 -0
  110. package/lib/blobManager/blobManagerSnapSum.js +75 -0
  111. package/lib/blobManager/blobManagerSnapSum.js.map +1 -0
  112. package/lib/blobManager/index.d.ts +7 -0
  113. package/lib/blobManager/index.d.ts.map +1 -0
  114. package/lib/blobManager/index.js +7 -0
  115. package/lib/blobManager/index.js.map +1 -0
  116. package/lib/channelCollection.d.ts +1 -1
  117. package/lib/channelCollection.d.ts.map +1 -1
  118. package/lib/channelCollection.js +40 -8
  119. package/lib/channelCollection.js.map +1 -1
  120. package/lib/containerRuntime.d.ts +15 -10
  121. package/lib/containerRuntime.d.ts.map +1 -1
  122. package/lib/containerRuntime.js +149 -112
  123. package/lib/containerRuntime.js.map +1 -1
  124. package/lib/dataStoreContext.d.ts +5 -0
  125. package/lib/dataStoreContext.d.ts.map +1 -1
  126. package/lib/dataStoreContext.js +17 -6
  127. package/lib/dataStoreContext.js.map +1 -1
  128. package/lib/gc/garbageCollection.d.ts +1 -1
  129. package/lib/gc/garbageCollection.d.ts.map +1 -1
  130. package/lib/gc/garbageCollection.js +16 -10
  131. package/lib/gc/garbageCollection.js.map +1 -1
  132. package/lib/gc/gcDefinitions.d.ts +4 -2
  133. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  134. package/lib/gc/gcDefinitions.js.map +1 -1
  135. package/lib/gc/gcHelpers.d.ts.map +1 -1
  136. package/lib/gc/gcHelpers.js +12 -0
  137. package/lib/gc/gcHelpers.js.map +1 -1
  138. package/lib/gc/gcTelemetry.d.ts +3 -2
  139. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  140. package/lib/gc/gcTelemetry.js +6 -6
  141. package/lib/gc/gcTelemetry.js.map +1 -1
  142. package/lib/index.d.ts +1 -1
  143. package/lib/index.d.ts.map +1 -1
  144. package/lib/index.js.map +1 -1
  145. package/lib/legacy.d.ts +1 -1
  146. package/lib/metadata.d.ts +7 -1
  147. package/lib/metadata.d.ts.map +1 -1
  148. package/lib/metadata.js +4 -1
  149. package/lib/metadata.js.map +1 -1
  150. package/lib/opLifecycle/batchManager.d.ts +8 -1
  151. package/lib/opLifecycle/batchManager.d.ts.map +1 -1
  152. package/lib/opLifecycle/batchManager.js +35 -15
  153. package/lib/opLifecycle/batchManager.js.map +1 -1
  154. package/lib/opLifecycle/definitions.d.ts +1 -1
  155. package/lib/opLifecycle/definitions.d.ts.map +1 -1
  156. package/lib/opLifecycle/definitions.js.map +1 -1
  157. package/lib/opLifecycle/index.d.ts +1 -1
  158. package/lib/opLifecycle/index.d.ts.map +1 -1
  159. package/lib/opLifecycle/index.js +1 -1
  160. package/lib/opLifecycle/index.js.map +1 -1
  161. package/lib/opLifecycle/opCompressor.d.ts.map +1 -1
  162. package/lib/opLifecycle/opCompressor.js +12 -8
  163. package/lib/opLifecycle/opCompressor.js.map +1 -1
  164. package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -1
  165. package/lib/opLifecycle/opGroupingManager.js +14 -11
  166. package/lib/opLifecycle/opGroupingManager.js.map +1 -1
  167. package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
  168. package/lib/opLifecycle/opSplitter.js +11 -6
  169. package/lib/opLifecycle/opSplitter.js.map +1 -1
  170. package/lib/opLifecycle/outbox.d.ts +22 -6
  171. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  172. package/lib/opLifecycle/outbox.js +44 -22
  173. package/lib/opLifecycle/outbox.js.map +1 -1
  174. package/lib/opLifecycle/remoteMessageProcessor.d.ts +22 -6
  175. package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  176. package/lib/opLifecycle/remoteMessageProcessor.js +57 -7
  177. package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
  178. package/lib/packageVersion.d.ts +1 -1
  179. package/lib/packageVersion.js +1 -1
  180. package/lib/packageVersion.js.map +1 -1
  181. package/lib/pendingStateManager.d.ts +39 -13
  182. package/lib/pendingStateManager.d.ts.map +1 -1
  183. package/lib/pendingStateManager.js +99 -34
  184. package/lib/pendingStateManager.js.map +1 -1
  185. package/lib/public.d.ts +1 -1
  186. package/lib/scheduleManager.js +4 -0
  187. package/lib/scheduleManager.js.map +1 -1
  188. package/lib/summary/index.d.ts +1 -1
  189. package/lib/summary/index.d.ts.map +1 -1
  190. package/lib/summary/index.js +1 -1
  191. package/lib/summary/index.js.map +1 -1
  192. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  193. package/lib/summary/summarizerNode/summarizerNodeUtils.js +2 -0
  194. package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  195. package/lib/summary/summaryFormat.d.ts +0 -1
  196. package/lib/summary/summaryFormat.d.ts.map +1 -1
  197. package/lib/summary/summaryFormat.js +5 -2
  198. package/lib/summary/summaryFormat.js.map +1 -1
  199. package/package.json +49 -34
  200. package/src/{blobManager.ts → blobManager/blobManager.ts} +57 -123
  201. package/src/blobManager/blobManagerSnapSum.ts +133 -0
  202. package/src/blobManager/index.ts +19 -0
  203. package/src/channelCollection.ts +48 -11
  204. package/src/containerRuntime.ts +213 -158
  205. package/src/dataStoreContext.ts +30 -6
  206. package/src/gc/garbageCollection.ts +17 -12
  207. package/src/gc/gcDefinitions.ts +7 -2
  208. package/src/gc/gcHelpers.ts +18 -6
  209. package/src/gc/gcTelemetry.ts +20 -8
  210. package/src/index.ts +1 -1
  211. package/src/metadata.ts +11 -1
  212. package/src/opLifecycle/README.md +0 -8
  213. package/src/opLifecycle/batchManager.ts +46 -16
  214. package/src/opLifecycle/definitions.ts +1 -1
  215. package/src/opLifecycle/index.ts +8 -1
  216. package/src/opLifecycle/opCompressor.ts +12 -8
  217. package/src/opLifecycle/opGroupingManager.ts +14 -11
  218. package/src/opLifecycle/opSplitter.ts +10 -6
  219. package/src/opLifecycle/outbox.ts +64 -26
  220. package/src/opLifecycle/remoteMessageProcessor.ts +84 -11
  221. package/src/packageVersion.ts +1 -1
  222. package/src/pendingStateManager.ts +177 -60
  223. package/src/scheduleManager.ts +6 -2
  224. package/src/summary/README.md +81 -0
  225. package/src/summary/index.ts +0 -1
  226. package/src/summary/summarizerNode/summarizerNodeUtils.ts +3 -1
  227. package/src/summary/summaryFormat.ts +4 -2
  228. package/src/summary/summaryFormats.md +69 -8
  229. package/tsconfig.json +0 -1
  230. package/dist/blobManager.d.ts.map +0 -1
  231. package/dist/blobManager.js.map +0 -1
  232. package/lib/blobManager.d.ts.map +0 -1
  233. package/lib/blobManager.js.map +0 -1
  234. package/src/summary/images/appTree.png +0 -0
  235. package/src/summary/images/protocolAndAppTree.png +0 -0
  236. package/src/summary/images/summaryTree.png +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/container-runtime",
3
- "version": "2.1.0-276326",
3
+ "version": "2.1.0-281041",
4
4
  "description": "Fluid container runtime",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -75,12 +75,12 @@
75
75
  },
76
76
  "./internal/test/blobManager": {
77
77
  "import": {
78
- "types": "./lib/blobManager.d.ts",
79
- "default": "./lib/blobManager.js"
78
+ "types": "./lib/blobManager/index.d.ts",
79
+ "default": "./lib/blobManager/index.js"
80
80
  },
81
81
  "require": {
82
- "types": "./dist/blobManager.d.ts",
83
- "default": "./dist/blobManager.js"
82
+ "types": "./dist/blobManager/index.d.ts",
83
+ "default": "./dist/blobManager/index.js"
84
84
  }
85
85
  },
86
86
  "./internal/test/summary": {
@@ -127,18 +127,18 @@
127
127
  "temp-directory": "nyc/.nyc_output"
128
128
  },
129
129
  "dependencies": {
130
- "@fluid-internal/client-utils": "2.1.0-276326",
131
- "@fluidframework/container-definitions": "2.1.0-276326",
132
- "@fluidframework/container-runtime-definitions": "2.1.0-276326",
133
- "@fluidframework/core-interfaces": "2.1.0-276326",
134
- "@fluidframework/core-utils": "2.1.0-276326",
135
- "@fluidframework/datastore": "2.1.0-276326",
136
- "@fluidframework/driver-definitions": "2.1.0-276326",
137
- "@fluidframework/driver-utils": "2.1.0-276326",
138
- "@fluidframework/id-compressor": "2.1.0-276326",
139
- "@fluidframework/runtime-definitions": "2.1.0-276326",
140
- "@fluidframework/runtime-utils": "2.1.0-276326",
141
- "@fluidframework/telemetry-utils": "2.1.0-276326",
130
+ "@fluid-internal/client-utils": "2.1.0-281041",
131
+ "@fluidframework/container-definitions": "2.1.0-281041",
132
+ "@fluidframework/container-runtime-definitions": "2.1.0-281041",
133
+ "@fluidframework/core-interfaces": "2.1.0-281041",
134
+ "@fluidframework/core-utils": "2.1.0-281041",
135
+ "@fluidframework/datastore": "2.1.0-281041",
136
+ "@fluidframework/driver-definitions": "2.1.0-281041",
137
+ "@fluidframework/driver-utils": "2.1.0-281041",
138
+ "@fluidframework/id-compressor": "2.1.0-281041",
139
+ "@fluidframework/runtime-definitions": "2.1.0-281041",
140
+ "@fluidframework/runtime-utils": "2.1.0-281041",
141
+ "@fluidframework/telemetry-utils": "2.1.0-281041",
142
142
  "@tylerbu/sorted-btree-es6": "^1.8.0",
143
143
  "double-ended-queue": "^2.1.0-0",
144
144
  "lz4js": "^0.2.0",
@@ -146,17 +146,17 @@
146
146
  },
147
147
  "devDependencies": {
148
148
  "@arethetypeswrong/cli": "^0.15.2",
149
- "@biomejs/biome": "^1.7.3",
150
- "@fluid-internal/mocha-test-setup": "2.1.0-276326",
151
- "@fluid-private/stochastic-test-utils": "2.1.0-276326",
152
- "@fluid-private/test-pairwise-generator": "2.1.0-276326",
149
+ "@biomejs/biome": "~1.8.3",
150
+ "@fluid-internal/mocha-test-setup": "2.1.0-281041",
151
+ "@fluid-private/stochastic-test-utils": "2.1.0-281041",
152
+ "@fluid-private/test-pairwise-generator": "2.1.0-281041",
153
153
  "@fluid-tools/benchmark": "^0.48.0",
154
- "@fluid-tools/build-cli": "^0.39.0",
154
+ "@fluid-tools/build-cli": "^0.40.0",
155
155
  "@fluidframework/build-common": "^2.0.3",
156
- "@fluidframework/build-tools": "^0.39.0",
157
- "@fluidframework/container-runtime-previous": "npm:@fluidframework/container-runtime@2.0.0-rc.5.0.0",
156
+ "@fluidframework/build-tools": "^0.40.0",
157
+ "@fluidframework/container-runtime-previous": "npm:@fluidframework/container-runtime@2.0.0",
158
158
  "@fluidframework/eslint-config-fluid": "^5.3.0",
159
- "@fluidframework/test-runtime-utils": "2.1.0-276326",
159
+ "@fluidframework/test-runtime-utils": "2.1.0-281041",
160
160
  "@microsoft/api-extractor": "^7.45.1",
161
161
  "@types/double-ended-queue": "^2.1.0",
162
162
  "@types/mocha": "^9.1.1",
@@ -178,25 +178,39 @@
178
178
  "typescript": "~5.4.5"
179
179
  },
180
180
  "typeValidation": {
181
- "broken": {}
181
+ "broken": {
182
+ "ClassDeclaration_LocalFluidDataStoreContext": {
183
+ "forwardCompat": false
184
+ },
185
+ "ClassDeclaration_FluidDataStoreContext": {
186
+ "forwardCompat": false
187
+ },
188
+ "ClassDeclaration_LocalFluidDataStoreContextBase": {
189
+ "forwardCompat": false
190
+ },
191
+ "InterfaceDeclaration_IGCNodeUpdatedProps": {
192
+ "backCompat": false
193
+ }
194
+ }
182
195
  },
183
196
  "scripts": {
184
197
  "api": "fluid-build . --task api",
185
198
  "api-extractor:commonjs": "flub generate entrypoints --outDir ./dist",
186
199
  "api-extractor:esnext": "flub generate entrypoints --outDir ./lib --node10TypeCompat",
187
200
  "build": "fluid-build . --task build",
201
+ "build:api-reports": "concurrently \"npm:build:api-reports:*\"",
202
+ "build:api-reports:current": "api-extractor run --local --config api-extractor/api-extractor.current.json",
203
+ "build:api-reports:legacy": "api-extractor run --local --config api-extractor/api-extractor.legacy.json",
188
204
  "build:commonjs": "fluid-build . --task commonjs",
189
205
  "build:compile": "fluid-build . --task compile",
190
- "build:docs": "concurrently \"npm:build:docs:*\"",
191
- "build:docs:current": "api-extractor run --local",
192
- "build:docs:legacy": "api-extractor run --local --config api-extractor/api-extractor.legacy.json",
206
+ "build:docs": "api-extractor run --local",
193
207
  "build:esnext": "tsc --project ./tsconfig.json",
194
208
  "build:genver": "gen-version",
195
209
  "build:test": "npm run build:test:esm && npm run build:test:cjs",
196
210
  "build:test:cjs": "fluid-tsc commonjs --project ./src/test/tsconfig.cjs.json",
197
211
  "build:test:esm": "tsc --project ./src/test/tsconfig.json",
198
212
  "check:are-the-types-wrong": "attw --pack . --exclude-entrypoints ./internal/test/containerRuntime ./internal/test/deltaScheduler ./internal/test/scheduleManager ./internal/test/blobManager ./internal/test/summary ./internal/test/gc",
199
- "check:biome": "biome check . --formatter-enabled=true",
213
+ "check:biome": "biome check .",
200
214
  "check:exports": "concurrently \"npm:check:exports:*\"",
201
215
  "check:exports:bundle-release-tags": "api-extractor run --config api-extractor/api-extractor-lint-bundle.json",
202
216
  "check:exports:cjs:legacy": "api-extractor run --config api-extractor/api-extractor-lint-legacy.cjs.json",
@@ -205,14 +219,15 @@
205
219
  "check:exports:esm:public": "api-extractor run --config api-extractor/api-extractor-lint-public.esm.json",
206
220
  "check:format": "npm run check:biome",
207
221
  "check:prettier": "prettier --check . --cache --ignore-path ../../../.prettierignore",
208
- "ci:build:docs": "concurrently \"npm:ci:build:docs:*\"",
209
- "ci:build:docs:current": "api-extractor run",
210
- "ci:build:docs:legacy": "api-extractor run --config api-extractor/api-extractor.legacy.json",
222
+ "ci:build:api-reports": "concurrently \"npm:ci:build:api-reports:*\"",
223
+ "ci:build:api-reports:current": "api-extractor run --config api-extractor/api-extractor.current.json",
224
+ "ci:build:api-reports:legacy": "api-extractor run --config api-extractor/api-extractor.legacy.json",
225
+ "ci:build:docs": "api-extractor run",
211
226
  "clean": "rimraf --glob dist lib \"*.d.ts\" \"**/*.tsbuildinfo\" \"**/*.build.log\" _api-extractor-temp nyc",
212
227
  "eslint": "eslint --format stylish src",
213
228
  "eslint:fix": "eslint --format stylish src --fix --fix-type problem,suggestion,layout",
214
229
  "format": "npm run format:biome",
215
- "format:biome": "biome check . --formatter-enabled=true --apply",
230
+ "format:biome": "biome check . --write",
216
231
  "format:prettier": "prettier --write . --cache --ignore-path ../../../.prettierignore",
217
232
  "lint": "fluid-build . --task lint",
218
233
  "lint:fix": "fluid-build . --task eslint:fix --task format",
@@ -21,7 +21,6 @@ import { assert, Deferred } from "@fluidframework/core-utils/internal";
21
21
  import {
22
22
  IDocumentStorageService,
23
23
  ICreateBlobResponse,
24
- ISnapshotTree,
25
24
  ISequencedDocumentMessage,
26
25
  } from "@fluidframework/driver-definitions/internal";
27
26
  import { canRetryOnError, runWithRetry } from "@fluidframework/driver-utils/internal";
@@ -32,7 +31,6 @@ import {
32
31
  } from "@fluidframework/runtime-definitions/internal";
33
32
  import {
34
33
  FluidHandleBase,
35
- SummaryTreeBuilder,
36
34
  createResponseError,
37
35
  generateHandleContextPath,
38
36
  responseToException,
@@ -47,7 +45,14 @@ import {
47
45
  } from "@fluidframework/telemetry-utils/internal";
48
46
  import { v4 as uuid } from "uuid";
49
47
 
50
- import { IBlobMetadata } from "./metadata.js";
48
+ import { IBlobMetadata } from "../metadata.js";
49
+
50
+ import {
51
+ getStorageIds,
52
+ summarizeBlobManagerState,
53
+ toRedirectTable,
54
+ type IBlobManagerLoadInfo,
55
+ } from "./blobManagerSnapSum.js";
51
56
 
52
57
  /**
53
58
  * This class represents blob (long string)
@@ -87,16 +92,6 @@ export class BlobHandle extends FluidHandleBase<ArrayBufferLike> {
87
92
  }
88
93
  }
89
94
 
90
- /**
91
- * Information from a snapshot needed to load BlobManager
92
- * @legacy
93
- * @alpha
94
- */
95
- export interface IBlobManagerLoadInfo {
96
- ids?: string[];
97
- redirectTable?: [string, string][];
98
- }
99
-
100
95
  // Restrict the IContainerRuntime interface to the subset required by BlobManager. This helps to make
101
96
  // the contract explicit and reduces the amount of mocking required for tests.
102
97
  export type IBlobManagerRuntime = Pick<
@@ -146,9 +141,9 @@ const stashedPendingBlobOverrides: Pick<
146
141
  uploadTime: undefined,
147
142
  } as const;
148
143
 
144
+ export const blobManagerBasePath = "_blobs" as const;
145
+
149
146
  export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
150
- public static readonly basePath = "_blobs";
151
- private static readonly redirectTableBlobName = ".redirectTable";
152
147
  private readonly mc: MonitoringContext;
153
148
 
154
149
  /**
@@ -178,10 +173,10 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
178
173
  private readonly routeContext: IFluidHandleContext;
179
174
  private readonly getStorage: () => IDocumentStorageService;
180
175
  // Called when a blob node is requested. blobPath is the path of the blob's node in GC's graph.
181
- // blobPath's format - `/<BlobManager.basePath>/<blobId>`.
176
+ // blobPath's format - `/<basePath>/<blobId>`.
182
177
  private readonly blobRequested: (blobPath: string) => void;
183
178
  // Called to check if a blob has been deleted by GC.
184
- // blobPath's format - `/<BlobManager.basePath>/<blobId>`.
179
+ // blobPath's format - `/<basePath>/<blobId>`.
185
180
  private readonly isBlobDeleted: (blobPath: string) => boolean;
186
181
  private readonly runtime: IBlobManagerRuntime;
187
182
  private readonly closeContainer: (error?: ICriticalContainerError) => void;
@@ -202,10 +197,10 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
202
197
  */
203
198
  sendBlobAttachOp: (localId: string, storageId?: string) => void;
204
199
  // Called when a blob node is requested. blobPath is the path of the blob's node in GC's graph.
205
- // blobPath's format - `/<BlobManager.basePath>/<blobId>`.
200
+ // blobPath's format - `/<basePath>/<blobId>`.
206
201
  readonly blobRequested: (blobPath: string) => void;
207
202
  // Called to check if a blob has been deleted by GC.
208
- // blobPath's format - `/<BlobManager.basePath>/<blobId>`.
203
+ // blobPath's format - `/<basePath>/<blobId>`.
209
204
  readonly isBlobDeleted: (blobPath: string) => boolean;
210
205
  readonly runtime: IBlobManagerRuntime;
211
206
  stashedBlobs: IPendingBlobs | undefined;
@@ -235,7 +230,7 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
235
230
  namespace: "BlobManager",
236
231
  });
237
232
 
238
- this.redirectTable = this.load(snapshot);
233
+ this.redirectTable = toRedirectTable(snapshot, this.mc.logger, this.runtime.attachState);
239
234
 
240
235
  // Begin uploading stashed blobs from previous container instance
241
236
  Object.entries(stashedBlobs ?? {}).forEach(([localId, entry]) => {
@@ -347,27 +342,6 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
347
342
  );
348
343
  }
349
344
 
350
- /**
351
- * Set of actual storage IDs (i.e., IDs that can be requested from storage). This will be empty if the container is
352
- * detached or there are no (non-pending) attachment blobs in the document
353
- */
354
- private get storageIds(): Set<string> {
355
- const ids = new Set<string | undefined>(this.redirectTable.values());
356
-
357
- // If we are detached, we will not have storage IDs, only undefined
358
- const undefinedValueInTable = ids.delete(undefined);
359
-
360
- // For a detached container, entries are inserted into the redirect table with an undefined storage ID.
361
- // For an attached container, entries are inserted w/storage ID after the BlobAttach op round-trips.
362
- assert(
363
- !undefinedValueInTable ||
364
- (this.runtime.attachState === AttachState.Detached && ids.size === 0),
365
- 0x382 /* 'redirectTable' must contain only undefined while detached / defined values while attached */,
366
- );
367
-
368
- return ids as Set<string>;
369
- }
370
-
371
345
  public async getBlob(blobId: string): Promise<ArrayBufferLike> {
372
346
  // Verify that the blob is not deleted, i.e., it has not been garbage collected. If it is, this will throw
373
347
  // an error, failing the call.
@@ -411,15 +385,17 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
411
385
  0x384 /* requesting handle for unknown blob */,
412
386
  );
413
387
  const pending = this.pendingBlobs.get(id);
388
+ // Create a callback function for once the blob has been attached
414
389
  const callback = pending
415
390
  ? () => {
416
391
  pending.attached = true;
392
+ // Notify listeners (e.g. serialization process) that blob has been attached
417
393
  this.emit("blobAttached", pending);
418
394
  this.deletePendingBlobMaybe(id);
419
395
  }
420
396
  : undefined;
421
397
  return new BlobHandle(
422
- `${BlobManager.basePath}/${id}`,
398
+ getGCNodePathFromBlobId(id),
423
399
  this.routeContext,
424
400
  async () => this.getBlob(id),
425
401
  callback,
@@ -569,7 +545,8 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
569
545
  if (!entry.opsent) {
570
546
  this.sendBlobAttachOp(localId, response.id);
571
547
  }
572
- if (this.storageIds.has(response.id)) {
548
+ const storageIds = getStorageIds(this.redirectTable, this.runtime.attachState);
549
+ if (storageIds.has(response.id)) {
573
550
  // The blob is de-duped. Set up a local ID to storage ID mapping and return the blob. Since this is
574
551
  // an existing blob, we don't have to wait for the op to be ack'd since this step has already
575
552
  // happened before and so, the server won't delete it.
@@ -662,74 +639,8 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
662
639
  }
663
640
  }
664
641
 
665
- /**
666
- * Reads blobs needed to load BlobManager from storage.
667
- * @param blobsTree - Tree containing IDs of previously attached blobs. We
668
- * look for the IDs in the blob entries of the tree since the both the r11s
669
- * and SPO drivers replace the attachment types returned in snapshot() with blobs.
670
- */
671
- public static async load(
672
- blobsTree: ISnapshotTree | undefined,
673
- tryFetchBlob: (id: string) => Promise<[string, string][]>,
674
- ): Promise<IBlobManagerLoadInfo> {
675
- if (!blobsTree) {
676
- return {};
677
- }
678
- let redirectTable;
679
- const tableId = blobsTree.blobs[this.redirectTableBlobName];
680
- if (tableId) {
681
- redirectTable = await tryFetchBlob(tableId);
682
- }
683
- const ids = Object.entries(blobsTree.blobs)
684
- .filter(([k, _]) => k !== this.redirectTableBlobName)
685
- .map(([_, v]) => v);
686
- return { ids, redirectTable };
687
- }
688
-
689
- /**
690
- * Load a set of previously attached blob IDs and redirect table from a previous snapshot.
691
- */
692
- private load(snapshot: IBlobManagerLoadInfo): Map<string, string | undefined> {
693
- this.mc.logger.sendTelemetryEvent({
694
- eventName: "AttachmentBlobsLoaded",
695
- count: snapshot.ids?.length ?? 0,
696
- redirectTable: snapshot.redirectTable?.length,
697
- });
698
- const table = new Map<string, string | undefined>(snapshot.redirectTable);
699
- if (snapshot.ids) {
700
- const detached = this.runtime.attachState === AttachState.Detached;
701
- // If we are detached, we don't have storage IDs yet, so set to undefined
702
- // Otherwise, set identity (id -> id) entries
703
- snapshot.ids.forEach((entry) => table.set(entry, detached ? undefined : entry));
704
- }
705
- return table;
706
- }
707
-
708
642
  public summarize(telemetryContext?: ITelemetryContext): ISummaryTreeWithStats {
709
- // if storageIds is empty, it means we are detached and have only local IDs, or that there are no blobs attached
710
- const blobIds =
711
- this.storageIds.size > 0
712
- ? Array.from(this.storageIds)
713
- : Array.from(this.redirectTable.keys());
714
- const builder = new SummaryTreeBuilder();
715
- blobIds.forEach((blobId) => {
716
- builder.addAttachment(blobId);
717
- });
718
-
719
- // Any non-identity entries in the table need to be saved in the summary
720
- if (this.redirectTable.size > blobIds.length) {
721
- builder.addBlob(
722
- BlobManager.redirectTableBlobName,
723
- // filter out identity entries
724
- JSON.stringify(
725
- Array.from(this.redirectTable.entries()).filter(
726
- ([localId, storageId]) => localId !== storageId,
727
- ),
728
- ),
729
- );
730
- }
731
-
732
- return builder.getSummaryTree();
643
+ return summarizeBlobManagerState(this.redirectTable, this.runtime.attachState);
733
644
  }
734
645
 
735
646
  /**
@@ -766,7 +677,7 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
766
677
 
767
678
  /**
768
679
  * Delete blobs with the given routes from the redirect table.
769
- * The routes are GC nodes paths of format -`/<BlobManager.basePath>/<blobId>`. The blob ids are all local ids.
680
+ * The routes are GC nodes paths of format -`/<blobManagerBasePath>/<blobId>`. The blob ids are all local ids.
770
681
  * Deleting the blobs involves 2 steps:
771
682
  * 1. The redirect table entry for the local ids are deleted.
772
683
  * 2. If the storage ids corresponding to the deleted local ids are not in-use anymore, the redirect table entries
@@ -839,7 +750,7 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
839
750
  this.mc.logger.sendErrorEvent(
840
751
  {
841
752
  eventName: "GC_Deleted_Blob_Requested",
842
- pkg: BlobManager.basePath,
753
+ pkg: blobManagerBasePath,
843
754
  },
844
755
  error,
845
756
  );
@@ -863,6 +774,16 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
863
774
  }
864
775
  }
865
776
 
777
+ /**
778
+ * Part of container serialization when imminent closure is enabled (Currently when calling closeAndGetPendingLocalState).
779
+ * This asynchronous function resolves all pending createBlob calls and waits for each blob
780
+ * to be attached. It will also send BlobAttach ops for each pending blob that hasn't sent it
781
+ * yet so that serialized container can resubmit them when rehydrated.
782
+ *
783
+ * @param stopBlobAttachingSignal - Optional signal to abort the blob attaching process.
784
+ * @returns - A promise that resolves with the details of the attached blobs,
785
+ * or undefined if no blobs were processed.
786
+ */
866
787
  public async attachAndGetPendingBlobs(
867
788
  stopBlobAttachingSignal?: AbortSignal,
868
789
  ): Promise<IPendingBlobs | undefined> {
@@ -875,12 +796,17 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
875
796
  }
876
797
  const blobs = {};
877
798
  const localBlobs = new Set<PendingBlob>();
799
+ // This while is used to stash blobs created while attaching and getting blobs
878
800
  while (localBlobs.size < this.pendingBlobs.size) {
879
801
  const attachBlobsP: Promise<void>[] = [];
880
802
  for (const [id, entry] of this.pendingBlobs) {
881
803
  if (!localBlobs.has(entry)) {
882
804
  localBlobs.add(entry);
805
+ // Resolving the blob handle to let hosts continue with their operations (it will resolve
806
+ // original createBlob call) and let them attach the blob. This is a lie we told since the upload
807
+ // hasn't finished yet, but it's fine since we will retry on rehydration.
883
808
  entry.handleP.resolve(this.getBlobHandle(id));
809
+ // Array of promises that will resolve when blobs get attached.
884
810
  attachBlobsP.push(
885
811
  new Promise<void>((resolve, reject) => {
886
812
  stopBlobAttachingSignal?.addEventListener(
@@ -906,6 +832,8 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
906
832
  );
907
833
  }
908
834
  }
835
+ // Wait for all blobs to be attached. This is important, otherwise serialized container
836
+ // could send the blobAttach op without any op that references the blob, making it useless.
909
837
  await Promise.allSettled(attachBlobsP).catch(() => {});
910
838
  }
911
839
 
@@ -936,22 +864,28 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
936
864
  }
937
865
 
938
866
  /**
939
- * For a blobId, returns its path in GC's graph. The node path is of the format `/<BlobManager.basePath>/<blobId>`.
867
+ * For a blobId, returns its path in GC's graph. The node path is of the format `/<blobManagerBasePath>/<blobId>`.
940
868
  * This path must match the path of the blob handle returned by the createBlob API because blobs are marked
941
869
  * referenced by storing these handles in a referenced DDS.
942
870
  */
943
- function getGCNodePathFromBlobId(blobId: string) {
944
- return `/${BlobManager.basePath}/${blobId}`;
945
- }
871
+ const getGCNodePathFromBlobId = (blobId: string) => `/${blobManagerBasePath}/${blobId}`;
946
872
 
947
873
  /**
948
- * For a given GC node path, return the blobId. The node path is of the format `/<BlobManager.basePath>/<blobId>`.
874
+ * For a given GC node path, return the blobId. The node path is of the format `/<basePath>/<blobId>`.
949
875
  */
950
- function getBlobIdFromGCNodePath(nodePath: string) {
876
+ const getBlobIdFromGCNodePath = (nodePath: string) => {
951
877
  const pathParts = nodePath.split("/");
952
- assert(
953
- pathParts.length === 3 && pathParts[1] === BlobManager.basePath,
954
- 0x5bd /* Invalid blob node path */,
955
- );
878
+ assert(areBlobPathParts(pathParts), 0x5bd /* Invalid blob node path */);
956
879
  return pathParts[2];
957
- }
880
+ };
881
+
882
+ /**
883
+ * Returns whether a given path is for attachment blobs that are in the format - "/blobManagerBasePath/...".
884
+ */
885
+ export const isBlobPath = (path: string): path is `/${typeof blobManagerBasePath}/${string}` =>
886
+ areBlobPathParts(path.split("/"));
887
+
888
+ export const areBlobPathParts = (
889
+ pathParts: string[],
890
+ ): pathParts is ["", typeof blobManagerBasePath, string] =>
891
+ pathParts.length === 3 && pathParts[1] === blobManagerBasePath;
@@ -0,0 +1,133 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import {
7
+ AttachState,
8
+ type IContainerContext,
9
+ } from "@fluidframework/container-definitions/internal";
10
+ import { assert } from "@fluidframework/core-utils/internal";
11
+ import { readAndParse } from "@fluidframework/driver-utils/internal";
12
+ import type { ISummaryTreeWithStats } from "@fluidframework/runtime-definitions/internal";
13
+ import { SummaryTreeBuilder } from "@fluidframework/runtime-utils/internal";
14
+ import type { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils/internal";
15
+
16
+ /**
17
+ * Information from a snapshot needed to load BlobManager
18
+ * @legacy
19
+ * @alpha
20
+ */
21
+ export interface IBlobManagerLoadInfo {
22
+ ids?: string[];
23
+ redirectTable?: [string, string][];
24
+ }
25
+
26
+ export const redirectTableBlobName = ".redirectTable";
27
+
28
+ /**
29
+ * @internal
30
+ */
31
+ export const blobsTreeName = ".blobs";
32
+
33
+ /**
34
+ * Reads blobs needed to load BlobManager from storage.
35
+ *
36
+ */
37
+ export const loadBlobManagerLoadInfo = async (
38
+ context: Pick<IContainerContext, "baseSnapshot" | "storage" | "attachState">,
39
+ ): Promise<IBlobManagerLoadInfo> => loadV1(context);
40
+
41
+ const loadV1 = async (
42
+ context: Pick<IContainerContext, "baseSnapshot" | "storage" | "attachState">,
43
+ ): Promise<IBlobManagerLoadInfo> => {
44
+ const blobsTree = context.baseSnapshot?.trees[blobsTreeName];
45
+
46
+ if (!blobsTree) {
47
+ return {};
48
+ }
49
+ let redirectTableEntries: [string, string][] = [];
50
+ const tableId = blobsTree.blobs[redirectTableBlobName];
51
+ if (tableId) {
52
+ redirectTableEntries = await readAndParse(context.storage, tableId);
53
+ }
54
+ const ids = Object.entries(blobsTree.blobs)
55
+ .filter(([k, _]) => k !== redirectTableBlobName)
56
+ .map(([_, v]) => v);
57
+
58
+ return { ids, redirectTable: redirectTableEntries };
59
+ };
60
+
61
+ export const toRedirectTable = (
62
+ snapshot: IBlobManagerLoadInfo,
63
+ logger: ITelemetryLoggerExt,
64
+ attachState: AttachState,
65
+ ): Map<string, string | undefined> => {
66
+ logger.sendTelemetryEvent({
67
+ eventName: "AttachmentBlobsLoaded",
68
+ count: snapshot.ids?.length ?? 0,
69
+ redirectTable: snapshot.redirectTable?.length,
70
+ });
71
+ const redirectTable = new Map<string, string | undefined>(snapshot.redirectTable);
72
+ const detached = attachState !== AttachState.Attached;
73
+ if (snapshot.ids) {
74
+ // If we are detached, we don't have storage IDs yet, so set to undefined
75
+ // Otherwise, set identity (id -> id) entries.
76
+ snapshot.ids.forEach((entry) => redirectTable.set(entry, detached ? undefined : entry));
77
+ }
78
+ return redirectTable;
79
+ };
80
+
81
+ export const summarizeBlobManagerState = (
82
+ redirectTable: Map<string, string | undefined>,
83
+ attachState: AttachState,
84
+ ): ISummaryTreeWithStats => summarizeV1(redirectTable, attachState);
85
+
86
+ const summarizeV1 = (
87
+ redirectTable: Map<string, string | undefined>,
88
+ attachState: AttachState,
89
+ ): ISummaryTreeWithStats => {
90
+ const storageIds = getStorageIds(redirectTable, attachState);
91
+
92
+ // if storageIds is empty, it means we are detached and have only local IDs, or that there are no blobs attached
93
+ const blobIds =
94
+ storageIds.size > 0 ? Array.from(storageIds) : Array.from(redirectTable.keys());
95
+ const builder = new SummaryTreeBuilder();
96
+ blobIds.forEach((blobId) => {
97
+ builder.addAttachment(blobId);
98
+ });
99
+
100
+ // Any non-identity entries in the table need to be saved in the summary
101
+ if (redirectTable.size > blobIds.length) {
102
+ builder.addBlob(
103
+ redirectTableBlobName,
104
+ // filter out identity entries
105
+ JSON.stringify(
106
+ Array.from(redirectTable.entries()).filter(
107
+ ([localId, storageId]) => localId !== storageId,
108
+ ),
109
+ ),
110
+ );
111
+ }
112
+
113
+ return builder.getSummaryTree();
114
+ };
115
+
116
+ export const getStorageIds = (
117
+ redirectTable: Map<string, string | undefined>,
118
+ attachState: AttachState,
119
+ ) => {
120
+ const ids = new Set<string | undefined>(redirectTable.values());
121
+
122
+ // If we are detached, we will not have storage IDs, only undefined
123
+ const undefinedValueInTable = ids.delete(undefined);
124
+
125
+ // For a detached container, entries are inserted into the redirect table with an undefined storage ID.
126
+ // For an attached container, entries are inserted w/storage ID after the BlobAttach op round-trips.
127
+ assert(
128
+ !undefinedValueInTable || (attachState === AttachState.Detached && ids.size === 0),
129
+ 0x382 /* 'redirectTable' must contain only undefined while detached / defined values while attached */,
130
+ );
131
+
132
+ return ids as Set<string>;
133
+ };
@@ -0,0 +1,19 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ export {
7
+ BlobManager,
8
+ IPendingBlobs,
9
+ IBlobManagerRuntime,
10
+ IBlobManagerEvents,
11
+ blobManagerBasePath,
12
+ isBlobPath,
13
+ } from "./blobManager.js";
14
+ export {
15
+ loadBlobManagerLoadInfo,
16
+ IBlobManagerLoadInfo,
17
+ blobsTreeName,
18
+ redirectTableBlobName,
19
+ } from "./blobManagerSnapSum.js";