@fluidframework/container-runtime 0.56.3 → 0.57.0-51086

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 (97) hide show
  1. package/dist/blobManager.d.ts.map +1 -1
  2. package/dist/blobManager.js +9 -1
  3. package/dist/blobManager.js.map +1 -1
  4. package/dist/connectionTelemetry.d.ts.map +1 -1
  5. package/dist/connectionTelemetry.js +6 -6
  6. package/dist/connectionTelemetry.js.map +1 -1
  7. package/dist/containerRuntime.d.ts +65 -24
  8. package/dist/containerRuntime.d.ts.map +1 -1
  9. package/dist/containerRuntime.js +139 -72
  10. package/dist/containerRuntime.js.map +1 -1
  11. package/dist/dataStore.d.ts +62 -0
  12. package/dist/dataStore.d.ts.map +1 -0
  13. package/dist/dataStore.js +135 -0
  14. package/dist/dataStore.js.map +1 -0
  15. package/dist/dataStoreContext.js.map +1 -1
  16. package/dist/dataStores.d.ts +9 -5
  17. package/dist/dataStores.d.ts.map +1 -1
  18. package/dist/dataStores.js +14 -19
  19. package/dist/dataStores.js.map +1 -1
  20. package/dist/garbageCollection.d.ts +47 -21
  21. package/dist/garbageCollection.d.ts.map +1 -1
  22. package/dist/garbageCollection.js +195 -61
  23. package/dist/garbageCollection.js.map +1 -1
  24. package/dist/index.d.ts +3 -2
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +4 -1
  27. package/dist/index.js.map +1 -1
  28. package/dist/packageVersion.d.ts +1 -1
  29. package/dist/packageVersion.d.ts.map +1 -1
  30. package/dist/packageVersion.js +1 -1
  31. package/dist/packageVersion.js.map +1 -1
  32. package/dist/runningSummarizer.d.ts +1 -0
  33. package/dist/runningSummarizer.d.ts.map +1 -1
  34. package/dist/runningSummarizer.js +23 -15
  35. package/dist/runningSummarizer.js.map +1 -1
  36. package/dist/summarizerTypes.d.ts +4 -6
  37. package/dist/summarizerTypes.d.ts.map +1 -1
  38. package/dist/summarizerTypes.js.map +1 -1
  39. package/dist/summaryGenerator.d.ts +2 -1
  40. package/dist/summaryGenerator.d.ts.map +1 -1
  41. package/dist/summaryGenerator.js +46 -29
  42. package/dist/summaryGenerator.js.map +1 -1
  43. package/lib/blobManager.d.ts.map +1 -1
  44. package/lib/blobManager.js +9 -1
  45. package/lib/blobManager.js.map +1 -1
  46. package/lib/connectionTelemetry.d.ts.map +1 -1
  47. package/lib/connectionTelemetry.js +6 -6
  48. package/lib/connectionTelemetry.js.map +1 -1
  49. package/lib/containerRuntime.d.ts +65 -24
  50. package/lib/containerRuntime.d.ts.map +1 -1
  51. package/lib/containerRuntime.js +140 -73
  52. package/lib/containerRuntime.js.map +1 -1
  53. package/lib/dataStore.d.ts +62 -0
  54. package/lib/dataStore.d.ts.map +1 -0
  55. package/lib/dataStore.js +130 -0
  56. package/lib/dataStore.js.map +1 -0
  57. package/lib/dataStoreContext.js.map +1 -1
  58. package/lib/dataStores.d.ts +9 -5
  59. package/lib/dataStores.d.ts.map +1 -1
  60. package/lib/dataStores.js +13 -18
  61. package/lib/dataStores.js.map +1 -1
  62. package/lib/garbageCollection.d.ts +47 -21
  63. package/lib/garbageCollection.d.ts.map +1 -1
  64. package/lib/garbageCollection.js +197 -63
  65. package/lib/garbageCollection.js.map +1 -1
  66. package/lib/index.d.ts +3 -2
  67. package/lib/index.d.ts.map +1 -1
  68. package/lib/index.js +2 -1
  69. package/lib/index.js.map +1 -1
  70. package/lib/packageVersion.d.ts +1 -1
  71. package/lib/packageVersion.d.ts.map +1 -1
  72. package/lib/packageVersion.js +1 -1
  73. package/lib/packageVersion.js.map +1 -1
  74. package/lib/runningSummarizer.d.ts +1 -0
  75. package/lib/runningSummarizer.d.ts.map +1 -1
  76. package/lib/runningSummarizer.js +23 -15
  77. package/lib/runningSummarizer.js.map +1 -1
  78. package/lib/summarizerTypes.d.ts +4 -6
  79. package/lib/summarizerTypes.d.ts.map +1 -1
  80. package/lib/summarizerTypes.js.map +1 -1
  81. package/lib/summaryGenerator.d.ts +2 -1
  82. package/lib/summaryGenerator.d.ts.map +1 -1
  83. package/lib/summaryGenerator.js +46 -29
  84. package/lib/summaryGenerator.js.map +1 -1
  85. package/package.json +13 -13
  86. package/src/blobManager.ts +12 -1
  87. package/src/connectionTelemetry.ts +7 -6
  88. package/src/containerRuntime.ts +220 -93
  89. package/src/dataStore.ts +187 -0
  90. package/src/dataStoreContext.ts +1 -1
  91. package/src/dataStores.ts +18 -38
  92. package/src/garbageCollection.ts +283 -105
  93. package/src/index.ts +3 -1
  94. package/src/packageVersion.ts +1 -1
  95. package/src/runningSummarizer.ts +25 -16
  96. package/src/summarizerTypes.ts +4 -8
  97. package/src/summaryGenerator.ts +71 -23
