@fluidframework/container-runtime 0.59.4002 → 0.59.4003

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.
@@ -1479,16 +1479,19 @@ export class ContainerRuntime extends TypedEventEmitter {
1479
1479
  const summaryNumberLogger = ChildLogger.create(summaryLogger, undefined, {
1480
1480
  all: { summaryNumber },
1481
1481
  });
1482
+ let latestSnapshotVersionId;
1482
1483
  if (refreshLatestAck) {
1483
- const latestSummaryRefSeq = await this.refreshLatestSummaryAckFromServer(ChildLogger.create(summaryNumberLogger, undefined, { all: { safeSummary: true } }));
1484
- if (latestSummaryRefSeq > this.deltaManager.lastSequenceNumber) {
1484
+ const latestSnapshotInfo = await this.refreshLatestSummaryAckFromServer(ChildLogger.create(summaryNumberLogger, undefined, { all: { safeSummary: true } }));
1485
+ const latestSnapshotRefSeq = latestSnapshotInfo.latestSnapshotRefSeq;
1486
+ latestSnapshotVersionId = latestSnapshotInfo.latestSnapshotVersionId;
1487
+ if (latestSnapshotRefSeq > this.deltaManager.lastSequenceNumber) {
1485
1488
  // We need to catch up to the latest summary's reference sequence number before pausing.
1486
1489
  await PerformanceEvent.timedExecAsync(summaryNumberLogger, {
1487
1490
  eventName: "WaitingForSeq",
1488
1491
  lastSequenceNumber: this.deltaManager.lastSequenceNumber,
1489
- targetSequenceNumber: latestSummaryRefSeq,
1492
+ targetSequenceNumber: latestSnapshotRefSeq,
1490
1493
  lastKnownSeqNumber: this.deltaManager.lastKnownSeqNumber,
1491
- }, async () => waitForSeq(this.deltaManager, latestSummaryRefSeq), { start: true, end: true, cancel: "error" });
1494
+ }, async () => waitForSeq(this.deltaManager, latestSnapshotRefSeq), { start: true, end: true, cancel: "error" });
1492
1495
  }
1493
1496
  }
