@fluidframework/datastore 2.0.0-rc.2.0.1 → 2.0.0-rc.3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/api-report/datastore.api.md +7 -5
- package/dist/channelContext.d.ts +5 -4
- package/dist/channelContext.d.ts.map +1 -1
- package/dist/channelContext.js +10 -10
- package/dist/channelContext.js.map +1 -1
- package/dist/channelDeltaConnection.d.ts +2 -2
- package/dist/channelDeltaConnection.d.ts.map +1 -1
- package/dist/channelDeltaConnection.js +5 -5
- package/dist/channelDeltaConnection.js.map +1 -1
- package/dist/channelStorageService.d.ts +2 -2
- package/dist/channelStorageService.d.ts.map +1 -1
- package/dist/channelStorageService.js +2 -2
- package/dist/channelStorageService.js.map +1 -1
- package/dist/dataStoreRuntime.d.ts +11 -8
- package/dist/dataStoreRuntime.d.ts.map +1 -1
- package/dist/dataStoreRuntime.js +129 -104
- package/dist/dataStoreRuntime.js.map +1 -1
- package/dist/fluidHandle.d.ts +1 -1
- package/dist/fluidHandle.d.ts.map +1 -1
- package/dist/fluidHandle.js +2 -2
- package/dist/fluidHandle.js.map +1 -1
- package/dist/legacy.d.ts +19 -0
- package/dist/localChannelContext.d.ts +8 -7
- package/dist/localChannelContext.d.ts.map +1 -1
- package/dist/localChannelContext.js +35 -25
- package/dist/localChannelContext.js.map +1 -1
- package/dist/localChannelStorageService.d.ts.map +1 -1
- package/dist/localChannelStorageService.js +2 -2
- package/dist/localChannelStorageService.js.map +1 -1
- package/dist/packageVersion.d.ts +9 -0
- package/dist/packageVersion.d.ts.map +1 -0
- package/dist/packageVersion.js +12 -0
- package/dist/packageVersion.js.map +1 -0
- package/dist/public.d.ts +12 -0
- package/dist/remoteChannelContext.d.ts +3 -2
- package/dist/remoteChannelContext.d.ts.map +1 -1
- package/dist/remoteChannelContext.js +12 -12
- package/dist/remoteChannelContext.js.map +1 -1
- package/internal.d.ts +11 -0
- package/legacy.d.ts +11 -0
- package/lib/channelContext.d.ts +5 -4
- package/lib/channelContext.d.ts.map +1 -1
- package/lib/channelContext.js +4 -4
- package/lib/channelContext.js.map +1 -1
- package/lib/channelDeltaConnection.d.ts +2 -2
- package/lib/channelDeltaConnection.d.ts.map +1 -1
- package/lib/channelDeltaConnection.js +2 -2
- package/lib/channelDeltaConnection.js.map +1 -1
- package/lib/channelStorageService.d.ts +2 -2
- package/lib/channelStorageService.d.ts.map +1 -1
- package/lib/channelStorageService.js +1 -1
- package/lib/channelStorageService.js.map +1 -1
- package/lib/dataStoreRuntime.d.ts +11 -8
- package/lib/dataStoreRuntime.d.ts.map +1 -1
- package/lib/dataStoreRuntime.js +68 -43
- package/lib/dataStoreRuntime.js.map +1 -1
- package/lib/fluidHandle.d.ts +1 -1
- package/lib/fluidHandle.d.ts.map +1 -1
- package/lib/fluidHandle.js +1 -1
- package/lib/fluidHandle.js.map +1 -1
- package/lib/legacy.d.ts +19 -0
- package/lib/localChannelContext.d.ts +8 -7
- package/lib/localChannelContext.d.ts.map +1 -1
- package/lib/localChannelContext.js +21 -8
- package/lib/localChannelContext.js.map +1 -1
- package/lib/localChannelStorageService.d.ts.map +1 -1
- package/lib/localChannelStorageService.js +1 -1
- package/lib/localChannelStorageService.js.map +1 -1
- package/lib/packageVersion.d.ts +9 -0
- package/lib/packageVersion.d.ts.map +1 -0
- package/lib/packageVersion.js +9 -0
- package/lib/packageVersion.js.map +1 -0
- package/lib/public.d.ts +12 -0
- package/lib/remoteChannelContext.d.ts +3 -2
- package/lib/remoteChannelContext.d.ts.map +1 -1
- package/lib/remoteChannelContext.js +2 -2
- package/lib/remoteChannelContext.js.map +1 -1
- package/package.json +37 -58
- package/src/channelContext.ts +12 -12
- package/src/channelDeltaConnection.ts +4 -4
- package/src/channelStorageService.ts +3 -3
- package/src/dataStoreRuntime.ts +143 -96
- package/src/fluidHandle.ts +2 -2
- package/src/localChannelContext.ts +33 -16
- package/src/localChannelStorageService.ts +2 -2
- package/src/packageVersion.ts +9 -0
- package/src/remoteChannelContext.ts +13 -13
- package/api-extractor-cjs.json +0 -8
- package/dist/datastore-alpha.d.ts +0 -333
- package/dist/datastore-beta.d.ts +0 -46
- package/dist/datastore-public.d.ts +0 -46
- package/dist/datastore-untrimmed.d.ts +0 -340
- package/lib/datastore-alpha.d.ts +0 -333
- package/lib/datastore-beta.d.ts +0 -46
- package/lib/datastore-public.d.ts +0 -46
- package/lib/datastore-untrimmed.d.ts +0 -340
- package/lib/test/channelStorageService.spec.js +0 -70
- package/lib/test/channelStorageService.spec.js.map +0 -1
- package/lib/test/dataStoreRuntime.spec.js +0 -121
- package/lib/test/dataStoreRuntime.spec.js.map +0 -1
- package/lib/test/localChannelContext.spec.js +0 -41
- package/lib/test/localChannelContext.spec.js.map +0 -1
- package/lib/test/localChannelStorageService.spec.js +0 -72
- package/lib/test/localChannelStorageService.spec.js.map +0 -1
- package/lib/test/remoteChannelContext.spec.js +0 -33
- package/lib/test/remoteChannelContext.spec.js.map +0 -1
- package/lib/test/types/validateDatastorePrevious.generated.js +0 -16
- package/lib/test/types/validateDatastorePrevious.generated.js.map +0 -1
- /package/{dist → lib}/tsdoc-metadata.json +0 -0
package/dist/dataStoreRuntime.js
CHANGED
|
@@ -6,18 +6,19 @@
|
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.mixinSummaryHandler = exports.mixinRequestHandler = exports.FluidDataStoreRuntime = exports.DataStoreMessageType = void 0;
|
|
8
8
|
const client_utils_1 = require("@fluid-internal/client-utils");
|
|
9
|
-
const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
|
|
10
|
-
const core_utils_1 = require("@fluidframework/core-utils");
|
|
11
9
|
const container_definitions_1 = require("@fluidframework/container-definitions");
|
|
12
|
-
const
|
|
10
|
+
const internal_1 = require("@fluidframework/core-utils/internal");
|
|
11
|
+
const internal_2 = require("@fluidframework/driver-utils/internal");
|
|
13
12
|
const protocol_definitions_1 = require("@fluidframework/protocol-definitions");
|
|
14
|
-
const
|
|
15
|
-
const
|
|
13
|
+
const internal_3 = require("@fluidframework/runtime-definitions/internal");
|
|
14
|
+
const internal_4 = require("@fluidframework/runtime-utils/internal");
|
|
15
|
+
const internal_5 = require("@fluidframework/telemetry-utils/internal");
|
|
16
16
|
const uuid_1 = require("uuid");
|
|
17
17
|
const channelContext_js_1 = require("./channelContext.js");
|
|
18
|
+
const fluidHandle_js_1 = require("./fluidHandle.js");
|
|
18
19
|
const localChannelContext_js_1 = require("./localChannelContext.js");
|
|
20
|
+
const packageVersion_js_1 = require("./packageVersion.js");
|
|
19
21
|
const remoteChannelContext_js_1 = require("./remoteChannelContext.js");
|
|
20
|
-
const fluidHandle_js_1 = require("./fluidHandle.js");
|
|
21
22
|
/**
|
|
22
23
|
* @alpha
|
|
23
24
|
*/
|
|
@@ -48,7 +49,7 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
48
49
|
return this._attachState;
|
|
49
50
|
}
|
|
50
51
|
get absolutePath() {
|
|
51
|
-
return (0,
|
|
52
|
+
return (0, internal_4.generateHandleContextPath)(this.id, this.routeContext);
|
|
52
53
|
}
|
|
53
54
|
get routeContext() {
|
|
54
55
|
return this.dataStoreContext.IFluidHandleContext;
|
|
@@ -106,18 +107,18 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
106
107
|
this._disposed = false;
|
|
107
108
|
this.contexts = new Map();
|
|
108
109
|
this.pendingAttach = new Set();
|
|
109
|
-
this.deferredAttached = new
|
|
110
|
+
this.deferredAttached = new internal_1.Deferred();
|
|
110
111
|
this.localChannelContextQueue = new Map();
|
|
111
112
|
this.notBoundedChannelContextSet = new Set();
|
|
112
113
|
// A list of handles that are bound when the data store is not visible. We have to make them visible when the data
|
|
113
114
|
// store becomes visible.
|
|
114
115
|
this.pendingHandlesToMakeVisible = new Set();
|
|
115
|
-
(0,
|
|
116
|
-
this.mc = (0,
|
|
116
|
+
(0, internal_1.assert)(!dataStoreContext.id.includes("/"), 0x30e /* Id cannot contain slashes. DataStoreContext should have validated this. */);
|
|
117
|
+
this.mc = (0, internal_5.createChildMonitoringContext)({
|
|
117
118
|
logger: dataStoreContext.logger,
|
|
118
119
|
namespace: "FluidDataStoreRuntime",
|
|
119
120
|
properties: {
|
|
120
|
-
all: { dataStoreId: (0, uuid_1.v4)() },
|
|
121
|
+
all: { dataStoreId: (0, uuid_1.v4)(), dataStoreVersion: packageVersion_js_1.pkgVersion },
|
|
121
122
|
},
|
|
122
123
|
});
|
|
123
124
|
this.id = dataStoreContext.id;
|
|
@@ -138,7 +139,7 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
138
139
|
// container from snapshot where we load detached container from a snapshot, isLocalDataStore would be
|
|
139
140
|
// true. In this case create a RehydratedLocalChannelContext.
|
|
140
141
|
if (dataStoreContext.isLocalDataStore) {
|
|
141
|
-
channelContext =
|
|
142
|
+
channelContext = this.createRehydratedLocalChannelContext(path, tree.trees[path]);
|
|
142
143
|
// This is the case of rehydrating a detached container from snapshot. Now due to delay loading of
|
|
143
144
|
// data store, if the data store is loaded after the container is attached, then we missed making
|
|
144
145
|
// the channel visible. So do it now. Otherwise, add it to local channel context queue, so
|
|
@@ -152,13 +153,13 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
152
153
|
}
|
|
153
154
|
else {
|
|
154
155
|
channelContext = new remoteChannelContext_js_1.RemoteChannelContext(this, dataStoreContext, dataStoreContext.storage, (content, localOpMetadata) => this.submitChannelOp(path, content, localOpMetadata), (address) => this.setChannelDirty(address), (srcHandle, outboundHandle) => this.addedGCOutboundReference(srcHandle, outboundHandle), path, tree.trees[path], this.sharedObjectRegistry, undefined /* extraBlobs */, this.dataStoreContext.getCreateChildSummarizerNodeFn(path, {
|
|
155
|
-
type:
|
|
156
|
+
type: internal_3.CreateSummarizerNodeSource.FromSummary,
|
|
156
157
|
}));
|
|
157
158
|
}
|
|
158
159
|
this.contexts.set(path, channelContext);
|
|
159
160
|
});
|
|
160
161
|
}
|
|
161
|
-
this.entryPoint = new fluidHandle_js_1.FluidObjectHandle(new
|
|
162
|
+
this.entryPoint = new fluidHandle_js_1.FluidObjectHandle(new internal_1.LazyPromise(async () => provideEntryPoint(this)), "", this.objectsRoutingContext);
|
|
162
163
|
this.attachListener();
|
|
163
164
|
this._attachState = dataStoreContext.attachState;
|
|
164
165
|
/**
|
|
@@ -174,11 +175,11 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
174
175
|
if (existing) {
|
|
175
176
|
this.visibilityState =
|
|
176
177
|
dataStoreContext.attachState === container_definitions_1.AttachState.Detached
|
|
177
|
-
?
|
|
178
|
-
:
|
|
178
|
+
? internal_3.VisibilityState.LocallyVisible
|
|
179
|
+
: internal_3.VisibilityState.GloballyVisible;
|
|
179
180
|
}
|
|
180
181
|
else {
|
|
181
|
-
this.visibilityState =
|
|
182
|
+
this.visibilityState = internal_3.VisibilityState.NotVisible;
|
|
182
183
|
}
|
|
183
184
|
// If it's existing we know it has been attached.
|
|
184
185
|
if (existing) {
|
|
@@ -201,7 +202,7 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
201
202
|
}
|
|
202
203
|
async request(request) {
|
|
203
204
|
try {
|
|
204
|
-
const parser =
|
|
205
|
+
const parser = internal_4.RequestParser.create(request);
|
|
205
206
|
const id = parser.pathParts[0];
|
|
206
207
|
if (id === "_channels" || id === "_custom") {
|
|
207
208
|
return await this.request(parser.createSubRequest(1));
|
|
@@ -215,21 +216,21 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
215
216
|
}
|
|
216
217
|
catch (error) {
|
|
217
218
|
this.mc.logger.sendErrorEvent({ eventName: "GetChannelFailedInRequest" }, error);
|
|
218
|
-
return (0,
|
|
219
|
+
return (0, internal_4.createResponseError)(500, `Failed to get Channel: ${error}`, request);
|
|
219
220
|
}
|
|
220
221
|
}
|
|
221
222
|
// Otherwise defer to an attached request handler
|
|
222
|
-
return (0,
|
|
223
|
+
return (0, internal_4.create404Response)(request);
|
|
223
224
|
}
|
|
224
225
|
catch (error) {
|
|
225
|
-
return (0,
|
|
226
|
+
return (0, internal_4.exceptionToResponse)(error);
|
|
226
227
|
}
|
|
227
228
|
}
|
|
228
229
|
async getChannel(id) {
|
|
229
230
|
this.verifyNotClosed();
|
|
230
231
|
const context = this.contexts.get(id);
|
|
231
232
|
if (context === undefined) {
|
|
232
|
-
throw new
|
|
233
|
+
throw new internal_5.LoggingError("Channel does not exist");
|
|
233
234
|
}
|
|
234
235
|
return context.getChannel();
|
|
235
236
|
}
|
|
@@ -241,10 +242,10 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
241
242
|
*/
|
|
242
243
|
validateChannelId(id) {
|
|
243
244
|
if (id.includes("/")) {
|
|
244
|
-
throw new
|
|
245
|
+
throw new internal_5.UsageError(`Id cannot contain slashes: ${id}`);
|
|
245
246
|
}
|
|
246
247
|
if (id.startsWith("_")) {
|
|
247
|
-
throw new
|
|
248
|
+
throw new internal_5.UsageError(`Id cannot start with underscore: ${id}`);
|
|
248
249
|
}
|
|
249
250
|
}
|
|
250
251
|
/**
|
|
@@ -258,7 +259,7 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
258
259
|
const id = channel.id;
|
|
259
260
|
this.validateChannelId(id);
|
|
260
261
|
this.verifyNotClosed();
|
|
261
|
-
(0,
|
|
262
|
+
(0, internal_1.assert)(!this.contexts.has(id), 0x865 /* addChannel() with existing ID */);
|
|
262
263
|
const type = channel.attributes.type;
|
|
263
264
|
const factory = this.sharedObjectRegistry.get(channel.attributes.type);
|
|
264
265
|
if (factory === undefined) {
|
|
@@ -281,21 +282,21 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
281
282
|
// - uuids
|
|
282
283
|
// In first two cases we will encode result as strings in more compact form, with leading underscore,
|
|
283
284
|
// to ensure no overlap with user-provided DDS names (see validateChannelId())
|
|
284
|
-
if (this.visibilityState !==
|
|
285
|
+
if (this.visibilityState !== internal_3.VisibilityState.GloballyVisible) {
|
|
285
286
|
// container is detached, only one client observes content, no way to hit collisions with other clients.
|
|
286
|
-
id = (0,
|
|
287
|
+
id = (0, internal_4.encodeCompactIdToString)(2 * this.contexts.size, "_");
|
|
287
288
|
}
|
|
288
289
|
else {
|
|
289
290
|
// Due to back-compat, we could not depend yet on generateDocumentUniqueId() being there.
|
|
290
291
|
// We can remove the need to leverage uuid() as fall-back in couple releases.
|
|
291
292
|
const res = this.dataStoreContext.containerRuntime.generateDocumentUniqueId?.() ?? (0, uuid_1.v4)();
|
|
292
|
-
id = typeof res === "number" ? (0,
|
|
293
|
+
id = typeof res === "number" ? (0, internal_4.encodeCompactIdToString)(2 * res + 1, "_") : res;
|
|
293
294
|
}
|
|
294
|
-
(0,
|
|
295
|
+
(0, internal_1.assert)(!id.includes("/"), 0x8fc /* slash */);
|
|
295
296
|
}
|
|
296
297
|
this.verifyNotClosed();
|
|
297
|
-
(0,
|
|
298
|
-
(0,
|
|
298
|
+
(0, internal_1.assert)(!this.contexts.has(id), 0x179 /* "createChannel() with existing ID" */);
|
|
299
|
+
(0, internal_1.assert)(type !== undefined, 0x209 /* "Factory Type should be defined" */);
|
|
299
300
|
const factory = this.sharedObjectRegistry.get(type);
|
|
300
301
|
if (factory === undefined) {
|
|
301
302
|
throw new Error(`Channel Factory ${type} not registered`);
|
|
@@ -311,13 +312,16 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
311
312
|
const context = new localChannelContext_js_1.LocalChannelContext(channel, this, this.dataStoreContext, this.dataStoreContext.storage, this.logger, (content, localOpMetadata) => this.submitChannelOp(channel.id, content, localOpMetadata), (address) => this.setChannelDirty(address), (srcHandle, outboundHandle) => this.addedGCOutboundReference(srcHandle, outboundHandle));
|
|
312
313
|
this.contexts.set(channel.id, context);
|
|
313
314
|
}
|
|
315
|
+
createRehydratedLocalChannelContext(id, tree, flatBlobs) {
|
|
316
|
+
return new localChannelContext_js_1.RehydratedLocalChannelContext(id, this.sharedObjectRegistry, this, this.dataStoreContext, this.dataStoreContext.storage, this.logger, (content, localOpMetadata) => this.submitChannelOp(id, content, localOpMetadata), (address) => this.setChannelDirty(address), (srcHandle, outboundHandle) => this.addedGCOutboundReference(srcHandle, outboundHandle), tree, flatBlobs);
|
|
317
|
+
}
|
|
314
318
|
/**
|
|
315
319
|
* Binds a channel with the runtime. If the runtime is attached we will attach the channel right away.
|
|
316
320
|
* If the runtime is not attached we will defer the attach until the runtime attaches.
|
|
317
321
|
* @param channel - channel to be registered.
|
|
318
322
|
*/
|
|
319
323
|
bindChannel(channel) {
|
|
320
|
-
(0,
|
|
324
|
+
(0, internal_1.assert)(this.notBoundedChannelContextSet.has(channel.id), 0x17b /* "Channel to be bound should be in not bounded set" */);
|
|
321
325
|
this.notBoundedChannelContextSet.delete(channel.id);
|
|
322
326
|
// If our data store is attached, then attach the channel.
|
|
323
327
|
if (this.isAttached) {
|
|
@@ -349,10 +353,10 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
349
353
|
* globally visible.
|
|
350
354
|
*/
|
|
351
355
|
makeVisibleAndAttachGraph() {
|
|
352
|
-
if (this.visibilityState !==
|
|
356
|
+
if (this.visibilityState !== internal_3.VisibilityState.NotVisible) {
|
|
353
357
|
return;
|
|
354
358
|
}
|
|
355
|
-
this.visibilityState =
|
|
359
|
+
this.visibilityState = internal_3.VisibilityState.LocallyVisible;
|
|
356
360
|
this.pendingHandlesToMakeVisible.forEach((handle) => {
|
|
357
361
|
handle.attachGraph();
|
|
358
362
|
});
|
|
@@ -367,7 +371,7 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
367
371
|
}
|
|
368
372
|
bind(handle) {
|
|
369
373
|
// If visible, attach the incoming handle's graph. Else, this will be done when we become visible.
|
|
370
|
-
if (this.visibilityState !==
|
|
374
|
+
if (this.visibilityState !== internal_3.VisibilityState.NotVisible) {
|
|
371
375
|
handle.attachGraph();
|
|
372
376
|
return;
|
|
373
377
|
}
|
|
@@ -378,7 +382,7 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
378
382
|
for (const [, object] of this.contexts) {
|
|
379
383
|
object.setConnectionState(connected, clientId);
|
|
380
384
|
}
|
|
381
|
-
(0,
|
|
385
|
+
(0, internal_5.raiseConnectedEvent)(this.logger, this, connected, clientId);
|
|
382
386
|
}
|
|
383
387
|
getQuorum() {
|
|
384
388
|
return this.quorum;
|
|
@@ -392,7 +396,7 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
392
396
|
}
|
|
393
397
|
createRemoteChannelContext(attachMessage, summarizerNodeParams) {
|
|
394
398
|
const flatBlobs = new Map();
|
|
395
|
-
const snapshotTree = (0,
|
|
399
|
+
const snapshotTree = (0, internal_2.buildSnapshotTree)(attachMessage.snapshot.entries, flatBlobs);
|
|
396
400
|
return new remoteChannelContext_js_1.RemoteChannelContext(this, this.dataStoreContext, this.dataStoreContext.storage, (content, localContentMetadata) => this.submitChannelOp(attachMessage.id, content, localContentMetadata), (address) => this.setChannelDirty(address), (srcHandle, outboundHandle) => this.addedGCOutboundReference(srcHandle, outboundHandle), attachMessage.id, snapshotTree, this.sharedObjectRegistry, flatBlobs, this.dataStoreContext.getCreateChildSummarizerNodeFn(attachMessage.id, summarizerNodeParams), attachMessage.type);
|
|
397
401
|
}
|
|
398
402
|
process(message, local, localOpMetadata) {
|
|
@@ -404,7 +408,7 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
404
408
|
const attachMessage = message.contents;
|
|
405
409
|
const id = attachMessage.id;
|
|
406
410
|
// We need to process the GC Data for both local and remote attach messages
|
|
407
|
-
(0,
|
|
411
|
+
(0, internal_4.processAttachMessageGCData)(attachMessage.snapshot, (nodeId, toPath) => {
|
|
408
412
|
// Note: nodeId will be "/" unless and until we support sub-DDS GC Nodes
|
|
409
413
|
const fromPath = `/${this.id}/${id}${nodeId === "/" ? "" : nodeId}`;
|
|
410
414
|
this.dataStoreContext.addedGCOutboundRoute?.(fromPath, toPath);
|
|
@@ -412,12 +416,12 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
412
416
|
// If a non-local operation then go and create the object
|
|
413
417
|
// Otherwise mark it as officially attached.
|
|
414
418
|
if (local) {
|
|
415
|
-
(0,
|
|
419
|
+
(0, internal_1.assert)(this.pendingAttach.delete(id), 0x17c /* "Unexpected attach (local) channel OP" */);
|
|
416
420
|
}
|
|
417
421
|
else {
|
|
418
|
-
(0,
|
|
422
|
+
(0, internal_1.assert)(!this.contexts.has(id), 0x17d /* "Unexpected attach channel OP" */);
|
|
419
423
|
const summarizerNodeParams = {
|
|
420
|
-
type:
|
|
424
|
+
type: internal_3.CreateSummarizerNodeSource.FromAttach,
|
|
421
425
|
sequenceNumber: message.sequenceNumber,
|
|
422
426
|
snapshot: attachMessage.snapshot,
|
|
423
427
|
};
|
|
@@ -434,7 +438,7 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
434
438
|
this.emit("op", message);
|
|
435
439
|
}
|
|
436
440
|
catch (error) {
|
|
437
|
-
throw
|
|
441
|
+
throw internal_5.DataProcessingError.wrapIfUnrecognized(error, "fluidDataStoreRuntimeFailedToProcessMessage", message);
|
|
438
442
|
}
|
|
439
443
|
}
|
|
440
444
|
processSignal(message, local) {
|
|
@@ -493,7 +497,7 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
493
497
|
* @param fullGC - true to bypass optimizations and force full generation of GC data.
|
|
494
498
|
*/
|
|
495
499
|
async getGCData(fullGC = false) {
|
|
496
|
-
const builder = new
|
|
500
|
+
const builder = new internal_4.GCDataBuilder();
|
|
497
501
|
// Iterate over each channel context and get their GC data.
|
|
498
502
|
await Promise.all(Array.from(this.contexts)
|
|
499
503
|
.filter(([contextId, _]) => {
|
|
@@ -517,10 +521,10 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
517
521
|
*/
|
|
518
522
|
updateUsedRoutes(usedRoutes) {
|
|
519
523
|
// Get a map of channel ids to routes used in it.
|
|
520
|
-
const usedContextRoutes = (0,
|
|
524
|
+
const usedContextRoutes = (0, internal_4.unpackChildNodesUsedRoutes)(usedRoutes);
|
|
521
525
|
// Verify that the used routes are correct.
|
|
522
526
|
for (const [id] of usedContextRoutes) {
|
|
523
|
-
(0,
|
|
527
|
+
(0, internal_1.assert)(this.contexts.has(id), 0x17e /* "Used route does not belong to any known context" */);
|
|
524
528
|
}
|
|
525
529
|
// Update the used routes in each context. Used routes is empty for unused context.
|
|
526
530
|
for (const [contextId, context] of this.contexts) {
|
|
@@ -547,13 +551,13 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
547
551
|
* @param telemetryContext - summary data passed through the layers for telemetry purposes
|
|
548
552
|
*/
|
|
549
553
|
async summarize(fullTree = false, trackState = true, telemetryContext) {
|
|
550
|
-
const summaryBuilder = new
|
|
554
|
+
const summaryBuilder = new internal_4.SummaryTreeBuilder();
|
|
551
555
|
// Iterate over each data store and ask it to summarize
|
|
552
556
|
await Promise.all(Array.from(this.contexts)
|
|
553
557
|
.filter(([contextId, _]) => {
|
|
554
558
|
const isAttached = this.isChannelAttached(contextId);
|
|
555
559
|
// We are not expecting local dds! Summary may not capture local state.
|
|
556
|
-
(0,
|
|
560
|
+
(0, internal_1.assert)(isAttached, 0x17f /* "Not expecting detached channels during summarize" */);
|
|
557
561
|
// If the object is registered - and we have received the sequenced op creating the object
|
|
558
562
|
// (i.e. it has a base mapping) - then we go ahead and summarize
|
|
559
563
|
return isAttached;
|
|
@@ -565,19 +569,19 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
565
569
|
return summaryBuilder.getSummaryTree();
|
|
566
570
|
}
|
|
567
571
|
getAttachSummary(telemetryContext) {
|
|
568
|
-
const summaryBuilder = new
|
|
572
|
+
const summaryBuilder = new internal_4.SummaryTreeBuilder();
|
|
569
573
|
this.visitLocalBoundContextsDuringAttach((contextId, context) => {
|
|
570
574
|
let summaryTree;
|
|
571
575
|
if (context.isLoaded) {
|
|
572
576
|
const contextSummary = context.getAttachSummary(telemetryContext);
|
|
573
|
-
(0,
|
|
577
|
+
(0, internal_1.assert)(contextSummary.summary.type === protocol_definitions_1.SummaryType.Tree, 0x180 /* "getAttachSummary should always return a tree" */);
|
|
574
578
|
summaryTree = { stats: contextSummary.stats, summary: contextSummary.summary };
|
|
575
579
|
}
|
|
576
580
|
else {
|
|
577
581
|
// If this channel is not yet loaded, then there should be no changes in the snapshot from which
|
|
578
582
|
// it was created as it is detached container. So just use the previous snapshot.
|
|
579
|
-
(0,
|
|
580
|
-
summaryTree = (0,
|
|
583
|
+
(0, internal_1.assert)(!!this.dataStoreContext.baseSnapshot, 0x181 /* "BaseSnapshot should be there as detached container loaded from snapshot" */);
|
|
584
|
+
summaryTree = (0, internal_4.convertSnapshotTreeToSummaryTree)(this.dataStoreContext.baseSnapshot.trees[contextId]);
|
|
581
585
|
}
|
|
582
586
|
summaryBuilder.addWithStats(contextId, summaryTree);
|
|
583
587
|
});
|
|
@@ -587,7 +591,7 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
587
591
|
* Get the GC Data for the initial state being attached so remote clients can learn of this DataStore's outbound routes
|
|
588
592
|
*/
|
|
589
593
|
getAttachGCData(telemetryContext) {
|
|
590
|
-
const gcDataBuilder = new
|
|
594
|
+
const gcDataBuilder = new internal_4.GCDataBuilder();
|
|
591
595
|
this.visitLocalBoundContextsDuringAttach((contextId, context) => {
|
|
592
596
|
if (context.isLoaded) {
|
|
593
597
|
const contextGCData = context.getAttachGCData(telemetryContext);
|
|
@@ -624,7 +628,7 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
624
628
|
// );
|
|
625
629
|
for (const [contextId, context] of this.contexts) {
|
|
626
630
|
if (!(context instanceof localChannelContext_js_1.LocalChannelContextBase)) {
|
|
627
|
-
throw new
|
|
631
|
+
throw new internal_5.LoggingError("Should only be called with local channel handles");
|
|
628
632
|
}
|
|
629
633
|
if (!this.notBoundedChannelContextSet.has(contextId)) {
|
|
630
634
|
visitor(contextId, context);
|
|
@@ -637,7 +641,7 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
637
641
|
/**
|
|
638
642
|
* Submits the signal to be sent to other clients.
|
|
639
643
|
* @param type - Type of the signal.
|
|
640
|
-
* @param content - Content of the signal.
|
|
644
|
+
* @param content - Content of the signal. Should be a JSON serializable object or primitive.
|
|
641
645
|
* @param targetClientId - When specified, the signal is only sent to the provided client id.
|
|
642
646
|
*/
|
|
643
647
|
submitSignal(type, content, targetClientId) {
|
|
@@ -661,14 +665,14 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
661
665
|
return;
|
|
662
666
|
}
|
|
663
667
|
channel.handle.attachGraph();
|
|
664
|
-
(0,
|
|
665
|
-
(0,
|
|
668
|
+
(0, internal_1.assert)(this.isAttached, 0x182 /* "Data store should be attached to attach the channel." */);
|
|
669
|
+
(0, internal_1.assert)(this.visibilityState === internal_3.VisibilityState.GloballyVisible, 0x2d0 /* "Data store should be globally visible to attach channels." */);
|
|
666
670
|
const summarizeResult = (0, channelContext_js_1.summarizeChannel)(channel, true /* fullTree */, false /* trackState */);
|
|
667
671
|
// We need to include the channel's GC Data so remote clients can learn of this channel's outbound routes
|
|
668
672
|
const gcData = channel.getGCData(/* fullGC: */ true);
|
|
669
|
-
(0,
|
|
673
|
+
(0, internal_4.addBlobToSummary)(summarizeResult, internal_3.gcDataBlobKey, JSON.stringify(gcData));
|
|
670
674
|
// Attach message needs the summary in ITree format. Convert the ISummaryTree into an ITree.
|
|
671
|
-
const snapshot = (0,
|
|
675
|
+
const snapshot = (0, internal_4.convertSummaryTreeToITree)(summarizeResult.summary);
|
|
672
676
|
const message = {
|
|
673
677
|
id: channel.id,
|
|
674
678
|
snapshot,
|
|
@@ -701,7 +705,7 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
701
705
|
// For Operations, find the right channel and trigger resubmission on it.
|
|
702
706
|
const envelope = content;
|
|
703
707
|
const channelContext = this.contexts.get(envelope.address);
|
|
704
|
-
(0,
|
|
708
|
+
(0, internal_1.assert)(!!channelContext, 0x183 /* "There should be a channel context for the op" */);
|
|
705
709
|
channelContext.reSubmit(envelope.contents, localOpMetadata);
|
|
706
710
|
break;
|
|
707
711
|
}
|
|
@@ -710,7 +714,7 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
710
714
|
this.submit(type, content, localOpMetadata);
|
|
711
715
|
break;
|
|
712
716
|
default:
|
|
713
|
-
(0,
|
|
717
|
+
(0, internal_1.unreachableCase)(type);
|
|
714
718
|
}
|
|
715
719
|
}
|
|
716
720
|
/**
|
|
@@ -725,12 +729,12 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
725
729
|
// For Operations, find the right channel and trigger resubmission on it.
|
|
726
730
|
const envelope = content;
|
|
727
731
|
const channelContext = this.contexts.get(envelope.address);
|
|
728
|
-
(0,
|
|
732
|
+
(0, internal_1.assert)(!!channelContext, 0x2ed /* "There should be a channel context for the op" */);
|
|
729
733
|
channelContext.rollback(envelope.contents, localOpMetadata);
|
|
730
734
|
break;
|
|
731
735
|
}
|
|
732
736
|
default:
|
|
733
|
-
throw new
|
|
737
|
+
throw new internal_5.LoggingError(`Can't rollback ${type} message`);
|
|
734
738
|
}
|
|
735
739
|
}
|
|
736
740
|
async applyStashedOp(content) {
|
|
@@ -738,24 +742,29 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
738
742
|
switch (type) {
|
|
739
743
|
case DataStoreMessageType.Attach: {
|
|
740
744
|
const attachMessage = content.content;
|
|
741
|
-
|
|
742
|
-
const
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
this.
|
|
747
|
-
|
|
745
|
+
const flatBlobs = new Map();
|
|
746
|
+
const snapshotTree = (0, internal_2.buildSnapshotTree)(attachMessage.snapshot.entries, flatBlobs);
|
|
747
|
+
const channelContext = this.createRehydratedLocalChannelContext(attachMessage.id, snapshotTree, flatBlobs);
|
|
748
|
+
await channelContext.getChannel();
|
|
749
|
+
this.contexts.set(attachMessage.id, channelContext);
|
|
750
|
+
if (this.attachState === container_definitions_1.AttachState.Detached) {
|
|
751
|
+
this.localChannelContextQueue.set(attachMessage.id, channelContext);
|
|
752
|
+
}
|
|
753
|
+
else {
|
|
754
|
+
channelContext.makeVisible();
|
|
755
|
+
this.pendingAttach.add(attachMessage.id);
|
|
756
|
+
}
|
|
748
757
|
return;
|
|
749
758
|
}
|
|
750
759
|
case DataStoreMessageType.ChannelOp: {
|
|
751
760
|
const envelope = content.content;
|
|
752
761
|
const channelContext = this.contexts.get(envelope.address);
|
|
753
|
-
(0,
|
|
762
|
+
(0, internal_1.assert)(!!channelContext, 0x184 /* "There should be a channel context for the op" */);
|
|
754
763
|
await channelContext.getChannel();
|
|
755
764
|
return channelContext.applyStashedOp(envelope.contents);
|
|
756
765
|
}
|
|
757
766
|
default:
|
|
758
|
-
(0,
|
|
767
|
+
(0, internal_1.unreachableCase)(type);
|
|
759
768
|
}
|
|
760
769
|
}
|
|
761
770
|
setChannelDirty(address) {
|
|
@@ -770,44 +779,26 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
770
779
|
contents: envelope.contents,
|
|
771
780
|
};
|
|
772
781
|
const channelContext = this.contexts.get(envelope.address);
|
|
773
|
-
(0,
|
|
782
|
+
(0, internal_1.assert)(!!channelContext, 0x185 /* "Channel not found" */);
|
|
774
783
|
channelContext.processOp(transformed, local, localOpMetadata);
|
|
775
784
|
return channelContext;
|
|
776
785
|
}
|
|
777
786
|
attachListener() {
|
|
778
787
|
this.setMaxListeners(Number.MAX_SAFE_INTEGER);
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
* store can move to "attaching" state in 2 scenarios:
|
|
784
|
-
* 1) Before attachGraph() is called - When a data store is created and bound in an attached container.
|
|
785
|
-
* 2) After attachGraph() is called - When a detached container is attached.
|
|
786
|
-
*
|
|
787
|
-
* The basic idea is that all local object should become locally visible before they are globally visible.
|
|
788
|
-
*/
|
|
789
|
-
this.attachGraph();
|
|
790
|
-
this._attachState = container_definitions_1.AttachState.Attaching;
|
|
791
|
-
(0, core_utils_1.assert)(this.visibilityState === runtime_definitions_1.VisibilityState.LocallyVisible, 0x2d1 /* "Data store should be locally visible before it can become globally visible." */);
|
|
792
|
-
// Mark the data store globally visible and make its child channels visible as well.
|
|
793
|
-
this.visibilityState = runtime_definitions_1.VisibilityState.GloballyVisible;
|
|
794
|
-
this.localChannelContextQueue.forEach((channel) => {
|
|
795
|
-
channel.makeVisible();
|
|
796
|
-
});
|
|
797
|
-
this.localChannelContextQueue.clear();
|
|
798
|
-
// This promise resolution will be moved to attached event once we fix the scheduler.
|
|
799
|
-
this.deferredAttached.resolve();
|
|
800
|
-
this.emit("attaching");
|
|
788
|
+
// back-compat, to be removed in the future.
|
|
789
|
+
// Added in "2.0.0-rc.2.0.0" timeframe.
|
|
790
|
+
this.dataStoreContext.once?.("attaching", () => {
|
|
791
|
+
this.setAttachState(container_definitions_1.AttachState.Attaching);
|
|
801
792
|
});
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
this.
|
|
793
|
+
// back-compat, to be removed in the future.
|
|
794
|
+
// Added in "2.0.0-rc.2.0.0" timeframe.
|
|
795
|
+
this.dataStoreContext.once?.("attached", () => {
|
|
796
|
+
this.setAttachState(container_definitions_1.AttachState.Attached);
|
|
806
797
|
});
|
|
807
798
|
}
|
|
808
799
|
verifyNotClosed() {
|
|
809
800
|
if (this._disposed) {
|
|
810
|
-
throw new
|
|
801
|
+
throw new internal_5.LoggingError("Runtime is closed");
|
|
811
802
|
}
|
|
812
803
|
}
|
|
813
804
|
/**
|
|
@@ -824,16 +815,50 @@ class FluidDataStoreRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
824
815
|
// in the summarizer and the data will help us plan this.
|
|
825
816
|
this.mc.logger.sendTelemetryEvent({
|
|
826
817
|
eventName,
|
|
827
|
-
...(0,
|
|
818
|
+
...(0, internal_5.tagCodeArtifacts)({
|
|
828
819
|
channelType,
|
|
829
820
|
channelId,
|
|
830
821
|
fluidDataStoreId: this.id,
|
|
831
822
|
fluidDataStorePackagePath: this.dataStoreContext.packagePath.join("/"),
|
|
832
823
|
}),
|
|
833
|
-
stack: (0,
|
|
824
|
+
stack: (0, internal_5.generateStack)(),
|
|
834
825
|
});
|
|
835
826
|
this.localChangesTelemetryCount--;
|
|
836
827
|
}
|
|
828
|
+
setAttachState(attachState) {
|
|
829
|
+
switch (attachState) {
|
|
830
|
+
case container_definitions_1.AttachState.Attaching:
|
|
831
|
+
/**
|
|
832
|
+
* back-compat 0.59.1000 - Ideally, attachGraph() should have already been called making the data store
|
|
833
|
+
* locally visible. However, before visibility state was added, this may not have been the case and data
|
|
834
|
+
* store can move to "attaching" state in 2 scenarios:
|
|
835
|
+
* 1) Before attachGraph() is called - When a data store is created and bound in an attached container.
|
|
836
|
+
* 2) After attachGraph() is called - When a detached container is attached.
|
|
837
|
+
*
|
|
838
|
+
* The basic idea is that all local object should become locally visible before they are globally visible.
|
|
839
|
+
*/
|
|
840
|
+
this.attachGraph();
|
|
841
|
+
this._attachState = container_definitions_1.AttachState.Attaching;
|
|
842
|
+
(0, internal_1.assert)(this.visibilityState === internal_3.VisibilityState.LocallyVisible, 0x2d1 /* "Data store should be locally visible before it can become globally visible." */);
|
|
843
|
+
// Mark the data store globally visible and make its child channels visible as well.
|
|
844
|
+
this.visibilityState = internal_3.VisibilityState.GloballyVisible;
|
|
845
|
+
this.localChannelContextQueue.forEach((channel) => {
|
|
846
|
+
channel.makeVisible();
|
|
847
|
+
});
|
|
848
|
+
this.localChannelContextQueue.clear();
|
|
849
|
+
// This promise resolution will be moved to attached event once we fix the scheduler.
|
|
850
|
+
this.deferredAttached.resolve();
|
|
851
|
+
this.emit("attaching");
|
|
852
|
+
break;
|
|
853
|
+
case container_definitions_1.AttachState.Attached:
|
|
854
|
+
(0, internal_1.assert)(this.visibilityState === internal_3.VisibilityState.GloballyVisible, 0x2d2 /* "Data store should be globally visible when its attached." */);
|
|
855
|
+
this._attachState = container_definitions_1.AttachState.Attached;
|
|
856
|
+
this.emit("attached");
|
|
857
|
+
break;
|
|
858
|
+
default:
|
|
859
|
+
(0, internal_1.unreachableCase)(attachState, "unreached");
|
|
860
|
+
}
|
|
861
|
+
}
|
|
837
862
|
}
|
|
838
863
|
exports.FluidDataStoreRuntime = FluidDataStoreRuntime;
|
|
839
864
|
/**
|
|
@@ -841,7 +866,7 @@ exports.FluidDataStoreRuntime = FluidDataStoreRuntime;
|
|
|
841
866
|
* Request handler is only called when data store can't resolve request, i.e. for custom requests.
|
|
842
867
|
* @param Base - base class, inherits from FluidDataStoreRuntime
|
|
843
868
|
* @param requestHandler - request handler to mix in
|
|
844
|
-
* @
|
|
869
|
+
* @alpha
|
|
845
870
|
*/
|
|
846
871
|
const mixinRequestHandler = (requestHandler, Base = FluidDataStoreRuntime) => class RuntimeWithRequestHandler extends Base {
|
|
847
872
|
async request(request) {
|
|
@@ -864,7 +889,7 @@ const mixinSummaryHandler = (handler, Base = FluidDataStoreRuntime) => class Run
|
|
|
864
889
|
addBlob(summary, path, content) {
|
|
865
890
|
const firstName = path.shift();
|
|
866
891
|
if (firstName === undefined) {
|
|
867
|
-
throw new
|
|
892
|
+
throw new internal_5.LoggingError("Path can't be empty");
|
|
868
893
|
}
|
|
869
894
|
let blob = {
|
|
870
895
|
type: protocol_definitions_1.SummaryType.Blob,
|
|
@@ -891,7 +916,7 @@ const mixinSummaryHandler = (handler, Base = FluidDataStoreRuntime) => class Run
|
|
|
891
916
|
}
|
|
892
917
|
catch (e) {
|
|
893
918
|
// Any error coming from app-provided handler should be marked as DataProcessingError
|
|
894
|
-
throw
|
|
919
|
+
throw internal_5.DataProcessingError.wrapIfUnrecognized(e, "mixinSummaryHandler");
|
|
895
920
|
}
|
|
896
921
|
return summary;
|
|
897
922
|
}
|