hudi-agent commented on code in PR #8338:
URL: https://github.com/apache/hudi/pull/8338#discussion_r3565804558


##########
hudi-flink-datasource/hudi-flink/src/test/java/org/apache/hudi/sink/ITTestDataStreamWrite.java:
##########
@@ -171,6 +178,38 @@ public void testWriteMergeOnReadWithCompaction(String 
indexType) throws Exceptio
     testWriteToHoodie(conf, "mor_write_with_compact", 1, EXPECTED);
   }
 
+  @Test
+  public void testVerifyConsistencyOfBucketNum() throws Exception {
+    String path = tempFile.getAbsolutePath();
+    Configuration conf = TestConfigurations.getDefaultConf(path);
+    conf.setString(FlinkOptions.INDEX_TYPE, "BUCKET");
+    conf.setInteger(FlinkOptions.BUCKET_INDEX_NUM_BUCKETS, 4);
+    conf.setInteger(FlinkOptions.COMPACTION_DELTA_COMMITS, 1);
+    conf.setString(FlinkOptions.TABLE_TYPE, 
HoodieTableType.MERGE_ON_READ.name());
+
+    OperatorCoordinator.Context context = new 
MockOperatorCoordinatorContext(new OperatorID(), 2);
+    StreamWriteOperatorCoordinator coordinator = new 
StreamWriteOperatorCoordinator(
+            conf, context);
+    coordinator.start();
+    final org.apache.hadoop.conf.Configuration hadoopConf = 
HadoopConfigurations.getHadoopConf(new Configuration());
+    try (FileSystem fs = HadoopFSUtils.getFs(path, hadoopConf)) {
+      assertTrue(fs.exists(new org.apache.hadoop.fs.Path(path, 
HoodieTableMetaClient.METAFOLDER_NAME)));
+    }
+    coordinator.close();
+
+    conf.setInteger(FlinkOptions.BUCKET_INDEX_NUM_BUCKETS, 5);
+    coordinator = new StreamWriteOperatorCoordinator(
+            conf, context);
+    try {
+      coordinator.start();
+    } catch (IllegalArgumentException e) {

Review Comment:
   πŸ€– This test passes even if `start()` never throws β€” the catch block is only 
reached when the exception fires. Could you add a `fail(...)` right after 
`coordinator.start()` so a regression that skips the validation is actually 
caught? Otherwise the assertion inside the catch may never run.
   
   <sub><i>⚠️ AI-generated; verify before applying. React πŸ‘/πŸ‘Ž to flag 
quality.</i></sub>



##########
hudi-flink-datasource/hudi-flink/src/main/java/org/apache/hudi/util/StreamerUtil.java:
##########
@@ -262,19 +263,52 @@ public static HoodieTableMetaClient initTableIfNotExists(
           .setCDCEnabled(conf.getBoolean(FlinkOptions.CDC_ENABLED))
           
.setCDCSupplementalLoggingMode(conf.getString(FlinkOptions.SUPPLEMENTAL_LOGGING_MODE))
           .setTimelineLayoutVersion(1)
+          .setHoodieIndexConf(OptionsResolver.getHoodieIndexConf(conf))
           .initTable(hadoopConf, basePath);
       LOG.info("Table initialized under base path {}", basePath);
     } else {
       LOG.info("Table [path={}, name={}] already exists, no need to initialize 
the table",
           basePath, conf.getString(FlinkOptions.TABLE_NAME));
     }
 
-    return StreamerUtil.createMetaClient(conf, hadoopConf);
-
+    HoodieTableMetaClient client = StreamerUtil.createMetaClient(basePath, 
hadoopConf);
+    validateTableConfig(conf, client.getTableConfig());
+    return client;
     // Do not close the filesystem in order to use the CACHE,
     // some filesystems release the handles in #close method.
   }
 
+  /**
+   * Detects conflicts between new parameters and existing table 
configurations.
+   */
+  public static void validateTableConfig(Configuration conf, HoodieTableConfig 
storedTableConf) {
+    // Should verify the consistency of bucket num at job startup.
+    if (storedTableConf.contains(FlinkOptions.INDEX_TYPE.key())) {
+      HoodieIndex.IndexType storedConfIndexType =
+              
HoodieIndex.IndexType.valueOf(storedTableConf.getString(FlinkOptions.INDEX_TYPE.key()));
+      if (conf.contains(FlinkOptions.INDEX_TYPE)) {
+        HoodieIndex.IndexType indexType = OptionsResolver.getIndexType(conf);
+        ValidationUtils.checkArgument(indexType.equals(storedConfIndexType),
+                  String.format("Config [%s] = [%s] is conflict with stored 
config [%s].",
+                          FlinkOptions.INDEX_TYPE.key(),
+                          indexType,
+                          storedConfIndexType));
+      }
+      if (storedConfIndexType.equals(HoodieIndex.IndexType.BUCKET)

Review Comment:
   πŸ€– Does this equality check hold for the consistent-hashing bucket engine? 
For `CONSISTENT_HASHING`, `BUCKET_INDEX_NUM_BUCKETS` is only the *initial* 
bucket count β€” the actual bucket number is managed by hashing metadata and can 
be resized via clustering. Enforcing strict equality here would reject a 
legitimately resized consistent-hashing table. Could you gate this check on 
`BUCKET_INDEX_ENGINE_TYPE == SIMPLE`?
   
   <sub><i>⚠️ AI-generated; verify before applying. React πŸ‘/πŸ‘Ž to flag 
quality.</i></sub>



##########
hudi-flink-datasource/hudi-flink/src/main/java/org/apache/hudi/configuration/OptionsResolver.java:
##########
@@ -135,6 +136,16 @@ public static String getPreCombineField(Configuration 
conf) {
     return preCombineField.equals(FlinkOptions.NO_PRE_COMBINE) ? null : 
preCombineField;
   }
 
+  public static Properties getHoodieIndexConf(Configuration conf) {
+    Properties pro = new Properties();
+    String indexType = conf.getString(FlinkOptions.INDEX_TYPE);

Review Comment:
   πŸ€– nit: `pro` is pretty cryptic here β€” could you rename it to `props` or 
`indexProps` to make it clearer at a glance?
   
   <sub><i>⚠️ AI-generated; verify before applying. React πŸ‘/πŸ‘Ž to flag 
quality.</i></sub>



##########
hudi-flink-datasource/hudi-flink/src/main/java/org/apache/hudi/util/StreamerUtil.java:
##########
@@ -262,19 +263,52 @@ public static HoodieTableMetaClient initTableIfNotExists(
           .setCDCEnabled(conf.getBoolean(FlinkOptions.CDC_ENABLED))
           
.setCDCSupplementalLoggingMode(conf.getString(FlinkOptions.SUPPLEMENTAL_LOGGING_MODE))
           .setTimelineLayoutVersion(1)
+          .setHoodieIndexConf(OptionsResolver.getHoodieIndexConf(conf))
           .initTable(hadoopConf, basePath);
       LOG.info("Table initialized under base path {}", basePath);
     } else {
       LOG.info("Table [path={}, name={}] already exists, no need to initialize 
the table",
           basePath, conf.getString(FlinkOptions.TABLE_NAME));
     }
 
-    return StreamerUtil.createMetaClient(conf, hadoopConf);
-
+    HoodieTableMetaClient client = StreamerUtil.createMetaClient(basePath, 
hadoopConf);
+    validateTableConfig(conf, client.getTableConfig());
+    return client;
     // Do not close the filesystem in order to use the CACHE,
     // some filesystems release the handles in #close method.
   }
 
+  /**
+   * Detects conflicts between new parameters and existing table 
configurations.
+   */
+  public static void validateTableConfig(Configuration conf, HoodieTableConfig 
storedTableConf) {
+    // Should verify the consistency of bucket num at job startup.
+    if (storedTableConf.contains(FlinkOptions.INDEX_TYPE.key())) {
+      HoodieIndex.IndexType storedConfIndexType =
+              
HoodieIndex.IndexType.valueOf(storedTableConf.getString(FlinkOptions.INDEX_TYPE.key()));
+      if (conf.contains(FlinkOptions.INDEX_TYPE)) {
+        HoodieIndex.IndexType indexType = OptionsResolver.getIndexType(conf);
+        ValidationUtils.checkArgument(indexType.equals(storedConfIndexType),
+                  String.format("Config [%s] = [%s] is conflict with stored 
config [%s].",
+                          FlinkOptions.INDEX_TYPE.key(),
+                          indexType,
+                          storedConfIndexType));
+      }
+      if (storedConfIndexType.equals(HoodieIndex.IndexType.BUCKET)
+              && conf.contains(FlinkOptions.BUCKET_INDEX_NUM_BUCKETS)
+              && 
storedTableConf.contains(FlinkOptions.BUCKET_INDEX_NUM_BUCKETS.key())) {
+        String bucketNums = 
conf.get(FlinkOptions.BUCKET_INDEX_NUM_BUCKETS).toString();
+        String storedConfBucketNums = 
storedTableConf.getString(FlinkOptions.BUCKET_INDEX_NUM_BUCKETS.key());
+        ValidationUtils.checkArgument(bucketNums.equals(storedConfBucketNums),
+                String.format("Config [%s] = [%s] is not equals stored config 
[%s].",
+                        HoodieIndexConfig.BUCKET_INDEX_NUM_BUCKETS.key(),
+                        bucketNums,
+                        storedConfBucketNums));
+      }
+    }
+    // Other config verification.

Review Comment:
   πŸ€– nit: `// Other config verification.` doesn't say anything actionable β€” if 
this is a placeholder for future work, could you make it a `// TODO:` comment 
(or remove it)?
   
   <sub><i>⚠️ AI-generated; verify before applying. React πŸ‘/πŸ‘Ž to flag 
quality.</i></sub>



##########
hudi-flink-datasource/hudi-flink/src/main/java/org/apache/hudi/util/StreamerUtil.java:
##########
@@ -262,19 +263,52 @@ public static HoodieTableMetaClient initTableIfNotExists(
           .setCDCEnabled(conf.getBoolean(FlinkOptions.CDC_ENABLED))
           
.setCDCSupplementalLoggingMode(conf.getString(FlinkOptions.SUPPLEMENTAL_LOGGING_MODE))
           .setTimelineLayoutVersion(1)
+          .setHoodieIndexConf(OptionsResolver.getHoodieIndexConf(conf))
           .initTable(hadoopConf, basePath);
       LOG.info("Table initialized under base path {}", basePath);
     } else {
       LOG.info("Table [path={}, name={}] already exists, no need to initialize 
the table",
           basePath, conf.getString(FlinkOptions.TABLE_NAME));
     }
 
-    return StreamerUtil.createMetaClient(conf, hadoopConf);
-
+    HoodieTableMetaClient client = StreamerUtil.createMetaClient(basePath, 
hadoopConf);
+    validateTableConfig(conf, client.getTableConfig());
+    return client;
     // Do not close the filesystem in order to use the CACHE,
     // some filesystems release the handles in #close method.
   }
 
+  /**
+   * Detects conflicts between new parameters and existing table 
configurations.
+   */
+  public static void validateTableConfig(Configuration conf, HoodieTableConfig 
storedTableConf) {
+    // Should verify the consistency of bucket num at job startup.
+    if (storedTableConf.contains(FlinkOptions.INDEX_TYPE.key())) {
+      HoodieIndex.IndexType storedConfIndexType =
+              
HoodieIndex.IndexType.valueOf(storedTableConf.getString(FlinkOptions.INDEX_TYPE.key()));
+      if (conf.contains(FlinkOptions.INDEX_TYPE)) {
+        HoodieIndex.IndexType indexType = OptionsResolver.getIndexType(conf);
+        ValidationUtils.checkArgument(indexType.equals(storedConfIndexType),
+                  String.format("Config [%s] = [%s] is conflict with stored 
config [%s].",

Review Comment:
   πŸ€– nit: `"is conflict with stored config"` reads awkwardly β€” maybe 
`"conflicts with stored config [%s]"` instead? Same issue on the bucket-num 
message a few lines down (`"is not equals stored config"` β†’ `"does not equal 
stored config"`). Worth catching now since the integration test asserts on 
these exact strings.
   
   <sub><i>⚠️ AI-generated; verify before applying. React πŸ‘/πŸ‘Ž to flag 
quality.</i></sub>



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