@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
|
@@ -8,11 +8,14 @@
|
|
|
8
8
|
import BTree from 'sorted-btree';
|
|
9
9
|
import {
|
|
10
10
|
assert,
|
|
11
|
+
hasLength,
|
|
11
12
|
assertNotUndefined,
|
|
12
13
|
compareFiniteNumbers,
|
|
14
|
+
compareFiniteNumbersReversed,
|
|
13
15
|
compareMaps,
|
|
14
16
|
compareStrings,
|
|
15
17
|
fail,
|
|
18
|
+
getOrCreate,
|
|
16
19
|
Mutable,
|
|
17
20
|
setPropertyIfDefined,
|
|
18
21
|
} from '../Common';
|
|
@@ -24,7 +27,10 @@ import {
|
|
|
24
27
|
OpSpaceCompressedId,
|
|
25
28
|
SessionId,
|
|
26
29
|
CompressedId,
|
|
30
|
+
UuidString,
|
|
31
|
+
AttributionId,
|
|
27
32
|
} from '../Identifiers';
|
|
33
|
+
import { assertIsStableId, assertIsUuidString, isStableId } from '../UuidUtilities';
|
|
28
34
|
import { AppendOnlyDoublySortedMap, AppendOnlySortedMap } from './AppendOnlySortedMap';
|
|
29
35
|
import { getIds } from './IdRange';
|
|
30
36
|
import {
|
|
@@ -34,12 +40,9 @@ import {
|
|
|
34
40
|
numericUuidFromStableId,
|
|
35
41
|
NumericUuid,
|
|
36
42
|
stableIdFromNumericUuid,
|
|
37
|
-
isStableId,
|
|
38
|
-
assertIsStableId,
|
|
39
43
|
ensureSessionUuid,
|
|
40
44
|
} from './NumericUuid';
|
|
41
45
|
import type {
|
|
42
|
-
AttributionInfo,
|
|
43
46
|
IdCreationRange,
|
|
44
47
|
SerializedCluster,
|
|
45
48
|
SerializedClusterOverrides,
|
|
@@ -114,9 +117,9 @@ interface Session {
|
|
|
114
117
|
lastFinalizedLocalId: LocalCompressedId | undefined;
|
|
115
118
|
|
|
116
119
|
/**
|
|
117
|
-
* The attribution
|
|
120
|
+
* The attribution ID for the session
|
|
118
121
|
*/
|
|
119
|
-
|
|
122
|
+
readonly attributionId: AttributionId;
|
|
120
123
|
}
|
|
121
124
|
|
|
122
125
|
/**
|
|
@@ -309,7 +312,14 @@ export class IdCompressor {
|
|
|
309
312
|
}
|
|
310
313
|
|
|
311
314
|
/**
|
|
312
|
-
*
|
|
315
|
+
* The UUID used for attribution of identities created by this compressor
|
|
316
|
+
*/
|
|
317
|
+
public get attributionId(): AttributionId {
|
|
318
|
+
return this.localSession.attributionId;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Session ID -\> data about the session's current cluster.
|
|
313
323
|
* Sessions are mutable, and thus should only be created via `createSession`.
|
|
314
324
|
*/
|
|
315
325
|
private readonly sessions = new Map<SessionId, Session>();
|
|
@@ -319,11 +329,6 @@ export class IdCompressor {
|
|
|
319
329
|
*/
|
|
320
330
|
private readonly localSession: Session;
|
|
321
331
|
|
|
322
|
-
/**
|
|
323
|
-
* Boolean to track whether attribution has been sent with an ID range yet. Prevents unnecessary bloat of ranges.
|
|
324
|
-
*/
|
|
325
|
-
private sentAttributionInfo = false;
|
|
326
|
-
|
|
327
332
|
/**
|
|
328
333
|
* The base final ID of the next cluster to be created.
|
|
329
334
|
*/
|
|
@@ -348,18 +353,14 @@ export class IdCompressor {
|
|
|
348
353
|
|
|
349
354
|
/**
|
|
350
355
|
* Maps local IDs to the cluster they belong to (if any). This can be used to efficiently convert a local ID to a
|
|
351
|
-
* final ID by finding an entry
|
|
356
|
+
* final ID by finding an entry \<= a given local ID (to find the cluster it is associated with) and checking
|
|
352
357
|
* it against `numFinalizedLocalIds`.
|
|
353
358
|
*/
|
|
354
359
|
private readonly localIdToCluster: AppendOnlyDoublySortedMap<
|
|
355
360
|
LocalCompressedId,
|
|
356
361
|
[FinalCompressedId, IdCluster],
|
|
357
362
|
FinalCompressedId
|
|
358
|
-
> = new AppendOnlyDoublySortedMap(
|
|
359
|
-
compareFiniteNumbersReversed,
|
|
360
|
-
(value) => value[0],
|
|
361
|
-
IdCompressor.overrideComparator
|
|
362
|
-
);
|
|
363
|
+
> = new AppendOnlyDoublySortedMap(compareFiniteNumbersReversed, (value) => value[0], compareFiniteNumbers);
|
|
363
364
|
|
|
364
365
|
/**
|
|
365
366
|
* Contains entries for cluster base UUIDs and override strings (both local and final).
|
|
@@ -390,20 +391,26 @@ export class IdCompressor {
|
|
|
390
391
|
}
|
|
391
392
|
|
|
392
393
|
/**
|
|
393
|
-
* @param localSessionId the `IdCompressor`'s current local session ID.
|
|
394
|
-
* @param reservedIdCount the number of IDs that will be known by this compressor without relying on consensus.
|
|
395
|
-
* for a given session must be constant for any compressor that contains IDs from that session
|
|
396
|
-
* compressor must have the same reservedIdCount forever). Compressors with different
|
|
397
|
-
* IDs.
|
|
398
|
-
* @param
|
|
394
|
+
* @param localSessionId - the `IdCompressor`'s current local session ID.
|
|
395
|
+
* @param reservedIdCount - the number of IDs that will be known by this compressor without relying on consensus.
|
|
396
|
+
* The reserved ID count for a given session must be constant for any compressor that contains IDs from that session
|
|
397
|
+
* (i.e. any DDS that uses the ID compressor must have the same reservedIdCount forever). Compressors with different
|
|
398
|
+
* reserved ID counts will fail to synchronize their IDs.
|
|
399
|
+
* @param attributionId - a UUID that identifies the user of this instance of the compressor. IDs created by this
|
|
400
|
+
* compressor will be associated with this UUID and can be queried later via `attributeID`. If no UUID is provided,
|
|
401
|
+
* this compressor will generate its own. An `AttributionId` is an `UuidString` which may be validated via
|
|
402
|
+
* {@link isUuidString} or generated via {@link generateStableId}.
|
|
399
403
|
*/
|
|
400
404
|
public constructor(
|
|
401
405
|
public readonly localSessionId: SessionId,
|
|
402
406
|
public readonly reservedIdCount: number,
|
|
403
|
-
|
|
407
|
+
attributionId?: AttributionId
|
|
404
408
|
) {
|
|
405
409
|
assert(reservedIdCount >= 0, 'reservedIdCount must be non-negative');
|
|
406
|
-
|
|
410
|
+
if (attributionId !== undefined) {
|
|
411
|
+
assertIsUuidString(attributionId);
|
|
412
|
+
}
|
|
413
|
+
this.localSession = this.createSession(localSessionId, attributionId);
|
|
407
414
|
if (reservedIdCount > 0) {
|
|
408
415
|
const clusterCapacity = this.clusterCapacity;
|
|
409
416
|
this.clusterCapacity = reservedIdCount;
|
|
@@ -423,33 +430,29 @@ export class IdCompressor {
|
|
|
423
430
|
/**
|
|
424
431
|
* Creates a session object for the supplied ID.
|
|
425
432
|
* Must only be called once per ID.
|
|
426
|
-
* @param sessionId the ID for the session
|
|
433
|
+
* @param sessionId - the ID for the session
|
|
427
434
|
* @returns the session object for the supplied ID
|
|
428
435
|
*/
|
|
429
|
-
private createSession(sessionId: SessionId,
|
|
436
|
+
private createSession(sessionId: SessionId, attributionId: AttributionId | undefined): Session {
|
|
437
|
+
assert(!this.clustersAndOverridesInversion.has(sessionId));
|
|
430
438
|
const existingSession = this.sessions.get(sessionId);
|
|
431
439
|
if (existingSession !== undefined) {
|
|
432
440
|
fail('createSession must only be called once for each session ID.');
|
|
433
441
|
}
|
|
434
442
|
const sessionUuid = numericUuidFromStableId(sessionId);
|
|
435
|
-
assert(!this.clustersAndOverridesInversion.has(sessionId));
|
|
436
443
|
const session: Session = {
|
|
437
444
|
sessionUuid,
|
|
438
445
|
currentClusterDetails: undefined,
|
|
439
446
|
lastFinalizedLocalId: undefined,
|
|
447
|
+
attributionId: attributionId ?? sessionId,
|
|
440
448
|
};
|
|
441
|
-
setPropertyIfDefined(attributionInfo, session, 'attributionInfo');
|
|
442
449
|
this.sessions.set(sessionId, session);
|
|
443
450
|
return session;
|
|
444
451
|
}
|
|
445
452
|
|
|
446
|
-
private tryGetSession(sessionId: SessionId): Session | undefined {
|
|
447
|
-
return this.sessions.get(sessionId);
|
|
448
|
-
}
|
|
449
|
-
|
|
450
453
|
/**
|
|
451
454
|
* Return the nth reserved ID.
|
|
452
|
-
* @param index the index of the ID to return
|
|
455
|
+
* @param index - the index of the ID to return
|
|
453
456
|
*/
|
|
454
457
|
public getReservedId(index: number): SessionSpaceCompressedId & FinalCompressedId {
|
|
455
458
|
if (index < 0 || index >= this.reservedIdCount) {
|
|
@@ -472,17 +475,17 @@ export class IdCompressor {
|
|
|
472
475
|
}
|
|
473
476
|
|
|
474
477
|
/**
|
|
475
|
-
* Returns the attribution
|
|
478
|
+
* Returns the attribution ID associated with the compressor that created the ID
|
|
476
479
|
*/
|
|
477
|
-
public attributeId(id: SessionSpaceCompressedId):
|
|
480
|
+
public attributeId(id: SessionSpaceCompressedId): AttributionId {
|
|
478
481
|
const opSpaceNormalizedId = this.normalizeToOpSpace(id);
|
|
479
482
|
if (isLocalId(opSpaceNormalizedId)) {
|
|
480
|
-
return this.
|
|
483
|
+
return this.attributionId;
|
|
481
484
|
}
|
|
482
485
|
const [_, cluster] =
|
|
483
486
|
this.getClusterForFinalId(opSpaceNormalizedId) ?? fail('Cluster does not exist for final ID');
|
|
484
487
|
|
|
485
|
-
return cluster.session.
|
|
488
|
+
return cluster.session.attributionId;
|
|
486
489
|
}
|
|
487
490
|
|
|
488
491
|
/**
|
|
@@ -505,7 +508,7 @@ export class IdCompressor {
|
|
|
505
508
|
},
|
|
506
509
|
};
|
|
507
510
|
} else {
|
|
508
|
-
const session = this.
|
|
511
|
+
const session = this.sessions.get(sessionId) ?? fail('Unknown session, range may not be finalized.');
|
|
509
512
|
const firstNumericUuid = incrementUuid(session.sessionUuid, -first - 1);
|
|
510
513
|
const firstFinal =
|
|
511
514
|
this.compressNumericUuid(firstNumericUuid) ??
|
|
@@ -560,18 +563,19 @@ export class IdCompressor {
|
|
|
560
563
|
const lastTakenNormalized = this.lastTakenLocalId ?? 0;
|
|
561
564
|
assert(lastLocalInRange <= lastTakenNormalized);
|
|
562
565
|
|
|
566
|
+
// The attribution ID is sent with each range, but it can be elided after the first IDs are allocated.
|
|
567
|
+
const sendAttributionId = this.lastTakenLocalId === undefined;
|
|
568
|
+
|
|
563
569
|
let ids: IdCreationRange.Ids | undefined;
|
|
564
570
|
if (lastLocalInRange !== lastTakenNormalized) {
|
|
565
571
|
const firstLocalInRange = (lastTakenNormalized - 1) as UnackedLocalId;
|
|
566
|
-
const
|
|
572
|
+
const overrides = [
|
|
567
573
|
...this.localOverrides.getRange(
|
|
568
574
|
(lastTakenNormalized - 1) as LocalCompressedId,
|
|
569
575
|
lastLocalInRange as LocalCompressedId
|
|
570
576
|
),
|
|
571
|
-
];
|
|
572
|
-
if (
|
|
573
|
-
// Cast: typecript 4.4.4 doesn't infer that `localOverrides` has at least one element and is therefore an `Overrides`
|
|
574
|
-
const overrides = localOverrides as unknown as IdCreationRange.Overrides;
|
|
577
|
+
] as (readonly [UnackedLocalId, string])[];
|
|
578
|
+
if (hasLength(overrides, 1)) {
|
|
575
579
|
assert(overrides[0][0] <= firstLocalInRange);
|
|
576
580
|
assert(overrides[overrides.length - 1][0] >= lastLocalInRange);
|
|
577
581
|
ids = {
|
|
@@ -591,9 +595,8 @@ export class IdCompressor {
|
|
|
591
595
|
}
|
|
592
596
|
|
|
593
597
|
const range: Mutable<IdCreationRange> = { sessionId: this.localSessionId };
|
|
594
|
-
if (
|
|
595
|
-
|
|
596
|
-
this.sentAttributionInfo = true;
|
|
598
|
+
if (this.attributionId !== this.localSessionId && sendAttributionId) {
|
|
599
|
+
range.attributionId = this.attributionId;
|
|
597
600
|
}
|
|
598
601
|
|
|
599
602
|
if (ids === undefined) {
|
|
@@ -611,18 +614,17 @@ export class IdCompressor {
|
|
|
611
614
|
|
|
612
615
|
/**
|
|
613
616
|
* Finalizes the supplied range of IDs (which may be from either a remote or local session).
|
|
614
|
-
* @param range the range of session-local IDs to finalize.
|
|
617
|
+
* @param range - the range of session-local IDs to finalize.
|
|
615
618
|
*/
|
|
616
619
|
public finalizeCreationRange(range: IdCreationRange): void {
|
|
617
|
-
const { sessionId,
|
|
620
|
+
const { sessionId, attributionId } = range;
|
|
618
621
|
|
|
619
622
|
const isLocal = sessionId === this.localSessionId;
|
|
620
|
-
|
|
623
|
+
const session = this.sessions.get(sessionId) ?? this.createSession(sessionId, attributionId);
|
|
621
624
|
assert(
|
|
622
|
-
range.
|
|
623
|
-
'
|
|
625
|
+
range.attributionId === undefined || range.attributionId === session.attributionId,
|
|
626
|
+
"A session's attribution ID may never be modified."
|
|
624
627
|
);
|
|
625
|
-
session ??= this.createSession(sessionId, attributionInfo);
|
|
626
628
|
|
|
627
629
|
const ids = getIds(range);
|
|
628
630
|
if (ids === undefined) {
|
|
@@ -765,11 +767,7 @@ export class IdCompressor {
|
|
|
765
767
|
cluster.overrides ??= new Map();
|
|
766
768
|
|
|
767
769
|
const inversionKey = IdCompressor.createInversionKey(override);
|
|
768
|
-
|
|
769
|
-
const existingIds = this.getExistingIdsForNewOverride(inversionKey, true) as [
|
|
770
|
-
LocalCompressedId,
|
|
771
|
-
FinalCompressedId
|
|
772
|
-
];
|
|
770
|
+
const existingIds = this.getExistingIdsForNewOverride(inversionKey, true);
|
|
773
771
|
let overrideForCluster: string | FinalCompressedId;
|
|
774
772
|
let associatedLocal: LocalCompressedId | undefined;
|
|
775
773
|
if (existingIds !== undefined) {
|
|
@@ -870,8 +868,7 @@ export class IdCompressor {
|
|
|
870
868
|
}
|
|
871
869
|
|
|
872
870
|
private static createInversionKey(inversionKey: string): InversionKey {
|
|
873
|
-
|
|
874
|
-
return isStableId(inversionKey) ? inversionKey : (`${nonStableOverridePrefix}${inversionKey}` as InversionKey);
|
|
871
|
+
return isStableId(inversionKey) ? inversionKey : `${nonStableOverridePrefix}${inversionKey}`;
|
|
875
872
|
}
|
|
876
873
|
|
|
877
874
|
private static isStableInversionKey(inversionKey: InversionKey): inversionKey is StableId {
|
|
@@ -940,7 +937,7 @@ export class IdCompressor {
|
|
|
940
937
|
|
|
941
938
|
/**
|
|
942
939
|
* Check if `a` might be within `range` of `b`, where both are treated as hex numbers.
|
|
943
|
-
* @param range an integer
|
|
940
|
+
* @param range - an integer
|
|
944
941
|
*/
|
|
945
942
|
private static uuidsMightCollide(a: StableId, b: StableId, range: number): boolean {
|
|
946
943
|
// Check if any of the UUIDs in the cluster collide (i.e. any in [base, base + capacity)).
|
|
@@ -972,7 +969,7 @@ export class IdCompressor {
|
|
|
972
969
|
/**
|
|
973
970
|
* Generates a new compressed ID or returns an existing one.
|
|
974
971
|
* This should ONLY be called to generate IDs for local operations.
|
|
975
|
-
* @param override Specifies a specific string to be associated with the returned compressed ID.
|
|
972
|
+
* @param override - Specifies a specific string to be associated with the returned compressed ID.
|
|
976
973
|
* Performance note: assigning override strings incurs a performance overhead.
|
|
977
974
|
* @returns an existing ID if one already exists for `override`, and a new local ID otherwise. The returned ID is in session space.
|
|
978
975
|
*/
|
|
@@ -999,7 +996,7 @@ export class IdCompressor {
|
|
|
999
996
|
/**
|
|
1000
997
|
* Generates a range of compressed IDs.
|
|
1001
998
|
* This should ONLY be called to generate IDs for local operations.
|
|
1002
|
-
* @param count the number of IDs to generate, must be
|
|
999
|
+
* @param count - the number of IDs to generate, must be \> 0.
|
|
1003
1000
|
* @returns a persistable descriptor of the ID range.
|
|
1004
1001
|
*/
|
|
1005
1002
|
public generateCompressedIdRange(count: number): IdRangeDescriptor<LocalCompressedId> {
|
|
@@ -1019,7 +1016,7 @@ export class IdCompressor {
|
|
|
1019
1016
|
|
|
1020
1017
|
/**
|
|
1021
1018
|
* Decompresses a previously compressed ID into a UUID or override string.
|
|
1022
|
-
* @param id the compressed ID to be decompressed.
|
|
1019
|
+
* @param id - the compressed ID to be decompressed.
|
|
1023
1020
|
* @returns the UUID or override string associated with the compressed ID. Fails if the ID was not generated by this compressor.
|
|
1024
1021
|
*/
|
|
1025
1022
|
public decompress(id: SessionSpaceCompressedId | FinalCompressedId): StableId | string {
|
|
@@ -1028,7 +1025,7 @@ export class IdCompressor {
|
|
|
1028
1025
|
|
|
1029
1026
|
/**
|
|
1030
1027
|
* Attempts to decompress a previously compressed ID into a UUID or override string.
|
|
1031
|
-
* @param id the compressed ID to be decompressed.
|
|
1028
|
+
* @param id - the compressed ID to be decompressed.
|
|
1032
1029
|
* @returns the UUID or override string associated with the compressed ID, or undefined if the ID was not generated by this compressor.
|
|
1033
1030
|
*/
|
|
1034
1031
|
public tryDecompress(id: SessionSpaceCompressedId | FinalCompressedId): StableId | string | undefined {
|
|
@@ -1067,7 +1064,7 @@ export class IdCompressor {
|
|
|
1067
1064
|
|
|
1068
1065
|
/**
|
|
1069
1066
|
* Recompresses a decompressed ID, which could be a UUID or an override string.
|
|
1070
|
-
* @param uncompressed the UUID or override string to recompress.
|
|
1067
|
+
* @param uncompressed - the UUID or override string to recompress.
|
|
1071
1068
|
* @returns the `CompressedId` associated with `uncompressed`. Fails if it has not been previously compressed by this compressor.
|
|
1072
1069
|
*/
|
|
1073
1070
|
public recompress(uncompressed: string): SessionSpaceCompressedId {
|
|
@@ -1076,7 +1073,7 @@ export class IdCompressor {
|
|
|
1076
1073
|
|
|
1077
1074
|
/**
|
|
1078
1075
|
* Attempts to recompresses a decompressed ID, which could be a UUID or an override string.
|
|
1079
|
-
* @param uncompressed the UUID or override string to recompress,
|
|
1076
|
+
* @param uncompressed - the UUID or override string to recompress,
|
|
1080
1077
|
* @returns the `CompressedId` associated with `uncompressed` or undefined if it has not been previously compressed by this compressor.
|
|
1081
1078
|
*/
|
|
1082
1079
|
public tryRecompress(uncompressed: string): SessionSpaceCompressedId | undefined {
|
|
@@ -1092,8 +1089,7 @@ export class IdCompressor {
|
|
|
1092
1089
|
uncompressedUuidNumeric?: NumericUuid
|
|
1093
1090
|
): SessionSpaceCompressedId | undefined {
|
|
1094
1091
|
let numericUuid = uncompressedUuidNumeric;
|
|
1095
|
-
|
|
1096
|
-
const inversionKey = IdCompressor.createInversionKey(uncompressed) as StableId;
|
|
1092
|
+
const inversionKey = IdCompressor.createInversionKey(uncompressed);
|
|
1097
1093
|
const isStable = IdCompressor.isStableInversionKey(inversionKey);
|
|
1098
1094
|
const closestMatch = this.clustersAndOverridesInversion.getPairOrNextLower(inversionKey, reusedArray);
|
|
1099
1095
|
if (closestMatch !== undefined) {
|
|
@@ -1140,7 +1136,6 @@ export class IdCompressor {
|
|
|
1140
1136
|
|
|
1141
1137
|
if (isStable) {
|
|
1142
1138
|
// May have already computed the numeric UUID, so avoid recomputing if possible
|
|
1143
|
-
// TODO: This cast can be removed on typescript 4.6
|
|
1144
1139
|
const localId = this.getLocalIdForStableId(numericUuid ?? inversionKey);
|
|
1145
1140
|
if (localId !== undefined) {
|
|
1146
1141
|
return localId;
|
|
@@ -1151,7 +1146,7 @@ export class IdCompressor {
|
|
|
1151
1146
|
|
|
1152
1147
|
/**
|
|
1153
1148
|
* Normalizes a session space ID into op space.
|
|
1154
|
-
* @param id the local ID to normalize.
|
|
1149
|
+
* @param id - the local ID to normalize.
|
|
1155
1150
|
* @returns the ID in op space.
|
|
1156
1151
|
*/
|
|
1157
1152
|
public normalizeToOpSpace(id: SessionSpaceCompressedId): OpSpaceCompressedId {
|
|
@@ -1196,9 +1191,9 @@ export class IdCompressor {
|
|
|
1196
1191
|
|
|
1197
1192
|
/**
|
|
1198
1193
|
* Normalizes an ID into session space.
|
|
1199
|
-
* @param id the ID to normalize. If it is a local ID, it is assumed to have been created by the session corresponding
|
|
1194
|
+
* @param id - the ID to normalize. If it is a local ID, it is assumed to have been created by the session corresponding
|
|
1200
1195
|
* to `sessionId`.
|
|
1201
|
-
* @param originSessionId the session from which `id` originated
|
|
1196
|
+
* @param originSessionId - the session from which `id` originated
|
|
1202
1197
|
* @returns the session-space ID corresponding to `id`, which might not have been a final ID if the client that created it had not yet
|
|
1203
1198
|
* finalized it. This can occur when a client references an ID during the window of time in which it is waiting to receive the ordered
|
|
1204
1199
|
* range that contained it from the server.
|
|
@@ -1207,7 +1202,7 @@ export class IdCompressor {
|
|
|
1207
1202
|
|
|
1208
1203
|
/**
|
|
1209
1204
|
* Normalizes a final ID into session space.
|
|
1210
|
-
* @param id the final ID to normalize.
|
|
1205
|
+
* @param id - the final ID to normalize.
|
|
1211
1206
|
* @returns the session-space ID corresponding to `id`.
|
|
1212
1207
|
*/
|
|
1213
1208
|
public normalizeToSessionSpace(id: FinalCompressedId): SessionSpaceCompressedId;
|
|
@@ -1222,7 +1217,7 @@ export class IdCompressor {
|
|
|
1222
1217
|
}
|
|
1223
1218
|
return id;
|
|
1224
1219
|
} else {
|
|
1225
|
-
const session = this.
|
|
1220
|
+
const session = this.sessions.get(originSessionId ?? fail());
|
|
1226
1221
|
if (session === undefined) {
|
|
1227
1222
|
fail('No IDs have ever been finalized by the supplied session.');
|
|
1228
1223
|
}
|
|
@@ -1282,10 +1277,7 @@ export class IdCompressor {
|
|
|
1282
1277
|
}
|
|
1283
1278
|
|
|
1284
1279
|
private getLocalIdForStableId(stableId: StableId | NumericUuid): LocalCompressedId | undefined {
|
|
1285
|
-
|
|
1286
|
-
const numericUuid = (
|
|
1287
|
-
typeof stableId === 'string' ? numericUuidFromStableId(stableId) : stableId
|
|
1288
|
-
) as NumericUuid;
|
|
1280
|
+
const numericUuid = typeof stableId === 'string' ? numericUuidFromStableId(stableId) : stableId;
|
|
1289
1281
|
const offset = getPositiveDelta(numericUuid, this.localSession.sessionUuid, this.localIdCount - 1);
|
|
1290
1282
|
if (offset === undefined) {
|
|
1291
1283
|
return undefined;
|
|
@@ -1309,8 +1301,8 @@ export class IdCompressor {
|
|
|
1309
1301
|
}
|
|
1310
1302
|
|
|
1311
1303
|
/**
|
|
1312
|
-
* @returns if `other` is equal to this `IdCompressor`. The equality check includes local session state.
|
|
1313
|
-
*
|
|
1304
|
+
* @returns if `other` is equal to this `IdCompressor`. The equality check includes local session state only if specified.
|
|
1305
|
+
* \@testOnly
|
|
1314
1306
|
*/
|
|
1315
1307
|
public equals(other: IdCompressor, compareLocalState: boolean): boolean {
|
|
1316
1308
|
if (compareLocalState) {
|
|
@@ -1318,7 +1310,7 @@ export class IdCompressor {
|
|
|
1318
1310
|
this.localIdCount !== other.localIdCount ||
|
|
1319
1311
|
this.localSessionId !== other.localSessionId ||
|
|
1320
1312
|
this.lastTakenLocalId !== other.lastTakenLocalId ||
|
|
1321
|
-
this.
|
|
1313
|
+
this.attributionId !== other.attributionId
|
|
1322
1314
|
) {
|
|
1323
1315
|
return false;
|
|
1324
1316
|
}
|
|
@@ -1422,7 +1414,7 @@ export class IdCompressor {
|
|
|
1422
1414
|
|
|
1423
1415
|
private static sessionDataEqual(a: Session, b: Session, checkCluster = true, compareLocalState = true): boolean {
|
|
1424
1416
|
if (
|
|
1425
|
-
a.
|
|
1417
|
+
a.attributionId !== b.attributionId ||
|
|
1426
1418
|
!numericUuidEquals(a.sessionUuid, b.sessionUuid) ||
|
|
1427
1419
|
a.lastFinalizedLocalId !== b.lastFinalizedLocalId
|
|
1428
1420
|
) {
|
|
@@ -1510,6 +1502,8 @@ export class IdCompressor {
|
|
|
1510
1502
|
public serialize(withSession: boolean): SerializedIdCompressor {
|
|
1511
1503
|
const serializedSessions: SerializedSessionData[] = [];
|
|
1512
1504
|
const sessionIdToSessionIndex = new Map<SessionId, number>();
|
|
1505
|
+
const attributionIdToAttributionIndex = new Map<AttributionId, number>();
|
|
1506
|
+
let serializedAttributionIds: UuidString[] | undefined;
|
|
1513
1507
|
|
|
1514
1508
|
for (const [sessionId, session] of this.sessions) {
|
|
1515
1509
|
const isLocalSession = sessionId === this.localSessionId;
|
|
@@ -1520,8 +1514,16 @@ export class IdCompressor {
|
|
|
1520
1514
|
|
|
1521
1515
|
if (includeSession) {
|
|
1522
1516
|
const sessionData: Mutable<SerializedSessionData> = [sessionId];
|
|
1523
|
-
if (session.
|
|
1524
|
-
|
|
1517
|
+
if (session.attributionId !== sessionId) {
|
|
1518
|
+
// As an optimization, don't include the attributionId if it is its default (the sessionId)
|
|
1519
|
+
// Get the index into the array for the given attribution ID. If it doesn't exist, push it onto the array and update the map.
|
|
1520
|
+
sessionData.push(
|
|
1521
|
+
getOrCreate(
|
|
1522
|
+
attributionIdToAttributionIndex,
|
|
1523
|
+
session.attributionId,
|
|
1524
|
+
(id) => (serializedAttributionIds ??= []).push(id) - 1
|
|
1525
|
+
)
|
|
1526
|
+
);
|
|
1525
1527
|
}
|
|
1526
1528
|
sessionIdToSessionIndex.set(sessionId, serializedSessions.length);
|
|
1527
1529
|
serializedSessions.push(sessionData);
|
|
@@ -1567,13 +1569,14 @@ export class IdCompressor {
|
|
|
1567
1569
|
// Reserved session not serialized, and local session is present but may not make IDs
|
|
1568
1570
|
assert(serializedSessions.length - this.sessions.size <= 2, 'session not serialized');
|
|
1569
1571
|
|
|
1570
|
-
const serializedIdCompressor = {
|
|
1572
|
+
const serializedIdCompressor: Omit<SerializedIdCompressor, '_versionedSerializedIdCompressor'> = {
|
|
1571
1573
|
version: currentWrittenVersion,
|
|
1572
1574
|
reservedIdCount: this.reservedIdCount,
|
|
1573
1575
|
clusterCapacity: this.clusterCapacity,
|
|
1574
1576
|
sessions: serializedSessions,
|
|
1575
1577
|
clusters: serializedClusters,
|
|
1576
|
-
}
|
|
1578
|
+
};
|
|
1579
|
+
setPropertyIfDefined(serializedAttributionIds, serializedIdCompressor, 'attributionIds');
|
|
1577
1580
|
|
|
1578
1581
|
if (withSession) {
|
|
1579
1582
|
const serializedWithSession = serializedIdCompressor as Mutable<SerializedIdCompressorWithOngoingSession>;
|
|
@@ -1585,14 +1588,13 @@ export class IdCompressor {
|
|
|
1585
1588
|
localIdCount: this.localIdCount,
|
|
1586
1589
|
overrides: [...this.localOverrides.entries()].map((entry) => [...entry]),
|
|
1587
1590
|
lastTakenLocalId: this.lastTakenLocalId,
|
|
1588
|
-
sentAttributionInfo: this.sentAttributionInfo,
|
|
1589
1591
|
};
|
|
1590
1592
|
}
|
|
1591
1593
|
|
|
1592
1594
|
return serializedWithSession;
|
|
1593
1595
|
}
|
|
1594
1596
|
|
|
1595
|
-
return serializedIdCompressor;
|
|
1597
|
+
return serializedIdCompressor as SerializedIdCompressor;
|
|
1596
1598
|
}
|
|
1597
1599
|
|
|
1598
1600
|
/**
|
|
@@ -1601,48 +1603,60 @@ export class IdCompressor {
|
|
|
1601
1603
|
public static deserialize(serialized: SerializedIdCompressorWithOngoingSession): IdCompressor;
|
|
1602
1604
|
|
|
1603
1605
|
/**
|
|
1604
|
-
* Deserialize
|
|
1605
|
-
*
|
|
1606
|
-
* @param
|
|
1607
|
-
* @param
|
|
1608
|
-
* @param attributionInfo information used by other clients to attribute IDs made by this client
|
|
1606
|
+
* Deserialize a serialized IdCompressor with a new session.
|
|
1607
|
+
* @param serialized - the serialized compressor state
|
|
1608
|
+
* @param newSessionId - the session ID for the new compressor.
|
|
1609
|
+
* @param attributionId - information used by other clients to attribute IDs made by this client
|
|
1609
1610
|
*/
|
|
1610
1611
|
public static deserialize(
|
|
1611
1612
|
serialized: SerializedIdCompressorWithNoSession,
|
|
1612
1613
|
newSessionId: SessionId,
|
|
1613
|
-
|
|
1614
|
+
attributionId?: AttributionId
|
|
1614
1615
|
): IdCompressor;
|
|
1615
1616
|
|
|
1616
1617
|
public static deserialize(
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1618
|
+
...args:
|
|
1619
|
+
| [
|
|
1620
|
+
serialized: SerializedIdCompressorWithNoSession,
|
|
1621
|
+
newSessionIdMaybe: SessionId,
|
|
1622
|
+
attributionIdMaybe?: AttributionId
|
|
1623
|
+
]
|
|
1624
|
+
| [
|
|
1625
|
+
serialized: SerializedIdCompressorWithOngoingSession,
|
|
1626
|
+
newSessionIdMaybe?: undefined,
|
|
1627
|
+
attributionIdMaybe?: undefined
|
|
1628
|
+
]
|
|
1620
1629
|
): IdCompressor {
|
|
1621
|
-
const
|
|
1622
|
-
let localSessionId: SessionId;
|
|
1623
|
-
let attributionInfo: AttributionInfo | undefined;
|
|
1624
|
-
let serializedLocalState: SerializedLocalState | undefined;
|
|
1625
|
-
if (hasSession) {
|
|
1626
|
-
assert(newSessionIdMaybe === undefined && attributionInfoMaybe === undefined);
|
|
1627
|
-
// TODO: This cast can be removed on typescript 4.6
|
|
1628
|
-
[localSessionId, attributionInfo] =
|
|
1629
|
-
serialized.sessions[(serialized as SerializedIdCompressorWithOngoingSession).localSessionIndex];
|
|
1630
|
-
// TODO: This cast can be removed on typescript 4.6
|
|
1631
|
-
serializedLocalState = (serialized as SerializedIdCompressorWithOngoingSession).localState;
|
|
1632
|
-
} else {
|
|
1633
|
-
assert(newSessionIdMaybe !== undefined);
|
|
1634
|
-
localSessionId = newSessionIdMaybe;
|
|
1635
|
-
attributionInfo = attributionInfoMaybe;
|
|
1636
|
-
}
|
|
1630
|
+
const [serialized, newSessionIdMaybe, attributionIdMaybe] = args;
|
|
1637
1631
|
|
|
1638
1632
|
const {
|
|
1639
1633
|
clusterCapacity,
|
|
1640
1634
|
reservedIdCount,
|
|
1641
1635
|
sessions: serializedSessions,
|
|
1642
1636
|
clusters: serializedClusters,
|
|
1637
|
+
attributionIds: serializedAttributionIds,
|
|
1643
1638
|
} = serialized;
|
|
1644
1639
|
|
|
1645
|
-
|
|
1640
|
+
let localSessionId: SessionId;
|
|
1641
|
+
let attributionId: AttributionId | undefined;
|
|
1642
|
+
let serializedLocalState: SerializedLocalState | undefined;
|
|
1643
|
+
if (newSessionIdMaybe === undefined) {
|
|
1644
|
+
// Alias of serialized, but known to be a SerializedIdCompressorWithOngoingSession
|
|
1645
|
+
const [serializedWithSession] = args;
|
|
1646
|
+
const serializedSessionData = serializedSessions[serializedWithSession.localSessionIndex];
|
|
1647
|
+
localSessionId = serializedSessionData[0];
|
|
1648
|
+
const attributionIndex = serializedSessionData[1];
|
|
1649
|
+
if (attributionIndex !== undefined) {
|
|
1650
|
+
assert(serializedAttributionIds !== undefined && serializedAttributionIds.length > attributionIndex);
|
|
1651
|
+
attributionId = serializedAttributionIds[attributionIndex];
|
|
1652
|
+
}
|
|
1653
|
+
serializedLocalState = serializedWithSession.localState;
|
|
1654
|
+
} else {
|
|
1655
|
+
localSessionId = newSessionIdMaybe;
|
|
1656
|
+
attributionId = attributionIdMaybe;
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
const compressor = new IdCompressor(localSessionId, reservedIdCount, attributionId);
|
|
1646
1660
|
compressor.clusterCapacity = clusterCapacity;
|
|
1647
1661
|
|
|
1648
1662
|
const localOverridesInverse = new Map<string, LocalCompressedId>();
|
|
@@ -1650,7 +1664,6 @@ export class IdCompressor {
|
|
|
1650
1664
|
// Do this part of local rehydration first since the cluster map population needs to query to local overrides
|
|
1651
1665
|
compressor.localIdCount = serializedLocalState.localIdCount;
|
|
1652
1666
|
compressor.lastTakenLocalId = serializedLocalState.lastTakenLocalId;
|
|
1653
|
-
compressor.sentAttributionInfo = serializedLocalState.sentAttributionInfo;
|
|
1654
1667
|
if (serializedLocalState.overrides !== undefined) {
|
|
1655
1668
|
for (const [localId, override] of serializedLocalState.overrides) {
|
|
1656
1669
|
compressor.localOverrides.append(localId, override);
|
|
@@ -1668,12 +1681,20 @@ export class IdCompressor {
|
|
|
1668
1681
|
readonly sessionId: SessionId;
|
|
1669
1682
|
}[] = [];
|
|
1670
1683
|
for (const serializedSession of serializedSessions) {
|
|
1671
|
-
const [sessionId,
|
|
1684
|
+
const [sessionId, attributionIndex] = serializedSession;
|
|
1672
1685
|
if (sessionId === localSessionId) {
|
|
1673
|
-
assert(
|
|
1686
|
+
assert(hasOngoingSession(serialized), 'Cannot resume existing session.');
|
|
1674
1687
|
sessionInfos.push({ session: compressor.localSession, sessionId });
|
|
1675
1688
|
} else {
|
|
1676
|
-
|
|
1689
|
+
let attributionId: AttributionId | undefined;
|
|
1690
|
+
if (attributionIndex !== undefined) {
|
|
1691
|
+
assert(
|
|
1692
|
+
serializedAttributionIds !== undefined && serializedAttributionIds.length > attributionIndex,
|
|
1693
|
+
'AttributionId index out of bounds'
|
|
1694
|
+
);
|
|
1695
|
+
attributionId = serializedAttributionIds[attributionIndex];
|
|
1696
|
+
}
|
|
1697
|
+
const session = compressor.createSession(sessionId, attributionId);
|
|
1677
1698
|
sessionInfos.push({ session, sessionId });
|
|
1678
1699
|
}
|
|
1679
1700
|
}
|
|
@@ -1766,7 +1787,7 @@ export class IdCompressor {
|
|
|
1766
1787
|
|
|
1767
1788
|
/**
|
|
1768
1789
|
* Converts the given serialized compressor to the current version.
|
|
1769
|
-
* @param serializedCompressor the serialized compressor to convert. Must not have been serialized with an ongoing session.
|
|
1790
|
+
* @param serializedCompressor - the serialized compressor to convert. Must not have been serialized with an ongoing session.
|
|
1770
1791
|
* @returns a serialized compressor with no ongoing session.
|
|
1771
1792
|
*/
|
|
1772
1793
|
public static convertToCurrentVersion(
|
|
@@ -1776,7 +1797,7 @@ export class IdCompressor {
|
|
|
1776
1797
|
|
|
1777
1798
|
/**
|
|
1778
1799
|
* Converts the given serialized compressor to the current version.
|
|
1779
|
-
* @param serializedCompressor the serialized compressor to convert. Must have been serialized with an ongoing session.
|
|
1800
|
+
* @param serializedCompressor - the serialized compressor to convert. Must have been serialized with an ongoing session.
|
|
1780
1801
|
* @returns a serialized compressor with the same ongoing session.
|
|
1781
1802
|
*/
|
|
1782
1803
|
public static convertToCurrentVersion(
|
|
@@ -1825,10 +1846,8 @@ function deserializeCluster(serializedCluster: SerializedCluster): {
|
|
|
1825
1846
|
return {
|
|
1826
1847
|
sessionIndex,
|
|
1827
1848
|
capacity,
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
// TODO: This cast can be removed on typescript 4.6
|
|
1831
|
-
overrides: (hasCount ? overrides : countOrOverrides) as SerializedClusterOverrides,
|
|
1849
|
+
count: hasCount ? countOrOverrides : capacity,
|
|
1850
|
+
overrides: hasCount ? overrides : countOrOverrides,
|
|
1832
1851
|
};
|
|
1833
1852
|
}
|
|
1834
1853
|
|
|
@@ -1839,10 +1858,3 @@ function deserializeCluster(serializedCluster: SerializedCluster): {
|
|
|
1839
1858
|
* lookup results should be extracted from the tuple immediately after invocation.
|
|
1840
1859
|
*/
|
|
1841
1860
|
const reusedArray: [any, any] = [] as unknown as [any, any];
|
|
1842
|
-
|
|
1843
|
-
/**
|
|
1844
|
-
* A numeric comparator used for sorting in descending order.
|
|
1845
|
-
*/
|
|
1846
|
-
function compareFiniteNumbersReversed<T extends number>(a: T, b: T): number {
|
|
1847
|
-
return b - a;
|
|
1848
|
-
}
|