Author: markt
Date: Sun Sep 23 19:12:44 2012
New Revision: 1389122

URL: http://svn.apache.org/viewvc?rev=1389122&view=rev
Log:
Expand functionality of ConcurrentStack and then switch to ConcurrentStack 
removing ~25% of the remaining object allocation during load test.
No noticeable performance hit.

Modified:
    tomcat/trunk/java/org/apache/catalina/valves/Constants.java
    tomcat/trunk/java/org/apache/tomcat/util/collections/ConcurrentStack.java
    tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java
    
tomcat/trunk/test/org/apache/tomcat/util/collections/TestConcurrentStack.java

Modified: tomcat/trunk/java/org/apache/catalina/valves/Constants.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/valves/Constants.java?rev=1389122&r1=1389121&r2=1389122&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/valves/Constants.java (original)
+++ tomcat/trunk/java/org/apache/catalina/valves/Constants.java Sun Sep 23 
19:12:44 2012
@@ -76,4 +76,12 @@ public final class Constants {
     public static final char[] SC_SERVICE_UNAVAILABLE_CHAR = new char[] {'5', 
'0', '3'};
     public static final char[] SC_GATEWAY_TIMEOUT_CHAR = new char[] {'5', '0', 
'4'};
     public static final char[] SC_HTTP_VERSION_NOT_SUPPORTED_CHAR = new char[] 
{'5', '0', '5'};
+
+    public static final char[][] OCTETS = new char[256][];
+
+    static {
+        for (int i = 0; i < 256; i++) {
+            OCTETS[i] = Integer.toString(i).toCharArray();
+        }
+    }
 }

