001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.namespace; 019 020import java.io.IOException; 021import org.apache.hadoop.hbase.HBaseIOException; 022import org.apache.hadoop.hbase.NamespaceDescriptor; 023import org.apache.hadoop.hbase.TableExistsException; 024import org.apache.hadoop.hbase.TableName; 025import org.apache.hadoop.hbase.client.RegionInfo; 026import org.apache.hadoop.hbase.master.MasterServices; 027import org.apache.hadoop.hbase.quotas.QuotaExceededException; 028import org.apache.yetus.audience.InterfaceAudience; 029import org.slf4j.Logger; 030import org.slf4j.LoggerFactory; 031 032/** 033 * The Class NamespaceAuditor performs checks to ensure operations like table creation and region 034 * splitting preserve namespace quota. The namespace quota can be specified while namespace 035 * creation. 036 */ 037@InterfaceAudience.Private 038public class NamespaceAuditor { 039 private static final Logger LOG = LoggerFactory.getLogger(NamespaceAuditor.class); 040 private NamespaceStateManager stateManager; 041 private MasterServices masterServices; 042 043 public NamespaceAuditor(MasterServices masterServices) { 044 this.masterServices = masterServices; 045 stateManager = new NamespaceStateManager(masterServices); 046 } 047 048 public void start() throws IOException { 049 stateManager.start(); 050 LOG.info("NamespaceAuditor started."); 051 } 052 053 /** 054 * Check quota to create table. We add the table information to namespace state cache, assuming 055 * the operation will pass. If the operation fails, then the next time namespace state chore runs 056 * namespace state cache will be corrected. 057 * @param tName - The table name to check quota. 058 * @param regions - Number of regions that will be added. 059 * @throws IOException Signals that an I/O exception has occurred. 060 */ 061 public void checkQuotaToCreateTable(TableName tName, int regions) throws IOException { 062 if (stateManager.isInitialized()) { 063 // We do this check to fail fast. 064 if (masterServices.getTableDescriptors().exists(tName)) { 065 throw new TableExistsException(tName); 066 } 067 stateManager.checkAndUpdateNamespaceTableCount(tName, regions); 068 } else { 069 checkTableTypeAndThrowException(tName); 070 } 071 } 072 073 /** 074 * Check and update region count quota for an existing table. 075 * @param tName - table name for which region count to be updated. 076 * @param regions - Number of regions that will be added. 077 * @throws IOException Signals that an I/O exception has occurred. 078 */ 079 public void checkQuotaToUpdateRegion(TableName tName, int regions) throws IOException { 080 if (stateManager.isInitialized()) { 081 stateManager.checkAndUpdateNamespaceRegionCount(tName, regions); 082 } else { 083 checkTableTypeAndThrowException(tName); 084 } 085 } 086 087 private void checkTableTypeAndThrowException(TableName name) throws IOException { 088 if (name.isSystemTable()) { 089 LOG.debug("Namespace auditor checks not performed for table " + name.getNameAsString()); 090 } else { 091 throw new HBaseIOException( 092 name + " is being created even before namespace auditor has been initialized."); 093 } 094 } 095 096 /** 097 * Get region count for table 098 * @param tName - table name 099 * @return cached region count, or -1 if table status not found 100 * @throws IOException Signals that the namespace auditor has not been initialized 101 */ 102 public int getRegionCountOfTable(TableName tName) throws IOException { 103 if (stateManager.isInitialized()) { 104 NamespaceTableAndRegionInfo state = stateManager.getState(tName.getNamespaceAsString()); 105 return state != null ? state.getRegionCountOfTable(tName) : -1; 106 } 107 checkTableTypeAndThrowException(tName); 108 return -1; 109 } 110 111 public void checkQuotaToSplitRegion(RegionInfo hri) throws IOException { 112 if (!stateManager.isInitialized()) { 113 throw new IOException( 114 "Split operation is being performed even before namespace auditor is initialized."); 115 } else if ( 116 !stateManager.checkAndUpdateNamespaceRegionCount(hri.getTable(), hri.getRegionName(), 1) 117 ) { 118 throw new QuotaExceededException("Region split not possible for :" + hri.getEncodedName() 119 + " as quota limits are exceeded "); 120 } 121 } 122 123 public void updateQuotaForRegionMerge(RegionInfo mergedRegion) throws IOException { 124 if (!stateManager.isInitialized()) { 125 throw new IOException( 126 "Merge operation is being performed even before namespace auditor is initialized."); 127 } else if ( 128 !stateManager.checkAndUpdateNamespaceRegionCount(mergedRegion.getTable(), 129 mergedRegion.getRegionName(), -1) 130 ) { 131 throw new QuotaExceededException("Region merge not possible for :" 132 + mergedRegion.getEncodedName() + " as quota limits are exceeded "); 133 } 134 } 135 136 public void addNamespace(NamespaceDescriptor ns) throws IOException { 137 stateManager.addNamespace(ns.getName()); 138 } 139 140 public void deleteNamespace(String namespace) throws IOException { 141 stateManager.deleteNamespace(namespace); 142 } 143 144 public void removeFromNamespaceUsage(TableName tableName) throws IOException { 145 stateManager.removeTable(tableName); 146 } 147 148 public void removeRegionFromNamespaceUsage(RegionInfo hri) throws IOException { 149 stateManager.removeRegionFromTable(hri); 150 } 151 152 /** 153 * @param namespace The name of the namespace 154 * @return An instance of NamespaceTableAndRegionInfo 155 */ 156 public NamespaceTableAndRegionInfo getState(String namespace) { 157 if (stateManager.isInitialized()) { 158 return stateManager.getState(namespace); 159 } 160 return null; 161 } 162 163 /** 164 * Checks if namespace auditor is initialized. Used only for testing. 165 * @return true, if is initialized 166 */ 167 public boolean isInitialized() { 168 return stateManager.isInitialized(); 169 } 170}