use of org.commonjava.util.partyline.lock.UnlockStatus in project partyline by Commonjava.
the class InfinispanJF method jointClosed.
/**
* Callback for use in {@link JoinInputStream} to notify this stream to decrement its count of associated input streams.
* @throws IOException
*/
private void jointClosed(JoinInputStream input, String originalThreadName) throws IOException {
try {
lockAnd((key, lock) -> {
inputs.remove(input.hashCode());
Logger logger = LoggerFactory.getLogger(getClass());
logger.trace("jointClosed() called in: {}, current joint count: {}", this, inputs.size());
if (inputs.isEmpty()) {
if (output == null || output.isClosed()) {
logger.trace("All input joint closed, and output is missing or closed. Really closing.");
closed = true;
reallyClose();
}
} else {
UnlockStatus unlockStatus = owner.unlock(labelFor(false, originalThreadName));
filesystem.updateDominantLocks(this.path, unlockStatus);
// owner.unlock( originalThreadName );
}
return null;
});
} catch (InterruptedException e) {
Logger logger = LoggerFactory.getLogger(getClass());
logger.warn("Interrupted while closing reader joint of: {}", getPath());
}
}
use of org.commonjava.util.partyline.lock.UnlockStatus in project partyline by Commonjava.
the class FileTree method unlockAssociatedEntries.
private boolean unlockAssociatedEntries(final FileEntry entry, final String label) {
// the 'alsoLocked' entry field constitutes a linked list of locked entries.
// When we unlock the topmost one, we need to unlock the ones that are linked too.
FileEntry alsoLocked = entry.alsoLocked;
while (alsoLocked != null) {
logger.trace("ALSO Unlocking: {}", alsoLocked.name);
UnlockStatus unlockStatus = alsoLocked.lockOwner.unlock(label);
String fname = alsoLocked.file != null ? alsoLocked.file.getPath() : alsoLocked.name;
filesystem.updateDominantLocks(fname, unlockStatus);
if (!alsoLocked.lockOwner.isLocked()) {
removeEntryAndReentrantLock(alsoLocked.name, null);
}
alsoLocked = alsoLocked.alsoLocked;
}
return true;
}
use of org.commonjava.util.partyline.lock.UnlockStatus in project partyline by Commonjava.
the class LockOwnerTest method lockClearAndLockAgainWithDifferentLevel.
@Test
public void lockClearAndLockAgainWithDifferentLevel() {
String label = "testing";
LocalLockOwner owner = new LocalLockOwner("/path/to/nowhere", label, LockLevel.write);
assertThat(owner.isLockedByCurrentThread(), equalTo(true));
UnlockStatus unlocked = owner.unlock(label);
assertThat(unlocked, notNullValue());
assertThat(unlocked.isUnlocked(), equalTo(true));
assertThat(owner.isLockedByCurrentThread(), equalTo(false));
boolean locked = owner.lock("relocking", LockLevel.delete);
assertThat(locked, equalTo(true));
}
use of org.commonjava.util.partyline.lock.UnlockStatus in project partyline by Commonjava.
the class FileTree method tryLock.
/**
* Acquire the given {@link LockLevel} on the specified file, under the provided ownership name and activity label,
* within the given timeout. If lock acquisition succeeds, execute the provided operation (normally a lambda).
* <br/>
* This method is used within FileTree to handle file lock acquisition before opening / deleting files, among other
* things.
* <br/>
* <b>NOTE:</b> Before attempting to acquire the file lock, this method will acquire the operation semaphore for
* the given file. This prevents other concurrent calls from overlapping when establishing the first lock on a file,
* or when releasing the last lock.
*
* @param f The file to lock
* @param label The activity label, to aid in debugging stuck locks
* @param lockLevel The type of lock to acquire (read, write, delete)
* @param timeout The timeout period before giving up on the lock acquisition
* @param unit The time units for the timeout period (milliseconds, etc)
* @param reentrantOperation The operation to perform once the file lock is acquired
* @return the result of the provided operation, or else null
* @throws InterruptedException
*
* @see LockLevel
*/
<T> T tryLock(File f, String label, LockLevel lockLevel, long timeout, TimeUnit unit, ReentrantOperation<T> reentrantOperation) throws InterruptedException, IOException {
AtomicReference<Exception> error = new AtomicReference<>();
T opResult = lockManager.lockAnd(f.getAbsolutePath(), TimeUnit.SECONDS.convert(timeout, unit), (key, opLock) -> {
long end = timeout < 1 ? -1 : System.currentTimeMillis() + TimeUnit.MILLISECONDS.convert(timeout, unit);
logger.trace("{}: Trying to lock until: {}", System.currentTimeMillis(), end);
String name = f.getAbsolutePath();
FileEntry entry = null;
try {
while (end < 1 || System.currentTimeMillis() < end) {
entry = getNearestLockingEntry(getUnmodifiableEntryMap(), f);
/*
There are three basic states we need to capture here:
1. The target file is already locked. Try to lock again, and retry / fail as appropriate.
2. The target file's ancestor is locked. Try to lock again, and retry / fail as appropriate.
When locked, set a flag to tell the system to lock the target file and proceed.
3. Neither the target file nor its ancestry is locked. Set a flag to tell the system to lock the
target file and proceed.
*/
boolean doFileLock = (entry == null);
if (!doFileLock) {
if (entry.name.equals(name)) {
if (entry.lockOwner.lock(label, lockLevel)) {
logger.trace("Added lock to existing entry: {}", entry.name);
try {
return reentrantOperation.apply(key, opLock);
} catch (Exception e) {
// we just locked this, and the call failed...reverse the lock operation.
UnlockStatus unlockStatus = entry.lockOwner.unlock(label);
filesystem.updateDominantLocks(entry.file.getPath(), unlockStatus);
error.set(e);
return null;
}
} else {
logger.trace("Lock failed, but retry may allow another attempt...");
}
} else if (name.startsWith(entry.name)) {
logger.trace("Re-locking the locking entry: {}.", entry.name);
entry.lockOwner.lock(label, lockLevel);
FileEntry alsoLocked = entry.alsoLocked;
while (alsoLocked != null) {
logger.trace("ALSO re-locking: {}", alsoLocked.name);
alsoLocked.lockOwner.lock(label, read);
alsoLocked = alsoLocked.alsoLocked;
}
doFileLock = true;
}
}
/*
If we've been cleared to proceed above, create a new FileEntry instance, lock it, and proceed.
*/
if (doFileLock) {
if (read == lockLevel && !f.exists()) {
error.set(new IOException(f + " does not exist. Cannot read-lock missing file!"));
return null;
}
entry = new FileEntry(name, label, lockLevel, entry);
logger.trace("No lock on {}, locking as: {}, label: {}, entry name: {}", name, lockLevel, label, entry.name);
entryMap.put(name, entry);
T result = null;
try {
result = reentrantOperation.apply(key, opLock);
} catch (Exception e) {
// we just locked this, and the call failed...reverse the lock operation.
// NOTE: This will CLEAR all locks, which is what we want since there was no FileEntry before.
clearLocks(f, label);
error.set(e);
}
return result;
} else /*
If we haven't succeeded in locking the file (or its ancestry), wait.
*/
{
logger.trace("Waiting for lock to clear; locking as: {} from: {}", lockLevel, label);
try {
opLock.await(WAIT_TIMEOUT);
} catch (InterruptedException e) {
logger.warn("Interrupted while waiting for {}", label);
}
}
}
} finally {
// no matter what else happens, do NOT allow a delete lock to remain
if (entry != null && entry.lockOwner.getLockLevel() == LockLevel.delete && entry.lockOwner.isLocked()) {
logger.trace("Clearing locks on delete-locked file entry: {}", f);
clearLocks(f, label);
}
}
logger.trace("{}: {}: Lock failed", System.currentTimeMillis(), name);
return null;
});
handleError(error, label);
return opResult;
}
use of org.commonjava.util.partyline.lock.UnlockStatus in project partyline by Commonjava.
the class FileTree method unlock.
/**
* (Manually) unlock a file for a given ownership label. The label allows the system to avoid unlocking for other
* active threads that might still be using the file.
* @param f The file to unlock
* @param label The label for the lock to remove
* @return true if the file has no remaining locks after unlocking for this owner; false otherwise
*/
boolean unlock(File f, final String label) {
return lockManager.lockAnd(f.getAbsolutePath(), (key, opLock) -> {
String ownerName = getLockReservationName();
FileEntry entry = entryMap.get(f.getAbsolutePath());
if (entry != null) {
logger.trace("Unlocking {} (owner: {})", f, ownerName);
UnlockStatus unlockStatus = entry.lockOwner.unlock(label);
filesystem.updateDominantLocks(f.getAbsolutePath(), unlockStatus);
if (unlockStatus.isUnlocked()) {
logger.trace("Unlocked; clearing resources associated with lock");
closeEntryFile(entry, ownerName);
if (!unlockAssociatedEntries(entry, label)) {
return false;
}
if (!entry.lockOwner.isLocked()) {
removeEntryAndReentrantLock(entry.name, opLock);
}
opLock.signal();
logger.trace("Unlock succeeded.");
return true;
} else {
logger.trace("{} Request did not completely unlock file. Remaining locks:\n\n{}", ownerName, entry.lockOwner.getLockInfo());
opLock.signal();
return false;
}
} else {
logger.trace("{} not locked by {}", f, ownerName);
}
opLock.signal();
return true;
});
}
Aggregations