Skip to content

HDDS-16280. Avoid eager Preconditions message on hot paths - #11131

Open
NickJavaDev88 wants to merge 2 commits into
apache:masterfrom
NickJavaDev88:HDDS-16280
Open

HDDS-16280. Avoid eager Preconditions message on hot paths#11131
NickJavaDev88 wants to merge 2 commits into
apache:masterfrom
NickJavaDev88:HDDS-16280

Conversation

@NickJavaDev88

@NickJavaDev88 NickJavaDev88 commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

What changes were proposed in this pull request?

Guava's Preconditions.checkState(boolean, String) evaluates its message argument before the call, so the error string is built via StringBuilder concatenation on every invocation even when the check passes. Two of these sit on hot paths:

  • XceiverClientRatis.watchForCommit runs the check on every commit-watch reply ("Returned index " + updated + " < expected " + index).
  • ReferenceCounted.decrementRefCount runs it on every snapshot reference release ("This thread " + tid + " already have a reference count of zero.").

Each successful check allocates a StringBuilder, its backing char[] and the resulting String, all short-lived garbage that only adds young-gen GC pressure.

This PR switches both call sites to Guava's template form (checkState(condition, "... %s ... %s", arg1, arg2)). Guava resolves these to its primitive long overloads (checkState(boolean, String, long, long) and checkState(boolean, String, long)), so no boxing or Object[] allocation occurs, and the message is only formatted when the check fails. The failure messages are unchanged.

This is a sub-task of HDDS-16276.

What is the link to the Apache JIRA

https://issues.apache.org/jira/browse/HDDS-16280

How was this patch tested?

No functional change, so no new tests were added:

  • Behavior is unchanged — the assertions and their failure messages are identical.
  • Overload resolution to the primitive long variants is compiler-verified (confirmed against Guava 33.6.0 sources; JLS most-specific applicable method).
  • The change only removes allocations on the passing path.

Verified locally:

  • mvn compile -pl :hdds-client,:ozone-manager -am -DskipShade -DskipRecon -DskipDocs -> BUILD SUCCESS
  • ./hadoop-ozone/dev-support/checks/checkstyle.sh -> 0 violations

A standalone JMH benchmark (not part of this PR — Ozone has no JMH harness) confirms
the allocation saved on the passing path (check always true), JDK 21.0.7, -prof gc:

Benchmark                                                Mode  Cnt     Score    Error   Units
PreconditionsMessageBenchmark.eager                     thrpt    5    41,606 ±  0,368  ops/us
PreconditionsMessageBenchmark.eager:gc.alloc.rate.norm  thrpt    5   240,000 ±  0,001    B/op
PreconditionsMessageBenchmark.lazy                      thrpt    5  3019,410 ±  9,308  ops/us
PreconditionsMessageBenchmark.lazy:gc.alloc.rate.norm   thrpt    5    ≈ 10⁻⁶             B/op

eager is the current "..." + a + " ... " + b form; lazy is the "... %s ... %s", a, b
template form, which Guava resolves to checkState(boolean, String, long, long) — no boxing,
no Object[], message built only on failure. 240 B/op of throwaway garbage per passing check
becomes zero.

CI on the fork: https://github.com/NickJavaDev88/ozone/actions/runs/33087782394

@NickJavaDev88

Copy link
Copy Markdown
Contributor Author

Hi @rich7420, thanks for reporting this issue in Jira!

Could you please take a look when you have a chance?

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.

1 participant