@fluidframework/container-runtime 2.0.0-internal.1.0.0.82628 → 2.0.0-internal.1.0.0.84253

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 (68) hide show
  1. package/dist/batchTracker.js +1 -1
  2. package/dist/batchTracker.js.map +1 -1
  3. package/dist/blobManager.d.ts.map +1 -1
  4. package/dist/blobManager.js +16 -16
  5. package/dist/blobManager.js.map +1 -1
  6. package/dist/containerRuntime.d.ts +1 -38
  7. package/dist/containerRuntime.d.ts.map +1 -1
  8. package/dist/containerRuntime.js +51 -105
  9. package/dist/containerRuntime.js.map +1 -1
  10. package/dist/dataStore.d.ts +1 -1
  11. package/dist/dataStore.d.ts.map +1 -1
  12. package/dist/dataStore.js +2 -3
  13. package/dist/dataStore.js.map +1 -1
  14. package/dist/dataStores.d.ts +1 -1
  15. package/dist/dataStores.d.ts.map +1 -1
  16. package/dist/dataStores.js +2 -2
  17. package/dist/dataStores.js.map +1 -1
  18. package/dist/packageVersion.d.ts +1 -1
  19. package/dist/packageVersion.js +1 -1
  20. package/dist/packageVersion.js.map +1 -1
  21. package/dist/runningSummarizer.d.ts +14 -0
  22. package/dist/runningSummarizer.d.ts.map +1 -1
  23. package/dist/runningSummarizer.js +25 -0
  24. package/dist/runningSummarizer.js.map +1 -1
  25. package/dist/summarizer.d.ts.map +1 -1
  26. package/dist/summarizer.js +33 -3
  27. package/dist/summarizer.js.map +1 -1
  28. package/dist/summaryGenerator.js +1 -1
  29. package/dist/summaryGenerator.js.map +1 -1
  30. package/lib/batchTracker.js +1 -1
  31. package/lib/batchTracker.js.map +1 -1
  32. package/lib/blobManager.d.ts.map +1 -1
  33. package/lib/blobManager.js +16 -16
  34. package/lib/blobManager.js.map +1 -1
  35. package/lib/containerRuntime.d.ts +1 -38
  36. package/lib/containerRuntime.d.ts.map +1 -1
  37. package/lib/containerRuntime.js +51 -105
  38. package/lib/containerRuntime.js.map +1 -1
  39. package/lib/dataStore.d.ts +1 -1
  40. package/lib/dataStore.d.ts.map +1 -1
  41. package/lib/dataStore.js +2 -3
  42. package/lib/dataStore.js.map +1 -1
  43. package/lib/dataStores.d.ts +1 -1
  44. package/lib/dataStores.d.ts.map +1 -1
  45. package/lib/dataStores.js +2 -2
  46. package/lib/dataStores.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/runningSummarizer.d.ts +14 -0
  51. package/lib/runningSummarizer.d.ts.map +1 -1
  52. package/lib/runningSummarizer.js +25 -0
  53. package/lib/runningSummarizer.js.map +1 -1
  54. package/lib/summarizer.d.ts.map +1 -1
  55. package/lib/summarizer.js +35 -5
  56. package/lib/summarizer.js.map +1 -1
  57. package/lib/summaryGenerator.js +1 -1
  58. package/lib/summaryGenerator.js.map +1 -1
  59. package/package.json +27 -18
  60. package/src/batchTracker.ts +1 -1
  61. package/src/blobManager.ts +20 -16
  62. package/src/containerRuntime.ts +71 -155
  63. package/src/dataStore.ts +1 -4
  64. package/src/dataStores.ts +13 -13
  65. package/src/packageVersion.ts +1 -1
  66. package/src/runningSummarizer.ts +33 -1
  67. package/src/summarizer.ts +46 -10
  68. package/src/summaryGenerator.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/container-runtime",
3
- "version": "2.0.0-internal.1.0.0.82628",
3
+ "version": "2.0.0-internal.1.0.0.84253",
4
4
  "description": "Fluid container runtime",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -62,30 +62,30 @@
62
62
  },
