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 <[email protected]>
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)