@fluidframework/datastore 2.0.0-internal.3.0.2 → 2.0.0-internal.3.2.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/.eslintrc.js +5 -7
- package/.mocharc.js +2 -2
- package/README.md +3 -0
- package/api-extractor.json +2 -2
- package/dist/channelContext.d.ts.map +1 -1
- package/dist/channelContext.js.map +1 -1
- package/dist/channelDeltaConnection.d.ts.map +1 -1
- package/dist/channelDeltaConnection.js.map +1 -1
- package/dist/channelStorageService.d.ts.map +1 -1
- package/dist/channelStorageService.js +1 -3
- package/dist/channelStorageService.js.map +1 -1
- package/dist/dataStoreRuntime.d.ts +10 -18
- package/dist/dataStoreRuntime.d.ts.map +1 -1
- package/dist/dataStoreRuntime.js +65 -83
- package/dist/dataStoreRuntime.js.map +1 -1
- package/dist/fluidHandle.d.ts.map +1 -1
- package/dist/fluidHandle.js.map +1 -1
- package/dist/localChannelContext.d.ts.map +1 -1
- package/dist/localChannelContext.js +9 -5
- package/dist/localChannelContext.js.map +1 -1
- package/dist/localChannelStorageService.d.ts.map +1 -1
- package/dist/localChannelStorageService.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/remoteChannelContext.d.ts +2 -2
- package/dist/remoteChannelContext.d.ts.map +1 -1
- package/dist/remoteChannelContext.js +4 -4
- package/dist/remoteChannelContext.js.map +1 -1
- package/lib/channelContext.d.ts.map +1 -1
- package/lib/channelContext.js.map +1 -1
- package/lib/channelDeltaConnection.d.ts.map +1 -1
- package/lib/channelDeltaConnection.js.map +1 -1
- package/lib/channelStorageService.d.ts.map +1 -1
- package/lib/channelStorageService.js +1 -3
- package/lib/channelStorageService.js.map +1 -1
- package/lib/dataStoreRuntime.d.ts +10 -18
- package/lib/dataStoreRuntime.d.ts.map +1 -1
- package/lib/dataStoreRuntime.js +68 -86
- package/lib/dataStoreRuntime.js.map +1 -1
- package/lib/fluidHandle.d.ts.map +1 -1
- package/lib/fluidHandle.js.map +1 -1
- package/lib/localChannelContext.d.ts.map +1 -1
- package/lib/localChannelContext.js +9 -5
- package/lib/localChannelContext.js.map +1 -1
- package/lib/localChannelStorageService.d.ts.map +1 -1
- package/lib/localChannelStorageService.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/remoteChannelContext.d.ts +2 -2
- package/lib/remoteChannelContext.d.ts.map +1 -1
- package/lib/remoteChannelContext.js +4 -4
- package/lib/remoteChannelContext.js.map +1 -1
- package/package.json +50 -49
- package/prettier.config.cjs +1 -1
- package/src/channelContext.ts +66 -65
- package/src/channelDeltaConnection.ts +50 -44
- package/src/channelStorageService.ts +58 -54
- package/src/dataStoreRuntime.ts +1131 -1087
- package/src/fluidHandle.ts +87 -91
- package/src/localChannelContext.ts +302 -255
- package/src/localChannelStorageService.ts +47 -45
- package/src/packageVersion.ts +1 -1
- package/src/remoteChannelContext.ts +297 -291
- package/tsconfig.esnext.json +6 -6
- package/tsconfig.json +9 -13
package/lib/dataStoreRuntime.js
CHANGED
|
@@ -8,12 +8,12 @@ import { assert, Deferred, LazyPromise, TypedEventEmitter, unreachableCase, } fr
|
|
|
8
8
|
import { ChildLogger, generateStack, LoggingError, loggerToMonitoringContext, raiseConnectedEvent, TelemetryDataTag, } from "@fluidframework/telemetry-utils";
|
|
9
9
|
import { buildSnapshotTree } from "@fluidframework/driver-utils";
|
|
10
10
|
import { SummaryType, } from "@fluidframework/protocol-definitions";
|
|
11
|
-
import {
|
|
11
|
+
import { CreateSummarizerNodeSource, VisibilityState, } from "@fluidframework/runtime-definitions";
|
|
12
12
|
import { convertSnapshotTreeToSummaryTree, convertSummaryTreeToITree, generateHandleContextPath, RequestParser, SummaryTreeBuilder, create404Response, createResponseError, exceptionToResponse, requestFluidObject, packagePathToTelemetryProperty, } from "@fluidframework/runtime-utils";
|
|
13
|
-
import { GCDataBuilder,
|
|
13
|
+
import { GCDataBuilder, unpackChildNodesUsedRoutes } from "@fluidframework/garbage-collector";
|
|
14
14
|
import { v4 as uuid } from "uuid";
|
|
15
15
|
import { summarizeChannel } from "./channelContext";
|
|
16
|
-
import { LocalChannelContext, LocalChannelContextBase, RehydratedLocalChannelContext } from "./localChannelContext";
|
|
16
|
+
import { LocalChannelContext, LocalChannelContextBase, RehydratedLocalChannelContext, } from "./localChannelContext";
|
|
17
17
|
import { RemoteChannelContext } from "./remoteChannelContext";
|
|
18
18
|
import { FluidObjectHandle } from "./fluidHandle";
|
|
19
19
|
export var DataStoreMessageType;
|
|
@@ -27,16 +27,16 @@ export var DataStoreMessageType;
|
|
|
27
27
|
*/
|
|
28
28
|
export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
29
29
|
/**
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
30
|
+
* Create an instance of a DataStore runtime.
|
|
31
|
+
*
|
|
32
|
+
* @param dataStoreContext - Context object for the runtime.
|
|
33
|
+
* @param sharedObjectRegistry - The registry of shared objects that this data store will be able to instantiate.
|
|
34
|
+
* @param existing - Pass 'true' if loading this datastore from an existing file; pass 'false' otherwise.
|
|
35
|
+
* @param initializeEntryPoint - Function to initialize the entryPoint object for the data store runtime. The
|
|
36
|
+
* handle to this data store runtime will point to the object returned by this function. If this function is not
|
|
37
|
+
* provided, the handle will be left undefined. This is here so we can start making handles a first-class citizen
|
|
38
|
+
* and the primary way of interacting with some Fluid objects, and should be used if possible.
|
|
39
|
+
*/
|
|
40
40
|
constructor(dataStoreContext, sharedObjectRegistry, existing, initializeEntryPoint) {
|
|
41
41
|
var _a;
|
|
42
42
|
super();
|
|
@@ -62,10 +62,6 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
62
62
|
this.quorum = dataStoreContext.getQuorum();
|
|
63
63
|
this.audience = dataStoreContext.getAudience();
|
|
64
64
|
const tree = dataStoreContext.baseSnapshot;
|
|
65
|
-
this.channelsBaseGCDetails = new LazyPromise(async () => {
|
|
66
|
-
const baseGCDetails = await this.dataStoreContext.getBaseGCDetails();
|
|
67
|
-
return unpackChildNodesGCDetails(baseGCDetails);
|
|
68
|
-
});
|
|
69
65
|
// Must always receive the data store type inside of the attributes
|
|
70
66
|
if ((tree === null || tree === void 0 ? void 0 : tree.trees) !== undefined) {
|
|
71
67
|
Object.keys(tree.trees).forEach((path) => {
|
|
@@ -91,7 +87,9 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
91
87
|
}
|
|
92
88
|
}
|
|
93
89
|
else {
|
|
94
|
-
channelContext = new 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, {
|
|
90
|
+
channelContext = new 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, {
|
|
91
|
+
type: CreateSummarizerNodeSource.FromSummary,
|
|
92
|
+
}));
|
|
95
93
|
}
|
|
96
94
|
const deferred = new Deferred();
|
|
97
95
|
deferred.resolve(channelContext);
|
|
@@ -104,8 +102,6 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
104
102
|
this.entryPoint = new FluidObjectHandle(promise, "", this.objectsRoutingContext);
|
|
105
103
|
}
|
|
106
104
|
this.attachListener();
|
|
107
|
-
// If exists on storage or loaded from a snapshot, it should already be bound.
|
|
108
|
-
this.bindState = existing ? BindState.Bound : BindState.NotBound;
|
|
109
105
|
this._attachState = dataStoreContext.attachState;
|
|
110
106
|
/**
|
|
111
107
|
* If existing flag is false, this is a new data store and is not visible. The existing flag can be true in two
|
|
@@ -118,8 +114,10 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
118
114
|
* when an attach op comes in. In both these cases, the data store is already globally visible.
|
|
119
115
|
*/
|
|
120
116
|
if (existing) {
|
|
121
|
-
this.visibilityState =
|
|
122
|
-
|
|
117
|
+
this.visibilityState =
|
|
118
|
+
dataStoreContext.attachState === AttachState.Detached
|
|
119
|
+
? VisibilityState.LocallyVisible
|
|
120
|
+
: VisibilityState.GloballyVisible;
|
|
123
121
|
}
|
|
124
122
|
else {
|
|
125
123
|
this.visibilityState = VisibilityState.NotVisible;
|
|
@@ -143,7 +141,9 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
143
141
|
static load(context, sharedObjectRegistry, existing) {
|
|
144
142
|
return new FluidDataStoreRuntime(context, sharedObjectRegistry, existing, async (dataStoreRuntime) => requestFluidObject(dataStoreRuntime, "/"));
|
|
145
143
|
}
|
|
146
|
-
get IFluidRouter() {
|
|
144
|
+
get IFluidRouter() {
|
|
145
|
+
return this;
|
|
146
|
+
}
|
|
147
147
|
get connected() {
|
|
148
148
|
return this.dataStoreContext.connected;
|
|
149
149
|
}
|
|
@@ -165,11 +165,21 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
165
165
|
get routeContext() {
|
|
166
166
|
return this.dataStoreContext.IFluidHandleContext;
|
|
167
167
|
}
|
|
168
|
-
get IFluidHandleContext() {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
get
|
|
172
|
-
|
|
168
|
+
get IFluidHandleContext() {
|
|
169
|
+
return this;
|
|
170
|
+
}
|
|
171
|
+
get rootRoutingContext() {
|
|
172
|
+
return this;
|
|
173
|
+
}
|
|
174
|
+
get channelsRoutingContext() {
|
|
175
|
+
return this;
|
|
176
|
+
}
|
|
177
|
+
get objectsRoutingContext() {
|
|
178
|
+
return this;
|
|
179
|
+
}
|
|
180
|
+
get disposed() {
|
|
181
|
+
return this._disposed;
|
|
182
|
+
}
|
|
173
183
|
get logger() {
|
|
174
184
|
return this.mc.logger;
|
|
175
185
|
}
|
|
@@ -183,9 +193,9 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
183
193
|
*/
|
|
184
194
|
ensureNoDataModelChanges(callback) {
|
|
185
195
|
// back-compat ADO:2309
|
|
186
|
-
return this.dataStoreContext.ensureNoDataModelChanges === undefined
|
|
187
|
-
callback()
|
|
188
|
-
this.dataStoreContext.ensureNoDataModelChanges(callback);
|
|
196
|
+
return this.dataStoreContext.ensureNoDataModelChanges === undefined
|
|
197
|
+
? callback()
|
|
198
|
+
: this.dataStoreContext.ensureNoDataModelChanges(callback);
|
|
189
199
|
}
|
|
190
200
|
dispose() {
|
|
191
201
|
if (this._disposed) {
|
|
@@ -307,7 +317,7 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
307
317
|
handle.attachGraph();
|
|
308
318
|
});
|
|
309
319
|
this.pendingHandlesToMakeVisible.clear();
|
|
310
|
-
this.
|
|
320
|
+
this.dataStoreContext.makeLocallyVisible();
|
|
311
321
|
}
|
|
312
322
|
/**
|
|
313
323
|
* This function is called when a handle to this data store is added to a visible DDS.
|
|
@@ -323,12 +333,7 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
323
333
|
* 2. Attaching the graph if the data store becomes attached.
|
|
324
334
|
*/
|
|
325
335
|
bindToContext() {
|
|
326
|
-
|
|
327
|
-
return;
|
|
328
|
-
}
|
|
329
|
-
this.bindState = BindState.Binding;
|
|
330
|
-
this.dataStoreContext.bindToContext();
|
|
331
|
-
this.bindState = BindState.Bound;
|
|
336
|
+
this.makeVisibleAndAttachGraph();
|
|
332
337
|
}
|
|
333
338
|
bind(handle) {
|
|
334
339
|
// If visible, attach the incoming handle's graph. Else, this will be done when we become visible.
|
|
@@ -370,14 +375,14 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
370
375
|
this.pendingAttach.delete(id);
|
|
371
376
|
}
|
|
372
377
|
else {
|
|
373
|
-
assert(!this.contexts.has(id), 0x17d);
|
|
378
|
+
assert(!this.contexts.has(id), 0x17d /* "Unexpected attach channel OP" */);
|
|
374
379
|
const flatBlobs = new Map();
|
|
375
380
|
const snapshotTree = buildSnapshotTree(attachMessage.snapshot.entries, flatBlobs);
|
|
376
381
|
const remoteChannelContext = new RemoteChannelContext(this, this.dataStoreContext, this.dataStoreContext.storage, (content, localContentMetadata) => this.submitChannelOp(id, content, localContentMetadata), (address) => this.setChannelDirty(address), (srcHandle, outboundHandle) => this.addedGCOutboundReference(srcHandle, outboundHandle), id, snapshotTree, this.sharedObjectRegistry, flatBlobs, this.dataStoreContext.getCreateChildSummarizerNodeFn(id, {
|
|
377
382
|
type: CreateSummarizerNodeSource.FromAttach,
|
|
378
383
|
sequenceNumber: message.sequenceNumber,
|
|
379
384
|
snapshot: attachMessage.snapshot,
|
|
380
|
-
}),
|
|
385
|
+
}), attachMessage.type);
|
|
381
386
|
this.contexts.set(id, remoteChannelContext);
|
|
382
387
|
if (this.contextsDeferred.has(id)) {
|
|
383
388
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
@@ -409,13 +414,13 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
409
414
|
return (
|
|
410
415
|
// Added in createChannel
|
|
411
416
|
// Removed when bindChannel is called
|
|
412
|
-
!this.notBoundedChannelContextSet.has(id)
|
|
417
|
+
!this.notBoundedChannelContextSet.has(id) &&
|
|
413
418
|
// Added in bindChannel only if this is not attached yet
|
|
414
419
|
// Removed when this is attached by calling attachGraph
|
|
415
|
-
|
|
420
|
+
!this.localChannelContextQueue.has(id) &&
|
|
416
421
|
// Added in attachChannel called by bindChannel
|
|
417
422
|
// Removed when attach op is broadcast
|
|
418
|
-
|
|
423
|
+
!this.pendingAttach.has(id));
|
|
419
424
|
}
|
|
420
425
|
/**
|
|
421
426
|
* Returns the outbound routes of this channel. Currently, all contexts in this channel are considered
|
|
@@ -465,7 +470,8 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
465
470
|
// Get GC data only for attached contexts. Detached contexts are not connected in the GC reference
|
|
466
471
|
// graph so any references they might have won't be connected as well.
|
|
467
472
|
return this.isChannelAttached(contextId);
|
|
468
|
-
})
|
|
473
|
+
})
|
|
474
|
+
.map(async ([contextId, context]) => {
|
|
469
475
|
const contextGCData = await context.getGCData(fullGC);
|
|
470
476
|
// Prefix the child's id to the ids of its GC nodes so they can be identified as belonging to the child.
|
|
471
477
|
// This also gradually builds the id of each node to be a path from the root.
|
|
@@ -502,29 +508,6 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
502
508
|
var _a, _b;
|
|
503
509
|
(_b = (_a = this.dataStoreContext).addedGCOutboundReference) === null || _b === void 0 ? void 0 : _b.call(_a, srcHandle, outboundHandle);
|
|
504
510
|
}
|
|
505
|
-
/**
|
|
506
|
-
* Returns the base GC details for the channel with the given id. This is used to initialize its GC state.
|
|
507
|
-
* @param channelId - The id of the channel context that is asked for the initial GC details.
|
|
508
|
-
* @returns the requested channel's base GC details.
|
|
509
|
-
*/
|
|
510
|
-
async getChannelBaseGCDetails(channelId) {
|
|
511
|
-
var _a;
|
|
512
|
-
let channelBaseGCDetails = (await this.channelsBaseGCDetails).get(channelId);
|
|
513
|
-
if (channelBaseGCDetails === undefined) {
|
|
514
|
-
channelBaseGCDetails = {};
|
|
515
|
-
}
|
|
516
|
-
else if (((_a = channelBaseGCDetails.gcData) === null || _a === void 0 ? void 0 : _a.gcNodes) !== undefined) {
|
|
517
|
-
// Note: if the child channel has an explicit handle route to its parent, it will be removed here and
|
|
518
|
-
// expected to be added back by the parent when getGCData is called.
|
|
519
|
-
removeRouteFromAllNodes(channelBaseGCDetails.gcData.gcNodes, this.absolutePath);
|
|
520
|
-
}
|
|
521
|
-
// Currently, channel context's are always considered used. So, it there are no used routes for it, we still
|
|
522
|
-
// need to mark it as used. Add self-route (empty string) to the channel context's used routes.
|
|
523
|
-
if (channelBaseGCDetails.usedRoutes === undefined || channelBaseGCDetails.usedRoutes.length === 0) {
|
|
524
|
-
channelBaseGCDetails.usedRoutes = [""];
|
|
525
|
-
}
|
|
526
|
-
return channelBaseGCDetails;
|
|
527
|
-
}
|
|
528
511
|
/**
|
|
529
512
|
* Returns a summary at the current sequence number.
|
|
530
513
|
* @param fullTree - true to bypass optimizations and force a full summary tree
|
|
@@ -542,7 +525,8 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
542
525
|
// If the object is registered - and we have received the sequenced op creating the object
|
|
543
526
|
// (i.e. it has a base mapping) - then we go ahead and summarize
|
|
544
527
|
return isAttached;
|
|
545
|
-
})
|
|
528
|
+
})
|
|
529
|
+
.map(async ([contextId, context]) => {
|
|
546
530
|
const contextSummary = await context.summarize(fullTree, trackState, telemetryContext);
|
|
547
531
|
summaryBuilder.addWithStats(contextId, contextSummary);
|
|
548
532
|
}));
|
|
@@ -647,15 +631,14 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
647
631
|
reSubmit(type, content, localOpMetadata) {
|
|
648
632
|
this.verifyNotClosed();
|
|
649
633
|
switch (type) {
|
|
650
|
-
case DataStoreMessageType.ChannelOp:
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
}
|
|
634
|
+
case DataStoreMessageType.ChannelOp: {
|
|
635
|
+
// For Operations, find the right channel and trigger resubmission on it.
|
|
636
|
+
const envelope = content;
|
|
637
|
+
const channelContext = this.contexts.get(envelope.address);
|
|
638
|
+
assert(!!channelContext, 0x183 /* "There should be a channel context for the op" */);
|
|
639
|
+
channelContext.reSubmit(envelope.contents, localOpMetadata);
|
|
640
|
+
break;
|
|
641
|
+
}
|
|
659
642
|
case DataStoreMessageType.Attach:
|
|
660
643
|
// For Attach messages, just submit them again.
|
|
661
644
|
this.submit(type, content, localOpMetadata);
|
|
@@ -672,15 +655,14 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
672
655
|
rollback(type, content, localOpMetadata) {
|
|
673
656
|
this.verifyNotClosed();
|
|
674
657
|
switch (type) {
|
|
675
|
-
case DataStoreMessageType.ChannelOp:
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
}
|
|
658
|
+
case DataStoreMessageType.ChannelOp: {
|
|
659
|
+
// For Operations, find the right channel and trigger resubmission on it.
|
|
660
|
+
const envelope = content;
|
|
661
|
+
const channelContext = this.contexts.get(envelope.address);
|
|
662
|
+
assert(!!channelContext, 0x2ed /* "There should be a channel context for the op" */);
|
|
663
|
+
channelContext.rollback(envelope.contents, localOpMetadata);
|
|
664
|
+
break;
|
|
665
|
+
}
|
|
684
666
|
default:
|
|
685
667
|
throw new LoggingError(`Can't rollback ${type} message`);
|
|
686
668
|
}
|