1
2
3
4
5
6
7
8
9
10
11
12 package org.apache.hadoop.hbase.quotas;
13
14 import java.io.IOException;
15 import java.util.List;
16
17 import org.apache.commons.logging.Log;
18 import org.apache.commons.logging.LogFactory;
19 import org.apache.hadoop.hbase.HBaseIOException;
20 import org.apache.hadoop.hbase.TableName;
21 import org.apache.hadoop.hbase.classification.InterfaceAudience;
22 import org.apache.hadoop.hbase.classification.InterfaceStability;
23 import org.apache.hadoop.hbase.ipc.RpcScheduler;
24 import org.apache.hadoop.hbase.ipc.RpcServer;
25 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos;
26 import org.apache.hadoop.hbase.regionserver.Region;
27 import org.apache.hadoop.hbase.regionserver.RegionServerServices;
28 import org.apache.hadoop.hbase.security.User;
29 import org.apache.hadoop.security.UserGroupInformation;
30
31
32
33
34
35
36
37 @InterfaceAudience.Private
38 @InterfaceStability.Evolving
39 public class RegionServerQuotaManager {
40 private static final Log LOG = LogFactory.getLog(RegionServerQuotaManager.class);
41
42 private final RegionServerServices rsServices;
43
44 private QuotaCache quotaCache = null;
45 private boolean useRetryableThrottlingException;
46
47 public RegionServerQuotaManager(final RegionServerServices rsServices) {
48 this.rsServices = rsServices;
49 }
50
51 public void start(final RpcScheduler rpcScheduler) throws IOException {
52 if (!QuotaUtil.isQuotaEnabled(rsServices.getConfiguration())) {
53 LOG.info("Quota support disabled");
54 return;
55 }
56
57 LOG.info("Initializing quota support");
58
59
60 quotaCache = new QuotaCache(rsServices);
61 quotaCache.start();
62
63 useRetryableThrottlingException = rsServices.getConfiguration()
64 .getBoolean(QuotaUtil.QUOTA_RETRYABLE_THROTTING_EXCEPTION_CONF_KEY,
65 QuotaUtil.QUOTA_RETRYABLE_THROTTING_EXCEPTION_DEFAULT);
66 }
67
68 public void stop() {
69 if (isQuotaEnabled()) {
70 quotaCache.stop("shutdown");
71 }
72 }
73
74 public boolean isQuotaEnabled() {
75 return quotaCache != null;
76 }
77
78 QuotaCache getQuotaCache() {
79 return quotaCache;
80 }
81
82
83
84
85
86
87
88 public OperationQuota getQuota(final UserGroupInformation ugi, final TableName table) {
89 if (isQuotaEnabled() && !table.isSystemTable()) {
90 UserQuotaState userQuotaState = quotaCache.getUserQuotaState(ugi);
91 QuotaLimiter userLimiter = userQuotaState.getTableLimiter(table);
92 boolean useNoop = userLimiter.isBypass();
93 if (userQuotaState.hasBypassGlobals()) {
94 if (LOG.isTraceEnabled()) {
95 LOG.trace("get quota for ugi=" + ugi + " table=" + table + " userLimiter=" + userLimiter);
96 }
97 if (!useNoop) {
98 return new DefaultOperationQuota(this.rsServices.getConfiguration(), userLimiter);
99 }
100 } else {
101 QuotaLimiter nsLimiter = quotaCache.getNamespaceLimiter(table.getNamespaceAsString());
102 QuotaLimiter tableLimiter = quotaCache.getTableLimiter(table);
103 useNoop &= tableLimiter.isBypass() && nsLimiter.isBypass();
104 if (LOG.isTraceEnabled()) {
105 LOG.trace("get quota for ugi=" + ugi + " table=" + table + " userLimiter=" + userLimiter
106 + " tableLimiter=" + tableLimiter + " nsLimiter=" + nsLimiter);
107 }
108 if (!useNoop) {
109 return new DefaultOperationQuota(this.rsServices.getConfiguration(), userLimiter,
110 tableLimiter, nsLimiter);
111 }
112 }
113 }
114 return NoopOperationQuota.get();
115 }
116
117
118
119
120
121
122
123
124
125 public OperationQuota checkQuota(final Region region, final OperationQuota.OperationType type)
126 throws IOException {
127 switch (type) {
128 case SCAN:
129 return checkQuota(region, 0, 0, 1);
130 case GET:
131 return checkQuota(region, 0, 1, 0);
132 case MUTATE:
133 return checkQuota(region, 1, 0, 0);
134 default:
135 throw new RuntimeException("Invalid operation type: " + type);
136 }
137 }
138
139
140
141
142
143
144
145
146
147 public OperationQuota checkQuota(final Region region, final List<ClientProtos.Action> actions)
148 throws IOException {
149 int numWrites = 0;
150 int numReads = 0;
151 for (final ClientProtos.Action action : actions) {
152 if (action.hasMutation()) {
153 numWrites++;
154 } else if (action.hasGet()) {
155 numReads++;
156 }
157 }
158 return checkQuota(region, numWrites, numReads, 0);
159 }
160
161
162
163
164
165
166
167
168
169
170
171 private OperationQuota checkQuota(final Region region, final int numWrites, final int numReads,
172 final int numScans) throws IOException {
173 User user = RpcServer.getRequestUser();
174 UserGroupInformation ugi;
175 if (user != null) {
176 ugi = user.getUGI();
177 } else {
178 ugi = User.getCurrent().getUGI();
179 }
180 TableName table = region.getTableDesc().getTableName();
181
182 OperationQuota quota = getQuota(ugi, table);
183 try {
184 quota.checkQuota(numWrites, numReads, numScans);
185 } catch (HBaseIOException e) {
186 LOG.debug("Throttling exception for user=" + ugi.getUserName() + " table=" + table
187 + " numWrites=" + numWrites + " numReads=" + numReads + " numScans=" + numScans + ": "
188 + e.getMessage());
189
190
191 if (useRetryableThrottlingException) {
192 throw e;
193 } else {
194 throw new ThrottlingException(e.getMessage());
195 }
196 }
197 return quota;
198 }
199 }