/** Do the real work of dumpLockTableInternal. */ void dumpLockTableInternal(StatGroup tableStats, int i, boolean clear) { StatGroup oneTable = new StatGroup("Single lock table", "Temporary stat group"); IntStat totalLocks = new IntStat(oneTable, LOCK_TOTAL); IntStat waiters = new IntStat(oneTable, LOCK_WAITERS); IntStat owners = new IntStat(oneTable, LOCK_OWNERS); IntStat readLocks = new IntStat(oneTable, LOCK_READ_LOCKS); IntStat writeLocks = new IntStat(oneTable, LOCK_WRITE_LOCKS); Map<Long, Lock> lockTable = lockTables[i]; totalLocks.add(lockTable.size()); for (Lock lock : lockTable.values()) { waiters.add(lock.nWaiters()); owners.add(lock.nOwners()); /* Go through all the owners for a lock. */ for (LockInfo info : lock.getOwnersClone()) { if (info.getLockType().isWriteLock()) { writeLocks.increment(); } else { readLocks.increment(); } } } tableStats.addAll(oneTable); }
private StringBuilder findDeadlock1(Set<Locker> ownerSet, Lock lock, Locker rootLocker) { Iterator<LockInfo> ownerIter = lock.getOwnersClone().iterator(); while (ownerIter.hasNext()) { LockInfo info = ownerIter.next(); Locker locker = info.getLocker(); Lock waitsFor = locker.getWaitingFor(); if (ownerSet.contains(locker) || locker == rootLocker) { /* Found a cycle. */ StringBuilder ret = new StringBuilder(); ret.append("Transaction ").append(locker.toString()); ret.append(" owns LockAddr:").append(System.identityHashCode(lock)); ret.append(" ").append(info).append("\n"); ret.append("Transaction ").append(locker.toString()); ret.append(" waits for"); if (waitsFor == null) { ret.append(" nothing"); } else { ret.append(" LockAddr:"); ret.append(System.identityHashCode(waitsFor)); } ret.append("\n"); return ret; } if (waitsFor != null) { ownerSet.add(locker); StringBuilder sb = findDeadlock1(ownerSet, waitsFor, rootLocker); if (sb != null) { String waitInfo = "Transaction " + locker + " waits for " + waitsFor + "\n"; sb.insert(0, waitInfo); return sb; } ownerSet.remove(locker); // is this necessary? } } return null; }
/** Do the real work of creating an lock or txn timeout message. */ LockConflictException makeTimeoutMsgInternal( boolean isLockNotTxnTimeout, Locker locker, long nodeId, LockType type, LockGrantType grantType, Lock useLock, long timeout, long start, long now, DatabaseImpl database) { /* * Because we're accessing parts of the lock, need to have protected * access to the lock table because things can be changing out from * underneath us. This is a big hammer to grab for so long while we * traverse the graph, but it's only when we have a deadlock and we're * creating a debugging message. * * The alternative would be to handle ConcurrentModificationExceptions * and retry until none of them happen. */ if (lockTableDump) { System.out.println("++++++++++ begin lock table dump ++++++++++"); for (int i = 0; i < nLockTables; i++) { boolean success = false; for (int j = 0; j < 3 && !success; j++) { try { StringBuilder sb = new StringBuilder(); dumpToStringNoLatch(sb, i); System.out.println(sb.toString()); success = true; break; // for j... } catch (ConcurrentModificationException CME) { continue; } } if (!success) { System.out.println("Couldn't dump locktable " + i); } } System.out.println("++++++++++ end lock table dump ++++++++++"); } StringBuilder sb = new StringBuilder(); sb.append(isLockNotTxnTimeout ? "Lock" : "Transaction"); sb.append(" expired. Locker ").append(locker); sb.append(": waited for lock"); if (database != null) { sb.append(" on database=").append(database.getDebugName()); } sb.append(" LockAddr:").append(System.identityHashCode(useLock)); sb.append(" node=").append(nodeId); sb.append(" type=").append(type); sb.append(" grant=").append(grantType); sb.append(" timeoutMillis=").append(timeout); sb.append(" startTime=").append(start); sb.append(" endTime=").append(now); Set<LockInfo> owners = useLock.getOwnersClone(); List<LockInfo> waiters = useLock.getWaitersListClone(); sb.append("\nOwners: ").append(owners); sb.append("\nWaiters: ").append(waiters).append("\n"); StringBuilder deadlockInfo = findDeadlock(useLock, locker); if (deadlockInfo != null) { sb.append(deadlockInfo); } LockConflictException ret = isLockNotTxnTimeout ? newLockTimeoutException(locker, sb.toString()) : newTxnTimeoutException(locker, sb.toString()); ret.setOwnerTxnIds(getTxnIds(owners)); ret.setWaiterTxnIds(getTxnIds(waiters)); ret.setTimeoutMillis(timeout); return ret; }