iloveeyjafjalla opened a new issue, #11441:
URL: https://github.com/apache/rocketmq/issues/11441

   ### Describe the Bug
   
   When the smallest broker of a group changes and this broker becomes the 
master, `BrokerController#onMinBrokerChange` ends with 
`pullRequestHoldService.notifyMasterOnline()`, whose job is to immediately 
re-execute every pull request that is currently suspended, so that clients do 
not have to wait for their own suspend timeout after a master comes online.
   
   That sweep assumes a bucket it has just seen as non-empty still holds 
requests when it drains it:
   
   ```java
   for (ManyPullRequest mpr : this.pullRequestTable.values()) {
       if (mpr == null || mpr.isEmpty()) {
           continue;
       }
       for (PullRequest request : mpr.cloneListAndClear()) {
   ```
   
   `ManyPullRequest#cloneListAndClear()` returns `null` (not an empty list) 
whenever the bucket is empty at drain time:
   
   ```java
   public synchronized List<PullRequest> cloneListAndClear() {
       if (!this.pullRequestList.isEmpty()) {
           ...
           return result;
       }
       return null;
   }
   ```
   
   The buckets are drained by the message-arrival path on the store's dispatch 
thread (`NotifyMessageArrivingListener` -> 
`PullRequestHoldService#notifyMessageArriving`, which drains the same bucket 
and replays the requests that did not match). An arrival that wins the race 
between the `isEmpty()` check above and the drain makes the loop iterable 
`null`, so the enhanced `for` throws a `NullPointerException`.
   
   ### Impact
   
   1. The `NullPointerException` escapes `notifyMasterOnline()` into 
`onMinBrokerChange`. The sweep is over, so every bucket that had not yet been 
visited keeps its requests suspended: those clients sit out their full suspend 
timeout instead of being woken immediately - exactly the stall this method 
exists to prevent, and in exactly the failover window it is meant for.
   2. The exception is thrown on the thread that updates the min-broker state 
(including the `UPDATE_MIN_BROKER` admin path), so the caller sees a failure 
for an operation that has otherwise already been applied.
   
   The same class shows what the intended contract is: `notifyMessageArriving` 
drains a bucket the same way and guards the result with `if (requestList != 
null)` before iterating, so the missing guard in `notifyMasterOnline` is an 
oversight rather than a documented behaviour.
   
   ### How to Reproduce
   
   - Suspend a pull request on some `topic@queueId` (long polling enabled, i.e. 
the client sent the suspend flag and the pull returned `PULL_NOT_FOUND` longer 
than the max. offset).
   - Produce a message for that queue from another thread, so the dispatch 
thread drains the same bucket through `notifyMessageArriving` in the same 
instant as `notifyMasterOnline()`.
   - The stricter, deterministic form of the race: the bucket reports itself as 
non-empty and is drained before `notifyMasterOnline()` drains it, which is what 
makes the sweep iterable `null`.
   - Result with the current code: `java.lang.NullPointerException at 
org.apache.rocketmq.broker.longpolling.PullRequestHoldService.notifyMasterOnline(PullRequestHoldService.java:191)`,
 and the remaining buckets are not woken.
   
   ### Expected Behavior
   
   A bucket that lost that race is skipped; the sweep continues and still wakes 
the requests held for the other queues.
   
   ### Proposed Fix
   
   Read the drained list into a local variable and skip the bucket when it 
answers `null`, instead of iterating the call result directly:
   
   ```java
   List<PullRequest> requestList = mpr.cloneListAndClear();
   if (requestList == null) {
       continue;
   }
   for (PullRequest request : requestList) {
   ```
   
   ### Environment
   
   - 5.5.1-SNAPSHOT (`develop`, 0dd48c39db), all platforms
   


-- 
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