1
2
3
4
5
6
7
8
9
10
11
12 package org.apache.hadoop.hbase.quotas;
13
14 import java.io.ByteArrayInputStream;
15 import java.io.ByteArrayOutputStream;
16 import java.io.IOException;
17 import java.util.HashMap;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Objects;
21 import java.util.regex.Pattern;
22
23 import org.apache.commons.logging.Log;
24 import org.apache.commons.logging.LogFactory;
25 import org.apache.hadoop.hbase.Cell;
26 import org.apache.hadoop.hbase.NamespaceDescriptor;
27 import org.apache.hadoop.hbase.ServerName;
28 import org.apache.hadoop.hbase.TableName;
29 import org.apache.hadoop.hbase.classification.InterfaceAudience;
30 import org.apache.hadoop.hbase.classification.InterfaceStability;
31 import org.apache.hadoop.hbase.client.ClusterConnection;
32 import org.apache.hadoop.hbase.client.Connection;
33 import org.apache.hadoop.hbase.client.Get;
34 import org.apache.hadoop.hbase.client.Put;
35 import org.apache.hadoop.hbase.client.QuotaStatusCalls;
36 import org.apache.hadoop.hbase.client.Result;
37 import org.apache.hadoop.hbase.client.ResultScanner;
38 import org.apache.hadoop.hbase.client.Scan;
39 import org.apache.hadoop.hbase.client.Table;
40 import org.apache.hadoop.hbase.filter.CompareFilter;
41 import org.apache.hadoop.hbase.filter.Filter;
42 import org.apache.hadoop.hbase.filter.FilterList;
43 import org.apache.hadoop.hbase.filter.QualifierFilter;
44 import org.apache.hadoop.hbase.filter.RegexStringComparator;
45 import org.apache.hadoop.hbase.filter.RowFilter;
46 import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
47 import org.apache.hadoop.hbase.protobuf.generated.TableProtos;
48 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos;
49 import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos;
50 import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.GetQuotaStatesResponse;
51 import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.GetSpaceQuotaRegionSizesResponse;
52 import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.GetSpaceQuotaSnapshotsResponse;
53 import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.GetSpaceQuotaSnapshotsResponse.TableQuotaSnapshot;
54 import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.GetSpaceQuotaRegionSizesResponse.RegionSizes;
55 import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Quotas;
56 import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.SpaceQuota;
57 import org.apache.hadoop.hbase.ipc.RpcControllerFactory;
58 import org.apache.hadoop.hbase.util.Bytes;
59 import org.apache.hadoop.hbase.util.Strings;
60
61 import com.google.protobuf.ByteString;
62 import com.google.protobuf.HBaseZeroCopyByteString;
63 import com.google.protobuf.InvalidProtocolBufferException;
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79 @InterfaceAudience.Private
80 @InterfaceStability.Evolving
81 public class QuotaTableUtil {
82 private static final Log LOG = LogFactory.getLog(QuotaTableUtil.class);
83
84
85 public static final TableName QUOTA_TABLE_NAME = TableName.valueOf(
86 NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR, "quota");
87
88 protected static final byte[] QUOTA_FAMILY_INFO = Bytes.toBytes("q");
89 protected static final byte[] QUOTA_FAMILY_USAGE = Bytes.toBytes("u");
90 protected static final byte[] QUOTA_QUALIFIER_SETTINGS = Bytes.toBytes("s");
91 protected static final byte[] QUOTA_QUALIFIER_SETTINGS_PREFIX = Bytes.toBytes("s.");
92 protected static final byte[] QUOTA_QUALIFIER_POLICY = Bytes.toBytes("p");
93 protected static final String QUOTA_POLICY_COLUMN =
94 Bytes.toString(QUOTA_FAMILY_USAGE) + ":" + Bytes.toString(QUOTA_QUALIFIER_POLICY);
95 protected static final byte[] QUOTA_USER_ROW_KEY_PREFIX = Bytes.toBytes("u.");
96 protected static final byte[] QUOTA_TABLE_ROW_KEY_PREFIX = Bytes.toBytes("t.");
97 protected static final byte[] QUOTA_NAMESPACE_ROW_KEY_PREFIX = Bytes.toBytes("n.");
98
99
100
101
102
103 public static Quotas getTableQuota(final Connection connection, final TableName table)
104 throws IOException {
105 return getQuotas(connection, getTableRowKey(table));
106 }
107
108 public static Quotas getNamespaceQuota(final Connection connection, final String namespace)
109 throws IOException {
110 return getQuotas(connection, getNamespaceRowKey(namespace));
111 }
112
113 public static Quotas getUserQuota(final Connection connection, final String user)
114 throws IOException {
115 return getQuotas(connection, getUserRowKey(user));
116 }
117
118 public static Quotas getUserQuota(final Connection connection, final String user,
119 final TableName table) throws IOException {
120 return getQuotas(connection, getUserRowKey(user), getSettingsQualifierForUserTable(table));
121 }
122
123 public static Quotas getUserQuota(final Connection connection, final String user,
124 final String namespace) throws IOException {
125 return getQuotas(connection, getUserRowKey(user),
126 getSettingsQualifierForUserNamespace(namespace));
127 }
128
129 private static Quotas getQuotas(final Connection connection, final byte[] rowKey)
130 throws IOException {
131 return getQuotas(connection, rowKey, QUOTA_QUALIFIER_SETTINGS);
132 }
133
134 private static Quotas getQuotas(final Connection connection, final byte[] rowKey,
135 final byte[] qualifier) throws IOException {
136 Get get = new Get(rowKey);
137 get.addColumn(QUOTA_FAMILY_INFO, qualifier);
138 Result result = doGet(connection, get);
139 if (result.isEmpty()) {
140 return null;
141 }
142 return quotasFromData(result.getValue(QUOTA_FAMILY_INFO, qualifier));
143 }
144
145 public static Get makeGetForTableQuotas(final TableName table) {
146 Get get = new Get(getTableRowKey(table));
147 get.addFamily(QUOTA_FAMILY_INFO);
148 return get;
149 }
150
151 public static Get makeGetForNamespaceQuotas(final String namespace) {
152 Get get = new Get(getNamespaceRowKey(namespace));
153 get.addFamily(QUOTA_FAMILY_INFO);
154 return get;
155 }
156
157 public static Get makeGetForUserQuotas(final String user, final Iterable<TableName> tables,
158 final Iterable<String> namespaces) {
159 Get get = new Get(getUserRowKey(user));
160 get.addColumn(QUOTA_FAMILY_INFO, QUOTA_QUALIFIER_SETTINGS);
161 for (final TableName table : tables) {
162 get.addColumn(QUOTA_FAMILY_INFO, getSettingsQualifierForUserTable(table));
163 }
164 for (final String ns : namespaces) {
165 get.addColumn(QUOTA_FAMILY_INFO, getSettingsQualifierForUserNamespace(ns));
166 }
167 return get;
168 }
169
170 public static Scan makeScan(final QuotaFilter filter) {
171 Scan scan = new Scan();
172 scan.addFamily(QUOTA_FAMILY_INFO);
173 if (filter != null && !filter.isNull()) {
174 scan.setFilter(makeFilter(filter));
175 }
176 return scan;
177 }
178
179
180
181
182 public static Filter makeFilter(final QuotaFilter filter) {
183 FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ALL);
184 if (!Strings.isEmpty(filter.getUserFilter())) {
185 FilterList userFilters = new FilterList(FilterList.Operator.MUST_PASS_ONE);
186 boolean hasFilter = false;
187
188 if (!Strings.isEmpty(filter.getNamespaceFilter())) {
189 FilterList nsFilters = new FilterList(FilterList.Operator.MUST_PASS_ALL);
190 nsFilters.addFilter(new RowFilter(CompareFilter.CompareOp.EQUAL, new RegexStringComparator(
191 getUserRowKeyRegex(filter.getUserFilter()), 0)));
192 nsFilters.addFilter(new QualifierFilter(CompareFilter.CompareOp.EQUAL,
193 new RegexStringComparator(getSettingsQualifierRegexForUserNamespace(filter
194 .getNamespaceFilter()), 0)));
195 userFilters.addFilter(nsFilters);
196 hasFilter = true;
197 }
198 if (!Strings.isEmpty(filter.getTableFilter())) {
199 FilterList tableFilters = new FilterList(FilterList.Operator.MUST_PASS_ALL);
200 tableFilters.addFilter(new RowFilter(CompareFilter.CompareOp.EQUAL,
201 new RegexStringComparator(getUserRowKeyRegex(filter.getUserFilter()), 0)));
202 tableFilters.addFilter(new QualifierFilter(CompareFilter.CompareOp.EQUAL,
203 new RegexStringComparator(
204 getSettingsQualifierRegexForUserTable(filter.getTableFilter()), 0)));
205 userFilters.addFilter(tableFilters);
206 hasFilter = true;
207 }
208 if (!hasFilter) {
209 userFilters.addFilter(new RowFilter(CompareFilter.CompareOp.EQUAL,
210 new RegexStringComparator(getUserRowKeyRegex(filter.getUserFilter()), 0)));
211 }
212
213 filterList.addFilter(userFilters);
214 } else if (!Strings.isEmpty(filter.getTableFilter())) {
215 filterList.addFilter(new RowFilter(CompareFilter.CompareOp.EQUAL, new RegexStringComparator(
216 getTableRowKeyRegex(filter.getTableFilter()), 0)));
217 } else if (!Strings.isEmpty(filter.getNamespaceFilter())) {
218 filterList.addFilter(new RowFilter(CompareFilter.CompareOp.EQUAL, new RegexStringComparator(
219 getNamespaceRowKeyRegex(filter.getNamespaceFilter()), 0)));
220 }
221 return filterList;
222 }
223
224
225
226
227 public static Scan makeQuotaSnapshotScan() {
228 Scan s = new Scan();
229
230 s.addColumn(QUOTA_FAMILY_USAGE, QUOTA_QUALIFIER_POLICY);
231
232 s.setRowPrefixFilter(QUOTA_TABLE_ROW_KEY_PREFIX);
233 return s;
234 }
235
236
237
238
239
240
241
242 public static Map<TableName,SpaceQuotaSnapshot> getSnapshots(Connection conn) throws IOException {
243 Map<TableName,SpaceQuotaSnapshot> snapshots = new HashMap<>();
244 try (Table quotaTable = conn.getTable(QUOTA_TABLE_NAME);
245 ResultScanner rs = quotaTable.getScanner(makeQuotaSnapshotScan())) {
246 for (Result r : rs) {
247 extractQuotaSnapshot(r, snapshots);
248 }
249 }
250 return snapshots;
251 }
252
253
254
255
256
257
258
259
260
261
262 public static void extractQuotaSnapshot(
263 Result result, Map<TableName,SpaceQuotaSnapshot> snapshots) {
264 byte[] row = Objects.requireNonNull(result).getRow();
265 if (row == null) {
266 throw new IllegalArgumentException("Provided result had a null row");
267 }
268 final TableName targetTableName = getTableFromRowKey(row);
269 Cell c = result.getColumnLatestCell(QUOTA_FAMILY_USAGE, QUOTA_QUALIFIER_POLICY);
270 if (c == null) {
271 throw new IllegalArgumentException("Result did not contain the expected column "
272 + QUOTA_POLICY_COLUMN + ", " + result.toString());
273 }
274 ByteString buffer = HBaseZeroCopyByteString.wrap(
275 c.getValueArray(), c.getValueOffset(), c.getValueLength());
276 try {
277 QuotaProtos.SpaceQuotaSnapshot snapshot = QuotaProtos.SpaceQuotaSnapshot.parseFrom(buffer);
278 snapshots.put(targetTableName, SpaceQuotaSnapshot.toSpaceQuotaSnapshot(snapshot));
279 } catch (InvalidProtocolBufferException e) {
280 throw new IllegalArgumentException(
281 "Result did not contain a valid SpaceQuota protocol buffer message", e);
282 }
283 }
284
285 public static interface UserQuotasVisitor {
286 void visitUserQuotas(final String userName, final Quotas quotas) throws IOException;
287
288 void visitUserQuotas(final String userName, final TableName table, final Quotas quotas)
289 throws IOException;
290
291 void visitUserQuotas(final String userName, final String namespace, final Quotas quotas)
292 throws IOException;
293 }
294
295 public static interface TableQuotasVisitor {
296 void visitTableQuotas(final TableName tableName, final Quotas quotas) throws IOException;
297 }
298
299 public static interface NamespaceQuotasVisitor {
300 void visitNamespaceQuotas(final String namespace, final Quotas quotas) throws IOException;
301 }
302
303 public static interface QuotasVisitor extends UserQuotasVisitor, TableQuotasVisitor,
304 NamespaceQuotasVisitor {
305 }
306
307 public static void parseResult(final Result result, final QuotasVisitor visitor)
308 throws IOException {
309 byte[] row = result.getRow();
310 if (isNamespaceRowKey(row)) {
311 parseNamespaceResult(result, visitor);
312 } else if (isTableRowKey(row)) {
313 parseTableResult(result, visitor);
314 } else if (isUserRowKey(row)) {
315 parseUserResult(result, visitor);
316 } else {
317 LOG.warn("unexpected row-key: " + Bytes.toString(row));
318 }
319 }
320
321 public static void
322 parseNamespaceResult(final Result result, final NamespaceQuotasVisitor visitor)
323 throws IOException {
324 String namespace = getNamespaceFromRowKey(result.getRow());
325 parseNamespaceResult(namespace, result, visitor);
326 }
327
328 protected static void parseNamespaceResult(final String namespace, final Result result,
329 final NamespaceQuotasVisitor visitor) throws IOException {
330 byte[] data = result.getValue(QUOTA_FAMILY_INFO, QUOTA_QUALIFIER_SETTINGS);
331 if (data != null) {
332 Quotas quotas = quotasFromData(data);
333 visitor.visitNamespaceQuotas(namespace, quotas);
334 }
335 }
336
337 public static void parseTableResult(final Result result, final TableQuotasVisitor visitor)
338 throws IOException {
339 TableName table = getTableFromRowKey(result.getRow());
340 parseTableResult(table, result, visitor);
341 }
342
343 protected static void parseTableResult(final TableName table, final Result result,
344 final TableQuotasVisitor visitor) throws IOException {
345 byte[] data = result.getValue(QUOTA_FAMILY_INFO, QUOTA_QUALIFIER_SETTINGS);
346 if (data != null) {
347 Quotas quotas = quotasFromData(data);
348 visitor.visitTableQuotas(table, quotas);
349 }
350 }
351
352 public static void parseUserResult(final Result result, final UserQuotasVisitor visitor)
353 throws IOException {
354 String userName = getUserFromRowKey(result.getRow());
355 parseUserResult(userName, result, visitor);
356 }
357
358 protected static void parseUserResult(final String userName, final Result result,
359 final UserQuotasVisitor visitor) throws IOException {
360 Map<byte[], byte[]> familyMap = result.getFamilyMap(QUOTA_FAMILY_INFO);
361 if (familyMap == null || familyMap.isEmpty()) return;
362
363 for (Map.Entry<byte[], byte[]> entry : familyMap.entrySet()) {
364 Quotas quotas = quotasFromData(entry.getValue());
365 if (Bytes.startsWith(entry.getKey(), QUOTA_QUALIFIER_SETTINGS_PREFIX)) {
366 String name = Bytes.toString(entry.getKey(), QUOTA_QUALIFIER_SETTINGS_PREFIX.length);
367 if (name.charAt(name.length() - 1) == TableName.NAMESPACE_DELIM) {
368 String namespace = name.substring(0, name.length() - 1);
369 visitor.visitUserQuotas(userName, namespace, quotas);
370 } else {
371 TableName table = TableName.valueOf(name);
372 visitor.visitUserQuotas(userName, table, quotas);
373 }
374 } else if (Bytes.equals(entry.getKey(), QUOTA_QUALIFIER_SETTINGS)) {
375 visitor.visitUserQuotas(userName, quotas);
376 }
377 }
378 }
379
380
381
382
383
384 public static Put putSpaceSnapshot(TableName tableName, SpaceQuotaSnapshot snapshot) {
385 Put p = new Put(getTableRowKey(tableName));
386 p.addColumn(QUOTA_FAMILY_USAGE, QUOTA_QUALIFIER_POLICY, SpaceQuotaSnapshot.toProtoSnapshot(snapshot).toByteArray());
387 return p;
388 }
389
390
391
392
393
394
395
396
397 public static Map<TableName,Long> getMasterReportedTableSizes(
398 Connection conn) throws IOException {
399 if (!(conn instanceof ClusterConnection)) {
400 throw new IllegalArgumentException("Expected a ClusterConnection");
401 }
402 ClusterConnection clusterConn = (ClusterConnection) conn;
403 GetSpaceQuotaRegionSizesResponse response = QuotaStatusCalls.getMasterRegionSizes(
404 clusterConn, 0);
405 Map<TableName,Long> tableSizes = new HashMap<>();
406 for (RegionSizes sizes : response.getSizesList()) {
407 TableName tn = ProtobufUtil.toTableName(sizes.getTableName());
408 tableSizes.put(tn, sizes.getSize());
409 }
410 return tableSizes;
411 }
412
413
414
415
416 public static Map<TableName,SpaceQuotaSnapshot> getRegionServerQuotaSnapshots(
417 Connection conn, ServerName regionServer) throws IOException {
418 if (!(conn instanceof ClusterConnection)) {
419 throw new IllegalArgumentException("Expected a ClusterConnection");
420 }
421 ClusterConnection clusterConn = (ClusterConnection) conn;
422 GetSpaceQuotaSnapshotsResponse response = QuotaStatusCalls.getRegionServerQuotaSnapshot(
423 clusterConn, 0, regionServer);
424 Map<TableName,SpaceQuotaSnapshot> snapshots = new HashMap<>();
425 for (TableQuotaSnapshot snapshot : response.getSnapshotsList()) {
426 snapshots.put(
427 ProtobufUtil.toTableName(snapshot.getTableName()),
428 SpaceQuotaSnapshot.toSpaceQuotaSnapshot(snapshot.getSnapshot()));
429 }
430 return snapshots;
431 }
432
433
434
435
436
437 public static SpaceQuotaSnapshot getCurrentSnapshot(
438 Connection conn, TableName tn) throws IOException {
439 if (!(conn instanceof ClusterConnection)) {
440 throw new IllegalArgumentException("Expected a ClusterConnection");
441 }
442 ClusterConnection clusterConn = (ClusterConnection) conn;
443 GetQuotaStatesResponse resp = QuotaStatusCalls.getMasterQuotaStates(clusterConn, 0);
444 TableProtos.TableName protoTableName = ProtobufUtil.toProtoTableName(tn);
445 for (GetQuotaStatesResponse.TableQuotaSnapshot tableSnapshot : resp.getTableSnapshotsList()) {
446 if (protoTableName.equals(tableSnapshot.getTableName())) {
447 return SpaceQuotaSnapshot.toSpaceQuotaSnapshot(tableSnapshot.getSnapshot());
448 }
449 }
450 return null;
451 }
452
453
454
455
456
457 public static SpaceQuotaSnapshot getCurrentSnapshot(
458 Connection conn, String namespace) throws IOException {
459 if (!(conn instanceof ClusterConnection)) {
460 throw new IllegalArgumentException("Expected a ClusterConnection");
461 }
462 ClusterConnection clusterConn = (ClusterConnection) conn;
463 GetQuotaStatesResponse resp = QuotaStatusCalls.getMasterQuotaStates(clusterConn, 0);
464 for (GetQuotaStatesResponse.NamespaceQuotaSnapshot nsSnapshot : resp.getNsSnapshotsList()) {
465 if (namespace.equals(nsSnapshot.getNamespace())) {
466 return SpaceQuotaSnapshot.toSpaceQuotaSnapshot(nsSnapshot.getSnapshot());
467 }
468 }
469 return null;
470 }
471
472
473
474
475 protected static Quotas quotasFromData(final byte[] data) throws IOException {
476 return quotasFromData(data, 0, data.length);
477 }
478
479 protected static Quotas quotasFromData(
480 final byte[] data, int offset, int length) throws IOException {
481 int magicLen = ProtobufUtil.lengthOfPBMagic();
482 if (!ProtobufUtil.isPBMagicPrefix(data, offset, magicLen)) {
483 throw new IOException("Missing pb magic prefix");
484 }
485 return Quotas.parseFrom(new ByteArrayInputStream(data, offset + magicLen, length - magicLen));
486 }
487
488 protected static byte[] quotasToData(final Quotas data) throws IOException {
489 ByteArrayOutputStream stream = new ByteArrayOutputStream();
490 stream.write(ProtobufUtil.PB_MAGIC);
491 data.writeTo(stream);
492 return stream.toByteArray();
493 }
494
495 public static boolean isEmptyQuota(final Quotas quotas) {
496 boolean hasSettings = false;
497 hasSettings |= quotas.hasThrottle();
498 hasSettings |= quotas.hasBypassGlobals();
499
500
501 if (quotas.hasSpace()) {
502 hasSettings |= (quotas.getSpace().hasSoftLimit() && quotas.getSpace().hasViolationPolicy());
503 }
504 return !hasSettings;
505 }
506
507
508
509
510 protected static Result doGet(final Connection connection, final Get get) throws IOException {
511 try (Table table = connection.getTable(QUOTA_TABLE_NAME)) {
512 return table.get(get);
513 }
514 }
515
516 protected static Result[] doGet(final Connection connection, final List<Get> gets)
517 throws IOException {
518 try (Table table = connection.getTable(QUOTA_TABLE_NAME)) {
519 return table.get(gets);
520 }
521 }
522
523
524
525
526
527 protected static byte[] getUserRowKey(final String user) {
528 return Bytes.add(QUOTA_USER_ROW_KEY_PREFIX, Bytes.toBytes(user));
529 }
530
531 protected static byte[] getTableRowKey(final TableName table) {
532 return Bytes.add(QUOTA_TABLE_ROW_KEY_PREFIX, table.getName());
533 }
534
535 protected static byte[] getNamespaceRowKey(final String namespace) {
536 return Bytes.add(QUOTA_NAMESPACE_ROW_KEY_PREFIX, Bytes.toBytes(namespace));
537 }
538
539 protected static byte[] getSettingsQualifierForUserTable(final TableName tableName) {
540 return Bytes.add(QUOTA_QUALIFIER_SETTINGS_PREFIX, tableName.getName());
541 }
542
543 protected static byte[] getSettingsQualifierForUserNamespace(final String namespace) {
544 return Bytes.add(QUOTA_QUALIFIER_SETTINGS_PREFIX,
545 Bytes.toBytes(namespace + TableName.NAMESPACE_DELIM));
546 }
547
548 protected static String getUserRowKeyRegex(final String user) {
549 return getRowKeyRegEx(QUOTA_USER_ROW_KEY_PREFIX, user);
550 }
551
552 protected static String getTableRowKeyRegex(final String table) {
553 return getRowKeyRegEx(QUOTA_TABLE_ROW_KEY_PREFIX, table);
554 }
555
556 protected static String getNamespaceRowKeyRegex(final String namespace) {
557 return getRowKeyRegEx(QUOTA_NAMESPACE_ROW_KEY_PREFIX, namespace);
558 }
559
560 private static String getRowKeyRegEx(final byte[] prefix, final String regex) {
561 return '^' + Pattern.quote(Bytes.toString(prefix)) + regex + '$';
562 }
563
564 protected static String getSettingsQualifierRegexForUserTable(final String table) {
565 return '^' + Pattern.quote(Bytes.toString(QUOTA_QUALIFIER_SETTINGS_PREFIX)) + table + "(?<!"
566 + Pattern.quote(Character.toString(TableName.NAMESPACE_DELIM)) + ")$";
567 }
568
569 protected static String getSettingsQualifierRegexForUserNamespace(final String namespace) {
570 return '^' + Pattern.quote(Bytes.toString(QUOTA_QUALIFIER_SETTINGS_PREFIX)) + namespace
571 + Pattern.quote(Character.toString(TableName.NAMESPACE_DELIM)) + '$';
572 }
573
574 protected static boolean isNamespaceRowKey(final byte[] key) {
575 return Bytes.startsWith(key, QUOTA_NAMESPACE_ROW_KEY_PREFIX);
576 }
577
578 protected static String getNamespaceFromRowKey(final byte[] key) {
579 return Bytes.toString(key, QUOTA_NAMESPACE_ROW_KEY_PREFIX.length);
580 }
581
582 protected static boolean isTableRowKey(final byte[] key) {
583 return Bytes.startsWith(key, QUOTA_TABLE_ROW_KEY_PREFIX);
584 }
585
586 protected static TableName getTableFromRowKey(final byte[] key) {
587 return TableName.valueOf(Bytes.toString(key, QUOTA_TABLE_ROW_KEY_PREFIX.length));
588 }
589
590 protected static boolean isUserRowKey(final byte[] key) {
591 return Bytes.startsWith(key, QUOTA_USER_ROW_KEY_PREFIX);
592 }
593
594 protected static String getUserFromRowKey(final byte[] key) {
595 return Bytes.toString(key, QUOTA_USER_ROW_KEY_PREFIX.length);
596 }
597
598 protected static SpaceQuota getProtoViolationPolicy(SpaceViolationPolicy policy) {
599 return SpaceQuota.newBuilder()
600 .setViolationPolicy(ProtobufUtil.toProtoViolationPolicy(policy))
601 .build();
602 }
603
604 protected static SpaceViolationPolicy getViolationPolicy(SpaceQuota proto) {
605 if (!proto.hasViolationPolicy()) {
606 throw new IllegalArgumentException("Protobuf SpaceQuota does not have violation policy.");
607 }
608 return ProtobufUtil.toViolationPolicy(proto.getViolationPolicy());
609 }
610 }