Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

id-compressor: Enable recommended lint #23624

Merged
merged 5 commits into from
Jan 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions packages/runtime/id-compressor/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@
*/

module.exports = {
extends: [
require.resolve("@fluidframework/eslint-config-fluid/minimal-deprecated"),
"prettier",
],
extends: [require.resolve("@fluidframework/eslint-config-fluid/recommended"), "prettier"],
parserOptions: {
project: ["./tsconfig.json", "./src/test/tsconfig.json"],
},
Expand Down
60 changes: 39 additions & 21 deletions packages/runtime/id-compressor/src/appendOnlySortedMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
* Licensed under the MIT License.
*/

/* eslint-disable tsdoc/syntax */
/* eslint-disable no-bitwise */
import { assert } from "@fluidframework/core-utils/internal";

Expand All @@ -20,42 +19,48 @@ export class AppendOnlySortedMap<K, V> {
public constructor(protected readonly comparator: (a: K, b: K) => number) {}

/**
* Gets the size of the map.
* @returns the number of entries in this map
*/
public get size(): number {
return this.elements.length / 2;
}

/**
* Gets the min key in the map.
* @returns the min key in the map.
*/
public minKey(): K | undefined {
return this.elements[0] as K | undefined;
}

/**
* Gets the max key in the map.
* @returns the max key in the map.
*/
public maxKey(): K | undefined {
return this.elements[this.elements.length - 2] as K | undefined;
}

/**
* Gets the min value in the map.
* @returns the min value in the map.
*/
public minValue(): V | undefined {
return this.elements[1] as V | undefined;
}

/**
* @returns the min value in the map.
* Gets the max value in the map.
* @returns the max value in the map.
*/
public maxValue(): V | undefined {
return this.elements[this.elements.length - 1] as V | undefined;
}

/**
* @returns the min key in the map.
* Gets the first key/value pair in the map.
* @returns the first pair if it exists, or undefined otherwise.
*/
public first(): [K, V] | undefined {
const { elements } = this;
Expand All @@ -67,7 +72,8 @@ export class AppendOnlySortedMap<K, V> {
}

/**
* @returns the max key in the map.
* Gets the last key/value pair in the map.
* @returns the last pair if it exists, or undefined otherwise.
*/
public last(): [K, V] | undefined {
const { elements } = this;
Expand All @@ -80,7 +86,9 @@ export class AppendOnlySortedMap<K, V> {
}

/**
* Returns the element at the insertion index.
* Gets the entry at the specified index.
* @param index - the entry index
* @returns the key/value pair if it exists, or undefined otherwise.
*/
public getAtIndex(index: number): [K, V] | undefined {
const realIndex = index * 2;
Expand All @@ -92,6 +100,7 @@ export class AppendOnlySortedMap<K, V> {
}

/**
* Gets the entries in the map.
* @returns an iterable of the entries in the map.
*/
public *entries(): IterableIterator<readonly [K, V]> {
Expand All @@ -102,6 +111,7 @@ export class AppendOnlySortedMap<K, V> {
}

/**
* Gets the keys in the map.
* @returns an iterable of the keys in the map.
*/
public *keys(): IterableIterator<K> {
Expand All @@ -112,6 +122,7 @@ export class AppendOnlySortedMap<K, V> {
}

/**
* Gets the values in the map.
* @returns an iterable of the values in the map.
*/
public *values(): IterableIterator<V> {
Expand All @@ -122,6 +133,7 @@ export class AppendOnlySortedMap<K, V> {
}

/**
* Gets the entries in the map, reversed.
* @returns an iterable of the entries in the map, reversed.
*/
public *entriesReversed(): IterableIterator<readonly [K, V]> {
Expand All @@ -132,25 +144,24 @@ export class AppendOnlySortedMap<K, V> {
}

/**
* Adds a new key/value pair to the map. `key` must be > to all keys in the map.
* @param key - the key to add.
* @param value - the value to add.
* Appends a new key/value pair at the end of the map. `key` must be greater than all other keys in the map.
* @param key - the key to add
* @param value - the value to add
*/
public append(key: K, value: V): void {
const { elements } = this;
const { length } = elements;
if (length !== 0 && this.comparator(key, this.maxKey() as K) <= 0) {
throw new Error("Inserted key must be > all others in the map.");
}
elements.push(key);
elements.push(value);
elements.push(key, value);
}

/**
* Replaces the last key/value pair with the given one. If the map is empty, it simply appends.
* `key` must be > to all keys in the map prior to the one replaced.
* @param key - the key to add.
* @param value - the value to add.
* Replaces the last key/value pair with a new one. If the map is empty, the new pair is appended.
* 'key' must be greater than all other keys in the map.
* @param key - the key to set
* @param value - the value to set
*/
public replaceLast(key: K, value: V): void {
const { elements, comparator } = this;
Expand All @@ -162,13 +173,13 @@ export class AppendOnlySortedMap<K, V> {
throw new Error("Inserted key must be > all others in the map.");
}
}
elements.push(key);
elements.push(value);
elements.push(key, value);
}

/**
* @param key - the key to lookup.
* @returns the value associated with `key` if such an entry exists, and undefined otherwise.
* Gets the value associated with a given key.
* @param key - the key to lookup
* @returns the value if it exists, or undefined otherwise.
*/
public get(key: K): V | undefined {
const index = AppendOnlySortedMap.keyIndexOf(this.elements, key, this.comparator);
Expand All @@ -179,15 +190,16 @@ export class AppendOnlySortedMap<K, V> {
}

/**
* @param key - the key to lookup.
* @returns the entry associated with `key` if such an entry exists, the entry associated with the next lower key if such an entry
* exists, and undefined otherwise.
* Gets the pair associated with the given key or the next smaller key.
* @param key - the key to lookup
* @returns the pair if it exists, or undefined otherwise.
*/
public getPairOrNextLower(key: K): readonly [K, V] | undefined {
return this.getPairOrNextLowerBy(key, this.comparator);
}

/**
* Gets the pair associated with the given key or the next higher key.
* @param key - the key to lookup.
* @returns the entry associated with `key` if such an entry exists, the entry associated with the next higher key if such an entry
* exists, and undefined otherwise.
Expand Down Expand Up @@ -293,6 +305,12 @@ export class AppendOnlySortedMap<K, V> {
return keyIndex;
}

/**
* Gets the pair associated with the given key or next higher key.
* @param search - the search value
* @param comparator - a comparison function
* @returns the pair if it exists, or undefined otherwise.
*/
protected getPairOrNextHigherBy<T>(
search: T,
comparator: (search: T, key: K, value: V) => number,
Expand Down
11 changes: 6 additions & 5 deletions packages/runtime/id-compressor/src/finalSpace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export class FinalSpace {
return this.clusterList[this.clusterList.length - 1];
}

public addCluster(newCluster: IdCluster) {
public addCluster(newCluster: IdCluster): void {
const lastCluster = this.getLastCluster();
assert(
lastCluster === undefined ||
Expand All @@ -40,7 +40,7 @@ export class FinalSpace {
}

/**
* @returns the upper bound (exclusive) of finalized IDs in final space, i.e. one greater than the last final ID in the last cluster.
* Gets the upper bound (exclusive) of finalized IDs in final space, i.e. one greater than the last final ID in the last cluster.
* Note: this does not include allocated but unfinalized space in clusters.
*/
public getFinalizedIdLimit(): FinalCompressedId {
Expand All @@ -51,7 +51,7 @@ export class FinalSpace {
}

/**
* @returns the upper bound (exclusive) of allocated IDs in final space, i.e. one greater than the last final ID in the last cluster.
* Gets the upper bound (exclusive) of allocated IDs in final space, i.e. one greater than the last final ID in the last cluster.
* Note: this does includes all allocated IDs in clusters.
*/
public getAllocatedIdLimit(): FinalCompressedId {
Expand All @@ -62,8 +62,9 @@ export class FinalSpace {
}

public equals(other: FinalSpace): boolean {
for (const [index, value] of Object.entries(this.clusterList)) {
if (!clustersEqual(value, other.clusterList[index])) {
for (let i = 0; i < this.clusterList.length; i++) {
const cluster = this.clusterList[i] as IdCluster;
if (!clustersEqual(cluster, other.clusterList[i] as IdCluster)) {
return false;
}
}
Expand Down
40 changes: 22 additions & 18 deletions packages/runtime/id-compressor/src/idCompressor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ import {
* The version of IdCompressor that is currently persisted.
* This should not be changed without careful consideration to compatibility.
*/
const currentWrittenVersion = 2.0;
const currentWrittenVersion = 2;

function rangeFinalizationError(expectedStart: number, actualStart: number): LoggingError {
return new LoggingError("Ranges finalized out of order", {
Expand Down Expand Up @@ -202,7 +202,7 @@ export class IdCompressor implements IIdCompressor, IIdCompressorCore {
/**
* {@inheritdoc IIdCompressorCore.beginGhostSession}
*/
public beginGhostSession(ghostSessionId: SessionId, ghostSessionCallback: () => void) {
public beginGhostSession(ghostSessionId: SessionId, ghostSessionCallback: () => void): void {
this.startGhostSession(ghostSessionId);
try {
ghostSessionCallback();
Expand Down Expand Up @@ -554,7 +554,8 @@ export class IdCompressor implements IIdCompressor, IIdCompressorCore {
!this.ongoingGhostSession,
0x8a9 /* IdCompressor should not be operated normally when in a ghost session */,
);
const { normalizer, finalSpace, sessions } = this;
const { normalizer, finalSpace, sessions, localGenCount, logger, nextRangeBaseGenCount } =
this;
const sessionIndexMap = new Map<Session, number>();
let sessionIndex = 0;
for (const session of sessions.sessions()) {
Expand All @@ -568,7 +569,7 @@ export class IdCompressor implements IIdCompressor, IIdCompressorCore {
? 1 + // generated ID count
1 + // next range base genCount
1 + // count of normalizer pairs
this.normalizer.idRanges.size * 2 // pairs
normalizer.idRanges.size * 2 // pairs
: 0;
// Layout size, in 8 byte increments
const totalSize =
Expand All @@ -592,19 +593,19 @@ export class IdCompressor implements IIdCompressor, IIdCompressorCore {
index = writeNumericUuid(serializedUint, index, session.sessionUuid);
}

finalSpace.clusters.forEach((cluster) => {
for (const cluster of finalSpace.clusters) {
index = writeNumber(
serializedFloat,
index,
sessionIndexMap.get(cluster.session) as number,
);
index = writeNumber(serializedFloat, index, cluster.capacity);
index = writeNumber(serializedFloat, index, cluster.count);
});
}

if (hasLocalState) {
index = writeNumber(serializedFloat, index, this.localGenCount);
index = writeNumber(serializedFloat, index, this.nextRangeBaseGenCount);
index = writeNumber(serializedFloat, index, localGenCount);
index = writeNumber(serializedFloat, index, nextRangeBaseGenCount);
index = writeNumber(serializedFloat, index, normalizer.idRanges.size);
for (const [leadingGenCount, count] of normalizer.idRanges.entries()) {
index = writeNumber(serializedFloat, index, leadingGenCount);
Expand All @@ -613,7 +614,7 @@ export class IdCompressor implements IIdCompressor, IIdCompressorCore {
}

assert(index === totalSize, 0x75b /* Serialized size was incorrectly calculated. */);
this.logger?.sendTelemetryEvent({
logger?.sendTelemetryEvent({
eventName: "RuntimeIdCompressor:SerializedIdCompressorSize",
size: serializedFloat.byteLength,
clusterCount: finalSpace.clusters.length,
Expand Down Expand Up @@ -652,12 +653,15 @@ export class IdCompressor implements IIdCompressor, IIdCompressorCore {
};
const version = readNumber(index);
switch (version) {
case 1.0:
case 1: {
throw new Error("IdCompressor version 1.0 is no longer supported.");
case 2.0:
}
case 2: {
return IdCompressor.deserialize2_0(index, sessionId, logger);
default:
}
default: {
throw new Error("Unknown IdCompressor serialized version.");
}
}
}

Expand All @@ -673,17 +677,17 @@ export class IdCompressor implements IIdCompressor, IIdCompressorCore {
// Sessions
let sessionOffset = 0;
const sessions: [NumericUuid, Session][] = [];
if (!hasLocalState) {
if (hasLocalState) {
assert(
sessionId === undefined,
0x75e /* Local state should not exist in serialized form. */,
);
} else {
// If !hasLocalState, there won't be a serialized local session ID so insert one at the beginning
assert(sessionId !== undefined, 0x75d /* Local session ID is undefined. */);
const localSessionNumeric = numericUuidFromStableId(sessionId);
sessions.push([localSessionNumeric, new Session(localSessionNumeric)]);
sessionOffset = 1;
} else {
assert(
sessionId === undefined,
0x75e /* Local state should not exist in serialized form. */,
);
}

for (let i = 0; i < sessionCount; i++) {
Expand Down
2 changes: 1 addition & 1 deletion packages/runtime/id-compressor/src/identifiers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export type LocalCompressedId = number & {
} & SessionSpaceCompressedId; // Same brand as CompressedId, as local IDs are always locally normalized

/**
* @returns true if the supplied ID is a final ID.
* Returns true if the supplied ID is a final ID.
*/
export function isFinalId(
id: SessionSpaceCompressedId | OpSpaceCompressedId,
Expand Down
4 changes: 2 additions & 2 deletions packages/runtime/id-compressor/src/sessions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export class Sessions {
}

public equals(other: Sessions, includeLocalState: boolean): boolean {
const checkIsSubset = (sessionsA: Sessions, sessionsB: Sessions) => {
const checkIsSubset = (sessionsA: Sessions, sessionsB: Sessions): boolean => {
const first = sessionsA.sessions().next();
const firstSessionThis = first.done ? undefined : first.value;
for (const [stableId, session] of sessionsA.sessionCache.entries()) {
Expand Down Expand Up @@ -296,7 +296,7 @@ export class Session {

public equals(other: Session): boolean {
for (const [index, value] of Object.entries(this.clusterChain)) {
if (!clustersEqual(value, other.clusterChain[index])) {
if (!clustersEqual(value, other.clusterChain[index] as IdCluster)) {
return false;
}
}
Expand Down
Loading
Loading