Skip to content

Commit 9e07b1b

Browse files
authored
Maven Resolver lockrepro (#1665)
Reproducer for Resolver 2.x. Does not run as part of test/build, is meant to be ad-hoc be run from IDE.
1 parent c47d48d commit 9e07b1b

File tree

1 file changed

+238
-0
lines changed

1 file changed

+238
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.maven.resolver.examples;
20+
21+
import java.time.Duration;
22+
import java.time.Instant;
23+
import java.time.temporal.ChronoUnit;
24+
import java.util.List;
25+
import java.util.concurrent.CountDownLatch;
26+
import java.util.concurrent.atomic.AtomicInteger;
27+
28+
import org.apache.maven.resolver.examples.util.Booter;
29+
import org.eclipse.aether.RepositorySystem;
30+
import org.eclipse.aether.RepositorySystemSession;
31+
import org.eclipse.aether.RepositorySystemSession.CloseableSession;
32+
import org.eclipse.aether.artifact.Artifact;
33+
import org.eclipse.aether.artifact.DefaultArtifact;
34+
import org.eclipse.aether.collection.CollectRequest;
35+
import org.eclipse.aether.graph.Dependency;
36+
import org.eclipse.aether.repository.RemoteRepository;
37+
import org.eclipse.aether.resolution.ArtifactResult;
38+
import org.eclipse.aether.resolution.DependencyRequest;
39+
import org.eclipse.aether.util.artifact.JavaScopes;
40+
41+
/**
42+
* Resolves the transitive (compile) LARGE dependencies of an imaginary artifact in parallel.
43+
* This is the reproducer for locking issues: <a href="https://github.com/apache/maven-resolver/issues/1644>GH-1644</a>
44+
* This code does NOT run as part of build/tests, it is meant to be ad-hoc run from IDE or alike. */
45+
public class ResolveTransitiveDependenciesParallel {
46+
47+
/**
48+
* Main.
49+
* @param args
50+
* @throws Exception
51+
*/
52+
public static void main(String[] args) throws Exception {
53+
System.out.println("------------------------------------------------------------");
54+
System.out.println(ResolveTransitiveDependenciesParallel.class.getSimpleName());
55+
56+
// note: these numbers below are not "universal", they stand for one given WS with one given network,
57+
// and they may need change with time if anything changes in relation (even remote like Central!)
58+
//
59+
// cstamas (DK HW+net) 17. 11. 2025 (w/ empty local repo)
60+
// One job is done in 20 sec
61+
// BUT other must wait as they are serialized (time adds up)
62+
// reproducer to succeed: 210 sec
63+
// my run:
64+
// DONE (21 sec): org.example:test:1: resolved 11; failed 0
65+
// DONE (37 sec): org.example:test:6: resolved 11; failed 0
66+
// DONE (60 sec): org.example:test:4: resolved 11; failed 0
67+
// DONE (60 sec): org.example:test:5: resolved 11; failed 0
68+
// DONE (170 sec): org.example:test:8: resolved 11; failed 0
69+
// DONE (181 sec): org.example:test:3: resolved 11; failed 0
70+
// DONE (181 sec): org.example:test:7: resolved 11; failed 0
71+
// DONE (181 sec): org.example:test:2: resolved 11; failed 0
72+
// =====
73+
// TOTAL success=8; fail=0
74+
//
75+
// Pattern: as said above, one job does in 20 sec, BUT subsequent one will do it in cca 40 sec (waiting 20 sec)
76+
// and so on, the times are adding up. Each subsequent job with start by waiting for previous jobs to finish
77+
// due (intentional) artifact overlaps.
78+
79+
try (RepositorySystem system = Booter.newRepositorySystem(Booter.selectFactory(args));
80+
CloseableSession session = Booter.newRepositorySystemSession(system, Booter.selectFs(args))
81+
.setTransferListener(null)
82+
.setRepositoryListener(null)
83+
.setConfigProperty("aether.syncContext.named.time", "210")
84+
.build()) {
85+
Artifact bigArtifact1 = new DefaultArtifact("org.bytedeco:llvm:jar:linux-arm64:16.0.4-1.5.9");
86+
Artifact bigArtifact2 = new DefaultArtifact("org.bytedeco:llvm:jar:linux-armhf:16.0.4-1.5.9");
87+
Artifact bigArtifact3 = new DefaultArtifact("org.bytedeco:llvm:jar:linux-ppc64le:16.0.4-1.5.9");
88+
Artifact bigArtifact4 = new DefaultArtifact("org.bytedeco:llvm:jar:linux-x86:16.0.4-1.5.9");
89+
Artifact bigArtifact5 = new DefaultArtifact("org.bytedeco:llvm:jar:linux-x86_64:16.0.4-1.5.9");
90+
Artifact bigArtifact6 = new DefaultArtifact("org.bytedeco:llvm:jar:macosx-arm64:16.0.4-1.5.9");
91+
Artifact bigArtifact7 = new DefaultArtifact("org.bytedeco:llvm:jar:macosx-x86_64:16.0.4-1.5.9");
92+
Artifact bigArtifact8 = new DefaultArtifact("org.bytedeco:llvm:jar:windows-x86:16.0.4-1.5.9");
93+
Artifact bigArtifact9 = new DefaultArtifact("org.bytedeco:llvm:jar:windows-x86_64:16.0.4-1.5.9");
94+
95+
CountDownLatch latch = new CountDownLatch(8);
96+
AtomicInteger success = new AtomicInteger(0);
97+
AtomicInteger fail = new AtomicInteger(0);
98+
99+
Thread thread1 = new Thread(resolveWithDependencies(
100+
latch,
101+
success,
102+
fail,
103+
system,
104+
session,
105+
Booter.newRepositories(system, session),
106+
"org.example:test:1",
107+
bigArtifact1,
108+
bigArtifact2));
109+
Thread thread2 = new Thread(resolveWithDependencies(
110+
latch,
111+
success,
112+
fail,
113+
system,
114+
session,
115+
Booter.newRepositories(system, session),
116+
"org.example:test:2",
117+
bigArtifact2,
118+
bigArtifact3));
119+
Thread thread3 = new Thread(resolveWithDependencies(
120+
latch,
121+
success,
122+
fail,
123+
system,
124+
session,
125+
Booter.newRepositories(system, session),
126+
"org.example:test:3",
127+
bigArtifact3,
128+
bigArtifact4));
129+
Thread thread4 = new Thread(resolveWithDependencies(
130+
latch,
131+
success,
132+
fail,
133+
system,
134+
session,
135+
Booter.newRepositories(system, session),
136+
"org.example:test:4",
137+
bigArtifact4,
138+
bigArtifact5));
139+
Thread thread5 = new Thread(resolveWithDependencies(
140+
latch,
141+
success,
142+
fail,
143+
system,
144+
session,
145+
Booter.newRepositories(system, session),
146+
"org.example:test:5",
147+
bigArtifact5,
148+
bigArtifact6));
149+
Thread thread6 = new Thread(resolveWithDependencies(
150+
latch,
151+
success,
152+
fail,
153+
system,
154+
session,
155+
Booter.newRepositories(system, session),
156+
"org.example:test:6",
157+
bigArtifact6,
158+
bigArtifact7));
159+
Thread thread7 = new Thread(resolveWithDependencies(
160+
latch,
161+
success,
162+
fail,
163+
system,
164+
session,
165+
Booter.newRepositories(system, session),
166+
"org.example:test:7",
167+
bigArtifact7,
168+
bigArtifact8));
169+
Thread thread8 = new Thread(resolveWithDependencies(
170+
latch,
171+
success,
172+
fail,
173+
system,
174+
session,
175+
Booter.newRepositories(system, session),
176+
"org.example:test:8",
177+
bigArtifact8,
178+
bigArtifact9));
179+
180+
thread1.start();
181+
thread2.start();
182+
thread3.start();
183+
thread4.start();
184+
thread5.start();
185+
thread6.start();
186+
thread7.start();
187+
thread8.start();
188+
189+
latch.await();
190+
191+
System.out.println("=====");
192+
System.out.println("TOTAL success=" + success.get() + "; fail=" + fail.get());
193+
}
194+
}
195+
196+
@SuppressWarnings("checkstyle:parameternumber")
197+
private static Runnable resolveWithDependencies(
198+
CountDownLatch latch,
199+
AtomicInteger success,
200+
AtomicInteger fail,
201+
RepositorySystem system,
202+
RepositorySystemSession session,
203+
List<RemoteRepository> repositories,
204+
String gav,
205+
Artifact... deps) {
206+
return () -> {
207+
try {
208+
Instant now = Instant.now();
209+
CollectRequest collectRequest = new CollectRequest();
210+
collectRequest.setRootArtifact(new DefaultArtifact(gav));
211+
for (Artifact dep : deps) {
212+
collectRequest.addDependency(new Dependency(dep, JavaScopes.COMPILE));
213+
}
214+
collectRequest.setRepositories(repositories);
215+
DependencyRequest dependencyRequest = new DependencyRequest(collectRequest, null);
216+
List<ArtifactResult> artifactResults =
217+
system.resolveDependencies(session, dependencyRequest).getArtifactResults();
218+
int resolved = 0;
219+
int fails = 0;
220+
for (ArtifactResult artifactResult : artifactResults) {
221+
if (artifactResult.isResolved()) {
222+
resolved++;
223+
} else {
224+
fails++;
225+
}
226+
}
227+
String dur = Duration.between(now, Instant.now()).get(ChronoUnit.SECONDS) + " sec";
228+
System.out.println("DONE (" + dur + "): " + gav + ": resolved " + resolved + "; failed " + fails);
229+
success.getAndIncrement();
230+
} catch (Exception e) {
231+
System.out.println("FAILED " + gav + ": " + e.getMessage());
232+
fail.getAndIncrement();
233+
} finally {
234+
latch.countDown();
235+
}
236+
};
237+
}
238+
}

0 commit comments

Comments
 (0)