/** * Releases the write lock held by the provided tx. If it is null then an attempt to acquire the * current transaction from the transaction manager will be made. This is to make safe calling * this method as an <code>afterCompletion()</code> hook where the transaction context is not * necessarily available. If write count is zero and there are waiting transactions in the queue * they will be interrupted if they can acquire the lock. */ synchronized void releaseWriteLock(Object tx) throws LockNotFoundException { TxLockElement tle = getLockElement(tx); if (tle.writeCount == 0) { throw new LockNotFoundException("" + tx + " don't have writeLock"); } totalWriteCount--; tle.writeCount--; if (tle.isFree()) { txLockElementMap.remove(tx); ragManager.lockReleased(this, tx); } // the threads in the waitingList cannot be currentThread // so we only have to wake other elements if writeCount is down to zero // (that is: If writeCount > 0 a waiting thread in the queue cannot be // the thread that holds the write locks because then it would never // have been put into wait mode) if (totalWriteCount == 0 && waitingThreadList.size() > 0) { // wake elements in queue until a write lock is found or queue is // empty do { WaitElement we = waitingThreadList.removeLast(); if (!we.element.movedOn) { we.waitingThread.interrupt(); if (we.lockType == LockType.WRITE) { break; } } } while (waitingThreadList.size() > 0); } }
/** * Tries to acquire write lock for a given transaction. If <CODE>this.writeCount</CODE> is greater * than the currents tx's write count or the read count is greater than the currents tx's read * count the transaction has to wait and the {@link RagManager#checkWaitOn} method is invoked for * deadlock detection. * * <p>If the lock can be acquires the lock count is updated on <CODE>this</CODE> and the * transaction lock element (tle). * * @throws DeadlockDetectedException if a deadlock is detected */ synchronized void acquireWriteLock(Object tx) throws DeadlockDetectedException { TxLockElement tle = getOrCreateLockElement(tx); try { tle.movedOn = false; boolean shouldAddWait = true; Thread currentThread = currentThread(); while (totalWriteCount > tle.writeCount || totalReadCount > tle.readCount) { ragManager.checkWaitOn(this, tx); if (shouldAddWait) { waitingThreadList.addFirst(new WaitElement(tle, WRITE, currentThread)); } try { wait(); shouldAddWait = false; } catch (InterruptedException e) { interrupted(); shouldAddWait = true; } ragManager.stopWaitOn(this, tx); } registerWriteLockAcquired(tx, tle); } finally { // if deadlocked, remove marking so lock is removed when empty tle.movedOn = true; marked--; } }
/** * Tries to acquire write lock for a given transaction. If <CODE>this.writeCount</CODE> is greater * than the currents tx's write count or the read count is greater than the currents tx's read * count the transaction has to wait and the {@link RagManager#checkWaitOn} method is invoked for * deadlock detection. * * <p>If the lock can be acquires the lock count is updated on <CODE>this</CODE> and the * transaction lock element (tle). * * @throws DeadlockDetectedException if a deadlock is detected */ synchronized void acquireWriteLock(Object tx) throws DeadlockDetectedException { TxLockElement tle = getOrCreateLockElement(tx); try { tle.movedOn = false; while (totalWriteCount > tle.writeCount || totalReadCount > tle.readCount) { deadlockGuardedWait(tx, tle, WRITE); } registerWriteLockAcquired(tx, tle); } finally { // if deadlocked, remove marking so lock is removed when empty tle.movedOn = true; marked--; } }
synchronized boolean tryAcquireWriteLock(Object tx) { TxLockElement tle = getOrCreateLockElement(tx); try { tle.movedOn = false; if (totalWriteCount > tle.writeCount || totalReadCount > tle.readCount) { return false; } registerWriteLockAcquired(tx, tle); return true; } finally { // if deadlocked, remove marking so lock is removed when empty tle.movedOn = true; marked--; } }
private void registerLockAcquired(Object tx, TxLockElement tle) { if (tle.isFree()) { ragManager.lockAcquired(this, tx); } }
/** * Releases the read lock held by the provided transaction. If it is null then an attempt to * acquire the current transaction will be made. This is to make safe calling the method from the * context of an <code>afterCompletion()</code> hook where the tx is locally stored and not * necessarily available through the tm. If there are waiting transactions in the queue they will * be interrupted if they can acquire the lock. */ synchronized void releaseReadLock(Object tx) throws LockNotFoundException { TxLockElement tle = getLockElement(tx); if (tle.readCount == 0) { throw new LockNotFoundException("" + tx + " don't have readLock"); } totalReadCount--; tle.readCount--; if (tle.isFree()) { txLockElementMap.remove(tx); ragManager.lockReleased(this, tx); } if (waitingThreadList.size() > 0) { WaitElement we = waitingThreadList.getLast(); if (we.lockType == LockType.WRITE) { // this one is tricky... // if readCount > 0 we either have to find a waiting read lock // in the queue or a waiting write lock that has all read // locks, if none of these are found it means that there // is a (are) thread(s) that will release read lock(s) in the // near future... if (totalReadCount == we.element.readCount) { // found a write lock with all read locks waitingThreadList.removeLast(); if (!we.element.movedOn) { we.waitingThread.interrupt(); } } else { ListIterator<WaitElement> listItr = waitingThreadList.listIterator(waitingThreadList.lastIndexOf(we)); // hm am I doing the first all over again? // think I am if cursor is at lastIndex + 0.5 oh well... while (listItr.hasPrevious()) { we = listItr.previous(); if (we.lockType == LockType.WRITE && totalReadCount == we.element.readCount) { // found a write lock with all read locks listItr.remove(); if (!we.element.movedOn) { we.waitingThread.interrupt(); // ---- break; } } else if (we.lockType == LockType.READ) { // found a read lock, let it do the job... listItr.remove(); if (!we.element.movedOn) { we.waitingThread.interrupt(); } } } } } else { // some thread may have the write lock and released a read lock // if writeCount is down to zero we can interrupt the waiting // read lock if (totalWriteCount == 0) { waitingThreadList.removeLast(); if (!we.element.movedOn) { we.waitingThread.interrupt(); } } } } }