feat: add native Delta Lake scan contrib module (page/row-group pruning) - #5365
feat: add native Delta Lake scan contrib module (page/row-group pruning)#5365dwsmith1983 wants to merge 5 commits into
Conversation
|
Update: pushed two follow-up commits extending the scan's pruning and object-store behavior.
|
…ng + in-scan DVs) Adds contrib/delta behind a -Pdelta profile: delta-spark keeps all planning (log replay, snapshot, partition pruning); Comet claims the DSv1 scan via a new CometScanRuleExtension SPI and reads data through the same native DataFusion parquet path as CometNativeScanExec, inheriting row-group stats pruning, page-index pruning, and filter pushdown. Deletion vectors are decoded natively into per-file ParquetAccessPlans that intersect with page-index pruning, so deleted rows are skipped in-scan; DV blob and footer fetches run concurrently and footers go through the scan's shared FileMetadataCache (no extra metadata round-trips for DV files). Scalar-subquery data filters are resolved at execution time and pushed to the native reader — a capability stock Spark 3.x lacks entirely. Column mapping name mode, DPP, time travel, checkpoints, schema evolution, and INT96 covered. The `delta` native feature ships in the default set: runtime stays double-gated (contrib jar via ServiceLoader + conf), so it is inert for non-Delta users; roaring is the only net-new default dependency. CI runs the contrib suites on Spark 3.5/4.0/4.1, byte-compiles the dev scripts on Python 3.11-3.14, and keeps the feature-off error path tested. Verified: 39-test differential suite green on Spark 3.5/4.0/4.1; Delta's own suites with Comet injected fully green, 1156/1156 (DeletionVectors, TimeTravel, ColumnMapping, DeleteSQL, UpdateSQL, MergeIntoSQL — one test-only harness patch maps the Comet scan node to its originalPlan for Delta's ScanReportHelper). Local bench (20M rows, release): 1.35x vs stock at 9.4% of bytes on literal bounds; 3.35x on subquery bounds (stock scans 100%, contrib 5%). Supersedes apache#4366 (delta-kernel-rs contrib) and apache#4669 (plain-table native scan), deliberately building on both. Co-authored-by: Scott Schenkein <schenksj@yahoo.com> Co-authored-by: Aditya Vaish <adivaish@microsoft.com>
888e4a7 to
7fd81aa
Compare
|
HI @andygrove, Can you review this as it adds Delta functionality? |
Two deficiencies surfaced by 'make release PROFILES="-Pspark-3.5,delta"' (the path a vendor uses to package the contrib), neither visible in CI: - CometScanRuleExtension scaladoc violated spotless line-wrapping (mvn spotless:apply; CI's contrib job builds deps with -Dspotless.check.skip=true so it never checked this file). - BanDuplicateClasses fired for five comet-common exception classes: the comet-spark shaded jar bundles comet-common, so inside a single reactor the contrib sees both artifacts (the dependency-reduced pom only shields repository consumers), and shade's ASM pass renumbers some constant pools so ignoreWhenIdentical cannot collapse them. Ignore the org.apache.comet.* overlap for that pair explicitly. Verified: ./mvnw install -Prelease -DskipTests -Pspark-3.5,delta now completes with no skip flags.
isDeltaScan used classOf[DeltaParquetFileFormat], which resolves the Delta class on the FIRST V1 scan the extension inspects. With the contrib jar deployed but delta-spark not on the classpath, that raises NoClassDefFoundError inside CometScanRule and takes down every parquet scan in the session - the exact opposite of the module's inert-by- default contract (found live: a parquet-only benchmark arm with the contrib jar staged died on its first query). Compare the class NAME instead: no Delta type is touched until the name matches, and a match proves delta-spark is present (the instance exists), so every Delta reference past this gate stays safe. Exact string equality preserves the previous exact-class semantics. Verified: compiled bytecode of isDeltaScan carries only a string constant (javap: getName + ldc + String.equals - no Delta constant- pool entry); compile, spotless and scalastyle green.
Which issue does this PR close?
Part of #174 (Explore integration with Delta Lake). It does not close #174, that issue also tracks writes, CDF, and broader integration; this PR delivers the native read path.
Supersedes two earlier efforts, and deliberately builds on both (both given co-authored by since ideas were learned and borrowed):
Rationale for this change
Comet currently falls back to Spark's reader for all Delta tables (
isFileFormatSupportedrequires exactParquetFileFormat, andDeltaParquetFileFormatis a subclass). That forfeits native execution and all of Comet's parquet pruning on one of the most common table formats.Key observation: delta-spark has already done log replay, snapshot resolution, time travel, and partition pruning by the time
CometScanRulesees theFileSourceScanExec. So no Delta planning is needed on the native side at all, the scan can route through the exact same DataFusionParquetSourcepath asCometNativeScanExec, inheriting row-group stats pruning, page-index pruning (#5142), and filter pushdown (#4722) for free. The only genuinely Delta-specific native code is deletion-vector decoding: DV bitmaps are decoded into per-fileParquetAccessPlans, which DataFusion intersects with page-index pruning, so deleted rows are skipped in-scan and DV skips compose with page skips.Local benchmark (20M rows, selective predicate): 1.44x faster than stock Spark 9.4% of bytes read; DV tables at time parity with in-scan DV application.
What changes are included in this PR?
contrib/delta/new Maven module behind a-Pdeltaprofile: scan rule, decline gates, serde,CometDeltaNativeScanExec(split-mode partition serialization, DPP via derived scan helper), ServiceLoader registrations, differential test suites, Delta own-suite regression harness, benchmark script.CometScanRuleExtensionSPI + ServiceLoader hook at the top oftransformV1Scan;CometNativeScan.convert body extracted into reusablebuildNativeScanCommon`.deltacargo feature:DeltaScanproto + planner arm delegati the shared parquet scan builder;delta_dv.rsfor DV blob unframing (CRC verified), roaring decode (portable + native magic), and access-plan construction.input_file_name().How are these changes tested?
page_index_rows_pruned > 0,row_groups_pruned_statistics > 0), not benchmark notes.useMetadataRowIndexmodes.Co-authored-by: Scott Schenkein schenksj@yahoo.com
Co-authored-by: Aditya Vaish adivaish@microsoft.com