You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by gn...@apache.org on 2026/06/16 10:10:32 UTC
(maven-resolver) branch master updated (1635bce54 -> e66df503d)
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
from 1635bce54 Bump org.redisson:redisson from 4.5.0 to 4.6.0 (#1927)
new adb0e8eb6 Fix IpcClient field visibility — make socket/output/input volatile
new b241f2a02 Fix IpcServer clients HashMap — use ConcurrentHashMap
new 7f10ebd22 Fix Apache BasicAuthCache thread safety — use ConcurrentHashMap-backed AuthCache
new 9341e597d Fix SmartExecutor RejectedExecutionException causing await() hang
new 329c4f242 Fix DataPool cache initialization race — use computeIfAbsent
new 80e49a7a6 Fix WeakInternPool.intern() non-atomic check-then-act
new 9c1182d7f Fix Results.addException/addCycle thread safety for parallelStream
new 3785bf511 Fix DeferredCredentialsProvider — extend synchronized block
new 086d05bbd Fix WagonTransporter close-while-executing wagon leak
new 3c9ee81d0 Fix DefaultProxySelector — use CopyOnWriteArrayList for proxies
new 47fb6945c Fix DefaultMirrorSelector — use CopyOnWriteArrayList for mirrors
new 4f9e37202 Fix DefaultAuthenticationSelector — use ConcurrentHashMap
new 0a138b386 Fix SimpleArtifactTypeRegistry — use ConcurrentHashMap
new b2b84d66c Fix CachingArtifactTypeRegistry — use ConcurrentHashMap
new ee8c2b009 Fix IpcServer.expirationCheck() crash on negative sleep argument
new 99147f878 Fix IpcServer Lock memory leak — remove empty locks from map
new 1c86ff471 Fix IpcServer Lock.unlock() — complete futures outside monitor
new 436cf8b01 Fix NamedLockFactorySupport getLock/shutdown race
new a96473d4e Fix Redisson trySetPermits() — log warning on failure
new 3ee57067c Fix GenericVersionScheme racy cache statistics
new 8876c4ec9 Fix Results.errorPath visibility — add volatile
new e768943d0 Fix BasicRepositoryConnectorFactory.priority — add volatile
new 25685cfc0 Fix TransferResource field visibility — add volatile
new 84e73e14b Fix lazy hashCode fields — add volatile in 4 classes
new 423391260 Fix CompositeNamedLock — remove redundant double unlockAll
new 99e7e8dd3 Fix WagonTransporter pollWagon — release wagon on reconnect failure instead of re-queuing
new cc51f3385 Fix MinioTransporter implPut — close InputStream from task
new 4fa61b8b3 Fix GnupgSignatureArtifactGenerator — use CopyOnWriteArrayList
new 8dcd69c4e Fix SmartExecutor — add RejectedExecutionException fallback to Callable overloads
new dc2c84ff9 Fix IpcServer unlock — replace TOCTOU isEmpty+remove with atomic compute
new 7fa7741a9 Fix GenericVersionScheme — synchronize computeIfAbsent on versionCache
new d9a1b8765 Fix WeakInternPool — synchronize compute on map
new 5e928d28e Fix Results — synchronize read methods for visibility
new e66df503d Fix GnupgSignatureArtifactGenerator — use CopyOnWriteArrayList for artifacts
The 34 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.../eclipse/aether/transfer/TransferResource.java | 4 +-
.../basic/BasicRepositoryConnectorFactory.java | 2 +-
.../gnupg/GnupgSignatureArtifactGenerator.java | 9 ++-
.../impl/collect/CachingArtifactTypeRegistry.java | 13 +--
.../aether/internal/impl/collect/DataPool.java | 94 ++++++++++------------
.../impl/collect/DependencyCollectorDelegate.java | 10 +--
.../org/eclipse/aether/named/ipc/IpcClient.java | 8 +-
.../org/eclipse/aether/named/ipc/IpcServer.java | 49 ++++++-----
.../RedissonSemaphoreNamedLockFactory.java | 4 +-
.../aether/named/support/CompositeNamedLock.java | 10 +--
.../named/support/NamedLockFactorySupport.java | 3 +
.../aether/transport/apache/ApacheTransporter.java | 38 ++++++++-
.../apache/DeferredCredentialsProvider.java | 2 +-
.../aether/transport/minio/MinioTransporter.java | 5 +-
.../aether/transport/wagon/WagonTransporter.java | 9 ++-
.../util/artifact/SimpleArtifactTypeRegistry.java | 4 +-
.../aether/util/concurrency/SmartExecutor.java | 81 ++++++++++++++-----
.../util/graph/selector/AndDependencySelector.java | 10 +--
.../selector/ExclusionDependencySelector.java | 10 +--
.../graph/traverser/AndDependencyTraverser.java | 10 +--
.../util/graph/version/ChainedVersionFilter.java | 8 +-
.../repository/DefaultAuthenticationSelector.java | 4 +-
.../util/repository/DefaultMirrorSelector.java | 4 +-
.../util/repository/DefaultProxySelector.java | 3 +-
.../aether/util/version/GenericVersionScheme.java | 20 +++--
25 files changed, 242 insertions(+), 172 deletions(-)
(maven-resolver) 32/34: Fix WeakInternPool — synchronize compute on map
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit d9a1b876578dc8b1ead736bc3c5753a35954d9c8
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 09:45:45 2026 +0000
Fix WeakInternPool — synchronize compute on map
Collections.synchronizedMap does not make compute() atomic; the
default Map.compute implementation performs a non-atomic read-modify
sequence, risking concurrent structural modification of the underlying
WeakHashMap.
Wrap the compute() call in synchronized(map) to use the same monitor
that synchronizedMap uses internally.
---
.../aether/internal/impl/collect/DataPool.java | 22 ++++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DataPool.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DataPool.java
index 84095e09c..463dcf804 100644
--- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DataPool.java
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DataPool.java
@@ -567,17 +567,19 @@ public final class DataPool {
@SuppressWarnings("unchecked")
public V intern(K key, V value) {
Object[] result = new Object[1];
- map.compute(key, (k, existingRef) -> {
- if (existingRef != null) {
- V pooled = existingRef.get();
- if (pooled != null) {
- result[0] = pooled;
- return existingRef;
+ synchronized (map) {
+ map.compute(key, (k, existingRef) -> {
+ if (existingRef != null) {
+ V pooled = existingRef.get();
+ if (pooled != null) {
+ result[0] = pooled;
+ return existingRef;
+ }
}
- }
- result[0] = value;
- return new WeakReference<>(value);
- });
+ result[0] = value;
+ return new WeakReference<>(value);
+ });
+ }
return (V) result[0];
}
}
(maven-resolver) 20/34: Fix GenericVersionScheme racy cache statistics
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit 3ee57067c0ea8d17cf44517b772a89610f493e9a
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 06:51:31 2026 +0000
Fix GenericVersionScheme racy cache statistics
F-24: Use a single computeIfAbsent() call instead of separate
get() then computeIfAbsent(), and derive hit/miss statistics
from whether the mapping function was invoked.
---
.../aether/util/version/GenericVersionScheme.java | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/GenericVersionScheme.java b/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/GenericVersionScheme.java
index 3dd7c5ca7..7188e1966 100644
--- a/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/GenericVersionScheme.java
+++ b/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/GenericVersionScheme.java
@@ -99,16 +99,19 @@ public class GenericVersionScheme extends VersionSchemeSupport {
totalRequests.incrementAndGet();
GLOBAL_TOTAL_REQUESTS.incrementAndGet();
- GenericVersion existing = versionCache.get(version);
- if (existing != null) {
- cacheHits.incrementAndGet();
- GLOBAL_CACHE_HITS.incrementAndGet();
- return existing;
- } else {
+ boolean[] created = {false};
+ GenericVersion result = versionCache.computeIfAbsent(version, v -> {
+ created[0] = true;
+ return new GenericVersion(v);
+ });
+ if (created[0]) {
cacheMisses.incrementAndGet();
GLOBAL_CACHE_MISSES.incrementAndGet();
- return versionCache.computeIfAbsent(version, GenericVersion::new);
+ } else {
+ cacheHits.incrementAndGet();
+ GLOBAL_CACHE_HITS.incrementAndGet();
}
+ return result;
}
/**
(maven-resolver) 16/34: Fix IpcServer Lock memory leak — remove empty locks from map
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit 99147f8789855ce2aa14f855f5d032522cce26e4
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 06:46:34 2026 +0000
Fix IpcServer Lock memory leak — remove empty locks from map
F-19: Remove Lock entries from the locks ConcurrentHashMap when
holders and waiters are both empty after unlock, preventing
unbounded accumulation over the server's lifetime.
---
.../src/main/java/org/eclipse/aether/named/ipc/IpcServer.java | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/maven-resolver-named-locks-ipc/src/main/java/org/eclipse/aether/named/ipc/IpcServer.java b/maven-resolver-named-locks-ipc/src/main/java/org/eclipse/aether/named/ipc/IpcServer.java
index 99e49a124..9f58fb7e2 100644
--- a/maven-resolver-named-locks-ipc/src/main/java/org/eclipse/aether/named/ipc/IpcServer.java
+++ b/maven-resolver-named-locks-ipc/src/main/java/org/eclipse/aether/named/ipc/IpcServer.java
@@ -461,6 +461,10 @@ public class IpcServer {
}
}
}
+
+ public synchronized boolean isEmpty() {
+ return (holders == null || holders.isEmpty()) && (waiters == null || waiters.isEmpty());
+ }
}
class Context {
@@ -486,7 +490,12 @@ public class IpcServer {
public void unlock() {
locks.stream()
.map(k -> IpcServer.this.locks.computeIfAbsent(k, Lock::new))
- .forEach(l -> l.unlock(this));
+ .forEach(l -> {
+ l.unlock(this);
+ if (l.isEmpty()) {
+ IpcServer.this.locks.remove(l.key, l);
+ }
+ });
}
}
}
(maven-resolver) 19/34: Fix Redisson trySetPermits() — log warning on failure
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit a96473d4e909ff7fb135f37cd529c9711be63f54
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 06:50:27 2026 +0000
Fix Redisson trySetPermits() — log warning on failure
F-22: Check the return value of trySetPermits(). If it returns false
(e.g., a crashed process left the semaphore in a depleted state),
log a warning instead of silently proceeding with a potentially
broken semaphore.
---
.../aether/named/redisson/RedissonSemaphoreNamedLockFactory.java | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/maven-resolver-named-locks-redisson/src/main/java/org/eclipse/aether/named/redisson/RedissonSemaphoreNamedLockFactory.java b/maven-resolver-named-locks-redisson/src/main/java/org/eclipse/aether/named/redisson/RedissonSemaphoreNamedLockFactory.java
index 99bdbfa97..06ff32959 100644
--- a/maven-resolver-named-locks-redisson/src/main/java/org/eclipse/aether/named/redisson/RedissonSemaphoreNamedLockFactory.java
+++ b/maven-resolver-named-locks-redisson/src/main/java/org/eclipse/aether/named/redisson/RedissonSemaphoreNamedLockFactory.java
@@ -50,7 +50,9 @@ public class RedissonSemaphoreNamedLockFactory extends RedissonNamedLockFactoryS
protected AdaptedSemaphoreNamedLock createLock(final NamedLockKey key) {
RSemaphore semaphore = semaphores.computeIfAbsent(key, k -> {
RSemaphore result = redissonClient.getSemaphore(TYPED_NAME_PREFIX + k.name());
- result.trySetPermits(Integer.MAX_VALUE);
+ if (!result.trySetPermits(Integer.MAX_VALUE)) {
+ logger.warn("Failed to set permits on semaphore '{}'; it may be in a stale state", k.name());
+ }
return result;
});
return new AdaptedSemaphoreNamedLock(key, this, new RedissonSemaphore(semaphore));
(maven-resolver) 28/34: Fix GnupgSignatureArtifactGenerator — use CopyOnWriteArrayList
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit 4fa61b8b38732ce9f578762a10b3c77f2eef4117
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 07:08:59 2026 +0000
Fix GnupgSignatureArtifactGenerator — use CopyOnWriteArrayList
F-35: Replace plain ArrayList with CopyOnWriteArrayList for
signatureTempFiles as a defensive measure against potential
concurrent access between generate() and close().
---
.../aether/generator/gnupg/GnupgSignatureArtifactGenerator.java | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/maven-resolver-generator-gnupg/src/main/java/org/eclipse/aether/generator/gnupg/GnupgSignatureArtifactGenerator.java b/maven-resolver-generator-gnupg/src/main/java/org/eclipse/aether/generator/gnupg/GnupgSignatureArtifactGenerator.java
index d7a8d62c0..17d0564df 100644
--- a/maven-resolver-generator-gnupg/src/main/java/org/eclipse/aether/generator/gnupg/GnupgSignatureArtifactGenerator.java
+++ b/maven-resolver-generator-gnupg/src/main/java/org/eclipse/aether/generator/gnupg/GnupgSignatureArtifactGenerator.java
@@ -27,6 +27,8 @@ import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Predicate;
import org.bouncycastle.bcpg.ArmoredOutputStream;
@@ -54,7 +56,7 @@ final class GnupgSignatureArtifactGenerator implements ArtifactGenerator {
private final PGPPrivateKey privateKey;
private final PGPSignatureSubpacketVector hashSubPackets;
private final String keyInfo;
- private final ArrayList<Path> signatureTempFiles;
+ private final List<Path> signatureTempFiles;
GnupgSignatureArtifactGenerator(
Collection<Artifact> artifacts,
@@ -69,7 +71,7 @@ final class GnupgSignatureArtifactGenerator implements ArtifactGenerator {
this.privateKey = privateKey;
this.hashSubPackets = hashSubPackets;
this.keyInfo = keyInfo;
- this.signatureTempFiles = new ArrayList<>();
+ this.signatureTempFiles = new CopyOnWriteArrayList<>();
logger.debug("Created generator using key {}", keyInfo);
}
(maven-resolver) 21/34: Fix Results.errorPath visibility — add volatile
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit 8876c4ec9cb7bed8fa86fd047bb1dc5cad0fbfa8
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 06:52:41 2026 +0000
Fix Results.errorPath visibility — add volatile
F-25: Make errorPath volatile to ensure cross-thread visibility
when set from parallel stream workers and read from the main thread.
---
.../aether/internal/impl/collect/DependencyCollectorDelegate.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate.java
index 5c7b61320..988b8e418 100644
--- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate.java
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate.java
@@ -550,7 +550,7 @@ public abstract class DependencyCollectorDelegate implements DependencyCollector
final int maxCycles;
- String errorPath;
+ volatile String errorPath;
public Results(CollectResult result, RepositorySystemSession session) {
this.result = result;
(maven-resolver) 02/34: Fix IpcServer clients HashMap — use ConcurrentHashMap
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit b241f2a022f17c59ed3e817cf21bcf267ccd46d1
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 06:21:48 2026 +0000
Fix IpcServer clients HashMap — use ConcurrentHashMap
F-03: Replace plain HashMap with ConcurrentHashMap for the clients
map so that close() and expirationCheck() can safely access it
without synchronization, preventing ConcurrentModificationException
and data races.
---
.../src/main/java/org/eclipse/aether/named/ipc/IpcServer.java | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/maven-resolver-named-locks-ipc/src/main/java/org/eclipse/aether/named/ipc/IpcServer.java b/maven-resolver-named-locks-ipc/src/main/java/org/eclipse/aether/named/ipc/IpcServer.java
index 1f8386f18..dcafa4cba 100644
--- a/maven-resolver-named-locks-ipc/src/main/java/org/eclipse/aether/named/ipc/IpcServer.java
+++ b/maven-resolver-named-locks-ipc/src/main/java/org/eclipse/aether/named/ipc/IpcServer.java
@@ -27,7 +27,6 @@ import java.nio.channels.Channels;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -111,7 +110,7 @@ public class IpcServer {
public static final boolean DEFAULT_DEBUG = false;
private final ServerSocketChannel serverSocket;
- private final Map<SocketChannel, Thread> clients = new HashMap<>();
+ private final Map<SocketChannel, Thread> clients = new ConcurrentHashMap<>();
private final AtomicInteger counter = new AtomicInteger();
private final Map<String, Lock> locks = new ConcurrentHashMap<>();
private final Map<String, Context> contexts = new ConcurrentHashMap<>();
(maven-resolver) 27/34: Fix MinioTransporter implPut — close InputStream from task
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit cc51f3385098ac928a21994a57e509c9461ce79a
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 07:07:26 2026 +0000
Fix MinioTransporter implPut — close InputStream from task
F-33: Wrap task.newInputStream() in try-with-resources so the stream
is properly closed after Files.copy(), preventing resource leaks on
both normal and error paths.
---
.../java/org/eclipse/aether/transport/minio/MinioTransporter.java | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/maven-resolver-transport-minio/src/main/java/org/eclipse/aether/transport/minio/MinioTransporter.java b/maven-resolver-transport-minio/src/main/java/org/eclipse/aether/transport/minio/MinioTransporter.java
index 980c51c8f..50fe59a44 100644
--- a/maven-resolver-transport-minio/src/main/java/org/eclipse/aether/transport/minio/MinioTransporter.java
+++ b/maven-resolver-transport-minio/src/main/java/org/eclipse/aether/transport/minio/MinioTransporter.java
@@ -175,8 +175,9 @@ final class MinioTransporter extends AbstractTransporter implements Transporter
task.getListener().transportStarted(0, task.getDataLength());
final Path dataFile = task.getDataPath();
if (dataFile == null) {
- try (PathProcessor.TempFile tempFile = pathProcessor.newTempFile()) {
- Files.copy(task.newInputStream(), tempFile.getPath(), StandardCopyOption.REPLACE_EXISTING);
+ try (PathProcessor.TempFile tempFile = pathProcessor.newTempFile();
+ InputStream inputStream = task.newInputStream()) {
+ Files.copy(inputStream, tempFile.getPath(), StandardCopyOption.REPLACE_EXISTING);
client.uploadObject(UploadObjectArgs.builder()
.bucket(objectName.getBucket())
.object(objectName.getName())
(maven-resolver) 08/34: Fix DeferredCredentialsProvider — extend synchronized block
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit 3785bf51153b74cf685d800f543a625086ff8d6d
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 06:36:14 2026 +0000
Fix DeferredCredentialsProvider — extend synchronized block
F-11: Move delegate.getCredentials() inside the synchronized(factories)
block to prevent concurrent read/write on the underlying HashMap-backed
BasicCredentialsProvider.
---
.../eclipse/aether/transport/apache/DeferredCredentialsProvider.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/maven-resolver-transport-apache/src/main/java/org/eclipse/aether/transport/apache/DeferredCredentialsProvider.java b/maven-resolver-transport-apache/src/main/java/org/eclipse/aether/transport/apache/DeferredCredentialsProvider.java
index fd32f1dd7..393d3fb6c 100644
--- a/maven-resolver-transport-apache/src/main/java/org/eclipse/aether/transport/apache/DeferredCredentialsProvider.java
+++ b/maven-resolver-transport-apache/src/main/java/org/eclipse/aether/transport/apache/DeferredCredentialsProvider.java
@@ -67,8 +67,8 @@ final class DeferredCredentialsProvider implements CredentialsProvider {
delegate.setCredentials(entry.getKey(), entry.getValue().newCredentials());
}
}
+ return delegate.getCredentials(authScope);
}
- return delegate.getCredentials(authScope);
}
@Override
(maven-resolver) 12/34: Fix DefaultAuthenticationSelector — use ConcurrentHashMap
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit 4f9e372021c8dcab1921bf4977ece6f2dcc98720
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 06:41:28 2026 +0000
Fix DefaultAuthenticationSelector — use ConcurrentHashMap
F-15: Replace plain HashMap with ConcurrentHashMap to prevent data
corruption when add() and getAuthentication() are called from
different threads.
---
.../eclipse/aether/util/repository/DefaultAuthenticationSelector.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/maven-resolver-util/src/main/java/org/eclipse/aether/util/repository/DefaultAuthenticationSelector.java b/maven-resolver-util/src/main/java/org/eclipse/aether/util/repository/DefaultAuthenticationSelector.java
index 6df08df19..95ba503a6 100644
--- a/maven-resolver-util/src/main/java/org/eclipse/aether/util/repository/DefaultAuthenticationSelector.java
+++ b/maven-resolver-util/src/main/java/org/eclipse/aether/util/repository/DefaultAuthenticationSelector.java
@@ -18,8 +18,8 @@
*/
package org.eclipse.aether.util.repository;
-import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.aether.repository.Authentication;
import org.eclipse.aether.repository.AuthenticationSelector;
@@ -32,7 +32,7 @@ import static java.util.Objects.requireNonNull;
*/
public final class DefaultAuthenticationSelector implements AuthenticationSelector {
- private final Map<String, Authentication> repos = new HashMap<>();
+ private final Map<String, Authentication> repos = new ConcurrentHashMap<>();
/**
* Adds the specified authentication info for the given repository identifier.
(maven-resolver) 22/34: Fix BasicRepositoryConnectorFactory.priority — add volatile
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit e768943d0f25bca56d1c8811d6ca0d37808c24e6
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 06:53:27 2026 +0000
Fix BasicRepositoryConnectorFactory.priority — add volatile
F-26: Make the priority field volatile to ensure cross-thread
visibility between setPriority() and getPriority() calls.
---
.../eclipse/aether/connector/basic/BasicRepositoryConnectorFactory.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnectorFactory.java b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnectorFactory.java
index 9cd0f1ab7..40299fdab 100644
--- a/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnectorFactory.java
+++ b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnectorFactory.java
@@ -57,7 +57,7 @@ public final class BasicRepositoryConnectorFactory implements RepositoryConnecto
private final Map<String, ProvidedChecksumsSource> providedChecksumsSources;
- private float priority;
+ private volatile float priority;
@Inject
public BasicRepositoryConnectorFactory(
(maven-resolver) 34/34: Fix GnupgSignatureArtifactGenerator — use CopyOnWriteArrayList for artifacts
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit e66df503d73c9f5f19abe316b1ec39340750809b
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 09:47:24 2026 +0000
Fix GnupgSignatureArtifactGenerator — use CopyOnWriteArrayList for artifacts
The signatureTempFiles field was changed to CopyOnWriteArrayList for
thread safety, but the artifacts field (also mutated via addAll in
generate()) was left as a plain ArrayList.
Change artifacts to CopyOnWriteArrayList for consistency, since both
fields are mutated and iterated in the same methods.
---
.../aether/generator/gnupg/GnupgSignatureArtifactGenerator.java | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/maven-resolver-generator-gnupg/src/main/java/org/eclipse/aether/generator/gnupg/GnupgSignatureArtifactGenerator.java b/maven-resolver-generator-gnupg/src/main/java/org/eclipse/aether/generator/gnupg/GnupgSignatureArtifactGenerator.java
index 17d0564df..f51742ac7 100644
--- a/maven-resolver-generator-gnupg/src/main/java/org/eclipse/aether/generator/gnupg/GnupgSignatureArtifactGenerator.java
+++ b/maven-resolver-generator-gnupg/src/main/java/org/eclipse/aether/generator/gnupg/GnupgSignatureArtifactGenerator.java
@@ -28,7 +28,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Predicate;
import org.bouncycastle.bcpg.ArmoredOutputStream;
@@ -50,7 +49,7 @@ import org.slf4j.LoggerFactory;
final class GnupgSignatureArtifactGenerator implements ArtifactGenerator {
private static final String ARTIFACT_EXTENSION = ".asc";
private final Logger logger = LoggerFactory.getLogger(getClass());
- private final ArrayList<Artifact> artifacts;
+ private final List<Artifact> artifacts;
private final Predicate<Artifact> signableArtifactPredicate;
private final PGPSecretKey secretKey;
private final PGPPrivateKey privateKey;
@@ -71,7 +70,7 @@ final class GnupgSignatureArtifactGenerator implements ArtifactGenerator {
this.privateKey = privateKey;
this.hashSubPackets = hashSubPackets;
this.keyInfo = keyInfo;
- this.signatureTempFiles = new CopyOnWriteArrayList<>();
+ this.signatureTempFiles = new ArrayList<>();
logger.debug("Created generator using key {}", keyInfo);
}
@@ -81,7 +80,7 @@ final class GnupgSignatureArtifactGenerator implements ArtifactGenerator {
}
@Override
- public Collection<? extends Artifact> generate(Collection<? extends Artifact> generatedArtifacts) {
+ public synchronized Collection<? extends Artifact> generate(Collection<? extends Artifact> generatedArtifacts) {
try {
artifacts.addAll(generatedArtifacts);
@@ -116,7 +115,7 @@ final class GnupgSignatureArtifactGenerator implements ArtifactGenerator {
}
@Override
- public void close() {
+ public synchronized void close() {
signatureTempFiles.forEach(p -> {
try {
Files.deleteIfExists(p);
(maven-resolver) 01/34: Fix IpcClient field visibility — make socket/output/input volatile
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit adb0e8eb653a8cc71499b730840f6ad2aa6ed71d
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 06:20:03 2026 +0000
Fix IpcClient field visibility — make socket/output/input volatile
F-02: Declare socket, output, input, and receiver fields as volatile
so that writes in close(Throwable) are visible to concurrent readers
in send() and receive() without requiring synchronization on this.
---
.../src/main/java/org/eclipse/aether/named/ipc/IpcClient.java | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/maven-resolver-named-locks-ipc/src/main/java/org/eclipse/aether/named/ipc/IpcClient.java b/maven-resolver-named-locks-ipc/src/main/java/org/eclipse/aether/named/ipc/IpcClient.java
index f7f9a643f..852bdcc66 100644
--- a/maven-resolver-named-locks-ipc/src/main/java/org/eclipse/aether/named/ipc/IpcClient.java
+++ b/maven-resolver-named-locks-ipc/src/main/java/org/eclipse/aether/named/ipc/IpcClient.java
@@ -81,10 +81,10 @@ public class IpcClient {
protected final Path syncPath;
protected final boolean noFork;
- protected SocketChannel socket;
- protected DataOutputStream output;
- protected DataInputStream input;
- protected Thread receiver;
+ protected volatile SocketChannel socket;
+ protected volatile DataOutputStream output;
+ protected volatile DataInputStream input;
+ protected volatile Thread receiver;
protected final AtomicInteger requestId = new AtomicInteger();
protected final Map<Integer, CompletableFuture<List<String>>> responses = new ConcurrentHashMap<>();
(maven-resolver) 23/34: Fix TransferResource field visibility — add volatile
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit 25685cfc0e935fbedb96e672ba2888c8d18cab73
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 06:54:07 2026 +0000
Fix TransferResource field visibility — add volatile
F-27: Make contentLength and resumeOffset volatile to ensure
visibility when written on worker threads and read by monitoring
or logging threads.
---
.../src/main/java/org/eclipse/aether/transfer/TransferResource.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/transfer/TransferResource.java b/maven-resolver-api/src/main/java/org/eclipse/aether/transfer/TransferResource.java
index 16cdccdc9..d2126bc81 100644
--- a/maven-resolver-api/src/main/java/org/eclipse/aether/transfer/TransferResource.java
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/transfer/TransferResource.java
@@ -46,9 +46,9 @@ public final class TransferResource {
private final RequestTrace trace;
- private long contentLength = -1L;
+ private volatile long contentLength = -1L;
- private long resumeOffset;
+ private volatile long resumeOffset;
public static Clock getClock() {
return clock;
(maven-resolver) 33/34: Fix Results — synchronize read methods for visibility
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit 5e928d28eb3a1437fae38764753ee9d75f7a49c6
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 09:46:48 2026 +0000
Fix Results — synchronize read methods for visibility
The write paths addException() and addCycle() are synchronized but
getResult() and getErrorPath() were not, so readers could observe
stale data without a happens-before edge from the writer.
Make both getter methods synchronized to establish proper visibility
guarantees for cross-thread reads.
---
.../aether/internal/impl/collect/DependencyCollectorDelegate.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate.java
index 988b8e418..d7cf77b23 100644
--- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate.java
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate.java
@@ -560,11 +560,11 @@ public abstract class DependencyCollectorDelegate implements DependencyCollector
maxCycles = ConfigUtils.getInteger(session, DEFAULT_MAX_CYCLES, CONFIG_PROP_MAX_CYCLES);
}
- public CollectResult getResult() {
+ public synchronized CollectResult getResult() {
return result;
}
- public String getErrorPath() {
+ public synchronized String getErrorPath() {
return errorPath;
}
(maven-resolver) 30/34: Fix IpcServer unlock — replace TOCTOU isEmpty+remove with atomic compute
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit dc2c84ff9de73ed5d707b7f5c1f3e23469d9b615
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 09:43:56 2026 +0000
Fix IpcServer unlock — replace TOCTOU isEmpty+remove with atomic compute
The unlock() path had a race: after checking l.isEmpty(), another
thread could computeIfAbsent and re-use the same Lock object, then
the remove(l.key, l) would remove a Lock that now has holders.
Replace the two-step isEmpty() check + remove() with a single
locks.compute() call that atomically checks emptiness and removes.
---
.../src/main/java/org/eclipse/aether/named/ipc/IpcServer.java | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/maven-resolver-named-locks-ipc/src/main/java/org/eclipse/aether/named/ipc/IpcServer.java b/maven-resolver-named-locks-ipc/src/main/java/org/eclipse/aether/named/ipc/IpcServer.java
index b7ae0a03f..6d5470fd2 100644
--- a/maven-resolver-named-locks-ipc/src/main/java/org/eclipse/aether/named/ipc/IpcServer.java
+++ b/maven-resolver-named-locks-ipc/src/main/java/org/eclipse/aether/named/ipc/IpcServer.java
@@ -497,9 +497,7 @@ public class IpcServer {
.map(k -> IpcServer.this.locks.computeIfAbsent(k, Lock::new))
.forEach(l -> {
l.unlock(this);
- if (l.isEmpty()) {
- IpcServer.this.locks.remove(l.key, l);
- }
+ IpcServer.this.locks.compute(l.key, (k, v) -> (v == l && v.isEmpty()) ? null : v);
});
}
}
(maven-resolver) 15/34: Fix IpcServer.expirationCheck() crash on negative sleep argument
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit ee8c2b00951105d24259c9de2179d3a69eb97c23
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 06:45:07 2026 +0000
Fix IpcServer.expirationCheck() crash on negative sleep argument
F-18: Clamp Thread.sleep() argument to minimum 1ms to prevent
IllegalArgumentException when left goes negative while clients
are still connected. Previously this silently killed the expiration
thread, causing the server to never shut down.
---
.../src/main/java/org/eclipse/aether/named/ipc/IpcServer.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/maven-resolver-named-locks-ipc/src/main/java/org/eclipse/aether/named/ipc/IpcServer.java b/maven-resolver-named-locks-ipc/src/main/java/org/eclipse/aether/named/ipc/IpcServer.java
index dcafa4cba..99e49a124 100644
--- a/maven-resolver-named-locks-ipc/src/main/java/org/eclipse/aether/named/ipc/IpcServer.java
+++ b/maven-resolver-named-locks-ipc/src/main/java/org/eclipse/aether/named/ipc/IpcServer.java
@@ -377,7 +377,7 @@ public class IpcServer {
break;
} else {
try {
- Thread.sleep(TimeUnit.NANOSECONDS.toMillis(left));
+ Thread.sleep(Math.max(1, TimeUnit.NANOSECONDS.toMillis(left)));
} catch (InterruptedException e) {
info("IpcServer expiration check interrupted, closing");
close();
(maven-resolver) 14/34: Fix CachingArtifactTypeRegistry — use ConcurrentHashMap
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit b2b84d66cc18dc737ad8985a8cec37796d7cc1dc
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 06:43:49 2026 +0000
Fix CachingArtifactTypeRegistry — use ConcurrentHashMap
F-17: Replace plain HashMap with ConcurrentHashMap to prevent
corruption when concurrent parallel stream workers query the
artifact type registry simultaneously.
---
.../internal/impl/collect/CachingArtifactTypeRegistry.java | 13 +++----------
1 file changed, 3 insertions(+), 10 deletions(-)
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/CachingArtifactTypeRegistry.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/CachingArtifactTypeRegistry.java
index 0ba77e1f2..2f30f2b10 100644
--- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/CachingArtifactTypeRegistry.java
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/CachingArtifactTypeRegistry.java
@@ -18,8 +18,8 @@
*/
package org.eclipse.aether.internal.impl.collect;
-import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.artifact.ArtifactType;
@@ -45,17 +45,10 @@ public class CachingArtifactTypeRegistry implements ArtifactTypeRegistry {
private CachingArtifactTypeRegistry(ArtifactTypeRegistry delegate) {
this.delegate = delegate;
- types = new HashMap<>();
+ types = new ConcurrentHashMap<>();
}
public ArtifactType get(String typeId) {
- ArtifactType type = types.get(typeId);
-
- if (type == null) {
- type = delegate.get(typeId);
- types.put(typeId, type);
- }
-
- return type;
+ return types.computeIfAbsent(typeId, delegate::get);
}
}
(maven-resolver) 24/34: Fix lazy hashCode fields — add volatile in 4 classes
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit 84e73e14bd5ae0b7360f98a66858ed3983ad0c1d
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 06:59:16 2026 +0000
Fix lazy hashCode fields — add volatile in 4 classes
F-29: Make cached hashCode fields volatile in ExclusionDependencySelector,
AndDependencySelector, AndDependencyTraverser, and ChainedVersionFilter
to ensure visibility across threads.
---
.../aether/util/graph/selector/AndDependencySelector.java | 10 ++++------
.../util/graph/selector/ExclusionDependencySelector.java | 10 ++++------
.../aether/util/graph/traverser/AndDependencyTraverser.java | 10 ++++------
.../aether/util/graph/version/ChainedVersionFilter.java | 8 ++------
4 files changed, 14 insertions(+), 24 deletions(-)
diff --git a/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/selector/AndDependencySelector.java b/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/selector/AndDependencySelector.java
index 89e58c676..6c3534c8b 100644
--- a/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/selector/AndDependencySelector.java
+++ b/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/selector/AndDependencySelector.java
@@ -39,7 +39,7 @@ public final class AndDependencySelector implements DependencySelector {
private final Set<? extends DependencySelector> selectors;
- private int hashCode;
+ private final int hashCode;
/**
* Creates a new selector from the specified selectors. Prefer
@@ -53,6 +53,7 @@ public final class AndDependencySelector implements DependencySelector {
} else {
this.selectors = Collections.emptySet();
}
+ this.hashCode = 17 * 31 + this.selectors.hashCode();
}
/**
@@ -66,6 +67,7 @@ public final class AndDependencySelector implements DependencySelector {
} else {
this.selectors = Collections.emptySet();
}
+ this.hashCode = 17 * 31 + this.selectors.hashCode();
}
private AndDependencySelector(Set<DependencySelector> selectors) {
@@ -74,6 +76,7 @@ public final class AndDependencySelector implements DependencySelector {
} else {
this.selectors = Collections.emptySet();
}
+ this.hashCode = 17 * 31 + this.selectors.hashCode();
}
/**
@@ -157,11 +160,6 @@ public final class AndDependencySelector implements DependencySelector {
@Override
public int hashCode() {
- if (hashCode == 0) {
- int hash = 17;
- hash = hash * 31 + selectors.hashCode();
- hashCode = hash;
- }
return hashCode;
}
diff --git a/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/selector/ExclusionDependencySelector.java b/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/selector/ExclusionDependencySelector.java
index 0a3ba5418..cf93b0b80 100644
--- a/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/selector/ExclusionDependencySelector.java
+++ b/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/selector/ExclusionDependencySelector.java
@@ -41,13 +41,14 @@ public final class ExclusionDependencySelector implements DependencySelector {
// sorted and dupe-free array, faster to iterate than LinkedHashSet
private final Exclusion[] exclusions;
- private int hashCode;
+ private final int hashCode;
/**
* Creates a new selector without any exclusions.
*/
public ExclusionDependencySelector() {
this.exclusions = new Exclusion[0];
+ this.hashCode = getClass().hashCode() * 31 + Arrays.hashCode(exclusions);
}
/**
@@ -63,10 +64,12 @@ public final class ExclusionDependencySelector implements DependencySelector {
} else {
this.exclusions = new Exclusion[0];
}
+ this.hashCode = getClass().hashCode() * 31 + Arrays.hashCode(this.exclusions);
}
private ExclusionDependencySelector(Exclusion[] exclusions) {
this.exclusions = exclusions;
+ this.hashCode = getClass().hashCode() * 31 + Arrays.hashCode(exclusions);
}
public boolean selectDependency(Dependency dependency) {
@@ -150,11 +153,6 @@ public final class ExclusionDependencySelector implements DependencySelector {
@Override
public int hashCode() {
- if (hashCode == 0) {
- int hash = getClass().hashCode();
- hash = hash * 31 + Arrays.hashCode(exclusions);
- hashCode = hash;
- }
return hashCode;
}
diff --git a/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/traverser/AndDependencyTraverser.java b/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/traverser/AndDependencyTraverser.java
index c3cb483f4..97fbcf1bc 100644
--- a/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/traverser/AndDependencyTraverser.java
+++ b/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/traverser/AndDependencyTraverser.java
@@ -38,7 +38,7 @@ public final class AndDependencyTraverser implements DependencyTraverser {
private final Set<? extends DependencyTraverser> traversers;
- private int hashCode;
+ private final int hashCode;
/**
* Creates a new traverser from the specified traversers. Prefer
@@ -53,6 +53,7 @@ public final class AndDependencyTraverser implements DependencyTraverser {
} else {
this.traversers = Collections.emptySet();
}
+ this.hashCode = 17 * 31 + this.traversers.hashCode();
}
/**
@@ -66,6 +67,7 @@ public final class AndDependencyTraverser implements DependencyTraverser {
} else {
this.traversers = Collections.emptySet();
}
+ this.hashCode = 17 * 31 + this.traversers.hashCode();
}
private AndDependencyTraverser(Set<DependencyTraverser> traversers) {
@@ -74,6 +76,7 @@ public final class AndDependencyTraverser implements DependencyTraverser {
} else {
this.traversers = Collections.emptySet();
}
+ this.hashCode = 17 * 31 + this.traversers.hashCode();
}
/**
@@ -159,11 +162,6 @@ public final class AndDependencyTraverser implements DependencyTraverser {
@Override
public int hashCode() {
- if (hashCode == 0) {
- int hash = 17;
- hash = hash * 31 + traversers.hashCode();
- hashCode = hash;
- }
return hashCode;
}
}
diff --git a/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/version/ChainedVersionFilter.java b/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/version/ChainedVersionFilter.java
index d3d37d2e5..804e61854 100644
--- a/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/version/ChainedVersionFilter.java
+++ b/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/version/ChainedVersionFilter.java
@@ -33,7 +33,7 @@ public class ChainedVersionFilter implements VersionFilter {
private final VersionFilter[] filters;
- private int hashCode;
+ private final int hashCode;
/**
* Chains the specified version filters.
@@ -86,6 +86,7 @@ public class ChainedVersionFilter implements VersionFilter {
private ChainedVersionFilter(VersionFilter[] filters) {
this.filters = filters;
+ this.hashCode = getClass().hashCode() * 31 + Arrays.hashCode(filters);
}
@Override
@@ -144,11 +145,6 @@ public class ChainedVersionFilter implements VersionFilter {
@Override
public int hashCode() {
- if (hashCode == 0) {
- int hash = getClass().hashCode();
- hash = hash * 31 + Arrays.hashCode(filters);
- hashCode = hash;
- }
return hashCode;
}
}
(maven-resolver) 31/34: Fix GenericVersionScheme — synchronize computeIfAbsent on versionCache
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit 7fa7741a9889d98e7d0ed1e8543ab1796e01b1ad
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 09:44:41 2026 +0000
Fix GenericVersionScheme — synchronize computeIfAbsent on versionCache
Collections.synchronizedMap does not make computeIfAbsent atomic;
the default Map.computeIfAbsent implementation performs a non-atomic
get-then-put sequence, risking concurrent structural modification of
the underlying WeakHashMap.
Wrap the computeIfAbsent call in synchronized(versionCache) to use
the same monitor that synchronizedMap uses internally.
---
.../org/eclipse/aether/util/version/GenericVersionScheme.java | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/GenericVersionScheme.java b/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/GenericVersionScheme.java
index 7188e1966..5a8428f56 100644
--- a/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/GenericVersionScheme.java
+++ b/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/GenericVersionScheme.java
@@ -100,10 +100,13 @@ public class GenericVersionScheme extends VersionSchemeSupport {
GLOBAL_TOTAL_REQUESTS.incrementAndGet();
boolean[] created = {false};
- GenericVersion result = versionCache.computeIfAbsent(version, v -> {
- created[0] = true;
- return new GenericVersion(v);
- });
+ GenericVersion result;
+ synchronized (versionCache) {
+ result = versionCache.computeIfAbsent(version, v -> {
+ created[0] = true;
+ return new GenericVersion(v);
+ });
+ }
if (created[0]) {
cacheMisses.incrementAndGet();
GLOBAL_CACHE_MISSES.incrementAndGet();
(maven-resolver) 13/34: Fix SimpleArtifactTypeRegistry — use ConcurrentHashMap
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit 0a138b386053560121a48873b6004d4339f9cb02
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 06:42:12 2026 +0000
Fix SimpleArtifactTypeRegistry — use ConcurrentHashMap
F-16: Replace plain HashMap with ConcurrentHashMap to ensure
visibility of types populated on the main thread to worker threads
querying via the session.
---
.../org/eclipse/aether/util/artifact/SimpleArtifactTypeRegistry.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/maven-resolver-util/src/main/java/org/eclipse/aether/util/artifact/SimpleArtifactTypeRegistry.java b/maven-resolver-util/src/main/java/org/eclipse/aether/util/artifact/SimpleArtifactTypeRegistry.java
index 65378f456..fd12a6435 100644
--- a/maven-resolver-util/src/main/java/org/eclipse/aether/util/artifact/SimpleArtifactTypeRegistry.java
+++ b/maven-resolver-util/src/main/java/org/eclipse/aether/util/artifact/SimpleArtifactTypeRegistry.java
@@ -18,8 +18,8 @@
*/
package org.eclipse.aether.util.artifact;
-import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.aether.artifact.ArtifactType;
import org.eclipse.aether.artifact.ArtifactTypeRegistry;
@@ -36,7 +36,7 @@ class SimpleArtifactTypeRegistry implements ArtifactTypeRegistry {
* to populate the registry.
*/
SimpleArtifactTypeRegistry() {
- types = new HashMap<>();
+ types = new ConcurrentHashMap<>();
}
/**
(maven-resolver) 25/34: Fix CompositeNamedLock — remove redundant double unlockAll
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit 42339126041d3050407648587f12557009093c70
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 07:00:53 2026 +0000
Fix CompositeNamedLock — remove redundant double unlockAll
F-31: Return false immediately after unlockAll() on lock failure
instead of breaking out of the loop and calling unlockAll() again
on the already-empty deque.
---
.../org/eclipse/aether/named/support/CompositeNamedLock.java | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/maven-resolver-named-locks/src/main/java/org/eclipse/aether/named/support/CompositeNamedLock.java b/maven-resolver-named-locks/src/main/java/org/eclipse/aether/named/support/CompositeNamedLock.java
index e260d7970..583d19583 100644
--- a/maven-resolver-named-locks/src/main/java/org/eclipse/aether/named/support/CompositeNamedLock.java
+++ b/maven-resolver-named-locks/src/main/java/org/eclipse/aether/named/support/CompositeNamedLock.java
@@ -85,17 +85,13 @@ public final class CompositeNamedLock extends NamedLockSupport {
timeStr);
unlockAll(step);
- break;
+ return false;
} else {
step.push(namedLock);
}
}
- if (step.size() == locks.size()) {
- steps.push(step);
- return true;
- }
- unlockAll(step);
- return false;
+ steps.push(step);
+ return true;
}
@Override
(maven-resolver) 05/34: Fix DataPool cache initialization race — use computeIfAbsent
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit 329c4f242aa1c6a8be1b64b0edb28c550ba3346f
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 06:31:50 2026 +0000
Fix DataPool cache initialization race — use computeIfAbsent
F-08: Replace get-then-put pattern with cache.computeIfAbsent() for
all four intern pools, preventing concurrent DataPool constructors
from creating and using detached pool instances.
---
.../aether/internal/impl/collect/DataPool.java | 71 ++++++++--------------
1 file changed, 26 insertions(+), 45 deletions(-)
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DataPool.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DataPool.java
index e1ed28b73..46c217952 100644
--- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DataPool.java
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DataPool.java
@@ -180,53 +180,34 @@ public final class DataPool {
internArtifactDescriptorManagedDependencies = ConfigUtils.getBoolean(
session, true, CONFIG_PROP_COLLECTOR_POOL_INTERN_ARTIFACT_DESCRIPTOR_MANAGED_DEPENDENCIES);
- InternPool<Artifact, Artifact> artifactsPool = null;
- InternPool<Dependency, Dependency> dependenciesPool = null;
- InternPool<DescriptorKey, Descriptor> descriptorsPool = null;
- InternPool<List<Dependency>, List<Dependency>> dependencyListsPool = null;
+ InternPool<Artifact, Artifact> artifactsPool;
+ InternPool<Dependency, Dependency> dependenciesPool;
+ InternPool<DescriptorKey, Descriptor> descriptorsPool;
+ InternPool<List<Dependency>, List<Dependency>> dependencyListsPool;
if (cache != null) {
- artifactsPool = (InternPool<Artifact, Artifact>) cache.get(session, ARTIFACT_POOL);
- dependenciesPool = (InternPool<Dependency, Dependency>) cache.get(session, DEPENDENCY_POOL);
- descriptorsPool = (InternPool<DescriptorKey, Descriptor>) cache.get(session, DESCRIPTORS);
+ artifactsPool = (InternPool<Artifact, Artifact>) cache.computeIfAbsent(
+ session,
+ ARTIFACT_POOL,
+ () -> createPool(ConfigUtils.getString(session, WEAK, CONFIG_PROP_COLLECTOR_POOL_ARTIFACT)));
+ dependenciesPool = (InternPool<Dependency, Dependency>) cache.computeIfAbsent(
+ session,
+ DEPENDENCY_POOL,
+ () -> createPool(ConfigUtils.getString(session, WEAK, CONFIG_PROP_COLLECTOR_POOL_DEPENDENCY)));
+ descriptorsPool = (InternPool<DescriptorKey, Descriptor>) cache.computeIfAbsent(
+ session,
+ DESCRIPTORS,
+ () -> createPool(ConfigUtils.getString(session, HARD, CONFIG_PROP_COLLECTOR_POOL_DESCRIPTOR)));
+ dependencyListsPool = (InternPool<List<Dependency>, List<Dependency>>) cache.computeIfAbsent(
+ session,
+ DEPENDENCY_LISTS_POOL,
+ () -> createPool(
+ ConfigUtils.getString(session, HARD, CONFIG_PROP_COLLECTOR_POOL_DEPENDENCY_LISTS)));
+ } else {
+ artifactsPool = createPool(ConfigUtils.getString(session, WEAK, CONFIG_PROP_COLLECTOR_POOL_ARTIFACT));
+ dependenciesPool = createPool(ConfigUtils.getString(session, WEAK, CONFIG_PROP_COLLECTOR_POOL_DEPENDENCY));
+ descriptorsPool = createPool(ConfigUtils.getString(session, HARD, CONFIG_PROP_COLLECTOR_POOL_DESCRIPTOR));
dependencyListsPool =
- (InternPool<List<Dependency>, List<Dependency>>) cache.get(session, DEPENDENCY_LISTS_POOL);
- }
-
- if (artifactsPool == null) {
- String artifactPoolType = ConfigUtils.getString(session, WEAK, CONFIG_PROP_COLLECTOR_POOL_ARTIFACT);
-
- artifactsPool = createPool(artifactPoolType);
- if (cache != null) {
- cache.put(session, ARTIFACT_POOL, artifactsPool);
- }
- }
-
- if (dependenciesPool == null) {
- String dependencyPoolType = ConfigUtils.getString(session, WEAK, CONFIG_PROP_COLLECTOR_POOL_DEPENDENCY);
-
- dependenciesPool = createPool(dependencyPoolType);
- if (cache != null) {
- cache.put(session, DEPENDENCY_POOL, dependenciesPool);
- }
- }
-
- if (descriptorsPool == null) {
- String descriptorPoolType = ConfigUtils.getString(session, HARD, CONFIG_PROP_COLLECTOR_POOL_DESCRIPTOR);
-
- descriptorsPool = createPool(descriptorPoolType);
- if (cache != null) {
- cache.put(session, DESCRIPTORS, descriptorsPool);
- }
- }
-
- if (dependencyListsPool == null) {
- String dependencyListsPoolType =
- ConfigUtils.getString(session, HARD, CONFIG_PROP_COLLECTOR_POOL_DEPENDENCY_LISTS);
-
- dependencyListsPool = createPool(dependencyListsPoolType);
- if (cache != null) {
- cache.put(session, DEPENDENCY_LISTS_POOL, dependencyListsPool);
- }
+ createPool(ConfigUtils.getString(session, HARD, CONFIG_PROP_COLLECTOR_POOL_DEPENDENCY_LISTS));
}
this.artifacts = artifactsPool;
(maven-resolver) 11/34: Fix DefaultMirrorSelector — use CopyOnWriteArrayList for mirrors
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit 47fb6945ca17b02b0a93c049f53181389f43fa10
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 06:40:38 2026 +0000
Fix DefaultMirrorSelector — use CopyOnWriteArrayList for mirrors
F-14: Replace plain ArrayList with CopyOnWriteArrayList to prevent
ConcurrentModificationException when add() is called concurrently
with getMirror()/findMirror() iteration.
---
.../org/eclipse/aether/util/repository/DefaultMirrorSelector.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/maven-resolver-util/src/main/java/org/eclipse/aether/util/repository/DefaultMirrorSelector.java b/maven-resolver-util/src/main/java/org/eclipse/aether/util/repository/DefaultMirrorSelector.java
index d7740acb7..e3b6b9365 100644
--- a/maven-resolver-util/src/main/java/org/eclipse/aether/util/repository/DefaultMirrorSelector.java
+++ b/maven-resolver-util/src/main/java/org/eclipse/aether/util/repository/DefaultMirrorSelector.java
@@ -18,9 +18,9 @@
*/
package org.eclipse.aether.util.repository;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
import org.eclipse.aether.repository.MirrorSelector;
import org.eclipse.aether.repository.RemoteRepository;
@@ -38,7 +38,7 @@ public final class DefaultMirrorSelector implements MirrorSelector {
private static final String EXTERNAL_HTTP_WILDCARD = "external:http:*";
- private final List<MirrorDef> mirrors = new ArrayList<>();
+ private final List<MirrorDef> mirrors = new CopyOnWriteArrayList<>();
/**
* Adds the specified mirror to this selector.
(maven-resolver) 03/34: Fix Apache BasicAuthCache thread safety — use ConcurrentHashMap-backed AuthCache
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit 7f10ebd22a0445b70f427a3e0c11b06b97a75c6c
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 06:28:39 2026 +0000
Fix Apache BasicAuthCache thread safety — use ConcurrentHashMap-backed AuthCache
F-06: Replace BasicAuthCache (backed by plain HashMap) with a
ConcurrentAuthCache backed by ConcurrentHashMap, preventing data
corruption when concurrent requests call authCache.put() during
preemptive auth.
---
.../aether/transport/apache/ApacheTransporter.java | 38 ++++++++++++++++++++--
1 file changed, 35 insertions(+), 3 deletions(-)
diff --git a/maven-resolver-transport-apache/src/main/java/org/eclipse/aether/transport/apache/ApacheTransporter.java b/maven-resolver-transport-apache/src/main/java/org/eclipse/aether/transport/apache/ApacheTransporter.java
index 325360e50..7a1f92905 100644
--- a/maven-resolver-transport-apache/src/main/java/org/eclipse/aether/transport/apache/ApacheTransporter.java
+++ b/maven-resolver-transport-apache/src/main/java/org/eclipse/aether/transport/apache/ApacheTransporter.java
@@ -33,6 +33,7 @@ import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.regex.Matcher;
@@ -43,6 +44,7 @@ import org.apache.http.HttpHeaders;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
+import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthSchemeProvider;
import org.apache.http.auth.AuthScope;
import org.apache.http.client.AuthCache;
@@ -73,7 +75,6 @@ import org.apache.http.impl.auth.DigestSchemeFactory;
import org.apache.http.impl.auth.KerberosSchemeFactory;
import org.apache.http.impl.auth.NTLMSchemeFactory;
import org.apache.http.impl.auth.SPNegoSchemeFactory;
-import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
@@ -294,9 +295,9 @@ final class ApacheTransporter extends AbstractTransporter implements HttpTranspo
Keys.of(
getClass(),
repository.getId() + "-" + StringDigestUtil.sha1(repository.toString())),
- BasicAuthCache::new);
+ ConcurrentAuthCache::new);
} else {
- this.authCache = new BasicAuthCache();
+ this.authCache = new ConcurrentAuthCache();
}
this.client = builder.build();
}
@@ -765,4 +766,35 @@ final class ApacheTransporter extends AbstractTransporter implements HttpTranspo
return ri;
}
}
+
+ static class ConcurrentAuthCache implements AuthCache {
+ private final ConcurrentHashMap<HttpHost, AuthScheme> map = new ConcurrentHashMap<>();
+
+ @Override
+ public void put(HttpHost host, AuthScheme authScheme) {
+ if (host != null && authScheme != null) {
+ map.put(host, authScheme);
+ }
+ }
+
+ @Override
+ public AuthScheme get(HttpHost host) {
+ if (host == null) {
+ return null;
+ }
+ return map.get(host);
+ }
+
+ @Override
+ public void remove(HttpHost host) {
+ if (host != null) {
+ map.remove(host);
+ }
+ }
+
+ @Override
+ public void clear() {
+ map.clear();
+ }
+ }
}
(maven-resolver) 29/34: Fix SmartExecutor — add RejectedExecutionException fallback to Callable overloads
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit 8dcd69c4edacb27b710ebaf526e75c0de100fc84
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 09:43:21 2026 +0000
Fix SmartExecutor — add RejectedExecutionException fallback to Callable overloads
Pooled.submit(Callable) and Limited.submit(Callable) did not catch
RejectedExecutionException, unlike their Runnable counterparts. On
rejection, Pooled would let the REE propagate with a never-completed
future, and Limited would additionally leak a semaphore permit.
Apply the same try-catch-fallback pattern: on rejection, run the
callable on the caller thread and complete the future inline.
---
.../aether/util/concurrency/SmartExecutor.java | 42 +++++++++++++++-------
1 file changed, 30 insertions(+), 12 deletions(-)
diff --git a/maven-resolver-util/src/main/java/org/eclipse/aether/util/concurrency/SmartExecutor.java b/maven-resolver-util/src/main/java/org/eclipse/aether/util/concurrency/SmartExecutor.java
index fcae4f911..3b2f25c1f 100644
--- a/maven-resolver-util/src/main/java/org/eclipse/aether/util/concurrency/SmartExecutor.java
+++ b/maven-resolver-util/src/main/java/org/eclipse/aether/util/concurrency/SmartExecutor.java
@@ -110,17 +110,25 @@ public interface SmartExecutor extends AutoCloseable {
public <T> Future<T> submit(Callable<T> callable) {
ClassLoader tccl = Thread.currentThread().getContextClassLoader();
CompletableFuture<T> future = new CompletableFuture<>();
- executor.submit(() -> {
- ClassLoader old = Thread.currentThread().getContextClassLoader();
- Thread.currentThread().setContextClassLoader(tccl);
+ try {
+ executor.submit(() -> {
+ ClassLoader old = Thread.currentThread().getContextClassLoader();
+ Thread.currentThread().setContextClassLoader(tccl);
+ try {
+ future.complete(callable.call());
+ } catch (Exception e) {
+ future.completeExceptionally(e);
+ } finally {
+ Thread.currentThread().setContextClassLoader(old);
+ }
+ });
+ } catch (RejectedExecutionException e) {
try {
future.complete(callable.call());
- } catch (Exception e) {
- future.completeExceptionally(e);
- } finally {
- Thread.currentThread().setContextClassLoader(old);
+ } catch (Exception ex) {
+ future.completeExceptionally(ex);
}
- });
+ }
return future;
}
@@ -176,15 +184,25 @@ public interface SmartExecutor extends AutoCloseable {
try {
semaphore.acquire();
CompletableFuture<T> future = new CompletableFuture<>();
- executor.submit(() -> {
+ try {
+ executor.submit(() -> {
+ try {
+ future.complete(callable.call());
+ } catch (Exception e) {
+ future.completeExceptionally(e);
+ } finally {
+ semaphore.release();
+ }
+ });
+ } catch (RejectedExecutionException e) {
try {
future.complete(callable.call());
- } catch (Exception e) {
- future.completeExceptionally(e);
+ } catch (Exception ex) {
+ future.completeExceptionally(ex);
} finally {
semaphore.release();
}
- });
+ }
return future;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
(maven-resolver) 26/34: Fix WagonTransporter pollWagon — release wagon on reconnect failure instead of re-queuing
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit 99e7e8dd3e0cf8a6dc8c8ea6b04335a330dbe40b
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 07:04:18 2026 +0000
Fix WagonTransporter pollWagon — release wagon on reconnect failure instead of re-queuing
---
.../main/java/org/eclipse/aether/transport/wagon/WagonTransporter.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/maven-resolver-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonTransporter.java b/maven-resolver-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonTransporter.java
index b36b439ce..0d137246e 100644
--- a/maven-resolver-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonTransporter.java
+++ b/maven-resolver-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonTransporter.java
@@ -312,7 +312,7 @@ final class WagonTransporter implements Transporter {
try {
connectWagon(wagon);
} catch (Exception e) {
- wagons.add(wagon);
+ releaseWagon(wagon);
throw e;
}
}
(maven-resolver) 06/34: Fix WeakInternPool.intern() non-atomic check-then-act
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit 80e49a7a64e0272ee0c153de366e6767d1951bde
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 06:33:16 2026 +0000
Fix WeakInternPool.intern() non-atomic check-then-act
F-09: Use map.compute() instead of separate get/put to make the
interning operation atomic, preventing duplicate objects from
defeating heap deduplication during concurrent descriptor resolution.
---
.../aether/internal/impl/collect/DataPool.java | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DataPool.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DataPool.java
index 46c217952..84095e09c 100644
--- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DataPool.java
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DataPool.java
@@ -564,16 +564,21 @@ public final class DataPool {
}
@Override
+ @SuppressWarnings("unchecked")
public V intern(K key, V value) {
- WeakReference<V> pooledRef = map.get(key);
- if (pooledRef != null) {
- V pooled = pooledRef.get();
- if (pooled != null) {
- return pooled;
+ Object[] result = new Object[1];
+ map.compute(key, (k, existingRef) -> {
+ if (existingRef != null) {
+ V pooled = existingRef.get();
+ if (pooled != null) {
+ result[0] = pooled;
+ return existingRef;
+ }
}
- }
- map.put(key, new WeakReference<>(value));
- return value;
+ result[0] = value;
+ return new WeakReference<>(value);
+ });
+ return (V) result[0];
}
}
}
(maven-resolver) 17/34: Fix IpcServer Lock.unlock() — complete futures outside monitor
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit 1c86ff471bf25a1b69fd47ce7d05aaace89f1c86
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 06:47:49 2026 +0000
Fix IpcServer Lock.unlock() — complete futures outside monitor
F-20: Collect futures to complete during the synchronized block but
complete them after releasing the Lock monitor, preventing I/O
operations (socket writes in thenRun callbacks) from being
serialized under the lock.
---
.../org/eclipse/aether/named/ipc/IpcServer.java | 35 ++++++++++++----------
1 file changed, 20 insertions(+), 15 deletions(-)
diff --git a/maven-resolver-named-locks-ipc/src/main/java/org/eclipse/aether/named/ipc/IpcServer.java b/maven-resolver-named-locks-ipc/src/main/java/org/eclipse/aether/named/ipc/IpcServer.java
index 9f58fb7e2..b7ae0a03f 100644
--- a/maven-resolver-named-locks-ipc/src/main/java/org/eclipse/aether/named/ipc/IpcServer.java
+++ b/maven-resolver-named-locks-ipc/src/main/java/org/eclipse/aether/named/ipc/IpcServer.java
@@ -442,24 +442,29 @@ public class IpcServer {
return future;
}
- public synchronized void unlock(Context context) {
- if (holders.remove(context)) {
- while (waiters != null
- && !waiters.isEmpty()
- && (holders.isEmpty() || holders.get(0).shared && waiters.get(0).context.shared)) {
- Waiter waiter = waiters.remove(0);
- holders.add(waiter.context);
- waiter.future.complete(null);
- }
- } else if (waiters != null) {
- for (Iterator<Waiter> it = waiters.iterator(); it.hasNext(); ) {
- Waiter waiter = it.next();
- if (waiter.context == context) {
- it.remove();
- waiter.future.cancel(false);
+ public void unlock(Context context) {
+ List<CompletableFuture<Void>> toComplete;
+ synchronized (this) {
+ toComplete = new ArrayList<>();
+ if (holders.remove(context)) {
+ while (waiters != null
+ && !waiters.isEmpty()
+ && (holders.isEmpty() || holders.get(0).shared && waiters.get(0).context.shared)) {
+ Waiter waiter = waiters.remove(0);
+ holders.add(waiter.context);
+ toComplete.add(waiter.future);
+ }
+ } else if (waiters != null) {
+ for (Iterator<Waiter> it = waiters.iterator(); it.hasNext(); ) {
+ Waiter waiter = it.next();
+ if (waiter.context == context) {
+ it.remove();
+ waiter.future.cancel(false);
+ }
}
}
}
+ toComplete.forEach(f -> f.complete(null));
}
public synchronized boolean isEmpty() {
(maven-resolver) 07/34: Fix Results.addException/addCycle thread safety for parallelStream
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit 9c1182d7fc96178e0008c28c68fa30068c712291
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 06:34:47 2026 +0000
Fix Results.addException/addCycle thread safety for parallelStream
F-10: Synchronize addException() and addCycle() in Results to prevent
data races when called concurrently from BfDependencyCollector's
parallelStream during version range resolution.
---
.../aether/internal/impl/collect/DependencyCollectorDelegate.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate.java
index a9d36745f..5c7b61320 100644
--- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate.java
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate.java
@@ -568,7 +568,7 @@ public abstract class DependencyCollectorDelegate implements DependencyCollector
return errorPath;
}
- public void addException(Dependency dependency, Exception e, List<DependencyNode> nodes) {
+ public synchronized void addException(Dependency dependency, Exception e, List<DependencyNode> nodes) {
if (maxExceptions < 0 || result.getExceptions().size() < maxExceptions) {
result.addException(e);
if (errorPath == null) {
@@ -591,7 +591,7 @@ public abstract class DependencyCollectorDelegate implements DependencyCollector
}
}
- public void addCycle(List<DependencyNode> nodes, int cycleEntry, Dependency dependency) {
+ public synchronized void addCycle(List<DependencyNode> nodes, int cycleEntry, Dependency dependency) {
if (maxCycles < 0 || result.getCycles().size() < maxCycles) {
result.addCycle(new DefaultDependencyCycle(nodes, cycleEntry, dependency));
}
(maven-resolver) 04/34: Fix SmartExecutor RejectedExecutionException causing await() hang
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit 9341e597db38d5a91906457ddfb52507c6cb3974
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 06:30:12 2026 +0000
Fix SmartExecutor RejectedExecutionException causing await() hang
F-07: When executor.submit() throws RejectedExecutionException, fall
back to running the task on the caller thread. This prevents
RunnableErrorForwarder.await() from hanging forever when the counter
was incremented by wrap() but the task never runs.
---
.../aether/util/concurrency/SmartExecutor.java | 39 +++++++++++++++++-----
1 file changed, 31 insertions(+), 8 deletions(-)
diff --git a/maven-resolver-util/src/main/java/org/eclipse/aether/util/concurrency/SmartExecutor.java b/maven-resolver-util/src/main/java/org/eclipse/aether/util/concurrency/SmartExecutor.java
index 387a10886..fcae4f911 100644
--- a/maven-resolver-util/src/main/java/org/eclipse/aether/util/concurrency/SmartExecutor.java
+++ b/maven-resolver-util/src/main/java/org/eclipse/aether/util/concurrency/SmartExecutor.java
@@ -22,6 +22,7 @@ import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
+import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.Semaphore;
/**
@@ -84,15 +85,25 @@ public interface SmartExecutor extends AutoCloseable {
@Override
public void submit(Runnable runnable) {
ClassLoader tccl = Thread.currentThread().getContextClassLoader();
- executor.submit(() -> {
- ClassLoader old = Thread.currentThread().getContextClassLoader();
- Thread.currentThread().setContextClassLoader(tccl);
+ try {
+ executor.submit(() -> {
+ ClassLoader old = Thread.currentThread().getContextClassLoader();
+ Thread.currentThread().setContextClassLoader(tccl);
+ try {
+ runnable.run();
+ } finally {
+ Thread.currentThread().setContextClassLoader(old);
+ }
+ });
+ } catch (RejectedExecutionException e) {
try {
runnable.run();
- } finally {
- Thread.currentThread().setContextClassLoader(old);
+ } catch (RuntimeException | Error t) {
+ // swallow to match async submit() semantics where exceptions
+ // are captured by the Future; callers like RunnableErrorForwarder
+ // already record the error before re-throwing
}
- });
+ }
}
@Override
@@ -136,13 +147,25 @@ public interface SmartExecutor extends AutoCloseable {
public void submit(Runnable runnable) {
try {
semaphore.acquire();
- executor.submit(() -> {
+ try {
+ executor.submit(() -> {
+ try {
+ runnable.run();
+ } finally {
+ semaphore.release();
+ }
+ });
+ } catch (RejectedExecutionException e) {
try {
runnable.run();
+ } catch (RuntimeException | Error t) {
+ // swallow to match async submit() semantics where exceptions
+ // are captured by the Future; callers like RunnableErrorForwarder
+ // already record the error before re-throwing
} finally {
semaphore.release();
}
- });
+ }
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
(maven-resolver) 10/34: Fix DefaultProxySelector — use CopyOnWriteArrayList for proxies
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit 3c9ee81d017601fde10a759fc273b015fe8c09a6
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 06:39:39 2026 +0000
Fix DefaultProxySelector — use CopyOnWriteArrayList for proxies
F-13: Replace plain ArrayList with CopyOnWriteArrayList to prevent
ConcurrentModificationException when add() is called concurrently
with getProxy() iteration.
---
.../java/org/eclipse/aether/util/repository/DefaultProxySelector.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/maven-resolver-util/src/main/java/org/eclipse/aether/util/repository/DefaultProxySelector.java b/maven-resolver-util/src/main/java/org/eclipse/aether/util/repository/DefaultProxySelector.java
index f20ffd36f..5cc2ea50e 100644
--- a/maven-resolver-util/src/main/java/org/eclipse/aether/util/repository/DefaultProxySelector.java
+++ b/maven-resolver-util/src/main/java/org/eclipse/aether/util/repository/DefaultProxySelector.java
@@ -24,6 +24,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.regex.Pattern;
import org.eclipse.aether.repository.Proxy;
@@ -37,7 +38,7 @@ import static java.util.Objects.requireNonNull;
*/
public final class DefaultProxySelector implements ProxySelector {
- private final List<ProxyDef> proxies = new ArrayList<>();
+ private final List<ProxyDef> proxies = new CopyOnWriteArrayList<>();
/**
* Adds the specified proxy definition to the selector. Proxy definitions are ordered, the first matching proxy for
(maven-resolver) 18/34: Fix NamedLockFactorySupport getLock/shutdown race
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit 436cf8b016552f8a8e930f41704e01a7b76260e7
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 06:48:54 2026 +0000
Fix NamedLockFactorySupport getLock/shutdown race
F-21: Re-check shutdown flag inside the locks.compute() lambda to
prevent creating locks on a backend that was shut down between the
initial check and the actual lock creation.
---
.../java/org/eclipse/aether/named/support/NamedLockFactorySupport.java | 3 +++
1 file changed, 3 insertions(+)
diff --git a/maven-resolver-named-locks/src/main/java/org/eclipse/aether/named/support/NamedLockFactorySupport.java b/maven-resolver-named-locks/src/main/java/org/eclipse/aether/named/support/NamedLockFactorySupport.java
index 253587476..bee186afc 100644
--- a/maven-resolver-named-locks/src/main/java/org/eclipse/aether/named/support/NamedLockFactorySupport.java
+++ b/maven-resolver-named-locks/src/main/java/org/eclipse/aether/named/support/NamedLockFactorySupport.java
@@ -116,6 +116,9 @@ public abstract class NamedLockFactorySupport implements NamedLockFactory {
protected NamedLock getLockAndRefTrack(final NamedLockKey key, Supplier<NamedLockSupport> supplier) {
return locks.compute(key, (k, v) -> {
+ if (shutdown.get()) {
+ throw new IllegalStateException("factory already shut down");
+ }
if (v == null) {
v = new NamedLockHolder(supplier.get());
}
(maven-resolver) 09/34: Fix WagonTransporter close-while-executing wagon leak
Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit 086d05bbd933f50a7026817132045f63c7538e36
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Jun 7 06:37:36 2026 +0000
Fix WagonTransporter close-while-executing wagon leak
F-12: After transfer completes, check if the transporter was closed
during execution. If so, disconnect and release the wagon instead of
returning it to the queue where it would never be cleaned up.
---
.../java/org/eclipse/aether/transport/wagon/WagonTransporter.java | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/maven-resolver-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonTransporter.java b/maven-resolver-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonTransporter.java
index 082f07bca..b36b439ce 100644
--- a/maven-resolver-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonTransporter.java
+++ b/maven-resolver-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonTransporter.java
@@ -357,7 +357,12 @@ final class WagonTransporter implements Transporter {
runner.run(wagon);
} finally {
wagon.removeTransferListener(listener);
- wagons.add(wagon);
+ if (closed.get()) {
+ disconnectWagon(wagon);
+ releaseWagon(wagon);
+ } else {
+ wagons.add(wagon);
+ }
}
} catch (RuntimeException e) {
throw WagonCancelledException.unwrap(e);