From: rjung Date: Fri, 29 Oct 2010 22:44:52 +0000 (+0000) Subject: Changes to FastRemovalDequeue: X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=d1fe893c7c54d591978112013ee4692d40bd9771;p=tomcat7.0 Changes to FastRemovalDequeue: - Make queue thread safe and remove external synchronisation - Provide maximal size to queue - Include size checking when adding entries - Return handle to displaced entries when queue overflows while adding a new entry - Explicitely invalidate queue entries on removal by using new field "valid" Changes to JspRuntimeContext: - Initialize FastRemovalDequeue with correct size - No more external synchronisation for FastRemovalDequeue - Private utility method to unload a wrapper - Check for displaced wrapper when adding a new wrapper to the queue and unload it Changes to JspServletWrapper: - No more explicit overflow check for the queue. It's now done implicitely when adding to the queue. git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@1028935 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/java/org/apache/jasper/compiler/JspRuntimeContext.java b/java/org/apache/jasper/compiler/JspRuntimeContext.java index 5185df6a0..ef21a5ac4 100644 --- a/java/org/apache/jasper/compiler/JspRuntimeContext.java +++ b/java/org/apache/jasper/compiler/JspRuntimeContext.java @@ -155,6 +155,11 @@ public final class JspRuntimeContext { && options.getCheckInterval() > 0) { lastCheck = System.currentTimeMillis(); } + + if (options.getMaxLoadedJsps() > 0) { + jspQueue = new FastRemovalDequeue(options.getMaxLoadedJsps()); + } + } // ----------------------------------------------------- Instance Variables @@ -178,7 +183,7 @@ public final class JspRuntimeContext { /** * Keeps JSP pages ordered by last access. */ - private FastRemovalDequeue jspQueue = new FastRemovalDequeue(); + private FastRemovalDequeue jspQueue = null; // ------------------------------------------------------ Public Methods @@ -213,15 +218,18 @@ public final class JspRuntimeContext { /** * Push a newly compiled JspServletWrapper into the queue at first - * execution of jsp. + * execution of jsp. Destroy any JSP the has been replaced in the queue. * * @param jsw Servlet wrapper for jsp. * @return a ticket that can be pushed to front of queue at later execution times. * */ public FastRemovalDequeue.Entry push(JspServletWrapper jsw) { - synchronized (jspQueue) { - return jspQueue.push(jsw); + FastRemovalDequeue.Entry entry = jspQueue.push(jsw); + JspServletWrapper replaced = entry.getReplaced(); + if (replaced != null) { + unloadJspServletWrapper(replaced); } + return entry; } /** @@ -230,9 +238,7 @@ public final class JspRuntimeContext { * @param ticket the ticket for the jsp. * */ public void makeYoungest(FastRemovalDequeue.Entry ticket) { - synchronized(jspQueue) { - jspQueue.moveFirst(ticket); - } + jspQueue.moveFirst(ticket); } /** @@ -500,6 +506,13 @@ public final class JspRuntimeContext { return new SecurityHolder(source, permissions); } + private void unloadJspServletWrapper(JspServletWrapper jsw) { + removeWrapper(jsw.getJspUri()); + synchronized(jsw) { + jsw.destroy(); + } + } + /** * Method used by background thread to check if any JSP's should be destroyed. * If JSP's to be unloaded are found, they will be destroyed. @@ -522,11 +535,8 @@ public final class JspRuntimeContext { } } if (jsw != null) { - removeWrapper(jsw.getJspUri()); - synchronized(jsw) { - jsw.destroy(); - return true; - } + unloadJspServletWrapper(jsw); + return true; } return false; } diff --git a/java/org/apache/jasper/servlet/JspServletWrapper.java b/java/org/apache/jasper/servlet/JspServletWrapper.java index 811fe1973..a6dc6e5ae 100644 --- a/java/org/apache/jasper/servlet/JspServletWrapper.java +++ b/java/org/apache/jasper/servlet/JspServletWrapper.java @@ -377,7 +377,6 @@ public class JspServletWrapper { synchronized(this) { if (ticket == null) { ticket = ctxt.getRuntimeContext().push(this); - ctxt.getRuntimeContext().unloadJsp(); } else { ctxt.getRuntimeContext().makeYoungest(ticket); } diff --git a/java/org/apache/jasper/util/FastRemovalDequeue.java b/java/org/apache/jasper/util/FastRemovalDequeue.java index 1d21cc6a1..97de61d9f 100644 --- a/java/org/apache/jasper/util/FastRemovalDequeue.java +++ b/java/org/apache/jasper/util/FastRemovalDequeue.java @@ -23,15 +23,18 @@ package org.apache.jasper.util; * added to the collection with an Entry type, that is returned to the consumer. * When removing an object from the list, the consumer provides this Entry object. * - * The Entry type is completely opaque to the consumer itself. + * The Entry type is nearly opaque to the consumer of the queue. The only public + * member is the getter for any object displaced when adding a new object to the + * queue. This can be used to destroy that object. * * The Entry object contains the links pointing to the neighbours in the doubly * linked list, so that removal of an Entry does not need to search for it but * instead can be done in constant time. * - * The implementation is not thread-safe. Full synchronisation has to be provided - * externally. Invalidation of Entry objects during removal from the list is done - * by setting their valid field to false. All public methods which take Entry + * The implementation is fully thread-safe. + * + * Invalidation of Entry objects during removal from the list is done + * by setting their "valid" field to false. All public methods which take Entry * objects as arguments are NOP if the entry is no longer valid. * * A typical use of the FastRemovalDequeue is a list of entries in sorted order, @@ -44,6 +47,8 @@ package org.apache.jasper.util; */ public class FastRemovalDequeue { + /** Maximum size of the queue */ + private final int maxSize; /** First element of the queue. */ private Entry first; /** Last element of the queue. */ @@ -52,7 +57,11 @@ public class FastRemovalDequeue { private int size; /** Initialize empty queue. */ - public FastRemovalDequeue() { + public FastRemovalDequeue(int maxSize) { + if (maxSize <=1 ) { + maxSize = 2; + } + this.maxSize = maxSize; first = null; last = null; size = 0; @@ -65,7 +74,7 @@ public class FastRemovalDequeue { * * @return the size of the list. * */ - public int getSize() { + public synchronized int getSize() { return size; } @@ -76,8 +85,11 @@ public class FastRemovalDequeue { * @param object the object to prepend to the start of the list. * @return an entry for use when the object should be moved. * */ - public Entry push(final T object) { + public synchronized Entry push(final T object) { Entry entry = new Entry(object); + if (size >= maxSize) { + entry.setReplaced(pop()); + } if (first == null) { first = last = entry; } else { @@ -97,8 +109,11 @@ public class FastRemovalDequeue { * @param object the object to append to the end of the list. * @return an entry for use when the object should be moved. * */ - public Entry unpop(final T object) { + public synchronized Entry unpop(final T object) { Entry entry = new Entry(object); + if (size >= maxSize) { + entry.setReplaced(unpush()); + } if (first == null) { first = last = entry; } else { @@ -116,16 +131,17 @@ public class FastRemovalDequeue { * * @return the content of the first element of the list. **/ - public T unpush() { + public synchronized T unpush() { T content = null; if (first != null) { - content = first.getContent(); - first.setValid(false); + Entry element = first; first = first.getNext(); + content = element.getContent(); if (first != null) { first.setPrevious(null); } size--; + element.setValid(false); } return content; } @@ -135,16 +151,17 @@ public class FastRemovalDequeue { * * @return the content of the last element of the list. **/ - public T pop() { + public synchronized T pop() { T content = null; if (last != null) { - content = last.getContent(); - last.setValid(false); + Entry element = last; last = last.getPrevious(); + content = element.getContent(); if (last != null) { last.setNext(null); } size--; + element.setValid(false); } return content; } @@ -152,7 +169,7 @@ public class FastRemovalDequeue { /** * Removes any element of the list and returns its content. **/ - public void remove(final Entry element) { + public synchronized void remove(final Entry element) { if (!element.getValid()) { return; } @@ -169,6 +186,7 @@ public class FastRemovalDequeue { first = next; } size--; + element.setValid(false); } /** @@ -179,7 +197,7 @@ public class FastRemovalDequeue { * * @param element the entry to move in front. * */ - public void moveFirst(final Entry element) { + public synchronized void moveFirst(final Entry element) { if (element.getValid() && element.getPrevious() != null) { Entry prev = element.getPrevious(); @@ -205,7 +223,7 @@ public class FastRemovalDequeue { * * @param element the entry to move to the back. * */ - public void moveLast(final Entry element) { + public synchronized void moveLast(final Entry element) { if (element.getValid() && element.getNext() != null) { Entry next = element.getNext(); @@ -235,6 +253,8 @@ public class FastRemovalDequeue { private boolean valid = true; /** The content this entry is valid for. */ private final T content; + /** Optional content that was displaced by this entry */ + private T replaced = null; /** Pointer to next element in queue. */ private Entry next = null; /** Pointer to previous element in queue. */ @@ -256,6 +276,14 @@ public class FastRemovalDequeue { return content; } + public final T getReplaced() { + return replaced; + } + + private final void setReplaced(final T replaced) { + this.replaced = replaced; + } + private final Entry getNext() { return next; }