@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.
- package/README.md +74 -21
- package/api-extractor/api-extractor.current.json +5 -0
- package/api-extractor/api-extractor.legacy.json +1 -1
- package/api-extractor.json +1 -1
- package/api-report/container-runtime.legacy.public.api.md +9 -0
- package/container-runtime.test-files.tar +0 -0
- package/dist/{blobManager.d.ts → blobManager/blobManager.d.ts} +19 -29
- package/dist/blobManager/blobManager.d.ts.map +1 -0
- package/dist/{blobManager.js → blobManager/blobManager.js} +42 -83
- package/dist/blobManager/blobManager.js.map +1 -0
- package/dist/blobManager/blobManagerSnapSum.d.ts +30 -0
- package/dist/blobManager/blobManagerSnapSum.d.ts.map +1 -0
- package/dist/blobManager/blobManagerSnapSum.js +82 -0
- package/dist/blobManager/blobManagerSnapSum.js.map +1 -0
- package/dist/blobManager/index.d.ts +7 -0
- package/dist/blobManager/index.d.ts.map +1 -0
- package/dist/blobManager/index.js +16 -0
- package/dist/blobManager/index.js.map +1 -0
- package/dist/channelCollection.d.ts +1 -1
- package/dist/channelCollection.d.ts.map +1 -1
- package/dist/channelCollection.js +40 -8
- package/dist/channelCollection.js.map +1 -1
- package/dist/containerRuntime.d.ts +15 -10
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +199 -162
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStoreContext.d.ts +5 -0
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +16 -5
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/gc/garbageCollection.d.ts +1 -1
- package/dist/gc/garbageCollection.d.ts.map +1 -1
- package/dist/gc/garbageCollection.js +16 -10
- package/dist/gc/garbageCollection.js.map +1 -1
- package/dist/gc/gcDefinitions.d.ts +4 -2
- package/dist/gc/gcDefinitions.d.ts.map +1 -1
- package/dist/gc/gcDefinitions.js.map +1 -1
- package/dist/gc/gcHelpers.d.ts.map +1 -1
- package/dist/gc/gcHelpers.js +12 -0
- package/dist/gc/gcHelpers.js.map +1 -1
- package/dist/gc/gcTelemetry.d.ts +3 -2
- package/dist/gc/gcTelemetry.d.ts.map +1 -1
- package/dist/gc/gcTelemetry.js +6 -6
- package/dist/gc/gcTelemetry.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/legacy.d.ts +1 -1
- package/dist/metadata.d.ts +7 -1
- package/dist/metadata.d.ts.map +1 -1
- package/dist/metadata.js +6 -0
- package/dist/metadata.js.map +1 -1
- package/dist/opLifecycle/batchManager.d.ts +8 -1
- package/dist/opLifecycle/batchManager.d.ts.map +1 -1
- package/dist/opLifecycle/batchManager.js +37 -16
- package/dist/opLifecycle/batchManager.js.map +1 -1
- package/dist/opLifecycle/definitions.d.ts +1 -1
- package/dist/opLifecycle/definitions.d.ts.map +1 -1
- package/dist/opLifecycle/definitions.js.map +1 -1
- package/dist/opLifecycle/index.d.ts +1 -1
- package/dist/opLifecycle/index.d.ts.map +1 -1
- package/dist/opLifecycle/index.js +2 -1
- package/dist/opLifecycle/index.js.map +1 -1
- package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opCompressor.js +12 -8
- package/dist/opLifecycle/opCompressor.js.map +1 -1
- package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/dist/opLifecycle/opGroupingManager.js +14 -11
- package/dist/opLifecycle/opGroupingManager.js.map +1 -1
- package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
- package/dist/opLifecycle/opSplitter.js +11 -6
- package/dist/opLifecycle/opSplitter.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts +22 -6
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +43 -21
- package/dist/opLifecycle/outbox.js.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.d.ts +22 -6
- package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.js +59 -9
- package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/pendingStateManager.d.ts +39 -13
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +98 -33
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/public.d.ts +1 -1
- package/dist/scheduleManager.js +4 -0
- package/dist/scheduleManager.js.map +1 -1
- package/dist/summary/index.d.ts +1 -1
- package/dist/summary/index.d.ts.map +1 -1
- package/dist/summary/index.js +1 -2
- package/dist/summary/index.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.js +2 -0
- package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/dist/summary/summaryFormat.d.ts +0 -1
- package/dist/summary/summaryFormat.d.ts.map +1 -1
- package/dist/summary/summaryFormat.js +7 -4
- package/dist/summary/summaryFormat.js.map +1 -1
- package/internal.d.ts +1 -1
- package/legacy.d.ts +1 -1
- package/lib/{blobManager.d.ts → blobManager/blobManager.d.ts} +19 -29
- package/lib/blobManager/blobManager.d.ts.map +1 -0
- package/lib/{blobManager.js → blobManager/blobManager.js} +40 -83
- package/lib/blobManager/blobManager.js.map +1 -0
- package/lib/blobManager/blobManagerSnapSum.d.ts +30 -0
- package/lib/blobManager/blobManagerSnapSum.d.ts.map +1 -0
- package/lib/blobManager/blobManagerSnapSum.js +75 -0
- package/lib/blobManager/blobManagerSnapSum.js.map +1 -0
- package/lib/blobManager/index.d.ts +7 -0
- package/lib/blobManager/index.d.ts.map +1 -0
- package/lib/blobManager/index.js +7 -0
- package/lib/blobManager/index.js.map +1 -0
- package/lib/channelCollection.d.ts +1 -1
- package/lib/channelCollection.d.ts.map +1 -1
- package/lib/channelCollection.js +40 -8
- package/lib/channelCollection.js.map +1 -1
- package/lib/containerRuntime.d.ts +15 -10
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +149 -112
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStoreContext.d.ts +5 -0
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +17 -6
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/gc/garbageCollection.d.ts +1 -1
- package/lib/gc/garbageCollection.d.ts.map +1 -1
- package/lib/gc/garbageCollection.js +16 -10
- package/lib/gc/garbageCollection.js.map +1 -1
- package/lib/gc/gcDefinitions.d.ts +4 -2
- package/lib/gc/gcDefinitions.d.ts.map +1 -1
- package/lib/gc/gcDefinitions.js.map +1 -1
- package/lib/gc/gcHelpers.d.ts.map +1 -1
- package/lib/gc/gcHelpers.js +12 -0
- package/lib/gc/gcHelpers.js.map +1 -1
- package/lib/gc/gcTelemetry.d.ts +3 -2
- package/lib/gc/gcTelemetry.d.ts.map +1 -1
- package/lib/gc/gcTelemetry.js +6 -6
- package/lib/gc/gcTelemetry.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/legacy.d.ts +1 -1
- package/lib/metadata.d.ts +7 -1
- package/lib/metadata.d.ts.map +1 -1
- package/lib/metadata.js +4 -1
- package/lib/metadata.js.map +1 -1
- package/lib/opLifecycle/batchManager.d.ts +8 -1
- package/lib/opLifecycle/batchManager.d.ts.map +1 -1
- package/lib/opLifecycle/batchManager.js +35 -15
- package/lib/opLifecycle/batchManager.js.map +1 -1
- package/lib/opLifecycle/definitions.d.ts +1 -1
- package/lib/opLifecycle/definitions.d.ts.map +1 -1
- package/lib/opLifecycle/definitions.js.map +1 -1
- package/lib/opLifecycle/index.d.ts +1 -1
- package/lib/opLifecycle/index.d.ts.map +1 -1
- package/lib/opLifecycle/index.js +1 -1
- package/lib/opLifecycle/index.js.map +1 -1
- package/lib/opLifecycle/opCompressor.d.ts.map +1 -1
- package/lib/opLifecycle/opCompressor.js +12 -8
- package/lib/opLifecycle/opCompressor.js.map +1 -1
- package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/lib/opLifecycle/opGroupingManager.js +14 -11
- package/lib/opLifecycle/opGroupingManager.js.map +1 -1
- package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
- package/lib/opLifecycle/opSplitter.js +11 -6
- package/lib/opLifecycle/opSplitter.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts +22 -6
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.js +44 -22
- package/lib/opLifecycle/outbox.js.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.d.ts +22 -6
- package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.js +57 -7
- package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/pendingStateManager.d.ts +39 -13
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +99 -34
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/public.d.ts +1 -1
- package/lib/scheduleManager.js +4 -0
- package/lib/scheduleManager.js.map +1 -1
- package/lib/summary/index.d.ts +1 -1
- package/lib/summary/index.d.ts.map +1 -1
- package/lib/summary/index.js +1 -1
- package/lib/summary/index.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.js +2 -0
- package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/lib/summary/summaryFormat.d.ts +0 -1
- package/lib/summary/summaryFormat.d.ts.map +1 -1
- package/lib/summary/summaryFormat.js +5 -2
- package/lib/summary/summaryFormat.js.map +1 -1
- package/package.json +49 -34
- package/src/{blobManager.ts → blobManager/blobManager.ts} +57 -123
- package/src/blobManager/blobManagerSnapSum.ts +133 -0
- package/src/blobManager/index.ts +19 -0
- package/src/channelCollection.ts +48 -11
- package/src/containerRuntime.ts +213 -158
- package/src/dataStoreContext.ts +30 -6
- package/src/gc/garbageCollection.ts +17 -12
- package/src/gc/gcDefinitions.ts +7 -2
- package/src/gc/gcHelpers.ts +18 -6
- package/src/gc/gcTelemetry.ts +20 -8
- package/src/index.ts +1 -1
- package/src/metadata.ts +11 -1
- package/src/opLifecycle/README.md +0 -8
- package/src/opLifecycle/batchManager.ts +46 -16
- package/src/opLifecycle/definitions.ts +1 -1
- package/src/opLifecycle/index.ts +8 -1
- package/src/opLifecycle/opCompressor.ts +12 -8
- package/src/opLifecycle/opGroupingManager.ts +14 -11
- package/src/opLifecycle/opSplitter.ts +10 -6
- package/src/opLifecycle/outbox.ts +64 -26
- package/src/opLifecycle/remoteMessageProcessor.ts +84 -11
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +177 -60
- package/src/scheduleManager.ts +6 -2
- package/src/summary/README.md +81 -0
- package/src/summary/index.ts +0 -1
- package/src/summary/summarizerNode/summarizerNodeUtils.ts +3 -1
- package/src/summary/summaryFormat.ts +4 -2
- package/src/summary/summaryFormats.md +69 -8
- package/tsconfig.json +0 -1
- package/dist/blobManager.d.ts.map +0 -1
- package/dist/blobManager.js.map +0 -1
- package/lib/blobManager.d.ts.map +0 -1
- package/lib/blobManager.js.map +0 -1
- package/src/summary/images/appTree.png +0 -0
- package/src/summary/images/protocolAndAppTree.png +0 -0
- 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-
|
|
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-
|
|
131
|
-
"@fluidframework/container-definitions": "2.1.0-
|
|
132
|
-
"@fluidframework/container-runtime-definitions": "2.1.0-
|
|
133
|
-
"@fluidframework/core-interfaces": "2.1.0-
|
|
134
|
-
"@fluidframework/core-utils": "2.1.0-
|
|
135
|
-
"@fluidframework/datastore": "2.1.0-
|
|
136
|
-
"@fluidframework/driver-definitions": "2.1.0-
|
|
137
|
-
"@fluidframework/driver-utils": "2.1.0-
|
|
138
|
-
"@fluidframework/id-compressor": "2.1.0-
|
|
139
|
-
"@fluidframework/runtime-definitions": "2.1.0-
|
|
140
|
-
"@fluidframework/runtime-utils": "2.1.0-
|
|
141
|
-
"@fluidframework/telemetry-utils": "2.1.0-
|
|
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": "
|
|
150
|
-
"@fluid-internal/mocha-test-setup": "2.1.0-
|
|
151
|
-
"@fluid-private/stochastic-test-utils": "2.1.0-
|
|
152
|
-
"@fluid-private/test-pairwise-generator": "2.1.0-
|
|
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.
|
|
154
|
+
"@fluid-tools/build-cli": "^0.40.0",
|
|
155
155
|
"@fluidframework/build-common": "^2.0.3",
|
|
156
|
-
"@fluidframework/build-tools": "^0.
|
|
157
|
-
"@fluidframework/container-runtime-previous": "npm:@fluidframework/container-runtime@2.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-
|
|
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": "
|
|
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 .
|
|
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:
|
|
209
|
-
"ci:build:
|
|
210
|
-
"ci:build:
|
|
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 . --
|
|
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 "
|
|
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 - `/<
|
|
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 - `/<
|
|
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 - `/<
|
|
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 - `/<
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 -`/<
|
|
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:
|
|
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 `/<
|
|
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
|
-
|
|
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 `/<
|
|
874
|
+
* For a given GC node path, return the blobId. The node path is of the format `/<basePath>/<blobId>`.
|
|
949
875
|
*/
|
|
950
|
-
|
|
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";
|