1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.util;
20
21 import java.lang.ref.Reference;
22 import java.lang.ref.ReferenceQueue;
23 import java.lang.ref.SoftReference;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.Comparator;
28 import java.util.LinkedHashSet;
29 import java.util.Map;
30 import java.util.NavigableMap;
31 import java.util.Set;
32 import java.util.SortedMap;
33 import java.util.TreeMap;
34
35 import org.apache.hadoop.classification.InterfaceAudience;
36 import org.apache.hadoop.classification.InterfaceStability;
37
38
39
40
41
42
43
44
45
46 @InterfaceAudience.Public
47 @InterfaceStability.Stable
48 public class SoftValueSortedMap<K,V> implements SortedMap<K,V> {
49 private final SortedMap<K, SoftValue<K,V>> internalMap;
50 private final ReferenceQueue<V> rq = new ReferenceQueue<V>();
51 private final Object sync;
52
53
54 public SoftValueSortedMap() {
55 this(new TreeMap<K, SoftValue<K,V>>());
56 }
57
58
59
60
61
62 public SoftValueSortedMap(final Comparator<K> c) {
63 this(new TreeMap<K, SoftValue<K,V>>(c));
64 }
65
66
67
68
69 private SoftValueSortedMap(SortedMap<K,SoftValue<K,V>> original) {
70 this(original, original);
71 }
72
73
74
75
76
77
78 private SoftValueSortedMap(SortedMap<K,SoftValue<K,V>> original, Object sync) {
79 this.internalMap = original;
80 this.sync = sync;
81 }
82
83
84
85
86
87
88
89 @SuppressWarnings("unchecked")
90 private int checkReferences() {
91 int i = 0;
92 for (Reference<? extends V> ref; (ref = this.rq.poll()) != null;) {
93 i++;
94 this.internalMap.remove(((SoftValue<K,V>)ref).key);
95 }
96 return i;
97 }
98
99 public V put(K key, V value) {
100 synchronized(sync) {
101 checkReferences();
102 SoftValue<K,V> oldValue = this.internalMap.put(key,
103 new SoftValue<K,V>(key, value, this.rq));
104 return oldValue == null ? null : oldValue.get();
105 }
106 }
107
108 @Override
109 public void putAll(Map<? extends K, ? extends V> m) {
110 throw new RuntimeException("Not implemented");
111 }
112
113 public V get(Object key) {
114 synchronized(sync) {
115 checkReferences();
116 SoftValue<K,V> value = this.internalMap.get(key);
117 if (value == null) {
118 return null;
119 }
120 if (value.get() == null) {
121 this.internalMap.remove(key);
122 return null;
123 }
124 return value.get();
125 }
126 }
127
128 public V remove(Object key) {
129 synchronized(sync) {
130 checkReferences();
131 SoftValue<K,V> value = this.internalMap.remove(key);
132 return value == null ? null : value.get();
133 }
134 }
135
136 public boolean containsKey(Object key) {
137 synchronized(sync) {
138 checkReferences();
139 return this.internalMap.containsKey(key);
140 }
141 }
142
143 public boolean containsValue(Object value) {
144 throw new UnsupportedOperationException("Don't support containsValue!");
145 }
146
147 public K firstKey() {
148 synchronized(sync) {
149 checkReferences();
150 return internalMap.firstKey();
151 }
152 }
153
154 public K lastKey() {
155 synchronized(sync) {
156 checkReferences();
157 return internalMap.lastKey();
158 }
159 }
160
161 public SoftValueSortedMap<K,V> headMap(K key) {
162 synchronized(sync) {
163 checkReferences();
164 return new SoftValueSortedMap<K,V>(this.internalMap.headMap(key), sync);
165 }
166 }
167
168 public SoftValueSortedMap<K,V> tailMap(K key) {
169 synchronized(sync) {
170 checkReferences();
171 return new SoftValueSortedMap<K,V>(this.internalMap.tailMap(key), sync);
172 }
173 }
174
175 public SoftValueSortedMap<K,V> subMap(K fromKey, K toKey) {
176 synchronized(sync) {
177 checkReferences();
178 return new SoftValueSortedMap<K,V>(this.internalMap.subMap(fromKey,
179 toKey), sync);
180 }
181 }
182
183
184
185
186
187
188 public synchronized V lowerValueByKey(K key) {
189 synchronized(sync) {
190 checkReferences();
191
192 Map.Entry<K,SoftValue<K,V>> entry =
193 ((NavigableMap<K, SoftValue<K,V>>) this.internalMap).lowerEntry(key);
194 if (entry==null) {
195 return null;
196 }
197 SoftValue<K,V> value=entry.getValue();
198 if (value==null) {
199 return null;
200 }
201 if (value.get() == null) {
202 this.internalMap.remove(key);
203 return null;
204 }
205 return value.get();
206 }
207 }
208
209 public boolean isEmpty() {
210 synchronized(sync) {
211 checkReferences();
212 return this.internalMap.isEmpty();
213 }
214 }
215
216 public int size() {
217 synchronized(sync) {
218 checkReferences();
219 return this.internalMap.size();
220 }
221 }
222
223 public void clear() {
224 synchronized(sync) {
225 checkReferences();
226 this.internalMap.clear();
227 }
228 }
229
230 public Set<K> keySet() {
231 synchronized(sync) {
232 checkReferences();
233
234
235
236
237 return Collections.unmodifiableSet(this.internalMap.keySet());
238 }
239 }
240
241 public Comparator<? super K> comparator() {
242 return this.internalMap.comparator();
243 }
244
245 public Set<Map.Entry<K,V>> entrySet() {
246 synchronized(sync) {
247 checkReferences();
248
249
250 Set<Map.Entry<K, V>> realEntries = new LinkedHashSet<Map.Entry<K, V>>();
251 for (Map.Entry<K, SoftValue<K, V>> entry : this.internalMap.entrySet()) {
252 realEntries.add(entry.getValue());
253 }
254 return realEntries;
255 }
256 }
257
258 public Collection<V> values() {
259 synchronized(sync) {
260 checkReferences();
261 ArrayList<V> hardValues = new ArrayList<V>();
262 for (SoftValue<K,V> softValue : this.internalMap.values()) {
263 hardValues.add(softValue.get());
264 }
265 return hardValues;
266 }
267 }
268
269 private static class SoftValue<K,V> extends SoftReference<V> implements Map.Entry<K, V> {
270 final K key;
271
272 SoftValue(K key, V value, ReferenceQueue<V> q) {
273 super(value, q);
274 this.key = key;
275 }
276
277 public K getKey() {
278 return this.key;
279 }
280
281 public V getValue() {
282 return get();
283 }
284
285 public V setValue(V value) {
286 throw new RuntimeException("Not implemented");
287 }
288 }
289 }