src/share/classes/java/util/logging/FileHandler.java
Print this page
*** 23,45 ****
--- 23,51 ----
* questions.
*/
package java.util.logging;
+ import static java.nio.file.StandardOpenOption.APPEND;
import static java.nio.file.StandardOpenOption.CREATE_NEW;
import static java.nio.file.StandardOpenOption.WRITE;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.channels.FileChannel;
+ import java.nio.channels.OverlappingFileLockException;
import java.nio.file.FileAlreadyExistsException;
+ import java.nio.file.Files;
+ import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.AccessController;
import java.security.PrivilegedAction;
+ import java.util.HashSet;
+ import java.util.Set;
/**
* Simple file logging <tt>Handler</tt>.
* <p>
* The <tt>FileHandler</tt> can either write to a specified file,
*** 147,157 ****
private String pattern;
private String lockFileName;
private FileChannel lockFileChannel;
private File files[];
private static final int MAX_LOCKS = 100;
! private static final java.util.HashMap<String, String> locks = new java.util.HashMap<>();
/**
* A metered stream is a subclass of OutputStream that
* (a) forwards all its output to a target stream
* (b) keeps track of how many bytes have been written
--- 153,163 ----
private String pattern;
private String lockFileName;
private FileChannel lockFileChannel;
private File files[];
private static final int MAX_LOCKS = 100;
! private static final Set<String> locks = new HashSet<>();
/**
* A metered stream is a subclass of OutputStream that
* (a) forwards all its output to a target stream
* (b) keeps track of how many bytes have been written
*** 426,463 ****
// Now try to lock that filename.
// Because some systems (e.g., Solaris) can only do file locks
// between processes (and not within a process), we first check
// if we ourself already have the file locked.
synchronized(locks) {
! if (locks.get(lockFileName) != null) {
// We already own this lock, for a different FileHandler
// object. Try again.
continue;
}
try {
! lockFileChannel = FileChannel.open(Paths.get(lockFileName),
CREATE_NEW, WRITE);
} catch (FileAlreadyExistsException ix) {
// try the next lock file name in the sequence
continue;
}
boolean available;
try {
available = lockFileChannel.tryLock() != null;
// We got the lock OK.
} catch (IOException ix) {
// We got an IOException while trying to get the lock.
// This normally indicates that locking is not supported
// on the target directory. We have to proceed without
! // getting a lock. Drop through.
! available = true;
}
if (available) {
// We got the lock. Remember it.
! locks.put(lockFileName, lockFileName);
break;
}
// We failed to get the lock. Try next file.
lockFileChannel.close();
--- 432,494 ----
// Now try to lock that filename.
// Because some systems (e.g., Solaris) can only do file locks
// between processes (and not within a process), we first check
// if we ourself already have the file locked.
synchronized(locks) {
! if (locks.contains(lockFileName)) {
// We already own this lock, for a different FileHandler
// object. Try again.
continue;
}
+ final Path lockFilePath = Paths.get(lockFileName);
+ boolean fileCreated;
try {
! lockFileChannel = FileChannel.open(lockFilePath,
CREATE_NEW, WRITE);
+ fileCreated = true;
} catch (FileAlreadyExistsException ix) {
+ // This may be a zombie file left over by a previous
+ // execution. Reuse it - but only if we can actually
+ // write to its directory.
+ if (Files.isRegularFile(lockFilePath)
+ && Files.isWritable(lockFilePath)
+ && Files.isWritable(lockFilePath.getParent())) {
+ lockFileChannel = FileChannel.open(lockFilePath,
+ WRITE, APPEND);
+ fileCreated = false;
+ } else {
// try the next lock file name in the sequence
continue;
}
+ }
boolean available;
try {
available = lockFileChannel.tryLock() != null;
// We got the lock OK.
+ // At this point we could call File.deleteOnExit().
+ // However, this could have undesirable side effects
+ // as indicated by JDK-4872014. So we will instead
+ // rely on the fact that close() will remove the lock
+ // file and that whoever is creating FileHandlers should
+ // be responsible for closing them.
} catch (IOException ix) {
// We got an IOException while trying to get the lock.
// This normally indicates that locking is not supported
// on the target directory. We have to proceed without
! // getting a lock. Drop through, but only if we did
! // create the file...
! available = fileCreated;
! } catch (OverlappingFileLockException x) {
! // someone already locked this file in this VM.
! // continue searching for an available lock.
! available = false;
}
if (available) {
// We got the lock. Remember it.
! locks.add(lockFileName);
break;
}
// We failed to get the lock. Try next file.
lockFileChannel.close();