Class 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:
    Serialized Form
    • Field Detail

      • shouldTrackStack

        protected static boolean shouldTrackStack
      • numberOfWritersWaiting

        protected AtomicInteger numberOfWritersWaiting
      • activeThread

        protected transient volatile Thread activeThread
      • lockedByMergeManager

        protected boolean lockedByMergeManager
    • Constructor Detail

      • ConcurrencyManager

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

      • 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
      • 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
      • 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 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 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.
      • 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
      • 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).
      • 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"
        Parameters:
        shouldTrackStack -
      • 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)
      • 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.