63
63
  "dependencies": {
64
64
  "@fluidframework/common-definitions": "^0.20.1",
65
- "@fluidframework/common-utils": "^0.32.1",
66
- "@fluidframework/container-definitions": "2.0.0-internal.1.0.0.82628",
67
- "@fluidframework/container-runtime-definitions": "2.0.0-internal.1.0.0.82628",
68
- "@fluidframework/container-utils": "2.0.0-internal.1.0.0.82628",
69
- "@fluidframework/core-interfaces": "2.0.0-internal.1.0.0.82628",
70
- "@fluidframework/datastore": "2.0.0-internal.1.0.0.82628",
71
- "@fluidframework/driver-definitions": "2.0.0-internal.1.0.0.82628",
72
- "@fluidframework/driver-utils": "2.0.0-internal.1.0.0.82628",
73
- "@fluidframework/garbage-collector": "2.0.0-internal.1.0.0.82628",
74
- "@fluidframework/protocol-base": "^0.1037.1000-0",
75
- "@fluidframework/protocol-definitions": "^0.1029.1000-0",
76
- "@fluidframework/runtime-definitions": "2.0.0-internal.1.0.0.82628",
77
- "@fluidframework/runtime-utils": "2.0.0-internal.1.0.0.82628",
78
- "@fluidframework/telemetry-utils": "2.0.0-internal.1.0.0.82628",
65
+ "@fluidframework/common-utils": "^1.0.0",
66
+ "@fluidframework/container-definitions": "2.0.0-internal.1.0.0.84253",
67
+ "@fluidframework/container-runtime-definitions": "2.0.0-internal.1.0.0.84253",
68
+ "@fluidframework/container-utils": "2.0.0-internal.1.0.0.84253",
69
+ "@fluidframework/core-interfaces": "2.0.0-internal.1.0.0.84253",
70
+ "@fluidframework/datastore": "2.0.0-internal.1.0.0.84253",
71
+ "@fluidframework/driver-definitions": "2.0.0-internal.1.0.0.84253",
72
+ "@fluidframework/driver-utils": "2.0.0-internal.1.0.0.84253",
73
+ "@fluidframework/garbage-collector": "2.0.0-internal.1.0.0.84253",
74
+ "@fluidframework/protocol-base": "^0.1037.1000",
75
+ "@fluidframework/protocol-definitions": "^1.0.0",
76
+ "@fluidframework/runtime-definitions": "2.0.0-internal.1.0.0.84253",
77
+ "@fluidframework/runtime-utils": "2.0.0-internal.1.0.0.84253",
78
+ "@fluidframework/telemetry-utils": "2.0.0-internal.1.0.0.84253",
79
79
  "double-ended-queue": "^2.1.0-0",
80
80
  "uuid": "^8.3.1"
81
81
  },
82
82
  "devDependencies": {
83
83
  "@fluidframework/build-common": "^0.24.0",
84
- "@fluidframework/build-tools": "^0.3.0-0",
84
+ "@fluidframework/build-tools": "^0.3.1000",
85
85
  "@fluidframework/container-runtime-previous": "npm:@fluidframework/container-runtime@^1.0.0",
86
86
  "@fluidframework/eslint-config-fluid": "^0.28.2000",
87
- "@fluidframework/mocha-test-setup": "2.0.0-internal.1.0.0.82628",
88
- "@fluidframework/test-runtime-utils": "2.0.0-internal.1.0.0.82628",
87
+ "@fluidframework/mocha-test-setup": "2.0.0-internal.1.0.0.84253",
88
+ "@fluidframework/test-runtime-utils": "2.0.0-internal.1.0.0.84253",
89
89
  "@microsoft/api-extractor": "^7.22.2",
90
90
  "@rushstack/eslint-config": "^2.5.1",
91
91
  "@types/double-ended-queue": "^2.1.0",
@@ -130,6 +130,15 @@
130
130
  },
131
131
  "TypeAliasDeclaration_SubmitSummaryResult": {
132
132
  "backCompat": false
133
+ },
134
+ "ClassDeclaration_ContainerRuntime": {
135
+ "backCompat": false
136
+ },
137
+ "InterfaceDeclaration_IConnectableRuntime": {
138
+ "backCompat": false
139
+ },
140
+ "InterfaceDeclaration_ISummarizerRuntime": {
141
+ "backCompat": false
133
142
  }
134
143
  }
135
144
  }
