Author: rickhall
Date: Tue Dec 11 21:18:21 2012
New Revision: 1420414
URL: http://svn.apache.org/viewvc?rev=1420414&view=rev
Log:
Apply patch (FELIX-3715) to make resolver thread safe.
Modified:
felix/trunk/resolver/src/main/java/org/apache/felix/resolver/ResolverImpl.java
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=1420414&r1=1420413&r2=1420414&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 Dec 11 21:18:21 2012
@@ -47,17 +47,62 @@ import org.osgi.service.resolver.Resolve
public class ResolverImpl implements Resolver
{
private final Logger m_logger;
- // Holds candidate permutations based on permutating "uses" chains.
- // These permutations are given higher priority.
- private final List<Candidates> m_usesPermutations = new
ArrayList<Candidates>();
- // Holds candidate permutations based on permutating requirement
candidates.
- // These permutations represent backtracking on previous decisions.
- private final List<Candidates> m_importPermutations = new
ArrayList<Candidates>();
- // Holds candidate permutations based on removing candidates that satisfy
- // multiple cardinality requirements.
- // This permutation represents a permutation that is consistent because we
have
- // removed the offending capabilities
- private Candidates m_multipleCardCandidates = null;
+
+ // Note this class is not thread safe.
+ // Only use in the context of a single thread.
+ class ResolveSession
+ {
+ // Holds the resolve context for this session
+ private final ResolveContext m_resolveContext;
+ // Holds candidate permutations based on permutating "uses" chains.
+ // These permutations are given higher priority.
+ private final List<Candidates> m_usesPermutations = new
ArrayList<Candidates>();
+ // Holds candidate permutations based on permutating requirement
candidates.
+ // These permutations represent backtracking on previous decisions.
+ private final List<Candidates> m_importPermutations = new
ArrayList<Candidates>();
+ // Holds candidate permutations based on removing candidates that
satisfy
+ // multiple cardinality requirements.
+ // This permutation represents a permutation that is consistent
because we have
+ // removed the offending capabilities
+ private Candidates m_multipleCardCandidates = null;
+
+ private final Map<Capability, List<Capability>> m_packageSourcesCache
= new HashMap();
+
+ ResolveSession(ResolveContext resolveContext)
+ {
+ m_resolveContext = resolveContext;
+ }
+
+ List<Candidates> getUsesPermutations()
+ {
+ return m_usesPermutations;
+ }
+
+ List<Candidates> getImportPermutations()
+ {
+ return m_importPermutations;
+ }
+
+ Candidates getMultipleCardCandidates()
+ {
+ return m_multipleCardCandidates;
+ }
+
+ void setMultipleCardCandidates(Candidates multipleCardCandidates)
+ {
+ m_multipleCardCandidates = multipleCardCandidates;
+ }
+
+ Map<Capability, List<Capability>> getPackageSourcesCache()
+ {
+ return m_packageSourcesCache;
+ }
+
+ ResolveContext getContext()
+ {
+ return m_resolveContext;
+ }
+ }
public ResolverImpl(Logger logger)
{
@@ -66,6 +111,7 @@ public class ResolverImpl implements Res
public Map<Resource, List<Wire>> resolve(ResolveContext rc) throws
ResolutionException
{
+ ResolveSession session = new ResolveSession(rc);
Map<Resource, List<Wire>> wireMap =
new HashMap<Resource, List<Wire>>();
Map<Resource, Packages> resourcePkgMap =
@@ -144,8 +190,11 @@ public class ResolverImpl implements Res
}
}
+ List<Candidates> usesPermutations =
session.getUsesPermutations();
+ List<Candidates> importPermutations =
session.getImportPermutations();
+
// Record the initial candidate permutation.
- m_usesPermutations.add(allCandidates);
+ usesPermutations.add(allCandidates);
ResolutionException rethrow = null;
@@ -169,15 +218,15 @@ public class ResolverImpl implements Res
rethrow = null;
resourcePkgMap.clear();
- m_packageSourcesCache.clear();
+ session.getPackageSourcesCache().clear();
// Null out each time a new permutation is attempted.
// We only use this to store a valid permutation which is a
// delta of the current permutation.
- m_multipleCardCandidates = null;
+ session.setMultipleCardCandidates(null);
- allCandidates = (m_usesPermutations.size() > 0)
- ? m_usesPermutations.remove(0)
- : m_importPermutations.remove(0);
+ allCandidates = (usesPermutations.size() > 0)
+ ? usesPermutations.remove(0)
+ : importPermutations.remove(0);
//allCandidates.dump();
// Reuse a resultCache map for checking package consistency
// for all resources.
@@ -198,7 +247,7 @@ public class ResolverImpl implements Res
}
calculatePackageSpaces(
- rc, allCandidates.getWrappedHost(target),
allCandidates,
+ session, allCandidates.getWrappedHost(target),
allCandidates,
resourcePkgMap, new HashMap(), new HashSet());
//System.out.println("+++ PACKAGE SPACES START +++");
//dumpResourcePkgMap(resourcePkgMap);
@@ -207,7 +256,7 @@ public class ResolverImpl implements Res
try
{
checkPackageSpaceConsistency(
- rc, allCandidates.getWrappedHost(target),
+ session, allCandidates.getWrappedHost(target),
allCandidates, resourcePkgMap, resultCache);
}
catch (ResolutionException ex)
@@ -217,7 +266,7 @@ public class ResolverImpl implements Res
}
}
while ((rethrow != null)
- && ((m_usesPermutations.size() > 0) ||
(m_importPermutations.size() > 0)));
+ && ((usesPermutations.size() > 0) ||
(importPermutations.size() > 0)));
// If there is a resolve exception, then determine if an
// optionally resolved resource is to blame (typically a
fragment).
@@ -257,12 +306,12 @@ public class ResolverImpl implements Res
// resolve, so populate the wire map.
else
{
- if (m_multipleCardCandidates != null)
+ if (session.getMultipleCardCandidates() != null)
{
// Candidates for multiple cardinality requirements
were
// removed in order to provide a consistent class
space.
// Use the consistent permutation
- allCandidates = m_multipleCardCandidates;
+ allCandidates = session.getMultipleCardCandidates();
}
for (Resource resource : allResources)
{
@@ -290,9 +339,11 @@ public class ResolverImpl implements Res
finally
{
// Always clear the state.
- m_usesPermutations.clear();
- m_importPermutations.clear();
- m_multipleCardCandidates = null;
+ session.getUsesPermutations().clear();
+ session.getImportPermutations().clear();
+ session.setMultipleCardCandidates(null);
+ // TODO this was not cleared out before; but it seems it
should be
+ session.getPackageSourcesCache().clear();
}
}
while (retry);
@@ -330,6 +381,7 @@ public class ResolverImpl implements Res
List<Capability> matches, Collection<Resource> ondemandFragments)
throws ResolutionException
{
+ ResolveSession session = new ResolveSession(rc);
Map<Resource, List<Wire>> wireMap = new HashMap<Resource,
List<Wire>>();
// We can only create a dynamic import if the following
@@ -380,8 +432,11 @@ public class ResolverImpl implements Res
// Merge any fragments into hosts.
allCandidates.prepare(rc);
+ List<Candidates> usesPermutations =
session.getUsesPermutations();
+ List<Candidates> importPermutations =
session.getImportPermutations();
+
// Record the initial candidate permutation.
- m_usesPermutations.add(allCandidates);
+ usesPermutations.add(allCandidates);
ResolutionException rethrow = null;
@@ -390,11 +445,11 @@ public class ResolverImpl implements Res
rethrow = null;
resourcePkgMap.clear();
- m_packageSourcesCache.clear();
+ session.getPackageSourcesCache().clear();
- allCandidates = (m_usesPermutations.size() > 0)
- ? m_usesPermutations.remove(0)
- : m_importPermutations.remove(0);
+ allCandidates = (usesPermutations.size() > 0)
+ ? usesPermutations.remove(0)
+ : importPermutations.remove(0);
//allCandidates.dump();
// For a dynamic import, the instigating resource
@@ -402,7 +457,7 @@ public class ResolverImpl implements Res
// execute code, so we don't need to check for
// this case like we do for a normal resolve.
- calculatePackageSpaces(rc,
+ calculatePackageSpaces(session,
allCandidates.getWrappedHost(host), allCandidates,
resourcePkgMap, new HashMap(), new HashSet());
//System.out.println("+++ PACKAGE SPACES START +++");
@@ -411,7 +466,7 @@ public class ResolverImpl implements Res
try
{
- checkDynamicPackageSpaceConsistency(rc,
+ checkDynamicPackageSpaceConsistency(session,
allCandidates.getWrappedHost(host),
allCandidates, resourcePkgMap, new HashMap());
}
@@ -421,7 +476,7 @@ public class ResolverImpl implements Res
}
}
while ((rethrow != null)
- && ((m_usesPermutations.size() > 0) ||
(m_importPermutations.size() > 0)));
+ && ((usesPermutations.size() > 0) ||
(importPermutations.size() > 0)));
// If there is a resolve exception, then determine if an
// optionally resolved resource is to blame (typically a
fragment).
@@ -457,6 +512,14 @@ public class ResolverImpl implements Res
// resolve, so populate the wire map.
else
{
+ if (session.getMultipleCardCandidates() != null)
+ {
+ // TODO this was not done before; but I think it
should be;
+ // Candidates for multiple cardinality
requirements were
+ // removed in order to provide a consistent class
space.
+ // Use the consistent permutation
+ allCandidates =
session.getMultipleCardCandidates();
+ }
wireMap = populateDynamicWireMap(rc,
host, dynamicReq, resourcePkgMap, wireMap,
allCandidates);
}
@@ -464,8 +527,11 @@ public class ResolverImpl implements Res
finally
{
// Always clear the state.
- m_usesPermutations.clear();
- m_importPermutations.clear();
+ session.getUsesPermutations().clear();
+ session.getImportPermutations().clear();
+ // TODO these were not cleared out before; but it seems
they should be
+ session.setMultipleCardCandidates(null);
+ session.getPackageSourcesCache().clear();
}
}
while (retry);
@@ -475,7 +541,7 @@ public class ResolverImpl implements Res
}
private void calculatePackageSpaces(
- ResolveContext rc,
+ ResolveSession session,
Resource resource,
Candidates allCandidates,
Map<Resource, Packages> resourcePkgMap,
@@ -509,7 +575,7 @@ public class ResolverImpl implements Res
List<Requirement> reqs = new ArrayList();
List<Capability> caps = new ArrayList();
boolean isDynamicImporting = false;
- Wiring wiring = rc.getWirings().get(resource);
+ Wiring wiring = session.getContext().getWirings().get(resource);
if (wiring != null)
{
// Use wires to get actual requirements and satisfying
capabilities.
@@ -606,7 +672,7 @@ public class ResolverImpl implements Res
}
// First, add all exported packages to the target resource's package
space.
- calculateExportedPackages(rc, resource, allCandidates, resourcePkgMap);
+ calculateExportedPackages(session.getContext(), resource,
allCandidates, resourcePkgMap);
resourcePkgs = resourcePkgMap.get(resource);
// Second, add all imported packages to the target resource's package
space.
@@ -614,7 +680,8 @@ public class ResolverImpl implements Res
{
Requirement req = reqs.get(i);
Capability cap = caps.get(i);
- calculateExportedPackages(rc, cap.getResource(), allCandidates,
resourcePkgMap);
+ calculateExportedPackages(
+ session.getContext(), cap.getResource(), allCandidates,
resourcePkgMap);
// If this resource is dynamically importing, then the last
requirement
// is the dynamic import being resolved, since it is added last to
the
@@ -638,7 +705,7 @@ public class ResolverImpl implements Res
}
mergeCandidatePackages(
- rc, resource, req, cap, resourcePkgMap, allCandidates,
+ session.getContext(), resource, req, cap, resourcePkgMap,
allCandidates,
new HashMap<Resource, List<Capability>>());
}
@@ -646,7 +713,7 @@ public class ResolverImpl implements Res
for (int i = 0; i < caps.size(); i++)
{
calculatePackageSpaces(
- rc, caps.get(i).getResource(), allCandidates, resourcePkgMap,
+ session, caps.get(i).getResource(), allCandidates,
resourcePkgMap,
usesCycleMap, cycle);
}
@@ -675,7 +742,7 @@ public class ResolverImpl implements Res
blameReqs.add(req);
mergeUses(
- rc,
+ session,
resource,
resourcePkgs,
cap,
@@ -698,7 +765,7 @@ public class ResolverImpl implements Res
blameReqs.add(blame.m_reqs.get(0));
mergeUses(
- rc,
+ session,
resource,
resourcePkgs,
blame.m_cap,
@@ -719,7 +786,7 @@ public class ResolverImpl implements Res
blameReqs.add(blame.m_reqs.get(0));
mergeUses(
- rc,
+ session,
resource,
resourcePkgs,
blame.m_cap,
@@ -868,7 +935,7 @@ public class ResolverImpl implements Res
}
private void mergeUses(
- ResolveContext rc, Resource current, Packages currentPkgs,
+ ResolveSession session, Resource current, Packages currentPkgs,
Capability mergeCap, List<Requirement> blameReqs, Capability
matchingCap,
Map<Resource, Packages> resourcePkgMap,
Candidates allCandidates,
@@ -893,7 +960,7 @@ public class ResolverImpl implements Res
list.add(current);
cycleMap.put(mergeCap, list);
- for (Capability candSourceCap : getPackageSources(rc, mergeCap,
resourcePkgMap))
+ for (Capability candSourceCap : getPackageSources(session, mergeCap,
resourcePkgMap))
{
List<String> uses;
// TODO: RFC-112 - Need impl-specific type
@@ -961,13 +1028,13 @@ public class ResolverImpl implements Res
// that is the requirement wired to the blamed
capability
blameReqs2.add(blame.m_reqs.get(blame.m_reqs.size() -
1));
addUsedBlame(usedPkgBlames, blame.m_cap, blameReqs2,
matchingCap);
- mergeUses(rc, current, currentPkgs, blame.m_cap,
blameReqs2, matchingCap,
+ mergeUses(session, current, currentPkgs, blame.m_cap,
blameReqs2, matchingCap,
resourcePkgMap, allCandidates, cycleMap);
}
else
{
addUsedBlame(usedPkgBlames, blame.m_cap, blameReqs,
matchingCap);
- mergeUses(rc, current, currentPkgs, blame.m_cap,
blameReqs, matchingCap,
+ mergeUses(session, current, currentPkgs, blame.m_cap,
blameReqs, matchingCap,
resourcePkgMap, allCandidates, cycleMap);
}
}
@@ -1004,22 +1071,22 @@ public class ResolverImpl implements Res
}
private void checkPackageSpaceConsistency(
- ResolveContext rc,
+ ResolveSession session,
Resource resource,
Candidates allCandidates,
Map<Resource, Packages> resourcePkgMap,
Map<Resource, Object> resultCache) throws ResolutionException
{
- if (rc.getWirings().containsKey(resource))
+ if (session.getContext().getWirings().containsKey(resource))
{
return;
}
checkDynamicPackageSpaceConsistency(
- rc, resource, allCandidates, resourcePkgMap, resultCache);
+ session, resource, allCandidates, resourcePkgMap, resultCache);
}
private void checkDynamicPackageSpaceConsistency(
- ResolveContext rc,
+ ResolveSession session,
Resource resource,
Candidates allCandidates,
Map<Resource, Packages> resourcePkgMap,
@@ -1036,6 +1103,9 @@ public class ResolverImpl implements Res
Candidates permutation = null;
Set<Requirement> mutated = null;
+ List<Candidates> importPermutations = session.getImportPermutations();
+ List<Candidates> usesPermutations = session.getUsesPermutations();
+
// Check for conflicting imports from fragments.
// TODO: Is this only needed for imports or are generic and bundle
requirements also needed?
// I think this is only a special case for fragment imports
because they can overlap
@@ -1054,9 +1124,9 @@ public class ResolverImpl implements Res
else if
(!sourceBlame.m_cap.getResource().equals(blame.m_cap.getResource()))
{
// Try to permutate the conflicting requirement.
- permutate(allCandidates, blame.m_reqs.get(0),
m_importPermutations);
+ permutate(allCandidates, blame.m_reqs.get(0),
importPermutations);
// Try to permutate the source requirement.
- permutate(allCandidates, sourceBlame.m_reqs.get(0),
m_importPermutations);
+ permutate(allCandidates, sourceBlame.m_reqs.get(0),
importPermutations);
// Report conflict.
ResolutionException ex = new ResolutionException(
"Uses constraint violation. Unable to resolve
resource "
@@ -1071,9 +1141,9 @@ public class ResolverImpl implements Res
+ Util.getSymbolicName(blame.m_cap.getResource())
+ " [" + blame.m_cap.getResource()
+ "] via two dependency chains.\n\nChain 1:\n"
- + toStringBlame(rc, allCandidates, sourceBlame)
+ + toStringBlame(session.getContext(),
allCandidates, sourceBlame)
+ "\n\nChain 2:\n"
- + toStringBlame(rc, allCandidates, blame),
+ + toStringBlame(session.getContext(),
allCandidates, blame),
null,
Collections.singleton(blame.m_reqs.get(0)));
m_logger.log(
@@ -1098,11 +1168,11 @@ public class ResolverImpl implements Res
}
for (UsedBlames usedBlames : pkgs.m_usedPkgs.get(pkgName))
{
- if (!isCompatible(rc, exportBlame.m_cap, usedBlames.m_cap,
resourcePkgMap))
+ if (!isCompatible(session, exportBlame.m_cap,
usedBlames.m_cap, resourcePkgMap))
{
for (Blame usedBlame : usedBlames.m_blames)
{
- if (checkMultiple(usedBlames, usedBlame,
allCandidates))
+ if (checkMultiple(session, usedBlames, usedBlame,
allCandidates))
{
// Continue to the next usedBlame, if possible we
// removed the conflicting candidates.
@@ -1125,7 +1195,7 @@ public class ResolverImpl implements Res
+
Util.getSymbolicName(usedBlame.m_cap.getResource())
+ " [" + usedBlame.m_cap.getResource()
+ "] via the following dependency chain:\n\n"
- + toStringBlame(rc, allCandidates, usedBlame),
+ + toStringBlame(session.getContext(),
allCandidates, usedBlame),
null,
null);
@@ -1170,7 +1240,7 @@ public class ResolverImpl implements Res
{
if (!mutated.isEmpty())
{
- m_usesPermutations.add(permutation);
+ usesPermutations.add(permutation);
}
m_logger.log(
Logger.LOG_DEBUG,
@@ -1200,11 +1270,11 @@ public class ResolverImpl implements Res
}
for (UsedBlames usedBlames : pkgs.m_usedPkgs.get(pkgName))
{
- if (!isCompatible(rc, requirementBlame.m_cap,
usedBlames.m_cap, resourcePkgMap))
+ if (!isCompatible(session, requirementBlame.m_cap,
usedBlames.m_cap, resourcePkgMap))
{
for (Blame usedBlame : usedBlames.m_blames)
{
- if (checkMultiple(usedBlames, usedBlame,
allCandidates))
+ if (checkMultiple(session, usedBlames, usedBlame,
allCandidates))
{
// Continue to the next usedBlame, if possible
we
// removed the conflicting candidates.
@@ -1230,9 +1300,9 @@ public class ResolverImpl implements Res
+
Util.getSymbolicName(usedBlame.m_cap.getResource())
+ " [" + usedBlame.m_cap.getResource()
+ "] via two dependency chains.\n\nChain 1:\n"
- + toStringBlame(rc, allCandidates,
requirementBlame)
+ + toStringBlame(session.getContext(),
allCandidates, requirementBlame)
+ "\n\nChain 2:\n"
- + toStringBlame(rc, allCandidates, usedBlame),
+ + toStringBlame(session.getContext(),
allCandidates, usedBlame),
null,
null);
@@ -1284,7 +1354,7 @@ public class ResolverImpl implements Res
// Add uses permutation if we mutated any candidates.
if (!mutated.isEmpty())
{
- m_usesPermutations.add(permutation);
+ usesPermutations.add(permutation);
}
// Try to permutate the candidate for the original
@@ -1297,7 +1367,7 @@ public class ResolverImpl implements Res
// with existing import decisions, we may end up trying
// to permutate the same import a lot of times, so we
should
// try to check if that the case and only permutate it
once.
- permutateIfNeeded(allCandidates, req,
m_importPermutations);
+ permutateIfNeeded(allCandidates, req,
importPermutations);
}
m_logger.log(
@@ -1316,7 +1386,7 @@ public class ResolverImpl implements Res
// current resource depends. Keep track of the current number
// of permutations so we know if the lower level check was
// able to create a permutation or not in the case of failure.
- int permCount = m_usesPermutations.size() +
m_importPermutations.size();
+ int permCount = usesPermutations.size() + importPermutations.size();
for (Requirement req : resource.getRequirements(null))
{
List<Capability> cands = allCandidates.getCandidates(req);
@@ -1328,7 +1398,7 @@ public class ResolverImpl implements Res
try
{
checkPackageSpaceConsistency(
- rc, cap.getResource(),
+ session, cap.getResource(),
allCandidates, resourcePkgMap, resultCache);
}
catch (ResolutionException ex)
@@ -1337,9 +1407,9 @@ public class ResolverImpl implements Res
// then we should create an import permutation for the
// requirement with the dependency on the failing
resource
// to backtrack on our current candidate selection.
- if (permCount == (m_usesPermutations.size() +
m_importPermutations.size()))
+ if (permCount == (usesPermutations.size() +
importPermutations.size()))
{
- permutate(allCandidates, req,
m_importPermutations);
+ permutate(allCandidates, req, importPermutations);
}
throw ex;
}
@@ -1349,6 +1419,7 @@ public class ResolverImpl implements Res
}
private boolean checkMultiple(
+ ResolveSession session,
UsedBlames usedBlames,
Blame usedBlame,
Candidates permutation)
@@ -1361,13 +1432,13 @@ public class ResolverImpl implements Res
{
// Create a copy of the current permutation so we can remove the
// candidates causing the blame.
- if (m_multipleCardCandidates == null)
+ if (session.getMultipleCardCandidates() == null)
{
- m_multipleCardCandidates = permutation.copy();
+ session.setMultipleCardCandidates(permutation.copy());
}
// Get the current candidate list and remove all the offending root
// cause candidates from a copy of the current permutation.
- candidates = m_multipleCardCandidates.getCandidates(req);
+ candidates =
session.getMultipleCardCandidates().getCandidates(req);
candidates.removeAll(usedBlames.getRootCauses(req));
}
// We only are successful if there is at least one candidate left
@@ -1489,7 +1560,7 @@ public class ResolverImpl implements Res
}
private boolean isCompatible(
- ResolveContext rc, Capability currentCap, Capability candCap,
+ ResolveSession session, Capability currentCap, Capability candCap,
Map<Resource, Packages> resourcePkgMap)
{
if ((currentCap != null) && (candCap != null))
@@ -1501,12 +1572,12 @@ public class ResolverImpl implements Res
List<Capability> currentSources =
getPackageSources(
- rc,
+ session,
currentCap,
resourcePkgMap);
List<Capability> candSources =
getPackageSources(
- rc,
+ session,
candCap,
resourcePkgMap);
@@ -1516,20 +1587,19 @@ public class ResolverImpl implements Res
return true;
}
- private Map<Capability, List<Capability>> m_packageSourcesCache = new
HashMap();
-
private List<Capability> getPackageSources(
- ResolveContext rc, Capability cap, Map<Resource, Packages>
resourcePkgMap)
+ ResolveSession session, Capability cap, Map<Resource, Packages>
resourcePkgMap)
{
+ Map<Capability, List<Capability>> packageSourcesCache =
session.getPackageSourcesCache();
// If it is a package, then calculate sources for it.
if (cap.getNamespace().equals(PackageNamespace.PACKAGE_NAMESPACE))
{
- List<Capability> sources = m_packageSourcesCache.get(cap);
+ List<Capability> sources = packageSourcesCache.get(cap);
if (sources == null)
{
sources = getPackageSourcesInternal(
- rc, cap, resourcePkgMap, new ArrayList(), new HashSet());
- m_packageSourcesCache.put(cap, sources);
+ session.getContext(), cap, resourcePkgMap, new
ArrayList(), new HashSet());
+ packageSourcesCache.put(cap, sources);
}
return sources;
}