yandrey321 opened a new pull request, #11942:
URL: https://github.com/apache/ozone/pull/11942
## What changes were proposed in this pull request?
**Problem.** Guava recommends Caffeine over its own
`com.google.common.cache`. Ozone used the Guava cache in 14
classes and 5 tests, across `hdds-common`, `hdds-server-framework`,
`hdds-client`, `container-service`,
`ozone-client`, `cli-debug` and `ozone-manager`.
**Change.**
- **Caffeine everywhere:** every Guava cache is now a Caffeine cache.
- `XceiverClientManager`, `RpcClient` (KMS key providers), `ScmClient`
(container locations and datanodes),
`FilePerBlockStrategy` (open files), `DefaultSecretKeyVerifierClient`,
`PrometheusMetricsSinkUtil`,
`DefaultContainerChoosingPolicy`, `S3InMemoryCache`,
`ContainerStateVerifier`, `StateMachine` and `CacheMetrics`.
- `SnapshotCache` / `OmSnapshotManager` take a Caffeine `CacheLoader`.
- **`ResourceCache` is a weighted FIFO without a cache library.** This is
the Ratis leader's cache of state machine
data in `ContainerStateMachine`. See Key decisions.
- **Caffeine is a managed, direct dependency:** `caffeine.version` 2.9.3 in
the root pom, declared in each module that
uses it.
- **No new Guava cache:** the enforcer's `ban-imports` bans
`com.google.common.cache.**`, in main and test code.
**Key decisions.**
- **Caffeine 2.9.3, not 3.x.**
- `hdds-common`, `hdds-client`, `ozone-client` and `hdds-server-framework`
compile for Java 8, and Caffeine 3
needs Java 11. One version must serve both those modules and the
servers, since they share the classpath.
- 2.9.3 is also the version the distribution already ships, through
iceberg-core. Its `checker-qual` (annotations
only) is excluded, so the shipped jars don't change.
- **Removal listeners run on the calling thread,** as Guava's did:
`executor(Runnable::run)`. Caffeine's default runs
maintenance and listeners on `ForkJoinPool.commonPool()`. Three caches
depend on the old behaviour:
- `XceiverClientManager.close()` collects the unreferenced clients in its
listener, to close them in parallel
(HDDS-15255);
- `RpcClient.close()` and `FilePerBlockStrategy.close(File)` must have
closed the key providers and files when they
return.
- **`ResourceCache` keeps FIFO eviction instead of moving to Caffeine.**
- Its Javadoc and its caller ask for FIFO: the newest log entries are the
ones that followers read next.
- Caffeine's TinyLFU admission policy works against that. A new entry,
read only a few times, loses to older ones.
- Simulated (16 entries; every entry written once and read right away):
| cache | newest entry missing after its put | read of the entry 8
behind misses |
|---|---|---|
| Guava (before) | 0% | 27% (its 4 segments evict per segment) |
| Caffeine | 0.6–1.2% | 68–82% |
| this PR's FIFO | 0% | 0% |
- So `ResourceCache` is now a small synchronized `LinkedHashMap` in
insertion order, with weights. It evicts the
eldest entries until within the limit, and reports `REPLACED`,
`EXPLICIT` and `SIZE` causes to the listener,
called outside the lock.
- **Exceptions:** Caffeine wraps a checked loader exception in
`CompletionException`, not `ExecutionException`.
- `DefaultSecretKeyVerifierClient` and `ScmClient` unwrap it as before.
- `XceiverClientManager` and `RpcClient` wrap their loader's `IOException`
in `UncheckedIOException`, which their
existing `catch (Exception)` handles as before.
- **`ScmClient.getContainerLocations`:** Caffeine's `getAll` leaves out
containers that SCM did not return. Guava
threw `InvalidCacheLoadException`, which the code caught to return the
cached ones. The result is the same, without
the exception.
**Side effects.**
- **Unchecked loader exceptions propagate unwrapped,** where Guava wrapped
them in `UncheckedExecutionException`:
- `FilePerBlockStrategy.getChannel` throws the `UncheckedIOException` of a
failed open;
- `ScmClient` throws a `RuntimeException` from SCM as is.
Nothing caught Guava's wrapper there (`TestScmClient` asserted on it, and
is updated).
- **`CacheMetrics`:** `LoadExceptionCount` now reports Caffeine's
`loadFailureCount`, and `Size` reports
`estimatedSize()`.
- **Eviction policy:** the other size-bounded caches now use TinyLFU instead
of Guava's segmented LRU. They are keyed
by pipeline, container, datanode, secret key or metric name, and looked up
repeatedly, which TinyLFU handles well.
- **Public signatures:**
- `XceiverClientManager#getClientCache()` and
`RpcClient#getKeyProviderCache()`, both `@VisibleForTesting`, return
Caffeine's `Cache`;
- `ResourceCache`'s constructor takes Caffeine's `Weigher` and
`RemovalListener`.
- **Distribution:** no change in the shipped jars. A `-Pdist` build matches
`jar-report.txt` exactly, with the same
`caffeine-2.9.3.jar` as before and no `checker-qual`.
Co-authored-by: Claude Opus 5.5 <[email protected]>
## What is the link to the Apache JIRA
https://issues.apache.org/jira/browse/HDDS-15309
## How was this patch tested?
Unit + integration tests.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]