Skip to content

Commit ab4149f

Browse files
authored
[MNG-8520] Add cache for model resolution during project building (#2047)
1 parent e9805bb commit ab4149f

File tree

3 files changed

+138
-79
lines changed

3 files changed

+138
-79
lines changed

impl/maven-impl/src/main/java/org/apache/maven/api/services/model/ModelCache.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@
1818
*/
1919
package org.apache.maven.api.services.model;
2020

21+
import java.util.List;
2122
import java.util.function.Supplier;
2223

24+
import org.apache.maven.api.RemoteRepository;
2325
import org.apache.maven.api.annotations.Experimental;
2426
import org.apache.maven.api.annotations.ThreadSafe;
2527
import org.apache.maven.api.services.Source;
@@ -40,7 +42,14 @@
4042
@ThreadSafe
4143
public interface ModelCache {
4244

43-
<T> T computeIfAbsent(String groupId, String artifactId, String version, String tag, Supplier<T> data);
45+
<T> T computeIfAbsent(
46+
List<RemoteRepository> repositories,
47+
String groupId,
48+
String artifactId,
49+
String version,
50+
String classifier,
51+
String tag,
52+
Supplier<T> data);
4453

4554
<T> T computeIfAbsent(Source path, String tag, Supplier<T> data);
4655

impl/maven-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java

Lines changed: 96 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import java.util.concurrent.Executor;
4141
import java.util.concurrent.Executors;
4242
import java.util.concurrent.atomic.AtomicReference;
43+
import java.util.function.Consumer;
4344
import java.util.function.Supplier;
4445
import java.util.function.UnaryOperator;
4546
import java.util.regex.Matcher;
@@ -129,6 +130,7 @@ public class DefaultModelBuilder implements ModelBuilder {
129130
private static final String FILE = "file";
130131
private static final String IMPORT = "import";
131132
private static final String PARENT = "parent";
133+
private static final String MODEL = "model";
132134

133135
private final Logger logger = LoggerFactory.getLogger(getClass());
134136

@@ -1025,7 +1027,8 @@ Model resolveAndReadParentExternally(Model childModel, DefaultProfileActivationC
10251027
modelSource = resolveReactorModel(parent.getGroupId(), parent.getArtifactId(), parent.getVersion());
10261028
if (modelSource == null) {
10271029
AtomicReference<Parent> modified = new AtomicReference<>();
1028-
modelSource = modelResolver.resolveModel(request.getSession(), repositories, parent, modified);
1030+
modelSource = new CachingModelResolver()
1031+
.resolveModel(request.getSession(), repositories, parent, modified);
10291032
if (modified.get() != null) {
10301033
parent = modified.get();
10311034
}
@@ -1605,9 +1608,11 @@ private DependencyManagement loadDependencyManagement(Dependency dependency, Col
16051608
}
16061609

16071610
Model importModel = cache(
1611+
repositories,
16081612
groupId,
16091613
artifactId,
16101614
version,
1615+
null,
16111616
IMPORT,
16121617
() -> doLoadDependencyManagement(dependency, groupId, artifactId, version, importIds));
16131618
DependencyManagement importMgmt = importModel != null ? importModel.getDependencyManagement() : null;
@@ -1641,8 +1646,8 @@ private Model doLoadDependencyManagement(
16411646
try {
16421647
importSource = resolveReactorModel(groupId, artifactId, version);
16431648
if (importSource == null) {
1644-
importSource = modelResolver.resolveModel(
1645-
request.getSession(), repositories, dependency, new AtomicReference<>());
1649+
importSource = new CachingModelResolver()
1650+
.resolveModel(request.getSession(), repositories, dependency, new AtomicReference<>());
16461651
}
16471652
} catch (ModelBuilderException | ModelResolverException e) {
16481653
StringBuilder buffer = new StringBuilder(256);
@@ -1711,8 +1716,15 @@ ModelSource resolveReactorModel(String groupId, String artifactId, String versio
17111716
return null;
17121717
}
17131718

1714-
private <T> T cache(String groupId, String artifactId, String version, String tag, Supplier<T> supplier) {
1715-
return cache.computeIfAbsent(groupId, artifactId, version, tag, supplier);
1719+
private <T> T cache(
1720+
List<RemoteRepository> repositories,
1721+
String groupId,
1722+
String artifactId,
1723+
String version,
1724+
String classifier,
1725+
String tag,
1726+
Supplier<T> supplier) {
1727+
return cache.computeIfAbsent(repositories, groupId, artifactId, version, classifier, tag, supplier);
17161728
}
17171729

17181730
private <T> T cache(Source source, String tag, Supplier<T> supplier) throws ModelBuilderException {
@@ -1801,6 +1813,85 @@ private String transformPath(String path, ActivationFile target, String location
18011813
}
18021814
return profiles.stream().map(new ProfileInterpolator()).toList();
18031815
}
1816+
1817+
record ModelResolverResult(ModelSource source, String resolvedVersion) {}
1818+
1819+
class CachingModelResolver implements ModelResolver {
1820+
@Override
1821+
public ModelSource resolveModel(
1822+
Session session,
1823+
List<RemoteRepository> repositories,
1824+
Parent parent,
1825+
AtomicReference<Parent> modified)
1826+
throws ModelResolverException {
1827+
ModelResolverResult result = cache.computeIfAbsent(
1828+
repositories,
1829+
parent.getGroupId(),
1830+
parent.getArtifactId(),
1831+
parent.getVersion(),
1832+
null,
1833+
MODEL,
1834+
() -> {
1835+
AtomicReference<Parent> mod = new AtomicReference<>();
1836+
ModelSource res = modelResolver.resolveModel(session, repositories, parent, mod);
1837+
return new ModelResolverResult(
1838+
res, mod.get() != null ? mod.get().getVersion() : null);
1839+
});
1840+
if (result.resolvedVersion != null && modified != null) {
1841+
modified.set(parent.withVersion(result.resolvedVersion));
1842+
}
1843+
return result.source;
1844+
}
1845+
1846+
@Override
1847+
public ModelSource resolveModel(
1848+
Session session,
1849+
List<RemoteRepository> repositories,
1850+
Dependency dependency,
1851+
AtomicReference<Dependency> modified)
1852+
throws ModelResolverException {
1853+
ModelResolverResult result = cache.computeIfAbsent(
1854+
repositories,
1855+
dependency.getGroupId(),
1856+
dependency.getArtifactId(),
1857+
dependency.getVersion(),
1858+
dependency.getClassifier(),
1859+
MODEL,
1860+
() -> {
1861+
AtomicReference<Dependency> mod = new AtomicReference<>();
1862+
ModelSource res = modelResolver.resolveModel(session, repositories, dependency, mod);
1863+
return new ModelResolverResult(
1864+
res, mod.get() != null ? mod.get().getVersion() : null);
1865+
});
1866+
if (result.resolvedVersion != null && modified != null) {
1867+
modified.set(dependency.withVersion(result.resolvedVersion));
1868+
}
1869+
return result.source;
1870+
}
1871+
1872+
@Override
1873+
public ModelSource resolveModel(
1874+
Session session,
1875+
List<RemoteRepository> repositories,
1876+
String groupId,
1877+
String artifactId,
1878+
String version,
1879+
String classifier,
1880+
Consumer<String> resolvedVersion)
1881+
throws ModelResolverException {
1882+
ModelResolverResult result =
1883+
cache.computeIfAbsent(repositories, groupId, artifactId, version, classifier, MODEL, () -> {
1884+
AtomicReference<String> mod = new AtomicReference<>();
1885+
ModelSource res = modelResolver.resolveModel(
1886+
session, repositories, groupId, artifactId, version, classifier, mod::set);
1887+
return new ModelResolverResult(res, mod.get());
1888+
});
1889+
if (result.resolvedVersion != null) {
1890+
resolvedVersion.accept(result.resolvedVersion);
1891+
}
1892+
return result.source;
1893+
}
1894+
}
18041895
}
18051896

18061897
@SuppressWarnings("deprecation")

impl/maven-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelCache.java

Lines changed: 32 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@
1818
*/
1919
package org.apache.maven.internal.impl.model;
2020

21-
import java.util.Objects;
21+
import java.util.List;
2222
import java.util.concurrent.ConcurrentHashMap;
2323
import java.util.concurrent.ConcurrentMap;
2424
import java.util.function.Supplier;
2525

26+
import org.apache.maven.api.RemoteRepository;
2627
import org.apache.maven.api.services.Source;
2728
import org.apache.maven.api.services.model.ModelCache;
2829

@@ -46,8 +47,15 @@ private DefaultModelCache(ConcurrentMap<Object, Supplier<?>> cache) {
4647

4748
@Override
4849
@SuppressWarnings({"unchecked"})
49-
public <T> T computeIfAbsent(String groupId, String artifactId, String version, String tag, Supplier<T> data) {
50-
return (T) computeIfAbsent(new GavCacheKey(groupId, artifactId, version, tag), data);
50+
public <T> T computeIfAbsent(
51+
List<RemoteRepository> repositories,
52+
String groupId,
53+
String artifactId,
54+
String version,
55+
String classifier,
56+
String tag,
57+
Supplier<T> data) {
58+
return (T) computeIfAbsent(new RgavCacheKey(repositories, groupId, artifactId, version, classifier, tag), data);
5159
}
5260

5361
@Override
@@ -65,26 +73,19 @@ protected Object computeIfAbsent(Object key, Supplier<?> data) {
6573
return cache.computeIfAbsent(key, k -> new CachingSupplier<>(data)).get();
6674
}
6775

68-
static class GavCacheKey {
76+
record RgavCacheKey(
77+
List<RemoteRepository> repositories,
78+
String groupId,
79+
String artifactId,
80+
String version,
81+
String classifier,
82+
String tag) {
6983

70-
private final String gav;
71-
72-
private final String tag;
73-
74-
private final int hash;
75-
76-
GavCacheKey(String groupId, String artifactId, String version, String tag) {
77-
this(gav(groupId, artifactId, version), tag);
78-
}
79-
80-
GavCacheKey(String gav, String tag) {
81-
this.gav = gav;
82-
this.tag = tag;
83-
this.hash = Objects.hash(gav, tag);
84-
}
85-
86-
private static String gav(String groupId, String artifactId, String version) {
84+
@Override
85+
public String toString() {
8786
StringBuilder sb = new StringBuilder();
87+
sb.append("GavCacheKey[");
88+
sb.append("gav='");
8889
if (groupId != null) {
8990
sb.append(groupId);
9091
}
@@ -96,71 +97,28 @@ private static String gav(String groupId, String artifactId, String version) {
9697
if (version != null) {
9798
sb.append(version);
9899
}
99-
return sb.toString();
100-
}
101-
102-
@Override
103-
public boolean equals(Object obj) {
104-
if (this == obj) {
105-
return true;
106-
}
107-
if (null == obj || !getClass().equals(obj.getClass())) {
108-
return false;
100+
sb.append(":");
101+
if (classifier != null) {
102+
sb.append(classifier);
109103
}
110-
GavCacheKey that = (GavCacheKey) obj;
111-
return Objects.equals(this.gav, that.gav) && Objects.equals(this.tag, that.tag);
112-
}
113-
114-
@Override
115-
public int hashCode() {
116-
return hash;
117-
}
118-
119-
@Override
120-
public String toString() {
121-
return "GavCacheKey[" + "gav='" + gav + '\'' + ", tag='" + tag + '\'' + ']';
104+
sb.append("', tag='");
105+
sb.append(tag);
106+
sb.append("']");
107+
return sb.toString();
122108
}
123109
}
124110

125-
private static final class SourceCacheKey {
126-
private final Source source;
127-
128-
private final String tag;
129-
130-
private final int hash;
131-
132-
SourceCacheKey(Source source, String tag) {
133-
this.source = source;
134-
this.tag = tag;
135-
this.hash = Objects.hash(source, tag);
136-
}
111+
record SourceCacheKey(Source source, String tag) {
137112

138113
@Override
139114
public String toString() {
140115
return "SourceCacheKey[" + "location=" + source.getLocation() + ", tag=" + tag + ", path="
141116
+ source.getPath() + ']';
142117
}
143-
144-
@Override
145-
public boolean equals(Object obj) {
146-
if (this == obj) {
147-
return true;
148-
}
149-
if (null == obj || !getClass().equals(obj.getClass())) {
150-
return false;
151-
}
152-
SourceCacheKey that = (SourceCacheKey) obj;
153-
return Objects.equals(this.source, that.source) && Objects.equals(this.tag, that.tag);
154-
}
155-
156-
@Override
157-
public int hashCode() {
158-
return hash;
159-
}
160118
}
161119

162120
static class CachingSupplier<T> implements Supplier<T> {
163-
final Supplier<T> supplier;
121+
Supplier<T> supplier;
164122
volatile Object value;
165123

166124
CachingSupplier(Supplier<T> supplier) {
@@ -176,6 +134,7 @@ public T get() {
176134
if ((v = value) == null) {
177135
try {
178136
v = value = supplier.get();
137+
supplier = null;
179138
} catch (Exception e) {
180139
v = value = new AltRes(e);
181140
}

0 commit comments

Comments
 (0)