Search in sources :

Example 1 with MultiLock

use of uk.ac.ic.doc.slurp.multilock.MultiLock in project exist by eXist-db.

the class LockManager method acquireDocumentWriteLock.

/**
 * Acquire a WRITE_LOCK on a Document
 *
 * @param documentPath The URI of the Document within the database
 *
 * @return the lock for the Document
 *
 * @throws LockException if the lock could not be acquired
 */
public ManagedDocumentLock acquireDocumentWriteLock(final XmldbURI documentPath) throws LockException {
    if (usePathLocksForDocuments) {
        final LockGroup lockGroup = acquirePathWriteLock(LockType.DOCUMENT, documentPath, false);
        return new ManagedDocumentLock(documentPath, Arrays.stream(lockGroup.locks).map(Tuple3::get_1).toArray(MultiLock[]::new), () -> unlockAll(lockGroup.locks, l -> lockTable.released(lockGroup.groupId, l._3, LockType.DOCUMENT, l._2)));
    } else {
        final long groupId = System.nanoTime();
        final String path = documentPath.toString();
        final MultiLock lock = getDocumentLock(path);
        lockTable.attempt(groupId, path, LockType.DOCUMENT, Lock.LockMode.WRITE_LOCK);
        if (lock(lock, Lock.LockMode.WRITE_LOCK)) {
            lockTable.acquired(groupId, path, LockType.DOCUMENT, Lock.LockMode.WRITE_LOCK);
        } else {
            lockTable.attemptFailed(groupId, path, LockType.DOCUMENT, Lock.LockMode.WRITE_LOCK);
            throw new LockException("Unable to acquire WRITE_LOCK for: " + path);
        }
        return new ManagedDocumentLock(documentPath, lock, () -> {
            lock.asWriteLock().unlock();
            lockTable.released(groupId, path, LockType.DOCUMENT, Lock.LockMode.WRITE_LOCK);
        });
    }
}
Also used : Tuple3(com.evolvedbinary.j8fu.tuple.Tuple3) Consumer(java.util.function.Consumer) Arrays(java.util.Arrays) Logger(org.apache.logging.log4j.Logger) ReentrantLock(java.util.concurrent.locks.ReentrantLock) WeakLazyStripes(org.exist.util.WeakLazyStripes) LockException(org.exist.util.LockException) XmldbURI(org.exist.xmldb.XmldbURI) LockType(org.exist.storage.lock.Lock.LockType) Configuration(org.exist.util.Configuration) MultiLock(uk.ac.ic.doc.slurp.multilock.MultiLock) LogManager(org.apache.logging.log4j.LogManager) LockException(org.exist.util.LockException) Tuple3(com.evolvedbinary.j8fu.tuple.Tuple3) MultiLock(uk.ac.ic.doc.slurp.multilock.MultiLock)

Example 2 with MultiLock

use of uk.ac.ic.doc.slurp.multilock.MultiLock in project exist by eXist-db.

the class LockManager method acquireDocumentReadLock.

/**
 * Acquire a READ_LOCK on a Document
 *
 * @param documentPath The URI of the Document within the database
 *
 * @return the lock for the Document
 *
 * @throws LockException if the lock could not be acquired
 */
public ManagedDocumentLock acquireDocumentReadLock(final XmldbURI documentPath) throws LockException {
    if (usePathLocksForDocuments) {
        final LockGroup lockGroup = acquirePathReadLock(LockType.DOCUMENT, documentPath);
        return new ManagedDocumentLock(documentPath, Arrays.stream(lockGroup.locks).map(Tuple3::get_1).toArray(MultiLock[]::new), () -> unlockAll(lockGroup.locks, l -> lockTable.released(lockGroup.groupId, l._3, LockType.DOCUMENT, l._2)));
    } else {
        final long groupId = System.nanoTime();
        final String path = documentPath.toString();
        final MultiLock lock = getDocumentLock(path);
        lockTable.attempt(groupId, path, LockType.DOCUMENT, Lock.LockMode.READ_LOCK);
        if (lock(lock, Lock.LockMode.READ_LOCK)) {
            lockTable.acquired(groupId, path, LockType.DOCUMENT, Lock.LockMode.READ_LOCK);
        } else {
            lockTable.attemptFailed(groupId, path, LockType.DOCUMENT, Lock.LockMode.READ_LOCK);
            throw new LockException("Unable to acquire READ_LOCK for: " + path);
        }
        return new ManagedDocumentLock(documentPath, lock, () -> {
            lock.asReadLock().unlock();
            lockTable.released(groupId, path, LockType.DOCUMENT, Lock.LockMode.READ_LOCK);
        });
    }
}
Also used : Tuple3(com.evolvedbinary.j8fu.tuple.Tuple3) Consumer(java.util.function.Consumer) Arrays(java.util.Arrays) Logger(org.apache.logging.log4j.Logger) ReentrantLock(java.util.concurrent.locks.ReentrantLock) WeakLazyStripes(org.exist.util.WeakLazyStripes) LockException(org.exist.util.LockException) XmldbURI(org.exist.xmldb.XmldbURI) LockType(org.exist.storage.lock.Lock.LockType) Configuration(org.exist.util.Configuration) MultiLock(uk.ac.ic.doc.slurp.multilock.MultiLock) LogManager(org.apache.logging.log4j.LogManager) LockException(org.exist.util.LockException) Tuple3(com.evolvedbinary.j8fu.tuple.Tuple3) MultiLock(uk.ac.ic.doc.slurp.multilock.MultiLock)