@@ -37,7 +37,7 @@ export class BatchTracker {
37
37
 
38
38
  const length = message.sequenceNumber - this.startBatchSequenceNumber + 1;
39
39
  if (length >= batchLengthThreshold) {
40
- this.logger.sendErrorEvent({
40
+ this.logger.sendPerformanceEvent({
41
41
  eventName: "LengthTooBig",
42
42
  length,
43
43
  threshold: batchLengthThreshold,
@@ -219,7 +219,7 @@ export class BlobManager {
219
219
  // For a detached container, entries are inserted into the redirect table with an undefined storage ID.
220
220
  // For an attached container, entries are inserted w/storage ID after the BlobAttach op round-trips.
221
221
  assert(!undefinedValueInTable || this.runtime.attachState === AttachState.Detached && ids.size === 0,
222
- "'redirectTable' must contain only undefined while detached / defined values while attached");
222
+ 0x382 /* 'redirectTable' must contain only undefined while detached / defined values while attached */);
223
223
 
224
224
  return ids as Set<string>;
225
225
  }
@@ -231,7 +231,7 @@ export class BlobManager {
231
231
  }
232
232
  let storageId;
233
233
  if (this.runtime.attachState === AttachState.Detached) {
234
- assert(this.redirectTable.has(blobId), "requesting unknown blobs");
234
+ assert(this.redirectTable.has(blobId), 0x383 /* requesting unknown blobs */);
235
235
 
236
236
  // Blobs created while the container is detached are stored in IDetachedBlobStorage.
237
237
  // The 'IDocumentStorageService.readBlob()' call below will retrieve these via localId.
@@ -256,7 +256,7 @@ export class BlobManager {
256
256
 
257
257
  private getBlobHandle(id: string): IFluidHandle<ArrayBufferLike> {
258
258
  assert(this.redirectTable.has(id) || this.pendingBlobs.has(id),
259
- "requesting handle for unknown blob");
259
+ 0x384 /* requesting handle for unknown blob */);
260
260
  return new BlobHandle(
261
261
  `${BlobManager.basePath}/${id}`,
262
262
  this.routeContext,
@@ -282,7 +282,7 @@ export class BlobManager {
282
282
  await new Promise<void>((resolve) => this.runtime.once("attached", resolve));
283
283
  }
284
284
  assert(this.runtime.attachState === AttachState.Attached,
285
- "For clarity and paranoid defense against adding future attachment states");
285
+ 0x385 /* For clarity and paranoid defense against adding future attachment states */);
286
286
 
287
287
  // Create a local ID for each blob. This is used to support blobs if/when the client goes
288
288
  // offline since we don't have the ID from storage yet. If online flow succeeds this won't be used.
@@ -314,7 +314,7 @@ export class BlobManager {
314
314
  const entry = this.pendingBlobs.get(localId);
315
315
  assert(entry?.status === PendingBlobStatus.OnlinePendingUpload ||
316
316
  entry?.status === PendingBlobStatus.OfflinePendingUpload,
317
- "Must have pending blob entry for uploaded blob");
317
+ 0x386 /* Must have pending blob entry for uploaded blob */);
318
318
  entry.storageId = response.id;
319
319
  if (this.runtime.connected) {
320
320
  if (entry.status === PendingBlobStatus.OnlinePendingUpload) {
@@ -348,7 +348,7 @@ export class BlobManager {
348
348
 
349
349
  private async onUploadReject(localId: string, error) {
350
350
  const entry = this.pendingBlobs.get(localId);
351
- assert(!!entry, "Must have pending blob entry for blob which failed to upload");
351
+ assert(!!entry, 0x387 /* Must have pending blob entry for blob which failed to upload */);
352
352
  if (!this.runtime.connected) {
353
353
  if (entry.status === PendingBlobStatus.OnlinePendingUpload) {
354
354
  this.transitionToOffline(localId);
@@ -363,11 +363,11 @@ export class BlobManager {
363
363
  }
364
364
 
365
365
  private transitionToOffline(localId: string) {
366
- assert(!this.runtime.connected, "Must only transition to offline flow while runtime is disconnected");
366
+ assert(!this.runtime.connected, 0x388 /* Must only transition to offline flow while runtime is disconnected */);
367
367
  const entry = this.pendingBlobs.get(localId);
368
- assert(!!entry, "No pending blob entry");
368
+ assert(!!entry, 0x389 /* No pending blob entry */);
369
369
  assert([PendingBlobStatus.OnlinePendingUpload, PendingBlobStatus.OnlinePendingOp].includes(entry.status),
370
- "Blob must be in online flow to transition to offline flow");
370
+ 0x38a /* Blob must be in online flow to transition to offline flow */);
371
371
 
372
372
  entry.status = entry.status === PendingBlobStatus.OnlinePendingUpload
373
373
  ? PendingBlobStatus.OfflinePendingUpload
@@ -388,14 +388,14 @@ export class BlobManager {
388
388
  * @param metadata - op metadata containing storage and/or local IDs
389
389
  */
390
390
  public reSubmit(metadata: Record<string, unknown> | undefined) {
391
- assert(!!metadata, "Resubmitted ops must have metadata");
391
+ assert(!!metadata, 0x38b /* Resubmitted ops must have metadata */);
392
392
  const { blobId, localId }: { blobId?: string; localId?: string; } = metadata;
393
393
  if (!blobId) {
394
- assert(!!localId, "Submitted BlobAttach ops must have a blobId or localId");
394
+ assert(!!localId, 0x38c /* Submitted BlobAttach ops must have a blobId or localId */);
395
395
  // We submitted this op while offline. The blob should have been uploaded by now.
396
396
  const pendingEntry = this.pendingBlobs.get(localId);
397
397
  assert(pendingEntry?.status === PendingBlobStatus.OfflinePendingOp &&
398
- !!pendingEntry?.storageId, "blob must be uploaded before resubmitting BlobAttach op");
398
+ !!pendingEntry?.storageId, 0x38d /* blob must be uploaded before resubmitting BlobAttach op */);
399
399
  return this.sendBlobAttachOp(pendingEntry.storageId, localId);
400
400
  }
401
401
  return this.sendBlobAttachOp(blobId, localId);
@@ -413,10 +413,13 @@ export class BlobManager {
413
413
  if (message.metadata.localId === undefined) {
414
414
  // Since there is no local ID, we know this op was submitted while online.
415
415
  const waitingBlobs = this.opsInFlight.get(message.metadata.blobId);
416
- assert(!!waitingBlobs, "local online BlobAttach op with no pending blob");
416
+ assert(!!waitingBlobs, 0x38e /* local online BlobAttach op with no pending blob */);
417
417
  waitingBlobs.forEach((localId) => {
418
418
  const pendingBlobEntry = this.pendingBlobs.get(localId);
419
- assert(pendingBlobEntry !== undefined, "local online BlobAttach op with no pending blob entry");
419
+ assert(
420
+ pendingBlobEntry !== undefined,
421
+ 0x38f, /* local online BlobAttach op with no pending blob entry */
422
+ );
420
423
 
421
424
  // It's possible we transitioned to offline flow while waiting for this op.
422
425
  if (pendingBlobEntry.status === PendingBlobStatus.OnlinePendingOp) {
@@ -497,7 +500,7 @@ export class BlobManager {
497
500
  // Note that because of de-duping, there can be multiple localIds that all redirect to the same storageId or
498
501
  // a blob may be referenced via its storageId handle.
499
502
  for (const [localId, storageId] of this.redirectTable) {
500
- assert(!!storageId, "Must be attached to get GC data");
503
+ assert(!!storageId, 0x390 /* Must be attached to get GC data */);
501
504
  // Add node for the localId and add a route to the storageId node. The storageId node will have been
502
505
  // added above when adding nodes for this.blobIds.
503
506
  gcData.gcNodes[this.getBlobGCNodePath(localId)] = [this.getBlobGCNodePath(storageId)];
@@ -554,7 +557,8 @@ export class BlobManager {
554
557
  public setRedirectTable(table: Map<string, string>) {
555
558
  assert(this.runtime.attachState === AttachState.Detached,
556
559
  0x252 /* "redirect table can only be set in detached container" */);
557
- assert(this.redirectTable.size === table.size, "Redirect table size must match BlobManager's local ID count");
560
+ assert(this.redirectTable.size === table.size,
561
+ 0x391 /* Redirect table size must match BlobManager's local ID count */);
558
562
  for (const [localId, storageId] of table) {
559
563
  assert(this.redirectTable.has(localId), 0x254 /* "unrecognized id in redirect table" */);
560
564
  this.redirectTable.set(localId, storageId);
@@ -425,12 +425,6 @@ export interface IContainerRuntimeOptions {
425
425
  * 3. "bypass" will skip the check entirely. This is not recommended.
426
426
  */
427
427
  readonly loadSequenceNumberVerification?: "close" | "log" | "bypass";
428
- /**
429
- * Should the runtime use data store aliasing for creating root datastores.
430
- * In case of aliasing conflicts, the runtime will raise an exception which does
431
- * not effect the status of the container.
432
- */
433
- readonly useDataStoreAliasing?: boolean;
434
428
  /**
435
429
  * Sets the flush mode for the runtime. In Immediate flush mode the runtime will immediately
436
430
  * send all operations to the driver layer, while in TurnBased the operations will be buffered
@@ -509,7 +503,6 @@ export interface IPendingRuntimeState {
509
503
  savedOps: ISequencedDocumentMessage[];
510
504
  }
511
505
 
512
- const useDataStoreAliasingKey = "Fluid.ContainerRuntime.UseDataStoreAliasing";
513
506
  const maxConsecutiveReconnectsKey = "Fluid.ContainerRuntime.MaxConsecutiveReconnects";
514
507
 
515
508
  // Feature gate for the max op size. If the value is negative, chunking is enabled
@@ -903,7 +896,6 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
903
896
  summaryOptions = {},
904
897
  gcOptions = {},
905
898
  loadSequenceNumberVerification = "close",
906
- useDataStoreAliasing = false,
907
899
  flushMode = defaultFlushMode,
908
900
  enableOfflineLoad = false,
909
901
  } = runtimeOptions;
@@ -979,7 +971,6 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
979
971
  summaryOptions,
980
972
  gcOptions,
981
973
  loadSequenceNumberVerification,
982
- useDataStoreAliasing,
983
974
  flushMode,
984
975
  enableOfflineLoad,
985
976
  },
@@ -1069,7 +1060,6 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
1069
1060
  private readonly summaryCollection: SummaryCollection;
1070
1061
 
1071
1062
  private readonly summarizerNode: IRootSummarizerNodeWithGC;
1072
- private readonly _aliasingEnabled: boolean;
1073
1063
  private readonly _maxOpSizeInBytes: number;
1074
1064
 
1075
1065
  private readonly maxConsecutiveReconnects: number;
@@ -1263,10 +1253,6 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
1263
1253
  this.maxOpsSinceLastSummary = this.getMaxOpsSinceLastSummary();
1264
1254
  this.initialSummarizerDelayMs = this.getInitialSummarizerDelayMs();
1265
1255
 
1266
- this._aliasingEnabled =
1267
- (this.mc.config.getBoolean(useDataStoreAliasingKey) ?? false) ||
1268
- (runtimeOptions.useDataStoreAliasing ?? false);
1269
-
1270
1256
  this._maxOpSizeInBytes = (this.mc.config.getNumber(maxOpSizeInBytesKey) ?? defaultMaxOpSizeInBytes);
1271
1257
  this.maxConsecutiveReconnects =
1272
1258
  this.mc.config.getNumber(maxConsecutiveReconnectsKey) ?? this.defaultMaxConsecutiveReconnects;
@@ -1829,8 +1815,9 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
1829
1815
  // ensure we don't submit ops referencing a blob that has not been uploaded
1830
1816
  const connecting = connected && !this._connected && !this.deltaManager.readOnlyInfo.readonly;
1831
1817
  if (connecting && this.blobManager.hasPendingOfflineUploads) {
1832
- assert(!this.delayConnectClientId, "Connect event delay must be canceled before subsequent connect event");
1833
- assert(!!clientId, "Must have clientId when connecting");
1818
+ assert(!this.delayConnectClientId,
1819
+ 0x392 /* Connect event delay must be canceled before subsequent connect event */);
1820
+ assert(!!clientId, 0x393 /* Must have clientId when connecting */);
1834
1821
  this.delayConnectClientId = clientId;
1835
1822
  this.blobManager.onConnected().then(() => {
1836
1823
  // make sure we didn't reconnect before the promise resolved
@@ -1846,7 +1833,8 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
1846
1833
  }
1847
1834
 
1848
1835
  private setConnectionStateCore(connected: boolean, clientId?: string) {
1849
- assert(!this.delayConnectClientId, "connect event delay must be cleared before propagating connect event");
1836
+ assert(!this.delayConnectClientId,
1837
+ 0x394 /* connect event delay must be cleared before propagating connect event */);
1850
1838
  this.verifyNotClosed();
1851
1839
 
1852
1840
  // There might be no change of state due to Container calling this API after loading runtime.
@@ -1870,11 +1858,11 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
1870
1858
  "Runtime detected too many reconnects with no progress syncing local ops",
1871
1859
  "setConnectionState",
1872
1860
  undefined,
1873
- {
1874
- dataLoss: 1,
1875
- attempts: this.consecutiveReconnects,
1876
- pendingMessages: this.pendingStateManager.pendingMessagesCount,
1877
- }));
1861
+ {
1862
+ dataLoss: 1,
1863
+ attempts: this.consecutiveReconnects,
1864
+ pendingMessages: this.pendingStateManager.pendingMessagesCount,
1865
+ }));
1878
1866
  return;
1879
1867
  }
1880
1868
  }
@@ -2137,83 +2125,13 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
2137
2125
  public async createDataStore(pkg: string | string[]): Promise<IDataStore> {
2138
2126
  const internalId = uuid();
2139
2127
  return channelToDataStore(
2140
- await this._createDataStore(pkg, false /* isRoot */, internalId),
2128
+ await this._createDataStore(pkg, internalId),
2141
2129
  internalId,
2142
2130
  this,
2143
2131
  this.dataStores,
2144
2132
  this.mc.logger);
2145
2133
  }
2146
2134
 
2147
- /**
2148
- * Creates a root datastore directly with a user generated id and attaches it to storage.
2149
- * It is vulnerable to name collisions and should not be used.
2150
- *
2151
- * This method will be removed. See #6465.
2152
- */
2153
- private async createRootDataStoreLegacy(pkg: string | string[], rootDataStoreId: string): Promise<IFluidRouter> {
2154
- const fluidDataStore = await this._createDataStore(pkg, true /* isRoot */, rootDataStoreId);
2155
- fluidDataStore.makeVisibleAndAttachGraph();
2156
- return fluidDataStore;
2157
- }
2158
-
2159
- /**
2160
- * @deprecated - will be removed in an upcoming release. See #9660.
2161
- */
2162
- public async createRootDataStore(pkg: string | string[], rootDataStoreId: string): Promise<IFluidRouter> {
2163
- if (rootDataStoreId.includes("/")) {
2164
- throw new UsageError(`Id cannot contain slashes: '${rootDataStoreId}'`);
2165
- }
2166
- return this._aliasingEnabled === true ?
2167
- this.createAndAliasDataStore(pkg, rootDataStoreId) :
2168
- this.createRootDataStoreLegacy(pkg, rootDataStoreId);
2169
- }
2170
-
2171
- /**
2172
- * Creates a data store then attempts to alias it.
2173
- * If aliasing fails, it will raise an exception.
2174
- *
2175
- * This method will be removed. See #6465.
2176
- *
2177
- * @param pkg - Package name of the data store
2178
- * @param alias - Alias to be assigned to the data store
2179
- * @param props - Properties for the data store
2180
- * @returns - An aliased data store which can can be found / loaded by alias.
2181
- */
2182
- private async createAndAliasDataStore(pkg: string | string[], alias: string, props?: any): Promise<IDataStore> {
2183
- const internalId = uuid();
2184
-
2185
- try {
2186
- // A similar call may have been initiated by the same client, so we should try to get
2187
- // a possible existing aliased datastore first.
2188
- const existingDataStore = await this.getRootDataStoreChannel(alias, /* wait */ false);
2189
- return channelToDataStore(
2190
- existingDataStore,
2191
- internalId,
2192
- this,
2193
- this.dataStores,
2194
- this.mc.logger,
2195
- true, // AlreadyAliased. This will block further alias attempts for the datastore
2196
- );
2197
- } catch (err) {
2198
- const newChannel = await this._createDataStore(pkg, false /* isRoot */, internalId, props);
2199
- const newDataStore = channelToDataStore(newChannel, internalId, this, this.dataStores, this.mc.logger);
2200
- const aliasResult = await newDataStore.trySetAlias(alias);
2201
- if (aliasResult === "Success") {
2202
- return newDataStore;
2203
- }
2204
-
2205
- const existingDataStore = await this.getRootDataStoreChannel(alias, /* wait */ false);
2206
- return channelToDataStore(
2207
- existingDataStore,
2208
- internalId,
2209
- this,
2210
- this.dataStores,
2211
- this.mc.logger,
2212
- true, // AlreadyAliased. This will block further alias attempts for the datastore
2213
- );
2214
- }
2215
- }
2216
-
2217
2135
  public createDetachedRootDataStore(
2218
2136
  pkg: Readonly<string[]>,
2219
2137
  rootDataStoreId: string): IFluidDataStoreContextDetached {
@@ -2227,49 +2145,23 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
2227
2145
  return this.dataStores.createDetachedDataStoreCore(pkg, false);
2228
2146
  }
2229
2147
 
2230
- /**
2231
- * Creates a possibly root datastore directly with a possibly user generated id and attaches it to storage.
2232
- * It is vulnerable to name collisions if both aforementioned conditions are true, and should not be used.
2233
- *
2234
- * This method will be removed. See #6465.
2235
- */
2236
- private async _createDataStoreWithPropsLegacy(
2148
+ public async _createDataStoreWithProps(
2237
2149
  pkg: string | string[],
2238
2150
  props?: any,
2239
2151
  id = uuid(),
2240
- isRoot = false,
2241
2152
  ): Promise<IDataStore> {
2242
2153
  const fluidDataStore = await this.dataStores._createFluidDataStoreContext(
2243
- Array.isArray(pkg) ? pkg : [pkg], id, isRoot, props).realize();
2244
- if (isRoot) {
2245
- fluidDataStore.makeVisibleAndAttachGraph();
2246
- this.logger.sendTelemetryEvent({
2247
- eventName: "Root datastore with props",
2248
- hasProps: props !== undefined,
2249
- });
2250
- }
2154
+ Array.isArray(pkg) ? pkg : [pkg], id, props).realize();
2251
2155
  return channelToDataStore(fluidDataStore, id, this, this.dataStores, this.mc.logger);
2252
2156
  }
2253
2157
 
2254
- public async _createDataStoreWithProps(
2255
- pkg: string | string[],
2256
- props?: any,
2257
- id = uuid(),
2258
- isRoot = false,
2259
- ): Promise<IDataStore> {
2260
- return this._aliasingEnabled === true && isRoot ?
2261
- this.createAndAliasDataStore(pkg, id, props) :
2262
- this._createDataStoreWithPropsLegacy(pkg, props, id, isRoot);
2263
- }
2264
-
2265
2158
  private async _createDataStore(
2266
2159
  pkg: string | string[],
2267
- isRoot: boolean,
2268
2160
  id = uuid(),
2269
2161
  props?: any,
2270
2162
  ): Promise<IFluidDataStoreChannel> {
2271
2163
  return this.dataStores
2272
- ._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, isRoot, props)
2164
+ ._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, props)
2273
2165
  .realize();
2274
2166
  }
2275
2167
 
@@ -2626,21 +2518,24 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
2626
2518
  },
2627
2519
  );
2628
2520
 
2521
+ let latestSnapshotVersionId: string | undefined;
2629
2522
  if (refreshLatestAck) {
2630
- const latestSummaryRefSeq = await this.refreshLatestSummaryAckFromServer(
2523
+ const latestSnapshotInfo = await this.refreshLatestSummaryAckFromServer(
2631
2524
  ChildLogger.create(summaryNumberLogger, undefined, { all: { safeSummary: true } }));
2525
+ const latestSnapshotRefSeq = latestSnapshotInfo.latestSnapshotRefSeq;
2526
+ latestSnapshotVersionId = latestSnapshotInfo.latestSnapshotVersionId;
2632
2527
 
2633
- if (latestSummaryRefSeq > this.deltaManager.lastSequenceNumber) {
2528
+ if (latestSnapshotRefSeq > this.deltaManager.lastSequenceNumber) {
2634
2529
  // We need to catch up to the latest summary's reference sequence number before pausing.
2635
2530
  await PerformanceEvent.timedExecAsync(
2636
2531
  summaryNumberLogger,
2637
2532
  {
2638
2533
  eventName: "WaitingForSeq",
2639
2534
  lastSequenceNumber: this.deltaManager.lastSequenceNumber,
2640
- targetSequenceNumber: latestSummaryRefSeq,
2535
+ targetSequenceNumber: latestSnapshotRefSeq,
2641
2536
  lastKnownSeqNumber: this.deltaManager.lastKnownSeqNumber,
2642
2537
  },
2643
- async () => waitForSeq(this.deltaManager, latestSummaryRefSeq),
2538
+ async () => waitForSeq(this.deltaManager, latestSnapshotRefSeq),
2644
2539
  { start: true, end: true, cancel: "error" }, // definitely want start event
2645
2540
  );
2646
2541
  }
@@ -2683,7 +2578,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
2683
2578
  };
2684
2579
  }
2685
2580
  assert(summaryRefSeqNum === this.deltaManager.lastMessage?.sequenceNumber,
2686
- "it's one and the same thing");
2581
+ 0x395 /* it's one and the same thing */);
2687
2582
 
2688
2583
  if (lastAck !== this.summaryCollection.latestAck) {
2689
2584
  return {
@@ -2765,18 +2660,32 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
2765
2660
  return { stage: "generate", ...generateSummaryData, error: continueResult.error };
2766
2661
  }
2767
2662
 
2768
- const summaryContext: ISummaryContext =
2769
- lastAck === undefined
2770
- ? {
2771
- proposalHandle: undefined,
2772
- ackHandle: this.context.getLoadedFromVersion()?.id,
2773
- referenceSequenceNumber: summaryRefSeqNum,
2774
- }
2775
- : {
2776
- proposalHandle: lastAck.summaryOp.contents.handle,
2777
- ackHandle: lastAck.summaryAck.contents.handle,
2778
- referenceSequenceNumber: summaryRefSeqNum,
2779
- };
2663
+ // It may happen that the lastAck it not correct due to missing summaryAck in case of single commit
2664
+ // summary. So if the previous summarizer closes just after submitting the summary and before
2665
+ // submitting the summaryOp then we can't rely on summaryAck. So in case we have
2666
+ // latestSnapshotVersionId from storage and it does not match with the lastAck ackHandle, then use
2667
+ // the one fetched from storage as parent as that is the latest.
2668
+ let summaryContext: ISummaryContext;
2669
+ if (lastAck?.summaryAck.contents.handle !== latestSnapshotVersionId
2670
+ && latestSnapshotVersionId !== undefined) {
2671
+ summaryContext = {
2672
+ proposalHandle: undefined,
2673
+ ackHandle: latestSnapshotVersionId,
2674
+ referenceSequenceNumber: summaryRefSeqNum,
2675
+ };
2676
+ } else if (lastAck === undefined) {
2677
+ summaryContext = {
2678
+ proposalHandle: undefined,
2679
+ ackHandle: this.context.getLoadedFromVersion()?.id,
2680
+ referenceSequenceNumber: summaryRefSeqNum,
2681
+ };
2682
+ } else {
2683
+ summaryContext = {
2684
+ proposalHandle: lastAck.summaryOp.contents.handle,
2685
+ ackHandle: lastAck.summaryAck.contents.handle,
2686
+ referenceSequenceNumber: summaryRefSeqNum,
2687
+ };
2688
+ }
2780
2689
 
2781
2690
  let handle: string;
2782
2691
  try {
@@ -3123,15 +3032,20 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
3123
3032
  summaryLogger: ITelemetryLogger,
3124
3033
  ) {
3125
3034
  const readAndParseBlob = async <T>(id: string) => readAndParse<T>(this.storage, id);
3126
- const result = await this.summarizerNode.refreshLatestSummary(
3127
- proposalHandle,
3128
- summaryRefSeq,
3129
- async () => this.fetchSnapshotFromStorage(ackHandle, summaryLogger, {
3035
+ const { snapshotTree } = await this.fetchSnapshotFromStorage(
3036
+ ackHandle,
3037
+ summaryLogger,
3038
+ {
3130
3039
  eventName: "RefreshLatestSummaryGetSnapshot",
3131
3040
  ackHandle,
3132
3041
  summaryRefSeq,
3133
3042
  fetchLatest: false,
3134
- }),
3043
+ },
3044
+ );
3045
+ const result = await this.summarizerNode.refreshLatestSummary(
3046
+ proposalHandle,
3047
+ summaryRefSeq,
3048
+ async () => snapshotTree,
3135
3049
  readAndParseBlob,
3136
3050
  summaryLogger,
3137
3051
  );
@@ -3146,21 +3060,23 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
3146
3060
  * @param summaryLogger - logger to use when fetching snapshot from storage
3147
3061
  * @returns downloaded snapshot's reference sequence number
3148
3062
  */
3149
- private async refreshLatestSummaryAckFromServer(summaryLogger: ITelemetryLogger): Promise<number> {
3150
- const snapshot = await this.fetchSnapshotFromStorage(null, summaryLogger, {
3151
- eventName: "RefreshLatestSummaryGetSnapshot",
3152
- fetchLatest: true,
3153
- },
3063
+ private async refreshLatestSummaryAckFromServer(
3064
+ summaryLogger: ITelemetryLogger,
3065
+ ): Promise<{ latestSnapshotRefSeq: number; latestSnapshotVersionId: string | undefined; }> {
3066
+ const { snapshotTree, versionId } = await this.fetchSnapshotFromStorage(null, summaryLogger, {
3067
+ eventName: "RefreshLatestSummaryGetSnapshot",
3068
+ fetchLatest: true,
3069
+ },
3154
3070
  FetchSource.noCache,
3155
3071
  );
3156
3072
 
3157
3073
  const readAndParseBlob = async <T>(id: string) => readAndParse<T>(this.storage, id);
3158
- const snapshotRefSeq = await seqFromTree(snapshot, readAndParseBlob);
3074
+ const latestSnapshotRefSeq = await seqFromTree(snapshotTree, readAndParseBlob);
3159
3075
 
3160
3076
  const result = await this.summarizerNode.refreshLatestSummary(
3161
3077
  undefined,
3162
- snapshotRefSeq,
3163
- async () => snapshot,
3078
+ latestSnapshotRefSeq,
3079
+ async () => snapshotTree,
3164
3080
  readAndParseBlob,
3165
3081
  summaryLogger,
3166
3082
  );
@@ -3168,7 +3084,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
3168
3084
  // Notify the garbage collector so it can update its latest summary state.
3169
3085
  await this.garbageCollector.latestSummaryStateRefreshed(result, readAndParseBlob);
3170
3086
 
3171
- return snapshotRefSeq;
3087
+ return { latestSnapshotRefSeq, latestSnapshotVersionId: versionId };
3172
3088
  }
3173
3089
 
3174
3090
  private async fetchSnapshotFromStorage(
@@ -3176,7 +3092,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
3176
3092
  logger: ITelemetryLogger,
3177
3093
  event: ITelemetryGenericEvent,
3178
3094
  fetchSource?: FetchSource,
3179
- ) {
3095
+ ): Promise<{ snapshotTree: ISnapshotTree; versionId: string; }> {
3180
3096
  return PerformanceEvent.timedExecAsync(
3181
3097
  logger, event, async (perfEvent: {
3182
3098
  end: (arg0: {
@@ -3197,7 +3113,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
3197
3113
  stats.getSnapshotDuration = trace.trace().duration;
3198
3114
 
3199
3115
  perfEvent.end(stats);
3200
- return maybeSnapshot;
3116
+ return { snapshotTree: maybeSnapshot, versionId: versions[0].id };
3201
3117
  });
3202
3118
  }
3203
3119
 
package/src/dataStore.ts CHANGED
@@ -43,8 +43,7 @@ export const channelToDataStore = (
43
43
  runtime: ContainerRuntime,
44
44
  datastores: DataStores,
45
45
  logger: ITelemetryLogger,
46
- alreadyAliased: boolean = false,
47
- ): IDataStore => new DataStore(fluidDataStoreChannel, internalId, runtime, datastores, logger, alreadyAliased);
46
+ ): IDataStore => new DataStore(fluidDataStoreChannel, internalId, runtime, datastores, logger);
48
47
 
49
48
  enum AliasState {
50
49
  Aliased = "Aliased",
@@ -158,10 +157,8 @@ class DataStore implements IDataStore {
158
157
  private readonly runtime: ContainerRuntime,
159
158
  private readonly datastores: DataStores,
160
159
  private readonly logger: ITelemetryLogger,
161
- alreadyAliased: boolean,
162
160
  ) {
163
161
  this.pendingAliases = datastores.pendingAliases;
164
- this.aliasState = alreadyAliased ? AliasState.Aliased : AliasState.None;
165
162
  }
166
163
 
167
164
  public get IFluidRouter() { return this.fluidDataStoreChannel; }