Skip to content

[CONNECT] Default refreshPhaseEnabled from spark.api.mode#57136

Open
longvu-db wants to merge 2 commits into
apache:masterfrom
longvu-db:longvu-db/connect-refresh-phase-api-mode
Open

[CONNECT] Default refreshPhaseEnabled from spark.api.mode#57136
longvu-db wants to merge 2 commits into
apache:masterfrom
longvu-db:longvu-db/connect-refresh-phase-api-mode

Conversation

@longvu-db

Copy link
Copy Markdown
Contributor

What changes were proposed in this pull request?

Derive the default value of QueryExecution.refreshPhaseEnabled from the session's spark.api.mode configuration instead of hardcoding it to true. The refresh phase stays enabled by default in Spark Classic and is disabled by default in Spark Connect.

Concretely, a small helper QueryExecution.refreshPhaseEnabledDefault(sparkSession) reads spark.api.mode (keyed off SparkSessionBuilder.API_MODE_KEY, case-insensitively) from the session's SQLConf and returns false only when the mode is connect. This helper becomes the default argument for refreshPhaseEnabled at the three sites that previously defaulted to true:

  • the QueryExecution primary constructor,
  • QueryExecution.create,
  • QueryExecution.runCommand.

Because SessionState.executePlan builds its QueryExecution via createQueryExecution without passing refreshPhaseEnabled explicitly, and Dataset.ofRows goes through executePlan, every construction site that does not opt out now picks up the mode-appropriate default with no per-call-site changes.

Why are the changes needed?

The QueryExecution refresh phase (tableVersionsRefreshed, backed by V2TableRefreshUtil.refresh) reloads every versioned DSv2 relation from the catalog at execution time to account for the delay between analysis and the subsequent phases. Spark Connect re-resolves and re-analyzes each plan on every request, so by the time a plan reaches execution the analyzed plan already references the latest table state. The refresh then issues redundant catalog.loadTable calls for tables that were just resolved in the same QueryExecution.

Disabling the refresh phase for Connect avoids these extra catalog round-trips. Because analysis and execution happen together in Connect, the refresh is redundant there. The refresh phase is not what keeps stored-plan temp views fresh (that is the V2TableReference analyzer rule), so disabling it does not regress view or table freshness.

Deriving the default from spark.api.mode keeps the switch in one place rather than threading refreshPhaseEnabled = false through every Connect-side construction site.

Does this PR introduce any user-facing change?

No.

How was this patch tested?

Added unit tests in QueryExecutionSuite:

  • refreshPhaseEnabled defaults to true in Classic and false in Connect verifies the default both through the refreshPhaseEnabledDefault helper and through an actual sessionState.executePlan(...), for the unset (Classic) default, spark.api.mode=connect, and spark.api.mode=classic.
  • refreshPhaseEnabled default is derived from spark.api.mode case-insensitively verifies CONNECT and " Connect " (mixed case and surrounding whitespace) resolve to the refresh-disabled default.

Was this patch authored or co-authored using generative AI tooling?

Generated-by: Claude Code

longvu-db added 2 commits July 8, 2026 16:10
Derive the default of `QueryExecution.refreshPhaseEnabled` from the session's
`spark.api.mode` config instead of hardcoding `true`: the refresh phase stays on
in Classic and is off in Connect.

The `QueryExecution` refresh phase (`tableVersionsRefreshed`, backed by
`V2TableRefreshUtil.refresh`) reloads every versioned DSv2 relation from the
catalog at execution time to account for the delay between analysis and the
subsequent phases. Spark Connect re-resolves and re-analyzes each plan on every
request, so by the time a plan reaches execution the analyzed plan already
references the latest table state, making the reload a redundant `catalog.loadTable`
round-trip.

Rather than threading `refreshPhaseEnabled = false` through every Connect-side
`QueryExecution` / `Dataset.ofRows` / `executePlan` construction site, this makes
the flag's default a function of `spark.api.mode` (keyed off
`SparkSessionBuilder.API_MODE_KEY`). All the existing construction sites that do
not pass the flag explicitly (including `SessionState.executePlan` via
`createQueryExecution`, and `QueryExecution.create` / `runCommand`) then pick up
the mode-appropriate default with no per-call-site changes.

Co-authored-by: Isaac
…ctor body

A default argument expression cannot reference another parameter in the same
parameter list, so `refreshPhaseEnabled: Boolean = refreshPhaseEnabledDefault(
sparkSession)` failed to compile ("not found: value sparkSession").

Make the primary constructor take a private `refreshPhaseEnabledOpt: Option[Boolean]`
(default None) and resolve the public `refreshPhaseEnabled` field in the class body,
where `sparkSession` is in scope: honor an explicit value, otherwise fall back to the
mode-based default (enabled in Classic, disabled in Connect). QueryExecution.create and
runCommand keep a plain Boolean parameter and forward it via refreshPhaseEnabledOpt.

Co-authored-by: Isaac

@dongjoon-hyun dongjoon-hyun left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please file a JIRA issue and use it, @longvu-db .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants