1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.hadoop.hbase.quotas;
18
19 import java.io.IOException;
20 import java.util.Collections;
21 import java.util.HashSet;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Objects;
25 import java.util.Set;
26 import java.util.concurrent.ConcurrentHashMap;
27 import java.util.concurrent.TimeUnit;
28
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31 import org.apache.hadoop.conf.Configuration;
32 import org.apache.hadoop.hbase.HRegionInfo;
33 import org.apache.hadoop.hbase.ScheduledChore;
34 import org.apache.hadoop.hbase.Stoppable;
35 import org.apache.hadoop.hbase.TableName;
36 import org.apache.hadoop.hbase.client.Connection;
37 import org.apache.hadoop.hbase.client.Scan;
38 import org.apache.hadoop.hbase.master.HMaster;
39 import org.apache.hadoop.hbase.quotas.QuotaSnapshotStore.ViolationState;
40 import org.apache.hadoop.hbase.master.MetricsMaster;
41 import org.apache.hadoop.hbase.quotas.SpaceQuotaSnapshot;
42 import org.apache.hadoop.hbase.quotas.SpaceQuotaSnapshot.SpaceQuotaStatus;
43 import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
44 import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.SpaceQuota;
45
46 import com.google.common.annotations.VisibleForTesting;
47 import com.google.common.collect.HashMultimap;
48 import com.google.common.collect.Iterables;
49 import com.google.common.collect.Multimap;
50
51
52
53
54
55 public class QuotaObserverChore extends ScheduledChore {
56 private static final Log LOG = LogFactory.getLog(QuotaObserverChore.class);
57 static final String QUOTA_OBSERVER_CHORE_PERIOD_KEY =
58 "hbase.master.quotas.observer.chore.period";
59 static final int QUOTA_OBSERVER_CHORE_PERIOD_DEFAULT = 1000 * 60 * 1;
60
61 static final String QUOTA_OBSERVER_CHORE_DELAY_KEY =
62 "hbase.master.quotas.observer.chore.delay";
63 static final long QUOTA_OBSERVER_CHORE_DELAY_DEFAULT = 1000L * 15L;
64
65 static final String QUOTA_OBSERVER_CHORE_TIMEUNIT_KEY =
66 "hbase.master.quotas.observer.chore.timeunit";
67 static final String QUOTA_OBSERVER_CHORE_TIMEUNIT_DEFAULT = TimeUnit.MILLISECONDS.name();
68
69 static final String QUOTA_OBSERVER_CHORE_REPORT_PERCENT_KEY =
70 "hbase.master.quotas.observer.report.percent";
71 static final double QUOTA_OBSERVER_CHORE_REPORT_PERCENT_DEFAULT= 0.95;
72
73 static final String REGION_REPORT_RETENTION_DURATION_KEY =
74 "hbase.master.quotas.region.report.retention.millis";
75 static final long REGION_REPORT_RETENTION_DURATION_DEFAULT =
76 1000 * 60 * 10;
77
78
79 private final Connection conn;
80 private final Configuration conf;
81 private final MasterQuotaManager quotaManager;
82 private final MetricsMaster metrics;
83
84
85
86 private final SpaceQuotaSnapshotNotifier snapshotNotifier;
87
88
89
90
91 private final Map<TableName,SpaceQuotaSnapshot> tableQuotaSnapshots;
92 private final Map<TableName,SpaceQuotaSnapshot> readOnlyTableQuotaSnapshots;
93 private final Map<String,SpaceQuotaSnapshot> namespaceQuotaSnapshots;
94 private final Map<String,SpaceQuotaSnapshot> readOnlyNamespaceSnapshots;
95
96
97 private final long regionReportLifetimeMillis;
98
99
100
101
102 private QuotaSnapshotStore<TableName> tableSnapshotStore;
103 private QuotaSnapshotStore<String> namespaceSnapshotStore;
104
105 public QuotaObserverChore(HMaster master, MetricsMaster metrics) {
106 this(
107 master.getConnection(), master.getConfiguration(),
108 master.getSpaceQuotaSnapshotNotifier(), master.getMasterQuotaManager(),
109 master, metrics);
110 }
111
112 QuotaObserverChore(
113 Connection conn, Configuration conf, SpaceQuotaSnapshotNotifier snapshotNotifier,
114 MasterQuotaManager quotaManager, Stoppable stopper, MetricsMaster metrics) {
115 super(
116 QuotaObserverChore.class.getSimpleName(), stopper, getPeriod(conf),
117 getInitialDelay(conf), getTimeUnit(conf));
118 this.conn = conn;
119 this.conf = conf;
120 this.metrics = metrics;
121 this.quotaManager = quotaManager;
122 this.snapshotNotifier = Objects.requireNonNull(snapshotNotifier);
123 this.tableQuotaSnapshots = new ConcurrentHashMap<>();
124 this.readOnlyTableQuotaSnapshots = Collections.unmodifiableMap(tableQuotaSnapshots);
125 this.namespaceQuotaSnapshots = new ConcurrentHashMap<>();
126 this.readOnlyNamespaceSnapshots = Collections.unmodifiableMap(namespaceQuotaSnapshots);
127 this.regionReportLifetimeMillis = conf.getLong(
128 REGION_REPORT_RETENTION_DURATION_KEY, REGION_REPORT_RETENTION_DURATION_DEFAULT);
129 }
130
131 @Override
132 protected void chore() {
133 try {
134 if (LOG.isTraceEnabled()) {
135 LOG.trace("Refreshing space quotas in RegionServer");
136 }
137 long start = System.nanoTime();
138 _chore();
139 if (metrics != null) {
140 metrics.incrementQuotaObserverTime((System.nanoTime() - start) / 1_000_000);
141 }
142 } catch (IOException e) {
143 LOG.warn("Failed to process quota reports and update quota violation state. Will retry.", e);
144 }
145 }
146
147 void _chore() throws IOException {
148
149
150 TablesWithQuotas tablesWithQuotas = fetchAllTablesWithQuotasDefined();
151 if (LOG.isTraceEnabled()) {
152 LOG.trace("Found following tables with quotas: " + tablesWithQuotas);
153 }
154
155 if (metrics != null) {
156
157 metrics.setNumSpaceQuotas(tablesWithQuotas.getTableQuotaTables().size()
158 + tablesWithQuotas.getNamespacesWithQuotas().size());
159 }
160
161
162 final Map<HRegionInfo,Long> reportedRegionSpaceUse = quotaManager.snapshotRegionSizes();
163 if (LOG.isTraceEnabled()) {
164 LOG.trace("Using " + reportedRegionSpaceUse.size() + " region space use reports");
165 }
166
167
168 pruneOldRegionReports();
169
170
171 initializeSnapshotStores(reportedRegionSpaceUse);
172
173 if (metrics != null) {
174 metrics.setNumRegionSizeReports(reportedRegionSpaceUse.size());
175 }
176
177
178
179
180
181 Set<TableName> tablesInLimbo = tablesWithQuotas.filterInsufficientlyReportedTables(
182 tableSnapshotStore);
183
184 if (LOG.isTraceEnabled()) {
185 LOG.trace("Filtered insufficiently reported tables, left with " +
186 reportedRegionSpaceUse.size() + " regions reported");
187 }
188
189 for (TableName tableInLimbo : tablesInLimbo) {
190 final SpaceQuotaSnapshot currentSnapshot = tableSnapshotStore.getCurrentState(tableInLimbo);
191 if (currentSnapshot.getQuotaStatus().isInViolation()) {
192 if (LOG.isTraceEnabled()) {
193 LOG.trace("Moving " + tableInLimbo + " out of violation because fewer region sizes were"
194 + " reported than required.");
195 }
196 SpaceQuotaSnapshot targetSnapshot = new SpaceQuotaSnapshot(
197 SpaceQuotaStatus.notInViolation(), currentSnapshot.getUsage(),
198 currentSnapshot.getLimit());
199 this.snapshotNotifier.transitionTable(tableInLimbo, targetSnapshot);
200
201 tableSnapshotStore.setCurrentState(tableInLimbo, targetSnapshot);
202 }
203 }
204
205
206
207 final Set<TableName> tablesWithTableQuotas = tablesWithQuotas.getTableQuotaTables();
208 processTablesWithQuotas(tablesWithTableQuotas);
209
210
211
212 final Set<String> namespacesWithQuotas = tablesWithQuotas.getNamespacesWithQuotas();
213 final Multimap<String,TableName> tablesByNamespace = tablesWithQuotas.getTablesByNamespace();
214 processNamespacesWithQuotas(namespacesWithQuotas, tablesByNamespace);
215 }
216
217 void initializeSnapshotStores(Map<HRegionInfo,Long> regionSizes) {
218 Map<HRegionInfo,Long> immutableRegionSpaceUse = Collections.unmodifiableMap(regionSizes);
219 if (tableSnapshotStore == null) {
220 tableSnapshotStore = new TableQuotaSnapshotStore(conn, this, immutableRegionSpaceUse);
221 } else {
222 tableSnapshotStore.setRegionUsage(immutableRegionSpaceUse);
223 }
224 if (namespaceSnapshotStore == null) {
225 namespaceSnapshotStore = new NamespaceQuotaSnapshotStore(
226 conn, this, immutableRegionSpaceUse);
227 } else {
228 namespaceSnapshotStore.setRegionUsage(immutableRegionSpaceUse);
229 }
230 }
231
232
233
234
235
236
237
238 void processTablesWithQuotas(final Set<TableName> tablesWithTableQuotas) throws IOException {
239 long numTablesInViolation = 0L;
240 for (TableName table : tablesWithTableQuotas) {
241 final SpaceQuota spaceQuota = tableSnapshotStore.getSpaceQuota(table);
242 if (spaceQuota == null) {
243 if (LOG.isDebugEnabled()) {
244 LOG.debug("Unexpectedly did not find a space quota for " + table
245 + ", maybe it was recently deleted.");
246 }
247 continue;
248 }
249 final SpaceQuotaSnapshot currentSnapshot = tableSnapshotStore.getCurrentState(table);
250 final SpaceQuotaSnapshot targetSnapshot = tableSnapshotStore.getTargetState(table, spaceQuota);
251 if (LOG.isTraceEnabled()) {
252 LOG.trace("Processing " + table + " with current=" + currentSnapshot + ", target="
253 + targetSnapshot);
254 }
255 updateTableQuota(table, currentSnapshot, targetSnapshot);
256
257 if (targetSnapshot.getQuotaStatus().isInViolation()) {
258 numTablesInViolation++;
259 }
260 }
261
262 if (metrics != null) {
263 metrics.setNumTableInSpaceQuotaViolation(numTablesInViolation);
264 }
265 }
266
267
268
269
270
271
272
273
274
275
276
277 void processNamespacesWithQuotas(
278 final Set<String> namespacesWithQuotas,
279 final Multimap<String,TableName> tablesByNamespace) throws IOException {
280 long numNamespacesInViolation = 0L;
281 for (String namespace : namespacesWithQuotas) {
282
283 final SpaceQuota spaceQuota = namespaceSnapshotStore.getSpaceQuota(namespace);
284 if (spaceQuota == null) {
285 if (LOG.isDebugEnabled()) {
286 LOG.debug("Could not get Namespace space quota for " + namespace
287 + ", maybe it was recently deleted.");
288 }
289 continue;
290 }
291 final SpaceQuotaSnapshot currentSnapshot = namespaceSnapshotStore.getCurrentState(namespace);
292 final SpaceQuotaSnapshot targetSnapshot = namespaceSnapshotStore.getTargetState(
293 namespace, spaceQuota);
294 if (LOG.isTraceEnabled()) {
295 LOG.trace("Processing " + namespace + " with current=" + currentSnapshot + ", target="
296 + targetSnapshot);
297 }
298 updateNamespaceQuota(namespace, currentSnapshot, targetSnapshot, tablesByNamespace);
299
300 if (targetSnapshot.getQuotaStatus().isInViolation()) {
301 numNamespacesInViolation++;
302 }
303 }
304
305
306 if (metrics != null) {
307 metrics.setNumNamespacesInSpaceQuotaViolation(numNamespacesInViolation);
308 }
309 }
310
311
312
313
314
315
316
317
318
319 void updateTableQuota(
320 TableName table, SpaceQuotaSnapshot currentSnapshot, SpaceQuotaSnapshot targetSnapshot)
321 throws IOException {
322 final SpaceQuotaStatus currentStatus = currentSnapshot.getQuotaStatus();
323 final SpaceQuotaStatus targetStatus = targetSnapshot.getQuotaStatus();
324
325
326 if (!currentSnapshot.equals(targetSnapshot)) {
327
328 if (!targetStatus.isInViolation()) {
329 if (LOG.isDebugEnabled()) {
330 LOG.debug(table + " moving into observance of table space quota.");
331 }
332 } else if (LOG.isDebugEnabled()) {
333
334 LOG.debug(table + " moving into violation of table space quota with policy of "
335 + targetStatus.getPolicy());
336 }
337
338 this.snapshotNotifier.transitionTable(table, targetSnapshot);
339
340 tableSnapshotStore.setCurrentState(table, targetSnapshot);
341 } else if (LOG.isTraceEnabled()) {
342
343
344 if (!currentStatus.isInViolation()) {
345 LOG.trace(table + " remains in observance of quota.");
346 } else {
347 LOG.trace(table + " remains in violation of quota.");
348 }
349 }
350 }
351
352
353
354
355
356
357
358
359
360
361 void updateNamespaceQuota(
362 String namespace, SpaceQuotaSnapshot currentSnapshot, SpaceQuotaSnapshot targetSnapshot,
363 final Multimap<String,TableName> tablesByNamespace) throws IOException {
364 final SpaceQuotaStatus targetStatus = targetSnapshot.getQuotaStatus();
365
366
367 if (!currentSnapshot.equals(targetSnapshot)) {
368
369 if (!targetStatus.isInViolation()) {
370 for (TableName tableInNS : tablesByNamespace.get(namespace)) {
371
372 if (tableSnapshotStore.getCurrentState(tableInNS).getQuotaStatus().isInViolation()) {
373
374 if (LOG.isTraceEnabled()) {
375 LOG.trace("Not activating Namespace violation policy because a Table violation"
376 + " policy is already in effect for " + tableInNS);
377 }
378 } else {
379 LOG.info(tableInNS + " moving into observance of namespace space quota");
380 this.snapshotNotifier.transitionTable(tableInNS, targetSnapshot);
381 }
382 }
383
384 } else {
385
386 for (TableName tableInNS : tablesByNamespace.get(namespace)) {
387 final SpaceQuotaSnapshot tableQuotaSnapshot =
388 tableSnapshotStore.getCurrentState(tableInNS);
389 final boolean hasTableQuota = QuotaSnapshotStore.NO_QUOTA != tableQuotaSnapshot;
390 if (hasTableQuota && tableQuotaSnapshot.getQuotaStatus().isInViolation()) {
391
392 if (LOG.isTraceEnabled()) {
393 LOG.trace("Not activating Namespace violation policy because a Table violation"
394 + " policy is already in effect for " + tableInNS);
395 }
396 } else {
397
398 LOG.info(tableInNS + " moving into violation of namespace space quota with policy "
399 + targetStatus.getPolicy());
400 this.snapshotNotifier.transitionTable(tableInNS, targetSnapshot);
401 }
402 }
403 }
404
405 namespaceSnapshotStore.setCurrentState(namespace, targetSnapshot);
406 } else {
407
408 if (!targetStatus.isInViolation()) {
409
410 if (LOG.isTraceEnabled()) {
411 LOG.trace(namespace + " remains in observance of quota.");
412 }
413 } else {
414
415
416 for (TableName tableInNS : tablesByNamespace.get(namespace)) {
417
418 if (tableSnapshotStore.getCurrentState(tableInNS).getQuotaStatus().isInViolation()) {
419
420 if (LOG.isTraceEnabled()) {
421 LOG.trace("Not activating Namespace violation policy because Table violation"
422 + " policy is already in effect for " + tableInNS);
423 }
424 } else {
425
426 LOG.info(tableInNS + " moving into violation of namespace space quota");
427 this.snapshotNotifier.transitionTable(tableInNS, targetSnapshot);
428 }
429 }
430 }
431 }
432 }
433
434
435
436
437 void pruneOldRegionReports() {
438 long now = EnvironmentEdgeManager.currentTime();
439 long pruneTime = now - regionReportLifetimeMillis;
440 if (LOG.isTraceEnabled()) {
441 LOG.trace("Pruning Region size reports older than " + pruneTime);
442 }
443 int numRemoved = quotaManager.pruneEntriesOlderThan(pruneTime);
444 if (LOG.isTraceEnabled()) {
445 LOG.trace("Removed " + numRemoved + " old region size reports.");
446 }
447 }
448
449 void initializeViolationStores(Map<HRegionInfo,Long> regionSizes) {
450 Map<HRegionInfo,Long> immutableRegionSpaceUse = Collections.unmodifiableMap(regionSizes);
451 tableSnapshotStore = new TableQuotaSnapshotStore(conn, this, immutableRegionSpaceUse);
452 namespaceSnapshotStore = new NamespaceQuotaSnapshotStore(conn, this, immutableRegionSpaceUse);
453 }
454
455
456
457
458
459
460 TablesWithQuotas fetchAllTablesWithQuotasDefined() throws IOException {
461 final Scan scan = QuotaTableUtil.makeScan(null);
462 final TablesWithQuotas tablesWithQuotas = new TablesWithQuotas(conn, conf);
463 try (final QuotaRetriever scanner = new QuotaRetriever()) {
464 scanner.init(conn, scan);
465 for (QuotaSettings quotaSettings : scanner) {
466
467 final String namespace = quotaSettings.getNamespace();
468 final TableName tableName = quotaSettings.getTableName();
469 if (QuotaType.SPACE != quotaSettings.getQuotaType()) {
470 continue;
471 }
472
473 if (namespace != null) {
474 assert tableName == null;
475
476 TableName[] tablesInNS = conn.getAdmin().listTableNamesByNamespace(namespace);
477 for (TableName tableUnderNs : tablesInNS) {
478 if (LOG.isTraceEnabled()) {
479 LOG.trace("Adding " + tableUnderNs + " under " + namespace
480 + " as having a namespace quota");
481 }
482 tablesWithQuotas.addNamespaceQuotaTable(tableUnderNs);
483 }
484 } else {
485 assert tableName != null;
486 if (LOG.isTraceEnabled()) {
487 LOG.trace("Adding " + tableName + " as having table quota.");
488 }
489
490 tablesWithQuotas.addTableQuotaTable(tableName);
491 }
492 }
493 return tablesWithQuotas;
494 }
495 }
496
497 @VisibleForTesting
498 QuotaSnapshotStore<TableName> getTableSnapshotStore() {
499 return tableSnapshotStore;
500 }
501
502 @VisibleForTesting
503 QuotaSnapshotStore<String> getNamespaceSnapshotStore() {
504 return namespaceSnapshotStore;
505 }
506
507
508
509
510
511 public Map<TableName,SpaceQuotaSnapshot> getTableQuotaSnapshots() {
512 return readOnlyTableQuotaSnapshots;
513 }
514
515
516
517
518
519 public Map<String,SpaceQuotaSnapshot> getNamespaceQuotaSnapshots() {
520 return readOnlyNamespaceSnapshots;
521 }
522
523
524
525
526 SpaceQuotaSnapshot getTableQuotaSnapshot(TableName table) {
527 SpaceQuotaSnapshot state = this.tableQuotaSnapshots.get(table);
528 if (state == null) {
529
530 return QuotaSnapshotStore.NO_QUOTA;
531 }
532 return state;
533 }
534
535
536
537
538 void setTableQuotaSnapshot(TableName table, SpaceQuotaSnapshot snapshot) {
539 this.tableQuotaSnapshots.put(table, snapshot);
540 }
541
542
543
544
545 SpaceQuotaSnapshot getNamespaceQuotaSnapshot(String namespace) {
546 SpaceQuotaSnapshot state = this.namespaceQuotaSnapshots.get(namespace);
547 if (state == null) {
548
549 return QuotaSnapshotStore.NO_QUOTA;
550 }
551 return state;
552 }
553
554
555
556
557 void setNamespaceQuotaViolation(String namespace, SpaceQuotaSnapshot snapshot) {
558 this.namespaceQuotaSnapshots.put(namespace, snapshot);
559 }
560
561
562
563
564
565
566
567
568 static int getPeriod(Configuration conf) {
569 return conf.getInt(QUOTA_OBSERVER_CHORE_PERIOD_KEY,
570 QUOTA_OBSERVER_CHORE_PERIOD_DEFAULT);
571 }
572
573
574
575
576
577
578
579
580 static long getInitialDelay(Configuration conf) {
581 return conf.getLong(QUOTA_OBSERVER_CHORE_DELAY_KEY,
582 QUOTA_OBSERVER_CHORE_DELAY_DEFAULT);
583 }
584
585
586
587
588
589
590
591
592
593 static TimeUnit getTimeUnit(Configuration conf) {
594 return TimeUnit.valueOf(conf.get(QUOTA_OBSERVER_CHORE_TIMEUNIT_KEY,
595 QUOTA_OBSERVER_CHORE_TIMEUNIT_DEFAULT));
596 }
597
598
599
600
601
602
603
604
605 static Double getRegionReportPercent(Configuration conf) {
606 return conf.getDouble(QUOTA_OBSERVER_CHORE_REPORT_PERCENT_KEY,
607 QUOTA_OBSERVER_CHORE_REPORT_PERCENT_DEFAULT);
608 }
609
610
611
612
613
614 static class TablesWithQuotas {
615 private final Set<TableName> tablesWithTableQuotas = new HashSet<>();
616 private final Set<TableName> tablesWithNamespaceQuotas = new HashSet<>();
617 private final Connection conn;
618 private final Configuration conf;
619
620 public TablesWithQuotas(Connection conn, Configuration conf) {
621 this.conn = Objects.requireNonNull(conn);
622 this.conf = Objects.requireNonNull(conf);
623 }
624
625 Configuration getConfiguration() {
626 return conf;
627 }
628
629
630
631
632 public void addTableQuotaTable(TableName tn) {
633 tablesWithTableQuotas.add(tn);
634 }
635
636
637
638
639 public void addNamespaceQuotaTable(TableName tn) {
640 tablesWithNamespaceQuotas.add(tn);
641 }
642
643
644
645
646 public boolean hasTableQuota(TableName tn) {
647 return tablesWithTableQuotas.contains(tn);
648 }
649
650
651
652
653 public boolean hasNamespaceQuota(TableName tn) {
654 return tablesWithNamespaceQuotas.contains(tn);
655 }
656
657
658
659
660 public Set<TableName> getTableQuotaTables() {
661 return Collections.unmodifiableSet(tablesWithTableQuotas);
662 }
663
664
665
666
667
668 public Set<TableName> getNamespaceQuotaTables() {
669 return Collections.unmodifiableSet(tablesWithNamespaceQuotas);
670 }
671
672 public Set<String> getNamespacesWithQuotas() {
673 Set<String> namespaces = new HashSet<>();
674 for (TableName tn : tablesWithNamespaceQuotas) {
675 namespaces.add(tn.getNamespaceAsString());
676 }
677 return namespaces;
678 }
679
680
681
682
683
684 public Multimap<String,TableName> getTablesByNamespace() {
685 Multimap<String,TableName> tablesByNS = HashMultimap.create();
686 for (TableName tn : tablesWithNamespaceQuotas) {
687 tablesByNS.put(tn.getNamespaceAsString(), tn);
688 }
689 return tablesByNS;
690 }
691
692
693
694
695
696 public Set<TableName> filterInsufficientlyReportedTables(QuotaSnapshotStore<TableName> tableStore)
697 throws IOException {
698 final double percentRegionsReportedThreshold = getRegionReportPercent(getConfiguration());
699 Set<TableName> tablesToRemove = new HashSet<>();
700 for (TableName table : Iterables.concat(tablesWithTableQuotas, tablesWithNamespaceQuotas)) {
701
702 if (tablesToRemove.contains(table)) {
703 continue;
704 }
705 final int numRegionsInTable = getNumRegions(table);
706
707 if (numRegionsInTable == 0) {
708 if (LOG.isTraceEnabled()) {
709 LOG.trace("Filtering " + table + " because no regions were reported.");
710 }
711 tablesToRemove.add(table);
712 continue;
713 }
714 final int reportedRegionsInQuota = getNumReportedRegions(table, tableStore);
715 final double ratioReported = ((double) reportedRegionsInQuota) / numRegionsInTable;
716 if (ratioReported < percentRegionsReportedThreshold) {
717 if (LOG.isTraceEnabled()) {
718 LOG.trace("Filtering " + table + " because " + reportedRegionsInQuota + " of " +
719 numRegionsInTable + " regions were reported.");
720 }
721 tablesToRemove.add(table);
722 } else if (LOG.isTraceEnabled()) {
723 LOG.trace("Retaining " + table + " because " + reportedRegionsInQuota + " of " +
724 numRegionsInTable + " regions were reported.");
725 }
726 }
727 for (TableName tableToRemove : tablesToRemove) {
728 tablesWithTableQuotas.remove(tableToRemove);
729 tablesWithNamespaceQuotas.remove(tableToRemove);
730 }
731 return tablesToRemove;
732 }
733
734
735
736
737 int getNumRegions(TableName table) throws IOException {
738 List<HRegionInfo> regions = this.conn.getAdmin().getTableRegions(table);
739 if (regions == null) {
740 return 0;
741 }
742 return regions.size();
743 }
744
745
746
747
748 int getNumReportedRegions(TableName table, QuotaSnapshotStore<TableName> tableStore)
749 throws IOException {
750 return Iterables.size(tableStore.filterBySubject(table));
751 }
752
753 @Override
754 public String toString() {
755 final StringBuilder sb = new StringBuilder(32);
756 sb.append(getClass().getSimpleName())
757 .append(": tablesWithTableQuotas=")
758 .append(this.tablesWithTableQuotas)
759 .append(", tablesWithNamespaceQuotas=")
760 .append(this.tablesWithNamespaceQuotas);
761 return sb.toString();
762 }
763 }
764 }