Author: markt Date: Wed Nov 17 17:59:49 2010 New Revision: 1036145 URL: http://svn.apache.org/viewvc?rev=1036145&view=rev Log: Session manager performance Switch to a queue of randomInputStreams Significant performance improvement on multi-core non-Windows platforms
Modified: tomcat/trunk/java/org/apache/catalina/session/ManagerBase.java tomcat/trunk/test/org/apache/catalina/session/Benchmarks.java Modified: tomcat/trunk/java/org/apache/catalina/session/ManagerBase.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/session/ManagerBase.java?rev=1036145&r1=1036144&r2=1036145&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/session/ManagerBase.java (original) +++ tomcat/trunk/java/org/apache/catalina/session/ManagerBase.java Wed Nov 17 17:59:49 2010 @@ -76,7 +76,8 @@ public abstract class ManagerBase extend // ----------------------------------------------------- Instance Variables - protected volatile InputStream randomIS = null; + protected volatile Queue<InputStream> randomInputStreams = + new ConcurrentLinkedQueue<InputStream>(); protected String randomFile = "/dev/urandom"; protected String randomFileCurrent = null; protected volatile boolean randomFileCurrentIsValid = true; @@ -253,27 +254,28 @@ public abstract class ManagerBase extend // ------------------------------------------------------------- Security classes - private class PrivilegedCreateRandomIS implements PrivilegedAction<Void> { + private class PrivilegedCreateRandomInputStream + implements PrivilegedAction<InputStream> { @Override - public Void run(){ + public InputStream run(){ try { File f = new File(randomFileCurrent); if (!f.exists()) { randomFileCurrentIsValid = false; - closeRandomFile(); + closeRandomInputStreams(); return null; } InputStream is = new FileInputStream(f); is.read(); if( log.isDebugEnabled() ) log.debug( "Opening " + randomFileCurrent ); - randomIS = is; randomFileCurrentIsValid = true; + return is; } catch (IOException ex){ log.warn("Error reading " + randomFileCurrent, ex); randomFileCurrentIsValid = false; - closeRandomFile(); + closeRandomInputStreams(); } return null; } @@ -570,28 +572,30 @@ public abstract class ManagerBase extend randomFile = s; } - protected void createRandomIS() { + protected InputStream createRandomInputStream() { if (Globals.IS_SECURITY_ENABLED){ - AccessController.doPrivileged(new PrivilegedCreateRandomIS()); + return AccessController.doPrivileged( + new PrivilegedCreateRandomInputStream()); } else { try{ File f = new File(randomFileCurrent); if (!f.exists()) { randomFileCurrentIsValid = false; - closeRandomFile(); - return; + closeRandomInputStreams(); + return null; } InputStream is = new FileInputStream(f); is.read(); if( log.isDebugEnabled() ) log.debug( "Opening " + randomFileCurrent ); - randomIS = is; randomFileCurrentIsValid = true; + return is; } catch( IOException ex ) { log.warn("Error reading " + randomFileCurrent, ex); randomFileCurrentIsValid = false; - closeRandomFile(); + closeRandomInputStreams(); } + return null; } } @@ -624,14 +628,16 @@ public abstract class ManagerBase extend } - protected synchronized void closeRandomFile() { - if (randomIS != null) { + protected synchronized void closeRandomInputStreams() { + InputStream is = randomInputStreams.poll(); + + while (is != null) { try { - randomIS.close(); + is.close(); } catch (Exception e) { - log.warn("Failed to close randomIS."); + log.warn("Failed to close randomInputStream."); } - randomIS = null; + is = randomInputStreams.poll(); } } @@ -851,7 +857,10 @@ public abstract class ManagerBase extend protected void startInternal() throws LifecycleException { randomFileCurrent = randomFile; - createRandomIS(); + InputStream is = createRandomInputStream(); + if (is != null) { + randomInputStreams.add(is); + } // Force initialization of the random number generator if (log.isDebugEnabled()) @@ -863,7 +872,7 @@ public abstract class ManagerBase extend @Override protected void stopInternal() throws LifecycleException { - closeRandomFile(); + closeRandomInputStreams(); } @@ -1037,17 +1046,18 @@ public abstract class ManagerBase extend protected void getRandomBytes(byte bytes[]) { - if (randomIS != null) { + if (randomFileCurrentIsValid) { + InputStream is = null; try { - // If randomIS is set to null by a call to setRandomFile that - // fails, the resulting NPE will trigger a fall-back to - // getRandom() - int len; - synchronized (randomIS) { - // FileInputStream is not thread safe on all platforms - len = randomIS.read(bytes); + // If one of the InputStreams fails, is will be null and the + // resulting NPE will trigger a fall-back to getRandom() + is = randomInputStreams.poll(); + if (is == null) { + is = createRandomInputStream(); } + int len = is.read(bytes); if (len == bytes.length) { + randomInputStreams.add(is); return; } if(log.isDebugEnabled()) @@ -1056,7 +1066,10 @@ public abstract class ManagerBase extend // Ignore } randomFileCurrentIsValid = false; - closeRandomFile(); + if (is != null) { + randomInputStreams.add(is); + } + closeRandomInputStreams(); } Random random = randoms.poll(); if (random == null) { Modified: tomcat/trunk/test/org/apache/catalina/session/Benchmarks.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/session/Benchmarks.java?rev=1036145&r1=1036144&r2=1036145&view=diff ============================================================================== --- tomcat/trunk/test/org/apache/catalina/session/Benchmarks.java (original) +++ tomcat/trunk/test/org/apache/catalina/session/Benchmarks.java Wed Nov 17 17:59:49 2010 @@ -37,10 +37,10 @@ public class Benchmarks extends TestCase * 16 threads - ~21,000ms * * Results on markt's 2-core OSX dev box - * 1 thread - ~5,900ms - * 2 threads - ~16,100ms - * 4 threads - ~32,500ms - * 16 threads - ~132,000ms + * 1 thread - ~5,600ms + * 2 threads - ~ 7,300ms + * 4 threads - ~14,400ms + * 16 threads - ~57,559ms */ public void testManagerBaseGenerateSessionId() throws Exception { doTestManagerBaseGenerateSessionId(1, 1000000); @@ -63,7 +63,7 @@ public class Benchmarks extends TestCase StandardManager mgr = new StandardManager(); // Calling start requires a valid container so do the equivalent mgr.randomFileCurrent = mgr.randomFile; - mgr.createRandomIS(); + mgr.createRandomInputStream(); mgr.generateSessionId(); @@ -125,10 +125,10 @@ public class Benchmarks extends TestCase * 16 threads - ~43,800ms * * Results on markt's 2-core OSX dev box - * 1 thread - ~8,800ms - * 2 threads - ~23,200ms - * 4 threads - ~51,900ms - * 16 threads - ~215,400ms + * 1 thread - ~9,100ms + * 2 threads - ~10,800ms + * 4 threads - ~21,400ms + * 16 threads - ~87,600ms */ public void testManagerBaseCreateSession() { doTestManagerBaseCreateSession(1, 1000000); @@ -145,7 +145,7 @@ public class Benchmarks extends TestCase mgr.setContainer(new StandardContext()); // Calling start requires a valid container so do the equivalent mgr.randomFileCurrent = mgr.randomFile; - mgr.createRandomIS(); + mgr.createRandomInputStream(); mgr.generateSessionId(); Thread[] threads = new Thread[threadCount]; --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org