Author: markt Date: Tue Mar 18 09:42:35 2014 New Revision: 1578799 URL: http://svn.apache.org/r1578799 Log: Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=56082 Fix thread safety issue in JULI's LogManager implementation
Modified: tomcat/tc6.0.x/trunk/ (props changed) tomcat/tc6.0.x/trunk/STATUS.txt tomcat/tc6.0.x/trunk/java/org/apache/juli/ClassLoaderLogManager.java tomcat/tc6.0.x/trunk/test/org/apache/juli/TestClassLoaderLogManager.java tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml Propchange: tomcat/tc6.0.x/trunk/ ------------------------------------------------------------------------------ Merged /tomcat/trunk:r1562742,1562746 Merged /tomcat/tc7.0.x/trunk:r1562748 Modified: tomcat/tc6.0.x/trunk/STATUS.txt URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/STATUS.txt?rev=1578799&r1=1578798&r2=1578799&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/STATUS.txt (original) +++ tomcat/tc6.0.x/trunk/STATUS.txt Tue Mar 18 09:42:35 2014 @@ -28,12 +28,6 @@ None PATCHES PROPOSED TO BACKPORT: [ New proposals should be added at the end of the list ] -* Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=56082 - Concurrency issue in JULI's LogManager - http://svn.apache.org/r1562748 - +1: markt, kkolinko, remm - -1: - * Make the xmlBlockExternal option in Catalina and Jasper to be true by default. https://people.apache.org/~kkolinko/patches/2014-02-17_tc6_xmlBlockExternalTrue.patch (backport of r1564747) Modified: tomcat/tc6.0.x/trunk/java/org/apache/juli/ClassLoaderLogManager.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/juli/ClassLoaderLogManager.java?rev=1578799&r1=1578798&r2=1578799&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/juli/ClassLoaderLogManager.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/juli/ClassLoaderLogManager.java Tue Mar 18 09:42:35 2014 @@ -35,6 +35,7 @@ import java.util.Map; import java.util.Properties; import java.util.StringTokenizer; import java.util.WeakHashMap; +import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.LogManager; @@ -676,7 +677,7 @@ public class ClassLoaderLogManager exten protected static final class ClassLoaderLogInfo { final LogNode rootNode; - final Map<String, Logger> loggers = new HashMap<String, Logger>(); + final Map<String, Logger> loggers = new ConcurrentHashMap<String, Logger>(); final Map<String, Handler> handlers = new HashMap<String, Handler>(); final Properties props = new Properties(); Modified: tomcat/tc6.0.x/trunk/test/org/apache/juli/TestClassLoaderLogManager.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/test/org/apache/juli/TestClassLoaderLogManager.java?rev=1578799&r1=1578798&r2=1578799&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/test/org/apache/juli/TestClassLoaderLogManager.java (original) +++ tomcat/tc6.0.x/trunk/test/org/apache/juli/TestClassLoaderLogManager.java Tue Mar 18 09:42:35 2014 @@ -14,11 +14,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.apache.juli; import junit.framework.TestCase; +import java.util.Collections; +import java.util.Random; +import java.util.logging.LogManager; +import java.util.logging.Logger; + +import org.junit.Assert; + /** * Test cases for {@link ClassLoaderLogManager}. */ @@ -26,33 +32,117 @@ public class TestClassLoaderLogManager e public void testReplace() { ClassLoaderLogManager logManager = new ClassLoaderLogManager(); - assertEquals("", logManager.replace("")); - assertEquals("${", logManager.replace("${")); - assertEquals("${undefinedproperty}", + Assert.assertEquals("", logManager.replace("")); + Assert.assertEquals("${", logManager.replace("${")); + Assert.assertEquals("${undefinedproperty}", logManager.replace("${undefinedproperty}")); - assertEquals( + Assert.assertEquals( System.getProperty("line.separator") + System.getProperty("path.separator") + System.getProperty("file.separator"), logManager .replace("${line.separator}${path.separator}${file.separator}")); - assertEquals( + Assert.assertEquals( "foo" + System.getProperty("file.separator") + "bar" + System.getProperty("line.separator") + System.getProperty("path.separator") + "baz", logManager .replace("foo${file.separator}bar${line.separator}${path.separator}baz")); // BZ 51249 - assertEquals( + Assert.assertEquals( "%{file.separator}" + System.getProperty("file.separator"), logManager.replace("%{file.separator}${file.separator}")); - assertEquals( + Assert.assertEquals( System.getProperty("file.separator") + "${undefinedproperty}" + System.getProperty("file.separator"), logManager .replace("${file.separator}${undefinedproperty}${file.separator}")); - assertEquals("${}" + System.getProperty("path.separator"), + Assert.assertEquals("${}" + System.getProperty("path.separator"), logManager.replace("${}${path.separator}")); } + public void testBug56082() { + ClassLoaderLogManager logManager = new ClassLoaderLogManager(); + + LoggerCreateThread[] createThreads = new LoggerCreateThread[10]; + for (int i = 0; i < createThreads.length; i ++) { + createThreads[i] = new LoggerCreateThread(logManager); + createThreads[i].setName("LoggerCreate-" + i); + createThreads[i].start(); + } + + LoggerListThread listThread = new LoggerListThread(logManager); + listThread.setName("LoggerList"); + listThread.start(); + + int count = 0; + while (count < 4 && listThread.isAlive()) { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + // Ignore + } + count++; + } + + for (int i = 0; i < createThreads.length; i ++) { + createThreads[i].setRunning(false); + } + + Assert.assertTrue(listThread.isRunning()); + listThread.setRunning(false); + } + + private static class LoggerCreateThread extends Thread { + + private final LogManager logManager; + private volatile boolean running = true; + + public LoggerCreateThread(LogManager logManager) { + this.logManager = logManager; + } + + @Override + public void run() { + Random r = new Random(); + while (running) { + Logger logger = Logger.getLogger("Bug56082-" + r.nextInt(100000)); + logManager.addLogger(logger); + } + } + + public void setRunning(boolean running) { + this.running = running; + } + } + + private static class LoggerListThread extends Thread { + + private final LogManager logManager; + private volatile boolean running = true; + + public LoggerListThread(LogManager logManager) { + this.logManager = logManager; + } + + @Override + public void run() { + while (running) { + try { + Collections.list(logManager.getLoggerNames()); + } catch (Exception e) { + e.printStackTrace(); + running = false; + } + } + } + + public boolean isRunning() { + return running; + } + + public void setRunning(boolean running) { + this.running = running; + } + } } 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=1578799&r1=1578798&r2=1578799&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml (original) +++ tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml Tue Mar 18 09:42:35 2014 @@ -52,6 +52,10 @@ a dependency on the JSP API before enabling validation for web.xml. Tomcat has no such dependency. (markt) </fix> + <fix> + <bug>56082</bug>: Fix a concurrency bug in JULI's LogManager + implementation. (markt) + </fix> </changelog> </subsection> <subsection name="Web applications"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org