[FEA] Add GPU low shuffle merge for Databricks 17.3 [databricks] - #15916
[FEA] Add GPU low shuffle merge for Databricks 17.3 [databricks]#15916liurenjie1024 wants to merge 16 commits into
Conversation
Signed-off-by: Ray Liu <liurenjie2008@gmail.com>
|
| def convertToGpu(mergeCmd: MergeIntoCommand, conf: RapidsConf): RunnableCommand = { | ||
| GpuMergeIntoCommand( | ||
| mergeCmd.source, | ||
| mergeCmd.target, | ||
| mergeCmd.catalogTable, | ||
| mergeCmd.targetFileIndex, | ||
| new GpuDeltaLog(mergeCmd.targetFileIndex.deltaLog, conf), | ||
| mergeCmd.condition, | ||
| mergeCmd.matchedClauses, | ||
| mergeCmd.notMatchedClauses, | ||
| mergeCmd.notMatchedBySourceClauses, | ||
| mergeCmd.migratedSchema, | ||
| mergeCmd.trackHighWaterMarks, | ||
| mergeCmd.schemaEvolutionEnabled)(conf) | ||
| if (conf.isDeltaLowShuffleMergeEnabled) { | ||
| GpuLowShuffleMergeCommand( | ||
| mergeCmd.source, | ||
| mergeCmd.target, | ||
| mergeCmd.catalogTable, | ||
| mergeCmd.targetFileIndex, | ||
| new GpuDeltaLog(mergeCmd.targetFileIndex.deltaLog, conf), | ||
| mergeCmd.condition, | ||
| mergeCmd.matchedClauses, | ||
| mergeCmd.notMatchedClauses, | ||
| mergeCmd.notMatchedBySourceClauses, | ||
| mergeCmd.migratedSchema, | ||
| mergeCmd.trackHighWaterMarks, | ||
| mergeCmd.schemaEvolutionEnabled)(conf) |
There was a problem hiding this comment.
Performance validation is required. This change selects a new runtime merge algorithm that alters scanning, broadcasting, shuffling, and writing, but the PR marks performance validation as “Not required.” The performance checklist directive requires measurements or a tracked performance issue unless the change cannot affect runtime performance. This requirement must be satisfied before merging.
Rule Used: Report Performance: Not required as a high-sever... (source)
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Signed-off-by: Ray Liu <liurenjie2008@gmail.com>
Replace the custom low-shuffle scan registry and file-format path with Databricks' native metadata-row-index and deletion-vector scans. Also address the review comments for copyrights and identity-column validation documentation. Signed-off-by: Ray Liu <liurenjie2008@gmail.com>
Remove the duplicate Databricks-only upsert test and its plan-capture helper, drop the AQE override, and use the exact DBR 17.3 runtime predicate for the shared low-shuffle-merge coverage. Signed-off-by: Ray Liu <liurenjie2008@gmail.com>
Signed-off-by: Ray Liu <liurenjie2008@gmail.com>
Signed-off-by: Ray Liu <liurenjie2008@gmail.com>
Signed-off-by: Ray Liu <liurenjie2008@gmail.com>
Signed-off-by: Ray Liu <liurenjie2008@gmail.com>
Signed-off-by: Ray Liu <liurenjie2008@gmail.com>
Signed-off-by: Ray Liu <liurenjie2008@gmail.com>
Signed-off-by: Ray Liu <liurenjie2008@gmail.com>
Signed-off-by: Ray Liu <liurenjie2008@gmail.com>
Signed-off-by: Ray Liu <liurenjie2008@gmail.com>
Signed-off-by: Ray Liu <liurenjie2008@gmail.com>
Signed-off-by: Ray Liu <liurenjie2008@gmail.com>
| val mainDataOutput = actions.map(_.expr) :+ FalseLiteral :+ incrMetricExpr :+ | ||
| CDC_TYPE_NOT_CDC_LITERAL | ||
| val preImageOutput = cdfTargetOutputCols :+ FalseLiteral :+ TrueLiteral :+ | ||
| Literal(CDC_TYPE_UPDATE_PREIMAGE) | ||
| val postImageOutput = mainDataOutput.dropRight(2) :+ TrueLiteral :+ | ||
| Literal(CDC_TYPE_UPDATE_POSTIMAGE) | ||
| Seq(mainDataOutput, preImageOutput, postImageOutput).map(resolveOnJoinedPlan) |
There was a problem hiding this comment.
For a CDF-enabled Delta 2.4 merge, non-deterministic update and insert expressions are evaluated separately for the table row and its CDF row. Expressions such as rand() or uuid() can therefore produce a CDF postimage or insert event whose values differ from the row written to the table. Materialize each clause-routed non-deterministic expression once before generating both outputs, as the Databricks 17.3 implementation does.
Knowledge Base Used: Delta Lake integration
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
|
@liurenjie1024 - Could you please update the performance results in the PR description. |
Yes, I'm working on this. |
| }) | ||
| .toMap | ||
|
|
||
| val duplicateCount = { |
There was a problem hiding this comment.
DBR 16.0+ only treats multiple source matches as ambiguous when more than one joined pair takes a WHEN MATCHED action. This counts every ON match, so a target matched by one apply=true and one apply=false source row is rejected even though DBR 17.3 and the classic GpuMergeIntoCommand accept it. Could we either port the classic command effective-match counting and joined-pair de-duplication, or fall back to classic merge whenever raw duplicates require that decision? It would also be good to run the existing accepted duplicate-match cases with low shuffle enabled.
|
|
||
| override def close(): Unit = {} | ||
|
|
||
| protected def targetOutputCols: Seq[NamedExpression] = { |
There was a problem hiding this comment.
Should this preserve the DBR row-tracking columns with UpdateCommandShims.preserveRowTrackingColumns, as GpuMergeIntoCommand.writeAllChanges does? Both the modified and unmodified passes rebuild their scans from metadata.schema, which excludes the hidden materialized row ID and row commit version. Those values are therefore absent at writeFiles, so rewritten copied and updated rows can receive new row IDs instead of preserving them. Please also add a low-shuffle row-tracking regression without a NOT MATCHED BY SOURCE clause, since that clause currently selects the classic fallback.
| return getModifiedDFWithCdf(touchedFiles) | ||
| } | ||
|
|
||
| val sourceDF = this.sourceDF |
There was a problem hiding this comment.
Could we make the non-CDF helper names collision-safe too? These fixed withColumn names replace same-named source or target columns, and the later string-based drop also removes user columns named row_dropped or incr_metrics. The CDF branch already uses uniqueColumnName and drops the generated control attributes precisely. Enabling low shuffle should not change classic-merge behavior for these schemas, so a low-shuffle regression with colliding user column names would help.
Fixes #11079.
Description
Databricks 17.3 supports low shuffle merge, but the GPU implementation was only available for older Delta/Databricks shims. As a result, merge operations on Databricks 17.3 could not use the GPU low shuffle merge path.
This change ports the Delta 2.4 GPU low shuffle merge algorithm to the Databricks 17.3 shim and adapts it to the Databricks 17.3 command interfaces. It supports both classic and Edge merge commands, including source materialization, schema evolution, identity columns, type widening, row tracking, set transactions, and statistics.
GPU low shuffle merge requires the
PERFILEParquet reader mode so metadata row indices remain file-relative. When another reader mode is configured, the command falls back to the existing classic GPU merge path.The integration-test gate enables the Databricks path only for exact DBR 17.3; later DBR versions remain skipped until they are explicitly supported.
For Databricks 17.3, touched-file discovery uses Databricks' native metadata-row-index scan preparation. The unmodified-row pass adds temporary inline deletion vectors to the touched
AddFileentries and relies on the existing Databricks deletion-vector scan path to filter modified rows. This avoids a custom low-shuffle scan registry or file-format implementation.CDF-enabled tables remain on the low-shuffle path. The modified-row pass now emits explicit insert, delete, update-preimage, and update-postimage rows alongside rewritten table rows. Merge expressions are tagged at the join-processing conversion boundary; replaceable expressions use
RapidsProcessDeltaMergeJoin, while unsupported expression trees use the existing joined-row processor without falling back the whole merge command. Non-deterministic update/insert expressions are materialized under their clause-routing predicates so table and CDF outputs share the same value. The same native CDF support is added to the Delta 2.4 implementation used as the basis for the Databricks shim.The change also generalizes the Databricks 17.3 table-write overflow wrapper to accept any converted GPU expression while retaining the original source type needed for Delta overflow semantics.
The branch contains upstream
mainatb50f77447(merge commit6b69ead62). The functional tree at that merge commit was validated locally and on a one-node, single-user DBR 17.3g4dn.xlargeGPU cluster. The current head45a7bc35aonly updates the modified Delta 2.4 file's copyright year for CI.jenkins/databricks/build.sh: build success; the DBR 17.3 Delta module compiled successfully (job238183867741769).536767695989422).280834283468655).git diff --check, current-year license-header validation, Python syntax validation, and Signed-off-by verification: success.Checklists
Documentation
Testing
Performance
This is a shim port of the established Delta 2.4 low shuffle merge algorithm. The validation above exercises the runtime path on the target DBR release; this change does not retune the algorithm.
AI assistance: Codex assisted with the review fixes, Databricks cluster automation, and validation. The author directed this update; normal maintainer review remains required.