pan3793 commented on code in PR #7636:
URL: https://github.com/apache/kyuubi/pull/7636#discussion_r3794657791


##########
externals/kyuubi-spark-sql-engine/src/main/scala/org/apache/spark/sql/kyuubi/SparkDatasetHelper.scala:
##########
@@ -77,6 +79,28 @@ object SparkDatasetHelper extends Logging {
     toArrowBatchRddMethod.bind(ds).invoke()
   }
 
+  /**
+   * Read the arrow compression codec config from the session conf, reusing 
the Spark upstream
+   * configuration keys (`spark.sql.execution.arrow.compression.codec` and
+   * `spark.sql.execution.arrow.compression.zstd.level`, introduced in Spark 
4.1). On Spark < 4.1

Review Comment:
   Add the JIRA ticket when referring to upstream Spark changes, e.g., 
`SPARK-XXXXX (4.1.0) do sth`



##########
externals/kyuubi-spark-sql-engine/src/main/scala/org/apache/spark/sql/kyuubi/SparkDatasetHelper.scala:
##########
@@ -77,6 +79,28 @@ object SparkDatasetHelper extends Logging {
     toArrowBatchRddMethod.bind(ds).invoke()
   }
 
+  /**
+   * Read the arrow compression codec config from the session conf, reusing 
the Spark upstream
+   * configuration keys (`spark.sql.execution.arrow.compression.codec` and
+   * `spark.sql.execution.arrow.compression.zstd.level`, introduced in Spark 
4.1). On Spark < 4.1
+   * these keys are not registered as typed SQLConf entries, so they are read 
as raw strings: a
+   * session-level SET lands in the SQLConf settings map and takes precedence, 
otherwise the
+   * engine-level kyuubi-defaults.conf value applies, otherwise the default.
+   * Returns (codecName, zstdLevel).
+   */
+  private def arrowCompressionConf(spark: SparkSession): (String, Int) = {
+    // Lower-case the codec name to match Spark upstream, whose typed entry 
applies
+    // `.transform(_.toLowerCase(Locale.ROOT))`; reading the key as a raw 
string here would
+    // otherwise make `ZSTD`/`Zstd` reject on Spark < 4.1 while accepted 
natively on 4.1+.

Review Comment:
   ```suggestion
       // Lowercase the codec name to match Spark upstream.
   ```



##########
kyuubi-hive-jdbc/pom.xml:
##########
@@ -46,6 +46,11 @@
             <artifactId>arrow-vector</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>org.apache.arrow</groupId>
+            <artifactId>arrow-compression</artifactId>
+        </dependency>

Review Comment:
   we should tune the `kyuubi-hive-jdbc-shaded`'s `pom.xml` too, include and 
relocate `arrow-compression`, but exclude `zstd-jni` and declare it as an 
optional dependency



##########
externals/kyuubi-spark-sql-engine/src/main/scala/org/apache/spark/sql/execution/arrow/KyuubiArrowConverters.scala:
##########
@@ -39,6 +41,28 @@ object KyuubiArrowConverters extends SQLConfHelper with 
Logging {
 
   type Batch = (Array[Byte], Long)
 
+  /**
+   * Create the Arrow compression codec for the given codec name. Returns the 
no-compression codec
+   * when the codec name is "none" or null.
+   *
+   * The zstd codec is constructed directly with the configured compression 
level rather than
+   * through a [[CompressionCodec.Factory]]: the factory overloads built from 
the codec type enum
+   * cannot carry a compression level and silently fall back to the default 
one, losing the
+   * user-configured level. This follows the latest Spark upstream behavior
+   * (ArrowCompressionUtils).
+   */
+  private def createCodec(codecName: String, zstdLevel: Int): CompressionCodec 
= {
+    if (codecName == null || codecName == "none") {
+      NoCompressionCodec.INSTANCE
+    } else {
+      codecName match {
+        case "zstd" => new ZstdCompressionCodec(zstdLevel)
+        case other =>

Review Comment:
   Why not merge the `null` and `"none"` branches into the pattern-match body? 
For `lz4`, we need to either fail with a clear error message, or fall back to 
null with a warning message



##########
externals/kyuubi-spark-sql-engine/src/test/scala/org/apache/kyuubi/engine/spark/operation/SparkArrowbasedOperationSuite.scala:
##########
@@ -380,6 +380,46 @@ class SparkArrowbasedOperationSuite extends 
WithSparkSQLEngine with SparkDataTyp
     }
   }
 
+  test("arrow zstd compression round-trips through the JDBC client") {
+    // End-to-end coverage of the compressed Arrow IPC path: the engine 
compresses batches with
+    // the upstream-named codec config, and the JDBC client transparently 
decompresses them from
+    // the batch body compression metadata (no server-side codec hint on the 
wire).

Review Comment:
   the "end-to-end coverage" is inaccurate, it's just the engine side coverage, 
you still need to add the server side coverage to verify the: jdbc client <==> 
kyuubi server <==> spark engine



##########
externals/kyuubi-spark-sql-engine/src/main/scala/org/apache/spark/sql/kyuubi/SparkDatasetHelper.scala:
##########
@@ -77,6 +79,28 @@ object SparkDatasetHelper extends Logging {
     toArrowBatchRddMethod.bind(ds).invoke()
   }
 
+  /**
+   * Read the arrow compression codec config from the session conf, reusing 
the Spark upstream
+   * configuration keys (`spark.sql.execution.arrow.compression.codec` and
+   * `spark.sql.execution.arrow.compression.zstd.level`, introduced in Spark 
4.1). On Spark < 4.1
+   * these keys are not registered as typed SQLConf entries, so they are read 
as raw strings: a
+   * session-level SET lands in the SQLConf settings map and takes precedence, 
otherwise the
+   * engine-level kyuubi-defaults.conf value applies, otherwise the default.

Review Comment:
   that's too verbose, you can just say: Read the session-level arrow 
compression codec configs ...



##########
externals/kyuubi-spark-sql-engine/pom.xml:
##########
@@ -405,6 +430,17 @@
                             <pattern>net.bytebuddy</pattern>
                             
<shadedPattern>${kyuubi.shade.packageName}.net.bytebuddy</shadedPattern>
                         </relocation>
+                        <!--
+                          Relocate the bundled arrow-compression classes so 
that Kyuubi's copy
+                          never conflicts with the arrow-compression jar 
shipped by Spark 4.1+.
+                          The relocated codec classes still resolve the 
unrelocated
+                          org.apache.arrow.vector.* and 
com.github.luben.zstd.* types, which are

Review Comment:
   I'm worried about the half-shading decision. Some questions:
   
   - if we don't enable this feature, and don't bundle this depenedency, does 
it work fine or throw a runtime class not found error?
   - if the answer to the above question is "work fine", we can leave it and 
ask the user to put the `arrow-compression` dependency in their Spark classpath 
manually



##########
externals/kyuubi-spark-sql-engine/src/main/scala/org/apache/spark/sql/kyuubi/SparkDatasetHelper.scala:
##########
@@ -89,20 +113,26 @@ object SparkDatasetHelper extends Logging {
     // note that, we can't pass the lazy variable `maxBatchSize` directly, 
this is because input
     // arguments are serialized and sent to the executor side for execution.
     val maxBatchSizePerBatch = maxBatchSize
+    val (codecName, zstdLevel) = arrowCompressionConf(spark)
     plan.execute().mapPartitionsInternal { iter =>
       KyuubiArrowConverters.toBatchIterator(
         iter,
         schemaCaptured,
         maxRecordsPerBatch,
         maxBatchSizePerBatch,
         -1,
-        timeZoneId)
+        timeZoneId,
+        codecName,
+        zstdLevel)
     }
   }
 
   def toArrowBatchLocalIterator(df: DataFrame): Iterator[Array[Byte]] = {
     withNewExecutionId(df) {
-      toArrowBatchRdd(df).toLocalIterator
+      // use the plan-based toArrowBatchRdd so that the arrow compression 
codec takes effect;
+      // the Dataset#toArrowBatchRdd (reflective) path uses the vanilla Spark 
ArrowConverters
+      // which does not apply the Kyuubi compression codec.
+      toArrowBatchRdd(df.queryExecution.executedPlan).toLocalIterator

Review Comment:
   do we still need `def toArrowBatchRdd[T](ds: Dataset[T])` then?



##########
pom.xml:
##########
@@ -348,6 +348,11 @@
                 <artifactId>arrow-vector</artifactId>
                 <version>${arrow.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.apache.arrow</groupId>
+                <artifactId>arrow-compression</artifactId>
+                <version>${arrow.version}</version>

Review Comment:
   actually, we can exclude `commons-compress` since we don't support lz4.
   
   note: things have changed since I suggested `none`, `gzip`, `lz4`, and 
`zstd` options, lz4-java was abandoned by the original author, and another guy 
took over but focused only on security patches, so I would suggest `none` and 
`zstd` only now. (arrow compression does not support `gzip` so exclude it too)



##########
externals/kyuubi-spark-sql-engine/pom.xml:
##########
@@ -283,6 +307,7 @@
                                 <exclude>NOTICE.txt</exclude>
                                 <exclude>mozilla/**</exclude>
                                 <exclude>**/module-info.class</exclude>
+                                <exclude>arrow-git.properties</exclude>

Review Comment:
   will this cause any side-effect it is unavailable at runtime?



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