[SPARK-58985][CORE] Fix HistoryServerDiskManager double-counting store size on concurrent release and makeRoom - #58312
[SPARK-58985][CORE] Fix HistoryServerDiskManager double-counting store size on concurrent release and makeRoom#58312pan3793 wants to merge 2 commits into
Conversation
…e size on concurrent release and makeRoom Assisted-by: Qwen 3.8 Max
|
Thanks for tracking this down. I walked through the four One thing worth calling out in the description: the I also checked the lock ordering. A few minor comments:
Finally, since SPARK-56044 shipped in 4.2.0 / 4.1.2 / 4.0.3, should this be backported to those branches as well? |
Assisted-by: Qwen 3.8 Max
|
Thanks for the careful review!
Backports: yes, SPARK-56044 shipped in 4.0.3/4.1.2/4.2.0, so the race is live there; will backport to branch-4.0/4.1/4.2/4.3/4.x once merged. |
|
Thanks for tracking this down. The direction looks right to me: putting the whole of Three comments. 1. The new test no longer exercises the interleaving it describesWith the fix in place, the latch handshake cannot work: The runtimes show this — 2.588 s with the fix, 2.567 s without; the 2 seconds are pure timeout wait. As a result // If openStore() handed out a path, the subsequent release in FsHistoryProvider must not
// deduct the size again.
opened.foreach { _ =>
manager.release("app1", None, delete = true)
}It is still a valid regression test, but it would read much better if it asserted the post-fix behavior explicitly ( 2.
|
What changes were proposed in this pull request?
Make the disk usage accounting in
HistoryServerDiskManageratomic with the store operation it accompanies:release()now performs the whole operation -- removing the app from theactivemap, updating usage accounting, and deleting or re-measuring the store -- under theactivelock.makeRoom()re-checks each eviction candidate under theactivelock before deleting it, skipping candidates that became active or whose store directory is already gone. It also removes the stale listing entry when the store directory is already gone, and prevents evicting a store that a concurrentopenStore()just handed out. 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 patternLease.commitalready uses under this lock. As a trade-off,openStore()from UI requests can block while a concurrentrelease()deletes a store (e.g., in thecleanLogsloop); this is deliberate to keep the accounting accurate.Why are the changes needed?
HistoryServerDiskManagercan deduct the same store size twice, driving the committed usage negative and making the History Server throwIllegalStateException: Disk usage tracker went negative.The race is longstanding:
release()updates usage and operates on the store directory outside theactivelock, andmakeRoom()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 theactivemap, a double deduction no longer requires the application to be actively open:release(delete = true)vsopenStore():release()deducts the measured size and deletes the store, but a concurrentopenStore()re-registered the app inactive, so a subsequentrelease()deducts the size again.release(delete = true)vsmakeRoom(): 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 concurrentmakeRoom()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:
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 openStoreinHistoryServerDiskManagerSuite, which fails on the pre-fix code withIllegalStateException: Disk usage tracker went negativeand passes with the fix.Was this patch authored or co-authored using generative AI tooling?
Generated-by: Qwen 3.8 Max