nsivabalan commented on code in PR #18984:
URL: https://github.com/apache/hudi/pull/18984#discussion_r3654392563


##########
hudi-sync/hudi-hive-sync/src/main/java/org/apache/hudi/hive/ddl/QueryBasedDDLExecutor.java:
##########
@@ -210,29 +224,43 @@ public void touchPartitionsToTable(String tableName, 
List<String> touchPartition
     }
     log.info("Touching partitions " + touchPartitions.size() + " on " + 
tableName);
     List<String> sqls = constructPartitionAlterStatements(tableName, 
touchPartitions, PartitionAlterType.TOUCH);
-    for (String sql : sqls) {
-      runSQL(sql);
-    }
+    runSQLs(sqls);
   }
 
   /**
    * Builds SQL statements to either touch partitions or set their location.
-   * TOUCH: one ALTER TABLE ... TOUCH PARTITION (p1) PARTITION (p2) ...
-   * SET_LOCATION: one ALTER TABLE ... PARTITION (p) SET LOCATION '...' per 
partition.
+   *
+   * <p>The first element of the returned list is always a {@code USE database}
+   * statement. Hive 2.x's ALTER PARTITION ... SET LOCATION does not respect 
the
+   * {@code db.table} qualifier (silently routes to the connection's current
+   * database), so the {@code USE} is load-bearing. Parallel execution paths 
must
+   * run this statement on every worker before fanning out the rest.
+   *
+   * <p>TOUCH: when {@code HIVE_SYNC_BATCHING_ENABLED} is set, one
+   * {@code ALTER TABLE ... TOUCH PARTITION (p1) ...} per batch of
+   * {@code HIVE_BATCH_SYNC_PARTITION_NUM} partitions. Otherwise a single 
statement
+   * covering all partitions, matching pre-batching behavior.
+   *
+   * <p>SET_LOCATION: one {@code ALTER TABLE ... PARTITION (p) SET LOCATION 
'...'}
+   * per partition (Hive SQL does not support multi-partition SET LOCATION in 
one
+   * statement).
    */
   private List<String> constructPartitionAlterStatements(String tableName, 
List<String> partitions, PartitionAlterType alterType) {
     List<String> result = new ArrayList<>();
-    // Hive 2.x doesn't like db.table name for operations, hence we need to 
change to using the database first
     String useDatabase = "USE " + HIVE_ESCAPE_CHARACTER + databaseName + 
HIVE_ESCAPE_CHARACTER;
     result.add(useDatabase);
     String alterTablePrefix = "ALTER TABLE " + HIVE_ESCAPE_CHARACTER + 
tableName + HIVE_ESCAPE_CHARACTER;
+    int batchSyncPartitionNum = 
config.getBooleanOrDefault(HIVE_SYNC_BATCHING_ENABLED)

Review Comment:
   You're right — `JDBCExecutor` doesn't override `runSQLs`, so with the flag 
on it was splitting TOUCH into `batch_num` statements and then executing them 
serially. Changed statement count and partial-application semantics for zero 
benefit, and directly contradicted the documented "JDBC is unaffected" 
contract. Fixed in `84691ce`.
   
   I took the stronger of the two options you offered. The config read in 
`constructPartitionAlterStatements` is replaced by a `getTouchBatchSize(int)` 
hook: the base implementation returns the full partition count (one statement, 
the long-standing behavior), and only `HiveQueryDDLExecutor` overrides it — 
keyed on `driverPool.isPresent()` rather than on the config. Gating on actual 
pool presence rather than the flag means the split structurally cannot take 
effect on a path that would just execute the batches serially, so this can't 
regress the same way if another subclass is added later.
   
   Regression test added as `TestQueryBasedDDLExecutorTouchBatching` — asserts 
a serial executor emits a single TOUCH statement with the flag on, that its SQL 
is byte-identical with the flag on and off, and (as a control) that a 
parallel-dispatch executor still splits. It's a unit test on SQL shape rather 
than an e2e run, so it pins the contract without needing Hive up.
   
   Also tightened the `batching.enabled` doc to lead with "has no effect in HMS 
or JDBC mode".



##########
hudi-sync/hudi-hive-sync/src/main/java/org/apache/hudi/hive/ddl/HiveQueryDDLExecutor.java:
##########
@@ -73,6 +86,15 @@ public HiveQueryDDLExecutor(HiveSyncConfig config, 
IMetaStoreClient metaStoreCli
       if (this.hiveDriver != null) {
         this.hiveDriver.close();
       }
+      // driverPool (if present) was already constructed by the caller before 
this
+      // ctor ran; since we're about to throw, no one else will call close() 
on it.
+      driverPool.ifPresent(pool -> {

Review Comment:
   Confirmed — real gap. `super(config)` runs the `PartitionValueExtractor` 
reflection before `HiveQueryDDLExecutor`'s try block is entered, so a bad 
`hoodie.datasource.hive_sync.partition_extractor_class` throws where neither 
catch covers the pool: the executor's catch never runs, and 
`HoodieHiveSyncClient`'s catch just rethrows. The pool's worker threads and 
Drivers leak.
   
   Fixed in `e56b4e9` — `HoodieHiveSyncClient`'s constructor catch now closes 
the pool. Putting it there rather than in the executor covers every window 
between building the pool and handing ownership over, including the pre-try one 
you identified. `close()` is idempotent, so overlapping with the executor's own 
cleanup is harmless.



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

Reply via email to