001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.objectserver.lockmanager.impl;
006:
007: import com.tc.net.groups.NodeID;
008: import com.tc.object.lockmanager.api.ServerThreadID;
009: import com.tc.object.lockmanager.api.ThreadID;
010: import com.tc.util.Assert;
011:
012: import java.util.HashSet;
013: import java.util.Set;
014:
015: /**
016: * This class represents a "open" transaction (ie. one that holds locks). It's only purpose is to hold the proper
017: * bookkeeping to do reasonably fast deadlock detection. Some day this might get merged with some of form of higher
018: * level server transaction class, but that really doesn't exist yet
019: */
020: class ServerThreadContext {
021: static final ServerThreadContext NULL_CONTEXT = new ServerThreadContext(
022: ServerThreadID.NULL_ID);
023:
024: private final static Lock[] EMPTY_LOCK_ARRAY = new Lock[] {};
025: private final boolean isNull;
026: private final Set locksHeld = new HashSet();
027: private final ServerThreadID id;
028: private ServerThreadContext cycle;
029: private Lock waitingOn = null;
030: private final int hashcode;
031:
032: ServerThreadContext(NodeID nid, ThreadID threadID) {
033: this (new ServerThreadID(nid, threadID));
034: }
035:
036: ServerThreadContext(ServerThreadID id2) {
037: Assert.assertNotNull(id2);
038: this .id = id2;
039: this .isNull = ServerThreadID.NULL_ID.equals(id2);
040: this .hashcode = this .id.hashCode();
041: }
042:
043: public String toString() {
044: return "ServerThreadContext@" + System.identityHashCode(this )
045: + "[" + id + "](HELD-LOCKS={" + locksHeld
046: + "}, WAITING-ON={ " + waitingOn + "})";
047: }
048:
049: public int hashCode() {
050: return this .hashcode;
051: }
052:
053: public boolean equals(Object obj) {
054: if (obj instanceof ServerThreadContext) {
055: ServerThreadContext other = (ServerThreadContext) obj;
056: return this .id.equals(other.id);
057: }
058: return false;
059: }
060:
061: public ServerThreadID getId() {
062: return this .id;
063: }
064:
065: synchronized void addLock(Lock lock) {
066: boolean added = locksHeld.add(lock);
067: if (!added) {
068: throw new AssertionError("Lock : " + lock
069: + " is already held : " + this );
070: }
071: clearWaitingOn();
072: }
073:
074: synchronized boolean removeLock(Lock lock) {
075: boolean removed = locksHeld.remove(lock);
076: if (!removed) {
077: throw new AssertionError(
078: lock
079: + " : This lock is not held in this ServerThreadContext ! Locks Held = "
080: + locksHeld);
081: }
082: return isClear();
083: }
084:
085: synchronized boolean isWaiting() {
086: return this .waitingOn != null;
087: }
088:
089: synchronized void setWaitingOn(Lock lock) {
090: if (!(this .waitingOn == null || !this .waitingOn.equals(lock))) {
091: throw new AssertionError("Assert Failed : " + toString()
092: + " : old = " + waitingOn + " : new = " + lock);
093: }
094: this .waitingOn = lock;
095: }
096:
097: synchronized boolean clearWaitingOn() {
098: this .waitingOn = null;
099: return isClear();
100: }
101:
102: synchronized boolean isClear() {
103: return this .waitingOn == null && this .locksHeld.isEmpty();
104: }
105:
106: synchronized Lock[] getLocksHeld() {
107: return (Lock[]) this .locksHeld.toArray(EMPTY_LOCK_ARRAY);
108: }
109:
110: synchronized Lock getWaitingOn() {
111: return this .waitingOn;
112: }
113:
114: // Deadlock cycle stuff. These methods not syncrhonized, only one thread will ever set/read
115: void setCycle(ServerThreadContext other) {
116: this .cycle = other;
117: }
118:
119: // Deadlock cycle stuff. These methods not syncrhonized, only one thread will ever set/read
120: ServerThreadContext getCycle() {
121: return this .cycle;
122: }
123:
124: public boolean isNull() {
125: return isNull;
126: }
127:
128: }
|