Example 3 with MultiLock

use of uk.ac.ic.doc.slurp.multilock.MultiLock in project exist by eXist-db.

the class LockManagerTest method getCollectionLock_isStripedByPath.

@Test
public void getCollectionLock_isStripedByPath() {
    final LockManager lockManager = new LockManager(CONCURRENCY_LEVEL);
    final MultiLock dbLock1 = lockManager.getPathLock("/db");
    assertNotNull(dbLock1);
    final MultiLock dbLock2 = lockManager.getPathLock("/db");
    assertNotNull(dbLock2);
    assertTrue(dbLock1 == dbLock2);
    final MultiLock abcLock = lockManager.getPathLock("/db/a/b/c");
    assertNotNull(abcLock);
    assertFalse(dbLock1 == abcLock);
    final MultiLock defLock = lockManager.getPathLock("/db/d/e/f");
    assertNotNull(defLock);
    assertFalse(dbLock1 == defLock);
    assertFalse(abcLock == defLock);
}
Also used : MultiLock(uk.ac.ic.doc.slurp.multilock.MultiLock)

Example 4 with MultiLock

use of uk.ac.ic.doc.slurp.multilock.MultiLock in project exist by eXist-db.

the class LockManager method acquirePathWriteLock.

/**
 * Acquires a WRITE_LOCK on a path (and implicitly all descendant paths).
 *
 * @param path The path for which a lock is requested.
 * @param lockParent true if we should also explicitly write lock the parent path.
 *
 * @return A WRITE_LOCK on the path.
 */
LockGroup acquirePathWriteLock(final LockType lockType, final XmldbURI path, final boolean lockParent) throws LockException {
    final XmldbURI[] segments = path.getPathSegments();
    final long groupId = System.nanoTime();
    String pathStr = "";
    final Tuple3<MultiLock, Lock.LockMode, String>[] locked = new Tuple3[segments.length];
    for (int i = 0; i < segments.length; i++) {
        pathStr += '/' + segments[i].toString();
        final Lock.LockMode lockMode;
        if (lockParent && i + 2 == segments.length) {
            // parent
            lockMode = Lock.LockMode.WRITE_LOCK;
        } else if (i + 1 == segments.length) {
            // leaf
            lockMode = Lock.LockMode.WRITE_LOCK;
        } else {
            if (!pathsMultiWriter) {
                // single-writer/multi-reader
                lockMode = Lock.LockMode.WRITE_LOCK;
            } else {
                // multi-writer/multi-reader
                lockMode = Lock.LockMode.INTENTION_WRITE;
            }
        }
        final MultiLock lock = getPathLock(pathStr);
        if (upgradeCheck && lockMode == Lock.LockMode.WRITE_LOCK && (lock.getIntentionReadHoldCount() > 0 || lock.getReadHoldCount() > 0)) {
            throw new LockException("Lock upgrading would lead to a self-deadlock: " + pathStr);
        }
        if (warnWaitOnReadForWrite && lockMode == Lock.LockMode.WRITE_LOCK) {
            if (lock.getIntentionReadLockCount() > 0) {
                LOG.warn("About to acquire WRITE_LOCK for: {}, but INTENTION_READ_LOCK held by other thread(s): ", pathStr);
            } else if (lock.getReadLockCount() > 0) {
                LOG.warn("About to acquire WRITE_LOCK for: {}, but READ_LOCK held by other thread(s): ", pathStr);
            }
        }
        lockTable.attempt(groupId, pathStr, lockType, lockMode);
        if (lock(lock, lockMode)) {
            locked[i] = new Tuple3<>(lock, lockMode, pathStr);
            lockTable.acquired(groupId, pathStr, lockType, lockMode);
        } else {
            lockTable.attemptFailed(groupId, pathStr, lockType, lockMode);
            unlockAll(locked, l -> lockTable.released(groupId, l._3, lockType, l._2));
            throw new LockException("Unable to acquire " + lockType + " " + lockMode + " for: " + pathStr);
        }
    }
    return new LockGroup(groupId, locked);
}
Also used : ReentrantLock(java.util.concurrent.locks.ReentrantLock) MultiLock(uk.ac.ic.doc.slurp.multilock.MultiLock) LockException(org.exist.util.LockException) Tuple3(com.evolvedbinary.j8fu.tuple.Tuple3) MultiLock(uk.ac.ic.doc.slurp.multilock.MultiLock) XmldbURI(org.exist.xmldb.XmldbURI)

