Author: markt
Date: Fri Aug 21 10:23:23 2015
New Revision: 1696925

URL: http://svn.apache.org/r1696925
Log:
Implement pruning of old streams

Modified:
    tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java
    tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties
    tomcat/trunk/java/org/apache/coyote/http2/Stream.java
    tomcat/trunk/java/org/apache/coyote/http2/StreamStateMachine.java

Modified: tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java?rev=1696925&r1=1696924&r2=1696925&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java 
(original)
+++ tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java Fri Aug 
21 10:23:23 2015
@@ -27,6 +27,7 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Queue;
 import java.util.Set;
+import java.util.TreeSet;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -131,7 +132,7 @@ public class Http2UpgradeHandler extends
     private volatile int maxActiveRemoteStreamId = -1;
     private volatile int maxProcessedStreamId;
     private final PingManager pingManager = new PingManager();
-
+    private volatile int newStreamsSinceLastPrune = 0;
     // Tracking for when the connection is blocked (windowSize < 1)
     private final Map<AbstractStream,int[]> backLogStreams = new 
ConcurrentHashMap<>();
     private long backLogSize = 0;
@@ -743,7 +744,7 @@ public class Http2UpgradeHandler extends
                     Integer.valueOf(maxRemoteStreamId)), 
Http2Error.PROTOCOL_ERROR);
         }
 
-        // TODO Implement periodic pruning of closed streams
+        pruneClosedStreams();
 
         Stream result = new Stream(key, this);
         streams.put(key, result);
@@ -761,6 +762,77 @@ public class Http2UpgradeHandler extends
         }
     }
 
+
+    private void pruneClosedStreams() {
+        // Only prune every 10 new streams
+        if (newStreamsSinceLastPrune < 9) {
+            newStreamsSinceLastPrune++;
+            return;
+        }
+        // Reset counter
+        newStreamsSinceLastPrune = 0;
+
+        // RFC 7540, 5.3.4 endpoints should maintain state for at least the
+        // maximum number of concurrent streams
+        long max = localSettings.getMaxConcurrentStreams();
+        // Allow an additional 10% for closed streams that are used in the
+        // priority tree
+        max = max + max / 10;
+        if (max > Integer.MAX_VALUE) {
+            max = Integer.MAX_VALUE;
+        }
+
+        if (log.isDebugEnabled()) {
+            log.debug(sm.getString("upgradeHandler.pruneStart", connectionId,
+                    Long.toString(max), Integer.toString(streams.size())));
+        }
+
+        int toClose = (int) max  - streams.size();
+        if (toClose < 1) {
+            return;
+        }
+
+        // Need to try and close some streams.
+        // Use this Set to keep track of streams that might be part of the
+        // priority tree. Only remove these if we absolutely have to.
+        TreeSet<Integer> additionalCandidates = new TreeSet<>();
+
+        Iterator<Entry<Integer,Stream>> entryIter = 
streams.entrySet().iterator();
+        while (entryIter.hasNext() && toClose > 0) {
+            Entry<Integer,Stream> entry = entryIter.next();
+            Stream stream = entry.getValue();
+            // Never remove active streams or streams with children
+            if (stream.isActive() || stream.getChildStreams().size() > 0) {
+                continue;
+            }
+            if (stream.isClosedFinal()) {
+                // This stream went from IDLE to CLOSED and is likely to have
+                // been created by the client as part of the priority tree. 
Keep
+                // it if possible.
+                additionalCandidates.add(entry.getKey());
+            } else {
+                if (log.isDebugEnabled()) {
+                    log.debug(sm.getString("upgradeHandler.pruned", 
connectionId, entry.getKey()));
+                }
+                entryIter.remove();
+                toClose--;
+            }
+        }
+
+        while (toClose > 0 && additionalCandidates.size() > 0) {
+            Integer pruned = additionalCandidates.pollLast();
+            if (log.isDebugEnabled()) {
+                log.debug(sm.getString("upgradeHandler.prunedPriority", 
connectionId, pruned));
+            }
+            toClose++;
+        }
+
+        if (toClose > 0) {
+            log.warn(sm.getString("upgradeHandler.pruneIncomplete", 
connectionId,
+                    Integer.toString(toClose)));
+        }
+    }
+
 
     String getProperty(String key) {
         return socketWrapper.getEndpoint().getProperty(key);

Modified: tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties?rev=1696925&r1=1696924&r2=1696925&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties (original)
+++ tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties Fri Aug 
21 10:23:23 2015
@@ -89,6 +89,10 @@ upgradeHandler.ioerror=Connection [{0}]
 upgradeHandler.noNewStreams=Connection [{0}], Stream [{1}], Stream ignored as 
no new streams are permitted on this connection
 upgradeHandler.pause.entry=Connection [{0}] Pausing
 upgradeHandler.pingFailed=Connection [{0}] Failed to send ping to client
+upgradeHandler.pruneIncomplete=Connection [{0}] Failed to fully prune the 
connection because streams were active / used in the priority tree. There are 
[{0}] too many streams
+upgradeHandler.pruneStart=Connection [{0}] Starting pruning of old streams. 
Limit is [{1}] and there are currently [{2}] streams.
+upgradeHandler.pruned=Connection [{0}] Pruned completed stream [{1}]
+upgradeHandler.prunedPriority=Connection [{0}] Pruned unused stream [{1}] that 
may have been part of the priority tree
 upgradeHandler.rst.debug=Connection [{0}], Stream [{1}], Error [{2}], RST 
(closing stream)
 upgradeHandler.sendPrefaceFail=Failed to send preface to client
 upgradeHandler.socketCloseFailed=Error closing socket

Modified: tomcat/trunk/java/org/apache/coyote/http2/Stream.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/Stream.java?rev=1696925&r1=1696924&r2=1696925&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/Stream.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http2/Stream.java Fri Aug 21 10:23:23 
2015
@@ -279,6 +279,11 @@ public class Stream extends AbstractStre
     }
 
 
+    boolean isClosedFinal() {
+        return state.isClosedFinal();
+    }
+
+
     void closeIfIdle() {
         state.closeIfIdle();
     }

Modified: tomcat/trunk/java/org/apache/coyote/http2/StreamStateMachine.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/StreamStateMachine.java?rev=1696925&r1=1696924&r2=1696925&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/StreamStateMachine.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http2/StreamStateMachine.java Fri Aug 
21 10:23:23 2015
@@ -130,6 +130,10 @@ public class StreamStateMachine {
     }
 
 
+    public synchronized boolean isClosedFinal() {
+        return state == State.CLOSED_FINAL;
+    }
+
     public synchronized void closeIfIdle() {
         stateChange(State.IDLE, State.CLOSED_FINAL);
     }



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

Reply via email to