001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
005: *
006: * $Id: BasicLocker.java,v 1.84.2.6 2008/01/07 15:14:17 cwl Exp $
007: */
008:
009: package com.sleepycat.je.txn;
010:
011: import java.util.HashSet;
012: import java.util.Iterator;
013: import java.util.Set;
014:
015: import com.sleepycat.je.Database;
016: import com.sleepycat.je.DatabaseException;
017: import com.sleepycat.je.DbInternal;
018: import com.sleepycat.je.LockStats;
019: import com.sleepycat.je.dbi.CursorImpl;
020: import com.sleepycat.je.dbi.DatabaseImpl;
021: import com.sleepycat.je.dbi.EnvironmentImpl;
022: import com.sleepycat.je.utilint.DbLsn;
023:
024: /**
025: * A concrete Locker that simply tracks locks and releases them when
026: * operationEnd is called.
027: */
028: public class BasicLocker extends Locker {
029:
030: /*
031: * A BasicLocker can release all locks, so there is no need to distinguish
032: * between read and write locks.
033: *
034: * ownedLock is used for the first lock obtained, and ownedLockSet is
035: * instantiated and used only if more than one lock is obtained. This is
036: * an optimization for the common case where only one lock is held by a
037: * non-transactional locker.
038: *
039: * There's no need to track memory utilization for these non-txnal lockers,
040: * because the lockers are short lived.
041: *
042: * ownedLock and ownedLockSet contains nids, not locks. We only need locks
043: * for the stats, so we can look them up on demand.
044: */
045: private Long ownedLock;
046: private Set ownedLockSet;
047:
048: /**
049: * Creates a BasicLocker.
050: */
051: public BasicLocker(EnvironmentImpl env) throws DatabaseException {
052:
053: super (env, false, false);
054: }
055:
056: /**
057: * BasicLockers always have a fixed id, because they are never used for
058: * recovery.
059: */
060: protected long generateId(TxnManager txnManager) {
061: return TxnManager.NULL_TXN_ID;
062: }
063:
064: protected void checkState(boolean ignoreCalledByAbort)
065: throws DatabaseException {
066: /* Do nothing. */
067: }
068:
069: /**
070: * @see Locker#lockInternal
071: * @Override
072: */
073: LockResult lockInternal(long nodeId, LockType lockType,
074: boolean noWait, DatabaseImpl database)
075: throws DatabaseException {
076:
077: /* Does nothing in BasicLocker. synchronized is for posterity. */
078: synchronized (this ) {
079: checkState(false);
080: }
081:
082: long timeout = 0;
083: boolean useNoWait = noWait || defaultNoWait;
084: if (!useNoWait) {
085: synchronized (this ) {
086: timeout = lockTimeOutMillis;
087: }
088: }
089:
090: /* Ask for the lock. */
091: LockGrantType grant = lockManager.lock(nodeId, this , lockType,
092: timeout, useNoWait, database);
093:
094: return new LockResult(grant, null);
095: }
096:
097: /**
098: * Get the txn that owns the lock on this node. Return null if there's no
099: * owning txn found.
100: */
101: public Locker getWriteOwnerLocker(long nodeId)
102: throws DatabaseException {
103:
104: return lockManager.getWriteOwnerLocker(new Long(nodeId));
105: }
106:
107: /**
108: * Get the abort LSN for this node in the txn that owns the lock on this
109: * node. Return null if there's no owning txn found.
110: */
111: public long getOwnerAbortLsn(long nodeId) throws DatabaseException {
112:
113: Locker ownerTxn = lockManager.getWriteOwnerLocker(new Long(
114: nodeId));
115: if (ownerTxn != null) {
116: return ownerTxn.getAbortLsn(nodeId);
117: }
118: return DbLsn.NULL_LSN;
119: }
120:
121: /**
122: * Is never transactional.
123: */
124: public boolean isTransactional() {
125: return false;
126: }
127:
128: /**
129: * Is never serializable isolation.
130: */
131: public boolean isSerializableIsolation() {
132: return false;
133: }
134:
135: /**
136: * Is never read-committed isolation.
137: */
138: public boolean isReadCommittedIsolation() {
139: return false;
140: }
141:
142: /**
143: * No transactional locker is available.
144: */
145: public Txn getTxnLocker() {
146: return null;
147: }
148:
149: /**
150: * Creates a new instance of this txn for the same environment. No
151: * transactional locks are held by this object, so no locks are retained.
152: */
153: public Locker newNonTxnLocker() throws DatabaseException {
154:
155: return new BasicLocker(envImpl);
156: }
157:
158: /**
159: * Releases all locks, since all locks held by this locker are
160: * non-transactional.
161: */
162: public void releaseNonTxnLocks() throws DatabaseException {
163:
164: operationEnd(true);
165: }
166:
167: /**
168: * Release locks at the end of the transaction.
169: */
170: public void operationEnd() throws DatabaseException {
171:
172: operationEnd(true);
173: }
174:
175: /**
176: * Release locks at the end of the transaction.
177: */
178: public void operationEnd(boolean operationOK)
179: throws DatabaseException {
180:
181: /*
182: * Don't remove locks from txn's lock collection until iteration is
183: * done, lest we get a ConcurrentModificationException during deadlock
184: * graph "display". [#9544]
185: */
186: if (ownedLock != null) {
187: lockManager.release(ownedLock.longValue(), this );
188: ownedLock = null;
189: }
190: if (ownedLockSet != null) {
191: Iterator iter = ownedLockSet.iterator();
192: while (iter.hasNext()) {
193: Long nid = (Long) iter.next();
194: lockManager.release(nid.longValue(), this );
195: }
196:
197: /* Now clear lock collection. */
198: ownedLockSet.clear();
199: }
200:
201: /* Unload delete info, but don't wake up the compressor. */
202: synchronized (this ) {
203: if ((deleteInfo != null) && (deleteInfo.size() > 0)) {
204: envImpl
205: .addToCompressorQueue(deleteInfo.values(),
206: false); // no wakeup
207: deleteInfo.clear();
208: }
209: }
210: }
211:
212: /**
213: * Transfer any MapLN locks to the db handle.
214: */
215: public void setHandleLockOwner(boolean operationOK,
216: Database dbHandle, boolean dbIsClosing)
217: throws DatabaseException {
218:
219: if (dbHandle != null) {
220: if (operationOK && !dbIsClosing) {
221: transferHandleLockToHandle(dbHandle);
222: } else {
223:
224: /*
225: * Release DB if there is a failure. This is done by Txn abort
226: * by calling Database.invalidate, but for a non-transactional
227: * locker must be done here. [#13415]
228: */
229: envImpl.releaseDb(DbInternal
230: .dbGetDatabaseImpl(dbHandle));
231: }
232: unregisterHandle(dbHandle);
233: }
234: }
235:
236: /**
237: * This txn doesn't store cursors.
238: */
239: public void registerCursor(CursorImpl cursor)
240: throws DatabaseException {
241: }
242:
243: /**
244: * This txn doesn't store cursors.
245: */
246: public void unRegisterCursor(CursorImpl cursor)
247: throws DatabaseException {
248: }
249:
250: /*
251: * Transactional methods are all no-oped.
252: */
253:
254: /**
255: * @return the abort LSN for this node.
256: */
257: public long getAbortLsn(long nodeId) throws DatabaseException {
258:
259: return DbLsn.NULL_LSN;
260: }
261:
262: /**
263: * @return a dummy WriteLockInfo for this node.
264: */
265: public WriteLockInfo getWriteLockInfo(long nodeId)
266: throws DatabaseException {
267:
268: return WriteLockInfo.basicWriteLockInfo;
269: }
270:
271: public void markDeleteAtTxnEnd(DatabaseImpl db,
272: boolean deleteAtCommit) throws DatabaseException {
273:
274: if (deleteAtCommit) {
275: /* releaseDb will be called by releaseDeletedINs. */
276: db.deleteAndReleaseINs();
277: } else {
278: envImpl.releaseDb(db);
279: }
280: }
281:
282: /**
283: * Add a lock to set owned by this transaction.
284: */
285: void addLock(Long nodeId, LockType type, LockGrantType grantStatus)
286: throws DatabaseException {
287:
288: if ((ownedLock != null && ownedLock.equals(nodeId))
289: || (ownedLockSet != null && ownedLockSet
290: .contains(nodeId))) {
291: return; // Already owned
292: }
293: if (ownedLock == null) {
294: ownedLock = nodeId;
295: } else {
296: if (ownedLockSet == null) {
297: ownedLockSet = new HashSet();
298: }
299: ownedLockSet.add(nodeId);
300: }
301: }
302:
303: /**
304: * Remove a lock from the set owned by this txn.
305: */
306: void removeLock(long nodeId) throws DatabaseException {
307:
308: if (ownedLock != null && ownedLock.longValue() == nodeId) {
309: ownedLock = null;
310: } else if (ownedLockSet != null) {
311: ownedLockSet.remove(new Long(nodeId));
312: }
313: }
314:
315: /**
316: * Always false for this txn.
317: */
318: public boolean createdNode(long nodeId) throws DatabaseException {
319:
320: return false;
321: }
322:
323: /**
324: * A lock is being demoted. Move it from the write collection into the read
325: * collection.
326: */
327: void moveWriteToReadLock(long nodeId, Lock lock) {
328: }
329:
330: /**
331: * stats
332: */
333: public LockStats collectStats(LockStats stats)
334: throws DatabaseException {
335:
336: if (ownedLock != null) {
337: Lock l = lockManager.lookupLock(ownedLock);
338: if (l != null) {
339: if (l.isOwnedWriteLock(this )) {
340: stats.setNWriteLocks(stats.getNWriteLocks() + 1);
341: } else {
342: stats.setNReadLocks(stats.getNReadLocks() + 1);
343: }
344: }
345: }
346: if (ownedLockSet != null) {
347: Iterator iter = ownedLockSet.iterator();
348:
349: while (iter.hasNext()) {
350: Long nid = (Long) iter.next();
351: Lock l = lockManager.lookupLock(nid);
352: if (l != null) {
353: if (l.isOwnedWriteLock(this )) {
354: stats
355: .setNWriteLocks(stats.getNWriteLocks() + 1);
356: } else {
357: stats.setNReadLocks(stats.getNReadLocks() + 1);
358: }
359: }
360: }
361: }
362: return stats;
363: }
364: }
|