You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by tr...@apache.org on 2007/06/07 12:02:37 UTC

svn commit: r545135 - in /mina/trunk/core/src: main/java/org/apache/mina/common/support/DefaultIoFuture.java test/java/org/apache/mina/common/support/FutureTest.java

Author: trustin
Date: Thu Jun  7 03:02:36 2007
New Revision: 545135

URL: http://svn.apache.org/viewvc?view=rev&rev=545135
Log:
Resolved issue: DIRMINA-377 (Reduce memory consumption of DefaultIoFuture)
* Minimized memory consumption by allocating a special member variable for the first listener.
* Applied additional (experimental) optimization to trunk

Modified:
    mina/trunk/core/src/main/java/org/apache/mina/common/support/DefaultIoFuture.java
    mina/trunk/core/src/test/java/org/apache/mina/common/support/FutureTest.java

Modified: mina/trunk/core/src/main/java/org/apache/mina/common/support/DefaultIoFuture.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/common/support/DefaultIoFuture.java?view=diff&rev=545135&r1=545134&r2=545135
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/common/support/DefaultIoFuture.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/common/support/DefaultIoFuture.java Thu Jun  7 03:02:36 2007
@@ -37,7 +37,8 @@
 {
     private final IoSession session;
     private final Object lock;
-    private final List<IoFutureListener> listeners = new ArrayList<IoFutureListener>();
+    private IoFutureListener firstListener;
+    private List<IoFutureListener> otherListeners;
     private Object result;
     private boolean ready;
 
@@ -179,9 +180,9 @@
             result = newValue;
             ready = true;
             lock.notifyAll();
-    
-            notifyListeners();
         }
