Module org.eclipse.persistence.core
Class ConcurrencyManager
java.lang.Object
org.eclipse.persistence.internal.helper.ConcurrencyManager
- All Implemented Interfaces:
Serializable
- Direct Known Subclasses:
CacheKey
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 Summary
Modifier and TypeFieldDescriptionprotected Thread
static final Map
<Thread, DeferredLockManager> protected AtomicInteger
protected boolean
protected AtomicInteger
protected AtomicInteger
protected static boolean
protected Exception
-
Constructor Summary
-
Method Summary
Modifier and TypeMethodDescriptionvoid
acquire()
Wait for all threads except the active thread.void
acquire
(boolean forMerge) Wait for all threads except the active thread.void
Add deferred lock into a hashtable to avoid deadlockboolean
acquireIfUnownedNoWait
(boolean forMerge) If the activeThread is not set, acquire it and return true.boolean
If the lock is not acquired already acquire it and return true.boolean
acquireNoWait
(boolean forMerge) If the lock is not acquired already acquire it and return true.void
Wait on any writer.boolean
If this is acquired return false otherwise acquire readlock and return trueboolean
acquireWithWait
(boolean forMerge, int wait) If the lock is not acquired already acquire it and return true.protected void
The current thread has incremented the number of readers on the current cache key.void
Check the lock state, if locked, acquire and release a deferred lock.void
Check the lock state, if locked, acquire and release a read lock.static void
Clear the justification why theisBuildObjectOnThreadComplete(Thread, Map, List, boolean)
is going nowhere.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.Return the active thread.Getter forconcurrencyManagerCreationDate
long
Getter forconcurrencyManagerId
static DeferredLockManager
getDeferredLockManager
(Thread thread) Return the deferred lock manager from the threadprotected static Map
<Thread, DeferredLockManager> Return the deferred lock manager hashtable (thread - DeferredLockManager).int
getDepth()
Return the current depth of the active thread.int
Number of writer that want the lock.int
Number of writers that want the lock.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.protected static ReadLockManager
Same asgetReadLockManager(Thread)
but in this case a not null result is ensuredprotected static Map
<Thread, ReadLockManager> Return the deferred lock manager hashtable (thread - DeferredLockManager).getStack()
static Map
<Thread, ConcurrencyManager> Getter forTHREADS_TO_WAIT_ON_ACQUIRE
Getter forTHREADS_TO_WAIT_ON_ACQUIRE_NAME_OF_METHOD_CREATING_TRACE
static Map
<Thread, ConcurrencyManager> Getter forTHREADS_TO_WAIT_ON_ACQUIRE_READ_LOCK
Getter forTHREADS_TO_WAIT_ON_ACQUIRE_READ_LOCK_NAME_OF_METHOD_CREATING_TRACE
Getter forTHREADS_WAITING_TO_RELEASE_DEFERRED_LOCKS
Getter forTHREADS_WAITING_TO_RELEASE_DEFERRED_LOCKS_BUILD_OBJECT_COMPLETE_GOES_NOWHERE
long
Getter fortotalNumberOfKeysAcquiredForReading
long
Getter fortotalNumberOfKeysReleasedForReading
long
Getter fortotalNumberOfKeysReleasedForReadingBlewUpExceptionDueToCacheKeyHavingReachedCounterZero
protected static Map
<Thread, DeferredLockManager> Init the deferred lock managers (thread - DeferredLockManager).boolean
Return if a thread has acquire this manager.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.boolean
INTERNAL: Used byt the refresh process to determine if this concurrency manager is locked by the merge process.boolean
isNested()
Return if this manager is within a nested acquire.void
putDeferredLock
(Thread thread, DeferredLockManager lockManager) 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.void
putThreadAsWaitingToAcquireLockForWriting
(Thread thread, String methodName) Normally this mehtod should only be called from withing the concurrency manager.void
release()
Decrement the depth for the active thread.void
releaseAllLocksAcquiredByThread
(DeferredLockManager lockManager) For the thread to release all of its locks.void
Release the deferred lock.void
Decrement the number of readers.static DeferredLockManager
removeDeferredLockManager
(Thread thread) Remove the deferred lock manager for the threadprotected void
The current thread is about to decrement the number of readers in cache key.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.void
void
The thread has acquired the lock for writing or decided to defer acquiring the lock putting this lock into its deferred lock list.void
setActiveThread
(Thread activeThread) Set the active thread.protected void
setDepth
(int depth) Set the current depth of the active thread.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.static void
SeeclearJustificationWhyMethodIsBuildingObjectCompleteReturnsFalse()
in this case we want to store the justification computed by theenrichStringBuildingExplainWhyThreadIsStuckInIsBuildObjectOnThreadComplete(List, ConcurrencyManager, Thread, boolean, StringBuilder)
protected void
setNumberOfReaders
(int numberOfReaders) Track the number of readers.protected void
setNumberOfWritersWaiting
(int numberOfWritersWaiting) Number of writers that want the lock.static void
setShouldTrackStack
(boolean shouldTrackStack) INTERNAL: This can be set during debugging to record the stacktrace when a lock is acquired.void
static boolean
toString()
Print the nested depth.void
-
Field Details
-
DEFERRED_LOCK_MANAGERS
-
shouldTrackStack
protected static boolean shouldTrackStack -
numberOfReaders
-
depth
-
numberOfWritersWaiting
-
activeThread
-
lockedByMergeManager
protected boolean lockedByMergeManager -
stack
-
-
Constructor Details
-
ConcurrencyManager
public ConcurrencyManager()Initialize the newly allocated instance of this class. Set the depth to zero.
-
-
Method Details
-
acquire
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
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
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
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
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
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
Add deferred lock into a hashtable to avoid deadlock- Throws:
ConcurrencyException
-
checkDeferredLock
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
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
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
Return the active thread. -
getDeferredLockManager
Return the deferred lock manager from the thread -
getDeferredLockManagers
Return the deferred lock manager hashtable (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 theTHREADS_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 recursionfinalDeferredLockCausingTrouble
- 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
-
release
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
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
Decrement the number of readers. Used to allow concurrent reads.- Throws:
ConcurrencyException
-
removeDeferredLockManager
Remove the deferred lock manager for the thread -
setActiveThread
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
For the thread to release all of its locks.- Parameters:
lockManager
- the deferred lock manager
-
getReadLockManager
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
Return the deferred lock manager hashtable (thread - DeferredLockManager). -
toString
Print the nested depth. -
getStack
-
setStack
-
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
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
The thread has acquired the lock for writing or decided to defer acquiring the lock putting this lock into its deferred lock list. -
putThreadAsWaitingToAcquireLockForReading
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
-
getConcurrencyManagerId
public long getConcurrencyManagerId()Getter forconcurrencyManagerId
-
getConcurrencyManagerCreationDate
Getter forconcurrencyManagerCreationDate
-
getTotalNumberOfKeysAcquiredForReading
public long getTotalNumberOfKeysAcquiredForReading()Getter fortotalNumberOfKeysAcquiredForReading
-
getTotalNumberOfKeysReleasedForReading
public long getTotalNumberOfKeysReleasedForReading()Getter fortotalNumberOfKeysReleasedForReading
-
getTotalNumberOfKeysReleasedForReadingBlewUpExceptionDueToCacheKeyHavingReachedCounterZero
public long getTotalNumberOfKeysReleasedForReadingBlewUpExceptionDueToCacheKeyHavingReachedCounterZero()Getter fortotalNumberOfKeysReleasedForReadingBlewUpExceptionDueToCacheKeyHavingReachedCounterZero
-
getThreadsToWaitOnAcquire
Getter forTHREADS_TO_WAIT_ON_ACQUIRE
-
getThreadsToWaitOnAcquireMethodName
Getter forTHREADS_TO_WAIT_ON_ACQUIRE_NAME_OF_METHOD_CREATING_TRACE
-
getThreadsToWaitOnAcquireReadLock
Getter forTHREADS_TO_WAIT_ON_ACQUIRE_READ_LOCK
-
getThreadsToWaitOnAcquireReadLockMethodName
Getter forTHREADS_TO_WAIT_ON_ACQUIRE_READ_LOCK_NAME_OF_METHOD_CREATING_TRACE
-
getThreadsWaitingToReleaseDeferredLocks
Getter forTHREADS_WAITING_TO_RELEASE_DEFERRED_LOCKS
-
getThreadsWaitingToReleaseDeferredLocksJustification
Getter forTHREADS_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
Same asgetReadLockManager(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
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 theisBuildObjectOnThreadComplete(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 theisBuildObjectOnThreadComplete(Thread, Map, List, boolean)
instead of the more verbose and slowerisBuildObjectOnThreadComplete(Thread, Map, List, boolean)
. -
setJustificationWhyMethodIsBuildingObjectCompleteReturnsFalse
public static void setJustificationWhyMethodIsBuildingObjectCompleteReturnsFalse(String justification) SeeclearJustificationWhyMethodIsBuildingObjectCompleteReturnsFalse()
in this case we want to store the justification computed by theenrichStringBuildingExplainWhyThreadIsStuckInIsBuildObjectOnThreadComplete(List, ConcurrencyManager, Thread, boolean, StringBuilder)
- Parameters:
justification
- a string that helps us understand why the recursive algorithm returned false, building object is not yet complete.
-
getInstanceLock
-
getInstanceLockCondition
-