Example 5 with MultiLock

use of uk.ac.ic.doc.slurp.multilock.MultiLock in project exist by eXist-db.

the class LockManager method acquirePathReadLock.

/**
 * Acquires a READ_LOCK on a database path (and implicitly all descendant paths).
 *
 * @param lockType The type of the lock
 * @param path The path for which a lock is requested.
 *
 * @return A READ_LOCK on the Collection.
 *
 * @throws LockException if a lock error occurs
 */
public LockGroup acquirePathReadLock(final LockType lockType, final XmldbURI path) throws LockException {
    final XmldbURI[] segments = path.getPathSegments();
    final long groupId = System.nanoTime();
    String pathStr = "";
    final Tuple3<MultiLock, Lock.LockMode, String>[] locked = new Tuple3[segments.length];
    for (int i = 0; i < segments.length; i++) {
        pathStr += '/' + segments[i].toString();
        final Lock.LockMode lockMode;
        if (i + 1 == segments.length) {
            // leaf
            lockMode = Lock.LockMode.READ_LOCK;
        } else {
            // ancestor
            lockMode = Lock.LockMode.INTENTION_READ;
        }
        final MultiLock lock = getPathLock(pathStr);
        lockTable.attempt(groupId, pathStr, lockType, lockMode);
        if (lock(lock, lockMode)) {
            locked[i] = new Tuple3<>(lock, lockMode, pathStr);
            lockTable.acquired(groupId, pathStr, lockType, lockMode);
        } else {
            lockTable.attemptFailed(groupId, pathStr, lockType, lockMode);
            unlockAll(locked, l -> lockTable.released(groupId, l._3, lockType, l._2));
            throw new LockException("Unable to acquire " + lockType + " " + lockMode + " for: " + pathStr);
        }
    }
    return new LockGroup(groupId, locked);
}
Also used : ReentrantLock(java.util.concurrent.locks.ReentrantLock) MultiLock(uk.ac.ic.doc.slurp.multilock.MultiLock) LockException(org.exist.util.LockException) Tuple3(com.evolvedbinary.j8fu.tuple.Tuple3) MultiLock(uk.ac.ic.doc.slurp.multilock.MultiLock) XmldbURI(org.exist.xmldb.XmldbURI)

Aggregations

MultiLock (uk.ac.ic.doc.slurp.multilock.MultiLock)7 XmldbURI (org.exist.xmldb.XmldbURI)5 Tuple3 (com.evolvedbinary.j8fu.tuple.Tuple3)4 ReentrantLock (java.util.concurrent.locks.ReentrantLock)4 LockException (org.exist.util.LockException)4 Arrays (java.util.Arrays)2 Consumer (java.util.function.Consumer)2 LogManager (org.apache.logging.log4j.LogManager)2 Logger (org.apache.logging.log4j.Logger)2 LockType (org.exist.storage.lock.Lock.LockType)2 Configuration (org.exist.util.Configuration)2 WeakLazyStripes (org.exist.util.WeakLazyStripes)2 Collection (org.exist.collections.Collection)1 LockedDocument (org.exist.dom.persistent.LockedDocument)1 BrokerPool (org.exist.storage.BrokerPool)1 DBBroker (org.exist.storage.DBBroker)1