2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 package org
.apache
.hadoop
.hbase
.quotas
;
21 import java
.util
.HashMap
;
22 import java
.util
.HashSet
;
26 import org
.apache
.hadoop
.hbase
.TableName
;
27 import org
.apache
.yetus
.audience
.InterfaceAudience
;
28 import org
.apache
.yetus
.audience
.InterfaceStability
;
29 import org
.apache
.hadoop
.hbase
.shaded
.protobuf
.generated
.QuotaProtos
.Quotas
;
30 import org
.apache
.hadoop
.hbase
.util
.EnvironmentEdgeManager
;
33 * In-Memory state of the user quotas
35 @InterfaceAudience.Private
36 @InterfaceStability.Evolving
37 @edu.umd
.cs
.findbugs
.annotations
.SuppressWarnings(value
="IS2_INCONSISTENT_SYNC",
38 justification
="FindBugs seems confused; says bypassGlobals, namepaceLimiters, and " +
39 "tableLimiters are mostly synchronized...but to me it looks like they are totally synchronized")
40 public class UserQuotaState
extends QuotaState
{
41 private Map
<String
, QuotaLimiter
> namespaceLimiters
= null;
42 private Map
<TableName
, QuotaLimiter
> tableLimiters
= null;
43 private boolean bypassGlobals
= false;
45 public UserQuotaState() {
49 public UserQuotaState(final long updateTs
) {
54 public synchronized String
toString() {
55 StringBuilder builder
= new StringBuilder();
56 builder
.append("UserQuotaState(ts=" + getLastUpdate());
57 if (bypassGlobals
) builder
.append(" bypass-globals");
60 builder
.append(" bypass");
62 if (getGlobalLimiterWithoutUpdatingLastQuery() != NoopQuotaLimiter
.get()) {
63 builder
.append(" global-limiter");
66 if (tableLimiters
!= null && !tableLimiters
.isEmpty()) {
68 for (TableName table
: tableLimiters
.keySet()) {
69 builder
.append(" " + table
);
74 if (namespaceLimiters
!= null && !namespaceLimiters
.isEmpty()) {
76 for (String ns
: namespaceLimiters
.keySet()) {
77 builder
.append(" " + ns
);
83 return builder
.toString();
87 * @return true if there is no quota information associated to this object
90 public synchronized boolean isBypass() {
91 return !bypassGlobals
&&
92 getGlobalLimiterWithoutUpdatingLastQuery() == NoopQuotaLimiter
.get() &&
93 (tableLimiters
== null || tableLimiters
.isEmpty()) &&
94 (namespaceLimiters
== null || namespaceLimiters
.isEmpty());
97 public synchronized boolean hasBypassGlobals() {
102 public synchronized void setQuotas(final Quotas quotas
) {
103 super.setQuotas(quotas
);
104 bypassGlobals
= quotas
.getBypassGlobals();
108 * Add the quota information of the specified table.
109 * (This operation is part of the QuotaState setup)
111 public synchronized void setQuotas(final TableName table
, Quotas quotas
) {
112 tableLimiters
= setLimiter(tableLimiters
, table
, quotas
);
116 * Add the quota information of the specified namespace.
117 * (This operation is part of the QuotaState setup)
119 public void setQuotas(final String namespace
, Quotas quotas
) {
120 namespaceLimiters
= setLimiter(namespaceLimiters
, namespace
, quotas
);
123 private <K
> Map
<K
, QuotaLimiter
> setLimiter(Map
<K
, QuotaLimiter
> limiters
,
124 final K key
, final Quotas quotas
) {
125 if (limiters
== null) {
126 limiters
= new HashMap
<>();
129 QuotaLimiter limiter
= quotas
.hasThrottle() ?
130 QuotaLimiterFactory
.fromThrottle(quotas
.getThrottle()) : null;
131 if (limiter
!= null && !limiter
.isBypass()) {
132 limiters
.put(key
, limiter
);
134 limiters
.remove(key
);
140 * Perform an update of the quota state based on the other quota state object.
141 * (This operation is executed by the QuotaCache)
144 public synchronized void update(final QuotaState other
) {
147 if (other
instanceof UserQuotaState
) {
148 UserQuotaState uOther
= (UserQuotaState
)other
;
149 tableLimiters
= updateLimiters(tableLimiters
, uOther
.tableLimiters
);
150 namespaceLimiters
= updateLimiters(namespaceLimiters
, uOther
.namespaceLimiters
);
151 bypassGlobals
= uOther
.bypassGlobals
;
153 tableLimiters
= null;
154 namespaceLimiters
= null;
155 bypassGlobals
= false;
159 private static <K
> Map
<K
, QuotaLimiter
> updateLimiters(final Map
<K
, QuotaLimiter
> map
,
160 final Map
<K
, QuotaLimiter
> otherMap
) {
165 if (otherMap
!= null) {
167 Set
<K
> toRemove
= new HashSet
<>(map
.keySet());
168 toRemove
.removeAll(otherMap
.keySet());
169 map
.keySet().removeAll(toRemove
);
172 for (final Map
.Entry
<K
, QuotaLimiter
> entry
: otherMap
.entrySet()) {
173 QuotaLimiter limiter
= map
.get(entry
.getKey());
174 if (limiter
== null) {
175 limiter
= entry
.getValue();
177 limiter
= QuotaLimiterFactory
.update(limiter
, entry
.getValue());
179 map
.put(entry
.getKey(), limiter
);
187 * Return the limiter for the specified table associated with this quota.
188 * If the table does not have its own quota limiter the global one will be returned.
189 * In case there is no quota limiter associated with this object a noop limiter will be returned.
191 * @return the quota limiter for the specified table
193 public synchronized QuotaLimiter
getTableLimiter(final TableName table
) {
194 lastQuery
= EnvironmentEdgeManager
.currentTime();
195 if (tableLimiters
!= null) {
196 QuotaLimiter limiter
= tableLimiters
.get(table
);
197 if (limiter
!= null) return limiter
;
199 if (namespaceLimiters
!= null) {
200 QuotaLimiter limiter
= namespaceLimiters
.get(table
.getNamespaceAsString());
201 if (limiter
!= null) return limiter
;
203 return getGlobalLimiterWithoutUpdatingLastQuery();