danny0405 commented on code in PR #19033:
URL: https://github.com/apache/hudi/pull/19033#discussion_r3662480717


##########
hudi-sync/hudi-hive-sync/src/main/java/org/apache/hudi/hive/HoodieHiveSyncClient.java:
##########
@@ -227,6 +241,22 @@ private IMetaStoreClient 
createMetaStoreClient(HiveSyncConfig config) {
     }
   }
 
+  private Option<IMetaStoreClientPool> 
maybeBuildPartitionClientPool(HiveSyncConfig config) {
+    if (!config.getBooleanOrDefault(HIVE_SYNC_BATCHING_ENABLED)) {
+      return Option.empty();
+    }
+    if (config.getBooleanOrDefault(HIVE_SYNC_USE_SPARK_CATALOG)) {
+      // The Spark catalog client is constructed via reflection against a 
Spark-side
+      // class and isn't compatible with the direct RetryingMetaStoreClient 
pool path.
+      // Fall back to single-client sequential behavior rather than failing 
the sync.
+      log.warn("hive_sync.batching.enabled=true is not supported with 
use_spark_catalog=true; "
+          + "falling back to sequential partition sync.");
+      return Option.empty();
+    }
+    int size = config.getIntOrDefault(HIVE_SYNC_BATCHING_THREADS);
+    return Option.of(new IMetaStoreClientPool(config, size));

Review Comment:
   **[P2] Update the public batching config contract for DROP**
   
   `HIVE_SYNC_BATCHING_ENABLED` in `HiveSyncConfigHolder` still documents that 
"DROP remains serial," but this pool makes DROP parallel under that exact flag. 
That text is the user-facing configuration contract, so it currently tells 
operators the opposite of the new behavior. Please update it to cover the 
Thrift-client DROP fan-out (including the Spark-catalog fallback) as part of 
this change.



##########
hudi-sync/hudi-hive-sync/src/main/java/org/apache/hudi/hive/ddl/HiveQueryDDLExecutor.java:
##########
@@ -209,21 +219,96 @@ public void dropPartitionsToTable(String tableName, 
List<String> partitionsToDro
 
     log.info("Drop partitions {} on {}", partitionsToDrop.size(), tableName);
     try {
-      for (String dropPartition : partitionsToDrop) {
-        if (HivePartitionUtil.partitionExists(metaStoreClient, tableName, 
dropPartition, partitionValueExtractor,
-            config)) {
-          String partitionClause =
-              HivePartitionUtil.getPartitionClauseForDrop(dropPartition, 
partitionValueExtractor, config);
-          metaStoreClient.dropPartition(databaseName, tableName, 
partitionClause, false);
-        }
-        log.info("Drop partition {} on {}", dropPartition, tableName);
-      }
+      int batchSyncPartitionNum = 
config.getIntOrDefault(HIVE_BATCH_SYNC_PARTITION_NUM);
+      List<List<String>> batches = CollectionUtils.batches(partitionsToDrop, 
batchSyncPartitionNum);
+      runDropBatches(tableName, batches);
     } catch (Exception e) {
       log.error("{} drop partition failed", tableId(databaseName, tableName), 
e);
       throw new HoodieHiveSyncException(tableId(databaseName, tableName) + " 
drop partition failed", e);
     }
   }
 
+  /**
+   * Drops partitions one batch at a time. When {@link #metaStoreClientPool} 
is present,
+   * batches fan out across the pool's worker threads (each borrowing an 
independent
+   * IMetaStoreClient); otherwise batches are dispatched sequentially against 
the
+   * session client. Hive has no batch-drop primitive that matches 
dropPartition's
+   * semantics, so each worker still iterates its chunk one partition at a 
time — the
+   * win is fanning chunks across independent Thrift clients.
+   *
+   * <p>First-error semantics match {@code HiveDriverPool.awaitAll}: the first 
failure is
+   * rethrown, not-yet-started batches are cancelled, and later failures are 
logged at WARN.
+   */
+  private void runDropBatches(String tableName, List<List<String>> batches) 
throws Exception {
+    if (!metaStoreClientPool.isPresent()) {
+      for (List<String> batch : batches) {
+        applyDropBatch(metaStoreClient, tableName, batch);
+      }
+      return;
+    }
+    IMetaStoreClientPool pool = metaStoreClientPool.get();
+    List<Future<Void>> futures = new ArrayList<>(batches.size());
+    for (List<String> batch : batches) {
+      futures.add(pool.executor().submit(() ->
+          pool.run(poolClient -> {
+            applyDropBatch(poolClient, tableName, batch);
+            return null;
+          })
+      ));
+    }
+
+    Exception firstError = null;
+    int cancelled = 0;
+    for (Future<Void> f : futures) {
+      // Once a batch has failed the sync is going to abort anyway, so stop 
handing
+      // more DROPs to the metastore. mayInterruptIfRunning=false mirrors
+      // HiveDriverPool.awaitAll: a batch already mid-flight runs to 
completion rather
+      // than leaving the partition list half-dropped at an arbitrary point.
+      if (firstError != null && f.cancel(false)) {
+        cancelled++;
+        continue;
+      }
+      try {
+        f.get();

Review Comment:
   **[P2] Stop queued DROP batches as soon as a worker fails**
   
   This waits on futures in submission order. If a later batch fails quickly 
while an earlier batch is slow, this thread remains blocked on the earlier 
`f.get()`, and the shared executor can keep starting every queued batch because 
the tasks do not observe an abort flag. By the time `firstError` is set, most 
or all "not-yet-started" DROPs may already have run, so the advertised 
abort-on-first-error behavior is not achieved. Please mirror 
`HiveDriverPool.Dispatch` (shared task-side abort plus completion-order 
notification), or use a completion service/abort flag so pending batches are 
stopped immediately after any worker fails.



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