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 java.util.Collections;
11 import java.util.HashSet;
12 import java.util.List;
13 import java.util.Set;
14 
15 import com.sleepycat.je.DatabaseException;
16 import com.sleepycat.je.dbi.MemoryBudget;
17 
18 /**
19  * Implements a lightweight Lock with no waiters and only a single Owner.  If,
20  * during an operation (lock) more than one owner or waiter is required, then
21  * this will mutate to a LockImpl, perform the requested operation, and return
22  * the new LockImpl to the caller.
23  *
24  * public for Sizeof.
25  */
26 public class ThinLockImpl extends LockInfo implements Lock {
27 
28     /**
29      * Create a Lock.  Public for Sizeof.
30      */
ThinLockImpl()31     public ThinLockImpl() {
32         super(null, null);
33     }
34 
getWaitersListClone()35     public List<LockInfo> getWaitersListClone() {
36         return Collections.emptyList();
37     }
38 
flushWaiter(Locker locker, MemoryBudget mb, int lockTableIndex)39     public void flushWaiter(Locker locker,
40                             MemoryBudget mb,
41                             int lockTableIndex) {
42 
43         /* Do nothing. */
44         return;
45     }
46 
getOwnersClone()47     public Set<LockInfo> getOwnersClone() {
48 
49         Set<LockInfo> ret = new HashSet<LockInfo>();
50         if (locker != null) {
51             ret.add(this);
52         }
53         return ret;
54     }
55 
isOwner(Locker locker, LockType lockType)56     public boolean isOwner(Locker locker, LockType lockType) {
57 
58         if (locker == this.locker) {
59             if (lockType == this.lockType) {
60                 return true;
61             }
62 
63             if (this.lockType != null) {
64                 LockUpgrade upgrade = this.lockType.getUpgrade(lockType);
65                 if (!upgrade.getPromotion()) {
66                     return true;
67                 }
68             }
69         } else {
70             return false;
71         }
72         return false;
73     }
74 
isOwnedWriteLock(Locker locker)75     public boolean isOwnedWriteLock(Locker locker) {
76 
77         if (locker != this.locker) {
78             return false;
79         }
80 
81         if (this.lockType != null) {
82             return this.lockType.isWriteLock();
83         } else {
84             return false;
85         }
86     }
87 
getOwnedLockType(Locker locker)88     public LockType getOwnedLockType(Locker locker) {
89         if (locker != this.locker) {
90             return null;
91         }
92         return this.lockType;
93     }
94 
isWaiter(Locker locker)95     public boolean isWaiter(Locker locker) {
96 
97         /* There can never be waiters on Thin Locks. */
98         return false;
99     }
100 
nWaiters()101     public int nWaiters() {
102         return 0;
103     }
104 
nOwners()105     public int nOwners() {
106         return (locker == null ? 0 : 1);
107     }
108 
lock(LockType requestType, Locker locker, boolean nonBlockingRequest, boolean jumpAheadOfWaiters, MemoryBudget mb, int lockTableIndex)109     public LockAttemptResult lock(LockType requestType,
110                                   Locker locker,
111                                   boolean nonBlockingRequest,
112                                   boolean jumpAheadOfWaiters,
113                                   MemoryBudget mb,
114                                   int lockTableIndex)
115         throws DatabaseException {
116 
117         if (this.locker != null &&
118             this.locker != locker) {
119             /* Lock is already held by someone else so mutate. */
120             Lock newLock = new LockImpl(new LockInfo(this));
121             return newLock.lock(requestType, locker, nonBlockingRequest,
122                                 jumpAheadOfWaiters, mb, lockTableIndex);
123         }
124 
125         LockGrantType grant = null;
126         if (this.locker == null) {
127             this.locker = locker;
128             this.lockType = requestType;
129             grant = LockGrantType.NEW;
130         } else {
131 
132             /* The requestor holds this lock.  Check for upgrades. */
133             LockUpgrade upgrade = lockType.getUpgrade(requestType);
134             if (upgrade.getUpgrade() == null) {
135                 grant = LockGrantType.EXISTING;
136             } else {
137                 LockType upgradeType = upgrade.getUpgrade();
138                 assert upgradeType != null;
139                 this.lockType = upgradeType;
140                 grant = (upgrade.getPromotion() ?
141                          LockGrantType.PROMOTION :
142                          LockGrantType.EXISTING);
143             }
144         }
145         return new LockAttemptResult(this, grant, false);
146     }
147 
release(Locker locker, MemoryBudget mb, int lockTableIndex)148     public Set<Locker> release(Locker locker,
149                                MemoryBudget mb,
150                                int lockTableIndex) {
151 
152         if (locker == this.locker) {
153             this.locker = null;
154             this.lockType = null;
155             return Collections.emptySet();
156         } else {
157             return null;
158         }
159     }
160 
stealLock(Locker locker, MemoryBudget mb, int lockTableIndex)161     public void stealLock(Locker locker, MemoryBudget mb, int lockTableIndex) {
162         if (this.locker != locker &&
163             this.locker.getPreemptable()) {
164             this.locker.setPreempted();
165             this.locker = null;
166         }
167     }
168 
demote(Locker locker)169     public void demote(Locker locker) {
170 
171         if (this.lockType.isWriteLock()) {
172             this.lockType = (lockType == LockType.RANGE_WRITE) ?
173                 LockType.RANGE_READ : LockType.READ;
174         }
175     }
176 
getWriteOwnerLocker()177     public Locker getWriteOwnerLocker() {
178 
179         if (lockType != null &&
180             lockType.isWriteLock()) {
181             return locker;
182         } else {
183             return null;
184         }
185     }
186 
isThin()187     public boolean isThin() {
188         return true;
189     }
190 
191     @Override
toString()192     public String toString() {
193 
194         StringBuilder sb = new StringBuilder();
195         sb.append(" ThinLockAddr:").append(System.identityHashCode(this));
196         sb.append(" Owner:");
197         if (nOwners() == 0) {
198             sb.append(" (none)");
199         } else {
200             sb.append(locker);
201         }
202 
203         sb.append(" Waiters: (none)");
204         return sb.toString();
205     }
206 }
207