1
2
3
4
5
6
7
8
9
10
11
12 package org.apache.hadoop.hbase.quotas;
13
14 import java.util.HashMap;
15 import java.util.HashSet;
16 import java.util.Map;
17 import java.util.Set;
18
19 import org.apache.hadoop.hbase.TableName;
20 import org.apache.hadoop.hbase.classification.InterfaceAudience;
21 import org.apache.hadoop.hbase.classification.InterfaceStability;
22 import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Quotas;
23 import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
24
25
26
27
28 @InterfaceAudience.Private
29 @InterfaceStability.Evolving
30 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="IS2_INCONSISTENT_SYNC",
31 justification="FindBugs seems confused; says bypassGlobals, namepaceLimiters, and " +
32 "tableLimiters are mostly synchronized...but to me it looks like they are totally synchronized")
33 public class UserQuotaState extends QuotaState {
34 private Map<String, QuotaLimiter> namespaceLimiters = null;
35 private Map<TableName, QuotaLimiter> tableLimiters = null;
36 private boolean bypassGlobals = false;
37
38 public UserQuotaState() {
39 super();
40 }
41
42 public UserQuotaState(final long updateTs) {
43 super(updateTs);
44 }
45
46 @Override
47 public synchronized String toString() {
48 StringBuilder builder = new StringBuilder();
49 builder.append("UserQuotaState(ts=" + getLastUpdate());
50 if (bypassGlobals) builder.append(" bypass-globals");
51
52 if (isBypass()) {
53 builder.append(" bypass");
54 } else {
55 if (getGlobalLimiterWithoutUpdatingLastQuery() != NoopQuotaLimiter.get()) {
56 builder.append(" global-limiter");
57 }
58
59 if (tableLimiters != null && !tableLimiters.isEmpty()) {
60 builder.append(" [");
61 for (TableName table : tableLimiters.keySet()) {
62 builder.append(" " + table);
63 }
64 builder.append(" ]");
65 }
66
67 if (namespaceLimiters != null && !namespaceLimiters.isEmpty()) {
68 builder.append(" [");
69 for (String ns : namespaceLimiters.keySet()) {
70 builder.append(" " + ns);
71 }
72 builder.append(" ]");
73 }
74 }
75 builder.append(')');
76 return builder.toString();
77 }
78
79
80
81
82 @Override
83 public synchronized boolean isBypass() {
84 return !bypassGlobals && getGlobalLimiterWithoutUpdatingLastQuery() == NoopQuotaLimiter.get()
85 && (tableLimiters == null || tableLimiters.isEmpty())
86 && (namespaceLimiters == null || namespaceLimiters.isEmpty());
87 }
88
89 public synchronized boolean hasBypassGlobals() {
90 return bypassGlobals;
91 }
92
93 @Override
94 public synchronized void setQuotas(final Quotas quotas) {
95 super.setQuotas(quotas);
96 bypassGlobals = quotas.getBypassGlobals();
97 }
98
99
100
101
102
103 public synchronized void setQuotas(final TableName table, Quotas quotas) {
104 tableLimiters = setLimiter(tableLimiters, table, quotas);
105 }
106
107
108
109
110
111 public synchronized void setQuotas(final String namespace, Quotas quotas) {
112 namespaceLimiters = setLimiter(namespaceLimiters, namespace, quotas);
113 }
114
115 private <K> Map<K, QuotaLimiter> setLimiter(Map<K, QuotaLimiter> limiters, final K key,
116 final Quotas quotas) {
117 if (limiters == null) {
118 limiters = new HashMap<K, QuotaLimiter>();
119 }
120
121 QuotaLimiter limiter =
122 quotas.hasThrottle() ? QuotaLimiterFactory.fromThrottle(quotas.getThrottle()) : null;
123 if (limiter != null && !limiter.isBypass()) {
124 limiters.put(key, limiter);
125 } else {
126 limiters.remove(key);
127 }
128 return limiters;
129 }
130
131
132
133
134
135 @Override
136 public synchronized void update(final QuotaState other) {
137 super.update(other);
138
139 if (other instanceof UserQuotaState) {
140 UserQuotaState uOther = (UserQuotaState) other;
141 tableLimiters = updateLimiters(tableLimiters, uOther.tableLimiters);
142 namespaceLimiters = updateLimiters(namespaceLimiters, uOther.namespaceLimiters);
143 bypassGlobals = uOther.bypassGlobals;
144 } else {
145 tableLimiters = null;
146 namespaceLimiters = null;
147 bypassGlobals = false;
148 }
149 }
150
151 private static <K> Map<K, QuotaLimiter> updateLimiters(final Map<K, QuotaLimiter> map,
152 final Map<K, QuotaLimiter> otherMap) {
153 if (map == null) {
154 return otherMap;
155 }
156
157 if (otherMap != null) {
158
159 Set<K> toRemove = new HashSet<K>(map.keySet());
160 toRemove.removeAll(otherMap.keySet());
161 map.keySet().removeAll(toRemove);
162
163
164 for (final Map.Entry<K, QuotaLimiter> entry : otherMap.entrySet()) {
165 QuotaLimiter limiter = map.get(entry.getKey());
166 if (limiter == null) {
167 limiter = entry.getValue();
168 } else {
169 limiter = QuotaLimiterFactory.update(limiter, entry.getValue());
170 }
171 map.put(entry.getKey(), limiter);
172 }
173 return map;
174 }
175 return null;
176 }
177
178
179
180
181
182
183
184 public synchronized QuotaLimiter getTableLimiter(final TableName table) {
185 setLastQuery(EnvironmentEdgeManager.currentTime());
186 if (tableLimiters != null) {
187 QuotaLimiter limiter = tableLimiters.get(table);
188 if (limiter != null) return limiter;
189 }
190 if (namespaceLimiters != null) {
191 QuotaLimiter limiter = namespaceLimiters.get(table.getNamespaceAsString());
192 if (limiter != null) return limiter;
193 }
194 return getGlobalLimiterWithoutUpdatingLastQuery();
195 }
196 }