Skip to content

feat: 53-bit unique id#858

Open
levkk wants to merge 10 commits intomainfrom
levkk-configurable-unique-id
Open

feat: 53-bit unique id#858
levkk wants to merge 10 commits intomainfrom
levkk-configurable-unique-id

Conversation

@levkk
Copy link
Copy Markdown
Collaborator

@levkk levkk commented Mar 30, 2026

Add support for 53-bit unique ID. This makes them smaller and "javascript-safe" in case identifiers are exposed as integers to the app API.

Alpha: do not use this yet. The function can change (e.g., we can shift which bits are used for node id / internal sequence), and those changes may not be backwards compatible

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 30, 2026

Comment on lines +174 to +178
// Compact (JS-safe) IDs only have 6 node bits.
if node_id > COMPACT_MAX_NODE_ID {
return Err(Error::CompactNodeIdTooLarge(node_id));
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's probably should be checked only if the function is compact. For standard it could cause unexpected error

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch!

Comment on lines 179 to 181
if min_id > MAX_OFFSET {
return Err(Error::OffsetTooLarge(min_id));
}
Copy link
Copy Markdown
Contributor

@meskill meskill Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check is done only for MAX_OFFSET which is based on the standard generator, but it really depends on the actual layout.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might worth to move the checks into the id_type or state itself to avoid adding more conditions here and be ready for other extensions

@@ -31,6 +32,14 @@ const TIMESTAMP_SHIFT: u8 = (SEQUENCE_BITS + NODE_BITS) as u8; // 22
const MAX_OFFSET: u64 = i64::MAX as u64
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

btw, MAX_OFFSET if effectively 0. That makes config.general.unique_id_function unusable except for default 0 value. It seems unit tests are bypasses this since the offset tests use next_id directly that has no validation for MAX_OFFSET

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what you mean. Could you elaborate? I think we test the min ID in unit tests by passing in as an argument.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here
image

if we do the math the value is 0. And the tests are not catching this because the tests for id_offset are only calling next_id function that has no validation.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch. Let me see what we can do here...

@levkk levkk force-pushed the levkk-configurable-unique-id branch from 7256483 to 6a91de6 Compare April 1, 2026 19:04
if now >= target_ms {
return now;
}
thread::sleep(Duration::from_millis(1));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a sidenote:
I wonder if we really need the sleep here to correct the clock drift. It seems like it's used to make sure the call to SystemTime::now() fits our expectation for monotonically increasing timestamp. But it's not strictly necessary for this calculation since it could be emulated by now_ms().max(self.last_timestamp_ms). Yes, it won't be not exactly the system time, but we fulfill the requirements.
Just because the sleep is not reliable and scheduler could skew the time in this case

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we're just trying to guarantee that the next call to now() returns the subsequent second or greater. This is used when the internal sequence is exhausted and we have to wait until next clock tick to guarantee that the sequence is monotonically increasing.

@levkk levkk force-pushed the levkk-configurable-unique-id branch from 5b544da to fc44147 Compare April 2, 2026 18:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants