felix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From tjwat...@apache.org
Subject svn commit: r1789035 - in /felix/trunk/resolver/src: main/java/org/apache/felix/resolver/Candidates.java main/java/org/apache/felix/resolver/ResolverImpl.java test/java/org/apache/felix/resolver/test/ResolverTest.java
Date Tue, 28 Mar 2017 02:42:22 GMT
Author: tjwatson
Date: Tue Mar 28 02:42:22 2017
New Revision: 1789035

URL: http://svn.apache.org/viewvc?rev=1789035&view=rev
Log:
FELIX-5601 - issues resolving with substitutable exports

Modified:
    felix/trunk/resolver/src/main/java/org/apache/felix/resolver/Candidates.java
    felix/trunk/resolver/src/main/java/org/apache/felix/resolver/ResolverImpl.java
    felix/trunk/resolver/src/test/java/org/apache/felix/resolver/test/ResolverTest.java

Modified: felix/trunk/resolver/src/main/java/org/apache/felix/resolver/Candidates.java
URL: http://svn.apache.org/viewvc/felix/trunk/resolver/src/main/java/org/apache/felix/resolver/Candidates.java?rev=1789035&r1=1789034&r2=1789035&view=diff
==============================================================================
--- felix/trunk/resolver/src/main/java/org/apache/felix/resolver/Candidates.java (original)
+++ felix/trunk/resolver/src/main/java/org/apache/felix/resolver/Candidates.java Tue Mar 28
02:42:22 2017
@@ -1203,7 +1203,54 @@ class Candidates
     public boolean canRemoveCandidate(Requirement req)
     {
         CandidateSelector candidates = m_candidateMap.get(req);
-        return ((candidates != null) && (candidates.getRemainingCandidateCount()
> 1 || Util.isOptional(req)));
+        if (candidates != null)
+        {
+            Capability current = candidates.getCurrentCandidate();
+            if (current != null)
+            {
+                // IMPLEMENTATION NOTE:
+                // Here we check for a req that is used for a substitutable export.
+                // If we find a substitutable req then an extra check is done to see
+                // if the substitutable capability is currently depended on as the
+                // only provider of some other requirement.  If it is then we do not
+                // allow the candidate to be removed.
+                // This is done because of the way we attempt to reduce permutations
+                // checked by permuting all used requirements that conflict with a
+                // directly imported/required capability in one go.
+                // If we allowed these types of substitutable requirements to move
+                // to the next capability then the permutation would be thrown out
+                // because it would cause some other resource to not resolve.
+                // That in turn would throw out the complete permutation along with
+                // any follow on permutations that could have resulted.
+                // See ResolverImpl::checkPackageSpaceConsistency
+
+                // Check if the current candidate is substitutable by the req;
+                // This check is necessary here because
+                if (req.equals(m_subtitutableMap.get(current)))
+                {
+                    // this is a substitute req,
+                    // make sure there is not an existing dependency that would fail if we
substitute
+                    Set<Requirement> dependents = m_dependentMap.get(current);
+                    if (dependents != null)
+                    {
+                        for (Requirement dependent : dependents)
+                        {
+                            CandidateSelector dependentSelector = m_candidateMap.get(dependent);
+                            // If the dependent selector only has one capability left then
we know it is
+                            // using the current candidate and has no options left
+                            if (dependentSelector != null && dependentSelector.getRemainingCandidateCount()
<= 1)
+                            {
+                                // return false since we do not want to allow this requirement
+                                // to substitute the capability
+                                return false;
+                            }
+                        }
+                    }
+                }
+            }
+            return candidates.getRemainingCandidateCount() > 1 || Util.isOptional(req);
+        }
+        return false;
     }
 
     static class DynamicImportFailed extends ResolutionError {

Modified: felix/trunk/resolver/src/main/java/org/apache/felix/resolver/ResolverImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/resolver/src/main/java/org/apache/felix/resolver/ResolverImpl.java?rev=1789035&r1=1789034&r2=1789035&view=diff
==============================================================================
--- felix/trunk/resolver/src/main/java/org/apache/felix/resolver/ResolverImpl.java (original)
+++ felix/trunk/resolver/src/main/java/org/apache/felix/resolver/ResolverImpl.java Tue Mar
28 02:42:22 2017
@@ -1288,8 +1288,6 @@ public class ResolverImpl implements Res
         Packages pkgs = resourcePkgMap.get(resource);
 
         ResolutionError rethrow = null;
-        Candidates permutation = null;
-        Set<Requirement> mutated = null;
 
         // Check for conflicting imports from fragments.
         // TODO: Is this only needed for imports or are generic and bundle requirements also
needed?
@@ -1332,6 +1330,16 @@ public class ResolverImpl implements Res
             }
         }
 
