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