001: /**
002: * C-JDBC: Clustered JDBC.
003: * Copyright (C) 2005 Emic Networks
004: * Science And Control (INRIA).
005: * Contact: c-jdbc@objectweb.org
006: *
007: * This library is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as published by the
009: * Free Software Foundation; either version 2.1 of the License, or any later
010: * version.
011: *
012: * This library is distributed in the hope that it will be useful, but WITHOUT
013: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
015: * for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public License
018: * along with this library; if not, write to the Free Software Foundation,
019: * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
020: *
021: * Initial developer(s): Emmanuel Cecchet.
022: * Contributor(s): ______________________.
023: */package org.continuent.sequoia.common.locks;
024:
025: import java.sql.SQLException;
026:
027: import org.continuent.sequoia.common.log.Trace;
028: import org.continuent.sequoia.controller.backend.DatabaseBackend;
029: import org.continuent.sequoia.controller.loadbalancer.BackendTaskQueueEntry;
030: import org.continuent.sequoia.controller.loadbalancer.BackendTaskQueues;
031: import org.continuent.sequoia.controller.virtualdatabase.VirtualDatabase;
032:
033: /**
034: * This class defines a DeadlockDetectionThread that runs periodically to detect
035: * possible deadlocks in the wait for graph of a given database schema.
036: *
037: * @author <a href="mailto:emmanuel.cecchet@emicnetworks.com">Emmanuel Cecchet</a>
038: * @version 1.0
039: */
040: public class DeadlockDetectionThread extends Thread {
041: private DatabaseBackend backend;
042: private VirtualDatabase vdb;
043: private Object dbsLock;
044: private long timeout;
045: private boolean killed = false;
046: private BackendTaskQueues queues;
047: private WaitForGraph waitForGraph;
048: protected static Trace logger = Trace
049: .getLogger("org.continuent.sequoia.controller.loadbalancer");
050:
051: /**
052: * Creates a new <code>DeadlockDetectionThread</code> object
053: *
054: * @param backend the backend we are taking care of
055: * @param vdb virtual database the backend is attached to
056: * @param dbsLock the object on which we can synchronize to prevent database
057: * schema modifications while we are running the deadlock detection
058: * algorithm
059: * @param timeout the time to wait before starting to look for deadlocks
060: */
061: public DeadlockDetectionThread(DatabaseBackend backend,
062: VirtualDatabase vdb, Object dbsLock, long timeout) {
063: super ("Deadlock detection thread");
064: this .backend = backend;
065: this .vdb = vdb;
066: this .dbsLock = dbsLock;
067: this .timeout = timeout;
068: this .queues = backend.getTaskQueues();
069: waitForGraph = new WaitForGraph(backend, queues
070: .getStoredProcedureQueue());
071: }
072:
073: /**
074: * Terminate this thread
075: */
076: public synchronized void kill() {
077: killed = true;
078: notify();
079: }
080:
081: /**
082: * @see java.lang.Thread#run()
083: */
084: public void run() {
085: BackendTaskQueueEntry lastEntry = queues
086: .getFirstConflictingRequestQueueOrStoredProcedureQueueEntry();
087: BackendTaskQueueEntry newEntry;
088: while (!killed) {
089: newEntry = queues
090: .getFirstConflictingRequestQueueOrStoredProcedureQueueEntry();
091: synchronized (this ) {
092: if ((newEntry == null) || (newEntry != lastEntry)) { // Queue empty or queue has changed
093: lastEntry = newEntry;
094: try {
095: wait(timeout);
096: } catch (InterruptedException ignore) {
097: }
098: } else { // Queue seems stucked, it is not empty and we have
099: // newEntry==lastEntry. Let's look for deadlocks
100: boolean deadlockDetected;
101: long tid = 0;
102: synchronized (dbsLock) {
103: deadlockDetected = waitForGraph
104: .detectDeadlocks();
105: if (deadlockDetected) { // Need to abort the transaction
106: tid = waitForGraph.getVictimTransactionId();
107: }
108: // Prevent infinite loop and let's sleep for a while since there
109: // is no one to kill now
110: lastEntry = null;
111: } // synchronized (dbsLock)
112: if (deadlockDetected) {
113: if (logger.isInfoEnabled())
114: logger.info("Deadlock detected on backend "
115: + backend.getName()
116: + ", aborting transaction " + tid);
117:
118: try {
119: // Abort the transaction
120: vdb.abort(tid, true, true);
121: } catch (SQLException e) {
122: logger.warn("Failed to abort transaction "
123: + tid, e);
124: }
125: }
126: } // else
127: } // synchronized
128: } // while
129: }
130:
131: }
|