@fluidframework/container-runtime 1.2.6 → 2.0.0-dev.1.3.0.96595

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 (221) hide show
  1. package/.mocharc.js +12 -0
  2. package/dist/batchManager.d.ts +37 -0
  3. package/dist/batchManager.d.ts.map +1 -0
  4. package/dist/batchManager.js +73 -0
  5. package/dist/batchManager.js.map +1 -0
  6. package/dist/batchTracker.d.ts +1 -2
  7. package/dist/batchTracker.d.ts.map +1 -1
  8. package/dist/batchTracker.js +2 -3
  9. package/dist/batchTracker.js.map +1 -1
  10. package/dist/blobManager.d.ts +87 -25
  11. package/dist/blobManager.d.ts.map +1 -1
  12. package/dist/blobManager.js +317 -99
  13. package/dist/blobManager.js.map +1 -1
  14. package/dist/containerRuntime.d.ts +109 -124
  15. package/dist/containerRuntime.d.ts.map +1 -1
  16. package/dist/containerRuntime.js +349 -542
  17. package/dist/containerRuntime.js.map +1 -1
  18. package/dist/dataStore.js +29 -24
  19. package/dist/dataStore.js.map +1 -1
  20. package/dist/dataStoreContext.d.ts +20 -14
  21. package/dist/dataStoreContext.d.ts.map +1 -1
  22. package/dist/dataStoreContext.js +49 -58
  23. package/dist/dataStoreContext.js.map +1 -1
  24. package/dist/dataStores.d.ts +12 -5
  25. package/dist/dataStores.d.ts.map +1 -1
  26. package/dist/dataStores.js +21 -20
  27. package/dist/dataStores.js.map +1 -1
  28. package/dist/deltaScheduler.d.ts +6 -4
  29. package/dist/deltaScheduler.d.ts.map +1 -1
  30. package/dist/deltaScheduler.js +6 -4
  31. package/dist/deltaScheduler.js.map +1 -1
  32. package/dist/garbageCollection.d.ts +74 -14
  33. package/dist/garbageCollection.d.ts.map +1 -1
  34. package/dist/garbageCollection.js +249 -170
  35. package/dist/garbageCollection.js.map +1 -1
  36. package/dist/gcSweepReadyUsageDetection.d.ts +53 -0
  37. package/dist/gcSweepReadyUsageDetection.d.ts.map +1 -0
  38. package/dist/gcSweepReadyUsageDetection.js +126 -0
  39. package/dist/gcSweepReadyUsageDetection.js.map +1 -0
  40. package/dist/index.d.ts +2 -1
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +3 -2
  43. package/dist/index.js.map +1 -1
  44. package/dist/opProperties.d.ts +7 -0
  45. package/dist/opProperties.d.ts.map +1 -0
  46. package/dist/opProperties.js +20 -0
  47. package/dist/opProperties.js.map +1 -0
  48. package/dist/orderedClientElection.d.ts +28 -10
  49. package/dist/orderedClientElection.d.ts.map +1 -1
  50. package/dist/orderedClientElection.js +14 -4
  51. package/dist/orderedClientElection.js.map +1 -1
  52. package/dist/packageVersion.d.ts +1 -1
  53. package/dist/packageVersion.d.ts.map +1 -1
  54. package/dist/packageVersion.js +1 -1
  55. package/dist/packageVersion.js.map +1 -1
  56. package/dist/pendingStateManager.d.ts +0 -11
  57. package/dist/pendingStateManager.d.ts.map +1 -1
  58. package/dist/pendingStateManager.js +24 -46
  59. package/dist/pendingStateManager.js.map +1 -1
  60. package/dist/runningSummarizer.d.ts +14 -4
  61. package/dist/runningSummarizer.d.ts.map +1 -1
  62. package/dist/runningSummarizer.js +68 -26
  63. package/dist/runningSummarizer.js.map +1 -1
  64. package/dist/scheduleManager.d.ts +31 -0
  65. package/dist/scheduleManager.d.ts.map +1 -0
  66. package/dist/scheduleManager.js +243 -0
  67. package/dist/scheduleManager.js.map +1 -0
  68. package/dist/summarizer.d.ts +0 -2
  69. package/dist/summarizer.d.ts.map +1 -1
  70. package/dist/summarizer.js +1 -12
  71. package/dist/summarizer.js.map +1 -1
  72. package/dist/summarizerHeuristics.d.ts +26 -4
  73. package/dist/summarizerHeuristics.d.ts.map +1 -1
  74. package/dist/summarizerHeuristics.js +95 -18
  75. package/dist/summarizerHeuristics.js.map +1 -1
  76. package/dist/summarizerTypes.d.ts +45 -18
  77. package/dist/summarizerTypes.d.ts.map +1 -1
  78. package/dist/summarizerTypes.js +1 -1
  79. package/dist/summarizerTypes.js.map +1 -1
  80. package/dist/summaryCollection.d.ts +1 -0
  81. package/dist/summaryCollection.d.ts.map +1 -1
  82. package/dist/summaryCollection.js +31 -15
  83. package/dist/summaryCollection.js.map +1 -1
  84. package/dist/summaryFormat.d.ts +0 -5
  85. package/dist/summaryFormat.d.ts.map +1 -1
  86. package/dist/summaryFormat.js.map +1 -1
  87. package/dist/summaryGenerator.d.ts +1 -0
  88. package/dist/summaryGenerator.d.ts.map +1 -1
  89. package/dist/summaryGenerator.js +11 -9
  90. package/dist/summaryGenerator.js.map +1 -1
  91. package/dist/summaryManager.d.ts +2 -2
  92. package/dist/summaryManager.d.ts.map +1 -1
  93. package/dist/summaryManager.js +22 -7
  94. package/dist/summaryManager.js.map +1 -1
  95. package/lib/batchManager.d.ts +37 -0
  96. package/lib/batchManager.d.ts.map +1 -0
  97. package/lib/batchManager.js +69 -0
  98. package/lib/batchManager.js.map +1 -0
  99. package/lib/batchTracker.d.ts +1 -2
  100. package/lib/batchTracker.d.ts.map +1 -1
  101. package/lib/batchTracker.js +2 -3
  102. package/lib/batchTracker.js.map +1 -1
  103. package/lib/blobManager.d.ts +87 -25
  104. package/lib/blobManager.d.ts.map +1 -1
  105. package/lib/blobManager.js +319 -101
  106. package/lib/blobManager.js.map +1 -1
  107. package/lib/containerRuntime.d.ts +109 -124
  108. package/lib/containerRuntime.d.ts.map +1 -1
  109. package/lib/containerRuntime.js +355 -547
  110. package/lib/containerRuntime.js.map +1 -1
  111. package/lib/dataStore.js +29 -24
  112. package/lib/dataStore.js.map +1 -1
  113. package/lib/dataStoreContext.d.ts +20 -14
  114. package/lib/dataStoreContext.d.ts.map +1 -1
  115. package/lib/dataStoreContext.js +46 -55
  116. package/lib/dataStoreContext.js.map +1 -1
  117. package/lib/dataStores.d.ts +12 -5
  118. package/lib/dataStores.d.ts.map +1 -1
  119. package/lib/dataStores.js +21 -20
  120. package/lib/dataStores.js.map +1 -1
  121. package/lib/deltaScheduler.d.ts +6 -4
  122. package/lib/deltaScheduler.d.ts.map +1 -1
  123. package/lib/deltaScheduler.js +6 -4
  124. package/lib/deltaScheduler.js.map +1 -1
  125. package/lib/garbageCollection.d.ts +74 -14
  126. package/lib/garbageCollection.d.ts.map +1 -1
  127. package/lib/garbageCollection.js +238 -160
  128. package/lib/garbageCollection.js.map +1 -1
  129. package/lib/gcSweepReadyUsageDetection.d.ts +53 -0
  130. package/lib/gcSweepReadyUsageDetection.d.ts.map +1 -0
  131. package/lib/gcSweepReadyUsageDetection.js +121 -0
  132. package/lib/gcSweepReadyUsageDetection.js.map +1 -0
  133. package/lib/index.d.ts +2 -1
  134. package/lib/index.d.ts.map +1 -1
  135. package/lib/index.js +2 -1
  136. package/lib/index.js.map +1 -1
  137. package/lib/opProperties.d.ts +7 -0
  138. package/lib/opProperties.d.ts.map +1 -0
  139. package/lib/opProperties.js +16 -0
  140. package/lib/opProperties.js.map +1 -0
  141. package/lib/orderedClientElection.d.ts +28 -10
  142. package/lib/orderedClientElection.d.ts.map +1 -1
  143. package/lib/orderedClientElection.js +14 -4
  144. package/lib/orderedClientElection.js.map +1 -1
  145. package/lib/packageVersion.d.ts +1 -1
  146. package/lib/packageVersion.d.ts.map +1 -1
  147. package/lib/packageVersion.js +1 -1
  148. package/lib/packageVersion.js.map +1 -1
  149. package/lib/pendingStateManager.d.ts +0 -11
  150. package/lib/pendingStateManager.d.ts.map +1 -1
  151. package/lib/pendingStateManager.js +24 -46
  152. package/lib/pendingStateManager.js.map +1 -1
  153. package/lib/runningSummarizer.d.ts +14 -4
  154. package/lib/runningSummarizer.d.ts.map +1 -1
  155. package/lib/runningSummarizer.js +68 -26
  156. package/lib/runningSummarizer.js.map +1 -1
  157. package/lib/scheduleManager.d.ts +31 -0
  158. package/lib/scheduleManager.d.ts.map +1 -0
  159. package/lib/scheduleManager.js +239 -0
  160. package/lib/scheduleManager.js.map +1 -0
  161. package/lib/summarizer.d.ts +0 -2
  162. package/lib/summarizer.d.ts.map +1 -1
  163. package/lib/summarizer.js +1 -12
  164. package/lib/summarizer.js.map +1 -1
  165. package/lib/summarizerHeuristics.d.ts +26 -4
  166. package/lib/summarizerHeuristics.d.ts.map +1 -1
  167. package/lib/summarizerHeuristics.js +95 -18
  168. package/lib/summarizerHeuristics.js.map +1 -1
  169. package/lib/summarizerTypes.d.ts +45 -18
  170. package/lib/summarizerTypes.d.ts.map +1 -1
  171. package/lib/summarizerTypes.js +1 -1
  172. package/lib/summarizerTypes.js.map +1 -1
  173. package/lib/summaryCollection.d.ts +1 -0
  174. package/lib/summaryCollection.d.ts.map +1 -1
  175. package/lib/summaryCollection.js +31 -15
  176. package/lib/summaryCollection.js.map +1 -1
  177. package/lib/summaryFormat.d.ts +0 -5
  178. package/lib/summaryFormat.d.ts.map +1 -1
  179. package/lib/summaryFormat.js.map +1 -1
  180. package/lib/summaryGenerator.d.ts +1 -0
  181. package/lib/summaryGenerator.d.ts.map +1 -1
  182. package/lib/summaryGenerator.js +11 -9
  183. package/lib/summaryGenerator.js.map +1 -1
  184. package/lib/summaryManager.d.ts +2 -2
  185. package/lib/summaryManager.d.ts.map +1 -1
  186. package/lib/summaryManager.js +22 -7
  187. package/lib/summaryManager.js.map +1 -1
  188. package/package.json +65 -24
  189. package/src/batchManager.ts +91 -0
  190. package/src/batchTracker.ts +2 -3
  191. package/src/blobManager.ts +385 -118
  192. package/src/containerRuntime.ts +529 -740
  193. package/src/dataStore.ts +49 -37
  194. package/src/dataStoreContext.ts +44 -56
  195. package/src/dataStores.ts +34 -30
  196. package/src/deltaScheduler.ts +6 -4
  197. package/src/garbageCollection.ts +297 -206
  198. package/src/gcSweepReadyUsageDetection.ts +139 -0
  199. package/src/index.ts +1 -2
  200. package/src/opProperties.ts +19 -0
  201. package/src/orderedClientElection.ts +31 -10
  202. package/src/packageVersion.ts +1 -1
  203. package/src/pendingStateManager.ts +27 -59
  204. package/src/runningSummarizer.ts +75 -22
  205. package/src/scheduleManager.ts +314 -0
  206. package/src/summarizer.ts +1 -18
  207. package/src/summarizerHeuristics.ts +133 -19
  208. package/src/summarizerTypes.ts +53 -18
  209. package/src/summaryCollection.ts +33 -18
  210. package/src/summaryFormat.ts +0 -6
  211. package/src/summaryGenerator.ts +40 -22
  212. package/src/summaryManager.ts +22 -7
  213. package/dist/opTelemetry.d.ts +0 -22
  214. package/dist/opTelemetry.d.ts.map +0 -1
  215. package/dist/opTelemetry.js +0 -59
  216. package/dist/opTelemetry.js.map +0 -1
  217. package/lib/opTelemetry.d.ts +0 -22
  218. package/lib/opTelemetry.d.ts.map +0 -1
  219. package/lib/opTelemetry.js +0 -55
  220. package/lib/opTelemetry.js.map +0 -1
  221. package/src/opTelemetry.ts +0 -71
