@fluidframework/datastore 2.0.0-internal.3.0.5 → 2.0.0-internal.3.1.1
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 +11 -24
- package/dist/dataStoreRuntime.d.ts.map +1 -1
- package/dist/dataStoreRuntime.js +68 -86
- 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.map +1 -1
- package/dist/remoteChannelContext.js +2 -2
- 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 +11 -24
- package/lib/dataStoreRuntime.d.ts.map +1 -1
- package/lib/dataStoreRuntime.js +71 -89
- 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.map +1 -1
- package/lib/remoteChannelContext.js +2 -2
- package/lib/remoteChannelContext.js.map +1 -1
- package/package.json +111 -110
- 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 +1122 -1086
- 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 +300 -291
- package/tsconfig.esnext.json +6 -6
- package/tsconfig.json +9 -13
package/lib/dataStoreRuntime.js
CHANGED
|
@@ -5,15 +5,15 @@
|
|
|
5
5
|
import { AttachState, } from "@fluidframework/container-definitions";
|
|
6
6
|
import { DataProcessingError, UsageError } from "@fluidframework/container-utils";
|
|
7
7
|
import { assert, Deferred, LazyPromise, TypedEventEmitter, unreachableCase, } from "@fluidframework/common-utils";
|
|
8
|
-
import { ChildLogger,
|
|
8
|
+
import { ChildLogger, LoggingError, raiseConnectedEvent } from "@fluidframework/telemetry-utils";
|
|
9
9
|
import { buildSnapshotTree } from "@fluidframework/driver-utils";
|
|
10
10
|
import { SummaryType, } from "@fluidframework/protocol-definitions";
|
|
11
11
|
import { BindState, CreateSummarizerNodeSource, VisibilityState, } from "@fluidframework/runtime-definitions";
|
|
12
|
-
import { convertSnapshotTreeToSummaryTree, convertSummaryTreeToITree, generateHandleContextPath, RequestParser, SummaryTreeBuilder, create404Response, createResponseError, exceptionToResponse, requestFluidObject,
|
|
12
|
+
import { convertSnapshotTreeToSummaryTree, convertSummaryTreeToITree, generateHandleContextPath, RequestParser, SummaryTreeBuilder, create404Response, createResponseError, exceptionToResponse, requestFluidObject, } from "@fluidframework/runtime-utils";
|
|
13
13
|
import { GCDataBuilder, removeRouteFromAllNodes, unpackChildNodesGCDetails, 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,18 +27,17 @@ 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
|
-
var _a;
|
|
42
41
|
super();
|
|
43
42
|
this.dataStoreContext = dataStoreContext;
|
|
44
43
|
this.sharedObjectRegistry = sharedObjectRegistry;
|
|
@@ -53,9 +52,9 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
53
52
|
// store becomes visible.
|
|
54
53
|
this.pendingHandlesToMakeVisible = new Set();
|
|
55
54
|
assert(!dataStoreContext.id.includes("/"), 0x30e /* Id cannot contain slashes. DataStoreContext should have validated this. */);
|
|
56
|
-
this.
|
|
55
|
+
this.logger = ChildLogger.create(dataStoreContext.logger, "FluidDataStoreRuntime", {
|
|
57
56
|
all: { dataStoreId: uuid() },
|
|
58
|
-
})
|
|
57
|
+
});
|
|
59
58
|
this.id = dataStoreContext.id;
|
|
60
59
|
this.options = dataStoreContext.options;
|
|
61
60
|
this.deltaManager = dataStoreContext.deltaManager;
|
|
@@ -91,7 +90,9 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
91
90
|
}
|
|
92
91
|
}
|
|
93
92
|
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, {
|
|
93
|
+
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, {
|
|
94
|
+
type: CreateSummarizerNodeSource.FromSummary,
|
|
95
|
+
}), async () => this.getChannelBaseGCDetails(path));
|
|
95
96
|
}
|
|
96
97
|
const deferred = new Deferred();
|
|
97
98
|
deferred.resolve(channelContext);
|
|
@@ -118,8 +119,10 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
118
119
|
* when an attach op comes in. In both these cases, the data store is already globally visible.
|
|
119
120
|
*/
|
|
120
121
|
if (existing) {
|
|
121
|
-
this.visibilityState =
|
|
122
|
-
|
|
122
|
+
this.visibilityState =
|
|
123
|
+
dataStoreContext.attachState === AttachState.Detached
|
|
124
|
+
? VisibilityState.LocallyVisible
|
|
125
|
+
: VisibilityState.GloballyVisible;
|
|
123
126
|
}
|
|
124
127
|
else {
|
|
125
128
|
this.visibilityState = VisibilityState.NotVisible;
|
|
@@ -128,9 +131,6 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
128
131
|
if (existing) {
|
|
129
132
|
this.deferredAttached.resolve();
|
|
130
133
|
}
|
|
131
|
-
// By default, a data store can log maximum 10 local changes telemetry in summarizer.
|
|
132
|
-
this.localChangesTelemetryCount =
|
|
133
|
-
(_a = this.mc.config.getNumber("Fluid.Telemetry.LocalChangesTelemetryCount")) !== null && _a !== void 0 ? _a : 10;
|
|
134
134
|
}
|
|
135
135
|
/**
|
|
136
136
|
* @deprecated - Instantiate the class using its constructor instead.
|
|
@@ -143,7 +143,9 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
143
143
|
static load(context, sharedObjectRegistry, existing) {
|
|
144
144
|
return new FluidDataStoreRuntime(context, sharedObjectRegistry, existing, async (dataStoreRuntime) => requestFluidObject(dataStoreRuntime, "/"));
|
|
145
145
|
}
|
|
146
|
-
get IFluidRouter() {
|
|
146
|
+
get IFluidRouter() {
|
|
147
|
+
return this;
|
|
148
|
+
}
|
|
147
149
|
get connected() {
|
|
148
150
|
return this.dataStoreContext.connected;
|
|
149
151
|
}
|
|
@@ -165,13 +167,20 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
165
167
|
get routeContext() {
|
|
166
168
|
return this.dataStoreContext.IFluidHandleContext;
|
|
167
169
|
}
|
|
168
|
-
get IFluidHandleContext() {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
get
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
170
|
+
get IFluidHandleContext() {
|
|
171
|
+
return this;
|
|
172
|
+
}
|
|
173
|
+
get rootRoutingContext() {
|
|
174
|
+
return this;
|
|
175
|
+
}
|
|
176
|
+
get channelsRoutingContext() {
|
|
177
|
+
return this;
|
|
178
|
+
}
|
|
179
|
+
get objectsRoutingContext() {
|
|
180
|
+
return this;
|
|
181
|
+
}
|
|
182
|
+
get disposed() {
|
|
183
|
+
return this._disposed;
|
|
175
184
|
}
|
|
176
185
|
/**
|
|
177
186
|
* Invokes the given callback and expects that no ops are submitted
|
|
@@ -183,9 +192,9 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
183
192
|
*/
|
|
184
193
|
ensureNoDataModelChanges(callback) {
|
|
185
194
|
// back-compat ADO:2309
|
|
186
|
-
return this.dataStoreContext.ensureNoDataModelChanges === undefined
|
|
187
|
-
callback()
|
|
188
|
-
this.dataStoreContext.ensureNoDataModelChanges(callback);
|
|
195
|
+
return this.dataStoreContext.ensureNoDataModelChanges === undefined
|
|
196
|
+
? callback()
|
|
197
|
+
: this.dataStoreContext.ensureNoDataModelChanges(callback);
|
|
189
198
|
}
|
|
190
199
|
dispose() {
|
|
191
200
|
if (this._disposed) {
|
|
@@ -214,7 +223,7 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
214
223
|
return { mimeType: "fluid/object", status: 200, value: channel };
|
|
215
224
|
}
|
|
216
225
|
catch (error) {
|
|
217
|
-
this.
|
|
226
|
+
this.logger.sendErrorEvent({ eventName: "GetChannelFailedInRequest" }, error);
|
|
218
227
|
return createResponseError(500, `Failed to get Channel: ${error}`, request);
|
|
219
228
|
}
|
|
220
229
|
}
|
|
@@ -256,8 +265,6 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
256
265
|
deferred.resolve(context);
|
|
257
266
|
this.contextsDeferred.set(id, deferred);
|
|
258
267
|
}
|
|
259
|
-
// Channels (DDS) should not be created in summarizer client.
|
|
260
|
-
this.identifyLocalChangeInSummarizer("DDSCreatedInSummarizer", id, type);
|
|
261
268
|
assert(!!context.channel, 0x17a /* "Channel should be loaded when created!!" */);
|
|
262
269
|
return context.channel;
|
|
263
270
|
}
|
|
@@ -370,7 +377,9 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
370
377
|
this.pendingAttach.delete(id);
|
|
371
378
|
}
|
|
372
379
|
else {
|
|
373
|
-
assert(!this.contexts.has(id), 0x17d
|
|
380
|
+
assert(!this.contexts.has(id), 0x17d /* `Unexpected attach channel OP,
|
|
381
|
+
is in pendingAttach set: ${this.pendingAttach.has(id)},
|
|
382
|
+
is local channel contexts: ${this.contexts.get(id) instanceof LocalChannelContextBase}` */);
|
|
374
383
|
const flatBlobs = new Map();
|
|
375
384
|
const snapshotTree = buildSnapshotTree(attachMessage.snapshot.entries, flatBlobs);
|
|
376
385
|
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, {
|
|
@@ -409,13 +418,13 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
409
418
|
return (
|
|
410
419
|
// Added in createChannel
|
|
411
420
|
// Removed when bindChannel is called
|
|
412
|
-
!this.notBoundedChannelContextSet.has(id)
|
|
421
|
+
!this.notBoundedChannelContextSet.has(id) &&
|
|
413
422
|
// Added in bindChannel only if this is not attached yet
|
|
414
423
|
// Removed when this is attached by calling attachGraph
|
|
415
|
-
|
|
424
|
+
!this.localChannelContextQueue.has(id) &&
|
|
416
425
|
// Added in attachChannel called by bindChannel
|
|
417
426
|
// Removed when attach op is broadcast
|
|
418
|
-
|
|
427
|
+
!this.pendingAttach.has(id));
|
|
419
428
|
}
|
|
420
429
|
/**
|
|
421
430
|
* Returns the outbound routes of this channel. Currently, all contexts in this channel are considered
|
|
@@ -465,7 +474,8 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
465
474
|
// Get GC data only for attached contexts. Detached contexts are not connected in the GC reference
|
|
466
475
|
// graph so any references they might have won't be connected as well.
|
|
467
476
|
return this.isChannelAttached(contextId);
|
|
468
|
-
})
|
|
477
|
+
})
|
|
478
|
+
.map(async ([contextId, context]) => {
|
|
469
479
|
const contextGCData = await context.getGCData(fullGC);
|
|
470
480
|
// Prefix the child's id to the ids of its GC nodes so they can be identified as belonging to the child.
|
|
471
481
|
// This also gradually builds the id of each node to be a path from the root.
|
|
@@ -520,7 +530,8 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
520
530
|
}
|
|
521
531
|
// Currently, channel context's are always considered used. So, it there are no used routes for it, we still
|
|
522
532
|
// need to mark it as used. Add self-route (empty string) to the channel context's used routes.
|
|
523
|
-
if (channelBaseGCDetails.usedRoutes === undefined ||
|
|
533
|
+
if (channelBaseGCDetails.usedRoutes === undefined ||
|
|
534
|
+
channelBaseGCDetails.usedRoutes.length === 0) {
|
|
524
535
|
channelBaseGCDetails.usedRoutes = [""];
|
|
525
536
|
}
|
|
526
537
|
return channelBaseGCDetails;
|
|
@@ -542,7 +553,8 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
542
553
|
// If the object is registered - and we have received the sequenced op creating the object
|
|
543
554
|
// (i.e. it has a base mapping) - then we go ahead and summarize
|
|
544
555
|
return isAttached;
|
|
545
|
-
})
|
|
556
|
+
})
|
|
557
|
+
.map(async ([contextId, context]) => {
|
|
546
558
|
const contextSummary = await context.summarize(fullTree, trackState, telemetryContext);
|
|
547
559
|
summaryBuilder.addWithStats(contextId, contextSummary);
|
|
548
560
|
}));
|
|
@@ -647,15 +659,14 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
647
659
|
reSubmit(type, content, localOpMetadata) {
|
|
648
660
|
this.verifyNotClosed();
|
|
649
661
|
switch (type) {
|
|
650
|
-
case DataStoreMessageType.ChannelOp:
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
}
|
|
662
|
+
case DataStoreMessageType.ChannelOp: {
|
|
663
|
+
// For Operations, find the right channel and trigger resubmission on it.
|
|
664
|
+
const envelope = content;
|
|
665
|
+
const channelContext = this.contexts.get(envelope.address);
|
|
666
|
+
assert(!!channelContext, 0x183 /* "There should be a channel context for the op" */);
|
|
667
|
+
channelContext.reSubmit(envelope.contents, localOpMetadata);
|
|
668
|
+
break;
|
|
669
|
+
}
|
|
659
670
|
case DataStoreMessageType.Attach:
|
|
660
671
|
// For Attach messages, just submit them again.
|
|
661
672
|
this.submit(type, content, localOpMetadata);
|
|
@@ -672,15 +683,14 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
672
683
|
rollback(type, content, localOpMetadata) {
|
|
673
684
|
this.verifyNotClosed();
|
|
674
685
|
switch (type) {
|
|
675
|
-
case DataStoreMessageType.ChannelOp:
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
}
|
|
686
|
+
case DataStoreMessageType.ChannelOp: {
|
|
687
|
+
// For Operations, find the right channel and trigger resubmission on it.
|
|
688
|
+
const envelope = content;
|
|
689
|
+
const channelContext = this.contexts.get(envelope.address);
|
|
690
|
+
assert(!!channelContext, 0x2ed /* "There should be a channel context for the op" */);
|
|
691
|
+
channelContext.rollback(envelope.contents, localOpMetadata);
|
|
692
|
+
break;
|
|
693
|
+
}
|
|
684
694
|
default:
|
|
685
695
|
throw new LoggingError(`Can't rollback ${type} message`);
|
|
686
696
|
}
|
|
@@ -741,34 +751,6 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
|
|
|
741
751
|
throw new LoggingError("Runtime is closed");
|
|
742
752
|
}
|
|
743
753
|
}
|
|
744
|
-
/**
|
|
745
|
-
* Summarizer client should not have local changes. These changes can become part of the summary and can break
|
|
746
|
-
* eventual consistency. For example, the next summary (say at ref seq# 100) may contain these changes whereas
|
|
747
|
-
* other clients that are up-to-date till seq# 100 may not have them yet.
|
|
748
|
-
*/
|
|
749
|
-
identifyLocalChangeInSummarizer(eventName, channelId, channelType) {
|
|
750
|
-
if (this.clientDetails.type !== "summarizer" || this.localChangesTelemetryCount <= 0) {
|
|
751
|
-
return;
|
|
752
|
-
}
|
|
753
|
-
// Log a telemetry if there are local changes in the summarizer. This will give us data on how often
|
|
754
|
-
// this is happening and which data stores do this. The eventual goal is to disallow local changes
|
|
755
|
-
// in the summarizer and the data will help us plan this.
|
|
756
|
-
this.mc.logger.sendTelemetryEvent({
|
|
757
|
-
eventName,
|
|
758
|
-
channelType,
|
|
759
|
-
channelId: {
|
|
760
|
-
value: channelId,
|
|
761
|
-
tag: TelemetryDataTag.CodeArtifact,
|
|
762
|
-
},
|
|
763
|
-
fluidDataStoreId: {
|
|
764
|
-
value: this.id,
|
|
765
|
-
tag: TelemetryDataTag.CodeArtifact,
|
|
766
|
-
},
|
|
767
|
-
fluidDataStorePackagePath: packagePathToTelemetryProperty(this.dataStoreContext.packagePath),
|
|
768
|
-
stack: generateStack(),
|
|
769
|
-
});
|
|
770
|
-
this.localChangesTelemetryCount--;
|
|
771
|
-
}
|
|
772
754
|
}
|
|
773
755
|
/**
|
|
774
756
|
* Mixin class that adds request handler to FluidDataStoreRuntime
|