@fluidframework/id-compressor
Advanced tools
@@ -38,2 +38,3 @@ ## API Report File for "@fluidframework/id-compressor" | ||
readonly requestedClusterSize: number; | ||
readonly localIdRanges: [genCount: number, count: number][]; | ||
}; | ||
@@ -58,3 +59,3 @@ // (undocumented) | ||
export interface IIdCompressorCore { | ||
beginGhostSession(ghostSessionId: SessionId, ghostSessionCallback: () => void): any; | ||
beginGhostSession(ghostSessionId: SessionId, ghostSessionCallback: () => void): void; | ||
finalizeCreationRange(range: IdCreationRange): void; | ||
@@ -61,0 +62,0 @@ serialize(withSession: true): SerializedIdCompressorWithOngoingSession; |
@@ -10,3 +10,3 @@ "use strict"; | ||
/* eslint-disable no-bitwise */ | ||
const core_utils_1 = require("@fluidframework/core-utils"); | ||
const internal_1 = require("@fluidframework/core-utils/internal"); | ||
/** | ||
@@ -215,3 +215,3 @@ * A map in which entries are always added in key-sorted order. | ||
if (prev !== undefined) { | ||
(0, core_utils_1.assert)(this.comparator(kv[0], prev[0]) > 0, 0x752 /* Keys in map must be sorted. */); | ||
(0, internal_1.assert)(this.comparator(kv[0], prev[0]) > 0, 0x752 /* Keys in map must be sorted. */); | ||
} | ||
@@ -218,0 +218,0 @@ prev = kv; |
@@ -8,3 +8,3 @@ "use strict"; | ||
exports.FinalSpace = void 0; | ||
const core_utils_1 = require("@fluidframework/core-utils"); | ||
const internal_1 = require("@fluidframework/core-utils/internal"); | ||
const sessions_js_1 = require("./sessions.js"); | ||
@@ -28,3 +28,3 @@ /** | ||
const lastCluster = this.getLastCluster(); | ||
(0, core_utils_1.assert)(lastCluster === undefined || | ||
(0, internal_1.assert)(lastCluster === undefined || | ||
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands | ||
@@ -31,0 +31,0 @@ newCluster.baseFinalId === lastCluster.baseFinalId + lastCluster.capacity, 0x753 /* Cluster insert to final_space is out of order. */); |
@@ -62,2 +62,6 @@ import { ITelemetryBaseLogger } from '@fluidframework/core-interfaces'; | ||
readonly requestedClusterSize: number; | ||
/** | ||
* The ranges of IDs that were allocated as local IDs in the range created by `sessionId.` | ||
*/ | ||
readonly localIdRanges: [genCount: number, count: number][]; | ||
}; | ||
@@ -275,3 +279,3 @@ } | ||
*/ | ||
beginGhostSession(ghostSessionId: SessionId, ghostSessionCallback: () => void): any; | ||
beginGhostSession(ghostSessionId: SessionId, ghostSessionCallback: () => void): void; | ||
/** | ||
@@ -278,0 +282,0 @@ * Returns a persistable form of the current state of this `IdCompressor` which can be rehydrated via `IdCompressor.deserialize()`. |
@@ -70,2 +70,6 @@ import { ITelemetryBaseLogger } from '@fluidframework/core-interfaces'; | ||
readonly requestedClusterSize: number; | ||
/** | ||
* The ranges of IDs that were allocated as local IDs in the range created by `sessionId.` | ||
*/ | ||
readonly localIdRanges: [genCount: number, count: number][]; | ||
}; | ||
@@ -283,3 +287,3 @@ } | ||
*/ | ||
beginGhostSession(ghostSessionId: SessionId, ghostSessionCallback: () => void): any; | ||
beginGhostSession(ghostSessionId: SessionId, ghostSessionCallback: () => void): void; | ||
/** | ||
@@ -286,0 +290,0 @@ * Returns a persistable form of the current state of this `IdCompressor` which can be rehydrated via `IdCompressor.deserialize()`. |
@@ -9,4 +9,4 @@ "use strict"; | ||
const client_utils_1 = require("@fluid-internal/client-utils"); | ||
const core_utils_1 = require("@fluidframework/core-utils"); | ||
const telemetry_utils_1 = require("@fluidframework/telemetry-utils"); | ||
const internal_1 = require("@fluidframework/core-utils/internal"); | ||
const internal_2 = require("@fluidframework/telemetry-utils/internal"); | ||
const finalSpace_js_1 = require("./finalSpace.js"); | ||
@@ -64,3 +64,3 @@ const identifiers_js_1 = require("./identifiers.js"); | ||
const firstSession = localSessionIdOrDeserialized.sessions().next(); | ||
(0, core_utils_1.assert)(!firstSession.done, 0x754 /* First session must be present. */); | ||
(0, internal_1.assert)(!firstSession.done, 0x754 /* First session must be present. */); | ||
this.localSession = firstSession.value; | ||
@@ -115,3 +115,3 @@ this.localSessionId = (0, utilities_js_1.stableIdFromNumericUuid)(this.localSession.sessionUuid); | ||
startGhostSession(ghostSessionId) { | ||
(0, core_utils_1.assert)(!this.ongoingGhostSession, 0x8fe /* Ghost session already in progress. */); | ||
(0, internal_1.assert)(!this.ongoingGhostSession, 0x8fe /* Ghost session already in progress. */); | ||
this.ongoingGhostSession = { ghostSessionId }; | ||
@@ -137,3 +137,3 @@ } | ||
takeNextCreationRange() { | ||
(0, core_utils_1.assert)(!this.ongoingGhostSession, 0x8a6 /* IdCompressor should not be operated normally when in a ghost session */); | ||
(0, internal_1.assert)(!this.ongoingGhostSession, 0x8a6 /* IdCompressor should not be operated normally when in a ghost session */); | ||
const count = this.localGenCount - (this.nextRangeBaseGenCount - 1); | ||
@@ -151,2 +151,3 @@ if (count === 0) { | ||
requestedClusterSize: this.nextRequestedClusterSize, | ||
localIdRanges: this.normalizer.getRangesBetween(this.nextRangeBaseGenCount, this.localGenCount), | ||
}, | ||
@@ -163,8 +164,8 @@ }; | ||
const { count, requestedClusterSize } = range.ids; | ||
(0, core_utils_1.assert)(count > 0, 0x755 /* Malformed ID Range. */); | ||
(0, core_utils_1.assert)(requestedClusterSize > 0, 0x876 /* Clusters must have a positive capacity. */); | ||
(0, core_utils_1.assert)(requestedClusterSize <= IdCompressor.maxClusterSize, 0x877 /* Clusters must not exceed max cluster size. */); | ||
(0, internal_1.assert)(count > 0, 0x755 /* Malformed ID Range. */); | ||
(0, internal_1.assert)(requestedClusterSize > 0, 0x876 /* Clusters must have a positive capacity. */); | ||
(0, internal_1.assert)(requestedClusterSize <= IdCompressor.maxClusterSize, 0x877 /* Clusters must not exceed max cluster size. */); | ||
} | ||
finalizeCreationRange(range) { | ||
(0, core_utils_1.assert)(!this.ongoingGhostSession, 0x8a7 /* IdCompressor should not be operated normally when in a ghost session */); | ||
(0, internal_1.assert)(!this.ongoingGhostSession, 0x8a7 /* IdCompressor should not be operated normally when in a ghost session */); | ||
// Check if the range has IDs | ||
@@ -209,3 +210,3 @@ if (range.ids === undefined) { | ||
lastCluster.count += count; | ||
(0, core_utils_1.assert)(!this.sessions.clusterCollides(lastCluster), 0x756 /* Cluster collision detected. */); | ||
(0, internal_1.assert)(!this.sessions.clusterCollides(lastCluster), 0x756 /* Cluster collision detected. */); | ||
if (isLocal) { | ||
@@ -244,8 +245,8 @@ this.logger?.sendTelemetryEvent({ | ||
} | ||
(0, core_utils_1.assert)(!session.isEmpty(), 0x757 /* Empty sessions should not be created. */); | ||
(0, internal_1.assert)(!session.isEmpty(), 0x757 /* Empty sessions should not be created. */); | ||
} | ||
addEmptyCluster(session, capacity) { | ||
(0, core_utils_1.assert)(!this.ongoingGhostSession?.cluster, 0x8a8 /* IdCompressor should not be operated normally when in a ghost session */); | ||
(0, internal_1.assert)(!this.ongoingGhostSession?.cluster, 0x8a8 /* IdCompressor should not be operated normally when in a ghost session */); | ||
const newCluster = session.addNewCluster(this.finalSpace.getAllocatedIdLimit(), capacity, 0); | ||
(0, core_utils_1.assert)(!this.sessions.clusterCollides(newCluster), 0x758 /* Cluster collision detected. */); | ||
(0, internal_1.assert)(!this.sessions.clusterCollides(newCluster), 0x758 /* Cluster collision detected. */); | ||
this.finalSpace.addCluster(newCluster); | ||
@@ -329,3 +330,3 @@ return newCluster; | ||
if (containingCluster.session === this.localSession) { | ||
(0, core_utils_1.assert)(!this.normalizer.contains(alignedLocal), 0x759 /* Normalizer out of sync. */); | ||
(0, internal_1.assert)(!this.normalizer.contains(alignedLocal), 0x759 /* Normalizer out of sync. */); | ||
} | ||
@@ -375,3 +376,3 @@ else { | ||
else { | ||
(0, core_utils_1.assert)((0, utilities_js_1.genCountFromLocalId)(alignedLocal) <= this.localGenCount, 0x75a /* Clusters out of sync. */); | ||
(0, internal_1.assert)((0, utilities_js_1.genCountFromLocalId)(alignedLocal) <= this.localGenCount, 0x75a /* Clusters out of sync. */); | ||
// Id is an eager final | ||
@@ -390,3 +391,3 @@ return (0, sessions_js_1.getAlignedFinal)(containingCluster, alignedLocal); | ||
serialize(hasLocalState) { | ||
(0, core_utils_1.assert)(!this.ongoingGhostSession, 0x8a9 /* IdCompressor should not be operated normally when in a ghost session */); | ||
(0, internal_1.assert)(!this.ongoingGhostSession, 0x8a9 /* IdCompressor should not be operated normally when in a ghost session */); | ||
const { normalizer, finalSpace, sessions } = this; | ||
@@ -440,3 +441,3 @@ const sessionIndexMap = new Map(); | ||
} | ||
(0, core_utils_1.assert)(index === totalSize, 0x75b /* Serialized size was incorrectly calculated. */); | ||
(0, internal_1.assert)(index === totalSize, 0x75b /* Serialized size was incorrectly calculated. */); | ||
this.logger?.sendTelemetryEvent({ | ||
@@ -484,3 +485,3 @@ eventName: "RuntimeIdCompressor:SerializedIdCompressorSize", | ||
// If !hasLocalState, there won't be a serialized local session ID so insert one at the beginning | ||
(0, core_utils_1.assert)(sessionId !== undefined, 0x75d /* Local session ID is undefined. */); | ||
(0, internal_1.assert)(sessionId !== undefined, 0x75d /* Local session ID is undefined. */); | ||
const localSessionNumeric = (0, utilities_js_1.numericUuidFromStableId)(sessionId); | ||
@@ -491,3 +492,3 @@ sessions.push([localSessionNumeric, new sessions_js_1.Session(localSessionNumeric)]); | ||
else { | ||
(0, core_utils_1.assert)(sessionId === undefined, 0x75e /* Local state should not exist in serialized form. */); | ||
(0, internal_1.assert)(sessionId === undefined, 0x75e /* Local state should not exist in serialized form. */); | ||
} | ||
@@ -519,3 +520,3 @@ for (let i = 0; i < sessionCount; i++) { | ||
} | ||
(0, core_utils_1.assert)(index.index === index.bufferFloat.length, 0x75f /* Failed to read entire serialized compressor. */); | ||
(0, internal_1.assert)(index.index === index.bufferFloat.length, 0x75f /* Failed to read entire serialized compressor. */); | ||
return compressor; | ||
@@ -557,3 +558,3 @@ } | ||
} | ||
const compressor = new IdCompressor(localSessionId, logger === undefined ? undefined : (0, telemetry_utils_1.createChildLogger)({ logger })); | ||
const compressor = new IdCompressor(localSessionId, logger === undefined ? undefined : (0, internal_2.createChildLogger)({ logger })); | ||
return compressor; | ||
@@ -560,0 +561,0 @@ } |
@@ -8,3 +8,3 @@ /*! | ||
export declare const pkgName = "@fluidframework/id-compressor"; | ||
export declare const pkgVersion = "2.0.0-dev-rc.3.0.0.250606"; | ||
export declare const pkgVersion = "2.0.0-dev-rc.3.0.0.253463"; | ||
//# sourceMappingURL=packageVersion.d.ts.map |
@@ -11,3 +11,3 @@ "use strict"; | ||
exports.pkgName = "@fluidframework/id-compressor"; | ||
exports.pkgVersion = "2.0.0-dev-rc.3.0.0.250606"; | ||
exports.pkgVersion = "2.0.0-dev-rc.3.0.0.253463"; | ||
//# sourceMappingURL=packageVersion.js.map |
@@ -8,3 +8,3 @@ "use strict"; | ||
exports.lastFinalizedLocal = exports.lastAllocatedLocal = exports.lastFinalizedFinal = exports.lastAllocatedFinal = exports.getAlignedLocal = exports.getAlignedFinal = exports.clustersEqual = exports.Session = exports.Sessions = void 0; | ||
const core_utils_1 = require("@fluidframework/core-utils"); | ||
const internal_1 = require("@fluidframework/core-utils/internal"); | ||
const sorted_btree_es6_1 = require("@tylerbu/sorted-btree-es6"); | ||
@@ -44,3 +44,3 @@ const utilities_js_1 = require("./utilities.js"); | ||
const session = new Session(sessionId); | ||
(0, core_utils_1.assert)(this.uuidSpace.set(session.sessionUuid, session), 0x760 /* Duplicate session in map. */); | ||
(0, internal_1.assert)(this.uuidSpace.set(session.sessionUuid, session), 0x760 /* Duplicate session in map. */); | ||
this.sessionCache.set(sessionId, session); | ||
@@ -92,3 +92,3 @@ return session; | ||
const [_, session] = closestMatch; | ||
(0, core_utils_1.assert)(session !== owningSession, 0x761 /* Failed to attempt to detect collisions. */); | ||
(0, internal_1.assert)(session !== owningSession, 0x761 /* Failed to attempt to detect collisions. */); | ||
const lastCluster = session.getLastCluster(); | ||
@@ -114,3 +114,3 @@ if (lastCluster === undefined) { | ||
} | ||
(0, core_utils_1.assert)(session === firstSessionThis, 0x762 /* The only non-empty session must be the local session. */); | ||
(0, internal_1.assert)(session === firstSessionThis, 0x762 /* The only non-empty session must be the local session. */); | ||
} | ||
@@ -273,3 +273,3 @@ else if (!session.equals(otherSession)) { | ||
function getAlignedLocal(cluster, finalWithin) { | ||
(0, core_utils_1.assert)(finalWithin >= cluster.baseFinalId && finalWithin <= lastAllocatedFinal(cluster), 0x763 /* Supplied ID is not within the cluster. */); | ||
(0, internal_1.assert)(finalWithin >= cluster.baseFinalId && finalWithin <= lastAllocatedFinal(cluster), 0x763 /* Supplied ID is not within the cluster. */); | ||
const finalDelta = finalWithin - cluster.baseFinalId; | ||
@@ -276,0 +276,0 @@ return (cluster.baseLocalId - finalDelta); |
@@ -42,2 +42,4 @@ /*! | ||
get idRanges(): Pick<AppendOnlySortedMap<number, number>, "size" | "entries">; | ||
getRangesBetween(firstGenCount: number, lastGenCount: number): [genCount: number, count: number][]; | ||
private rangeContains; | ||
addLocalRange(baseGenCount: number, count: number): void; | ||
@@ -44,0 +46,0 @@ contains(query: LocalCompressedId): boolean; |
@@ -8,2 +8,3 @@ "use strict"; | ||
exports.SessionSpaceNormalizer = void 0; | ||
const internal_1 = require("@fluidframework/core-utils/internal"); | ||
const appendOnlySortedMap_js_1 = require("./appendOnlySortedMap.js"); | ||
@@ -52,2 +53,45 @@ const utilities_js_1 = require("./utilities.js"); | ||
} | ||
getRangesBetween(firstGenCount, lastGenCount) { | ||
const ranges = []; | ||
// we need to find the first range that either contains firstGenCount or is after it, | ||
// since this method must find ranges between firstGenCount and lastGenCount | ||
let firstRange = this.localIdRanges.getPairOrNextLower(firstGenCount); | ||
// if the first range does not contain the first ID, next higher range is between but non-containing | ||
if (firstRange === undefined || !this.rangeContains(firstRange, firstGenCount)) { | ||
firstRange = this.localIdRanges.getPairOrNextHigher(firstGenCount); | ||
if (firstRange === undefined) { | ||
return ranges; | ||
} | ||
} | ||
for (const [genCount, count] of this.localIdRanges.getRange(firstRange[0], lastGenCount)) { | ||
ranges.push([genCount, count]); | ||
} | ||
if (ranges.length === 0) { | ||
return ranges; | ||
} | ||
// now we touch up the first and last ranges to ensure that if they contain the | ||
// queried IDs they are trimmed to start/end with the queried IDs | ||
const [baseGenCount, baseCount] = ranges[0]; | ||
if (this.rangeContains(ranges[0], firstGenCount)) { | ||
ranges[0] = [firstGenCount, baseCount - (firstGenCount - baseGenCount)]; | ||
(0, internal_1.assert)(this.rangeContains(ranges[0], firstGenCount), "Expected the touched up range to contain the queried ID"); | ||
} | ||
else { | ||
(0, internal_1.assert)(baseGenCount > firstGenCount, "Expected the first range to start after the queried ID"); | ||
} | ||
const lastRangeIndex = ranges.length - 1; | ||
const [limitGenCount, limitCount] = ranges[lastRangeIndex]; | ||
if (this.rangeContains(ranges[lastRangeIndex], lastGenCount)) { | ||
ranges[lastRangeIndex] = [limitGenCount, lastGenCount - limitGenCount + 1]; | ||
(0, internal_1.assert)(this.rangeContains(ranges[lastRangeIndex], lastGenCount), "Expected the touched up range to contain the queried ID"); | ||
} | ||
else { | ||
(0, internal_1.assert)(limitGenCount + limitCount - 1 < lastGenCount, "Expected the last range to end before the queried ID"); | ||
} | ||
return ranges; | ||
} | ||
rangeContains(range, genCount) { | ||
const [baseGenCount, count] = range; | ||
return genCount >= baseGenCount && genCount < baseGenCount + count; | ||
} | ||
addLocalRange(baseGenCount, count) { | ||
@@ -54,0 +98,0 @@ const last = this.localIdRanges.last(); |
@@ -7,4 +7,4 @@ /*! | ||
import { ITelemetryBaseLogger } from "@fluidframework/core-interfaces"; | ||
import { type IIdCompressor, type IIdCompressorCore, OpSpaceCompressedId, SerializedIdCompressorWithNoSession, SerializedIdCompressorWithOngoingSession, SessionId, SessionSpaceCompressedId } from "..//index.js"; | ||
import { IdCompressor } from "../idCompressor.js"; | ||
import { type IIdCompressor, type IIdCompressorCore, OpSpaceCompressedId, SerializedIdCompressorWithNoSession, SerializedIdCompressorWithOngoingSession, SessionId, SessionSpaceCompressedId } from "../index.js"; | ||
import { ReadonlyIdCompressor } from "./testCommon.js"; | ||
@@ -11,0 +11,0 @@ /** |
@@ -10,4 +10,4 @@ "use strict"; | ||
const stochastic_test_utils_1 = require("@fluid-private/stochastic-test-utils"); | ||
const index_js_1 = require("..//index.js"); | ||
const idCompressor_js_1 = require("../idCompressor.js"); | ||
const index_js_1 = require("../index.js"); | ||
const utilities_js_1 = require("../utilities.js"); | ||
@@ -77,2 +77,3 @@ const testCommon_js_1 = require("./testCommon.js"); | ||
requestedClusterSize: capacity, | ||
localIdRanges: [], // remote session, can safely ignore in tests | ||
}, | ||
@@ -223,2 +224,3 @@ }); | ||
"nextRequestedClusterSize"], | ||
localIdRanges: [], // remote session, can safely ignore in tests | ||
}, | ||
@@ -289,2 +291,24 @@ }; | ||
const sequencedLogs = Object.values(Client).map((client) => [this.compressors.get(client), this.getSequencedIdLog(client)]); | ||
// Ensure creation ranges for clients we track contain the correct local ID ranges | ||
this.serverOperations.forEach(([range, opSpaceIds, clientFrom]) => { | ||
const localIdsInCreationRange = new Set(); | ||
if (clientFrom !== exports.OriginatingClient.Remote) { | ||
const ids = range.ids; | ||
if (ids !== undefined) { | ||
const { firstGenCount, localIdRanges } = ids; | ||
for (const [genCount, count] of localIdRanges) { | ||
for (let g = genCount; g < genCount + count; g++) { | ||
const local = (0, utilities_js_1.localIdFromGenCount)(g); | ||
assert_1.strict.strictEqual(opSpaceIds[g - firstGenCount], local); | ||
localIdsInCreationRange.add(local); | ||
} | ||
} | ||
} | ||
opSpaceIds.forEach((id) => { | ||
if ((0, testCommon_js_1.isLocalId)(id)) { | ||
(0, assert_1.strict)(localIdsInCreationRange.has(id), "Local ID not in creation range"); | ||
} | ||
}); | ||
} | ||
}); | ||
// First, ensure all clients each generated a unique ID for each of their own calls to generate. | ||
@@ -291,0 +315,0 @@ for (const [compressor, ids] of sequencedLogs) { |
@@ -5,4 +5,4 @@ /*! | ||
*/ | ||
import { OpSpaceCompressedId, SessionSpaceCompressedId, StableId } from "..//index.js"; | ||
import { IdCompressor } from "../idCompressor.js"; | ||
import { OpSpaceCompressedId, SessionSpaceCompressedId, StableId } from "../index.js"; | ||
/** | ||
@@ -9,0 +9,0 @@ * An identifier (v4 UUID) that has been shortened by a distributed compression algorithm. |
@@ -8,3 +8,3 @@ "use strict"; | ||
exports.fail = exports.assertNotUndefined = exports.incrementStableId = exports.getOrCreate = exports.makeLocalId = exports.isLocalId = exports.isFinalId = void 0; | ||
const core_utils_1 = require("@fluidframework/core-utils"); | ||
const internal_1 = require("@fluidframework/core-utils/internal"); | ||
const utilities_js_1 = require("../utilities.js"); | ||
@@ -30,3 +30,3 @@ /** | ||
const id = negativeInteger; | ||
(0, core_utils_1.assert)(isLocalId(id), "Not a negative integer."); | ||
(0, internal_1.assert)(isLocalId(id), "Not a negative integer."); | ||
return id; | ||
@@ -79,3 +79,3 @@ } | ||
function assertNotUndefined(value, message = "value must not be undefined") { | ||
(0, core_utils_1.assert)(value !== undefined, message); | ||
(0, internal_1.assert)(value !== undefined, message); | ||
return value; | ||
@@ -90,5 +90,5 @@ } | ||
function fail(message) { | ||
(0, core_utils_1.assert)(false, message); | ||
(0, internal_1.assert)(false, message); | ||
} | ||
exports.fail = fail; | ||
//# sourceMappingURL=testCommon.js.map |
@@ -102,3 +102,3 @@ /*! | ||
*/ | ||
beginGhostSession(ghostSessionId: SessionId, ghostSessionCallback: () => void): any; | ||
beginGhostSession(ghostSessionId: SessionId, ghostSessionCallback: () => void): void; | ||
/** | ||
@@ -105,0 +105,0 @@ * Returns a persistable form of the current state of this `IdCompressor` which can be rehydrated via `IdCompressor.deserialize()`. |
@@ -50,4 +50,8 @@ /*! | ||
readonly requestedClusterSize: number; | ||
/** | ||
* The ranges of IDs that were allocated as local IDs in the range created by `sessionId.` | ||
*/ | ||
readonly localIdRanges: [genCount: number, count: number][]; | ||
}; | ||
} | ||
//# sourceMappingURL=0.0.1.d.ts.map |
@@ -9,3 +9,3 @@ "use strict"; | ||
/* eslint-disable no-bitwise */ | ||
const core_utils_1 = require("@fluidframework/core-utils"); | ||
const internal_1 = require("@fluidframework/core-utils/internal"); | ||
const uuid_1 = require("uuid"); | ||
@@ -31,3 +31,3 @@ const hexadecimalCharCodes = Array.from("09afAF").map((c) => c.charCodeAt(0)); | ||
function assertIsStableId(stableId) { | ||
(0, core_utils_1.assert)(isStableId(stableId), 0x4a3 /* Expected a StableId */); | ||
(0, internal_1.assert)(isStableId(stableId), 0x4a3 /* Expected a StableId */); | ||
return stableId; | ||
@@ -34,0 +34,0 @@ } |
@@ -7,3 +7,3 @@ /*! | ||
/* eslint-disable no-bitwise */ | ||
import { assert } from "@fluidframework/core-utils"; | ||
import { assert } from "@fluidframework/core-utils/internal"; | ||
/** | ||
@@ -10,0 +10,0 @@ * A map in which entries are always added in key-sorted order. |
@@ -5,3 +5,3 @@ /*! | ||
*/ | ||
import { assert } from "@fluidframework/core-utils"; | ||
import { assert } from "@fluidframework/core-utils/internal"; | ||
import { clustersEqual, lastAllocatedFinal, lastFinalizedFinal } from "./sessions.js"; | ||
@@ -8,0 +8,0 @@ /** |
@@ -62,2 +62,6 @@ import { ITelemetryBaseLogger } from '@fluidframework/core-interfaces'; | ||
readonly requestedClusterSize: number; | ||
/** | ||
* The ranges of IDs that were allocated as local IDs in the range created by `sessionId.` | ||
*/ | ||
readonly localIdRanges: [genCount: number, count: number][]; | ||
}; | ||
@@ -275,3 +279,3 @@ } | ||
*/ | ||
beginGhostSession(ghostSessionId: SessionId, ghostSessionCallback: () => void): any; | ||
beginGhostSession(ghostSessionId: SessionId, ghostSessionCallback: () => void): void; | ||
/** | ||
@@ -278,0 +282,0 @@ * Returns a persistable form of the current state of this `IdCompressor` which can be rehydrated via `IdCompressor.deserialize()`. |
@@ -70,2 +70,6 @@ import { ITelemetryBaseLogger } from '@fluidframework/core-interfaces'; | ||
readonly requestedClusterSize: number; | ||
/** | ||
* The ranges of IDs that were allocated as local IDs in the range created by `sessionId.` | ||
*/ | ||
readonly localIdRanges: [genCount: number, count: number][]; | ||
}; | ||
@@ -283,3 +287,3 @@ } | ||
*/ | ||
beginGhostSession(ghostSessionId: SessionId, ghostSessionCallback: () => void): any; | ||
beginGhostSession(ghostSessionId: SessionId, ghostSessionCallback: () => void): void; | ||
/** | ||
@@ -286,0 +290,0 @@ * Returns a persistable form of the current state of this `IdCompressor` which can be rehydrated via `IdCompressor.deserialize()`. |
@@ -6,4 +6,4 @@ /*! | ||
import { bufferToString, stringToBuffer } from "@fluid-internal/client-utils"; | ||
import { assert } from "@fluidframework/core-utils"; | ||
import { createChildLogger } from "@fluidframework/telemetry-utils"; | ||
import { assert } from "@fluidframework/core-utils/internal"; | ||
import { createChildLogger } from "@fluidframework/telemetry-utils/internal"; | ||
import { FinalSpace } from "./finalSpace.js"; | ||
@@ -145,2 +145,3 @@ import { isFinalId } from "./identifiers.js"; | ||
requestedClusterSize: this.nextRequestedClusterSize, | ||
localIdRanges: this.normalizer.getRangesBetween(this.nextRangeBaseGenCount, this.localGenCount), | ||
}, | ||
@@ -147,0 +148,0 @@ }; |
@@ -8,3 +8,3 @@ /*! | ||
export declare const pkgName = "@fluidframework/id-compressor"; | ||
export declare const pkgVersion = "2.0.0-dev-rc.3.0.0.250606"; | ||
export declare const pkgVersion = "2.0.0-dev-rc.3.0.0.253463"; | ||
//# sourceMappingURL=packageVersion.d.ts.map |
@@ -8,3 +8,3 @@ /*! | ||
export const pkgName = "@fluidframework/id-compressor"; | ||
export const pkgVersion = "2.0.0-dev-rc.3.0.0.250606"; | ||
export const pkgVersion = "2.0.0-dev-rc.3.0.0.253463"; | ||
//# sourceMappingURL=packageVersion.js.map |
@@ -5,3 +5,3 @@ /*! | ||
*/ | ||
import { assert } from "@fluidframework/core-utils"; | ||
import { assert } from "@fluidframework/core-utils/internal"; | ||
import { BTree } from "@tylerbu/sorted-btree-es6"; | ||
@@ -8,0 +8,0 @@ import { compareBigints, genCountFromLocalId, localIdFromGenCount, numericUuidFromStableId, offsetNumericUuid, stableIdFromNumericUuid, subtractNumericUuids, } from "./utilities.js"; |
@@ -42,2 +42,4 @@ /*! | ||
get idRanges(): Pick<AppendOnlySortedMap<number, number>, "size" | "entries">; | ||
getRangesBetween(firstGenCount: number, lastGenCount: number): [genCount: number, count: number][]; | ||
private rangeContains; | ||
addLocalRange(baseGenCount: number, count: number): void; | ||
@@ -44,0 +46,0 @@ contains(query: LocalCompressedId): boolean; |
@@ -5,2 +5,3 @@ /*! | ||
*/ | ||
import { assert } from "@fluidframework/core-utils/internal"; | ||
import { AppendOnlySortedMap } from "./appendOnlySortedMap.js"; | ||
@@ -49,2 +50,45 @@ import { compareFiniteNumbers, genCountFromLocalId } from "./utilities.js"; | ||
} | ||
getRangesBetween(firstGenCount, lastGenCount) { | ||
const ranges = []; | ||
// we need to find the first range that either contains firstGenCount or is after it, | ||
// since this method must find ranges between firstGenCount and lastGenCount | ||
let firstRange = this.localIdRanges.getPairOrNextLower(firstGenCount); | ||
// if the first range does not contain the first ID, next higher range is between but non-containing | ||
if (firstRange === undefined || !this.rangeContains(firstRange, firstGenCount)) { | ||
firstRange = this.localIdRanges.getPairOrNextHigher(firstGenCount); | ||
if (firstRange === undefined) { | ||
return ranges; | ||
} | ||
} | ||
for (const [genCount, count] of this.localIdRanges.getRange(firstRange[0], lastGenCount)) { | ||
ranges.push([genCount, count]); | ||
} | ||
if (ranges.length === 0) { | ||
return ranges; | ||
} | ||
// now we touch up the first and last ranges to ensure that if they contain the | ||
// queried IDs they are trimmed to start/end with the queried IDs | ||
const [baseGenCount, baseCount] = ranges[0]; | ||
if (this.rangeContains(ranges[0], firstGenCount)) { | ||
ranges[0] = [firstGenCount, baseCount - (firstGenCount - baseGenCount)]; | ||
assert(this.rangeContains(ranges[0], firstGenCount), "Expected the touched up range to contain the queried ID"); | ||
} | ||
else { | ||
assert(baseGenCount > firstGenCount, "Expected the first range to start after the queried ID"); | ||
} | ||
const lastRangeIndex = ranges.length - 1; | ||
const [limitGenCount, limitCount] = ranges[lastRangeIndex]; | ||
if (this.rangeContains(ranges[lastRangeIndex], lastGenCount)) { | ||
ranges[lastRangeIndex] = [limitGenCount, lastGenCount - limitGenCount + 1]; | ||
assert(this.rangeContains(ranges[lastRangeIndex], lastGenCount), "Expected the touched up range to contain the queried ID"); | ||
} | ||
else { | ||
assert(limitGenCount + limitCount - 1 < lastGenCount, "Expected the last range to end before the queried ID"); | ||
} | ||
return ranges; | ||
} | ||
rangeContains(range, genCount) { | ||
const [baseGenCount, count] = range; | ||
return genCount >= baseGenCount && genCount < baseGenCount + count; | ||
} | ||
addLocalRange(baseGenCount, count) { | ||
@@ -51,0 +95,0 @@ const last = this.localIdRanges.last(); |
@@ -7,4 +7,4 @@ /*! | ||
import { ITelemetryBaseLogger } from "@fluidframework/core-interfaces"; | ||
import { type IIdCompressor, type IIdCompressorCore, OpSpaceCompressedId, SerializedIdCompressorWithNoSession, SerializedIdCompressorWithOngoingSession, SessionId, SessionSpaceCompressedId } from "..//index.js"; | ||
import { IdCompressor } from "../idCompressor.js"; | ||
import { type IIdCompressor, type IIdCompressorCore, OpSpaceCompressedId, SerializedIdCompressorWithNoSession, SerializedIdCompressorWithOngoingSession, SessionId, SessionSpaceCompressedId } from "../index.js"; | ||
import { ReadonlyIdCompressor } from "./testCommon.js"; | ||
@@ -11,0 +11,0 @@ /** |
@@ -7,5 +7,5 @@ /*! | ||
import { createWeightedGenerator, interleave, makeRandom, performFuzzActions as performFuzzActionsBase, repeat, take, } from "@fluid-private/stochastic-test-utils"; | ||
import { createIdCompressor, } from "..//index.js"; | ||
import { IdCompressor } from "../idCompressor.js"; | ||
import { assertIsSessionId, createSessionId } from "../utilities.js"; | ||
import { createIdCompressor, } from "../index.js"; | ||
import { assertIsSessionId, createSessionId, localIdFromGenCount } from "../utilities.js"; | ||
import { fail, getOrCreate, incrementStableId, isFinalId, isLocalId, } from "./testCommon.js"; | ||
@@ -73,2 +73,3 @@ /** Identifies a compressor in a network */ | ||
requestedClusterSize: capacity, | ||
localIdRanges: [], // remote session, can safely ignore in tests | ||
}, | ||
@@ -218,2 +219,3 @@ }); | ||
"nextRequestedClusterSize"], | ||
localIdRanges: [], // remote session, can safely ignore in tests | ||
}, | ||
@@ -284,2 +286,24 @@ }; | ||
const sequencedLogs = Object.values(Client).map((client) => [this.compressors.get(client), this.getSequencedIdLog(client)]); | ||
// Ensure creation ranges for clients we track contain the correct local ID ranges | ||
this.serverOperations.forEach(([range, opSpaceIds, clientFrom]) => { | ||
const localIdsInCreationRange = new Set(); | ||
if (clientFrom !== OriginatingClient.Remote) { | ||
const ids = range.ids; | ||
if (ids !== undefined) { | ||
const { firstGenCount, localIdRanges } = ids; | ||
for (const [genCount, count] of localIdRanges) { | ||
for (let g = genCount; g < genCount + count; g++) { | ||
const local = localIdFromGenCount(g); | ||
assert.strictEqual(opSpaceIds[g - firstGenCount], local); | ||
localIdsInCreationRange.add(local); | ||
} | ||
} | ||
} | ||
opSpaceIds.forEach((id) => { | ||
if (isLocalId(id)) { | ||
assert(localIdsInCreationRange.has(id), "Local ID not in creation range"); | ||
} | ||
}); | ||
} | ||
}); | ||
// First, ensure all clients each generated a unique ID for each of their own calls to generate. | ||
@@ -286,0 +310,0 @@ for (const [compressor, ids] of sequencedLogs) { |
@@ -5,4 +5,4 @@ /*! | ||
*/ | ||
import { OpSpaceCompressedId, SessionSpaceCompressedId, StableId } from "..//index.js"; | ||
import { IdCompressor } from "../idCompressor.js"; | ||
import { OpSpaceCompressedId, SessionSpaceCompressedId, StableId } from "../index.js"; | ||
/** | ||
@@ -9,0 +9,0 @@ * An identifier (v4 UUID) that has been shortened by a distributed compression algorithm. |
@@ -5,3 +5,3 @@ /*! | ||
*/ | ||
import { assert } from "@fluidframework/core-utils"; | ||
import { assert } from "@fluidframework/core-utils/internal"; | ||
import { numericUuidFromStableId, offsetNumericUuid, stableIdFromNumericUuid, } from "../utilities.js"; | ||
@@ -8,0 +8,0 @@ /** |
@@ -102,3 +102,3 @@ /*! | ||
*/ | ||
beginGhostSession(ghostSessionId: SessionId, ghostSessionCallback: () => void): any; | ||
beginGhostSession(ghostSessionId: SessionId, ghostSessionCallback: () => void): void; | ||
/** | ||
@@ -105,0 +105,0 @@ * Returns a persistable form of the current state of this `IdCompressor` which can be rehydrated via `IdCompressor.deserialize()`. |
@@ -50,4 +50,8 @@ /*! | ||
readonly requestedClusterSize: number; | ||
/** | ||
* The ranges of IDs that were allocated as local IDs in the range created by `sessionId.` | ||
*/ | ||
readonly localIdRanges: [genCount: number, count: number][]; | ||
}; | ||
} | ||
//# sourceMappingURL=0.0.1.d.ts.map |
@@ -6,3 +6,3 @@ /*! | ||
/* eslint-disable no-bitwise */ | ||
import { assert } from "@fluidframework/core-utils"; | ||
import { assert } from "@fluidframework/core-utils/internal"; | ||
import { v4 } from "uuid"; | ||
@@ -9,0 +9,0 @@ const hexadecimalCharCodes = Array.from("09afAF").map((c) => c.charCodeAt(0)); |
{ | ||
"name": "@fluidframework/id-compressor", | ||
"version": "2.0.0-dev-rc.3.0.0.250606", | ||
"version": "2.0.0-dev-rc.3.0.0.253463", | ||
"description": "ID compressor", | ||
@@ -18,12 +18,2 @@ "homepage": "https://fluidframework.com", | ||
"import": { | ||
"types": "./lib/index.d.ts", | ||
"default": "./lib/index.js" | ||
}, | ||
"require": { | ||
"types": "./dist/index.d.ts", | ||
"default": "./dist/index.js" | ||
} | ||
}, | ||
"./public": { | ||
"import": { | ||
"types": "./lib/id-compressor-public.d.ts", | ||
@@ -57,3 +47,3 @@ "default": "./lib/index.js" | ||
}, | ||
"./test": { | ||
"./internal/test-utils": { | ||
"import": { | ||
@@ -67,16 +57,6 @@ "types": "./lib/test/index.d.ts", | ||
} | ||
}, | ||
"./test/idCompressorTestUtilities": { | ||
"import": { | ||
"types": "./lib/test/idCompressorTestUtilities.d.ts", | ||
"default": "./lib/test/idCompressorTestUtilities.js" | ||
}, | ||
"require": { | ||
"types": "./dist/test/idCompressorTestUtilities.d.ts", | ||
"default": "./dist/test/idCompressorTestUtilities.js" | ||
} | ||
} | ||
}, | ||
"main": "dist/index.js", | ||
"types": "dist/index.d.ts", | ||
"types": "dist/id-compressor-public.d.ts", | ||
"c8": { | ||
@@ -87,3 +67,3 @@ "all": true, | ||
"src/test/**/*.*ts", | ||
"dist/test/**/*.*js" | ||
"lib/test/**/*.*js" | ||
], | ||
@@ -93,3 +73,3 @@ "exclude-after-remap": false, | ||
"src/**/*.*ts", | ||
"dist/**/*.*js" | ||
"lib/**/*.*js" | ||
], | ||
@@ -105,6 +85,6 @@ "report-dir": "nyc/report", | ||
"dependencies": { | ||
"@fluid-internal/client-utils": "2.0.0-dev-rc.3.0.0.250606", | ||
"@fluidframework/core-interfaces": "2.0.0-dev-rc.3.0.0.250606", | ||
"@fluidframework/core-utils": "2.0.0-dev-rc.3.0.0.250606", | ||
"@fluidframework/telemetry-utils": "2.0.0-dev-rc.3.0.0.250606", | ||
"@fluid-internal/client-utils": "2.0.0-dev-rc.3.0.0.253463", | ||
"@fluidframework/core-interfaces": "2.0.0-dev-rc.3.0.0.253463", | ||
"@fluidframework/core-utils": "2.0.0-dev-rc.3.0.0.253463", | ||
"@fluidframework/telemetry-utils": "2.0.0-dev-rc.3.0.0.253463", | ||
"@tylerbu/sorted-btree-es6": "^1.8.0", | ||
@@ -114,6 +94,6 @@ "uuid": "^9.0.0" | ||
"devDependencies": { | ||
"@arethetypeswrong/cli": "^0.13.3", | ||
"@arethetypeswrong/cli": "^0.15.2", | ||
"@biomejs/biome": "^1.6.2", | ||
"@fluid-internal/mocha-test-setup": "2.0.0-dev-rc.3.0.0.250606", | ||
"@fluid-private/stochastic-test-utils": "2.0.0-dev-rc.3.0.0.250606", | ||
"@fluid-internal/mocha-test-setup": "2.0.0-dev-rc.3.0.0.253463", | ||
"@fluid-private/stochastic-test-utils": "2.0.0-dev-rc.3.0.0.253463", | ||
"@fluid-tools/benchmark": "^0.48.0", | ||
@@ -170,3 +150,2 @@ "@fluid-tools/build-cli": "^0.34.0", | ||
"check:are-the-types-wrong": "attw --pack . --entrypoints .", | ||
"check:biome": "biome check .", | ||
"check:prettier": "prettier --check . --cache --ignore-path ../../../.prettierignore", | ||
@@ -179,3 +158,2 @@ "check:release-tags": "api-extractor run --local --config ./api-extractor-lint.json", | ||
"format": "fluid-build --task format .", | ||
"format:biome": "biome check --apply .", | ||
"format:prettier": "prettier --write . --cache --ignore-path ../../../.prettierignore", | ||
@@ -185,3 +163,3 @@ "lint": "fluid-build . --task lint", | ||
"test": "npm run test:mocha", | ||
"test:benchmark:report": "mocha --timeout 999999 --perfMode --parentProcess --fgrep @Benchmark --reporter @fluid-tools/benchmark/dist/MochaReporter.js \"./dist/**/*.perf.spec.*js\"", | ||
"test:benchmark:report": "mocha --timeout 999999 --perfMode --parentProcess --fgrep @Benchmark --reporter @fluid-tools/benchmark/dist/MochaReporter.js \"./lib/**/*.perf.spec.*js\"", | ||
"test:coverage": "c8 npm test", | ||
@@ -194,4 +172,4 @@ "test:mocha": "npm run test:mocha:esm && echo skipping cjs to avoid overhead - npm run test:mocha:cjs", | ||
"tsc": "fluid-tsc commonjs --project ./tsconfig.cjs.json && copyfiles -f ../../../common/build/build-common/src/cjs/package.json ./dist", | ||
"tsc:watch": "tsc --watch" | ||
"tsc:watch": "copyfiles -f ../../../common/build/build-common/src/cjs/package.json ./dist && fluid-tsc commonjs --watch --project ./tsconfig.cjs.json" | ||
} | ||
} |
@@ -8,3 +8,3 @@ /*! | ||
/* eslint-disable no-bitwise */ | ||
import { assert } from "@fluidframework/core-utils"; | ||
import { assert } from "@fluidframework/core-utils/internal"; | ||
@@ -11,0 +11,0 @@ /** |
@@ -6,3 +6,4 @@ /*! | ||
import { assert } from "@fluidframework/core-utils"; | ||
import { assert } from "@fluidframework/core-utils/internal"; | ||
import { FinalCompressedId } from "./identifiers.js"; | ||
@@ -9,0 +10,0 @@ import { IdCluster, clustersEqual, lastAllocatedFinal, lastFinalizedFinal } from "./sessions.js"; |
@@ -8,4 +8,6 @@ /*! | ||
import { ITelemetryBaseLogger } from "@fluidframework/core-interfaces"; | ||
import { assert } from "@fluidframework/core-utils"; | ||
import { ITelemetryLoggerExt, createChildLogger } from "@fluidframework/telemetry-utils"; | ||
import { assert } from "@fluidframework/core-utils/internal"; | ||
import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils"; | ||
import { createChildLogger } from "@fluidframework/telemetry-utils/internal"; | ||
import { FinalSpace } from "./finalSpace.js"; | ||
@@ -219,2 +221,6 @@ import { FinalCompressedId, LocalCompressedId, NumericUuid, isFinalId } from "./identifiers.js"; | ||
requestedClusterSize: this.nextRequestedClusterSize, | ||
localIdRanges: this.normalizer.getRangesBetween( | ||
this.nextRangeBaseGenCount, | ||
this.localGenCount, | ||
), | ||
}, | ||
@@ -221,0 +227,0 @@ }; |
@@ -9,2 +9,2 @@ /*! | ||
export const pkgName = "@fluidframework/id-compressor"; | ||
export const pkgVersion = "2.0.0-dev-rc.3.0.0.250606"; | ||
export const pkgVersion = "2.0.0-dev-rc.3.0.0.253463"; |
@@ -6,4 +6,5 @@ /*! | ||
import { assert } from "@fluidframework/core-utils"; | ||
import { assert } from "@fluidframework/core-utils/internal"; | ||
import { BTree } from "@tylerbu/sorted-btree-es6"; | ||
import { FinalCompressedId, LocalCompressedId, NumericUuid } from "./identifiers.js"; | ||
@@ -10,0 +11,0 @@ import { SessionId, StableId } from "./types/index.js"; |
@@ -6,2 +6,3 @@ /*! | ||
import { assert } from "@fluidframework/core-utils/internal"; | ||
import { AppendOnlySortedMap } from "./appendOnlySortedMap.js"; | ||
@@ -52,2 +53,64 @@ import { LocalCompressedId } from "./identifiers.js"; | ||
public getRangesBetween( | ||
firstGenCount: number, | ||
lastGenCount: number, | ||
): [genCount: number, count: number][] { | ||
const ranges: [genCount: number, count: number][] = []; | ||
// we need to find the first range that either contains firstGenCount or is after it, | ||
// since this method must find ranges between firstGenCount and lastGenCount | ||
let firstRange = this.localIdRanges.getPairOrNextLower(firstGenCount); | ||
// if the first range does not contain the first ID, next higher range is between but non-containing | ||
if (firstRange === undefined || !this.rangeContains(firstRange, firstGenCount)) { | ||
firstRange = this.localIdRanges.getPairOrNextHigher(firstGenCount); | ||
if (firstRange === undefined) { | ||
return ranges; | ||
} | ||
} | ||
for (const [genCount, count] of this.localIdRanges.getRange(firstRange[0], lastGenCount)) { | ||
ranges.push([genCount, count]); | ||
} | ||
if (ranges.length === 0) { | ||
return ranges; | ||
} | ||
// now we touch up the first and last ranges to ensure that if they contain the | ||
// queried IDs they are trimmed to start/end with the queried IDs | ||
const [baseGenCount, baseCount] = ranges[0]; | ||
if (this.rangeContains(ranges[0], firstGenCount)) { | ||
ranges[0] = [firstGenCount, baseCount - (firstGenCount - baseGenCount)]; | ||
assert( | ||
this.rangeContains(ranges[0], firstGenCount), | ||
"Expected the touched up range to contain the queried ID", | ||
); | ||
} else { | ||
assert( | ||
baseGenCount > firstGenCount, | ||
"Expected the first range to start after the queried ID", | ||
); | ||
} | ||
const lastRangeIndex = ranges.length - 1; | ||
const [limitGenCount, limitCount] = ranges[lastRangeIndex]; | ||
if (this.rangeContains(ranges[lastRangeIndex], lastGenCount)) { | ||
ranges[lastRangeIndex] = [limitGenCount, lastGenCount - limitGenCount + 1]; | ||
assert( | ||
this.rangeContains(ranges[lastRangeIndex], lastGenCount), | ||
"Expected the touched up range to contain the queried ID", | ||
); | ||
} else { | ||
assert( | ||
limitGenCount + limitCount - 1 < lastGenCount, | ||
"Expected the last range to end before the queried ID", | ||
); | ||
} | ||
return ranges; | ||
} | ||
private rangeContains(range: readonly [number, number], genCount: number): boolean { | ||
const [baseGenCount, count] = range; | ||
return genCount >= baseGenCount && genCount < baseGenCount + count; | ||
} | ||
public addLocalRange(baseGenCount: number, count: number): void { | ||
@@ -54,0 +117,0 @@ const last = this.localIdRanges.last(); |
@@ -7,2 +7,3 @@ /*! | ||
import { strict as assert } from "assert"; | ||
import { | ||
@@ -20,2 +21,4 @@ BaseFuzzTestState, | ||
import { ITelemetryBaseLogger } from "@fluidframework/core-interfaces"; | ||
import { IdCompressor } from "../idCompressor.js"; | ||
import { | ||
@@ -32,5 +35,5 @@ type IIdCompressor, | ||
createIdCompressor, | ||
} from "..//index.js"; | ||
import { IdCompressor } from "../idCompressor.js"; | ||
import { assertIsSessionId, createSessionId } from "../utilities.js"; | ||
} from "../index.js"; | ||
import { assertIsSessionId, createSessionId, localIdFromGenCount } from "../utilities.js"; | ||
import { | ||
@@ -141,2 +144,3 @@ FinalCompressedId, | ||
requestedClusterSize: capacity, | ||
localIdRanges: [], // remote session, can safely ignore in tests | ||
}, | ||
@@ -345,2 +349,3 @@ }); | ||
], | ||
localIdRanges: [], // remote session, can safely ignore in tests | ||
}, | ||
@@ -430,2 +435,25 @@ }; | ||
// Ensure creation ranges for clients we track contain the correct local ID ranges | ||
this.serverOperations.forEach(([range, opSpaceIds, clientFrom]) => { | ||
const localIdsInCreationRange = new Set<SessionSpaceCompressedId>(); | ||
if (clientFrom !== OriginatingClient.Remote) { | ||
const ids = range.ids; | ||
if (ids !== undefined) { | ||
const { firstGenCount, localIdRanges } = ids; | ||
for (const [genCount, count] of localIdRanges) { | ||
for (let g = genCount; g < genCount + count; g++) { | ||
const local = localIdFromGenCount(g); | ||
assert.strictEqual(opSpaceIds[g - firstGenCount], local); | ||
localIdsInCreationRange.add(local); | ||
} | ||
} | ||
} | ||
opSpaceIds.forEach((id) => { | ||
if (isLocalId(id)) { | ||
assert(localIdsInCreationRange.has(id), "Local ID not in creation range"); | ||
} | ||
}); | ||
} | ||
}); | ||
// First, ensure all clients each generated a unique ID for each of their own calls to generate. | ||
@@ -432,0 +460,0 @@ for (const [compressor, ids] of sequencedLogs) { |
@@ -6,5 +6,6 @@ /*! | ||
import { assert } from "@fluidframework/core-utils"; | ||
import { OpSpaceCompressedId, SessionSpaceCompressedId, StableId } from "..//index.js"; | ||
import { assert } from "@fluidframework/core-utils/internal"; | ||
import { IdCompressor } from "../idCompressor.js"; | ||
import { OpSpaceCompressedId, SessionSpaceCompressedId, StableId } from "../index.js"; | ||
import { | ||
@@ -11,0 +12,0 @@ numericUuidFromStableId, |
@@ -115,3 +115,3 @@ /*! | ||
*/ | ||
beginGhostSession(ghostSessionId: SessionId, ghostSessionCallback: () => void); | ||
beginGhostSession(ghostSessionId: SessionId, ghostSessionCallback: () => void): void; | ||
@@ -118,0 +118,0 @@ /** |
@@ -57,3 +57,8 @@ /*! | ||
readonly requestedClusterSize: number; | ||
/** | ||
* The ranges of IDs that were allocated as local IDs in the range created by `sessionId.` | ||
*/ | ||
readonly localIdRanges: [genCount: number, count: number][]; | ||
}; | ||
} |
@@ -7,4 +7,5 @@ /*! | ||
/* eslint-disable no-bitwise */ | ||
import { assert } from "@fluidframework/core-utils"; | ||
import { assert } from "@fluidframework/core-utils/internal"; | ||
import { v4 } from "uuid"; | ||
import { LocalCompressedId, NumericUuid } from "./identifiers.js"; | ||
@@ -11,0 +12,0 @@ import { SessionId, StableId } from "./types/index.js"; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
0
-100%1348471
-3.53%247
-2.37%12475
-10.21%