gerashegalov commented on code in PR #18709:
URL: https://github.com/apache/iceberg/pull/18709#discussion_r4513567816


##########
spark/v4.2/spark/src/main/java/org/apache/iceberg/spark/source/SparkScan.java:
##########
@@ -114,6 +116,7 @@ abstract class SparkScan implements Scan, 
SupportsReportStatistics {
 
   // lazy variables
   private StructType readSchema;
+  private Long effectiveSplitTargetSize;

Review Comment:
   Done in c5ebd6fa7: it's now a `long` initialized to the configured split 
size and overwritten by adaptive sizing.



##########
spark/v4.2/spark/src/main/java/org/apache/iceberg/spark/source/SparkScan.java:
##########
@@ -301,12 +304,15 @@ public String toString() {
   @Override
   public CustomTaskMetric[] reportDriverMetrics() {
     ScanReport scanReport = scanReportSupplier != null ? 
scanReportSupplier.get() : null;
+    List<CustomTaskMetric> driverMetrics = Lists.newArrayList();
 
-    if (scanReport == null) {
-      return new CustomTaskMetric[0];
+    if (effectiveSplitTargetSize != null) {

Review Comment:
   `SparkStagedScan` passes a null scan-report supplier, so moving this after 
the null check would drop the metric for staged rewrite scans (covered in 
`TestSparkStagedScan`). The split target doesn't depend on the scan report, so 
I kept it unconditional.



##########
spark/v4.2/spark/src/main/java/org/apache/iceberg/spark/source/SparkStagedScan.java:
##########
@@ -66,6 +66,7 @@ protected List<ScanTaskGroup<ScanTask>> taskGroups() {
           taskSetId);
 
       this.taskGroups = TableScanUtil.planTaskGroups(tasks, splitSize, 
splitLookback, openFileCost);
+      recordEffectiveSplitTargetSize(splitSize);

Review Comment:
   Done in c5ebd6fa7: removed, since the initial value is the staged scan's 
split size.



##########
spark/v4.2/spark/src/test/java/org/apache/iceberg/spark/source/TestSparkReadMetrics.java:
##########
@@ -46,6 +52,80 @@ public void removeTables() {
     sql("DROP TABLE IF EXISTS %s", tableName);
   }
 
+  @TestTemplate
+  public void testEffectiveSplitTargetSize() throws NoSuchTableException {
+    sql(
+        "CREATE TABLE %s (id BIGINT) USING iceberg TBLPROPERTIES 
('read.split.target-size'='134217728')",
+        tableName);
+    spark.range(100).coalesce(1).writeTo(tableName).append();
+
+    withSQLConf(
+        ImmutableMap.of(
+            SparkSQLProperties.READ_ADAPTIVE_SPLIT_SIZE_ENABLED,
+            "true",
+            SparkSQLProperties.READ_ADAPTIVE_SPLIT_SIZE_PARALLELISM,
+            "1000"),
+        () -> assertEffectiveSplitTargetSize(16L * 1024 * 1024));
+
+    withSQLConf(
+        ImmutableMap.of(SparkSQLProperties.READ_ADAPTIVE_SPLIT_SIZE_ENABLED, 
"false"),
+        () -> assertEffectiveSplitTargetSize(128L * 1024 * 1024));
+
+    withSQLConf(
+        ImmutableMap.of(SparkSQLProperties.READ_ADAPTIVE_SPLIT_SIZE_ENABLED, 
"true"),
+        () -> {
+          Dataset<Row> df =
+              spark
+                  .read()
+                  .format("iceberg")
+                  .option(SparkReadOptions.SPLIT_SIZE, String.valueOf(32L * 
1024 * 1024))
+                  .load(tableName);
+          assertEffectiveSplitTargetSize(df, 32L * 1024 * 1024);
+        });
+  }
+
+  @TestTemplate
+  public void testCustomMetricsAreInstantiableBySpark() {

Review Comment:
   Done in c5ebd6fa7: folded the check into `testReadMetricsForV1Table` and 
`testReadMetricsForV2Table`.



##########
spark/v4.2/spark/src/test/java/org/apache/iceberg/spark/source/TestSparkReadMetrics.java:
##########
@@ -46,6 +52,80 @@ public void removeTables() {
     sql("DROP TABLE IF EXISTS %s", tableName);
   }
 
+  @TestTemplate
+  public void testEffectiveSplitTargetSize() throws NoSuchTableException {
+    sql(
+        "CREATE TABLE %s (id BIGINT) USING iceberg TBLPROPERTIES 
('read.split.target-size'='134217728')",
+        tableName);
+    spark.range(100).coalesce(1).writeTo(tableName).append();
+
+    withSQLConf(
+        ImmutableMap.of(
+            SparkSQLProperties.READ_ADAPTIVE_SPLIT_SIZE_ENABLED,
+            "true",
+            SparkSQLProperties.READ_ADAPTIVE_SPLIT_SIZE_PARALLELISM,
+            "1000"),
+        () -> assertEffectiveSplitTargetSize(16L * 1024 * 1024));
+
+    withSQLConf(
+        ImmutableMap.of(SparkSQLProperties.READ_ADAPTIVE_SPLIT_SIZE_ENABLED, 
"false"),
+        () -> assertEffectiveSplitTargetSize(128L * 1024 * 1024));
+
+    withSQLConf(
+        ImmutableMap.of(SparkSQLProperties.READ_ADAPTIVE_SPLIT_SIZE_ENABLED, 
"true"),
+        () -> {
+          Dataset<Row> df =
+              spark
+                  .read()
+                  .format("iceberg")
+                  .option(SparkReadOptions.SPLIT_SIZE, String.valueOf(32L * 
1024 * 1024))
+                  .load(tableName);
+          assertEffectiveSplitTargetSize(df, 32L * 1024 * 1024);
+        });
+  }
+
+  @TestTemplate
+  public void testCustomMetricsAreInstantiableBySpark() {
+    sql("CREATE TABLE %s (id BIGINT) USING iceberg", tableName);
+
+    Dataset<Row> df = spark.sql(String.format("SELECT * FROM %s", tableName));
+    SparkPlan scanPlan = 
df.queryExecution().executedPlan().collectLeaves().head();
+
+    assertThat(scanPlan).isInstanceOf(BatchScanExec.class);
+    CustomMetric[] metrics = ((BatchScanExec) 
scanPlan).scan().supportedCustomMetrics();
+
+    // Spark's SQLAppStatusListener creates each metric reflectively by class 
name using a public
+    // zero-argument constructor; a private or nested class silently drops the 
metric from the UI
+    assertThat(metrics).isNotEmpty();
+    for (CustomMetric metric : metrics) {
+      scala.collection.immutable.Seq<CustomMetric> loaded =
+          Utils.loadExtensions(
+              CustomMetric.class,
+              
JavaConverters.asScalaBuffer(List.of(metric.getClass().getName())).toSeq(),
+              spark.sparkContext().conf());
+      assertThat(loaded.size()).as("metric %s", metric.name()).isEqualTo(1);
+    }
+  }
+
+  private void assertEffectiveSplitTargetSize(long expectedSize) {
+    Dataset<Row> df = spark.sql(String.format("SELECT * FROM %s", tableName));
+    assertEffectiveSplitTargetSize(df, expectedSize);
+  }
+
+  private void assertEffectiveSplitTargetSize(Dataset<Row> df, long 
expectedSize) {

Review Comment:
   Done in c5ebd6fa7.



##########
spark/v4.2/spark/src/test/java/org/apache/iceberg/spark/source/TestSparkReadMetrics.java:
##########
@@ -46,6 +52,80 @@ public void removeTables() {
     sql("DROP TABLE IF EXISTS %s", tableName);
   }
 
+  @TestTemplate
+  public void testEffectiveSplitTargetSize() throws NoSuchTableException {

Review Comment:
   Added `effectiveSplitTargetSizeWithRuntimeFilter` in c5ebd6fa7. Note that 
the scan-report metrics (e.g. `resultDataFiles`) reflect planning before the 
runtime filter, while the split target is recorded when task groups are 
re-planned after it.



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