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.master; 019 020import edu.umd.cs.findbugs.annotations.NonNull; 021import edu.umd.cs.findbugs.annotations.Nullable; 022import java.io.IOException; 023import java.util.Set; 024import java.util.concurrent.ConcurrentHashMap; 025import java.util.concurrent.ConcurrentMap; 026import java.util.concurrent.locks.ReadWriteLock; 027import org.apache.hadoop.hbase.CatalogFamilyFormat; 028import org.apache.hadoop.hbase.ClientMetaTableAccessor; 029import org.apache.hadoop.hbase.MetaTableAccessor; 030import org.apache.hadoop.hbase.TableName; 031import org.apache.hadoop.hbase.TableNotFoundException; 032import org.apache.hadoop.hbase.client.Result; 033import org.apache.hadoop.hbase.client.TableState; 034import org.apache.hadoop.hbase.exceptions.IllegalArgumentIOException; 035import org.apache.hadoop.hbase.util.IdReadWriteLock; 036import org.apache.hadoop.hbase.util.IdReadWriteLockWithObjectPool; 037import org.apache.yetus.audience.InterfaceAudience; 038import org.slf4j.Logger; 039import org.slf4j.LoggerFactory; 040 041import org.apache.hbase.thirdparty.com.google.common.collect.Sets; 042 043/** 044 * This is a helper class used to manage table states. This class uses hbase:meta as its store for 045 * table state so hbase:meta must be online before accessing its methods. 046 */ 047@InterfaceAudience.Private 048public class TableStateManager { 049 050 private static final Logger LOG = LoggerFactory.getLogger(TableStateManager.class); 051 052 private final IdReadWriteLock<TableName> tnLock = new IdReadWriteLockWithObjectPool<>(); 053 private final MasterServices master; 054 055 private final ConcurrentMap<TableName, TableState.State> tableName2State = 056 new ConcurrentHashMap<>(); 057 058 TableStateManager(MasterServices master) { 059 this.master = master; 060 } 061 062 /** 063 * Set table state to provided. Caller should lock table on write. 064 * @param tableName table to change state for 065 * @param newState new state 066 */ 067 public void setTableState(TableName tableName, TableState.State newState) throws IOException { 068 ReadWriteLock lock = tnLock.getLock(tableName); 069 lock.writeLock().lock(); 070 try { 071 updateMetaState(tableName, newState); 072 } finally { 073 lock.writeLock().unlock(); 074 } 075 } 076 077 public boolean isTableState(TableName tableName, TableState.State... states) { 078 try { 079 TableState tableState = getTableState(tableName); 080 return tableState.isInStates(states); 081 } catch (IOException e) { 082 LOG.error("Unable to get table " + tableName + " state", e); 083 // XXX: is it safe to just return false here? 084 return false; 085 } 086 } 087 088 public void setDeletedTable(TableName tableName) throws IOException { 089 if (tableName.equals(TableName.META_TABLE_NAME)) { 090 // Can't delete the hbase:meta table. 091 return; 092 } 093 ReadWriteLock lock = tnLock.getLock(tableName); 094 lock.writeLock().lock(); 095 try { 096 MetaTableAccessor.deleteTableState(master.getConnection(), tableName); 097 } finally { 098 tableName2State.remove(tableName); 099 lock.writeLock().unlock(); 100 } 101 } 102 103 public boolean isTablePresent(TableName tableName) throws IOException { 104 ReadWriteLock lock = tnLock.getLock(tableName); 105 lock.readLock().lock(); 106 try { 107 return readMetaState(tableName) != null; 108 } finally { 109 lock.readLock().unlock(); 110 } 111 } 112 113 /** 114 * Return all tables in given states. 115 * @param states filter by states 116 * @return tables in given states 117 */ 118 Set<TableName> getTablesInStates(TableState.State... states) throws IOException { 119 // Only be called in region normalizer, will not use cache. 120 final Set<TableName> rv = Sets.newHashSet(); 121 MetaTableAccessor.fullScanTables(master.getConnection(), new ClientMetaTableAccessor.Visitor() { 122 @Override 123 public boolean visit(Result r) throws IOException { 124 TableState tableState = CatalogFamilyFormat.getTableState(r); 125 if (tableState != null && tableState.inStates(states)) { 126 rv.add(tableState.getTableName()); 127 } 128 return true; 129 } 130 }); 131 return rv; 132 } 133 134 @NonNull 135 public TableState getTableState(TableName tableName) throws IOException { 136 ReadWriteLock lock = tnLock.getLock(tableName); 137 lock.readLock().lock(); 138 try { 139 TableState currentState = readMetaState(tableName); 140 if (currentState == null) { 141 throw new TableNotFoundException("No state found for " + tableName); 142 } 143 return currentState; 144 } finally { 145 lock.readLock().unlock(); 146 } 147 } 148 149 private void updateMetaState(TableName tableName, TableState.State newState) throws IOException { 150 if (tableName.equals(TableName.META_TABLE_NAME)) { 151 if ( 152 TableState.State.DISABLING.equals(newState) || TableState.State.DISABLED.equals(newState) 153 ) { 154 throw new IllegalArgumentIOException("Cannot disable meta table; " + newState); 155 } 156 // Otherwise, just return; no need to set ENABLED on meta -- it is always ENABLED. 157 return; 158 } 159 boolean succ = false; 160 try { 161 MetaTableAccessor.updateTableState(master.getConnection(), tableName, newState); 162 tableName2State.put(tableName, newState); 163 succ = true; 164 } finally { 165 if (!succ) { 166 this.tableName2State.remove(tableName); 167 } 168 } 169 } 170 171 @Nullable 172 private TableState readMetaState(TableName tableName) throws IOException { 173 TableState.State state = tableName2State.get(tableName); 174 if (state != null) { 175 return new TableState(tableName, state); 176 } 177 TableState tableState = MetaTableAccessor.getTableState(master.getConnection(), tableName); 178 if (tableState != null) { 179 tableName2State.putIfAbsent(tableName, tableState.getState()); 180 } 181 return tableState; 182 } 183}