Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / MyDerby-10.3 / java / engine / org / apache / derby / impl / services / locks / LockSet.java
diff --git a/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/services/locks/LockSet.java b/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/services/locks/LockSet.java
new file mode 100644 (file)
index 0000000..f7aaf97
--- /dev/null
@@ -0,0 +1,788 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.services.locks.LockSet\r
+\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to you under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+      http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.impl.services.locks;\r
+\r
+import org.apache.derby.iapi.services.locks.CompatibilitySpace;\r
+import org.apache.derby.iapi.services.locks.Latch;\r
+import org.apache.derby.iapi.services.locks.Lockable;\r
+import org.apache.derby.iapi.services.locks.C_LockFactory;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.services.diag.DiagnosticUtil;\r
+\r
+import org.apache.derby.iapi.reference.Property;\r
+import org.apache.derby.iapi.reference.SQLState;\r
+\r
+import java.util.HashMap;\r
+import java.util.Enumeration;\r
+import java.util.Iterator;\r
+import java.util.Map;\r
+\r
+\r
+/**\r
+       A LockSet is a complete lock table.     A lock table is a hash table\r
+       keyed by a Lockable and with a LockControl as the data element.\r
+\r
+       <P>\r
+       A LockControl contains information about the locks held on a Lockable.\r
+\r
+       <BR>\r
+       MT - Mutable - Container Object : All non-private methods of this class are\r
+       thread safe unless otherwise stated by their javadoc comments.\r
+\r
+       <BR>\r
+       All searching of\r
+    the hashtable is performed using java synchroization(this).\r
+       <BR>\r
+       The class creates ActiveLock and LockControl objects.\r
+       \r
+       LockControl objects are never passed out of this class, All the methods of \r
+    LockControl are called while being synchronized on this, thus providing the\r
+    single threading that LockControl required.\r
+\r
+       Methods of Lockables are only called by this class or LockControl, and \r
+    always while being synchronized on this, thus providing the single \r
+    threading that Lockable requires.\r
+       \r
+       @see LockControl\r
+*/\r
+\r
+final class LockSet implements LockTable {\r
+       /*\r
+       ** Fields\r
+       */\r
+       private final SinglePool factory;\r
+\r
+    /** Hash table which maps <code>Lockable</code> objects to\r
+     * <code>Lock</code>s. */\r
+    private final HashMap locks;\r
+\r
+       /**\r
+               Timeout for deadlocks, in ms.\r
+               <BR>\r
+               MT - immutable\r
+       */\r
+       private int deadlockTimeout = Property.DEADLOCK_TIMEOUT_DEFAULT * 1000;\r
+       private int waitTimeout = Property.WAIT_TIMEOUT_DEFAULT * 1000;\r
+\r
+//EXCLUDE-START-lockdiag- \r
+\r
+       // this varible is set and get without synchronization.  \r
+       // Only one thread should be setting it at one time.\r
+       private boolean deadlockTrace;\r
+\r
+//EXCLUDE-END-lockdiag- \r
+\r
+       // The number of waiters for locks\r
+       private int blockCount;\r
+\r
+       /*\r
+       ** Constructor\r
+       */\r
+\r
+       protected LockSet(SinglePool factory) {\r
+               this.factory = factory;\r
+               locks = new HashMap();\r
+       }\r
+\r
+\r
+       /*\r
+       ** Public Methods\r
+       */\r
+\r
+       /**\r
+        *      Lock an object within a specific compatibility space.\r
+        *\r
+        *      @param  compatibilitySpace Compatibility space.\r
+        *      @param  ref Lockable reference.\r
+        *      @param  qualifier Qualifier.\r
+        *      @param  timeout Timeout in milli-seconds\r
+        *\r
+        *      @return Object that represents the lock.\r
+        *\r
+        *      @exception      StandardException Standard Derby policy.\r
+\r
+       */\r
+       public Lock lockObject(CompatibilitySpace compatibilitySpace, Lockable ref,\r
+                                                  Object qualifier, int timeout)\r
+               throws StandardException\r
+       {               \r
+               if (SanityManager.DEBUG) {\r
+\r
+                       if (SanityManager.DEBUG_ON("memoryLeakTrace")) {\r
+\r
+                               if (locks.size() > 1000)\r
+                                       System.out.println("memoryLeakTrace:LockSet: " +\r
+                                           locks.size());\r
+                       }\r
+               }\r
+\r
+               Control gc;\r
+               LockControl control;\r
+               Lock lockItem;\r
+        String  lockDebug = null;\r
+\r
+               synchronized (this) {\r
+\r
+                       gc = getControl(ref);\r
+\r
+                       if (gc == null) {\r
+\r
+                               // object is not locked, can be granted\r
+                               Lock gl = new Lock(compatibilitySpace, ref, qualifier);\r
+\r
+                               gl.grant();\r
+\r
+                               locks.put(ref, gl);\r
+\r
+                               return gl;\r
+                       }\r
+\r
+                       control = gc.getLockControl();\r
+                       if (control != gc) {\r
+                               locks.put(ref, control);\r
+                       }\r
+                       \r
+\r
+                       if (SanityManager.DEBUG) {\r
+                               SanityManager.ASSERT(ref.equals(control.getLockable()));\r
+\r
+                               // ASSERT item is in the list\r
+                if (getControl(control.getLockable()) != control)\r
+                {\r
+                                       SanityManager.THROWASSERT(\r
+                        "lockObject mismatched lock items " + \r
+                        getControl(control.getLockable()) + " " + control);\r
+                }\r
+                       }\r
+\r
+                       lockItem = control.addLock(this, compatibilitySpace, qualifier);\r
+\r
+                       if (lockItem.getCount() != 0) {\r
+                               return lockItem;\r
+                       }\r
+\r
+                       if (timeout == C_LockFactory.NO_WAIT) {\r
+\r
+                       // remove all trace of lock\r
+                       control.giveUpWait(lockItem, this);\r
+\r
+                if (SanityManager.DEBUG) \r
+                {\r
+                    if (SanityManager.DEBUG_ON("DeadlockTrace"))\r
+                    {\r
+\r
+                        SanityManager.showTrace(new Throwable());\r
+\r
+                        // The following dumps the lock table as it \r
+                        // exists at the time a timeout is about to \r
+                        // cause a deadlock exception to be thrown.\r
+\r
+                        lockDebug = \r
+                            DiagnosticUtil.toDiagString(lockItem)   +\r
+                            "\nCould not grant lock with zero timeout, here's the table" +\r
+                            this.toDebugString();\r
+                    }\r
+                }\r
+\r
+                               return null;\r
+                       }\r
+\r
+               } // synchronized block\r
+\r
+               boolean deadlockWait = false;\r
+               int actualTimeout;\r
+\r
+               if (timeout == C_LockFactory.WAIT_FOREVER)\r
+               {\r
+                       // always check for deadlocks as there should not be any\r
+                       deadlockWait = true;\r
+                       if ((actualTimeout = deadlockTimeout) == C_LockFactory.WAIT_FOREVER)\r
+                               actualTimeout = Property.DEADLOCK_TIMEOUT_DEFAULT * 1000;\r
+               }\r
+               else\r
+               {\r
+\r
+                       if (timeout == C_LockFactory.TIMED_WAIT)\r
+                               timeout = actualTimeout = waitTimeout;\r
+                       else\r
+                               actualTimeout = timeout;\r
+\r
+\r
+                       // five posible cases\r
+                       // i)   timeout -1, deadlock -1         -> \r
+            //          just wait forever, no deadlock check\r
+                       // ii)  timeout >= 0, deadlock -1       -> \r
+            //          just wait for timeout, no deadlock check\r
+                       // iii) timeout -1, deadlock >= 0       -> \r
+            //          wait for deadlock, then deadlock check, \r
+            //          then infinite timeout\r
+                       // iv)  timeout >=0, deadlock < timeout -> \r
+            //          wait for deadlock, then deadlock check, \r
+            //          then wait for (timeout - deadlock)\r
+                       // v)   timeout >=0, deadlock >= timeout -> \r
+            //          just wait for timeout, no deadlock check\r
+\r
+\r
+                       if (deadlockTimeout >= 0) {\r
+\r
+                               if (actualTimeout < 0) {\r
+                                       // infinite wait but perform a deadlock check first\r
+                                       deadlockWait = true;\r
+                                       actualTimeout = deadlockTimeout;\r
+                               } else if (deadlockTimeout < actualTimeout) {\r
+\r
+                                       // deadlock wait followed by a timeout wait\r
+\r
+                                       deadlockWait = true;\r
+                                       actualTimeout = deadlockTimeout;\r
+\r
+                                       // leave timeout as the remaining time\r
+                                       timeout -= deadlockTimeout;\r
+                               }\r
+                       }\r
+               }\r
+\r
+\r
+        ActiveLock waitingLock = (ActiveLock) lockItem;\r
+        lockItem = null;\r
+\r
+        int earlyWakeupCount = 0;\r
+        long startWaitTime = 0;\r
+\r
+forever:       for (;;) {\r
+\r
+                byte wakeupReason = waitingLock.waitForGrant(actualTimeout);\r
+                \r
+                ActiveLock nextWaitingLock = null;\r
+                Object[] deadlockData = null;\r
+\r
+                try {\r
+                    boolean willQuitWait;\r
+                    Enumeration timeoutLockTable = null;\r
+                    long currentTime = 0;\r
+        \r
+                    synchronized (this) {\r
+\r
+                        if (control.isGrantable(\r
+                                control.firstWaiter() == waitingLock,\r
+                                compatibilitySpace,\r
+                                qualifier)) {\r
+\r
+                            // Yes, we are granted, put us on the granted queue.\r
+                            control.grant(waitingLock);\r
+\r
+                            // Remove from the waiting queue & get next waiter\r
+                            nextWaitingLock = \r
+                                control.getNextWaiter(waitingLock, true, this);\r
+\r
+                            return waitingLock;\r
+                        }\r
+\r
+                        // try again later\r
+                        waitingLock.clearPotentiallyGranted(); \r
+\r
+                        willQuitWait = \r
+                            (wakeupReason != Constants.WAITING_LOCK_GRANT);\r
+\r
+                        if (((wakeupReason == Constants.WAITING_LOCK_IN_WAIT) &&\r
+                                    deadlockWait) ||\r
+                            (wakeupReason == Constants.WAITING_LOCK_DEADLOCK))\r
+                        {\r
+\r
+                            // check for a deadlock, even if we were woken up \r
+                            // because we were selected as a victim we still \r
+                            // check because the situation may have changed.\r
+                            deadlockData = \r
+                                Deadlock.look(\r
+                                    factory, this, control, waitingLock, \r
+                                    wakeupReason);\r
+\r
+                            if (deadlockData == null) {\r
+                                // we don't have a deadlock\r
+                                deadlockWait = false;\r
+\r
+                                actualTimeout = timeout;\r
+                                startWaitTime = 0;\r
+                                willQuitWait = false;\r
+                            } else {\r
+                                willQuitWait = true;\r
+                            }\r
+                        }\r
+\r
+                        nextWaitingLock = \r
+                            control.getNextWaiter(\r
+                                waitingLock, willQuitWait, this);\r
+\r
+\r
+                        // If we were not woken by another then we have\r
+                        // timed out. Either deadlock out or timeout\r
+                        if (willQuitWait) {\r
+\r
+                            if (SanityManager.DEBUG) \r
+                            {\r
+                                if (SanityManager.DEBUG_ON("DeadlockTrace"))\r
+                                {\r
+\r
+                                    SanityManager.showTrace(new Throwable());\r
+\r
+                                    // The following dumps the lock table as it \r
+                                    // exists at the time a timeout is about to \r
+                                    // cause a deadlock exception to be thrown.\r
+\r
+                                    lockDebug = \r
+                                    DiagnosticUtil.toDiagString(waitingLock)   +\r
+                                    "\nGot deadlock/timeout, here's the table" +\r
+                                    this.toDebugString();\r
+                                }\r
+                            }\r
+                            \r
+                            if (deadlockTrace && (deadlockData == null))\r
+                            {\r
+                                // if ending lock request due to lock timeout\r
+                                // want a copy of the LockTable and the time,\r
+                                // in case of deadlock deadlockData has the\r
+                                // info we need.\r
+                                currentTime = System.currentTimeMillis(); \r
+                                timeoutLockTable = \r
+                                    factory.makeVirtualLockTable();\r
+                            }\r
+                        }\r
+\r
+                    } // synchronized block\r
+\r
+                    // need to do this outside of the synchronized block as the\r
+                    // message text building (timeouts and deadlocks) may \r
+                    // involve getting locks to look up table names from \r
+                    // identifiers.\r
+\r
+                    if (willQuitWait)\r
+                    {\r
+                        if (SanityManager.DEBUG)\r
+                        {\r
+                            if (lockDebug != null)\r
+                            {\r
+                                String type = \r
+                                    ((deadlockData != null) ? \r
+                                         "deadlock:" : "timeout:"); \r
+\r
+                                SanityManager.DEBUG_PRINT(\r
+                                    type,\r
+                                    "wait on lockitem caused " + type + \r
+                                    lockDebug);\r
+                            }\r
+\r
+                        }\r
+\r
+                        if (deadlockData == null)\r
+                        {\r
+                            // ending wait because of lock timeout.\r
+\r
+                            if (deadlockTrace)\r
+                            {   \r
+                                // Turn ON derby.locks.deadlockTrace to build \r
+                                // the lockTable.\r
+                                    \r
+                                \r
+                                throw Timeout.buildException(\r
+                                    waitingLock, timeoutLockTable, currentTime);\r
+                            }\r
+                            else\r
+                            {\r
+                                StandardException se = \r
+                                    StandardException.newException(\r
+                                        SQLState.LOCK_TIMEOUT);\r
+\r
+                                throw se;\r
+                            }\r
+                        }\r
+                        else \r
+                        {\r
+                            // ending wait because of lock deadlock.\r
+\r
+                            throw Deadlock.buildException(\r
+                                    factory, deadlockData);\r
+                        }\r
+                    }\r
+                } finally {\r
+                    if (nextWaitingLock != null) {\r
+                        nextWaitingLock.wakeUp(Constants.WAITING_LOCK_GRANT);\r
+                        nextWaitingLock = null;\r
+                    }\r
+                }\r
+\r
+                if (actualTimeout != C_LockFactory.WAIT_FOREVER) {\r
+\r
+                    if (wakeupReason != Constants.WAITING_LOCK_IN_WAIT)\r
+                        earlyWakeupCount++;\r
+\r
+                    if (earlyWakeupCount > 5) {\r
+\r
+                        long now = System.currentTimeMillis();\r
+\r
+                        if (startWaitTime != 0) {\r
+\r
+                            long sleepTime = now - startWaitTime;\r
+\r
+                            actualTimeout -= sleepTime;\r
+                        }\r
+\r
+                        startWaitTime = now;\r
+                    }\r
+                }\r
+\r
+\r
+            } // for(;;)\r
+       }\r
+\r
+       /**\r
+               Unlock an object, previously locked by lockObject(). \r
+\r
+               If unlockCOunt is not zero then the lock will be unlocked\r
+               that many times, otherwise the unlock count is taken from\r
+               item.\r
+\r
+       */\r
+       public void unlock(Latch item, int unlockCount) {\r
+\r
+               if (SanityManager.DEBUG) {\r
+                       if (SanityManager.DEBUG_ON(Constants.LOCK_TRACE)) {\r
+                               /*\r
+                               ** I don't like checking the trace flag twice, but SanityManager\r
+                               ** doesn't provide a way to get to the debug trace stream\r
+                               ** directly.\r
+                               */\r
+                               SanityManager.DEBUG(\r
+                    Constants.LOCK_TRACE, \r
+                    "Release lock: " + DiagnosticUtil.toDiagString(item));\r
+                       }\r
+               }\r
+\r
+               boolean tryGrant = false;\r
+               ActiveLock nextGrant = null;\r
+\r
+               synchronized (this) {\r
+\r
+                       Control control = getControl(item.getLockable());\r
+                       \r
+                       if (SanityManager.DEBUG) {\r
+\r
+                // only valid Lock's expected\r
+                if (item.getLockable() == null)\r
+                {\r
+                    SanityManager.THROWASSERT(\r
+                        "item.getLockable() = null." +\r
+                        "unlockCount " + unlockCount + \r
+                        "item = " + DiagnosticUtil.toDiagString(item));\r
+                }\r
+\r
+                // only valid Lock's expected\r
+                if (control == null)\r
+                {\r
+                    SanityManager.THROWASSERT(\r
+                        "control = null." +\r
+                        "unlockCount " + unlockCount + \r
+                        "item = " + DiagnosticUtil.toDiagString(item));\r
+                }\r
+\r
+                               if (getControl(control.getLockable()) != control)\r
+                {\r
+                    SanityManager.THROWASSERT(\r
+                        "unlock mismatched lock items " + \r
+                        getControl(control.getLockable()) + " " + control);\r
+                }\r
+\r
+                               if ((unlockCount != 0) && (unlockCount > item.getCount()))\r
+                                       SanityManager.THROWASSERT("unlockCount " + unlockCount +\r
+                                               " larger than actual lock count " + item.getCount() + " item " + item);\r
+                       }\r
+\r
+                       tryGrant = control.unlock(item, unlockCount);\r
+                       item = null;\r
+\r
+                       boolean mayBeEmpty = true;\r
+                       if (tryGrant) {\r
+                               nextGrant = control.firstWaiter();\r
+                               if (nextGrant != null) {\r
+                                       mayBeEmpty = false;\r
+                                       if (!nextGrant.setPotentiallyGranted())\r
+                                               nextGrant = null;\r
+                               }\r
+                       }\r
+\r
+                       if (mayBeEmpty) {\r
+                               if (control.isEmpty()) {\r
+                                       // no-one granted, no-one waiting, remove lock control\r
+                                       locks.remove(control.getLockable());\r
+                               }\r
+                               return;\r
+                       }\r
+               } // synchronized (this)\r
+\r
+               if (tryGrant && (nextGrant != null)) {\r
+                       nextGrant.wakeUp(Constants.WAITING_LOCK_GRANT);\r
+               }\r
+       }\r
+\r
+    /**\r
+     * Unlock an object once if it is present in the specified group. Also\r
+     * remove the object from the group.\r
+     *\r
+     * @param space the compatibility space\r
+     * @param ref a reference to the locked object\r
+     * @param qualifier qualifier of the lock\r
+     * @param group a map representing the locks in a group\r
+     * @return the corresponding lock in the group map, or <code>null</code> if\r
+     * the object was not unlocked\r
+     */\r
+    public synchronized Lock unlockReference(CompatibilitySpace space,\r
+                                             Lockable ref, Object qualifier,\r
+                                             Map group) {\r
+\r
+        Control control = getControl(ref);\r
+        if (control == null) {\r
+            return null;\r
+        }\r
+\r
+        Lock setLock = control.getLock(space, qualifier);\r
+        if (setLock == null) {\r
+            return null;\r
+        }\r
+\r
+        Lock lockInGroup = (Lock) group.remove(setLock);\r
+        if (lockInGroup != null) {\r
+            unlock(lockInGroup, 1);\r
+        }\r
+\r
+        return lockInGroup;\r
+    }\r
+\r
+    /**\r
+     * Lock an object and release the lock immediately. Equivalent to\r
+     * <pre>\r
+     * Lock lock = lockTable.lockObject(space, ref, qualifier, timeout);\r
+     * lockTable.unlock(lock, 1);\r
+     * </pre>\r
+     * except that the implementation is more efficient.\r
+     *\r
+     * @param space the compatibility space\r
+     * @param ref a reference to the locked object\r
+     * @param qualifier qualifier of the lock\r
+     * @param timeout maximum time to wait in milliseconds\r
+     * (<code>LockFactory.NO_WAIT</code> means don't wait)\r
+     * @return <code>true</code> if the object was locked, or\r
+     * <code>false</code>if the timeout was <code>NO_WAIT</code> and the lock\r
+     * couldn't be obtained immediately\r
+     * @exception StandardException if the lock could not be obtained\r
+     */\r
+    public boolean zeroDurationLockObject(\r
+        CompatibilitySpace space, Lockable ref, Object qualifier, int timeout)\r
+            throws StandardException {\r
+\r
+        if (SanityManager.DEBUG) {\r
+            if (SanityManager.DEBUG_ON(Constants.LOCK_TRACE)) {\r
+                D_LockControl.debugLock(\r
+                    "Zero Duration Lock Request before Grant: ",\r
+                    space, null, ref, qualifier, timeout);\r
+                if (SanityManager.DEBUG_ON(Constants.LOCK_STACK_TRACE)) {\r
+                    // The following will print the stack trace of the lock\r
+                    // request to the log.\r
+                    Throwable t = new Throwable();\r
+                    java.io.PrintWriter istream =\r
+                        SanityManager.GET_DEBUG_STREAM();\r
+                    istream.println("Stack trace of lock request:");\r
+                    t.printStackTrace(istream);\r
+                }\r
+            }\r
+        }\r
+\r
+        // Very fast zeroDurationLockObject() for unlocked objects.\r
+        // If no entry exists in the lock manager for this reference\r
+        // then it must be unlocked.\r
+        // If the object is locked then we perform a grantable\r
+        // check, skipping over any waiters.\r
+        // If the caller wants to wait and the lock cannot\r
+        // be granted then we do the slow join the queue and\r
+        // release the lock method.\r
+\r
+        synchronized (this) {\r
+            Control control = getControl(ref);\r
+            if (control == null) {\r
+                return true;\r
+            }\r
+\r
+            // If we are grantable, ignoring waiting locks then\r
+            // we can also grant this request now, as skipping\r
+            // over the waiters won't block them as we release\r
+            // the lock rightway.\r
+            if (control.isGrantable(true, space, qualifier)) {\r
+                return true;\r
+            }\r
+\r
+            // can't be granted and are not willing to wait.\r
+            if (timeout == C_LockFactory.NO_WAIT) {\r
+                return false;\r
+            }\r
+        }\r
+\r
+        Lock lock = lockObject(space, ref, qualifier, timeout);\r
+\r
+        if (SanityManager.DEBUG) {\r
+            if (SanityManager.DEBUG_ON(Constants.LOCK_TRACE)) {\r
+                D_LockControl.debugLock(\r
+                    "Zero Lock Request Granted: ",\r
+                    space, null, ref, qualifier, timeout);\r
+            }\r
+        }\r
+\r
+        // and simply unlock it once\r
+        unlock(lock, 1);\r
+\r
+        return true;\r
+    }\r
+\r
+    /**\r
+     * Set the deadlock timeout.\r
+     *\r
+     * @param timeout deadlock timeout in milliseconds\r
+     */\r
+    public void setDeadlockTimeout(int timeout) {\r
+        deadlockTimeout = timeout;\r
+    }\r
+\r
+    /**\r
+     * Set the wait timeout.\r
+     *\r
+     * @param timeout wait timeout in milliseconds\r
+     */\r
+    public void setWaitTimeout(int timeout) {\r
+        waitTimeout = timeout;\r
+    }\r
+       \r
+       /*\r
+       ** Non public methods\r
+       */\r
+//EXCLUDE-START-lockdiag- \r
+\r
+       public void setDeadlockTrace(boolean val)\r
+       {\r
+               // set this without synchronization\r
+               deadlockTrace = val;\r
+       }                       \r
+//EXCLUDE-END-lockdiag- \r
+\r
+    public String toDebugString()\r
+    {\r
+        if (SanityManager.DEBUG)\r
+        {\r
+            String str = new String();\r
+\r
+            int i = 0;\r
+            for (Iterator it = locks.values().iterator(); it.hasNext(); )\r
+            {\r
+                str += "\n  lock[" + i + "]: " + \r
+                    DiagnosticUtil.toDiagString(it.next());\r
+            }\r
+\r
+            return(str);\r
+        }\r
+        else\r
+        {\r
+            return(null);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Add all waiters in this lock table to a <code>Map</code> object.\r
+     * <br>\r
+     * MT - must be synchronized on this <code>LockSet</code> object.\r
+     */\r
+    public void addWaiters(Map waiters) {\r
+        for (Iterator it = locks.values().iterator(); it.hasNext(); ) {\r
+            Control control = (Control) it.next();\r
+            control.addWaiters(waiters);\r
+        }\r
+    }\r
+\r
+//EXCLUDE-START-lockdiag- \r
+       /**\r
+        * make a shallow clone of myself and my lock controls\r
+        */\r
+       public synchronized Map shallowClone()\r
+       {\r
+               HashMap clone = new HashMap();\r
+\r
+               for (Iterator it = locks.keySet().iterator(); it.hasNext(); )\r
+               {\r
+                       Lockable lockable = (Lockable) it.next();\r
+                       Control control = getControl(lockable);\r
+\r
+                       clone.put(lockable, control.shallowClone());\r
+               }\r
+\r
+               return clone;\r
+       }\r
+//EXCLUDE-END-lockdiag- \r
+\r
+       /*\r
+       ** Support for anyoneBlocked(). These methods assume that caller\r
+       ** is synchronized on this LockSet object.\r
+       */\r
+\r
+       /**\r
+        * Increase blockCount by one.\r
+        * <BR>\r
+        * MT - must be synchronized on this <code>LockSet</code> object.\r
+        */\r
+       public void oneMoreWaiter() {\r
+               blockCount++;\r
+       }\r
+\r
+       /**\r
+        * Decrease blockCount by one.\r
+        * <BR>\r
+        * MT - must be synchronized on this <code>LockSet</code> object.\r
+        */\r
+       public void oneLessWaiter() {\r
+               blockCount--;\r
+       }\r
+\r
+       public synchronized boolean anyoneBlocked() {\r
+               if (SanityManager.DEBUG) {\r
+                       SanityManager.ASSERT(\r
+                               blockCount >= 0, "blockCount should not be negative");\r
+               }\r
+\r
+               return blockCount != 0;\r
+       }\r
+\r
+       /**\r
+        * Get the <code>Control</code> for an object in the lock table.\r
+        * <br>\r
+        * MT - must be synchronized on this <code>LockSet</code> object.\r
+        */\r
+       private final Control getControl(Lockable ref) {\r
+               return (Control) locks.get(ref);\r
+       }\r
+}\r