New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@fluidframework/id-compressor

Package Overview
Dependencies
Maintainers
2
Versions
136
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@fluidframework/id-compressor - npm Package Compare versions

Comparing version 2.0.0-rc.3.0.3 to 2.0.0-rc.3.0.4

3

api-report/id-compressor.api.md

@@ -8,3 +8,3 @@ ## API Report File for "@fluidframework/id-compressor"

import { ITelemetryBaseLogger } from '@fluidframework/core-interfaces';
import { ITelemetryLoggerExt } from '@fluidframework/telemetry-utils';
import { ITelemetryLoggerExt } from '@fluidframework/telemetry-utils/internal';

@@ -64,2 +64,3 @@ // @internal

takeNextCreationRange(): IdCreationRange;
takeUnfinalizedCreationRange(): IdCreationRange;
}

@@ -66,0 +67,0 @@

@@ -6,3 +6,3 @@ /*!

import { ITelemetryBaseLogger } from "@fluidframework/core-interfaces";
import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils/internal";
import { Index } from "./persistanceUtilities.js";

@@ -51,2 +51,4 @@ import { Sessions } from "./sessions.js";

takeNextCreationRange(): IdCreationRange;
takeUnfinalizedCreationRange(): IdCreationRange;
private updateToRange;
private static assertValidRange;

@@ -53,0 +55,0 @@ finalizeCreationRange(range: IdCreationRange): void;

@@ -22,2 +22,8 @@ "use strict";

const currentWrittenVersion = 2.0;
function rangeFinalizationError(expectedStart, actualStart) {
return new internal_2.LoggingError("Ranges finalized out of order", {
expectedStart,
actualStart,
});
}
/**

@@ -151,9 +157,39 @@ * See {@link IIdCompressor} and {@link IIdCompressorCore}

};
return this.updateToRange(range);
}
takeUnfinalizedCreationRange() {
const lastLocalCluster = this.localSession.getLastCluster();
let count;
let firstGenCount;
if (lastLocalCluster === undefined) {
firstGenCount = 1;
count = this.localGenCount;
}
else {
firstGenCount = (0, utilities_js_1.genCountFromLocalId)((lastLocalCluster.baseLocalId - lastLocalCluster.count));
count = this.localGenCount - firstGenCount + 1;
}
if (count === 0) {
return {
sessionId: this.localSessionId,
};
}
const range = {
ids: {
count,
firstGenCount,
localIdRanges: this.normalizer.getRangesBetween(firstGenCount, this.localGenCount),
requestedClusterSize: this.nextRequestedClusterSize,
},
sessionId: this.localSessionId,
};
return this.updateToRange(range);
}
updateToRange(range) {
this.nextRangeBaseGenCount = this.localGenCount + 1;
IdCompressor.assertValidRange(range);
return range;
return IdCompressor.assertValidRange(range);
}
static assertValidRange(range) {
if (range.ids === undefined) {
return;
return range;
}

@@ -164,2 +200,3 @@ const { count, requestedClusterSize } = range.ids;

(0, internal_1.assert)(requestedClusterSize <= IdCompressor.maxClusterSize, 0x877 /* Clusters must not exceed max cluster size. */);
return range;
}

