This is an automated email from the ASF dual-hosted git repository.

voonhous pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hudi.git


The following commit(s) were added to refs/heads/master by this push:
     new 8ee40b4fb54f fix(hive-sync): make skip_ro_suffix take precedence over 
sync_snapshot_with_table_name (#19427)
8ee40b4fb54f is described below

commit 8ee40b4fb54fff3beb924134af2367438913062a
Author: Y Ethan Guo <[email protected]>
AuthorDate: Fri Jul 31 02:24:32 2026 -0700

    fix(hive-sync): make skip_ro_suffix take precedence over 
sync_snapshot_with_table_name (#19427)
    
    * fix(hive-sync): make skip_ro_suffix take precedence over 
sync_snapshot_with_table_name
    
    hoodie.datasource.hive_sync.skip_ro_suffix=true claims the bare table name
    for the read-optimized (RO) view of a MOR table. Hudi 1.x flipped the 
default
    of hoodie.meta.sync.sync_snapshot_with_table_name from false to true
    (HUDI-7415), so under the default ALL hive-sync-table-strategy,
    HiveSyncTool.doSync() now syncs the bare table name twice in the same run
    when both configs are true: once as the RO table, then again as the RT
    table, with the RT sync silently winning. This makes skip_ro_suffix a no-op
    and breaks read-optimized queries against the bare table name in case the
    engine can't read with HoodieParquetRealtimeInputFormat (e.g., Presto).
    
    This change skips the redundant bare-name RT sync when skip_ro_suffix is
    set, and logs a WARN naming the table and stating which config wins. The
    real-time view remains available at <table>_rt.
    
    * Address review comments: fix bare-table-name wording, remove 
now-redundant comment, strengthen regression test to a second sync round
    
    * Drop the second-round explanation comment per review feedback
---
 .../java/org/apache/hudi/hive/HiveSyncTool.java    |  9 ++++-
 .../org/apache/hudi/hive/TestHiveSyncTool.java     | 47 ++++++++++++++++++++++
 2 files changed, 55 insertions(+), 1 deletion(-)

diff --git 
a/hudi-sync/hudi-hive-sync/src/main/java/org/apache/hudi/hive/HiveSyncTool.java 
b/hudi-sync/hudi-hive-sync/src/main/java/org/apache/hudi/hive/HiveSyncTool.java
index 21b361d16dfc..80b83816be8b 100644
--- 
a/hudi-sync/hudi-hive-sync/src/main/java/org/apache/hudi/hive/HiveSyncTool.java
+++ 
b/hudi-sync/hudi-hive-sync/src/main/java/org/apache/hudi/hive/HiveSyncTool.java
@@ -212,7 +212,14 @@ public class HiveSyncTool extends HoodieSyncTool 
implements AutoCloseable {
             syncHoodieTable(snapshotTableName, true, false);
             // sync origin table for MOR
             if (config.getBoolean(META_SYNC_SNAPSHOT_WITH_TABLE_NAME)) {
-              syncHoodieTable(tableName, true, false);
+              if 
(config.getBoolean(HIVE_SKIP_RO_SUFFIX_FOR_READ_OPTIMIZED_TABLE)) {
+                log.warn("{}=true claims the bare table name '{}' for the 
read-optimized view; "
+                        + "ignoring {} for this table (the real-time view 
remains registered as '{}').",
+                    HIVE_SKIP_RO_SUFFIX_FOR_READ_OPTIMIZED_TABLE.key(), 
tableId(databaseName, tableName),
+                    META_SYNC_SNAPSHOT_WITH_TABLE_NAME.key(), 
snapshotTableName);
+              } else {
+                syncHoodieTable(tableName, true, false);
+              }
             }
         }
         break;
diff --git 
a/hudi-sync/hudi-hive-sync/src/test/java/org/apache/hudi/hive/TestHiveSyncTool.java
 
b/hudi-sync/hudi-hive-sync/src/test/java/org/apache/hudi/hive/TestHiveSyncTool.java
index 50384913fb82..9f5211ba5efe 100644
--- 
a/hudi-sync/hudi-hive-sync/src/test/java/org/apache/hudi/hive/TestHiveSyncTool.java
+++ 
b/hudi-sync/hudi-hive-sync/src/test/java/org/apache/hudi/hive/TestHiveSyncTool.java
@@ -99,6 +99,7 @@ import static 
org.apache.hudi.hive.HiveSyncConfigHolder.HIVE_AUTO_CREATE_DATABAS
 import static 
org.apache.hudi.hive.HiveSyncConfigHolder.HIVE_BATCH_SYNC_PARTITION_NUM;
 import static 
org.apache.hudi.hive.HiveSyncConfigHolder.HIVE_CREATE_MANAGED_TABLE;
 import static org.apache.hudi.hive.HiveSyncConfigHolder.HIVE_IGNORE_EXCEPTIONS;
+import static 
org.apache.hudi.hive.HiveSyncConfigHolder.HIVE_SKIP_RO_SUFFIX_FOR_READ_OPTIMIZED_TABLE;
 import static 
org.apache.hudi.hive.HiveSyncConfigHolder.HIVE_SYNC_AS_DATA_SOURCE_TABLE;
 import static 
org.apache.hudi.hive.HiveSyncConfigHolder.HIVE_SYNC_BATCHING_ENABLED;
 import static 
org.apache.hudi.hive.HiveSyncConfigHolder.HIVE_SYNC_BATCHING_THREADS;
@@ -120,6 +121,7 @@ import static 
org.apache.hudi.sync.common.HoodieSyncConfig.META_SYNC_FORCE_RECRE
 import static 
org.apache.hudi.sync.common.HoodieSyncConfig.META_SYNC_INCREMENTAL;
 import static 
org.apache.hudi.sync.common.HoodieSyncConfig.META_SYNC_PARTITION_EXTRACTOR_CLASS;
 import static 
org.apache.hudi.sync.common.HoodieSyncConfig.META_SYNC_PARTITION_FIELDS;
+import static 
org.apache.hudi.sync.common.HoodieSyncConfig.META_SYNC_SNAPSHOT_WITH_TABLE_NAME;
 import static 
org.apache.hudi.sync.common.HoodieSyncConfig.META_SYNC_TABLE_NAME;
 import static 
org.apache.hudi.sync.common.HoodieSyncConfig.META_SYNC_TOUCH_PARTITIONS_ENABLED;
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
@@ -1593,6 +1595,51 @@ public class TestHiveSyncTool {
     }
   }
 
