Denovo1998 opened a new pull request, #26180:
URL: https://github.com/apache/pulsar/pull/26180
### Motivation
PR #26030 replaced `PendingAcksMap` object values with packed primitive
values and removed the public `PendingAcksMap#get(long, long)` method. However,
this method was included in previous Pulsar releases, including Pulsar 4.0.x
and 4.1.x, and is reachable by broker extensions through the public
`Consumer#getPendingAcks()` method.
A `BrokerInterceptor` compiled against one of those releases can therefore
fail with `NoSuchMethodError` after the broker is upgraded to a version
containing #26030.
### Why `NoSuchMethodError` occurs
`BrokerInterceptor` callbacks such as `messageDispatched` receive a broker
`Consumer` instance. An existing extension can use the following API path:
```java
@Override
public void messageDispatched(ServerCnx cnx, Consumer consumer,
long ledgerId, long entryId,
ByteBuf headersAndPayload) {
IntIntPair pendingAck =
consumer.getPendingAcks().get(ledgerId, entryId);
}
```
When this extension is compiled against an earlier Pulsar release, the Java
compiler records the following symbolic method reference in the extension
bytecode:
```text
org/apache/pulsar/broker/service/PendingAcksMap.get:
(JJ)Lit/unimi/dsi/fastutil/ints/IntIntPair;
```
The relevant bytecode is equivalent to:
```text
invokevirtual Consumer.getPendingAcks:
()Lorg/apache/pulsar/broker/service/PendingAcksMap;
invokevirtual PendingAcksMap.get:
(JJ)Lit/unimi/dsi/fastutil/ints/IntIntPair;
```
The extension does not get recompiled when the broker is upgraded. When the
interceptor callback is executed, the JVM resolves the existing `invokevirtual`
reference against the `PendingAcksMap` loaded from the upgraded broker.
After #26030, that exact method name and descriptor no longer exist. The
newly added primitive accessor has a different name and return type:
```text
PendingAcksMap.getRemainingUnacked:(JJ)I
```
The JVM cannot substitute one method for the other. Method resolution
therefore fails with a linkage error similar to:
```text
java.lang.NoSuchMethodError:
'it.unimi.dsi.fastutil.ints.IntIntPair
org.apache.pulsar.broker.service.PendingAcksMap.get(long, long)'
```
The interceptor can load successfully and only fail when the affected
callback and call site are first executed, making the problem dependent on
extension behavior and broker traffic.
### Modifications
- Restore the exact `PendingAcksMap#get(long, long)` JVM method signature
available in previous releases.
- Mark the restored method as deprecated so new broker code continues to
prefer primitive accessors.
- Reconstruct `IntIntPair` from the packed primitive value while holding the
existing read lock.
- Return `null` for missing ledger and entry mappings, preserving the
previous behavior.
- Add coverage for maximum remaining-unacked values, signed sticky-key
hashes, and missing entries.
- Add a `BrokerInterceptor` extension fixture that accesses the method
through `Consumer#getPendingAcks()`, reproducing the extension API call path.
### Performance impact
The broker production paths changed by #26030 continue to use
`getRemainingUnacked` and `removeAndGetRemainingUnacked`. They do not call the
compatibility method and therefore do not recreate `IntIntPair` objects on the
pending-ack hot paths.
An `IntIntPair` is allocated only when an existing extension explicitly
invokes the deprecated compatibility method.
### Verifying this change
- [x] Make sure that the change passes the CI checks.
The following targeted test and style checks pass:
```bash
./gradlew :pulsar-broker:test \
--tests org.apache.pulsar.broker.service.PendingAcksMapTest \
--max-workers=1 \
-PtestRetryCount=0 \
:pulsar-broker:checkstyleMain \
:pulsar-broker:checkstyleTest
```
### Does this pull request potentially affect one of the following parts:
<!-- DO NOT REMOVE THIS SECTION. CHECK THE PROPER BOX ONLY. -->
*If the box was checked, please highlight the changes*
- [ ] Dependencies (add or upgrade a dependency)
- [ ] The public API
- [ ] The schema
- [ ] The default values of configurations
- [ ] The threading model
- [ ] The binary protocol
- [ ] The REST endpoints
- [ ] The admin CLI options
- [ ] The metrics
- [ ] Anything that affects deployment
--
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]