@fluidframework/container-runtime 2.5.0-302463 → 2.10.0-304831
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.
- package/CHANGELOG.md +18 -0
- package/api-report/container-runtime.legacy.alpha.api.md +3 -1
- package/container-runtime.test-files.tar +0 -0
- package/dist/blobManager/blobManager.d.ts +3 -3
- package/dist/blobManager/blobManager.d.ts.map +1 -1
- package/dist/blobManager/blobManager.js +1 -1
- package/dist/blobManager/blobManager.js.map +1 -1
- package/dist/channelCollection.d.ts +20 -5
- package/dist/channelCollection.d.ts.map +1 -1
- package/dist/channelCollection.js +185 -129
- package/dist/channelCollection.js.map +1 -1
- package/dist/containerRuntime.d.ts +14 -4
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +145 -64
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStoreContext.d.ts +15 -3
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +48 -19
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStoreContexts.d.ts.map +1 -1
- package/dist/dataStoreContexts.js +6 -14
- package/dist/dataStoreContexts.js.map +1 -1
- package/dist/gc/garbageCollection.d.ts +5 -6
- package/dist/gc/garbageCollection.d.ts.map +1 -1
- package/dist/gc/garbageCollection.js +23 -22
- package/dist/gc/garbageCollection.js.map +1 -1
- package/dist/gc/gcDefinitions.d.ts +2 -2
- package/dist/gc/gcDefinitions.d.ts.map +1 -1
- package/dist/gc/gcDefinitions.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts +3 -0
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +9 -0
- package/dist/opLifecycle/outbox.js.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.d.ts +1 -0
- package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.js +2 -0
- package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.d.ts.map +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/summary/documentSchema.d.ts +11 -0
- package/dist/summary/documentSchema.d.ts.map +1 -1
- package/dist/summary/documentSchema.js +43 -28
- package/dist/summary/documentSchema.js.map +1 -1
- package/lib/blobManager/blobManager.d.ts +3 -3
- package/lib/blobManager/blobManager.d.ts.map +1 -1
- package/lib/blobManager/blobManager.js +1 -1
- package/lib/blobManager/blobManager.js.map +1 -1
- package/lib/channelCollection.d.ts +20 -5
- package/lib/channelCollection.d.ts.map +1 -1
- package/lib/channelCollection.js +186 -130
- package/lib/channelCollection.js.map +1 -1
- package/lib/containerRuntime.d.ts +14 -4
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +144 -63
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStoreContext.d.ts +15 -3
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +48 -19
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStoreContexts.d.ts.map +1 -1
- package/lib/dataStoreContexts.js +7 -15
- package/lib/dataStoreContexts.js.map +1 -1
- package/lib/gc/garbageCollection.d.ts +5 -6
- package/lib/gc/garbageCollection.d.ts.map +1 -1
- package/lib/gc/garbageCollection.js +23 -22
- package/lib/gc/garbageCollection.js.map +1 -1
- package/lib/gc/gcDefinitions.d.ts +2 -2
- package/lib/gc/gcDefinitions.d.ts.map +1 -1
- package/lib/gc/gcDefinitions.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts +3 -0
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.js +9 -0
- package/lib/opLifecycle/outbox.js.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.d.ts +1 -0
- package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.js +2 -0
- package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.d.ts.map +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/summary/documentSchema.d.ts +11 -0
- package/lib/summary/documentSchema.d.ts.map +1 -1
- package/lib/summary/documentSchema.js +43 -28
- package/lib/summary/documentSchema.js.map +1 -1
- package/package.json +21 -21
- package/src/blobManager/blobManager.ts +2 -2
- package/src/channelCollection.ts +234 -176
- package/src/containerRuntime.ts +189 -79
- package/src/dataStoreContext.ts +66 -23
- package/src/dataStoreContexts.ts +7 -20
- package/src/gc/garbageCollection.ts +32 -32
- package/src/gc/gcDefinitions.ts +3 -3
- package/src/opLifecycle/outbox.ts +12 -0
- package/src/opLifecycle/remoteMessageProcessor.ts +3 -0
- package/src/packageVersion.ts +1 -1
- package/src/summary/documentSchema.ts +56 -37
package/lib/containerRuntime.js
CHANGED
|
@@ -89,6 +89,12 @@ export const TombstoneResponseHeaderKey = "isTombstoned";
|
|
|
89
89
|
* to this was experimental and is no longer supported.
|
|
90
90
|
*/
|
|
91
91
|
export const InactiveResponseHeaderKey = "isInactive";
|
|
92
|
+
/** Default values for Runtime Headers */
|
|
93
|
+
export const defaultRuntimeHeaderData = {
|
|
94
|
+
wait: true,
|
|
95
|
+
viaHandle: false,
|
|
96
|
+
allowTombstone: false,
|
|
97
|
+
};
|
|
92
98
|
/**
|
|
93
99
|
* Available compression algorithms for op compression.
|
|
94
100
|
* @legacy
|
|
@@ -1581,20 +1587,13 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1581
1587
|
: inboundResult.type === "batchStartingMessage"
|
|
1582
1588
|
? { batchStart: true, batchEnd: false }
|
|
1583
1589
|
: { batchStart: false, batchEnd: inboundResult.batchEnd === true };
|
|
1584
|
-
this.processInboundMessages(messagesWithPendingState, locationInBatch, local, savedOp, runtimeBatch
|
|
1590
|
+
this.processInboundMessages(messagesWithPendingState, locationInBatch, local, savedOp, runtimeBatch, inboundResult.type === "fullBatch"
|
|
1591
|
+
? inboundResult.groupedBatch
|
|
1592
|
+
: false /* groupedBatch */);
|
|
1585
1593
|
}
|
|
1586
1594
|
else {
|
|
1587
|
-
if (!runtimeBatch) {
|
|
1588
|
-
// The DeltaManager used to do this, but doesn't anymore as of Loader v2.4
|
|
1589
|
-
// Anyone listening to our "op" event would expect the contents to be parsed per this same logic
|
|
1590
|
-
if (typeof messageCopy.contents === "string" &&
|
|
1591
|
-
messageCopy.contents !== "" &&
|
|
1592
|
-
messageCopy.type !== MessageType.ClientLeave) {
|
|
1593
|
-
messageCopy.contents = JSON.parse(messageCopy.contents);
|
|
1594
|
-
}
|
|
1595
|
-
}
|
|
1596
1595
|
this.processInboundMessages([{ message: messageCopy, localOpMetadata: undefined }], { batchStart: true, batchEnd: true }, // Single message
|
|
1597
|
-
local, savedOp, runtimeBatch);
|
|
1596
|
+
local, savedOp, runtimeBatch, false /* groupedBatch */);
|
|
1598
1597
|
}
|
|
1599
1598
|
if (local) {
|
|
1600
1599
|
// If we have processed a local op, this means that the container is
|
|
@@ -1605,35 +1604,93 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1605
1604
|
}
|
|
1606
1605
|
/**
|
|
1607
1606
|
* Processes inbound message(s). It calls schedule manager according to the messages' location in the batch.
|
|
1608
|
-
* @param
|
|
1607
|
+
* @param messagesWithMetadata - messages to process along with their metadata.
|
|
1609
1608
|
* @param locationInBatch - Are we processing the start and/or end of a batch?
|
|
1610
1609
|
* @param local - true if the messages were originally generated by the client receiving it.
|
|
1611
1610
|
* @param savedOp - true if the message is a replayed saved op.
|
|
1612
1611
|
* @param runtimeBatch - true if these are runtime messages.
|
|
1612
|
+
* @param groupedBatch - true if these messages are part of a grouped op batch.
|
|
1613
1613
|
*/
|
|
1614
|
-
processInboundMessages(
|
|
1614
|
+
processInboundMessages(messagesWithMetadata, locationInBatch, local, savedOp, runtimeBatch, groupedBatch) {
|
|
1615
1615
|
if (locationInBatch.batchStart) {
|
|
1616
|
-
const firstMessage =
|
|
1616
|
+
const firstMessage = messagesWithMetadata[0]?.message;
|
|
1617
1617
|
assert(firstMessage !== undefined, 0xa31 /* Batch must have at least one message */);
|
|
1618
1618
|
this.scheduleManager.batchBegin(firstMessage);
|
|
1619
1619
|
}
|
|
1620
1620
|
let error;
|
|
1621
1621
|
try {
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
this.validateAndProcessRuntimeMessage({
|
|
1626
|
-
message: message,
|
|
1627
|
-
local,
|
|
1628
|
-
savedOp,
|
|
1629
|
-
localOpMetadata,
|
|
1630
|
-
});
|
|
1631
|
-
}
|
|
1632
|
-
else {
|
|
1622
|
+
if (!runtimeBatch) {
|
|
1623
|
+
messagesWithMetadata.forEach(({ message }) => {
|
|
1624
|
+
this.ensureNoDataModelChanges(() => {
|
|
1633
1625
|
this.observeNonRuntimeMessage(message);
|
|
1634
|
-
}
|
|
1626
|
+
});
|
|
1635
1627
|
});
|
|
1636
|
-
|
|
1628
|
+
return;
|
|
1629
|
+
}
|
|
1630
|
+
// Helper that updates a message's minimum sequence number to the minimum sequence number that container
|
|
1631
|
+
// runtime is tracking and sets _processedClientSequenceNumber. It returns the updated message.
|
|
1632
|
+
const updateSequenceNumbers = (message) => {
|
|
1633
|
+
// Set the minimum sequence number to the containerRuntime's understanding of minimum sequence number.
|
|
1634
|
+
message.minimumSequenceNumber =
|
|
1635
|
+
this.useDeltaManagerOpsProxy &&
|
|
1636
|
+
this.deltaManager.minimumSequenceNumber < message.minimumSequenceNumber
|
|
1637
|
+
? this.deltaManager.minimumSequenceNumber
|
|
1638
|
+
: message.minimumSequenceNumber;
|
|
1639
|
+
this._processedClientSequenceNumber = message.clientSequenceNumber;
|
|
1640
|
+
return message;
|
|
1641
|
+
};
|
|
1642
|
+
// Non-grouped batch messages are processed one at a time.
|
|
1643
|
+
if (!groupedBatch) {
|
|
1644
|
+
for (const { message, localOpMetadata } of messagesWithMetadata) {
|
|
1645
|
+
updateSequenceNumbers(message);
|
|
1646
|
+
this.ensureNoDataModelChanges(() => {
|
|
1647
|
+
this.validateAndProcessRuntimeMessages(message, [
|
|
1648
|
+
{
|
|
1649
|
+
contents: message.contents,
|
|
1650
|
+
localOpMetadata,
|
|
1651
|
+
clientSequenceNumber: message.clientSequenceNumber,
|
|
1652
|
+
},
|
|
1653
|
+
], local, savedOp);
|
|
1654
|
+
this.emit("op", message, true /* runtimeMessage */);
|
|
1655
|
+
});
|
|
1656
|
+
}
|
|
1657
|
+
return;
|
|
1658
|
+
}
|
|
1659
|
+
let bunchedMessagesContent = [];
|
|
1660
|
+
let previousMessage;
|
|
1661
|
+
// Helper that processes the previous bunch of messages.
|
|
1662
|
+
const sendBunchedMessages = () => {
|
|
1663
|
+
assert(previousMessage !== undefined, 0xa67 /* previous message must exist */);
|
|
1664
|
+
this.ensureNoDataModelChanges(() => {
|
|
1665
|
+
this.validateAndProcessRuntimeMessages(
|
|
1666
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1667
|
+
previousMessage, bunchedMessagesContent, local, savedOp);
|
|
1668
|
+
});
|
|
1669
|
+
bunchedMessagesContent = [];
|
|
1670
|
+
};
|
|
1671
|
+
/**
|
|
1672
|
+
* For grouped batch messages, bunch contiguous messages of the same type and process them together.
|
|
1673
|
+
* This is an optimization mainly for DDSes, where it can process a bunch of ops together. DDSes
|
|
1674
|
+
* like merge tree or shared tree can process ops more efficiently when they are bunched together.
|
|
1675
|
+
*/
|
|
1676
|
+
for (const { message, localOpMetadata } of messagesWithMetadata) {
|
|
1677
|
+
const currentMessage = updateSequenceNumbers(message);
|
|
1678
|
+
if (previousMessage && previousMessage.type !== currentMessage.type) {
|
|
1679
|
+
sendBunchedMessages();
|
|
1680
|
+
}
|
|
1681
|
+
previousMessage = currentMessage;
|
|
1682
|
+
bunchedMessagesContent.push({
|
|
1683
|
+
contents: message.contents,
|
|
1684
|
+
localOpMetadata,
|
|
1685
|
+
clientSequenceNumber: message.clientSequenceNumber,
|
|
1686
|
+
});
|
|
1687
|
+
}
|
|
1688
|
+
// Process the last bunch of messages.
|
|
1689
|
+
sendBunchedMessages();
|
|
1690
|
+
// Send the "op" events for the messages now that the ops have been processed.
|
|
1691
|
+
for (const { message } of messagesWithMetadata) {
|
|
1692
|
+
this.emit("op", message, true /* runtimeMessage */);
|
|
1693
|
+
}
|
|
1637
1694
|
}
|
|
1638
1695
|
catch (e) {
|
|
1639
1696
|
error = e;
|
|
@@ -1641,7 +1698,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1641
1698
|
}
|
|
1642
1699
|
finally {
|
|
1643
1700
|
if (locationInBatch.batchEnd) {
|
|
1644
|
-
const lastMessage =
|
|
1701
|
+
const lastMessage = messagesWithMetadata[messagesWithMetadata.length - 1]?.message;
|
|
1645
1702
|
assert(lastMessage !== undefined, 0xa32 /* Batch must have at least one message */);
|
|
1646
1703
|
this.scheduleManager.batchEnd(error, lastMessage);
|
|
1647
1704
|
}
|
|
@@ -1662,65 +1719,60 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1662
1719
|
if (!this.hasPendingMessages()) {
|
|
1663
1720
|
this.updateDocumentDirtyState(false);
|
|
1664
1721
|
}
|
|
1722
|
+
// The DeltaManager used to do this, but doesn't anymore as of Loader v2.4
|
|
1723
|
+
// Anyone listening to our "op" event would expect the contents to be parsed per this same logic
|
|
1724
|
+
if (typeof message.contents === "string" &&
|
|
1725
|
+
message.contents !== "" &&
|
|
1726
|
+
message.type !== MessageType.ClientLeave) {
|
|
1727
|
+
message.contents = JSON.parse(message.contents);
|
|
1728
|
+
}
|
|
1665
1729
|
this.emit("op", message, false /* runtimeMessage */);
|
|
1666
1730
|
}
|
|
1667
1731
|
/**
|
|
1668
|
-
*
|
|
1669
|
-
*
|
|
1732
|
+
* Process runtime messages. The messages here are contiguous messages in a batch.
|
|
1733
|
+
* Assuming the messages in the given bunch are also a TypedContainerRuntimeMessage, checks its type and dispatch
|
|
1734
|
+
* the messages to the appropriate handler in the runtime.
|
|
1670
1735
|
* Throws a DataProcessingError if the message looks like but doesn't conform to a known TypedContainerRuntimeMessage type.
|
|
1736
|
+
* @param message - The core message with common properties for all the messages.
|
|
1737
|
+
* @param messageContents - The contents, local metadata and clientSequenceNumbers of the messages.
|
|
1738
|
+
* @param local - true if the messages were originally generated by the client receiving it.
|
|
1739
|
+
* @param savedOp - true if the message is a replayed saved op.
|
|
1740
|
+
*
|
|
1671
1741
|
*/
|
|
1672
|
-
|
|
1673
|
-
const { local, message, savedOp, localOpMetadata } = messageWithContext;
|
|
1674
|
-
// Set the minimum sequence number to the containerRuntime's understanding of minimum sequence number.
|
|
1675
|
-
if (this.useDeltaManagerOpsProxy &&
|
|
1676
|
-
this.deltaManager.minimumSequenceNumber < message.minimumSequenceNumber) {
|
|
1677
|
-
message.minimumSequenceNumber = this.deltaManager.minimumSequenceNumber;
|
|
1678
|
-
}
|
|
1679
|
-
this._processedClientSequenceNumber = message.clientSequenceNumber;
|
|
1742
|
+
validateAndProcessRuntimeMessages(message, messagesContent, local, savedOp) {
|
|
1680
1743
|
// If there are no more pending messages after processing a local message,
|
|
1681
1744
|
// the document is no longer dirty.
|
|
1682
1745
|
if (!this.hasPendingMessages()) {
|
|
1683
1746
|
this.updateDocumentDirtyState(false);
|
|
1684
1747
|
}
|
|
1748
|
+
// Get the contents without the localOpMetadata because not all message types know about localOpMetadata.
|
|
1749
|
+
const contents = messagesContent.map((c) => c.contents);
|
|
1685
1750
|
switch (message.type) {
|
|
1751
|
+
case ContainerMessageType.FluidDataStoreOp:
|
|
1686
1752
|
case ContainerMessageType.Attach:
|
|
1687
1753
|
case ContainerMessageType.Alias:
|
|
1688
|
-
|
|
1689
|
-
|
|
1754
|
+
// Remove the metadata from the message before sending it to the channel collection. The metadata
|
|
1755
|
+
// is added by the container runtime and is not part of the message that the channel collection and
|
|
1756
|
+
// layers below it expect.
|
|
1757
|
+
this.channelCollection.processMessages({ envelope: message, messagesContent, local });
|
|
1690
1758
|
break;
|
|
1691
1759
|
case ContainerMessageType.BlobAttach:
|
|
1692
|
-
this.blobManager.
|
|
1760
|
+
this.blobManager.processBlobAttachMessage(message, local);
|
|
1693
1761
|
break;
|
|
1694
1762
|
case ContainerMessageType.IdAllocation:
|
|
1695
|
-
|
|
1696
|
-
// stashed ops flow. The compressor is stashed with these ops already processed.
|
|
1697
|
-
// That said, in idCompressorMode === "delayed", we might not serialize ID compressor, and
|
|
1698
|
-
// thus we need to process all the ops.
|
|
1699
|
-
if (!(this.skipSavedCompressorOps && savedOp === true)) {
|
|
1700
|
-
const range = message.contents;
|
|
1701
|
-
// Some other client turned on the id compressor. If we have not turned it on,
|
|
1702
|
-
// put it in a pending queue and delay finalization.
|
|
1703
|
-
if (this._idCompressor === undefined) {
|
|
1704
|
-
assert(this.idCompressorMode !== undefined, 0x93c /* id compressor should be enabled */);
|
|
1705
|
-
this.pendingIdCompressorOps.push(range);
|
|
1706
|
-
}
|
|
1707
|
-
else {
|
|
1708
|
-
assert(this.pendingIdCompressorOps.length === 0, 0x979 /* there should be no pending ops! */);
|
|
1709
|
-
this._idCompressor.finalizeCreationRange(range);
|
|
1710
|
-
}
|
|
1711
|
-
}
|
|
1763
|
+
this.processIdCompressorMessages(contents, savedOp);
|
|
1712
1764
|
break;
|
|
1713
1765
|
case ContainerMessageType.GC:
|
|
1714
|
-
this.garbageCollector.
|
|
1766
|
+
this.garbageCollector.processMessages(contents, message.timestamp, local);
|
|
1715
1767
|
break;
|
|
1716
1768
|
case ContainerMessageType.ChunkedOp:
|
|
1717
|
-
// From observability POV, we should not
|
|
1769
|
+
// From observability POV, we should not expose the rest of the system (including "op" events on object) to these messages.
|
|
1718
1770
|
// Also resetReconnectCount() would be wrong - see comment that was there before this change was made.
|
|
1719
1771
|
assert(false, 0x93d /* should not even get here */);
|
|
1720
1772
|
case ContainerMessageType.Rejoin:
|
|
1721
1773
|
break;
|
|
1722
1774
|
case ContainerMessageType.DocumentSchemaChange:
|
|
1723
|
-
this.documentsSchemaController.
|
|
1775
|
+
this.documentsSchemaController.processDocumentSchemaMessages(contents, local, message.sequenceNumber);
|
|
1724
1776
|
break;
|
|
1725
1777
|
default: {
|
|
1726
1778
|
const error = getUnknownMessageTypeError(message.type, "validateAndProcessRuntimeMessage" /* codePath */, message);
|
|
@@ -1728,7 +1780,26 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1728
1780
|
throw error;
|
|
1729
1781
|
}
|
|
1730
1782
|
}
|
|
1731
|
-
|
|
1783
|
+
}
|
|
1784
|
+
processIdCompressorMessages(messageContents, savedOp) {
|
|
1785
|
+
for (const range of messageContents) {
|
|
1786
|
+
// Don't re-finalize the range if we're processing a "savedOp" in
|
|
1787
|
+
// stashed ops flow. The compressor is stashed with these ops already processed.
|
|
1788
|
+
// That said, in idCompressorMode === "delayed", we might not serialize ID compressor, and
|
|
1789
|
+
// thus we need to process all the ops.
|
|
1790
|
+
if (!(this.skipSavedCompressorOps && savedOp === true)) {
|
|
1791
|
+
// Some other client turned on the id compressor. If we have not turned it on,
|
|
1792
|
+
// put it in a pending queue and delay finalization.
|
|
1793
|
+
if (this._idCompressor === undefined) {
|
|
1794
|
+
assert(this.idCompressorMode !== undefined, 0x93c /* id compressor should be enabled */);
|
|
1795
|
+
this.pendingIdCompressorOps.push(range);
|
|
1796
|
+
}
|
|
1797
|
+
else {
|
|
1798
|
+
assert(this.pendingIdCompressorOps.length === 0, 0x979 /* there should be no pending ops! */);
|
|
1799
|
+
this._idCompressor.finalizeCreationRange(range);
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1732
1803
|
}
|
|
1733
1804
|
/**
|
|
1734
1805
|
* Emits the Signal event and update the perf signal data.
|
|
@@ -2304,7 +2375,17 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2304
2375
|
},
|
|
2305
2376
|
},
|
|
2306
2377
|
});
|
|
2307
|
-
assert
|
|
2378
|
+
// legacy: assert 0x3d1
|
|
2379
|
+
if (!this.outbox.isEmpty) {
|
|
2380
|
+
throw DataProcessingError.create("Can't trigger summary in the middle of a batch", "submitSummary", undefined, {
|
|
2381
|
+
summaryNumber,
|
|
2382
|
+
pendingMessages: this.pendingMessagesCount,
|
|
2383
|
+
outboxLength: this.outbox.messageCount,
|
|
2384
|
+
mainBatchLength: this.outbox.mainBatchMessageCount,
|
|
2385
|
+
blobAttachBatchLength: this.outbox.blobAttachBatchMessageCount,
|
|
2386
|
+
idAllocationBatchLength: this.outbox.idAllocationBatchMessageCount,
|
|
2387
|
+
});
|
|
2388
|
+
}
|
|
2308
2389
|
// If the container is dirty, i.e., there are pending unacked ops, the summary will not be eventual consistent
|
|
2309
2390
|
// and it may even be incorrect. So, wait for the container to be saved with a timeout. If the container is not
|
|
2310
2391
|
// saved within the timeout, check if it should be failed or can continue.
|