This is an automated email from the ASF dual-hosted git repository.
cstamas pushed a commit to branch maven-resolver-1.9.x
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
The following commit(s) were added to refs/heads/maven-resolver-1.9.x by this
push:
new f181c06e2 [1.9.x] Fix locking issues (#1662)
f181c06e2 is described below
commit f181c06e2fc7b92abdf10328eeff21ee4766eb6a
Author: Tamas Cservenak <[email protected]>
AuthorDate: Mon Nov 17 20:38:56 2025 +0100
[1.9.x] Fix locking issues (#1662)
Crude and most obvious changes.
Changes:
* introduce dedicated ex (backport from 2)
* up default timeouts (from 30s to 900s)
* improve message by listing all lock subjects
* improve message by mentioning the property that user should use to
increase timeouts (there is no one size fits all; we could go with "infinite"
timeouts. but am unsure about that)
---
.../main/java/org/eclipse/aether/SyncContext.java | 29 +++++++++++++-
.../synccontext/named/NamedLockFactoryAdapter.java | 44 +++++++++++++++++++++-
src/site/markdown/configuration.md | 2 +-
3 files changed, 71 insertions(+), 4 deletions(-)
diff --git
a/maven-resolver-api/src/main/java/org/eclipse/aether/SyncContext.java
b/maven-resolver-api/src/main/java/org/eclipse/aether/SyncContext.java
index 63e8394bf..d9d0bfd45 100644
--- a/maven-resolver-api/src/main/java/org/eclipse/aether/SyncContext.java
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/SyncContext.java
@@ -61,12 +61,39 @@ public interface SyncContext extends Closeable {
*
* @param artifacts The artifacts to acquire, may be {@code null} or empty
if none.
* @param metadatas The metadatas to acquire, may be {@code null} or empty
if none.
+ * @throws FailedToAcquireLockException if method calls to acquire lock
within configured time.
*/
- void acquire(Collection<? extends Artifact> artifacts, Collection<?
extends Metadata> metadatas);
+ void acquire(Collection<? extends Artifact> artifacts, Collection<?
extends Metadata> metadatas)
+ throws FailedToAcquireLockException;
/**
* Releases all previously acquired artifacts/metadatas. If no resources
have been acquired before or if this
* synchronization context has already been closed, this method does
nothing.
*/
+ @Override
void close();
+
+ /**
+ * Specific exception thrown by {@link #acquire(Collection, Collection)}
method when it cannot acquire the lock.
+ *
+ * @since 1.9.25
+ */
+ final class FailedToAcquireLockException extends IllegalStateException {
+ private final boolean shared;
+
+ /**
+ * Constructor.
+ */
+ public FailedToAcquireLockException(boolean shared, String message) {
+ super(message);
+ this.shared = shared;
+ }
+
+ /**
+ * Returns {@code true} for shared and {@code false} for exclusive
sync contexts.
+ */
+ public boolean isShared() {
+ return shared;
+ }
+ }
}
diff --git
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactoryAdapter.java
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactoryAdapter.java
index 7a608c95d..20d6132ec 100644
---
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactoryAdapter.java
+++
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactoryAdapter.java
@@ -23,6 +23,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Deque;
import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.SyncContext;
@@ -32,6 +33,7 @@ import org.eclipse.aether.named.NamedLock;
import org.eclipse.aether.named.NamedLockFactory;
import org.eclipse.aether.named.providers.FileLockNamedLockFactory;
import org.eclipse.aether.util.ConfigUtils;
+import org.eclipse.aether.util.artifact.ArtifactIdUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -43,7 +45,7 @@ import static java.util.Objects.requireNonNull;
public final class NamedLockFactoryAdapter {
public static final String TIME_KEY = "aether.syncContext.named.time";
- public static final long DEFAULT_TIME = 30L;
+ public static final long DEFAULT_TIME = 900L;
public static final String TIME_UNIT_KEY =
"aether.syncContext.named.time.unit";
@@ -216,12 +218,50 @@ public final class NamedLockFactoryAdapter {
}
}
if (!illegalStateExceptions.isEmpty()) {
- IllegalStateException ex = new IllegalStateException("Could
not acquire lock(s)");
+ String message = "Could not acquire " + (shared ? "shared" :
"exclusive") + " lock for "
+ + lockSubjects(artifacts, metadatas) + " in " + time +
" " + timeUnit
+ + "; consider using '" + TIME_KEY
+ + "' property to increase lock timeout to a value that
fits your environment";
+ FailedToAcquireLockException ex = new
FailedToAcquireLockException(shared, message);
illegalStateExceptions.forEach(ex::addSuppressed);
throw namedLockFactory.onFailure(ex);
}
}
+ private String lockSubjects(
+ Collection<? extends Artifact> artifacts, Collection<? extends
Metadata> metadatas) {
+ StringBuilder builder = new StringBuilder();
+ if (artifacts != null && !artifacts.isEmpty()) {
+ builder.append("artifacts: ")
+
.append(artifacts.stream().map(ArtifactIdUtils::toId).collect(Collectors.joining(",
")));
+ }
+ if (metadatas != null && !metadatas.isEmpty()) {
+ if (builder.length() != 0) {
+ builder.append("; ");
+ }
+ builder.append("metadata: ")
+
.append(metadatas.stream().map(this::metadataSubjects).collect(Collectors.joining(",
")));
+ }
+ return builder.toString();
+ }
+
+ private String metadataSubjects(Metadata metadata) {
+ String name = "";
+ if (!metadata.getGroupId().isEmpty()) {
+ name += metadata.getGroupId();
+ if (!metadata.getArtifactId().isEmpty()) {
+ name += ":" + metadata.getArtifactId();
+ if (!metadata.getVersion().isEmpty()) {
+ name += ":" + metadata.getVersion();
+ }
+ }
+ }
+ if (!metadata.getType().isEmpty()) {
+ name += (name.isEmpty() ? "" : ":") + metadata.getType();
+ }
+ return name;
+ }
+
private void closeAll() {
if (locks.isEmpty()) {
return;
diff --git a/src/site/markdown/configuration.md
b/src/site/markdown/configuration.md
index 83db98530..6669adba3 100644
--- a/src/site/markdown/configuration.md
+++ b/src/site/markdown/configuration.md
@@ -103,7 +103,7 @@ under the License.
| `aether.syncContext.named.nameMapper`
| String | Name of name mapper implementing the
`org.eclipse.aether.internal.impl.synccontext.named.NameMapper` interface.
[...]
| `aether.syncContext.named.retry`
| int | Count of retries SyncContext adapter should perform,
when obtaining locks.
[...]
| `aether.syncContext.named.retry.wait`
| long | Amount of milliseconds a thread to wait between
retries, when obtaining locks.
[...]
-| `aether.syncContext.named.time`
| long | Amount of time a synchronization context shall wait
to obtain a lock.
[...]
+| `aether.syncContext.named.time`
| long | Amount of time a synchronization context shall wait
to obtain a lock.
[...]
| `aether.syncContext.named.time.unit`
| long | Unit of the lock wait time.
[...]
| `aether.syncContext.named.discriminating.discriminator`
| String | A discriminator name prefix identifying a Resolver
instance.
[...]
| `aether.syncContext.named.discriminating.hostname`
| String | The hostname to be used with discriminating mapper.
[...]