@@ -182,3 +219,3 @@ finalizeCreationRange(range) {

if (rangeBaseLocal !== -1) {
throw new Error("Ranges finalized out of order.");
throw rangeFinalizationError(-1, rangeBaseLocal);
}

@@ -195,3 +232,3 @@ lastCluster = this.addEmptyCluster(session, requestedClusterSize + count);

if (lastCluster.baseLocalId - lastCluster.count !== rangeBaseLocal) {
throw new Error("Ranges finalized out of order.");
throw rangeFinalizationError(lastCluster.baseLocalId - lastCluster.count, rangeBaseLocal);
}

@@ -198,0 +235,0 @@ if (remainingCapacity >= count) {

@@ -8,3 +8,3 @@ /*!

export declare const pkgName = "@fluidframework/id-compressor";
export declare const pkgVersion = "2.0.0-rc.3.0.3";
export declare const pkgVersion = "2.0.0-rc.3.0.4";
//# sourceMappingURL=packageVersion.d.ts.map

@@ -11,3 +11,3 @@ "use strict";

exports.pkgName = "@fluidframework/id-compressor";
exports.pkgVersion = "2.0.0-rc.3.0.3";
exports.pkgVersion = "2.0.0-rc.3.0.4";
//# sourceMappingURL=packageVersion.js.map

@@ -13,2 +13,3 @@ "use strict";

const utilities_js_1 = require("../utilities.js");
const sessionSpaceNormalizer_js_1 = require("../sessionSpaceNormalizer.js");
const testCommon_js_1 = require("./testCommon.js");

@@ -185,4 +186,3 @@ /** Identifies a compressor in a network */

changeCapacity(client, newClusterCapacity) {
// eslint-disable-next-line @typescript-eslint/dot-notation
this.compressors.get(client)["nextRequestedClusterSize"] = newClusterCapacity;
changeCapacity(this.compressors.get(client), newClusterCapacity);
}

@@ -290,24 +290,74 @@ addNewId(client, id, originatingClient, sessionIdFrom, isSequenced) {

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 getLocalIdsInRange = (range, opSpaceIds) => {
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);
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);
if (opSpaceIds) {
assert_1.strict.strictEqual(opSpaceIds[g - firstGenCount], local);
localIdsInCreationRange.add(local);
}
localIdsInCreationRange.add(local);
}
}
}
return localIdsInCreationRange;
};
// Ensure creation ranges for clients we track contain the correct local ID ranges
this.serverOperations.forEach(([range, opSpaceIds, clientFrom]) => {
if (clientFrom !== exports.OriginatingClient.Remote) {
const localIdsInCreationRange = getLocalIdsInRange(range, opSpaceIds);
let localCount = 0;
opSpaceIds.forEach((id) => {
if ((0, testCommon_js_1.isLocalId)(id)) {
localCount++;
(0, assert_1.strict)(localIdsInCreationRange.has(id), "Local ID not in creation range");
}
});
assert_1.strict.strictEqual(localCount, localIdsInCreationRange.size, "Local ID count mismatch");
}
});
const undeliveredRanges = new Map();
this.clientProgress.forEach((progress, client) => {
const ranges = this.serverOperations
.slice(progress)
.filter((op) => op[2] === client)
.map(([range]) => range);
undeliveredRanges.set(client, ranges);
});
undeliveredRanges.forEach((ranges, client) => {
const compressor = this.compressors.get(client);
let firstGenCount;
let totalCount = 0;
const unionedLocalRanges = new sessionSpaceNormalizer_js_1.SessionSpaceNormalizer();
ranges.forEach((range) => {
(0, assert_1.strict)(range.sessionId === compressor.localSessionId);
if (range.ids !== undefined) {
// initialize firstGenCount if not set
if (firstGenCount === undefined) {
firstGenCount = range.ids.firstGenCount;
}
totalCount += range.ids.count;
range.ids.localIdRanges.forEach(([genCount, count]) => {
unionedLocalRanges.addLocalRange(genCount, count);
});
}
});
const retakenRange = compressor.takeUnfinalizedCreationRange();
if (retakenRange.ids !== undefined) {
const retakenLocalIds = new sessionSpaceNormalizer_js_1.SessionSpaceNormalizer();
retakenRange.ids.localIdRanges.forEach(([genCount, count]) => {
retakenLocalIds.addLocalRange(genCount, count);
});
assert_1.strict.strictEqual(retakenLocalIds.equals(unionedLocalRanges), true, "Local ID ranges mismatch");
assert_1.strict.strictEqual(retakenRange.ids.count, totalCount, "Count mismatch");
assert_1.strict.strictEqual(retakenRange.ids.firstGenCount, firstGenCount, "Count mismatch");
}
else {
assert_1.strict.strictEqual(totalCount, 0);
assert_1.strict.strictEqual(unionedLocalRanges.idRanges.size, 0);
}
});
// First, ensure all clients each generated a unique ID for each of their own calls to generate.

