From 72a793f55de599c1c8942ed57e7f043e3822c5bc Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Sun, 25 Apr 2021 22:05:42 +0200 Subject: [PATCH 1/2] Introduce ResolverLock, layer on top of low level Named Locks The resolver lock adds a thin layer above low lever named locks, does not leak actualy named lock names, but is keyed by artifact, hence lock ordering is stable (is based on Artifact not on name mapper). Finally, resolver lock factory is able to spice up the logic for locking that is now "hacked in" to not alter SyncContextFactory API. This is EXPERIMENT for testing reasons only. --- .../impl/DefaultArtifactResolver.java | 27 ++-- .../impl/DefaultMetadataResolver.java | 23 +++- .../synccontext/NamedSyncContextFactory.java | 3 +- .../named/DiscriminatingNameMapper.java | 19 +-- .../impl/synccontext/named/GAVNameMapper.java | 49 +++---- .../impl/synccontext/named/NameMapper.java | 7 +- .../named/NamedLockFactoryAdapter.java | 72 ++++------- .../impl/synccontext/named/ResolverLock.java | 122 ++++++++++++++++++ .../named/ResolverLockFactory.java | 112 ++++++++++++++++ .../synccontext/named/StaticNameMapper.java | 14 +- .../NamedLockFactoryAdapterTestSupport.java | 2 +- .../NamedLockFactoryAdapterTestSupport.java | 4 +- .../spi/synccontext/SyncContextHint.java | 36 ++++++ 13 files changed, 373 insertions(+), 117 deletions(-) create mode 100644 maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/ResolverLock.java create mode 100644 maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/ResolverLockFactory.java create mode 100644 maven-resolver-spi/src/main/java/org/eclipse/aether/spi/synccontext/SyncContextHint.java diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultArtifactResolver.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultArtifactResolver.java index 12ef0d696..292a45d0e 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultArtifactResolver.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultArtifactResolver.java @@ -70,6 +70,7 @@ import org.eclipse.aether.spi.io.FileProcessor; import org.eclipse.aether.spi.locator.Service; import org.eclipse.aether.spi.locator.ServiceLocator; +import org.eclipse.aether.spi.synccontext.SyncContextHint; import org.eclipse.aether.transfer.ArtifactNotFoundException; import org.eclipse.aether.transfer.ArtifactTransferException; import org.eclipse.aether.transfer.NoRepositoryConnectorException; @@ -214,21 +215,29 @@ public List resolveArtifacts( RepositorySystemSession session, throws ArtifactResolutionException { - try ( SyncContext syncContext = syncContextFactory.newInstance( session, false ) ) + SyncContextHint.SCOPE.set( SyncContextHint.Scope.RESOLVE ); // HACK + try { - Collection artifacts = new ArrayList<>( requests.size() ); - for ( ArtifactRequest request : requests ) + try ( SyncContext syncContext = syncContextFactory.newInstance( session, false ) ) { - if ( request.getArtifact().getProperty( ArtifactProperties.LOCAL_PATH, null ) != null ) + Collection artifacts = new ArrayList<>( requests.size() ); + for ( ArtifactRequest request : requests ) { - continue; + if ( request.getArtifact().getProperty( ArtifactProperties.LOCAL_PATH, null ) != null ) + { + continue; + } + artifacts.add( request.getArtifact() ); } - artifacts.add( request.getArtifact() ); - } - syncContext.acquire( artifacts, null ); + syncContext.acquire( artifacts, null ); - return resolve( session, requests ); + return resolve( session, requests ); + } + } + finally + { + SyncContextHint.SCOPE.set( null ); } } diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultMetadataResolver.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultMetadataResolver.java index cd217b512..7c4dba79b 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultMetadataResolver.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultMetadataResolver.java @@ -66,6 +66,7 @@ import org.eclipse.aether.spi.connector.RepositoryConnector; import org.eclipse.aether.spi.locator.Service; import org.eclipse.aether.spi.locator.ServiceLocator; +import org.eclipse.aether.spi.synccontext.SyncContextHint; import org.eclipse.aether.transfer.MetadataNotFoundException; import org.eclipse.aether.transfer.MetadataTransferException; import org.eclipse.aether.transfer.NoRepositoryConnectorException; @@ -170,17 +171,25 @@ public List resolveMetadata( RepositorySystemSession session, Collection requests ) { - try ( SyncContext syncContext = syncContextFactory.newInstance( session, false ) ) + SyncContextHint.SCOPE.set( SyncContextHint.Scope.RESOLVE ); // HACK + try { - Collection metadata = new ArrayList<>( requests.size() ); - for ( MetadataRequest request : requests ) + try ( SyncContext syncContext = syncContextFactory.newInstance( session, false ) ) { - metadata.add( request.getMetadata() ); - } + Collection metadata = new ArrayList<>( requests.size() ); + for ( MetadataRequest request : requests ) + { + metadata.add( request.getMetadata() ); + } - syncContext.acquire( null, metadata ); + syncContext.acquire( null, metadata ); - return resolve( session, requests ); + return resolve( session, requests ); + } + } + finally + { + SyncContextHint.SCOPE.set( null ); // HACK } } diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/NamedSyncContextFactory.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/NamedSyncContextFactory.java index ba47c8d45..38f8bed15 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/NamedSyncContextFactory.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/NamedSyncContextFactory.java @@ -25,6 +25,7 @@ import org.eclipse.aether.internal.impl.synccontext.named.GAVNameMapper; import org.eclipse.aether.internal.impl.synccontext.named.NameMapper; import org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactoryAdapter; +import org.eclipse.aether.internal.impl.synccontext.named.ResolverLockFactory; import org.eclipse.aether.internal.impl.synccontext.named.StaticNameMapper; import org.eclipse.aether.named.NamedLockFactory; import org.eclipse.aether.named.providers.LocalReadWriteLockNamedLockFactory; @@ -107,7 +108,7 @@ private static NamedLockFactoryAdapter selectAndAdapt( final Map * The default setup wraps {@link GAVNameMapper}, but manually may be created any instance needed. */ @@ -84,13 +81,17 @@ public DiscriminatingNameMapper( @Named( GAVNameMapper.NAME ) final NameMapper n } @Override - public Collection nameLocks( final RepositorySystemSession session, - final Collection artifacts, - final Collection metadatas ) + public String nameLock( final RepositorySystemSession session, final Artifact artifact ) + { + String discriminator = createDiscriminator( session ); + return discriminator + ":" + nameMapper.nameLock( session, artifact ); + } + + @Override + public String nameLock( final RepositorySystemSession session, Metadata metadata ) { String discriminator = createDiscriminator( session ); - return nameMapper.nameLocks( session, artifacts, metadatas ).stream().map( s -> discriminator + ":" + s ) - .collect( toList() ); + return discriminator + ":" + nameMapper.nameLock( session, metadata ); } private String getHostname() diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/GAVNameMapper.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/GAVNameMapper.java index ea0149c47..6cebb407e 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/GAVNameMapper.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/GAVNameMapper.java @@ -25,8 +25,6 @@ import javax.inject.Named; import javax.inject.Singleton; -import java.util.Collection; -import java.util.TreeSet; /** * Artifact GAV {@link NameMapper}, uses artifact and metadata coordinates to name their corresponding locks. Is not @@ -39,44 +37,29 @@ public class GAVNameMapper implements NameMapper public static final String NAME = "gav"; @Override - public Collection nameLocks( final RepositorySystemSession session, - final Collection artifacts, - final Collection metadatas ) + public String nameLock( final RepositorySystemSession session, final Artifact artifact ) { - // Deadlock prevention: https://stackoverflow.com/a/16780988/696632 - // We must acquire multiple locks always in the same order! - Collection keys = new TreeSet<>(); - if ( artifacts != null ) - { - for ( Artifact artifact : artifacts ) - { - String key = "artifact:" + artifact.getGroupId() - + ":" + artifact.getArtifactId() - + ":" + artifact.getBaseVersion(); - keys.add( key ); - } - } + return "artifact:" + artifact.getGroupId() + + ":" + artifact.getArtifactId() + + ":" + artifact.getBaseVersion(); + } - if ( metadatas != null ) + @Override + public String nameLock( final RepositorySystemSession session, final Metadata metadata ) + { + StringBuilder key = new StringBuilder( "metadata:" ); + if ( !metadata.getGroupId().isEmpty() ) { - for ( Metadata metadata : metadatas ) + key.append( metadata.getGroupId() ); + if ( !metadata.getArtifactId().isEmpty() ) { - StringBuilder key = new StringBuilder( "metadata:" ); - if ( !metadata.getGroupId().isEmpty() ) + key.append( ':' ).append( metadata.getArtifactId() ); + if ( !metadata.getVersion().isEmpty() ) { - key.append( metadata.getGroupId() ); - if ( !metadata.getArtifactId().isEmpty() ) - { - key.append( ':' ).append( metadata.getArtifactId() ); - if ( !metadata.getVersion().isEmpty() ) - { - key.append( ':' ).append( metadata.getVersion() ); - } - } + key.append( ':' ).append( metadata.getVersion() ); } - keys.add( key.toString() ); } } - return keys; + return key.toString(); } } diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/NameMapper.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/NameMapper.java index b5fd2f0e5..89ff3f1c3 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/NameMapper.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/NameMapper.java @@ -23,8 +23,6 @@ import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.metadata.Metadata; -import java.util.Collection; - /** * Component mapping lock names to passed in artifacts and metadata as required. */ @@ -37,6 +35,7 @@ public interface NameMapper * same criteria) to avoid deadlocks by acquiring locks in same order, essentially disregarding the order of * the input collections. */ - Collection nameLocks( RepositorySystemSession session, Collection artifacts, - Collection metadatas ); + String nameLock( RepositorySystemSession session, Artifact artifact ); + + String nameLock( RepositorySystemSession session, Metadata metadata ); } 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 6fb68d31f..beb77fcd9 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 @@ -39,19 +39,16 @@ */ public final class NamedLockFactoryAdapter { - private final NameMapper nameMapper; - - private final NamedLockFactory namedLockFactory; + private final ResolverLockFactory resolverLockFactory; private final long time; private final TimeUnit timeUnit; - public NamedLockFactoryAdapter( final NameMapper nameMapper, final NamedLockFactory namedLockFactory, + public NamedLockFactoryAdapter( final ResolverLockFactory resolverLockFactory, final long time, final TimeUnit timeUnit ) { - this.nameMapper = Objects.requireNonNull( nameMapper ); - this.namedLockFactory = Objects.requireNonNull( namedLockFactory ); + this.resolverLockFactory = resolverLockFactory; if ( time < 0L ) { throw new IllegalArgumentException( "time cannot be negative" ); @@ -62,12 +59,12 @@ public NamedLockFactoryAdapter( final NameMapper nameMapper, final NamedLockFact public SyncContext newInstance( final RepositorySystemSession session, final boolean shared ) { - return new AdaptedLockSyncContext( session, shared, nameMapper, namedLockFactory, time, timeUnit ); + return new AdaptedLockSyncContext( session, shared, resolverLockFactory, time, timeUnit ); } public void shutdown() { - namedLockFactory.shutdown(); + resolverLockFactory.shutdown(); } private static class AdaptedLockSyncContext implements SyncContext @@ -78,28 +75,21 @@ private static class AdaptedLockSyncContext implements SyncContext private final boolean shared; - private final NameMapper lockNaming; - - private final SessionAwareNamedLockFactory sessionAwareNamedLockFactory; - - private final NamedLockFactory namedLockFactory; + private final ResolverLockFactory resolverLockFactory; private final long time; private final TimeUnit timeUnit; - private final Deque locks; + private final Deque locks; private AdaptedLockSyncContext( final RepositorySystemSession session, final boolean shared, - final NameMapper lockNaming, final NamedLockFactory namedLockFactory, + final ResolverLockFactory resolverLockFactory, final long time, final TimeUnit timeUnit ) { this.session = session; this.shared = shared; - this.lockNaming = lockNaming; - this.sessionAwareNamedLockFactory = namedLockFactory instanceof SessionAwareNamedLockFactory - ? (SessionAwareNamedLockFactory) namedLockFactory : null; - this.namedLockFactory = namedLockFactory; + this.resolverLockFactory = resolverLockFactory; this.time = time; this.timeUnit = timeUnit; this.locks = new ArrayDeque<>(); @@ -108,45 +98,35 @@ private AdaptedLockSyncContext( final RepositorySystemSession session, final boo @Override public void acquire( Collection artifacts, Collection metadatas ) { - Collection keys = lockNaming.nameLocks( session, artifacts, metadatas ); - if ( keys.isEmpty() ) + Collection resolverLocks = resolverLockFactory.resolverLocks( + session, shared, artifacts, metadatas ); + if ( resolverLocks.isEmpty() ) { return; } - LOGGER.trace( "Need {} {} lock(s) for {}", keys.size(), shared ? "read" : "write", keys ); + LOGGER.trace( "Need {} {} lock(s) for {}", resolverLocks.size(), shared ? "read" : "write", resolverLocks ); int acquiredLockCount = 0; - for ( String key : keys ) + for ( ResolverLock resolverLock : resolverLocks ) { - NamedLock namedLock = sessionAwareNamedLockFactory != null ? sessionAwareNamedLockFactory - .getLock( session, key ) : namedLockFactory.getLock( key ); try { - LOGGER.trace( "Acquiring {} lock for '{}'", - shared ? "read" : "write", key ); - - boolean locked; - if ( shared ) - { - locked = namedLock.lockShared( time, timeUnit ); - } - else - { - locked = namedLock.lockExclusively( time, timeUnit ); - } + LOGGER.trace( "Acquiring effective {} lock for '{}'", + resolverLock.isEffectiveShared() ? "read" : "write", resolverLock.key() ); + boolean locked = resolverLock.tryLock( time, timeUnit ); if ( !locked ) { - LOGGER.trace( "Failed to acquire {} lock for '{}'", - shared ? "read" : "write", key ); + LOGGER.trace( "Failed to acquire effective {} lock for '{}'", + resolverLock.isEffectiveShared() ? "read" : "write", resolverLock.key() ); - namedLock.close(); + resolverLock.close(); throw new IllegalStateException( - "Could not acquire " + ( shared ? "read" : "write" ) - + " lock for '" + namedLock.name() + "'" ); + "Could not acquire effective " + ( resolverLock.isEffectiveShared() ? "read" : "write" ) + + " lock for '" + resolverLock.key() + "'" ); } - locks.push( namedLock ); + locks.push( resolverLock ); acquiredLockCount++; } catch ( InterruptedException e ) @@ -170,11 +150,11 @@ public void close() int released = 0; while ( !locks.isEmpty() ) { - try ( NamedLock namedLock = locks.pop() ) + try ( ResolverLock resolverLock = locks.pop() ) { LOGGER.trace( "Releasing {} lock for '{}'", - shared ? "read" : "write", namedLock.name() ); - namedLock.unlock(); + shared ? "read" : "write", resolverLock.key() ); + resolverLock.unlock(); released++; } } diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/ResolverLock.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/ResolverLock.java new file mode 100644 index 000000000..89b26b868 --- /dev/null +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/ResolverLock.java @@ -0,0 +1,122 @@ +package org.eclipse.aether.internal.impl.synccontext.named; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.eclipse.aether.named.NamedLock; + +import java.io.Closeable; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +/** + * Resolver lock. + */ +public final class ResolverLock implements Closeable +{ + private final String key; + + private final NamedLock namedLock; + + private final boolean requestedShared; + + private final boolean effectiveShared; + + public ResolverLock( final String key, + final NamedLock namedLock, + final boolean requestedShared, + final boolean effectiveShared ) + { + this.key = Objects.requireNonNull( key ); + this.namedLock = Objects.requireNonNull( namedLock ); + this.requestedShared = requestedShared; + this.effectiveShared = effectiveShared; + } + + public String key() + { + return key; + } + + public boolean isRequestedShared() + { + return requestedShared; + } + + public boolean isEffectiveShared() + { + return effectiveShared; + } + + public boolean tryLock( final long time, final TimeUnit unit ) throws InterruptedException + { + if ( effectiveShared ) + { + return namedLock.lockShared( time, unit ); + } + else + { + return namedLock.lockExclusively( time, unit ); + } + } + + public void unlock() + { + namedLock.unlock(); + } + + @Override + public void close() + { + namedLock.close(); + } + + @Override + public boolean equals( Object o ) + { + if ( this == o ) + { + return true; + } + if ( o == null || getClass() != o.getClass() ) + { + return false; + } + ResolverLock that = (ResolverLock) o; + return key.equals( that.key ); + } + + @Override + public int hashCode() + { + return Objects.hash( key ); + } + + @Override + public String toString() + { + return getClass().getSimpleName() + + "{" + + "key='" + key + '\'' + + ", namedLock=" + namedLock + + ", requestedShared=" + requestedShared + + ", effectiveShared=" + effectiveShared + + '}'; + } +} diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/ResolverLockFactory.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/ResolverLockFactory.java new file mode 100644 index 000000000..f4536d032 --- /dev/null +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/ResolverLockFactory.java @@ -0,0 +1,112 @@ +package org.eclipse.aether.internal.impl.synccontext.named; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.metadata.Metadata; +import org.eclipse.aether.named.NamedLock; +import org.eclipse.aether.named.NamedLockFactory; +import org.eclipse.aether.repository.LocalArtifactRequest; +import org.eclipse.aether.repository.LocalArtifactResult; +import org.eclipse.aether.repository.LocalMetadataRequest; +import org.eclipse.aether.repository.LocalMetadataResult; +import org.eclipse.aether.spi.synccontext.SyncContextHint; + +import java.util.Collection; +import java.util.Comparator; +import java.util.Objects; +import java.util.TreeSet; + +/** + * Component mapping lock names to passed in artifacts and metadata as required. + */ +public final class ResolverLockFactory +{ + private final NameMapper nameMapper; + + private final NamedLockFactory namedLockFactory; + + public ResolverLockFactory( final NameMapper nameMapper, final NamedLockFactory namedLockFactory ) + { + this.nameMapper = Objects.requireNonNull( nameMapper ); + this.namedLockFactory = Objects.requireNonNull( namedLockFactory ); + } + + public Collection resolverLocks( final RepositorySystemSession session, + final boolean shared, + final Collection artifacts, + final Collection metadatas ) + { + TreeSet result = new TreeSet<>( Comparator.comparing( ResolverLock::key ) ); + boolean effectiveShared = shared; + boolean mayOverride = SyncContextHint.Scope.RESOLVE.equals( SyncContextHint.SCOPE.get() ); + + if ( artifacts != null ) + { + for ( Artifact artifact : artifacts ) + { + NamedLock namedLock = namedLockFactory.getLock( nameMapper.nameLock( session, artifact ) ); + if ( mayOverride && !shared ) + { + effectiveShared = isArtifactAvailable( session, artifact ); + } + result.add( new ResolverLock( artifact.toString(), namedLock, shared, effectiveShared ) ); + } + } + + if ( metadatas != null ) + { + for ( Metadata metadata : metadatas ) + { + NamedLock namedLock = namedLockFactory.getLock( nameMapper.nameLock( session, metadata ) ); + if ( mayOverride && !shared ) + { + effectiveShared = isMetadataAvailable( session, metadata ); + } + result.add( new ResolverLock( metadata.toString(), namedLock, shared, effectiveShared ) ); + } + } + + return result; + } + + private boolean isArtifactAvailable( final RepositorySystemSession session, final Artifact artifact ) + { + LocalArtifactRequest request = new LocalArtifactRequest( artifact, null, null ); + LocalArtifactResult result = session.getLocalRepositoryManager().find( session, request ); + return result.isAvailable(); + } + + private boolean isMetadataAvailable( final RepositorySystemSession session, final Metadata metadata ) + { + LocalMetadataRequest request = new LocalMetadataRequest( metadata, null, null ); + LocalMetadataResult result = session.getLocalRepositoryManager().find( session, request ); + return !result.isStale(); + } + + /** + * Performs a clean shut down of the factory. + */ + public void shutdown() + { + namedLockFactory.shutdown(); + } +} diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/StaticNameMapper.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/StaticNameMapper.java index 14fc7e79a..1cb498c12 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/StaticNameMapper.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/StaticNameMapper.java @@ -27,8 +27,6 @@ import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; -import java.util.Collection; -import java.util.Collections; import java.util.Objects; /** @@ -65,10 +63,14 @@ public StaticNameMapper( final String name ) } @Override - public Collection nameLocks( final RepositorySystemSession session, - final Collection artifacts, - final Collection metadatas ) + public String nameLock( final RepositorySystemSession session, Artifact artifact ) { - return Collections.singletonList( ConfigUtils.getString( session, name, CONFIG_PROP_NAME ) ); + return ConfigUtils.getString( session, name, CONFIG_PROP_NAME ); + } + + @Override + public String nameLock( final RepositorySystemSession session, Metadata metadata ) + { + return ConfigUtils.getString( session, name, CONFIG_PROP_NAME ); } } diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/synccontext/NamedLockFactoryAdapterTestSupport.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/synccontext/NamedLockFactoryAdapterTestSupport.java index 87cab6f86..4acf1fccd 100644 --- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/synccontext/NamedLockFactoryAdapterTestSupport.java +++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/synccontext/NamedLockFactoryAdapterTestSupport.java @@ -67,7 +67,7 @@ public abstract class NamedLockFactoryAdapterTestSupport { public static void createAdapter() { Objects.requireNonNull(namedLockFactory, "NamedLockFactory not set"); - adapter = new NamedLockFactoryAdapter(nameMapper, namedLockFactory, ADAPTER_TIME, ADAPTER_TIME_UNIT); + adapter = new NamedLockFactoryAdapter(new ResolverLockFactory( nameMapper, namedLockFactory ), ADAPTER_TIME, ADAPTER_TIME_UNIT); } @AfterClass diff --git a/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/NamedLockFactoryAdapterTestSupport.java b/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/NamedLockFactoryAdapterTestSupport.java index 7fc824179..5471ff715 100644 --- a/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/NamedLockFactoryAdapterTestSupport.java +++ b/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/NamedLockFactoryAdapterTestSupport.java @@ -25,6 +25,7 @@ import org.eclipse.aether.internal.impl.synccontext.named.DiscriminatingNameMapper; import org.eclipse.aether.internal.impl.synccontext.named.GAVNameMapper; import org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactoryAdapter; +import org.eclipse.aether.internal.impl.synccontext.named.ResolverLockFactory; import org.eclipse.aether.named.NamedLockFactory; import org.eclipse.aether.repository.LocalRepository; import org.eclipse.aether.spi.synccontext.SyncContextFactory; @@ -62,7 +63,8 @@ public abstract class NamedLockFactoryAdapterTestSupport protected static void setNamedLockFactory(final NamedLockFactory namedLockFactory) { adapter = new NamedLockFactoryAdapter( - new DiscriminatingNameMapper(new GAVNameMapper()), namedLockFactory, ADAPTER_TIME, ADAPTER_TIME_UNIT + new ResolverLockFactory( new DiscriminatingNameMapper(new GAVNameMapper()), namedLockFactory ), + ADAPTER_TIME, ADAPTER_TIME_UNIT ); } diff --git a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/synccontext/SyncContextHint.java b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/synccontext/SyncContextHint.java new file mode 100644 index 000000000..2904703fe --- /dev/null +++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/synccontext/SyncContextHint.java @@ -0,0 +1,36 @@ +package org.eclipse.aether.spi.synccontext; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * Hint for sync scope implemented as "hack" to not modify SyncContextFactory API. + */ +public final class SyncContextHint +{ + /** + * The scope for which {@link org.eclipse.aether.SyncContext} is to be used. + */ + public enum Scope + { + RESOLVE, DEPLOY, INSTALL + } + + public static final InheritableThreadLocal SCOPE = new InheritableThreadLocal<>(); +} From 165a1d3930dda1d5891958a1472c29eeab4fbd61 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Sun, 25 Apr 2021 22:41:21 +0200 Subject: [PATCH 2/2] Hack more --- .../internal/impl/synccontext/named/ResolverLockFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/ResolverLockFactory.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/ResolverLockFactory.java index f4536d032..f1189ef7a 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/ResolverLockFactory.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/ResolverLockFactory.java @@ -92,14 +92,14 @@ private boolean isArtifactAvailable( final RepositorySystemSession session, fina { LocalArtifactRequest request = new LocalArtifactRequest( artifact, null, null ); LocalArtifactResult result = session.getLocalRepositoryManager().find( session, request ); - return result.isAvailable(); + return result.getFile() != null; } private boolean isMetadataAvailable( final RepositorySystemSession session, final Metadata metadata ) { LocalMetadataRequest request = new LocalMetadataRequest( metadata, null, null ); LocalMetadataResult result = session.getLocalRepositoryManager().find( session, request ); - return !result.isStale(); + return result.getFile() != null; } /**