You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by pa...@apache.org on 2022/05/18 14:57:21 UTC
[felix-dev] 01/01: FELIX-6529: deduplicate strings and dirs/attrs of reqs and caps
This is an automated email from the ASF dual-hosted git repository.
pauls pushed a commit to branch FELIX-6529
in repository https://gitbox.apache.org/repos/asf/felix-dev.git
commit b2d225c380da17cd82868eb81969ba73bf63f686
Author: Karl Pauls <ka...@gmail.com>
AuthorDate: Wed May 18 16:57:08 2022 +0200
FELIX-6529: deduplicate strings and dirs/attrs of reqs and caps
---
.../apache/felix/framework/cache/BundleCache.java | 3 ++
.../framework/capabilityset/SimpleFilter.java | 18 +++++++
.../java/org/apache/felix/framework/util/Util.java | 4 +-
.../util/manifestparser/ManifestParser.java | 56 +++++++++++++++++-----
.../framework/wiring/BundleCapabilityImpl.java | 28 ++++++++++-
.../framework/wiring/BundleRequirementImpl.java | 23 +++++++++
6 files changed, 117 insertions(+), 15 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..d11533c5b8 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,9 @@ 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 (value.length() < 100) {
+ value = value.intern();
+ }
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/Util.java b/framework/src/main/java/org/apache/felix/framework/util/Util.java
index ee2545286e..1745efe121 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/Util.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/Util.java
@@ -1090,8 +1090,8 @@ public class Util
return manifest;
}
- private static final List EMPTY_LIST = Collections.unmodifiableList(Collections.EMPTY_LIST);
- private static final Map EMPTY_MAP = Collections.unmodifiableMap(Collections.EMPTY_MAP);
+ private static final List EMPTY_LIST = Collections.EMPTY_LIST;
+ private static final Map EMPTY_MAP = Collections.EMPTY_MAP;
public static <T> List<T> newImmutableList(List<T> list)
{
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)