Skip to content

Upgrade microVersionId to timestamp-ordered format and add isReplica#2628

Open
maeldonn wants to merge 2 commits into
development/8.4from
improvement/ARSN-578/micro-version-id
Open

Upgrade microVersionId to timestamp-ordered format and add isReplica#2628
maeldonn wants to merge 2 commits into
development/8.4from
improvement/ARSN-578/micro-version-id

Conversation

@maeldonn
Copy link
Copy Markdown
Contributor

Replace the random 8-byte hex microVersionId with a 20-character timestamp-ordered identifier matching the versionId scheme, and add encode/decode/compare helpers in a new MicroVersionID module. Add an optional isReplica flag to ReplicationInfo to distinguish replica writes from user writes, enabling cascaded CRR.

Issue: ARSN-578

@maeldonn maeldonn requested review from a team, SylvainSenechal and benzekrimaha May 22, 2026 14:11
@bert-e
Copy link
Copy Markdown
Contributor

bert-e commented May 22, 2026

Hello maeldonn,

My role is to assist you with the merge of this
pull request. Please type @bert-e help to get information
on this process, or consult the user documentation.

Available options
name description privileged authored
/after_pull_request Wait for the given pull request id to be merged before continuing with the current one.
/bypass_author_approval Bypass the pull request author's approval
/bypass_build_status Bypass the build and test status
/bypass_commit_size Bypass the check on the size of the changeset TBA
/bypass_incompatible_branch Bypass the check on the source branch prefix
/bypass_jira_check Bypass the Jira issue check
/bypass_peer_approval Bypass the pull request peers' approval
/bypass_leader_approval Bypass the pull request leaders' approval
/approve Instruct Bert-E that the author has approved the pull request. ✍️
/create_pull_requests Allow the creation of integration pull requests.
/create_integration_branches Allow the creation of integration branches.
/no_octopus Prevent Wall-E from doing any octopus merge and use multiple consecutive merge instead
/unanimity Change review acceptance criteria from one reviewer at least to all reviewers
/wait Instruct Bert-E not to run until further notice.
Available commands
name description privileged
/help Print Bert-E's manual in the pull request.
/status Print Bert-E's current status in the pull request TBA
/clear Remove all comments from Bert-E from the history TBA
/retry Re-start a fresh build TBA
/build Re-start a fresh build TBA
/force_reset Delete integration branches & pull requests, and restart merge process from the beginning.
/reset Try to remove integration branches unless there are commits on them which do not appear on the source branch.

Status report is not available.

@bert-e
Copy link
Copy Markdown
Contributor

bert-e commented May 22, 2026

Incorrect fix version

The Fix Version/s in issue ARSN-578 contains:

  • None

Considering where you are trying to merge, I ignored possible hotfix versions and I expected to find:

  • 8.4.3

Please check the Fix Version/s of ARSN-578, or the target
branch of this pull request.

@claude
Copy link
Copy Markdown

claude Bot commented May 22, 2026

LGTM

Review by Claude Code

Comment thread lib/models/ObjectMD.ts
Comment thread lib/models/ObjectMD.ts
Comment thread lib/models/ObjectMD.ts Outdated
Comment thread lib/versioning/MicroVersionId.ts
@maeldonn maeldonn force-pushed the improvement/ARSN-578/micro-version-id branch from caf9a51 to 868cae8 Compare May 22, 2026 14:55
Comment thread lib/versioning/MicroVersionId.ts Outdated
Comment thread lib/models/ObjectMD.ts
Comment thread lib/models/ObjectMD.ts
@claude
Copy link
Copy Markdown

claude Bot commented May 22, 2026

  • Breaking API change: updateMicroVersionId() now requires a replicationGroupId argument, which will break all existing callers in downstream repos (CloudServer, Backbeat, etc.). Coordinate updates or consider an optional parameter with a fallback.
    • Make the parameter optional with a random default, or ensure all consumers are updated in the same release cycle.
  • updateMicroVersionId JSDoc says @return itself but the method body has no return this statement.
    • Add return this; for consistency with other ObjectMD setters.

Review by Claude Code

