This is an automated email from the ASF dual-hosted git repository. pauls pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/felix-dev.git
The following commit(s) were added to refs/heads/master by this push: new f8f0def4fa FELIX-6529: deduplicate strings and dirs/attrs of reqs and caps (#151) f8f0def4fa is described below commit f8f0def4fa863e3de7bf49522340956da1a367d9 Author: Karl Pauls <karlpa...@gmail.com> AuthorDate: Fri May 20 00:08:45 2022 +0200 FELIX-6529: deduplicate strings and dirs/attrs of reqs and caps (#151) --- .../apache/felix/framework/cache/BundleCache.java | 1 + .../framework/capabilityset/SimpleFilter.java | 18 +++++++ .../util/manifestparser/ManifestParser.java | 56 +++++++++++++++++----- .../framework/wiring/BundleCapabilityImpl.java | 28 ++++++++++- .../framework/wiring/BundleRequirementImpl.java | 23 +++++++++ 5 files changed, 113 insertions(+), 13 deletions(-) diff --git a/framework/src/main/java/org/apache/felix/framework/cache/BundleCache.java b/framework/src/main/java/org/apache/felix/framework/cache/BundleCache.java index ef544d07dc..27e59da68e 100644 --- a/framework/src/main/java/org/apache/felix/framework/cache/BundleCache.java +++ b/framework/src/main/java/org/apache/felix/framework/cache/BundleCache.java @@ -336,6 +336,7 @@ public class BundleCache // Otherwise, parse the value and add it to the map (we throw an // exception if we don't have a key or the key already exist. String value = new String(bytes, last, (current - last), "UTF-8"); + if (key == null) { throw new Exception("Manifest error: Missing attribute name - " + value); diff --git a/framework/src/main/java/org/apache/felix/framework/capabilityset/SimpleFilter.java b/framework/src/main/java/org/apache/felix/framework/capabilityset/SimpleFilter.java index 6e56485292..b3d85a1811 100644 --- a/framework/src/main/java/org/apache/felix/framework/capabilityset/SimpleFilter.java +++ b/framework/src/main/java/org/apache/felix/framework/capabilityset/SimpleFilter.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; public class SimpleFilter { @@ -49,6 +50,23 @@ public class SimpleFilter m_op = op; } + public boolean equals(Object o) + { + if (o instanceof SimpleFilter) + { + SimpleFilter other = (SimpleFilter) o; + return m_op == other.m_op && + Objects.equals(m_name,other.m_name) && + Objects.equals(m_value, other.m_value); + } + return false; + } + + public int hashCode() + { + return m_op + Objects.hashCode(m_name) + Objects.hashCode(m_value); + } + public String getName() { return m_name; diff --git a/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java b/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java index 09e0572774..013300b1ea 100644 --- a/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java +++ b/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java @@ -38,6 +38,7 @@ import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRequirement; import org.osgi.framework.wiring.BundleRevision; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -47,7 +48,12 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; import java.util.Set; +import java.util.WeakHashMap; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Function; +import java.util.stream.Collectors; public class ManifestParser { @@ -67,6 +73,32 @@ public class ManifestParser private volatile List<NativeLibraryClause> m_libraryClauses; private volatile boolean m_libraryHeadersOptional = false; + private static final Map<Object, WeakReference<Object>> objectCache = new WeakHashMap<>(); + private static final Function<Object, Object> cache = (foo) -> + { + if (foo instanceof String) + { + return ((String) foo).intern(); + } + else if (foo != null) + { + synchronized (objectCache) + { + WeakReference<Object> ref = objectCache.get(foo); + if (ref != null) + { + Object refValue = ref.get(); + if (refValue != null) + { + return refValue; + } + } + objectCache.put(foo, new WeakReference<>(foo)); + } + } + return foo; + }; + public ManifestParser(Logger logger, Map<String, Object> configMap, BundleRevision owner, Map<String, Object> headerMap) throws BundleException { @@ -108,6 +140,8 @@ public class ManifestParser } } + m_bundleVersion = (Version) cache.apply(m_bundleVersion); + // // Parse bundle symbolic name. // @@ -269,25 +303,25 @@ public class ManifestParser } List<BundleRequirement> nativeCodeReqs = convertNativeCode(owner, m_libraryClauses, m_libraryHeadersOptional); - + // Combine all requirements. m_requirements = new ArrayList<BundleRequirement>( hostReqs.size() + importReqs.size() + rbReqs.size() + requireReqs.size() + dynamicReqs.size() + breeReqs.size()); - m_requirements.addAll(hostReqs); - m_requirements.addAll(importReqs); - m_requirements.addAll(rbReqs); - m_requirements.addAll(requireReqs); - m_requirements.addAll(dynamicReqs); - m_requirements.addAll(breeReqs); - m_requirements.addAll(nativeCodeReqs); + m_requirements.addAll(hostReqs.stream().map(req -> BundleRequirementImpl.createFrom((BundleRequirementImpl) req, cache)).collect(Collectors.toList())); + m_requirements.addAll(importReqs.stream().map(req -> BundleRequirementImpl.createFrom((BundleRequirementImpl) req, cache)).collect(Collectors.toList())); + m_requirements.addAll(rbReqs.stream().map(req -> BundleRequirementImpl.createFrom((BundleRequirementImpl) req, cache)).collect(Collectors.toList())); + m_requirements.addAll(requireReqs.stream().map(req -> BundleRequirementImpl.createFrom((BundleRequirementImpl) req, cache)).collect(Collectors.toList())); + m_requirements.addAll(dynamicReqs.stream().map(req -> BundleRequirementImpl.createFrom((BundleRequirementImpl) req, cache)).collect(Collectors.toList())); + m_requirements.addAll(breeReqs.stream().map(req -> BundleRequirementImpl.createFrom((BundleRequirementImpl) req, cache)).collect(Collectors.toList())); + m_requirements.addAll(nativeCodeReqs.stream().map(req -> BundleRequirementImpl.createFrom((BundleRequirementImpl) req, cache)).collect(Collectors.toList())); // Combine all capabilities. m_capabilities = new ArrayList<BundleCapability>( capList.size() + exportCaps.size() + provideCaps.size()); - m_capabilities.addAll(capList); - m_capabilities.addAll(exportCaps); - m_capabilities.addAll(provideCaps); + m_capabilities.addAll(capList.stream().map(cap -> BundleCapabilityImpl.createFrom((BundleCapabilityImpl) cap, cache)).collect(Collectors.toList())); + m_capabilities.addAll(exportCaps.stream().map(cap -> BundleCapabilityImpl.createFrom((BundleCapabilityImpl) cap, cache)).collect(Collectors.toList())); + m_capabilities.addAll(provideCaps.stream().map(cap -> BundleCapabilityImpl.createFrom((BundleCapabilityImpl) cap, cache)).collect(Collectors.toList())); // // Parse activation policy. diff --git a/framework/src/main/java/org/apache/felix/framework/wiring/BundleCapabilityImpl.java b/framework/src/main/java/org/apache/felix/framework/wiring/BundleCapabilityImpl.java index f426ad12ff..ddc6a4169c 100644 --- a/framework/src/main/java/org/apache/felix/framework/wiring/BundleCapabilityImpl.java +++ b/framework/src/main/java/org/apache/felix/framework/wiring/BundleCapabilityImpl.java @@ -20,11 +20,15 @@ package org.apache.felix.framework.wiring; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; +import java.util.function.Function; + +import org.apache.felix.framework.capabilityset.SimpleFilter; import org.apache.felix.framework.util.Util; import org.apache.felix.framework.util.manifestparser.ManifestParser; import org.osgi.framework.Constants; @@ -42,6 +46,26 @@ public class BundleCapabilityImpl implements BundleCapability private final List<String> m_uses; private final Set<String> m_mandatory; + public static BundleCapabilityImpl createFrom(BundleCapabilityImpl capability, Function<Object, Object> cache) + { + String namespaceI = (String) cache.apply(capability.m_namespace); + Map<String, String> dirsI = new HashMap<>(); + for (Map.Entry<String, String> entry : capability.m_dirs.entrySet()) + { + dirsI.put((String) cache.apply(entry.getKey()), (String) cache.apply(entry.getValue())); + } + dirsI = (Map<String, String>) cache.apply(dirsI); + + Map<String, Object> attrsI = new HashMap<>(); + for (Map.Entry<String, Object> entry : capability.m_attrs.entrySet()) + { + attrsI.put((String) cache.apply(entry.getKey()), cache.apply(entry.getValue())); + } + attrsI = (Map<String, Object>) cache.apply(attrsI); + + return new BundleCapabilityImpl(capability.m_revision, namespaceI, dirsI, attrsI); + } + public BundleCapabilityImpl(BundleRevision revision, String namespace, Map<String, String> dirs, Map<String, Object> attrs) { @@ -61,7 +85,7 @@ public class BundleCapabilityImpl implements BundleCapability uses = new ArrayList<>(tok.countTokens()); while (tok.hasMoreTokens()) { - uses.add(tok.nextToken().trim()); + uses.add(tok.nextToken().trim().intern()); } } m_uses = uses; @@ -77,7 +101,7 @@ public class BundleCapabilityImpl implements BundleCapability // If attribute exists, then record it as mandatory. if (m_attrs.containsKey(name)) { - mandatory.add(name); + mandatory.add(name.intern()); } // Otherwise, report an error. else diff --git a/framework/src/main/java/org/apache/felix/framework/wiring/BundleRequirementImpl.java b/framework/src/main/java/org/apache/felix/framework/wiring/BundleRequirementImpl.java index 881d366c6b..a8a111913a 100644 --- a/framework/src/main/java/org/apache/felix/framework/wiring/BundleRequirementImpl.java +++ b/framework/src/main/java/org/apache/felix/framework/wiring/BundleRequirementImpl.java @@ -19,7 +19,10 @@ package org.apache.felix.framework.wiring; import java.util.Collections; +import java.util.HashMap; import java.util.Map; +import java.util.function.Function; + import org.apache.felix.framework.capabilityset.CapabilitySet; import org.apache.felix.framework.capabilityset.SimpleFilter; import org.apache.felix.framework.util.Util; @@ -37,6 +40,26 @@ public class BundleRequirementImpl implements BundleRequirement private final Map<String, String> m_dirs; private final Map<String, Object> m_attrs; + public static BundleRequirementImpl createFrom(BundleRequirementImpl requirement, Function<Object, Object> cache) + { + String namespaceI = (String) cache.apply(requirement.m_namespace); + Map<String, String> dirsI = new HashMap<>(); + for (Map.Entry<String, String> entry : requirement.m_dirs.entrySet()) + { + dirsI.put((String) cache.apply(entry.getKey()), (String) cache.apply(entry.getValue())); + } + dirsI = (Map<String, String>) cache.apply(dirsI); + + Map<String, Object> attrsI = new HashMap<>(); + for (Map.Entry<String, Object> entry : requirement.m_attrs.entrySet()) + { + attrsI.put((String) cache.apply(entry.getKey()), cache.apply(entry.getValue())); + } + attrsI = (Map<String, Object>) cache.apply(attrsI); + SimpleFilter filterI = (SimpleFilter) cache.apply(requirement.m_filter); + return new BundleRequirementImpl(requirement.m_revision, namespaceI, dirsI, attrsI, filterI); + } + public BundleRequirementImpl( BundleRevision revision, String namespace, Map<String, String> dirs, Map<String, Object> attrs, SimpleFilter filter)