From: <an...@us...> - 2009-09-08 12:06:45
|
Revision: 9843 http://wonder.svn.sourceforge.net/wonder/?rev=9843&view=rev Author: anjo Date: 2009-09-08 12:06:39 +0000 (Tue, 08 Sep 2009) Log Message: ----------- the DBC normally uses the lock form the OSC, so we move the lock tracing there Modified Paths: -------------- trunk/Wonder/Frameworks/Core/ERExtensions/Sources/er/extensions/eof/ERXObjectStoreCoordinator.java Modified: trunk/Wonder/Frameworks/Core/ERExtensions/Sources/er/extensions/eof/ERXObjectStoreCoordinator.java =================================================================== --- trunk/Wonder/Frameworks/Core/ERExtensions/Sources/er/extensions/eof/ERXObjectStoreCoordinator.java 2009-09-08 12:06:00 UTC (rev 9842) +++ trunk/Wonder/Frameworks/Core/ERExtensions/Sources/er/extensions/eof/ERXObjectStoreCoordinator.java 2009-09-08 12:06:39 UTC (rev 9843) @@ -1,20 +1,41 @@ package er.extensions.eof; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Collections; +import java.util.Map; +import java.util.WeakHashMap; + import org.apache.log4j.Logger; +import sun.misc.Signal; +import sun.misc.SignalHandler; + import com.webobjects.eocontrol.EOCooperatingObjectStore; import com.webobjects.eocontrol.EOObjectStoreCoordinator; +import com.webobjects.foundation.NSMutableArray; +import com.webobjects.foundation.NSMutableDictionary; /** + * Adds functionality to automatically close all related JDBC Connections. Also has open-lock debugging. * @author david - * - * Adds functionality to automatically close all related JDBC Connections. + * @author ak */ public class ERXObjectStoreCoordinator extends EOObjectStoreCoordinator { + public static Logger log = Logger.getLogger(ERXObjectStoreCoordinator.class); + NSMutableDictionary<Thread, NSMutableArray<Exception>> openLockTraces; + + Thread lockingThread; + + protected static Map<ERXObjectStoreCoordinator, String> activeDatabaseContexts = Collections.synchronizedMap(new WeakHashMap()); + + private long lockCount = 0; + public boolean _didClose = false; + public boolean _shouldClose = false; /** @@ -23,6 +44,9 @@ */ public ERXObjectStoreCoordinator() { super(); + if (ERXEC.traceOpenLocks()) { + activeDatabaseContexts.put(this, Thread.currentThread().getName()); + } } public ERXObjectStoreCoordinator(boolean shouldClose) { @@ -30,6 +54,77 @@ _shouldClose = shouldClose; } + /** + * Adds the current stack trace to openLockTraces. + */ + private synchronized void traceLock() { + if(openLockTraces == null) { + openLockTraces = new NSMutableDictionary<Thread, NSMutableArray<Exception>>(); + } + Exception openLockTrace = new Exception("Locked"); + openLockTrace.fillInStackTrace(); + Thread currentThread = Thread.currentThread(); + NSMutableArray<Exception> currentTraces = openLockTraces.objectForKey(currentThread); + if(currentTraces == null) { + currentTraces = new NSMutableArray<Exception>(); + openLockTraces.setObjectForKey(currentTraces, currentThread); + } + currentTraces.addObject(openLockTrace); + } + + /** + * Removes the current trace from the openLockTraces. + */ + private synchronized void traceUnlock() { + if (openLockTraces != null) { + NSMutableArray<Exception> traces = openLockTraces.objectForKey(lockingThread); + if(traces != null) { + //log.error("unlock: " + lockingThread); + traces.removeLastObject(); + + if (traces.count() == 0) { + openLockTraces.removeObjectForKey(lockingThread); + } + } else { + log.error("Missing lock: " + lockingThread); + } + if (openLockTraces.count() == 0) { + openLockTraces = null; + } + } + if(lockCount == 0) { + lockingThread = null; + } + } + + /** + * Overridden to emit log messages and push this instance to the locked + * editing contexts in this thread. + */ + public void lock() { + boolean tracing = ERXEC.traceOpenLocks(); + if (tracing) { + traceLock(); + } + super.lock(); + lockCount++; + lockingThread = Thread.currentThread(); + //log.error("locked: " + lockingThread); + } + + /** + * Overridden to emit log messages and pull this instance from the locked + * editing contexts in this thread. + */ + public void unlock() { + lockCount--; + if (ERXEC.traceOpenLocks()) { + traceUnlock(); + } + super.unlock(); + } + + @Override public void addCooperatingObjectStore(EOCooperatingObjectStore objectStore) { if (cooperatingObjectStores().indexOfIdenticalObject(objectStore) < 0) { @@ -50,4 +145,35 @@ } super.dispose(); } + + public static String outstandingLockDescription() { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + boolean hadLocks = false; + for (ERXObjectStoreCoordinator ec : activeDatabaseContexts.keySet()) { + NSMutableDictionary<Thread, NSMutableArray<Exception>> traces = ec.openLockTraces; + if (traces != null && traces.count() > 0) { + hadLocks = true; + pw.println("\n------------------------"); + pw.println("ObjectStoreCoordinator: " + ec + " Locking thread: " + ec.lockingThread); + for (Thread thread : traces.keySet()) { + pw.println("@" + thread); + for(Exception ex: traces.objectForKey(thread)) { + ex.printStackTrace(pw); + } + } + } + } + if(!hadLocks) { + pw.print("No open ObjectStoreCoordinator (of " + activeDatabaseContexts.size() + ")"); + } + pw.close(); + return sw.toString(); + } + + public static class DumpLocksSignalHandler implements SignalHandler { + public void handle(Signal signal) { + log.info(outstandingLockDescription()); + } + } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |