Search in sources :

Example 1 with UnlockStatus

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());
    }
}
Also used : Logger(org.slf4j.Logger) UnlockStatus(org.commonjava.util.partyline.lock.UnlockStatus)

Example 2 with UnlockStatus

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;
}
Also used : UnlockStatus(org.commonjava.util.partyline.lock.UnlockStatus)

Example 3 with UnlockStatus

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));
}
Also used : LocalLockOwner(org.commonjava.util.partyline.lock.local.LocalLockOwner) UnlockStatus(org.commonjava.util.partyline.lock.UnlockStatus) Test(org.junit.Test)

Example 4 with UnlockStatus

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;
}
Also used : AtomicReference(java.util.concurrent.atomic.AtomicReference) IOException(java.io.IOException) UnlockStatus(org.commonjava.util.partyline.lock.UnlockStatus) IOException(java.io.IOException)

Example 5 with UnlockStatus

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;
    });
}
Also used : UnlockStatus(org.commonjava.util.partyline.lock.UnlockStatus)

Aggregations

UnlockStatus (org.commonjava.util.partyline.lock.UnlockStatus)5 IOException (java.io.IOException)1 AtomicReference (java.util.concurrent.atomic.AtomicReference)1 LocalLockOwner (org.commonjava.util.partyline.lock.local.LocalLockOwner)1 Test (org.junit.Test)1 Logger (org.slf4j.Logger)1