1 package org.jboss.cache.lock; 2 3 import org.apache.commons.logging.Log; 4 import org.apache.commons.logging.LogFactory; 5 import org.jboss.cache.CacheImpl; 6 import org.jboss.cache.GlobalTransaction; 7 import org.jboss.cache.Node; 8 import org.jboss.cache.NodeSPI; 9 import org.jboss.cache.TransactionTable; 10 import org.jboss.cache.statetransfer.StateTransferManager; 11 12 import javax.transaction.Status ; 13 import javax.transaction.Transaction ; 14 import javax.transaction.TransactionManager ; 15 import java.util.Iterator ; 16 17 public abstract class LockUtil 18 { 19 private final static Log log = LogFactory.getLog(StateTransferManager.class); 20 21 private static interface TransactionLockStatus extends Status 22 { 23 public static final int STATUS_BROKEN = Integer.MIN_VALUE; 24 } 25 26 public static boolean breakTransactionLock(NodeLock lock, 27 GlobalTransaction gtx, 28 boolean localTx, 29 CacheImpl cache) 30 { 31 TransactionTable tx_table = cache.getTransactionTable(); 32 TransactionManager tm = cache.getTransactionManager(); 33 34 boolean broken = false; 35 int tryCount = 0; 36 int lastStatus = TransactionLockStatus.STATUS_BROKEN; 37 38 while (!broken && lock.isOwner(gtx)) 39 { 40 int status = breakTransactionLock(gtx, lock, tx_table, tm, localTx, lastStatus, tryCount); 41 if (status == TransactionLockStatus.STATUS_BROKEN) 42 { 43 broken = true; 44 } 45 else if (status != lastStatus) 46 { 47 tryCount = 0; 48 } 49 lastStatus = status; 50 51 tryCount++; 52 } 53 54 return broken; 55 } 56 57 68 public static void forceAcquireLock(NodeSPI node, 69 Object newOwner, 70 CacheImpl cache, 71 boolean lockChildren) 72 { 73 74 NodeLock lock = node.getLock(); 75 boolean acquired = lock.isOwner(newOwner); 76 77 if (!acquired && log.isDebugEnabled()) 78 { 79 log.debug("Force acquiring lock on node " + node.getFqn()); 80 } 81 82 TransactionTable tx_table = cache.getTransactionTable(); 83 TransactionManager tm = cache.getTransactionManager(); 84 Object localAddress = cache.getLocalAddress(); 85 boolean serializable = cache.getConfiguration().getIsolationLevel() == IsolationLevel.SERIALIZABLE; 86 87 while (!acquired) 88 { 89 Object curOwner = null; 90 boolean attempted = false; 91 92 while (!acquired && ((curOwner = lock.getWriterOwner()) != null)) 95 { 96 acquired = acquireLockFromOwner(node, lock, curOwner, newOwner, tx_table, tm, localAddress); 97 attempted = true; 98 } 99 100 if (!acquired && serializable) 103 { 104 Iterator it = lock.getReaderOwners().iterator(); 105 if (it.hasNext()) 106 { 107 curOwner = it.next(); 108 acquired = acquireLockFromOwner(node, lock, curOwner, newOwner, tx_table, tm, localAddress); 109 attempted = true; 110 } 114 } 115 116 if (!acquired && !attempted) 117 { 118 try 121 { 122 acquired = lock.acquire(newOwner, 1, NodeLock.LockType.READ); 123 } 124 catch (Exception ignored) 125 { 126 } 127 } 128 } 129 130 if (lockChildren) 132 { 133 for (NodeSPI n : node.getChildrenDirect()) 134 { 135 forceAcquireLock(n, newOwner, cache, true); 136 } 137 } 138 } 139 140 150 private static boolean acquireLockFromOwner(Node node, 151 NodeLock lock, 152 Object curOwner, 153 Object newOwner, 154 TransactionTable tx_table, 155 TransactionManager tm, 156 Object localAddress) 157 { 158 if (log.isTraceEnabled()) 159 { 160 log.trace("Attempting to acquire lock for node " + node.getFqn() + 161 " from owner " + curOwner); 162 } 163 164 boolean acquired = false; 165 boolean broken = false; 166 int tryCount = 0; 167 int lastStatus = TransactionLockStatus.STATUS_BROKEN; 168 169 while (!broken && !acquired) 170 { 171 if (curOwner instanceof GlobalTransaction) 172 { 173 GlobalTransaction gtx = (GlobalTransaction) curOwner; 174 boolean local = gtx.getAddress().equals(localAddress); 175 int status = breakTransactionLock(gtx, lock, tx_table, tm, local, lastStatus, tryCount); 176 if (status == TransactionLockStatus.STATUS_BROKEN) 177 { 178 broken = true; 179 } 180 else if (status != lastStatus) 181 { 182 tryCount = 0; 183 } 184 lastStatus = status; 185 } 186 else if (tryCount > 0) 187 { 188 lock.release(curOwner); 189 broken = true; 190 } 191 192 if (broken && log.isTraceEnabled()) 193 { 194 log.trace("Broke lock for node " + node.getFqn() + 195 " held by owner " + curOwner); 196 } 197 198 try 199 { 200 acquired = lock.acquire(newOwner, 1, NodeLock.LockType.READ); 201 } 202 catch (Exception ignore) 203 { 204 } 205 206 tryCount++; 207 } 208 209 return acquired; 210 } 211 212 237 private static int breakTransactionLock(GlobalTransaction gtx, 238 NodeLock lock, 239 TransactionTable tx_table, 240 TransactionManager tm, 241 boolean localTx, 242 int lastStatus, 243 int tryCount) 244 { 245 int status = Status.STATUS_UNKNOWN; 246 Transaction tx = tx_table.getLocalTransaction(gtx); 247 if (tx != null) 248 { 249 try 250 { 251 status = tx.getStatus(); 252 253 if (status != lastStatus) 254 { 255 tryCount = 0; 256 } 257 258 switch (status) 259 { 260 case Status.STATUS_ACTIVE: 261 case Status.STATUS_MARKED_ROLLBACK: 262 case Status.STATUS_PREPARING: 263 case Status.STATUS_UNKNOWN: 264 if (tryCount == 0) 265 { 266 if (log.isTraceEnabled()) 267 { 268 log.trace("Attempting to break transaction lock held " + 269 " by " + gtx + " by rolling back local tx"); 270 } 271 tm.resume(tx); 273 try 274 { 275 tx.rollback(); 276 } 277 finally 278 { 279 tm.suspend(); 280 } 281 282 } 283 else if (tryCount > 100) 284 { 285 lock.release(gtx); 288 status = TransactionLockStatus.STATUS_BROKEN; 289 } 290 break; 291 292 case Status.STATUS_COMMITTING: 293 case Status.STATUS_ROLLING_BACK: 294 if (tryCount < 10) 296 { 297 break; } 299 301 case Status.STATUS_COMMITTED: 302 case Status.STATUS_ROLLEDBACK: 303 case Status.STATUS_NO_TRANSACTION: 304 lock.release(gtx); 305 status = TransactionLockStatus.STATUS_BROKEN; 306 break; 307 308 case Status.STATUS_PREPARED: 309 if (tryCount == 0 && localTx) 313 { 314 if (log.isTraceEnabled()) 316 { 317 log.trace("Attempting to break transaction lock held " + 318 "by " + gtx + " by marking local tx as " + 319 "rollback-only"); 320 } 321 tx.setRollbackOnly(); 322 break; 323 } 324 else if (tryCount < 10) 325 { 326 break; 332 } 333 334 default: 336 lock.release(gtx); 337 status = TransactionLockStatus.STATUS_BROKEN; 338 } 339 } 340 catch (Exception e) 341 { 342 log.error("Exception breaking locks held by " + gtx, e); 343 lock.release(gtx); 344 status = TransactionLockStatus.STATUS_BROKEN; 345 } 346 } 347 else 348 { 349 if (gtx == lock.getWriterOwner() 352 || lock.getReaderOwners().contains(gtx)) 353 { 354 lock.release(gtx); 356 status = TransactionLockStatus.STATUS_BROKEN; 357 } 358 } 359 360 return status; 361 } 362 363 } 364 | Popular Tags |