+
+        notifyListeners();
     }
 
     /**
@@ -202,15 +203,25 @@
             throw new NullPointerException( "listener" );
         }
 
-        synchronized( lock )
-        {
-            listeners.add( listener );
-            if( ready )
-            {
-                listener.operationComplete( this );
+        boolean notifyNow = false;
+        synchronized (lock) {
+            if (ready) {
+                notifyNow = true;
+            } else {
+                if (firstListener == null) {
+                    firstListener = listener;
+                } else {
+                    if (otherListeners == null) {
+                        otherListeners = new ArrayList<IoFutureListener>(1);
+                    }
+                    otherListeners.add(listener);
+                }
             }
         }
         
+        if (notifyNow) {
+            listener.operationComplete( this );
+        }
         return this;
     }
     
@@ -223,7 +234,15 @@
 
         synchronized( lock )
         {
-            listeners.remove( listener );
+            if (!ready) {
+                if (listener == firstListener) {
+                    if (otherListeners != null && !otherListeners.isEmpty()) {
+                        firstListener = otherListeners.remove(0);
+                    }
+                } else if (otherListeners != null) {
+                    otherListeners.remove(listener);
+                }
+            }
         }
         
         return this;
@@ -231,10 +250,18 @@
 
     private void notifyListeners()
     {
-        synchronized( lock )
-        {
-            for (IoFutureListener l : listeners) {
-                l.operationComplete( this );
+        // There won't be any visibility problem or concurrent modification
+        // because 'ready' flag will be checked against both addListener and
+        // removeListener calls.
+        if (firstListener != null) {
+            firstListener.operationComplete(this);
+            firstListener = null;
+
+            if (otherListeners != null) {
+                for (IoFutureListener l : otherListeners) {
+                    l.operationComplete( this );
+                }
+                otherListeners = null;
             }
         }
     }

Modified: mina/trunk/core/src/test/java/org/apache/mina/common/support/FutureTest.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/test/java/org/apache/mina/common/support/FutureTest.java?view=diff&rev=545135&r1=545134&r2=545135
==============================================================================
--- mina/trunk/core/src/test/java/org/apache/mina/common/support/FutureTest.java (original)
+++ mina/trunk/core/src/test/java/org/apache/mina/common/support/FutureTest.java Thu Jun  7 03:02:36 2007
@@ -26,6 +26,7 @@
 
 import org.apache.mina.common.IoFilterChain;
 import org.apache.mina.common.IoFuture;
+import org.apache.mina.common.IoFutureListener;
 import org.apache.mina.common.IoHandler;
 import org.apache.mina.common.IoService;
 import org.apache.mina.common.IoSession;
@@ -192,6 +193,100 @@
         assertFalse( future.isWritten() );
     }
     
+    public void testAddListener() throws Exception {
+        DefaultCloseFuture future = new DefaultCloseFuture( null );
+        assertFalse( future.isReady() );
+        assertFalse( future.isClosed() );
+        
+        TestListener listener1 = new TestListener();
+        TestListener listener2 = new TestListener();
+        future.addListener(listener1);
+        future.addListener(listener2);
+        
+        TestThread thread = new TestThread( future );
+        thread.start();
+        
+        future.setClosed();
+        thread.join();
+        
+        assertTrue( thread.success );
+        assertTrue( future.isReady() );
+        assertTrue( future.isClosed() );
+
+        assertSame( future, listener1.notifiedFuture );
+        assertSame( future, listener2.notifiedFuture );
+    }
+    
+    public void testLateAddListener() throws Exception {
+        DefaultCloseFuture future = new DefaultCloseFuture( null );
+        assertFalse( future.isReady() );
+        assertFalse( future.isClosed() );
+        
+        TestThread thread = new TestThread( future );
+        thread.start();
+        
+        future.setClosed();
+        thread.join();
+        
+        assertTrue( thread.success );
+        assertTrue( future.isReady() );
+        assertTrue( future.isClosed() );
+
+        TestListener listener = new TestListener();
+        future.addListener(listener);
+        assertSame( future, listener.notifiedFuture );
+    }
+    
+    public void testRemoveListener1() throws Exception {
+        DefaultCloseFuture future = new DefaultCloseFuture( null );
+        assertFalse( future.isReady() );
+        assertFalse( future.isClosed() );
+        
+        TestListener listener1 = new TestListener();
+        TestListener listener2 = new TestListener();
+        future.addListener(listener1);
+        future.addListener(listener2);
+        future.removeListener(listener1);
+        
+        TestThread thread = new TestThread( future );
+        thread.start();
+        
+        future.setClosed();
+        thread.join();
+        
+        assertTrue( thread.success );
+        assertTrue( future.isReady() );
+        assertTrue( future.isClosed() );
+
+        assertSame( null, listener1.notifiedFuture );
+        assertSame( future, listener2.notifiedFuture );
+    }
+    
+    public void testRemoveListener2() throws Exception {
+        DefaultCloseFuture future = new DefaultCloseFuture( null );
+        assertFalse( future.isReady() );
+        assertFalse( future.isClosed() );
+        
+        TestListener listener1 = new TestListener();
+        TestListener listener2 = new TestListener();
+        future.addListener(listener1);
+        future.addListener(listener2);
+        future.removeListener(listener2);
+        
+        TestThread thread = new TestThread( future );
+        thread.start();
+        
+        future.setClosed();
+        thread.join();
+        
+        assertTrue( thread.success );
+        assertTrue( future.isReady() );
+        assertTrue( future.isClosed() );
+
+        assertSame( future, listener1.notifiedFuture );
+        assertSame( null, listener2.notifiedFuture );
+    }
+    
     private static class TestThread extends Thread
     {
         private final IoFuture future;
@@ -206,6 +301,14 @@
         public void run()
         {
             success = future.awaitUninterruptibly( 10000 );
+        }
+    }
+    
+    private static class TestListener implements IoFutureListener {
+        private IoFuture notifiedFuture;
+        
+        public void operationComplete(IoFuture future) {
+            this.notifiedFuture = future;
         }
     }
 }