@fluidframework/container-runtime 2.0.0-internal.7.3.0 → 2.0.0-internal.8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (271) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/api-extractor-lint.json +13 -0
  3. package/api-extractor.json +9 -1
  4. package/api-report/container-runtime.api.md +123 -123
  5. package/dist/blobManager.d.ts +4 -4
  6. package/dist/blobManager.d.ts.map +1 -1
  7. package/dist/blobManager.js.map +1 -1
  8. package/dist/container-runtime-alpha.d.ts +1444 -0
  9. package/dist/container-runtime-beta.d.ts +292 -0
  10. package/dist/container-runtime-public.d.ts +292 -0
  11. package/dist/container-runtime-untrimmed.d.ts +1792 -0
  12. package/dist/containerRuntime.d.ts +36 -66
  13. package/dist/containerRuntime.d.ts.map +1 -1
  14. package/dist/containerRuntime.js +68 -104
  15. package/dist/containerRuntime.js.map +1 -1
  16. package/dist/dataStore.js +0 -12
  17. package/dist/dataStore.js.map +1 -1
  18. package/dist/dataStoreRegistry.d.ts +1 -1
  19. package/dist/dataStoreRegistry.js +1 -1
  20. package/dist/dataStoreRegistry.js.map +1 -1
  21. package/dist/dataStores.d.ts +10 -15
  22. package/dist/dataStores.d.ts.map +1 -1
  23. package/dist/dataStores.js +77 -40
  24. package/dist/dataStores.js.map +1 -1
  25. package/dist/gc/garbageCollection.d.ts +41 -13
  26. package/dist/gc/garbageCollection.d.ts.map +1 -1
  27. package/dist/gc/garbageCollection.js +215 -78
  28. package/dist/gc/garbageCollection.js.map +1 -1
  29. package/dist/gc/gcConfigs.d.ts.map +1 -1
  30. package/dist/gc/gcConfigs.js +34 -37
  31. package/dist/gc/gcConfigs.js.map +1 -1
  32. package/dist/gc/gcDefinitions.d.ts +121 -46
  33. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  34. package/dist/gc/gcDefinitions.js +26 -18
  35. package/dist/gc/gcDefinitions.js.map +1 -1
  36. package/dist/gc/gcHelpers.d.ts +18 -25
  37. package/dist/gc/gcHelpers.d.ts.map +1 -1
  38. package/dist/gc/gcHelpers.js +29 -45
  39. package/dist/gc/gcHelpers.js.map +1 -1
  40. package/dist/gc/gcTelemetry.d.ts +0 -5
  41. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  42. package/dist/gc/gcTelemetry.js +14 -42
  43. package/dist/gc/gcTelemetry.js.map +1 -1
  44. package/dist/gc/gcUnreferencedStateTracker.d.ts +11 -5
  45. package/dist/gc/gcUnreferencedStateTracker.d.ts.map +1 -1
  46. package/dist/gc/gcUnreferencedStateTracker.js +43 -19
  47. package/dist/gc/gcUnreferencedStateTracker.js.map +1 -1
  48. package/dist/gc/index.d.ts +1 -1
  49. package/dist/gc/index.d.ts.map +1 -1
  50. package/dist/gc/index.js +4 -5
  51. package/dist/gc/index.js.map +1 -1
  52. package/dist/index.d.ts +15 -3
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +16 -6
  55. package/dist/index.js.map +1 -1
  56. package/dist/messageTypes.d.ts +15 -7
  57. package/dist/messageTypes.d.ts.map +1 -1
  58. package/dist/messageTypes.js +6 -1
  59. package/dist/messageTypes.js.map +1 -1
  60. package/dist/opLifecycle/definitions.d.ts +1 -1
  61. package/dist/opLifecycle/definitions.js.map +1 -1
  62. package/dist/packageVersion.d.ts +1 -1
  63. package/dist/packageVersion.js +1 -1
  64. package/dist/packageVersion.js.map +1 -1
  65. package/dist/pendingStateManager.d.ts +1 -0
  66. package/dist/pendingStateManager.d.ts.map +1 -1
  67. package/dist/pendingStateManager.js +1 -0
  68. package/dist/pendingStateManager.js.map +1 -1
  69. package/dist/summary/orderedClientElection.d.ts +1 -1
  70. package/dist/summary/orderedClientElection.js.map +1 -1
  71. package/dist/summary/runWhileConnectedCoordinator.d.ts +2 -2
  72. package/dist/summary/runWhileConnectedCoordinator.js +1 -1
  73. package/dist/summary/runWhileConnectedCoordinator.js.map +1 -1
  74. package/dist/summary/summarizer.d.ts +1 -13
  75. package/dist/summary/summarizer.d.ts.map +1 -1
  76. package/dist/summary/summarizer.js +1 -47
  77. package/dist/summary/summarizer.js.map +1 -1
  78. package/dist/summary/summarizerTypes.d.ts +30 -30
  79. package/dist/summary/summarizerTypes.js.map +1 -1
  80. package/dist/summary/summaryCollection.d.ts +10 -10
  81. package/dist/summary/summaryCollection.js +1 -1
  82. package/dist/summary/summaryCollection.js.map +1 -1
  83. package/dist/summary/summaryFormat.d.ts +3 -3
  84. package/dist/summary/summaryFormat.js.map +1 -1
  85. package/lib/blobManager.d.ts +4 -4
  86. package/lib/blobManager.d.ts.map +1 -1
  87. package/lib/blobManager.js.map +1 -1
  88. package/lib/container-runtime-alpha.d.ts +1444 -0
  89. package/lib/container-runtime-beta.d.ts +292 -0
  90. package/lib/container-runtime-public.d.ts +292 -0
  91. package/lib/container-runtime-untrimmed.d.ts +1792 -0
  92. package/lib/containerRuntime.d.ts +36 -66
  93. package/lib/containerRuntime.d.ts.map +1 -1
  94. package/lib/containerRuntime.js +69 -104
  95. package/lib/containerRuntime.js.map +1 -1
  96. package/lib/dataStore.js +0 -12
  97. package/lib/dataStore.js.map +1 -1
  98. package/lib/dataStoreRegistry.d.ts +1 -1
  99. package/lib/dataStoreRegistry.js +1 -1
  100. package/lib/dataStoreRegistry.js.map +1 -1
  101. package/lib/dataStores.d.ts +10 -15
  102. package/lib/dataStores.d.ts.map +1 -1
  103. package/lib/dataStores.js +80 -43
  104. package/lib/dataStores.js.map +1 -1
  105. package/lib/gc/garbageCollection.d.ts +41 -13
  106. package/lib/gc/garbageCollection.d.ts.map +1 -1
  107. package/lib/gc/garbageCollection.js +217 -80
  108. package/lib/gc/garbageCollection.js.map +1 -1
  109. package/lib/gc/gcConfigs.d.ts.map +1 -1
  110. package/lib/gc/gcConfigs.js +37 -40
  111. package/lib/gc/gcConfigs.js.map +1 -1
  112. package/lib/gc/gcDefinitions.d.ts +121 -46
  113. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  114. package/lib/gc/gcDefinitions.js +25 -17
  115. package/lib/gc/gcDefinitions.js.map +1 -1
  116. package/lib/gc/gcHelpers.d.ts +18 -25
  117. package/lib/gc/gcHelpers.d.ts.map +1 -1
  118. package/lib/gc/gcHelpers.js +27 -43
  119. package/lib/gc/gcHelpers.js.map +1 -1
  120. package/lib/gc/gcTelemetry.d.ts +0 -5
  121. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  122. package/lib/gc/gcTelemetry.js +15 -43
  123. package/lib/gc/gcTelemetry.js.map +1 -1
  124. package/lib/gc/gcUnreferencedStateTracker.d.ts +11 -5
  125. package/lib/gc/gcUnreferencedStateTracker.d.ts.map +1 -1
  126. package/lib/gc/gcUnreferencedStateTracker.js +43 -19
  127. package/lib/gc/gcUnreferencedStateTracker.js.map +1 -1
  128. package/lib/gc/index.d.ts +1 -1
  129. package/lib/gc/index.d.ts.map +1 -1
  130. package/lib/gc/index.js +1 -1
  131. package/lib/gc/index.js.map +1 -1
  132. package/lib/index.d.ts +15 -3
  133. package/lib/index.d.ts.map +1 -1
  134. package/lib/index.js +16 -2
  135. package/lib/index.js.map +1 -1
  136. package/lib/messageTypes.d.ts +15 -7
  137. package/lib/messageTypes.d.ts.map +1 -1
  138. package/lib/messageTypes.js +6 -1
  139. package/lib/messageTypes.js.map +1 -1
  140. package/lib/opLifecycle/definitions.d.ts +1 -1
  141. package/lib/opLifecycle/definitions.js.map +1 -1
  142. package/lib/packageVersion.d.ts +1 -1
  143. package/lib/packageVersion.js +1 -1
  144. package/lib/packageVersion.js.map +1 -1
  145. package/lib/pendingStateManager.d.ts +1 -0
  146. package/lib/pendingStateManager.d.ts.map +1 -1
  147. package/lib/pendingStateManager.js +1 -0
  148. package/lib/pendingStateManager.js.map +1 -1
  149. package/lib/summary/orderedClientElection.d.ts +1 -1
  150. package/lib/summary/orderedClientElection.js.map +1 -1
  151. package/lib/summary/runWhileConnectedCoordinator.d.ts +2 -2
  152. package/lib/summary/runWhileConnectedCoordinator.js +1 -1
  153. package/lib/summary/runWhileConnectedCoordinator.js.map +1 -1
  154. package/lib/summary/summarizer.d.ts +1 -13
  155. package/lib/summary/summarizer.d.ts.map +1 -1
  156. package/lib/summary/summarizer.js +1 -47
  157. package/lib/summary/summarizer.js.map +1 -1
  158. package/lib/summary/summarizerTypes.d.ts +30 -30
  159. package/lib/summary/summarizerTypes.js.map +1 -1
  160. package/lib/summary/summaryCollection.d.ts +10 -10
  161. package/lib/summary/summaryCollection.js +1 -1
  162. package/lib/summary/summaryCollection.js.map +1 -1
  163. package/lib/summary/summaryFormat.d.ts +3 -3
  164. package/lib/summary/summaryFormat.js.map +1 -1
  165. package/package.json +46 -19
  166. package/src/blobManager.ts +5 -5
  167. package/src/containerRuntime.ts +93 -141
  168. package/src/dataStore.ts +1 -15
  169. package/src/dataStoreRegistry.ts +1 -1
  170. package/src/dataStores.ts +140 -69
  171. package/src/gc/garbageCollection.md +14 -15
  172. package/src/gc/garbageCollection.ts +256 -96
  173. package/src/gc/gcConfigs.ts +50 -52
  174. package/src/gc/gcDefinitions.ts +137 -52
  175. package/src/gc/gcHelpers.ts +31 -52
  176. package/src/gc/gcTelemetry.ts +16 -57
  177. package/src/gc/gcUnreferencedStateTracker.ts +61 -22
  178. package/src/gc/index.ts +6 -4
  179. package/src/index.ts +19 -2
  180. package/src/messageTypes.ts +19 -4
  181. package/src/opLifecycle/definitions.ts +1 -1
  182. package/src/packageVersion.ts +1 -1
  183. package/src/pendingStateManager.ts +1 -0
  184. package/src/summary/orderedClientElection.ts +1 -1
  185. package/src/summary/runWhileConnectedCoordinator.ts +2 -2
  186. package/src/summary/summarizer.ts +2 -51
  187. package/src/summary/summarizerTypes.ts +30 -30
  188. package/src/summary/summaryCollection.ts +10 -10
  189. package/src/summary/summaryFormat.ts +3 -3
  190. package/dist/id-compressor/appendOnlySortedMap.d.ts +0 -124
  191. package/dist/id-compressor/appendOnlySortedMap.d.ts.map +0 -1
  192. package/dist/id-compressor/appendOnlySortedMap.js +0 -318
  193. package/dist/id-compressor/appendOnlySortedMap.js.map +0 -1
  194. package/dist/id-compressor/finalSpace.d.ts +0 -29
  195. package/dist/id-compressor/finalSpace.d.ts.map +0 -1
  196. package/dist/id-compressor/finalSpace.js +0 -62
  197. package/dist/id-compressor/finalSpace.js.map +0 -1
  198. package/dist/id-compressor/idCompressor.d.ts +0 -54
  199. package/dist/id-compressor/idCompressor.d.ts.map +0 -1
  200. package/dist/id-compressor/idCompressor.js +0 -495
  201. package/dist/id-compressor/idCompressor.js.map +0 -1
  202. package/dist/id-compressor/identifiers.d.ts +0 -32
  203. package/dist/id-compressor/identifiers.d.ts.map +0 -1
  204. package/dist/id-compressor/identifiers.js +0 -15
  205. package/dist/id-compressor/identifiers.js.map +0 -1
  206. package/dist/id-compressor/index.d.ts +0 -13
  207. package/dist/id-compressor/index.d.ts.map +0 -1
  208. package/dist/id-compressor/index.js +0 -32
  209. package/dist/id-compressor/index.js.map +0 -1
  210. package/dist/id-compressor/persistanceUtilities.d.ts +0 -22
  211. package/dist/id-compressor/persistanceUtilities.d.ts.map +0 -1
  212. package/dist/id-compressor/persistanceUtilities.js +0 -43
  213. package/dist/id-compressor/persistanceUtilities.js.map +0 -1
  214. package/dist/id-compressor/sessionSpaceNormalizer.d.ts +0 -46
  215. package/dist/id-compressor/sessionSpaceNormalizer.d.ts.map +0 -1
  216. package/dist/id-compressor/sessionSpaceNormalizer.js +0 -80
  217. package/dist/id-compressor/sessionSpaceNormalizer.js.map +0 -1
  218. package/dist/id-compressor/sessions.d.ts +0 -115
  219. package/dist/id-compressor/sessions.d.ts.map +0 -1
  220. package/dist/id-compressor/sessions.js +0 -305
  221. package/dist/id-compressor/sessions.js.map +0 -1
  222. package/dist/id-compressor/utilities.d.ts +0 -52
  223. package/dist/id-compressor/utilities.d.ts.map +0 -1
  224. package/dist/id-compressor/utilities.js +0 -169
  225. package/dist/id-compressor/utilities.js.map +0 -1
  226. package/lib/id-compressor/appendOnlySortedMap.d.ts +0 -124
  227. package/lib/id-compressor/appendOnlySortedMap.d.ts.map +0 -1
  228. package/lib/id-compressor/appendOnlySortedMap.js +0 -314
  229. package/lib/id-compressor/appendOnlySortedMap.js.map +0 -1
  230. package/lib/id-compressor/finalSpace.d.ts +0 -29
  231. package/lib/id-compressor/finalSpace.d.ts.map +0 -1
  232. package/lib/id-compressor/finalSpace.js +0 -58
  233. package/lib/id-compressor/finalSpace.js.map +0 -1
  234. package/lib/id-compressor/idCompressor.d.ts +0 -54
  235. package/lib/id-compressor/idCompressor.d.ts.map +0 -1
  236. package/lib/id-compressor/idCompressor.js +0 -491
  237. package/lib/id-compressor/idCompressor.js.map +0 -1
  238. package/lib/id-compressor/identifiers.d.ts +0 -32
  239. package/lib/id-compressor/identifiers.d.ts.map +0 -1
  240. package/lib/id-compressor/identifiers.js +0 -11
  241. package/lib/id-compressor/identifiers.js.map +0 -1
  242. package/lib/id-compressor/index.d.ts +0 -13
  243. package/lib/id-compressor/index.d.ts.map +0 -1
  244. package/lib/id-compressor/index.js +0 -13
  245. package/lib/id-compressor/index.js.map +0 -1
  246. package/lib/id-compressor/persistanceUtilities.d.ts +0 -22
  247. package/lib/id-compressor/persistanceUtilities.d.ts.map +0 -1
  248. package/lib/id-compressor/persistanceUtilities.js +0 -34
  249. package/lib/id-compressor/persistanceUtilities.js.map +0 -1
  250. package/lib/id-compressor/sessionSpaceNormalizer.d.ts +0 -46
  251. package/lib/id-compressor/sessionSpaceNormalizer.d.ts.map +0 -1
  252. package/lib/id-compressor/sessionSpaceNormalizer.js +0 -76
  253. package/lib/id-compressor/sessionSpaceNormalizer.js.map +0 -1
  254. package/lib/id-compressor/sessions.d.ts +0 -115
  255. package/lib/id-compressor/sessions.d.ts.map +0 -1
  256. package/lib/id-compressor/sessions.js +0 -290
  257. package/lib/id-compressor/sessions.js.map +0 -1
  258. package/lib/id-compressor/utilities.d.ts +0 -52
  259. package/lib/id-compressor/utilities.d.ts.map +0 -1
  260. package/lib/id-compressor/utilities.js +0 -151
  261. package/lib/id-compressor/utilities.js.map +0 -1
  262. package/src/id-compressor/README.md +0 -3
  263. package/src/id-compressor/appendOnlySortedMap.ts +0 -366
  264. package/src/id-compressor/finalSpace.ts +0 -67
  265. package/src/id-compressor/idCompressor.ts +0 -630
  266. package/src/id-compressor/identifiers.ts +0 -42
  267. package/src/id-compressor/index.ts +0 -26
  268. package/src/id-compressor/persistanceUtilities.ts +0 -58
  269. package/src/id-compressor/sessionSpaceNormalizer.ts +0 -83
  270. package/src/id-compressor/sessions.ts +0 -405
  271. package/src/id-compressor/utilities.ts +0 -190
