@fluid-experimental/tree 0.59.2001 → 0.59.3000
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/.eslintrc.js +2 -0
- package/.vscode/SharedTree.code-workspace +15 -0
- package/.vscode/settings.json +6 -0
- package/dist/ChangeCompression.js +9 -9
- package/dist/ChangeCompression.js.map +1 -1
- package/dist/ChangeTypes.d.ts +1 -6
- package/dist/ChangeTypes.d.ts.map +1 -1
- package/dist/ChangeTypes.js +5 -5
- package/dist/ChangeTypes.js.map +1 -1
- package/dist/Checkout.js +14 -14
- package/dist/Checkout.js.map +1 -1
- package/dist/Common.d.ts +21 -3
- package/dist/Common.d.ts.map +1 -1
- package/dist/Common.js +29 -4
- package/dist/Common.js.map +1 -1
- package/dist/EditLog.js +26 -25
- package/dist/EditLog.js.map +1 -1
- package/dist/EditUtilities.js +17 -17
- package/dist/EditUtilities.js.map +1 -1
- package/dist/Forest.js +31 -31
- package/dist/Forest.js.map +1 -1
- package/dist/HistoryEditFactory.js +9 -9
- package/dist/HistoryEditFactory.js.map +1 -1
- package/dist/IdConversion.js +9 -9
- package/dist/IdConversion.js.map +1 -1
- package/dist/Identifiers.d.ts +4 -0
- package/dist/Identifiers.d.ts.map +1 -1
- package/dist/Identifiers.js.map +1 -1
- package/dist/LogViewer.d.ts +1 -5
- package/dist/LogViewer.d.ts.map +1 -1
- package/dist/LogViewer.js +11 -19
- package/dist/LogViewer.js.map +1 -1
- package/dist/MergeHealth.js +2 -2
- package/dist/MergeHealth.js.map +1 -1
- package/dist/NodeIdUtilities.js +2 -2
- package/dist/NodeIdUtilities.js.map +1 -1
- package/dist/PayloadUtilities.js +1 -1
- package/dist/PayloadUtilities.js.map +1 -1
- package/dist/RevisionValueCache.d.ts +13 -10
- package/dist/RevisionValueCache.d.ts.map +1 -1
- package/dist/RevisionValueCache.js +14 -11
- package/dist/RevisionValueCache.js.map +1 -1
- package/dist/RevisionView.js +4 -4
- package/dist/RevisionView.js.map +1 -1
- package/dist/SerializationUtilities.js +4 -4
- package/dist/SerializationUtilities.js.map +1 -1
- package/dist/SharedTree.d.ts +93 -31
- package/dist/SharedTree.d.ts.map +1 -1
- package/dist/SharedTree.js +160 -131
- package/dist/SharedTree.js.map +1 -1
- package/dist/SharedTreeEncoder.d.ts +3 -3
- package/dist/SharedTreeEncoder.d.ts.map +1 -1
- package/dist/SharedTreeEncoder.js +36 -36
- package/dist/SharedTreeEncoder.js.map +1 -1
- package/dist/StringInterner.js +1 -1
- package/dist/StringInterner.js.map +1 -1
- package/dist/Summary.js +1 -1
- package/dist/Summary.js.map +1 -1
- package/dist/SummaryBackCompatibility.js +8 -8
- package/dist/SummaryBackCompatibility.js.map +1 -1
- package/dist/Transaction.js +1 -1
- package/dist/Transaction.js.map +1 -1
- package/dist/TransactionInternal.js +17 -17
- package/dist/TransactionInternal.js.map +1 -1
- package/dist/TreeCompressor.d.ts.map +1 -1
- package/dist/TreeCompressor.js +6 -8
- package/dist/TreeCompressor.js.map +1 -1
- package/dist/TreeNodeHandle.js +4 -4
- package/dist/TreeNodeHandle.js.map +1 -1
- package/dist/TreeView.js +7 -7
- package/dist/TreeView.js.map +1 -1
- package/dist/TreeViewUtilities.js +2 -2
- package/dist/TreeViewUtilities.js.map +1 -1
- package/dist/UndoRedoHandler.js +1 -1
- package/dist/UndoRedoHandler.js.map +1 -1
- package/dist/UuidUtilities.d.ts +30 -0
- package/dist/UuidUtilities.d.ts.map +1 -0
- package/dist/UuidUtilities.js +106 -0
- package/dist/UuidUtilities.js.map +1 -0
- package/dist/id-compressor/AppendOnlySortedMap.d.ts +52 -28
- package/dist/id-compressor/AppendOnlySortedMap.d.ts.map +1 -1
- package/dist/id-compressor/AppendOnlySortedMap.js +167 -90
- package/dist/id-compressor/AppendOnlySortedMap.js.map +1 -1
- package/dist/id-compressor/IdCompressor.d.ts +43 -42
- package/dist/id-compressor/IdCompressor.d.ts.map +1 -1
- package/dist/id-compressor/IdCompressor.js +179 -177
- package/dist/id-compressor/IdCompressor.js.map +1 -1
- package/dist/id-compressor/IdRange.js +1 -1
- package/dist/id-compressor/IdRange.js.map +1 -1
- package/dist/id-compressor/NumericUuid.d.ts +6 -14
- package/dist/id-compressor/NumericUuid.d.ts.map +1 -1
- package/dist/id-compressor/NumericUuid.js +15 -76
- package/dist/id-compressor/NumericUuid.js.map +1 -1
- package/dist/id-compressor/SessionIdNormalizer.d.ts +122 -0
- package/dist/id-compressor/SessionIdNormalizer.d.ts.map +1 -0
- package/dist/id-compressor/SessionIdNormalizer.js +418 -0
- package/dist/id-compressor/SessionIdNormalizer.js.map +1 -0
- package/dist/id-compressor/persisted-types/0.0.1.d.ts +6 -13
- package/dist/id-compressor/persisted-types/0.0.1.d.ts.map +1 -1
- package/dist/id-compressor/persisted-types/0.0.1.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/persisted-types/0.1.1.d.ts +1 -6
- package/dist/persisted-types/0.1.1.d.ts.map +1 -1
- package/dist/persisted-types/0.1.1.js +3 -3
- package/dist/persisted-types/0.1.1.js.map +1 -1
- package/lib/ChangeTypes.d.ts +1 -6
- package/lib/ChangeTypes.d.ts.map +1 -1
- package/lib/Checkout.js.map +1 -1
- package/lib/Common.d.ts +21 -3
- package/lib/Common.d.ts.map +1 -1
- package/lib/Common.js +25 -3
- package/lib/Common.js.map +1 -1
- package/lib/EditLog.js +2 -1
- package/lib/EditLog.js.map +1 -1
- package/lib/EditUtilities.js.map +1 -1
- package/lib/Forest.js.map +1 -1
- package/lib/HistoryEditFactory.js.map +1 -1
- package/lib/Identifiers.d.ts +4 -0
- package/lib/Identifiers.d.ts.map +1 -1
- package/lib/Identifiers.js.map +1 -1
- package/lib/LogViewer.d.ts +1 -5
- package/lib/LogViewer.d.ts.map +1 -1
- package/lib/LogViewer.js +5 -13
- package/lib/LogViewer.js.map +1 -1
- package/lib/MergeHealth.js.map +1 -1
- package/lib/NodeIdUtilities.js.map +1 -1
- package/lib/RevisionValueCache.d.ts +13 -10
- package/lib/RevisionValueCache.d.ts.map +1 -1
- package/lib/RevisionValueCache.js +10 -7
- package/lib/RevisionValueCache.js.map +1 -1
- package/lib/RevisionView.js.map +1 -1
- package/lib/SharedTree.d.ts +93 -31
- package/lib/SharedTree.d.ts.map +1 -1
- package/lib/SharedTree.js +107 -78
- package/lib/SharedTree.js.map +1 -1
- package/lib/SharedTreeEncoder.d.ts +3 -3
- package/lib/SharedTreeEncoder.d.ts.map +1 -1
- package/lib/SharedTreeEncoder.js +4 -4
- package/lib/SharedTreeEncoder.js.map +1 -1
- package/lib/StringInterner.js.map +1 -1
- package/lib/Summary.js.map +1 -1
- package/lib/TreeCompressor.d.ts.map +1 -1
- package/lib/TreeCompressor.js +1 -3
- package/lib/TreeCompressor.js.map +1 -1
- package/lib/TreeNodeHandle.js.map +1 -1
- package/lib/TreeView.js.map +1 -1
- package/lib/TreeViewUtilities.js.map +1 -1
- package/lib/UuidUtilities.d.ts +30 -0
- package/lib/UuidUtilities.d.ts.map +1 -0
- package/lib/UuidUtilities.js +98 -0
- package/lib/UuidUtilities.js.map +1 -0
- package/lib/id-compressor/AppendOnlySortedMap.d.ts +52 -28
- package/lib/id-compressor/AppendOnlySortedMap.d.ts.map +1 -1
- package/lib/id-compressor/AppendOnlySortedMap.js +165 -88
- package/lib/id-compressor/AppendOnlySortedMap.js.map +1 -1
- package/lib/id-compressor/IdCompressor.d.ts +43 -42
- package/lib/id-compressor/IdCompressor.d.ts.map +1 -1
- package/lib/id-compressor/IdCompressor.js +97 -95
- package/lib/id-compressor/IdCompressor.js.map +1 -1
- package/lib/id-compressor/NumericUuid.d.ts +6 -14
- package/lib/id-compressor/NumericUuid.d.ts.map +1 -1
- package/lib/id-compressor/NumericUuid.js +11 -70
- package/lib/id-compressor/NumericUuid.js.map +1 -1
- package/lib/id-compressor/SessionIdNormalizer.d.ts +122 -0
- package/lib/id-compressor/SessionIdNormalizer.d.ts.map +1 -0
- package/lib/id-compressor/SessionIdNormalizer.js +414 -0
- package/lib/id-compressor/SessionIdNormalizer.js.map +1 -0
- package/lib/id-compressor/persisted-types/0.0.1.d.ts +6 -13
- package/lib/id-compressor/persisted-types/0.0.1.d.ts.map +1 -1
- package/lib/id-compressor/persisted-types/0.0.1.js.map +1 -1
- package/lib/index.d.ts +2 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/persisted-types/0.1.1.d.ts +1 -6
- package/lib/persisted-types/0.1.1.d.ts.map +1 -1
- package/lib/persisted-types/0.1.1.js.map +1 -1
- package/lib/test/AppendOnlySortedMap.perf.tests.d.ts +6 -0
- package/lib/test/AppendOnlySortedMap.perf.tests.d.ts.map +1 -0
- package/lib/test/AppendOnlySortedMap.perf.tests.js +49 -0
- package/lib/test/AppendOnlySortedMap.perf.tests.js.map +1 -0
- package/lib/test/AppendOnlySortedMap.tests.js +56 -14
- package/lib/test/AppendOnlySortedMap.tests.js.map +1 -1
- package/lib/test/Checkout.tests.js +2 -2
- package/lib/test/Checkout.tests.js.map +1 -1
- package/lib/test/Forest.tests.js.map +1 -1
- package/lib/test/IdCompressor.perf.tests.js +8 -2
- package/lib/test/IdCompressor.perf.tests.js.map +1 -1
- package/lib/test/IdCompressor.tests.js +75 -24
- package/lib/test/IdCompressor.tests.js.map +1 -1
- package/lib/test/LogViewer.tests.js +3 -5
- package/lib/test/LogViewer.tests.js.map +1 -1
- package/lib/test/NumericUuid.perf.tests.js +4 -4
- package/lib/test/NumericUuid.perf.tests.js.map +1 -1
- package/lib/test/NumericUuid.tests.js +5 -4
- package/lib/test/NumericUuid.tests.js.map +1 -1
- package/lib/test/RevisionValueCache.tests.js.map +1 -1
- package/lib/test/RevisionView.tests.js.map +1 -1
- package/lib/test/SessionIdNormalizer.tests.d.ts +6 -0
- package/lib/test/SessionIdNormalizer.tests.d.ts.map +1 -0
- package/lib/test/SessionIdNormalizer.tests.js +299 -0
- package/lib/test/SessionIdNormalizer.tests.js.map +1 -0
- package/lib/test/Summary.tests.js +1 -1
- package/lib/test/Summary.tests.js.map +1 -1
- package/lib/test/TreeCompression.tests.js +1 -1
- package/lib/test/TreeCompression.tests.js.map +1 -1
- package/lib/test/Virtualization.tests.js +1 -1
- package/lib/test/Virtualization.tests.js.map +1 -1
- package/lib/test/fuzz/Generators.d.ts +3 -14
- package/lib/test/fuzz/Generators.d.ts.map +1 -1
- package/lib/test/fuzz/Generators.js +60 -151
- package/lib/test/fuzz/Generators.js.map +1 -1
- package/lib/test/fuzz/SharedTreeFuzzTests.d.ts +10 -7
- package/lib/test/fuzz/SharedTreeFuzzTests.d.ts.map +1 -1
- package/lib/test/fuzz/SharedTreeFuzzTests.js +94 -104
- package/lib/test/fuzz/SharedTreeFuzzTests.js.map +1 -1
- package/lib/test/fuzz/Types.d.ts +2 -9
- package/lib/test/fuzz/Types.d.ts.map +1 -1
- package/lib/test/fuzz/Types.js +1 -1
- package/lib/test/fuzz/Types.js.map +1 -1
- package/lib/test/utilities/IdCompressorTestUtilities.d.ts +57 -11
- package/lib/test/utilities/IdCompressorTestUtilities.d.ts.map +1 -1
- package/lib/test/utilities/IdCompressorTestUtilities.js +112 -98
- package/lib/test/utilities/IdCompressorTestUtilities.js.map +1 -1
- package/lib/test/utilities/PendingLocalStateTests.d.ts.map +1 -1
- package/lib/test/utilities/PendingLocalStateTests.js +2 -1
- package/lib/test/utilities/PendingLocalStateTests.js.map +1 -1
- package/lib/test/utilities/SharedTreeTests.d.ts.map +1 -1
- package/lib/test/utilities/SharedTreeTests.js +30 -1
- package/lib/test/utilities/SharedTreeTests.js.map +1 -1
- package/lib/test/utilities/SharedTreeVersioningTests.d.ts.map +1 -1
- package/lib/test/utilities/SharedTreeVersioningTests.js +20 -0
- package/lib/test/utilities/SharedTreeVersioningTests.js.map +1 -1
- package/lib/test/utilities/SummaryLoadPerfTests.d.ts.map +1 -1
- package/lib/test/utilities/SummaryLoadPerfTests.js +6 -3
- package/lib/test/utilities/SummaryLoadPerfTests.js.map +1 -1
- package/lib/test/utilities/TestNode.js.map +1 -1
- package/lib/test/utilities/TestUtilities.d.ts +9 -1
- package/lib/test/utilities/TestUtilities.d.ts.map +1 -1
- package/lib/test/utilities/TestUtilities.js +27 -13
- package/lib/test/utilities/TestUtilities.js.map +1 -1
- package/package.json +19 -17
- package/src/Common.ts +42 -4
- package/src/EditLog.ts +1 -1
- package/src/Identifiers.ts +5 -0
- package/src/LogViewer.ts +4 -20
- package/src/RevisionValueCache.ts +11 -8
- package/src/SharedTree.ts +222 -75
- package/src/SharedTreeEncoder.ts +17 -11
- package/src/TreeCompressor.ts +2 -4
- package/src/UuidUtilities.ts +123 -0
- package/src/id-compressor/AppendOnlySortedMap.ts +183 -94
- package/src/id-compressor/IdCompressor.ts +144 -132
- package/src/id-compressor/NumericUuid.ts +11 -80
- package/src/id-compressor/SessionIdNormalizer.ts +497 -0
- package/src/id-compressor/persisted-types/0.0.1.ts +12 -15
- package/src/index.ts +5 -0
package/lib/MergeHealth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MergeHealth.js","sourceRoot":"","sources":["../src/MergeHealth.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from '@fluidframework/common-definitions';\nimport { assertNotUndefined, fail } from './Common';\nimport { PlaceValidationResult, RangeValidationResultKind } from './EditUtilities';\nimport { SharedTreeEvent } from './EventTypes';\nimport { EditStatus } from './persisted-types';\nimport { SequencedEditAppliedEventArguments, SharedTree } from './SharedTree';\nimport { TransactionInternal } from './TransactionInternal';\n\n/**\n * Logs generic telemetry for failed sequenced edits.\n * Only failing edits that were originally made locally are logged.\n * @param tree - The tree for which to log the telemetry.\n */\nexport function useFailedSequencedEditTelemetry(tree: SharedTree): { disable: () => void } {\n\tfunction onEdit({ wasLocal, logger, outcome }: SequencedEditAppliedEventArguments): void {\n\t\tif (wasLocal && outcome.status !== EditStatus.Applied) {\n\t\t\tlogger.send({\n\t\t\t\tcategory: 'generic',\n\t\t\t\teventName:\n\t\t\t\t\toutcome.status === EditStatus.Malformed ? 'MalformedSharedTreeEdit' : 'InvalidSharedTreeEdit',\n\t\t\t});\n\t\t}\n\t}\n\ttree.on(SharedTreeEvent.SequencedEditApplied, onEdit);\n\treturn {\n\t\tdisable: () => {\n\t\t\ttree.off(SharedTreeEvent.SequencedEditApplied, onEdit);\n\t\t},\n\t};\n}\n\n/**\n * Statistics about the health of collaborative edit merging when using {@link SharedTree}.\n * All of those numbers constitute a tally since the last heartbeat was logged or cleared.\n */\nexport interface MergeHealthStats {\n\t/** Number of sequenced edits applied (failed or not). */\n\teditCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply.\n\t * Such cases are also counted under {@link MergeHealthStats.editCount}.\n\t *\n\t * If this number is greater than the sum of:\n\t * * {@link MergeHealthStats.badPlaceCount}\n\t * * {@link MergeHealthStats.badRangeCount}\n\t * * {@link MergeHealthStats.constraintViolationCount}\n\t * * {@link MergeHealthStats.idAlreadyInUseCount}\n\t * * {@link MergeHealthStats.unknownIdCount}\n\t * * {@link MergeHealthStats.malformedEditCount}\n\t *\n\t * then some failure scenarios are not being tracked adequately.\n\t */\n\tfailedEditCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to a bad place.\n\t * Such cases are also counted under {@link MergeHealthStats.failedEditCount}.\n\t *\n\t * If this number is greater than the sum of:\n\t * * {@link MergeHealthStats.deletedAncestorBadPlaceCount}\n\t * * {@link MergeHealthStats.deletedSiblingBadPlaceCount}\n\t *\n\t * then some failure scenarios are not being tracked adequately.\n\t */\n\tbadPlaceCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to a bad range.\n\t * Such cases are also counted under {@link MergeHealthStats.failedEditCount}.\n\t *\n\t * If this number is greater than the sum of:\n\t * * {@link MergeHealthStats.deletedAncestorBadRangeCount}\n\t * * {@link MergeHealthStats.deletedSiblingBadRangeCount}\n\t * * {@link MergeHealthStats.updatedRangeInvertedCount}\n\t * * {@link MergeHealthStats.updatedRangeHasPlacesInDifferentTraitsCount}\n\t * * {@link MergeHealthStats.updatedRangeBadPlaceCount}\n\t * * {@link MergeHealthStats.updatedRangeNeverValidPlaceCount}\n\t *\n\t * then some failure scenarios are not being tracked adequately.\n\t */\n\tbadRangeCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to a place whose ancestors had been concurrently deleted.\n\t * Such cases are also counted under {@link MergeHealthStats.badPlaceCount}.\n\t */\n\tdeletedAncestorBadPlaceCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to a range whose ancestors had been concurrently deleted.\n\t * Such cases are also counted under {@link MergeHealthStats.badRangeCount}.\n\t */\n\tdeletedAncestorBadRangeCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to a place whose sibling (but not its parent) had been concurrently deleted.\n\t * Such cases are also counted under {@link MergeHealthStats.badPlaceCount}.\n\t */\n\tdeletedSiblingBadPlaceCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to a range whose delimiting sibling(s) (but not its parent) had been concurrently\n\t * deleted.\n\t * Such cases are also counted under {@link MergeHealthStats.badRangeCount}.\n\t */\n\tdeletedSiblingBadRangeCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to a range whose places were resolvable but inverted (i.e., end before start).\n\t * Such cases are also counted under {@link MergeHealthStats.badRangeCount}.\n\t */\n\tupdatedRangeInvertedCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to a range whose places were resolvable but in different traits.\n\t * Such cases are also counted under {@link MergeHealthStats.badRangeCount}.\n\t */\n\tupdatedRangeHasPlacesInDifferentTraitsCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to a range whose places were resolvable but bad.\n\t * This should not happen because place resolution is expected to either return a valid place or fail.\n\t * Such cases are also counted under {@link MergeHealthStats.badRangeCount}.\n\t */\n\tupdatedRangeBadPlaceCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to a range whose places were not resolvable due to not being valid for any state.\n\t * Such cases are also counted under {@link MergeHealthStats.badRangeCount}.\n\t */\n\tupdatedRangeNeverValidPlaceCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to a constraint violation.\n\t * Such cases are also counted under {@link MergeHealthStats.failedEditCount}.\n\t *\n\t * If this number is greater than the sum of:\n\t * * {@link MergeHealthStats.rangeConstraintViolationCount}\n\t * * {@link MergeHealthStats.lengthConstraintViolationCount}\n\t * * {@link MergeHealthStats.parentConstraintViolationCount}\n\t * * {@link MergeHealthStats.labelConstraintViolationCount}\n\t *\n\t * then some failure scenarios are not being tracked adequately.\n\t */\n\tconstraintViolationCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to a constrained range becoming invalid or malformed.\n\t * Such cases are also counted under {@link MergeHealthStats.constraintViolationCount}.\n\t */\n\trangeConstraintViolationCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to a constrained range having a different length.\n\t * Such cases are also counted under {@link MergeHealthStats.constraintViolationCount}.\n\t */\n\tlengthConstraintViolationCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to a constrained range being under a different parent.\n\t * Such cases are also counted under {@link MergeHealthStats.constraintViolationCount}.\n\t */\n\tparentConstraintViolationCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to a constrained range being under a different label.\n\t * Such cases are also counted under {@link MergeHealthStats.constraintViolationCount}.\n\t */\n\tlabelConstraintViolationCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to an ID collision.\n\t * Such cases are also counted under {@link MergeHealthStats.failedEditCount}.\n\t */\n\tidAlreadyInUseCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to an ID being unknown.\n\t * Such cases are also counted under {@link MergeHealthStats.failedEditCount}.\n\t */\n\tunknownIdCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to an edit becoming malformed.\n\t * This should theoretically never happen.\n\t * Such cases are also counted under {@link MergeHealthStats.failedEditCount}.\n\t */\n\tmalformedEditCount: number;\n\n\t/**\n\t * The counts of occurrences for a given path length. `pathLengths[1] === 2` means two occurrences of length one.\n\t */\n\tpathLengths: number[];\n\n\t/** The highest number previous attempts on a sequenced edit. */\n\tmaxAttemptCount: number;\n}\n\n/**\n * Aggregates and logs telemetry about the success of concurrent edits.\n */\nexport class SharedTreeMergeHealthTelemetryHeartbeat {\n\tprivate heartbeatTimerId = 0;\n\tprivate readonly treeData = new Map<SharedTree, { tally: MergeHealthStats; logger?: ITelemetryLogger }>();\n\n\t/**\n\t * Adds a tree to the set of tree to log merge health telemetry for.\n\t * Noop if such a tree was already in the set.\n\t * @param tree - The tree to log merge health telemetry for.\n\t */\n\tpublic attachTree(tree: SharedTree) {\n\t\tif (this.treeData.has(tree) === false) {\n\t\t\tthis.resetTreeData(tree);\n\t\t\ttree.on(SharedTreeEvent.SequencedEditApplied, this.sequencedEditHandler);\n\t\t}\n\t}\n\n\t/**\n\t * Removes a tree from the set of tree to log merge health telemetry for.\n\t * Noop if such a tree was never in the set.\n\t * @param tree - The tree to stop logging merge health telemetry for.\n\t */\n\tpublic detachTree(tree: SharedTree) {\n\t\tif (this.treeData.has(tree)) {\n\t\t\ttree.off(SharedTreeEvent.SequencedEditApplied, this.sequencedEditHandler);\n\t\t\tthis.treeData.delete(tree);\n\t\t}\n\t}\n\n\t/**\n\t * Exposes the aggregated statistics about merge health for the given tree.\n\t * @param tree - The tree to get stats for.\n\t * @returns Aggregated statistics about merge health for the given tree.\n\t */\n\tpublic getStats(tree: SharedTree): MergeHealthStats {\n\t\treturn assertNotUndefined(this.treeData.get(tree), 'No such tree was attached to the logger').tally;\n\t}\n\n\t/**\n\t * Removes all trees from the set of tree to log merge health telemetry for.\n\t */\n\tpublic detachAllTrees() {\n\t\tfor (const tree of this.treeData.keys()) {\n\t\t\tthis.detachTree(tree);\n\t\t}\n\t}\n\n\t/**\n\t * Resets the aggregated merge health data for the given tree.\n\t * @param tree - The tree to reset the merge health data for.\n\t */\n\tpublic resetTreeData(tree: SharedTree): void {\n\t\tthis.treeData.set(tree, {\n\t\t\ttally: {\n\t\t\t\tmaxAttemptCount: 0,\n\t\t\t\tpathLengths: [],\n\t\t\t\teditCount: 0,\n\t\t\t\tfailedEditCount: 0,\n\t\t\t\tbadPlaceCount: 0,\n\t\t\t\tbadRangeCount: 0,\n\n\t\t\t\tdeletedAncestorBadPlaceCount: 0,\n\t\t\t\tdeletedAncestorBadRangeCount: 0,\n\n\t\t\t\tdeletedSiblingBadPlaceCount: 0,\n\t\t\t\tdeletedSiblingBadRangeCount: 0,\n\t\t\t\tupdatedRangeInvertedCount: 0,\n\t\t\t\tupdatedRangeHasPlacesInDifferentTraitsCount: 0,\n\t\t\t\tupdatedRangeBadPlaceCount: 0,\n\t\t\t\tupdatedRangeNeverValidPlaceCount: 0,\n\n\t\t\t\tconstraintViolationCount: 0,\n\t\t\t\trangeConstraintViolationCount: 0,\n\t\t\t\tlengthConstraintViolationCount: 0,\n\t\t\t\tparentConstraintViolationCount: 0,\n\t\t\t\tlabelConstraintViolationCount: 0,\n\n\t\t\t\tidAlreadyInUseCount: 0,\n\t\t\t\tunknownIdCount: 0,\n\t\t\t\tmalformedEditCount: 0,\n\t\t\t},\n\t\t});\n\t}\n\n\t/**\n\t * Enables the regular telemetry logging of merge health data.\n\t * The first message will be sent after `interval` milliseconds. See {@link SharedTreeMergeHealthTelemetryHeartbeat.flushHeartbeat} for\n\t * immediate logging.\n\t * @param interval - The amount of time in milliseconds between log messages.\n\t */\n\tpublic startHeartbeat(interval: number = 60000): void {\n\t\tif (this.heartbeatTimerId !== 0) {\n\t\t\tthis.stopHeartbeat();\n\t\t}\n\t\tthis.heartbeatTimerId = window.setInterval(this.logHeartbeat, interval);\n\t}\n\n\t/**\n\t * Disables the regular telemetry logging of merge health data.\n\t */\n\tpublic stopHeartbeat(): void {\n\t\twindow.clearInterval(this.heartbeatTimerId);\n\t\tthis.heartbeatTimerId = 0;\n\t}\n\n\t/**\n\t * Sends all collected merge health data and resets the aggregated state.\n\t */\n\tpublic flushHeartbeat(): void {\n\t\tthis.logHeartbeat();\n\t\tthis.clearData();\n\t}\n\n\t/**\n\t * Resets all aggregated state.\n\t */\n\tpublic clearData(): void {\n\t\tfor (const tree of this.treeData.keys()) {\n\t\t\tthis.resetTreeData(tree);\n\t\t}\n\t}\n\n\t/**\n\t * Receives SequencedEditApplied events from trees.\n\t */\n\tprivate readonly sequencedEditHandler = (params: SequencedEditAppliedEventArguments) => {\n\t\tconst { edit, tree, wasLocal, logger, outcome, reconciliationPath } = params;\n\t\tif (wasLocal) {\n\t\t\tconst tallyAndLogger = this.treeData.get(tree) ?? fail('Should only receive events for registered trees');\n\t\t\ttallyAndLogger.logger = logger;\n\t\t\tconst tally = tallyAndLogger.tally;\n\t\t\ttally.editCount += 1;\n\t\t\ttally.pathLengths[reconciliationPath.length] = (tally.pathLengths[reconciliationPath.length] ?? 0) + 1;\n\t\t\tif (edit.pastAttemptCount !== undefined && edit.pastAttemptCount > tally.maxAttemptCount) {\n\t\t\t\ttally.maxAttemptCount = edit.pastAttemptCount;\n\t\t\t}\n\t\t\tif (outcome.status !== EditStatus.Applied) {\n\t\t\t\ttally.failedEditCount += 1;\n\t\t\t\tswitch (outcome.failure.kind) {\n\t\t\t\t\tcase TransactionInternal.FailureKind.BadPlace: {\n\t\t\t\t\t\ttally.badPlaceCount += 1;\n\t\t\t\t\t\tif (outcome.failure.placeFailure === PlaceValidationResult.MissingSibling) {\n\t\t\t\t\t\t\ttally.deletedSiblingBadPlaceCount += 1;\n\t\t\t\t\t\t} else if (outcome.failure.placeFailure === PlaceValidationResult.MissingParent) {\n\t\t\t\t\t\t\ttally.deletedAncestorBadPlaceCount += 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase TransactionInternal.FailureKind.BadRange: {\n\t\t\t\t\t\ttally.badRangeCount += 1;\n\t\t\t\t\t\tswitch (outcome.failure.rangeFailure) {\n\t\t\t\t\t\t\tcase RangeValidationResultKind.Inverted:\n\t\t\t\t\t\t\t\ttally.updatedRangeInvertedCount += 1;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase RangeValidationResultKind.PlacesInDifferentTraits:\n\t\t\t\t\t\t\t\ttally.updatedRangeHasPlacesInDifferentTraitsCount += 1;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase RangeValidationResultKind.BadPlace:\n\t\t\t\t\t\t\t\ttally.updatedRangeBadPlaceCount += 1;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase TransactionInternal.FailureKind.ConstraintViolation: {\n\t\t\t\t\t\ttally.constraintViolationCount += 1;\n\t\t\t\t\t\tswitch (outcome.failure.violation.kind) {\n\t\t\t\t\t\t\tcase TransactionInternal.ConstraintViolationKind.BadRange: {\n\t\t\t\t\t\t\t\ttally.rangeConstraintViolationCount += 1;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcase TransactionInternal.ConstraintViolationKind.BadLength: {\n\t\t\t\t\t\t\t\ttally.lengthConstraintViolationCount += 1;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcase TransactionInternal.ConstraintViolationKind.BadParent: {\n\t\t\t\t\t\t\t\ttally.parentConstraintViolationCount += 1;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcase TransactionInternal.ConstraintViolationKind.BadLabel: {\n\t\t\t\t\t\t\t\ttally.labelConstraintViolationCount += 1;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tdefault: {\n\t\t\t\t\t\t\t\t// If this doesn't type-check, the above switch statement needs to be extended to handle a new case.\n\t\t\t\t\t\t\t\tconst _: never = outcome.failure.violation;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase TransactionInternal.FailureKind.IdAlreadyInUse: {\n\t\t\t\t\t\ttally.idAlreadyInUseCount += 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase TransactionInternal.FailureKind.UnknownId: {\n\t\t\t\t\t\ttally.unknownIdCount += 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase TransactionInternal.FailureKind.DetachedSequenceIdAlreadyInUse:\n\t\t\t\t\tcase TransactionInternal.FailureKind.DetachedSequenceNotFound:\n\t\t\t\t\tcase TransactionInternal.FailureKind.DuplicateIdInBuild:\n\t\t\t\t\tcase TransactionInternal.FailureKind.UnusedDetachedSequence: {\n\t\t\t\t\t\ttally.malformedEditCount += 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\t// If this doesn't type-check, the above switch statement needs to be extended to handle a new case.\n\t\t\t\t\t\tconst _: never = outcome.failure;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\t/**\n\t * Logs the accumulated merge health data to each tree's designated logger.\n\t */\n\tprivate readonly logHeartbeat = () => {\n\t\tfor (const [tree, { tally, logger }] of this.treeData) {\n\t\t\tif (logger && tally.editCount > 0) {\n\t\t\t\t// Note: all this data is for sequenced edits that were originally produced by the local client.\n\t\t\t\tlogger.send({\n\t\t\t\t\tcategory: 'Heartbeat',\n\t\t\t\t\teventName: 'EditMergeHealth',\n\t\t\t\t\t...tally,\n\t\t\t\t\t// The counts of occurrences for a given path length.\n\t\t\t\t\t// '1:2' means two occurrences of length one.\n\t\t\t\t\t// Overwrites `tally.pathLengths` which is incompatible with ITelemetryBaseEvent.\n\t\t\t\t\tpathLengths: pathLengthsCounts(tally.pathLengths),\n\t\t\t\t});\n\t\t\t\tthis.resetTreeData(tree);\n\t\t\t}\n\t\t}\n\t};\n}\n\nfunction pathLengthsCounts(lengths: readonly number[]): string {\n\treturn Object.entries(lengths)\n\t\t.map(([length, count]) => `${length}:${count}`)\n\t\t.join(',');\n}\n"]}
|
|
1
|
+
{"version":3,"file":"MergeHealth.js","sourceRoot":"","sources":["../src/MergeHealth.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from '@fluidframework/common-definitions';\nimport { assertNotUndefined, fail } from './Common';\nimport { PlaceValidationResult, RangeValidationResultKind } from './EditUtilities';\nimport { SharedTreeEvent } from './EventTypes';\nimport { EditStatus } from './persisted-types';\nimport { SequencedEditAppliedEventArguments, SharedTree } from './SharedTree';\nimport { TransactionInternal } from './TransactionInternal';\n\n/**\n * Logs generic telemetry for failed sequenced edits.\n * Only failing edits that were originally made locally are logged.\n * @param tree - The tree for which to log the telemetry.\n */\nexport function useFailedSequencedEditTelemetry(tree: SharedTree): { disable: () => void } {\n\tfunction onEdit({ wasLocal, logger, outcome }: SequencedEditAppliedEventArguments): void {\n\t\tif (wasLocal && outcome.status !== EditStatus.Applied) {\n\t\t\tlogger.send({\n\t\t\t\tcategory: 'generic',\n\t\t\t\teventName:\n\t\t\t\t\toutcome.status === EditStatus.Malformed ? 'MalformedSharedTreeEdit' : 'InvalidSharedTreeEdit',\n\t\t\t});\n\t\t}\n\t}\n\ttree.on(SharedTreeEvent.SequencedEditApplied, onEdit);\n\treturn {\n\t\tdisable: () => {\n\t\t\ttree.off(SharedTreeEvent.SequencedEditApplied, onEdit);\n\t\t},\n\t};\n}\n\n/**\n * Statistics about the health of collaborative edit merging when using {@link SharedTree}.\n * All of those numbers constitute a tally since the last heartbeat was logged or cleared.\n */\nexport interface MergeHealthStats {\n\t/** Number of sequenced edits applied (failed or not). */\n\teditCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply.\n\t * Such cases are also counted under {@link MergeHealthStats.editCount}.\n\t *\n\t * If this number is greater than the sum of:\n\t * * {@link MergeHealthStats.badPlaceCount}\n\t * * {@link MergeHealthStats.badRangeCount}\n\t * * {@link MergeHealthStats.constraintViolationCount}\n\t * * {@link MergeHealthStats.idAlreadyInUseCount}\n\t * * {@link MergeHealthStats.unknownIdCount}\n\t * * {@link MergeHealthStats.malformedEditCount}\n\t *\n\t * then some failure scenarios are not being tracked adequately.\n\t */\n\tfailedEditCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to a bad place.\n\t * Such cases are also counted under {@link MergeHealthStats.failedEditCount}.\n\t *\n\t * If this number is greater than the sum of:\n\t * * {@link MergeHealthStats.deletedAncestorBadPlaceCount}\n\t * * {@link MergeHealthStats.deletedSiblingBadPlaceCount}\n\t *\n\t * then some failure scenarios are not being tracked adequately.\n\t */\n\tbadPlaceCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to a bad range.\n\t * Such cases are also counted under {@link MergeHealthStats.failedEditCount}.\n\t *\n\t * If this number is greater than the sum of:\n\t * * {@link MergeHealthStats.deletedAncestorBadRangeCount}\n\t * * {@link MergeHealthStats.deletedSiblingBadRangeCount}\n\t * * {@link MergeHealthStats.updatedRangeInvertedCount}\n\t * * {@link MergeHealthStats.updatedRangeHasPlacesInDifferentTraitsCount}\n\t * * {@link MergeHealthStats.updatedRangeBadPlaceCount}\n\t * * {@link MergeHealthStats.updatedRangeNeverValidPlaceCount}\n\t *\n\t * then some failure scenarios are not being tracked adequately.\n\t */\n\tbadRangeCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to a place whose ancestors had been concurrently deleted.\n\t * Such cases are also counted under {@link MergeHealthStats.badPlaceCount}.\n\t */\n\tdeletedAncestorBadPlaceCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to a range whose ancestors had been concurrently deleted.\n\t * Such cases are also counted under {@link MergeHealthStats.badRangeCount}.\n\t */\n\tdeletedAncestorBadRangeCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to a place whose sibling (but not its parent) had been concurrently deleted.\n\t * Such cases are also counted under {@link MergeHealthStats.badPlaceCount}.\n\t */\n\tdeletedSiblingBadPlaceCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to a range whose delimiting sibling(s) (but not its parent) had been concurrently\n\t * deleted.\n\t * Such cases are also counted under {@link MergeHealthStats.badRangeCount}.\n\t */\n\tdeletedSiblingBadRangeCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to a range whose places were resolvable but inverted (i.e., end before start).\n\t * Such cases are also counted under {@link MergeHealthStats.badRangeCount}.\n\t */\n\tupdatedRangeInvertedCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to a range whose places were resolvable but in different traits.\n\t * Such cases are also counted under {@link MergeHealthStats.badRangeCount}.\n\t */\n\tupdatedRangeHasPlacesInDifferentTraitsCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to a range whose places were resolvable but bad.\n\t * This should not happen because place resolution is expected to either return a valid place or fail.\n\t * Such cases are also counted under {@link MergeHealthStats.badRangeCount}.\n\t */\n\tupdatedRangeBadPlaceCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to a range whose places were not resolvable due to not being valid for any state.\n\t * Such cases are also counted under {@link MergeHealthStats.badRangeCount}.\n\t */\n\tupdatedRangeNeverValidPlaceCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to a constraint violation.\n\t * Such cases are also counted under {@link MergeHealthStats.failedEditCount}.\n\t *\n\t * If this number is greater than the sum of:\n\t * * {@link MergeHealthStats.rangeConstraintViolationCount}\n\t * * {@link MergeHealthStats.lengthConstraintViolationCount}\n\t * * {@link MergeHealthStats.parentConstraintViolationCount}\n\t * * {@link MergeHealthStats.labelConstraintViolationCount}\n\t *\n\t * then some failure scenarios are not being tracked adequately.\n\t */\n\tconstraintViolationCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to a constrained range becoming invalid or malformed.\n\t * Such cases are also counted under {@link MergeHealthStats.constraintViolationCount}.\n\t */\n\trangeConstraintViolationCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to a constrained range having a different length.\n\t * Such cases are also counted under {@link MergeHealthStats.constraintViolationCount}.\n\t */\n\tlengthConstraintViolationCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to a constrained range being under a different parent.\n\t * Such cases are also counted under {@link MergeHealthStats.constraintViolationCount}.\n\t */\n\tparentConstraintViolationCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to a constrained range being under a different label.\n\t * Such cases are also counted under {@link MergeHealthStats.constraintViolationCount}.\n\t */\n\tlabelConstraintViolationCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to an ID collision.\n\t * Such cases are also counted under {@link MergeHealthStats.failedEditCount}.\n\t */\n\tidAlreadyInUseCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to an ID being unknown.\n\t * Such cases are also counted under {@link MergeHealthStats.failedEditCount}.\n\t */\n\tunknownIdCount: number;\n\n\t/**\n\t * Number of sequenced edits that failed to apply due to an edit becoming malformed.\n\t * This should theoretically never happen.\n\t * Such cases are also counted under {@link MergeHealthStats.failedEditCount}.\n\t */\n\tmalformedEditCount: number;\n\n\t/**\n\t * The counts of occurrences for a given path length. `pathLengths[1] === 2` means two occurrences of length one.\n\t */\n\tpathLengths: number[];\n\n\t/** The highest number previous attempts on a sequenced edit. */\n\tmaxAttemptCount: number;\n}\n\n/**\n * Aggregates and logs telemetry about the success of concurrent edits.\n */\nexport class SharedTreeMergeHealthTelemetryHeartbeat {\n\tprivate heartbeatTimerId = 0;\n\tprivate readonly treeData = new Map<SharedTree, { tally: MergeHealthStats; logger?: ITelemetryLogger }>();\n\n\t/**\n\t * Adds a tree to the set of tree to log merge health telemetry for.\n\t * Noop if such a tree was already in the set.\n\t * @param tree - The tree to log merge health telemetry for.\n\t */\n\tpublic attachTree(tree: SharedTree) {\n\t\tif (this.treeData.has(tree) === false) {\n\t\t\tthis.resetTreeData(tree);\n\t\t\ttree.on(SharedTreeEvent.SequencedEditApplied, this.sequencedEditHandler);\n\t\t}\n\t}\n\n\t/**\n\t * Removes a tree from the set of tree to log merge health telemetry for.\n\t * Noop if such a tree was never in the set.\n\t * @param tree - The tree to stop logging merge health telemetry for.\n\t */\n\tpublic detachTree(tree: SharedTree) {\n\t\tif (this.treeData.has(tree)) {\n\t\t\ttree.off(SharedTreeEvent.SequencedEditApplied, this.sequencedEditHandler);\n\t\t\tthis.treeData.delete(tree);\n\t\t}\n\t}\n\n\t/**\n\t * Exposes the aggregated statistics about merge health for the given tree.\n\t * @param tree - The tree to get stats for.\n\t * @returns Aggregated statistics about merge health for the given tree.\n\t */\n\tpublic getStats(tree: SharedTree): MergeHealthStats {\n\t\treturn assertNotUndefined(this.treeData.get(tree), 'No such tree was attached to the logger').tally;\n\t}\n\n\t/**\n\t * Removes all trees from the set of tree to log merge health telemetry for.\n\t */\n\tpublic detachAllTrees() {\n\t\tfor (const tree of this.treeData.keys()) {\n\t\t\tthis.detachTree(tree);\n\t\t}\n\t}\n\n\t/**\n\t * Resets the aggregated merge health data for the given tree.\n\t * @param tree - The tree to reset the merge health data for.\n\t */\n\tpublic resetTreeData(tree: SharedTree): void {\n\t\tthis.treeData.set(tree, {\n\t\t\ttally: {\n\t\t\t\tmaxAttemptCount: 0,\n\t\t\t\tpathLengths: [],\n\t\t\t\teditCount: 0,\n\t\t\t\tfailedEditCount: 0,\n\t\t\t\tbadPlaceCount: 0,\n\t\t\t\tbadRangeCount: 0,\n\n\t\t\t\tdeletedAncestorBadPlaceCount: 0,\n\t\t\t\tdeletedAncestorBadRangeCount: 0,\n\n\t\t\t\tdeletedSiblingBadPlaceCount: 0,\n\t\t\t\tdeletedSiblingBadRangeCount: 0,\n\t\t\t\tupdatedRangeInvertedCount: 0,\n\t\t\t\tupdatedRangeHasPlacesInDifferentTraitsCount: 0,\n\t\t\t\tupdatedRangeBadPlaceCount: 0,\n\t\t\t\tupdatedRangeNeverValidPlaceCount: 0,\n\n\t\t\t\tconstraintViolationCount: 0,\n\t\t\t\trangeConstraintViolationCount: 0,\n\t\t\t\tlengthConstraintViolationCount: 0,\n\t\t\t\tparentConstraintViolationCount: 0,\n\t\t\t\tlabelConstraintViolationCount: 0,\n\n\t\t\t\tidAlreadyInUseCount: 0,\n\t\t\t\tunknownIdCount: 0,\n\t\t\t\tmalformedEditCount: 0,\n\t\t\t},\n\t\t});\n\t}\n\n\t/**\n\t * Enables the regular telemetry logging of merge health data.\n\t * The first message will be sent after `interval` milliseconds. See {@link SharedTreeMergeHealthTelemetryHeartbeat.flushHeartbeat} for\n\t * immediate logging.\n\t * @param interval - The amount of time in milliseconds between log messages.\n\t */\n\tpublic startHeartbeat(interval: number = 60000): void {\n\t\tif (this.heartbeatTimerId !== 0) {\n\t\t\tthis.stopHeartbeat();\n\t\t}\n\t\tthis.heartbeatTimerId = window.setInterval(this.logHeartbeat, interval);\n\t}\n\n\t/**\n\t * Disables the regular telemetry logging of merge health data.\n\t */\n\tpublic stopHeartbeat(): void {\n\t\twindow.clearInterval(this.heartbeatTimerId);\n\t\tthis.heartbeatTimerId = 0;\n\t}\n\n\t/**\n\t * Sends all collected merge health data and resets the aggregated state.\n\t */\n\tpublic flushHeartbeat(): void {\n\t\tthis.logHeartbeat();\n\t\tthis.clearData();\n\t}\n\n\t/**\n\t * Resets all aggregated state.\n\t */\n\tpublic clearData(): void {\n\t\tfor (const tree of this.treeData.keys()) {\n\t\t\tthis.resetTreeData(tree);\n\t\t}\n\t}\n\n\t/**\n\t * Receives SequencedEditApplied events from trees.\n\t */\n\tprivate readonly sequencedEditHandler = (params: SequencedEditAppliedEventArguments) => {\n\t\tconst { edit, tree, wasLocal, logger, outcome, reconciliationPath } = params;\n\t\tif (wasLocal) {\n\t\t\tconst tallyAndLogger = this.treeData.get(tree) ?? fail('Should only receive events for registered trees');\n\t\t\ttallyAndLogger.logger = logger;\n\t\t\tconst tally = tallyAndLogger.tally;\n\t\t\ttally.editCount += 1;\n\t\t\ttally.pathLengths[reconciliationPath.length] = (tally.pathLengths[reconciliationPath.length] ?? 0) + 1;\n\t\t\tif (edit.pastAttemptCount !== undefined && edit.pastAttemptCount > tally.maxAttemptCount) {\n\t\t\t\ttally.maxAttemptCount = edit.pastAttemptCount;\n\t\t\t}\n\t\t\tif (outcome.status !== EditStatus.Applied) {\n\t\t\t\ttally.failedEditCount += 1;\n\t\t\t\tswitch (outcome.failure.kind) {\n\t\t\t\t\tcase TransactionInternal.FailureKind.BadPlace: {\n\t\t\t\t\t\ttally.badPlaceCount += 1;\n\t\t\t\t\t\tif (outcome.failure.placeFailure === PlaceValidationResult.MissingSibling) {\n\t\t\t\t\t\t\ttally.deletedSiblingBadPlaceCount += 1;\n\t\t\t\t\t\t} else if (outcome.failure.placeFailure === PlaceValidationResult.MissingParent) {\n\t\t\t\t\t\t\ttally.deletedAncestorBadPlaceCount += 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase TransactionInternal.FailureKind.BadRange: {\n\t\t\t\t\t\ttally.badRangeCount += 1;\n\t\t\t\t\t\tswitch (outcome.failure.rangeFailure) {\n\t\t\t\t\t\t\tcase RangeValidationResultKind.Inverted:\n\t\t\t\t\t\t\t\ttally.updatedRangeInvertedCount += 1;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase RangeValidationResultKind.PlacesInDifferentTraits:\n\t\t\t\t\t\t\t\ttally.updatedRangeHasPlacesInDifferentTraitsCount += 1;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase RangeValidationResultKind.BadPlace:\n\t\t\t\t\t\t\t\ttally.updatedRangeBadPlaceCount += 1;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase TransactionInternal.FailureKind.ConstraintViolation: {\n\t\t\t\t\t\ttally.constraintViolationCount += 1;\n\t\t\t\t\t\tswitch (outcome.failure.violation.kind) {\n\t\t\t\t\t\t\tcase TransactionInternal.ConstraintViolationKind.BadRange: {\n\t\t\t\t\t\t\t\ttally.rangeConstraintViolationCount += 1;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcase TransactionInternal.ConstraintViolationKind.BadLength: {\n\t\t\t\t\t\t\t\ttally.lengthConstraintViolationCount += 1;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcase TransactionInternal.ConstraintViolationKind.BadParent: {\n\t\t\t\t\t\t\t\ttally.parentConstraintViolationCount += 1;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcase TransactionInternal.ConstraintViolationKind.BadLabel: {\n\t\t\t\t\t\t\t\ttally.labelConstraintViolationCount += 1;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tdefault: {\n\t\t\t\t\t\t\t\t// If this doesn't type-check, the above switch statement needs to be extended to handle a new case.\n\t\t\t\t\t\t\t\tconst _: never = outcome.failure.violation;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase TransactionInternal.FailureKind.IdAlreadyInUse: {\n\t\t\t\t\t\ttally.idAlreadyInUseCount += 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase TransactionInternal.FailureKind.UnknownId: {\n\t\t\t\t\t\ttally.unknownIdCount += 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase TransactionInternal.FailureKind.DetachedSequenceIdAlreadyInUse:\n\t\t\t\t\tcase TransactionInternal.FailureKind.DetachedSequenceNotFound:\n\t\t\t\t\tcase TransactionInternal.FailureKind.DuplicateIdInBuild:\n\t\t\t\t\tcase TransactionInternal.FailureKind.UnusedDetachedSequence: {\n\t\t\t\t\t\ttally.malformedEditCount += 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\t// If this doesn't type-check, the above switch statement needs to be extended to handle a new case.\n\t\t\t\t\t\tconst _: never = outcome.failure;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\t/**\n\t * Logs the accumulated merge health data to each tree's designated logger.\n\t */\n\tprivate readonly logHeartbeat = () => {\n\t\tfor (const [tree, { tally, logger }] of this.treeData) {\n\t\t\tif (logger && tally.editCount > 0) {\n\t\t\t\t// Note: all this data is for sequenced edits that were originally produced by the local client.\n\t\t\t\tlogger.send({\n\t\t\t\t\tcategory: 'Heartbeat',\n\t\t\t\t\teventName: 'EditMergeHealth',\n\t\t\t\t\t...tally,\n\t\t\t\t\t// The counts of occurrences for a given path length.\n\t\t\t\t\t// '1:2' means two occurrences of length one.\n\t\t\t\t\t// Overwrites `tally.pathLengths` which is incompatible with ITelemetryBaseEvent.\n\t\t\t\t\tpathLengths: pathLengthsCounts(tally.pathLengths),\n\t\t\t\t});\n\t\t\t\tthis.resetTreeData(tree);\n\t\t\t}\n\t\t}\n\t};\n}\n\nfunction pathLengthsCounts(lengths: readonly number[]): string {\n\treturn Object.entries(lengths)\n\t\t.map(([length, count]) => `${length}:${count}`)\n\t\t.join(',');\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NodeIdUtilities.js","sourceRoot":"","sources":["../src/NodeIdUtilities.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAgB,SAAS,EAAE,MAAM,iBAAiB,CAAC;AA+F1D;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAChC,YAAmC,EACnC,SAAqB;IAErB,OAAO;QACN,kBAAkB,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,YAAY,CAAC,kBAAkB,CAAC,EAAE,CAAC;QAC/D,uBAAuB,EAAE,CAAC,EAAE,EAAE,EAAE,CAC/B,YAAY,CAAC,uBAAuB,CAAC,EAAE,EAAE,SAAS,aAAT,SAAS,cAAT,SAAS,GAAI,YAAY,CAAC,cAAc,CAAC;KACnF,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CACpC,YAAmC;IAEnC,OAAO;QACN,kBAAkB,EAAE,CAAC,EAAE,EAAE,EAAE;YAC1B,MAAM,UAAU,GAAG,YAAY,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;YACvD,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;YAC9B,OAAO,UAAU,CAAC;QACnB,CAAC;QACD,uBAAuB,EAAE,CAAC,EAAE,EAAE,EAAE;YAC/B,MAAM,UAAU,GAAG,YAAY,CAAC,uBAAuB,CAAC,EAAE,EAAE,YAAY,CAAC,cAAc,CAAC,CAAC;YACzF,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;YAC9B,OAAO,UAAU,CAAC;QACnB,CAAC;KACD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,UAAwB;IACxD,OAAO;QACN,cAAc,EAAE,CAAC,QAAiB,EAAE,EAAE,CAAC,UAAU,CAAC,oBAAoB,CAAC,QAAQ,CAAW;QAC1F,eAAe,EAAE,CAAC,EAAgB,EAAE,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAW;QAC1E,kBAAkB,EAAE,CAAC,EAAgB,EAAE,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAuB;QAC5F,qBAAqB,EAAE,CAAC,EAAU,EAAE,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAiB;QAChF,wBAAwB,EAAE,CAAC,EAAU,EAAE,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAiB;QACtF,kBAAkB,EAAE,CAAC,EAAU,EAAE,EAAE,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAkB;QACtF,uBAAuB,EAAE,CAAC,EAAiB,EAAE,SAAoB,EAAE,EAAE,CACpE,UAAU,CAAC,uBAAuB,CAAC,EAAE,EAAE,SAAS,CAAW;QAC5D,cAAc,EAAE,UAAU,CAAC,cAAc;KACzC,CAAC;AACH,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,SAAS,CAA8B,IAAyB;;IAC/E,
|
|
1
|
+
{"version":3,"file":"NodeIdUtilities.js","sourceRoot":"","sources":["../src/NodeIdUtilities.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAgB,SAAS,EAAE,MAAM,iBAAiB,CAAC;AA+F1D;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAChC,YAAmC,EACnC,SAAqB;IAErB,OAAO;QACN,kBAAkB,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,YAAY,CAAC,kBAAkB,CAAC,EAAE,CAAC;QAC/D,uBAAuB,EAAE,CAAC,EAAE,EAAE,EAAE,CAC/B,YAAY,CAAC,uBAAuB,CAAC,EAAE,EAAE,SAAS,aAAT,SAAS,cAAT,SAAS,GAAI,YAAY,CAAC,cAAc,CAAC;KACnF,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CACpC,YAAmC;IAEnC,OAAO;QACN,kBAAkB,EAAE,CAAC,EAAE,EAAE,EAAE;YAC1B,MAAM,UAAU,GAAG,YAAY,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;YACvD,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;YAC9B,OAAO,UAAU,CAAC;QACnB,CAAC;QACD,uBAAuB,EAAE,CAAC,EAAE,EAAE,EAAE;YAC/B,MAAM,UAAU,GAAG,YAAY,CAAC,uBAAuB,CAAC,EAAE,EAAE,YAAY,CAAC,cAAc,CAAC,CAAC;YACzF,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;YAC9B,OAAO,UAAU,CAAC;QACnB,CAAC;KACD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,UAAwB;IACxD,OAAO;QACN,cAAc,EAAE,CAAC,QAAiB,EAAE,EAAE,CAAC,UAAU,CAAC,oBAAoB,CAAC,QAAQ,CAAW;QAC1F,eAAe,EAAE,CAAC,EAAgB,EAAE,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAW;QAC1E,kBAAkB,EAAE,CAAC,EAAgB,EAAE,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAuB;QAC5F,qBAAqB,EAAE,CAAC,EAAU,EAAE,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAiB;QAChF,wBAAwB,EAAE,CAAC,EAAU,EAAE,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAiB;QACtF,kBAAkB,EAAE,CAAC,EAAU,EAAE,EAAE,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAkB;QACtF,uBAAuB,EAAE,CAAC,EAAiB,EAAE,SAAoB,EAAE,EAAE,CACpE,UAAU,CAAC,uBAAuB,CAAC,EAAE,EAAE,SAAS,CAAW;QAC5D,cAAc,EAAE,UAAU,CAAC,cAAc;KACzC,CAAC;AACH,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,SAAS,CAA8B,IAAyB;;IAC/E,OAAO,MAAC,IAAsB,CAAC,UAAU,mCAAK,IAAY,CAAC;AAC5D,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { assert } from './Common';\nimport { IdCompressor, isFinalId } from './id-compressor';\nimport { FinalNodeId, NodeId, OpSpaceNodeId, SessionId, StableNodeId } from './Identifiers';\nimport { NodeData } from './persisted-types';\n\n/**\n * An object which can generate node IDs and convert node IDs between compressed and stable variants\n * @public\n */\nexport interface NodeIdContext extends NodeIdGenerator, NodeIdConverter {}\n\n/**\n * An object which can generate node IDs\n * @public\n */\nexport interface NodeIdGenerator {\n\t/**\n\t * Generates a node identifier.\n\t * The returned IDs may be used as the identifier of a node in the SharedTree.\n\t * `NodeId`s are *always* unique and stable within the scope of the tree and session that generated them. They are *not* unique within\n\t * a Fluid container, and *cannot* be compared across instances of a SharedTree. They are *not* stable across sessions/lifetimes of a\n\t * SharedTree, and *cannot* be persisted (e.g. stored in payloads, uploaded in blobs, etc.). If stable persistence is needed,\n\t * NodeIdConverter.convertToStableNodeId may be used to return a corresponding UUID that is globally unique and stable.\n\t * @param override - if supplied, calls to `convertToStableNodeId` using the returned node ID will return the override instead of\n\t * the UUID. Calls to `generateNodeId` with the same override always return the same ID. Performance note: passing an override string\n\t * incurs a storage cost that is significantly higher that a node ID without one, and should be avoided if possible.\n\t */\n\tgenerateNodeId(override?: string): NodeId;\n}\n\n/**\n * An object which can convert node IDs between compressed and stable variants\n * @public\n */\nexport interface NodeIdConverter {\n\t/**\n\t * Given a NodeId, returns the corresponding stable ID or throws if the supplied node ID was not generated with this tree (`NodeId`s\n\t * may not be used across SharedTree instances, see `generateNodeId` for more).\n\t * The returned value will be a UUID, unless the creation of `id` used an override string (see `generateNodeId` for more).\n\t * The result is safe to persist and re-use across `SharedTree` instances, unlike `NodeId`.\n\t */\n\tconvertToStableNodeId(id: NodeId): StableNodeId;\n\n\t/**\n\t * Given a NodeId, attempt to return the corresponding stable ID.\n\t * The returned value will be a UUID, unless the creation of `id` used an override string (see `generateNodeId` for more).\n\t * The returned stable ID is undefined if `id` was never created with this SharedTree. If a stable ID is returned, this does not imply\n\t * that there is a node with `id` in the current revision of the tree, only that `id` was at some point generated by some instance of\n\t * this tree.\n\t */\n\ttryConvertToStableNodeId(id: NodeId): StableNodeId | undefined;\n\n\t/**\n\t * Given a stable ID, return the corresponding NodeId or throws if the supplied stable ID was never generated with this tree, either\n\t * as a UUID corresponding to a `NodeId` or as an override passed to `generateNodeId`.\n\t * If a stable ID is returned, this does not imply that there is a node with `id` in the current revision of the tree, only that\n\t * `id` was at some point generated by an instance of this SharedTree.\n\t */\n\tconvertToNodeId(id: StableNodeId): NodeId;\n\n\t/**\n\t * Given a stable ID, return the corresponding NodeId or return undefined if the supplied stable ID was never generated with this tree,\n\t * either as a UUID corresponding to a `NodeId` or as an override passed to `generateNodeId`.\n\t * If a stable ID is returned, this does not imply that there is a node with `id` in the current revision of the tree, only that\n\t * `id` was at some point generated by an instance of this SharedTree.\n\t */\n\ttryConvertToNodeId(id: StableNodeId): NodeId | undefined;\n}\n\n/**\n * An object which can normalize node IDs. See docs on {@link IdCompressor} for semantics of normalization.\n */\nexport interface NodeIdNormalizer<TId extends OpSpaceNodeId> {\n\tlocalSessionId: SessionId;\n\t/**\n\t * Normalizes the given ID to op space\n\t */\n\tnormalizeToOpSpace(id: NodeId): TId;\n\t/**\n\t * Normalizes the given ID to session space\n\t */\n\tnormalizeToSessionSpace(id: TId, sessionId: SessionId): NodeId;\n}\n\n/**\n * An object which can normalize node IDs. It is contextualized to a known session context, and therefore\n * can normalize IDs into session space without requiring any additional information.\n */\nexport interface ContextualizedNodeIdNormalizer<TId extends OpSpaceNodeId>\n\textends Omit<NodeIdNormalizer<TId>, 'localSessionId' | 'normalizeToSessionSpace'> {\n\t/**\n\t * Normalizes the given ID to session space\n\t */\n\tnormalizeToSessionSpace(id: TId): NodeId;\n}\n\n/**\n * Create a {@link ContextualizedNodeIdNormalizer} that uses either the given session ID to normalize IDs\n * to session space. If no ID is given, it will use the local session ID belonging to the normalizer.\n */\nexport function scopeIdNormalizer<TId extends OpSpaceNodeId>(\n\tidNormalizer: NodeIdNormalizer<TId>,\n\tsessionId?: SessionId\n): ContextualizedNodeIdNormalizer<TId> {\n\treturn {\n\t\tnormalizeToOpSpace: (id) => idNormalizer.normalizeToOpSpace(id),\n\t\tnormalizeToSessionSpace: (id) =>\n\t\t\tidNormalizer.normalizeToSessionSpace(id, sessionId ?? idNormalizer.localSessionId),\n\t};\n}\n\n/**\n * Create a {@link ContextualizedNodeIdNormalizer} that uses the local session ID belonging to the normalizer\n * to normalize IDs to session space. These IDs are expected to be sequenced, and will fail to normalize if\n * they are not.\n */\nexport function sequencedIdNormalizer<TId extends OpSpaceNodeId>(\n\tidNormalizer: NodeIdNormalizer<TId>\n): ContextualizedNodeIdNormalizer<FinalNodeId & TId> {\n\treturn {\n\t\tnormalizeToOpSpace: (id) => {\n\t\t\tconst normalized = idNormalizer.normalizeToOpSpace(id);\n\t\t\tassert(isFinalId(normalized));\n\t\t\treturn normalized;\n\t\t},\n\t\tnormalizeToSessionSpace: (id) => {\n\t\t\tconst normalized = idNormalizer.normalizeToSessionSpace(id, idNormalizer.localSessionId);\n\t\t\tassert(isFinalId(normalized));\n\t\t\treturn normalized;\n\t\t},\n\t};\n}\n\nexport function getNodeIdContext(compressor: IdCompressor): NodeIdContext & NodeIdNormalizer<OpSpaceNodeId> {\n\treturn {\n\t\tgenerateNodeId: (override?: string) => compressor.generateCompressedId(override) as NodeId,\n\t\tconvertToNodeId: (id: StableNodeId) => compressor.recompress(id) as NodeId,\n\t\ttryConvertToNodeId: (id: StableNodeId) => compressor.tryRecompress(id) as NodeId | undefined,\n\t\tconvertToStableNodeId: (id: NodeId) => compressor.decompress(id) as StableNodeId,\n\t\ttryConvertToStableNodeId: (id: NodeId) => compressor.tryDecompress(id) as StableNodeId,\n\t\tnormalizeToOpSpace: (id: NodeId) => compressor.normalizeToOpSpace(id) as OpSpaceNodeId,\n\t\tnormalizeToSessionSpace: (id: OpSpaceNodeId, sessionId: SessionId) =>\n\t\t\tcompressor.normalizeToSessionSpace(id, sessionId) as NodeId,\n\t\tlocalSessionId: compressor.localSessionId,\n\t};\n}\n\n/** Accepts either a node or a node's identifier, and returns the identifier */\nexport function getNodeId<TId extends number | string>(node: TId | NodeData<TId>): TId {\n\treturn (node as NodeData<TId>).identifier ?? (node as TId);\n}\n"]}
|
|
@@ -15,15 +15,17 @@ export declare type Revision = number;
|
|
|
15
15
|
* A cache of `TValue`s corresponding to `Revision`s.
|
|
16
16
|
*
|
|
17
17
|
* A value is kept in cache if it meets any of the following criteria:
|
|
18
|
-
*
|
|
19
|
-
* - The
|
|
20
|
-
*
|
|
21
|
-
*
|
|
18
|
+
*
|
|
19
|
+
* - The revision is \>= `retentionWindowStart`
|
|
20
|
+
* - The value has been used recently, meaning getClosestEntry or cacheValue was called with its revision. Note that
|
|
21
|
+
* being returned when a large revision was passed to getClosestEntry does not count.
|
|
22
|
+
* - The value is `retained` meaning it was provided to to constructor in retainedEntries or passed to
|
|
23
|
+
* `cacheRetainedValue`
|
|
22
24
|
*/
|
|
23
25
|
export declare class RevisionValueCache<TValue> {
|
|
24
26
|
/**
|
|
25
|
-
* The first revision within the retention window. All entries with revisions
|
|
26
|
-
* Must be
|
|
27
|
+
* The first revision within the retention window. All entries with revisions \>= retentionWindowStart will be retained.
|
|
28
|
+
* Must be \>= 0.
|
|
27
29
|
*/
|
|
28
30
|
private retentionWindowStart;
|
|
29
31
|
/**
|
|
@@ -34,7 +36,7 @@ export declare class RevisionValueCache<TValue> {
|
|
|
34
36
|
private readonly sortedEntries;
|
|
35
37
|
/**
|
|
36
38
|
* Cache of most recently used evictable entries.
|
|
37
|
-
* Subset of
|
|
39
|
+
* Subset of `sortedValues` eligible for eviction:
|
|
38
40
|
* All entries are also in `sortedValues`, and are removed from `sortedValues` when evicted from this cache.
|
|
39
41
|
* Evicts least recently used entries.
|
|
40
42
|
*/
|
|
@@ -49,8 +51,8 @@ export declare class RevisionValueCache<TValue> {
|
|
|
49
51
|
*/
|
|
50
52
|
evictableSize: number,
|
|
51
53
|
/**
|
|
52
|
-
* The first revision within the retention window. All entries with revisions
|
|
53
|
-
* Must be
|
|
54
|
+
* The first revision within the retention window. All entries with revisions \>= retentionWindowStart will be retained.
|
|
55
|
+
* Must be \>= 0.
|
|
54
56
|
*/
|
|
55
57
|
retentionWindowStart: Revision,
|
|
56
58
|
/**
|
|
@@ -67,7 +69,8 @@ export declare class RevisionValueCache<TValue> {
|
|
|
67
69
|
*/
|
|
68
70
|
updateRetentionWindow(newRetentionWindowStart: Revision): void;
|
|
69
71
|
/**
|
|
70
|
-
* @returns a [cachedRevision, value] where cachedRevision
|
|
72
|
+
* @returns a [cachedRevision, value] where cachedRevision \<= requestedRevision, or undefined if no such revision
|
|
73
|
+
* is cached.
|
|
71
74
|
*/
|
|
72
75
|
getClosestEntry(requestedRevision: Revision): [revision: Revision, value: TValue] | undefined;
|
|
73
76
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RevisionValueCache.d.ts","sourceRoot":"","sources":["../src/RevisionValueCache.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH;;;;;;;GAOG;AACH,oBAAY,QAAQ,GAAG,MAAM,CAAC;AAE9B
|
|
1
|
+
{"version":3,"file":"RevisionValueCache.d.ts","sourceRoot":"","sources":["../src/RevisionValueCache.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH;;;;;;;GAOG;AACH,oBAAY,QAAQ,GAAG,MAAM,CAAC;AAE9B;;;;;;;;;;GAUG;AACH,qBAAa,kBAAkB,CAAC,MAAM;IA0BpC;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IA7B7B;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgE;IAE9F;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAwB;IAE3D;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAuB;;IAGxD;;OAEG;IACH,aAAa,EAAE,MAAM;IACrB;;;OAGG;IACK,oBAAoB,EAAE,QAAQ;IACtC;;OAEG;IACH,eAAe,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE;IAqBvC;;OAEG;IACI,uBAAuB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO;IAI3D;;;OAGG;IACI,qBAAqB,CAAC,uBAAuB,EAAE,QAAQ,GAAG,IAAI;IAwBrE;;;OAGG;IACI,eAAe,CAAC,iBAAiB,EAAE,QAAQ,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,SAAS;IAQpG;;OAEG;IACI,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAKlE;;;;;;OAMG;IACI,UAAU,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;CAS1D"}
|
|
@@ -9,10 +9,12 @@ import { assert, fail, compareFiniteNumbers } from './Common';
|
|
|
9
9
|
* A cache of `TValue`s corresponding to `Revision`s.
|
|
10
10
|
*
|
|
11
11
|
* A value is kept in cache if it meets any of the following criteria:
|
|
12
|
-
*
|
|
13
|
-
* - The
|
|
14
|
-
*
|
|
15
|
-
*
|
|
12
|
+
*
|
|
13
|
+
* - The revision is \>= `retentionWindowStart`
|
|
14
|
+
* - The value has been used recently, meaning getClosestEntry or cacheValue was called with its revision. Note that
|
|
15
|
+
* being returned when a large revision was passed to getClosestEntry does not count.
|
|
16
|
+
* - The value is `retained` meaning it was provided to to constructor in retainedEntries or passed to
|
|
17
|
+
* `cacheRetainedValue`
|
|
16
18
|
*/
|
|
17
19
|
export class RevisionValueCache {
|
|
18
20
|
constructor(
|
|
@@ -21,8 +23,8 @@ export class RevisionValueCache {
|
|
|
21
23
|
*/
|
|
22
24
|
evictableSize,
|
|
23
25
|
/**
|
|
24
|
-
* The first revision within the retention window. All entries with revisions
|
|
25
|
-
* Must be
|
|
26
|
+
* The first revision within the retention window. All entries with revisions \>= retentionWindowStart will be retained.
|
|
27
|
+
* Must be \>= 0.
|
|
26
28
|
*/
|
|
27
29
|
retentionWindowStart,
|
|
28
30
|
/**
|
|
@@ -87,7 +89,8 @@ export class RevisionValueCache {
|
|
|
87
89
|
});
|
|
88
90
|
}
|
|
89
91
|
/**
|
|
90
|
-
* @returns a [cachedRevision, value] where cachedRevision
|
|
92
|
+
* @returns a [cachedRevision, value] where cachedRevision \<= requestedRevision, or undefined if no such revision
|
|
93
|
+
* is cached.
|
|
91
94
|
*/
|
|
92
95
|
getClosestEntry(requestedRevision) {
|
|
93
96
|
var _a;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RevisionValueCache.js","sourceRoot":"","sources":["../src/RevisionValueCache.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,MAAM,cAAc,CAAC;AACjC,OAAO,GAAG,MAAM,WAAW,CAAC;AAC5B,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAY9D
|
|
1
|
+
{"version":3,"file":"RevisionValueCache.js","sourceRoot":"","sources":["../src/RevisionValueCache.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport BTree from 'sorted-btree';\nimport LRU from 'lru-cache';\nimport { assert, fail, compareFiniteNumbers } from './Common';\n\n/**\n * A revision corresponds to an index in an `EditLog`.\n *\n * It is associated with the output `RevisionView` of applying the edit at the index to the previous revision.\n * For example:\n * - revision 0 corresponds to the initialRevision.\n * - revision 1 corresponds to the output of editLog[0] applied to the initialRevision.\n */\nexport type Revision = number;\n\n/**\n * A cache of `TValue`s corresponding to `Revision`s.\n *\n * A value is kept in cache if it meets any of the following criteria:\n *\n * - The revision is \\>= `retentionWindowStart`\n * - The value has been used recently, meaning getClosestEntry or cacheValue was called with its revision. Note that\n * being returned when a large revision was passed to getClosestEntry does not count.\n * - The value is `retained` meaning it was provided to to constructor in retainedEntries or passed to\n * `cacheRetainedValue`\n */\nexport class RevisionValueCache<TValue> {\n\t/**\n\t * A cache of entries for revisions.\n\t * This is sorted to allow efficient access to the nearest preceding entry (see getClosestEntry).\n\t * Contains all cached values, regardless of why they are cached (retained, LRU or window).\n\t */\n\tprivate readonly sortedEntries = new BTree<Revision, TValue>(undefined, compareFiniteNumbers);\n\n\t/**\n\t * Cache of most recently used evictable entries.\n\t * Subset of `sortedValues` eligible for eviction:\n\t * All entries are also in `sortedValues`, and are removed from `sortedValues` when evicted from this cache.\n\t * Evicts least recently used entries.\n\t */\n\tprivate readonly evictableRevisions: LRU<Revision, TValue>;\n\n\t/**\n\t * Set of all revisions that should never be evicted.\n\t */\n\tprivate readonly retainedRevisions = new Set<Revision>();\n\n\tpublic constructor(\n\t\t/**\n\t\t * Maximum capacity for evictable cache entries (those neither marked as retained nor within the retention window).\n\t\t */\n\t\tevictableSize: number,\n\t\t/**\n\t\t * The first revision within the retention window. All entries with revisions \\>= retentionWindowStart will be retained.\n\t\t * Must be \\>= 0.\n\t\t */\n\t\tprivate retentionWindowStart: Revision,\n\t\t/**\n\t\t * Optional list of entries to permanently retain.\n\t\t */\n\t\tretainedEntries?: [Revision, TValue][]\n\t) {\n\t\tassert(retentionWindowStart >= 0, 'retentionWindowStart must be initialized >= 0');\n\t\tthis.evictableRevisions = new LRU({\n\t\t\tmax: evictableSize,\n\t\t\tnoDisposeOnSet: true,\n\t\t\tdispose: (revision) => {\n\t\t\t\tif (revision >= this.retentionWindowStart) {\n\t\t\t\t\tfail('Entries in retention window should never be evicted.');\n\t\t\t\t}\n\t\t\t\tif (this.retainedRevisions.has(revision)) {\n\t\t\t\t\tfail('Retained entries should not be evicted');\n\t\t\t\t}\n\t\t\t\tthis.sortedEntries.delete(revision);\n\t\t\t},\n\t\t});\n\t\tif (retainedEntries !== undefined) {\n\t\t\tretainedEntries.forEach(([revision, entry]) => this.cacheRetainedValue(revision, entry));\n\t\t}\n\t}\n\n\t/**\n\t * @returns if the supplied revision is within the retention window.\n\t */\n\tpublic isWithinRetentionWindow(revision: Revision): boolean {\n\t\treturn revision >= this.retentionWindowStart;\n\t}\n\n\t/**\n\t * Sets the new retention window.\n\t * @param newRetentionWindowStart - defines the trailing edge (inclusive) of the new retention window.\n\t */\n\tpublic updateRetentionWindow(newRetentionWindowStart: Revision): void {\n\t\tif (newRetentionWindowStart < this.retentionWindowStart) {\n\t\t\tfail('retention window boundary must not move backwards');\n\t\t}\n\t\tconst prevRetentionWindowStart = this.retentionWindowStart;\n\t\tthis.retentionWindowStart = newRetentionWindowStart;\n\t\tconst oldWindowEntries: [Revision, TValue][] = [];\n\t\tthis.sortedEntries.forRange(\n\t\t\tprevRetentionWindowStart,\n\t\t\tthis.retentionWindowStart,\n\t\t\tfalse,\n\t\t\t(windowRevision, windowEntry) => {\n\t\t\t\tif (!this.retainedRevisions.has(windowRevision)) {\n\t\t\t\t\t// Adding to the LRU can cause eviction which in turn mutates the b-tree we are enumerating. Thus, store list of\n\t\t\t\t\t// old window entries separately.\n\t\t\t\t\toldWindowEntries.push([windowRevision, windowEntry]);\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t\toldWindowEntries.forEach(([revision, value]) => {\n\t\t\tthis.evictableRevisions.set(revision, value);\n\t\t});\n\t}\n\n\t/**\n\t * @returns a [cachedRevision, value] where cachedRevision \\<= requestedRevision, or undefined if no such revision\n\t * is cached.\n\t */\n\tpublic getClosestEntry(requestedRevision: Revision): [revision: Revision, value: TValue] | undefined {\n\t\tconst fromLRU = this.evictableRevisions.get(requestedRevision);\n\t\tif (fromLRU !== undefined) {\n\t\t\treturn [requestedRevision, fromLRU];\n\t\t}\n\t\treturn this.sortedEntries.getPairOrNextLower(requestedRevision) ?? undefined;\n\t}\n\n\t/**\n\t * Caches the supplied value and guarantees it will never be evicted.\n\t */\n\tpublic cacheRetainedValue(revision: Revision, value: TValue): void {\n\t\tthis.retainedRevisions.add(revision);\n\t\tthis.sortedEntries.set(revision, value);\n\t}\n\n\t/**\n\t * Caches the supplied value.\n\t * The cached value is subject to eviction unless it is within the retention window or was previously added\n\t * via `cacheRetainedValue`.\n\t * Note that if a non-retained entry starts out within the retention window and passes outside of it due to a call to\n\t * updateRetentionWindow it is then subject to eviction.\n\t */\n\tpublic cacheValue(revision: Revision, value: TValue): void {\n\t\tif (this.retainedRevisions.has(revision)) {\n\t\t\treturn;\n\t\t}\n\t\tthis.sortedEntries.set(revision, value);\n\t\tif (revision < this.retentionWindowStart) {\n\t\t\tthis.evictableRevisions.set(revision, value);\n\t\t}\n\t}\n}\n"]}
|
package/lib/RevisionView.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RevisionView.js","sourceRoot":"","sources":["../src/RevisionView.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { copyPropertyIfDefined, fail, Mutable, MutableMap } from './Common';\nimport { Forest } from './Forest';\nimport { NodeId, StableNodeId, TraitLabel } from './Identifiers';\nimport { NodeIdConverter } from './NodeIdUtilities';\nimport { Payload, TreeNode, TreeNodeSequence } from './persisted-types';\nimport { TreeView, TreeViewNode, TreeViewPlace, TreeViewRange } from './TreeView';\nimport { HasVariadicTraits } from './ChangeTypes';\n\n/**\n * An immutable view of a distributed tree.\n * @public\n */\nexport class RevisionView extends TreeView {\n\t/**\n\t * Constructs a {@link RevisionView} using the supplied tree.\n\t * @param root - the root of the tree to use as the contents of the {@link RevisionView}\n\t * @param expensiveValidation - whether or not to perform additional validation, e.g. to catch errors when testing\n\t */\n\tpublic static fromTree<T extends TreeNode<T, NodeId>>(root: T, expensiveValidation?: boolean): RevisionView;\n\t/**\n\t * Constructs a {@link RevisionView} using the supplied tree.\n\t * @param root - the root of the tree to use as the contents of the `RevisionView`\n\t * @param idConverter - the {@link NodeIdConverter} that will recompress the IDs the in the tree\n\t * @param expensiveValidation - whether or not to perform additional validation, e.g. to catch errors when testing\n\t */\n\tpublic static fromTree<T extends TreeNode<T, StableNodeId>>(\n\t\troot: T,\n\t\tidConverter: NodeIdConverter,\n\t\texpensiveValidation?: boolean\n\t): RevisionView;\n\n\tpublic static fromTree<T extends TreeNode<T, NodeId> | TreeNode<T, StableNodeId>>(\n\t\troot: T,\n\t\tidConverterOrExpensiveValidation?: NodeIdConverter | boolean,\n\t\texpensiveValidation = false\n\t): RevisionView {\n\t\tif (typeof idConverterOrExpensiveValidation === 'object') {\n\t\t\tconst rootId = idConverterOrExpensiveValidation.convertToNodeId(root.identifier as StableNodeId);\n\n\t\t\tconst treeViewNodes = convertTreeNodesToViewNodes(root, (node) => {\n\t\t\t\tconst identifier = idConverterOrExpensiveValidation.convertToNodeId(node.identifier as StableNodeId);\n\t\t\t\tconst viewNode = {\n\t\t\t\t\tdefinition: node.definition,\n\t\t\t\t\tidentifier,\n\t\t\t\t};\n\t\t\t\tcopyPropertyIfDefined(node, viewNode, 'payload');\n\t\t\t\treturn viewNode;\n\t\t\t});\n\n\t\t\treturn new RevisionView(rootId, Forest.create(expensiveValidation).add(treeViewNodes));\n\t\t} else {\n\t\t\treturn new RevisionView(\n\t\t\t\troot.identifier as NodeId,\n\t\t\t\tForest.create(expensiveValidation).add(\n\t\t\t\t\tconvertTreeNodesToViewNodes(root, (node) => {\n\t\t\t\t\t\tconst viewNode = {\n\t\t\t\t\t\t\tdefinition: node.definition,\n\t\t\t\t\t\t\tidentifier: node.identifier as NodeId,\n\t\t\t\t\t\t};\n\t\t\t\t\t\tcopyPropertyIfDefined(node, viewNode, 'payload');\n\t\t\t\t\t\treturn viewNode;\n\t\t\t\t\t})\n\t\t\t\t)\n\t\t\t);\n\t\t}\n\t}\n\n\t/** Begin a transaction by generating a mutable `TransactionView` from this view */\n\tpublic openForTransaction(): TransactionView {\n\t\treturn new TransactionView(this.root, this.forest);\n\t}\n\n\tpublic equals(view: TreeView): boolean {\n\t\tif (!(view instanceof RevisionView)) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn this.hasEqualForest(view);\n\t}\n}\n\n/**\n * An view of a distributed tree that is part of an ongoing transaction between `RevisionView`s.\n * @public\n */\nexport class TransactionView extends TreeView {\n\t/** Conclude a transaction by generating an immutable `RevisionView` from this view */\n\tpublic close(): RevisionView {\n\t\treturn new RevisionView(this.root, this.forest);\n\t}\n\n\t/** Inserts all nodes in a NodeSequence into the view */\n\tpublic addNodes(sequence: Iterable<TreeViewNode>): TransactionView {\n\t\treturn new TransactionView(this.root, this.forest.add(sequence));\n\t}\n\n\t/** Remove all nodes with the given ids from the view */\n\tpublic deleteNodes(nodes: Iterable<NodeId>): TransactionView {\n\t\treturn new TransactionView(this.root, this.forest.delete(nodes, true));\n\t}\n\n\t/**\n\t * Parents a set of detached nodes at a specified place.\n\t * @param nodesToAttach - the nodes to parent in the specified place. The nodes must already be present in the view.\n\t * @param place - the location to insert the nodes.\n\t */\n\tpublic attachRange(nodesToAttach: readonly NodeId[], place: TreeViewPlace): TransactionView {\n\t\tconst { parent, label } = place.trait;\n\t\tconst index = this.findIndexWithinTrait(place);\n\t\treturn new TransactionView(this.root, this.forest.attachRangeOfChildren(parent, label, index, nodesToAttach));\n\t}\n\n\t/**\n\t * Detaches a range of nodes from their parent. The detached nodes remain in the view.\n\t * @param rangeToDetach - the range of nodes to detach\n\t */\n\tpublic detachRange(rangeToDetach: TreeViewRange): { view: TransactionView; detached: readonly NodeId[] } {\n\t\tconst { start, end } = rangeToDetach;\n\t\tconst { trait: traitLocation } = start;\n\t\tconst { parent, label } = traitLocation;\n\t\tconst startIndex = this.findIndexWithinTrait(start);\n\t\tconst endIndex = this.findIndexWithinTrait(end);\n\t\tconst { forest, detached } = this.forest.detachRangeOfChildren(parent, label, startIndex, endIndex);\n\t\treturn { view: new TransactionView(this.root, forest), detached };\n\t}\n\n\t/**\n\t * Sets or overwrites a node's value. The node must exist in this view.\n\t * @param nodeId - the id of the node\n\t * @param value - the new value\n\t */\n\tpublic setNodeValue(nodeId: NodeId, value: Payload): TransactionView {\n\t\treturn new TransactionView(this.root, this.forest.setValue(nodeId, value));\n\t}\n\n\tpublic equals(view: TreeView): boolean {\n\t\tif (!(view instanceof TransactionView)) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn this.hasEqualForest(view);\n\t}\n}\n\n/**\n * Transform an input tree into a list of {@link TreeViewNode}s.\n * @param tree - the input tree\n * @param convert - a conversion function that will run on each node in the input tree to produce the output nodes.\n * Returning undefined means that conversion for the given node was impossible, at which time the entire tree conversion will be aborted\n * and return undefined.\n */\nexport function convertTreeNodesToViewNodes<\n\tTIn extends HasVariadicTraits<TIn>,\n\tTOut extends TreeViewNode = TreeViewNode\n>(root: TIn, convert: (node: TIn) => Omit<TOut, 'traits'>): TOut[];\n\n/**\n * Transform an input tree into a list of {@link TreeViewNode}s.\n * @param tree - the input tree\n * @param convert - a conversion function that will run on each node in the input tree to produce the output nodes.\n */\nexport function convertTreeNodesToViewNodes<\n\tTIn extends HasVariadicTraits<TIn>,\n\tTOut extends TreeViewNode = TreeViewNode\n>(root: TIn, convert: (node: TIn) => Omit<TOut, 'traits'> | undefined): TOut[] | undefined;\n\n/**\n * Transform an input tree into a list of {@link TreeViewNode}s.\n * @param tree - the input tree\n * @param convert - a conversion function that will run on each node in the input tree to produce the output nodes.\n * Returning undefined means that conversion for the given node was impossible, at which time the entire tree conversion will be aborted\n * and return undefined.\n */\nexport function convertTreeNodesToViewNodes<\n\tTIn extends HasVariadicTraits<TIn>,\n\tTOut extends TreeViewNode = TreeViewNode\n>(root: TIn, convert: (node: TIn) => Omit<TOut, 'traits'> | undefined): TOut[] | undefined {\n\tconst convertedRoot = convert(root) as Mutable<TOut>;\n\tif (convertedRoot === undefined || root.traits === undefined) {\n\t\treturn undefined;\n\t}\n\t// `convertedRoot` might be the same as `root`, in which case stash the children of `root` before wiping them from `convertedRoot`\n\tconst rootTraits = (root as unknown as TOut) === convertedRoot ? { traits: root.traits } : root;\n\tconvertedRoot.traits = new Map();\n\tconst pendingNodes: {\n\t\tchildIterator: Iterator<[TraitLabel, TIn]>;\n\t\tnewNode: Mutable<TOut>;\n\t}[] = [{ childIterator: iterateChildren(rootTraits)[Symbol.iterator](), newNode: convertedRoot }];\n\tconst resultNodes: TOut[] = [];\n\n\twhile (pendingNodes.length > 0) {\n\t\tconst { childIterator, newNode } = pendingNodes[pendingNodes.length - 1] ?? fail('Undefined node');\n\t\tconst { value, done } = childIterator.next();\n\t\tif (done === true) {\n\t\t\tresultNodes.push(\n\t\t\t\tpendingNodes.pop()?.newNode ?? fail('covertTreeNodesToViewNodes incorrectly coordinated parentage')\n\t\t\t);\n\t\t} else {\n\t\t\tconst [traitLabel, child] = value as [TraitLabel, TIn];\n\t\t\tconst convertedChild = convert(child) as TOut;\n\t\t\tif (convertedChild === undefined) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tif (child.traits !== undefined) {\n\t\t\t\tconst childTraits = (child as unknown as TOut) === convertedChild ? { traits: child.traits } : child;\n\t\t\t\t(convertedChild as Mutable<TOut>).traits = new Map();\n\t\t\t\tpendingNodes.push({\n\t\t\t\t\tchildIterator: iterateChildren(childTraits)[Symbol.iterator](),\n\t\t\t\t\tnewNode: convertedChild,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst newTraits = newNode.traits as MutableMap<TOut['traits']>;\n\t\t\tlet newTrait = newTraits.get(traitLabel);\n\t\t\tif (newTrait === undefined) {\n\t\t\t\tnewTrait = [];\n\t\t\t\tnewTraits.set(traitLabel, newTrait);\n\t\t\t}\n\t\t\t(newTrait as NodeId[]).push(convertedChild.identifier);\n\t\t}\n\t}\n\n\treturn resultNodes;\n}\n\n/**\n * Returns an iterable of the supplied node's traits in a stable order.\n */\nexport function* iterateChildren<T>(hasTraits: HasVariadicTraits<T>): Iterable<[TraitLabel, T]> {\n\tif (hasTraits.traits !== undefined) {\n\t\tfor (const [label, trait] of Object.entries(hasTraits.traits).sort()) {\n\t\t\tif (trait !== undefined) {\n\t\t\t\tif (isTreeNodeSequence(trait)) {\n\t\t\t\t\tfor (const child of trait) {\n\t\t\t\t\t\tyield [label as TraitLabel, child];\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tyield [label as TraitLabel, trait];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction isTreeNodeSequence<TChild>(sequence: TreeNodeSequence<TChild> | TChild): sequence is TreeNodeSequence<TChild> {\n\treturn Array.isArray(sequence);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"RevisionView.js","sourceRoot":"","sources":["../src/RevisionView.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { copyPropertyIfDefined, fail, Mutable, MutableMap } from './Common';\nimport { Forest } from './Forest';\nimport { NodeId, StableNodeId, TraitLabel } from './Identifiers';\nimport { NodeIdConverter } from './NodeIdUtilities';\nimport { Payload, TreeNode, TreeNodeSequence } from './persisted-types';\nimport { TreeView, TreeViewNode, TreeViewPlace, TreeViewRange } from './TreeView';\nimport { HasVariadicTraits } from './ChangeTypes';\n\n/**\n * An immutable view of a distributed tree.\n * @public\n */\nexport class RevisionView extends TreeView {\n\t/**\n\t * Constructs a {@link RevisionView} using the supplied tree.\n\t * @param root - the root of the tree to use as the contents of the {@link RevisionView}\n\t * @param expensiveValidation - whether or not to perform additional validation, e.g. to catch errors when testing\n\t */\n\tpublic static fromTree<T extends TreeNode<T, NodeId>>(root: T, expensiveValidation?: boolean): RevisionView;\n\t/**\n\t * Constructs a {@link RevisionView} using the supplied tree.\n\t * @param root - the root of the tree to use as the contents of the `RevisionView`\n\t * @param idConverter - the {@link NodeIdConverter} that will recompress the IDs the in the tree\n\t * @param expensiveValidation - whether or not to perform additional validation, e.g. to catch errors when testing\n\t */\n\tpublic static fromTree<T extends TreeNode<T, StableNodeId>>(\n\t\troot: T,\n\t\tidConverter: NodeIdConverter,\n\t\texpensiveValidation?: boolean\n\t): RevisionView;\n\n\tpublic static fromTree<T extends TreeNode<T, NodeId> | TreeNode<T, StableNodeId>>(\n\t\troot: T,\n\t\tidConverterOrExpensiveValidation?: NodeIdConverter | boolean,\n\t\texpensiveValidation = false\n\t): RevisionView {\n\t\tif (typeof idConverterOrExpensiveValidation === 'object') {\n\t\t\tconst rootId = idConverterOrExpensiveValidation.convertToNodeId(root.identifier as StableNodeId);\n\n\t\t\tconst treeViewNodes = convertTreeNodesToViewNodes(root, (node) => {\n\t\t\t\tconst identifier = idConverterOrExpensiveValidation.convertToNodeId(node.identifier as StableNodeId);\n\t\t\t\tconst viewNode = {\n\t\t\t\t\tdefinition: node.definition,\n\t\t\t\t\tidentifier,\n\t\t\t\t};\n\t\t\t\tcopyPropertyIfDefined(node, viewNode, 'payload');\n\t\t\t\treturn viewNode;\n\t\t\t});\n\n\t\t\treturn new RevisionView(rootId, Forest.create(expensiveValidation).add(treeViewNodes));\n\t\t} else {\n\t\t\treturn new RevisionView(\n\t\t\t\troot.identifier as NodeId,\n\t\t\t\tForest.create(expensiveValidation).add(\n\t\t\t\t\tconvertTreeNodesToViewNodes(root, (node) => {\n\t\t\t\t\t\tconst viewNode = {\n\t\t\t\t\t\t\tdefinition: node.definition,\n\t\t\t\t\t\t\tidentifier: node.identifier as NodeId,\n\t\t\t\t\t\t};\n\t\t\t\t\t\tcopyPropertyIfDefined(node, viewNode, 'payload');\n\t\t\t\t\t\treturn viewNode;\n\t\t\t\t\t})\n\t\t\t\t)\n\t\t\t);\n\t\t}\n\t}\n\n\t/** Begin a transaction by generating a mutable `TransactionView` from this view */\n\tpublic openForTransaction(): TransactionView {\n\t\treturn new TransactionView(this.root, this.forest);\n\t}\n\n\tpublic equals(view: TreeView): boolean {\n\t\tif (!(view instanceof RevisionView)) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn this.hasEqualForest(view);\n\t}\n}\n\n/**\n * An view of a distributed tree that is part of an ongoing transaction between `RevisionView`s.\n * @public\n */\nexport class TransactionView extends TreeView {\n\t/** Conclude a transaction by generating an immutable `RevisionView` from this view */\n\tpublic close(): RevisionView {\n\t\treturn new RevisionView(this.root, this.forest);\n\t}\n\n\t/** Inserts all nodes in a NodeSequence into the view */\n\tpublic addNodes(sequence: Iterable<TreeViewNode>): TransactionView {\n\t\treturn new TransactionView(this.root, this.forest.add(sequence));\n\t}\n\n\t/** Remove all nodes with the given ids from the view */\n\tpublic deleteNodes(nodes: Iterable<NodeId>): TransactionView {\n\t\treturn new TransactionView(this.root, this.forest.delete(nodes, true));\n\t}\n\n\t/**\n\t * Parents a set of detached nodes at a specified place.\n\t * @param nodesToAttach - the nodes to parent in the specified place. The nodes must already be present in the view.\n\t * @param place - the location to insert the nodes.\n\t */\n\tpublic attachRange(nodesToAttach: readonly NodeId[], place: TreeViewPlace): TransactionView {\n\t\tconst { parent, label } = place.trait;\n\t\tconst index = this.findIndexWithinTrait(place);\n\t\treturn new TransactionView(this.root, this.forest.attachRangeOfChildren(parent, label, index, nodesToAttach));\n\t}\n\n\t/**\n\t * Detaches a range of nodes from their parent. The detached nodes remain in the view.\n\t * @param rangeToDetach - the range of nodes to detach\n\t */\n\tpublic detachRange(rangeToDetach: TreeViewRange): { view: TransactionView; detached: readonly NodeId[] } {\n\t\tconst { start, end } = rangeToDetach;\n\t\tconst { trait: traitLocation } = start;\n\t\tconst { parent, label } = traitLocation;\n\t\tconst startIndex = this.findIndexWithinTrait(start);\n\t\tconst endIndex = this.findIndexWithinTrait(end);\n\t\tconst { forest, detached } = this.forest.detachRangeOfChildren(parent, label, startIndex, endIndex);\n\t\treturn { view: new TransactionView(this.root, forest), detached };\n\t}\n\n\t/**\n\t * Sets or overwrites a node's value. The node must exist in this view.\n\t * @param nodeId - the id of the node\n\t * @param value - the new value\n\t */\n\tpublic setNodeValue(nodeId: NodeId, value: Payload): TransactionView {\n\t\treturn new TransactionView(this.root, this.forest.setValue(nodeId, value));\n\t}\n\n\tpublic equals(view: TreeView): boolean {\n\t\tif (!(view instanceof TransactionView)) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn this.hasEqualForest(view);\n\t}\n}\n\n/**\n * Transform an input tree into a list of {@link TreeViewNode}s.\n * @param tree - the input tree\n * @param convert - a conversion function that will run on each node in the input tree to produce the output nodes.\n * Returning undefined means that conversion for the given node was impossible, at which time the entire tree conversion will be aborted\n * and return undefined.\n */\nexport function convertTreeNodesToViewNodes<\n\tTIn extends HasVariadicTraits<TIn>,\n\tTOut extends TreeViewNode = TreeViewNode\n>(root: TIn, convert: (node: TIn) => Omit<TOut, 'traits'>): TOut[];\n\n/**\n * Transform an input tree into a list of {@link TreeViewNode}s.\n * @param tree - the input tree\n * @param convert - a conversion function that will run on each node in the input tree to produce the output nodes.\n */\nexport function convertTreeNodesToViewNodes<\n\tTIn extends HasVariadicTraits<TIn>,\n\tTOut extends TreeViewNode = TreeViewNode\n>(root: TIn, convert: (node: TIn) => Omit<TOut, 'traits'> | undefined): TOut[] | undefined;\n\n/**\n * Transform an input tree into a list of {@link TreeViewNode}s.\n * @param tree - the input tree\n * @param convert - a conversion function that will run on each node in the input tree to produce the output nodes.\n * Returning undefined means that conversion for the given node was impossible, at which time the entire tree conversion will be aborted\n * and return undefined.\n */\nexport function convertTreeNodesToViewNodes<\n\tTIn extends HasVariadicTraits<TIn>,\n\tTOut extends TreeViewNode = TreeViewNode\n>(root: TIn, convert: (node: TIn) => Omit<TOut, 'traits'> | undefined): TOut[] | undefined {\n\tconst convertedRoot = convert(root) as Mutable<TOut>;\n\tif (convertedRoot === undefined || root.traits === undefined) {\n\t\treturn undefined;\n\t}\n\t// `convertedRoot` might be the same as `root`, in which case stash the children of `root` before wiping them from `convertedRoot`\n\tconst rootTraits = (root as unknown as TOut) === convertedRoot ? { traits: root.traits } : root;\n\tconvertedRoot.traits = new Map();\n\tconst pendingNodes: {\n\t\tchildIterator: Iterator<[TraitLabel, TIn]>;\n\t\tnewNode: Mutable<TOut>;\n\t}[] = [{ childIterator: iterateChildren(rootTraits)[Symbol.iterator](), newNode: convertedRoot }];\n\tconst resultNodes: TOut[] = [];\n\n\twhile (pendingNodes.length > 0) {\n\t\tconst { childIterator, newNode } = pendingNodes[pendingNodes.length - 1] ?? fail('Undefined node');\n\t\tconst { value, done } = childIterator.next();\n\t\tif (done === true) {\n\t\t\tresultNodes.push(\n\t\t\t\tpendingNodes.pop()?.newNode ?? fail('covertTreeNodesToViewNodes incorrectly coordinated parentage')\n\t\t\t);\n\t\t} else {\n\t\t\tconst [traitLabel, child] = value as [TraitLabel, TIn];\n\t\t\tconst convertedChild = convert(child) as TOut;\n\t\t\tif (convertedChild === undefined) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tif (child.traits !== undefined) {\n\t\t\t\tconst childTraits = (child as unknown as TOut) === convertedChild ? { traits: child.traits } : child;\n\t\t\t\t(convertedChild as Mutable<TOut>).traits = new Map();\n\t\t\t\tpendingNodes.push({\n\t\t\t\t\tchildIterator: iterateChildren(childTraits)[Symbol.iterator](),\n\t\t\t\t\tnewNode: convertedChild,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst newTraits = newNode.traits as MutableMap<TOut['traits']>;\n\t\t\tlet newTrait = newTraits.get(traitLabel);\n\t\t\tif (newTrait === undefined) {\n\t\t\t\tnewTrait = [];\n\t\t\t\tnewTraits.set(traitLabel, newTrait);\n\t\t\t}\n\t\t\t(newTrait as NodeId[]).push(convertedChild.identifier);\n\t\t}\n\t}\n\n\treturn resultNodes;\n}\n\n/**\n * Returns an iterable of the supplied node's traits in a stable order.\n */\nexport function* iterateChildren<T>(hasTraits: HasVariadicTraits<T>): Iterable<[TraitLabel, T]> {\n\tif (hasTraits.traits !== undefined) {\n\t\tfor (const [label, trait] of Object.entries(hasTraits.traits).sort()) {\n\t\t\tif (trait !== undefined) {\n\t\t\t\tif (isTreeNodeSequence(trait)) {\n\t\t\t\t\tfor (const child of trait) {\n\t\t\t\t\t\tyield [label as TraitLabel, child];\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tyield [label as TraitLabel, trait];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction isTreeNodeSequence<TChild>(sequence: TreeNodeSequence<TChild> | TChild): sequence is TreeNodeSequence<TChild> {\n\treturn Array.isArray(sequence);\n}\n"]}
|
package/lib/SharedTree.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { IFluidSerializer, ISharedObjectEvents, SharedObject } from '@fluidframe
|
|
|
7
7
|
import { ITelemetryLogger, ITelemetryProperties } from '@fluidframework/common-definitions';
|
|
8
8
|
import { ISummaryTreeWithStats } from '@fluidframework/runtime-definitions';
|
|
9
9
|
import { OrderedEditSet } from './EditLog';
|
|
10
|
-
import { EditId, NodeId, StableNodeId } from './Identifiers';
|
|
10
|
+
import { EditId, NodeId, StableNodeId, AttributionId } from './Identifiers';
|
|
11
11
|
import { LogViewer } from './LogViewer';
|
|
12
12
|
import { ReconciliationPath } from './ReconciliationPath';
|
|
13
13
|
import { ChangeInternal, Edit, EditStatus, SharedTreeSummaryBase, WriteFormat, InternalizedChange } from './persisted-types';
|
|
@@ -15,15 +15,68 @@ import { NodeIdContext } from './NodeIdUtilities';
|
|
|
15
15
|
import { RevisionView } from './RevisionView';
|
|
16
16
|
import { Change } from './ChangeTypes';
|
|
17
17
|
import { TransactionInternal } from './TransactionInternal';
|
|
18
|
+
/**
|
|
19
|
+
* The write format and associated options used to construct a `SharedTree`
|
|
20
|
+
* @public
|
|
21
|
+
*/
|
|
22
|
+
export declare type SharedTreeArgs<WF extends WriteFormat = WriteFormat> = [writeFormat: WF, options?: SharedTreeOptions<WF>];
|
|
23
|
+
/**
|
|
24
|
+
* The type of shared tree options for a given write format
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
27
|
+
export declare type SharedTreeOptions<WF extends WriteFormat, HistoryCompatibility extends 'Forwards' | 'None' = 'Forwards'> = Omit<WF extends WriteFormat.v0_0_2 ? SharedTreeOptions_0_0_2 : WF extends WriteFormat.v0_1_1 ? SharedTreeOptions_0_1_1 : never, HistoryCompatibility extends 'Forwards' ? 'summarizeHistory' : never>;
|
|
28
|
+
/**
|
|
29
|
+
* Configuration options for a SharedTree with write format 0.0.2
|
|
30
|
+
* @public
|
|
31
|
+
*/
|
|
32
|
+
export interface SharedTreeOptions_0_0_2 {
|
|
33
|
+
/**
|
|
34
|
+
* Determines if the history is included in summaries.
|
|
35
|
+
*
|
|
36
|
+
* Warning: enabling history summarization incurs a permanent cost in the document. It is not possible to disable history summarization
|
|
37
|
+
* later once it has been enabled, and thus the history cannot be safely deleted.
|
|
38
|
+
*
|
|
39
|
+
* On 0.1.1 documents, due to current code limitations, this parameter is only impactful for newly created documents.
|
|
40
|
+
* `SharedTree`s which load existing documents will summarize history if and only if the loaded summary included history.
|
|
41
|
+
*
|
|
42
|
+
* The technical limitations here relate to clients with mixed versions collaborating.
|
|
43
|
+
* In the future we may allow modification of whether or not a particular document saves history, but only via a consensus mechanism.
|
|
44
|
+
* See the skipped test in SharedTreeFuzzTests.ts for more details on this issue.
|
|
45
|
+
* See docs/Breaking-Change-Migration for more details on the consensus scheme.
|
|
46
|
+
*/
|
|
47
|
+
summarizeHistory?: boolean;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Configuration options for a SharedTree with write format 0.1.1
|
|
51
|
+
* @public
|
|
52
|
+
*/
|
|
53
|
+
export interface SharedTreeOptions_0_1_1 {
|
|
54
|
+
/**
|
|
55
|
+
* Determines if the history is included in summaries and if edit chunks are uploaded when they are full.
|
|
56
|
+
*
|
|
57
|
+
* Warning: enabling history summarization incurs a permanent cost in the document. It is not possible to disable history summarization
|
|
58
|
+
* later once it has been enabled, and thus the history cannot be safely deleted.
|
|
59
|
+
*
|
|
60
|
+
* On 0.1.1 documents, due to current code limitations, this parameter is only impactful for newly created documents.
|
|
61
|
+
* `SharedTree`s which load existing documents will summarize history if and only if the loaded summary included history.
|
|
62
|
+
*
|
|
63
|
+
* The technical limitations here relate to clients with mixed versions collaborating.
|
|
64
|
+
* In the future we may allow modification of whether or not a particular document saves history, but only via a consensus mechanism.
|
|
65
|
+
* See the skipped test in SharedTreeFuzzTests.ts for more details on this issue.
|
|
66
|
+
* See docs/Breaking-Change-Migration for more details on the consensus scheme.
|
|
67
|
+
*/
|
|
68
|
+
summarizeHistory?: false | {
|
|
69
|
+
uploadEditChunks: boolean;
|
|
70
|
+
};
|
|
71
|
+
/** a UUID that identifies the user of this tree; all node IDs generated by this tree will be associated with this UUID */
|
|
72
|
+
attributionId?: AttributionId;
|
|
73
|
+
}
|
|
18
74
|
/**
|
|
19
75
|
* Factory for SharedTree.
|
|
20
76
|
* Includes history in the summary.
|
|
21
77
|
* @public
|
|
22
78
|
*/
|
|
23
79
|
export declare class SharedTreeFactory implements IChannelFactory {
|
|
24
|
-
private readonly writeFormat;
|
|
25
|
-
private readonly summarizeHistory;
|
|
26
|
-
private expensiveValidation;
|
|
27
80
|
/**
|
|
28
81
|
* {@inheritDoc @fluidframework/shared-object-base#ISharedObjectFactory."type"}
|
|
29
82
|
*/
|
|
@@ -32,18 +85,16 @@ export declare class SharedTreeFactory implements IChannelFactory {
|
|
|
32
85
|
* {@inheritDoc @fluidframework/shared-object-base#ISharedObjectFactory.attributes}
|
|
33
86
|
*/
|
|
34
87
|
static Attributes: IChannelAttributes;
|
|
88
|
+
private readonly args;
|
|
35
89
|
/**
|
|
36
90
|
* Get a factory for SharedTree to register with the data store.
|
|
37
91
|
* @param writeFormat - Determines the format version the SharedTree will write ops and summaries in. See [the write format
|
|
38
92
|
* documentation](../docs/Write-Format.md) for more information.
|
|
39
|
-
* @param
|
|
40
|
-
* See the [breaking change migration documentation](docs/Breaking-Change-Migration) for more details on this scheme.
|
|
41
|
-
* @param expensiveValidation - Enables expensive asserts on SharedTree.
|
|
93
|
+
* @param options - Configuration options for this tree
|
|
42
94
|
* @returns A factory that creates `SharedTree`s and loads them from storage.
|
|
43
95
|
*/
|
|
44
|
-
constructor(
|
|
45
|
-
|
|
46
|
-
}, expensiveValidation?: boolean);
|
|
96
|
+
constructor(...args: SharedTreeArgs<WriteFormat.v0_0_2>);
|
|
97
|
+
constructor(...args: SharedTreeArgs<WriteFormat.v0_1_1>);
|
|
47
98
|
/**
|
|
48
99
|
* {@inheritDoc @fluidframework/shared-object-base#ISharedObjectFactory."type"}
|
|
49
100
|
*/
|
|
@@ -61,7 +112,7 @@ export declare class SharedTreeFactory implements IChannelFactory {
|
|
|
61
112
|
* @param runtime - data store runtime that owns the new SharedTree
|
|
62
113
|
* @param id - optional name for the SharedTree
|
|
63
114
|
*/
|
|
64
|
-
create(runtime: IFluidDataStoreRuntime, id: string
|
|
115
|
+
create(runtime: IFluidDataStoreRuntime, id: string): SharedTree;
|
|
65
116
|
private createSharedTree;
|
|
66
117
|
}
|
|
67
118
|
/**
|
|
@@ -141,33 +192,30 @@ export declare type SequencedEditAppliedHandler = (args: SequencedEditAppliedEve
|
|
|
141
192
|
*/
|
|
142
193
|
export declare class SharedTree extends SharedObject<ISharedTreeEvents> implements NodeIdContext {
|
|
143
194
|
private writeFormat;
|
|
144
|
-
private readonly expensiveValidation;
|
|
145
195
|
/**
|
|
146
196
|
* Create a new SharedTree. It will contain the default value (see initialTree).
|
|
147
197
|
*/
|
|
148
198
|
static create(runtime: IFluidDataStoreRuntime, id?: string): SharedTree;
|
|
149
199
|
/**
|
|
150
200
|
* Get a factory for SharedTree to register with the data store.
|
|
151
|
-
* @param summarizeHistory - Determines if the history is included in summaries and if edit chunks are uploaded when they are full.
|
|
152
|
-
*
|
|
153
|
-
* On 0.1.1 documents, due to current code limitations, this parameter is only impactful for newly created documents.
|
|
154
|
-
* `SharedTree`s which load existing documents will summarize history if and only if the loaded summary included history.
|
|
155
|
-
*
|
|
156
|
-
* The technical limitations here relate to clients with mixed versions collaborating.
|
|
157
|
-
* In the future we may allow modification of whether or not a particular document saves history, but only via a consensus mechanism.
|
|
158
|
-
* See the skipped test in SharedTreeFuzzTests.ts for more details on this issue.
|
|
159
|
-
* See docs/Breaking-Change-Migration for more details on the consensus scheme.
|
|
160
201
|
* @param writeFormat - Determines the format version the SharedTree will write ops and summaries in.
|
|
161
202
|
* This format may be updated to a newer (supported) version at runtime if a collaborating shared-tree
|
|
162
203
|
* that was initialized with a newer write version connects to the session. Care must be taken when changing this value,
|
|
163
204
|
* as a staged rollout must of occurred such that all collaborating clients must have the code to read at least the version
|
|
164
205
|
* written.
|
|
165
206
|
* See [the write format documentation](../docs/Write-Format.md) for more information.
|
|
207
|
+
* @param options - Configuration options for this tree
|
|
166
208
|
* @returns A factory that creates `SharedTree`s and loads them from storage.
|
|
167
209
|
*/
|
|
168
|
-
static getFactory(
|
|
169
|
-
|
|
170
|
-
|
|
210
|
+
static getFactory(...args: SharedTreeArgs<WriteFormat.v0_0_2>): SharedTreeFactory;
|
|
211
|
+
static getFactory(...args: SharedTreeArgs<WriteFormat.v0_1_1>): SharedTreeFactory;
|
|
212
|
+
/**
|
|
213
|
+
* The UUID used for attribution of nodes created by this SharedTree. All shared trees with a write format of 0.1.1 or
|
|
214
|
+
* greater have a unique attribution ID which may be configured in the constructor. All other shared trees (i.e. those
|
|
215
|
+
* with a write format of 0.0.2) use the nil UUID as their attribution ID.
|
|
216
|
+
* @public
|
|
217
|
+
*/
|
|
218
|
+
get attributionId(): AttributionId;
|
|
171
219
|
private idCompressor;
|
|
172
220
|
private readonly idNormalizer;
|
|
173
221
|
private interner;
|
|
@@ -195,18 +243,22 @@ export declare class SharedTree extends SharedObject<ISharedTreeEvents> implemen
|
|
|
195
243
|
private readonly processSequencedEditResult;
|
|
196
244
|
private summarizeHistory;
|
|
197
245
|
private uploadEditChunks;
|
|
246
|
+
private getHistoryPolicy;
|
|
198
247
|
/**
|
|
199
|
-
* Create a new
|
|
248
|
+
* Create a new SharedTree.
|
|
200
249
|
* @param runtime - The runtime the SharedTree will be associated with
|
|
201
250
|
* @param id - Unique ID for the SharedTree
|
|
202
251
|
* @param writeFormat - Determines the format version the SharedTree will write ops and summaries in. See [the write format
|
|
203
252
|
* documentation](../docs/Write-Format.md) for more information.
|
|
204
|
-
* @param
|
|
205
|
-
|
|
253
|
+
* @param options - Configuration options for this tree
|
|
254
|
+
*/
|
|
255
|
+
constructor(runtime: IFluidDataStoreRuntime, id: string, ...args: SharedTreeArgs<WriteFormat.v0_0_2>);
|
|
256
|
+
constructor(runtime: IFluidDataStoreRuntime, id: string, ...args: SharedTreeArgs<WriteFormat.v0_1_1>);
|
|
257
|
+
/**
|
|
258
|
+
* The write format version currently used by this `SharedTree`. This is always initialized to the write format
|
|
259
|
+
* passed to the tree's constructor, but it may automatically upgrade over time (e.g. when connected to another
|
|
260
|
+
* SharedTree with a higher write format, or when loading a summary with a higher write format).
|
|
206
261
|
*/
|
|
207
|
-
constructor(runtime: IFluidDataStoreRuntime, id: string, writeFormat: WriteFormat, summarizeHistory?: false | {
|
|
208
|
-
uploadEditChunks: boolean;
|
|
209
|
-
}, expensiveValidation?: boolean);
|
|
210
262
|
getWriteFormat(): WriteFormat;
|
|
211
263
|
/**
|
|
212
264
|
* Re-computes currentIsOldest and emits an event if it has changed.
|
|
@@ -268,6 +320,13 @@ export declare class SharedTree extends SharedObject<ISharedTreeEvents> implemen
|
|
|
268
320
|
* @public
|
|
269
321
|
*/
|
|
270
322
|
tryConvertToNodeId(id: StableNodeId): NodeId | undefined;
|
|
323
|
+
/**
|
|
324
|
+
* Returns the attribution ID associated with the SharedTree that generated the given node ID. This is generally only useful for clients
|
|
325
|
+
* with a write format of 0.1.1 or greater since older clients cannot be given an attribution ID and will always use the default
|
|
326
|
+
* `attributionId` of the tree.
|
|
327
|
+
* @public
|
|
328
|
+
*/
|
|
329
|
+
attributeNodeId(id: NodeId): AttributionId;
|
|
271
330
|
/**
|
|
272
331
|
* @returns the edit history of the tree.
|
|
273
332
|
* @public
|
|
@@ -275,9 +334,12 @@ export declare class SharedTree extends SharedObject<ISharedTreeEvents> implemen
|
|
|
275
334
|
get edits(): OrderedEditSet<InternalizedChange>;
|
|
276
335
|
private deserializeHandle;
|
|
277
336
|
/**
|
|
278
|
-
* Uploads the edit chunk and
|
|
337
|
+
* Uploads the edit chunk and submits a `SharedTreeHandleOp`.
|
|
338
|
+
* This method is fire-and-forget and will swallow any errors that occur during upload or the `onUploadComplete` hook.
|
|
339
|
+
* If the upload or op submission does fail then a future client will attempt the submission instead.
|
|
279
340
|
*/
|
|
280
341
|
private uploadEditChunk;
|
|
342
|
+
private uploadEditChunkAsync;
|
|
281
343
|
/**
|
|
282
344
|
* {@inheritDoc @fluidframework/shared-object-base#SharedObject.summarizeCore}
|
|
283
345
|
*/
|