+        // IMPLEMENTATION NOTE:
+        // Below we track the mutated reqs that have been permuted
+        // in a single candidates permutation.  This permutation may contain a
+        // delta of several reqs which conflict with a directly imported/required candidates.
+        // When several reqs are permuted at the same time this reduces the number of solutions
tried.
+        // See the method Candidates::canRemoveCandidate for a case where substitutions must
be checked
+        // because of this code that may permute multiple reqs in on candidates permutation.
+        Set<Requirement> mutated = null;
+        Candidates permutation = null;
+
         // Check if there are any uses conflicts with exported packages.
         for (Entry<String, Blame> entry : pkgs.m_exportedPkgs.fast())
         {

Modified: felix/trunk/resolver/src/test/java/org/apache/felix/resolver/test/ResolverTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/resolver/src/test/java/org/apache/felix/resolver/test/ResolverTest.java?rev=1789035&r1=1789034&r2=1789035&view=diff
==============================================================================
--- felix/trunk/resolver/src/test/java/org/apache/felix/resolver/test/ResolverTest.java (original)
+++ felix/trunk/resolver/src/test/java/org/apache/felix/resolver/test/ResolverTest.java Tue
Mar 28 02:42:22 2017
@@ -905,6 +905,14 @@ public class ResolverTest
         resolver.resolve(rci);
     }
 
+    @Test
+    public void testScenario18() throws Exception
+    {
+        ResolveContext rci = populateScenario18();
+        ResolverImpl resolver = new ResolverImpl(new Logger(Logger.LOG_DEBUG), 1);
+        resolver.resolve(rci);
+    }
+
     private ResolveContext populateScenario17(boolean realSubstitute,
         boolean felixResolveContext, boolean existingWirings)
     {
@@ -999,6 +1007,91 @@ public class ResolverTest
         }
     }
 