+  @Test
+  void testSkipRoSuffixTakesPrecedenceOverSnapshotWithTableName() throws 
Exception {
+    // skip_ro_suffix explicitly claims the bare table name for the RO view; 
the now-default-true
+    // sync_snapshot_with_table_name must not be allowed to flip it to RT.
+    hiveSyncProps.setProperty(HIVE_SYNC_TABLE_STRATEGY.key(), 
HoodieSyncTableStrategy.ALL.name());
+    
hiveSyncProps.setProperty(HIVE_SKIP_RO_SUFFIX_FOR_READ_OPTIMIZED_TABLE.key(), 
"true");
+    hiveSyncProps.setProperty(META_SYNC_SNAPSHOT_WITH_TABLE_NAME.key(), 
"true");
+    hiveSyncProps.setProperty(HIVE_SYNC_AS_DATA_SOURCE_TABLE.key(), "true");
+
+    String instantTime = "100";
+    String deltaCommitTime = "101";
+    HiveTestUtil.createMORTable(instantTime, deltaCommitTime, 5, true, true);
+
+    reInitHiveSyncClient();
+    reSyncHiveTable();
+
+    // a second sync round with a new commit reproduces the flip; a single 
round does not
+    ZonedDateTime dateTime = ZonedDateTime.now().plusDays(6);
+    String commitTime2 = "102";
+    String deltaCommitTime2 = "103";
+    HiveTestUtil.addMORPartitions(1, true, false, true, dateTime, commitTime2, 
deltaCommitTime2);
+    reInitHiveSyncClient();
+    reSyncHiveTable();
+
+    String snapshotTableName = HiveTestUtil.TABLE_NAME + 
HiveSyncTool.SUFFIX_SNAPSHOT_TABLE;
+    String roSuffixTableName = HiveTestUtil.TABLE_NAME + 
HiveSyncTool.SUFFIX_READ_OPTIMIZED_TABLE;
+
+    // the bare table name must stay registered as the read-optimized view
+    StorageDescriptor bareTableSd = 
hiveClient.getMetastoreStorageDescriptor(HiveTestUtil.TABLE_NAME);
+    assertEquals(HoodieParquetInputFormat.class.getName(), 
bareTableSd.getInputFormat(),
+        "Bare table name should remain the RO view (skip_ro_suffix=true) 
despite sync_snapshot_with_table_name=true");
+    assertEquals("true", 
bareTableSd.getSerdeInfo().getParameters().get(ConfigUtils.IS_QUERY_AS_RO_TABLE),
+        "Bare table name should still be marked as the RO table");
+
+    // the real-time/snapshot view remains available, and only there
+    assertTrue(hiveClient.tableExists(snapshotTableName), "Table " + 
snapshotTableName + " should exist after sync completes");
+    StorageDescriptor snapshotTableSd = 
hiveClient.getMetastoreStorageDescriptor(snapshotTableName);
+    assertEquals(HoodieParquetRealtimeInputFormat.class.getName(), 
snapshotTableSd.getInputFormat(),
+        "Table " + snapshotTableName + " should use the realtime input 
format");
+
+    // no separate "<t>_ro" table should be created when skip_ro_suffix is set
+    assertFalse(hiveClient.tableExists(roSuffixTableName),
+        "Table " + roSuffixTableName + " should not exist when skip_ro_suffix 
is set");
+  }
+
   @ParameterizedTest
   @EnumSource(value = HoodieSyncTableStrategy.class, names = {"RO", "RT"})
   public void 
testSyncMergeOnReadWithStrategyWhenTableExist(HoodieSyncTableStrategy strategy) 
throws Exception {

Reply via email to