@@ -417,9 +467,23 @@ for (const [compressor, ids] of sequencedLogs) {

exports.IdCompressorTestNetwork = IdCompressorTestNetwork;
function changeCapacity(compressor, newClusterCapacity) {
// eslint-disable-next-line @typescript-eslint/dot-notation
compressor["nextRequestedClusterSize"] = newClusterCapacity;
}
function roundtrip(compressor, withSession) {
// preserve the capacity request as this property is normally private and resets
// to a default on construction (deserialization)
// eslint-disable-next-line @typescript-eslint/dot-notation
const capacity = compressor["nextRequestedClusterSize"];
if (withSession) {
const serialized = compressor.serialize(withSession);
return [serialized, idCompressor_js_1.IdCompressor.deserialize(serialized)];
const roundtripped = idCompressor_js_1.IdCompressor.deserialize(serialized);
changeCapacity(roundtripped, capacity);
return [serialized, roundtripped];
}
const nonLocalSerialized = compressor.serialize(withSession);
return [nonLocalSerialized, idCompressor_js_1.IdCompressor.deserialize(nonLocalSerialized, (0, utilities_js_1.createSessionId)())];
else {
const nonLocalSerialized = compressor.serialize(withSession);
const roundtripped = idCompressor_js_1.IdCompressor.deserialize(nonLocalSerialized, (0, utilities_js_1.createSessionId)());
changeCapacity(roundtripped, capacity);
return [nonLocalSerialized, roundtripped];
}
}

@@ -526,3 +590,3 @@ exports.roundtrip = roundtrip;

}
const allocationWeight = 16;
const allocationWeight = 20;
return (0, stochastic_test_utils_1.interleave)((0, stochastic_test_utils_1.createWeightedGenerator)([

@@ -532,3 +596,3 @@ [changeCapacityGenerator, 1],

[allocateOutsideIdsGenerator, Math.round(allocationWeight * outsideAllocationFraction)],
[deliverAllOperationsGenerator, 2],
[deliverAllOperationsGenerator, 1],
[deliverSomeOperationsGenerator, 6],

@@ -586,3 +650,2 @@ [reconnectGenerator, 1],

validate: (state) => {
network.deliverOperations(exports.DestinationClient.All);
validator?.(network);

@@ -589,0 +652,0 @@ return state;

@@ -72,3 +72,4 @@ /*!

* Returns a range of IDs created by this session in a format for sending to the server for finalizing.
* The range will include all IDs generated via calls to `generateCompressedId` since the last time this method was called.
* The range will include all IDs generated via calls to `generateCompressedId` since the last time a
* range was taken (via this method or `takeUnfinalizedCreationRange`).
* @returns the range of IDs, which may be empty. This range must be sent to the server for ordering before

@@ -79,2 +80,11 @@ * it is finalized. Ranges must be sent to the server in the order that they are taken via calls to this method.

/**
* Returns a range of IDs created by this session in a format for sending to the server for finalizing.
* The range will include all unfinalized IDs generated via calls to `generateCompressedId`.
* @returns the range of IDs, which may be empty. This range must be sent to the server for ordering before
* it is finalized. Ranges must be sent to the server in the order that they are taken via calls to this method.
* Note: after finalizing the range returned by this method, finalizing any ranges that had been previously taken
* will result in an error.
*/
takeUnfinalizedCreationRange(): IdCreationRange;
/**
* Finalizes the supplied range of IDs (which may be from either a remote or local session).

@@ -81,0 +91,0 @@ * @param range - the range of session-local IDs to finalize.

@@ -6,3 +6,3 @@ /*!

import { ITelemetryBaseLogger } from "@fluidframework/core-interfaces";
import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils/internal";
import { Index } from "./persistanceUtilities.js";

@@ -51,2 +51,4 @@ import { Sessions } from "./sessions.js";

takeNextCreationRange(): IdCreationRange;
takeUnfinalizedCreationRange(): IdCreationRange;
private updateToRange;
private static assertValidRange;

@@ -53,0 +55,0 @@ finalizeCreationRange(range: IdCreationRange): void;

@@ -7,3 +7,3 @@ /*!

import { assert } from "@fluidframework/core-utils/internal";
import { createChildLogger } from "@fluidframework/telemetry-utils/internal";
import { LoggingError, createChildLogger, } from "@fluidframework/telemetry-utils/internal";
import { FinalSpace } from "./finalSpace.js";

@@ -20,2 +20,8 @@ import { isFinalId } from "./identifiers.js";

const currentWrittenVersion = 2.0;
function rangeFinalizationError(expectedStart, actualStart) {
return new LoggingError("Ranges finalized out of order", {
expectedStart,
actualStart,
});
}
/**

@@ -149,9 +155,39 @@ * See {@link IIdCompressor} and {@link IIdCompressorCore}

};
return this.updateToRange(range);
}
takeUnfinalizedCreationRange() {
const lastLocalCluster = this.localSession.getLastCluster();
let count;
let firstGenCount;
if (lastLocalCluster === undefined) {
firstGenCount = 1;
count = this.localGenCount;
}
else {
firstGenCount = genCountFromLocalId((lastLocalCluster.baseLocalId - lastLocalCluster.count));
count = this.localGenCount - firstGenCount + 1;
}
if (count === 0) {
return {
sessionId: this.localSessionId,
};
}
const range = {
ids: {
count,
firstGenCount,
localIdRanges: this.normalizer.getRangesBetween(firstGenCount, this.localGenCount),
requestedClusterSize: this.nextRequestedClusterSize,
},
sessionId: this.localSessionId,
};
return this.updateToRange(range);
}
updateToRange(range) {
this.nextRangeBaseGenCount = this.localGenCount + 1;
IdCompressor.assertValidRange(range);
return range;
return IdCompressor.assertValidRange(range);
}
static assertValidRange(range) {
if (range.ids === undefined) {
return;
return range;
}

@@ -162,2 +198,3 @@ const { count, requestedClusterSize } = range.ids;

assert(requestedClusterSize <= IdCompressor.maxClusterSize, 0x877 /* Clusters must not exceed max cluster size. */);
return range;
}

@@ -180,3 +217,3 @@ finalizeCreationRange(range) {

if (rangeBaseLocal !== -1) {
throw new Error("Ranges finalized out of order.");
throw rangeFinalizationError(-1, rangeBaseLocal);
}

@@ -193,3 +230,3 @@ lastCluster = this.addEmptyCluster(session, requestedClusterSize + count);

if (lastCluster.baseLocalId - lastCluster.count !== rangeBaseLocal) {
throw new Error("Ranges finalized out of order.");
throw rangeFinalizationError(lastCluster.baseLocalId - lastCluster.count, rangeBaseLocal);
}

@@ -196,0 +233,0 @@ if (remainingCapacity >= count) {

@@ -8,3 +8,3 @@ /*!

export declare const pkgName = "@fluidframework/id-compressor";
export declare const pkgVersion = "2.0.0-rc.3.0.3";
export declare const pkgVersion = "2.0.0-rc.3.0.4";
//# sourceMappingURL=packageVersion.d.ts.map

@@ -8,3 +8,3 @@ /*!

export const pkgName = "@fluidframework/id-compressor";
export const pkgVersion = "2.0.0-rc.3.0.3";
export const pkgVersion = "2.0.0-rc.3.0.4";
//# sourceMappingURL=packageVersion.js.map

@@ -10,2 +10,3 @@ /*!

import { assertIsSessionId, createSessionId, localIdFromGenCount } from "../utilities.js";
import { SessionSpaceNormalizer } from "../sessionSpaceNormalizer.js";
import { fail, getOrCreate, incrementStableId, isFinalId, isLocalId, } from "./testCommon.js";

@@ -180,4 +181,3 @@ /** Identifies a compressor in a network */

changeCapacity(client, newClusterCapacity) {
// eslint-disable-next-line @typescript-eslint/dot-notation
this.compressors.get(client)["nextRequestedClusterSize"] = newClusterCapacity;
changeCapacity(this.compressors.get(client), newClusterCapacity);
}

@@ -285,24 +285,74 @@ addNewId(client, id, originatingClient, sessionIdFrom, isSequenced) {

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 getLocalIdsInRange = (range, opSpaceIds) => {
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);
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);
if (opSpaceIds) {
assert.strictEqual(opSpaceIds[g - firstGenCount], local);
localIdsInCreationRange.add(local);
}
localIdsInCreationRange.add(local);
}
}
}
return localIdsInCreationRange;
};
// Ensure creation ranges for clients we track contain the correct local ID ranges
this.serverOperations.forEach(([range, opSpaceIds, clientFrom]) => {
if (clientFrom !== OriginatingClient.Remote) {
const localIdsInCreationRange = getLocalIdsInRange(range, opSpaceIds);
let localCount = 0;
opSpaceIds.forEach((id) => {
if (isLocalId(id)) {
localCount++;
assert(localIdsInCreationRange.has(id), "Local ID not in creation range");
}
});
assert.strictEqual(localCount, localIdsInCreationRange.size, "Local ID count mismatch");
}
});
const undeliveredRanges = new Map();
this.clientProgress.forEach((progress, client) => {
const ranges = this.serverOperations
.slice(progress)
.filter((op) => op[2] === client)
.map(([range]) => range);
undeliveredRanges.set(client, ranges);
});
undeliveredRanges.forEach((ranges, client) => {
const compressor = this.compressors.get(client);
let firstGenCount;
let totalCount = 0;
const unionedLocalRanges = new SessionSpaceNormalizer();
ranges.forEach((range) => {
assert(range.sessionId === compressor.localSessionId);
if (range.ids !== undefined) {
// initialize firstGenCount if not set
if (firstGenCount === undefined) {
firstGenCount = range.ids.firstGenCount;
}
totalCount += range.ids.count;
range.ids.localIdRanges.forEach(([genCount, count]) => {
unionedLocalRanges.addLocalRange(genCount, count);
});
}
});
const retakenRange = compressor.takeUnfinalizedCreationRange();
if (retakenRange.ids !== undefined) {
const retakenLocalIds = new SessionSpaceNormalizer();
retakenRange.ids.localIdRanges.forEach(([genCount, count]) => {
retakenLocalIds.addLocalRange(genCount, count);
});
assert.strictEqual(retakenLocalIds.equals(unionedLocalRanges), true, "Local ID ranges mismatch");
assert.strictEqual(retakenRange.ids.count, totalCount, "Count mismatch");
assert.strictEqual(retakenRange.ids.firstGenCount, firstGenCount, "Count mismatch");
}
else {
assert.strictEqual(totalCount, 0);
assert.strictEqual(unionedLocalRanges.idRanges.size, 0);
}
});
// First, ensure all clients each generated a unique ID for each of their own calls to generate.

