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.snapshot; 019 020import java.io.IOException; 021import java.util.ArrayList; 022import java.util.HashMap; 023import java.util.List; 024import java.util.Map; 025import java.util.TreeMap; 026import org.apache.commons.lang3.NotImplementedException; 027import org.apache.hadoop.conf.Configuration; 028import org.apache.hadoop.fs.FileSystem; 029import org.apache.hadoop.fs.Path; 030import org.apache.hadoop.hbase.HRegionLocation; 031import org.apache.hadoop.hbase.ServerName; 032import org.apache.hadoop.hbase.TableName; 033import org.apache.hadoop.hbase.client.RegionInfo; 034import org.apache.hadoop.hbase.client.RegionInfoBuilder; 035import org.apache.hadoop.hbase.client.RegionLocator; 036import org.apache.hadoop.hbase.util.Bytes; 037import org.apache.yetus.audience.InterfaceAudience; 038 039import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos; 040import org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos; 041 042/** 043 * {@link RegionLocator} built using the most recent full backup's snapshot manifest for a given 044 * table. Useful for aligning any subsequent incremental backups along the same splits as the full 045 * backup 046 */ 047@InterfaceAudience.Private 048public final class SnapshotRegionLocator implements RegionLocator { 049 050 private static final String SNAPSHOT_MANIFEST_DIR_PREFIX = 051 "region.locator.snapshot.manifest.dir."; 052 053 private static final ServerName FAKE_SERVER_NAME = 054 ServerName.parseServerName("www.example.net,1234,1212121212"); 055 056 private final TableName tableName; 057 private final TreeMap<byte[], HRegionReplicas> regions; 058 059 private final List<HRegionLocation> rawLocations; 060 061 public static SnapshotRegionLocator create(Configuration conf, TableName table) 062 throws IOException { 063 Path workingDir = new Path(conf.get(getSnapshotManifestDirKey(table))); 064 FileSystem fs = workingDir.getFileSystem(conf); 065 SnapshotProtos.SnapshotDescription desc = 066 SnapshotDescriptionUtils.readSnapshotInfo(fs, workingDir); 067 SnapshotManifest manifest = SnapshotManifest.open(conf, fs, workingDir, desc); 068 069 TableName tableName = manifest.getTableDescriptor().getTableName(); 070 TreeMap<byte[], HRegionReplicas> replicas = new TreeMap<>(Bytes.BYTES_COMPARATOR); 071 List<HRegionLocation> rawLocations = new ArrayList<>(); 072 073 for (SnapshotProtos.SnapshotRegionManifest region : manifest.getRegionManifests()) { 074 HBaseProtos.RegionInfo ri = region.getRegionInfo(); 075 if (ri.getOffline() || ri.getSplit()) { 076 continue; 077 } 078 byte[] key = ri.getStartKey().toByteArray(); 079 080 SnapshotHRegionLocation location = toLocation(ri, tableName); 081 rawLocations.add(location); 082 HRegionReplicas hrr = replicas.get(key); 083 084 if (hrr == null) { 085 hrr = new HRegionReplicas(location); 086 } else { 087 hrr.addReplica(location); 088 } 089 090 replicas.put(key, hrr); 091 } 092 093 return new SnapshotRegionLocator(tableName, replicas, rawLocations); 094 } 095 096 private SnapshotRegionLocator(TableName tableName, TreeMap<byte[], HRegionReplicas> regions, 097 List<HRegionLocation> rawLocations) { 098 this.tableName = tableName; 099 this.regions = regions; 100 this.rawLocations = rawLocations; 101 } 102 103 @Override 104 public HRegionLocation getRegionLocation(byte[] row, int replicaId, boolean reload) 105 throws IOException { 106 return regions.floorEntry(row).getValue().getReplica(replicaId); 107 } 108 109 @Override 110 public List<HRegionLocation> getRegionLocations(byte[] row, boolean reload) throws IOException { 111 return List.of(getRegionLocation(row, reload)); 112 } 113 114 @Override 115 public void clearRegionLocationCache() { 116 117 } 118 119 @Override 120 public List<HRegionLocation> getAllRegionLocations() throws IOException { 121 return rawLocations; 122 } 123 124 @Override 125 public TableName getName() { 126 return tableName; 127 } 128 129 @Override 130 public void close() throws IOException { 131 132 } 133 134 public static boolean shouldUseSnapshotRegionLocator(Configuration conf, TableName table) { 135 return conf.get(getSnapshotManifestDirKey(table)) != null; 136 } 137 138 public static void setSnapshotManifestDir(Configuration conf, String dir, TableName table) { 139 conf.set(getSnapshotManifestDirKey(table), dir); 140 } 141 142 private static String getSnapshotManifestDirKey(TableName table) { 143 return SNAPSHOT_MANIFEST_DIR_PREFIX + table.getNameWithNamespaceInclAsString(); 144 } 145 146 private static SnapshotHRegionLocation toLocation(HBaseProtos.RegionInfo ri, 147 TableName tableName) { 148 RegionInfo region = RegionInfoBuilder.newBuilder(tableName) 149 .setStartKey(ri.getStartKey().toByteArray()).setEndKey(ri.getEndKey().toByteArray()) 150 .setRegionId(ri.getRegionId()).setReplicaId(ri.getReplicaId()).build(); 151 152 return new SnapshotHRegionLocation(region); 153 } 154 155 private static final class HRegionReplicas { 156 private final Map<Integer, SnapshotHRegionLocation> replicas = new HashMap<>(); 157 158 private HRegionReplicas(SnapshotHRegionLocation region) { 159 addReplica(region); 160 } 161 162 private void addReplica(SnapshotHRegionLocation replica) { 163 this.replicas.put(replica.getRegion().getReplicaId(), replica); 164 } 165 166 private HRegionLocation getReplica(int replicaId) { 167 return replicas.get(replicaId); 168 } 169 } 170 171 public static final class SnapshotHRegionLocation extends HRegionLocation { 172 173 public SnapshotHRegionLocation(RegionInfo regionInfo) { 174 super(regionInfo, FAKE_SERVER_NAME); 175 } 176 177 @Override 178 public ServerName getServerName() { 179 throw new NotImplementedException("SnapshotHRegionLocation doesn't have a server name"); 180 } 181 182 @Override 183 public String getHostname() { 184 throw new NotImplementedException("SnapshotHRegionLocation doesn't have a host name"); 185 } 186 187 @Override 188 public int getPort() { 189 throw new NotImplementedException("SnapshotHRegionLocation doesn't have a port"); 190 } 191 192 @Override 193 public int hashCode() { 194 return this.getRegion().hashCode(); 195 } 196 197 @Override 198 public boolean equals(Object o) { 199 return super.equals(o); 200 } 201 202 @Override 203 public int compareTo(HRegionLocation o) { 204 return this.getRegion().compareTo(o.getRegion()); 205 } 206 } 207}