Author: markt Date: Thu Jan 20 18:10:16 2011 New Revision: 1061433 URL: http://svn.apache.org/viewvc?rev=1061433&view=rev Log: Add session creation / expiration rate statistics to the session managers Adds ~10% to the session creation/destruction process when that is all Tomcat is doing. Should be less overhead with less contention.
Modified: tomcat/tc6.0.x/trunk/STATUS.txt tomcat/tc6.0.x/trunk/java/org/apache/catalina/ha/session/DeltaManager.java tomcat/tc6.0.x/trunk/java/org/apache/catalina/session/ManagerBase.java tomcat/tc6.0.x/trunk/java/org/apache/catalina/session/StandardSession.java tomcat/tc6.0.x/trunk/java/org/apache/catalina/session/mbeans-descriptors.xml tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml Modified: tomcat/tc6.0.x/trunk/STATUS.txt URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/STATUS.txt?rev=1061433&r1=1061432&r2=1061433&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/STATUS.txt (original) +++ tomcat/tc6.0.x/trunk/STATUS.txt Thu Jan 20 18:10:16 2011 @@ -89,16 +89,6 @@ PATCHES PROPOSED TO BACKPORT: We can stall this item until we get some feedback about 7.0.5. -1: -* Add session creation / expiration rate statistics to the session managers - Adds ~10% to the session creation/destruction process when that is all Tomcat - is doing. Should be less overhead with less contention. - http://people.apache.org/~markt/patches/2010-11-18-session-rate-stats.patch - +1: markt, rjung, fhanik - -1: - rjung: getSessionExpireRate() and getSessionCreateRate() could share a common - implementation (same method body except for the input list). The member - "duration" of SessionTiming does not seem to get used. - * Backport AprEndpoint shutdown patch (BZ49795 and similar). http://people.apache.org/~mturk/tomcat/patches/tomcat-6.0.x-aprshutdown.patch +1: mturk Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/ha/session/DeltaManager.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/ha/session/DeltaManager.java?rev=1061433&r1=1061432&r2=1061433&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/catalina/ha/session/DeltaManager.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/ha/session/DeltaManager.java Thu Jan 20 18:10:16 2011 @@ -40,6 +40,7 @@ import org.apache.catalina.core.Standard import org.apache.catalina.ha.CatalinaCluster; import org.apache.catalina.ha.ClusterMessage; import org.apache.catalina.ha.tcp.ReplicationValve; +import org.apache.catalina.session.ManagerBase; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.io.ReplicationStream; import org.apache.catalina.util.LifecycleSupport; @@ -1286,6 +1287,16 @@ public class DeltaManager extends Cluste public synchronized void resetStatistics() { processingTime = 0 ; expiredSessions = 0 ; + sessionCreationTiming.clear(); + while (sessionCreationTiming.size() < + ManagerBase.TIMING_STATS_CACHE_SIZE) { + sessionCreationTiming.add(null); + } + sessionExpirationTiming.clear(); + while (sessionExpirationTiming.size() < + ManagerBase.TIMING_STATS_CACHE_SIZE) { + sessionExpirationTiming.add(null); + } rejectedSessions = 0 ; sessionReplaceCounter = 0 ; counterNoStateTransfered = 0 ; Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/session/ManagerBase.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/session/ManagerBase.java?rev=1061433&r1=1061432&r2=1061433&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/catalina/session/ManagerBase.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/session/ManagerBase.java Thu Jan 20 18:10:16 2011 @@ -30,10 +30,13 @@ import java.security.AccessController; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.PrivilegedAction; +import java.util.ArrayList; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; import java.util.Map; import java.util.Random; import java.util.concurrent.ConcurrentHashMap; @@ -165,6 +168,15 @@ public abstract class ManagerBase implem protected int sessionAverageAliveTime; + protected static final int TIMING_STATS_CACHE_SIZE = 100; + + protected LinkedList<SessionTiming> sessionCreationTiming = + new LinkedList<SessionTiming>(); + + protected LinkedList<SessionTiming> sessionExpirationTiming = + new LinkedList<SessionTiming>(); + + /** * Number of sessions that have expired. */ @@ -752,6 +764,15 @@ public abstract class ManagerBase implem // Initialize random number generation getRandomBytes(new byte[16]); + // Ensure caches for timing stats are the right size by filling with + // nulls. + while (sessionCreationTiming.size() < TIMING_STATS_CACHE_SIZE) { + sessionCreationTiming.add(null); + } + while (sessionExpirationTiming.size() < TIMING_STATS_CACHE_SIZE) { + sessionExpirationTiming.add(null); + } + if(log.isDebugEnabled()) log.debug("Registering " + oname ); @@ -860,6 +881,11 @@ public abstract class ManagerBase implem session.setId(sessionId); sessionCounter++; + SessionTiming timing = new SessionTiming(session.getCreationTime(), 0); + synchronized (sessionCreationTiming) { + sessionCreationTiming.add(timing); + sessionCreationTiming.poll(); + } return (session); } @@ -1167,6 +1193,91 @@ public abstract class ManagerBase implem } + /** + * Gets the current rate of session creation (in session per minute) based + * on the creation time of the previous 100 sessions created. If less than + * 100 sessions have been created then all available data is used. + * + * @return The current rate (in sessions per minute) of session creation + */ + public int getSessionCreateRate() { + long now = System.currentTimeMillis(); + // Copy current stats + List<SessionTiming> copy = new ArrayList<SessionTiming>(); + synchronized (sessionCreationTiming) { + copy.addAll(sessionCreationTiming); + } + + // Init + long oldest = now; + int counter = 0; + int result = 0; + Iterator<SessionTiming> iter = copy.iterator(); + + // Calculate rate + while (iter.hasNext()) { + SessionTiming timing = iter.next(); + if (timing != null) { + counter++; + if (timing.getTimestamp() < oldest) { + oldest = timing.getTimestamp(); + } + } + } + if (counter > 0) { + if (oldest < now) { + result = (int) ((1000*60*counter)/(now - oldest)); + } else { + result = Integer.MAX_VALUE; + } + } + return result; + } + + + /** + * Gets the current rate of session expiration (in session per minute) based + * on the expiry time of the previous 100 sessions expired. If less than + * 100 sessions have expired then all available data is used. + * + * @return The current rate (in sessions per minute) of session expiration + */ + public int getSessionExpireRate() { + long now = System.currentTimeMillis(); + // Copy current stats + List<SessionTiming> copy = new ArrayList<SessionTiming>(); + synchronized (sessionExpirationTiming) { + copy.addAll(sessionExpirationTiming); + } + + // Init + long oldest = now; + int counter = 0; + int result = 0; + Iterator<SessionTiming> iter = copy.iterator(); + + // Calculate rate + while (iter.hasNext()) { + SessionTiming timing = iter.next(); + if (timing != null) { + counter++; + if (timing.getTimestamp() < oldest) { + oldest = timing.getTimestamp(); + } + } + } + if (counter > 0) { + if (oldest < now) { + result = (int) ((1000*60*counter)/(now - oldest)); + } else { + // Better than reporting zero + result = Integer.MAX_VALUE; + } + } + return result; + } + + /** * For debugging: return a list of all session ids currently active * @@ -1311,4 +1422,30 @@ public abstract class ManagerBase implem public void postDeregister() { } + // ----------------------------------------------------------- Inner classes + + protected static final class SessionTiming { + private long timestamp; + private int duration; + + public SessionTiming(long timestamp, int duration) { + this.timestamp = timestamp; + this.duration = duration; + } + + /** + * Time stamp associated with this piece of timing information in + * milliseconds. + */ + public long getTimestamp() { + return timestamp; + } + + /** + * Duration associated with this piece of timing information in seconds. + */ + public int getDuration() { + return duration; + } + } } Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/session/StandardSession.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/session/StandardSession.java?rev=1061433&r1=1061432&r2=1061433&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/catalina/session/StandardSession.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/session/StandardSession.java Thu Jan 20 18:10:16 2011 @@ -59,6 +59,7 @@ import org.apache.catalina.util.StringMa import org.apache.catalina.core.StandardContext; import org.apache.catalina.realm.GenericPrincipal; import org.apache.catalina.security.SecurityUtil; +import org.apache.catalina.session.ManagerBase.SessionTiming; /** * Standard implementation of the <b>Session</b> interface. This object is @@ -762,6 +763,15 @@ public class StandardSession manager.setSessionAverageAliveTime(average); } + if (manager instanceof ManagerBase) { + ManagerBase mb = (ManagerBase) manager; + SessionTiming timing = new SessionTiming(timeNow, timeAlive); + synchronized (mb.sessionExpirationTiming) { + mb.sessionExpirationTiming.add(timing); + mb.sessionExpirationTiming.poll(); + } + } + // Remove this session from our manager's active sessions manager.remove(this); Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/session/mbeans-descriptors.xml URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/session/mbeans-descriptors.xml?rev=1061433&r1=1061432&r2=1061433&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/catalina/session/mbeans-descriptors.xml (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/session/mbeans-descriptors.xml Thu Jan 20 18:10:16 2011 @@ -83,10 +83,20 @@ type="int" writeable="false"/> + <attribute name="sessionCreateRate" + description="Session creation rate in sessions per minute" + type="int" + writeable="false" /> + <attribute name="sessionCounter" description="Total number of sessions created by this manager" type="int" /> - + + <attribute name="sessionExpireRate" + description="Session expiration rate in sessions per minute" + type="int" + writeable="false" /> + <attribute name="maxActive" description="Maximum number of active sessions so far" type="int" /> @@ -245,10 +255,20 @@ type="int" writeable="false"/> + <attribute name="sessionCreateRate" + description="Session creation rate in sessions per minute" + type="int" + writeable="false" /> + <attribute name="sessionCounter" description="Total number of sessions created by this manager" type="int" /> - + + <attribute name="sessionExpireRate" + description="Session expiration rate in sessions per minute" + type="int" + writeable="false" /> + <attribute name="maxActive" description="Maximum number of active sessions so far" type="int" /> Modified: tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml?rev=1061433&r1=1061432&r2=1061433&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml (original) +++ tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml Thu Jan 20 18:10:16 2011 @@ -59,6 +59,10 @@ ensure that a subsequent request for that directory does not result in a 404 response. (markt/kkolinko) </fix> + <add> + Provide session creation and destruction rate metrics in the session + managers. (markt) + </add> </changelog> </subsection> <subsection name="Coyote"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org