1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.ibatis.cache.decorators;
17
18 import java.util.concurrent.ConcurrentHashMap;
19 import java.util.concurrent.TimeUnit;
20 import java.util.concurrent.locks.Lock;
21 import java.util.concurrent.locks.ReadWriteLock;
22 import java.util.concurrent.locks.ReentrantLock;
23
24 import org.apache.ibatis.cache.Cache;
25 import org.apache.ibatis.cache.CacheException;
26
27
28
29
30
31
32
33
34
35
36
37 public class BlockingCache implements Cache {
38
39 private long timeout;
40 private final Cache delegate;
41 private final ConcurrentHashMap<Object, ReentrantLock> locks;
42
43 public BlockingCache(Cache delegate) {
44 this.delegate = delegate;
45 this.locks = new ConcurrentHashMap<Object, ReentrantLock>();
46 }
47
48 @Override
49 public String getId() {
50 return delegate.getId();
51 }
52
53 @Override
54 public int getSize() {
55 return delegate.getSize();
56 }
57
58 @Override
59 public void putObject(Object key, Object value) {
60 try {
61 delegate.putObject(key, value);
62 } finally {
63 releaseLock(key);
64 }
65 }
66
67 @Override
68 public Object getObject(Object key) {
69 acquireLock(key);
70 Object value = delegate.getObject(key);
71 if (value != null) {
72 releaseLock(key);
73 }
74 return value;
75 }
76
77 @Override
78 public Object removeObject(Object key) {
79
80 releaseLock(key);
81 return null;
82 }
83
84 @Override
85 public void clear() {
86 delegate.clear();
87 }
88
89 @Override
90 public ReadWriteLock getReadWriteLock() {
91 return null;
92 }
93
94 private ReentrantLock getLockForKey(Object key) {
95 ReentrantLock lock = new ReentrantLock();
96 ReentrantLock previous = locks.putIfAbsent(key, lock);
97 return previous == null ? lock : previous;
98 }
99
100 private void acquireLock(Object key) {
101 Lock lock = getLockForKey(key);
102 if (timeout > 0) {
103 try {
104 boolean acquired = lock.tryLock(timeout, TimeUnit.MILLISECONDS);
105 if (!acquired) {
106 throw new CacheException("Couldn't get a lock in " + timeout + " for the key " + key + " at the cache " + delegate.getId());
107 }
108 } catch (InterruptedException e) {
109 throw new CacheException("Got interrupted while trying to acquire lock for key " + key, e);
110 }
111 } else {
112 lock.lock();
113 }
114 }
115
116 private void releaseLock(Object key) {
117 ReentrantLock lock = locks.get(key);
118 if (lock.isHeldByCurrentThread()) {
119 lock.unlock();
120 }
121 }
122
123 public long getTimeout() {
124 return timeout;
125 }
126
127 public void setTimeout(long timeout) {
128 this.timeout = timeout;
129 }
130 }