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.CountDownLatch;
20 import java.util.concurrent.TimeUnit;
21
22 import org.apache.ibatis.cache.Cache;
23 import org.apache.ibatis.cache.CacheException;
24
25
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, CountDownLatch> locks;
42
43 public BlockingCache(Cache delegate) {
44 this.delegate = delegate;
45 this.locks = new ConcurrentHashMap<>();
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 private void acquireLock(Object key) {
90 CountDownLatch newLatch = new CountDownLatch(1);
91 while (true) {
92 CountDownLatch latch = locks.putIfAbsent(key, newLatch);
93 if (latch == null) {
94 break;
95 }
96 try {
97 if (timeout > 0) {
98 boolean acquired = latch.await(timeout, TimeUnit.MILLISECONDS);
99 if (!acquired) {
100 throw new CacheException(
101 "Couldn't get a lock in " + timeout + " for the key " + key + " at the cache " + delegate.getId());
102 }
103 } else {
104 latch.await();
105 }
106 } catch (InterruptedException e) {
107 throw new CacheException("Got interrupted while trying to acquire lock for key " + key, e);
108 }
109 }
110 }
111
112 private void releaseLock(Object key) {
113 CountDownLatch latch = locks.remove(key);
114 if (latch == null) {
115 throw new IllegalStateException("Detected an attempt at releasing unacquired lock. This should never happen.");
116 }
117 latch.countDown();
118 }
119
120 public long getTimeout() {
121 return timeout;
122 }
123
124 public void setTimeout(long timeout) {
125 this.timeout = timeout;
126 }
127 }