diff --git a/VERSION.txt b/VERSION.txt index c92f5ab017c..05da1d1d934 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -11,6 +11,7 @@ jetty-7.2.0.RC1 15 October 2010 + 327601 Multipart Filter handles quoted tokens + 327725 Nested ResourceCaches + JETTY-1288 Info statement when atypical classloader set on WebAppContext + + JETTY-1289 LRU cache for filter chains jetty-7.2.0.RC0 1 October 2010 + 314087 Simplified SelectorManager diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java index 1c88fabdad7..c73ecc4e79e 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java @@ -21,7 +21,10 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Queue; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ConcurrentMap; import org.eclipse.jetty.server.DispatcherType; import javax.servlet.Filter; @@ -81,7 +84,7 @@ public class ServletHandler extends ScopedHandler private FilterHolder[] _filters; private FilterMapping[] _filterMappings; private boolean _filterChainsCached=true; - private int _maxFilterChainsCacheSize=1000; + private int _maxFilterChainsCacheSize=512; private boolean _startWithUnavailable=true; private IdentityService _identityService; @@ -95,7 +98,8 @@ public class ServletHandler extends ScopedHandler private final Map _servletNameMap=new HashMap(); private PathMap _servletPathMap; - protected ConcurrentHashMap _chainCache[]; + protected final ConcurrentMap _chainCache[] = new ConcurrentMap[FilterMapping.ALL]; + protected final Queue[] _chainLRU = new Queue[FilterMapping.ALL]; /* ------------------------------------------------------------ */ @@ -147,7 +151,19 @@ public class ServletHandler extends ScopedHandler updateMappings(); if(_filterChainsCached) - _chainCache= new ConcurrentHashMap[]{null,new ConcurrentHashMap(),new ConcurrentHashMap(),null,new ConcurrentHashMap(),null,null,null,new ConcurrentHashMap(),null,null,null,null,null,null,null,new ConcurrentHashMap()}; + { + _chainCache[FilterMapping.REQUEST]=new ConcurrentHashMap(); + _chainCache[FilterMapping.FORWARD]=new ConcurrentHashMap(); + _chainCache[FilterMapping.INCLUDE]=new ConcurrentHashMap(); + _chainCache[FilterMapping.ERROR]=new ConcurrentHashMap(); + _chainCache[FilterMapping.ASYNC]=new ConcurrentHashMap(); + + _chainLRU[FilterMapping.REQUEST]=new ConcurrentLinkedQueue(); + _chainLRU[FilterMapping.FORWARD]=new ConcurrentLinkedQueue(); + _chainLRU[FilterMapping.INCLUDE]=new ConcurrentLinkedQueue(); + _chainLRU[FilterMapping.ERROR]=new ConcurrentLinkedQueue(); + _chainLRU[FilterMapping.ASYNC]=new ConcurrentLinkedQueue(); + } super.doStart(); @@ -184,7 +200,6 @@ public class ServletHandler extends ScopedHandler _filterNameMappings=null; _servletPathMap=null; - _chainCache=null; } /* ------------------------------------------------------------ */ @@ -402,7 +417,6 @@ public class ServletHandler extends ScopedHandler baseRequest.setPathInfo(old_path_info); } } - } /* ------------------------------------------------------------ */ @@ -618,20 +632,58 @@ public class ServletHandler extends ScopedHandler if (filters==null) return null; + FilterChain chain = null; if (_filterChainsCached) { - if (LazyList.size(filters) > 0) - chain= new CachedChain(filters, servletHolder); - if (_maxFilterChainsCacheSize>0 && _chainCache[dispatch].size()>_maxFilterChainsCacheSize) - _chainCache[dispatch].clear(); - _chainCache[dispatch].put(key,chain); + if (LazyList.size(filters) > 0) + chain= new CachedChain(filters, servletHolder); + + final Map cache=_chainCache[dispatch]; + final Queue lru=_chainLRU[dispatch]; + + // Do we have too many cached chains? + while (_maxFilterChainsCacheSize>0 && cache.size()>=_maxFilterChainsCacheSize) + { + // The LRU list is not atomic with the cache map, so be prepared to invalidate if + // a key is not found to delete. + // Delete by LRU (where U==created) + String k=lru.poll(); + if (k==null) + { + cache.clear(); + break; + } + cache.remove(k); + } + + cache.put(key,chain); + lru.add(key); } else if (LazyList.size(filters) > 0) chain = new Chain(baseRequest,filters, servletHolder); return chain; } + + /* ------------------------------------------------------------ */ + private void invalidateChainsCache() + { + if (_chainLRU[FilterMapping.REQUEST]!=null) + { + _chainLRU[FilterMapping.REQUEST].clear(); + _chainLRU[FilterMapping.FORWARD].clear(); + _chainLRU[FilterMapping.INCLUDE].clear(); + _chainLRU[FilterMapping.ERROR].clear(); + _chainLRU[FilterMapping.ASYNC].clear(); + + _chainCache[FilterMapping.REQUEST].clear(); + _chainCache[FilterMapping.FORWARD].clear(); + _chainCache[FilterMapping.INCLUDE].clear(); + _chainCache[FilterMapping.ERROR].clear(); + _chainCache[FilterMapping.ASYNC].clear(); + } + } /* ------------------------------------------------------------ */ /** @@ -1195,6 +1247,7 @@ public class ServletHandler extends ScopedHandler getServer().getContainer().update(this,_filterMappings,filterMappings,"filterMapping",true); _filterMappings = filterMappings; updateMappings(); + invalidateChainsCache(); } /* ------------------------------------------------------------ */ @@ -1204,6 +1257,7 @@ public class ServletHandler extends ScopedHandler getServer().getContainer().update(this,_filters,holders,"filter",true); _filters=holders; updateNameMappings(); + invalidateChainsCache(); } /* ------------------------------------------------------------ */ @@ -1216,6 +1270,7 @@ public class ServletHandler extends ScopedHandler getServer().getContainer().update(this,_servletMappings,servletMappings,"servletMapping",true); _servletMappings = servletMappings; updateMappings(); + invalidateChainsCache(); } /* ------------------------------------------------------------ */ @@ -1228,6 +1283,7 @@ public class ServletHandler extends ScopedHandler getServer().getContainer().update(this,_servlets,holders,"servlet",true); _servlets=holders; updateNameMappings(); + invalidateChainsCache(); }