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.util; 019 020import java.io.IOException; 021import java.util.Arrays; 022import java.util.Comparator; 023import java.util.List; 024 025import org.apache.hadoop.conf.Configuration; 026import org.apache.hadoop.fs.FileSystem; 027import org.apache.hadoop.fs.Path; 028import org.apache.hadoop.hbase.HRegionInfo; 029import org.apache.hadoop.hbase.ServerName; 030import org.apache.hadoop.hbase.TableName; 031import org.apache.hadoop.hbase.client.RegionInfo; 032import org.apache.hadoop.hbase.client.RegionReplicaUtil; 033import org.apache.hadoop.hbase.regionserver.HRegionFileSystem; 034import org.apache.yetus.audience.InterfaceAudience; 035import org.apache.yetus.audience.InterfaceStability; 036import org.slf4j.Logger; 037import org.slf4j.LoggerFactory; 038 039import org.apache.hbase.thirdparty.com.google.common.base.Joiner; 040import org.apache.hbase.thirdparty.com.google.common.collect.Lists; 041 042/** 043 * Maintain information about a particular region. It gathers information 044 * from three places -- HDFS, META, and region servers. 045 */ 046@InterfaceAudience.Private 047@InterfaceStability.Evolving 048public class HbckRegionInfo implements KeyRange { 049 private static final Logger LOG = LoggerFactory.getLogger(HbckRegionInfo.class.getName()); 050 051 private MetaEntry metaEntry = null; // info in META 052 private HdfsEntry hdfsEntry = null; // info in HDFS 053 private List<OnlineEntry> deployedEntries = Lists.newArrayList(); // on Region Server 054 private List<ServerName> deployedOn = Lists.newArrayList(); // info on RS's 055 private boolean skipChecks = false; // whether to skip further checks to this region info. 056 private boolean isMerged = false;// whether this region has already been merged into another one 057 private int deployedReplicaId = RegionInfo.DEFAULT_REPLICA_ID; 058 private RegionInfo primaryHRIForDeployedReplica = null; 059 060 public HbckRegionInfo(MetaEntry metaEntry) { 061 this.metaEntry = metaEntry; 062 } 063 064 public synchronized int getReplicaId() { 065 return metaEntry != null? metaEntry.getReplicaId(): deployedReplicaId; 066 } 067 068 public synchronized void addServer(RegionInfo regionInfo, ServerName serverName) { 069 OnlineEntry rse = new OnlineEntry(regionInfo, serverName) ; 070 this.deployedEntries.add(rse); 071 this.deployedOn.add(serverName); 072 // save the replicaId that we see deployed in the cluster 073 this.deployedReplicaId = regionInfo.getReplicaId(); 074 this.primaryHRIForDeployedReplica = 075 RegionReplicaUtil.getRegionInfoForDefaultReplica(regionInfo); 076 } 077 078 @Override 079 public synchronized String toString() { 080 StringBuilder sb = new StringBuilder(); 081 sb.append("{ meta => "); 082 sb.append((metaEntry != null)? metaEntry.getRegionNameAsString() : "null"); 083 sb.append(", hdfs => " + getHdfsRegionDir()); 084 sb.append(", deployed => " + Joiner.on(", ").join(deployedEntries)); 085 sb.append(", replicaId => " + getReplicaId()); 086 sb.append(" }"); 087 return sb.toString(); 088 } 089 090 @Override 091 public byte[] getStartKey() { 092 if (this.metaEntry != null) { 093 return this.metaEntry.getStartKey(); 094 } else if (this.hdfsEntry != null) { 095 return this.hdfsEntry.hri.getStartKey(); 096 } else { 097 LOG.error("Entry " + this + " has no meta or hdfs region start key."); 098 return null; 099 } 100 } 101 102 @Override 103 public byte[] getEndKey() { 104 if (this.metaEntry != null) { 105 return this.metaEntry.getEndKey(); 106 } else if (this.hdfsEntry != null) { 107 return this.hdfsEntry.hri.getEndKey(); 108 } else { 109 LOG.error("Entry " + this + " has no meta or hdfs region start key."); 110 return null; 111 } 112 } 113 114 public MetaEntry getMetaEntry() { 115 return this.metaEntry; 116 } 117 118 public void setMetaEntry(MetaEntry metaEntry) { 119 this.metaEntry = metaEntry; 120 } 121 122 public HdfsEntry getHdfsEntry() { 123 return this.hdfsEntry; 124 } 125 126 public void setHdfsEntry(HdfsEntry hdfsEntry) { 127 this.hdfsEntry = hdfsEntry; 128 } 129 130 public List<OnlineEntry> getOnlineEntries() { 131 return this.deployedEntries; 132 } 133 134 public List<ServerName> getDeployedOn() { 135 return this.deployedOn; 136 } 137 138 /** 139 * Read the .regioninfo file from the file system. If there is no 140 * .regioninfo, add it to the orphan hdfs region list. 141 */ 142 public void loadHdfsRegioninfo(Configuration conf) throws IOException { 143 Path regionDir = getHdfsRegionDir(); 144 if (regionDir == null) { 145 if (getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) { 146 // Log warning only for default/ primary replica with no region dir 147 LOG.warn("No HDFS region dir found: " + this + " meta=" + metaEntry); 148 } 149 return; 150 } 151 152 if (hdfsEntry.hri != null) { 153 // already loaded data 154 return; 155 } 156 157 FileSystem fs = FileSystem.get(conf); 158 RegionInfo hri = HRegionFileSystem.loadRegionInfoFileContent(fs, regionDir); 159 LOG.debug("RegionInfo read: " + hri.toString()); 160 hdfsEntry.hri = hri; 161 } 162 163 public TableName getTableName() { 164 if (this.metaEntry != null) { 165 return this.metaEntry.getTable(); 166 } else if (this.hdfsEntry != null) { 167 // we are only guaranteed to have a path and not an HRI for hdfsEntry, 168 // so we get the name from the Path 169 Path tableDir = this.hdfsEntry.regionDir.getParent(); 170 return FSUtils.getTableName(tableDir); 171 } else { 172 // return the info from the first online/deployed hri 173 for (OnlineEntry e : deployedEntries) { 174 return e.getRegionInfo().getTable(); 175 } 176 return null; 177 } 178 } 179 180 public String getRegionNameAsString() { 181 if (metaEntry != null) { 182 return metaEntry.getRegionNameAsString(); 183 } else if (hdfsEntry != null) { 184 if (hdfsEntry.hri != null) { 185 return hdfsEntry.hri.getRegionNameAsString(); 186 } 187 } else { 188 // return the info from the first online/deployed hri 189 for (OnlineEntry e : deployedEntries) { 190 return e.getRegionInfo().getRegionNameAsString(); 191 } 192 } 193 return null; 194 } 195 196 public byte[] getRegionName() { 197 if (metaEntry != null) { 198 return metaEntry.getRegionName(); 199 } else if (hdfsEntry != null) { 200 return hdfsEntry.hri.getRegionName(); 201 } else { 202 // return the info from the first online/deployed hri 203 for (OnlineEntry e : deployedEntries) { 204 return e.getRegionInfo().getRegionName(); 205 } 206 return null; 207 } 208 } 209 210 public RegionInfo getPrimaryHRIForDeployedReplica() { 211 return primaryHRIForDeployedReplica; 212 } 213 214 public Path getHdfsRegionDir() { 215 if (hdfsEntry == null) { 216 return null; 217 } 218 return hdfsEntry.regionDir; 219 } 220 221 public boolean containsOnlyHdfsEdits() { 222 if (hdfsEntry == null) { 223 return false; 224 } 225 return hdfsEntry.hdfsOnlyEdits; 226 } 227 228 public boolean isHdfsRegioninfoPresent() { 229 if (hdfsEntry == null) { 230 return false; 231 } 232 return hdfsEntry.hdfsRegioninfoFilePresent; 233 } 234 235 public long getModTime() { 236 if (hdfsEntry == null) { 237 return 0; 238 } 239 return hdfsEntry.regionDirModTime; 240 } 241 242 public RegionInfo getHdfsHRI() { 243 if (hdfsEntry == null) { 244 return null; 245 } 246 return hdfsEntry.hri; 247 } 248 249 public void setSkipChecks(boolean skipChecks) { 250 this.skipChecks = skipChecks; 251 } 252 253 public boolean isSkipChecks() { 254 return skipChecks; 255 } 256 257 public void setMerged(boolean isMerged) { 258 this.isMerged = isMerged; 259 } 260 261 public boolean isMerged() { 262 return this.isMerged; 263 } 264 265 /** 266 * Stores the regioninfo entries scanned from META 267 */ 268 public static class MetaEntry extends HRegionInfo { 269 ServerName regionServer; // server hosting this region 270 long modTime; // timestamp of most recent modification metadata 271 RegionInfo splitA, splitB; //split daughters 272 273 public MetaEntry(RegionInfo rinfo, ServerName regionServer, long modTime) { 274 this(rinfo, regionServer, modTime, null, null); 275 } 276 277 public MetaEntry(RegionInfo rinfo, ServerName regionServer, long modTime, 278 RegionInfo splitA, RegionInfo splitB) { 279 super(rinfo); 280 this.regionServer = regionServer; 281 this.modTime = modTime; 282 this.splitA = splitA; 283 this.splitB = splitB; 284 } 285 286 public ServerName getRegionServer() { 287 return this.regionServer; 288 } 289 290 @Override 291 public boolean equals(Object o) { 292 boolean superEq = super.equals(o); 293 if (!superEq) { 294 return superEq; 295 } 296 297 MetaEntry me = (MetaEntry) o; 298 if (!regionServer.equals(me.regionServer)) { 299 return false; 300 } 301 return (modTime == me.modTime); 302 } 303 304 @Override 305 public int hashCode() { 306 int hash = Arrays.hashCode(getRegionName()); 307 hash = (int) (hash ^ getRegionId()); 308 hash ^= Arrays.hashCode(getStartKey()); 309 hash ^= Arrays.hashCode(getEndKey()); 310 hash ^= Boolean.valueOf(isOffline()).hashCode(); 311 hash ^= getTable().hashCode(); 312 if (regionServer != null) { 313 hash ^= regionServer.hashCode(); 314 } 315 hash = (int) (hash ^ modTime); 316 return hash; 317 } 318 } 319 320 /** 321 * Stores the regioninfo entries from HDFS 322 */ 323 public static class HdfsEntry { 324 RegionInfo hri; 325 Path regionDir = null; 326 long regionDirModTime = 0; 327 boolean hdfsRegioninfoFilePresent = false; 328 boolean hdfsOnlyEdits = false; 329 330 HdfsEntry() { 331 } 332 333 public HdfsEntry(Path regionDir) { 334 this.regionDir = regionDir; 335 } 336 } 337 338 /** 339 * Stores the regioninfo retrieved from Online region servers. 340 */ 341 static class OnlineEntry { 342 private RegionInfo regionInfo; 343 private ServerName serverName; 344 345 OnlineEntry(RegionInfo regionInfo, ServerName serverName) { 346 this.regionInfo = regionInfo; 347 this.serverName = serverName; 348 } 349 350 public RegionInfo getRegionInfo() { 351 return regionInfo; 352 } 353 354 public ServerName getServerName() { 355 return serverName; 356 } 357 358 @Override 359 public String toString() { 360 return serverName.toString() + ";" + regionInfo.getRegionNameAsString(); 361 } 362 } 363 364 final static Comparator<HbckRegionInfo> COMPARATOR = new Comparator<HbckRegionInfo>() { 365 @Override 366 public int compare(HbckRegionInfo l, HbckRegionInfo r) { 367 if (l == r) { 368 // same instance 369 return 0; 370 } 371 372 int tableCompare = l.getTableName().compareTo(r.getTableName()); 373 if (tableCompare != 0) { 374 return tableCompare; 375 } 376 377 int startComparison = RegionSplitCalculator.BYTES_COMPARATOR.compare( 378 l.getStartKey(), r.getStartKey()); 379 if (startComparison != 0) { 380 return startComparison; 381 } 382 383 // Special case for absolute endkey 384 byte[] endKey = r.getEndKey(); 385 endKey = (endKey.length == 0) ? null : endKey; 386 byte[] endKey2 = l.getEndKey(); 387 endKey2 = (endKey2.length == 0) ? null : endKey2; 388 int endComparison = RegionSplitCalculator.BYTES_COMPARATOR.compare( 389 endKey2, endKey); 390 391 if (endComparison != 0) { 392 return endComparison; 393 } 394 395 // use regionId as tiebreaker. 396 // Null is considered after all possible values so make it bigger. 397 if (l.getHdfsEntry() == null && r.getHdfsEntry() == null) { 398 return 0; 399 } 400 if (l.getHdfsEntry() == null && r.getHdfsEntry() != null) { 401 return 1; 402 } 403 // l.hdfsEntry must not be null 404 if (r.getHdfsEntry() == null) { 405 return -1; 406 } 407 // both l.hdfsEntry and r.hdfsEntry must not be null. 408 return Long.compare(l.getHdfsEntry().hri.getRegionId(), r.getHdfsEntry().hri.getRegionId()); 409 } 410 }; 411}