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