Modified: 
tomcat/trunk/java/org/apache/tomcat/util/collections/ConcurrentStack.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/collections/ConcurrentStack.java?rev=1389122&r1=1389121&r2=1389122&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/collections/ConcurrentStack.java 
(original)
+++ tomcat/trunk/java/org/apache/tomcat/util/collections/ConcurrentStack.java 
Sun Sep 23 19:12:44 2012
@@ -25,18 +25,40 @@ package org.apache.tomcat.util.collectio
  */
 public class ConcurrentStack<T> {
 
-    private int size = 128;
+    public static final int DEFAULT_SIZE = 128;
+    private static final int DEFAULT_LIMIT = -1;
+
+    private int size;
+    private int limit;
+
     /*
      * Points to the next available object in the stack
      */
     private int index = -1;
 
-    private Object[] stack = new Object[size];
+    private Object[] stack;
+
+
+    public ConcurrentStack() {
+        this(DEFAULT_SIZE, DEFAULT_LIMIT);
+    }
+
+    public ConcurrentStack(int size, int limit) {
+        this.size = size;
+        this.limit = limit;
+        stack = new Object[size];
+    }
+
 
     public synchronized void push(T obj) {
         index++;
         if (index == size) {
-            expand();
+            if (limit == -1 || size < limit) {
+                expand();
+            } else {
+                index--;
+                return;
+            }
         }
         stack[index] = obj;
     }
@@ -46,11 +68,25 @@ public class ConcurrentStack<T> {
         if (index == -1) {
             return null;
         }
-        return (T) stack[index--];
+        T result = (T) stack[index];
+        stack[index--] = null;
+        return result;
+    }
+
+    public synchronized void clear() {
+        if (index > -1) {
+            for (int i = 0; i < index + 1; i++) {
+                stack[i] = null;
+            }
+        }
+        index = -1;
     }
 
     private void expand() {
         int newSize = size * 2;
+        if (limit != -1 && newSize > limit) {
+            newSize = limit;
+        }
         Object[] newStack = new Object[newSize];
         System.arraycopy(stack, 0, newStack, 0, size);
         // This is the only point where garbage is created by throwing away the

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java?rev=1389122&r1=1389121&r2=1389122&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java Sun Sep 23 
19:12:44 2012
@@ -51,6 +51,7 @@ import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
 import org.apache.tomcat.util.ExceptionUtils;
 import org.apache.tomcat.util.IntrospectionUtils;
+import org.apache.tomcat.util.collections.ConcurrentStack;
 import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
 import org.apache.tomcat.util.net.SecureNioChannel.ApplicationBufferHandler;
 import org.apache.tomcat.util.net.jsse.NioX509KeyManager;
@@ -126,157 +127,30 @@ public class NioEndpoint extends Abstrac
     /**
      * Cache for SocketProcessor objects
      */
-    protected ConcurrentLinkedQueue<SocketProcessor> processorCache = new 
ConcurrentLinkedQueue<SocketProcessor>() {
-        private static final long serialVersionUID = 1L;
-        protected AtomicInteger size = new AtomicInteger(0);
-        @Override
-        public boolean offer(SocketProcessor sc) {
-            sc.reset(null,null);
-            boolean offer = 
socketProperties.getProcessorCache()==-1?true:size.get()<socketProperties.getProcessorCache();
-            //avoid over growing our cache or add after we have stopped
-            if ( running && (!paused) && (offer) ) {
-                boolean result = super.offer(sc);
-                if ( result ) {
-                    size.incrementAndGet();
-                }
-                return result;
-            }
-            else return false;
-        }
-
-        @Override
-        public SocketProcessor poll() {
-            SocketProcessor result = super.poll();
-            if ( result != null ) {
-                size.decrementAndGet();
-            }
-            return result;
-        }
-
-        @Override
-        public void clear() {
-            super.clear();
-            size.set(0);
-        }
-    };
-
+    protected final ConcurrentStack<SocketProcessor> processorCache =
+            new ConcurrentStack<>(ConcurrentStack.DEFAULT_SIZE,
+                    socketProperties.getProcessorCache());
 
     /**
      * Cache for key attachment objects
      */
-    protected ConcurrentLinkedQueue<KeyAttachment> keyCache = new 
ConcurrentLinkedQueue<KeyAttachment>() {
-        private static final long serialVersionUID = 1L;
-        protected AtomicInteger size = new AtomicInteger(0);
-        @Override
-        public boolean offer(KeyAttachment ka) {
-            ka.reset();
-            boolean offer = 
socketProperties.getKeyCache()==-1?true:size.get()<socketProperties.getKeyCache();
-            //avoid over growing our cache or add after we have stopped
-            if ( running && (!paused) && (offer) ) {
-                boolean result = super.offer(ka);
-                if ( result ) {
-                    size.incrementAndGet();
-                }
-                return result;
-            }
-            else return false;
-        }
-
-        @Override
-        public KeyAttachment poll() {
-            KeyAttachment result = super.poll();
-            if ( result != null ) {
-                size.decrementAndGet();
-            }
-            return result;
-        }
-
-        @Override
-        public void clear() {
-            super.clear();
-            size.set(0);
-        }
-    };
-
+    protected final ConcurrentStack<KeyAttachment> keyCache =
+            new ConcurrentStack<>(ConcurrentStack.DEFAULT_SIZE,
+                    socketProperties.getKeyCache());
 
     /**
      * Cache for poller events
      */
-    protected ConcurrentLinkedQueue<PollerEvent> eventCache = new 
ConcurrentLinkedQueue<PollerEvent>() {
-        private static final long serialVersionUID = 1L;
-        protected AtomicInteger size = new AtomicInteger(0);
-        @Override
-        public boolean offer(PollerEvent pe) {
-            pe.reset();
-            boolean offer = 
socketProperties.getEventCache()==-1?true:size.get()<socketProperties.getEventCache();
-            //avoid over growing our cache or add after we have stopped
-            if ( running && (!paused) && (offer) ) {
-                boolean result = super.offer(pe);
-                if ( result ) {
-                    size.incrementAndGet();
-                }
-                return result;
-            }
-            else return false;
-        }
-
-        @Override
-        public PollerEvent poll() {
-            PollerEvent result = super.poll();
-            if ( result != null ) {
-                size.decrementAndGet();
-            }
-            return result;
-        }
-
-        @Override
-        public void clear() {
-            super.clear();
-            size.set(0);
-        }
-    };
-
+    protected final ConcurrentStack<PollerEvent> eventCache =
+            new ConcurrentStack<>(ConcurrentStack.DEFAULT_SIZE,
+                    socketProperties.getEventCache());
 
     /**
      * Bytebuffer cache, each channel holds a set of buffers (two, except for 
SSL holds four)
      */
-    protected ConcurrentLinkedQueue<NioChannel> nioChannels = new 
ConcurrentLinkedQueue<NioChannel>() {
-        private static final long serialVersionUID = 1L;
-        protected AtomicInteger size = new AtomicInteger(0);
-        protected AtomicInteger bytes = new AtomicInteger(0);
-        @Override
-        public boolean offer(NioChannel socket) {
-            boolean offer = 
socketProperties.getBufferPool()==-1?true:size.get()<socketProperties.getBufferPool();
-            offer = offer && 
(socketProperties.getBufferPoolSize()==-1?true:(bytes.get()+socket.getBufferSize())<socketProperties.getBufferPoolSize());
-            //avoid over growing our cache or add after we have stopped
-            if ( running && (!paused) && (offer) ) {
-                boolean result = super.offer(socket);
-                if ( result ) {
-                    size.incrementAndGet();
-                    bytes.addAndGet(socket.getBufferSize());
-                }
-                return result;
-            }
-            else return false;
-        }
-
-        @Override
-        public NioChannel poll() {
-            NioChannel result = super.poll();
-            if ( result != null ) {
-                size.decrementAndGet();
-                bytes.addAndGet(-result.getBufferSize());
-            }
-            return result;
-        }
-
-        @Override
-        public void clear() {
-            super.clear();
-            size.set(0);
-            bytes.set(0);
-        }
-    };
+    protected final ConcurrentStack<NioChannel> nioChannels =
+            new ConcurrentStack<>(ConcurrentStack.DEFAULT_SIZE,
+                    socketProperties.getBufferPoolSize());
 
 
     // ------------------------------------------------------------- Properties
@@ -663,7 +537,7 @@ public class NioEndpoint extends Abstrac
             Socket sock = socket.socket();
             socketProperties.setProperties(sock);
 
-            NioChannel channel = nioChannels.poll();
+            NioChannel channel = nioChannels.pop();
             if ( channel == null ) {
                 // SSL setup
                 if (sslContext != null) {
@@ -747,7 +621,7 @@ public class NioEndpoint extends Abstrac
                 return false;
             }
             attachment.setCometNotify(false); //will get reset upon next reg
-            SocketProcessor sc = processorCache.poll();
+            SocketProcessor sc = processorCache.pop();
             if ( sc == null ) sc = new SocketProcessor(socket,status);
             else sc.reset(socket,status);
             if ( dispatch && getExecutor()!=null ) getExecutor().execute(sc);
@@ -1020,7 +894,7 @@ public class NioEndpoint extends Abstrac
         }
 
         public void add(final NioChannel socket, final int interestOps) {
-            PollerEvent r = eventCache.poll();
+            PollerEvent r = eventCache.pop();
             if ( r==null) r = new PollerEvent(socket,null,interestOps);
             else r.reset(socket,null,interestOps);
             if ( (interestOps&OP_CALLBACK) == OP_CALLBACK ) {
@@ -1048,7 +922,9 @@ public class NioEndpoint extends Abstrac
                     r.run();
                     if ( r instanceof PollerEvent ) {
                         ((PollerEvent)r).reset();
-                        eventCache.offer((PollerEvent)r);
+                        if (running && !paused) {
+                            eventCache.push((PollerEvent)r);
+                        }
                     }
                 } catch ( Throwable x ) {
                     log.error("",x);
@@ -1061,11 +937,11 @@ public class NioEndpoint extends Abstrac
         public void register(final NioChannel socket)
         {
             socket.setPoller(this);
-            KeyAttachment key = keyCache.poll();
+            KeyAttachment key = keyCache.pop();
             final KeyAttachment ka = key!=null?key:new KeyAttachment(socket);
             ka.reset(this,socket,getSocketProperties().getSoTimeout());
             ka.setKeepAliveLeft(NioEndpoint.this.getMaxKeepAliveRequests());
-            PollerEvent r = eventCache.poll();
+            PollerEvent r = eventCache.pop();
             ka.interestOps(SelectionKey.OP_READ);//this is what OP_REGISTER 
turns into.
             if ( r==null) r = new PollerEvent(socket,ka,OP_REGISTER);
             else r.reset(socket,ka,OP_REGISTER);
@@ -1699,9 +1575,13 @@ public class NioEndpoint extends Abstrac
                             try {
                                 if (ka!=null) ka.setComet(false);
                                 socket.getPoller().cancelledKey(key, 
SocketStatus.ERROR);
-                                nioChannels.offer(socket);
+                                if (running && !paused) {
+                                    nioChannels.push(socket);
+                                }
                                 socket = null;
-                                if ( ka!=null ) keyCache.offer(ka);
+                                if (running && !paused && ka != null) {
+                                    keyCache.push(ka);
+                                }
                                 ka = null;
                             }catch ( Exception x ) {
                                 log.error("",x);
@@ -1716,9 +1596,13 @@ public class NioEndpoint extends Abstrac
                             ka = (KeyAttachment) key.attachment();
                             socket.getPoller().cancelledKey(key, 
SocketStatus.DISCONNECT);
                         }
-                        nioChannels.offer(socket);
+                        if (running && !paused) {
+                            nioChannels.push(socket);
+                        }
                         socket = null;
-                        if ( ka!=null ) keyCache.offer(ka);
+                        if (running && !paused && ka != null) {
+                            keyCache.push(ka);
+                        }
                         ka = null;
                     } else {
                         final SelectionKey fk = key;
@@ -1759,7 +1643,9 @@ public class NioEndpoint extends Abstrac
                     socket = null;
                     status = null;
                     //return to cache
-                    processorCache.offer(this);
+                    if (running && !paused) {
+                        processorCache.push(this);
+                    }
                 }
             }
         }

Modified: 
tomcat/trunk/test/org/apache/tomcat/util/collections/TestConcurrentStack.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/util/collections/TestConcurrentStack.java?rev=1389122&r1=1389121&r2=1389122&view=diff
==============================================================================
--- 
tomcat/trunk/test/org/apache/tomcat/util/collections/TestConcurrentStack.java 
(original)
+++ 
tomcat/trunk/test/org/apache/tomcat/util/collections/TestConcurrentStack.java 
Sun Sep 23 19:12:44 2012
@@ -75,4 +75,45 @@ public class TestConcurrentStack {
         Assert.assertNull(stack.pop());
     }
 
+    @Test
+    public void testLimit() {
+        ConcurrentStack<Object> stack = new ConcurrentStack<>(2,2);
+
+        Object o1 = new Object();
+        Object o2 = new Object();
+        Object o3 = new Object();
+        Object o4 = new Object();
+
+        stack.push(o1);
+        stack.push(o2);
+        stack.push(o3);
+        stack.push(o4);
+
+        Assert.assertSame(stack.pop(), o2);
+        Assert.assertSame(stack.pop(), o1);
+
+        Assert.assertNull(stack.pop());
+    }
+
+
+    @Test
+    public void testLimitExpand() {
+        ConcurrentStack<Object> stack = new ConcurrentStack<>(1,3);
+
+        Object o1 = new Object();
+        Object o2 = new Object();
+        Object o3 = new Object();
+        Object o4 = new Object();
+
+        stack.push(o1);
+        stack.push(o2);
+        stack.push(o3);
+        stack.push(o4);
+
+        Assert.assertSame(stack.pop(), o3);
+        Assert.assertSame(stack.pop(), o2);
+        Assert.assertSame(stack.pop(), o1);
+
+        Assert.assertNull(stack.pop());
+    }
 }



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

Reply via email to