1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.hadoop.hbase.metrics.impl;
22
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.Set;
26 import java.util.concurrent.ConcurrentHashMap;
27 import java.util.concurrent.atomic.AtomicInteger;
28
29 import org.apache.hadoop.hbase.classification.InterfaceAudience;
30
31 import com.google.common.base.Supplier;
32
33
34
35
36
37
38
39 @InterfaceAudience.Private
40 class RefCountingMap<K, V> {
41
42 private ConcurrentHashMap<K, Payload<V>> map = new ConcurrentHashMap<>();
43 private static class Payload<V> {
44 V v;
45 final AtomicInteger refCount = new AtomicInteger(1);
46 Payload(V v) {
47 this.v = v;
48 }
49 }
50
51 @edu.umd.cs.findbugs.annotations.SuppressWarnings(
52 value="AT_OPERATION_SEQUENCE_ON_CONCURRENT_ABSTRACTION",
53 justification="We use the object monitor to serialize operations on the concurrent map")
54 V put(K key, Supplier<V> supplier) {
55 synchronized (this) {
56 Payload<V> oldValue = map.get(key);
57 if (oldValue == null) {
58 oldValue = new Payload<V>(supplier.get());
59 map.put(key, oldValue);
60 return oldValue.v;
61 }
62 oldValue.refCount.incrementAndGet();
63 return oldValue.v;
64 }
65 }
66
67 V get(K k) {
68 Payload<V> p = map.get(k);
69 return p == null ? null : p.v;
70 }
71
72
73
74
75
76
77 V remove(K key) {
78 synchronized (this) {
79 Payload<V> oldValue = map.get(key);
80 if (oldValue != null) {
81 if (oldValue.refCount.decrementAndGet() == 0) {
82 map.remove(key);
83 return null;
84 }
85 return oldValue.v;
86 }
87 }
88 return null;
89 }
90
91 void clear() {
92 map.clear();
93 }
94
95 Set<K> keySet() {
96 return map.keySet();
97 }
98
99 Collection<V> values() {
100 ArrayList<V> values = new ArrayList<V>(map.size());
101 for (Payload<V> v : map.values()) {
102 values.add(v.v);
103 }
104 return values;
105 }
106
107 int size() {
108 return map.size();
109 }
110 }