--- old/src/share/classes/java/util/logging/FileHandler.java 2014-06-25 10:24:06.000000000 +0200
+++ new/src/share/classes/java/util/logging/FileHandler.java 2014-06-25 10:24:06.000000000 +0200
@@ -25,6 +25,7 @@
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;
@@ -34,10 +35,15 @@
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 Handler.
@@ -149,7 +155,7 @@
private FileChannel lockFileChannel;
private File files[];
private static final int MAX_LOCKS = 100;
- private static final java.util.HashMap locks = new java.util.HashMap<>();
+ private static final Set locks = new HashSet<>();
/**
* A metered stream is a subclass of OutputStream that
@@ -428,34 +434,59 @@
// 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) {
+ 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(Paths.get(lockFileName),
+ lockFileChannel = FileChannel.open(lockFilePath,
CREATE_NEW, WRITE);
+ fileCreated = true;
} catch (FileAlreadyExistsException ix) {
- // try the next lock file name in the sequence
- continue;
+ // 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.
- available = true;
+ // 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.put(lockFileName, lockFileName);
+ locks.add(lockFileName);
break;
}