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