org.apache.ivy.plugins.lock.FileBasedLockStrategy Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.ivy.plugins.lock;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.util.HashMap;
import java.util.Map;
import org.apache.ivy.util.Message;
public abstract class FileBasedLockStrategy extends AbstractLockStrategy {
private static final int SLEEP_TIME = 100;
private static final long DEFAULT_TIMEOUT = 2 * 60 * 1000;
/**
* The locker to use to make file lock attempts.
*
* Two implementations of FileLocker are provided below, according to our tests the
* CreateFileLocker is both performing better and much more reliable than NIOFileLocker.
*
*/
private FileLocker locker;
private long timeout = DEFAULT_TIMEOUT;
private Map/**/ currentLockCounters = new HashMap();
protected FileBasedLockStrategy() {
this(new CreateFileLocker(false), false);
}
protected FileBasedLockStrategy(boolean debugLocking) {
this(new CreateFileLocker(debugLocking), debugLocking);
}
protected FileBasedLockStrategy(FileLocker locker, boolean debugLocking) {
super(debugLocking);
this.locker = locker;
}
protected boolean acquireLock(File file) throws InterruptedException {
if (isDebugLocking()) {
debugLocking("acquiring lock on " + file);
}
long start = System.currentTimeMillis();
do {
synchronized (this) {
if (hasLock(file)) {
int holdLocks = incrementLock(file);
if (isDebugLocking()) {
debugLocking("reentrant lock acquired on " + file
+ " in " + (System.currentTimeMillis() - start) + "ms"
+ " - hold locks = " + holdLocks);
}
return true;
}
if (locker.tryLock(file)) {
if (isDebugLocking()) {
debugLocking("lock acquired on " + file
+ " in " + (System.currentTimeMillis() - start) + "ms");
}
incrementLock(file);
return true;
}
}
Thread.sleep(SLEEP_TIME);
} while (System.currentTimeMillis() - start < timeout);
return false;
}
protected void releaseLock(File file) {
synchronized (this) {
int holdLocks = decrementLock(file);
if (holdLocks == 0) {
locker.unlock(file);
if (isDebugLocking()) {
debugLocking("lock released on " + file);
}
} else {
if (isDebugLocking()) {
debugLocking("reentrant lock released on " + file
+ " - hold locks = " + holdLocks);
}
}
}
}
private static void debugLocking(String msg) {
Message.info(Thread.currentThread() + " " + System.currentTimeMillis() + " " + msg);
}
private boolean hasLock(File file) {
Integer c = (Integer) currentLockCounters.get(file);
return c != null && c.intValue() > 0;
}
private int incrementLock(File file) {
Integer c = (Integer) currentLockCounters.get(file);
int holdLocks = c == null ? 1 : c.intValue() + 1;
currentLockCounters.put(file, new Integer(holdLocks));
return holdLocks;
}
private int decrementLock(File file) {
Integer c = (Integer) currentLockCounters.get(file);
int dc = c == null ? 0 : c.intValue() - 1;
currentLockCounters.put(file, new Integer(dc));
return dc;
}
public static interface FileLocker {
boolean tryLock(File f);
void unlock(File f);
}
/**
* "locks" a file by creating it if it doesn't exist, relying on the
* {@link File#createNewFile()} atomicity.
*/
public static class CreateFileLocker implements FileLocker {
private boolean debugLocking;
public CreateFileLocker(boolean debugLocking) {
this.debugLocking = debugLocking;
}
public boolean tryLock(File file) {
try {
if (file.getParentFile().exists() || file.getParentFile().mkdirs()) {
if (file.createNewFile()) {
return true;
} else {
if (debugLocking) {
debugLocking("file creation failed " + file);
}
}
}
} catch (IOException e) {
// ignored
Message.verbose("file creation failed due to an exception: "
+ e.getMessage() + " (" + file + ")");
}
return false;
}
public void unlock(File file) {
file.delete();
}
}
/**
* Locks a file using the {@link FileLock} mechanism.
*/
public static class NIOFileLocker implements FileLocker {
private Map locks = new HashMap();
private boolean debugLocking;
public NIOFileLocker(boolean debugLocking) {
this.debugLocking = debugLocking;
}
public boolean tryLock(File file) {
try {
if (file.getParentFile().exists() || file.getParentFile().mkdirs()) {
RandomAccessFile raf =
new RandomAccessFile(file, "rw");
FileChannel channel = raf.getChannel();
try {
FileLock l = channel.tryLock();
if (l != null) {
synchronized (this) {
locks.put(file, l);
}
return true;
} else {
if (debugLocking) {
debugLocking("failed to acquire lock on " + file);
}
}
} finally {
raf.close();
}
}
} catch (IOException e) {
// ignored
Message.verbose("file lock failed due to an exception: "
+ e.getMessage() + " (" + file + ")");
}
return false;
}
public void unlock(File file) {
synchronized (this) {
FileLock l = (FileLock) locks.get(file);
if (l == null) {
throw new IllegalArgumentException("file not previously locked: " + file);
}
try {
l.release();
} catch (IOException e) {
Message.error(
"problem while releasing lock on " + file + ": " + e.getMessage());
}
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy