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