@fluidframework/map 2.0.0-dev.2.3.0.115467 → 2.0.0-dev.4.1.0.148229
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/.eslintrc.js +12 -14
- package/.mocharc.js +2 -2
- package/README.md +3 -3
- package/api-extractor.json +2 -2
- package/dist/directory.d.ts +38 -5
- package/dist/directory.d.ts.map +1 -1
- package/dist/directory.js +285 -88
- package/dist/directory.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/interfaces.d.ts +27 -17
- package/dist/interfaces.d.ts.map +1 -1
- package/dist/interfaces.js.map +1 -1
- package/dist/internalInterfaces.d.ts +39 -0
- package/dist/internalInterfaces.d.ts.map +1 -1
- package/dist/internalInterfaces.js.map +1 -1
- package/dist/localValues.d.ts +12 -3
- package/dist/localValues.d.ts.map +1 -1
- package/dist/localValues.js +10 -0
- package/dist/localValues.js.map +1 -1
- package/dist/map.d.ts +5 -5
- package/dist/map.d.ts.map +1 -1
- package/dist/map.js +15 -2
- package/dist/map.js.map +1 -1
- package/dist/mapKernel.d.ts +5 -5
- package/dist/mapKernel.d.ts.map +1 -1
- package/dist/mapKernel.js +58 -33
- package/dist/mapKernel.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/lib/directory.d.ts +38 -5
- package/lib/directory.d.ts.map +1 -1
- package/lib/directory.js +287 -90
- package/lib/directory.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/interfaces.d.ts +27 -17
- package/lib/interfaces.d.ts.map +1 -1
- package/lib/interfaces.js.map +1 -1
- package/lib/internalInterfaces.d.ts +39 -0
- package/lib/internalInterfaces.d.ts.map +1 -1
- package/lib/internalInterfaces.js.map +1 -1
- package/lib/localValues.d.ts +12 -3
- package/lib/localValues.d.ts.map +1 -1
- package/lib/localValues.js +10 -0
- package/lib/localValues.js.map +1 -1
- package/lib/map.d.ts +5 -5
- package/lib/map.d.ts.map +1 -1
- package/lib/map.js +16 -3
- package/lib/map.js.map +1 -1
- package/lib/mapKernel.d.ts +5 -5
- package/lib/mapKernel.d.ts.map +1 -1
- package/lib/mapKernel.js +59 -34
- package/lib/mapKernel.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/package.json +60 -59
- package/prettier.config.cjs +1 -1
- package/src/directory.ts +2207 -1848
- package/src/index.ts +1 -0
- package/src/interfaces.ts +309 -288
- package/src/internalInterfaces.ts +83 -38
- package/src/localValues.ts +95 -93
- package/src/map.ts +364 -345
- package/src/mapKernel.ts +729 -676
- package/src/packageVersion.ts +1 -1
- package/tsconfig.esnext.json +5 -5
- package/tsconfig.json +9 -15
package/src/map.ts
CHANGED
|
@@ -5,29 +5,23 @@
|
|
|
5
5
|
|
|
6
6
|
import { ISequencedDocumentMessage, MessageType } from "@fluidframework/protocol-definitions";
|
|
7
7
|
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
IChannelAttributes,
|
|
9
|
+
IFluidDataStoreRuntime,
|
|
10
|
+
IChannelStorageService,
|
|
11
|
+
IChannelServices,
|
|
12
|
+
IChannelFactory,
|
|
13
13
|
} from "@fluidframework/datastore-definitions";
|
|
14
14
|
import { ISummaryTreeWithStats, ITelemetryContext } from "@fluidframework/runtime-definitions";
|
|
15
15
|
import { readAndParse } from "@fluidframework/driver-utils";
|
|
16
|
-
import {
|
|
17
|
-
IFluidSerializer,
|
|
18
|
-
SharedObject,
|
|
19
|
-
} from "@fluidframework/shared-object-base";
|
|
16
|
+
import { IFluidSerializer, SharedObject } from "@fluidframework/shared-object-base";
|
|
20
17
|
import { SummaryTreeBuilder } from "@fluidframework/runtime-utils";
|
|
21
|
-
import {
|
|
22
|
-
|
|
23
|
-
ISharedMapEvents,
|
|
24
|
-
} from "./interfaces";
|
|
25
|
-
import { IMapDataObjectSerializable, MapKernel } from "./mapKernel";
|
|
18
|
+
import { ISharedMap, ISharedMapEvents } from "./interfaces";
|
|
19
|
+
import { IMapDataObjectSerializable, IMapOperation, MapKernel } from "./mapKernel";
|
|
26
20
|
import { pkgVersion } from "./packageVersion";
|
|
27
21
|
|
|
28
22
|
interface IMapSerializationFormat {
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
blobs?: string[];
|
|
24
|
+
content: IMapDataObjectSerializable;
|
|
31
25
|
}
|
|
32
26
|
|
|
33
27
|
const snapshotFileName = "header";
|
|
@@ -38,339 +32,364 @@ const snapshotFileName = "header";
|
|
|
38
32
|
* @sealed
|
|
39
33
|
*/
|
|
40
34
|
export class MapFactory implements IChannelFactory {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
35
|
+
/**
|
|
36
|
+
* {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory."type"}
|
|
37
|
+
*/
|
|
38
|
+
public static readonly Type = "https://graph.microsoft.com/types/map";
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory.attributes}
|
|
42
|
+
*/
|
|
43
|
+
public static readonly Attributes: IChannelAttributes = {
|
|
44
|
+
type: MapFactory.Type,
|
|
45
|
+
snapshotFormatVersion: "0.2",
|
|
46
|
+
packageVersion: pkgVersion,
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory."type"}
|
|
51
|
+
*/
|
|
52
|
+
public get type(): string {
|
|
53
|
+
return MapFactory.Type;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory.attributes}
|
|
58
|
+
*/
|
|
59
|
+
public get attributes(): IChannelAttributes {
|
|
60
|
+
return MapFactory.Attributes;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory.load}
|
|
65
|
+
*/
|
|
66
|
+
public async load(
|
|
67
|
+
runtime: IFluidDataStoreRuntime,
|
|
68
|
+
id: string,
|
|
69
|
+
services: IChannelServices,
|
|
70
|
+
attributes: IChannelAttributes,
|
|
71
|
+
): Promise<ISharedMap> {
|
|
72
|
+
const map = new SharedMap(id, runtime, attributes);
|
|
73
|
+
await map.load(services);
|
|
74
|
+
|
|
75
|
+
return map;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory.create}
|
|
80
|
+
*/
|
|
81
|
+
public create(runtime: IFluidDataStoreRuntime, id: string): ISharedMap {
|
|
82
|
+
const map = new SharedMap(id, runtime, MapFactory.Attributes);
|
|
83
|
+
map.initializeLocal();
|
|
84
|
+
|
|
85
|
+
return map;
|
|
86
|
+
}
|
|
92
87
|
}
|
|
93
88
|
|
|
94
89
|
/**
|
|
95
90
|
* {@inheritDoc ISharedMap}
|
|
96
91
|
*/
|
|
97
92
|
export class SharedMap extends SharedObject<ISharedMapEvents> implements ISharedMap {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
93
|
+
/**
|
|
94
|
+
* Create a new shared map.
|
|
95
|
+
* @param runtime - The data store runtime that the new shared map belongs to.
|
|
96
|
+
* @param id - Optional name of the shared map.
|
|
97
|
+
* @returns Newly created shared map.
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* To create a `SharedMap`, call the static create method:
|
|
101
|
+
*
|
|
102
|
+
* ```typescript
|
|
103
|
+
* const myMap = SharedMap.create(this.runtime, id);
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
public static create(runtime: IFluidDataStoreRuntime, id?: string): SharedMap {
|
|
107
|
+
return runtime.createChannel(id, MapFactory.Type) as SharedMap;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Get a factory for SharedMap to register with the data store.
|
|
112
|
+
* @returns A factory that creates SharedMaps and loads them from storage.
|
|
113
|
+
*/
|
|
114
|
+
public static getFactory(): IChannelFactory {
|
|
115
|
+
return new MapFactory();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* String representation for the class.
|
|
120
|
+
*/
|
|
121
|
+
public readonly [Symbol.toStringTag]: string = "SharedMap";
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* MapKernel which manages actual map operations.
|
|
125
|
+
*/
|
|
126
|
+
private readonly kernel: MapKernel;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Do not call the constructor. Instead, you should use the {@link SharedMap.create | create method}.
|
|
130
|
+
*
|
|
131
|
+
* @param id - String identifier.
|
|
132
|
+
* @param runtime - Data store runtime.
|
|
133
|
+
* @param attributes - The attributes for the map.
|
|
134
|
+
*/
|
|
135
|
+
public constructor(
|
|
136
|
+
id: string,
|
|
137
|
+
runtime: IFluidDataStoreRuntime,
|
|
138
|
+
attributes: IChannelAttributes,
|
|
139
|
+
) {
|
|
140
|
+
super(id, runtime, attributes, "fluid_map_");
|
|
141
|
+
this.kernel = new MapKernel(
|
|
142
|
+
this.serializer,
|
|
143
|
+
this.handle,
|
|
144
|
+
(op, localOpMetadata) => this.submitLocalMessage(op, localOpMetadata),
|
|
145
|
+
() => this.isAttached(),
|
|
146
|
+
this,
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Get an iterator over the keys in this map.
|
|
152
|
+
* @returns The iterator
|
|
153
|
+
*/
|
|
154
|
+
public keys(): IterableIterator<string> {
|
|
155
|
+
return this.kernel.keys();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Get an iterator over the entries in this map.
|
|
160
|
+
* @returns The iterator
|
|
161
|
+
*/
|
|
162
|
+
// TODO: Use `unknown` instead (breaking change).
|
|
163
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
164
|
+
public entries(): IterableIterator<[string, any]> {
|
|
165
|
+
return this.kernel.entries();
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Get an iterator over the values in this map.
|
|
170
|
+
* @returns The iterator
|
|
171
|
+
*/
|
|
172
|
+
// TODO: Use `unknown` instead (breaking change).
|
|
173
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
174
|
+
public values(): IterableIterator<any> {
|
|
175
|
+
return this.kernel.values();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Get an iterator over the entries in this map.
|
|
180
|
+
* @returns The iterator
|
|
181
|
+
*/
|
|
182
|
+
// TODO: Use `unknown` instead (breaking change).
|
|
183
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
184
|
+
public [Symbol.iterator](): IterableIterator<[string, any]> {
|
|
185
|
+
return this.kernel.entries();
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* The number of key/value pairs stored in the map.
|
|
190
|
+
*/
|
|
191
|
+
public get size(): number {
|
|
192
|
+
return this.kernel.size;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Executes the given callback on each entry in the map.
|
|
197
|
+
* @param callbackFn - Callback function
|
|
198
|
+
*/
|
|
199
|
+
// TODO: Use `unknown` instead (breaking change).
|
|
200
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
201
|
+
public forEach(callbackFn: (value: any, key: string, map: Map<string, any>) => void): void {
|
|
202
|
+
// eslint-disable-next-line unicorn/no-array-for-each, unicorn/no-array-callback-reference
|
|
203
|
+
this.kernel.forEach(callbackFn);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* {@inheritDoc ISharedMap.get}
|
|
208
|
+
*/
|
|
209
|
+
// TODO: Use `unknown` instead (breaking change).
|
|
210
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
211
|
+
public get<T = any>(key: string): T | undefined {
|
|
212
|
+
return this.kernel.get<T>(key);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Check if a key exists in the map.
|
|
217
|
+
* @param key - The key to check
|
|
218
|
+
* @returns True if the key exists, false otherwise
|
|
219
|
+
*/
|
|
220
|
+
public has(key: string): boolean {
|
|
221
|
+
return this.kernel.has(key);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* {@inheritDoc ISharedMap.set}
|
|
226
|
+
*/
|
|
227
|
+
public set(key: string, value: unknown): this {
|
|
228
|
+
this.kernel.set(key, value);
|
|
229
|
+
return this;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Delete a key from the map.
|
|
234
|
+
* @param key - Key to delete
|
|
235
|
+
* @returns True if the key existed and was deleted, false if it did not exist
|
|
236
|
+
*/
|
|
237
|
+
public delete(key: string): boolean {
|
|
238
|
+
return this.kernel.delete(key);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Clear all data from the map.
|
|
243
|
+
*/
|
|
244
|
+
public clear(): void {
|
|
245
|
+
this.kernel.clear();
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* {@inheritDoc @fluidframework/shared-object-base#SharedObject.summarizeCore}
|
|
250
|
+
* @internal
|
|
251
|
+
*/
|
|
252
|
+
protected summarizeCore(
|
|
253
|
+
serializer: IFluidSerializer,
|
|
254
|
+
telemetryContext?: ITelemetryContext,
|
|
255
|
+
): ISummaryTreeWithStats {
|
|
256
|
+
let currentSize = 0;
|
|
257
|
+
let counter = 0;
|
|
258
|
+
let headerBlob: IMapDataObjectSerializable = {};
|
|
259
|
+
const blobs: string[] = [];
|
|
260
|
+
|
|
261
|
+
const builder = new SummaryTreeBuilder();
|
|
262
|
+
|
|
263
|
+
const data = this.kernel.getSerializedStorage(serializer);
|
|
264
|
+
|
|
265
|
+
// If single property exceeds this size, it goes into its own blob
|
|
266
|
+
const MinValueSizeSeparateSnapshotBlob = 8 * 1024;
|
|
267
|
+
|
|
268
|
+
// Maximum blob size for multiple map properties
|
|
269
|
+
// Should be bigger than MinValueSizeSeparateSnapshotBlob
|
|
270
|
+
const MaxSnapshotBlobSize = 16 * 1024;
|
|
271
|
+
|
|
272
|
+
// Partitioning algorithm:
|
|
273
|
+
// 1) Split large (over MinValueSizeSeparateSnapshotBlob = 8K) properties into their own blobs.
|
|
274
|
+
// Naming (across snapshots) of such blob does not have to be stable across snapshots,
|
|
275
|
+
// As de-duping process (in driver) should not care about paths, only content.
|
|
276
|
+
// 2) Split remaining properties into blobs of MaxSnapshotBlobSize (16K) size.
|
|
277
|
+
// This process does not produce stable partitioning. This means
|
|
278
|
+
// modification (including addition / deletion) of property can shift properties across blobs
|
|
279
|
+
// and result in non-incremental snapshot.
|
|
280
|
+
// This can be improved in the future, without being format breaking change, as loading sequence
|
|
281
|
+
// loads all blobs at once and partitioning schema has no impact on that process.
|
|
282
|
+
for (const key of Object.keys(data)) {
|
|
283
|
+
const value = data[key];
|
|
284
|
+
if (value.value && value.value.length >= MinValueSizeSeparateSnapshotBlob) {
|
|
285
|
+
const blobName = `blob${counter}`;
|
|
286
|
+
counter++;
|
|
287
|
+
blobs.push(blobName);
|
|
288
|
+
const content: IMapDataObjectSerializable = {
|
|
289
|
+
[key]: {
|
|
290
|
+
type: value.type,
|
|
291
|
+
value: JSON.parse(value.value) as unknown,
|
|
292
|
+
},
|
|
293
|
+
};
|
|
294
|
+
builder.addBlob(blobName, JSON.stringify(content));
|
|
295
|
+
} else {
|
|
296
|
+
currentSize += value.type.length + 21; // Approximation cost of property header
|
|
297
|
+
if (value.value) {
|
|
298
|
+
currentSize += value.value.length;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (currentSize > MaxSnapshotBlobSize) {
|
|
302
|
+
const blobName = `blob${counter}`;
|
|
303
|
+
counter++;
|
|
304
|
+
blobs.push(blobName);
|
|
305
|
+
builder.addBlob(blobName, JSON.stringify(headerBlob));
|
|
306
|
+
headerBlob = {};
|
|
307
|
+
currentSize = 0;
|
|
308
|
+
}
|
|
309
|
+
headerBlob[key] = {
|
|
310
|
+
type: value.type,
|
|
311
|
+
value:
|
|
312
|
+
value.value === undefined
|
|
313
|
+
? undefined
|
|
314
|
+
: (JSON.parse(value.value) as unknown),
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const header: IMapSerializationFormat = {
|
|
320
|
+
blobs,
|
|
321
|
+
content: headerBlob,
|
|
322
|
+
};
|
|
323
|
+
builder.addBlob(snapshotFileName, JSON.stringify(header));
|
|
324
|
+
|
|
325
|
+
return builder.getSummaryTree();
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* {@inheritDoc @fluidframework/shared-object-base#SharedObject.loadCore}
|
|
330
|
+
* @internal
|
|
331
|
+
*/
|
|
332
|
+
protected async loadCore(storage: IChannelStorageService): Promise<void> {
|
|
333
|
+
const json = await readAndParse<object>(storage, snapshotFileName);
|
|
334
|
+
const newFormat = json as IMapSerializationFormat;
|
|
335
|
+
if (Array.isArray(newFormat.blobs)) {
|
|
336
|
+
this.kernel.populateFromSerializable(newFormat.content);
|
|
337
|
+
await Promise.all(
|
|
338
|
+
newFormat.blobs.map(async (value) => {
|
|
339
|
+
const content = await readAndParse<IMapDataObjectSerializable>(storage, value);
|
|
340
|
+
this.kernel.populateFromSerializable(content);
|
|
341
|
+
}),
|
|
342
|
+
);
|
|
343
|
+
} else {
|
|
344
|
+
this.kernel.populateFromSerializable(json as IMapDataObjectSerializable);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* {@inheritDoc @fluidframework/shared-object-base#SharedObject.onDisconnect}
|
|
350
|
+
* @internal
|
|
351
|
+
*/
|
|
352
|
+
protected onDisconnect(): void {}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* {@inheritDoc @fluidframework/shared-object-base#SharedObject.reSubmitCore}
|
|
356
|
+
* @internal
|
|
357
|
+
*/
|
|
358
|
+
protected reSubmitCore(content: unknown, localOpMetadata: unknown): void {
|
|
359
|
+
this.kernel.trySubmitMessage(content as IMapOperation, localOpMetadata);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.applyStashedOp}
|
|
364
|
+
* @internal
|
|
365
|
+
*/
|
|
366
|
+
protected applyStashedOp(content: unknown): unknown {
|
|
367
|
+
return this.kernel.tryApplyStashedOp(content as IMapOperation);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* {@inheritDoc @fluidframework/shared-object-base#SharedObject.processCore}
|
|
372
|
+
* @internal
|
|
373
|
+
*/
|
|
374
|
+
protected processCore(
|
|
375
|
+
message: ISequencedDocumentMessage,
|
|
376
|
+
local: boolean,
|
|
377
|
+
localOpMetadata: unknown,
|
|
378
|
+
): void {
|
|
379
|
+
if (message.type === MessageType.Operation) {
|
|
380
|
+
this.kernel.tryProcessMessage(
|
|
381
|
+
message.contents as IMapOperation,
|
|
382
|
+
local,
|
|
383
|
+
localOpMetadata,
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* {@inheritDoc @fluidframework/shared-object-base#SharedObject.rollback}
|
|
390
|
+
* @internal
|
|
391
|
+
*/
|
|
392
|
+
protected rollback(content: unknown, localOpMetadata: unknown): void {
|
|
393
|
+
this.kernel.rollback(content, localOpMetadata);
|
|
394
|
+
}
|
|
376
395
|
}
|