+    private ResolveContext populateScenario18()
+    {
+        Map<Requirement, List<Capability>> candMap = new HashMap<Requirement,
List<Capability>>();
+
+        ResourceImpl core1 = new ResourceImpl("core1");
+        Capability core1_pkgCap1 = addCap(core1, PackageNamespace.PACKAGE_NAMESPACE,
+            "corepkg1");
+        Capability core1_pkgCap2 = addCap(core1, PackageNamespace.PACKAGE_NAMESPACE,
+            "corepkg2", "corepkg1");
+        Capability core1_pkgCap3 = addCap(core1, PackageNamespace.PACKAGE_NAMESPACE,
+            "corepkg3", "corepkg2");
+
+        ResourceImpl core2 = new ResourceImpl("core2");
+        Capability core2_pkgCap1 = addCap(core2, PackageNamespace.PACKAGE_NAMESPACE,
+            "corepkg1");
+        Capability core2_pkgCap2 = addCap(core2, PackageNamespace.PACKAGE_NAMESPACE,
+            "corepkg2", "corepkg1");
+        Capability core2_pkgCap3 = addCap(core2, PackageNamespace.PACKAGE_NAMESPACE,
+            "corepkg3", "corepkg2");
+        Requirement core2_pkgReq1 = addReq(core2, PackageNamespace.PACKAGE_NAMESPACE,
+            "corepkg1");
+        Requirement core2_pkgReq2 = addReq(core2, PackageNamespace.PACKAGE_NAMESPACE,
+            "corepkg2");
+        Requirement core2_pkgReq3 = addReq(core2, PackageNamespace.PACKAGE_NAMESPACE,
+            "corepkg3");
+
+        ResourceImpl core3 = new ResourceImpl("core3");
+        Capability core3_pkgCap1 = addCap(core3, PackageNamespace.PACKAGE_NAMESPACE,
+            "corepkg1");
+        Capability core3_pkgCap2 = addCap(core3, PackageNamespace.PACKAGE_NAMESPACE,
+            "corepkg2", "corepkg1");
+        Capability core3_pkgCap3 = addCap(core3, PackageNamespace.PACKAGE_NAMESPACE,
+            "corepkg3", "corepkg2");
+        Requirement core3_pkgReq1 = addReq(core3, PackageNamespace.PACKAGE_NAMESPACE,
+            "corepkg1");
+        Requirement core3_pkgReq2 = addReq(core3, PackageNamespace.PACKAGE_NAMESPACE,
+            "corepkg2");
+        Requirement core3_pkgReq3 = addReq(core3, PackageNamespace.PACKAGE_NAMESPACE,
+            "corepkg3");
+
+        ResourceImpl client1 = new ResourceImpl("client1");
+        Capability client1_pkgCap = addCap(client1, PackageNamespace.PACKAGE_NAMESPACE,
+            "clientpkg1", "corepkg3");
+        Requirement client1_pkgReq1 = addReq(client1, PackageNamespace.PACKAGE_NAMESPACE,
+            "corepkg3");
+
+        ResourceImpl client2 = new ResourceImpl("client2");
+        Capability client2_pkgCap = addCap(client2, PackageNamespace.PACKAGE_NAMESPACE,
+            "clientpkg1", "corepkg3");
+        Requirement client2_pkgReq1 = addReq(client2, PackageNamespace.PACKAGE_NAMESPACE,
+            "corepkg3");
+
+        ResourceImpl bundle1 = new ResourceImpl("bundle1");
+        Requirement bundle1_pkgReq1 = addReq(bundle1, PackageNamespace.PACKAGE_NAMESPACE,
+            "corepkg1");
+        Requirement bundle1_pkgReq2 = addReq(bundle1, PackageNamespace.PACKAGE_NAMESPACE,
+            "clientpkg1");
+
+        ResourceImpl bundle2 = new ResourceImpl("bundle2");
+        Requirement bundle2_pkgReq1 = addReq(bundle2, PackageNamespace.PACKAGE_NAMESPACE,
+            "corepkg1");
+
+        candMap.put(core2_pkgReq1, Arrays.asList(core3_pkgCap1, core2_pkgCap1));
+        candMap.put(core2_pkgReq2, Arrays.asList(core3_pkgCap2, core2_pkgCap2));
+        candMap.put(core2_pkgReq3, Arrays.asList(core3_pkgCap3, core2_pkgCap3));
+
+        candMap.put(core3_pkgReq1, Arrays.asList(core3_pkgCap1, core2_pkgCap1));
+        candMap.put(core3_pkgReq2, Arrays.asList(core3_pkgCap2, core2_pkgCap2));
+        candMap.put(core3_pkgReq3, Arrays.asList(core3_pkgCap3, core2_pkgCap3));
+
+        candMap.put(client1_pkgReq1,
+            Arrays.asList(core3_pkgCap3, core2_pkgCap3, core1_pkgCap3));
+        candMap.put(client2_pkgReq1, Arrays.asList(core3_pkgCap3));
+
+        candMap.put(bundle1_pkgReq1, Arrays.asList(core1_pkgCap1));
+        candMap.put(bundle1_pkgReq2, Arrays.asList(client1_pkgCap));
+
+        candMap.put(bundle2_pkgReq1, Arrays.asList(core3_pkgCap1));
+
+        Collection<Resource> mandatory = Arrays.<Resource> asList(core1, core2,
core3,
+            client1, client2, bundle1, bundle2);
+        return new ResolveContextImpl(Collections.<Resource, Wiring> emptyMap(), candMap,
+            mandatory, Collections.<Resource> emptyList());
+    }
+
     private static String getResourceName(Resource r)
     {
         return r.getCapabilities(IdentityNamespace.IDENTITY_NAMESPACE).get(0).getAttributes()



Mime
View raw message