Class ConcurrencyManager

java.lang.Object
org.eclipse.persistence.internal.helper.ConcurrencyManager
All Implemented Interfaces:
Serializable
Direct Known Subclasses:
CacheKey

public class ConcurrencyManager extends Object implements Serializable
INTERNAL:

Purpose: To maintain concurrency for a particular task. It is a wrappers of a semaphore that allows recursive waits by a single thread.

Responsibilities:

  • Keep track of the active thread.
  • Wait all other threads until the first thread is done.
  • Maintain the depth of the active thread.
See Also:
  • Field Details

    • DEFERRED_LOCK_MANAGERS

      public static final Map<Thread,DeferredLockManager> DEFERRED_LOCK_MANAGERS
    • shouldTrackStack

      protected static boolean shouldTrackStack
    • numberOfReaders

      protected AtomicInteger numberOfReaders
    • depth

      protected AtomicInteger depth
    • numberOfWritersWaiting

      protected AtomicInteger numberOfWritersWaiting
    • activeThread

      protected transient volatile Thread activeThread
    • lockedByMergeManager

      protected boolean lockedByMergeManager
    • stack

      protected Exception stack
  • Constructor Details

    • ConcurrencyManager

      public ConcurrencyManager()
      Initialize the newly allocated instance of this class. Set the depth to zero.
  • Method Details

    • acquire

      public void acquire() throws ConcurrencyException
      Wait for all threads except the active thread. If the active thread just increment the depth. This should be called before entering a critical section.
      Throws:
      ConcurrencyException
    • acquire

      public void acquire(boolean forMerge) throws ConcurrencyException
      Wait for all threads except the active thread. If the active thread just increment the depth. This should be called before entering a critical section. called with true from the merge process, if true then the refresh will not refresh the object
      Throws:
      ConcurrencyException
    • acquireNoWait

      public boolean acquireNoWait() throws ConcurrencyException
      If the lock is not acquired already acquire it and return true. If it has been acquired already return false Added for CR 2317
      Throws:
      ConcurrencyException
    • acquireNoWait

      public boolean acquireNoWait(boolean forMerge) throws ConcurrencyException
      If the lock is not acquired already acquire it and return true. If it has been acquired already return false Added for CR 2317 called with true from the merge process, if true then the refresh will not refresh the object
      Throws:
      ConcurrencyException
    • acquireWithWait

      public boolean acquireWithWait(boolean forMerge, int wait) throws ConcurrencyException
      If the lock is not acquired already acquire it and return true. If it has been acquired already return false Added for CR 2317 called with true from the merge process, if true then the refresh will not refresh the object
      Throws:
      ConcurrencyException
    • acquireIfUnownedNoWait

      public boolean acquireIfUnownedNoWait(boolean forMerge) throws ConcurrencyException
      If the activeThread is not set, acquire it and return true. If the activeThread is set, it has been acquired already, return false. Added for Bug 5840635 Call with true from the merge process, if true then the refresh will not refresh the object.
      Throws:
      ConcurrencyException
    • acquireDeferredLock

      public void acquireDeferredLock() throws ConcurrencyException
      Add deferred lock into a hashtable to avoid deadlock
      Throws:
      ConcurrencyException
    • checkDeferredLock

      public void checkDeferredLock() throws ConcurrencyException
      Check the lock state, if locked, acquire and release a deferred lock. This optimizes out the normal deferred-lock check if not locked.
      Throws:
      ConcurrencyException
    • checkReadLock

      public void checkReadLock() throws ConcurrencyException
      Check the lock state, if locked, acquire and release a read lock. This optimizes out the normal read-lock check if not locked.
      Throws:
      ConcurrencyException
    • acquireReadLock

      public void acquireReadLock() throws ConcurrencyException
      Wait on any writer. Allow concurrent reads.
      Throws:
      ConcurrencyException
    • acquireReadLockNoWait

      public boolean acquireReadLockNoWait()
      If this is acquired return false otherwise acquire readlock and return true
    • getActiveThread

      public Thread getActiveThread()
      Return the active thread.
    • getDeferredLockManager

      public static DeferredLockManager getDeferredLockManager(Thread thread)
      Return the deferred lock manager from the thread
    • getDeferredLockManagers

      protected static Map<Thread,DeferredLockManager> getDeferredLockManagers()
      Return the deferred lock manager hashtable (thread - DeferredLockManager).
    • initializeDeferredLockManagers

      protected static Map<Thread,DeferredLockManager> initializeDeferredLockManagers()
      Init the deferred lock managers (thread - DeferredLockManager).
    • getDepth

      public int getDepth()
      Return the current depth of the active thread.
    • getNumberOfReaders

      public int getNumberOfReaders()
      Number of writer that want the lock. This is used to ensure that a writer is not starved.
    • getNumberOfWritersWaiting

      public int getNumberOfWritersWaiting()
      Number of writers that want the lock. This is used to ensure that a writer is not starved.
    • isAcquired

      public boolean isAcquired()
      Return if a thread has acquire this manager.
    • isLockedByMergeManager

      public boolean isLockedByMergeManager()
      INTERNAL: Used byt the refresh process to determine if this concurrency manager is locked by the merge process. If it is then the refresh should not refresh the object
    • isBuildObjectOnThreadComplete

      public static boolean isBuildObjectOnThreadComplete(Thread thread, Map<Thread,Thread> recursiveSet, List<Thread> parentChainOfThreads, boolean deadLockDiagnostic)
      Check if the deferred locks of a thread are all released. Should write dead lock diagnostic information into the THREADS_WAITING_TO_RELEASE_DEFERRED_LOCKS_BUILD_OBJECT_COMPLETE_GOES_NOWHERE.
      Parameters:
      thread - the current thread to be explored. It starts by being the thread that it is stuck but then it evolves to be other that have acquired locks our main thread was needing but whcich themslves are stuck... threads in the deffered lock chain that are going nowhere themselves.
      recursiveSet - this prevents the algorithm going into an infinite loop of expanding the same thread more than once.
      parentChainOfThreads - this starts by being a basket containing the current thread, but each time we go deeper it evolves to contain the thread we will explore next.
      Returns:
      true if object is complete
    • enrichStringBuildingExplainWhyThreadIsStuckInIsBuildObjectOnThreadComplete

      public static void enrichStringBuildingExplainWhyThreadIsStuckInIsBuildObjectOnThreadComplete(List<Thread> chainOfThreadsExpandedInRecursion, ConcurrencyManager finalDeferredLockCausingTrouble, Thread activeThreadOnDeferredLock, boolean hasDeferredLockManager, StringBuilder justification)
      When the recursive algorithm decides to return false it is because it is confronted with a cache key that had to be deferred. And the cache key is either being owned by a thread that did not flage itsef as being finished and waiting in the wait for deferred locks. Or the thread that ows the cache key is not playing nice - and not using deferred locks - so it has acquire the cache key, it is going about its business (e.g. committing a transaction or perhaps doing object building. Normally, but not always, in object building threads do have a lock manager, but sometimes not when they agressive acquire lock policy. )
      Parameters:
      chainOfThreadsExpandedInRecursion - This the chaing threads that were expanded as we went down with the recursion
      finalDeferredLockCausingTrouble - this is a lock that was deferred either by current thread or by a thread that is also itself waiting around . This lock is what is causing us ultimately to return FALSE, because the lock is still ACUIRED so not yet free. And the thread that owns it is also still not finished yet.
      activeThreadOnDeferredLock - this is the thread that was spotted as owning/being actively owning the the deferred lock. So we can consider this thread as being the ultimate cause of why the current thread and perhaps a hole chaing of related threads are not evolving. But certainly the current thread.
      hasDeferredLockManager - Some threads have deferred lock managers some not. Not clear when they do. But threads doing object building typically end up creating a deferred lock manager when they find themselves unable to acquire an object and need to defer on the cache key.
      justification - this is what we want to populate it will allow us to build a trace to explain why the thread on the wait for deferred lock is going nowhere. This trace will be quite important to help us interpret the massive dumps since it is quite typical to find threads in this state.
    • isNested

      public boolean isNested()
      Return if this manager is within a nested acquire.
    • putDeferredLock

      public void putDeferredLock(Thread thread, DeferredLockManager lockManager)
    • release

      public void release() throws ConcurrencyException
      Decrement the depth for the active thread. Assume the current thread is the active one. Raise an error if the depth become < 0. The notify will release the first thread waiting on the object, if no threads are waiting it will do nothing.
      Throws:
      ConcurrencyException
    • releaseDeferredLock

      public void releaseDeferredLock() throws ConcurrencyException
      Release the deferred lock. This uses a deadlock detection and resolution algorithm to avoid cache deadlocks. The deferred lock manager keeps track of the lock for a thread, so that other thread know when a deadlock has occurred and can resolve it.
      Throws:
      ConcurrencyException
    • releaseReadLock

      public void releaseReadLock() throws ConcurrencyException
      Decrement the number of readers. Used to allow concurrent reads.
      Throws:
      ConcurrencyException
    • removeDeferredLockManager

      public static DeferredLockManager removeDeferredLockManager(Thread thread)
      Remove the deferred lock manager for the thread
    • setActiveThread

      public void setActiveThread(Thread activeThread)
      Set the active thread.
    • setDepth

      protected void setDepth(int depth)
      Set the current depth of the active thread.
    • setIsLockedByMergeManager

      public void setIsLockedByMergeManager(boolean state)
      INTERNAL: Used by the mergemanager to let the read know not to refresh this object as it is being loaded by the merge process.
    • setNumberOfReaders

      protected void setNumberOfReaders(int numberOfReaders)
      Track the number of readers.
    • setNumberOfWritersWaiting

      protected void setNumberOfWritersWaiting(int numberOfWritersWaiting)
      Number of writers that want the lock. This is used to ensure that a writer is not starved.
    • transitionToDeferredLock

      public void transitionToDeferredLock()
    • releaseAllLocksAcquiredByThread

      public void releaseAllLocksAcquiredByThread(DeferredLockManager lockManager)
      For the thread to release all of its locks.
      Parameters:
      lockManager - the deferred lock manager
    • getReadLockManager

      protected static ReadLockManager getReadLockManager(Thread thread)
      The method is not synchronized because for now we assume that each thread will ask for its own lock manager. If we were writing a dead lock detection mechanism then a ThreadA could be trying understand the ReadLocks of a ThreadB and this would no longer be true.
      Parameters:
      thread - The thread for which we want to have look at the acquired read locks.
      Returns:
      Never null if the read lock manager does not yet exist for the current thread. otherwise its read log manager is returned.
    • getReadLockManagers

      protected static Map<Thread,ReadLockManager> getReadLockManagers()
      Return the deferred lock manager hashtable (thread - DeferredLockManager).
    • toString

      public String toString()
      Print the nested depth.
      Overrides:
      toString in class Object
    • getStack

      public Exception getStack()
    • setStack

      public void setStack(Exception stack)
    • shouldTrackStack

      public static boolean shouldTrackStack()
    • setShouldTrackStack

      public static void setShouldTrackStack(boolean shouldTrackStack)
      INTERNAL: This can be set during debugging to record the stacktrace when a lock is acquired. Then once IdentityMapAccessor.printIdentityMapLocks() is called the stack call for each lock will be printed as well. Because locking issues are usually quite time sensitive setting this flag may inadvertently remove the deadlock because of the change in timings. There is also a system level property for this setting. "eclipselink.cache.record-stack-on-lock"
    • putThreadAsWaitingToAcquireLockForWriting

      public void putThreadAsWaitingToAcquireLockForWriting(Thread thread, String methodName)
      Normally this mehtod should only be called from withing the concurrency manager. However the write lock manager while it is building clones also does some while loop waiting to try to acquire a cache key this acquiring logic is not being managed directly inside of the wait manager.
    • removeThreadNoLongerWaitingToAcquireLockForWriting

      public void removeThreadNoLongerWaitingToAcquireLockForWriting(Thread thread)
      The thread has acquired the lock for writing or decided to defer acquiring the lock putting this lock into its deferred lock list.
    • putThreadAsWaitingToAcquireLockForReading

      public void putThreadAsWaitingToAcquireLockForReading(Thread currentThread, String methodName)
      The thread is trying to acquire a read lock but it is not being able to make process on getting the read lock.
      Parameters:
      methodName - metadata to help us debug trace leaking. If we start blowing up threads we do not want the traces created by the current thread to remain.
    • removeThreadNoLongerWaitingToAcquireLockForReading

      public void removeThreadNoLongerWaitingToAcquireLockForReading(Thread thread)
    • getConcurrencyManagerId

      public long getConcurrencyManagerId()
      Getter for concurrencyManagerId
    • getConcurrencyManagerCreationDate

      public Date getConcurrencyManagerCreationDate()
      Getter for concurrencyManagerCreationDate
    • getTotalNumberOfKeysAcquiredForReading

      public long getTotalNumberOfKeysAcquiredForReading()
      Getter for totalNumberOfKeysAcquiredForReading
    • getTotalNumberOfKeysReleasedForReading

      public long getTotalNumberOfKeysReleasedForReading()
      Getter for totalNumberOfKeysReleasedForReading
    • getTotalNumberOfKeysReleasedForReadingBlewUpExceptionDueToCacheKeyHavingReachedCounterZero

      public long getTotalNumberOfKeysReleasedForReadingBlewUpExceptionDueToCacheKeyHavingReachedCounterZero()
      Getter for totalNumberOfKeysReleasedForReadingBlewUpExceptionDueToCacheKeyHavingReachedCounterZero
    • getThreadsToWaitOnAcquire

      public static Map<Thread,ConcurrencyManager> getThreadsToWaitOnAcquire()
      Getter for THREADS_TO_WAIT_ON_ACQUIRE
    • getThreadsToWaitOnAcquireMethodName

      public static Map<Thread,String> getThreadsToWaitOnAcquireMethodName()
      Getter for THREADS_TO_WAIT_ON_ACQUIRE_NAME_OF_METHOD_CREATING_TRACE
    • getThreadsToWaitOnAcquireReadLock

      public static Map<Thread,ConcurrencyManager> getThreadsToWaitOnAcquireReadLock()
      Getter for THREADS_TO_WAIT_ON_ACQUIRE_READ_LOCK
    • getThreadsToWaitOnAcquireReadLockMethodName

      public static Map<Thread,String> getThreadsToWaitOnAcquireReadLockMethodName()
      Getter for THREADS_TO_WAIT_ON_ACQUIRE_READ_LOCK_NAME_OF_METHOD_CREATING_TRACE
    • getThreadsWaitingToReleaseDeferredLocks

      public static Set<Thread> getThreadsWaitingToReleaseDeferredLocks()
      Getter for THREADS_WAITING_TO_RELEASE_DEFERRED_LOCKS
    • getThreadsWaitingToReleaseDeferredLocksJustification

      public static Map<Thread,String> getThreadsWaitingToReleaseDeferredLocksJustification()
      Getter for THREADS_WAITING_TO_RELEASE_DEFERRED_LOCKS_BUILD_OBJECT_COMPLETE_GOES_NOWHERE
    • addReadLockToReadLockManager

      protected void addReadLockToReadLockManager()
      The current thread has incremented the number of readers on the current cache key. It also wants to record into the read lock manager that this thread has acquired the cache key. This method should be user in all places where the cache key nunber of readers is incremented.
    • removeReadLockFromReadLockManager

      protected void removeReadLockFromReadLockManager()
      The current thread is about to decrement the number of readers in cache key. The thread also wants to update the read lock manager and remove the cache key that has previously been aquired from there.
    • getReadLockManagerEnsureResultIsNotNull

      protected static ReadLockManager getReadLockManagerEnsureResultIsNotNull(Thread thread)
      Same as getReadLockManager(Thread) but in this case a not null result is ensured
      Parameters:
      thread - the thread wanting its read lock manager
      Returns:
      the read lock manager for the current thread.
    • removeReadLockManagerIfEmpty

      protected static void removeReadLockManagerIfEmpty(Thread thread)
      Just like we see that the satic map of deffered locks is cleared of cache values for the current thread we also want to try to keep the static map of acquired read locks by a thread light weight by removing the association between the current thread and a read lock manager whenever the read lock manager becomes empty.
      Parameters:
      thread - the thread that wants its read lock manager destroyed if it is empty.
    • clearJustificationWhyMethodIsBuildingObjectCompleteReturnsFalse

      public static void clearJustificationWhyMethodIsBuildingObjectCompleteReturnsFalse()
      Clear the justification why the isBuildObjectOnThreadComplete(Thread, Map, List, boolean) is going nowhere.

      WHEN TO INVOKE:
      Should be invoked if we decide to blowup a thread with the explosive approach, for a thread in wait for release deferred lock. We do not want to keep traces of threads that left eclipselink code.
      Should be infokved when the algorithm returns TRUE - build object is complete.
      Should be invoked when we are not yet stuck for sufficient time and the release defferred logic algorithm is using the isBuildObjectOnThreadComplete(Thread, Map, List, boolean) instead of the more verbose and slower isBuildObjectOnThreadComplete(Thread, Map, List, boolean).

    • setJustificationWhyMethodIsBuildingObjectCompleteReturnsFalse

      public static void setJustificationWhyMethodIsBuildingObjectCompleteReturnsFalse(String justification)
      Parameters:
      justification - a string that helps us understand why the recursive algorithm returned false, building object is not yet complete.
    • getInstanceLock

      public Lock getInstanceLock()
    • getInstanceLockCondition

      public Condition getInstanceLockCondition()