1 21 package oracle.toplink.essentials.internal.helper; 23 24 import java.util.*; 25 26 import oracle.toplink.essentials.exceptions.ConcurrencyException; 27 import oracle.toplink.essentials.internal.queryframework.ContainerPolicy; 28 import oracle.toplink.essentials.mappings.DatabaseMapping; 29 import oracle.toplink.essentials.descriptors.ClassDescriptor; 30 import oracle.toplink.essentials.internal.sessions.*; 31 import oracle.toplink.essentials.internal.identitymaps.*; 32 import oracle.toplink.essentials.internal.helper.linkedlist.*; 33 import oracle.toplink.essentials.logging.SessionLog; 34 35 51 public class WriteLockManager { 52 53 54 55 protected ExposedNodeLinkedList prevailingQueue; 56 57 public WriteLockManager() { 58 this.prevailingQueue = new ExposedNodeLinkedList(); 59 } 60 61 public static int MAXTRIES = 10000; 63 64 69 public Map acquireLocksForClone(Object objectForClone, ClassDescriptor descriptor, Vector primaryKeys, AbstractSession session) { 70 boolean successful = false; 71 TopLinkIdentityHashMap lockedObjects = new TopLinkIdentityHashMap(); 72 try { 73 CacheKey toWaitOn = acquireLockAndRelatedLocks(objectForClone, lockedObjects, primaryKeys, descriptor, session); 75 int tries = 0; 76 while (toWaitOn != null) { for (Iterator lockedList = lockedObjects.values().iterator(); lockedList.hasNext();) { 78 ((CacheKey)lockedList.next()).releaseReadLock(); 79 lockedList.remove(); 80 } 81 synchronized (toWaitOn.getMutex()) { 82 try { 83 if (toWaitOn.isAcquired()) { toWaitOn.getMutex().wait(); } 86 } catch (InterruptedException ex) { 87 } 89 } 90 toWaitOn = acquireLockAndRelatedLocks(objectForClone, lockedObjects, primaryKeys, descriptor, session); 91 if ((toWaitOn != null) && ((++tries) > MAXTRIES)) { 92 throw ConcurrencyException.maxTriesLockOnCloneExceded(objectForClone); 94 } 95 } 96 successful = true; } finally { 98 if (!successful) { for (Iterator lockedList = lockedObjects.values().iterator(); lockedList.hasNext();) { 100 ((CacheKey)lockedList.next()).releaseReadLock(); 101 lockedList.remove(); 102 } 103 } 104 } 105 return lockedObjects; 106 } 107 108 117 public CacheKey acquireLockAndRelatedLocks(Object objectForClone, Map lockedObjects, Vector primaryKeys, ClassDescriptor descriptor, AbstractSession session) { 118 CacheKey lockedCacheKey = session.getIdentityMapAccessorInstance().acquireReadLockOnCacheKeyNoWait(primaryKeys, descriptor.getJavaClass(), descriptor); 120 if (lockedCacheKey != null) { 121 if (lockedCacheKey.getObject() == null) { 122 lockedObjects.put(objectForClone, lockedCacheKey); 124 } else { 125 objectForClone = lockedCacheKey.getObject(); 126 if (lockedObjects.containsKey(objectForClone)) { 127 lockedCacheKey.releaseReadLock(); 130 return null; 131 } 132 lockedObjects.put(objectForClone, lockedCacheKey); } 134 return traverseRelatedLocks(objectForClone, lockedObjects, descriptor, session); 135 } else { 136 return session.getIdentityMapAccessorInstance().getCacheKeyForObject(primaryKeys, descriptor.getJavaClass(), descriptor); 138 } 139 } 140 141 145 public CacheKey traverseRelatedLocks(Object objectForClone, Map lockedObjects, ClassDescriptor descriptor, AbstractSession session) { 146 if (descriptor.shouldAcquireCascadedLocks()) { 148 for (Iterator mappings = descriptor.getLockableMappings().iterator(); 149 mappings.hasNext();) { 150 DatabaseMapping mapping = (DatabaseMapping)mappings.next(); 151 152 Object objectToLock = mapping.getAttributeValueFromObject(objectForClone); 154 if (mapping.isCollectionMapping()) { 155 ContainerPolicy cp = mapping.getContainerPolicy(); 156 Object iterator = cp.iteratorFor(objectToLock); 157 while (cp.hasNext(iterator)) { 158 Object object = cp.next(iterator, session); 159 if (mapping.getReferenceDescriptor().hasWrapperPolicy()) { 160 object = mapping.getReferenceDescriptor().getWrapperPolicy().unwrapObject(object, session); 161 } 162 CacheKey toWaitOn = checkAndLockObject(object, lockedObjects, mapping, session); 163 if (toWaitOn != null) { 164 return toWaitOn; 165 } 166 } 167 } else { 168 if (mapping.getReferenceDescriptor().hasWrapperPolicy()) { 169 objectToLock = mapping.getReferenceDescriptor().getWrapperPolicy().unwrapObject(objectToLock, session); 170 } 171 CacheKey toWaitOn = checkAndLockObject(objectToLock, lockedObjects, mapping, session); 172 if (toWaitOn != null) { 173 return toWaitOn; 174 } 175 } 176 } 177 } 178 return null; 179 } 180 181 188 public void acquireRequiredLocks(MergeManager mergeManager, UnitOfWorkChangeSet changeSet) { 189 if (!MergeManager.LOCK_ON_MERGE) { return; 191 } 192 boolean locksToAcquire = true; 193 boolean isForDistributedMerge = false; 194 195 try { 197 AbstractSession session = mergeManager.getSession(); 198 if (session.isUnitOfWork()) { 199 session = ((UnitOfWorkImpl)session).getParent(); 200 } else { 201 isForDistributedMerge = true; 204 } 205 while (locksToAcquire) { 206 locksToAcquire = false; 208 Iterator classIterator = changeSet.getObjectChanges().keySet().iterator(); 210 while (classIterator.hasNext()) { 211 String objectClassName = (String )classIterator.next(); 213 Hashtable changeSetTable = (Hashtable)changeSet.getObjectChanges().get(objectClassName); 214 215 Iterator changeSetIterator = changeSetTable.keySet().iterator(); 218 219 Class objectClass = null; 221 while (changeSetIterator.hasNext()) { 222 ObjectChangeSet objectChangeSet = (ObjectChangeSet)changeSetIterator.next(); 223 if (objectChangeSet.getCacheKey() == null) { 224 continue; 227 } 228 if (objectClass == null) { 229 objectClass = objectChangeSet.getClassType(session); 230 } 231 ClassDescriptor descriptor = session.getDescriptor(objectClass); 234 CacheKey activeCacheKey = attemptToAcquireLock(objectClass, objectChangeSet.getCacheKey(), session); 235 if (activeCacheKey == null) { 236 if (this.prevailingQueue.getFirst() == mergeManager) { 240 activeCacheKey = waitOnObjectLock(objectClass, objectChangeSet.getCacheKey(), session); 242 mergeManager.getAcquiredLocks().add(activeCacheKey); 243 } else { 244 releaseAllAcquiredLocks(mergeManager); 246 activeCacheKey = session.getIdentityMapAccessorInstance().getCacheKeyForObject(objectChangeSet.getCacheKey().getKey(), objectClass, descriptor); 248 Object [] params = new Object [2]; 249 params[0] = activeCacheKey.getObject(); 250 params[1] = Thread.currentThread().getName(); 251 session.log(SessionLog.FINER, SessionLog.CACHE, "dead_lock_encountered_on_write", params, null, true); 252 if (mergeManager.getWriteLockQueued() == null) { 253 mergeManager.setQueueNode(this.prevailingQueue.addLast(mergeManager)); 257 } 258 259 mergeManager.setWriteLockQueued(objectChangeSet.getCacheKey()); 261 try { 262 synchronized (activeCacheKey.getMutex()) { 264 if (activeCacheKey.getMutex().isAcquired() && (activeCacheKey.getMutex().getActiveThread() != Thread.currentThread())) { 267 activeCacheKey.getMutex().wait(); 268 } 269 } 270 } catch (InterruptedException exception) { 271 throw oracle.toplink.essentials.exceptions.ConcurrencyException.waitWasInterrupted(exception.getMessage()); 272 } 273 locksToAcquire = true; 274 break; 276 } 277 } else { 278 mergeManager.getAcquiredLocks().add(activeCacheKey); 279 } 280 } 281 282 if (locksToAcquire) { 284 break; 285 } 286 } 287 } 288 } catch (RuntimeException exception) { 289 releaseAllAcquiredLocks(mergeManager); 293 throw exception; 294 } finally { 295 if (mergeManager.getWriteLockQueued() != null) { 296 this.prevailingQueue.remove(mergeManager.getQueueNode()); 298 mergeManager.setWriteLockQueued(null); 299 } 300 } 301 } 302 303 309 public Object appendLock(Vector primaryKeys, Object objectToLock, ClassDescriptor descriptor, MergeManager mergeManager, AbstractSession session){ 310 for (int tries = 0; tries < 1000; ++tries) { CacheKey lockedCacheKey = session.getIdentityMapAccessorInstance().acquireLockNoWait(primaryKeys, descriptor.getJavaClass(), true, descriptor); 312 if (lockedCacheKey == null){ 313 lockedCacheKey = session.getIdentityMapAccessorInstance().acquireReadLockOnCacheKey(primaryKeys, descriptor.getJavaClass(), descriptor); 316 Object cachedObject = lockedCacheKey.getObject(); 317 lockedCacheKey.releaseReadLock(); 318 if (cachedObject == null){ 319 session.getSessionLog().log(SessionLog.FINEST, SessionLog.CACHE, "Found null object in identity map on appendLock, retrying"); 320 continue; 321 }else{ 322 return cachedObject; 323 } 324 } 325 if (lockedCacheKey.getObject() == null){ 326 lockedCacheKey.setObject(objectToLock); } 329 mergeManager.getAcquiredLocks().add(lockedCacheKey); 330 return objectToLock; 331 } 332 throw ConcurrencyException.maxTriesLockOnMergeExceded(objectToLock); 333 } 334 335 340 protected CacheKey attemptToAcquireLock(Class objectClass, CacheKey cacheKey, AbstractSession session) { 341 return session.getIdentityMapAccessorInstance().acquireLockNoWait(cacheKey.getKey(), objectClass, true, session.getDescriptor(objectClass)); 342 } 343 344 348 protected CacheKey checkAndLockObject(Object objectToLock, Map lockedObjects, DatabaseMapping mapping, AbstractSession session) { 349 if ((objectToLock != null) && !lockedObjects.containsKey(objectToLock)) { 351 Vector primaryKeysToLock = null; 352 ClassDescriptor referenceDescriptor = null; 353 if (mapping.getReferenceDescriptor().hasInheritance()) { 354 referenceDescriptor = session.getDescriptor(objectToLock); 355 } else { 356 referenceDescriptor = mapping.getReferenceDescriptor(); 357 } 358 if (referenceDescriptor.isAggregateDescriptor() || referenceDescriptor.isAggregateCollectionDescriptor()) { 360 traverseRelatedLocks(objectToLock, lockedObjects, referenceDescriptor, session); 361 } else { 362 primaryKeysToLock = referenceDescriptor.getObjectBuilder().extractPrimaryKeyFromObject(objectToLock, session); 363 CacheKey toWaitOn = acquireLockAndRelatedLocks(objectToLock, lockedObjects, primaryKeysToLock, referenceDescriptor, session); 364 if (toWaitOn != null) { 365 return toWaitOn; 366 } 367 } 368 } 369 return null; 370 } 371 372 376 public void releaseAllAcquiredLocks(MergeManager mergeManager) { 377 if (!MergeManager.LOCK_ON_MERGE) { return; 379 } 380 Iterator locks = mergeManager.getAcquiredLocks().iterator(); 381 while (locks.hasNext()) { 382 CacheKey cacheKeyToRemove = (CacheKey)locks.next(); 383 if (cacheKeyToRemove.getObject() == null && cacheKeyToRemove.getOwningMap() != null){ 384 cacheKeyToRemove.getOwningMap().remove(cacheKeyToRemove); 385 } 386 cacheKeyToRemove.release(); 387 locks.remove(); 388 } 389 } 390 391 396 protected CacheKey waitOnObjectLock(Class objectClass, CacheKey cacheKey, AbstractSession session) { 397 return session.getIdentityMapAccessorInstance().acquireLock(cacheKey.getKey(), objectClass, true, session.getDescriptor(objectClass)); 398 } 399 } 400 | Popular Tags |