You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by cs...@apache.org on 2023/04/05 09:56:09 UTC

[maven-resolver] branch master updated: [MRESOLVER-346] Too eager locking in resolver (#272)

This is an automated email from the ASF dual-hosted git repository.

cstamas pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git


The following commit(s) were added to refs/heads/master by this push:
     new 4c5e9ea9 [MRESOLVER-346] Too eager locking in resolver (#272)
4c5e9ea9 is described below

commit 4c5e9ea98f8815c6df8bf26baa9032c8d9cd5f2d
Author: Tamas Cservenak <ta...@cservenak.net>
AuthorDate: Wed Apr 5 11:56:03 2023 +0200

    [MRESOLVER-346] Too eager locking in resolver (#272)
    
    The locking in resolver is too eager. This PR relaxes locking by introducing use of shared locks (not used before) and following changes:
    * installer -- no change, remains exclusive locking
    * deployer -- laxed to shared locking, as it only reads local repo
    * Artifact and Metadata resolver -- implemented "upgrade", they are optimistic and start with shared lock (and will happily finish if local repo has all) but will "upgrade" to exclusive if remote access (hence local caching) is about to happen.
    
    Best viewed with whitespace ignore, as there are not much change but blocks got nested.
    
    ---
    
    https://issues.apache.org/jira/browse/MRESOLVER-346
---
 .../internal/impl/DefaultArtifactResolver.java     | 356 ++++++++++---------
 .../aether/internal/impl/DefaultDeployer.java      |   2 +-
 .../internal/impl/DefaultMetadataResolver.java     | 385 +++++++++++----------
 3 files changed, 393 insertions(+), 350 deletions(-)

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 d01608e3..a77ab906 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
@@ -247,7 +247,8 @@ public class DefaultArtifactResolver implements ArtifactResolver, Service {
             throws ArtifactResolutionException {
         requireNonNull(session, "session cannot be null");
         requireNonNull(requests, "requests cannot be null");
-        try (SyncContext syncContext = syncContextFactory.newInstance(session, false)) {
+        try (SyncContext shared = syncContextFactory.newInstance(session, true);
+                SyncContext exclusive = syncContextFactory.newInstance(session, false)) {
             Collection<Artifact> artifacts = new ArrayList<>(requests.size());
             for (ArtifactRequest request : requests) {
                 if (request.getArtifact().getProperty(ArtifactProperties.LOCAL_PATH, null) != null) {
@@ -256,207 +257,226 @@ public class DefaultArtifactResolver implements ArtifactResolver, Service {
                 artifacts.add(request.getArtifact());
             }
 
-            syncContext.acquire(artifacts, null);
-
-            return resolve(session, requests);
+            return resolve(shared, exclusive, artifacts, session, requests);
         }
     }
 
     @SuppressWarnings("checkstyle:methodlength")
     private List<ArtifactResult> resolve(
-            RepositorySystemSession session, Collection<? extends ArtifactRequest> requests)
+            SyncContext shared,
+            SyncContext exclusive,
+            Collection<Artifact> subjects,
+            RepositorySystemSession session,
+            Collection<? extends ArtifactRequest> requests)
             throws ArtifactResolutionException {
-        List<ArtifactResult> results = new ArrayList<>(requests.size());
-        boolean failures = false;
-        final boolean simpleLrmInterop = ConfigUtils.getBoolean(session, false, CONFIG_PROP_SIMPLE_LRM_INTEROP);
+        SyncContext current = shared;
+        try {
+            while (true) {
+                current.acquire(subjects, null);
 
-        LocalRepositoryManager lrm = session.getLocalRepositoryManager();
-        WorkspaceReader workspace = session.getWorkspaceReader();
+                boolean failures = false;
+                final List<ArtifactResult> results = new ArrayList<>(requests.size());
+                final boolean simpleLrmInterop = ConfigUtils.getBoolean(session, false, CONFIG_PROP_SIMPLE_LRM_INTEROP);
+                final LocalRepositoryManager lrm = session.getLocalRepositoryManager();
+                final WorkspaceReader workspace = session.getWorkspaceReader();
+                final List<ResolutionGroup> groups = new ArrayList<>();
+                // filter != null: means "filtering applied", if null no filtering applied (behave as before)
+                final RemoteRepositoryFilter filter = remoteRepositoryFilterManager.getRemoteRepositoryFilter(session);
 
-        List<ResolutionGroup> groups = new ArrayList<>();
-        // filter != null: means "filtering applied", if null no filtering applied (behave as before)
-        RemoteRepositoryFilter filter = remoteRepositoryFilterManager.getRemoteRepositoryFilter(session);
+                for (ArtifactRequest request : requests) {
+                    RequestTrace trace = RequestTrace.newChild(request.getTrace(), request);
 
-        for (ArtifactRequest request : requests) {
-            RequestTrace trace = RequestTrace.newChild(request.getTrace(), request);
+                    ArtifactResult result = new ArtifactResult(request);
+                    results.add(result);
 
-            ArtifactResult result = new ArtifactResult(request);
-            results.add(result);
+                    Artifact artifact = request.getArtifact();
 
-            Artifact artifact = request.getArtifact();
+                    if (current == shared) {
+                        artifactResolving(session, trace, artifact);
+                    }
 
-            artifactResolving(session, trace, artifact);
+                    String localPath = artifact.getProperty(ArtifactProperties.LOCAL_PATH, null);
+                    if (localPath != null) {
+                        // unhosted artifact, just validate file
+                        File file = new File(localPath);
+                        if (!file.isFile()) {
+                            failures = true;
+                            result.addException(new ArtifactNotFoundException(artifact, null));
+                        } else {
+                            artifact = artifact.setFile(file);
+                            result.setArtifact(artifact);
+                            artifactResolved(session, trace, artifact, null, result.getExceptions());
+                        }
+                        continue;
+                    }
 
-            String localPath = artifact.getProperty(ArtifactProperties.LOCAL_PATH, null);
-            if (localPath != null) {
-                // unhosted artifact, just validate file
-                File file = new File(localPath);
-                if (!file.isFile()) {
-                    failures = true;
-                    result.addException(new ArtifactNotFoundException(artifact, null));
-                } else {
-                    artifact = artifact.setFile(file);
-                    result.setArtifact(artifact);
-                    artifactResolved(session, trace, artifact, null, result.getExceptions());
-                }
-                continue;
-            }
+                    List<RemoteRepository> remoteRepositories = request.getRepositories();
+                    List<RemoteRepository> filteredRemoteRepositories = new ArrayList<>(remoteRepositories);
+                    if (filter != null) {
+                        for (RemoteRepository repository : remoteRepositories) {
+                            RemoteRepositoryFilter.Result filterResult = filter.acceptArtifact(repository, artifact);
+                            if (!filterResult.isAccepted()) {
+                                result.addException(new ArtifactFilteredOutException(
+                                        artifact, repository, filterResult.reasoning()));
+                                filteredRemoteRepositories.remove(repository);
+                            }
+                        }
+                    }
 
-            List<RemoteRepository> remoteRepositories = request.getRepositories();
-            List<RemoteRepository> filteredRemoteRepositories = new ArrayList<>(remoteRepositories);
-            if (filter != null) {
-                for (RemoteRepository repository : remoteRepositories) {
-                    RemoteRepositoryFilter.Result filterResult = filter.acceptArtifact(repository, artifact);
-                    if (!filterResult.isAccepted()) {
-                        result.addException(
-                                new ArtifactFilteredOutException(artifact, repository, filterResult.reasoning()));
-                        filteredRemoteRepositories.remove(repository);
+                    VersionResult versionResult;
+                    try {
+                        VersionRequest versionRequest =
+                                new VersionRequest(artifact, filteredRemoteRepositories, request.getRequestContext());
+                        versionRequest.setTrace(trace);
+                        versionResult = versionResolver.resolveVersion(session, versionRequest);
+                    } catch (VersionResolutionException e) {
+                        result.addException(e);
+                        continue;
                     }
-                }
-            }
 
-            VersionResult versionResult;
-            try {
-                VersionRequest versionRequest =
-                        new VersionRequest(artifact, filteredRemoteRepositories, request.getRequestContext());
-                versionRequest.setTrace(trace);
-                versionResult = versionResolver.resolveVersion(session, versionRequest);
-            } catch (VersionResolutionException e) {
-                result.addException(e);
-                continue;
-            }
+                    artifact = artifact.setVersion(versionResult.getVersion());
 
-            artifact = artifact.setVersion(versionResult.getVersion());
+                    if (versionResult.getRepository() != null) {
+                        if (versionResult.getRepository() instanceof RemoteRepository) {
+                            filteredRemoteRepositories =
+                                    Collections.singletonList((RemoteRepository) versionResult.getRepository());
+                        } else {
+                            filteredRemoteRepositories = Collections.emptyList();
+                        }
+                    }
 
-            if (versionResult.getRepository() != null) {
-                if (versionResult.getRepository() instanceof RemoteRepository) {
-                    filteredRemoteRepositories =
-                            Collections.singletonList((RemoteRepository) versionResult.getRepository());
-                } else {
-                    filteredRemoteRepositories = Collections.emptyList();
-                }
-            }
+                    if (workspace != null) {
+                        File file = workspace.findArtifact(artifact);
+                        if (file != null) {
+                            artifact = artifact.setFile(file);
+                            result.setArtifact(artifact);
+                            result.setRepository(workspace.getRepository());
+                            artifactResolved(session, trace, artifact, result.getRepository(), null);
+                            continue;
+                        }
+                    }
 
-            if (workspace != null) {
-                File file = workspace.findArtifact(artifact);
-                if (file != null) {
-                    artifact = artifact.setFile(file);
-                    result.setArtifact(artifact);
-                    result.setRepository(workspace.getRepository());
-                    artifactResolved(session, trace, artifact, result.getRepository(), null);
-                    continue;
-                }
-            }
+                    LocalArtifactResult local = lrm.find(
+                            session,
+                            new LocalArtifactRequest(
+                                    artifact, filteredRemoteRepositories, request.getRequestContext()));
+                    result.setLocalArtifactResult(local);
+                    boolean found = (filter != null && local.isAvailable()) || isLocallyInstalled(local, versionResult);
+                    // with filtering it is availability that drives logic
+                    // without filtering it is simply presence of file that drives the logic
+                    // "interop" logic with simple LRM leads to RRF breakage: hence is ignored when filtering in effect
+                    if (found) {
+                        if (local.getRepository() != null) {
+                            result.setRepository(local.getRepository());
+                        } else {
+                            result.setRepository(lrm.getRepository());
+                        }
+
+                        try {
+                            artifact = artifact.setFile(getFile(session, artifact, local.getFile()));
+                            result.setArtifact(artifact);
+                            artifactResolved(session, trace, artifact, result.getRepository(), null);
+                        } catch (ArtifactTransferException e) {
+                            result.addException(e);
+                        }
+                        if (filter == null && simpleLrmInterop && !local.isAvailable()) {
+                            /*
+                             * NOTE: Interop with simple local repository: An artifact installed by a simple local repo
+                             * manager will not show up in the repository tracking file of the enhanced local repository.
+                             * If however the maven-metadata-local.xml tells us the artifact was installed locally, we
+                             * sync the repository tracking file.
+                             */
+                            lrm.add(session, new LocalArtifactRegistration(artifact));
+                        }
+
+                        continue;
+                    }
 
-            LocalArtifactResult local = lrm.find(
-                    session,
-                    new LocalArtifactRequest(artifact, filteredRemoteRepositories, request.getRequestContext()));
-            result.setLocalArtifactResult(local);
-            boolean found = (filter != null && local.isAvailable()) || isLocallyInstalled(local, versionResult);
-            // with filtering it is availability that drives logic
-            // without filtering it is simply presence of file that drives the logic
-            // "interop" logic with simple LRM leads to RRF breakage: hence is ignored when filtering in effect
-            if (found) {
-                if (local.getRepository() != null) {
-                    result.setRepository(local.getRepository());
-                } else {
-                    result.setRepository(lrm.getRepository());
-                }
+                    if (local.getFile() != null) {
+                        LOGGER.info(
+                                "Artifact {} is present in the local repository, but cached from a remote repository ID that is unavailable in current build context, verifying that is downloadable from {}",
+                                artifact,
+                                remoteRepositories);
+                    }
 
-                try {
-                    artifact = artifact.setFile(getFile(session, artifact, local.getFile()));
-                    result.setArtifact(artifact);
-                    artifactResolved(session, trace, artifact, result.getRepository(), null);
-                } catch (ArtifactTransferException e) {
-                    result.addException(e);
-                }
-                if (filter == null && simpleLrmInterop && !local.isAvailable()) {
-                    /*
-                     * NOTE: Interop with simple local repository: An artifact installed by a simple local repo
-                     * manager will not show up in the repository tracking file of the enhanced local repository.
-                     * If however the maven-metadata-local.xml tells us the artifact was installed locally, we
-                     * sync the repository tracking file.
-                     */
-                    lrm.add(session, new LocalArtifactRegistration(artifact));
+                    LOGGER.debug("Resolving artifact {} from {}", artifact, remoteRepositories);
+                    AtomicBoolean resolved = new AtomicBoolean(false);
+                    Iterator<ResolutionGroup> groupIt = groups.iterator();
+                    for (RemoteRepository repo : filteredRemoteRepositories) {
+                        if (!repo.getPolicy(artifact.isSnapshot()).isEnabled()) {
+                            continue;
+                        }
+
+                        try {
+                            Utils.checkOffline(session, offlineController, repo);
+                        } catch (RepositoryOfflineException e) {
+                            Exception exception = new ArtifactNotFoundException(
+                                    artifact,
+                                    repo,
+                                    "Cannot access " + repo.getId() + " ("
+                                            + repo.getUrl() + ") in offline mode and the artifact " + artifact
+                                            + " has not been downloaded from it before.",
+                                    e);
+                            result.addException(exception);
+                            continue;
+                        }
+
+                        ResolutionGroup group = null;
+                        while (groupIt.hasNext()) {
+                            ResolutionGroup t = groupIt.next();
+                            if (t.matches(repo)) {
+                                group = t;
+                                break;
+                            }
+                        }
+                        if (group == null) {
+                            group = new ResolutionGroup(repo);
+                            groups.add(group);
+                            groupIt = Collections.emptyIterator();
+                        }
+                        group.items.add(new ResolutionItem(trace, artifact, resolved, result, local, repo));
+                    }
                 }
 
-                continue;
-            }
-
-            if (local.getFile() != null) {
-                LOGGER.info(
-                        "Artifact {} is present in the local repository, but cached from a remote repository ID that is unavailable in current build context, verifying that is downloadable from {}",
-                        artifact,
-                        remoteRepositories);
-            }
-
-            LOGGER.debug("Resolving artifact {} from {}", artifact, remoteRepositories);
-            AtomicBoolean resolved = new AtomicBoolean(false);
-            Iterator<ResolutionGroup> groupIt = groups.iterator();
-            for (RemoteRepository repo : filteredRemoteRepositories) {
-                if (!repo.getPolicy(artifact.isSnapshot()).isEnabled()) {
+                if (!groups.isEmpty() && current == shared) {
+                    current.close();
+                    current = exclusive;
                     continue;
                 }
 
-                try {
-                    Utils.checkOffline(session, offlineController, repo);
-                } catch (RepositoryOfflineException e) {
-                    Exception exception = new ArtifactNotFoundException(
-                            artifact,
-                            repo,
-                            "Cannot access " + repo.getId() + " ("
-                                    + repo.getUrl() + ") in offline mode and the artifact " + artifact
-                                    + " has not been downloaded from it before.",
-                            e);
-                    result.addException(exception);
-                    continue;
+                for (ResolutionGroup group : groups) {
+                    performDownloads(session, group);
                 }
 
-                ResolutionGroup group = null;
-                while (groupIt.hasNext()) {
-                    ResolutionGroup t = groupIt.next();
-                    if (t.matches(repo)) {
-                        group = t;
-                        break;
-                    }
-                }
-                if (group == null) {
-                    group = new ResolutionGroup(repo);
-                    groups.add(group);
-                    groupIt = Collections.emptyIterator();
+                for (ArtifactResolverPostProcessor artifactResolverPostProcessor :
+                        artifactResolverPostProcessors.values()) {
+                    artifactResolverPostProcessor.postProcess(session, results);
                 }
-                group.items.add(new ResolutionItem(trace, artifact, resolved, result, local, repo));
-            }
-        }
-
-        for (ResolutionGroup group : groups) {
-            performDownloads(session, group);
-        }
-
-        for (ArtifactResolverPostProcessor artifactResolverPostProcessor : artifactResolverPostProcessors.values()) {
-            artifactResolverPostProcessor.postProcess(session, results);
-        }
 
-        for (ArtifactResult result : results) {
-            ArtifactRequest request = result.getRequest();
+                for (ArtifactResult result : results) {
+                    ArtifactRequest request = result.getRequest();
+
+                    Artifact artifact = result.getArtifact();
+                    if (artifact == null || artifact.getFile() == null) {
+                        failures = true;
+                        if (result.getExceptions().isEmpty()) {
+                            Exception exception = new ArtifactNotFoundException(request.getArtifact(), null);
+                            result.addException(exception);
+                        }
+                        RequestTrace trace = RequestTrace.newChild(request.getTrace(), request);
+                        artifactResolved(session, trace, request.getArtifact(), null, result.getExceptions());
+                    }
+                }
 
-            Artifact artifact = result.getArtifact();
-            if (artifact == null || artifact.getFile() == null) {
-                failures = true;
-                if (result.getExceptions().isEmpty()) {
-                    Exception exception = new ArtifactNotFoundException(request.getArtifact(), null);
-                    result.addException(exception);
+                if (failures) {
+                    throw new ArtifactResolutionException(results);
                 }
-                RequestTrace trace = RequestTrace.newChild(request.getTrace(), request);
-                artifactResolved(session, trace, request.getArtifact(), null, result.getExceptions());
-            }
-        }
 
-        if (failures) {
-            throw new ArtifactResolutionException(results);
+                return results;
+            }
+        } finally {
+            current.close();
         }
-
-        return results;
     }
 
     private boolean isLocallyInstalled(LocalArtifactResult lar, VersionResult vr) {
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDeployer.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDeployer.java
index df24742f..be9df02c 100644
--- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDeployer.java
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDeployer.java
@@ -197,7 +197,7 @@ public class DefaultDeployer implements Deployer, Service {
                     e);
         }
 
-        try (SyncContext syncContext = syncContextFactory.newInstance(session, false)) {
+        try (SyncContext syncContext = syncContextFactory.newInstance(session, true)) {
             return deploy(syncContext, session, request);
         }
     }
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 a6743958..48cca3be 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
@@ -169,222 +169,245 @@ public class DefaultMetadataResolver implements MetadataResolver, Service {
             RepositorySystemSession session, Collection<? extends MetadataRequest> requests) {
         requireNonNull(session, "session cannot be null");
         requireNonNull(requests, "requests cannot be null");
-        try (SyncContext syncContext = syncContextFactory.newInstance(session, false)) {
+        try (SyncContext shared = syncContextFactory.newInstance(session, true);
+                SyncContext exclusive = syncContextFactory.newInstance(session, false)) {
             Collection<Metadata> metadata = new ArrayList<>(requests.size());
             for (MetadataRequest request : requests) {
                 metadata.add(request.getMetadata());
             }
 
-            syncContext.acquire(null, metadata);
-
-            return resolve(session, requests);
+            return resolve(shared, exclusive, metadata, session, requests);
         }
     }
 
     @SuppressWarnings("checkstyle:methodlength")
     private List<MetadataResult> resolve(
-            RepositorySystemSession session, Collection<? extends MetadataRequest> requests) {
-        List<MetadataResult> results = new ArrayList<>(requests.size());
-
-        List<ResolveTask> tasks = new ArrayList<>(requests.size());
+            SyncContext shared,
+            SyncContext exclusive,
+            Collection<Metadata> subjects,
+            RepositorySystemSession session,
+            Collection<? extends MetadataRequest> requests) {
+        SyncContext current = shared;
+        try {
+            while (true) {
+                current.acquire(null, subjects);
 
-        Map<File, Long> localLastUpdates = new HashMap<>();
+                final List<MetadataResult> results = new ArrayList<>(requests.size());
+                final List<ResolveTask> tasks = new ArrayList<>(requests.size());
+                final Map<File, Long> localLastUpdates = new HashMap<>();
+                final RemoteRepositoryFilter remoteRepositoryFilter =
+                        remoteRepositoryFilterManager.getRemoteRepositoryFilter(session);
 
-        RemoteRepositoryFilter remoteRepositoryFilter =
-                remoteRepositoryFilterManager.getRemoteRepositoryFilter(session);
+                for (MetadataRequest request : requests) {
+                    RequestTrace trace = RequestTrace.newChild(request.getTrace(), request);
 
-        for (MetadataRequest request : requests) {
-            RequestTrace trace = RequestTrace.newChild(request.getTrace(), request);
+                    MetadataResult result = new MetadataResult(request);
+                    results.add(result);
 
-            MetadataResult result = new MetadataResult(request);
-            results.add(result);
+                    Metadata metadata = request.getMetadata();
+                    RemoteRepository repository = request.getRepository();
 
-            Metadata metadata = request.getMetadata();
-            RemoteRepository repository = request.getRepository();
+                    if (repository == null) {
+                        LocalRepository localRepo =
+                                session.getLocalRepositoryManager().getRepository();
 
-            if (repository == null) {
-                LocalRepository localRepo = session.getLocalRepositoryManager().getRepository();
+                        metadataResolving(session, trace, metadata, localRepo);
 
-                metadataResolving(session, trace, metadata, localRepo);
+                        File localFile = getLocalFile(session, metadata);
 
-                File localFile = getLocalFile(session, metadata);
+                        if (localFile != null) {
+                            metadata = metadata.setFile(localFile);
+                            result.setMetadata(metadata);
+                        } else {
+                            result.setException(new MetadataNotFoundException(metadata, localRepo));
+                        }
 
-                if (localFile != null) {
-                    metadata = metadata.setFile(localFile);
-                    result.setMetadata(metadata);
-                } else {
-                    result.setException(new MetadataNotFoundException(metadata, localRepo));
-                }
-
-                metadataResolved(session, trace, metadata, localRepo, result.getException());
-                continue;
-            }
-
-            if (remoteRepositoryFilter != null) {
-                RemoteRepositoryFilter.Result filterResult =
-                        remoteRepositoryFilter.acceptMetadata(repository, metadata);
-                if (!filterResult.isAccepted()) {
-                    result.setException(new MetadataNotFoundException(metadata, repository, filterResult.reasoning()));
-                    continue;
-                }
-            }
-
-            List<RemoteRepository> repositories = getEnabledSourceRepositories(repository, metadata.getNature());
-
-            if (repositories.isEmpty()) {
-                continue;
-            }
+                        metadataResolved(session, trace, metadata, localRepo, result.getException());
+                        continue;
+                    }
 
-            metadataResolving(session, trace, metadata, repository);
-            LocalRepositoryManager lrm = session.getLocalRepositoryManager();
-            LocalMetadataRequest localRequest =
-                    new LocalMetadataRequest(metadata, repository, request.getRequestContext());
-            LocalMetadataResult lrmResult = lrm.find(session, localRequest);
+                    if (remoteRepositoryFilter != null) {
+                        RemoteRepositoryFilter.Result filterResult =
+                                remoteRepositoryFilter.acceptMetadata(repository, metadata);
+                        if (!filterResult.isAccepted()) {
+                            result.setException(
+                                    new MetadataNotFoundException(metadata, repository, filterResult.reasoning()));
+                            continue;
+                        }
+                    }
 
-            File metadataFile = lrmResult.getFile();
+                    List<RemoteRepository> repositories =
+                            getEnabledSourceRepositories(repository, metadata.getNature());
 
-            try {
-                Utils.checkOffline(session, offlineController, repository);
-            } catch (RepositoryOfflineException e) {
-                if (metadataFile != null) {
-                    metadata = metadata.setFile(metadataFile);
-                    result.setMetadata(metadata);
-                } else {
-                    String msg = "Cannot access " + repository.getId() + " (" + repository.getUrl()
-                            + ") in offline mode and the metadata " + metadata
-                            + " has not been downloaded from it before";
-                    result.setException(new MetadataNotFoundException(metadata, repository, msg, e));
-                }
+                    if (repositories.isEmpty()) {
+                        continue;
+                    }
 
-                metadataResolved(session, trace, metadata, repository, result.getException());
-                continue;
-            }
+                    metadataResolving(session, trace, metadata, repository);
+                    LocalRepositoryManager lrm = session.getLocalRepositoryManager();
+                    LocalMetadataRequest localRequest =
+                            new LocalMetadataRequest(metadata, repository, request.getRequestContext());
+                    LocalMetadataResult lrmResult = lrm.find(session, localRequest);
+
+                    File metadataFile = lrmResult.getFile();
+
+                    try {
+                        Utils.checkOffline(session, offlineController, repository);
+                    } catch (RepositoryOfflineException e) {
+                        if (metadataFile != null) {
+                            metadata = metadata.setFile(metadataFile);
+                            result.setMetadata(metadata);
+                        } else {
+                            String msg = "Cannot access " + repository.getId() + " (" + repository.getUrl()
+                                    + ") in offline mode and the metadata " + metadata
+                                    + " has not been downloaded from it before";
+                            result.setException(new MetadataNotFoundException(metadata, repository, msg, e));
+                        }
+
+                        metadataResolved(session, trace, metadata, repository, result.getException());
+                        continue;
+                    }
 
-            Long localLastUpdate = null;
-            if (request.isFavorLocalRepository()) {
-                File localFile = getLocalFile(session, metadata);
-                localLastUpdate = localLastUpdates.get(localFile);
-                if (localLastUpdate == null) {
-                    localLastUpdate = localFile != null ? localFile.lastModified() : 0;
-                    localLastUpdates.put(localFile, localLastUpdate);
-                }
-            }
+                    Long localLastUpdate = null;
+                    if (request.isFavorLocalRepository()) {
+                        File localFile = getLocalFile(session, metadata);
+                        localLastUpdate = localLastUpdates.get(localFile);
+                        if (localLastUpdate == null) {
+                            localLastUpdate = localFile != null ? localFile.lastModified() : 0;
+                            localLastUpdates.put(localFile, localLastUpdate);
+                        }
+                    }
 
-            List<UpdateCheck<Metadata, MetadataTransferException>> checks = new ArrayList<>();
-            Exception exception = null;
-            for (RemoteRepository repo : repositories) {
-                UpdateCheck<Metadata, MetadataTransferException> check = new UpdateCheck<>();
-                check.setLocalLastUpdated((localLastUpdate != null) ? localLastUpdate : 0);
-                check.setItem(metadata);
-
-                // use 'main' installation file for the check (-> use requested repository)
-                File checkFile = new File(
-                        session.getLocalRepository().getBasedir(),
-                        session.getLocalRepositoryManager()
-                                .getPathForRemoteMetadata(metadata, repository, request.getRequestContext()));
-                check.setFile(checkFile);
-                check.setRepository(repository);
-                check.setAuthoritativeRepository(repo);
-                check.setPolicy(getPolicy(session, repo, metadata.getNature()).getUpdatePolicy());
-
-                if (lrmResult.isStale()) {
-                    checks.add(check);
-                } else {
-                    updateCheckManager.checkMetadata(session, check);
-                    if (check.isRequired()) {
-                        checks.add(check);
-                    } else if (exception == null) {
-                        exception = check.getException();
+                    List<UpdateCheck<Metadata, MetadataTransferException>> checks = new ArrayList<>();
+                    Exception exception = null;
+                    for (RemoteRepository repo : repositories) {
+                        UpdateCheck<Metadata, MetadataTransferException> check = new UpdateCheck<>();
+                        check.setLocalLastUpdated((localLastUpdate != null) ? localLastUpdate : 0);
+                        check.setItem(metadata);
+
+                        // use 'main' installation file for the check (-> use requested repository)
+                        File checkFile = new File(
+                                session.getLocalRepository().getBasedir(),
+                                session.getLocalRepositoryManager()
+                                        .getPathForRemoteMetadata(metadata, repository, request.getRequestContext()));
+                        check.setFile(checkFile);
+                        check.setRepository(repository);
+                        check.setAuthoritativeRepository(repo);
+                        check.setPolicy(
+                                getPolicy(session, repo, metadata.getNature()).getUpdatePolicy());
+
+                        if (lrmResult.isStale()) {
+                            checks.add(check);
+                        } else {
+                            updateCheckManager.checkMetadata(session, check);
+                            if (check.isRequired()) {
+                                checks.add(check);
+                            } else if (exception == null) {
+                                exception = check.getException();
+                            }
+                        }
                     }
-                }
-            }
 
-            if (!checks.isEmpty()) {
-                RepositoryPolicy policy = getPolicy(session, repository, metadata.getNature());
-
-                // install path may be different from lookup path
-                File installFile = new File(
-                        session.getLocalRepository().getBasedir(),
-                        session.getLocalRepositoryManager()
-                                .getPathForRemoteMetadata(
-                                        metadata, request.getRepository(), request.getRequestContext()));
-
-                metadataDownloading(
-                        session,
-                        trace,
-                        result.getRequest().getMetadata(),
-                        result.getRequest().getRepository());
-
-                ResolveTask task =
-                        new ResolveTask(session, trace, result, installFile, checks, policy.getChecksumPolicy());
-                tasks.add(task);
-            } else {
-                result.setException(exception);
-                if (metadataFile != null) {
-                    metadata = metadata.setFile(metadataFile);
-                    result.setMetadata(metadata);
+                    if (!checks.isEmpty()) {
+                        RepositoryPolicy policy = getPolicy(session, repository, metadata.getNature());
+
+                        // install path may be different from lookup path
+                        File installFile = new File(
+                                session.getLocalRepository().getBasedir(),
+                                session.getLocalRepositoryManager()
+                                        .getPathForRemoteMetadata(
+                                                metadata, request.getRepository(), request.getRequestContext()));
+
+                        metadataDownloading(
+                                session,
+                                trace,
+                                result.getRequest().getMetadata(),
+                                result.getRequest().getRepository());
+
+                        ResolveTask task = new ResolveTask(
+                                session, trace, result, installFile, checks, policy.getChecksumPolicy());
+                        tasks.add(task);
+                    } else {
+                        result.setException(exception);
+                        if (metadataFile != null) {
+                            metadata = metadata.setFile(metadataFile);
+                            result.setMetadata(metadata);
+                        }
+                        metadataResolved(session, trace, metadata, repository, result.getException());
+                    }
                 }
-                metadataResolved(session, trace, metadata, repository, result.getException());
-            }
-        }
-
-        if (!tasks.isEmpty()) {
-            int threads = ExecutorUtils.threadCount(session, 4, CONFIG_PROP_THREADS);
-            Executor executor = ExecutorUtils.executor(
-                    Math.min(tasks.size(), threads), getClass().getSimpleName() + '-');
-            try {
-                RunnableErrorForwarder errorForwarder = new RunnableErrorForwarder();
 
-                for (ResolveTask task : tasks) {
-                    executor.execute(errorForwarder.wrap(task));
+                if (!tasks.isEmpty() && current == shared) {
+                    current.close();
+                    current = exclusive;
+                    continue;
                 }
 
-                errorForwarder.await();
-
-                for (ResolveTask task : tasks) {
-                    /*
-                     * NOTE: Touch after registration with local repo to ensure concurrent resolution is not
-                     * rejected with "already updated" via session data when actual update to local repo is
-                     * still pending.
-                     */
-                    for (UpdateCheck<Metadata, MetadataTransferException> check : task.checks) {
-                        updateCheckManager.touchMetadata(task.session, check.setException(task.exception));
+                if (!tasks.isEmpty()) {
+                    int threads = ExecutorUtils.threadCount(session, 4, CONFIG_PROP_THREADS);
+                    Executor executor = ExecutorUtils.executor(
+                            Math.min(tasks.size(), threads), getClass().getSimpleName() + '-');
+                    try {
+                        RunnableErrorForwarder errorForwarder = new RunnableErrorForwarder();
+
+                        for (ResolveTask task : tasks) {
+                            executor.execute(errorForwarder.wrap(task));
+                        }
+
+                        errorForwarder.await();
+
+                        for (ResolveTask task : tasks) {
+                            /*
+                             * NOTE: Touch after registration with local repo to ensure concurrent resolution is not
+                             * rejected with "already updated" via session data when actual update to local repo is
+                             * still pending.
+                             */
+                            for (UpdateCheck<Metadata, MetadataTransferException> check : task.checks) {
+                                updateCheckManager.touchMetadata(task.session, check.setException(task.exception));
+                            }
+
+                            metadataDownloaded(
+                                    session,
+                                    task.trace,
+                                    task.request.getMetadata(),
+                                    task.request.getRepository(),
+                                    task.metadataFile,
+                                    task.exception);
+
+                            task.result.setException(task.exception);
+                        }
+                    } finally {
+                        ExecutorUtils.shutdown(executor);
+                    }
+                    for (ResolveTask task : tasks) {
+                        Metadata metadata = task.request.getMetadata();
+                        // re-lookup metadata for resolve
+                        LocalMetadataRequest localRequest = new LocalMetadataRequest(
+                                metadata, task.request.getRepository(), task.request.getRequestContext());
+                        File metadataFile = session.getLocalRepositoryManager()
+                                .find(session, localRequest)
+                                .getFile();
+                        if (metadataFile != null) {
+                            metadata = metadata.setFile(metadataFile);
+                            task.result.setMetadata(metadata);
+                        }
+                        if (task.result.getException() == null) {
+                            task.result.setUpdated(true);
+                        }
+                        metadataResolved(
+                                session,
+                                task.trace,
+                                metadata,
+                                task.request.getRepository(),
+                                task.result.getException());
                     }
-
-                    metadataDownloaded(
-                            session,
-                            task.trace,
-                            task.request.getMetadata(),
-                            task.request.getRepository(),
-                            task.metadataFile,
-                            task.exception);
-
-                    task.result.setException(task.exception);
-                }
-            } finally {
-                ExecutorUtils.shutdown(executor);
-            }
-            for (ResolveTask task : tasks) {
-                Metadata metadata = task.request.getMetadata();
-                // re-lookup metadata for resolve
-                LocalMetadataRequest localRequest = new LocalMetadataRequest(
-                        metadata, task.request.getRepository(), task.request.getRequestContext());
-                File metadataFile = session.getLocalRepositoryManager()
-                        .find(session, localRequest)
-                        .getFile();
-                if (metadataFile != null) {
-                    metadata = metadata.setFile(metadataFile);
-                    task.result.setMetadata(metadata);
-                }
-                if (task.result.getException() == null) {
-                    task.result.setUpdated(true);
                 }
-                metadataResolved(
-                        session, task.trace, metadata, task.request.getRepository(), task.result.getException());
+
+                return results;
             }
+        } finally {
+            current.close();
         }
-
-        return results;
     }
 
     private File getLocalFile(RepositorySystemSession session, Metadata metadata) {