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

cstamas pushed a commit to branch maven-resolver-1.9.x
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git


The following commit(s) were added to refs/heads/maven-resolver-1.9.x by this 
push:
     new 7b41467ce Sync TrackingFileManager with 2.x (#1802)
7b41467ce is described below

commit 7b41467ce4318a2e14b8ca087e32118b49dc01ab
Author: Tamas Cservenak <[email protected]>
AuthorDate: Fri Feb 20 13:19:38 2026 +0100

    Sync TrackingFileManager with 2.x (#1802)
    
    Backport all the changes from 2.x to 1.x
---
 .../internal/impl/DefaultTrackingFileManager.java  | 37 +++++++++++++++++++---
 1 file changed, 33 insertions(+), 4 deletions(-)

diff --git 
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultTrackingFileManager.java
 
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultTrackingFileManager.java
index 7076f38f7..83785ef47 100644
--- 
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultTrackingFileManager.java
+++ 
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultTrackingFileManager.java
@@ -140,10 +140,28 @@ public final class DefaultTrackingFileManager implements 
TrackingFileManager {
         return false;
     }
 
-    private Object mutex(Path path) {
+    /**
+     * This method creates a "mutex" object to synchronize on thread level, 
within same JVM, to prevent multiple
+     * threads from trying to lock the same file at the same time. Threads 
concurrently working on different files
+     * are okay, as after syncing on mutex, they operate with FS locking, that 
goal is to synchronize with possible
+     * other Maven processes, and not with other threads in this JVM.
+     */
+    private static Object mutex(Path path) {
         // The interned string of path is (mis)used as mutex, to exclude 
different threads going for same file,
         // as JVM file locking happens on JVM not on Thread level. This is how 
original code did it  ¯\_(ツ)_/¯
-        return path.toAbsolutePath().normalize().toString().intern();
+        return canonicalPath(path).toString().intern();
+    }
+
+    /**
+     * Tries the best it can to figure out actual file the workload is about, 
while resolving cases like symlinked
+     * local repository etc.
+     */
+    private static Path canonicalPath(Path path) {
+        try {
+            return path.toRealPath();
+        } catch (IOException e) {
+            return canonicalPath(path.getParent()).resolve(path.getFileName());
+        }
     }
 
     private FileLock fileLock(FileChannel channel, boolean shared) throws 
IOException {
@@ -152,9 +170,20 @@ public final class DefaultTrackingFileManager implements 
TrackingFileManager {
             try {
                 lock = channel.lock(0, Long.MAX_VALUE, shared);
                 break;
-            } catch (OverlappingFileLockException e) {
+            } catch (OverlappingFileLockException | IOException e) {
+                // For Unix process sun.nio.ch.UnixFileDispatcherImpl.lock0() 
is a native method that can throw
+                // IOException with message "Resource deadlock avoided"
+                // the system call level is involving fcntl() or flock()
+                // If the kernel detects that granting the lock would result 
in a deadlock
+                // (where two processes are waiting for each other to release 
locks which can happen when two processes
+                // are trying to lock the same file),
+                // it returns an EDEADLK error, which Java throws as an 
IOException.
+                // Read another comment from
+                // 
https://github.com/bdeployteam/bdeploy/blob/7c04e7228d6d48b8990e6703a8d476e21024c639/bhive/src/main/java/io/bdeploy/bhive/objects/LockableDatabase.java#L57
+                // Note (cstamas): seems this MAY also happen where there is 
ONE process but performs locking on same
+                // file from multiple threads, as Linux kernel performs lock 
detection on process level.
                 if (attempts <= 0) {
-                    throw new IOException(e);
+                    throw (e instanceof IOException) ? (IOException) e : new 
IOException(e);
                 }
                 try {
                     Thread.sleep(50L);

Reply via email to