[836] xtable-spark-runtime: thin drop-in bundle (packaging) + resilient target discovery#838
[836] xtable-spark-runtime: thin drop-in bundle (packaging) + resilient target discovery#838vinishjail97 wants to merge 4 commits into
Conversation
ConversionTargetFactory loads targets via ServiceLoader and eagerly instantiates every registered target when resolving any one of them. With a thin runtime where engines are provided, that hard-fails (e.g. DeltaKernelConversionTarget needs io.delta.kernel) even for a sync that never touches Delta. Skip providers whose engine library is not on the classpath so a subset of engines can be used (e.g. Hudi + Iceberg, no Delta). Also make the Delta-kernel check name-based to avoid loading DeltaKernelConversionTarget (and its io.delta.kernel dependencies) when Delta is absent. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
New xtable-spark-runtime module producing a thin, drop-in bundle for in-job XTable metadata sync, plus RFC-3. Packaging (the Hudi/Iceberg model): - Spark, Hadoop, and the engine libs (Hudi/Iceberg/Delta) are provided; the user brings their own engine versions and the bundle stays compatible across them. - Curated shade allowlist: only XTable's own modules + guava/protobuf (relocated under org.apache.xtable.shaded.*). Libraries exchanged with the engines (avro/parquet/jackson/commons) are NOT relocated/bundled - relocating avro breaks the boundary (Hudi returns a real avro Schema). - Resulting bundle: ~4 MB. Includes XTableSparkSync, a standalone spark-submit entry point (the RunSync-equivalent for this bundle), and TableSyncSpec/XTableSyncService shared with the listener (stacked follow-up PR). Validation: ITXTableSparkRuntimeBundle spark-submits the shaded jar via $SPARK_HOME with Hudi + Iceberg supplied through --packages (versions from the root pom) and asserts the Iceberg metadata is produced. Skipped when SPARK_HOME is unset. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| private static final String DELTA_KERNEL_TARGET_CLASS = | ||
| "org.apache.xtable.kernel.DeltaKernelConversionTarget"; | ||
|
|
||
| // Name-based to avoid loading DeltaKernelConversionTarget (and its io.delta.kernel dependencies) |
There was a problem hiding this comment.
Remove this comment..the code is self explanatory.
| // A registered target whose engine library is not on the classpath (e.g. Delta when only | ||
| // Hudi/Iceberg are provided). Skip it so a subset of engines can still be used; a missing | ||
| // engine for the requested format surfaces below as NotSupportedException. | ||
| log.debug( |
There was a problem hiding this comment.
Make this a warn log so that it's visible for the user if some provided package is missing?
There was a problem hiding this comment.
Changed to log.warn with a message pointing the user to provide the missing engine, so an absent provided package is visible. Done in 96da5d6.
| } | ||
| } | ||
|
|
||
| private static Map<String, String> parseArgs(String[] args) { |
There was a problem hiding this comment.
Is this the right to parse? Any existing libraries that can be used to avoid hand-written logic?
https://github.com/apache/incubator-xtable/blob/main/xtable-utilities/src/main/java/org/apache/xtable/utilities/RunSync.java#L240
There was a problem hiding this comment.
Good call. Switched to Apache Commons CLI (Options + DefaultParser + HelpFormatter), mirroring RunSync. commons-cli is bundled and relocated under org.apache.xtable.shaded.*. Done in 96da5d6.
…al bundle IT Review feedback on PR apache#838: - XTableSparkSync now parses args with Apache Commons CLI (mirrors RunSync) instead of hand-rolled parsing; the relocated commons-cli is bundled. - ConversionTargetFactory logs a warn (was debug) when it skips a registered target whose engine library is absent, so a missing provided engine is visible; dropped the self-explanatory comment on isDeltaKernelTarget. Bundle integration test (ITXTableSparkRuntimeBundle): - Supplies engines on a flat classpath via spark.driver.extraClassPath, and adds Avro 1.12 + parquet-avro to the engine classpath: Iceberg 1.9.2 (bumped in apache#784) compiles against Avro 1.12 APIs, which Spark 3.5's Avro 1.11.2 lacks. A flat classpath keeps one Avro on one loader, unlike --packages layering. - Adds jol-core (provided) that Hudi needs at runtime. - XTableSyncService writes target metadata at the source data path (required by Hudi; Iceberg data lives under <basePath>/data); IT passes --dataPath. - Readback mirrors ITConversionController: target read at the data path, Hudi metadata read options, per-format timestamp normalization, scalar-column data-equivalence, and non-vectorized Iceberg reads. - Relocates guava's com.google.thirdparty with the rest of guava. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
What is the purpose of the pull request
First of two PRs splitting #837 (per review feedback) into packaging and listener. This is the packaging PR (the listener stacks on top): it introduces the
xtable-spark-runtimemodule producing a thin, drop-in Spark bundle, plus RFC-3, and validates the jar end-to-end viaspark-submit.Brief change log
rfc/rfc-3/rfc-3.md).xtable-spark-runtime_${scala.binary.version}(thin shaded bundle, ~3.6 MB).XTableSparkSync— standalonespark-submitentry point (RunSync-equivalent for this bundle).TableSyncSpec/XTableSyncService— shared sync building blocks (reused by the listener PR).ConversionTargetFactory: makeServiceLoadertarget discovery resilient — skip targets whose engine lib isn't on the classpath (separable core change; see commit 1).ITXTableSparkRuntimeBundle— spark-submit jar-validation test.Packaging model (the important part)
Per review feedback, engines are not bundled. Spark, Hadoop, and Hudi/Iceberg/Delta are all
provided— the user brings their own engine versions (Hudi 1.1 / 1.2 / …) and the thin XTable jar stays compatible across them.guava/protobuf(relocated underorg.apache.xtable.shaded.*).avrobreaks the boundary (Hudi returns a realorg.apache.avro.Schema→NoSuchMethodError).avro/parquet/jackson/commonscome from the provided runtime.ServiceLoader, it's made resilient so a user can run with only the engines they use (e.g. Hudi + Iceberg, no Delta).Verify this pull request
ITXTableSparkRuntimeBundle(skipped unlessSPARK_HOMEis set) builds the shaded jar and runs a real sync:It creates a local Hudi table,
spark-submits the bundle with Hudi + Iceberg supplied via--packages(versions from the root pom: Hudi 1.2.0, Iceberg 1.9.2), and asserts the Iceberg metadata is produced. Validated locally on Spark 3.5.2 (engines built for 3.4 → also a cross-version check).Part of #836. Listener PR follows, stacked on this branch.
🤖 Generated with Claude Code