package/src/dataStore.ts CHANGED
@@ -54,6 +54,7 @@ enum AliasState {
54
54
  class DataStore implements IDataStore {
55
55
  private aliasState: AliasState = AliasState.None;
56
56
  private alias: string | undefined;
57
+ private readonly pendingAliases: Map<string, Promise<AliasResult>>;
57
58
  private aliasResult: Promise<AliasResult> | undefined;
58
59
 
59
60
  async trySetAlias(alias: string): Promise<AliasResult> {
@@ -75,14 +76,25 @@ class DataStore implements IDataStore {
75
76
  case AliasState.Aliased:
76
77
  return this.alias === alias ? "Success" : "AlreadyAliased";
77
78
 
78
- // There is no current or past alias operation for this datastore,
79
- // it is safe to continue execution
80
- case AliasState.None: break;
79
+ case AliasState.None: {
80
+ const existingAlias = this.pendingAliases.get(alias);
81
+ if (existingAlias !== undefined) {
82
+ // There is already another datastore which will be aliased
83
+ // to the same name
84
+ return "Conflict";
85
+ }
86
+
87
+ // There is no current or past alias operation for this datastore,
88
+ // or for this alias, so it is safe to continue execution
89
+ break;
90
+ }
91
+
81
92
  default: unreachableCase(this.aliasState);
82
93
  }
83
94
 
84
95
  this.aliasState = AliasState.Aliasing;
85
96
  this.aliasResult = this.trySetAliasInternal(alias);
97
+ this.pendingAliases.set(alias, this.aliasResult);
86
98
  return this.aliasResult;
87
99
  }
88
100
 
@@ -92,13 +104,7 @@ class DataStore implements IDataStore {
92
104
  alias,
93
105
  };
94
106
 
95
- // back-compat 0.58.2000 - makeVisibleAndAttachGraph was added in this version to IFluidDataStoreChannel. For
96
- // older versions, we still have to call bindToContext.
97
- if (this.fluidDataStoreChannel.makeVisibleAndAttachGraph !== undefined) {
98
- this.fluidDataStoreChannel.makeVisibleAndAttachGraph();
99
- } else {
100
- this.fluidDataStoreChannel.bindToContext();
101
- }
107
+ this.fluidDataStoreChannel.makeVisibleAndAttachGraph();
102
108
 
103
109
  if (this.runtime.attachState === AttachState.Detached) {
104
110
  const localResult = this.datastores.processAliasMessageCore(message);
@@ -108,34 +114,37 @@ class DataStore implements IDataStore {
108
114
  return localResult ? "Success" : "Conflict";
109
115
  }
110
116
 
111
- const aliased = await this.ackBasedPromise<boolean>((resolve) => {
112
- this.runtime.submitDataStoreAliasOp(message, resolve);
113
- }).then((succeeded) => {
114
- // Explicitly Lock-out future attempts of aliasing,
115
- // regardless of result
116
- this.aliasState = AliasState.Aliased;
117
- if (succeeded) {
118
- this.alias = alias;
119
- }
120
-
121
- return succeeded;
122
- }).catch((error) => {
123
- this.logger.sendErrorEvent({
124
- eventName: "AliasingException",
125
- alias: {
126
- value: alias,
127
- tag: TelemetryDataTag.UserData,
128
- },
129
- internalId: {
130
- value: this.internalId,
131
- tag: TelemetryDataTag.PackageData,
132
- },
133
- }, error);
117
+ const aliased = await this
118
+ .ackBasedPromise<boolean>((resolve) => {
119
+ this.runtime.submitDataStoreAliasOp(message, resolve);
120
+ })
121
+ .catch((error) => {
122
+ this.logger.sendErrorEvent({
123
+ eventName: "AliasingException",
124
+ alias: {
125
+ value: alias,
126
+ tag: TelemetryDataTag.UserData,
127
+ },
128
+ internalId: {
129
+ value: this.internalId,
130
+ tag: TelemetryDataTag.CodeArtifact,
131
+ },
132
+ }, error);
133
+
134
+ return false;
135
+ }).finally(() => {
136
+ this.pendingAliases.delete(alias);
137
+ });
138
+
139
+ if (!aliased) {
134
140
  this.aliasState = AliasState.None;
135
- return false;
136
- });
141
+ this.aliasResult = undefined;
142
+ return "Conflict";
143
+ }
137
144
 
138
- return aliased ? "Success" : "Conflict";
145
+ this.alias = alias;
146
+ this.aliasState = AliasState.Aliased;
147
+ return "Success";
139
148
  }
140
149
 
141
150
  async request(request: IRequest): Promise<IResponse> {
@@ -148,7 +157,10 @@ class DataStore implements IDataStore {
148
157
  private readonly runtime: ContainerRuntime,
149
158
  private readonly datastores: DataStores,
150
159
  private readonly logger: ITelemetryLogger,
151
- ) { }
160
+ ) {
161
+ this.pendingAliases = datastores.pendingAliases;
162
+ }
163
+
152
164
  public get IFluidRouter() { return this.fluidDataStoreChannel; }
153
165
 
154
166
  private async ackBasedPromise<T>(
@@ -13,7 +13,6 @@ import {
13
13
  import {
14
14
  IAudience,
15
15
  IDeltaManager,
16
- BindState,
17
16
  AttachState,
18
17
  ILoaderOptions,
19
18
  } from "@fluidframework/container-definitions";
@@ -38,6 +37,7 @@ import {
38
37
  IContainerRuntime,
39
38
  } from "@fluidframework/container-runtime-definitions";
40
39
  import {
40
+ BindState,
41
41
  channelsTreeName,
42
42
  CreateChildSummarizerNodeFn,
43
43
  CreateChildSummarizerNodeParam,
@@ -83,14 +83,9 @@ import {
83
83
  function createAttributes(
84
84
  pkg: readonly string[],
85
85
  isRootDataStore: boolean,
86
- disableIsolatedChannels: boolean,
87
86
  ): WriteFluidDataStoreAttributes {
88
87
  const stringifiedPkg = JSON.stringify(pkg);
89
- return disableIsolatedChannels ? {
90
- pkg: stringifiedPkg,
91
- snapshotFormatVersion: "0.1",
92
- isRootDataStore,
93
- } : {
88
+ return {
94
89
  pkg: stringifiedPkg,
95
90
  summaryFormatVersion: 2,
96
91
  isRootDataStore,
@@ -99,9 +94,8 @@ function createAttributes(
99
94
  export function createAttributesBlob(
100
95
  pkg: readonly string[],
101
96
  isRootDataStore: boolean,
102
- disableIsolatedChannels: boolean,
103
97
  ): ITreeEntry {
104
- const attributes = createAttributes(pkg, isRootDataStore, disableIsolatedChannels);
98
+ const attributes = createAttributes(pkg, isRootDataStore);
105
99
  return new BlobTreeEntry(dataStoreAttributesBlobName, JSON.stringify(attributes));
106
100
  }
107
101
 
@@ -124,7 +118,6 @@ export interface IFluidDataStoreContextProps {
124
118
  readonly scope: FluidObject;
125
119
  readonly createSummarizerNodeFn: CreateChildSummarizerNodeFn;
126
120
  readonly writeGCDataAtRoot: boolean;
127
- readonly disableIsolatedChannels: boolean;
128
121
  readonly pkg?: Readonly<string[]>;
129
122
  }
130
123
 
@@ -232,6 +225,7 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
232
225
  protected registry: IFluidDataStoreRegistry | undefined;
233
226
 
234
227
  protected detachedRuntimeCreation = false;
228
+ /** @deprecated - To be replaced by calling makeLocallyVisible directly */
235
229
  public readonly bindToContext: () => void;
236
230
  protected channel: IFluidDataStoreChannel | undefined;
237
231
  private loaded = false;
@@ -254,13 +248,12 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
254
248
  public readonly storage: IDocumentStorageService;
255
249
  public readonly scope: FluidObject;
256
250
  private readonly writeGCDataAtRoot: boolean;
257
- protected readonly disableIsolatedChannels: boolean;
258
251
  protected pkg?: readonly string[];
259
252
 
260
253
  constructor(
261
254
  props: IFluidDataStoreContextProps,
262
255
  private readonly existing: boolean,
263
- private bindState: BindState,
256
+ private bindState: BindState, // Used to assert for state tracking purposes
264
257
  public readonly isLocalDataStore: boolean,
265
258
  private readonly makeLocallyVisibleFn: () => void,
266
259
  ) {
@@ -271,7 +264,6 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
271
264
  this.storage = props.storage;
272
265
  this.scope = props.scope;
273
266
  this.writeGCDataAtRoot = props.writeGCDataAtRoot;
274
- this.disableIsolatedChannels = props.disableIsolatedChannels;
275
267
  this.pkg = props.pkg;
276
268
 
277
269
  // URIs use slashes as delimiters. Handles use URIs.
@@ -319,7 +311,7 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
319
311
  }
320
312
 
321
313
  private rejectDeferredRealize(reason: string, packageName?: string): never {
322
- throw new LoggingError(reason, { packageName: { value: packageName, tag: TelemetryDataTag.PackageData } });
314
+ throw new LoggingError(reason, { packageName: { value: packageName, tag: TelemetryDataTag.CodeArtifact } });
323
315
  }
324
316
 
325
317
  public async realize(): Promise<IFluidDataStoreChannel> {
@@ -328,7 +320,12 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
328
320
  this.channelDeferred = new Deferred<IFluidDataStoreChannel>();
329
321
  this.realizeCore(this.existing).catch((error) => {
330
322
  const errorWrapped = DataProcessingError.wrapIfUnrecognized(error, "realizeFluidDataStoreContext");
331
- errorWrapped.addTelemetryProperties({ fluidDataStoreId: { value: this.id, tag: "PackageData" } });
323
+ errorWrapped.addTelemetryProperties({
324
+ fluidDataStoreId: {
325
+ value: this.id,
326
+ tag: TelemetryDataTag.CodeArtifact,
327
+ },
328
+ });
332
329
  this.channelDeferred?.reject(errorWrapped);
333
330
  this.logger.sendErrorEvent({ eventName: "RealizeError" }, errorWrapped);
334
331
  });
@@ -385,8 +382,8 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
385
382
  /**
386
383
  * Notifies this object about changes in the connection state.
387
384
  * @param value - New connection state.
388
- * @param clientId - ID of the client. It's old ID when in disconnected state and
389
- * it's new client ID when we are connecting or connected.
385
+ * @param clientId - ID of the client. Its old ID when in disconnected state and
386
+ * its new client ID when we are connecting or connected.
390
387
  */
391
388
  public setConnectionState(connected: boolean, clientId?: string) {
392
389
  this.verifyNotClosed();
@@ -466,18 +463,15 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
466
463
 
467
464
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
468
465
  const summarizeResult = await this.channel!.summarize(fullTree, trackState, telemetryContext);
469
- let pathPartsForChildren: string[] | undefined;
470
466
 
471
- if (!this.disableIsolatedChannels) {
472
- // Wrap dds summaries in .channels subtree.
473
- wrapSummaryInChannelsTree(summarizeResult);
474
- pathPartsForChildren = [channelsTreeName];
475
- }
467
+ // Wrap dds summaries in .channels subtree.
468
+ wrapSummaryInChannelsTree(summarizeResult);
469
+ const pathPartsForChildren = [channelsTreeName];
476
470
 
477
471
  // Add data store's attributes to the summary.
478
472
  const { pkg } = await this.getInitialSnapshotDetails();
479
473
  const isRoot = await this.isRoot();
480
- const attributes = createAttributes(pkg, isRoot, this.disableIsolatedChannels);
474
+ const attributes = createAttributes(pkg, isRoot);
481
475
  addBlobToSummary(summarizeResult, dataStoreAttributesBlobName, JSON.stringify(attributes));
482
476
 
483
477
  // Add GC data to the summary if it's not written at the root.
@@ -525,12 +519,18 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
525
519
 
526
520
  /**
527
521
  * After GC has run, called to notify the data store of routes used in it. These are used for the following:
522
+ *
528
523
  * 1. To identify if this data store is being referenced in the document or not.
524
+ *
529
525
  * 2. To determine if it needs to re-summarize in case used routes changed since last summary.
526
+ *
530
527
  * 3. These are added to the summary generated by the data store.
531
- * 4. To notify child contexts of their used routes. This is done immediately if the data store is loaded. Else,
532
- * it is done when realizing the data store.
528
+ *
529
+ * 4. To notify child contexts of their used routes. This is done immediately if the data store is loaded.
530
+ * Else, it is done when realizing the data store.
531
+ *
533
532
  * 5. To update the timestamp when this data store or any children are marked as unreferenced.
533
+ *
534
534
  * @param usedRoutes - The routes that are used in this data store.
535
535
  * @param gcTimestamp - The time when GC was run that generated these used routes. If any node becomes unreferenced
536
536
  * as part of this GC run, this should be used to update the time when it happens.
@@ -690,7 +690,10 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
690
690
  } catch (error) {
691
691
  this.channelDeferred?.reject(error);
692
692
  this.logger.sendErrorEvent(
693
- { eventName: "BindRuntimeError", fluidDataStoreId: { value: this.id, tag: "PackageData" } },
693
+ { eventName: "BindRuntimeError", fluidDataStoreId: {
694
+ value: this.id,
695
+ tag: TelemetryDataTag.CodeArtifact,
696
+ } },
694
697
  error);
695
698
  }
696
699
  }
@@ -707,7 +710,7 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
707
710
  public abstract getInitialSnapshotDetails(): Promise<ISnapshotDetails>;
708
711
 
709
712
  /**
710
- * @deprecated - Sets the datastore as root, for aliasing purposes: #7948
713
+ * @deprecated Sets the datastore as root, for aliasing purposes: #7948
711
714
  * This method should not be used outside of the aliasing context.
712
715
  * It will be removed, as the source of truth for this flag will be the aliasing blob.
713
716
  */
@@ -716,7 +719,7 @@ export abstract class FluidDataStoreContext extends TypedEventEmitter<IFluidData
716
719
  }
717
720
 
718
721
  /**
719
- * @deprecated - Renamed to getBaseGCDetails().
722
+ * @deprecated Renamed to `{@link FluidDataStoreContext.getBaseGCDetails}()`.
720
723
  */
721
724
  public abstract getInitialGCSummaryDetails(): Promise<IGarbageCollectionSummaryDetails>;
722
725
 
@@ -809,11 +812,7 @@ export class RemoteFluidDataStoreContext extends FluidDataStoreContext {
809
812
 
810
813
  const localReadAndParse = async <T>(id: string) => readAndParse<T>(this.storage, id);
811
814
  if (tree) {
812
- const loadedSummary = await this.summarizerNode.loadBaseSummary(tree, localReadAndParse);
813
- tree = loadedSummary.baseSummary;
814
- // Prepend outstanding ops to pending queue of ops to process.
815
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
816
- this.pending = loadedSummary.outstandingOps.concat(this.pending!);
815
+ tree = await this.summarizerNode.loadBaseSummary(tree, localReadAndParse);
817
816
  }
818
817
 
819
818
  if (!!tree && tree.blobs[dataStoreAttributesBlobName] !== undefined) {
@@ -826,11 +825,9 @@ export class RemoteFluidDataStoreContext extends FluidDataStoreContext {
826
825
  // For snapshotFormatVersion = "0.1" (1) or above, pkg is jsonified, otherwise it is just a string.
827
826
  const formatVersion = getAttributesFormatVersion(attributes);
828
827
  if (formatVersion < 1) {
829
- if (attributes.pkg.startsWith("[\"") && attributes.pkg.endsWith("\"]")) {
830
- pkgFromSnapshot = JSON.parse(attributes.pkg) as string[];
831
- } else {
832
- pkgFromSnapshot = [attributes.pkg];
833
- }
828
+ pkgFromSnapshot = attributes.pkg.startsWith("[\"") && attributes.pkg.endsWith("\"]")
829
+ ? JSON.parse(attributes.pkg) as string[]
830
+ : [attributes.pkg];
834
831
  } else {
835
832
  pkgFromSnapshot = JSON.parse(attributes.pkg) as string[];
836
833
  }
@@ -863,7 +860,7 @@ export class RemoteFluidDataStoreContext extends FluidDataStoreContext {
863
860
  }
864
861
 
865
862
  /**
866
- * @deprecated - Renamed to getBaseGCDetails.
863
+ * @deprecated Renamed to {@link RemoteFluidDataStoreContext.getBaseGCDetails}.
867
864
  */
868
865
  public async getInitialGCSummaryDetails(): Promise<IGarbageCollectionSummaryDetails> {
869
866
  return this.getBaseGCDetails();
@@ -922,16 +919,13 @@ export class LocalFluidDataStoreContextBase extends FluidDataStoreContext {
922
919
 
923
920
  const summarizeResult = this.channel.getAttachSummary();
924
921
 
925
- if (!this.disableIsolatedChannels) {
926
- // Wrap dds summaries in .channels subtree.
927
- wrapSummaryInChannelsTree(summarizeResult);
928
- }
922
+ // Wrap dds summaries in .channels subtree.
923
+ wrapSummaryInChannelsTree(summarizeResult);
929
924
 
930
925
  // Add data store's attributes to the summary.
931
926
  const attributes = createAttributes(
932
927
  this.pkg,
933
928
  this.isInMemoryRoot(),
934
- this.disableIsolatedChannels,
935
929
  );
936
930
  addBlobToSummary(summarizeResult, dataStoreAttributesBlobName, JSON.stringify(attributes));
937
931
 
@@ -981,7 +975,7 @@ export class LocalFluidDataStoreContextBase extends FluidDataStoreContext {
981
975
  }
982
976
 
983
977
  /**
984
- * @deprecated - Renamed to getBaseGCDetails.
978
+ * @deprecated Renamed to {@link LocalFluidDataStoreContextBase.getBaseGCDetails}.
985
979
  */
986
980
  public async getInitialGCSummaryDetails(): Promise<IGarbageCollectionSummaryDetails> {
987
981
  // Local data store does not have initial summary.
@@ -1024,7 +1018,10 @@ export class LocalDetachedFluidDataStoreContext
1024
1018
  registry: IProvideFluidDataStoreFactory,
1025
1019
  dataStoreChannel: IFluidDataStoreChannel) {
1026
1020
  assert(this.detachedRuntimeCreation, 0x154 /* "runtime creation is already attached" */);
1021
+ this.detachedRuntimeCreation = false;
1022
+
1027
1023
  assert(this.channelDeferred === undefined, 0x155 /* "channel deferral is already set" */);
1024
+ this.channelDeferred = new Deferred<IFluidDataStoreChannel>();
1028
1025
 
1029
1026
  const factory = registry.IFluidDataStoreFactory;
1030
1027
 
@@ -1034,19 +1031,10 @@ export class LocalDetachedFluidDataStoreContext
1034
1031
  assert(this.registry === undefined, 0x157 /* "datastore registry already attached" */);
1035
1032
  this.registry = entry.registry;
1036
1033
 
1037
- this.detachedRuntimeCreation = false;
1038
- this.channelDeferred = new Deferred<IFluidDataStoreChannel>();
1039
-
1040
1034
  super.bindRuntime(dataStoreChannel);
1041
1035
 
1042
1036
  if (await this.isRoot()) {
1043
- // back-compat 0.59.1000 - makeVisibleAndAttachGraph was added in this version to IFluidDataStoreChannel.
1044
- // For older versions, we still have to call bindToContext.
1045
- if (dataStoreChannel.makeVisibleAndAttachGraph !== undefined) {
1046
- dataStoreChannel.makeVisibleAndAttachGraph();
1047
- } else {
1048
- dataStoreChannel.bindToContext();
1049
- }
1037
+ dataStoreChannel.makeVisibleAndAttachGraph();
1050
1038
  }
1051
1039
  }
1052
1040
 
package/src/dataStores.ts CHANGED
@@ -12,6 +12,7 @@ import {
12
12
  ISnapshotTree,
13
13
  } from "@fluidframework/protocol-definitions";
14
14
  import {
15
+ AliasResult,
15
16
  channelsTreeName,
16
17
  CreateChildSummarizerNodeFn,
17
18
  CreateChildSummarizerNodeParam,
@@ -28,11 +29,11 @@ import {
28
29
  ITelemetryContext,
29
30
  } from "@fluidframework/runtime-definitions";
30
31
  import {
31
- convertSnapshotTreeToSummaryTree,
32
- convertToSummaryTree,
33
- create404Response,
34
- responseToException,
35
- SummaryTreeBuilder,
32
+ convertSnapshotTreeToSummaryTree,
33
+ convertToSummaryTree,
34
+ create404Response,
35
+ responseToException,
36
+ SummaryTreeBuilder,
36
37
  } from "@fluidframework/runtime-utils";
37
38
  import { ChildLogger, LoggingError, TelemetryDataTag } from "@fluidframework/telemetry-utils";
38
39
  import { AttachState } from "@fluidframework/container-definitions";
@@ -55,10 +56,10 @@ import { GCNodeType } from "./garbageCollection";
55
56
 
56
57
  type PendingAliasResolve = (success: boolean) => void;
57
58
 
58
- /**
59
- * This class encapsulates data store handling. Currently it is only used by the container runtime,
60
- * but eventually could be hosted on any channel once we formalize the channel api boundary.
61
- */
59
+ /**
60
+ * This class encapsulates data store handling. Currently it is only used by the container runtime,
61
+ * but eventually could be hosted on any channel once we formalize the channel api boundary.
62
+ */
62
63
  export class DataStores implements IDisposable {
63
64
  // Stores tracked by the Domain
64
65
  private readonly pendingAttach = new Map<string, IAttachMessage>();
@@ -82,6 +83,7 @@ export class DataStores implements IDisposable {
82
83
  // The handle to the container runtime. This is used mainly for GC purposes to represent outbound reference from
83
84
  // the container runtime to other nodes.
84
85
  private readonly containerRuntimeHandle: IFluidHandle;
86
+ private readonly pendingAliasMap: Map<string, Promise<AliasResult>> = new Map<string, Promise<AliasResult>>();
85
87
 
86
88
  constructor(
87
89
  private readonly baseSnapshot: ISnapshotTree | undefined,
@@ -141,7 +143,6 @@ export class DataStores implements IDisposable {
141
143
  { type: CreateSummarizerNodeSource.FromSummary },
142
144
  ),
143
145
  writeGCDataAtRoot: this.writeGCDataAtRoot,
144
- disableIsolatedChannels: this.runtime.disableIsolatedChannels,
145
146
  });
146
147
  } else {
147
148
  if (typeof value !== "object") {
@@ -162,7 +163,6 @@ export class DataStores implements IDisposable {
162
163
  snapshotTree,
163
164
  isRootDataStore: undefined,
164
165
  writeGCDataAtRoot: this.writeGCDataAtRoot,
165
- disableIsolatedChannels: this.runtime.disableIsolatedChannels,
166
166
  });
167
167
  }
168
168
  this.contexts.addBoundOrRemoted(dataStoreContext);
@@ -173,10 +173,19 @@ export class DataStores implements IDisposable {
173
173
  };
174
174
  }
175
175
 
176
- public aliases(): ReadonlyMap<string, string> {
176
+ public get aliases(): ReadonlyMap<string, string> {
177
177
  return this.aliasMap;
178
178
  }
179
179
 
180
+ public get pendingAliases(): Map<string, Promise<AliasResult>> {
181
+ return this.pendingAliasMap;
182
+ }
183
+
184
+ public async waitIfPendingAlias(maybeAlias: string): Promise<AliasResult> {
185
+ const pendingAliasPromise = this.pendingAliases.get(maybeAlias);
186
+ return pendingAliasPromise === undefined ? "Success" : pendingAliasPromise;
187
+ }
188
+
180
189
  public processAttachMessage(message: ISequencedDocumentMessage, local: boolean) {
181
190
  const attachMessage = message.contents as InboundAttachMessage;
182
191
 
@@ -191,7 +200,7 @@ export class DataStores implements IDisposable {
191
200
  return;
192
201
  }
193
202
 
194
- // If a non-local operation then go and create the object, otherwise mark it as officially attached.
203
+ // If a non-local operation then go and create the object, otherwise mark it as officially attached.
195
204
  if (this.alreadyProcessed(attachMessage.id)) {
196
205
  // TODO: dataStoreId may require a different tag from PackageData #7488
197
206
  const error = new DataCorruptionError(
@@ -201,7 +210,7 @@ export class DataStores implements IDisposable {
201
210
  ...extractSafePropertiesFromMessage(message),
202
211
  dataStoreId: {
203
212
  value: attachMessage.id,
204
- tag: TelemetryDataTag.PackageData,
213
+ tag: TelemetryDataTag.CodeArtifact,
205
214
  },
206
215
  },
207
216
  );
@@ -234,13 +243,11 @@ export class DataStores implements IDisposable {
234
243
  entries: [createAttributesBlob(
235
244
  pkg,
236
245
  true /* isRootDataStore */,
237
- this.runtime.disableIsolatedChannels,
238
246
  )],
239
247
  },
240
248
  },
241
249
  ),
242
250
  writeGCDataAtRoot: this.writeGCDataAtRoot,
243
- disableIsolatedChannels: this.runtime.disableIsolatedChannels,
244
251
  pkg,
245
252
  });
246
253
 
@@ -345,13 +352,12 @@ export class DataStores implements IDisposable {
345
352
  snapshotTree: undefined,
346
353
  isRootDataStore: isRoot,
347
354
  writeGCDataAtRoot: this.writeGCDataAtRoot,
348
- disableIsolatedChannels: this.runtime.disableIsolatedChannels,
349
355
  });
350
356
  this.contexts.addUnbound(context);
351
357
  return context;
352
358
  }
353
359
 
354
- public _createFluidDataStoreContext(pkg: string[], id: string, isRoot: boolean, props?: any) {
360
+ public _createFluidDataStoreContext(pkg: string[], id: string, props?: any) {
355
361
  assert(!id.includes("/"), 0x30d /* Id cannot contain slashes */);
356
362
  const context = new LocalFluidDataStoreContext({
357
363
  id,
@@ -365,9 +371,8 @@ export class DataStores implements IDisposable {
365
371
  ),
366
372
  makeLocallyVisibleFn: () => this.makeDataStoreLocallyVisible(id),
367
373
  snapshotTree: undefined,
368
- isRootDataStore: isRoot,
374
+ isRootDataStore: false,
369
375
  writeGCDataAtRoot: this.writeGCDataAtRoot,
370
- disableIsolatedChannels: this.runtime.disableIsolatedChannels,
371
376
  createProps: props,
372
377
  });
373
378
  this.contexts.addUnbound(context);
@@ -440,7 +445,7 @@ export class DataStores implements IDisposable {
440
445
  eventName: "SignalFluidDataStoreNotFound",
441
446
  fluidDataStoreId: {
442
447
  value: address,
443
- tag: TelemetryDataTag.PackageData,
448
+ tag: TelemetryDataTag.CodeArtifact,
444
449
  },
445
450
  });
446
451
  return;
@@ -464,13 +469,8 @@ export class DataStores implements IDisposable {
464
469
  }
465
470
 
466
471
  public setAttachState(attachState: AttachState.Attaching | AttachState.Attached): void {
467
- let eventName: "attaching" | "attached";
468
- if (attachState === AttachState.Attaching) {
469
- eventName = "attaching";
470
- } else {
471
- eventName = "attached";
472
- }
473
- for (const [,context] of this.contexts) {
472
+ const eventName = attachState === AttachState.Attaching ? "attaching" : "attached";
473
+ for (const [, context] of this.contexts) {
474
474
  // Fire only for bounded stores.
475
475
  if (!this.contexts.isNotBound(context.id)) {
476
476
  context.emit(eventName);
@@ -561,11 +561,15 @@ export class DataStores implements IDisposable {
561
561
 
562
562
  /**
563
563
  * Generates data used for garbage collection. It does the following:
564
+ *
564
565
  * 1. Calls into each child data store context to get its GC data.
566
+ *
565
567
  * 2. Prefixes the child context's id to the GC nodes in the child's GC data. This makes sure that the node can be
566
- * identified as belonging to the child.
568
+ * identified as belonging to the child.
569
+ *
567
570
  * 3. Adds a GC node for this channel to the nodes received from the children. All these nodes together represent
568
- * the GC data of this channel.
571
+ * the GC data of this channel.
572
+ *
569
573
  * @param fullGC - true to bypass optimizations and force full generation of GC data.
570
574
  */
571
575
  public async getGCData(fullGC: boolean = false): Promise<IGarbageCollectionData> {
@@ -18,12 +18,14 @@ import {
18
18
  * DeltaScheduler is responsible for the scheduling of inbound delta queue in cases where there
19
19
  * is more than one op a particular run of the queue. It does not schedule if there is just one
20
20
  * op or just one batch in the run. It does the following two things:
21
+ *
21
22
  * 1. If the ops have been processed for more than a specific amount of time, it pauses the queue
22
- * and calls setTimeout to schedule a resume of the queue. This ensures that we don't block
23
- * the JS thread for a long time processing ops synchronously (for example, when catching up
24
- * ops right after boot or catching up ops / delayed realizing data stores by summarizer).
23
+ * and calls setTimeout to schedule a resume of the queue. This ensures that we don't block
24
+ * the JS thread for a long time processing ops synchronously (for example, when catching up
25
+ * ops right after boot or catching up ops / delayed realizing data stores by summarizer).
26
+ *
25
27
  * 2. If we scheduled a particular run of the queue, it logs telemetry for the number of ops
26
- * processed, the time and number of turns it took to process the ops.
28
+ * processed, the time and number of turns it took to process the ops.
27
29
  */
28
30
  export class DeltaScheduler {
29
31
  private readonly deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>;