From 27666894544bdac84c840875cc2e87739b73b0c6 Mon Sep 17 00:00:00 2001 From: markt Date: Wed, 17 Nov 2010 17:59:49 +0000 Subject: [PATCH] Session manager performance Switch to a queue of randomInputStreams Significant performance improvement on multi-core non-Windows platforms git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@1036145 13f79535-47bb-0310-9956-ffa450edef68 --- java/org/apache/catalina/session/ManagerBase.java | 69 ++++++++++++++--------- test/org/apache/catalina/session/Benchmarks.java | 20 +++---- 2 files changed, 51 insertions(+), 38 deletions(-) diff --git a/java/org/apache/catalina/session/ManagerBase.java b/java/org/apache/catalina/session/ManagerBase.java index 62666dff5..88bca2696 100644 --- a/java/org/apache/catalina/session/ManagerBase.java +++ b/java/org/apache/catalina/session/ManagerBase.java @@ -76,7 +76,8 @@ public abstract class ManagerBase extends LifecycleMBeanBase // ----------------------------------------------------- Instance Variables - protected volatile InputStream randomIS = null; + protected volatile Queue randomInputStreams = + new ConcurrentLinkedQueue(); protected String randomFile = "/dev/urandom"; protected String randomFileCurrent = null; protected volatile boolean randomFileCurrentIsValid = true; @@ -253,27 +254,28 @@ public abstract class ManagerBase extends LifecycleMBeanBase // ------------------------------------------------------------- Security classes - private class PrivilegedCreateRandomIS implements PrivilegedAction { + private class PrivilegedCreateRandomInputStream + implements PrivilegedAction { @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 extends LifecycleMBeanBase 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 extends LifecycleMBeanBase } - 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 extends LifecycleMBeanBase 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 extends LifecycleMBeanBase @Override protected void stopInternal() throws LifecycleException { - closeRandomFile(); + closeRandomInputStreams(); } @@ -1037,17 +1046,18 @@ public abstract class ManagerBase extends LifecycleMBeanBase 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 extends LifecycleMBeanBase // Ignore } randomFileCurrentIsValid = false; - closeRandomFile(); + if (is != null) { + randomInputStreams.add(is); + } + closeRandomInputStreams(); } Random random = randoms.poll(); if (random == null) { diff --git a/test/org/apache/catalina/session/Benchmarks.java b/test/org/apache/catalina/session/Benchmarks.java index eb35a1b49..191c12451 100644 --- a/test/org/apache/catalina/session/Benchmarks.java +++ b/test/org/apache/catalina/session/Benchmarks.java @@ -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]; -- 2.11.0