private void RegisterLockAcquired(object tx, TxLockElement tle) { if (tle.Free) { _ragManager.lockAcquired(this, tx); } }
// in case of spurious wake up, deadlock during spurious wake up, termination // when we already have request in a queue we need to clean it up private void CleanupWaitingListRequests(LockRequest lockRequest, TxLockElement lockElement, bool addLockRequest) { if (lockRequest != null && (lockElement.Terminated || !addLockRequest)) { //JAVA TO C# CONVERTER TODO TASK: There is no .NET LinkedList equivalent to the Java 'remove' method: _waitingThreadList.remove(lockRequest); } }
private TxLockElement GetLockElement(object tx) { TxLockElement tle = _txLockElementMap[tx]; if (tle == null) { throw new LockNotFoundException("No transaction lock element found for " + tx); } return(tle); }
private TxLockElement GetOrCreateLockElement(object tx) { AssertTransaction(tx); TxLockElement tle = _txLockElementMap[tx]; if (tle == null) { _txLockElementMap[tx] = tle = new TxLockElement(tx); } return(tle); }
// for specified transaction object mark all lock elements as terminated // and interrupt all waiters internal virtual void TerminateLockRequestsForLockTransaction(object lockTransaction) { lock (this) { TxLockElement lockElement = _txLockElementMap[lockTransaction]; if (lockElement != null && !lockElement.Terminated) { lockElement.Terminated = true; foreach (LockRequest lockRequest in _waitingThreadList) { if (lockRequest.Element.tx.Equals(lockTransaction)) { lockRequest.WaitingThread.Interrupt(); } } } } }
/// <summary> /// 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. /// </summary> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //ORIGINAL LINE: synchronized void releaseWriteLock(Object tx) throws LockNotFoundException internal virtual void ReleaseWriteLock(object tx) { lock (this) { TxLockElement tle = GetLockElement(tx); if (tle.WriteCount == 0) { throw new LockNotFoundException("" + tx + " don't have writeLock"); } _totalWriteCount = MathUtil.decrementExactNotPastZero(_totalWriteCount); tle.WriteCount = MathUtil.decrementExactNotPastZero(tle.WriteCount); if (tle.Free) { _ragManager.lockReleased(this, tx); if (tle.HasNoRequests()) { _txLockElementMap.Remove(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.Count > 0) { // wake elements in queue until a write lock is found or queue is // empty do { LockRequest lockRequest = _waitingThreadList.RemoveLast(); lockRequest.WaitingThread.Interrupt(); if (lockRequest.LockType == LockType.WRITE) { break; } } while (_waitingThreadList.Count > 0); } } }
internal virtual bool TryAcquireWriteLock(object tx) { lock (this) { TxLockElement tle = GetOrCreateLockElement(tx); try { if (tle.Terminated || (_totalWriteCount > tle.WriteCount) || (_totalReadCount > tle.ReadCount)) { return(false); } RegisterWriteLockAcquired(tx, tle); return(true); } finally { // if deadlocked, remove marking so lock is removed when empty Unmark(); } } }
private void RegisterWriteLockAcquired(object tx, TxLockElement tle) { RegisterLockAcquired(tx, tle); _totalWriteCount = Math.incrementExact(_totalWriteCount); tle.WriteCount = Math.incrementExact(tle.WriteCount); }
private void RegisterReadLockAcquired(object tx, TxLockElement tle) { RegisterLockAcquired(tx, tle); _totalReadCount = Math.incrementExact(_totalReadCount); tle.ReadCount = Math.incrementExact(tle.ReadCount); }
/// <summary> /// 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 <seealso cref="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). /// Waiting for a lock can also be terminated. In that case waiting thread will be interrupted and corresponding /// <seealso cref="org.neo4j.kernel.impl.locking.community.RWLock.TxLockElement"/> will be marked as terminated. /// In that case lock will not be acquired and false will be return as result of acquisition /// </summary> /// <returns> true is lock was acquired, false otherwise </returns> /// <exception cref="DeadlockDetectedException"> if a deadlock is detected </exception> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //ORIGINAL LINE: synchronized boolean acquireWriteLock(org.neo4j.storageengine.api.lock.LockTracer tracer, Object tx) throws org.neo4j.kernel.DeadlockDetectedException internal virtual bool AcquireWriteLock(LockTracer tracer, object tx) { lock (this) { TxLockElement tle = GetOrCreateLockElement(tx); LockRequest lockRequest = null; LockWaitEvent waitEvent = null; // used to track do we need to add lock request to a waiting queue or we still have it there bool addLockRequest = true; try { tle.IncrementRequests(); Thread currentThread = currentThread(); long lockAcquisitionTimeBoundary = _clock.millis() + _lockAcquisitionTimeoutMillis; while (!tle.Terminated && (_totalWriteCount > tle.WriteCount || _totalReadCount > tle.ReadCount)) { AssertNotExpired(lockAcquisitionTimeBoundary); _ragManager.checkWaitOn(this, tx); if (addLockRequest) { lockRequest = new LockRequest(tle, WRITE, currentThread); _waitingThreadList.AddFirst(lockRequest); } if (waitEvent == null) { waitEvent = tracer.WaitForLock(true, _resource.type(), _resource.resourceId()); } addLockRequest = WaitUninterruptedly(lockAcquisitionTimeBoundary); _ragManager.stopWaitOn(this, tx); } if (!tle.Terminated) { RegisterWriteLockAcquired(tx, tle); return(true); } else { // in case if lock element was interrupted and it was never register before // we need to clean it from lock element map // if it was register before it will be cleaned up during standard lock release call if (tle.Requests == 1 && tle.Free) { _txLockElementMap.Remove(tx); } return(false); } } finally { if (waitEvent != null) { waitEvent.Close(); } CleanupWaitingListRequests(lockRequest, tle, addLockRequest); // for cases when spurious wake up was the reason why we waked up, but also there // was an interruption as described at 17.2 just clearing interruption flag interrupted(); // if deadlocked, remove marking so lock is removed when empty tle.DecrementRequests(); Unmark(); } } }
/// <summary> /// 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. /// </summary> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //ORIGINAL LINE: synchronized void releaseReadLock(Object tx) throws LockNotFoundException internal virtual void ReleaseReadLock(object tx) { lock (this) { TxLockElement tle = GetLockElement(tx); if (tle.ReadCount == 0) { throw new LockNotFoundException("" + tx + " don't have readLock"); } _totalReadCount = MathUtil.decrementExactNotPastZero(_totalReadCount); tle.ReadCount = MathUtil.decrementExactNotPastZero(tle.ReadCount); if (tle.Free) { _ragManager.lockReleased(this, tx); if (tle.HasNoRequests()) { _txLockElementMap.Remove(tx); } } if (_waitingThreadList.Count > 0) { LockRequest lockRequest = _waitingThreadList.Last.Value; if (lockRequest.LockType == LockType.WRITE) { // this one is tricky... // if readCount > 0 lockRequest 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 == lockRequest.Element.readCount) { // found a write lock with all read locks _waitingThreadList.RemoveLast(); lockRequest.WaitingThread.Interrupt(); } else { IEnumerator <LockRequest> listItr = _waitingThreadList.listIterator(_waitingThreadList.LastIndexOf(lockRequest)); // hm am I doing the first all over again? // think I am if cursor is at lastIndex + 0.5 oh well... while (listItr.hasPrevious()) { lockRequest = listItr.previous(); if (lockRequest.LockType == LockType.WRITE && _totalReadCount == lockRequest.Element.readCount) { // found a write lock with all read locks //JAVA TO C# CONVERTER TODO TASK: .NET enumerators are read-only: listItr.remove(); lockRequest.WaitingThread.Interrupt(); break; } else if (lockRequest.LockType == LockType.READ) { // found a read lock, let it do the job... //JAVA TO C# CONVERTER TODO TASK: .NET enumerators are read-only: listItr.remove(); lockRequest.WaitingThread.Interrupt(); } } } } else { // some thread may have the write lock and released a read lock // if writeCount is down to zero lockRequest can interrupt the waiting // read lock if (_totalWriteCount == 0) { _waitingThreadList.RemoveLast(); lockRequest.WaitingThread.Interrupt(); } } } } }
internal LockRequest(TxLockElement element, LockType lockType, Thread thread) { this.Element = element; this.LockType = lockType; this.WaitingThread = thread; }