@@ -4,13 +4,13 @@
4
4
  */
5
5
  import { AttachState, LoaderHeader, } from "@fluidframework/container-definitions";
6
6
  import { assert, Trace, TypedEventEmitter, unreachableCase, performance, } from "@fluidframework/common-utils";
7
- import { ChildLogger, raiseConnectedEvent, PerformanceEvent, normalizeError, TaggedLoggerAdapter, loggerToMonitoringContext, } from "@fluidframework/telemetry-utils";
7
+ import { ChildLogger, raiseConnectedEvent, PerformanceEvent, normalizeError, TaggedLoggerAdapter, loggerToMonitoringContext, TelemetryDataTag, } from "@fluidframework/telemetry-utils";
8
8
  import { DriverHeader } from "@fluidframework/driver-definitions";
9
9
  import { readAndParse, BlobAggregationStorage } from "@fluidframework/driver-utils";
10
10
  import { DataCorruptionError, GenericError, UsageError, extractSafePropertiesFromMessage, } from "@fluidframework/container-utils";
11
11
  import { MessageType, SummaryType, } from "@fluidframework/protocol-definitions";
12
12
  import { FlushMode, channelsTreeName, } from "@fluidframework/runtime-definitions";
13
- import { addBlobToSummary, addTreeToSummary, convertToSummaryTree, createRootSummarizerNodeWithGC, RequestParser, create404Response, exceptionToResponse, requestFluidObject, responseToException, seqFromTree, convertSummaryTreeToITree, } from "@fluidframework/runtime-utils";
13
+ import { addBlobToSummary, addTreeToSummary, convertToSummaryTree, createRootSummarizerNodeWithGC, RequestParser, create404Response, exceptionToResponse, requestFluidObject, responseToException, seqFromTree, } from "@fluidframework/runtime-utils";
14
14
  import { v4 as uuid } from "uuid";
15
15
  import { ContainerFluidHandleContext } from "./containerHandleContext";
16
16
  import { FluidDataStoreRegistry } from "./dataStoreRegistry";
@@ -29,6 +29,7 @@ import { SummarizerClientElection, summarizerClientType } from "./summarizerClie
29
29
  import { formExponentialFn, Throttler } from "./throttler";
30
30
  import { RunWhileConnectedCoordinator } from "./runWhileConnectedCoordinator";
31
31
  import { GarbageCollector, gcTreeKey, } from "./garbageCollection";
32
+ import { AliasResult, channelToDataStore, isDataStoreAliasMessage, } from "./dataStore";
32
33
  export var ContainerMessageType;
