1 |
| package org.jboss.cache.lock; |
2 |
| |
3 |
| import net.jcip.annotations.ThreadSafe; |
4 |
| import org.apache.commons.logging.Log; |
5 |
| import org.apache.commons.logging.LogFactory; |
6 |
| import org.jboss.cache.Fqn; |
7 |
| |
8 |
| import java.util.List; |
9 |
| import java.util.concurrent.locks.ReentrantReadWriteLock; |
10 |
| |
11 |
| |
12 |
| |
13 |
| |
14 |
| |
15 |
| |
16 |
| |
17 |
| |
18 |
| |
19 |
| |
20 |
| |
21 |
| |
22 |
| |
23 |
| |
24 |
| |
25 |
| @ThreadSafe |
26 |
| public class StripedLock |
27 |
| { |
28 |
| private static final int DEFAULT_CONCURRENCY = 20; |
29 |
| private int lockSegmentMask; |
30 |
| private int lockSegmentShift; |
31 |
| |
32 |
| ReentrantReadWriteLock[] sharedLocks; |
33 |
| private Log log = LogFactory.getLog(StripedLock.class); |
34 |
| |
35 |
| |
36 |
| |
37 |
| |
38 |
653
| public StripedLock()
|
39 |
| { |
40 |
653
| this(DEFAULT_CONCURRENCY);
|
41 |
| } |
42 |
| |
43 |
| |
44 |
| |
45 |
| |
46 |
| |
47 |
| |
48 |
653
| public StripedLock(int concurrency)
|
49 |
| { |
50 |
653
| int tempLockSegShift = 0;
|
51 |
653
| int numLocks = 1;
|
52 |
653
| while (numLocks < concurrency)
|
53 |
| { |
54 |
3265
| ++tempLockSegShift;
|
55 |
3265
| numLocks <<= 1;
|
56 |
| } |
57 |
653
| lockSegmentShift = 32 - tempLockSegShift;
|
58 |
653
| lockSegmentMask = numLocks - 1;
|
59 |
| |
60 |
653
| sharedLocks = new ReentrantReadWriteLock[numLocks];
|
61 |
| |
62 |
20896
| for (int i = 0; i < numLocks; i++) sharedLocks[i] = new ReentrantReadWriteLock();
|
63 |
| } |
64 |
| |
65 |
| |
66 |
| |
67 |
| |
68 |
| |
69 |
| |
70 |
| |
71 |
247191
| public void acquireLock(Fqn fqn, boolean exclusive)
|
72 |
| { |
73 |
247191
| ReentrantReadWriteLock lock = getLock(fqn);
|
74 |
| |
75 |
247191
| if (exclusive)
|
76 |
| { |
77 |
| |
78 |
227889
| lock.writeLock().lock();
|
79 |
| } |
80 |
| else |
81 |
19302
| lock.readLock().lock();
|
82 |
| } |
83 |
| |
84 |
| |
85 |
| |
86 |
| |
87 |
| |
88 |
| |
89 |
247191
| public void releaseLock(Fqn fqn)
|
90 |
| { |
91 |
247191
| ReentrantReadWriteLock lock = getLock(fqn);
|
92 |
247191
| if (lock.isWriteLockedByCurrentThread())
|
93 |
| { |
94 |
227889
| lock.writeLock().unlock();
|
95 |
| |
96 |
227889
| if (lock.isWriteLockedByCurrentThread() && log.isWarnEnabled())
|
97 |
0
| log.warn("Write lock still exists on Fqn " + fqn + " for current thread. Perhaps this was write-locked more than once?");
|
98 |
| } |
99 |
| else |
100 |
| { |
101 |
19302
| try
|
102 |
| { |
103 |
19302
| lock.readLock().unlock();
|
104 |
| } |
105 |
| catch (IllegalMonitorStateException imse) |
106 |
| { |
107 |
| |
108 |
| } |
109 |
| } |
110 |
| } |
111 |
| |
112 |
495382
| ReentrantReadWriteLock getLock(Object o)
|
113 |
| { |
114 |
495378
| return sharedLocks[hashToIndex(o)];
|
115 |
| } |
116 |
| |
117 |
495382
| int hashToIndex(Object o)
|
118 |
| { |
119 |
495382
| return (hash(o) >>> lockSegmentShift) & lockSegmentMask;
|
120 |
| } |
121 |
| |
122 |
| |
123 |
| |
124 |
| |
125 |
| |
126 |
| |
127 |
| |
128 |
| |
129 |
| |
130 |
495382
| int hash(Object x)
|
131 |
| { |
132 |
495382
| int h = x.toString().hashCode();
|
133 |
495382
| h += ~(h << 9);
|
134 |
495380
| h ^= (h >>> 14);
|
135 |
495382
| h += (h << 4);
|
136 |
495382
| h ^= (h >>> 10);
|
137 |
495382
| return h;
|
138 |
| } |
139 |
| |
140 |
| |
141 |
| |
142 |
| |
143 |
| |
144 |
| |
145 |
| |
146 |
0
| public void releaseAllLocks(List<Fqn> fqns)
|
147 |
| { |
148 |
0
| for (Fqn f : fqns) releaseLock(f);
|
149 |
| } |
150 |
| |
151 |
| |
152 |
| |
153 |
| |
154 |
| |
155 |
| |
156 |
| |
157 |
| |
158 |
0
| public void acquireAllLocks(List<Fqn> fqns, boolean exclusive)
|
159 |
| { |
160 |
0
| for (Fqn f : fqns) acquireLock(f, exclusive);
|
161 |
| } |
162 |
| } |