java.lang.Object
org.eclipse.persistence.internal.helper.WriteLockManager

public class WriteLockManager extends Object
INTERNAL:

Purpose: Acquires all required locks for a particular merge process. Implements a deadlock avoidance algorithm to prevent concurrent merge conflicts.

Responsibilities:

  • Acquires locks for writing threads.
  • Provides deadlock avoidance behavior.
  • Releases locks for writing threads.
Since:
10.0.3
  • Field Details

  • Constructor Details

    • WriteLockManager

      public WriteLockManager()
  • Method Details

    • acquireLocksForClone

      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.
    • acquireLockAndRelatedLocks

      public CacheKey acquireLockAndRelatedLocks(Object objectForClone, Map lockedObjects, Map 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.
    • transitionToDeferredLocks

      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

      public CacheKey traverseRelatedLocks(Object objectForClone, Map lockedObjects, Map refreshedObjects, ClassDescriptor descriptor, AbstractSession cloningSession)
      INTERNAL: Traverse the object and acquire locks on all related objects.
    • acquireRequiredLocks

      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.
    • appendLock

      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

      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

      protected CacheKey checkAndLockObject(Object objectToLock, Map lockedObjects, Map refreshedObjects, DatabaseMapping mapping, AbstractSession cloningSession)
      INTERNAL: Simply check that the object is not already locked then pass it on to the locking method
    • releaseAllAcquiredLocks

      public void releaseAllAcquiredLocks(MergeManager mergeManager)
      INTERNAL: This method will release all acquired locks
    • waitOnObjectLock

      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
    • getThreadToFailToAcquireCacheKeys

      public static Map<Thread,Set<ConcurrencyManager>> getThreadToFailToAcquireCacheKeys()
      Getter for THREAD_TO_FAIL_TO_ACQUIRE_CACHE_KEYS
    • getMapWriteLockManagerThreadToObjectIdsWithChangeSet

      public static Map<Thread,Set<Object>> getMapWriteLockManagerThreadToObjectIdsWithChangeSet()
      Getter for MAP_WRITE_LOCK_MANAGER_THREAD_TO_OBJECT_IDS_WITH_CHANGE_SET
    • clearMapThreadToObjectIdsWithChagenSet

      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
      Parameters:
      thread - the thread that is clearing itself out of the map of change sets it needs to merge into the shared cache
    • populateMapThreadToObjectIdsWithChagenSet

      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.
      Parameters:
      thread - the thread that is in the middle of merge to the shared cache trying to acquire write locks to do this merge
      objectChangeSets - the object change sets it has in its hands and that it would like to merge into the cache
    • clearMapWriteLockManagerToCacheKeysThatCouldNotBeAcquired

      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.
      Parameters:
      thread - the thread that what clear his set of cache keys it is struggling to acquire.
    • addCacheKeyToMapWriteLockManagerToCacheKeysThatCouldNotBeAcquired

      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
      Parameters:
      thread - thread the thread working on updating the shared cache
      cacheKeyThatCouldNotBeAcquired - the cache key it is not managing to acquire
      Throws:
      InterruptedException - Should be fired because we are passing a flag into the determineIfReleaseDeferredLockAppearsToBeDeadLocked to say we do not want the thread to be blown up (e.g. we are afraid of breaking threads in the middle of a commit process could be quite dangerous). See ALLOW_INTERRUPTED_EXCEPTION_TO_BE_FIRED_UP_FALSE
    • removeCacheKeyFromMapWriteLockManagerToCacheKeysThatCouldNotBeAcquired

      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.
      Parameters:
      thread - the thread that just managed to grab a write lock
      cacheKeyThatCouldNotBeAcquired - the cache key it managed to acquire for writing.