001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
005: *
006: * $Id: Java5SharedLatchImpl.java,v 1.8.2.3 2008/01/07 15:14:12 cwl Exp $
007: */
008:
009: package com.sleepycat.je.latch;
010:
011: import java.util.ArrayList;
012: import java.util.Collections;
013: import java.util.List;
014: import java.util.concurrent.locks.ReentrantReadWriteLock;
015:
016: import com.sleepycat.je.DatabaseException;
017: import com.sleepycat.je.dbi.EnvironmentImpl;
018:
019: /**
020: * Java5SharedLatchImpl provides an implementation of the SharedLatch
021: * interface. By using a wrapper class we can avoid link errors when we run in
022: * Java 1.4 JVMs. LatchSupport will only reference this class if it knows that
023: * the ReentrantReadWriteLock class is available at runtime through
024: * Class.forName(). LatchSupport only references this class through the
025: * SharedLatch interface and only constructs this using
026: *
027: * Class.forName("Java5SharedLatchImpl").newInstance();
028: */
029: class Java5SharedLatchImpl extends ReentrantReadWriteLock implements
030: SharedLatch {
031:
032: private String name;
033: private boolean noteLatch;
034: private List readers;
035:
036: /**
037: * If true, this shared latch is only ever latched exclusively. Used for
038: * BINs.
039: */
040: private boolean exclusiveOnly;
041:
042: Java5SharedLatchImpl() {
043: super (EnvironmentImpl.getFairLatches());
044: assert (readers = Collections.synchronizedList(new ArrayList())) != null;
045: exclusiveOnly = false;
046: }
047:
048: public void setExclusiveOnly(boolean exclusiveOnly) {
049: this .exclusiveOnly = exclusiveOnly;
050: }
051:
052: /**
053: * Set the latch name, used for latches in objects instantiated from the
054: * log.
055: */
056: public void setName(String name) {
057: this .name = name;
058: }
059:
060: /**
061: * If noteLatch is true, then track latch usage in the latchTable.
062: * Always return true so this can be called as an assert.
063: */
064: public boolean setNoteLatch(boolean noteLatch) {
065: this .noteLatch = noteLatch;
066: return true;
067: }
068:
069: /**
070: * Acquire a latch for exclusive/write access.
071: *
072: * Wait for the latch if some other thread is holding it. If there are
073: * threads waiting for access, they will be granted the latch on a FIFO
074: * basis if fair latches are set. When the method returns, the latch is
075: * held for exclusive access.
076: *
077: * @throws LatchException if the latch is already held by the current
078: * thread for exclusive access.
079: */
080: public void acquireExclusive() throws DatabaseException {
081:
082: try {
083: if (isWriteLockedByCurrentThread()) {
084: throw new LatchException(name + " already held");
085: }
086:
087: writeLock().lock();
088:
089: assert (noteLatch ? noteLatch() : true);// intentional side effect;
090: } finally {
091: assert EnvironmentImpl.maybeForceYield();
092: }
093: }
094:
095: public boolean acquireExclusiveNoWait() throws DatabaseException {
096:
097: try {
098: if (isWriteLockedByCurrentThread()) {
099: throw new LatchException(name + " already held");
100: }
101:
102: boolean ret = writeLock().tryLock();
103:
104: /* Intentional side effect. */
105: assert ((noteLatch & ret) ? noteLatch() : true);
106: return ret;
107: } finally {
108: assert EnvironmentImpl.maybeForceYield();
109: }
110: }
111:
112: /**
113: * Acquire a latch for shared/read access.
114: */
115: public void acquireShared() throws DatabaseException {
116:
117: if (exclusiveOnly) {
118: acquireExclusive();
119: return;
120: }
121:
122: try {
123: boolean assertionsEnabled = false;
124: assert assertionsEnabled = true;
125: if (assertionsEnabled) {
126: if (readers.add(Thread.currentThread())) {
127: readLock().lock();
128: } else {
129: /* Already latched, do nothing. */
130: }
131: } else {
132: readLock().lock();
133: }
134:
135: assert (noteLatch ? noteLatch() : true);// intentional side effect
136: } finally {
137: assert EnvironmentImpl.maybeForceYield();
138: }
139: }
140:
141: public boolean isOwner() {
142: boolean assertionsEnabled = false;
143: assert assertionsEnabled = true;
144: if (assertionsEnabled && !exclusiveOnly) {
145: return readers.contains(Thread.currentThread())
146: || isWriteLockedByCurrentThread();
147: } else {
148: return isWriteLockedByCurrentThread();
149: }
150: }
151:
152: /**
153: * Release an exclusive or shared latch. If there are other thread(s)
154: * waiting for the latch, they are woken up and granted the latch.
155: */
156: public void release() throws LatchNotHeldException {
157:
158: try {
159: if (isWriteLockedByCurrentThread()) {
160: writeLock().unlock();
161: /* Intentional side effect. */
162: assert (noteLatch ? unNoteLatch() : true);
163: return;
164: }
165:
166: if (exclusiveOnly) {
167: return;
168: }
169:
170: boolean assertionsEnabled = false;
171: assert assertionsEnabled = true;
172: if (assertionsEnabled) {
173: if (readers.remove(Thread.currentThread())) {
174: readLock().unlock();
175: } else {
176: throw new LatchNotHeldException(name + " not held");
177: }
178: } else {
179:
180: /*
181: * There's no way to tell if a readlock is held by the current
182: * thread so just try unlocking it.
183: */
184: readLock().unlock();
185: }
186: /* Intentional side effect. */
187: assert (noteLatch ? unNoteLatch() : true);
188: } catch (IllegalMonitorStateException IMSE) {
189: IMSE.printStackTrace();
190: return;
191: }
192: }
193:
194: public void releaseIfOwner() throws LatchNotHeldException {
195:
196: if (isWriteLockedByCurrentThread()) {
197: writeLock().unlock();
198: assert (noteLatch ? unNoteLatch() : true);
199: return;
200: }
201:
202: if (exclusiveOnly) {
203: return;
204: }
205:
206: assert (getReadLockCount() > 0);
207: boolean assertionsEnabled = false;
208: assert assertionsEnabled = true;
209: if (assertionsEnabled) {
210: if (readers.contains(Thread.currentThread())) {
211: readLock().unlock();
212: assert (noteLatch ? unNoteLatch() : true);
213: }
214: } else {
215:
216: /*
217: * There's no way to tell if a readlock is held by the current
218: * thread so just try unlocking it.
219: */
220: readLock().unlock();
221: }
222: }
223:
224: /**
225: * Only call under the assert system. This records latching by thread.
226: */
227: private boolean noteLatch() throws LatchException {
228:
229: return LatchSupport.latchTable.noteLatch(this );
230: }
231:
232: /**
233: * Only call under the assert system. This records latching by thread.
234: */
235: private boolean unNoteLatch() {
236:
237: return LatchSupport.latchTable.unNoteLatch(this, name);
238: }
239: }
|