pan3793 opened a new pull request, #58312:
URL: https://github.com/apache/spark/pull/58312

   ### What changes were proposed in this pull request?
   
   Make the disk usage accounting in `HistoryServerDiskManager` atomic with the 
store operation it accompanies:
   
   - `release()` now performs the whole operation -- removing the app from the 
`active` map, updating usage accounting, and deleting or re-measuring the store 
-- under the `active` lock.
   - `makeRoom()` re-checks each eviction candidate under the `active` lock 
before deleting it, skipping candidates that became active or whose store 
directory is already gone. The summary log reports the stores actually deleted 
and the space actually freed.
   
   The lock now covers directory I/O (`sizeOf`, deletion, listing read/write), 
the same pattern `Lease.commit` already uses under this lock.
   
   ### Why are the changes needed?
   
   `HistoryServerDiskManager` can deduct the same store size twice, driving the 
committed usage negative and making the History Server throw 
`IllegalStateException: Disk usage tracker went negative`.
   
   The race is longstanding: `release()` updates usage and operates on the 
store directory outside the `active` lock, and `makeRoom()` deletes eviction 
candidates without re-checking, so two paths have been able to deduct the same 
store since the disk manager was introduced by SPARK-20654 (2.3.0).
   
   SPARK-56044 (4.0.3) widened the race. By adding a deduction in `release()` 
based on the size measured from disk for apps not in the `active` map, a double 
deduction no longer requires the application to be actively open:
   
   - `release(delete = true)` vs `openStore()`: `release()` deducts the 
measured size and deletes the store, but a concurrent `openStore()` 
re-registered the app in `active`, so a subsequent `release()` deducts the size 
again.
   - `release(delete = true)` vs `makeRoom()`: both paths deduct the size of 
the same store.
   
   This makes the race reachable in normal History Server operation, e.g. log 
cleanup calling `release(delete = true)` for an app never opened after a 
restart while a concurrent UI request opens or evicts the same store. The fix 
also closes two concurrent `makeRoom()` calls evicting the same store twice.
   
   This crash was observed on a production History Server (4.1-based build), in 
the periodic log cleanup path:
   
   ```
   java.lang.IllegalStateException: Disk usage tracker went negative (now = 
-118595158, delta = -151974353)
     at 
o.a.s.deploy.history.HistoryServerDiskManager.updateUsage(HistoryServerDiskManager.scala:285)
     at 
o.a.s.deploy.history.HistoryServerDiskManager.release(HistoryServerDiskManager.scala:186)
     at 
o.a.s.deploy.history.FsHistoryProvider.cleanAppData(FsHistoryProvider.scala:746)
     at 
o.a.s.deploy.history.FsHistoryProvider.deleteAttemptLogs(FsHistoryProvider.scala:1132)
     at 
o.a.s.deploy.history.FsHistoryProvider.cleanLogs(FsHistoryProvider.scala:1063)
     at 
o.a.s.deploy.history.FsHistoryProvider.$anonfun$startPolling$4(FsHistoryProvider.scala:305)
   ```
   
   ### Does this PR introduce _any_ user-facing change?
   
   No.
   
   ### How was this patch tested?
   
   Added a new test `SPARK-58985: release with delete is atomic with openStore` 
in `HistoryServerDiskManagerSuite`, which fails on the pre-fix code with 
`IllegalStateException: Disk usage tracker went negative` and passes with the 
fix.
   
   ### Was this patch authored or co-authored using generative AI tooling?
   
   Generated-by: Qwen 3.8 Max
   


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