1 /*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2002, 2014 Oracle and/or its affiliates. All rights reserved. 5 * 6 */ 7 8 package com.sleepycat.je.txn; 9 10 import com.sleepycat.je.DatabaseException; 11 import com.sleepycat.je.dbi.CursorImpl; 12 import com.sleepycat.je.dbi.DatabaseImpl; 13 import com.sleepycat.je.dbi.EnvironmentImpl; 14 import com.sleepycat.je.tree.BIN; 15 16 /** 17 * Extends BuddyLocker to acquire write locks using the buddy locker (the 18 * transaction locker). This is used for ReadCommitted (Degree 2) isolation. 19 */ 20 public class ReadCommittedLocker extends BuddyLocker { 21 22 /** 23 * Creates a ReadCommittedLocker. 24 * @param buddy is a transactional locker that will be used for acquiring 25 * write locks. 26 */ ReadCommittedLocker(EnvironmentImpl env, Locker buddy)27 private ReadCommittedLocker(EnvironmentImpl env, Locker buddy) { 28 29 /* 30 * If the buddy param is a read-committed locker, reach in to get its 31 * transactional buddy locker. 32 */ 33 super(env, 34 (buddy instanceof ReadCommittedLocker) ? 35 ((ReadCommittedLocker) buddy).getBuddy() : buddy); 36 37 assert(getBuddy() instanceof Txn); 38 } 39 createReadCommittedLocker( EnvironmentImpl env, Locker buddy)40 public static ReadCommittedLocker createReadCommittedLocker( 41 EnvironmentImpl env, 42 Locker buddy) 43 throws DatabaseException { 44 45 return new ReadCommittedLocker(env, buddy); 46 } 47 48 /** 49 * Returns a new ReadCommittedLocker that shares locks with this locker by 50 * virtue of both lockers only holding READ locks. The buddy locker 51 * underlying both ReadCommittedLocker lockers is the same transactional 52 * locker, so WRITE locks are also shared. 53 */ 54 @Override newNonTxnLocker()55 public Locker newNonTxnLocker() 56 throws DatabaseException { 57 58 /* 59 * getBuddy().newNonTxnLocker() will return the transactional buddy 60 * locker itself (same as getBuddy), but we call newNonTxnLocker for 61 * consistency. 62 */ 63 return ReadCommittedLocker.createReadCommittedLocker 64 (envImpl, getBuddy().newNonTxnLocker()); 65 } 66 67 /** 68 * Forwards write locks to the buddy locker (the transaction locker). 69 * 70 * @see Locker#lockInternal 71 */ 72 @Override lockInternal(long lsn, LockType lockType, boolean noWait, boolean jumpAheadOfWaiters, DatabaseImpl database)73 protected LockResult lockInternal(long lsn, 74 LockType lockType, 75 boolean noWait, 76 boolean jumpAheadOfWaiters, 77 DatabaseImpl database) 78 throws DatabaseException { 79 80 if (lockType.isWriteLock()) { 81 return getBuddy().lockInternal 82 (lsn, lockType, noWait, jumpAheadOfWaiters, database); 83 } else { 84 return super.lockInternal 85 (lsn, lockType, noWait, jumpAheadOfWaiters, database); 86 } 87 } 88 89 /** 90 * Releases the lock from this locker, or if not owned by this locker then 91 * releases it from the buddy locker. 92 */ 93 @Override releaseLock(long lsn)94 public boolean releaseLock(long lsn) 95 throws DatabaseException { 96 97 boolean ret = true; 98 if (!lockManager.release(lsn, this)) { 99 ret = lockManager.release(lsn, getBuddy()); 100 } 101 removeLock(lsn); 102 return ret; 103 } 104 105 /** 106 * @return the WriteLockInfo for this node. 107 */ 108 @Override getWriteLockInfo(long lsn)109 public WriteLockInfo getWriteLockInfo(long lsn) { 110 return getBuddy().getWriteLockInfo(lsn); 111 } 112 113 /** 114 * Write operations are handled by the buddy Txn. 115 */ 116 @Override markDeleteAtTxnEnd(DatabaseImpl db, boolean deleteAtCommit)117 public void markDeleteAtTxnEnd(DatabaseImpl db, boolean deleteAtCommit) { 118 getBuddy().markDeleteAtTxnEnd(db, deleteAtCommit); 119 } 120 121 /** 122 * Forwards this method to the transactional buddy. The buddy handles 123 * write locks and therefore handles delete information. 124 */ 125 @Override addDeleteInfo(BIN bin)126 public void addDeleteInfo(BIN bin) { 127 getBuddy().addDeleteInfo(bin); 128 } 129 130 /** 131 * Forwards this method to the transactional buddy. The buddy Txn tracks 132 * cursors. 133 */ 134 @Override registerCursor(CursorImpl cursor)135 public void registerCursor(CursorImpl cursor) { 136 getBuddy().registerCursor(cursor); 137 } 138 139 /** 140 * Forwards this method to the transactional buddy. The buddy Txn tracks 141 * cursors. 142 */ 143 @Override unRegisterCursor(CursorImpl cursor)144 public void unRegisterCursor(CursorImpl cursor) { 145 getBuddy().unRegisterCursor(cursor); 146 } 147 148 /** 149 * ReadCommittedLockers always require locking. 150 */ 151 @Override lockingRequired()152 public boolean lockingRequired() { 153 return true; 154 } 155 156 /** 157 * Is always transactional because the buddy locker is transactional. 158 */ 159 @Override isTransactional()160 public boolean isTransactional() { 161 return true; 162 } 163 164 /** 165 * Is always read-committed isolation. 166 */ 167 @Override isReadCommittedIsolation()168 public boolean isReadCommittedIsolation() { 169 return true; 170 } 171 } 172