amaechler opened a new pull request, #20408:
URL: https://github.com/apache/druid/pull/20408

   ### Description
   
   `DruidCoordinator.getStatusOfDuties()` reads `dutiesRunnables` without 
holding `lock`, while `becomeLeader()` and `stopAllDutyGroups()` mutate the 
same `ArrayList` under `lock`. A caller of `/druid/coordinator/v1/duties` that 
races with a leadership change can therefore observe a half-cleared list and 
hit a `NullPointerException` in the stream.
   
   The same race makes `DruidCoordinatorTest` flaky. Three tests 
(`testCompactSegmentsDutyWhenCustomDutyGroupEmpty` and the two 
`testInitializeCompactSegmentsDuty…` tests) call `start()` and immediately read 
`getStatusOfDuties()`. They stub 
`segmentsMetadataManager.isPollingDatabasePeriodically()` but not 
`serverInventoryView.isStarted()`, so the mock answers `false`. With the 1 ms 
start delay in the test config, the first duty run takes the "Inventory view 
not initialized yet" branch and calls `stopBeingLeader()`, which clears 
`dutiesRunnables` on the executor thread. Depending on timing the test thread 
sees 4 groups, 0 groups, or:
   
   ```
   java.lang.NullPointerException: Cannot read field "dutyGroup" because "r" is 
null
     at DruidCoordinator.lambda$getStatusOfDuties$0(DruidCoordinator.java:355)
   ```
   
   Inserting `Thread.sleep(50)` before the `getStatusOfDuties()` call makes the 
tests fail deterministically with `expected: <4> but was: <0>`.
   
   #### Guarded `dutiesRunnables` with `lock`
   
   Annotated the field with `@GuardedBy("lock")` and wrapped the read in 
`getStatusOfDuties()` in `synchronized (lock)`. Every other access already runs 
under `lock`, so this is the only call site that changes. Error Prone's 
`GuardedBy` checker (enabled in the `strict` profile) now enforces the 
invariant at compile time.
   
   #### Stubbed `serverInventoryView.isStarted()` in the three flaky tests
   
   The three tests now stub `serverInventoryView.isStarted()` to `true`, as 
every other test in the class already does, so the coordinator keeps leadership 
for the duration of the test.
   
   <hr>
   
   ##### Key changed/added classes in this PR
    * `DruidCoordinator`
    * `DruidCoordinatorTest`
   
   <hr>
   
   This PR has:
   
   - [x] been self-reviewed.
      - [x] using the [concurrency 
checklist](https://github.com/apache/druid/blob/master/dev/code-review/concurrency.md)
   - [x] added or updated unit 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]

Reply via email to