1 21 22 package org.apache.derby.impl.services.locks; 23 24 import org.apache.derby.iapi.services.locks.Lockable; 25 import org.apache.derby.iapi.services.locks.VirtualLockTable; 26 27 import org.apache.derby.iapi.services.sanity.SanityManager; 28 29 import org.apache.derby.iapi.error.StandardException; 30 import org.apache.derby.iapi.reference.SQLState; 31 32 import org.apache.derby.iapi.sql.conn.LanguageConnectionFactory; 33 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext; 34 import org.apache.derby.iapi.services.context.ContextService; 35 import org.apache.derby.iapi.store.access.TransactionController; 36 import org.apache.derby.iapi.store.access.TransactionInfo; 37 38 import java.util.Hashtable ; 39 import java.util.Enumeration ; 40 import java.util.Dictionary ; 41 import java.util.Stack ; 42 43 import java.util.List ; 44 45 48 49 class Deadlock { 50 51 private Deadlock() {} 52 53 static Object [] look(SinglePool factory, LockSet set, LockControl control, ActiveLock startingLock, byte deadlockWake) { 54 55 Dictionary waiters = Deadlock.getWaiters(set); 57 58 61 65 Stack chain = new Stack (); 66 67 chain.push(startingLock.getCompatabilitySpace()); 68 chain.push(control.getGrants()); 69 outer: for (;;) { 70 71 if (chain.isEmpty()) { 72 break outer; 74 } 75 76 List grants = (List ) chain.peek(); 77 if (grants.isEmpty()) { 78 rollback(chain); 80 continue outer; 81 } 82 int endStack = grants.size() - 1; 83 Object space = ((Lock) grants.get(endStack)).getCompatabilitySpace(); 84 85 for (int gs = 0; gs < endStack; gs++) { 89 if (space.equals(((Lock) grants.get(gs)).getCompatabilitySpace())) { 90 chain.push(space); rollback(chain); 92 continue outer; 93 } 94 } 95 96 inner: for (;;) { 98 int index = chain.indexOf(space); 99 if (index != -1) { 100 101 112 if ((index == (chain.size() - 1)) || 113 ((index == (chain.size() - 2)) 114 && (index == (chain.indexOf(grants) - 1)))) { 115 116 ActiveLock lock = (ActiveLock) waiters.get(space); 118 119 if (lock.canSkip) { 120 chain.push(space); 123 rollback(chain); 124 continue outer; 125 } 126 } 127 128 return Deadlock.handle(factory, chain, index, waiters, deadlockWake); 129 } 130 chain.push(space); 131 132 Lock waitingLock = (Lock) waiters.get(space); 133 if (waitingLock == null) { 134 rollback(chain); 137 continue outer; 138 } 139 140 Object waitOn = waiters.get(waitingLock); 142 if (waitOn instanceof LockControl) { 143 144 LockControl waitOnControl = (LockControl) waitOn; 145 146 151 if (waitOnControl.isUnlocked()) { 152 rollback(chain); 155 continue outer; 156 } 157 158 chain.push(waitOnControl.getGrants()); 159 160 continue outer; 161 } else { 162 space = waitingLock.getCompatabilitySpace(); 164 } 165 } 166 } 167 168 return null; 169 } 170 171 private static void rollback(Stack chain) { 172 do { 173 chain.pop(); 174 if (chain.isEmpty()) 175 return; 176 } while (!(chain.peek() instanceof List )); 177 178 List grants = (List ) chain.peek(); 180 grants.remove(grants.size() - 1); 181 } 182 183 private static Hashtable getWaiters(LockSet set) { 184 185 Hashtable waiters = new Hashtable (set.size() * 2); 186 187 for (Enumeration e = set.elements(); e.hasMoreElements(); ) { 188 189 Control control = (Control) e.nextElement(); 190 191 control.addWaiters(waiters); 192 } 193 194 return waiters; 195 } 196 197 private static Object [] handle(SinglePool factory, Stack chain, int start, Dictionary waiters, byte deadlockWake) { 198 199 202 Object checker = chain.elementAt(0); 203 204 int minLockCount = Integer.MAX_VALUE; 205 Object victim = null; 206 for (int i = start; i < chain.size(); i++) { 207 Object space = chain.elementAt(i); 208 if (space instanceof List ) { 209 continue; 210 } 211 212 if ((checker.equals(space)) && (deadlockWake == Constants.WAITING_LOCK_DEADLOCK)) { 215 victim = checker; 216 break; 217 } 218 219 LockSpace ls = (LockSpace) factory.get(space); 220 if (ls == null) { 221 victim = space; 223 break; 224 } 225 226 int spaceCount = ls.deadlockCount(minLockCount); 227 228 if (spaceCount <= minLockCount) { 229 victim = space; 230 minLockCount = spaceCount; 231 } 232 } 233 234 if (checker.equals(victim)) { 236 Object [] data = new Object [2]; 237 data[0] = chain; 238 data[1] = waiters; 239 return data; 240 } 241 242 ActiveLock victimLock = (ActiveLock) waiters.get(victim); 243 244 victimLock.wakeUp(Constants.WAITING_LOCK_DEADLOCK); 245 246 return null; 247 248 } 249 250 static StandardException buildException(SinglePool factory, Object [] data) { 251 252 Stack chain = (Stack ) data[0]; 253 Dictionary waiters = (Dictionary ) data[1]; 254 255 256 LanguageConnectionContext lcc = (LanguageConnectionContext) 257 ContextService.getContext(LanguageConnectionContext.CONTEXT_ID); 258 259 TableNameInfo tabInfo = null; 260 TransactionInfo[] tt = null; 261 TransactionController tc = null; 262 263 if (lcc != null) { 264 265 try { 266 tc = lcc.getTransactionExecute(); 267 tabInfo = new TableNameInfo(lcc, false); 268 269 tt = lcc.getLanguageConnectionFactory().getAccessFactory().getTransactionInfo(); 270 271 } catch (StandardException se) { 272 } 274 } 275 276 277 StringBuffer sb = new StringBuffer (200); 278 279 Hashtable attributes = new Hashtable (17); 280 281 String victimXID = null; 282 283 for (int i = 0; i < chain.size(); i++) { 284 Object space = chain.elementAt(i); 285 if (space instanceof List ) { 286 List grants = (List ) space; 287 288 if (grants.size() != 0) { 289 290 sb.append(" Granted XID : "); 291 292 for (int j = 0; j < grants.size(); j ++) { 293 294 if (j != 0) 295 sb.append(", "); 296 297 Lock gl = (Lock) grants.get(j); 298 299 sb.append("{"); 300 sb.append(gl.getCompatabilitySpace()); 301 sb.append(", "); 302 sb.append(gl.getQualifier()); 303 sb.append("} "); 304 } 305 sb.append('\n'); 306 } 307 continue; 308 } 309 Lock lock = ((Lock) waiters.get(space)); 312 313 lock.getLockable().lockAttributes(VirtualLockTable.ALL, attributes); 315 316 addInfo(sb, "Lock : ", attributes.get(VirtualLockTable.LOCKTYPE)); 317 if (tabInfo != null) { 318 Long conglomId = (Long ) attributes.get(VirtualLockTable.CONGLOMID); 319 if (conglomId == null) { 320 Long containerId = (Long ) attributes.get(VirtualLockTable.CONTAINERID); 321 try { 322 conglomId = new Long (tc.findConglomid(containerId.longValue())); 323 } catch (StandardException se) { 324 } 325 } 326 addInfo(sb, ", ", tabInfo.getTableName(conglomId)); 327 } 328 addInfo(sb, ", ", attributes.get(VirtualLockTable.LOCKNAME)); 329 sb.append('\n'); 330 331 String xid = space.toString(); 332 if (i == 0) 333 victimXID = xid; 334 335 336 addInfo(sb, " Waiting XID : {", xid); 337 addInfo(sb, ", ", lock.getQualifier()); 338 sb.append("} "); 339 if (tt != null) { 340 for (int tti = tt.length - 1; tti >= 0; tti--) { 341 TransactionInfo ti = tt[tti]; 342 343 if (ti != null) 346 { 347 String idString = ti.getTransactionIdString(); 348 349 if (idString != null && idString.equals(xid)) { 350 351 addInfo(sb, ", ", ti.getUsernameString()); 352 addInfo(sb, ", ", ti.getStatementTextString()); 353 break; 354 } 355 } 356 } 357 } 358 sb.append('\n'); 359 360 attributes.clear(); 361 } 362 363 StandardException se = StandardException.newException(SQLState.DEADLOCK, sb.toString(), victimXID); 364 se.setReport(factory.deadlockMonitor); 365 return se; 366 } 367 368 private static void addInfo(StringBuffer sb, String desc, Object data) { 369 sb.append(desc); 370 if (data == null) 371 data = "?"; 372 sb.append(data); 373 } 374 375 } 376 | Popular Tags |