Skip to content

Fixes #8426: Inline LinearCongruentialGenerator into consistentHash.#8429

Closed
Tsalachsnow wants to merge 1 commit into
google:masterfrom
Tsalachsnow:fix/inline-lcg-consistent-hash
Closed

Fixes #8426: Inline LinearCongruentialGenerator into consistentHash.#8429
Tsalachsnow wants to merge 1 commit into
google:masterfrom
Tsalachsnow:fix/inline-lcg-consistent-hash

Conversation

@Tsalachsnow
Copy link
Copy Markdown

Summary

This PR eliminates the per-call heap allocation in Hashing.consistentHash by inlining the LinearCongruentialGenerator inner class directly into the method body.

Motivation

Hashing.consistentHash(long, int) constructed a new LinearCongruentialGenerator object on every invocation. That class existed solely to hold one long field and perform two arithmetic steps — there was no behavioral complexity to encapsulate. Under high call frequency (e.g. thousands of calls per second in a load balancer hot path) this generates a continuous stream of short-lived objects, increasing minor GC pressure and producing measurable allocation noise in profiler traces.

Inlining the single field and the two arithmetic operations directly into the method as local variables eliminates the allocation entirely with zero behavioral change.

Changes

Hashing.java (JRE): replaces new LinearCongruentialGenerator(input) with a local long state variable; inlines the two arithmetic steps directly into the loop body; deletes the LinearCongruentialGenerator inner class entirely — it has no remaining callers.

HashingTest.java (JRE): adds two new test methods covering previously untested boundary conditions on consistentHash.

Testing

All existing HashingTest cases continue to pass. Two new test methods added:

testConsistentHash_singleBucketAlwaysReturnsZero
testConsistentHash_largeBucketCountResultInRange
Full ./mvnw clean install passes with 0 failures, 0 errors across the entire test suite.

RELNOTES=Hashing: eliminated per-call LinearCongruentialGenerator allocation in consistentHash; output is bit-for-bit identical to the previous implementation.
Fixes #8426

@google-cla
Copy link
Copy Markdown

google-cla Bot commented May 15, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

consistentHash allocated a new LinearCongruentialGenerator object on
every call solely to hold one long and advance it with two arithmetic
steps. Under high call frequency this produces a continuous stream of
short-lived objects, increasing minor GC pressure for no gain.

Replace the allocation with a local long state variable and inline the
two arithmetic operations directly into the loop body. The class has no
remaining callers and is deleted in full. Output is bit-for-bit identical
to the previous implementation: the inlined expressions are the same
floating-point operations in the same order.

Also add two tests: testConsistentHash_singleBucketAlwaysReturnsZero
(buckets=1 must always return 0) and
testConsistentHash_largeBucketCountResultInRange (result stays within
[0, Integer.MAX_VALUE) for extreme bucket counts).
@Tsalachsnow Tsalachsnow force-pushed the fix/inline-lcg-consistent-hash branch from 8d6754a to 9184f66 Compare May 15, 2026 11:31
@chaoren chaoren closed this May 15, 2026
copybara-service Bot pushed a commit that referenced this pull request May 16, 2026
…Fixes #8426. Closes #8429.

RELNOTES=n/a
PiperOrigin-RevId: 916465257
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.

Hashing.consistentHash() allocates a new object on every call

2 participants