*
* @return - the generated microVersionId
*/
export function generate(replicationGroupId: string): string {
Copy link
Copy Markdown
Contributor

@SylvainSenechal SylvainSenechal May 22, 2026

Choose a reason for hiding this comment

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

discussed briefly in person with Maël already but, i had no idea id generation was this complicated
I think here its mostly inspired from the VersionID file to have something similar, but yeah this whole thing looks kinda smelly.
A good ID generation should be independent from basically anything,

  • we shouldn't have to call wait,
  • we shouldn't have to rely on a previous stored lastTimetamp
  • we shouldn't have to do weird conditionnal + 1 increment on current timestamp

I mean at the end of the day, why don't we use uuidv7 ? It's globally unique, time ordered and sortable, and particularly recommended for distributed system

Copy link
Copy Markdown
Contributor

@SylvainSenechal SylvainSenechal May 22, 2026

Choose a reason for hiding this comment

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

Maybe we want uuids to be as small as possible, because I remember in other context we talked about how important it is to have metadata that doesn't occupy too much storage (especially important when users have many multiple small objects, we end up having metadata that is larger than the object itself).

Claude also tells me for mongodb calls ordering, it might be easier to have reversed ordered Version Id but not sure its relevant here (and not sure its true anyways)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

A few clarifications on the "smells":

  • wait is called once per process lifetime, not per id
  • lastTimestamp + 1 is the per-ms counter giving strict monotonicity per generator
  • with uuid v7, two writers generating in the same ms are unordered

So we are keeping the version id format. We can plan a refactoring as follow-up if you want.

Replace the random 8-byte hex microVersionId with a 20-character
timestamp-ordered identifier matching the versionId scheme, and add
encode/decode/compare helpers in a new MicroVersionID module. Add an
optional isReplica flag to ReplicationInfo to distinguish replica
writes from user writes, enabling cascaded CRR.

Issue: ARSN-578
@maeldonn maeldonn force-pushed the improvement/ARSN-578/micro-version-id branch from 868cae8 to 2eae0c5 Compare May 22, 2026 15:22
@maeldonn maeldonn marked this pull request as ready for review May 22, 2026 15:24
@claude
Copy link
Copy Markdown

claude Bot commented May 22, 2026

LGTM

The changes are well-structured: the new MicroVersionId module correctly mirrors the VersionId timestamp-ordering scheme with its own isolated sequencing state, the isReplica flag is cleanly additive and backward compatible, and the test coverage is thorough (uniqueness, ordering, encode/decode round-trip, compare, padding/truncation).

Review by Claude Code

Comment thread lib/versioning/MicroVersionId.ts
* sequence are stored in reversed form (MAX - value), followed by the
* replication group id normalized to {@link LENGTH_RG} characters
* (space-padded if shorter, truncated if longer). String comparison
* orders microVersionIds from newest to oldest, matching the
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.

discussed briefly in person with Maël already but, i had no idea id generation was this complicated
I think here its mostly inspired from the VersionID file to have something similar, but yeah this whole looks rather smelly.
A good ID generation should be independent from basically anything,

  • we shouldn't have to call wait,
  • we should have to rely on a previous stored lastTimetamp
  • we should have to do weird conditionnal + 1 increment on current timestamp

I mean at the end of the day, why don't we use uuidv7 ? It's globally unique, time ordered and sortable

Copy link
Copy Markdown
Contributor

@SylvainSenechal SylvainSenechal May 22, 2026

Choose a reason for hiding this comment

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

Re thinking some more 🌚
We want two things from this microVersionID :

  • Avoid infinite loop cascading : uuidv7 is good for this : when we receive the request, we compare the uuidv7 received with whats currently stored, if its the same, it means we have a loop. uuidv7 does not suffer from collision (2 ids generated in the same millisecond have 1/2^74 collision chance)
  • Deal with stale object : If we receive an object that is older than the currently stored object, we don't want to store it. uuidv7 can be compared and ordered with a millisecond precision (which is largely enough, imo even ~1 second would be enough)

Also, uuidv7 storage space is 128 bits, which I think is the same order of magnitude with this 27 chars microVersionId

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Uuid v7 doesn't actually solve the same-ms case across sites, so it's not a real win over what we have. Snowflake-style (ms timestamp + per-generator counter + node bits) gives us:

  • Strict monotonicity per generator (the wait / lastTimestamp / +1 logic is the counter, not smell)
  • Deterministic cross-site tiebreak via the node bits
  • Same equality check for loop detection

We need to keep the versionId format. But i'm sure we can do a little refactor to make the file clearer.

@bert-e
Copy link
Copy Markdown
Contributor

bert-e commented May 22, 2026

Waiting for approval

The following approvals are needed before I can proceed with the merge:

  • the author

  • 2 peers

@maeldonn maeldonn requested a review from SylvainSenechal May 22, 2026 18:03
Comment thread lib/models/ObjectMD.ts
this._data.microVersionId = crypto.randomBytes(8).toString('hex');
updateMicroVersionId(replicationGroupId: string) {
this._data.microVersionId = MicroVersionIdUtils.generate(replicationGroupId);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

updateMicroVersionId is documented with @return itself but doesn't actually return this, unlike every other setter/updater in the class (e.g. setReplicationIsReplica, setReplicationIsNFS). Since this method is being rewritten anyway, this is a good opportunity to fix the mismatch.

Suggested change
}
updateMicroVersionId(replicationGroupId: string) {
this._data.microVersionId = MicroVersionIdUtils.generate(replicationGroupId);
return this;
}


— Claude Code

@claude
Copy link
Copy Markdown

claude Bot commented May 22, 2026

  • updateMicroVersionId JSDoc says @return itself but the method doesn't return this, breaking the chaining convention used by all other setters in ObjectMD. Since the method is being rewritten, add return this;.

Review by Claude Code

@maeldonn maeldonn force-pushed the improvement/ARSN-578/micro-version-id branch from fbaf3fe to 3160d6b Compare May 22, 2026 18:25
Comment thread lib/models/ObjectMD.ts
*/
updateMicroVersionId() {
this._data.microVersionId = crypto.randomBytes(8).toString('hex');
updateMicroVersionId(replicationGroupId: string) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Breaking API change: updateMicroVersionId() now requires a replicationGroupId argument. All downstream callers (CloudServer, Backbeat, etc.) that invoke this method without arguments will fail at compile time. Ensure coordinated updates across dependent repos.

— Claude Code

@claude
Copy link
Copy Markdown

claude Bot commented May 22, 2026

LGTM — one breaking change to flag:

- updateMicroVersionId() signature changed to require a replicationGroupId parameter — downstream callers (CloudServer, Backbeat) must be updated in lockstep

The new MicroVersionId module, isReplica field, and timestamp-ordered format all look correct. Backward compatibility for existing stored metadata (old 16-char random hex microVersionIds) is preserved since getMicroVersionId() returns the raw value and _updateFromParsedJSON copies it as-is.

Review by Claude Code

@maeldonn maeldonn force-pushed the improvement/ARSN-578/micro-version-id branch from 3160d6b to 5f4839a Compare May 22, 2026 18:31
Comment thread lib/models/ObjectMD.ts
this._data.microVersionId = crypto.randomBytes(8).toString('hex');
updateMicroVersionId(replicationGroupId: string) {
this._data.microVersionId = MicroVersionIdUtils.generate(replicationGroupId);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@return itself in the JSDoc, but the method never returns this. Every other setter in this class (setReplicationIsNFS, setReplicationIsReplica, etc.) returns this for chaining. Since this PR is already editing the method and its JSDoc, either add the missing return this; or drop the @return tag.

Suggested change
}
updateMicroVersionId(replicationGroupId: string) {
this._data.microVersionId = MicroVersionIdUtils.generate(replicationGroupId);
return this;
}

— Claude Code

@claude
Copy link
Copy Markdown

claude Bot commented May 22, 2026

  • updateMicroVersionId JSDoc says @return itself but the method body has no return this — either add the return or remove the tag (see inline suggestion)
  • Note: updateMicroVersionId() now requires a replicationGroupId parameter — this is a breaking API change for all downstream callers (CloudServer, Backbeat, etc.). Ensure consumers are updated in lockstep.

Review by Claude Code

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.

3 participants