@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.
Files changed (65) hide show
  1. package/.eslintrc.js +5 -7
  2. package/.mocharc.js +2 -2
  3. package/README.md +3 -0
  4. package/api-extractor.json +2 -2
  5. package/dist/channelContext.d.ts.map +1 -1
  6. package/dist/channelContext.js.map +1 -1
  7. package/dist/channelDeltaConnection.d.ts.map +1 -1
  8. package/dist/channelDeltaConnection.js.map +1 -1
  9. package/dist/channelStorageService.d.ts.map +1 -1
  10. package/dist/channelStorageService.js +1 -3
  11. package/dist/channelStorageService.js.map +1 -1
  12. package/dist/dataStoreRuntime.d.ts +11 -24
  13. package/dist/dataStoreRuntime.d.ts.map +1 -1
  14. package/dist/dataStoreRuntime.js +68 -86
  15. package/dist/dataStoreRuntime.js.map +1 -1
  16. package/dist/fluidHandle.d.ts.map +1 -1
  17. package/dist/fluidHandle.js.map +1 -1
  18. package/dist/localChannelContext.d.ts.map +1 -1
  19. package/dist/localChannelContext.js +9 -5
  20. package/dist/localChannelContext.js.map +1 -1
  21. package/dist/localChannelStorageService.d.ts.map +1 -1
  22. package/dist/localChannelStorageService.js.map +1 -1
  23. package/dist/packageVersion.d.ts +1 -1
  24. package/dist/packageVersion.js +1 -1
  25. package/dist/packageVersion.js.map +1 -1
  26. package/dist/remoteChannelContext.d.ts.map +1 -1
  27. package/dist/remoteChannelContext.js +2 -2
  28. package/dist/remoteChannelContext.js.map +1 -1
  29. package/lib/channelContext.d.ts.map +1 -1
  30. package/lib/channelContext.js.map +1 -1
  31. package/lib/channelDeltaConnection.d.ts.map +1 -1
  32. package/lib/channelDeltaConnection.js.map +1 -1
  33. package/lib/channelStorageService.d.ts.map +1 -1
  34. package/lib/channelStorageService.js +1 -3
  35. package/lib/channelStorageService.js.map +1 -1
  36. package/lib/dataStoreRuntime.d.ts +11 -24
  37. package/lib/dataStoreRuntime.d.ts.map +1 -1
  38. package/lib/dataStoreRuntime.js +71 -89
  39. package/lib/dataStoreRuntime.js.map +1 -1
  40. package/lib/fluidHandle.d.ts.map +1 -1
  41. package/lib/fluidHandle.js.map +1 -1
  42. package/lib/localChannelContext.d.ts.map +1 -1
  43. package/lib/localChannelContext.js +9 -5
  44. package/lib/localChannelContext.js.map +1 -1
  45. package/lib/localChannelStorageService.d.ts.map +1 -1
  46. package/lib/localChannelStorageService.js.map +1 -1
  47. package/lib/packageVersion.d.ts +1 -1
  48. package/lib/packageVersion.js +1 -1
  49. package/lib/packageVersion.js.map +1 -1
  50. package/lib/remoteChannelContext.d.ts.map +1 -1
  51. package/lib/remoteChannelContext.js +2 -2
  52. package/lib/remoteChannelContext.js.map +1 -1
  53. package/package.json +111 -110
  54. package/prettier.config.cjs +1 -1
  55. package/src/channelContext.ts +66 -65
  56. package/src/channelDeltaConnection.ts +50 -44
  57. package/src/channelStorageService.ts +58 -54
  58. package/src/dataStoreRuntime.ts +1122 -1086
  59. package/src/fluidHandle.ts +87 -91
  60. package/src/localChannelContext.ts +302 -255
  61. package/src/localChannelStorageService.ts +47 -45
  62. package/src/packageVersion.ts +1 -1
  63. package/src/remoteChannelContext.ts +300 -291
  64. package/tsconfig.esnext.json +6 -6
  65. package/tsconfig.json +9 -13
@@ -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, generateStack, LoggingError, loggerToMonitoringContext, raiseConnectedEvent, TelemetryDataTag, } from "@fluidframework/telemetry-utils";
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, packagePathToTelemetryProperty, } from "@fluidframework/runtime-utils";
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
- * 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
- */
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.mc = loggerToMonitoringContext(ChildLogger.create(dataStoreContext.logger, "FluidDataStoreRuntime", {
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, { type: CreateSummarizerNodeSource.FromSummary }), async () => this.getChannelBaseGCDetails(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 = dataStoreContext.attachState === AttachState.Detached
122
- ? VisibilityState.LocallyVisible : VisibilityState.GloballyVisible;
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() { return this; }
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() { return this; }
169
- get rootRoutingContext() { return this; }
170
- get channelsRoutingContext() { return this; }
171
- get objectsRoutingContext() { return this; }
172
- get disposed() { return this._disposed; }
173
- get logger() {
174
- return this.mc.logger;
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.mc.logger.sendErrorEvent({ eventName: "GetChannelFailedInRequest" }, error);
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
- && !this.localChannelContextQueue.has(id)
424
+ !this.localChannelContextQueue.has(id) &&
416
425
  // Added in attachChannel called by bindChannel
417
426
  // Removed when attach op is broadcast
418
- && !this.pendingAttach.has(id));
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
- }).map(async ([contextId, context]) => {
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 || channelBaseGCDetails.usedRoutes.length === 0) {
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
- }).map(async ([contextId, context]) => {
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
- // For Operations, find the right channel and trigger resubmission on it.
653
- const envelope = content;
654
- const channelContext = this.contexts.get(envelope.address);
655
- assert(!!channelContext, 0x183 /* "There should be a channel context for the op" */);
656
- channelContext.reSubmit(envelope.contents, localOpMetadata);
657
- break;
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
- // For Operations, find the right channel and trigger resubmission on it.
678
- const envelope = content;
679
- const channelContext = this.contexts.get(envelope.address);
680
- assert(!!channelContext, 0x2ed /* "There should be a channel context for the op" */);
681
- channelContext.rollback(envelope.contents, localOpMetadata);
682
- break;
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