FELIX-2136: a few further optimisations to improve OBR speeed. - insertion of a resource in the repository does not create a full copy of the array + sorting, this is now done lazily
- avoid case insensitive filters and maps (those string comparisons are really costly)
- caches the Resource hash code
- use interned strings for capabilities / requirements namespaces
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@916284 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/CapabilityImpl.java b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/CapabilityImpl.java
index ddde6cc..20d596a 100644
--- a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/CapabilityImpl.java
+++ b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/CapabilityImpl.java
@@ -27,16 +27,10 @@
{
private Resource m_resource;
private String m_name = null;
- private Map m_map = null;
+ private final Map m_map = new HashMap();
public CapabilityImpl()
{
- m_map = new TreeMap(new Comparator() {
- public int compare(Object o1, Object o2)
- {
- return o1.toString().compareToIgnoreCase(o2.toString());
- }
- });
}
public Resource getResource()
@@ -56,7 +50,7 @@
public void setName(String name)
{
- m_name = name;
+ m_name = name.intern();
}
public Map getProperties()
@@ -66,11 +60,11 @@
protected void addP(PropertyImpl prop)
{
- m_map.put(prop.getN(), prop.getV());
+ addP(prop.getN(), prop.getV());
}
protected void addP(String name, Object value)
{
- m_map.put(name, value);
+ m_map.put(name.toLowerCase(), value);
}
}
\ No newline at end of file
diff --git a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/FilterImpl.java b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/FilterImpl.java
index 90bb8a0..b1b52e4 100644
--- a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/FilterImpl.java
+++ b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/FilterImpl.java
@@ -88,7 +88,12 @@
*/
static FilterImpl newInstance(String filterString)
throws InvalidSyntaxException {
- return new Parser(filterString).parse();
+ return newInstance(filterString, false);
+ }
+
+ static FilterImpl newInstance(String filterString, boolean ignoreCase)
+ throws InvalidSyntaxException {
+ return new Parser(filterString, ignoreCase).parse();
}
FilterImpl(int operation, String attr, Object value) {
@@ -101,7 +106,7 @@
{
conv = getSet(value);
}
- else if ("version".equals(attr))
+ else if ("version".equalsIgnoreCase(attr))
{
if (value instanceof String) {
conv = new Version((String) value);
@@ -178,7 +183,7 @@
* @throws IllegalArgumentException If <code>map</code> contains
* case variants of the same key name.
*/
- public boolean match(Map map) {
+ public boolean matchCase(Map map) {
return match0(map);
}
@@ -1151,11 +1156,13 @@
*/
private static class Parser {
private final String filterstring;
+ private final boolean ignoreCase;
private final char[] filterChars;
private int pos;
- Parser(String filterstring) {
+ Parser(String filterstring, boolean ignoreCase) {
this.filterstring = filterstring;
+ this.ignoreCase = ignoreCase;
filterChars = filterstring.toCharArray();
pos = 0;
}
@@ -1384,7 +1391,12 @@
+ filterstring.substring(pos), filterstring);
}
- return new String(filterChars, begin, length);
+ String str = new String(filterChars, begin, length);
+ if (ignoreCase)
+ {
+ str = str.toLowerCase();
+ }
+ return str;
}
private String parse_value() throws InvalidSyntaxException {
diff --git a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryImpl.java b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryImpl.java
index f4e6c04..5635619 100644
--- a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryImpl.java
+++ b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryImpl.java
@@ -30,7 +30,10 @@
import java.security.PrivilegedExceptionAction;
import java.text.ParseException;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
@@ -53,6 +56,7 @@
private Resource[] m_resources = null;
private Referral[] m_referrals = null;
private RepositoryAdminImpl m_repoAdmin = null;
+ private List m_resourceList;
// Reusable comparator for sorting resources by name.
private ResourceComparator m_nameComparator = new ResourceComparator();
@@ -69,6 +73,7 @@
m_repoAdmin = repoAdmin;
m_url = url;
m_logger = logger;
+ m_resourceList = new ArrayList();
try
{
AccessController.doPrivileged(new PrivilegedExceptionAction()
@@ -98,6 +103,10 @@
public Resource[] getResources()
{
+ if (m_resources == null) {
+ Collections.sort(m_resourceList, m_nameComparator);
+ m_resources = (Resource[]) m_resourceList.toArray(new Resource[m_resourceList.size()]);
+ }
return m_resources;
}
@@ -107,19 +116,8 @@
((ResourceImpl) resource).setRepository(this);
// Add to resource array.
- if (m_resources == null)
- {
- m_resources = new Resource[] { resource };
- }
- else
- {
- Resource[] newResources = new Resource[m_resources.length + 1];
- System.arraycopy(m_resources, 0, newResources, 0, m_resources.length);
- newResources[m_resources.length] = resource;
- m_resources = newResources;
- }
-
- Arrays.sort(m_resources, m_nameComparator);
+ m_resourceList.add(resource);
+ m_resources = null;
}
public Referral[] getReferrals()
diff --git a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/RequirementImpl.java b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/RequirementImpl.java
index 87ed2ef..fcc1ae9 100644
--- a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/RequirementImpl.java
+++ b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/RequirementImpl.java
@@ -29,9 +29,8 @@
private boolean m_extend = false;
private boolean m_multiple = false;
private boolean m_optional = false;
- private Filter m_filter = null;
+ private FilterImpl m_filter = null;
private String m_comment = null;
- private MapToDictionary m_dict = new MapToDictionary(null);
public RequirementImpl()
{
@@ -44,7 +43,9 @@
public synchronized void setName(String name)
{
- m_name = name;
+ // Name of capabilities and requirements are interned for performances
+ // (with a very slow inter consumption as there are only a handful of values)
+ m_name = name.intern();
}
public synchronized String getFilter()
@@ -54,13 +55,12 @@
public synchronized void setFilter(String filter) throws InvalidSyntaxException
{
- m_filter = FilterImpl.newInstance(filter);
+ m_filter = FilterImpl.newInstance(filter, true);
}
public synchronized boolean isSatisfied(Capability capability)
{
- m_dict.setSourceMap(capability.getProperties());
- return m_filter.match(m_dict);
+ return m_filter.matchCase(capability.getProperties());
}
public synchronized boolean isExtend()
diff --git a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResourceImpl.java b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResourceImpl.java
index cc89181..6cfda8b 100644
--- a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResourceImpl.java
+++ b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResourceImpl.java
@@ -29,8 +29,8 @@
{
private final String URI = "uri";
+ private final Map m_map = new HashMap();
private Repository m_repo = null;
- private Map m_map = null;
private List m_capList = new ArrayList();
private List m_reqList = new ArrayList();
@@ -41,6 +41,8 @@
private String m_javadocURI = null;
private boolean m_converted = false;
+ private int m_hash;
+
public ResourceImpl()
{
this(null);
@@ -48,13 +50,6 @@
public ResourceImpl(ResourceImpl resource)
{
- m_map = new TreeMap(new Comparator() {
- public int compare(Object o1, Object o2)
- {
- return o1.toString().compareToIgnoreCase(o2.toString());
- }
- });
-
if (resource != null)
{
m_map.putAll(resource.getProperties());
@@ -79,11 +74,18 @@
public int hashCode()
{
- if (getSymbolicName() == null || getVersion() == null)
+ if (m_hash == 0)
{
- return super.hashCode();
+ if (getSymbolicName() == null || getVersion() == null)
+ {
+ m_hash = super.hashCode();
+ }
+ else
+ {
+ m_hash = getSymbolicName().hashCode() ^ getVersion().hashCode();
+ }
}
- return getSymbolicName().hashCode() ^ getVersion().hashCode();
+ return m_hash;
}
public Map getProperties()
@@ -183,6 +185,9 @@
**/
protected Object put(Object key, Object value)
{
+ key = key.toString().toLowerCase();
+ m_converted = false;
+ m_hash = 0;
// Capture the URIs since they might be relative, so we
// need to defer setting the actual URL value until they
// are used so that we will know our repository and its