~ubuntu-branches/ubuntu/quantal/ehcache/quantal

« back to all changes in this revision

Viewing changes to src/main/java/net/sf/ehcache/concurrent/StripedReadWriteLockSync.java

  • Committer: Package Import Robot
  • Author(s): Miguel Landaeta
  • Date: 2012-03-01 19:15:46 UTC
  • mfrom: (1.1.6) (2.1.7 sid)
  • Revision ID: package-import@ubuntu.com-20120301191546-rvlk8tomip0c2m9p
Tags: 2.5.0-1
* Team upload.
* New upstream release. (Closes: #661450).
* Bump Standards-Version to 3.9.3. No changes were required.
* Fix lintian warning with copyright file.
* Remove unnecessary dependencies on JRE for libehcache-java.
* Wrap list of dependencies and uploaders.
* Fix clean target by adding a mh_clean call, to allow twice in a row builds.

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
 */
16
16
package net.sf.ehcache.concurrent;
17
17
 
18
 
import java.util.ArrayList;
 
18
import java.util.Arrays;
 
19
import java.util.Collections;
19
20
import java.util.List;
20
 
import java.util.Map;
21
 
import java.util.SortedMap;
22
 
import java.util.TreeMap;
23
 
import java.util.concurrent.TimeoutException;
24
 
import java.util.concurrent.atomic.AtomicInteger;
 
21
import java.util.concurrent.locks.ReadWriteLock;
25
22
 
26
23
import net.sf.ehcache.CacheException;
27
24
 
39
36
 * Based on the lock striping concept from Brian Goetz. See Java Concurrency in Practice 11.4.3
40
37
 * @author Alex Snaps
41
38
 */
42
 
public class StripedReadWriteLockSync implements CacheLockProvider {
 
39
public class StripedReadWriteLockSync implements StripedReadWriteLock {
43
40
 
44
41
    /**
45
42
     * The default number of locks to use. Must be a power of 2.
47
44
     * The choice of 2048 enables 2048 concurrent operations per cache or cache store, which should be enough for most
48
45
     * uses.
49
46
     */
50
 
    public  static final int    DEFAULT_NUMBER_OF_MUTEXES = 2048;
 
47
    public static final int DEFAULT_NUMBER_OF_MUTEXES = 2048;
51
48
 
52
49
    private final ReadWriteLockSync[] mutexes;
53
 
    private final int                 numberOfStripes;
54
 
 
 
50
    private final List<ReadWriteLockSync> mutexesAsList;
55
51
    /**
56
52
     * Constructs a striped mutex with the default 2048 stripes.
57
53
     */
66
62
     * @param numberOfStripes - must be a factor of two
67
63
     */
68
64
    public StripedReadWriteLockSync(int numberOfStripes) {
69
 
        if (numberOfStripes % 2 != 0) {
70
 
            throw new CacheException("Cannot create a CacheLockProvider with an odd number of stripes");
 
65
        if ((numberOfStripes & (numberOfStripes - 1)) != 0) {
 
66
            throw new CacheException("Cannot create a CacheLockProvider with a non power-of-two number of stripes");
71
67
        }
72
 
 
73
68
        if (numberOfStripes == 0) {
74
69
            throw new CacheException("A zero size CacheLockProvider does not have useful semantics.");
75
70
        }
76
71
 
77
 
        this.numberOfStripes = numberOfStripes;
78
72
        mutexes = new ReadWriteLockSync[numberOfStripes];
79
73
 
80
 
        for (int i = 0; i < numberOfStripes; i++) {
 
74
        for (int i = 0; i < mutexes.length; i++) {
81
75
            mutexes[i] = new ReadWriteLockSync();
82
76
        }
 
77
        mutexesAsList = Collections.unmodifiableList(Arrays.asList(mutexes));
83
78
    }
84
79
 
85
80
    /**
91
86
     * @return one of a limited number of Sync's.
92
87
     */
93
88
    public ReadWriteLockSync getSyncForKey(final Object key) {
94
 
        int lockNumber = ConcurrencyUtil.selectLock(key, numberOfStripes);
 
89
        int lockNumber = ConcurrencyUtil.selectLock(key, mutexes.length);
95
90
        return mutexes[lockNumber];
96
91
    }
97
92
 
98
93
    /**
99
 
     * {@inheritDoc}
100
 
     */
101
 
    public Sync[] getAndWriteLockAllSyncForKeys(Object... keys) {
102
 
        SortedMap<ReadWriteLockSync, AtomicInteger> locks = getLockMap(keys);
103
 
 
104
 
        Sync[] syncs = new Sync[locks.size()];
105
 
        int i = 0;
106
 
        for (Map.Entry<ReadWriteLockSync, AtomicInteger> entry : locks.entrySet()) {
107
 
            while (entry.getValue().getAndDecrement() > 0) {
108
 
                entry.getKey().lock(LockType.WRITE);
109
 
            }
110
 
            syncs[i++] = entry.getKey();
111
 
        }
112
 
        return syncs;
113
 
    }
114
 
 
115
 
    /**
116
 
     * {@inheritDoc}
117
 
     */
118
 
    public Sync[] getAndWriteLockAllSyncForKeys(long timeout, Object... keys) throws TimeoutException {
119
 
        SortedMap<ReadWriteLockSync, AtomicInteger> locks = getLockMap(keys);
120
 
 
121
 
        boolean lockHeld;
122
 
        List<ReadWriteLockSync> heldLocks = new ArrayList<ReadWriteLockSync>();
123
 
 
124
 
        Sync[] syncs = new Sync[locks.size()];
125
 
        int i = 0;
126
 
        for (Map.Entry<ReadWriteLockSync, AtomicInteger> entry : locks.entrySet()) {
127
 
            while (entry.getValue().getAndDecrement() > 0) {
128
 
                try {
129
 
                    ReadWriteLockSync writeLockSync = entry.getKey();
130
 
                    lockHeld = writeLockSync.tryLock(LockType.WRITE, timeout);
131
 
                    if (lockHeld) {
132
 
                        heldLocks.add(writeLockSync);
133
 
                    }
134
 
                } catch (InterruptedException e) {
135
 
                    lockHeld = false;
136
 
                }
137
 
 
138
 
                if (!lockHeld) {
139
 
                    for (int j = heldLocks.size() - 1; j >= 0; j--) {
140
 
                        ReadWriteLockSync readWriteLockSync = heldLocks.get(j);
141
 
                        readWriteLockSync.unlock(LockType.WRITE);
142
 
                    }
143
 
                    throw new TimeoutException("could not acquire all locks in " + timeout + " ms");
144
 
                }
145
 
            }
146
 
            syncs[i++] = entry.getKey();
147
 
        }
148
 
        return syncs;
149
 
    }
150
 
 
151
 
    /**
152
 
     * {@inheritDoc}
153
 
     */
154
 
    public void unlockWriteLockForAllKeys(Object... keys) {
155
 
        SortedMap<ReadWriteLockSync, AtomicInteger> locks = getLockMap(keys);
156
 
 
157
 
        for (Map.Entry<ReadWriteLockSync, AtomicInteger> entry : locks.entrySet()) {
158
 
            while (entry.getValue().getAndDecrement() > 0) {
159
 
                entry.getKey().unlock(LockType.WRITE);
160
 
            }
161
 
        }
162
 
    }
163
 
 
164
 
    private SortedMap<ReadWriteLockSync, AtomicInteger> getLockMap(final Object... keys) {
165
 
        SortedMap<ReadWriteLockSync, AtomicInteger> locks = new TreeMap<ReadWriteLockSync, AtomicInteger>();
166
 
        for (Object key : keys) {
167
 
            ReadWriteLockSync syncForKey = getSyncForKey(key);
168
 
            if (locks.containsKey(syncForKey)) {
169
 
                locks.get(syncForKey).incrementAndGet();
170
 
            } else {
171
 
                locks.put(syncForKey, new AtomicInteger(1));
172
 
            }
173
 
        }
174
 
        return locks;
 
94
     * Gets the RWL Stripe to use for a given key.
 
95
     * <p/>
 
96
     * This lookup must always return the same RWL for a given key.
 
97
     * <p/>
 
98
     * @param key the key
 
99
     * @return one of a limited number of RWLs.
 
100
     */
 
101
    public ReadWriteLock getLockForKey(final Object key) {
 
102
        int lockNumber = ConcurrencyUtil.selectLock(key, mutexes.length);
 
103
        return mutexes[lockNumber].getReadWriteLock();
 
104
    }
 
105
 
 
106
    /**
 
107
     * Returns all internal syncs
 
108
     * @return all internal syncs
 
109
     */
 
110
    public List<ReadWriteLockSync> getAllSyncs() {
 
111
        return mutexesAsList;
175
112
    }
176
113
}