/* * Copyright 2015 Kakao Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.kakao.hbase.stat.load; import com.kakao.hbase.common.Args; import com.kakao.hbase.common.util.Util; import com.kakao.hbase.specific.CommandAdapter; import com.kakao.hbase.specific.RegionLoadAdapter; import com.kakao.hbase.specific.RegionLoadDelegator; import com.kakao.hbase.specific.RegionLocationCleaner; import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.ServerName; import org.apache.hadoop.hbase.client.HBaseAdmin; import org.apache.hadoop.hbase.util.Bytes; import java.io.IOException; import java.util.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; public class TableInfo { private final HBaseAdmin admin; private final Load load; private final String tableName; private final Args args; private NavigableMap<HRegionInfo, ServerName> regionServerMap; private Map<byte[], HRegionInfo> regionMap; private Set<ServerName> serverNameSet = new TreeSet<>(); private RegionLoadAdapter regionLoadAdapter; private Set<Integer> indexRSs = null; public TableInfo(HBaseAdmin admin, String tableName, Args args) throws Exception { super(); this.admin = admin; this.tableName = tableName; this.args = args; load = new Load(new LevelClass(isMultiTable(), args)); } public String getTableName() { return tableName; } private boolean isMultiTable() throws IOException { try { return tableName.equals(Args.ALL_TABLES) || !admin.tableExists(tableName); } catch (IllegalArgumentException e) { if (e.getMessage().contains("Illegal character code") || e.getMessage().contains("Illegal first character") || e.getMessage().contains("Namespaces can only start with alphanumeric characters")) return true; throw e; } } public Load getLoad() { return load; } public Set<HRegionInfo> getRegionInfoSet() { Set<HRegionInfo> regionInfoSet = new TreeSet<>(); for (Map.Entry<HRegionInfo, ServerName> entry : regionServerMap.entrySet()) { regionInfoSet.add(entry.getKey()); } return regionInfoSet; } public RegionLoadDelegator getRegionLoad(HRegionInfo hRegionInfo) { return regionLoadAdapter.get(hRegionInfo); } public ServerName getServer(HRegionInfo regionInfo) { return regionServerMap.get(regionInfo); } private void prepare() throws Exception { long timestamp = System.currentTimeMillis(); load.prepare(); initializeRegionServerMap(); initializeRegionBytesMap(); regionLoadAdapter = new RegionLoadAdapter(admin, regionMap, args); Util.printVerboseMessage(args, "TableInfo.prepare", timestamp); } private void initializeRegionServerMap() throws Exception { long timestamp = System.currentTimeMillis(); if (load.getLevelClass().getLevelClass() == RegionName.class || args.has(Args.OPTION_REGION_SERVER)) { initializeServerNameSet(); } Set<String> tables = Args.tables(args, admin); if (tables == null) { regionServerMap = CommandAdapter.regionServerMap(args, admin.getConfiguration() , admin.getConnection(), false); } else { if (isMultiTable()) { regionServerMap = CommandAdapter.regionServerMap(args, admin.getConfiguration(), admin.getConnection(), tables, false); } else { regionServerMap = CommandAdapter.regionServerMap(args, admin.getConfiguration(), admin.getConnection(), new TreeSet<>(Collections.singletonList(tableName)), false); } } clean(regionServerMap); Util.printVerboseMessage(args, "TableInfo.initializeRegionServerMap", timestamp); } private void clean(NavigableMap<HRegionInfo, ServerName> regionServerMap) throws InterruptedException, IOException { long timestamp = System.currentTimeMillis(); Set<String> tableNameSet = tableNameSet(regionServerMap); ExecutorService executorService = Executors.newFixedThreadPool(RegionLocationCleaner.THREAD_POOL_SIZE); try { for (String tableName : tableNameSet) executorService.execute( new RegionLocationCleaner(tableName, admin.getConfiguration(), regionServerMap)); } finally { executorService.shutdown(); executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); } Util.printVerboseMessage(args, "TableInfo.clean", timestamp); } private Set<String> tableNameSet(NavigableMap<HRegionInfo, ServerName> regionServerMap) { long timestamp = System.currentTimeMillis(); Set<String> tableNameSet = new TreeSet<>(); for (Map.Entry<HRegionInfo, ServerName> entry : regionServerMap.entrySet()) { tableNameSet.add(CommandAdapter.getTableName(entry.getKey())); } Util.printVerboseMessage(args, "TableInfo.tableNameSet", timestamp); return tableNameSet; } private void initializeServerNameSet() throws IOException { long timestamp = System.currentTimeMillis(); serverNameSet = new TreeSet<>(admin.getClusterStatus().getServers()); Util.printVerboseMessage(args, "TableInfo.initializeServerNameSet", timestamp); } /** * For looking up HRegionInfo instances by byte[] */ private void initializeRegionBytesMap() { long timestamp = System.currentTimeMillis(); regionMap = new TreeMap<>(Bytes.BYTES_COMPARATOR); for (Map.Entry<HRegionInfo, ServerName> entry : regionServerMap.entrySet()) { regionMap.put(entry.getKey().getRegionName(), entry.getKey()); } Util.printVerboseMessage(args, "TableInfo.initializeRegionBytesMap", timestamp); } /** * Refresh region load information by querying data from HBase cluster. * * @throws Exception */ public void refresh() throws Exception { if (load.isUpdating()) return; synchronized (load) { load.setIsUpdating(true); long timestamp = System.currentTimeMillis(); prepare(); load.update(this, args); Util.printVerboseMessage(args, "TableInfo.refresh", timestamp); load.setIsUpdating(false); } } /** * Return zero based index of a region server that serves the given region. * * @param hRegionInfo region * @return region server index from all region servers */ public int serverIndex(HRegionInfo hRegionInfo) { ServerName serverName = regionServerMap.get(hRegionInfo); return Arrays.asList(serverNameSet.toArray()).indexOf(serverName); } Set<Integer> getServerIndexes(Args args) { if (indexRSs == null) { indexRSs = new HashSet<>(); if (args.has(Args.OPTION_REGION_SERVER)) { Object arg = args.valueOf(Args.OPTION_REGION_SERVER); if (arg != null) { int i = 0; for (ServerName serverName : serverNameSet) { if (serverName.getServerName().matches((String) arg)) { indexRSs.add(i); } i++; } if (indexRSs.size() == 0) throw new IllegalStateException(arg + " is invalid"); } } } return indexRSs; } }