Author: markt
Date: Tue Jun 12 12:40:00 2012
New Revision: 1349300

URL: http://svn.apache.org/viewvc?rev=1349300&view=rev
Log:
Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=52999
Remove synchronization bottleneck in container event handling

Modified:
    tomcat/tc7.0.x/trunk/   (props changed)
    tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/ContainerBase.java
    tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml

Propchange: tomcat/tc7.0.x/trunk/
------------------------------------------------------------------------------
  Merged /tomcat/trunk:r1349298

Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/ContainerBase.java
URL: 
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/ContainerBase.java?rev=1349300&r1=1349299&r2=1349300&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/ContainerBase.java 
(original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/ContainerBase.java Tue 
Jun 12 12:40:00 2012
@@ -178,7 +178,9 @@ public abstract class ContainerBase exte
     /**
      * The container event listeners for this Container.
      */
-    protected ArrayList<ContainerListener> listeners = new 
ArrayList<ContainerListener>();
+    protected ArrayList<ContainerListener> listeners =
+            new ArrayList<ContainerListener>();
+    protected ReadWriteLock listenersLock = new ReentrantReadWriteLock();
 
 
     /**
@@ -914,10 +916,13 @@ public abstract class ContainerBase exte
     @Override
     public void addContainerListener(ContainerListener listener) {
 
-        synchronized (listeners) {
+        Lock write = listenersLock.writeLock();
+        write.lock();
+        try {
             listeners.add(listener);
+        } finally {
+            write.unlock();
         }
-
     }
 
 
@@ -975,12 +980,15 @@ public abstract class ContainerBase exte
     @Override
     public ContainerListener[] findContainerListeners() {
 
-        synchronized (listeners) {
+        Lock read = listenersLock.readLock();
+        read.lock();
+        try {
             ContainerListener[] results = 
                 new ContainerListener[listeners.size()];
             return listeners.toArray(results);
+        } finally {
+            read.unlock();
         }
-
     }
 
 
@@ -1059,10 +1067,13 @@ public abstract class ContainerBase exte
     @Override
     public void removeContainerListener(ContainerListener listener) {
 
-        synchronized (listeners) {
+        Lock write = listenersLock.writeLock();
+        write.lock();
+        try {
             listeners.remove(listener);
+        } finally {
+            write.unlock();
         }
-
     }
 
 
@@ -1397,16 +1408,31 @@ public abstract class ContainerBase exte
     @Override
     public void fireContainerEvent(String type, Object data) {
 
-        if (listeners.size() < 1)
-            return;
-        ContainerEvent event = new ContainerEvent(this, type, data);
-        ContainerListener list[] = new ContainerListener[0];
-        synchronized (listeners) {
-            list = listeners.toArray(list);
+        /*
+         * Implementation note
+         * There are two options here.
+         * 1) Take a copy of listeners and fire the events outside of the read
+         *    lock
+         * 2) Don't take a copy and fire the events inside the read lock
+         *
+         * Approach 2 has been used here since holding the read lock only
+         * prevents writes and that is preferable to creating lots of array
+         * objects. Since writes occur on start / stop (unless an external
+         * management tool is used) then holding the read lock for a relatively
+         * long time should not be an issue.
+         */
+        Lock read = listenersLock.readLock();
+        read.lock();
+        try {
+            if (listeners.size() < 1)
+                return;
+            ContainerEvent event = new ContainerEvent(this, type, data);
+            for (ContainerListener listener : listeners) {
+                listener.containerEvent(event);
+            }
+        } finally {
+            read.unlock();
         }
-        for (int i = 0; i < list.length; i++)
-            list[i].containerEvent(event);
-
     }
 
 

Modified: tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml
URL: 
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml?rev=1349300&r1=1349299&r2=1349300&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml Tue Jun 12 12:40:00 2012
@@ -65,6 +65,10 @@
         start-stop thread pool. It allows to use daemon threads and give
         them more distinct names. (kfujino)
       </update>
+      <fix>
+        <bug>52999</bug>: Remove synchronization bottleneck from the firing of
+        <code>Container</code> events. (markt)  
+      </fix>
       <add>
         <bug>53008</bug>: Additional test cases for BASIC authentication and
         RFC2617 compliance. Patch provided by Brian Burch. (markt)



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to