33
34
  (function (ContainerMessageType) {
34
35
  // An op to be delivered to store
@@ -56,9 +57,24 @@ const DefaultSummaryConfiguration = {
56
57
  // the min of the two will be chosen
57
58
  maxAckWaitTime: 120000,
58
59
  };
59
- ;
60
+ /**
61
+ * Accepted header keys for requests coming to the runtime.
62
+ */
63
+ export var RuntimeHeaders;
64
+ (function (RuntimeHeaders) {
65
+ /** True to wait for a data store to be created and loaded before returning it. */
66
+ RuntimeHeaders["wait"] = "wait";
67
+ /**
68
+ * True if the request is from an external app. Used for GC to handle scenarios where a data store
69
+ * is deleted and requested via an external app.
70
+ */
71
+ RuntimeHeaders["externalRequest"] = "externalRequest";
72
+ /** True if the request is coming from an IFluidHandle. */
73
+ RuntimeHeaders["viaHandle"] = "viaHandle";
74
+ })(RuntimeHeaders || (RuntimeHeaders = {}));
60
75
  // Local storage key to set the default flush mode to TurnBased
61
76
  const turnBasedFlushModeKey = "Fluid.ContainerRuntime.FlushModeTurnBased";
77
+ const useDataStoreAliasingKey = "Fluid.ContainerRuntime.UseDataStoreAliasing";
62
78
  export var RuntimeMessage;
63
79
  (function (RuntimeMessage) {
64
80
  RuntimeMessage["FluidDataStoreOp"] = "component";
@@ -332,7 +348,7 @@ export function getDeviceSpec() {
332
348
  */
333
349
  export class ContainerRuntime extends TypedEventEmitter {
334
350
  constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, requestHandler, _storage) {
335
- var _a, _b, _c, _d, _e;
351
+ var _a, _b, _c, _d, _e, _f, _g, _h;
336
352
  super();
337
353
  this.context = context;
338
354
  this.registry = registry;
@@ -346,7 +362,6 @@ export class ContainerRuntime extends TypedEventEmitter {
346
362
  this.flushTrigger = false;
347
363
  this.paused = false;
348
364
  this._disposed = false;
349
- this.dirtyContainer = false;
350
365
  this.emitDirtyDocumentEvent = true;
351
366
  this.summarizerWarning = (warning) => this.mc.logger.sendTelemetryEvent({ eventName: "summarizerWarning" }, warning);
352
367
  /**
@@ -422,6 +437,9 @@ export class ContainerRuntime extends TypedEventEmitter {
422
437
  this.mc = loggerToMonitoringContext(ChildLogger.create(this.logger, "ContainerRuntime"));
423
438
  this._flushMode =
424
439
  ((_b = this.mc.config.getBoolean(turnBasedFlushModeKey)) !== null && _b !== void 0 ? _b : false) ? FlushMode.TurnBased : FlushMode.Immediate;
440
+ this._aliasingEnabled =
441
+ ((_c = this.mc.config.getBoolean(useDataStoreAliasingKey)) !== null && _c !== void 0 ? _c : false) ||
442
+ ((_d = runtimeOptions.useDataStoreAliasing) !== null && _d !== void 0 ? _d : false);
425
443
  /**
426
444
  * Function that return the current server timestamp. This is used by the garbage collector to set the
427
445
  * time when a node becomes unreferenced.
@@ -435,7 +453,7 @@ export class ContainerRuntime extends TypedEventEmitter {
435
453
  const timestamp = client === null || client === void 0 ? void 0 : client.timestamp;
436
454
  return (_c = (_b = (_a = this.deltaManager.lastMessage) === null || _a === void 0 ? void 0 : _a.timestamp) !== null && _b !== void 0 ? _b : timestamp) !== null && _c !== void 0 ? _c : Date.now();
437
455
  };
438
- this.garbageCollector = GarbageCollector.create(this, this.runtimeOptions.gcOptions, (unusedRoutes) => this.dataStores.deleteUnusedRoutes(unusedRoutes), getCurrentTimestamp, this.closeFn, context.baseSnapshot, async (id) => readAndParse(this.storage, id), this.mc.logger, existing, metadata);
456
+ this.garbageCollector = GarbageCollector.create(this, this.runtimeOptions.gcOptions, (unusedRoutes) => this.dataStores.deleteUnusedRoutes(unusedRoutes), (nodePath) => this.dataStores.getNodePackagePath(nodePath), getCurrentTimestamp, this.closeFn, context.baseSnapshot, async (id) => readAndParse(this.storage, id), this.mc.logger, existing, metadata);
439
457
  const loadedFromSequenceNumber = this.deltaManager.initialSequenceNumber;
440
458
  this.summarizerNode = createRootSummarizerNodeWithGC(ChildLogger.create(this.logger, "SummarizerNode"),
441
459
  // Summarize function to call when summarize is called. Summarizer node always tracks summary state.
@@ -456,7 +474,7 @@ export class ContainerRuntime extends TypedEventEmitter {
456
474
  if (this.context.baseSnapshot) {
457
475
  this.summarizerNode.loadBaseSummaryWithoutDifferential(this.context.baseSnapshot);
458
476
  }
459
- this.dataStores = new DataStores(getSummaryForDatastores(context.baseSnapshot, metadata), this, (attachMsg) => this.submit(ContainerMessageType.Attach, attachMsg), (id, createParam) => (summarizeInternal, getGCDataFn, getBaseGCDetailsFn) => this.summarizerNode.createChild(summarizeInternal, id, createParam, undefined, getGCDataFn, getBaseGCDetailsFn), (id) => this.summarizerNode.deleteChild(id), this.mc.logger, async () => this.garbageCollector.getDataStoreBaseGCDetails(), (id) => this.garbageCollector.nodeChanged(id), new Map(dataStoreAliasMap), this.garbageCollector.writeDataAtRoot);
477
+ this.dataStores = new DataStores(getSummaryForDatastores(context.baseSnapshot, metadata), this, (attachMsg) => this.submit(ContainerMessageType.Attach, attachMsg), (id, createParam) => (summarizeInternal, getGCDataFn, getBaseGCDetailsFn) => this.summarizerNode.createChild(summarizeInternal, id, createParam, undefined, getGCDataFn, getBaseGCDetailsFn), (id) => this.summarizerNode.deleteChild(id), this.mc.logger, async () => this.garbageCollector.getDataStoreBaseGCDetails(), (dataStorePath, packagePath) => this.garbageCollector.nodeUpdated(dataStorePath, "Changed", packagePath), new Map(dataStoreAliasMap), this.garbageCollector.writeDataAtRoot);
460
478
  this.blobManager = new BlobManager(this.handleContext, blobManagerSnapshot, () => this.storage, (blobId) => this.submit(ContainerMessageType.BlobAttach, undefined, undefined, { blobId }), this, this.logger);
461
479
  this.scheduleManager = new ScheduleManager(context.deltaManager, this, ChildLogger.create(this.logger, "ScheduleManager"));
462
480
  this.deltaSender = this.deltaManager;
@@ -465,6 +483,10 @@ export class ContainerRuntime extends TypedEventEmitter {
465
483
  this.clearPartialChunks(clientId);
466
484
  });
467
485
  this.summaryCollection = new SummaryCollection(this.deltaManager, this.logger);
486
+ const { attachState, pendingLocalState } = this.context;
487
+ this.dirtyContainer = attachState !== AttachState.Attached
488
+ || ((_e = pendingLocalState) === null || _e === void 0 ? void 0 : _e.pendingStates.length) > 0;
489
+ this.context.updateDirtyContainerState(this.dirtyContainer);
468
490
  // Map the deprecated generateSummaries flag to disableSummaries.
469
491
  if (this.runtimeOptions.summaryOptions.generateSummaries === false) {
470
492
  this.runtimeOptions.summaryOptions.disableSummaries = true;
@@ -476,8 +498,8 @@ export class ContainerRuntime extends TypedEventEmitter {
476
498
  const orderedClientLogger = ChildLogger.create(this.logger, "OrderedClientElection");
477
499
  const orderedClientCollection = new OrderedClientCollection(orderedClientLogger, this.context.deltaManager, this.context.quorum);
478
500
  const orderedClientElectionForSummarizer = new OrderedClientElection(orderedClientLogger, orderedClientCollection, electedSummarizerData !== null && electedSummarizerData !== void 0 ? electedSummarizerData : this.context.deltaManager.lastSequenceNumber, SummarizerClientElection.isClientEligible);
479
- const summarizerClientElectionEnabled = (_c = this.mc.config.getBoolean("Fluid.ContainerRuntime.summarizerClientElection")) !== null && _c !== void 0 ? _c : ((_d = this.runtimeOptions.summaryOptions) === null || _d === void 0 ? void 0 : _d.summarizerClientElection) === true;
480
- const maxOpsSinceLastSummary = (_e = this.runtimeOptions.summaryOptions.maxOpsSinceLastSummary) !== null && _e !== void 0 ? _e : 7000;
501
+ const summarizerClientElectionEnabled = (_f = this.mc.config.getBoolean("Fluid.ContainerRuntime.summarizerClientElection")) !== null && _f !== void 0 ? _f : ((_g = this.runtimeOptions.summaryOptions) === null || _g === void 0 ? void 0 : _g.summarizerClientElection) === true;
502
+ const maxOpsSinceLastSummary = (_h = this.runtimeOptions.summaryOptions.maxOpsSinceLastSummary) !== null && _h !== void 0 ? _h : 7000;
481
503
  this.summarizerClientElection = new SummarizerClientElection(orderedClientLogger, this.summaryCollection, orderedClientElectionForSummarizer, maxOpsSinceLastSummary, summarizerClientElectionEnabled);
482
504
  if (this.context.clientDetails.type === summarizerClientType) {
483
505
  this._summarizer = new Summarizer("/_summarizer", this /* ISummarizerRuntime */, () => this.summaryConfiguration, this /* ISummarizerInternalsProvider */, this.handleContext, this.summaryCollection, async (runtime) => RunWhileConnectedCoordinator.create(runtime));
@@ -561,7 +583,7 @@ export class ContainerRuntime extends TypedEventEmitter {
561
583
  runtimeVersion: pkgVersion,
562
584
  },
563
585
  });
564
- const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", } = runtimeOptions;
586
+ const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", useDataStoreAliasing = false, } = runtimeOptions;
565
587
  // We pack at data store level only. If isolated channels are disabled,
566
588
  // then there are no .channel layers, we pack at level 1, otherwise we pack at level 2
567
589
  const packingLevel = summaryOptions.disableIsolatedChannels ? 1 : 2;
@@ -629,6 +651,7 @@ export class ContainerRuntime extends TypedEventEmitter {
629
651
  summaryOptions,
630
652
  gcOptions,
631
653
  loadSequenceNumberVerification,
654
+ useDataStoreAliasing,
632
655
  }, containerScope, logger, loadExisting, blobManagerSnapshot, requestHandler, storage);
633
656
  return runtime;
634
657
  }
@@ -768,7 +791,6 @@ export class ContainerRuntime extends TypedEventEmitter {
768
791
  * @param request - Request made to the handler.
769
792
  */
770
793
  async resolveHandle(request) {
771
- var _a, _b;
772
794
  try {
773
795
  const requestParser = RequestParser.create(request);
774
796
  const id = requestParser.pathParts[0];
@@ -789,18 +811,7 @@ export class ContainerRuntime extends TypedEventEmitter {
789
811
  }
790
812
  }
791
813
  else if (requestParser.pathParts.length > 0) {
792
- /**
793
- * If GC should run and this an external app request with "externalRequest" header, we need to return
794
- * an error if the data store being requested is marked as unreferenced as per the data store's initial
795
- * summary.
796
- *
797
- * This is a workaround to handle scenarios where a data store shared with an external app is deleted
798
- * and marked as unreferenced by GC. Returning an error will fail to load the data store for the app.
799
- */
800
- const wait = typeof ((_a = request.headers) === null || _a === void 0 ? void 0 : _a.wait) === "boolean" ? request.headers.wait : undefined;
801
- const dataStore = ((_b = request.headers) === null || _b === void 0 ? void 0 : _b.externalRequest) && this.garbageCollector.shouldRunGC
802
- ? await this.getDataStoreIfInitiallyReferenced(id, wait)
803
- : await this.getDataStore(id, wait);
814
+ const dataStore = await this.getDataStoreFromRequest(id, request);
804
815
  const subRequest = requestParser.createSubRequest(1);
805
816
  // We always expect createSubRequest to include a leading slash, but asserting here to protect against
806
817
  // unintentionally modifying the url if that changes.
@@ -813,6 +824,33 @@ export class ContainerRuntime extends TypedEventEmitter {
813
824
  return exceptionToResponse(error);
814
825
  }
815
826
  }
827
+ async getDataStoreFromRequest(id, request) {
828
+ var _a, _b, _c;
829
+ const wait = typeof ((_a = request.headers) === null || _a === void 0 ? void 0 : _a[RuntimeHeaders.wait]) === "boolean"
830
+ ? (_b = request.headers) === null || _b === void 0 ? void 0 : _b[RuntimeHeaders.wait] : true;
831
+ const dataStoreContext = await this.dataStores.getDataStore(id, wait);
832
+ /**
833
+ * If GC should run and this an external app request with "externalRequest" header, we need to return
834
+ * an error if the data store being requested is marked as unreferenced as per the data store's base
835
+ * GC data.
836
+ *
837
+ * This is a workaround to handle scenarios where a data store shared with an external app is deleted
838
+ * and marked as unreferenced by GC. Returning an error will fail to load the data store for the app.
839
+ */
840
+ if (((_c = request.headers) === null || _c === void 0 ? void 0 : _c[RuntimeHeaders.externalRequest]) && this.garbageCollector.shouldRunGC) {
841
+ // The data store is referenced if used routes in the base summary has a route to self.
842
+ // Older documents may not have used routes in the summary. They are considered referenced.
843
+ const usedRoutes = (await dataStoreContext.getBaseGCDetails()).usedRoutes;
844
+ if (!(usedRoutes === undefined || usedRoutes.includes("") || usedRoutes.includes("/"))) {
845
+ throw responseToException(create404Response(request), request);
846
+ }
847
+ }
848
+ const dataStoreChannel = await dataStoreContext.realize();
849
+ // Let the garbage collector know that a data store was requested / loaded. Realize the data store first so
850
+ // that the package path is available.
851
+ this.garbageCollector.nodeUpdated(`/${id}`, "Loaded", dataStoreContext.packagePath, request === null || request === void 0 ? void 0 : request.headers);
852
+ return dataStoreChannel;
853
+ }
816
854
  formMetadata() {
817
855
  var _a;
818
856
  return Object.assign(Object.assign({}, this.createContainerMetadata), { summaryCount: this.summaryCount, summaryFormatVersion: 1, disableIsolatedChannels: this.disableIsolatedChannels || undefined, gcFeature: this.garbageCollector.gcSummaryFeatureVersion,
@@ -820,40 +858,6 @@ export class ContainerRuntime extends TypedEventEmitter {
820
858
  // the base summary we loaded from. So, use the message from its metadata blob.
821
859
  message: (_a = extractSummaryMetadataMessage(this.deltaManager.lastMessage)) !== null && _a !== void 0 ? _a : this.baseSummaryMessage, sessionExpiryTimeoutMs: this.garbageCollector.sessionExpiryTimeoutMs });
822
860
  }
823
- /**
824
- * Retrieves the runtime for a data store if it's referenced as per the initially summary that it is loaded with.
825
- * This is a workaround to handle scenarios where a data store shared with an external app is deleted and marked
826
- * as unreferenced by GC.
827
- * @param id - Id supplied during creating the data store.
828
- * @param wait - True if you want to wait for it.
829
- * @returns the data store runtime if the data store exists and is initially referenced; undefined otherwise.
830
- */
831
- async getDataStoreIfInitiallyReferenced(id, wait = true) {
832
- const dataStoreContext = await this.dataStores.getDataStore(id, wait);
833
- // The data store is referenced if used routes in the initial summary has a route to self.
834
- // Older documents may not have used routes in the summary. They are considered referenced.
835
- const usedRoutes = (await dataStoreContext.getBaseGCDetails()).usedRoutes;
836
- if (usedRoutes === undefined || usedRoutes.includes("") || usedRoutes.includes("/")) {
837
- return dataStoreContext.realize();
838
- }
839
- // The data store is unreferenced. Throw a 404 response exception.
840
- const request = { url: id };
841
- throw responseToException(create404Response(request), request);
842
- }
843
- /**
844
- * Notifies this object to take the snapshot of the container.
845
- * @deprecated - Use summarize to get summary of the container runtime.
846
- */
847
- async snapshot() {
848
- const summaryResult = await this.summarize({
849
- summaryLogger: this.logger,
850
- fullTree: true,
851
- trackState: false,
852
- runGC: this.garbageCollector.shouldRunGC,
853
- fullGC: true,
854
- });
855
- return convertSummaryTreeToITree(summaryResult.summary);
856
- }
857
861
  addContainerStateToSummary(summaryTree) {
858
862
  var _a;
859
863
  addBlobToSummary(summaryTree, metadataBlobName, JSON.stringify(this.formMetadata()));
@@ -1015,9 +1019,6 @@ export class ContainerRuntime extends TypedEventEmitter {
1015
1019
  assert(await context.isRoot(), 0x12b /* "did not get root data store" */);
1016
1020
  return context.realize();
1017
1021
  }
1018
- async getDataStore(id, wait = true) {
1019
- return (await this.dataStores.getDataStore(id, wait)).realize();
1020
- }
1021
1022
  setFlushMode(mode) {
1022
1023
  if (mode === this._flushMode) {
1023
1024
  return;
@@ -1082,28 +1083,84 @@ export class ContainerRuntime extends TypedEventEmitter {
1082
1083
  }
1083
1084
  }
1084
1085
  async createDataStore(pkg) {
1085
- return this._createDataStore(pkg, false /* isRoot */);
1086
+ const internalId = uuid();
1087
+ return channelToDataStore(await this._createDataStore(pkg, false /* isRoot */, internalId), internalId, this, this.dataStores, this.mc.logger);
1086
1088
  }
1087
- async createRootDataStore(pkg, rootDataStoreId) {
1089
+ /**
1090
+ * Creates a root datastore directly with a user generated id and attaches it to storage.
1091
+ * It is vulnerable to name collisions and should not be used.
1092
+ *
1093
+ * This method will be removed. See #6465.
1094
+ */
1095
+ async createRootDataStoreLegacy(pkg, rootDataStoreId) {
1088
1096
  const fluidDataStore = await this._createDataStore(pkg, true /* isRoot */, rootDataStoreId);
1089
1097
  fluidDataStore.bindToContext();
1090
1098
  return fluidDataStore;
1091
1099
  }
1100
+ async createRootDataStore(pkg, rootDataStoreId) {
1101
+ return this._aliasingEnabled === true ?
1102
+ this.createAndAliasDataStore(pkg, rootDataStoreId) :
1103
+ this.createRootDataStoreLegacy(pkg, rootDataStoreId);
1104
+ }
1105
+ /**
1106
+ * Creates a data store then attempts to alias it.
1107
+ * If aliasing fails, it will raise an exception.
1108
+ *
1109
+ * This method will be removed. See #6465.
1110
+ *
1111
+ * @param pkg - Package name of the data store
1112
+ * @param alias - Alias to be assigned to the data store
1113
+ * @param props - Properties for the data store
1114
+ * @returns - An aliased data store which can can be found / loaded by alias.
1115
+ */
1116
+ async createAndAliasDataStore(pkg, alias, props) {
1117
+ const internalId = uuid();
1118
+ const dataStore = await this._createDataStore(pkg, false /* isRoot */, internalId, props);
1119
+ const aliasedDataStore = channelToDataStore(dataStore, internalId, this, this.dataStores, this.mc.logger);
1120
+ const result = await aliasedDataStore.trySetAlias(alias);
1121
+ if (result !== AliasResult.Success) {
1122
+ throw new GenericError("dataStoreAliasFailure", undefined /* error */, {
1123
+ alias: {
1124
+ value: alias,
1125
+ tag: TelemetryDataTag.UserData,
1126
+ },
1127
+ internalId: {
1128
+ value: internalId,
1129
+ tag: TelemetryDataTag.PackageData,
1130
+ },
1131
+ aliasResult: result,
1132
+ });
1133
+ }
1134
+ return aliasedDataStore;
1135
+ }
1092
1136
  createDetachedRootDataStore(pkg, rootDataStoreId) {
1093
1137
  return this.dataStores.createDetachedDataStoreCore(pkg, true, rootDataStoreId);
1094
1138
  }
1095
1139
  createDetachedDataStore(pkg) {
1096
1140
  return this.dataStores.createDetachedDataStoreCore(pkg, false);
1097
1141
  }
1098
- async _createDataStoreWithProps(pkg, props, id = uuid(), isRoot = false) {
1142
+ /**
1143
+ * Creates a possibly root datastore directly with a possibly user generated id and attaches it to storage.
1144
+ * It is vulnerable to name collisions if both aforementioned conditions are true, and should not be used.
1145
+ *
1146
+ * This method will be removed. See #6465.
1147
+ */
1148
+ async _createDataStoreWithPropsLegacy(pkg, props, id = uuid(), isRoot = false) {
1099
1149
  const fluidDataStore = await this.dataStores._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, isRoot, props).realize();
1100
1150
  if (isRoot) {
1101
1151
  fluidDataStore.bindToContext();
1102
1152
  }
1103
1153
  return fluidDataStore;
1104
1154
  }
1105
- async _createDataStore(pkg, isRoot, id = uuid()) {
1106
- return this.dataStores._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, isRoot).realize();
1155
+ async _createDataStoreWithProps(pkg, props, id = uuid(), isRoot = false) {
1156
+ return this._aliasingEnabled === true && isRoot ?
1157
+ this.createAndAliasDataStore(pkg, id, props) :
1158
+ this._createDataStoreWithPropsLegacy(pkg, props, id, isRoot);
1159
+ }
1160
+ async _createDataStore(pkg, isRoot, id = uuid(), props) {
1161
+ return this.dataStores
1162
+ ._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, isRoot, props)
1163
+ .realize();
1107
1164
  }
1108
1165
  canSendOps() {
1109
1166
  return this.connected && !this.deltaManager.readOnlyInfo.readonly;
@@ -1161,6 +1218,9 @@ export class ContainerRuntime extends TypedEventEmitter {
1161
1218
  assert(this.attachState === AttachState.Attached, 0x12e /* "Container Context should already be in attached state" */);
1162
1219
  this.emit("attached");
1163
1220
  }
1221
+ if (attachState === AttachState.Attached && !this.pendingStateManager.hasPendingMessages()) {
1222
+ this.updateDocumentDirtyState(false);
1223
+ }
1164
1224
  this.dataStores.setAttachState(attachState);
1165
1225
  }
1166
1226
  /**
@@ -1207,13 +1267,14 @@ export class ContainerRuntime extends TypedEventEmitter {
1207
1267
  */
1208
1268
  async summarize(options) {
1209
1269
  this.verifyNotClosed();
1210
- const { summaryLogger, fullTree = false, trackState = true, runGC = true, runSweep, fullGC } = options;
1270
+ const { fullTree = false, trackState = true, summaryLogger = this.logger, runGC = this.garbageCollector.shouldRunGC, runSweep, fullGC, } = options;
1271
+ let gcStats;
1211
1272
  if (runGC) {
1212
- await this.collectGarbage({ logger: summaryLogger, runSweep, fullGC });
1273
+ gcStats = await this.collectGarbage({ logger: summaryLogger, runSweep, fullGC });
1213
1274
  }
1214
1275
  const summarizeResult = await this.summarizerNode.summarize(fullTree, trackState);
1215
1276
  assert(summarizeResult.summary.type === SummaryType.Tree, 0x12f /* "Container Runtime's summarize should always return a tree" */);
1216
- return summarizeResult;
1277
+ return Object.assign(Object.assign({}, summarizeResult), { gcStats });
1217
1278
  }
1218
1279
  /**
1219
1280
  * Implementation of IGarbageCollectionRuntime::updateStateBeforeGC.
@@ -1238,7 +1299,6 @@ export class ContainerRuntime extends TypedEventEmitter {
1238
1299
  * @param usedRoutes - The routes that are used in all nodes in this Container.
1239
1300
  * @param gcTimestamp - The time when GC was run that generated these used routes. If any node node becomes
1240
1301
  * unreferenced as part of this GC run, this should be used to update the time when it happens.
1241
- * @returns the statistics of the used state of the data stores.
1242
1302
  */
1243
1303
  updateUsedRoutes(usedRoutes, gcTimestamp) {
1244
1304
  // Update our summarizer node's used routes. Updating used routes in summarizer node before
@@ -1272,7 +1332,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1272
1332
  * @param options - options controlling how the summary is generated or submitted
1273
1333
  */
1274
1334
  async submitSummary(options) {
1275
- var _a;
1335
+ var _a, _b;
1276
1336
  const { fullTree, refreshLatestAck, summaryLogger } = options;
1277
1337
  if (refreshLatestAck) {
1278
1338
  const latestSummaryRefSeq = await this.refreshLatestSummaryAckFromServer(ChildLogger.create(summaryLogger, undefined, { all: { safeSummary: true } }));
@@ -1336,9 +1396,9 @@ export class ContainerRuntime extends TypedEventEmitter {
1336
1396
  const forcedFullTree = this.garbageCollector.summaryStateNeedsReset;
1337
1397
  try {
1338
1398
  summarizeResult = await this.summarize({
1339
- summaryLogger,
1340
1399
  fullTree: fullTree || forcedFullTree,
1341
1400
  trackState: true,
1401
+ summaryLogger,
1342
1402
  runGC: this.garbageCollector.shouldRunGC,
1343
1403
  });
1344
1404
  }
@@ -1352,7 +1412,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1352
1412
  const dataStoreTree = this.disableIsolatedChannels ? summaryTree : summaryTree.tree[channelsTreeName];
1353
1413
  assert(dataStoreTree.type === SummaryType.Tree, 0x1fc /* "summary is not a tree" */);
1354
1414
  const handleCount = Object.values(dataStoreTree.tree).filter((value) => value.type === SummaryType.Handle).length;
1355
- const summaryStats = Object.assign({ dataStoreCount: this.dataStores.size, summarizedDataStoreCount: this.dataStores.size - handleCount }, partialStats);
1415
+ const summaryStats = Object.assign({ dataStoreCount: this.dataStores.size, summarizedDataStoreCount: this.dataStores.size - handleCount, gcStateUpdatedDataStoreCount: (_a = summarizeResult.gcStats) === null || _a === void 0 ? void 0 : _a.updatedDataStoreCount }, partialStats);
1356
1416
  const generateSummaryData = {
1357
1417
  referenceSequenceNumber: summaryRefSeqNum,
1358
1418
  summaryTree,
@@ -1368,7 +1428,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1368
1428
  const summaryContext = lastAck === undefined
1369
1429
  ? {
1370
1430
  proposalHandle: undefined,
1371
- ackHandle: (_a = this.context.getLoadedFromVersion()) === null || _a === void 0 ? void 0 : _a.id,
1431
+ ackHandle: (_b = this.context.getLoadedFromVersion()) === null || _b === void 0 ? void 0 : _b.id,
1372
1432
  referenceSequenceNumber: summaryRefSeqNum,
1373
1433
  }
1374
1434
  : {
@@ -1463,6 +1523,13 @@ export class ContainerRuntime extends TypedEventEmitter {
1463
1523
  };
1464
1524
  this.submit(ContainerMessageType.FluidDataStoreOp, envelope, localOpMetadata);
1465
1525
  }
1526
+ submitDataStoreAliasOp(contents, localOpMetadata) {
1527
+ const aliasMessage = contents;
1528
+ if (!isDataStoreAliasMessage(aliasMessage)) {
1529
+ throw new UsageError("malformedDataStoreAliasMessage");
1530
+ }
1531
+ this.submit(ContainerMessageType.Alias, contents, localOpMetadata);
1532
+ }
1466
1533
  async uploadBlob(blob) {
1467
1534
  this.verifyNotClosed();
1468
1535
  return this.blobManager.createBlob(blob);