JDK-8153955 : increase java.util.logging.FileHandler MAX_LOCKS limit
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: java.util.logging
  • Affected Version: 6u65,7,8u77
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2016-04-11
  • Updated: 2018-05-23
  • Resolved: 2016-06-28
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 6 JDK 7 JDK 8 JDK 9 Other
6u191Fixed 7u181Fixed 8u171Fixed 9 b126Fixed openjdk7uFixed
Sub Tasks
JDK-8159877 :  
JDK-8193696 :  
Description
The submitter faced following problem.
OS : Solaris
Java : 6u65 (may be 64bit ) / JDK 7 and 8 are same result.
When they invoke a lot of same Java Program that using java.util.logger with
FileHandler,
IOException occured.
Can't load log handler "java.util.logging.FileHandler"
java.io.IOException: Couldn't get lock for test%u.%g.log
java.io.IOException: Couldn't get lock for test%u.%g.log
        at java.util.logging.FileHandler.openFiles(FileHandler.java:nnn)
        at java.util.logging.FileHandler.<init>(FileHandler.java:nnn)
         ...
    (Note: it is not a actual stacktrace)
    
Submitter's evaluation:
[src/share/classes/java/util/logging/FileHandler.java]
     ...
    private static final int MAX_LOCKS = 100;
     ...
        // Create a lock file. This grants us exclusive access
        // to our set of output files, as long as we are alive.
        int unique = -1;
        for (;;) {
            unique++;
            if (unique > MAX_LOCKS) {
                throw new IOException("Couldn't get lock for " + pattern); <<
this Exception happen >>
            }
            // Generate a lock file name from the "unique" int.
    "unique" range is 0 to 100, so "max number of concurrent process" is
limited to 101.

[test case]:
-- logging.properties --
handlers= java.util.logging.FileHandler
.level= ALL
java.util.logging.FileHandler.pattern = test%u.%g.log
java.util.logging.FileHandler.limit = 10000
java.util.logging.FileHandler.count = 10
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
-- LoggingTest.java --
import java.io.*;
import java.util.*;
import java.util.logging.*;
class LoggingTest {
  public static void main(String[] args) throws Exception {
    System.setProperty("java.util.logging.config.file",
"logging.properties");
    Logger logger = Logger.getLogger(LoggingTest.class.getName());
    for (int i = 0; i < 1200; i++) {
      logger.log(Level.INFO, String.format("Test: %s", logger));
      Thread.sleep(100L);
    }
  }
}
-- do101.bash --
#!/usr/bin/bash
rm *.log *.lck
for i in {0..101}
do
  echo $i
  ${JAVA_HOME}/bin/java -Xmx8m LoggingTest &
done
sleep 15
pkill java
----------------------------------------------------
% ./do101.bash
  ...
95
96
97
98
99
100
101
Can't load log handler "java.util.logging.FileHandler"
java.io.IOException: Couldn't get lock for test%u.%g.log
java.io.IOException: Couldn't get lock for test%u.%g.log
        at java.util.logging.FileHandler.openFiles(FileHandler.java:372)
        at java.util.logging.FileHandler.<init>(FileHandler.java:208)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native
Method)
        at
sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccesso
rImpl.java:39)
        at
sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructo
rAccessorImpl.java:27)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
        at java.lang.Class.newInstance0(Class.java:355)
        at java.lang.Class.newInstance(Class.java:308)
        at java.util.logging.LogManager$3.run(LogManager.java:359)
��  @         at java.security.AccessController.doPrivileged(Native Method)
        at
java.util.logging.LogManager.loadLoggerHandlers(LogManager.java:345)
        at
java.util.logging.LogManager.initializeGlobalHandlers(LogManager.java:1032)
        at java.util.logging.LogManager.access$1100(LogManager.java:129)
        at
java.util.logging.LogManager$RootLogger.getHandlers(LogManager.java:1113)
        at java.util.logging.Logger.log(Logger.java:474)
        at java.util.logging.Logger.doLog(Logger.java:500)
        at java.util.logging.Logger.log(Logger.java:523)
        at LoggingTest.main(LoggingTest.java:13)
        
[Expected]
"max number of concurrent process" is unlimited (logically).

Java API doc (java.util.logging.FileHanlder) writes:
==============================================================================
 Normally the "%u" unique field is set to 0.
 However, if the FileHandler tries to open the filename and finds the file
 is currently in use by another process it will increment the unique number
 field and try again. This will be repeated until FileHandler finds a file
name
 that is not currently in use. If there is a conflict and no "%u" field has
been
 specified, it will be added at the end of the filename after a dot.
 (This will be after any automatically added generation number.)
==============================================================================
 This is not describe the limitation of max number of process / conflict.
 
Comments
UR SQE OK to defer it from PSU16_04
10-08-2016

The licensee believes that a fundamental point of this issue is MAX_LOCKS cannot be changed. Even if MAX_LOCKS set a reasonable value for now, maybe same problem turns up in the future. Also, https://docs.oracle.com/javase/7/docs/api/java/util/logging/FileHandler.html mentioned "increment the unique number field and try again". So MAX_LOCKS should NOT be extremely large because it may cause a performance problem in scalability.
15-04-2016