Purpose: Acquires all required locks for a particular merge process. Implements a deadlock avoidance algorithm to prevent concurrent merge conflicts.
Responsibilities:
| Modifier and Type | Field and Description |
|---|---|
| private static final Boolean | ALLOW_INTERRUPTED_EXCEPTION_TO_BE_FIRED_UP_FALSE
The code spots where we use this constant are code spots where we afraid the thread might be trying to run a commit. |
| private static final Boolean | ALLOW_INTERRUPTED_EXCEPTION_TO_BE_FIRED_UP_TRUE
This flag we use if the write lock manager is stuck building clones of objects. |
| private static final Map | MAP_WRITE_LOCK_MANAGER_THREAD_TO_OBJECT_IDS_WITH_CHANGE_SET
We want to have traceability of what objects where changed by thread that is in the middle of a commit. |
| public static final int | |
| public static final int | |
| protected ExposedNodeLinkedList | |
| private static final transient Semaphore | |
| private static final transient int | |
| private static final transient ThreadLocal | SEMAPHORE_THREAD_LOCAL_VAR
Semaphore related properties |
| private static final Map | THREAD_TO_FAIL_TO_ACQUIRE_CACHE_KEYS
This a map from a thread to cache keys the thread is finding itself not being able to acquire. |
| private transient ConcurrencySemaphore |
| Access | Constructor and Description |
|---|---|
| public |
| Modifier and Type | Method and Description |
|---|---|
| public CacheKey | acquireLockAndRelatedLocks(Object objectForClone, Map<K, V> lockedObjects, Map<K, V> refreshedObjects, CacheKey cacheKey, ClassDescriptor descriptor, AbstractSession cloningSession)
INTERNAL: This is a recursive method used to acquire read locks on all objects that will be cloned. |
| public Map | acquireLocksForClone(Object objectForClone, ClassDescriptor descriptor, CacheKey cacheKey, AbstractSession cloningSession)
INTERNAL: This method will return once the object is locked and all non-indirect related objects are also locked. |
| public void | acquireRequiredLocks(MergeManager mergeManager, UnitOfWorkChangeSet changeSet)
INTERNAL: This method will be the entry point for threads attempting to acquire locks for all objects that have a changeset. |
| private void | acquireRequiredLocksInternal(MergeManager mergeManager, UnitOfWorkChangeSet changeSet)
INTERNAL: This method will be the entry point for threads attempting to acquire locks for all objects that have a changeset. |
| public static void | addCacheKeyToMapWriteLockManagerToCacheKeysThatCouldNotBeAcquired(Thread
thread the thread working on updating the shared cache thread, ConcurrencyManager the cache key it is not managing to acquire cacheKeyThatCouldNotBeAcquired, long whileStartDate)The thread was doing its while loop to acquire all required locks to proceed with the commmit and it realized there was one cache key it is unable to acquire |
| public CacheKey | appendLock(Object primaryKey, Object objectToLock, ClassDescriptor descriptor, MergeManager mergeManager, AbstractSession session)
INTERNAL: This method will be called by a merging thread that is attempting to lock a new object that was not locked previously. |
| protected CacheKey | attemptToAcquireLock(ClassDescriptor descriptor, Object primaryKey, AbstractSession session)
INTERNAL: This method performs the operations of finding the cacheKey and locking it if possible. |
| protected CacheKey | checkAndLockObject(Object objectToLock, Map<K, V> lockedObjects, Map<K, V> refreshedObjects, DatabaseMapping mapping, AbstractSession cloningSession)
INTERNAL: Simply check that the object is not already locked then pass it on to the locking method |
| public static void | clearMapThreadToObjectIdsWithChagenSet(Thread
the thread that is clearing itself out of the map of change sets it needs to merge into the shared
cache thread)Remove the current thread from the map of object ids with change sets that are about to bec ommited |
| public static void | clearMapWriteLockManagerToCacheKeysThatCouldNotBeAcquired(Thread
the thread that what clear his set of cache keys it is struggling to acquire. thread)Before the problematic while loop starts we should always clear for this thread the set of cache keys it could not acquire. |
| private static Set | Returns: the set of cache keys the thrad is struggling to acquirethe thread that wants to get its set of cache keys it is not managing to acquire. thread)If the thread is not yet registered in the map it will get registered with an empty map. |
| public static Map | |
| public static Map | |
| public static void | populateMapThreadToObjectIdsWithChagenSet(Thread
the thread that is in the middle of merge to the shared cache trying to acquire write locks to do this
merge thread, Collection<ObjectChangeSet> the object change sets it has in its hands and that it would like to merge into the cache objectChangeSets)Before a thread starts long wait loop to acquire write locks during a commit transaction the thread will record in this map the object ids it holds with chance sets. |
| public void | releaseAllAcquiredLocks(MergeManager mergeManager)
INTERNAL: This method will release all acquired locks |
| public static void | removeCacheKeyFromMapWriteLockManagerToCacheKeysThatCouldNotBeAcquired(Thread
the thread that just managed to grab a write lock thread, ConcurrencyManager the cache key it managed to acquire for writing. cacheKeyThatCouldNotBeAcquired)A cache keys was successfully acquired we want to make sure it is not recorded in the map of cache keys that could not be acquired. |
| public void | transitionToDeferredLocks(MergeManager mergeManager)
INTERNAL: This method will transition the previously acquired active locks to deferred locks in the case a readlock could not be acquired for a related object. |
| public CacheKey | traverseRelatedLocks(Object objectForClone, Map<K, V> lockedObjects, Map<K, V> refreshedObjects, ClassDescriptor descriptor, AbstractSession cloningSession)
INTERNAL: Traverse the object and acquire locks on all related objects. |
| protected CacheKey | waitOnObjectLock(ClassDescriptor descriptor, Object primaryKey, AbstractSession session, int waitTime)
INTERNAL: This method performs the operations of finding the cacheKey and locking it if possible. |
| ALLOW_INTERRUPTED_EXCEPTION_TO_BE_FIRED_UP_FALSE | back to summary |
|---|---|
| private static final Boolean ALLOW_INTERRUPTED_EXCEPTION_TO_BE_FIRED_UP_FALSE The code spots where we use this constant are code spots where we afraid the thread might be trying to run a commit. Blowing up the thread with an interrupted exception might be too dangerous. We are not certain the eclipselink code is able to cope with it and release all resources appropriately. | |
| ALLOW_INTERRUPTED_EXCEPTION_TO_BE_FIRED_UP_TRUE | back to summary |
|---|---|
| private static final Boolean ALLOW_INTERRUPTED_EXCEPTION_TO_BE_FIRED_UP_TRUE This flag we use if the write lock manager is stuck building clones of objects. Because we are not in the code area of commit to the db anything. | |
| MAP_WRITE_LOCK_MANAGER_THREAD_TO_OBJECT_IDS_WITH_CHANGE_SET | back to summary |
|---|---|
| private static final Map<Thread, Set<Object>> MAP_WRITE_LOCK_MANAGER_THREAD_TO_OBJECT_IDS_WITH_CHANGE_SET We want to have traceability of what objects where changed by thread that is in the middle of a commit. This
information can be useful when a massive dump is performed to explain the situation of any thread that might
eventually be stuck inside of the write lock manager to tells us what exactly are the objects it has changed and
wants to commit or merge into the shared cache. Relates to the
| |
| MAX_WAIT | back to summary |
|---|---|
| public static final int MAX_WAIT | |
| MAXTRIES | back to summary |
|---|---|
| public static final int MAXTRIES | |
| prevailingQueue | back to summary |
|---|---|
| protected ExposedNodeLinkedList prevailingQueue | |
| SEMAPHORE_LIMIT_MAX_NUMBER_OF_THREADS_WRITE_LOCK_MANAGER | back to summary |
|---|---|
| private static final transient Semaphore SEMAPHORE_LIMIT_MAX_NUMBER_OF_THREADS_WRITE_LOCK_MANAGER | |
| SEMAPHORE_MAX_NUMBER_THREADS | back to summary |
|---|---|
| private static final transient int SEMAPHORE_MAX_NUMBER_THREADS | |
| SEMAPHORE_THREAD_LOCAL_VAR | back to summary |
|---|---|
| private static final transient ThreadLocal<Boolean> SEMAPHORE_THREAD_LOCAL_VAR Semaphore related properties | |
| THREAD_TO_FAIL_TO_ACQUIRE_CACHE_KEYS | back to summary |
|---|---|
| private static final Map<Thread, Set<ConcurrencyManager>> THREAD_TO_FAIL_TO_ACQUIRE_CACHE_KEYS This a map from a thread to cache keys the thread is finding itself not being able to acquire. This map is
important to explain why a thread might be stuck in a stack trace of the form: | |
| writeLockManagerSemaphore | back to summary |
|---|---|
| private transient ConcurrencySemaphore writeLockManagerSemaphore | |
| WriteLockManager | back to summary |
|---|---|
| public WriteLockManager() | |
| acquireLockAndRelatedLocks | back to summary |
|---|---|
| public CacheKey acquireLockAndRelatedLocks(Object objectForClone, Map<K, V> lockedObjects, Map<K, V> refreshedObjects, CacheKey cacheKey, ClassDescriptor descriptor, AbstractSession cloningSession) INTERNAL: This is a recursive method used to acquire read locks on all objects that will be cloned. These include all related objects for which there is no indirection. The returned object is the first object that the lock could not be acquired for. The caller must try for exceptions and release locked objects in the case of an exception. | |
| acquireLocksForClone | back to summary |
|---|---|
| public Map INTERNAL: This method will return once the object is locked and all non-indirect related objects are also locked. | |
| acquireRequiredLocks | back to summary |
|---|---|
| public void acquireRequiredLocks(MergeManager mergeManager, UnitOfWorkChangeSet changeSet) INTERNAL: This method will be the entry point for threads attempting to acquire locks for all objects that have a changeset. This method will hand off the processing of the deadlock algorithm to other member methods. The mergeManager must be the active mergemanager for the calling thread. Returns true if all required locks were acquired This is wrapper method with semaphore logic. | |
| acquireRequiredLocksInternal | back to summary |
|---|---|
| private void acquireRequiredLocksInternal(MergeManager mergeManager, UnitOfWorkChangeSet changeSet) INTERNAL: This method will be the entry point for threads attempting to acquire locks for all objects that have a changeset. This method will hand off the processing of the deadlock algorithm to other member methods. The mergeManager must be the active mergemanager for the calling thread. Returns true if all required locks were acquired | |
| addCacheKeyToMapWriteLockManagerToCacheKeysThatCouldNotBeAcquired | back to summary |
|---|---|
| public static void addCacheKeyToMapWriteLockManagerToCacheKeysThatCouldNotBeAcquired(Thread thread, ConcurrencyManager cacheKeyThatCouldNotBeAcquired, long whileStartDate) throws InterruptedException The thread was doing its while loop to acquire all required locks to proceed with the commmit and it realized there was one cache key it is unable to acquire
| |
| appendLock | back to summary |
|---|---|
| public CacheKey appendLock(Object primaryKey, Object objectToLock, ClassDescriptor descriptor, MergeManager mergeManager, AbstractSession session) INTERNAL: This method will be called by a merging thread that is attempting to lock a new object that was not locked previously. Unlike the other methods within this class this method will lock only this object. | |
| attemptToAcquireLock | back to summary |
|---|---|
| protected CacheKey attemptToAcquireLock(ClassDescriptor descriptor, Object primaryKey, AbstractSession session) INTERNAL: This method performs the operations of finding the cacheKey and locking it if possible. Returns True if the lock was acquired, false otherwise | |
| checkAndLockObject | back to summary |
|---|---|
| protected CacheKey checkAndLockObject(Object objectToLock, Map<K, V> lockedObjects, Map<K, V> refreshedObjects, DatabaseMapping mapping, AbstractSession cloningSession) INTERNAL: Simply check that the object is not already locked then pass it on to the locking method | |
| clearMapThreadToObjectIdsWithChagenSet | back to summary |
|---|---|
| public static void clearMapThreadToObjectIdsWithChagenSet(Thread thread) Remove the current thread from the map of object ids with change sets that are about to bec ommited
| |
| clearMapWriteLockManagerToCacheKeysThatCouldNotBeAcquired | back to summary |
|---|---|
| public static void clearMapWriteLockManagerToCacheKeysThatCouldNotBeAcquired(Thread thread) Before the problematic while loop starts we should always clear for this thread the set of cache keys it could not acquire.
| |
| getCacheKeysThatCouldNotBeAcquiredByThread | back to summary |
|---|---|
| private static Set If the thread is not yet registered in the map it will get registered with an empty map.
| |
| getMapWriteLockManagerThreadToObjectIdsWithChangeSet | back to summary |
|---|---|
| public static Map Getter for | |
| getThreadToFailToAcquireCacheKeys | back to summary |
|---|---|
| public static Map Getter for | |
| populateMapThreadToObjectIdsWithChagenSet | back to summary |
|---|---|
| public static void populateMapThreadToObjectIdsWithChagenSet(Thread thread, Collection<ObjectChangeSet> objectChangeSets) Before a thread starts long wait loop to acquire write locks during a commit transaction the thread will record in this map the object ids it holds with chance sets. It will be useful information if a dead lock is taking place.
| |
| releaseAllAcquiredLocks | back to summary |
|---|---|
| public void releaseAllAcquiredLocks(MergeManager mergeManager) INTERNAL: This method will release all acquired locks | |
| removeCacheKeyFromMapWriteLockManagerToCacheKeysThatCouldNotBeAcquired | back to summary |
|---|---|
| public static void removeCacheKeyFromMapWriteLockManagerToCacheKeysThatCouldNotBeAcquired(Thread thread, ConcurrencyManager cacheKeyThatCouldNotBeAcquired) A cache keys was successfully acquired we want to make sure it is not recorded in the map of cache keys that could not be acquired. The situation theoretically can change. Failing to acquire a write lock can be a temporary situation. The lock might become available eventually. Otherwise there would be no point for the while loop that is trying to acquire these locks.
| |
| transitionToDeferredLocks | back to summary |
|---|---|
| public void transitionToDeferredLocks(MergeManager mergeManager) INTERNAL: This method will transition the previously acquired active locks to deferred locks in the case a readlock could not be acquired for a related object. Deferred locks must be employed to prevent deadlock when waiting for the readlock while still protecting readers from incomplete data. | |
| traverseRelatedLocks | back to summary |
|---|---|
| public CacheKey traverseRelatedLocks(Object objectForClone, Map<K, V> lockedObjects, Map<K, V> refreshedObjects, ClassDescriptor descriptor, AbstractSession cloningSession) INTERNAL: Traverse the object and acquire locks on all related objects. | |
| waitOnObjectLock | back to summary |
|---|---|
| protected CacheKey waitOnObjectLock(ClassDescriptor descriptor, Object primaryKey, AbstractSession session, int waitTime) INTERNAL: This method performs the operations of finding the cacheKey and locking it if possible. Waits until the lock can be acquired | |