Raviston6296 opened a new pull request, #59915:
URL: https://github.com/apache/spark/pull/59915
### What changes were proposed in this pull request?
Backport of #59821 to `branch-4.0`.
In `CacheManager.uncacheByCondition`, the condition passed to
`recacheByCondition` now checks whether the entry depends on the uncached plan
before calling `CachedRDDBuilder.isCachedColumnBuffersLoaded`:
```scala
cd.plan.exists(isMatchedPlan) &&
!cd.cachedRepresentation.cacheBuilder.isCachedColumnBuffersLoaded
```
The comment at that call site is updated too. It described the check as
non-locking, which has not been true since SPARK-53435.
The `CacheManager` change applies cleanly. The test file needed a manual
resolution only because `master` has two later tests in `DatasetCacheSuite`
(SPARK-53418, SPARK-54812) that are not on `branch-4.0`; the added regression
test is identical to the one in #59821.
### Why are the changes needed?
Since SPARK-53435 (#52199), `isCachedColumnBuffersLoaded` is `synchronized`
on the entry's `CachedRDDBuilder`. `cachedColumnBuffers` holds the same monitor
while building the cached RDD. When the cached plan contains a shuffle and AQE
is enabled, `buildBuffers` materializes the shuffle query stage before
returning, so the monitor is held for that stage's full duration.
`recacheByCondition` evaluated that check on every cache entry before the
plan match, so `Dataset.unpersist()` and `Catalog.dropTempView()` waited for
any in-progress shuffle-backed cache materialization on the driver, including
unrelated ones whose result is never used. One long-running materialization
therefore delays cache cleanup for all other work on the driver.
This affects 4.0.1+ (SPARK-53435 was backported to `branch-4.0`). 4.0.0 is
not affected.
### Does this PR introduce _any_ user-facing change?
Yes. `unpersist()` and `dropTempView()` no longer wait for unrelated
in-progress cache materializations, restoring the 4.0.0 behavior. Results are
unchanged: the same entries are recached, and the SPARK-53435 locking is
unchanged for entries that depend on the uncached plan.
Repro from #59803 (spark-shell, `local[8]`; timings were measured there on
4.2.0):
```scala
import org.apache.spark.sql.functions._
val small = spark.range(10).cache(); small.count()
val sleepy = udf((x: Long) => { Thread.sleep(30000); x })
val slow = spark.range(0, 2, 1,
2).select(sleepy(col("id"))).repartition(4).cache()
new Thread(() => slow.count()).start(); Thread.sleep(5000)
small.unpersist() // before: ~25 s; after: ~10 ms
```
### How was this patch tested?
- New test in `DatasetCacheSuite`: "uncaching an unrelated Dataset does not
wait for an in-progress cache materialization". It blocks a shuffle-backed
cache materialization on a latch and requires `unpersist()` of an unrelated
cache to complete within 10 s. The latch is always released, so a regression
fails rather than hangs.
- On `branch-4.0` with JDK 17: `build/sbt 'sql/testOnly *DatasetCacheSuite
*CachedTableSuite'` passes (93/93).
- With the `CacheManager` change reverted, the new test fails with
`TimeoutException: Future timed out after [10 seconds]`.
### Was this patch authored or co-authored using generative AI tooling?
Generated-by: Claude Code (Claude Opus 5.5)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
--
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]