View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to you under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    * http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.hadoop.hbase.quotas;
18  
19  import java.io.IOException;
20  import java.util.Map;
21  import java.util.Map.Entry;
22  import java.util.Objects;
23  import java.util.concurrent.locks.ReentrantReadWriteLock;
24  import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
25  import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
26  
27  import org.apache.hadoop.hbase.HRegionInfo;
28  import org.apache.hadoop.hbase.TableName;
29  import org.apache.hadoop.hbase.client.Connection;
30  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
31  import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Quotas;
32  import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.SpaceQuota;
33  import org.apache.hadoop.hbase.quotas.SpaceQuotaSnapshot.SpaceQuotaStatus;
34  
35  import com.google.common.base.Predicate;
36  import com.google.common.collect.Iterables;
37  
38  /**
39   * {@link QuotaSnapshotStore} for tables.
40   */
41  public class TableQuotaSnapshotStore implements QuotaSnapshotStore<TableName> {
42    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
43    private final ReadLock rlock = lock.readLock();
44    private final WriteLock wlock = lock.writeLock();
45  
46    private final Connection conn;
47    private final QuotaObserverChore chore;
48    private Map<HRegionInfo,Long> regionUsage;
49  
50    public TableQuotaSnapshotStore(Connection conn, QuotaObserverChore chore, Map<HRegionInfo,Long> regionUsage) {
51      this.conn = Objects.requireNonNull(conn);
52      this.chore = Objects.requireNonNull(chore);
53      this.regionUsage = Objects.requireNonNull(regionUsage);
54    }
55  
56    @Override
57    public SpaceQuota getSpaceQuota(TableName subject) throws IOException {
58      Quotas quotas = getQuotaForTable(subject);
59      if (quotas != null && quotas.hasSpace()) {
60        return quotas.getSpace();
61      }
62      return null;
63    }
64    /**
65     * Fetches the table quota. Visible for mocking/testing.
66     */
67    Quotas getQuotaForTable(TableName table) throws IOException {
68      return QuotaTableUtil.getTableQuota(conn, table);
69    }
70  
71    @Override
72    public SpaceQuotaSnapshot getCurrentState(TableName table) {
73      // Defer the "current state" to the chore
74      return chore.getTableQuotaSnapshot(table);
75    }
76  
77    @Override
78    public SpaceQuotaSnapshot getTargetState(TableName table, SpaceQuota spaceQuota) {
79      rlock.lock();
80      try {
81        final long sizeLimitInBytes = spaceQuota.getSoftLimit();
82        long sum = 0L;
83        for (Entry<HRegionInfo,Long> entry : filterBySubject(table)) {
84          sum += entry.getValue();
85        }
86        // Observance is defined as the size of the table being less than the limit
87        SpaceQuotaStatus status = sum <= sizeLimitInBytes ? SpaceQuotaStatus.notInViolation()
88            : new SpaceQuotaStatus(ProtobufUtil.toViolationPolicy(spaceQuota.getViolationPolicy()));
89        return new SpaceQuotaSnapshot(status, sum, sizeLimitInBytes);
90      } finally {
91        rlock.unlock();
92      }
93    }
94  
95    @Override
96    public Iterable<Entry<HRegionInfo,Long>> filterBySubject(final TableName table) {
97      rlock.lock();
98      try {
99        return Iterables.filter(regionUsage.entrySet(), new Predicate<Entry<HRegionInfo,Long>>() {
100         @Override
101         public boolean apply(Entry<HRegionInfo,Long> input) {
102           return table.equals(input.getKey().getTable());
103         }
104       });
105     } finally {
106       rlock.unlock();
107     }
108   }
109 
110   @Override
111   public void setCurrentState(TableName table, SpaceQuotaSnapshot snapshot) {
112     // Defer the "current state" to the chore
113     this.chore.setTableQuotaSnapshot(table, snapshot);
114   }
115 
116   @Override
117   public void setRegionUsage(Map<HRegionInfo,Long> regionUsage) {
118     wlock.lock();
119     try {
120       this.regionUsage = Objects.requireNonNull(regionUsage);
121     } finally {
122       wlock.unlock();
123     }
124   }
125 }