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 2016/09/25 22:06:58 UTC
svn commit: r1762242 - in
/felix/trunk/framework/src/main/java/org/apache/felix/framework:
URLHandlers.java URLHandlersBundleStreamHandler.java
URLHandlersContentHandlerProxy.java URLHandlersStreamHandlerProxy.java
util/Util.java
Author: pauls
Date: Sun Sep 25 22:06:58 2016
New Revision: 1762242
URL: http://svn.apache.org/viewvc?rev=1762242&view=rev
Log:
Use less locking in URL handlers in order to speed up urls under concurrency (FELIX-5363).
Modified:
felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlers.java
felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersBundleStreamHandler.java
felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersContentHandlerProxy.java
felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersStreamHandlerProxy.java
felix/trunk/framework/src/main/java/org/apache/felix/framework/util/Util.java
Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlers.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlers.java?rev=1762242&r1=1762241&r2=1762242&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlers.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlers.java Sun Sep 25 22:06:58 2016
@@ -24,11 +24,14 @@ import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import static org.apache.felix.framework.util.Util.putIfAbsentAndReturn;
import org.apache.felix.framework.util.FelixConstants;
import org.apache.felix.framework.util.SecureAction;
@@ -87,22 +90,24 @@ class URLHandlers implements URLStreamHa
// This maps classloaders of URLHandlers in other classloaders to lists of
// their frameworks.
- private final static Map m_classloaderToFrameworkLists = new HashMap();
+ private final static ConcurrentHashMap<ClassLoader, List<Object>> m_classloaderToFrameworkLists = new ConcurrentHashMap<ClassLoader, List<Object>>();
// The list to hold all enabled frameworks registered with this handlers
- private static final List m_frameworks = new ArrayList();
- private static int m_counter = 0;
+ private static final CopyOnWriteArrayList m_frameworks = new CopyOnWriteArrayList();
+ private static volatile int m_counter = 0;
+
+ private static final ConcurrentHashMap<String, ContentHandler> m_contentHandlerCache = new ConcurrentHashMap<String, ContentHandler>();
+ private static final ConcurrentHashMap<String, URLStreamHandler> m_streamHandlerCache = new ConcurrentHashMap<String, URLStreamHandler>();
+ private static final ConcurrentHashMap<URLStreamHandler, URL> m_handlerToURL = new ConcurrentHashMap<URLStreamHandler, URL>();
- private static Map m_contentHandlerCache = null;
- private static Map m_streamHandlerCache = null;
- private static URLStreamHandlerFactory m_streamHandlerFactory;
- private static ContentHandlerFactory m_contentHandlerFactory;
+ private static volatile URLStreamHandlerFactory m_streamHandlerFactory;
+ private static volatile ContentHandlerFactory m_contentHandlerFactory;
private static final String STREAM_HANDLER_PACKAGE_PROP = "java.protocol.handler.pkgs";
private static final String DEFAULT_STREAM_HANDLER_PACKAGE = "sun.net.www.protocol|com.ibm.oti.net.www.protocol|gnu.java.net.protocol|wonka.net|com.acunia.wonka.net|org.apache.harmony.luni.internal.net.www.protocol|weblogic.utils|weblogic.net|javax.net.ssl|COM.newmonics.www.protocols";
- private static Object m_rootURLHandlers;
+ private static volatile Object m_rootURLHandlers;
private static final String m_streamPkgs;
- private static final Map m_builtIn = new HashMap();
+ private static final ConcurrentHashMap<String, URLStreamHandler> m_builtIn = new ConcurrentHashMap<String, URLStreamHandler>();
private static final boolean m_loaded;
static
@@ -115,8 +120,6 @@ class URLHandlers implements URLStreamHa
(null != URLHandlersContentHandlerProxy.class) && (null != URLStreamHandlerService.class);
}
-
- private static final Map m_handlerToURL = new HashMap();
private void init(String protocol, URLStreamHandlerFactory factory)
{
try
@@ -125,7 +128,7 @@ class URLHandlers implements URLStreamHa
if (handler != null)
{
URL url = new URL(protocol, null, -1, "", handler);
- m_handlerToURL.put(handler, url);
+ addToCache(m_handlerToURL, handler, url);
}
}
catch (Throwable ex)
@@ -354,29 +357,31 @@ class URLHandlers implements URLStreamHa
private URLStreamHandler getBuiltInStreamHandler(String protocol, URLStreamHandlerFactory factory)
{
- synchronized (m_builtIn)
+ URLStreamHandler handler = getFromCache(m_builtIn, protocol);
+
+ if (handler != null)
{
- if (m_builtIn.containsKey(protocol))
- {
- return (URLStreamHandler) m_builtIn.get(protocol);
- }
+ return handler;
}
+
if (factory != null)
{
- URLStreamHandler result = factory.createURLStreamHandler(protocol);
- if (result != null)
- {
- return addToCache(protocol, result);
- }
+ handler = factory.createURLStreamHandler(protocol);
+ }
+
+ if (handler == null)
+ {
+ // Check for built-in handlers for the mime type.
+ // Iterate over built-in packages.
+ handler = loadBuiltInStreamHandler(protocol, null);
}
- // Check for built-in handlers for the mime type.
- // Iterate over built-in packages.
- URLStreamHandler handler = loadBuiltInStreamHandler(protocol, null);
+
if (handler == null)
{
handler = loadBuiltInStreamHandler(protocol, ClassLoader.getSystemClassLoader());
}
- return addToCache(protocol, handler);
+
+ return addToCache(m_builtIn, protocol, handler);
}
private URLStreamHandler loadBuiltInStreamHandler(String protocol, ClassLoader classLoader) {
@@ -445,16 +450,6 @@ class URLHandlers implements URLStreamHa
return null;
}
- private synchronized URLStreamHandler addToCache(String protocol, URLStreamHandler result)
- {
- if (!m_builtIn.containsKey(protocol))
- {
- m_builtIn.put(protocol, result);
- return result;
- }
- return (URLStreamHandler) m_builtIn.get(protocol);
- }
-
/**
* <p>
* This is a method implementation for the <tt>URLStreamHandlerFactory</tt>
@@ -473,7 +468,7 @@ class URLHandlers implements URLStreamHa
// performed for code consistency between stream and content
// handlers and also because caching behavior may not be guaranteed
// across different JRE implementations.
- URLStreamHandler handler = getFromStreamCache(protocol);
+ URLStreamHandler handler = getFromCache(m_streamHandlerCache, protocol);
if (handler != null)
{
@@ -484,17 +479,17 @@ class URLHandlers implements URLStreamHa
// allowed to deal with it.
if (protocol.equals(FelixConstants.BUNDLE_URL_PROTOCOL))
{
- return addToStreamCache(protocol,
+ return addToCache(m_streamHandlerCache, protocol,
new URLHandlersBundleStreamHandler(m_secureAction));
}
- handler = getBuiltInStreamHandler(protocol,
- (m_streamHandlerFactory != this) ? m_streamHandlerFactory : null);
+ handler = getBuiltInStreamHandler(protocol,
+ (m_streamHandlerFactory != this) ? m_streamHandlerFactory : null);
// If built-in content handler, then create a proxy handler.
- return addToStreamCache(protocol,
+ return addToCache(m_streamHandlerCache, protocol,
new URLHandlersStreamHandlerProxy(protocol, m_secureAction,
- handler, (URL) m_handlerToURL.get(handler)));
+ handler, getFromCache(m_handlerToURL,handler)));
}
/**
@@ -515,63 +510,26 @@ class URLHandlers implements URLStreamHa
// performed for code consistency between stream and content
// handlers and also because caching behavior may not be guaranteed
// across different JRE implementations.
- ContentHandler handler = getFromContentCache(mimeType);
+ ContentHandler handler = getFromCache(m_contentHandlerCache, mimeType);
if (handler != null)
{
return handler;
}
- return addToContentCache(mimeType,
+ return addToCache(m_contentHandlerCache, mimeType,
new URLHandlersContentHandlerProxy(mimeType, m_secureAction,
(m_contentHandlerFactory != this) ? m_contentHandlerFactory : null));
}
- private synchronized ContentHandler addToContentCache(String mimeType, ContentHandler handler)
- {
- if (m_contentHandlerCache == null)
- {
- m_contentHandlerCache = new HashMap();
- }
- return (ContentHandler) addToCache(m_contentHandlerCache, mimeType, handler);
- }
-
- private synchronized ContentHandler getFromContentCache(String mimeType)
- {
- return (ContentHandler) ((m_contentHandlerCache != null) ?
- m_contentHandlerCache.get(mimeType) : null);
- }
-
- private synchronized URLStreamHandler addToStreamCache(String protocol, URLStreamHandler handler)
+ private static <K,V> V addToCache(ConcurrentHashMap<K,V> cache, K key, V value)
{
- if (m_streamHandlerCache == null)
- {
- m_streamHandlerCache = new HashMap();
- }
- return (URLStreamHandler) addToCache(m_streamHandlerCache, protocol, handler);
+ return key != null && value != null ? putIfAbsentAndReturn(cache, key, value) : null;
}
- private synchronized URLStreamHandler getFromStreamCache(String protocol)
+ private static <K,V> V getFromCache(ConcurrentHashMap<K,V> cache, K key)
{
- return (URLStreamHandler) ((m_streamHandlerCache != null) ?
- m_streamHandlerCache.get(protocol) : null);
- }
-
- private Object addToCache(Map cache, String key, Object value)
- {
- if (value == null)
- {
- return null;
- }
-
- Object result = cache.get(key);
-
- if (result == null)
- {
- cache.put(key, value);
- result = value;
- }
- return result;
+ return key != null ? cache.get(key) : null;
}
/**
@@ -709,20 +667,22 @@ class URLHandlers implements URLStreamHa
**/
public static Object getFrameworkFromContext()
{
- // This is a hack. The idea is to return the only registered framework
- synchronized (m_classloaderToFrameworkLists)
+ // This is a hack. The idea is to return the only registered framework quickly
+ int attempts = 0;
+ while (m_classloaderToFrameworkLists.isEmpty() && (m_counter == 1) && (m_frameworks.size() == 1))
{
- if (m_classloaderToFrameworkLists.isEmpty())
+ Object framework = m_frameworks.get(0);
+
+ if (framework != null)
{
- synchronized (m_frameworks)
- {
- if ((m_counter == 1) && (m_frameworks.size() == 1))
- {
- return m_frameworks.get(0);
- }
- }
+ return framework;
+ }
+ else if (attempts++ > 3)
+ {
+ break;
}
}
+
// get the current class call stack.
Class[] stack = m_sm.getClassContext();
// Find the first class that is loaded from a bundle.
@@ -747,44 +707,36 @@ class URLHandlers implements URLStreamHa
// the bundle that loaded the class.
if (targetClass != null)
{
- synchronized (m_classloaderToFrameworkLists)
- {
- ClassLoader index = targetClass.getClassLoader().getClass().getClassLoader();
+ ClassLoader index = targetClass.getClassLoader().getClass().getClassLoader();
- List frameworks = (List) m_classloaderToFrameworkLists.get(
- index);
+ List frameworks = (List) m_classloaderToFrameworkLists.get(index);
- if ((frameworks == null) && (index == URLHANDLERS_CLASS.getClassLoader()))
- {
- frameworks = m_frameworks;
- }
- if (frameworks != null)
+ if ((frameworks == null) && (index == URLHANDLERS_CLASS.getClassLoader()))
+ {
+ frameworks = m_frameworks;
+ }
+ if (frameworks != null)
+ {
+ // Check the registry of framework instances
+ for (Object framework : frameworks)
{
- synchronized (frameworks)
+ try
{
- // Check the registry of framework instances
- for (int i = 0; i < frameworks.size(); i++)
+ if (m_secureAction.invoke(
+ m_secureAction.getDeclaredMethod(framework.getClass(),
+ "getBundle", CLASS_TYPE),
+ framework, new Object[]{targetClass}) != null)
{
- Object framework = frameworks.get(i);
- try
- {
- if (m_secureAction.invoke(
- m_secureAction.getDeclaredMethod(framework.getClass(),
- "getBundle", CLASS_TYPE),
- framework, new Object[]{targetClass}) != null)
- {
- return framework;
- }
- }
- catch (Exception ex)
- {
- // This should not happen but if it does there is
- // not much we can do other then ignore it.
- // Maybe log this or something.
- ex.printStackTrace();
- }
+ return framework;
}
}
+ catch (Exception ex)
+ {
+ // This should not happen but if it does there is
+ // not much we can do other then ignore it.
+ // Maybe log this or something.
+ ex.printStackTrace();
+ }
}
}
}
Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersBundleStreamHandler.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersBundleStreamHandler.java?rev=1762242&r1=1762241&r2=1762242&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersBundleStreamHandler.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersBundleStreamHandler.java Sun Sep 25 22:06:58 2016
@@ -1,4 +1,4 @@
-/*
+/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
@@ -44,7 +44,7 @@ class URLHandlersBundleStreamHandler ext
m_action = action;
}
- protected synchronized URLConnection openConnection(URL url) throws IOException
+ protected URLConnection openConnection(URL url) throws IOException
{
if (!"felix".equals(url.getAuthority()))
{
@@ -54,9 +54,9 @@ class URLHandlersBundleStreamHandler ext
{
return new URLHandlersBundleURLConnection(url, m_framework);
}
-
+
Object framework = URLHandlers.getFrameworkFromContext();
-
+
if (framework != null)
{
if (framework instanceof Felix)
@@ -67,8 +67,8 @@ class URLHandlersBundleStreamHandler ext
{
Class targetClass = framework.getClass().getClassLoader().loadClass(
URLHandlersBundleURLConnection.class.getName());
-
- Constructor constructor = m_action.getConstructor(targetClass,
+
+ Constructor constructor = m_action.getConstructor(targetClass,
new Class[]{URL.class, framework.getClass().getClassLoader().loadClass(
Felix.class.getName())});
m_action.setAccesssible(constructor);
@@ -82,7 +82,7 @@ class URLHandlersBundleStreamHandler ext
throw new IOException("No framework context found");
}
- protected void parseURL(URL u, String spec, int start, int limit)
+ protected void parseURL(URL u, String spec, int start, int limit)
{
super.parseURL(u, spec, start, limit);
@@ -92,31 +92,31 @@ class URLHandlersBundleStreamHandler ext
}
}
- protected String toExternalForm(URL u)
+ protected String toExternalForm(URL u)
{
- StringBuffer result = new StringBuffer();
+ StringBuilder result = new StringBuilder();
result.append(u.getProtocol());
result.append("://");
result.append(u.getHost());
result.append(':');
result.append(u.getPort());
- if (u.getPath() != null)
+ if (u.getPath() != null)
{
result.append(u.getPath());
}
- if (u.getQuery() != null)
+ if (u.getQuery() != null)
{
result.append('?');
result.append(u.getQuery());
}
- if (u.getRef() != null)
+ if (u.getRef() != null)
{
result.append("#");
result.append(u.getRef());
}
return result.toString();
}
-
+
protected java.net.InetAddress getHostAddress(URL u)
{
return null;
Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersContentHandlerProxy.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersContentHandlerProxy.java?rev=1762242&r1=1762241&r2=1762242&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersContentHandlerProxy.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersContentHandlerProxy.java Sun Sep 25 22:06:58 2016
@@ -22,11 +22,11 @@ import java.io.IOException;
import java.net.ContentHandler;
import java.net.ContentHandlerFactory;
import java.net.URLConnection;
-import java.util.HashMap;
-import java.util.Map;
import java.util.StringTokenizer;
+import java.util.concurrent.ConcurrentHashMap;
import org.apache.felix.framework.util.SecureAction;
+import static org.apache.felix.framework.util.Util.putIfAbsentAndReturn;
/**
* <p>
@@ -57,7 +57,7 @@ class URLHandlersContentHandlerProxy ext
private static final String CONTENT_HANDLER_PACKAGE_PROP = "java.content.handler.pkgs";
private static final String DEFAULT_CONTENT_HANDLER_PACKAGE = "sun.net.www.content|com.ibm.oti.net.www.content|gnu.java.net.content|org.apache.harmony.luni.internal.net.www.content|COM.newmonics.www.content";
- private static final Map m_builtIn = new HashMap();
+ private static final ConcurrentHashMap<String, ContentHandler> m_builtIn = new ConcurrentHashMap<String, ContentHandler>();
private static final String m_pkgs;
static
@@ -141,19 +141,19 @@ class URLHandlersContentHandlerProxy ext
private ContentHandler getBuiltIn()
{
- synchronized (m_builtIn)
+ ContentHandler result = m_builtIn.get(m_mimeType);
+
+ if (result == null)
{
- if (m_builtIn.containsKey(m_mimeType))
- {
- return (ContentHandler) m_builtIn.get(m_mimeType);
- }
+ return result;
}
+
if (m_factory != null)
{
- ContentHandler result = m_factory.createContentHandler(m_mimeType);
+ result = m_factory.createContentHandler(m_mimeType);
if (result != null)
{
- return addToCache(m_mimeType, result);
+ return putIfAbsentAndReturn(m_builtIn, m_mimeType, result);
}
}
// Check for built-in handlers for the mime type.
@@ -172,7 +172,7 @@ class URLHandlersContentHandlerProxy ext
Class handler = m_action.forName(className, null);
if (handler != null)
{
- return addToCache(m_mimeType,
+ return putIfAbsentAndReturn(m_builtIn, m_mimeType,
(ContentHandler) handler.newInstance());
}
}
@@ -183,16 +183,6 @@ class URLHandlersContentHandlerProxy ext
// case other than ignore it.
}
}
- return addToCache(m_mimeType, null);
- }
-
- private synchronized ContentHandler addToCache(String mimeType, ContentHandler handler)
- {
- if (!m_builtIn.containsKey(mimeType))
- {
- m_builtIn.put(mimeType, handler);
- return handler;
- }
- return (ContentHandler) m_builtIn.get(mimeType);
+ return null;
}
}
\ No newline at end of file
Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersStreamHandlerProxy.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersStreamHandlerProxy.java?rev=1762242&r1=1762241&r2=1762242&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersStreamHandlerProxy.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersStreamHandlerProxy.java Sun Sep 25 22:06:58 2016
@@ -526,7 +526,7 @@ public class URLHandlersStreamHandlerPro
// case it can -- hence, we catch the NPE and do the work
// ourselvs. The only difference is that we check whether the
// URL.getFile() is null or not.
- StringBuffer answer = new StringBuffer();
+ StringBuilder answer = new StringBuilder();
answer.append(url.getProtocol());
answer.append(':');
String authority = url.getAuthority();
@@ -572,14 +572,14 @@ public class URLHandlersStreamHandlerPro
{
// Get the framework instance associated with call stack.
Object framework = URLHandlers.getFrameworkFromContext();
-
+
if (framework == null)
{
return m_builtIn;
}
- Object service = null;
+ Object service;
if (framework instanceof Felix)
{
service = ((Felix) framework).getStreamHandlerService(m_protocol);
@@ -612,7 +612,7 @@ public class URLHandlersStreamHandlerPro
{
// In case that we are inside tomcat - the problem is that the webapp classloader
// creates a new url to load a class. This gets us to this method. Now, if we
- // trigger a classload while executing tomcat is creating a new url and we end-up with
+ // trigger a classload while executing, tomcat is creating a new url and we end-up with
// a loop which is cut short after two iterations (because of a circularclassload).
// We catch this exception (and all others) and just return the built-in handler
// (if we have any) as this way we at least eventually get started (this just means
@@ -624,28 +624,20 @@ public class URLHandlersStreamHandlerPro
public Object invoke(Object obj, Method method, Object[] params)
throws Throwable
{
- try
+ Class[] types = method.getParameterTypes();
+ if (m_service == null)
{
-
- Class[] types = method.getParameterTypes();
- if (m_service == null)
- {
- return m_action.invoke(m_action.getMethod(this.getClass(), method.getName(), types), this, params);
- }
- if ("parseURL".equals(method.getName()))
- {
- types[0] = m_service.getClass().getClassLoader().loadClass(
- URLStreamHandlerSetter.class.getName());
- params[0] = Proxy.newProxyInstance(
- m_service.getClass().getClassLoader(), new Class[]{types[0]},
- (URLHandlersStreamHandlerProxy) params[0]);
- }
- return m_action.invokeDirect(m_action.getDeclaredMethod(m_service.getClass(),
- method.getName(), types), m_service, params);
+ return m_action.invoke(m_action.getMethod(this.getClass(), method.getName(), types), this, params);
}
- catch (Exception ex)
+ if ("parseURL".equals(method.getName()))
{
- throw ex;
+ types[0] = m_service.getClass().getClassLoader().loadClass(
+ URLStreamHandlerSetter.class.getName());
+ params[0] = Proxy.newProxyInstance(
+ m_service.getClass().getClassLoader(), new Class[]{types[0]},
+ (URLHandlersStreamHandlerProxy) params[0]);
}
+ return m_action.invokeDirect(m_action.getDeclaredMethod(m_service.getClass(),
+ method.getName(), types), m_service, params);
}
}
Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/util/Util.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/util/Util.java?rev=1762242&r1=1762241&r2=1762242&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/util/Util.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/util/Util.java Sun Sep 25 22:06:58 2016
@@ -33,6 +33,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import org.apache.felix.framework.Logger;
import org.osgi.framework.Bundle;
@@ -831,4 +832,10 @@ public class Util
builder.insert(23, '-');
return builder.toString();
}
+
+ public static <K,V> V putIfAbsentAndReturn(ConcurrentHashMap<K,V> map, K key, V value)
+ {
+ V result = map.putIfAbsent(key, value);
+ return result != null ? result : value;
+ }
}
\ No newline at end of file