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