@@ -1,67 +0,0 @@
1
- /*!
2
- * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
- * Licensed under the MIT License.
4
- */
5
-
6
- import { assert } from "@fluidframework/core-utils";
7
- import { IdCluster, clustersEqual, lastAllocatedFinal, lastFinalizedFinal } from "./sessions";
8
- import { FinalCompressedId } from "./identifiers";
9
-
10
- /**
11
- * All IDs that have been finalized (acked), grouped into clusters sorted by their base final IDs.
12
- * These clusters span the positive integer space and are not sparse, meaning a cluster's base final
13
- * ID will always be one greater than the last final ID in the previous cluster (or 0 if there is not one).
14
- */
15
- export class FinalSpace {
16
- private readonly clusterList: IdCluster[] = [];
17
-
18
- public get clusters(): readonly IdCluster[] {
19
- return this.clusterList;
20
- }
21
-
22
- public getLastCluster(): IdCluster | undefined {
23
- return this.clusterList[this.clusterList.length - 1];
24
- }
25
-
26
- public addCluster(newCluster: IdCluster) {
27
- const lastCluster = this.getLastCluster();
28
- assert(
29
- lastCluster === undefined ||
30
- // eslint-disable-next-line @typescript-eslint/restrict-plus-operands
31
- newCluster.baseFinalId === lastCluster.baseFinalId + lastCluster.capacity,
32
- 0x753 /* Cluster insert to final_space is out of order. */,
33
- );
34
- this.clusterList.push(newCluster);
35
- }
36
-
37
- /**
38
- * @returns the upper bound (exclusive) of finalized IDs in final space, i.e. one greater than the last final ID in the last cluster.
39
- * Note: this does not include allocated but unfinalized space in clusters.
40
- */
41
- public getFinalizedIdLimit(): FinalCompressedId {
42
- const lastCluster = this.getLastCluster();
43
- return lastCluster === undefined
44
- ? (0 as FinalCompressedId)
45
- : (((lastFinalizedFinal(lastCluster) as number) + 1) as FinalCompressedId);
46
- }
47
-
48
- /**
49
- * @returns the upper bound (exclusive) of allocated IDs in final space, i.e. one greater than the last final ID in the last cluster.
50
- * Note: this does includes all allocated IDs in clusters.
51
- */
52
- public getAllocatedIdLimit(): FinalCompressedId {
53
- const lastCluster = this.getLastCluster();
54
- return lastCluster === undefined
55
- ? (0 as FinalCompressedId)
56
- : (((lastAllocatedFinal(lastCluster) as number) + 1) as FinalCompressedId);
57
- }
58
-
59
- public equals(other: FinalSpace): boolean {
60
- for (let i = 0; i < this.clusterList.length; i++) {
61
- if (!clustersEqual(this.clusterList[i], other.clusterList[i])) {
62
- return false;
63
- }
64
- }
65
- return this.clusterList.length === other.clusterList.length;
66
- }
67
- }
@@ -1,630 +0,0 @@
1
- /*!
2
- * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
- * Licensed under the MIT License.
4
- */
5
-
6
- import { assert } from "@fluidframework/core-utils";
7
- import { bufferToString, stringToBuffer } from "@fluid-internal/client-utils";
8
- import {
9
- IdCreationRange,
10
- IIdCompressor,
11
- IIdCompressorCore,
12
- OpSpaceCompressedId,
13
- SerializedIdCompressor,
14
- SerializedIdCompressorWithNoSession,
15
- SerializedIdCompressorWithOngoingSession,
16
- SessionId,
17
- SessionSpaceCompressedId,
18
- StableId,
19
- initialClusterCapacity,
20
- } from "@fluidframework/runtime-definitions";
21
- import { ITelemetryBaseLogger } from "@fluidframework/core-interfaces";
22
- import { ITelemetryLoggerExt, createChildLogger } from "@fluidframework/telemetry-utils";
23
- import { FinalCompressedId, isFinalId, LocalCompressedId, NumericUuid } from "./identifiers";
24
- import {
25
- createSessionId,
26
- localIdFromGenCount,
27
- genCountFromLocalId,
28
- numericUuidFromStableId,
29
- offsetNumericUuid,
30
- stableIdFromNumericUuid,
31
- subtractNumericUuids,
32
- } from "./utilities";
33
- import {
34
- Index,
35
- readBoolean,
36
- readNumber,
37
- readNumericUuid,
38
- writeBoolean,
39
- writeNumber,
40
- writeNumericUuid,
41
- } from "./persistanceUtilities";
42
- import {
43
- getAlignedLocal,
44
- getAlignedFinal,
45
- IdCluster,
46
- lastFinalizedLocal,
47
- Session,
48
- Sessions,
49
- } from "./sessions";
50
- import { SessionSpaceNormalizer } from "./sessionSpaceNormalizer";
51
- import { FinalSpace } from "./finalSpace";
52
-
53
- /**
54
- * The version of IdCompressor that is currently persisted.
55
- * This should not be changed without careful consideration to compatibility.
56
- */
57
- const currentWrittenVersion = 1;
58
-
59
- /**
60
- * See {@link IIdCompressor} and {@link IIdCompressorCore}
61
- */
62
- export class IdCompressor implements IIdCompressor, IIdCompressorCore {
63
- /**
64
- * Max allowed initial cluster size.
65
- */
66
- public static readonly maxClusterSize = 2 ** 20;
67
-
68
- // ----- Local state -----
69
-
70
- public readonly localSessionId: SessionId;
71
- private readonly localSession: Session;
72
- private readonly normalizer = new SessionSpaceNormalizer();
73
- // The number of IDs generated by the local session
74
- private localGenCount = 0;
75
-
76
- // -----------------------
77
-
78
- // ----- Final state -----
79
-
80
- // The gen count to be annotated on the range returned by the next call to `takeNextCreationRange`.
81
- // This is updated to be equal to `generatedIdCount` + 1 each time it is called.
82
- private nextRangeBaseGenCount = 1;
83
- // The capacity of the next cluster to be created
84
- private newClusterCapacity = initialClusterCapacity;
85
- private readonly sessions = new Sessions();
86
- private readonly finalSpace = new FinalSpace();
87
-
88
- // -----------------------
89
-
90
- // ----- Telemetry state -----
91
-
92
- // The number of local IDs generated since the last telemetry was sent.
93
- private telemetryLocalIdCount = 0;
94
- // The number of eager final IDs generated since the last telemetry was sent.
95
- private telemetryEagerFinalIdCount = 0;
96
-
97
- // -----------------------
98
-
99
- private constructor(
100
- localSessionIdOrDeserialized: SessionId | Sessions,
101
- private readonly logger?: ITelemetryLoggerExt,
102
- ) {
103
- if (typeof localSessionIdOrDeserialized === "string") {
104
- this.localSessionId = localSessionIdOrDeserialized;
105
- this.localSession = this.sessions.getOrCreate(localSessionIdOrDeserialized);
106
- } else {
107
- // Deserialize case
108
- this.sessions = localSessionIdOrDeserialized;
109
- // As policy, the first session is always the local session. Preserve this invariant
110
- // during deserialization.
111
- const firstSession = localSessionIdOrDeserialized.sessions().next();
112
- assert(!firstSession.done, 0x754 /* First session must be present. */);
113
- this.localSession = firstSession.value;
114
- this.localSessionId = stableIdFromNumericUuid(
115
- this.localSession.sessionUuid,
116
- ) as SessionId;
117
- }
118
- }
119
-
120
- public static create(logger?: ITelemetryBaseLogger): IdCompressor;
121
- public static create(sessionId: SessionId, logger?: ITelemetryBaseLogger): IdCompressor;
122
- public static create(
123
- sessionIdOrLogger?: SessionId | ITelemetryBaseLogger,
124
- loggerOrUndefined?: ITelemetryBaseLogger,
125
- ): IdCompressor {
126
- let localSessionId: SessionId;
127
- let logger: ITelemetryBaseLogger | undefined;
128
- if (sessionIdOrLogger === undefined) {
129
- localSessionId = createSessionId();
130
- } else {
131
- if (typeof sessionIdOrLogger === "string") {
132
- localSessionId = sessionIdOrLogger;
133
- logger = loggerOrUndefined;
134
- } else {
135
- localSessionId = createSessionId();
136
- logger = loggerOrUndefined;
137
- }
138
- }
139
- const compressor = new IdCompressor(
140
- localSessionId,
141
- logger === undefined ? undefined : createChildLogger({ logger }),
142
- );
143
- return compressor;
144
- }
145
-
146
- /**
147
- * The size of each newly created ID cluster.
148
- */
149
- public get clusterCapacity(): number {
150
- return this.newClusterCapacity;
151
- }
152
-
153
- /**
154
- * Must only be set with a value upon which consensus has been reached. Value must be greater than zero and less than
155
- * `IdCompressor.maxClusterSize`.
156
- */
157
- public set clusterCapacity(value: number) {
158
- if (value <= 0) {
159
- throw new Error("Clusters must have a positive capacity.");
160
- }
161
- if (value > IdCompressor.maxClusterSize) {
162
- throw new Error("Clusters must not exceed max cluster size.");
163
- }
164
- this.newClusterCapacity = value;
165
- }
166
-
167
- public generateCompressedId(): SessionSpaceCompressedId {
168
- this.localGenCount++;
169
- const lastCluster = this.localSession.getLastCluster();
170
- if (lastCluster === undefined) {
171
- this.telemetryLocalIdCount++;
172
- return this.generateNextLocalId();
173
- }
174
-
175
- // If there exists a cluster of final IDs already claimed by the local session that still has room in it,
176
- // it is known prior to range sequencing what a local ID's corresponding final ID will be.
177
- // In this case, it is safe to return the final ID immediately. This is guaranteed to be safe because
178
- // any op that the local session sends that contains one of those final IDs are guaranteed to arrive to
179
- // collaborators *after* the one containing the creation range.
180
- const clusterOffset = this.localGenCount - genCountFromLocalId(lastCluster.baseLocalId);
181
- if (lastCluster.capacity > clusterOffset) {
182
- this.telemetryEagerFinalIdCount++;
183
- // Space in the cluster: eager final
184
- return ((lastCluster.baseFinalId as number) +
185
- clusterOffset) as SessionSpaceCompressedId;
186
- }
187
- // No space in the cluster, return next local
188
- this.telemetryLocalIdCount++;
189
- return this.generateNextLocalId();
190
- }
191
-
192
- private generateNextLocalId(): LocalCompressedId {
193
- // Must tell the normalizer that we generated a local ID
194
- this.normalizer.addLocalRange(this.localGenCount, 1);
195
- return localIdFromGenCount(this.localGenCount);
196
- }
197
-
198
- public takeNextCreationRange(): IdCreationRange {
199
- const count = this.localGenCount - (this.nextRangeBaseGenCount - 1);
200
- if (count === 0) {
201
- return {
202
- sessionId: this.localSessionId,
203
- };
204
- }
205
- const range: IdCreationRange = {
206
- sessionId: this.localSessionId,
207
- ids: {
208
- firstGenCount: this.nextRangeBaseGenCount,
209
- count,
210
- },
211
- };
212
- this.nextRangeBaseGenCount = this.localGenCount + 1;
213
- return range;
214
- }
215
-
216
- public finalizeCreationRange(range: IdCreationRange): void {
217
- // Check if the range has IDs
218
- if (range.ids === undefined) {
219
- return;
220
- }
221
-
222
- assert(range.ids.count > 0, 0x755 /* Malformed ID Range. */);
223
- const { sessionId, ids } = range;
224
- const { count, firstGenCount } = ids;
225
- const session = this.sessions.getOrCreate(sessionId);
226
- const isLocal = session === this.localSession;
227
- const rangeBaseLocal = localIdFromGenCount(firstGenCount);
228
- let lastCluster = session.getLastCluster();
229
- if (lastCluster === undefined) {
230
- // This is the first cluster in the session space
231
- if (rangeBaseLocal !== -1) {
232
- throw new Error("Ranges finalized out of order.");
233
- }
234
- lastCluster = this.addEmptyCluster(session, this.clusterCapacity + count);
235
- if (isLocal) {
236
- this.logger?.sendTelemetryEvent({
237
- eventName: "RuntimeIdCompressor:FirstCluster",
238
- sessionId: this.localSessionId,
239
- });
240
- }
241
- }
242
-
243
- const remainingCapacity = lastCluster.capacity - lastCluster.count;
244
- if (lastCluster.baseLocalId - lastCluster.count !== rangeBaseLocal) {
245
- throw new Error("Ranges finalized out of order.");
246
- }
247
-
248
- if (remainingCapacity >= count) {
249
- // The current range fits in the existing cluster
250
- lastCluster.count += count;
251
- } else {
252
- const overflow = count - remainingCapacity;
253
- const newClaimedFinalCount = overflow + this.clusterCapacity;
254
- if (lastCluster === this.finalSpace.getLastCluster()) {
255
- // The last cluster in the sessions chain is the last cluster globally, so it can be expanded.
256
- lastCluster.capacity += newClaimedFinalCount;
257
- lastCluster.count += count;
258
- assert(
259
- !this.sessions.clusterCollides(lastCluster),
260
- 0x756 /* Cluster collision detected. */,
261
- );
262
- if (isLocal) {
263
- this.logger?.sendTelemetryEvent({
264
- eventName: "RuntimeIdCompressor:ClusterExpansion",
265
- sessionId: this.localSessionId,
266
- previousCapacity: lastCluster.capacity - newClaimedFinalCount,
267
- newCapacity: lastCluster.capacity,
268
- overflow,
269
- });
270
- }
271
- } else {
272
- // The last cluster in the sessions chain is *not* the last cluster globally. Fill and overflow to new.
273
- lastCluster.count = lastCluster.capacity;
274
- const newCluster = this.addEmptyCluster(session, newClaimedFinalCount);
275
- newCluster.count += overflow;
276
- if (isLocal) {
277
- this.logger?.sendTelemetryEvent({
278
- eventName: "RuntimeIdCompressor:NewCluster",
279
- sessionId: this.localSessionId,
280
- });
281
- }
282
- }
283
- }
284
-
285
- if (isLocal) {
286
- this.logger?.sendTelemetryEvent({
287
- eventName: "RuntimeIdCompressor:IdCompressorStatus",
288
- eagerFinalIdCount: this.telemetryEagerFinalIdCount,
289
- localIdCount: this.telemetryLocalIdCount,
290
- sessionId: this.localSessionId,
291
- });
292
- this.telemetryEagerFinalIdCount = 0;
293
- this.telemetryLocalIdCount = 0;
294
- }
295
-
296
- assert(!session.isEmpty(), 0x757 /* Empty sessions should not be created. */);
297
- }
298
-
299
- private addEmptyCluster(session: Session, capacity: number): IdCluster {
300
- const newCluster = session.addNewCluster(
301
- this.finalSpace.getAllocatedIdLimit(),
302
- capacity,
303
- 0,
304
- );
305
- assert(!this.sessions.clusterCollides(newCluster), 0x758 /* Cluster collision detected. */);
306
- this.finalSpace.addCluster(newCluster);
307
- return newCluster;
308
- }
309
-
310
- public normalizeToOpSpace(id: SessionSpaceCompressedId): OpSpaceCompressedId {
311
- if (isFinalId(id)) {
312
- return id;
313
- } else {
314
- const local = id as unknown as LocalCompressedId;
315
- if (!this.normalizer.contains(local)) {
316
- throw new Error("Invalid ID to normalize.");
317
- }
318
- const finalForm = this.localSession.tryConvertToFinal(local, true);
319
- return finalForm === undefined
320
- ? (local as unknown as OpSpaceCompressedId)
321
- : (finalForm as OpSpaceCompressedId);
322
- }
323
- }
324
-
325
- public normalizeToSessionSpace(
326
- id: OpSpaceCompressedId,
327
- originSessionId: SessionId,
328
- ): SessionSpaceCompressedId {
329
- if (isFinalId(id)) {
330
- const containingCluster = this.localSession.getClusterByAllocatedFinal(id);
331
- if (containingCluster === undefined) {
332
- // Does not exist in local cluster chain
333
- if (id >= this.finalSpace.getFinalizedIdLimit()) {
334
- throw new Error("Unknown op space ID.");
335
- }
336
- return id as unknown as SessionSpaceCompressedId;
337
- } else {
338
- const alignedLocal = getAlignedLocal(containingCluster, id);
339
- if (this.normalizer.contains(alignedLocal)) {
340
- return alignedLocal;
341
- } else {
342
- if (genCountFromLocalId(alignedLocal) > this.localGenCount) {
343
- throw new Error("Unknown op space ID.");
344
- }
345
- return id as unknown as SessionSpaceCompressedId;
346
- }
347
- }
348
- } else {
349
- const localToNormalize = id as unknown as LocalCompressedId;
350
- if (originSessionId === this.localSessionId) {
351
- if (this.normalizer.contains(localToNormalize)) {
352
- return localToNormalize;
353
- } else {
354
- // We never generated this local ID, so fail
355
- throw new Error("Unknown op space ID.");
356
- }
357
- } else {
358
- // LocalId from a remote session
359
- const remoteSession = this.sessions.get(originSessionId);
360
- if (remoteSession === undefined) {
361
- throw new Error("No IDs have ever been finalized by the supplied session.");
362
- }
363
- const correspondingFinal = remoteSession.tryConvertToFinal(localToNormalize, false);
364
- if (correspondingFinal === undefined) {
365
- throw new Error("Unknown op space ID.");
366
- }
367
- return correspondingFinal as unknown as SessionSpaceCompressedId;
368
- }
369
- }
370
- }
371
-
372
- public decompress(id: SessionSpaceCompressedId): StableId {
373
- if (isFinalId(id)) {
374
- const containingCluster = Session.getContainingCluster(id, this.finalSpace.clusters);
375
- if (containingCluster === undefined) {
376
- throw new Error("Unknown ID");
377
- }
378
- const alignedLocal = getAlignedLocal(containingCluster, id);
379
- const alignedGenCount = genCountFromLocalId(alignedLocal);
380
- const lastFinalizedGenCount = genCountFromLocalId(
381
- lastFinalizedLocal(containingCluster),
382
- );
383
- if (alignedGenCount > lastFinalizedGenCount) {
384
- // should be an eager final id generated by the local session
385
- if (containingCluster.session === this.localSession) {
386
- assert(
387
- !this.normalizer.contains(alignedLocal),
388
- 0x759 /* Normalizer out of sync. */,
389
- );
390
- } else {
391
- throw new Error("Unknown ID");
392
- }
393
- }
394
-
395
- return stableIdFromNumericUuid(
396
- offsetNumericUuid(containingCluster.session.sessionUuid, alignedGenCount - 1),
397
- );
398
- } else {
399
- const localToDecompress = id as unknown as LocalCompressedId;
400
- if (!this.normalizer.contains(localToDecompress)) {
401
- throw new Error("Unknown ID");
402
- }
403
- return stableIdFromNumericUuid(
404
- offsetNumericUuid(
405
- this.localSession.sessionUuid,
406
- genCountFromLocalId(localToDecompress) - 1,
407
- ),
408
- );
409
- }
410
- }
411
-
412
- public recompress(uncompressed: StableId): SessionSpaceCompressedId {
413
- const recompressed = this.tryRecompress(uncompressed);
414
- if (recompressed === undefined) {
415
- throw new Error("Could not recompress.");
416
- }
417
- return recompressed;
418
- }
419
-
420
- public tryRecompress(uncompressed: StableId): SessionSpaceCompressedId | undefined {
421
- const match = this.sessions.getContainingCluster(uncompressed);
422
- if (match === undefined) {
423
- const numericUncompressed = numericUuidFromStableId(uncompressed);
424
- const offset = subtractNumericUuids(numericUncompressed, this.localSession.sessionUuid);
425
- if (offset < Number.MAX_SAFE_INTEGER) {
426
- const genCountEquivalent = Number(offset) + 1;
427
- const localEquivalent = localIdFromGenCount(genCountEquivalent);
428
- if (this.normalizer.contains(localEquivalent)) {
429
- return localEquivalent;
430
- }
431
- }
432
- return undefined;
433
- } else {
434
- const [containingCluster, alignedLocal] = match;
435
- if (containingCluster.session === this.localSession) {
436
- // Local session
437
- if (this.normalizer.contains(alignedLocal)) {
438
- return alignedLocal;
439
- } else {
440
- assert(
441
- genCountFromLocalId(alignedLocal) <= this.localGenCount,
442
- 0x75a /* Clusters out of sync. */,
443
- );
444
- // Id is an eager final
445
- return getAlignedFinal(containingCluster, alignedLocal) as
446
- | SessionSpaceCompressedId
447
- | undefined;
448
- }
449
- } else {
450
- // Not the local session
451
- return genCountFromLocalId(alignedLocal) >= lastFinalizedLocal(containingCluster)
452
- ? (getAlignedFinal(containingCluster, alignedLocal) as
453
- | SessionSpaceCompressedId
454
- | undefined)
455
- : undefined;
456
- }
457
- }
458
- }
459
-
460
- public serialize(withSession: true): SerializedIdCompressorWithOngoingSession;
461
- public serialize(withSession: false): SerializedIdCompressorWithNoSession;
462
- public serialize(hasLocalState: boolean): SerializedIdCompressor {
463
- const { normalizer, finalSpace, sessions } = this;
464
- const sessionIndexMap = new Map<Session, number>();
465
- let sessionIndex = 0;
466
- for (const session of sessions.sessions()) {
467
- // Filter empty sessions to prevent them accumulating in the serialized state
468
- if (!session.isEmpty() || hasLocalState) {
469
- sessionIndexMap.set(session, sessionIndex);
470
- sessionIndex++;
471
- }
472
- }
473
- const localStateSize = hasLocalState
474
- ? 1 + // generated ID count
475
- 1 + // next range base genCount
476
- 1 + // count of normalizer pairs
477
- this.normalizer.idRanges.size * 2 // pairs
478
- : 0;
479
- // Layout size, in 8 byte increments
480
- const totalSize =
481
- 1 + // version
482
- 1 + // hasLocalState
483
- 1 + // cluster capacity
484
- 1 + // session count
485
- 1 + // cluster count
486
- sessionIndexMap.size * 2 + // session IDs
487
- finalSpace.clusters.length * 3 + // clusters: (sessionIndex, capacity, count)[]
488
- localStateSize; // local state, if present
489
-
490
- const serializedFloat = new Float64Array(totalSize);
491
- const serializedUint = new BigUint64Array(serializedFloat.buffer);
492
- let index = 0;
493
- index = writeNumber(serializedFloat, index, currentWrittenVersion);
494
- index = writeBoolean(serializedFloat, index, hasLocalState);
495
- index = writeNumber(serializedFloat, index, this.clusterCapacity);
496
- index = writeNumber(serializedFloat, index, sessionIndexMap.size);
497
- index = writeNumber(serializedFloat, index, finalSpace.clusters.length);
498
-
499
- for (const [session] of sessionIndexMap.entries()) {
500
- index = writeNumericUuid(serializedUint, index, session.sessionUuid);
501
- }
502
-
503
- finalSpace.clusters.forEach((cluster) => {
504
- index = writeNumber(
505
- serializedFloat,
506
- index,
507
- sessionIndexMap.get(cluster.session) as number,
508
- );
509
- index = writeNumber(serializedFloat, index, cluster.capacity);
510
- index = writeNumber(serializedFloat, index, cluster.count);
511
- });
512
-
513
- if (hasLocalState) {
514
- index = writeNumber(serializedFloat, index, this.localGenCount);
515
- index = writeNumber(serializedFloat, index, this.nextRangeBaseGenCount);
516
- index = writeNumber(serializedFloat, index, normalizer.idRanges.size);
517
- for (const [leadingGenCount, count] of normalizer.idRanges.entries()) {
518
- index = writeNumber(serializedFloat, index, leadingGenCount);
519
- index = writeNumber(serializedFloat, index, count);
520
- }
521
- }
522
-
523
- assert(index === totalSize, 0x75b /* Serialized size was incorrectly calculated. */);
524
- this.logger?.sendTelemetryEvent({
525
- eventName: "RuntimeIdCompressor:SerializedIdCompressorSize",
526
- size: serializedFloat.byteLength,
527
- clusterCount: finalSpace.clusters.length,
528
- sessionCount: sessionIndexMap.size,
529
- });
530
-
531
- return bufferToString(serializedFloat.buffer, "base64") as SerializedIdCompressor;
532
- }
533
-
534
- public static deserialize(serialized: SerializedIdCompressorWithOngoingSession): IdCompressor;
535
- public static deserialize(
536
- serialized: SerializedIdCompressorWithNoSession,
537
- newSessionId: SessionId,
538
- ): IdCompressor;
539
- public static deserialize(
540
- serialized: SerializedIdCompressor,
541
- sessionId?: SessionId,
542
- ): IdCompressor {
543
- const buffer = stringToBuffer(serialized, "base64");
544
- const index: Index = {
545
- index: 0,
546
- bufferFloat: new Float64Array(buffer),
547
- bufferUint: new BigUint64Array(buffer),
548
- };
549
- const version = readNumber(index);
550
- assert(version === currentWrittenVersion, 0x75c /* Unknown serialized version. */);
551
- const hasLocalState = readBoolean(index);
552
- const clusterCapacity = readNumber(index);
553
- const sessionCount = readNumber(index);
554
- const clusterCount = readNumber(index);
555
-
556
- // Sessions
557
- let sessionOffset = 0;
558
- const sessions: [NumericUuid, Session][] = [];
559
- if (!hasLocalState) {
560
- // If !hasLocalState, there won't be a serialized local session ID so insert one at the beginning
561
- assert(sessionId !== undefined, 0x75d /* Local session ID is undefined. */);
562
- const localSessionNumeric = numericUuidFromStableId(sessionId);
563
- sessions.push([localSessionNumeric, new Session(localSessionNumeric)]);
564
- sessionOffset = 1;
565
- } else {
566
- assert(
567
- sessionId === undefined,
568
- 0x75e /* Local state should not exist in serialized form. */,
569
- );
570
- }
571
-
572
- for (let i = 0; i < sessionCount; i++) {
573
- const numeric = readNumericUuid(index);
574
- sessions.push([numeric, new Session(numeric)]);
575
- }
576
-
577
- const compressor = new IdCompressor(new Sessions(sessions));
578
- compressor.clusterCapacity = clusterCapacity;
579
-
580
- // Clusters
581
- let baseFinalId = 0;
582
- for (let i = 0; i < clusterCount; i++) {
583
- const sessionIndex = readNumber(index);
584
- const session = sessions[sessionIndex + sessionOffset][1];
585
- const capacity = readNumber(index);
586
- const count = readNumber(index);
587
- const cluster = session.addNewCluster(
588
- baseFinalId as FinalCompressedId,
589
- capacity,
590
- count,
591
- );
592
- compressor.finalSpace.addCluster(cluster);
593
- baseFinalId += capacity;
594
- }
595
-
596
- // Local state
597
- if (hasLocalState) {
598
- compressor.localGenCount = readNumber(index);
599
- compressor.nextRangeBaseGenCount = readNumber(index);
600
- const normalizerCount = readNumber(index);
601
- for (let i = 0; i < normalizerCount; i++) {
602
- compressor.normalizer.addLocalRange(readNumber(index), readNumber(index));
603
- }
604
- }
605
-
606
- assert(
607
- index.index === index.bufferFloat.length,
608
- 0x75f /* Failed to read entire serialized compressor. */,
609
- );
610
- return compressor;
611
- }
612
-
613
- public equals(other: IdCompressor, includeLocalState: boolean): boolean {
614
- if (
615
- includeLocalState &&
616
- (this.localSessionId !== other.localSessionId ||
617
- !this.localSession.equals(other.localSession) ||
618
- !this.normalizer.equals(other.normalizer) ||
619
- this.nextRangeBaseGenCount !== other.nextRangeBaseGenCount ||
620
- this.localGenCount !== other.localGenCount)
621
- ) {
622
- return false;
623
- }
624
- return (
625
- this.newClusterCapacity === other.newClusterCapacity &&
626
- this.sessions.equals(other.sessions, includeLocalState) &&
627
- this.finalSpace.equals(other.finalSpace)
628
- );
629
- }
630
- }