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


##########
hudi-client/hudi-client-common/src/main/java/org/apache/hudi/client/transaction/lock/FileSystemBasedLockProvider.java:
##########
@@ -115,8 +114,8 @@ public FileSystemBasedLockProvider(final LockConfiguration 
lockConfiguration, fi
     this.lockConfiguration = lockConfiguration;
     String lockDirectory = 
lockConfiguration.getConfig().getString(FILESYSTEM_LOCK_PATH_PROP_KEY, null);
     if (StringUtils.isNullOrEmpty(lockDirectory)) {
-      lockDirectory = 
lockConfiguration.getConfig().getString(HoodieWriteConfig.BASE_PATH.key())
-          + StoragePath.SEPARATOR + HoodieTableMetaClient.METAFOLDER_NAME;
+      // Match getLockConfig() so writers using either default share the same 
lock.
+      lockDirectory = 
defaultLockPath(lockConfiguration.getConfig().getString(HoodieWriteConfig.BASE_PATH.key()));

Review Comment:
   🤖 This flips the default lock file for every existing writer that sets only 
`hoodie.write.lock.provider=FileSystemBasedLockProvider` (no explicit 
`filesystem.path`) from `<base>/.hoodie/lock` to `<base>/.hoodie/.aux/lock`. 
During a rolling upgrade, an old-jar writer and a new-jar writer would take two 
different lock files and no longer exclude each other — concurrent commits on 
the same table. Could we call this out in release notes, or keep old-path 
compatibility (e.g. honor `.hoodie/lock` if it exists)? @nsivabalan could you 
weigh in on whether relocating the default FS lock path is safe for 
mixed-version multi-writer setups?
   
   <sub><i>⚠️ AI-generated; verify before applying. React 👍/👎 to flag 
quality.</i></sub>



##########
hudi-spark-datasource/hudi-spark-common/src/main/scala/org/apache/hudi/HoodieCLIUtils.scala:
##########
@@ -166,9 +172,19 @@ object HoodieCLIUtils extends Logging {
     key -> value
   }
 
-  def getLockOptions(tablePath: String, schema: String, lockConfig: 
TypedProperties): Map[String, String] = {
-    val customSupportedFSs = 
lockConfig.getStringList(HoodieCommonConfig.HOODIE_FS_ATOMIC_CREATION_SUPPORT.key,
 ",", new ArrayList[String])
-    if (schema == null || customSupportedFSs.contains(schema) || 
StorageSchemes.isAtomicCreationSupported(schema)) {
+  /**
+   * Builds the filesystem-based lock configuration for the metadata table, or 
an empty map when the
+   * table's filesystem cannot support atomic file creation (a hard 
requirement for the FS lock).
+   *

Review Comment:
   🤖 nit: the merge order flipped from `confs ++ getLockOptions(...)` (old 
callers) to `getLockOptions(...) ++ confs` (new callers), which changes 
precedence. Might be worth a line in the javadoc here noting that 
`params`/caller-supplied confs are expected to win over the derived lock 
options, since that's not obvious from the signature alone.
   
   <sub><i>⚠️ AI-generated; verify before applying. React 👍/👎 to flag 
quality.</i></sub>



##########
hudi-spark-datasource/hudi-spark-common/src/main/scala/org/apache/hudi/HoodieCLIUtils.scala:
##########
@@ -60,13 +59,26 @@ object HoodieCLIUtils extends Logging {
     }
 
     // Priority: defaults < catalog props < table config < sparkSession conf < 
specified conf
-    val finalParameters = HoodieWriterUtils.parametersWithWriteDefaults(
+    val parameters = HoodieWriterUtils.parametersWithWriteDefaults(
       (catalogProps ++
         metaClient.getTableConfig.getProps.asScala.toMap ++
         filterHoodieConfigs(sparkSession.sqlContext.getAllConfs) ++
         conf).toMap
     )
 
+    // Auto-config a DFS-based lock for the metadata table when the table has 
an MDT and no lock
+    // provider is configured at any layer. Table-service writers created here 
(compaction,
+    // clustering, clean, TTL, restore, rollback, savepoint, ...) can update 
the metadata table, so
+    // they must be mutually exclusive with concurrent writers on the shared 
lock path. This must be
+    // applied before building the client so the lock config actually takes 
effect.
+    val finalParameters =

Review Comment:
   🤖 One more that looks like the same shape: `run_ttl` (`RunTTLProcedure`) 
already threads a `confs` map into `HoodieCLIUtils.createHoodieWriteClient` and 
then issues a replace-commit via `startDeletePartitionCommit`/`commit`, so it 
mutates the MDT with exactly the same exposure as clean/clustering — that one 
should be a one-line addition.
   
   The rollback/restore family (`RollbackToInstantTimeProcedure`, 
`RestoreToInstantProcedure`, `RunRollbackInflightTableServiceProcedure`) also 
writes MDT, but they pass `Map.empty` today, so they'd need a `confs` 
plumb-through first — probably fine to leave to a follow-up if you want to keep 
this PR scoped.



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