View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
3    * agreements. See the NOTICE file distributed with this work for additional information regarding
4    * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
5    * "License"); you may not use this file except in compliance with the License. You may obtain a
6    * copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable
7    * law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
8    * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
9    * for the specific language governing permissions and limitations under the License.
10   */
11  package org.apache.hadoop.hbase.namespace;
12  
13  import java.io.IOException;
14  
15  import org.apache.commons.logging.Log;
16  import org.apache.commons.logging.LogFactory;
17  import org.apache.hadoop.hbase.HBaseIOException;
18  import org.apache.hadoop.hbase.HRegionInfo;
19  import org.apache.hadoop.hbase.MetaTableAccessor;
20  import org.apache.hadoop.hbase.NamespaceDescriptor;
21  import org.apache.hadoop.hbase.TableExistsException;
22  import org.apache.hadoop.hbase.TableName;
23  import org.apache.hadoop.hbase.classification.InterfaceAudience;
24  import org.apache.hadoop.hbase.master.MasterServices;
25  import org.apache.hadoop.hbase.quotas.QuotaExceededException;
26  
27  import com.google.common.annotations.VisibleForTesting;
28  
29  /**
30   * The Class NamespaceAuditor performs checks to ensure operations like table creation and region
31   * splitting preserve namespace quota. The namespace quota can be specified while namespace
32   * creation.
33   */
34  @InterfaceAudience.Private
35  public class NamespaceAuditor {
36    private static Log LOG = LogFactory.getLog(NamespaceAuditor.class);
37    static final String NS_AUDITOR_INIT_TIMEOUT = "hbase.namespace.auditor.init.timeout";
38    static final int DEFAULT_NS_AUDITOR_INIT_TIMEOUT = 120000;
39    private NamespaceStateManager stateManager;
40    private MasterServices masterServices;
41  
42    public NamespaceAuditor(MasterServices masterServices) {
43      this.masterServices = masterServices;
44      stateManager = new NamespaceStateManager(masterServices, masterServices.getZooKeeper());
45    }
46  
47    public void start() throws IOException {
48      stateManager.start();
49      LOG.info("NamespaceAuditor started.");
50    }
51  
52    /**
53     * Check quota to create table. We add the table information to namespace state cache, assuming
54     * the operation will pass. If the operation fails, then the next time namespace state chore runs
55     * namespace state cache will be corrected.
56     * @param tName - The table name to check quota.
57     * @param regions - Number of regions that will be added.
58     * @throws IOException Signals that an I/O exception has occurred.
59     */
60    public void checkQuotaToCreateTable(TableName tName, int regions) throws IOException {
61      if (stateManager.isInitialized()) {
62        // We do this check to fail fast.
63        if (MetaTableAccessor.tableExists(this.masterServices.getConnection(), tName)) {
64          throw new TableExistsException(tName);
65        }
66        stateManager.checkAndUpdateNamespaceTableCount(tName, regions);
67      } else {
68        checkTableTypeAndThrowException(tName);
69      }
70    }
71    
72    /**
73     * Check and update region count quota for an existing table.
74     * @param tName - table name for which region count to be updated.
75     * @param regions - Number of regions that will be added.
76     * @throws IOException Signals that an I/O exception has occurred.
77     */
78    public void checkQuotaToUpdateRegion(TableName tName, int regions) throws IOException {
79      if (stateManager.isInitialized()) {
80        stateManager.checkAndUpdateNamespaceRegionCount(tName, regions);
81      } else {
82        checkTableTypeAndThrowException(tName);
83      }
84    }
85  
86    private void checkTableTypeAndThrowException(TableName name) throws IOException {
87      if (name.isSystemTable()) {
88        LOG.debug("Namespace auditor checks not performed for table " + name.getNameAsString());
89      } else {
90        throw new HBaseIOException(name
91            + " is being created even before namespace auditor has been initialized.");
92      }
93    }
94  
95    public void checkQuotaToSplitRegion(HRegionInfo hri) throws IOException {
96      if (!stateManager.isInitialized()) {
97        throw new IOException(
98            "Split operation is being performed even before namespace auditor is initialized.");
99      } else if (!stateManager.checkAndUpdateNamespaceRegionCount(hri.getTable(),
100       hri.getRegionName(), 1)) {
101       throw new QuotaExceededException("Region split not possible for :" + hri.getEncodedName()
102           + " as quota limits are exceeded ");
103     }
104   }
105 
106   public void updateQuotaForRegionMerge(HRegionInfo hri) throws IOException {
107     if (!stateManager.isInitialized()) {
108       throw new IOException(
109           "Merge operation is being performed even before namespace auditor is initialized.");
110     } else if (!stateManager
111         .checkAndUpdateNamespaceRegionCount(hri.getTable(), hri.getRegionName(), -1)) {
112       throw new QuotaExceededException("Region split not possible for :" + hri.getEncodedName()
113           + " as quota limits are exceeded ");
114     }
115   }
116 
117   public void addNamespace(NamespaceDescriptor ns) throws IOException {
118     stateManager.addNamespace(ns.getName());
119   }
120 
121   public void deleteNamespace(String namespace) throws IOException {
122     stateManager.deleteNamespace(namespace);
123   }
124 
125   public void removeFromNamespaceUsage(TableName tableName) throws IOException {
126     stateManager.removeTable(tableName);
127   }
128 
129   public void removeRegionFromNamespaceUsage(HRegionInfo hri) throws IOException {
130     stateManager.removeRegionFromTable(hri);
131   }
132 
133   /**
134    * Used only for unit tests.
135    * @param namespace The name of the namespace
136    * @return An instance of NamespaceTableAndRegionInfo
137    */
138   @VisibleForTesting
139   NamespaceTableAndRegionInfo getState(String namespace) {
140     if (stateManager.isInitialized()) {
141       return stateManager.getState(namespace);
142     }
143     return null;
144   }
145 
146   /**
147    * Checks if namespace auditor is initialized. Used only for testing.
148    * @return true, if is initialized
149    */
150   public boolean isInitialized() {
151     return stateManager.isInitialized();
152   }
153 }