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.regionserver.storefiletracker; 019 020import java.util.Collections; 021import java.util.HashMap; 022import java.util.Map; 023import org.apache.hadoop.conf.Configuration; 024import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor; 025import org.apache.hadoop.hbase.client.TableDescriptor; 026import org.apache.hadoop.hbase.client.TableDescriptorBuilder; 027import org.apache.hadoop.hbase.procedure2.util.StringUtils; 028import org.apache.hadoop.hbase.regionserver.HRegionFileSystem; 029import org.apache.hadoop.hbase.regionserver.StoreContext; 030import org.apache.hadoop.hbase.regionserver.StoreUtils; 031import org.apache.hadoop.hbase.util.ReflectionUtils; 032import org.apache.yetus.audience.InterfaceAudience; 033import org.slf4j.Logger; 034import org.slf4j.LoggerFactory; 035 036import org.apache.hbase.thirdparty.com.google.common.base.Preconditions; 037 038/** 039 * Factory method for creating store file tracker. 040 * <p/> 041 * The current implementations are: 042 * <ul> 043 * <li><em>default</em>: DefaultStoreFileTracker, see {@link DefaultStoreFileTracker}.</li> 044 * <li><em>file</em>:FileBasedStoreFileTracker, see {@link FileBasedStoreFileTracker}.</li> 045 * <li><em>migration</em>:MigrationStoreFileTracker, see {@link MigrationStoreFileTracker}.</li> 046 * </ul> 047 * @see DefaultStoreFileTracker 048 * @see FileBasedStoreFileTracker 049 * @see MigrationStoreFileTracker 050 */ 051@InterfaceAudience.Private 052public final class StoreFileTrackerFactory { 053 054 private static final Logger LOG = LoggerFactory.getLogger(StoreFileTrackerFactory.class); 055 056 public static final String TRACKER_IMPL = "hbase.store.file-tracker.impl"; 057 058 /** 059 * Maps between configuration names for trackers and implementation classes. 060 */ 061 public enum Trackers { 062 DEFAULT(DefaultStoreFileTracker.class), 063 FILE(FileBasedStoreFileTracker.class), 064 MIGRATION(MigrationStoreFileTracker.class); 065 066 final Class<? extends StoreFileTracker> clazz; 067 068 Trackers(Class<? extends StoreFileTracker> clazz) { 069 this.clazz = clazz; 070 } 071 } 072 073 private static final Map<Class<? extends StoreFileTracker>, Trackers> CLASS_TO_ENUM = reverse(); 074 075 private static Map<Class<? extends StoreFileTracker>, Trackers> reverse() { 076 Map<Class<? extends StoreFileTracker>, Trackers> map = new HashMap<>(); 077 for (Trackers tracker : Trackers.values()) { 078 map.put(tracker.clazz, tracker); 079 } 080 return Collections.unmodifiableMap(map); 081 } 082 083 private StoreFileTrackerFactory() { 084 } 085 086 public static String getStoreFileTrackerName(Configuration conf) { 087 return conf.get(TRACKER_IMPL, Trackers.DEFAULT.name()); 088 } 089 090 public static String getStoreFileTrackerName(Class<? extends StoreFileTracker> clazz) { 091 Trackers name = CLASS_TO_ENUM.get(clazz); 092 return name != null ? name.name() : clazz.getName(); 093 } 094 095 public static Class<? extends StoreFileTracker> getTrackerClass(Configuration conf) { 096 try { 097 Trackers tracker = Trackers.valueOf(getStoreFileTrackerName(conf).toUpperCase()); 098 return tracker.clazz; 099 } catch (IllegalArgumentException e) { 100 // Fall back to them specifying a class name 101 return conf.getClass(TRACKER_IMPL, Trackers.DEFAULT.clazz, StoreFileTracker.class); 102 } 103 } 104 105 public static Class<? extends StoreFileTracker> getTrackerClass(String trackerNameOrClass) { 106 try { 107 Trackers tracker = Trackers.valueOf(trackerNameOrClass.toUpperCase()); 108 return tracker.clazz; 109 } catch (IllegalArgumentException e) { 110 // Fall back to them specifying a class name 111 try { 112 return Class.forName(trackerNameOrClass).asSubclass(StoreFileTracker.class); 113 } catch (ClassNotFoundException e1) { 114 throw new RuntimeException(e1); 115 } 116 } 117 } 118 119 public static StoreFileTracker create(Configuration conf, boolean isPrimaryReplica, 120 StoreContext ctx) { 121 Class<? extends StoreFileTracker> tracker = getTrackerClass(conf); 122 LOG.debug("instantiating StoreFileTracker impl {}", tracker.getName()); 123 return ReflectionUtils.newInstance(tracker, conf, isPrimaryReplica, ctx); 124 } 125 126 /** 127 * Used at master side when splitting/merging regions, as we do not have a Store, thus no 128 * StoreContext at master side. 129 */ 130 public static StoreFileTracker create(Configuration conf, TableDescriptor td, 131 ColumnFamilyDescriptor cfd, HRegionFileSystem regionFs) { 132 return create(conf, td, cfd, regionFs, true); 133 } 134 135 public static StoreFileTracker create(Configuration conf, TableDescriptor td, 136 ColumnFamilyDescriptor cfd, HRegionFileSystem regionFs, boolean isPrimaryReplica) { 137 StoreContext ctx = 138 StoreContext.getBuilder().withColumnFamilyDescriptor(cfd).withRegionFileSystem(regionFs) 139 .withFamilyStoreDirectoryPath(regionFs.getStoreDir(cfd.getNameAsString())).build(); 140 return StoreFileTrackerFactory.create(mergeConfigurations(conf, td, cfd), isPrimaryReplica, 141 ctx); 142 } 143 144 private static Configuration mergeConfigurations(Configuration global, TableDescriptor table, 145 ColumnFamilyDescriptor family) { 146 return StoreUtils.createStoreConfiguration(global, table, family); 147 } 148 149 static Class<? extends StoreFileTrackerBase> 150 getStoreFileTrackerClassForMigration(Configuration conf, String configName) { 151 String trackerName = 152 Preconditions.checkNotNull(conf.get(configName), "config %s is not set", configName); 153 try { 154 return Trackers.valueOf(trackerName.toUpperCase()).clazz 155 .asSubclass(StoreFileTrackerBase.class); 156 } catch (IllegalArgumentException e) { 157 // Fall back to them specifying a class name 158 try { 159 return Class.forName(trackerName).asSubclass(StoreFileTrackerBase.class); 160 } catch (ClassNotFoundException cnfe) { 161 throw new RuntimeException(cnfe); 162 } 163 } 164 } 165 166 /** 167 * Create store file tracker to be used as source or destination for 168 * {@link MigrationStoreFileTracker}. 169 */ 170 static StoreFileTrackerBase createForMigration(Configuration conf, String configName, 171 boolean isPrimaryReplica, StoreContext ctx) { 172 Class<? extends StoreFileTrackerBase> tracker = 173 getStoreFileTrackerClassForMigration(conf, configName); 174 // prevent nest of MigrationStoreFileTracker, it will cause infinite recursion. 175 if (MigrationStoreFileTracker.class.isAssignableFrom(tracker)) { 176 throw new IllegalArgumentException("Should not specify " + configName + " as " 177 + Trackers.MIGRATION + " because it can not be nested"); 178 } 179 LOG.debug("instantiating StoreFileTracker impl {} as {}", tracker.getName(), configName); 180 return ReflectionUtils.newInstance(tracker, conf, isPrimaryReplica, ctx); 181 } 182 183 public static TableDescriptor updateWithTrackerConfigs(Configuration conf, 184 TableDescriptor descriptor) { 185 // CreateTableProcedure needs to instantiate the configured SFT impl, in order to update table 186 // descriptors with the SFT impl specific configs. By the time this happens, the table has no 187 // regions nor stores yet, so it can't create a proper StoreContext. 188 if (StringUtils.isEmpty(descriptor.getValue(TRACKER_IMPL))) { 189 StoreFileTracker tracker = StoreFileTrackerFactory.create(conf, true, null); 190 TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(descriptor); 191 return tracker.updateWithTrackerConfigs(builder).build(); 192 } 193 return descriptor; 194 } 195 196 public static boolean isMigration(Class<?> clazz) { 197 return MigrationStoreFileTracker.class.isAssignableFrom(clazz); 198 } 199}