Skip to content

Commit 725edd7

Browse files
authored
[MRESOLVER-421] Extend NamedLock API to make possible 1..n lock to name (apache#431)
This PR implements MRESOLVER-421, basically allowing not only 1:1 resource to lock mapping as Named Locks were originally incepted. Also, change lock name to dedicated "key" type, and this improves tremendously logging and diagnostic (ie. if you used hashing name mapper, good luck to tell what artifact it was). This PR also adds tests to Redisson as there were no tests in the module since its inception. --- https://issues.apache.org/jira/browse/MRESOLVER-421
1 parent 393d77c commit 725edd7

File tree

46 files changed

+1345
-414
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1345
-414
lines changed

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.eclipse.aether.RepositorySystemSession;
2828
import org.eclipse.aether.artifact.Artifact;
2929
import org.eclipse.aether.metadata.Metadata;
30+
import org.eclipse.aether.named.NamedLockKey;
3031
import org.eclipse.aether.util.DirectoryUtils;
3132

3233
import static java.util.Objects.requireNonNull;
@@ -82,7 +83,7 @@ public boolean isFileSystemFriendly() {
8283
}
8384

8485
@Override
85-
public Collection<String> nameLocks(
86+
public Collection<NamedLockKey> nameLocks(
8687
final RepositorySystemSession session,
8788
final Collection<? extends Artifact> artifacts,
8889
final Collection<? extends Metadata> metadatas) {
@@ -92,7 +93,8 @@ public Collection<String> nameLocks(
9293
: DirectoryUtils.resolveDirectory(session, DEFAULT_LOCKS_DIR, CONFIG_PROP_LOCKS_DIR, false);
9394

9495
return delegate.nameLocks(session, artifacts, metadatas).stream()
95-
.map(name -> basedir.resolve(name).toAbsolutePath().toUri().toASCIIString())
96+
.map(k -> NamedLockKey.of(
97+
basedir.resolve(k.name()).toAbsolutePath().toUri().toASCIIString(), k.resources()))
9698
.collect(Collectors.toList());
9799
} catch (IOException e) {
98100
throw new UncheckedIOException(e);

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.eclipse.aether.RepositorySystemSession;
2727
import org.eclipse.aether.artifact.Artifact;
2828
import org.eclipse.aether.metadata.Metadata;
29+
import org.eclipse.aether.named.NamedLockKey;
2930
import org.eclipse.aether.util.ConfigUtils;
3031
import org.eclipse.aether.util.StringDigestUtil;
3132
import org.slf4j.Logger;
@@ -86,13 +87,13 @@ public boolean isFileSystemFriendly() {
8687
}
8788

8889
@Override
89-
public Collection<String> nameLocks(
90+
public Collection<NamedLockKey> nameLocks(
9091
final RepositorySystemSession session,
9192
final Collection<? extends Artifact> artifacts,
9293
final Collection<? extends Metadata> metadatas) {
9394
String discriminator = createDiscriminator(session);
9495
return delegate.nameLocks(session, artifacts, metadatas).stream()
95-
.map(s -> discriminator + ":" + s)
96+
.map(k -> NamedLockKey.of(discriminator + ":" + k.name(), k.resources()))
9697
.collect(toList());
9798
}
9899

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

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@
1919
package org.eclipse.aether.internal.impl.synccontext.named;
2020

2121
import java.util.Collection;
22+
import java.util.Comparator;
2223
import java.util.TreeSet;
2324

2425
import org.eclipse.aether.RepositorySystemSession;
2526
import org.eclipse.aether.artifact.Artifact;
2627
import org.eclipse.aether.metadata.Metadata;
28+
import org.eclipse.aether.named.NamedLockKey;
2729

2830
import static java.util.Objects.requireNonNull;
2931

@@ -66,49 +68,53 @@ public boolean isFileSystemFriendly() {
6668
}
6769

6870
@Override
69-
public Collection<String> nameLocks(
71+
public Collection<NamedLockKey> nameLocks(
7072
final RepositorySystemSession session,
7173
final Collection<? extends Artifact> artifacts,
7274
final Collection<? extends Metadata> metadatas) {
7375
// Deadlock prevention: https://stackoverflow.com/a/16780988/696632
7476
// We must acquire multiple locks always in the same order!
75-
TreeSet<String> keys = new TreeSet<>();
77+
TreeSet<NamedLockKey> keys = new TreeSet<>(Comparator.comparing(NamedLockKey::name));
7678
if (artifacts != null) {
7779
for (Artifact artifact : artifacts) {
78-
keys.add(getArtifactName(artifact));
80+
keys.add(NamedLockKey.of(
81+
getArtifactName(artifact, artifactPrefix, fieldSeparator, artifactSuffix),
82+
getArtifactName(artifact, "", ":", "")));
7983
}
8084
}
8185

8286
if (metadatas != null) {
8387
for (Metadata metadata : metadatas) {
84-
keys.add(getMetadataName(metadata));
88+
keys.add(NamedLockKey.of(
89+
getMetadataName(metadata, metadataPrefix, fieldSeparator, metadataSuffix),
90+
getMetadataName(metadata, "", ":", "")));
8591
}
8692
}
8793
return keys;
8894
}
8995

90-
private String getArtifactName(Artifact artifact) {
91-
return artifactPrefix
96+
private static String getArtifactName(Artifact artifact, String prefix, String separator, String suffix) {
97+
return prefix
9298
+ artifact.getGroupId()
93-
+ fieldSeparator
99+
+ separator
94100
+ artifact.getArtifactId()
95-
+ fieldSeparator
101+
+ separator
96102
+ artifact.getBaseVersion()
97-
+ artifactSuffix;
103+
+ suffix;
98104
}
99105

100-
private String getMetadataName(Metadata metadata) {
101-
String name = metadataPrefix;
106+
private static String getMetadataName(Metadata metadata, String prefix, String separator, String suffix) {
107+
String name = prefix;
102108
if (!metadata.getGroupId().isEmpty()) {
103109
name += metadata.getGroupId();
104110
if (!metadata.getArtifactId().isEmpty()) {
105-
name += fieldSeparator + metadata.getArtifactId();
111+
name += separator + metadata.getArtifactId();
106112
if (!metadata.getVersion().isEmpty()) {
107-
name += fieldSeparator + metadata.getVersion();
113+
name += separator + metadata.getVersion();
108114
}
109115
}
110116
}
111-
return name + metadataSuffix;
117+
return name + suffix;
112118
}
113119

114120
public static NameMapper gav() {

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.eclipse.aether.RepositorySystemSession;
2525
import org.eclipse.aether.artifact.Artifact;
2626
import org.eclipse.aether.metadata.Metadata;
27+
import org.eclipse.aether.named.NamedLockKey;
2728
import org.eclipse.aether.util.ConfigUtils;
2829
import org.eclipse.aether.util.StringDigestUtil;
2930

@@ -63,7 +64,7 @@ public boolean isFileSystemFriendly() {
6364
}
6465

6566
@Override
66-
public Collection<String> nameLocks(
67+
public Collection<NamedLockKey> nameLocks(
6768
RepositorySystemSession session,
6869
Collection<? extends Artifact> artifacts,
6970
Collection<? extends Metadata> metadatas) {
@@ -72,7 +73,7 @@ public Collection<String> nameLocks(
7273
throw new IllegalArgumentException("allowed depth value is between 0 and 4 (inclusive)");
7374
}
7475
return delegate.nameLocks(session, artifacts, metadatas).stream()
75-
.map(n -> hashName(n, depth))
76+
.map(k -> NamedLockKey.of(hashName(k.name(), depth), k.resources()))
7677
.collect(Collectors.toList());
7778
}
7879

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.eclipse.aether.RepositorySystemSession;
2424
import org.eclipse.aether.artifact.Artifact;
2525
import org.eclipse.aether.metadata.Metadata;
26+
import org.eclipse.aether.named.NamedLockKey;
2627

2728
/**
2829
* Component mapping lock names to passed in artifacts and metadata as required.
@@ -56,7 +57,7 @@ public interface NameMapper {
5657
* Note: name mapper must not use same string for artifacts and metadata, so even the simplest possible
5758
* implementation like {@link StaticNameMapper} uses two different static strings.
5859
*/
59-
Collection<String> nameLocks(
60+
Collection<NamedLockKey> nameLocks(
6061
RepositorySystemSession session,
6162
Collection<? extends Artifact> artifacts,
6263
Collection<? extends Metadata> metadatas);

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

Lines changed: 54 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
package org.eclipse.aether.internal.impl.synccontext.named;
2020

2121
import java.util.ArrayDeque;
22-
import java.util.ArrayList;
2322
import java.util.Collection;
2423
import java.util.Deque;
2524
import java.util.concurrent.TimeUnit;
@@ -31,6 +30,7 @@
3130
import org.eclipse.aether.metadata.Metadata;
3231
import org.eclipse.aether.named.NamedLock;
3332
import org.eclipse.aether.named.NamedLockFactory;
33+
import org.eclipse.aether.named.NamedLockKey;
3434
import org.eclipse.aether.named.providers.FileLockNamedLockFactory;
3535
import org.eclipse.aether.util.ConfigUtils;
3636
import org.slf4j.Logger;
@@ -196,87 +196,82 @@ private long getRetryWait(final RepositorySystemSession session) {
196196

197197
@Override
198198
public void acquire(Collection<? extends Artifact> artifacts, Collection<? extends Metadata> metadatas) {
199-
Collection<String> keys = lockNaming.nameLocks(session, artifacts, metadatas);
199+
Collection<NamedLockKey> keys = lockNaming.nameLocks(session, artifacts, metadatas);
200200
if (keys.isEmpty()) {
201201
return;
202202
}
203203

204+
final String timeStr = time + " " + timeUnit;
205+
final String lockKind = shared ? "shared" : "exclusive";
206+
final NamedLock namedLock = namedLockFactory.getLock(keys);
207+
if (LOGGER.isTraceEnabled()) {
208+
LOGGER.trace(
209+
"Need {} lock for {} from {}",
210+
lockKind,
211+
namedLock.key().resources(),
212+
namedLock.key().name());
213+
}
214+
204215
final int attempts = retry + 1;
205-
final ArrayList<IllegalStateException> illegalStateExceptions = new ArrayList<>();
206216
for (int attempt = 1; attempt <= attempts; attempt++) {
207-
LOGGER.trace(
208-
"Attempt {}: Need {} {} lock(s) for {}", attempt, keys.size(), shared ? "read" : "write", keys);
209-
int acquiredLockCount = 0;
217+
if (LOGGER.isTraceEnabled()) {
218+
LOGGER.trace(
219+
"Attempt {}: Acquire {} lock from {}",
220+
attempt,
221+
lockKind,
222+
namedLock.key().name());
223+
}
210224
try {
211225
if (attempt > 1) {
212226
Thread.sleep(retryWait);
213227
}
214-
for (String key : keys) {
215-
NamedLock namedLock = namedLockFactory.getLock(key);
216-
LOGGER.trace("Acquiring {} lock for '{}'", shared ? "read" : "write", key);
217-
218-
boolean locked;
219-
if (shared) {
220-
locked = namedLock.lockShared(time, timeUnit);
221-
} else {
222-
locked = namedLock.lockExclusively(time, timeUnit);
223-
}
224-
225-
if (!locked) {
226-
String timeStr = time + " " + timeUnit;
227-
LOGGER.trace(
228-
"Failed to acquire {} lock for '{}' in {}",
229-
shared ? "read" : "write",
230-
key,
231-
timeStr);
232-
233-
namedLock.close();
234-
closeAll();
235-
illegalStateExceptions.add(new IllegalStateException(
236-
"Attempt " + attempt + ": Could not acquire " + (shared ? "read" : "write")
237-
+ " lock for '" + namedLock.name() + "' in " + timeStr));
238-
break;
239-
} else {
240-
locks.push(namedLock);
241-
acquiredLockCount++;
242-
}
228+
boolean locked;
229+
if (shared) {
230+
locked = namedLock.lockShared(time, timeUnit);
231+
} else {
232+
locked = namedLock.lockExclusively(time, timeUnit);
233+
}
234+
235+
if (locked) {
236+
// we are done, get out
237+
locks.push(namedLock);
238+
return;
239+
}
240+
241+
// we failed; retry
242+
if (LOGGER.isTraceEnabled()) {
243+
LOGGER.trace(
244+
"Failed to acquire {} lock for '{}' in {}",
245+
lockKind,
246+
namedLock.key().name(),
247+
timeStr);
243248
}
244249
} catch (InterruptedException e) {
250+
// if we are here, means we were interrupted: fail
251+
close();
245252
Thread.currentThread().interrupt();
246253
throw new RuntimeException(e);
247254
}
248-
LOGGER.trace("Attempt {}: Total locks acquired: {}", attempt, acquiredLockCount);
249-
if (acquiredLockCount == keys.size()) {
250-
break;
251-
}
252-
}
253-
if (!illegalStateExceptions.isEmpty()) {
254-
IllegalStateException ex = new IllegalStateException("Could not acquire lock(s)");
255-
illegalStateExceptions.forEach(ex::addSuppressed);
256-
throw namedLockFactory.onFailure(ex);
257255
}
256+
// if we are here, means all attempts were unsuccessful: fail
257+
close();
258+
IllegalStateException ex = new IllegalStateException("Could not acquire " + lockKind + " lock for "
259+
+ namedLock.key().resources() + " using lock "
260+
+ namedLock.key().name() + " in " + timeStr);
261+
throw namedLockFactory.onFailure(ex);
258262
}
259263

260-
private void closeAll() {
261-
if (locks.isEmpty()) {
262-
return;
263-
}
264-
265-
// Release locks in reverse insertion order
266-
int released = 0;
264+
@Override
265+
public void close() {
267266
while (!locks.isEmpty()) {
268267
try (NamedLock namedLock = locks.pop()) {
269-
LOGGER.trace("Releasing {} lock for '{}'", shared ? "read" : "write", namedLock.name());
270268
namedLock.unlock();
271-
released++;
269+
if (LOGGER.isTraceEnabled()) {
270+
LOGGER.trace(
271+
"Unlocked and closed {} lock of {}", shared ? "shared" : "exclusive", namedLock.key());
272+
}
272273
}
273274
}
274-
LOGGER.trace("Total locks released: {}", released);
275-
}
276-
277-
@Override
278-
public void close() {
279-
closeAll();
280275
}
281276
}
282277
}

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.eclipse.aether.RepositorySystemSession;
2525
import org.eclipse.aether.artifact.Artifact;
2626
import org.eclipse.aether.metadata.Metadata;
27+
import org.eclipse.aether.named.NamedLockKey;
2728

2829
/**
2930
* Static {@link NameMapper}, always assigns one same name, effectively becoming equivalent to "static" sync context:
@@ -36,15 +37,14 @@ public boolean isFileSystemFriendly() {
3637
}
3738

3839
@Override
39-
public Collection<String> nameLocks(
40+
public Collection<NamedLockKey> nameLocks(
4041
final RepositorySystemSession session,
4142
final Collection<? extends Artifact> artifacts,
4243
final Collection<? extends Metadata> metadatas) {
4344
if (artifacts != null && !artifacts.isEmpty()) {
44-
return Collections.singletonList("static-artifact");
45+
return Collections.singletonList(NamedLockKey.of("static-artifact"));
4546
} else if (metadatas != null && !metadatas.isEmpty()) {
46-
return Collections.singletonList("static-metadata");
47-
47+
return Collections.singletonList(NamedLockKey.of("static-metadata"));
4848
} else {
4949
return Collections.emptyList();
5050
}

0 commit comments

Comments
 (0)