Skip to content

Commit f181c06

Browse files
authored
[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)
1 parent 8c3fb18 commit f181c06

File tree

3 files changed

+71
-4
lines changed

3 files changed

+71
-4
lines changed

maven-resolver-api/src/main/java/org/eclipse/aether/SyncContext.java

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,39 @@ public interface SyncContext extends Closeable {
6161
*
6262
* @param artifacts The artifacts to acquire, may be {@code null} or empty if none.
6363
* @param metadatas The metadatas to acquire, may be {@code null} or empty if none.
64+
* @throws FailedToAcquireLockException if method calls to acquire lock within configured time.
6465
*/
65-
void acquire(Collection<? extends Artifact> artifacts, Collection<? extends Metadata> metadatas);
66+
void acquire(Collection<? extends Artifact> artifacts, Collection<? extends Metadata> metadatas)
67+
throws FailedToAcquireLockException;
6668

6769
/**
6870
* Releases all previously acquired artifacts/metadatas. If no resources have been acquired before or if this
6971
* synchronization context has already been closed, this method does nothing.
7072
*/
73+
@Override
7174
void close();
75+
76+
/**
77+
* Specific exception thrown by {@link #acquire(Collection, Collection)} method when it cannot acquire the lock.
78+
*
79+
* @since 1.9.25
80+
*/
81+
final class FailedToAcquireLockException extends IllegalStateException {
82+
private final boolean shared;
83+
84+
/**
85+
* Constructor.
86+
*/
87+
public FailedToAcquireLockException(boolean shared, String message) {
88+
super(message);
89+
this.shared = shared;
90+
}
91+
92+
/**
93+
* Returns {@code true} for shared and {@code false} for exclusive sync contexts.
94+
*/
95+
public boolean isShared() {
96+
return shared;
97+
}
98+
}
7299
}

maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactoryAdapter.java

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.util.Collection;
2424
import java.util.Deque;
2525
import java.util.concurrent.TimeUnit;
26+
import java.util.stream.Collectors;
2627

2728
import org.eclipse.aether.RepositorySystemSession;
2829
import org.eclipse.aether.SyncContext;
@@ -32,6 +33,7 @@
3233
import org.eclipse.aether.named.NamedLockFactory;
3334
import org.eclipse.aether.named.providers.FileLockNamedLockFactory;
3435
import org.eclipse.aether.util.ConfigUtils;
36+
import org.eclipse.aether.util.artifact.ArtifactIdUtils;
3537
import org.slf4j.Logger;
3638
import org.slf4j.LoggerFactory;
3739

@@ -43,7 +45,7 @@
4345
public final class NamedLockFactoryAdapter {
4446
public static final String TIME_KEY = "aether.syncContext.named.time";
4547

46-
public static final long DEFAULT_TIME = 30L;
48+
public static final long DEFAULT_TIME = 900L;
4749

4850
public static final String TIME_UNIT_KEY = "aether.syncContext.named.time.unit";
4951

@@ -216,12 +218,50 @@ public void acquire(Collection<? extends Artifact> artifacts, Collection<? exten
216218
}
217219
}
218220
if (!illegalStateExceptions.isEmpty()) {
219-
IllegalStateException ex = new IllegalStateException("Could not acquire lock(s)");
221+
String message = "Could not acquire " + (shared ? "shared" : "exclusive") + " lock for "
222+
+ lockSubjects(artifacts, metadatas) + " in " + time + " " + timeUnit
223+
+ "; consider using '" + TIME_KEY
224+
+ "' property to increase lock timeout to a value that fits your environment";
225+
FailedToAcquireLockException ex = new FailedToAcquireLockException(shared, message);
220226
illegalStateExceptions.forEach(ex::addSuppressed);
221227
throw namedLockFactory.onFailure(ex);
222228
}
223229
}
224230

231+
private String lockSubjects(
232+
Collection<? extends Artifact> artifacts, Collection<? extends Metadata> metadatas) {
233+
StringBuilder builder = new StringBuilder();
234+
if (artifacts != null && !artifacts.isEmpty()) {
235+
builder.append("artifacts: ")
236+
.append(artifacts.stream().map(ArtifactIdUtils::toId).collect(Collectors.joining(", ")));
237+
}
238+
if (metadatas != null && !metadatas.isEmpty()) {
239+
if (builder.length() != 0) {
240+
builder.append("; ");
241+
}
242+
builder.append("metadata: ")
243+
.append(metadatas.stream().map(this::metadataSubjects).collect(Collectors.joining(", ")));
244+
}
245+
return builder.toString();
246+
}
247+
248+
private String metadataSubjects(Metadata metadata) {
249+
String name = "";
250+
if (!metadata.getGroupId().isEmpty()) {
251+
name += metadata.getGroupId();
252+
if (!metadata.getArtifactId().isEmpty()) {
253+
name += ":" + metadata.getArtifactId();
254+
if (!metadata.getVersion().isEmpty()) {
255+
name += ":" + metadata.getVersion();
256+
}
257+
}
258+
}
259+
if (!metadata.getType().isEmpty()) {
260+
name += (name.isEmpty() ? "" : ":") + metadata.getType();
261+
}
262+
return name;
263+
}
264+
225265
private void closeAll() {
226266
if (locks.isEmpty()) {
227267
return;

src/site/markdown/configuration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ under the License.
103103
| `aether.syncContext.named.nameMapper` | String | Name of name mapper implementing the `org.eclipse.aether.internal.impl.synccontext.named.NameMapper` interface. | `"gav"` | no |
104104
| `aether.syncContext.named.retry` | int | Count of retries SyncContext adapter should perform, when obtaining locks. | `1` | no |
105105
| `aether.syncContext.named.retry.wait` | long | Amount of milliseconds a thread to wait between retries, when obtaining locks. | `200` | no |
106-
| `aether.syncContext.named.time` | long | Amount of time a synchronization context shall wait to obtain a lock. | `30` | no |
106+
| `aether.syncContext.named.time` | long | Amount of time a synchronization context shall wait to obtain a lock. | `900` | no |
107107
| `aether.syncContext.named.time.unit` | long | Unit of the lock wait time. | `"SECONDS"` | no |
108108
| `aether.syncContext.named.discriminating.discriminator` | String | A discriminator name prefix identifying a Resolver instance. | `"sha1('${hostname:-localhost}:${maven.repo.local}')"` or `"sha1('')"` if generation fails | no |
109109
| `aether.syncContext.named.discriminating.hostname` | String | The hostname to be used with discriminating mapper. | Detected with `InetAddress.getLocalHost().getHostName()` | no |

0 commit comments

Comments
 (0)