1494
1497
  try {
@@ -1587,18 +1590,35 @@ export class ContainerRuntime extends TypedEventEmitter {
1587
1590
  if (!continueResult.continue) {
1588
1591
  return Object.assign(Object.assign({ stage: "generate" }, generateSummaryData), { error: continueResult.error });
1589
1592
  }
1593
+ // It may happen that the lastAck it not correct due to missing summaryAck in case of single commit
1594
+ // summary. So if the previous summarizer closes just after submitting the summary and before
1595
+ // submitting the summaryOp then we can't rely on summaryAck. So in case we have
1596
+ // latestSnapshotVersionId from storage and it does not match with the lastAck ackHandle, then use
1597
+ // the one fetched from storage as parent as that is the latest.
1590
1598
  const lastAck = this.summaryCollection.latestAck;
1591
- const summaryContext = lastAck === undefined
1592
- ? {
1599
+ let summaryContext;
1600
+ if ((lastAck === null || lastAck === void 0 ? void 0 : lastAck.summaryAck.contents.handle) !== latestSnapshotVersionId
1601
+ && latestSnapshotVersionId !== undefined) {
1602
+ summaryContext = {
1603
+ proposalHandle: undefined,
1604
+ ackHandle: latestSnapshotVersionId,
1605
+ referenceSequenceNumber: summaryRefSeqNum,
1606
+ };
1607
+ }
1608
+ else if (lastAck === undefined) {
1609
+ summaryContext = {
1593
1610
  proposalHandle: undefined,
1594
1611
  ackHandle: (_c = this.context.getLoadedFromVersion()) === null || _c === void 0 ? void 0 : _c.id,
1595
1612
  referenceSequenceNumber: summaryRefSeqNum,
1596
- }
1597
- : {
1613
+ };
1614
+ }
1615
+ else {
1616
+ summaryContext = {
1598
1617
  proposalHandle: lastAck.summaryOp.contents.handle,
1599
1618
  ackHandle: lastAck.summaryAck.contents.handle,
1600
1619
  referenceSequenceNumber: summaryRefSeqNum,
1601
1620
  };
1621
+ }
1602
1622
  let handle;
1603
1623
  try {
1604
1624
  handle = await this.storage.uploadSummaryWithContext(summarizeResult.summary, summaryContext);
@@ -1836,12 +1856,18 @@ export class ContainerRuntime extends TypedEventEmitter {
1836
1856
  /** Implementation of ISummarizerInternalsProvider.refreshLatestSummaryAck */
1837
1857
  async refreshLatestSummaryAck(proposalHandle, ackHandle, summaryRefSeq, summaryLogger) {
1838
1858
  const readAndParseBlob = async (id) => readAndParse(this.storage, id);
1839
- const result = await this.summarizerNode.refreshLatestSummary(proposalHandle, summaryRefSeq, async () => this.fetchSnapshotFromStorage(ackHandle, summaryLogger, {
1840
- eventName: "RefreshLatestSummaryGetSnapshot",
1841
- ackHandle,
1842
- summaryRefSeq,
1843
- fetchLatest: false,
1844
- }), readAndParseBlob, summaryLogger);
1859
+ // The call to fetch the snapshot is very expensive and not always needed.
1860
+ // It should only be done by the summarizerNode, if required.
1861
+ const snapshotTreeFetcher = async () => {
1862
+ const fetchResult = await this.fetchSnapshotFromStorage(ackHandle, summaryLogger, {
1863
+ eventName: "RefreshLatestSummaryGetSnapshot",
1864
+ ackHandle,
1865
+ summaryRefSeq,
1866
+ fetchLatest: false,
1867
+ });
1868
+ return fetchResult.snapshotTree;
1869
+ };
1870
+ const result = await this.summarizerNode.refreshLatestSummary(proposalHandle, summaryRefSeq, snapshotTreeFetcher, readAndParseBlob, summaryLogger);
1845
1871
  // Notify the garbage collector so it can update its latest summary state.
1846
1872
  await this.garbageCollector.latestSummaryStateRefreshed(result, readAndParseBlob);
1847
1873
  }
@@ -1852,16 +1878,16 @@ export class ContainerRuntime extends TypedEventEmitter {
1852
1878
  * @returns downloaded snapshot's reference sequence number
1853
1879
  */
1854
1880
  async refreshLatestSummaryAckFromServer(summaryLogger) {
1855
- const snapshot = await this.fetchSnapshotFromStorage(null, summaryLogger, {
1881
+ const { snapshotTree, versionId } = await this.fetchSnapshotFromStorage(null, summaryLogger, {
1856
1882
  eventName: "RefreshLatestSummaryGetSnapshot",
1857
1883
  fetchLatest: true,
1858
1884
  });
1859
1885
  const readAndParseBlob = async (id) => readAndParse(this.storage, id);
1860
- const snapshotRefSeq = await seqFromTree(snapshot, readAndParseBlob);
1861
- const result = await this.summarizerNode.refreshLatestSummary(undefined, snapshotRefSeq, async () => snapshot, readAndParseBlob, summaryLogger);
1886
+ const latestSnapshotRefSeq = await seqFromTree(snapshotTree, readAndParseBlob);
1887
+ const result = await this.summarizerNode.refreshLatestSummary(undefined, latestSnapshotRefSeq, async () => snapshotTree, readAndParseBlob, summaryLogger);
1862
1888
  // Notify the garbage collector so it can update its latest summary state.
1863
1889
  await this.garbageCollector.latestSummaryStateRefreshed(result, readAndParseBlob);
1864
- return snapshotRefSeq;
1890
+ return { latestSnapshotRefSeq, latestSnapshotVersionId: versionId };
1865
1891
  }
1866
1892
  async fetchSnapshotFromStorage(versionId, logger, event) {
1867
1893
  return PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
@@ -1874,7 +1900,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1874
1900
  assert(!!maybeSnapshot, 0x138 /* "Failed to get snapshot from storage" */);
1875
1901
  stats.getSnapshotDuration = trace.trace().duration;
1876
1902
  perfEvent.end(stats);
1877
- return maybeSnapshot;
1903
+ return { snapshotTree: maybeSnapshot, versionId: versions[0].id };
1878
1904
  });
1879
1905
  }
1880
1906
  getPendingLocalState() {