From 3b30730ec324e5e4386093575f41959c264960a9 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Sun, 16 Nov 2025 21:41:22 +0100 Subject: [PATCH 01/11] Reproducer --- ...ResolveTransitiveDependenciesParallel.java | 180 ++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java diff --git a/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java b/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java new file mode 100644 index 000000000..116830156 --- /dev/null +++ b/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java @@ -0,0 +1,180 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.maven.resolver.examples; + +import java.util.List; +import java.util.concurrent.CountDownLatch; + +import org.apache.maven.resolver.examples.util.Booter; +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.artifact.DefaultArtifact; +import org.eclipse.aether.collection.CollectRequest; +import org.eclipse.aether.graph.Dependency; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.resolution.ArtifactResult; +import org.eclipse.aether.resolution.DependencyRequest; +import org.eclipse.aether.util.artifact.JavaScopes; + +/** + * Resolves the transitive (compile) dependencies of an artifact. + */ +public class ResolveTransitiveDependenciesParallel { + + /** + * Main. + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println("------------------------------------------------------------"); + System.out.println(ResolveTransitiveDependencies.class.getSimpleName()); + + System.setProperty("aether.syncContext.named.time", "3"); + + RepositorySystem system = Booter.newRepositorySystem(Booter.selectFactory(args)); + + RepositorySystemSession session = Booter.newRepositorySystemSession(system); + + Artifact bigArtifact1 = new DefaultArtifact("org.bytedeco:llvm:jar:linux-arm64:16.0.4-1.5.9"); + Artifact bigArtifact2 = new DefaultArtifact("org.bytedeco:llvm:jar:linux-armhf:16.0.4-1.5.9"); + Artifact bigArtifact3 = new DefaultArtifact("org.bytedeco:llvm:jar:linux-ppc64le:16.0.4-1.5.9"); + Artifact bigArtifact4 = new DefaultArtifact("org.bytedeco:llvm:jar:linux-x86:16.0.4-1.5.9"); + Artifact bigArtifact5 = new DefaultArtifact("org.bytedeco:llvm:jar:linux-x86_64:16.0.4-1.5.9"); + Artifact bigArtifact6 = new DefaultArtifact("org.bytedeco:llvm:jar:macosx-arm64:16.0.4-1.5.9"); + Artifact bigArtifact7 = new DefaultArtifact("org.bytedeco:llvm:jar:macosx-x86_64:16.0.4-1.5.9"); + Artifact bigArtifact8 = new DefaultArtifact("org.bytedeco:llvm:jar:windows_x86:16.0.4-1.5.9"); + Artifact bigArtifact9 = new DefaultArtifact("org.bytedeco:llvm:jar:windows_x86)64:16.0.4-1.5.9"); + + CountDownLatch latch = new CountDownLatch(8); + + Thread thread1 = new Thread(resolveWithDependencies( + latch, + system, + session, + Booter.newRepositories(system, session), + "org.example:test:1", + bigArtifact1, + bigArtifact2)); + Thread thread2 = new Thread(resolveWithDependencies( + latch, + system, + session, + Booter.newRepositories(system, session), + "org.example:test:2", + bigArtifact2, + bigArtifact3)); + Thread thread3 = new Thread(resolveWithDependencies( + latch, + system, + session, + Booter.newRepositories(system, session), + "org.example:test:3", + bigArtifact3, + bigArtifact4)); + Thread thread4 = new Thread(resolveWithDependencies( + latch, + system, + session, + Booter.newRepositories(system, session), + "org.example:test:4", + bigArtifact4, + bigArtifact5)); + Thread thread5 = new Thread(resolveWithDependencies( + latch, + system, + session, + Booter.newRepositories(system, session), + "org.example:test:5", + bigArtifact5, + bigArtifact6)); + Thread thread6 = new Thread(resolveWithDependencies( + latch, + system, + session, + Booter.newRepositories(system, session), + "org.example:test:6", + bigArtifact6, + bigArtifact7)); + Thread thread7 = new Thread(resolveWithDependencies( + latch, + system, + session, + Booter.newRepositories(system, session), + "org.example:test:7", + bigArtifact7, + bigArtifact8)); + Thread thread8 = new Thread(resolveWithDependencies( + latch, + system, + session, + Booter.newRepositories(system, session), + "org.example:test:8", + bigArtifact8, + bigArtifact9)); + + thread1.start(); + thread2.start(); + thread3.start(); + thread4.start(); + thread5.start(); + thread6.start(); + thread7.start(); + thread8.start(); + + latch.await(); + } + + private static Runnable resolveWithDependencies( + CountDownLatch latch, + RepositorySystem system, + RepositorySystemSession session, + List repositories, + String gav, + Artifact... deps) { + return () -> { + try { + CollectRequest collectRequest = new CollectRequest(); + collectRequest.setRootArtifact(new DefaultArtifact(gav)); + for (Artifact dep : deps) { + collectRequest.addDependency(new Dependency(dep, JavaScopes.COMPILE)); + } + collectRequest.setRepositories(repositories); + DependencyRequest dependencyRequest = new DependencyRequest(collectRequest, null); + List artifactResults = + system.resolveDependencies(session, dependencyRequest).getArtifactResults(); + int resolved = 9; + int fails = 0; + for (ArtifactResult artifactResult : artifactResults) { + if (artifactResult.isResolved()) { + resolved++; + } else { + fails++; + } + } + System.out.println(gav + ": resolved " + resolved + "; failed " + fails); + } catch (Exception e) { + e.printStackTrace(System.out); + } finally { + latch.countDown(); + } + }; + } +} From a41c592aabbe656a37ee0737c3e51cab5dd0b3c9 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Sun, 16 Nov 2025 21:56:16 +0100 Subject: [PATCH 02/11] Fixes --- ...ResolveTransitiveDependenciesParallel.java | 37 ++++++++++++++++--- .../maven/resolver/examples/util/Booter.java | 1 + 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java b/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java index 116830156..824909d76 100644 --- a/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java +++ b/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java @@ -20,8 +20,10 @@ import java.util.List; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicInteger; import org.apache.maven.resolver.examples.util.Booter; +import org.eclipse.aether.DefaultRepositorySystemSession; import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.artifact.Artifact; @@ -51,7 +53,8 @@ public static void main(String[] args) throws Exception { RepositorySystem system = Booter.newRepositorySystem(Booter.selectFactory(args)); - RepositorySystemSession session = Booter.newRepositorySystemSession(system); + DefaultRepositorySystemSession session = Booter.newRepositorySystemSession(system); + session.setTransferListener(null); Artifact bigArtifact1 = new DefaultArtifact("org.bytedeco:llvm:jar:linux-arm64:16.0.4-1.5.9"); Artifact bigArtifact2 = new DefaultArtifact("org.bytedeco:llvm:jar:linux-armhf:16.0.4-1.5.9"); @@ -60,13 +63,17 @@ public static void main(String[] args) throws Exception { Artifact bigArtifact5 = new DefaultArtifact("org.bytedeco:llvm:jar:linux-x86_64:16.0.4-1.5.9"); Artifact bigArtifact6 = new DefaultArtifact("org.bytedeco:llvm:jar:macosx-arm64:16.0.4-1.5.9"); Artifact bigArtifact7 = new DefaultArtifact("org.bytedeco:llvm:jar:macosx-x86_64:16.0.4-1.5.9"); - Artifact bigArtifact8 = new DefaultArtifact("org.bytedeco:llvm:jar:windows_x86:16.0.4-1.5.9"); - Artifact bigArtifact9 = new DefaultArtifact("org.bytedeco:llvm:jar:windows_x86)64:16.0.4-1.5.9"); + Artifact bigArtifact8 = new DefaultArtifact("org.bytedeco:llvm:jar:windows-x86:16.0.4-1.5.9"); + Artifact bigArtifact9 = new DefaultArtifact("org.bytedeco:llvm:jar:windows-x86_64:16.0.4-1.5.9"); CountDownLatch latch = new CountDownLatch(8); + AtomicInteger success = new AtomicInteger(0); + AtomicInteger fail = new AtomicInteger(0); Thread thread1 = new Thread(resolveWithDependencies( latch, + success, + fail, system, session, Booter.newRepositories(system, session), @@ -75,6 +82,8 @@ public static void main(String[] args) throws Exception { bigArtifact2)); Thread thread2 = new Thread(resolveWithDependencies( latch, + success, + fail, system, session, Booter.newRepositories(system, session), @@ -83,6 +92,8 @@ public static void main(String[] args) throws Exception { bigArtifact3)); Thread thread3 = new Thread(resolveWithDependencies( latch, + success, + fail, system, session, Booter.newRepositories(system, session), @@ -91,6 +102,8 @@ public static void main(String[] args) throws Exception { bigArtifact4)); Thread thread4 = new Thread(resolveWithDependencies( latch, + success, + fail, system, session, Booter.newRepositories(system, session), @@ -99,6 +112,8 @@ public static void main(String[] args) throws Exception { bigArtifact5)); Thread thread5 = new Thread(resolveWithDependencies( latch, + success, + fail, system, session, Booter.newRepositories(system, session), @@ -107,6 +122,8 @@ public static void main(String[] args) throws Exception { bigArtifact6)); Thread thread6 = new Thread(resolveWithDependencies( latch, + success, + fail, system, session, Booter.newRepositories(system, session), @@ -115,6 +132,8 @@ public static void main(String[] args) throws Exception { bigArtifact7)); Thread thread7 = new Thread(resolveWithDependencies( latch, + success, + fail, system, session, Booter.newRepositories(system, session), @@ -123,6 +142,8 @@ public static void main(String[] args) throws Exception { bigArtifact8)); Thread thread8 = new Thread(resolveWithDependencies( latch, + success, + fail, system, session, Booter.newRepositories(system, session), @@ -140,10 +161,14 @@ public static void main(String[] args) throws Exception { thread8.start(); latch.await(); + + System.out.println("TOTAL success=" + success.get() + "; fail=" + fail.get()); } private static Runnable resolveWithDependencies( CountDownLatch latch, + AtomicInteger success, + AtomicInteger fail, RepositorySystem system, RepositorySystemSession session, List repositories, @@ -169,9 +194,11 @@ private static Runnable resolveWithDependencies( fails++; } } - System.out.println(gav + ": resolved " + resolved + "; failed " + fails); + System.out.println("DONE " + gav + ": resolved " + resolved + "; failed " + fails); + success.getAndIncrement(); } catch (Exception e) { - e.printStackTrace(System.out); + System.out.println("FAILED " + gav + ": " + e.getMessage()); + fail.getAndIncrement(); } finally { latch.countDown(); } diff --git a/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/util/Booter.java b/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/util/Booter.java index e650786d6..72eac9607 100644 --- a/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/util/Booter.java +++ b/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/util/Booter.java @@ -70,6 +70,7 @@ public static RepositorySystem newRepositorySystem(final String factory) { public static DefaultRepositorySystemSession newRepositorySystemSession(RepositorySystem system) { DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession(); + session.setSystemProperties(System.getProperties()); LocalRepository localRepo = new LocalRepository("target/local-repo"); session.setLocalRepositoryManager(system.newLocalRepositoryManager(session, localRepo)); From d5d2a45d2d95eac8483bc975c7ff17a5f1d6926b Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Sun, 16 Nov 2025 22:12:06 +0100 Subject: [PATCH 03/11] Improve message --- .../examples/ResolveTransitiveDependenciesParallel.java | 5 +++-- .../impl/synccontext/named/NamedLockFactoryAdapter.java | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java b/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java index 824909d76..514cfc8c3 100644 --- a/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java +++ b/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java @@ -49,12 +49,12 @@ public static void main(String[] args) throws Exception { System.out.println("------------------------------------------------------------"); System.out.println(ResolveTransitiveDependencies.class.getSimpleName()); - System.setProperty("aether.syncContext.named.time", "3"); - RepositorySystem system = Booter.newRepositorySystem(Booter.selectFactory(args)); DefaultRepositorySystemSession session = Booter.newRepositorySystemSession(system); + session.setConfigProperty("aether.syncContext.named.time", "3"); session.setTransferListener(null); + session.setRepositoryListener(null); Artifact bigArtifact1 = new DefaultArtifact("org.bytedeco:llvm:jar:linux-arm64:16.0.4-1.5.9"); Artifact bigArtifact2 = new DefaultArtifact("org.bytedeco:llvm:jar:linux-armhf:16.0.4-1.5.9"); @@ -162,6 +162,7 @@ public static void main(String[] args) throws Exception { latch.await(); + System.out.println("====="); System.out.println("TOTAL success=" + success.get() + "; fail=" + fail.get()); } diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactoryAdapter.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactoryAdapter.java index 7a608c95d..b53b09fd5 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactoryAdapter.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactoryAdapter.java @@ -216,7 +216,8 @@ public void acquire(Collection artifacts, Collection Date: Sun, 16 Nov 2025 22:49:36 +0100 Subject: [PATCH 04/11] WIP --- ...ResolveTransitiveDependenciesParallel.java | 1 + .../impl/DefaultArtifactResolver.java | 59 +++++++++++++------ 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java b/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java index 514cfc8c3..78c68b503 100644 --- a/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java +++ b/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java @@ -31,6 +31,7 @@ import org.eclipse.aether.collection.CollectRequest; import org.eclipse.aether.graph.Dependency; import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.resolution.ArtifactRequest; import org.eclipse.aether.resolution.ArtifactResult; import org.eclipse.aether.resolution.DependencyRequest; import org.eclipse.aether.util.artifact.JavaScopes; diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultArtifactResolver.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultArtifactResolver.java index 044302461..2b96a2a4f 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultArtifactResolver.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultArtifactResolver.java @@ -27,10 +27,12 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Supplier; import org.eclipse.aether.RepositoryEvent; import org.eclipse.aether.RepositoryEvent.EventType; @@ -248,32 +250,44 @@ public List resolveArtifacts( throws ArtifactResolutionException { requireNonNull(session, "session cannot be null"); requireNonNull(requests, "requests cannot be null"); - try (SyncContext shared = syncContextFactory.newInstance(session, true); - SyncContext exclusive = syncContextFactory.newInstance(session, false)) { - Collection artifacts = new ArrayList<>(requests.size()); - for (ArtifactRequest request : requests) { - if (request.getArtifact().getProperty(ArtifactProperties.LOCAL_PATH, null) != null) { - continue; - } - artifacts.add(request.getArtifact()); + Collection artifacts = new ArrayList<>(requests.size()); + for (ArtifactRequest request : requests) { + if (request.getArtifact().getProperty(ArtifactProperties.LOCAL_PATH, null) != null) { + continue; } - - return resolve(shared, exclusive, artifacts, session, requests); + artifacts.add(request.getArtifact()); } + + return resolve( + () -> syncContextFactory.newInstance(session, true), + () -> syncContextFactory.newInstance(session, false), + artifacts, + session, + requests); } @SuppressWarnings("checkstyle:methodlength") private List resolve( - SyncContext shared, - SyncContext exclusive, + Supplier sharedSupplier, + Supplier exclusiveSupplier, Collection subjects, RepositorySystemSession session, Collection requests) throws ArtifactResolutionException { - SyncContext current = shared; + HashSet needShared = new HashSet<>(subjects); + HashSet needExclusive = new HashSet<>(); + boolean firstAttempt = true; + SyncContext sharedContext = null; + SyncContext exclusiveContext = null; try { while (true) { - current.acquire(subjects, null); + boolean relock = false; + sharedContext = sharedSupplier.get(); + exclusiveContext = exclusiveSupplier.get(); + sharedContext.acquire(needShared, null); + exclusiveContext.acquire(needExclusive, null); + + LOGGER.info("S={}, X={}", needShared, needExclusive); boolean failures = false; final List results = new ArrayList<>(requests.size()); @@ -292,7 +306,7 @@ private List resolve( Artifact artifact = request.getArtifact(); - if (current == shared) { + if (firstAttempt) { artifactResolving(session, trace, artifact); } @@ -400,6 +414,11 @@ private List resolve( remoteRepositories); } + if (needExclusive.add(artifact)) { + needShared.remove(artifact); + relock = true; + } + LOGGER.debug("Resolving artifact {} from {}", artifact, remoteRepositories); AtomicBoolean resolved = new AtomicBoolean(false); Iterator groupIt = groups.iterator(); @@ -439,9 +458,10 @@ private List resolve( } } - if (!groups.isEmpty() && current == shared) { - current.close(); - current = exclusive; + if (relock) { + firstAttempt = false; + exclusiveContext.close(); + sharedContext.close(); continue; } @@ -476,7 +496,8 @@ private List resolve( return results; } } finally { - current.close(); + exclusiveContext.close(); + sharedContext.close(); } } From 9c6d4eddeb89bec6dafae6e5b7055b3aebabae7e Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Sun, 16 Nov 2025 22:53:19 +0100 Subject: [PATCH 05/11] Fix chkstyle --- .../resolver/examples/ResolveTransitiveDependenciesParallel.java | 1 + 1 file changed, 1 insertion(+) diff --git a/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java b/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java index 78c68b503..f9f8d6410 100644 --- a/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java +++ b/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java @@ -167,6 +167,7 @@ public static void main(String[] args) throws Exception { System.out.println("TOTAL success=" + success.get() + "; fail=" + fail.get()); } + @SuppressWarnings("checkstyle:parameternumber") private static Runnable resolveWithDependencies( CountDownLatch latch, AtomicInteger success, From 1783977c5ec10ed24d1ec7dae3523c0817e98ecc Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Mon, 17 Nov 2025 10:36:09 +0100 Subject: [PATCH 06/11] WIP --- .../resolver/examples/ResolveTransitiveDependenciesParallel.java | 1 - 1 file changed, 1 deletion(-) diff --git a/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java b/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java index f9f8d6410..056c40b6c 100644 --- a/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java +++ b/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java @@ -31,7 +31,6 @@ import org.eclipse.aether.collection.CollectRequest; import org.eclipse.aether.graph.Dependency; import org.eclipse.aether.repository.RemoteRepository; -import org.eclipse.aether.resolution.ArtifactRequest; import org.eclipse.aether.resolution.ArtifactResult; import org.eclipse.aether.resolution.DependencyRequest; import org.eclipse.aether.util.artifact.JavaScopes; From bb3e5eefd14bcc2583396ec4ca1fa6e260fcbe80 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Mon, 17 Nov 2025 10:37:07 +0100 Subject: [PATCH 07/11] Drop unrelated --- .../java/org/apache/maven/resolver/examples/util/Booter.java | 1 - 1 file changed, 1 deletion(-) diff --git a/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/util/Booter.java b/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/util/Booter.java index 72eac9607..e650786d6 100644 --- a/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/util/Booter.java +++ b/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/util/Booter.java @@ -70,7 +70,6 @@ public static RepositorySystem newRepositorySystem(final String factory) { public static DefaultRepositorySystemSession newRepositorySystemSession(RepositorySystem system) { DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession(); - session.setSystemProperties(System.getProperties()); LocalRepository localRepo = new LocalRepository("target/local-repo"); session.setLocalRepositoryManager(system.newLocalRepositoryManager(session, localRepo)); From 72026b8ef55e1841321759b9b826892d2fb82570 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Mon, 17 Nov 2025 10:53:26 +0100 Subject: [PATCH 08/11] Revert unrelated --- .../impl/DefaultArtifactResolver.java | 59 ++++++------------- .../named/NamedLockFactoryAdapter.java | 3 +- 2 files changed, 20 insertions(+), 42 deletions(-) diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultArtifactResolver.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultArtifactResolver.java index 2b96a2a4f..044302461 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultArtifactResolver.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultArtifactResolver.java @@ -27,12 +27,10 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Supplier; import org.eclipse.aether.RepositoryEvent; import org.eclipse.aether.RepositoryEvent.EventType; @@ -250,44 +248,32 @@ public List resolveArtifacts( throws ArtifactResolutionException { requireNonNull(session, "session cannot be null"); requireNonNull(requests, "requests cannot be null"); - Collection artifacts = new ArrayList<>(requests.size()); - for (ArtifactRequest request : requests) { - if (request.getArtifact().getProperty(ArtifactProperties.LOCAL_PATH, null) != null) { - continue; + try (SyncContext shared = syncContextFactory.newInstance(session, true); + SyncContext exclusive = syncContextFactory.newInstance(session, false)) { + Collection artifacts = new ArrayList<>(requests.size()); + for (ArtifactRequest request : requests) { + if (request.getArtifact().getProperty(ArtifactProperties.LOCAL_PATH, null) != null) { + continue; + } + artifacts.add(request.getArtifact()); } - artifacts.add(request.getArtifact()); - } - return resolve( - () -> syncContextFactory.newInstance(session, true), - () -> syncContextFactory.newInstance(session, false), - artifacts, - session, - requests); + return resolve(shared, exclusive, artifacts, session, requests); + } } @SuppressWarnings("checkstyle:methodlength") private List resolve( - Supplier sharedSupplier, - Supplier exclusiveSupplier, + SyncContext shared, + SyncContext exclusive, Collection subjects, RepositorySystemSession session, Collection requests) throws ArtifactResolutionException { - HashSet needShared = new HashSet<>(subjects); - HashSet needExclusive = new HashSet<>(); - boolean firstAttempt = true; - SyncContext sharedContext = null; - SyncContext exclusiveContext = null; + SyncContext current = shared; try { while (true) { - boolean relock = false; - sharedContext = sharedSupplier.get(); - exclusiveContext = exclusiveSupplier.get(); - sharedContext.acquire(needShared, null); - exclusiveContext.acquire(needExclusive, null); - - LOGGER.info("S={}, X={}", needShared, needExclusive); + current.acquire(subjects, null); boolean failures = false; final List results = new ArrayList<>(requests.size()); @@ -306,7 +292,7 @@ private List resolve( Artifact artifact = request.getArtifact(); - if (firstAttempt) { + if (current == shared) { artifactResolving(session, trace, artifact); } @@ -414,11 +400,6 @@ private List resolve( remoteRepositories); } - if (needExclusive.add(artifact)) { - needShared.remove(artifact); - relock = true; - } - LOGGER.debug("Resolving artifact {} from {}", artifact, remoteRepositories); AtomicBoolean resolved = new AtomicBoolean(false); Iterator groupIt = groups.iterator(); @@ -458,10 +439,9 @@ private List resolve( } } - if (relock) { - firstAttempt = false; - exclusiveContext.close(); - sharedContext.close(); + if (!groups.isEmpty() && current == shared) { + current.close(); + current = exclusive; continue; } @@ -496,8 +476,7 @@ private List resolve( return results; } } finally { - exclusiveContext.close(); - sharedContext.close(); + current.close(); } } diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactoryAdapter.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactoryAdapter.java index b53b09fd5..7a608c95d 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactoryAdapter.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactoryAdapter.java @@ -216,8 +216,7 @@ public void acquire(Collection artifacts, Collection Date: Mon, 17 Nov 2025 12:57:55 +0100 Subject: [PATCH 09/11] Add more to reproducer --- ...ResolveTransitiveDependenciesParallel.java | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java b/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java index 056c40b6c..4bcdfc745 100644 --- a/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java +++ b/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java @@ -18,6 +18,9 @@ */ package org.apache.maven.resolver.examples; +import java.time.Duration; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; @@ -51,8 +54,27 @@ public static void main(String[] args) throws Exception { RepositorySystem system = Booter.newRepositorySystem(Booter.selectFactory(args)); + // note: these numbers below are not "universal", they stand for one given WS with one given network, + // and they may need change with time if anything changes in relation (even remote like Central!) + // + // cstamas (DK HW+net) 17. 11. 2025 (w/ empty local repo) + // One job is done in 20 sec + // BUT other must wait as they are serialized (time adds up) + // reproducer to succeed: 210 sec + // my run: + // DONE (21 sec): org.example:test:1: resolved 11; failed 0 + // DONE (37 sec): org.example:test:6: resolved 11; failed 0 + // DONE (60 sec): org.example:test:4: resolved 11; failed 0 + // DONE (60 sec): org.example:test:5: resolved 11; failed 0 + // DONE (170 sec): org.example:test:8: resolved 11; failed 0 + // DONE (181 sec): org.example:test:3: resolved 11; failed 0 + // DONE (181 sec): org.example:test:7: resolved 11; failed 0 + // DONE (181 sec): org.example:test:2: resolved 11; failed 0 + // ===== + // TOTAL success=8; fail=0 + DefaultRepositorySystemSession session = Booter.newRepositorySystemSession(system); - session.setConfigProperty("aether.syncContext.named.time", "3"); + session.setConfigProperty("aether.syncContext.named.time", "210"); session.setTransferListener(null); session.setRepositoryListener(null); @@ -178,6 +200,7 @@ private static Runnable resolveWithDependencies( Artifact... deps) { return () -> { try { + Instant now = Instant.now(); CollectRequest collectRequest = new CollectRequest(); collectRequest.setRootArtifact(new DefaultArtifact(gav)); for (Artifact dep : deps) { @@ -196,7 +219,8 @@ private static Runnable resolveWithDependencies( fails++; } } - System.out.println("DONE " + gav + ": resolved " + resolved + "; failed " + fails); + String dur = Duration.between(now, Instant.now()).get(ChronoUnit.SECONDS) + " sec"; + System.out.println("DONE (" + dur + "): " + gav + ": resolved " + resolved + "; failed " + fails); success.getAndIncrement(); } catch (Exception e) { System.out.println("FAILED " + gav + ": " + e.getMessage()); From d7d65eb47e7260e5f1a4a2159fed5e63b2bb4271 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Mon, 17 Nov 2025 13:24:03 +0100 Subject: [PATCH 10/11] Add comments --- .../examples/ResolveTransitiveDependenciesParallel.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java b/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java index 4bcdfc745..dba71232f 100644 --- a/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java +++ b/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples/ResolveTransitiveDependenciesParallel.java @@ -39,7 +39,9 @@ import org.eclipse.aether.util.artifact.JavaScopes; /** - * Resolves the transitive (compile) dependencies of an artifact. + * Resolves the transitive (compile) LARGE dependencies of an imaginary artifact in parallel. + * This is the reproducer for locking issues: