This is an automated email from the ASF dual-hosted git repository.
cstamas pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
The following commit(s) were added to refs/heads/master by this push:
new 93bd1cb0 DepMgr hashCode handling (#749)
93bd1cb0 is described below
commit 93bd1cb084e756beb3e544d368afaf006082f557
Author: Tamas Cservenak <[email protected]>
AuthorDate: Thu Jun 12 23:16:55 2025 +0200
DepMgr hashCode handling (#749)
As graph is growing, same instances of HashMaps are repeatedly asked for
hashCode, that in default implementation goes over all keys and values over and
over again.
Changes:
* fix missing entry in equals as @mbien reported
* "invent" a special construct that fits this very use case: map is
modified once, and copied if next level is about to modify it
* the construct once asked for hashCode, memoizes it (the "read only" check
never happens in this code, is just there to be foolproof)
---
.../graph/manager/AbstractDependencyManager.java | 104 +++++++++++--------
.../graph/manager/ClassicDependencyManager.java | 21 ++--
.../graph/manager/DefaultDependencyManager.java | 21 ++--
.../eclipse/aether/util/graph/manager/MMap.java | 114 +++++++++++++++++++++
.../graph/manager/TransitiveDependencyManager.java | 21 ++--
5 files changed, 208 insertions(+), 73 deletions(-)
diff --git
a/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/manager/AbstractDependencyManager.java
b/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/manager/AbstractDependencyManager.java
index 0b9c1cf7..90bb3c1e 100644
---
a/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/manager/AbstractDependencyManager.java
+++
b/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/manager/AbstractDependencyManager.java
@@ -20,10 +20,8 @@ package org.eclipse.aether.util.graph.manager;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
-import java.util.Map;
import java.util.Objects;
import org.eclipse.aether.artifact.Artifact;
@@ -64,15 +62,15 @@ public abstract class AbstractDependencyManager implements
DependencyManager {
protected final int applyFrom;
- protected final Map<Object, Holder<String>> managedVersions;
+ protected final MMap<Key, Holder<String>> managedVersions;
- protected final Map<Object, Holder<String>> managedScopes;
+ protected final MMap<Key, Holder<String>> managedScopes;
- protected final Map<Object, Holder<Boolean>> managedOptionals;
+ protected final MMap<Key, Holder<Boolean>> managedOptionals;
- protected final Map<Object, Holder<String>> managedLocalPaths;
+ protected final MMap<Key, Holder<String>> managedLocalPaths;
- protected final Map<Object, Collection<Holder<Collection<Exclusion>>>>
managedExclusions;
+ protected final MMap<Key, Collection<Holder<Collection<Exclusion>>>>
managedExclusions;
protected final SystemDependencyScope systemDependencyScope;
@@ -83,11 +81,11 @@ public abstract class AbstractDependencyManager implements
DependencyManager {
0,
deriveUntil,
applyFrom,
- Collections.emptyMap(),
- Collections.emptyMap(),
- Collections.emptyMap(),
- Collections.emptyMap(),
- Collections.emptyMap(),
+ MMap.empty(),
+ MMap.empty(),
+ MMap.empty(),
+ MMap.empty(),
+ MMap.empty(),
scopeManager != null
? scopeManager.getSystemDependencyScope().orElse(null)
: SystemDependencyScope.LEGACY);
@@ -98,11 +96,11 @@ public abstract class AbstractDependencyManager implements
DependencyManager {
int depth,
int deriveUntil,
int applyFrom,
- Map<Object, Holder<String>> managedVersions,
- Map<Object, Holder<String>> managedScopes,
- Map<Object, Holder<Boolean>> managedOptionals,
- Map<Object, Holder<String>> managedLocalPaths,
- Map<Object, Collection<Holder<Collection<Exclusion>>>>
managedExclusions,
+ MMap<Key, Holder<String>> managedVersions,
+ MMap<Key, Holder<String>> managedScopes,
+ MMap<Key, Holder<Boolean>> managedOptionals,
+ MMap<Key, Holder<String>> managedLocalPaths,
+ MMap<Key, Collection<Holder<Collection<Exclusion>>>>
managedExclusions,
SystemDependencyScope systemDependencyScope) {
this.depth = depth;
this.deriveUntil = deriveUntil;
@@ -127,11 +125,11 @@ public abstract class AbstractDependencyManager
implements DependencyManager {
}
protected abstract DependencyManager newInstance(
- Map<Object, Holder<String>> managedVersions,
- Map<Object, Holder<String>> managedScopes,
- Map<Object, Holder<Boolean>> managedOptionals,
- Map<Object, Holder<String>> managedLocalPaths,
- Map<Object, Collection<Holder<Collection<Exclusion>>>>
managedExclusions);
+ MMap<Key, Holder<String>> managedVersions,
+ MMap<Key, Holder<String>> managedScopes,
+ MMap<Key, Holder<Boolean>> managedOptionals,
+ MMap<Key, Holder<String>> managedLocalPaths,
+ MMap<Key, Collection<Holder<Collection<Exclusion>>>>
managedExclusions);
@Override
public DependencyManager deriveChildManager(DependencyCollectionContext
context) {
@@ -140,20 +138,20 @@ public abstract class AbstractDependencyManager
implements DependencyManager {
return this;
}
- Map<Object, Holder<String>> managedVersions = this.managedVersions;
- Map<Object, Holder<String>> managedScopes = this.managedScopes;
- Map<Object, Holder<Boolean>> managedOptionals = this.managedOptionals;
- Map<Object, Holder<String>> managedLocalPaths = this.managedLocalPaths;
- Map<Object, Collection<Holder<Collection<Exclusion>>>>
managedExclusions = this.managedExclusions;
+ MMap<Key, Holder<String>> managedVersions = this.managedVersions;
+ MMap<Key, Holder<String>> managedScopes = this.managedScopes;
+ MMap<Key, Holder<Boolean>> managedOptionals = this.managedOptionals;
+ MMap<Key, Holder<String>> managedLocalPaths = this.managedLocalPaths;
+ MMap<Key, Collection<Holder<Collection<Exclusion>>>> managedExclusions
= this.managedExclusions;
for (Dependency managedDependency : context.getManagedDependencies()) {
Artifact artifact = managedDependency.getArtifact();
- Object key = new Key(artifact);
+ Key key = new Key(artifact);
String version = artifact.getVersion();
if (!version.isEmpty() && !managedVersions.containsKey(key)) {
if (managedVersions == this.managedVersions) {
- managedVersions = new HashMap<>(this.managedVersions);
+ managedVersions = MMap.copy(this.managedVersions);
}
managedVersions.put(key, new Holder<>(depth, version));
}
@@ -161,7 +159,7 @@ public abstract class AbstractDependencyManager implements
DependencyManager {
String scope = managedDependency.getScope();
if (!scope.isEmpty() && !managedScopes.containsKey(key)) {
if (managedScopes == this.managedScopes) {
- managedScopes = new HashMap<>(this.managedScopes);
+ managedScopes = MMap.copy(this.managedScopes);
}
managedScopes.put(key, new Holder<>(depth, scope));
}
@@ -169,7 +167,7 @@ public abstract class AbstractDependencyManager implements
DependencyManager {
Boolean optional = managedDependency.getOptional();
if (optional != null && !managedOptionals.containsKey(key)) {
if (managedOptionals == this.managedOptionals) {
- managedOptionals = new HashMap<>(this.managedOptionals);
+ managedOptionals = MMap.copy(this.managedOptionals);
}
managedOptionals.put(key, new Holder<>(depth, optional));
}
@@ -179,7 +177,7 @@ public abstract class AbstractDependencyManager implements
DependencyManager {
:
systemDependencyScope.getSystemPath(managedDependency.getArtifact());
if (localPath != null && !managedLocalPaths.containsKey(key)) {
if (managedLocalPaths == this.managedLocalPaths) {
- managedLocalPaths = new HashMap<>(this.managedLocalPaths);
+ managedLocalPaths = MMap.copy(this.managedLocalPaths);
}
managedLocalPaths.put(key, new Holder<>(depth, localPath));
}
@@ -187,22 +185,30 @@ public abstract class AbstractDependencyManager
implements DependencyManager {
Collection<Exclusion> exclusions =
managedDependency.getExclusions();
if (!exclusions.isEmpty()) {
if (managedExclusions == this.managedExclusions) {
- managedExclusions = new HashMap<>(this.managedExclusions);
+ managedExclusions = MMap.copy(this.managedExclusions);
+ }
+ Collection<Holder<Collection<Exclusion>>> managed =
managedExclusions.get(key);
+ if (managed == null) {
+ managed = new ArrayList<>();
+ managedExclusions.put(key, managed);
}
- Collection<Holder<Collection<Exclusion>>> managed =
- managedExclusions.computeIfAbsent(key, k -> new
ArrayList<>());
managed.add(new Holder<>(depth, exclusions));
}
}
- return newInstance(managedVersions, managedScopes, managedOptionals,
managedLocalPaths, managedExclusions);
+ return newInstance(
+ managedVersions.done(),
+ managedScopes.done(),
+ managedOptionals.done(),
+ managedLocalPaths.done(),
+ managedExclusions.done());
}
@Override
public DependencyManagement manageDependency(Dependency dependency) {
requireNonNull(dependency, "dependency cannot be null");
DependencyManagement management = null;
- Object key = new Key(dependency.getArtifact());
+ Key key = new Key(dependency.getArtifact());
if (isApplied()) {
Holder<String> version = managedVersions.get(key);
@@ -225,7 +231,7 @@ public abstract class AbstractDependencyManager implements
DependencyManager {
if (systemDependencyScope != null
&& !systemDependencyScope.is(scope.getValue())
&&
systemDependencyScope.getSystemPath(dependency.getArtifact()) != null) {
- Map<String, String> properties =
+ HashMap<String, String> properties =
new
HashMap<>(dependency.getArtifact().getProperties());
systemDependencyScope.setSystemPath(properties, null);
management.setProperties(properties);
@@ -242,7 +248,7 @@ public abstract class AbstractDependencyManager implements
DependencyManager {
if (management == null) {
management = new DependencyManagement();
}
- Map<String, String> properties =
+ HashMap<String, String> properties =
new
HashMap<>(dependency.getArtifact().getProperties());
systemDependencyScope.setSystemPath(properties,
localPath.getValue());
management.setProperties(properties);
@@ -320,6 +326,7 @@ public abstract class AbstractDependencyManager implements
DependencyManager {
&& managedVersions.equals(that.managedVersions)
&& managedScopes.equals(that.managedScopes)
&& managedOptionals.equals(that.managedOptionals)
+ && managedLocalPaths.equals(that.managedLocalPaths)
&& managedExclusions.equals(that.managedExclusions);
}
@@ -334,7 +341,8 @@ public abstract class AbstractDependencyManager implements
DependencyManager {
Key(Artifact artifact) {
this.artifact = artifact;
- this.hashCode = Objects.hash(artifact.getGroupId(),
artifact.getArtifactId());
+ this.hashCode = Objects.hash(
+ artifact.getArtifactId(), artifact.getGroupId(),
artifact.getExtension(), artifact.getClassifier());
}
@Override
@@ -365,10 +373,12 @@ public abstract class AbstractDependencyManager
implements DependencyManager {
protected static class Holder<T> {
private final int depth;
private final T value;
+ private final int hashCode;
Holder(int depth, T value) {
this.depth = depth;
this.value = requireNonNull(value);
+ this.hashCode = Objects.hash(depth, value);
}
public int getDepth() {
@@ -378,5 +388,19 @@ public abstract class AbstractDependencyManager implements
DependencyManager {
public T getValue() {
return value;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Holder)) {
+ return false;
+ }
+ Holder<?> holder = (Holder<?>) o;
+ return depth == holder.depth && Objects.equals(value,
holder.value);
+ }
+
+ @Override
+ public int hashCode() {
+ return hashCode;
+ }
}
}
diff --git
a/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/manager/ClassicDependencyManager.java
b/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/manager/ClassicDependencyManager.java
index cdf82db5..baa4b7e3 100644
---
a/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/manager/ClassicDependencyManager.java
+++
b/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/manager/ClassicDependencyManager.java
@@ -19,7 +19,6 @@
package org.eclipse.aether.util.graph.manager;
import java.util.Collection;
-import java.util.Map;
import org.eclipse.aether.collection.DependencyCollectionContext;
import org.eclipse.aether.collection.DependencyManager;
@@ -67,11 +66,11 @@ public final class ClassicDependencyManager extends
AbstractDependencyManager {
int depth,
int deriveUntil,
int applyFrom,
- Map<Object, Holder<String>> managedVersions,
- Map<Object, Holder<String>> managedScopes,
- Map<Object, Holder<Boolean>> managedOptionals,
- Map<Object, Holder<String>> managedLocalPaths,
- Map<Object, Collection<Holder<Collection<Exclusion>>>>
managedExclusions,
+ MMap<Key, Holder<String>> managedVersions,
+ MMap<Key, Holder<String>> managedScopes,
+ MMap<Key, Holder<Boolean>> managedOptionals,
+ MMap<Key, Holder<String>> managedLocalPaths,
+ MMap<Key, Collection<Holder<Collection<Exclusion>>>>
managedExclusions,
SystemDependencyScope systemDependencyScope) {
super(
depth,
@@ -98,11 +97,11 @@ public final class ClassicDependencyManager extends
AbstractDependencyManager {
@Override
protected DependencyManager newInstance(
- Map<Object, Holder<String>> managedVersions,
- Map<Object, Holder<String>> managedScopes,
- Map<Object, Holder<Boolean>> managedOptionals,
- Map<Object, Holder<String>> managedLocalPaths,
- Map<Object, Collection<Holder<Collection<Exclusion>>>>
managedExclusions) {
+ MMap<Key, Holder<String>> managedVersions,
+ MMap<Key, Holder<String>> managedScopes,
+ MMap<Key, Holder<Boolean>> managedOptionals,
+ MMap<Key, Holder<String>> managedLocalPaths,
+ MMap<Key, Collection<Holder<Collection<Exclusion>>>>
managedExclusions) {
return new ClassicDependencyManager(
depth + 1,
deriveUntil,
diff --git
a/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/manager/DefaultDependencyManager.java
b/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/manager/DefaultDependencyManager.java
index 9c1f8bb2..7ea86c05 100644
---
a/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/manager/DefaultDependencyManager.java
+++
b/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/manager/DefaultDependencyManager.java
@@ -19,7 +19,6 @@
package org.eclipse.aether.util.graph.manager;
import java.util.Collection;
-import java.util.Map;
import org.eclipse.aether.collection.DependencyManager;
import org.eclipse.aether.graph.Exclusion;
@@ -58,11 +57,11 @@ public final class DefaultDependencyManager extends
AbstractDependencyManager {
int depth,
int deriveUntil,
int applyFrom,
- Map<Object, Holder<String>> managedVersions,
- Map<Object, Holder<String>> managedScopes,
- Map<Object, Holder<Boolean>> managedOptionals,
- Map<Object, Holder<String>> managedLocalPaths,
- Map<Object, Collection<Holder<Collection<Exclusion>>>>
managedExclusions,
+ MMap<Key, Holder<String>> managedVersions,
+ MMap<Key, Holder<String>> managedScopes,
+ MMap<Key, Holder<Boolean>> managedOptionals,
+ MMap<Key, Holder<String>> managedLocalPaths,
+ MMap<Key, Collection<Holder<Collection<Exclusion>>>>
managedExclusions,
SystemDependencyScope systemDependencyScope) {
super(
depth,
@@ -78,11 +77,11 @@ public final class DefaultDependencyManager extends
AbstractDependencyManager {
@Override
protected DependencyManager newInstance(
- Map<Object, Holder<String>> managedVersions,
- Map<Object, Holder<String>> managedScopes,
- Map<Object, Holder<Boolean>> managedOptionals,
- Map<Object, Holder<String>> managedLocalPaths,
- Map<Object, Collection<Holder<Collection<Exclusion>>>>
managedExclusions) {
+ MMap<Key, Holder<String>> managedVersions,
+ MMap<Key, Holder<String>> managedScopes,
+ MMap<Key, Holder<Boolean>> managedOptionals,
+ MMap<Key, Holder<String>> managedLocalPaths,
+ MMap<Key, Collection<Holder<Collection<Exclusion>>>>
managedExclusions) {
return new DefaultDependencyManager(
depth + 1,
deriveUntil,
diff --git
a/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/manager/MMap.java
b/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/manager/MMap.java
new file mode 100644
index 00000000..8981a74d
--- /dev/null
+++
b/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/manager/MMap.java
@@ -0,0 +1,114 @@
+/*
+ * 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.eclipse.aether.util.graph.manager;
+
+import java.util.HashMap;
+
+/**
+ * Warning: this is a special map-like construct that suits only and should be
used only in this package!
+ * It has the following properties:
+ * <ul>
+ * <ul>memorizes once calculated hashCode</ul>
+ * <ul>once hashCode calculated, goes into "read only" mode (put method
will fail)</ul>
+ * <ul>otherwise all the rest is same as for {@link HashMap}</ul>
+ * </ul>
+ *
+ * This class is not a generic map class; only those methods are "protected"
that are in use in this very
+ * package.
+ *
+ * @param <K>
+ * @param <V>
+ */
+public class MMap<K, V> {
+ private static final MMap<?, ?> EMPTY_MAP = new MMap<>(new
HashMap<>(0)).done();
+
+ @SuppressWarnings("unchecked")
+ public static <K, V> MMap<K, V> empty() {
+ return (MMap<K, V>) MMap.EMPTY_MAP;
+ }
+
+ public static <K, V> MMap<K, V> copy(MMap<K, V> orig) {
+ return new MMap<>(orig.delegate);
+ }
+
+ protected final HashMap<K, V> delegate;
+
+ private MMap(HashMap<K, V> delegate) {
+ this.delegate = new HashMap<>(delegate);
+ }
+
+ public boolean containsKey(K key) {
+ return delegate.containsKey(key);
+ }
+
+ public V get(K key) {
+ return delegate.get(key);
+ }
+
+ public V put(K key, V value) {
+ return delegate.put(key, value);
+ }
+
+ public MMap<K, V> done() {
+ return new DoneMMap<>(delegate);
+ }
+
+ @Override
+ public int hashCode() {
+ throw new IllegalStateException("MMap is not done yet");
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ throw new IllegalStateException("MMap is not done yet");
+ }
+
+ private static class DoneMMap<K, V> extends MMap<K, V> {
+ private final int hashCode;
+
+ private DoneMMap(HashMap<K, V> delegate) {
+ super(delegate);
+ this.hashCode = delegate.hashCode();
+ }
+
+ @Override
+ public V put(K key, V value) {
+ throw new IllegalStateException("Done MMap is immutable");
+ }
+
+ @Override
+ public MMap<K, V> done() {
+ return this;
+ }
+
+ @Override
+ public int hashCode() {
+ return hashCode;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof MMap)) {
+ return false;
+ }
+ MMap<?, ?> other = (MMap<?, ?>) o;
+ return delegate.equals(other.delegate);
+ }
+ }
+}
diff --git
a/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/manager/TransitiveDependencyManager.java
b/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/manager/TransitiveDependencyManager.java
index e9c87c21..f49fb209 100644
---
a/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/manager/TransitiveDependencyManager.java
+++
b/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/manager/TransitiveDependencyManager.java
@@ -19,7 +19,6 @@
package org.eclipse.aether.util.graph.manager;
import java.util.Collection;
-import java.util.Map;
import org.eclipse.aether.collection.DependencyManager;
import org.eclipse.aether.graph.Exclusion;
@@ -55,11 +54,11 @@ public final class TransitiveDependencyManager extends
AbstractDependencyManager
int depth,
int deriveUntil,
int applyFrom,
- Map<Object, Holder<String>> managedVersions,
- Map<Object, Holder<String>> managedScopes,
- Map<Object, Holder<Boolean>> managedOptionals,
- Map<Object, Holder<String>> managedLocalPaths,
- Map<Object, Collection<Holder<Collection<Exclusion>>>>
managedExclusions,
+ MMap<Key, Holder<String>> managedVersions,
+ MMap<Key, Holder<String>> managedScopes,
+ MMap<Key, Holder<Boolean>> managedOptionals,
+ MMap<Key, Holder<String>> managedLocalPaths,
+ MMap<Key, Collection<Holder<Collection<Exclusion>>>>
managedExclusions,
SystemDependencyScope systemDependencyScope) {
super(
depth,
@@ -75,11 +74,11 @@ public final class TransitiveDependencyManager extends
AbstractDependencyManager
@Override
protected DependencyManager newInstance(
- Map<Object, Holder<String>> managedVersions,
- Map<Object, Holder<String>> managedScopes,
- Map<Object, Holder<Boolean>> managedOptionals,
- Map<Object, Holder<String>> managedLocalPaths,
- Map<Object, Collection<Holder<Collection<Exclusion>>>>
managedExclusions) {
+ MMap<Key, Holder<String>> managedVersions,
+ MMap<Key, Holder<String>> managedScopes,
+ MMap<Key, Holder<Boolean>> managedOptionals,
+ MMap<Key, Holder<String>> managedLocalPaths,
+ MMap<Key, Collection<Holder<Collection<Exclusion>>>>
managedExclusions) {
return new TransitiveDependencyManager(
depth + 1,
deriveUntil,