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]

Reply via email to