Skip to content

Commit f8f0def

Browse files
authored
FELIX-6529: deduplicate strings and dirs/attrs of reqs and caps (#151)
1 parent c0ee164 commit f8f0def

5 files changed

Lines changed: 113 additions & 13 deletions

File tree

framework/src/main/java/org/apache/felix/framework/cache/BundleCache.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,7 @@ else if (size + 1 > bytes.length)
336336
// Otherwise, parse the value and add it to the map (we throw an
337337
// exception if we don't have a key or the key already exist.
338338
String value = new String(bytes, last, (current - last), "UTF-8");
339+
339340
if (key == null)
340341
{
341342
throw new Exception("Manifest error: Missing attribute name - " + value);

framework/src/main/java/org/apache/felix/framework/capabilityset/SimpleFilter.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.List;
2525
import java.util.Map;
2626
import java.util.Map.Entry;
27+
import java.util.Objects;
2728

2829
public class SimpleFilter
2930
{
@@ -49,6 +50,23 @@ public SimpleFilter(String attr, Object value, int op)
4950
m_op = op;
5051
}
5152

53+
public boolean equals(Object o)
54+
{
55+
if (o instanceof SimpleFilter)
56+
{
57+
SimpleFilter other = (SimpleFilter) o;
58+
return m_op == other.m_op &&
59+
Objects.equals(m_name,other.m_name) &&
60+
Objects.equals(m_value, other.m_value);
61+
}
62+
return false;
63+
}
64+
65+
public int hashCode()
66+
{
67+
return m_op + Objects.hashCode(m_name) + Objects.hashCode(m_value);
68+
}
69+
5270
public String getName()
5371
{
5472
return m_name;

framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.osgi.framework.wiring.BundleRequirement;
3939
import org.osgi.framework.wiring.BundleRevision;
4040

41+
import java.lang.ref.WeakReference;
4142
import java.util.ArrayList;
4243
import java.util.Collections;
4344
import java.util.HashMap;
@@ -47,7 +48,12 @@
4748
import java.util.List;
4849
import java.util.Map;
4950
import java.util.Map.Entry;
51+
import java.util.Objects;
5052
import java.util.Set;
53+
import java.util.WeakHashMap;
54+
import java.util.concurrent.atomic.AtomicLong;
55+
import java.util.function.Function;
56+
import java.util.stream.Collectors;
5157

5258
public class ManifestParser
5359
{
@@ -67,6 +73,32 @@ public class ManifestParser
6773
private volatile List<NativeLibraryClause> m_libraryClauses;
6874
private volatile boolean m_libraryHeadersOptional = false;
6975

76+
private static final Map<Object, WeakReference<Object>> objectCache = new WeakHashMap<>();
77+
private static final Function<Object, Object> cache = (foo) ->
78+
{
79+
if (foo instanceof String)
80+
{
81+
return ((String) foo).intern();
82+
}
83+
else if (foo != null)
84+
{
85+
synchronized (objectCache)
86+
{
87+
WeakReference<Object> ref = objectCache.get(foo);
88+
if (ref != null)
89+
{
90+
Object refValue = ref.get();
91+
if (refValue != null)
92+
{
93+
return refValue;
94+
}
95+
}
96+
objectCache.put(foo, new WeakReference<>(foo));
97+
}
98+
}
99+
return foo;
100+
};
101+
70102
public ManifestParser(Logger logger, Map<String, Object> configMap, BundleRevision owner, Map<String, Object> headerMap)
71103
throws BundleException
72104
{
@@ -108,6 +140,8 @@ public ManifestParser(Logger logger, Map<String, Object> configMap, BundleRevisi
108140
}
109141
}
110142

143+
m_bundleVersion = (Version) cache.apply(m_bundleVersion);
144+
111145
//
112146
// Parse bundle symbolic name.
113147
//
@@ -269,25 +303,25 @@ public ManifestParser(Logger logger, Map<String, Object> configMap, BundleRevisi
269303
}
270304

271305
List<BundleRequirement> nativeCodeReqs = convertNativeCode(owner, m_libraryClauses, m_libraryHeadersOptional);
272-
306+
273307
// Combine all requirements.
274308
m_requirements = new ArrayList<BundleRequirement>(
275309
hostReqs.size() + importReqs.size() + rbReqs.size()
276310
+ requireReqs.size() + dynamicReqs.size() + breeReqs.size());
277-
m_requirements.addAll(hostReqs);
278-
m_requirements.addAll(importReqs);
279-
m_requirements.addAll(rbReqs);
280-
m_requirements.addAll(requireReqs);
281-
m_requirements.addAll(dynamicReqs);
282-
m_requirements.addAll(breeReqs);
283-
m_requirements.addAll(nativeCodeReqs);
311+
m_requirements.addAll(hostReqs.stream().map(req -> BundleRequirementImpl.createFrom((BundleRequirementImpl) req, cache)).collect(Collectors.toList()));
312+
m_requirements.addAll(importReqs.stream().map(req -> BundleRequirementImpl.createFrom((BundleRequirementImpl) req, cache)).collect(Collectors.toList()));
313+
m_requirements.addAll(rbReqs.stream().map(req -> BundleRequirementImpl.createFrom((BundleRequirementImpl) req, cache)).collect(Collectors.toList()));
314+
m_requirements.addAll(requireReqs.stream().map(req -> BundleRequirementImpl.createFrom((BundleRequirementImpl) req, cache)).collect(Collectors.toList()));
315+
m_requirements.addAll(dynamicReqs.stream().map(req -> BundleRequirementImpl.createFrom((BundleRequirementImpl) req, cache)).collect(Collectors.toList()));
316+
m_requirements.addAll(breeReqs.stream().map(req -> BundleRequirementImpl.createFrom((BundleRequirementImpl) req, cache)).collect(Collectors.toList()));
317+
m_requirements.addAll(nativeCodeReqs.stream().map(req -> BundleRequirementImpl.createFrom((BundleRequirementImpl) req, cache)).collect(Collectors.toList()));
284318

285319
// Combine all capabilities.
286320
m_capabilities = new ArrayList<BundleCapability>(
287321
capList.size() + exportCaps.size() + provideCaps.size());
288-
m_capabilities.addAll(capList);
289-
m_capabilities.addAll(exportCaps);
290-
m_capabilities.addAll(provideCaps);
322+
m_capabilities.addAll(capList.stream().map(cap -> BundleCapabilityImpl.createFrom((BundleCapabilityImpl) cap, cache)).collect(Collectors.toList()));
323+
m_capabilities.addAll(exportCaps.stream().map(cap -> BundleCapabilityImpl.createFrom((BundleCapabilityImpl) cap, cache)).collect(Collectors.toList()));
324+
m_capabilities.addAll(provideCaps.stream().map(cap -> BundleCapabilityImpl.createFrom((BundleCapabilityImpl) cap, cache)).collect(Collectors.toList()));
291325

292326
//
293327
// Parse activation policy.

framework/src/main/java/org/apache/felix/framework/wiring/BundleCapabilityImpl.java

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,15 @@
2020

2121
import java.util.ArrayList;
2222
import java.util.Collections;
23+
import java.util.HashMap;
2324
import java.util.HashSet;
2425
import java.util.List;
2526
import java.util.Map;
2627
import java.util.Set;
2728
import java.util.StringTokenizer;
29+
import java.util.function.Function;
30+
31+
import org.apache.felix.framework.capabilityset.SimpleFilter;
2832
import org.apache.felix.framework.util.Util;
2933
import org.apache.felix.framework.util.manifestparser.ManifestParser;
3034
import org.osgi.framework.Constants;
@@ -42,6 +46,26 @@ public class BundleCapabilityImpl implements BundleCapability
4246
private final List<String> m_uses;
4347
private final Set<String> m_mandatory;
4448

49+
public static BundleCapabilityImpl createFrom(BundleCapabilityImpl capability, Function<Object, Object> cache)
50+
{
51+
String namespaceI = (String) cache.apply(capability.m_namespace);
52+
Map<String, String> dirsI = new HashMap<>();
53+
for (Map.Entry<String, String> entry : capability.m_dirs.entrySet())
54+
{
55+
dirsI.put((String) cache.apply(entry.getKey()), (String) cache.apply(entry.getValue()));
56+
}
57+
dirsI = (Map<String, String>) cache.apply(dirsI);
58+
59+
Map<String, Object> attrsI = new HashMap<>();
60+
for (Map.Entry<String, Object> entry : capability.m_attrs.entrySet())
61+
{
62+
attrsI.put((String) cache.apply(entry.getKey()), cache.apply(entry.getValue()));
63+
}
64+
attrsI = (Map<String, Object>) cache.apply(attrsI);
65+
66+
return new BundleCapabilityImpl(capability.m_revision, namespaceI, dirsI, attrsI);
67+
}
68+
4569
public BundleCapabilityImpl(BundleRevision revision, String namespace,
4670
Map<String, String> dirs, Map<String, Object> attrs)
4771
{
@@ -61,7 +85,7 @@ public BundleCapabilityImpl(BundleRevision revision, String namespace,
6185
uses = new ArrayList<>(tok.countTokens());
6286
while (tok.hasMoreTokens())
6387
{
64-
uses.add(tok.nextToken().trim());
88+
uses.add(tok.nextToken().trim().intern());
6589
}
6690
}
6791
m_uses = uses;
@@ -77,7 +101,7 @@ public BundleCapabilityImpl(BundleRevision revision, String namespace,
77101
// If attribute exists, then record it as mandatory.
78102
if (m_attrs.containsKey(name))
79103
{
80-
mandatory.add(name);
104+
mandatory.add(name.intern());
81105
}
82106
// Otherwise, report an error.
83107
else

framework/src/main/java/org/apache/felix/framework/wiring/BundleRequirementImpl.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@
1919
package org.apache.felix.framework.wiring;
2020

2121
import java.util.Collections;
22+
import java.util.HashMap;
2223
import java.util.Map;
24+
import java.util.function.Function;
25+
2326
import org.apache.felix.framework.capabilityset.CapabilitySet;
2427
import org.apache.felix.framework.capabilityset.SimpleFilter;
2528
import org.apache.felix.framework.util.Util;
@@ -37,6 +40,26 @@ public class BundleRequirementImpl implements BundleRequirement
3740
private final Map<String, String> m_dirs;
3841
private final Map<String, Object> m_attrs;
3942

43+
public static BundleRequirementImpl createFrom(BundleRequirementImpl requirement, Function<Object, Object> cache)
44+
{
45+
String namespaceI = (String) cache.apply(requirement.m_namespace);
46+
Map<String, String> dirsI = new HashMap<>();
47+
for (Map.Entry<String, String> entry : requirement.m_dirs.entrySet())
48+
{
49+
dirsI.put((String) cache.apply(entry.getKey()), (String) cache.apply(entry.getValue()));
50+
}
51+
dirsI = (Map<String, String>) cache.apply(dirsI);
52+
53+
Map<String, Object> attrsI = new HashMap<>();
54+
for (Map.Entry<String, Object> entry : requirement.m_attrs.entrySet())
55+
{
56+
attrsI.put((String) cache.apply(entry.getKey()), cache.apply(entry.getValue()));
57+
}
58+
attrsI = (Map<String, Object>) cache.apply(attrsI);
59+
SimpleFilter filterI = (SimpleFilter) cache.apply(requirement.m_filter);
60+
return new BundleRequirementImpl(requirement.m_revision, namespaceI, dirsI, attrsI, filterI);
61+
}
62+
4063
public BundleRequirementImpl(
4164
BundleRevision revision, String namespace,
4265
Map<String, String> dirs, Map<String, Object> attrs, SimpleFilter filter)

0 commit comments

Comments
 (0)