@@ -411,9 +461,23 @@ for (const [compressor, ids] of sequencedLogs) {

}
function changeCapacity(compressor, newClusterCapacity) {
// eslint-disable-next-line @typescript-eslint/dot-notation
compressor["nextRequestedClusterSize"] = newClusterCapacity;
}
export function roundtrip(compressor, withSession) {
// preserve the capacity request as this property is normally private and resets
// to a default on construction (deserialization)
// eslint-disable-next-line @typescript-eslint/dot-notation
const capacity = compressor["nextRequestedClusterSize"];
if (withSession) {
const serialized = compressor.serialize(withSession);
return [serialized, IdCompressor.deserialize(serialized)];
const roundtripped = IdCompressor.deserialize(serialized);
changeCapacity(roundtripped, capacity);
return [serialized, roundtripped];
}
const nonLocalSerialized = compressor.serialize(withSession);
return [nonLocalSerialized, IdCompressor.deserialize(nonLocalSerialized, createSessionId())];
else {
const nonLocalSerialized = compressor.serialize(withSession);
const roundtripped = IdCompressor.deserialize(nonLocalSerialized, createSessionId());
changeCapacity(roundtripped, capacity);
return [nonLocalSerialized, roundtripped];
}
}

@@ -517,3 +581,3 @@ /**

}
const allocationWeight = 16;
const allocationWeight = 20;
return interleave(createWeightedGenerator([

@@ -523,3 +587,3 @@ [changeCapacityGenerator, 1],

[allocateOutsideIdsGenerator, Math.round(allocationWeight * outsideAllocationFraction)],
[deliverAllOperationsGenerator, 2],
[deliverAllOperationsGenerator, 1],
[deliverSomeOperationsGenerator, 6],

@@ -576,3 +640,2 @@ [reconnectGenerator, 1],

validate: (state) => {
network.deliverOperations(DestinationClient.All);
validator?.(network);

@@ -579,0 +642,0 @@ return state;

@@ -72,3 +72,4 @@ /*!

* Returns a range of IDs created by this session in a format for sending to the server for finalizing.
* The range will include all IDs generated via calls to `generateCompressedId` since the last time this method was called.
* The range will include all IDs generated via calls to `generateCompressedId` since the last time a
* range was taken (via this method or `takeUnfinalizedCreationRange`).
* @returns the range of IDs, which may be empty. This range must be sent to the server for ordering before

@@ -79,2 +80,11 @@ * it is finalized. Ranges must be sent to the server in the order that they are taken via calls to this method.

/**
* Returns a range of IDs created by this session in a format for sending to the server for finalizing.
* The range will include all unfinalized IDs generated via calls to `generateCompressedId`.
* @returns the range of IDs, which may be empty. This range must be sent to the server for ordering before
* it is finalized. Ranges must be sent to the server in the order that they are taken via calls to this method.
* Note: after finalizing the range returned by this method, finalizing any ranges that had been previously taken
* will result in an error.
*/
takeUnfinalizedCreationRange(): IdCreationRange;
/**
* Finalizes the supplied range of IDs (which may be from either a remote or local session).

@@ -81,0 +91,0 @@ * @param range - the range of session-local IDs to finalize.

{
"name": "@fluidframework/id-compressor",
"version": "2.0.0-rc.3.0.3",
"version": "2.0.0-rc.3.0.4",
"description": "ID compressor",

@@ -82,6 +82,6 @@ "homepage": "https://fluidframework.com",

"dependencies": {
"@fluid-internal/client-utils": ">=2.0.0-rc.3.0.3 <2.0.0-rc.3.1.0",
"@fluidframework/core-interfaces": ">=2.0.0-rc.3.0.3 <2.0.0-rc.3.1.0",
"@fluidframework/core-utils": ">=2.0.0-rc.3.0.3 <2.0.0-rc.3.1.0",
"@fluidframework/telemetry-utils": ">=2.0.0-rc.3.0.3 <2.0.0-rc.3.1.0",
"@fluid-internal/client-utils": ">=2.0.0-rc.3.0.4 <2.0.0-rc.3.1.0",
"@fluidframework/core-interfaces": ">=2.0.0-rc.3.0.4 <2.0.0-rc.3.1.0",
"@fluidframework/core-utils": ">=2.0.0-rc.3.0.4 <2.0.0-rc.3.1.0",
"@fluidframework/telemetry-utils": ">=2.0.0-rc.3.0.4 <2.0.0-rc.3.1.0",
"@tylerbu/sorted-btree-es6": "^1.8.0",

@@ -93,4 +93,4 @@ "uuid": "^9.0.0"

"@biomejs/biome": "^1.6.2",
"@fluid-internal/mocha-test-setup": ">=2.0.0-rc.3.0.3 <2.0.0-rc.3.1.0",
"@fluid-private/stochastic-test-utils": ">=2.0.0-rc.3.0.3 <2.0.0-rc.3.1.0",
"@fluid-internal/mocha-test-setup": ">=2.0.0-rc.3.0.4 <2.0.0-rc.3.1.0",
"@fluid-private/stochastic-test-utils": ">=2.0.0-rc.3.0.4 <2.0.0-rc.3.1.0",
"@fluid-tools/benchmark": "^0.48.0",

@@ -97,0 +97,0 @@ "@fluid-tools/build-cli": "^0.37.0",

@@ -9,4 +9,7 @@ /*!

import { assert } from "@fluidframework/core-utils/internal";
import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
import { createChildLogger } from "@fluidframework/telemetry-utils/internal";
import {
ITelemetryLoggerExt,
LoggingError,
createChildLogger,
} from "@fluidframework/telemetry-utils/internal";

@@ -62,2 +65,9 @@ import { FinalSpace } from "./finalSpace.js";

function rangeFinalizationError(expectedStart: number, actualStart: number): LoggingError {
return new LoggingError("Ranges finalized out of order", {
expectedStart,
actualStart,
});
}
/**

@@ -228,10 +238,45 @@ * See {@link IIdCompressor} and {@link IIdCompressorCore}

};
return this.updateToRange(range);
}
public takeUnfinalizedCreationRange(): IdCreationRange {
const lastLocalCluster = this.localSession.getLastCluster();
let count: number;
let firstGenCount: number;
if (lastLocalCluster === undefined) {
firstGenCount = 1;
count = this.localGenCount;
} else {
firstGenCount = genCountFromLocalId(
(lastLocalCluster.baseLocalId - lastLocalCluster.count) as LocalCompressedId,
);
count = this.localGenCount - firstGenCount + 1;
}
if (count === 0) {
return {
sessionId: this.localSessionId,
};
}
const range: IdCreationRange = {
ids: {
count,
firstGenCount,
localIdRanges: this.normalizer.getRangesBetween(firstGenCount, this.localGenCount),
requestedClusterSize: this.nextRequestedClusterSize,
},
sessionId: this.localSessionId,
};
return this.updateToRange(range);
}
private updateToRange(range: IdCreationRange): IdCreationRange {
this.nextRangeBaseGenCount = this.localGenCount + 1;
IdCompressor.assertValidRange(range);
return range;
return IdCompressor.assertValidRange(range);
}
private static assertValidRange(range: IdCreationRange): void {
private static assertValidRange(range: IdCreationRange): IdCreationRange {
if (range.ids === undefined) {
return;
return range;
}

@@ -245,2 +290,3 @@ const { count, requestedClusterSize } = range.ids;

);
return range;
}

@@ -268,3 +314,3 @@

if (rangeBaseLocal !== -1) {
throw new Error("Ranges finalized out of order.");
throw rangeFinalizationError(-1, rangeBaseLocal);
}

@@ -282,3 +328,6 @@ lastCluster = this.addEmptyCluster(session, requestedClusterSize + count);

if (lastCluster.baseLocalId - lastCluster.count !== rangeBaseLocal) {
throw new Error("Ranges finalized out of order.");
throw rangeFinalizationError(
lastCluster.baseLocalId - lastCluster.count,
rangeBaseLocal,
);
}

@@ -285,0 +334,0 @@

@@ -9,2 +9,2 @@ /*!

export const pkgName = "@fluidframework/id-compressor";
export const pkgVersion = "2.0.0-rc.3.0.3";
export const pkgVersion = "2.0.0-rc.3.0.4";

@@ -36,2 +36,3 @@ /*!

import { SessionSpaceNormalizer } from "../sessionSpaceNormalizer.js";
import {

@@ -290,4 +291,3 @@ FinalCompressedId,

public changeCapacity(client: Client, newClusterCapacity: number): void {
// eslint-disable-next-line @typescript-eslint/dot-notation
this.compressors.get(client)["nextRequestedClusterSize"] = newClusterCapacity;
changeCapacity(this.compressors.get(client), newClusterCapacity);
}

@@ -432,25 +432,88 @@

// Ensure creation ranges for clients we track contain the correct local ID ranges
this.serverOperations.forEach(([range, opSpaceIds, clientFrom]) => {
const getLocalIdsInRange = (
range: IdCreationRange,
opSpaceIds?: OpSpaceCompressedId[],
): Set<SessionSpaceCompressedId> => {
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);
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);
if (opSpaceIds) {
assert.strictEqual(opSpaceIds[g - firstGenCount], local);
localIdsInCreationRange.add(local);
}
localIdsInCreationRange.add(local);
}
}
}
return localIdsInCreationRange;
};
// Ensure creation ranges for clients we track contain the correct local ID ranges
this.serverOperations.forEach(([range, opSpaceIds, clientFrom]) => {
if (clientFrom !== OriginatingClient.Remote) {
const localIdsInCreationRange = getLocalIdsInRange(range, opSpaceIds);
let localCount = 0;
opSpaceIds.forEach((id) => {
if (isLocalId(id)) {
localCount++;
assert(localIdsInCreationRange.has(id), "Local ID not in creation range");
}
});
assert.strictEqual(
localCount,
localIdsInCreationRange.size,
"Local ID count mismatch",
);
}
});
const undeliveredRanges = new Map<Client, IdCreationRange[]>();
this.clientProgress.forEach((progress, client) => {
const ranges = this.serverOperations
.slice(progress)
.filter((op) => op[2] === client)
.map(([range]) => range);
undeliveredRanges.set(client, ranges);
});
undeliveredRanges.forEach((ranges, client) => {
const compressor = this.compressors.get(client);
let firstGenCount: number | undefined;
let totalCount = 0;
const unionedLocalRanges = new SessionSpaceNormalizer();
ranges.forEach((range) => {
assert(range.sessionId === compressor.localSessionId);
if (range.ids !== undefined) {
// initialize firstGenCount if not set
if (firstGenCount === undefined) {
firstGenCount = range.ids.firstGenCount;
}
totalCount += range.ids.count;
range.ids.localIdRanges.forEach(([genCount, count]) => {
unionedLocalRanges.addLocalRange(genCount, count);
});
}
});
const retakenRange = compressor.takeUnfinalizedCreationRange();
if (retakenRange.ids !== undefined) {
const retakenLocalIds = new SessionSpaceNormalizer();
retakenRange.ids.localIdRanges.forEach(([genCount, count]) => {
retakenLocalIds.addLocalRange(genCount, count);
});
assert.strictEqual(
retakenLocalIds.equals(unionedLocalRanges),
true,
"Local ID ranges mismatch",
);
assert.strictEqual(retakenRange.ids.count, totalCount, "Count mismatch");
assert.strictEqual(retakenRange.ids.firstGenCount, firstGenCount, "Count mismatch");
} else {
assert.strictEqual(totalCount, 0);
assert.strictEqual(unionedLocalRanges.idRanges.size, 0);
}
});
// First, ensure all clients each generated a unique ID for each of their own calls to generate.

@@ -594,2 +657,7 @@ for (const [compressor, ids] of sequencedLogs) {

function changeCapacity(compressor: IdCompressor, newClusterCapacity: number): void {
// eslint-disable-next-line @typescript-eslint/dot-notation
compressor["nextRequestedClusterSize"] = newClusterCapacity;
}
/**

@@ -615,9 +683,17 @@ * Roundtrips the supplied compressor through serialization and deserialization.

): [SerializedIdCompressorWithOngoingSession | SerializedIdCompressorWithNoSession, IdCompressor] {
// preserve the capacity request as this property is normally private and resets
// to a default on construction (deserialization)
// eslint-disable-next-line @typescript-eslint/dot-notation
const capacity = compressor["nextRequestedClusterSize"];
if (withSession) {
const serialized = compressor.serialize(withSession);
return [serialized, IdCompressor.deserialize(serialized)];
const roundtripped = IdCompressor.deserialize(serialized);
changeCapacity(roundtripped, capacity);
return [serialized, roundtripped];
} else {
const nonLocalSerialized = compressor.serialize(withSession);
const roundtripped = IdCompressor.deserialize(nonLocalSerialized, createSessionId());
changeCapacity(roundtripped, capacity);
return [nonLocalSerialized, roundtripped];
}
const nonLocalSerialized = compressor.serialize(withSession);
return [nonLocalSerialized, IdCompressor.deserialize(nonLocalSerialized, createSessionId())];
}

@@ -819,3 +895,3 @@

const allocationWeight = 16;
const allocationWeight = 20;
return interleave(

@@ -826,3 +902,3 @@ createWeightedGenerator<Operation, FuzzTestState>([

[allocateOutsideIdsGenerator, Math.round(allocationWeight * outsideAllocationFraction)],
[deliverAllOperationsGenerator, 2],
[deliverAllOperationsGenerator, 1],
[deliverSomeOperationsGenerator, 6],

@@ -899,3 +975,2 @@ [reconnectGenerator, 1],

validate: (state) => {
network.deliverOperations(DestinationClient.All);
validator?.(network);

@@ -902,0 +977,0 @@ return state;

@@ -83,3 +83,4 @@ /*!

* Returns a range of IDs created by this session in a format for sending to the server for finalizing.
* The range will include all IDs generated via calls to `generateCompressedId` since the last time this method was called.
* The range will include all IDs generated via calls to `generateCompressedId` since the last time a
* range was taken (via this method or `takeUnfinalizedCreationRange`).
* @returns the range of IDs, which may be empty. This range must be sent to the server for ordering before

@@ -91,2 +92,12 @@ * it is finalized. Ranges must be sent to the server in the order that they are taken via calls to this method.

/**
* Returns a range of IDs created by this session in a format for sending to the server for finalizing.
* The range will include all unfinalized IDs generated via calls to `generateCompressedId`.
* @returns the range of IDs, which may be empty. This range must be sent to the server for ordering before
* it is finalized. Ranges must be sent to the server in the order that they are taken via calls to this method.
* Note: after finalizing the range returned by this method, finalizing any ranges that had been previously taken
* will result in an error.
*/
takeUnfinalizedCreationRange(): IdCreationRange;
/**
* Finalizes the supplied range of IDs (which may be from either a remote or local session).

@@ -93,0 +104,0 @@ * @param range - the range of session-local IDs to finalize.

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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc