dongjoon-hyun commented on PR #58314:
URL: https://github.com/apache/spark/pull/58314#issuecomment-5429556991

   Thanks for working on this — the underlying problem is real, and defaulting 
the config to `false` keeps this safe. A few comments.
   
   ### 1. Part of this can be fixed without a config
   
   `cachedName` has only two consumers:
   
   - `InMemoryTableScanExec#nodeName` — but only in the `case Some(_) =>` 
branch, i.e. **named** tables only.
   - `CachedRDDBuilder#buildBuffers` → `cached.setName(cachedName)`.
   
   So for anonymous caches, `cachedName` feeds exactly one thing: the RDD 
display name in the Storage tab. Yet it is a `val` in the case class body, so 
`Utils.abbreviate(cachedPlan.toString, 1024)` is evaluated at **every** 
`CachedRDDBuilder` construction — including caches that are never materialized 
(e.g. `df.cache()` that is never triggered, or a plan AQE ends up not using).
   
   Making it `lazy val` removes that cost unconditionally, with no config and 
no behavior change:
   
   ```scala
   lazy val cachedName: String = tableName.map(n => s"In-memory table 
$n").getOrElse { ... }
   ```
   
   One thing to confirm if you take this: `cachedPlan` is `@transient`, so a 
`lazy val` forced after deserialization would NPE. Both consumers above look 
driver-side (`setName`, and `override val nodeName` which is itself eager), so 
it seems safe — but worth stating explicitly.
   
   This would also narrow what the new config has to justify, down to "large 
anonymous caches that *are* materialized".
   
   ### 2. Off-by-one between the doc and the behavior
   
   ```scala
   private val _nextCachedRDDId = new AtomicLong(0)
   def nextCachedRDDId(): Long = _nextCachedRDDId.getAndIncrement
   ```
   
   `AtomicLong(0)` + `getAndIncrement` means the first name is `CachedRDD 0`, 
but both the config `doc` and the PR description say `'CachedRDD 1'`. Either 
use `incrementAndGet` or fix the doc.
   
   Minor: the closest precedent in this area is `SparkPlan.newPlanId()`:
   
   ```scala
   private val nextPlanId = new AtomicInteger(0)
   private[execution] def newPlanId(): Int = nextPlanId.getAndIncrement()
   ```
   
   `private val nextId` reads better here than the underscore-prefixed name.
   
   ### 3. The config should be `.internal()`, and the name is off-convention
   
   Since the only observable effect for anonymous caches is an RDD display 
name, this is a debugging/tuning knob — `.internal()` seems right. As written 
it will show up in the public SQL config docs table.
   
   The name also doesn't match its neighbors in `SQLConf`, which is where it is 
(correctly) placed:
   
   - `spark.sql.defaultCacheStorageLevel`
   - `spark.sql.dataframeCache.logLevel`  ← directly above the new entry
   - `spark.sql.useSequentialCacheName`   ← new
   
   Something like `spark.sql.dataframeCache.sequentialName.enabled` would be 
more consistent, and follows the usual `.enabled` suffix for boolean confs.
   
   ### 4. Prefer `cachedPlan.conf` over `cachedPlan.session.conf`
   
   ```scala
   if (cachedPlan.session.conf.get(SQLConf.USE_SEQUENTIAL_CACHE_NAME)) {
   ```
   
   `SparkPlan.conf` already resolves to `session.sessionState.conf` when a 
session is active and falls back to `SQLConf.get` otherwise, and it is what 
this very file uses a few lines down (`cachedPlan.conf.clone()` in 
`buildBuffers`):
   
   ```scala
   if (cachedPlan.conf.getConf(SQLConf.USE_SEQUENTIAL_CACHE_NAME)) {
   ```
   
   (`cachedPlan.session` is `getActiveSession.orNull`, so the current form NPEs 
on a null session. `newPartitionStats()` already assumes non-null, so this 
isn't a new risk — but no reason to add another one.)
   
   ### 5. Side-effecting `val` in a case class body
   
   `CachedRDDBuilder` is a case class, and `cachedName` now increments a global 
counter as a side effect of construction. Any future `copy(...)` would silently 
change the name and burn an id. There are no `copy` call sites on the builder 
today (`InMemoryRelation.copy()` shares the builder reference), so this is 
latent — but a short comment would help.
   
   For what it's worth, the equality side is fine: `cachedName` is a body 
`val`, not a constructor param, so `equals`/`hashCode`/canonicalization are 
unaffected and `sameResult` / plan reuse can't be perturbed by this.
   
   ### 6. Test
   
   - The other two tests in `InMemoryRelationSuite` are prefixed 
(`SPARK-46779:`, `SPARK-47177:`); please add `SPARK-59024:` for consistency.
   - The disabled-config assertion is weak:
     ```scala
     assert(!r4.cacheBuilder.cachedName.startsWith("CachedRDD "))
     ```
     This only checks it isn't the new format, not that it *is* the abbreviated 
plan tree string. Asserting equality against `Utils.abbreviate(...)` (or at 
least that it starts with the plan's first line) would actually protect the 
fallback path.
   
   ### Nits confirmed OK
   
   - `.version("4.4.0")` matches `branch-4.x`, which is right for a 
normally-backported change.
   - Placement inside the cache-related config cluster in `SQLConf` is good.
   - Default `false` means no golden-file or explain-output impact.
   


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