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.Closeable; 021import java.io.FileNotFoundException; 022import java.io.IOException; 023import java.io.InterruptedIOException; 024import java.io.PrintWriter; 025import java.io.StringWriter; 026import java.net.InetAddress; 027import java.net.URI; 028import java.util.ArrayList; 029import java.util.Collection; 030import java.util.Collections; 031import java.util.Comparator; 032import java.util.EnumSet; 033import java.util.HashMap; 034import java.util.HashSet; 035import java.util.Iterator; 036import java.util.List; 037import java.util.Locale; 038import java.util.Map; 039import java.util.Map.Entry; 040import java.util.Objects; 041import java.util.Optional; 042import java.util.Set; 043import java.util.SortedMap; 044import java.util.TreeMap; 045import java.util.Vector; 046import java.util.concurrent.Callable; 047import java.util.concurrent.ConcurrentSkipListMap; 048import java.util.concurrent.ExecutionException; 049import java.util.concurrent.ExecutorService; 050import java.util.concurrent.Executors; 051import java.util.concurrent.Future; 052import java.util.concurrent.FutureTask; 053import java.util.concurrent.ScheduledThreadPoolExecutor; 054import java.util.concurrent.TimeUnit; 055import java.util.concurrent.TimeoutException; 056import java.util.concurrent.atomic.AtomicBoolean; 057import java.util.concurrent.atomic.AtomicInteger; 058import java.util.stream.Collectors; 059import org.apache.commons.io.IOUtils; 060import org.apache.commons.lang3.StringUtils; 061import org.apache.hadoop.conf.Configuration; 062import org.apache.hadoop.conf.Configured; 063import org.apache.hadoop.fs.FSDataOutputStream; 064import org.apache.hadoop.fs.FileStatus; 065import org.apache.hadoop.fs.FileSystem; 066import org.apache.hadoop.fs.Path; 067import org.apache.hadoop.fs.permission.FsAction; 068import org.apache.hadoop.fs.permission.FsPermission; 069import org.apache.hadoop.hbase.Abortable; 070import org.apache.hadoop.hbase.CatalogFamilyFormat; 071import org.apache.hadoop.hbase.Cell; 072import org.apache.hadoop.hbase.CellUtil; 073import org.apache.hadoop.hbase.ClientMetaTableAccessor; 074import org.apache.hadoop.hbase.ClusterMetrics; 075import org.apache.hadoop.hbase.ClusterMetrics.Option; 076import org.apache.hadoop.hbase.ExtendedCell; 077import org.apache.hadoop.hbase.HBaseConfiguration; 078import org.apache.hadoop.hbase.HBaseInterfaceAudience; 079import org.apache.hadoop.hbase.HConstants; 080import org.apache.hadoop.hbase.HRegionLocation; 081import org.apache.hadoop.hbase.KeyValue; 082import org.apache.hadoop.hbase.MasterNotRunningException; 083import org.apache.hadoop.hbase.MetaTableAccessor; 084import org.apache.hadoop.hbase.RegionLocations; 085import org.apache.hadoop.hbase.ServerName; 086import org.apache.hadoop.hbase.TableName; 087import org.apache.hadoop.hbase.TableNotFoundException; 088import org.apache.hadoop.hbase.ZooKeeperConnectionException; 089import org.apache.hadoop.hbase.client.Admin; 090import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor; 091import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; 092import org.apache.hadoop.hbase.client.Connection; 093import org.apache.hadoop.hbase.client.ConnectionFactory; 094import org.apache.hadoop.hbase.client.Delete; 095import org.apache.hadoop.hbase.client.Get; 096import org.apache.hadoop.hbase.client.Put; 097import org.apache.hadoop.hbase.client.RegionInfo; 098import org.apache.hadoop.hbase.client.RegionInfoBuilder; 099import org.apache.hadoop.hbase.client.RegionLocator; 100import org.apache.hadoop.hbase.client.RegionReplicaUtil; 101import org.apache.hadoop.hbase.client.Result; 102import org.apache.hadoop.hbase.client.ResultScanner; 103import org.apache.hadoop.hbase.client.RowMutations; 104import org.apache.hadoop.hbase.client.Scan; 105import org.apache.hadoop.hbase.client.Table; 106import org.apache.hadoop.hbase.client.TableDescriptor; 107import org.apache.hadoop.hbase.client.TableDescriptorBuilder; 108import org.apache.hadoop.hbase.client.TableState; 109import org.apache.hadoop.hbase.io.FileLink; 110import org.apache.hadoop.hbase.io.HFileLink; 111import org.apache.hadoop.hbase.io.hfile.CacheConfig; 112import org.apache.hadoop.hbase.io.hfile.HFile; 113import org.apache.hadoop.hbase.master.RegionState; 114import org.apache.hadoop.hbase.regionserver.HRegion; 115import org.apache.hadoop.hbase.regionserver.HRegionFileSystem; 116import org.apache.hadoop.hbase.regionserver.StoreFileInfo; 117import org.apache.hadoop.hbase.replication.ReplicationException; 118import org.apache.hadoop.hbase.replication.ReplicationPeerDescription; 119import org.apache.hadoop.hbase.replication.ReplicationQueueStorage; 120import org.apache.hadoop.hbase.replication.ReplicationStorageFactory; 121import org.apache.hadoop.hbase.security.UserProvider; 122import org.apache.hadoop.hbase.util.Bytes.ByteArrayComparator; 123import org.apache.hadoop.hbase.util.HbckErrorReporter.ERROR_CODE; 124import org.apache.hadoop.hbase.util.hbck.HFileCorruptionChecker; 125import org.apache.hadoop.hbase.util.hbck.ReplicationChecker; 126import org.apache.hadoop.hbase.util.hbck.TableIntegrityErrorHandler; 127import org.apache.hadoop.hbase.wal.WALSplitUtil; 128import org.apache.hadoop.hbase.zookeeper.ZKUtil; 129import org.apache.hadoop.hbase.zookeeper.ZKWatcher; 130import org.apache.hadoop.hbase.zookeeper.ZNodePaths; 131import org.apache.hadoop.hdfs.protocol.AlreadyBeingCreatedException; 132import org.apache.hadoop.ipc.RemoteException; 133import org.apache.hadoop.security.AccessControlException; 134import org.apache.hadoop.security.UserGroupInformation; 135import org.apache.hadoop.util.ReflectionUtils; 136import org.apache.hadoop.util.Tool; 137import org.apache.hadoop.util.ToolRunner; 138import org.apache.yetus.audience.InterfaceAudience; 139import org.apache.yetus.audience.InterfaceStability; 140import org.apache.zookeeper.KeeperException; 141import org.slf4j.Logger; 142import org.slf4j.LoggerFactory; 143 144import org.apache.hbase.thirdparty.com.google.common.base.Joiner; 145import org.apache.hbase.thirdparty.com.google.common.base.Preconditions; 146import org.apache.hbase.thirdparty.com.google.common.collect.Lists; 147import org.apache.hbase.thirdparty.com.google.common.collect.Sets; 148import org.apache.hbase.thirdparty.com.google.common.io.Closeables; 149import org.apache.hbase.thirdparty.com.google.common.util.concurrent.ThreadFactoryBuilder; 150 151/** 152 * HBaseFsck (hbck) is a tool for checking and repairing region consistency and table integrity 153 * problems in a corrupted HBase. This tool was written for hbase-1.x. It does not work with 154 * hbase-2.x; it can read state but is not allowed to change state; i.e. effect 'repair'. Even 155 * though it can 'read' state, given how so much has changed in how hbase1 and hbase2 operate, it 156 * will often misread. See hbck2 (HBASE-19121) for a hbck tool for hbase2. This class is deprecated. 157 * <p> 158 * Region consistency checks verify that hbase:meta, region deployment on region servers and the 159 * state of data in HDFS (.regioninfo files) all are in accordance. 160 * <p> 161 * Table integrity checks verify that all possible row keys resolve to exactly one region of a 162 * table. This means there are no individual degenerate or backwards regions; no holes between 163 * regions; and that there are no overlapping regions. 164 * <p> 165 * The general repair strategy works in two phases: 166 * <ol> 167 * <li>Repair Table Integrity on HDFS. (merge or fabricate regions) 168 * <li>Repair Region Consistency with hbase:meta and assignments 169 * </ol> 170 * <p> 171 * For table integrity repairs, the tables' region directories are scanned for .regioninfo files. 172 * Each table's integrity is then verified. If there are any orphan regions (regions with no 173 * .regioninfo files) or holes, new regions are fabricated. Backwards regions are sidelined as well 174 * as empty degenerate (endkey==startkey) regions. If there are any overlapping regions, a new 175 * region is created and all data is merged into the new region. 176 * <p> 177 * Table integrity repairs deal solely with HDFS and could potentially be done offline -- the hbase 178 * region servers or master do not need to be running. This phase can eventually be used to 179 * completely reconstruct the hbase:meta table in an offline fashion. 180 * <p> 181 * Region consistency requires three conditions -- 1) valid .regioninfo file present in an HDFS 182 * region dir, 2) valid row with .regioninfo data in META, and 3) a region is deployed only at the 183 * regionserver that was assigned to with proper state in the master. 184 * <p> 185 * Region consistency repairs require hbase to be online so that hbck can contact the HBase master 186 * and region servers. The hbck#connect() method must first be called successfully. Much of the 187 * region consistency information is transient and less risky to repair. 188 * <p> 189 * If hbck is run from the command line, there are a handful of arguments that can be used to limit 190 * the kinds of repairs hbck will do. See the code in {@link #printUsageAndExit()} for more details. 191 * @deprecated For removal in hbase-4.0.0. Use HBCK2 instead. 192 */ 193@Deprecated 194@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.TOOLS) 195@InterfaceStability.Evolving 196public class HBaseFsck extends Configured implements Closeable { 197 public static final long DEFAULT_TIME_LAG = 60000; // default value of 1 minute 198 public static final long DEFAULT_SLEEP_BEFORE_RERUN = 10000; 199 private static final int MAX_NUM_THREADS = 50; // #threads to contact regions 200 private static boolean rsSupportsOffline = true; 201 private static final int DEFAULT_OVERLAPS_TO_SIDELINE = 2; 202 private static final int DEFAULT_MAX_MERGE = 5; 203 204 /** 205 * Here is where hbase-1.x used to default the lock for hbck1. It puts in place a lock when it 206 * goes to write/make changes. 207 */ 208 @InterfaceAudience.Private 209 public static final String HBCK_LOCK_FILE = "hbase-hbck.lock"; 210 private static final int DEFAULT_MAX_LOCK_FILE_ATTEMPTS = 5; 211 private static final int DEFAULT_LOCK_FILE_ATTEMPT_SLEEP_INTERVAL = 200; // milliseconds 212 private static final int DEFAULT_LOCK_FILE_ATTEMPT_MAX_SLEEP_TIME = 5000; // milliseconds 213 // We have to set the timeout value > HdfsConstants.LEASE_SOFTLIMIT_PERIOD. 214 // In HADOOP-2.6 and later, the Namenode proxy now created with custom RetryPolicy for 215 // AlreadyBeingCreatedException which is implies timeout on this operations up to 216 // HdfsConstants.LEASE_SOFTLIMIT_PERIOD (60 seconds). 217 private static final int DEFAULT_WAIT_FOR_LOCK_TIMEOUT = 80; // seconds 218 private static final int DEFAULT_MAX_CREATE_ZNODE_ATTEMPTS = 5; 219 private static final int DEFAULT_CREATE_ZNODE_ATTEMPT_SLEEP_INTERVAL = 200; // milliseconds 220 private static final int DEFAULT_CREATE_ZNODE_ATTEMPT_MAX_SLEEP_TIME = 5000; // milliseconds 221 222 /********************** 223 * Internal resources 224 **********************/ 225 private static final Logger LOG = LoggerFactory.getLogger(HBaseFsck.class.getName()); 226 private ClusterMetrics status; 227 private Connection connection; 228 private Admin admin; 229 private Table meta; 230 // threads to do ||izable tasks: retrieve data from regionservers, handle overlapping regions 231 protected ExecutorService executor; 232 private long startMillis = EnvironmentEdgeManager.currentTime(); 233 private HFileCorruptionChecker hfcc; 234 private int retcode = 0; 235 private Path HBCK_LOCK_PATH; 236 private FSDataOutputStream hbckOutFd; 237 // This lock is to prevent cleanup of balancer resources twice between 238 // ShutdownHook and the main code. We cleanup only if the connect() is 239 // successful 240 private final AtomicBoolean hbckLockCleanup = new AtomicBoolean(false); 241 242 // Unsupported options in HBase 2.0+ 243 private static final Set<String> unsupportedOptionsInV2 = Sets.newHashSet("-fix", 244 "-fixAssignments", "-fixMeta", "-fixHdfsHoles", "-fixHdfsOrphans", "-fixTableOrphans", 245 "-fixHdfsOverlaps", "-sidelineBigOverlaps", "-fixSplitParents", "-removeParents", 246 "-fixEmptyMetaCells", "-repair", "-repairHoles", "-maxOverlapsToSideline", "-maxMerge"); 247 248 /*********** 249 * Options 250 ***********/ 251 private static boolean details = false; // do we display the full report 252 private long timelag = DEFAULT_TIME_LAG; // tables whose modtime is older 253 private static boolean forceExclusive = false; // only this hbck can modify HBase 254 private boolean fixAssignments = false; // fix assignment errors? 255 private boolean fixMeta = false; // fix meta errors? 256 private boolean checkHdfs = true; // load and check fs consistency? 257 private boolean fixHdfsHoles = false; // fix fs holes? 258 private boolean fixHdfsOverlaps = false; // fix fs overlaps (risky) 259 private boolean fixHdfsOrphans = false; // fix fs holes (missing .regioninfo) 260 private boolean fixTableOrphans = false; // fix fs holes (missing .tableinfo) 261 private boolean fixVersionFile = false; // fix missing hbase.version file in hdfs 262 private boolean fixSplitParents = false; // fix lingering split parents 263 private boolean removeParents = false; // remove split parents 264 private boolean fixReferenceFiles = false; // fix lingering reference store file 265 private boolean fixHFileLinks = false; // fix lingering HFileLinks 266 private boolean fixEmptyMetaCells = false; // fix (remove) empty REGIONINFO_QUALIFIER rows 267 private boolean fixReplication = false; // fix undeleted replication queues for removed peer 268 private boolean cleanReplicationBarrier = false; // clean replication barriers of a table 269 private boolean fixAny = false; // Set to true if any of the fix is required. 270 271 // limit checking/fixes to listed tables, if empty attempt to check/fix all 272 // hbase:meta are always checked 273 private Set<TableName> tablesIncluded = new HashSet<>(); 274 private TableName cleanReplicationBarrierTable; 275 private int maxMerge = DEFAULT_MAX_MERGE; // maximum number of overlapping regions to merge 276 // maximum number of overlapping regions to sideline 277 private int maxOverlapsToSideline = DEFAULT_OVERLAPS_TO_SIDELINE; 278 private boolean sidelineBigOverlaps = false; // sideline overlaps with >maxMerge regions 279 private Path sidelineDir = null; 280 281 private boolean rerun = false; // if we tried to fix something, rerun hbck 282 private static boolean summary = false; // if we want to print less output 283 private boolean checkMetaOnly = false; 284 private boolean checkRegionBoundaries = false; 285 private boolean ignorePreCheckPermission = false; // if pre-check permission 286 287 /********* 288 * State 289 *********/ 290 final private HbckErrorReporter errors; 291 int fixes = 0; 292 293 /** 294 * This map contains the state of all hbck items. It maps from encoded region name to 295 * HbckRegionInfo structure. The information contained in HbckRegionInfo is used to detect and 296 * correct consistency (hdfs/meta/deployment) problems. 297 */ 298 private TreeMap<String, HbckRegionInfo> regionInfoMap = new TreeMap<>(); 299 // Empty regioninfo qualifiers in hbase:meta 300 private Set<Result> emptyRegionInfoQualifiers = new HashSet<>(); 301 302 /** 303 * This map from Tablename -> TableInfo contains the structures necessary to detect table 304 * consistency problems (holes, dupes, overlaps). It is sorted to prevent dupes. If tablesIncluded 305 * is empty, this map contains all tables. Otherwise, it contains only meta tables and tables in 306 * tablesIncluded, unless checkMetaOnly is specified, in which case, it contains only the meta 307 * table 308 */ 309 private SortedMap<TableName, HbckTableInfo> tablesInfo = new ConcurrentSkipListMap<>(); 310 311 /** 312 * When initially looking at HDFS, we attempt to find any orphaned data. 313 */ 314 private List<HbckRegionInfo> orphanHdfsDirs = Collections.synchronizedList(new ArrayList<>()); 315 316 private Map<TableName, Set<String>> orphanTableDirs = new HashMap<>(); 317 private Map<TableName, TableState> tableStates = new HashMap<>(); 318 private final RetryCounterFactory lockFileRetryCounterFactory; 319 private final RetryCounterFactory createZNodeRetryCounterFactory; 320 321 private Map<TableName, Set<String>> skippedRegions = new HashMap<>(); 322 323 private ZKWatcher zkw = null; 324 private String hbckEphemeralNodePath = null; 325 private boolean hbckZodeCreated = false; 326 327 /** 328 * Constructor 329 * @param conf Configuration object 330 * @throws MasterNotRunningException if the master is not running 331 * @throws ZooKeeperConnectionException if unable to connect to ZooKeeper 332 */ 333 public HBaseFsck(Configuration conf) throws IOException, ClassNotFoundException { 334 this(conf, createThreadPool(conf)); 335 } 336 337 private static ExecutorService createThreadPool(Configuration conf) { 338 int numThreads = conf.getInt("hbasefsck.numthreads", MAX_NUM_THREADS); 339 return new ScheduledThreadPoolExecutor(numThreads, 340 new ThreadFactoryBuilder().setNameFormat("hbasefsck-pool-%d").setDaemon(true) 341 .setUncaughtExceptionHandler(Threads.LOGGING_EXCEPTION_HANDLER).build()); 342 } 343 344 /** 345 * Constructor Configuration object if the master is not running if unable to connect to ZooKeeper 346 */ 347 public HBaseFsck(Configuration conf, ExecutorService exec) throws MasterNotRunningException, 348 ZooKeeperConnectionException, IOException, ClassNotFoundException { 349 super(conf); 350 errors = getErrorReporter(getConf()); 351 this.executor = exec; 352 lockFileRetryCounterFactory = createLockRetryCounterFactory(getConf()); 353 createZNodeRetryCounterFactory = createZnodeRetryCounterFactory(getConf()); 354 zkw = createZooKeeperWatcher(); 355 } 356 357 /** Returns A retry counter factory configured for retrying lock file creation. */ 358 public static RetryCounterFactory createLockRetryCounterFactory(Configuration conf) { 359 return new RetryCounterFactory( 360 conf.getInt("hbase.hbck.lockfile.attempts", DEFAULT_MAX_LOCK_FILE_ATTEMPTS), 361 conf.getInt("hbase.hbck.lockfile.attempt.sleep.interval", 362 DEFAULT_LOCK_FILE_ATTEMPT_SLEEP_INTERVAL), 363 conf.getInt("hbase.hbck.lockfile.attempt.maxsleeptime", 364 DEFAULT_LOCK_FILE_ATTEMPT_MAX_SLEEP_TIME)); 365 } 366 367 /** Returns A retry counter factory configured for retrying znode creation. */ 368 private static RetryCounterFactory createZnodeRetryCounterFactory(Configuration conf) { 369 return new RetryCounterFactory( 370 conf.getInt("hbase.hbck.createznode.attempts", DEFAULT_MAX_CREATE_ZNODE_ATTEMPTS), 371 conf.getInt("hbase.hbck.createznode.attempt.sleep.interval", 372 DEFAULT_CREATE_ZNODE_ATTEMPT_SLEEP_INTERVAL), 373 conf.getInt("hbase.hbck.createznode.attempt.maxsleeptime", 374 DEFAULT_CREATE_ZNODE_ATTEMPT_MAX_SLEEP_TIME)); 375 } 376 377 /** Returns Return the tmp dir this tool writes too. */ 378 @InterfaceAudience.Private 379 public static Path getTmpDir(Configuration conf) throws IOException { 380 return new Path(CommonFSUtils.getRootDir(conf), HConstants.HBASE_TEMP_DIRECTORY); 381 } 382 383 private static class FileLockCallable implements Callable<FSDataOutputStream> { 384 RetryCounter retryCounter; 385 private final Configuration conf; 386 private Path hbckLockPath = null; 387 388 public FileLockCallable(Configuration conf, RetryCounter retryCounter) { 389 this.retryCounter = retryCounter; 390 this.conf = conf; 391 } 392 393 /** Returns Will be <code>null</code> unless you call {@link #call()} */ 394 Path getHbckLockPath() { 395 return this.hbckLockPath; 396 } 397 398 @Override 399 public FSDataOutputStream call() throws IOException { 400 try { 401 FileSystem fs = CommonFSUtils.getCurrentFileSystem(this.conf); 402 FsPermission defaultPerms = 403 CommonFSUtils.getFilePermissions(fs, this.conf, HConstants.DATA_FILE_UMASK_KEY); 404 Path tmpDir = getTmpDir(conf); 405 this.hbckLockPath = new Path(tmpDir, HBCK_LOCK_FILE); 406 fs.mkdirs(tmpDir); 407 final FSDataOutputStream out = createFileWithRetries(fs, this.hbckLockPath, defaultPerms); 408 out.writeBytes(InetAddress.getLocalHost().toString()); 409 // Add a note into the file we write on why hbase2 is writing out an hbck1 lock file. 410 out.writeBytes(" Written by an hbase-2.x Master to block an " 411 + "attempt by an hbase-1.x HBCK tool making modification to state. " 412 + "See 'HBCK must match HBase server version' in the hbase refguide."); 413 out.flush(); 414 return out; 415 } catch (RemoteException e) { 416 if (AlreadyBeingCreatedException.class.getName().equals(e.getClassName())) { 417 return null; 418 } else { 419 throw e; 420 } 421 } 422 } 423 424 private FSDataOutputStream createFileWithRetries(final FileSystem fs, 425 final Path hbckLockFilePath, final FsPermission defaultPerms) throws IOException { 426 IOException exception = null; 427 do { 428 try { 429 return CommonFSUtils.create(fs, hbckLockFilePath, defaultPerms, false); 430 } catch (IOException ioe) { 431 LOG.info("Failed to create lock file " + hbckLockFilePath.getName() + ", try=" 432 + (retryCounter.getAttemptTimes() + 1) + " of " + retryCounter.getMaxAttempts()); 433 LOG.debug("Failed to create lock file " + hbckLockFilePath.getName(), ioe); 434 try { 435 exception = ioe; 436 retryCounter.sleepUntilNextRetry(); 437 } catch (InterruptedException ie) { 438 throw (InterruptedIOException) new InterruptedIOException( 439 "Can't create lock file " + hbckLockFilePath.getName()).initCause(ie); 440 } 441 } 442 } while (retryCounter.shouldRetry()); 443 444 throw exception; 445 } 446 } 447 448 /** 449 * This method maintains a lock using a file. If the creation fails we return null 450 * @return FSDataOutputStream object corresponding to the newly opened lock file 451 * @throws IOException if IO failure occurs 452 */ 453 public static Pair<Path, FSDataOutputStream> checkAndMarkRunningHbck(Configuration conf, 454 RetryCounter retryCounter) throws IOException { 455 FileLockCallable callable = new FileLockCallable(conf, retryCounter); 456 ExecutorService executor = Executors.newFixedThreadPool(1); 457 FutureTask<FSDataOutputStream> futureTask = new FutureTask<>(callable); 458 executor.execute(futureTask); 459 final int timeoutInSeconds = 460 conf.getInt("hbase.hbck.lockfile.maxwaittime", DEFAULT_WAIT_FOR_LOCK_TIMEOUT); 461 FSDataOutputStream stream = null; 462 try { 463 stream = futureTask.get(timeoutInSeconds, TimeUnit.SECONDS); 464 } catch (ExecutionException ee) { 465 LOG.warn("Encountered exception when opening lock file", ee); 466 } catch (InterruptedException ie) { 467 LOG.warn("Interrupted when opening lock file", ie); 468 Thread.currentThread().interrupt(); 469 } catch (TimeoutException exception) { 470 // took too long to obtain lock 471 LOG.warn("Took more than " + timeoutInSeconds + " seconds in obtaining lock"); 472 futureTask.cancel(true); 473 } finally { 474 executor.shutdownNow(); 475 } 476 return new Pair<Path, FSDataOutputStream>(callable.getHbckLockPath(), stream); 477 } 478 479 private void unlockHbck() { 480 if (isExclusive() && hbckLockCleanup.compareAndSet(true, false)) { 481 RetryCounter retryCounter = lockFileRetryCounterFactory.create(); 482 do { 483 try { 484 Closeables.close(hbckOutFd, true); 485 CommonFSUtils.delete(CommonFSUtils.getCurrentFileSystem(getConf()), HBCK_LOCK_PATH, true); 486 LOG.info("Finishing hbck"); 487 return; 488 } catch (IOException ioe) { 489 LOG.info("Failed to delete " + HBCK_LOCK_PATH + ", try=" 490 + (retryCounter.getAttemptTimes() + 1) + " of " + retryCounter.getMaxAttempts()); 491 LOG.debug("Failed to delete " + HBCK_LOCK_PATH, ioe); 492 try { 493 retryCounter.sleepUntilNextRetry(); 494 } catch (InterruptedException ie) { 495 Thread.currentThread().interrupt(); 496 LOG.warn("Interrupted while deleting lock file" + HBCK_LOCK_PATH); 497 return; 498 } 499 } 500 } while (retryCounter.shouldRetry()); 501 } 502 } 503 504 /** 505 * To repair region consistency, one must call connect() in order to repair online state. 506 */ 507 public void connect() throws IOException { 508 509 if (isExclusive()) { 510 // Grab the lock 511 Pair<Path, FSDataOutputStream> pair = 512 checkAndMarkRunningHbck(getConf(), this.lockFileRetryCounterFactory.create()); 513 HBCK_LOCK_PATH = pair.getFirst(); 514 this.hbckOutFd = pair.getSecond(); 515 if (hbckOutFd == null) { 516 setRetCode(-1); 517 LOG.error("Another instance of hbck is fixing HBase, exiting this instance. " 518 + "[If you are sure no other instance is running, delete the lock file " + HBCK_LOCK_PATH 519 + " and rerun the tool]"); 520 throw new IOException("Duplicate hbck - Abort"); 521 } 522 523 // Make sure to cleanup the lock 524 hbckLockCleanup.set(true); 525 } 526 527 // Add a shutdown hook to this thread, in case user tries to 528 // kill the hbck with a ctrl-c, we want to cleanup the lock so that 529 // it is available for further calls 530 Runtime.getRuntime().addShutdownHook(new Thread() { 531 @Override 532 public void run() { 533 IOUtils.closeQuietly(HBaseFsck.this, e -> LOG.warn("", e)); 534 cleanupHbckZnode(); 535 unlockHbck(); 536 } 537 }); 538 539 LOG.info("Launching hbck"); 540 541 connection = ConnectionFactory.createConnection(getConf()); 542 admin = connection.getAdmin(); 543 meta = connection.getTable(TableName.META_TABLE_NAME); 544 status = admin.getClusterMetrics(EnumSet.of(Option.LIVE_SERVERS, Option.DEAD_SERVERS, 545 Option.MASTER, Option.BACKUP_MASTERS, Option.REGIONS_IN_TRANSITION, Option.HBASE_VERSION)); 546 } 547 548 /** 549 * Get deployed regions according to the region servers. 550 */ 551 private void loadDeployedRegions() throws IOException, InterruptedException { 552 // From the master, get a list of all known live region servers 553 Collection<ServerName> regionServers = status.getLiveServerMetrics().keySet(); 554 errors.print("Number of live region servers: " + regionServers.size()); 555 if (details) { 556 for (ServerName rsinfo : regionServers) { 557 errors.print(" " + rsinfo.getServerName()); 558 } 559 } 560 561 // From the master, get a list of all dead region servers 562 Collection<ServerName> deadRegionServers = status.getDeadServerNames(); 563 errors.print("Number of dead region servers: " + deadRegionServers.size()); 564 if (details) { 565 for (ServerName name : deadRegionServers) { 566 errors.print(" " + name); 567 } 568 } 569 570 // Print the current master name and state 571 errors.print("Master: " + status.getMasterName()); 572 573 // Print the list of all backup masters 574 Collection<ServerName> backupMasters = status.getBackupMasterNames(); 575 errors.print("Number of backup masters: " + backupMasters.size()); 576 if (details) { 577 for (ServerName name : backupMasters) { 578 errors.print(" " + name); 579 } 580 } 581 582 errors.print("Average load: " + status.getAverageLoad()); 583 errors.print("Number of requests: " + status.getRequestCount()); 584 errors.print("Number of regions: " + status.getRegionCount()); 585 586 List<RegionState> rits = status.getRegionStatesInTransition(); 587 errors.print("Number of regions in transition: " + rits.size()); 588 if (details) { 589 for (RegionState state : rits) { 590 errors.print(" " + state.toDescriptiveString()); 591 } 592 } 593 594 // Determine what's deployed 595 processRegionServers(regionServers); 596 } 597 598 /** 599 * Clear the current state of hbck. 600 */ 601 private void clearState() { 602 // Make sure regionInfo is empty before starting 603 fixes = 0; 604 regionInfoMap.clear(); 605 emptyRegionInfoQualifiers.clear(); 606 tableStates.clear(); 607 errors.clear(); 608 tablesInfo.clear(); 609 orphanHdfsDirs.clear(); 610 skippedRegions.clear(); 611 } 612 613 /** 614 * This repair method analyzes hbase data in hdfs and repairs it to satisfy the table integrity 615 * rules. HBase doesn't need to be online for this operation to work. 616 */ 617 public void offlineHdfsIntegrityRepair() throws IOException, InterruptedException { 618 // Initial pass to fix orphans. 619 if ( 620 shouldCheckHdfs() && (shouldFixHdfsOrphans() || shouldFixHdfsHoles() 621 || shouldFixHdfsOverlaps() || shouldFixTableOrphans()) 622 ) { 623 LOG.info("Loading regioninfos HDFS"); 624 // if nothing is happening this should always complete in two iterations. 625 int maxIterations = getConf().getInt("hbase.hbck.integrityrepair.iterations.max", 3); 626 int curIter = 0; 627 do { 628 clearState(); // clears hbck state and reset fixes to 0 and. 629 // repair what's on HDFS 630 restoreHdfsIntegrity(); 631 curIter++;// limit the number of iterations. 632 } while (fixes > 0 && curIter <= maxIterations); 633 634 // Repairs should be done in the first iteration and verification in the second. 635 // If there are more than 2 passes, something funny has happened. 636 if (curIter > 2) { 637 if (curIter == maxIterations) { 638 LOG.warn("Exiting integrity repairs after max " + curIter + " iterations. " 639 + "Tables integrity may not be fully repaired!"); 640 } else { 641 LOG.info("Successfully exiting integrity repairs after " + curIter + " iterations"); 642 } 643 } 644 } 645 } 646 647 /** 648 * This repair method requires the cluster to be online since it contacts region servers and the 649 * masters. It makes each region's state in HDFS, in hbase:meta, and deployments consistent. 650 * @return If > 0 , number of errors detected, if < 0 there was an unrecoverable error. If 651 * 0, we have a clean hbase. 652 */ 653 public int onlineConsistencyRepair() throws IOException, KeeperException, InterruptedException { 654 655 // get regions according to what is online on each RegionServer 656 loadDeployedRegions(); 657 // check whether hbase:meta is deployed and online 658 recordMetaRegion(); 659 // Report inconsistencies if there are any unknown servers. 660 reportUnknownServers(); 661 // Check if hbase:meta is found only once and in the right place 662 if (!checkMetaRegion()) { 663 String errorMsg = TableName.META_TABLE_NAME + " table is not consistent. "; 664 if (shouldFixAssignments()) { 665 errorMsg += "HBCK will try fixing it. Rerun once " + TableName.META_TABLE_NAME + " is back " 666 + "to consistent state."; 667 } else { 668 errorMsg += "Run HBCK with proper fix options to fix " + TableName.META_TABLE_NAME 669 + " inconsistency."; 670 } 671 errors.reportError(errorMsg + " Exiting..."); 672 return -2; 673 } 674 // Not going with further consistency check for tables when hbase:meta itself is not consistent. 675 LOG.info("Loading regionsinfo from the {} table", TableName.META_TABLE_NAME); 676 boolean success = loadMetaEntries(); 677 if (!success) return -1; 678 679 // Empty cells in hbase:meta? 680 reportEmptyMetaCells(); 681 682 // Check if we have to cleanup empty REGIONINFO_QUALIFIER rows from hbase:meta 683 if (shouldFixEmptyMetaCells()) { 684 fixEmptyMetaCells(); 685 } 686 687 // get a list of all tables that have not changed recently. 688 if (!checkMetaOnly) { 689 reportTablesInFlux(); 690 } 691 692 // Get disabled tables states 693 loadTableStates(); 694 695 // load regiondirs and regioninfos from HDFS 696 if (shouldCheckHdfs()) { 697 LOG.info("Loading region directories from HDFS"); 698 loadHdfsRegionDirs(); 699 LOG.info("Loading region information from HDFS"); 700 loadHdfsRegionInfos(); 701 } 702 703 // fix the orphan tables 704 fixOrphanTables(); 705 706 LOG.info("Checking and fixing region consistency"); 707 // Check and fix consistency 708 checkAndFixConsistency(); 709 710 // Check integrity (does not fix) 711 checkIntegrity(); 712 return errors.getErrorList().size(); 713 } 714 715 private void reportUnknownServers() throws IOException { 716 List<ServerName> unknownServers = admin.listUnknownServers(); 717 if (!unknownServers.isEmpty()) { 718 unknownServers.stream().forEach(serverName -> { 719 errors.reportError(ERROR_CODE.UNKNOWN_SERVER, 720 "Found unknown server, some of the regions held by this server may not get assigned. " 721 + String.format("Use HBCK2 scheduleRecoveries %s to recover.", serverName)); 722 }); 723 } 724 } 725 726 /** 727 * This method maintains an ephemeral znode. If the creation fails we return false or throw 728 * exception 729 * @return true if creating znode succeeds; false otherwise 730 * @throws IOException if IO failure occurs 731 */ 732 private boolean setMasterInMaintenanceMode() throws IOException { 733 RetryCounter retryCounter = createZNodeRetryCounterFactory.create(); 734 hbckEphemeralNodePath = ZNodePaths.joinZNode(zkw.getZNodePaths().masterMaintZNode, 735 "hbck-" + Long.toString(EnvironmentEdgeManager.currentTime())); 736 do { 737 try { 738 hbckZodeCreated = ZKUtil.createEphemeralNodeAndWatch(zkw, hbckEphemeralNodePath, null); 739 if (hbckZodeCreated) { 740 break; 741 } 742 } catch (KeeperException e) { 743 if (retryCounter.getAttemptTimes() >= retryCounter.getMaxAttempts()) { 744 throw new IOException("Can't create znode " + hbckEphemeralNodePath, e); 745 } 746 // fall through and retry 747 } 748 749 LOG.warn("Fail to create znode " + hbckEphemeralNodePath + ", try=" 750 + (retryCounter.getAttemptTimes() + 1) + " of " + retryCounter.getMaxAttempts()); 751 752 try { 753 retryCounter.sleepUntilNextRetry(); 754 } catch (InterruptedException ie) { 755 throw (InterruptedIOException) new InterruptedIOException( 756 "Can't create znode " + hbckEphemeralNodePath).initCause(ie); 757 } 758 } while (retryCounter.shouldRetry()); 759 return hbckZodeCreated; 760 } 761 762 private void cleanupHbckZnode() { 763 try { 764 if (zkw != null && hbckZodeCreated) { 765 ZKUtil.deleteNode(zkw, hbckEphemeralNodePath); 766 hbckZodeCreated = false; 767 } 768 } catch (KeeperException e) { 769 // Ignore 770 if (!e.code().equals(KeeperException.Code.NONODE)) { 771 LOG.warn("Delete HBCK znode " + hbckEphemeralNodePath + " failed ", e); 772 } 773 } 774 } 775 776 /** 777 * Contacts the master and prints out cluster-wide information 778 * @return 0 on success, non-zero on failure 779 */ 780 public int onlineHbck() 781 throws IOException, KeeperException, InterruptedException, ReplicationException { 782 // print hbase server version 783 errors.print("Version: " + status.getHBaseVersion()); 784 785 // Clean start 786 clearState(); 787 // Do offline check and repair first 788 offlineHdfsIntegrityRepair(); 789 offlineReferenceFileRepair(); 790 offlineHLinkFileRepair(); 791 // If Master runs maintenance tasks (such as balancer, catalog janitor, etc) during online 792 // hbck, it is likely that hbck would be misled and report transient errors. Therefore, it 793 // is better to set Master into maintenance mode during online hbck. 794 // 795 if (!setMasterInMaintenanceMode()) { 796 LOG.warn("HBCK is running while master is not in maintenance mode, you might see transient " 797 + "error. Please run HBCK multiple times to reduce the chance of transient error."); 798 } 799 800 onlineConsistencyRepair(); 801 802 if (checkRegionBoundaries) { 803 checkRegionBoundaries(); 804 } 805 806 checkAndFixReplication(); 807 808 cleanReplicationBarrier(); 809 810 // Remove the hbck znode 811 cleanupHbckZnode(); 812 813 // Remove the hbck lock 814 unlockHbck(); 815 816 // Print table summary 817 printTableSummary(tablesInfo); 818 return errors.summarize(); 819 } 820 821 public static byte[] keyOnly(byte[] b) { 822 if (b == null) return b; 823 int rowlength = Bytes.toShort(b, 0); 824 byte[] result = new byte[rowlength]; 825 System.arraycopy(b, Bytes.SIZEOF_SHORT, result, 0, rowlength); 826 return result; 827 } 828 829 @Override 830 public void close() throws IOException { 831 try { 832 cleanupHbckZnode(); 833 unlockHbck(); 834 } catch (Exception io) { 835 LOG.warn(io.toString(), io); 836 } finally { 837 if (zkw != null) { 838 zkw.close(); 839 zkw = null; 840 } 841 IOUtils.closeQuietly(admin, e -> LOG.warn("", e)); 842 IOUtils.closeQuietly(meta, e -> LOG.warn("", e)); 843 IOUtils.closeQuietly(connection, e -> LOG.warn("", e)); 844 } 845 } 846 847 private static class RegionBoundariesInformation { 848 public byte[] regionName; 849 public byte[] metaFirstKey; 850 public byte[] metaLastKey; 851 public byte[] storesFirstKey; 852 public byte[] storesLastKey; 853 854 @Override 855 public String toString() { 856 return "regionName=" + Bytes.toStringBinary(regionName) + "\nmetaFirstKey=" 857 + Bytes.toStringBinary(metaFirstKey) + "\nmetaLastKey=" + Bytes.toStringBinary(metaLastKey) 858 + "\nstoresFirstKey=" + Bytes.toStringBinary(storesFirstKey) + "\nstoresLastKey=" 859 + Bytes.toStringBinary(storesLastKey); 860 } 861 } 862 863 public void checkRegionBoundaries() { 864 try { 865 ByteArrayComparator comparator = new ByteArrayComparator(); 866 List<RegionInfo> regions = MetaTableAccessor.getAllRegions(connection, true); 867 final RegionBoundariesInformation currentRegionBoundariesInformation = 868 new RegionBoundariesInformation(); 869 Path hbaseRoot = CommonFSUtils.getRootDir(getConf()); 870 for (RegionInfo regionInfo : regions) { 871 Path tableDir = CommonFSUtils.getTableDir(hbaseRoot, regionInfo.getTable()); 872 currentRegionBoundariesInformation.regionName = regionInfo.getRegionName(); 873 // For each region, get the start and stop key from the META and compare them to the 874 // same information from the Stores. 875 Path path = new Path(tableDir, regionInfo.getEncodedName()); 876 FileSystem fs = path.getFileSystem(getConf()); 877 FileStatus[] files = fs.listStatus(path); 878 // For all the column families in this region... 879 byte[] storeFirstKey = null; 880 byte[] storeLastKey = null; 881 for (FileStatus file : files) { 882 String fileName = file.getPath().toString(); 883 fileName = fileName.substring(fileName.lastIndexOf("/") + 1); 884 if (!fileName.startsWith(".") && !fileName.endsWith("recovered.edits")) { 885 FileStatus[] storeFiles = fs.listStatus(file.getPath()); 886 // For all the stores in this column family. 887 for (FileStatus storeFile : storeFiles) { 888 HFile.Reader reader = 889 HFile.createReader(fs, storeFile.getPath(), CacheConfig.DISABLED, true, getConf()); 890 if ( 891 (reader.getFirstKey() != null) 892 && ((storeFirstKey == null) || (comparator.compare(storeFirstKey, 893 ((KeyValue.KeyOnlyKeyValue) reader.getFirstKey().get()).getKey()) > 0)) 894 ) { 895 storeFirstKey = ((KeyValue.KeyOnlyKeyValue) reader.getFirstKey().get()).getKey(); 896 } 897 if ( 898 (reader.getLastKey() != null) 899 && ((storeLastKey == null) || (comparator.compare(storeLastKey, 900 ((KeyValue.KeyOnlyKeyValue) reader.getLastKey().get()).getKey())) < 0) 901 ) { 902 storeLastKey = ((KeyValue.KeyOnlyKeyValue) reader.getLastKey().get()).getKey(); 903 } 904 reader.close(); 905 } 906 } 907 } 908 currentRegionBoundariesInformation.metaFirstKey = regionInfo.getStartKey(); 909 currentRegionBoundariesInformation.metaLastKey = regionInfo.getEndKey(); 910 currentRegionBoundariesInformation.storesFirstKey = keyOnly(storeFirstKey); 911 currentRegionBoundariesInformation.storesLastKey = keyOnly(storeLastKey); 912 if (currentRegionBoundariesInformation.metaFirstKey.length == 0) 913 currentRegionBoundariesInformation.metaFirstKey = null; 914 if (currentRegionBoundariesInformation.metaLastKey.length == 0) 915 currentRegionBoundariesInformation.metaLastKey = null; 916 917 // For a region to be correct, we need the META start key to be smaller or equal to the 918 // smallest start key from all the stores, and the start key from the next META entry to 919 // be bigger than the last key from all the current stores. First region start key is null; 920 // Last region end key is null; some regions can be empty and not have any store. 921 922 boolean valid = true; 923 // Checking start key. 924 if ( 925 (currentRegionBoundariesInformation.storesFirstKey != null) 926 && (currentRegionBoundariesInformation.metaFirstKey != null) 927 ) { 928 valid = valid && comparator.compare(currentRegionBoundariesInformation.storesFirstKey, 929 currentRegionBoundariesInformation.metaFirstKey) >= 0; 930 } 931 // Checking stop key. 932 if ( 933 (currentRegionBoundariesInformation.storesLastKey != null) 934 && (currentRegionBoundariesInformation.metaLastKey != null) 935 ) { 936 valid = valid && comparator.compare(currentRegionBoundariesInformation.storesLastKey, 937 currentRegionBoundariesInformation.metaLastKey) < 0; 938 } 939 if (!valid) { 940 errors.reportError(ERROR_CODE.BOUNDARIES_ERROR, "Found issues with regions boundaries", 941 tablesInfo.get(regionInfo.getTable())); 942 LOG.warn("Region's boundaries not aligned between stores and META for:"); 943 LOG.warn(Objects.toString(currentRegionBoundariesInformation)); 944 } 945 } 946 } catch (IOException e) { 947 LOG.error(e.toString(), e); 948 } 949 } 950 951 /** 952 * Iterates through the list of all orphan/invalid regiondirs. 953 */ 954 private void adoptHdfsOrphans(Collection<HbckRegionInfo> orphanHdfsDirs) throws IOException { 955 for (HbckRegionInfo hi : orphanHdfsDirs) { 956 LOG.info("Attempting to handle orphan hdfs dir: " + hi.getHdfsRegionDir()); 957 adoptHdfsOrphan(hi); 958 } 959 } 960 961 /** 962 * Orphaned regions are regions without a .regioninfo file in them. We "adopt" these orphans by 963 * creating a new region, and moving the column families, recovered edits, WALs, into the new 964 * region dir. We determine the region startkey and endkeys by looking at all of the hfiles inside 965 * the column families to identify the min and max keys. The resulting region will likely violate 966 * table integrity but will be dealt with by merging overlapping regions. 967 */ 968 @SuppressWarnings("deprecation") 969 private void adoptHdfsOrphan(HbckRegionInfo hi) throws IOException { 970 Path p = hi.getHdfsRegionDir(); 971 FileSystem fs = p.getFileSystem(getConf()); 972 FileStatus[] dirs = fs.listStatus(p); 973 if (dirs == null) { 974 LOG.warn("Attempt to adopt orphan hdfs region skipped because no files present in " + p 975 + ". This dir could probably be deleted."); 976 return; 977 } 978 979 TableName tableName = hi.getTableName(); 980 HbckTableInfo tableInfo = tablesInfo.get(tableName); 981 Preconditions.checkNotNull(tableInfo, "Table '" + tableName + "' not present!"); 982 TableDescriptor template = tableInfo.getTableDescriptor(); 983 984 // find min and max key values 985 Pair<byte[], byte[]> orphanRegionRange = null; 986 for (FileStatus cf : dirs) { 987 String cfName = cf.getPath().getName(); 988 // TODO Figure out what the special dirs are 989 if (cfName.startsWith(".") || cfName.equals(HConstants.SPLIT_LOGDIR_NAME)) continue; 990 991 FileStatus[] hfiles = fs.listStatus(cf.getPath()); 992 for (FileStatus hfile : hfiles) { 993 byte[] start, end; 994 HFile.Reader hf = null; 995 try { 996 hf = HFile.createReader(fs, hfile.getPath(), CacheConfig.DISABLED, true, getConf()); 997 Optional<ExtendedCell> startKv = hf.getFirstKey(); 998 start = CellUtil.cloneRow(startKv.get()); 999 Optional<ExtendedCell> endKv = hf.getLastKey(); 1000 end = CellUtil.cloneRow(endKv.get()); 1001 } catch (Exception ioe) { 1002 LOG.warn("Problem reading orphan file " + hfile + ", skipping"); 1003 continue; 1004 } finally { 1005 if (hf != null) { 1006 hf.close(); 1007 } 1008 } 1009 1010 // expand the range to include the range of all hfiles 1011 if (orphanRegionRange == null) { 1012 // first range 1013 orphanRegionRange = new Pair<>(start, end); 1014 } else { 1015 // TODO add test 1016 1017 // expand range only if the hfile is wider. 1018 if (Bytes.compareTo(orphanRegionRange.getFirst(), start) > 0) { 1019 orphanRegionRange.setFirst(start); 1020 } 1021 if (Bytes.compareTo(orphanRegionRange.getSecond(), end) < 0) { 1022 orphanRegionRange.setSecond(end); 1023 } 1024 } 1025 } 1026 } 1027 if (orphanRegionRange == null) { 1028 LOG.warn("No data in dir " + p + ", sidelining data"); 1029 fixes++; 1030 sidelineRegionDir(fs, hi); 1031 return; 1032 } 1033 LOG.info("Min max keys are : [" + Bytes.toString(orphanRegionRange.getFirst()) + ", " 1034 + Bytes.toString(orphanRegionRange.getSecond()) + ")"); 1035 1036 // create new region on hdfs. move data into place. 1037 RegionInfo regionInfo = RegionInfoBuilder.newBuilder(template.getTableName()) 1038 .setStartKey(orphanRegionRange.getFirst()) 1039 .setEndKey(Bytes.add(orphanRegionRange.getSecond(), new byte[1])).build(); 1040 LOG.info("Creating new region : " + regionInfo); 1041 HRegion region = HBaseFsckRepair.createHDFSRegionDir(getConf(), regionInfo, template); 1042 Path target = region.getRegionFileSystem().getRegionDir(); 1043 1044 // rename all the data to new region 1045 mergeRegionDirs(target, hi); 1046 fixes++; 1047 } 1048 1049 /** 1050 * This method determines if there are table integrity errors in HDFS. If there are errors and the 1051 * appropriate "fix" options are enabled, the method will first correct orphan regions making them 1052 * into legit regiondirs, and then reload to merge potentially overlapping regions. 1053 * @return number of table integrity errors found 1054 */ 1055 private int restoreHdfsIntegrity() throws IOException, InterruptedException { 1056 // Determine what's on HDFS 1057 LOG.info("Loading HBase regioninfo from HDFS..."); 1058 loadHdfsRegionDirs(); // populating regioninfo table. 1059 1060 int errs = errors.getErrorList().size(); 1061 // First time just get suggestions. 1062 tablesInfo = loadHdfsRegionInfos(); // update tableInfos based on region info in fs. 1063 checkHdfsIntegrity(false, false); 1064 1065 if (errors.getErrorList().size() == errs) { 1066 LOG.info("No integrity errors. We are done with this phase. Glorious."); 1067 return 0; 1068 } 1069 1070 if (shouldFixHdfsOrphans() && orphanHdfsDirs.size() > 0) { 1071 adoptHdfsOrphans(orphanHdfsDirs); 1072 // TODO optimize by incrementally adding instead of reloading. 1073 } 1074 1075 // Make sure there are no holes now. 1076 if (shouldFixHdfsHoles()) { 1077 clearState(); // this also resets # fixes. 1078 loadHdfsRegionDirs(); 1079 tablesInfo = loadHdfsRegionInfos(); // update tableInfos based on region info in fs. 1080 tablesInfo = checkHdfsIntegrity(shouldFixHdfsHoles(), false); 1081 } 1082 1083 // Now we fix overlaps 1084 if (shouldFixHdfsOverlaps()) { 1085 // second pass we fix overlaps. 1086 clearState(); // this also resets # fixes. 1087 loadHdfsRegionDirs(); 1088 tablesInfo = loadHdfsRegionInfos(); // update tableInfos based on region info in fs. 1089 tablesInfo = checkHdfsIntegrity(false, shouldFixHdfsOverlaps()); 1090 } 1091 1092 return errors.getErrorList().size(); 1093 } 1094 1095 /** 1096 * Scan all the store file names to find any lingering reference files, which refer to some 1097 * none-exiting files. If "fix" option is enabled, any lingering reference file will be sidelined 1098 * if found. 1099 * <p> 1100 * Lingering reference file prevents a region from opening. It has to be fixed before a cluster 1101 * can start properly. 1102 */ 1103 private void offlineReferenceFileRepair() throws IOException, InterruptedException { 1104 clearState(); 1105 Configuration conf = getConf(); 1106 Path hbaseRoot = CommonFSUtils.getRootDir(conf); 1107 FileSystem fs = hbaseRoot.getFileSystem(conf); 1108 LOG.info("Computing mapping of all store files"); 1109 Map<String, Path> allFiles = FSUtils.getTableStoreFilePathMap(fs, hbaseRoot, 1110 new FSUtils.ReferenceFileFilter(fs), executor, errors); 1111 errors.print(""); 1112 LOG.info("Validating mapping using HDFS state"); 1113 for (Path path : allFiles.values()) { 1114 Path referredToFile = StoreFileInfo.getReferredToFile(path); 1115 if (fs.exists(referredToFile)) continue; // good, expected 1116 1117 // Found a lingering reference file 1118 errors.reportError(ERROR_CODE.LINGERING_REFERENCE_HFILE, 1119 "Found lingering reference file " + path); 1120 if (!shouldFixReferenceFiles()) continue; 1121 1122 // Now, trying to fix it since requested 1123 boolean success = false; 1124 String pathStr = path.toString(); 1125 1126 // A reference file path should be like 1127 // ${hbase.rootdir}/data/namespace/table_name/region_id/family_name/referred_file.region_name 1128 // Up 5 directories to get the root folder. 1129 // So the file will be sidelined to a similar folder structure. 1130 int index = pathStr.lastIndexOf(Path.SEPARATOR_CHAR); 1131 for (int i = 0; index > 0 && i < 5; i++) { 1132 index = pathStr.lastIndexOf(Path.SEPARATOR_CHAR, index - 1); 1133 } 1134 if (index > 0) { 1135 Path rootDir = getSidelineDir(); 1136 Path dst = new Path(rootDir, pathStr.substring(index + 1)); 1137 fs.mkdirs(dst.getParent()); 1138 LOG.info("Trying to sideline reference file " + path + " to " + dst); 1139 setShouldRerun(); 1140 1141 success = fs.rename(path, dst); 1142 debugLsr(dst); 1143 1144 } 1145 if (!success) { 1146 LOG.error("Failed to sideline reference file " + path); 1147 } 1148 } 1149 } 1150 1151 /** 1152 * Scan all the store file names to find any lingering HFileLink files, which refer to some 1153 * none-exiting files. If "fix" option is enabled, any lingering HFileLink file will be sidelined 1154 * if found. 1155 */ 1156 private void offlineHLinkFileRepair() throws IOException, InterruptedException { 1157 Configuration conf = getConf(); 1158 Path hbaseRoot = CommonFSUtils.getRootDir(conf); 1159 FileSystem fs = hbaseRoot.getFileSystem(conf); 1160 LOG.info("Computing mapping of all link files"); 1161 Map<String, Path> allFiles = FSUtils.getTableStoreFilePathMap(fs, hbaseRoot, 1162 new FSUtils.HFileLinkFilter(), executor, errors); 1163 errors.print(""); 1164 1165 LOG.info("Validating mapping using HDFS state"); 1166 for (Path path : allFiles.values()) { 1167 // building HFileLink object to gather locations 1168 HFileLink actualLink = HFileLink.buildFromHFileLinkPattern(conf, path); 1169 if (actualLink.exists(fs)) continue; // good, expected 1170 1171 // Found a lingering HFileLink 1172 errors.reportError(ERROR_CODE.LINGERING_HFILELINK, "Found lingering HFileLink " + path); 1173 if (!shouldFixHFileLinks()) continue; 1174 1175 // Now, trying to fix it since requested 1176 setShouldRerun(); 1177 1178 // An HFileLink path should be like 1179 // ${hbase.rootdir}/data/namespace/table_name/region_id/family_name/linkedtable=linkedregionname-linkedhfilename 1180 // sidelineing will happen in the ${hbase.rootdir}/${sidelinedir} directory with the same 1181 // folder structure. 1182 boolean success = sidelineFile(fs, hbaseRoot, path); 1183 1184 if (!success) { 1185 LOG.error("Failed to sideline HFileLink file " + path); 1186 } 1187 1188 // An HFileLink backreference path should be like 1189 // ${hbase.rootdir}/archive/data/namespace/table_name/region_id/family_name/.links-linkedhfilename 1190 // sidelineing will happen in the ${hbase.rootdir}/${sidelinedir} directory with the same 1191 // folder structure. 1192 Path backRefPath = FileLink.getBackReferencesDir( 1193 HFileArchiveUtil.getStoreArchivePath(conf, 1194 HFileLink.getReferencedTableName(path.getName().toString()), 1195 HFileLink.getReferencedRegionName(path.getName().toString()), path.getParent().getName()), 1196 HFileLink.getReferencedHFileName(path.getName().toString())); 1197 success = sidelineFile(fs, hbaseRoot, backRefPath); 1198 1199 if (!success) { 1200 LOG.error("Failed to sideline HFileLink backreference file " + path); 1201 } 1202 } 1203 } 1204 1205 private boolean sidelineFile(FileSystem fs, Path hbaseRoot, Path path) throws IOException { 1206 URI uri = hbaseRoot.toUri().relativize(path.toUri()); 1207 if (uri.isAbsolute()) return false; 1208 String relativePath = uri.getPath(); 1209 Path rootDir = getSidelineDir(); 1210 Path dst = new Path(rootDir, relativePath); 1211 boolean pathCreated = fs.mkdirs(dst.getParent()); 1212 if (!pathCreated) { 1213 LOG.error("Failed to create path: " + dst.getParent()); 1214 return false; 1215 } 1216 LOG.info("Trying to sideline file " + path + " to " + dst); 1217 return fs.rename(path, dst); 1218 } 1219 1220 /** 1221 * TODO -- need to add tests for this. 1222 */ 1223 private void reportEmptyMetaCells() { 1224 errors.print("Number of empty REGIONINFO_QUALIFIER rows in " + TableName.META_TABLE_NAME + ": " 1225 + emptyRegionInfoQualifiers.size()); 1226 if (details) { 1227 for (Result r : emptyRegionInfoQualifiers) { 1228 errors.print(" " + r); 1229 } 1230 } 1231 } 1232 1233 /** 1234 * TODO -- need to add tests for this. 1235 */ 1236 private void reportTablesInFlux() { 1237 AtomicInteger numSkipped = new AtomicInteger(0); 1238 TableDescriptor[] allTables = getTables(numSkipped); 1239 errors.print("Number of Tables: " + allTables.length); 1240 if (details) { 1241 if (numSkipped.get() > 0) { 1242 errors.detail("Number of Tables in flux: " + numSkipped.get()); 1243 } 1244 for (TableDescriptor td : allTables) { 1245 errors.detail(" Table: " + td.getTableName() + "\t" + (td.isReadOnly() ? "ro" : "rw") 1246 + "\t" + (td.isMetaRegion() ? "META" : " ") + "\t" + " families: " 1247 + td.getColumnFamilyCount()); 1248 } 1249 } 1250 } 1251 1252 public HbckErrorReporter getErrors() { 1253 return errors; 1254 } 1255 1256 /** 1257 * Populate hbi's from regionInfos loaded from file system. 1258 */ 1259 private SortedMap<TableName, HbckTableInfo> loadHdfsRegionInfos() 1260 throws IOException, InterruptedException { 1261 tablesInfo.clear(); // regenerating the data 1262 // generate region split structure 1263 Collection<HbckRegionInfo> hbckRegionInfos = regionInfoMap.values(); 1264 1265 // Parallelized read of .regioninfo files. 1266 List<WorkItemHdfsRegionInfo> hbis = new ArrayList<>(hbckRegionInfos.size()); 1267 List<Future<Void>> hbiFutures; 1268 1269 for (HbckRegionInfo hbi : hbckRegionInfos) { 1270 WorkItemHdfsRegionInfo work = new WorkItemHdfsRegionInfo(hbi, this, errors); 1271 hbis.add(work); 1272 } 1273 1274 // Submit and wait for completion 1275 hbiFutures = executor.invokeAll(hbis); 1276 1277 for (int i = 0; i < hbiFutures.size(); i++) { 1278 WorkItemHdfsRegionInfo work = hbis.get(i); 1279 Future<Void> f = hbiFutures.get(i); 1280 try { 1281 f.get(); 1282 } catch (ExecutionException e) { 1283 LOG.warn("Failed to read .regioninfo file for region " + work.hbi.getRegionNameAsString(), 1284 e.getCause()); 1285 } 1286 } 1287 1288 Path hbaseRoot = CommonFSUtils.getRootDir(getConf()); 1289 FileSystem fs = hbaseRoot.getFileSystem(getConf()); 1290 // serialized table info gathering. 1291 for (HbckRegionInfo hbi : hbckRegionInfos) { 1292 1293 if (hbi.getHdfsHRI() == null) { 1294 // was an orphan 1295 continue; 1296 } 1297 1298 // get table name from hdfs, populate various HBaseFsck tables. 1299 TableName tableName = hbi.getTableName(); 1300 if (tableName == null) { 1301 // There was an entry in hbase:meta not in the HDFS? 1302 LOG.warn("tableName was null for: " + hbi); 1303 continue; 1304 } 1305 1306 HbckTableInfo modTInfo = tablesInfo.get(tableName); 1307 if (modTInfo == null) { 1308 // only executed once per table. 1309 modTInfo = new HbckTableInfo(tableName, this); 1310 tablesInfo.put(tableName, modTInfo); 1311 try { 1312 TableDescriptor htd = 1313 FSTableDescriptors.getTableDescriptorFromFs(fs, hbaseRoot, tableName); 1314 modTInfo.htds.add(htd); 1315 } catch (IOException ioe) { 1316 if (!orphanTableDirs.containsKey(tableName)) { 1317 LOG.warn("Unable to read .tableinfo from " + hbaseRoot, ioe); 1318 // should only report once for each table 1319 errors.reportError(ERROR_CODE.NO_TABLEINFO_FILE, 1320 "Unable to read .tableinfo from " + hbaseRoot + "/" + tableName); 1321 Set<String> columns = new HashSet<>(); 1322 orphanTableDirs.put(tableName, getColumnFamilyList(columns, hbi)); 1323 } 1324 } 1325 } 1326 if (!hbi.isSkipChecks()) { 1327 modTInfo.addRegionInfo(hbi); 1328 } 1329 } 1330 1331 loadTableInfosForTablesWithNoRegion(); 1332 errors.print(""); 1333 1334 return tablesInfo; 1335 } 1336 1337 /** 1338 * To get the column family list according to the column family dirs 1339 * @return a set of column families 1340 */ 1341 private Set<String> getColumnFamilyList(Set<String> columns, HbckRegionInfo hbi) 1342 throws IOException { 1343 Path regionDir = hbi.getHdfsRegionDir(); 1344 FileSystem fs = regionDir.getFileSystem(getConf()); 1345 FileStatus[] subDirs = fs.listStatus(regionDir, new FSUtils.FamilyDirFilter(fs)); 1346 for (FileStatus subdir : subDirs) { 1347 String columnfamily = subdir.getPath().getName(); 1348 columns.add(columnfamily); 1349 } 1350 return columns; 1351 } 1352 1353 /** 1354 * To fabricate a .tableinfo file with following contents<br> 1355 * 1. the correct tablename <br> 1356 * 2. the correct colfamily list<br> 1357 * 3. the default properties for both {@link TableDescriptor} and 1358 * {@link ColumnFamilyDescriptor}<br> 1359 */ 1360 private boolean fabricateTableInfo(FSTableDescriptors fstd, TableName tableName, 1361 Set<String> columns) throws IOException { 1362 if (columns == null || columns.isEmpty()) return false; 1363 TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(tableName); 1364 for (String columnfamimly : columns) { 1365 builder.setColumnFamily(ColumnFamilyDescriptorBuilder.of(columnfamimly)); 1366 } 1367 fstd.createTableDescriptor(builder.build(), true); 1368 return true; 1369 } 1370 1371 /** 1372 * To fix the empty REGIONINFO_QUALIFIER rows from hbase:meta <br> 1373 */ 1374 public void fixEmptyMetaCells() throws IOException { 1375 if (shouldFixEmptyMetaCells() && !emptyRegionInfoQualifiers.isEmpty()) { 1376 LOG.info("Trying to fix empty REGIONINFO_QUALIFIER {} rows.", TableName.META_TABLE_NAME); 1377 for (Result region : emptyRegionInfoQualifiers) { 1378 deleteMetaRegion(region.getRow()); 1379 errors.getErrorList().remove(ERROR_CODE.EMPTY_META_CELL); 1380 } 1381 emptyRegionInfoQualifiers.clear(); 1382 } 1383 } 1384 1385 /** 1386 * To fix orphan table by creating a .tableinfo file under tableDir <br> 1387 * 1. if TableInfo is cached, to recover the .tableinfo accordingly <br> 1388 * 2. else create a default .tableinfo file with following items<br> 1389 * 2.1 the correct tablename <br> 1390 * 2.2 the correct colfamily list<br> 1391 * 2.3 the default properties for both {@link TableDescriptor} and 1392 * {@link ColumnFamilyDescriptor}<br> 1393 */ 1394 public void fixOrphanTables() throws IOException { 1395 if (shouldFixTableOrphans() && !orphanTableDirs.isEmpty()) { 1396 1397 List<TableName> tmpList = new ArrayList<>(orphanTableDirs.keySet().size()); 1398 tmpList.addAll(orphanTableDirs.keySet()); 1399 TableDescriptor[] htds = getTableDescriptors(tmpList); 1400 Iterator<Entry<TableName, Set<String>>> iter = orphanTableDirs.entrySet().iterator(); 1401 int j = 0; 1402 int numFailedCase = 0; 1403 FSTableDescriptors fstd = new FSTableDescriptors(getConf()); 1404 while (iter.hasNext()) { 1405 Entry<TableName, Set<String>> entry = iter.next(); 1406 TableName tableName = entry.getKey(); 1407 LOG.info("Trying to fix orphan table error: " + tableName); 1408 if (j < htds.length) { 1409 if (tableName.equals(htds[j].getTableName())) { 1410 TableDescriptor htd = htds[j]; 1411 LOG.info("fixing orphan table: " + tableName + " from cache"); 1412 fstd.createTableDescriptor(htd, true); 1413 j++; 1414 iter.remove(); 1415 } 1416 } else { 1417 if (fabricateTableInfo(fstd, tableName, entry.getValue())) { 1418 LOG.warn("fixing orphan table: " + tableName + " with a default .tableinfo file"); 1419 LOG.warn( 1420 "Strongly recommend to modify the TableDescriptor if necessary for: " + tableName); 1421 iter.remove(); 1422 } else { 1423 LOG.error("Unable to create default .tableinfo for " + tableName 1424 + " while missing column family information"); 1425 numFailedCase++; 1426 } 1427 } 1428 fixes++; 1429 } 1430 1431 if (orphanTableDirs.isEmpty()) { 1432 // all orphanTableDirs are luckily recovered 1433 // re-run doFsck after recovering the .tableinfo file 1434 setShouldRerun(); 1435 LOG.warn( 1436 "Strongly recommend to re-run manually hfsck after all orphanTableDirs being fixed"); 1437 } else if (numFailedCase > 0) { 1438 LOG.error("Failed to fix " + numFailedCase + " OrphanTables with default .tableinfo files"); 1439 } 1440 1441 } 1442 // cleanup the list 1443 orphanTableDirs.clear(); 1444 1445 } 1446 1447 /** 1448 * Log an appropriate message about whether or not overlapping merges are computed in parallel. 1449 */ 1450 private void logParallelMerge() { 1451 if (getConf().getBoolean("hbasefsck.overlap.merge.parallel", true)) { 1452 LOG.info("Handling overlap merges in parallel. set hbasefsck.overlap.merge.parallel to" 1453 + " false to run serially."); 1454 } else { 1455 LOG.info("Handling overlap merges serially. set hbasefsck.overlap.merge.parallel to" 1456 + " true to run in parallel."); 1457 } 1458 } 1459 1460 private SortedMap<TableName, HbckTableInfo> checkHdfsIntegrity(boolean fixHoles, 1461 boolean fixOverlaps) throws IOException { 1462 LOG.info("Checking HBase region split map from HDFS data..."); 1463 logParallelMerge(); 1464 for (HbckTableInfo tInfo : tablesInfo.values()) { 1465 TableIntegrityErrorHandler handler; 1466 if (fixHoles || fixOverlaps) { 1467 handler = tInfo.new HDFSIntegrityFixer(tInfo, errors, getConf(), fixHoles, fixOverlaps); 1468 } else { 1469 handler = tInfo.new IntegrityFixSuggester(tInfo, errors); 1470 } 1471 if (!tInfo.checkRegionChain(handler)) { 1472 // should dump info as well. 1473 errors.report("Found inconsistency in table " + tInfo.getName()); 1474 } 1475 } 1476 return tablesInfo; 1477 } 1478 1479 Path getSidelineDir() throws IOException { 1480 if (sidelineDir == null) { 1481 Path hbaseDir = CommonFSUtils.getRootDir(getConf()); 1482 Path hbckDir = new Path(hbaseDir, HConstants.HBCK_SIDELINEDIR_NAME); 1483 sidelineDir = new Path(hbckDir, hbaseDir.getName() + "-" + startMillis); 1484 } 1485 return sidelineDir; 1486 } 1487 1488 /** 1489 * Sideline a region dir (instead of deleting it) 1490 */ 1491 Path sidelineRegionDir(FileSystem fs, HbckRegionInfo hi) throws IOException { 1492 return sidelineRegionDir(fs, null, hi); 1493 } 1494 1495 /** 1496 * Sideline a region dir (instead of deleting it) 1497 * @param parentDir if specified, the region will be sidelined to folder like 1498 * {@literal .../parentDir/<table name>/<region name>}. The purpose is to group 1499 * together similar regions sidelined, for example, those regions should be bulk 1500 * loaded back later on. If NULL, it is ignored. 1501 */ 1502 Path sidelineRegionDir(FileSystem fs, String parentDir, HbckRegionInfo hi) throws IOException { 1503 TableName tableName = hi.getTableName(); 1504 Path regionDir = hi.getHdfsRegionDir(); 1505 1506 if (!fs.exists(regionDir)) { 1507 LOG.warn("No previous " + regionDir + " exists. Continuing."); 1508 return null; 1509 } 1510 1511 Path rootDir = getSidelineDir(); 1512 if (parentDir != null) { 1513 rootDir = new Path(rootDir, parentDir); 1514 } 1515 Path sidelineTableDir = CommonFSUtils.getTableDir(rootDir, tableName); 1516 Path sidelineRegionDir = new Path(sidelineTableDir, regionDir.getName()); 1517 fs.mkdirs(sidelineRegionDir); 1518 boolean success = false; 1519 FileStatus[] cfs = fs.listStatus(regionDir); 1520 if (cfs == null) { 1521 LOG.info("Region dir is empty: " + regionDir); 1522 } else { 1523 for (FileStatus cf : cfs) { 1524 Path src = cf.getPath(); 1525 Path dst = new Path(sidelineRegionDir, src.getName()); 1526 if (fs.isFile(src)) { 1527 // simple file 1528 success = fs.rename(src, dst); 1529 if (!success) { 1530 String msg = "Unable to rename file " + src + " to " + dst; 1531 LOG.error(msg); 1532 throw new IOException(msg); 1533 } 1534 continue; 1535 } 1536 1537 // is a directory. 1538 fs.mkdirs(dst); 1539 1540 LOG.info("Sidelining files from " + src + " into containing region " + dst); 1541 // FileSystem.rename is inconsistent with directories -- if the 1542 // dst (foo/a) exists and is a dir, and the src (foo/b) is a dir, 1543 // it moves the src into the dst dir resulting in (foo/a/b). If 1544 // the dst does not exist, and the src a dir, src becomes dst. (foo/b) 1545 FileStatus[] hfiles = fs.listStatus(src); 1546 if (hfiles != null && hfiles.length > 0) { 1547 for (FileStatus hfile : hfiles) { 1548 success = fs.rename(hfile.getPath(), dst); 1549 if (!success) { 1550 String msg = "Unable to rename file " + src + " to " + dst; 1551 LOG.error(msg); 1552 throw new IOException(msg); 1553 } 1554 } 1555 } 1556 LOG.debug("Sideline directory contents:"); 1557 debugLsr(sidelineRegionDir); 1558 } 1559 } 1560 1561 LOG.info("Removing old region dir: " + regionDir); 1562 success = fs.delete(regionDir, true); 1563 if (!success) { 1564 String msg = "Unable to delete dir " + regionDir; 1565 LOG.error(msg); 1566 throw new IOException(msg); 1567 } 1568 return sidelineRegionDir; 1569 } 1570 1571 /** 1572 * Load the list of disabled tables in ZK into local set. 1573 */ 1574 private void loadTableStates() throws IOException { 1575 tableStates = MetaTableAccessor.getTableStates(connection); 1576 // Add hbase:meta so this tool keeps working. In hbase2, meta is always enabled though it 1577 // has no entry in the table states. HBCK doesn't work right w/ hbase2 but just do this in 1578 // meantime. 1579 this.tableStates.put(TableName.META_TABLE_NAME, 1580 new TableState(TableName.META_TABLE_NAME, TableState.State.ENABLED)); 1581 } 1582 1583 /** 1584 * Check if the specified region's table is disabled. 1585 * @param tableName table to check status of 1586 */ 1587 boolean isTableDisabled(TableName tableName) { 1588 return tableStates.containsKey(tableName) 1589 && tableStates.get(tableName).inStates(TableState.State.DISABLED, TableState.State.DISABLING); 1590 } 1591 1592 /** 1593 * Scan HDFS for all regions, recording their information into regionInfoMap 1594 */ 1595 public void loadHdfsRegionDirs() throws IOException, InterruptedException { 1596 Path rootDir = CommonFSUtils.getRootDir(getConf()); 1597 FileSystem fs = rootDir.getFileSystem(getConf()); 1598 1599 // list all tables from HDFS 1600 List<FileStatus> tableDirs = Lists.newArrayList(); 1601 1602 boolean foundVersionFile = fs.exists(new Path(rootDir, HConstants.VERSION_FILE_NAME)); 1603 1604 List<Path> paths = FSUtils.getTableDirs(fs, rootDir); 1605 for (Path path : paths) { 1606 TableName tableName = CommonFSUtils.getTableName(path); 1607 if ( 1608 (!checkMetaOnly && isTableIncluded(tableName)) 1609 || tableName.equals(TableName.META_TABLE_NAME) 1610 ) { 1611 tableDirs.add(fs.getFileStatus(path)); 1612 } 1613 } 1614 1615 // verify that version file exists 1616 if (!foundVersionFile) { 1617 errors.reportError(ERROR_CODE.NO_VERSION_FILE, 1618 "Version file does not exist in root dir " + rootDir); 1619 if (shouldFixVersionFile()) { 1620 LOG.info("Trying to create a new " + HConstants.VERSION_FILE_NAME + " file."); 1621 setShouldRerun(); 1622 FSUtils.setVersion(fs, rootDir, 1623 getConf().getInt(HConstants.THREAD_WAKE_FREQUENCY, 10 * 1000), 1624 getConf().getInt(HConstants.VERSION_FILE_WRITE_ATTEMPTS, 1625 HConstants.DEFAULT_VERSION_FILE_WRITE_ATTEMPTS)); 1626 } 1627 } 1628 1629 // Avoid multithreading at table-level because already multithreaded internally at 1630 // region-level. Additionally multithreading at table-level can lead to deadlock 1631 // if there are many tables in the cluster. Since there are a limited # of threads 1632 // in the executor's thread pool and if we multithread at the table-level by putting 1633 // WorkItemHdfsDir callables into the executor, then we will have some threads in the 1634 // executor tied up solely in waiting for the tables' region-level calls to complete. 1635 // If there are enough tables then there will be no actual threads in the pool left 1636 // for the region-level callables to be serviced. 1637 for (FileStatus tableDir : tableDirs) { 1638 LOG.debug("Loading region dirs from " + tableDir.getPath()); 1639 WorkItemHdfsDir item = new WorkItemHdfsDir(fs, errors, tableDir); 1640 try { 1641 item.call(); 1642 } catch (ExecutionException e) { 1643 LOG.warn("Could not completely load table dir " + tableDir.getPath(), e.getCause()); 1644 } 1645 } 1646 errors.print(""); 1647 } 1648 1649 /** 1650 * Record the location of the hbase:meta region as found in ZooKeeper. 1651 */ 1652 private boolean recordMetaRegion() throws IOException { 1653 List<HRegionLocation> locs; 1654 try (RegionLocator locator = connection.getRegionLocator(TableName.META_TABLE_NAME)) { 1655 locs = locator.getRegionLocations(HConstants.EMPTY_START_ROW, true); 1656 } 1657 if (locs == null || locs.isEmpty()) { 1658 errors.reportError(ERROR_CODE.NULL_META_REGION, "META region was not found in ZooKeeper"); 1659 return false; 1660 } 1661 for (HRegionLocation metaLocation : locs) { 1662 // Check if Meta region is valid and existing 1663 if (metaLocation == null) { 1664 errors.reportError(ERROR_CODE.NULL_META_REGION, "META region location is null"); 1665 return false; 1666 } 1667 if (metaLocation.getRegion() == null) { 1668 errors.reportError(ERROR_CODE.NULL_META_REGION, "META location regionInfo is null"); 1669 return false; 1670 } 1671 if (metaLocation.getHostname() == null) { 1672 errors.reportError(ERROR_CODE.NULL_META_REGION, "META location hostName is null"); 1673 return false; 1674 } 1675 ServerName sn = metaLocation.getServerName(); 1676 HbckRegionInfo.MetaEntry m = new HbckRegionInfo.MetaEntry(metaLocation.getRegion(), sn, 1677 EnvironmentEdgeManager.currentTime()); 1678 HbckRegionInfo hbckRegionInfo = regionInfoMap.get(metaLocation.getRegion().getEncodedName()); 1679 if (hbckRegionInfo == null) { 1680 regionInfoMap.put(metaLocation.getRegion().getEncodedName(), new HbckRegionInfo(m)); 1681 } else { 1682 hbckRegionInfo.setMetaEntry(m); 1683 } 1684 } 1685 return true; 1686 } 1687 1688 private ZKWatcher createZooKeeperWatcher() throws IOException { 1689 return new ZKWatcher(getConf(), "hbase Fsck", new Abortable() { 1690 @Override 1691 public void abort(String why, Throwable e) { 1692 LOG.error(why, e); 1693 System.exit(1); 1694 } 1695 1696 @Override 1697 public boolean isAborted() { 1698 return false; 1699 } 1700 1701 }); 1702 } 1703 1704 /** 1705 * Contacts each regionserver and fetches metadata about regions. 1706 * @param regionServerList - the list of region servers to connect to 1707 * @throws IOException if a remote or network exception occurs 1708 */ 1709 void processRegionServers(Collection<ServerName> regionServerList) 1710 throws IOException, InterruptedException { 1711 1712 List<WorkItemRegion> workItems = new ArrayList<>(regionServerList.size()); 1713 List<Future<Void>> workFutures; 1714 1715 // loop to contact each region server in parallel 1716 for (ServerName rsinfo : regionServerList) { 1717 workItems.add(new WorkItemRegion(this, rsinfo, errors, connection)); 1718 } 1719 1720 workFutures = executor.invokeAll(workItems); 1721 1722 for (int i = 0; i < workFutures.size(); i++) { 1723 WorkItemRegion item = workItems.get(i); 1724 Future<Void> f = workFutures.get(i); 1725 try { 1726 f.get(); 1727 } catch (ExecutionException e) { 1728 LOG.warn("Could not process regionserver {}", item.rsinfo.getAddress(), e.getCause()); 1729 } 1730 } 1731 } 1732 1733 /** 1734 * Check consistency of all regions that have been found in previous phases. 1735 */ 1736 private void checkAndFixConsistency() throws IOException, KeeperException, InterruptedException { 1737 // Divide the checks in two phases. One for default/primary replicas and another 1738 // for the non-primary ones. Keeps code cleaner this way. 1739 1740 List<CheckRegionConsistencyWorkItem> workItems = new ArrayList<>(regionInfoMap.size()); 1741 for (java.util.Map.Entry<String, HbckRegionInfo> e : regionInfoMap.entrySet()) { 1742 if (e.getValue().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) { 1743 workItems.add(new CheckRegionConsistencyWorkItem(e.getKey(), e.getValue())); 1744 } 1745 } 1746 checkRegionConsistencyConcurrently(workItems); 1747 1748 boolean prevHdfsCheck = shouldCheckHdfs(); 1749 setCheckHdfs(false); // replicas don't have any hdfs data 1750 // Run a pass over the replicas and fix any assignment issues that exist on the currently 1751 // deployed/undeployed replicas. 1752 List<CheckRegionConsistencyWorkItem> replicaWorkItems = new ArrayList<>(regionInfoMap.size()); 1753 for (java.util.Map.Entry<String, HbckRegionInfo> e : regionInfoMap.entrySet()) { 1754 if (e.getValue().getReplicaId() != RegionInfo.DEFAULT_REPLICA_ID) { 1755 replicaWorkItems.add(new CheckRegionConsistencyWorkItem(e.getKey(), e.getValue())); 1756 } 1757 } 1758 checkRegionConsistencyConcurrently(replicaWorkItems); 1759 setCheckHdfs(prevHdfsCheck); 1760 1761 // If some regions is skipped during checkRegionConsistencyConcurrently() phase, we might 1762 // not get accurate state of the hbase if continuing. The config here allows users to tune 1763 // the tolerance of number of skipped region. 1764 // TODO: evaluate the consequence to continue the hbck operation without config. 1765 int terminateThreshold = getConf().getInt("hbase.hbck.skipped.regions.limit", 0); 1766 int numOfSkippedRegions = skippedRegions.size(); 1767 if (numOfSkippedRegions > 0 && numOfSkippedRegions > terminateThreshold) { 1768 throw new IOException( 1769 numOfSkippedRegions + " region(s) could not be checked or repaired. See logs for detail."); 1770 } 1771 1772 if (shouldCheckHdfs()) { 1773 checkAndFixTableStates(); 1774 } 1775 } 1776 1777 /** 1778 * Check consistency of all regions using multiple threads concurrently. 1779 */ 1780 private void 1781 checkRegionConsistencyConcurrently(final List<CheckRegionConsistencyWorkItem> workItems) 1782 throws IOException, KeeperException, InterruptedException { 1783 if (workItems.isEmpty()) { 1784 return; // nothing to check 1785 } 1786 1787 List<Future<Void>> workFutures = executor.invokeAll(workItems); 1788 for (Future<Void> f : workFutures) { 1789 try { 1790 f.get(); 1791 } catch (ExecutionException e1) { 1792 LOG.warn("Could not check region consistency ", e1.getCause()); 1793 if (e1.getCause() instanceof IOException) { 1794 throw (IOException) e1.getCause(); 1795 } else if (e1.getCause() instanceof KeeperException) { 1796 throw (KeeperException) e1.getCause(); 1797 } else if (e1.getCause() instanceof InterruptedException) { 1798 throw (InterruptedException) e1.getCause(); 1799 } else { 1800 throw new IOException(e1.getCause()); 1801 } 1802 } 1803 } 1804 } 1805 1806 class CheckRegionConsistencyWorkItem implements Callable<Void> { 1807 private final String key; 1808 private final HbckRegionInfo hbi; 1809 1810 CheckRegionConsistencyWorkItem(String key, HbckRegionInfo hbi) { 1811 this.key = key; 1812 this.hbi = hbi; 1813 } 1814 1815 @Override 1816 public synchronized Void call() throws Exception { 1817 try { 1818 checkRegionConsistency(key, hbi); 1819 } catch (Exception e) { 1820 // If the region is non-META region, skip this region and send warning/error message; if 1821 // the region is META region, we should not continue. 1822 LOG.warn( 1823 "Unable to complete check or repair the region '" + hbi.getRegionNameAsString() + "'.", 1824 e); 1825 if (hbi.getHdfsHRI().isMetaRegion()) { 1826 throw e; 1827 } 1828 LOG.warn("Skip region '" + hbi.getRegionNameAsString() + "'"); 1829 addSkippedRegion(hbi); 1830 } 1831 return null; 1832 } 1833 } 1834 1835 private void addSkippedRegion(final HbckRegionInfo hbi) { 1836 Set<String> skippedRegionNames = skippedRegions.get(hbi.getTableName()); 1837 if (skippedRegionNames == null) { 1838 skippedRegionNames = new HashSet<>(); 1839 } 1840 skippedRegionNames.add(hbi.getRegionNameAsString()); 1841 skippedRegions.put(hbi.getTableName(), skippedRegionNames); 1842 } 1843 1844 /** 1845 * Check and fix table states, assumes full info available: - tableInfos - empty tables loaded 1846 */ 1847 private void checkAndFixTableStates() throws IOException { 1848 // first check dangling states 1849 for (Entry<TableName, TableState> entry : tableStates.entrySet()) { 1850 TableName tableName = entry.getKey(); 1851 TableState tableState = entry.getValue(); 1852 HbckTableInfo tableInfo = tablesInfo.get(tableName); 1853 if (isTableIncluded(tableName) && !tableName.isSystemTable() && tableInfo == null) { 1854 if (fixMeta) { 1855 MetaTableAccessor.deleteTableState(connection, tableName); 1856 TableState state = MetaTableAccessor.getTableState(connection, tableName); 1857 if (state != null) { 1858 errors.reportError(ERROR_CODE.ORPHAN_TABLE_STATE, 1859 tableName + " unable to delete dangling table state " + tableState); 1860 } 1861 } else if (!checkMetaOnly) { 1862 // dangling table state in meta if checkMetaOnly is false. If checkMetaOnly is 1863 // true, tableInfo will be null as tablesInfo are not polulated for all tables from hdfs 1864 errors.reportError(ERROR_CODE.ORPHAN_TABLE_STATE, 1865 tableName + " has dangling table state " + tableState); 1866 } 1867 } 1868 } 1869 // check that all tables have states 1870 for (TableName tableName : tablesInfo.keySet()) { 1871 if (isTableIncluded(tableName) && !tableStates.containsKey(tableName)) { 1872 if (fixMeta) { 1873 MetaTableAccessor.updateTableState(connection, tableName, TableState.State.ENABLED); 1874 TableState newState = MetaTableAccessor.getTableState(connection, tableName); 1875 if (newState == null) { 1876 errors.reportError(ERROR_CODE.NO_TABLE_STATE, 1877 "Unable to change state for table " + tableName + " in meta "); 1878 } 1879 } else { 1880 errors.reportError(ERROR_CODE.NO_TABLE_STATE, tableName + " has no state in meta "); 1881 } 1882 } 1883 } 1884 } 1885 1886 private void preCheckPermission() throws IOException { 1887 if (shouldIgnorePreCheckPermission()) { 1888 return; 1889 } 1890 1891 Path hbaseDir = CommonFSUtils.getRootDir(getConf()); 1892 FileSystem fs = hbaseDir.getFileSystem(getConf()); 1893 UserProvider userProvider = UserProvider.instantiate(getConf()); 1894 UserGroupInformation ugi = userProvider.getCurrent().getUGI(); 1895 FileStatus[] files = fs.listStatus(hbaseDir); 1896 for (FileStatus file : files) { 1897 try { 1898 fs.access(file.getPath(), FsAction.WRITE); 1899 } catch (AccessControlException ace) { 1900 LOG.warn("Got AccessDeniedException when preCheckPermission ", ace); 1901 errors.reportError(ERROR_CODE.WRONG_USAGE, 1902 "Current user " + ugi.getUserName() + " does not have write perms to " + file.getPath() 1903 + ". Please rerun hbck as hdfs user " + file.getOwner()); 1904 throw ace; 1905 } 1906 } 1907 } 1908 1909 /** 1910 * Deletes region from meta table 1911 */ 1912 private void deleteMetaRegion(HbckRegionInfo hi) throws IOException { 1913 deleteMetaRegion(hi.getMetaEntry().getRegionInfo().getRegionName()); 1914 } 1915 1916 /** 1917 * Deletes region from meta table 1918 */ 1919 private void deleteMetaRegion(byte[] metaKey) throws IOException { 1920 Delete d = new Delete(metaKey); 1921 meta.delete(d); 1922 LOG.info("Deleted " + Bytes.toString(metaKey) + " from META"); 1923 } 1924 1925 /** 1926 * Reset the split parent region info in meta table 1927 */ 1928 private void resetSplitParent(HbckRegionInfo hi) throws IOException { 1929 RowMutations mutations = new RowMutations(hi.getMetaEntry().getRegionInfo().getRegionName()); 1930 Delete d = new Delete(hi.getMetaEntry().getRegionInfo().getRegionName()); 1931 d.addColumn(HConstants.CATALOG_FAMILY, HConstants.SPLITA_QUALIFIER); 1932 d.addColumn(HConstants.CATALOG_FAMILY, HConstants.SPLITB_QUALIFIER); 1933 mutations.add(d); 1934 1935 RegionInfo hri = RegionInfoBuilder.newBuilder(hi.getMetaEntry().getRegionInfo()) 1936 .setOffline(false).setSplit(false).build(); 1937 Put p = MetaTableAccessor.makePutFromRegionInfo(hri); 1938 mutations.add(p); 1939 1940 meta.mutateRow(mutations); 1941 LOG.info("Reset split parent " + hi.getMetaEntry().getRegionInfo().getRegionNameAsString() 1942 + " in META"); 1943 } 1944 1945 /** 1946 * This backwards-compatibility wrapper for permanently offlining a region that should not be 1947 * alive. If the region server does not support the "offline" method, it will use the closest 1948 * unassign method instead. This will basically work until one attempts to disable or delete the 1949 * affected table. The problem has to do with in-memory only master state, so restarting the 1950 * HMaster or failing over to another should fix this. 1951 */ 1952 void offline(byte[] regionName) throws IOException { 1953 String regionString = Bytes.toStringBinary(regionName); 1954 if (!rsSupportsOffline) { 1955 LOG.warn("Using unassign region " + regionString 1956 + " instead of using offline method, you should" + " restart HMaster after these repairs"); 1957 admin.unassign(regionName, true); 1958 return; 1959 } 1960 1961 // first time we assume the rs's supports #offline. 1962 try { 1963 LOG.info("Offlining region " + regionString); 1964 admin.offline(regionName); 1965 } catch (IOException ioe) { 1966 String notFoundMsg = 1967 "java.lang.NoSuchMethodException: " + "org.apache.hadoop.hbase.master.HMaster.offline([B)"; 1968 if (ioe.getMessage().contains(notFoundMsg)) { 1969 LOG.warn( 1970 "Using unassign region " + regionString + " instead of using offline method, you should" 1971 + " restart HMaster after these repairs"); 1972 rsSupportsOffline = false; // in the future just use unassign 1973 admin.unassign(regionName, true); 1974 return; 1975 } 1976 throw ioe; 1977 } 1978 } 1979 1980 /** 1981 * Attempts to undeploy a region from a region server based in information in META. Any operations 1982 * that modify the file system should make sure that its corresponding region is not deployed to 1983 * prevent data races. A separate call is required to update the master in-memory region state 1984 * kept in the AssignementManager. Because disable uses this state instead of that found in META, 1985 * we can't seem to cleanly disable/delete tables that have been hbck fixed. When used on a 1986 * version of HBase that does not have the offline ipc call exposed on the master (<0.90.5, 1987 * <0.92.0) a master restart or failover may be required. 1988 */ 1989 void closeRegion(HbckRegionInfo hi) throws IOException, InterruptedException { 1990 if (hi.getMetaEntry() == null && hi.getHdfsEntry() == null) { 1991 undeployRegions(hi); 1992 return; 1993 } 1994 1995 // get assignment info and hregioninfo from meta. 1996 Get get = new Get(hi.getRegionName()); 1997 get.addColumn(HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER); 1998 get.addColumn(HConstants.CATALOG_FAMILY, HConstants.SERVER_QUALIFIER); 1999 get.addColumn(HConstants.CATALOG_FAMILY, HConstants.STARTCODE_QUALIFIER); 2000 // also get the locations of the replicas to close if the primary region is being closed 2001 if (hi.getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) { 2002 int numReplicas = admin.getDescriptor(hi.getTableName()).getRegionReplication(); 2003 for (int i = 0; i < numReplicas; i++) { 2004 get.addColumn(HConstants.CATALOG_FAMILY, CatalogFamilyFormat.getServerColumn(i)); 2005 get.addColumn(HConstants.CATALOG_FAMILY, CatalogFamilyFormat.getStartCodeColumn(i)); 2006 } 2007 } 2008 Result r = meta.get(get); 2009 RegionLocations rl = CatalogFamilyFormat.getRegionLocations(r); 2010 if (rl == null) { 2011 LOG.warn("Unable to close region " + hi.getRegionNameAsString() 2012 + " since meta does not have handle to reach it"); 2013 return; 2014 } 2015 for (HRegionLocation h : rl.getRegionLocations()) { 2016 ServerName serverName = h.getServerName(); 2017 if (serverName == null) { 2018 errors.reportError("Unable to close region " + hi.getRegionNameAsString() 2019 + " because meta does not " + "have handle to reach it."); 2020 continue; 2021 } 2022 RegionInfo hri = h.getRegion(); 2023 if (hri == null) { 2024 LOG.warn( 2025 "Unable to close region " + hi.getRegionNameAsString() 2026 + " because {} had invalid or missing " + HConstants.CATALOG_FAMILY_STR + ":" 2027 + Bytes.toString(HConstants.REGIONINFO_QUALIFIER) + " qualifier value.", 2028 TableName.META_TABLE_NAME); 2029 continue; 2030 } 2031 // close the region -- close files and remove assignment 2032 HBaseFsckRepair.closeRegionSilentlyAndWait(connection, serverName, hri); 2033 } 2034 } 2035 2036 private void undeployRegions(HbckRegionInfo hi) throws IOException, InterruptedException { 2037 undeployRegionsForHbi(hi); 2038 // undeploy replicas of the region (but only if the method is invoked for the primary) 2039 if (hi.getReplicaId() != RegionInfo.DEFAULT_REPLICA_ID) { 2040 return; 2041 } 2042 int numReplicas = admin.getDescriptor(hi.getTableName()).getRegionReplication(); 2043 for (int i = 1; i < numReplicas; i++) { 2044 if (hi.getPrimaryHRIForDeployedReplica() == null) continue; 2045 RegionInfo hri = 2046 RegionReplicaUtil.getRegionInfoForReplica(hi.getPrimaryHRIForDeployedReplica(), i); 2047 HbckRegionInfo h = regionInfoMap.get(hri.getEncodedName()); 2048 if (h != null) { 2049 undeployRegionsForHbi(h); 2050 // set skip checks; we undeployed it, and we don't want to evaluate this anymore 2051 // in consistency checks 2052 h.setSkipChecks(true); 2053 } 2054 } 2055 } 2056 2057 private void undeployRegionsForHbi(HbckRegionInfo hi) throws IOException, InterruptedException { 2058 for (HbckRegionInfo.OnlineEntry rse : hi.getOnlineEntries()) { 2059 LOG.debug("Undeploy region " + rse.getRegionInfo() + " from " + rse.getServerName()); 2060 try { 2061 HBaseFsckRepair.closeRegionSilentlyAndWait(connection, rse.getServerName(), 2062 rse.getRegionInfo()); 2063 offline(rse.getRegionInfo().getRegionName()); 2064 } catch (IOException ioe) { 2065 LOG.warn("Got exception when attempting to offline region " 2066 + Bytes.toString(rse.getRegionInfo().getRegionName()), ioe); 2067 } 2068 } 2069 } 2070 2071 private void tryAssignmentRepair(HbckRegionInfo hbi, String msg) 2072 throws IOException, KeeperException, InterruptedException { 2073 // If we are trying to fix the errors 2074 if (shouldFixAssignments()) { 2075 errors.print(msg); 2076 undeployRegions(hbi); 2077 setShouldRerun(); 2078 RegionInfo hri = hbi.getHdfsHRI(); 2079 if (hri == null) { 2080 hri = hbi.getMetaEntry().getRegionInfo(); 2081 } 2082 HBaseFsckRepair.fixUnassigned(admin, hri); 2083 HBaseFsckRepair.waitUntilAssigned(admin, hri); 2084 2085 // also assign replicas if needed (do it only when this call operates on a primary replica) 2086 if (hbi.getReplicaId() != RegionInfo.DEFAULT_REPLICA_ID) return; 2087 int replicationCount = admin.getDescriptor(hri.getTable()).getRegionReplication(); 2088 for (int i = 1; i < replicationCount; i++) { 2089 hri = RegionReplicaUtil.getRegionInfoForReplica(hri, i); 2090 HbckRegionInfo h = regionInfoMap.get(hri.getEncodedName()); 2091 if (h != null) { 2092 undeployRegions(h); 2093 // set skip checks; we undeploy & deploy it; we don't want to evaluate this hbi anymore 2094 // in consistency checks 2095 h.setSkipChecks(true); 2096 } 2097 HBaseFsckRepair.fixUnassigned(admin, hri); 2098 HBaseFsckRepair.waitUntilAssigned(admin, hri); 2099 } 2100 2101 } 2102 } 2103 2104 /** 2105 * Check a single region for consistency and correct deployment. 2106 */ 2107 private void checkRegionConsistency(final String key, final HbckRegionInfo hbi) 2108 throws IOException, KeeperException, InterruptedException { 2109 2110 if (hbi.isSkipChecks()) return; 2111 String descriptiveName = hbi.toString(); 2112 boolean inMeta = hbi.getMetaEntry() != null; 2113 // In case not checking HDFS, assume the region is on HDFS 2114 boolean inHdfs = !shouldCheckHdfs() || hbi.getHdfsRegionDir() != null; 2115 boolean hasMetaAssignment = inMeta && hbi.getMetaEntry().regionServer != null; 2116 boolean isDeployed = !hbi.getDeployedOn().isEmpty(); 2117 boolean isMultiplyDeployed = hbi.getDeployedOn().size() > 1; 2118 boolean deploymentMatchesMeta = hasMetaAssignment && isDeployed && !isMultiplyDeployed 2119 && hbi.getMetaEntry().regionServer.equals(hbi.getDeployedOn().get(0)); 2120 boolean splitParent = inMeta && hbi.getMetaEntry().getRegionInfo().isSplit() 2121 && hbi.getMetaEntry().getRegionInfo().isOffline(); 2122 boolean shouldBeDeployed = 2123 inMeta && !isTableDisabled(hbi.getMetaEntry().getRegionInfo().getTable()); 2124 boolean recentlyModified = 2125 inHdfs && hbi.getModTime() + timelag > EnvironmentEdgeManager.currentTime(); 2126 2127 // ========== First the healthy cases ============= 2128 if (hbi.containsOnlyHdfsEdits()) { 2129 return; 2130 } 2131 if (inMeta && inHdfs && isDeployed && deploymentMatchesMeta && shouldBeDeployed) { 2132 return; 2133 } else if (inMeta && inHdfs && !shouldBeDeployed && !isDeployed) { 2134 LOG.info("Region " + descriptiveName + " is in META, and in a disabled " 2135 + "tabled that is not deployed"); 2136 return; 2137 } else if (recentlyModified) { 2138 LOG.warn("Region " + descriptiveName + " was recently modified -- skipping"); 2139 return; 2140 } 2141 // ========== Cases where the region is not in hbase:meta ============= 2142 else if (!inMeta && !inHdfs && !isDeployed) { 2143 // We shouldn't have record of this region at all then! 2144 assert false : "Entry for region with no data"; 2145 } else if (!inMeta && !inHdfs && isDeployed) { 2146 errors.reportError(ERROR_CODE.NOT_IN_META_HDFS, 2147 "Region " + descriptiveName + ", key=" + key + ", not on HDFS or in " 2148 + TableName.META_TABLE_NAME + " but " + "deployed on " 2149 + Joiner.on(", ").join(hbi.getDeployedOn())); 2150 if (shouldFixAssignments()) { 2151 undeployRegions(hbi); 2152 } 2153 2154 } else if (!inMeta && inHdfs && !isDeployed) { 2155 if (hbi.isMerged()) { 2156 // This region has already been merged, the remaining hdfs file will be 2157 // cleaned by CatalogJanitor later 2158 hbi.setSkipChecks(true); 2159 LOG.info("Region " + descriptiveName 2160 + " got merge recently, its file(s) will be cleaned by CatalogJanitor later"); 2161 return; 2162 } 2163 errors.reportError(ERROR_CODE.NOT_IN_META_OR_DEPLOYED, 2164 "Region " + descriptiveName + " on HDFS, but not listed in " + TableName.META_TABLE_NAME 2165 + " or deployed on any region server"); 2166 // restore region consistency of an adopted orphan 2167 if (shouldFixMeta()) { 2168 if (!hbi.isHdfsRegioninfoPresent()) { 2169 LOG.error("Region " + hbi.getHdfsHRI() + " could have been repaired" 2170 + " in table integrity repair phase if -fixHdfsOrphans was" + " used."); 2171 return; 2172 } 2173 2174 RegionInfo hri = hbi.getHdfsHRI(); 2175 HbckTableInfo tableInfo = tablesInfo.get(hri.getTable()); 2176 2177 for (RegionInfo region : tableInfo.getRegionsFromMeta(this.regionInfoMap)) { 2178 if ( 2179 Bytes.compareTo(region.getStartKey(), hri.getStartKey()) <= 0 2180 && (region.getEndKey().length == 0 2181 || Bytes.compareTo(region.getEndKey(), hri.getEndKey()) >= 0) 2182 && Bytes.compareTo(region.getStartKey(), hri.getEndKey()) <= 0 2183 ) { 2184 if (region.isSplit() || region.isOffline()) continue; 2185 Path regionDir = hbi.getHdfsRegionDir(); 2186 FileSystem fs = regionDir.getFileSystem(getConf()); 2187 List<Path> familyDirs = FSUtils.getFamilyDirs(fs, regionDir); 2188 for (Path familyDir : familyDirs) { 2189 List<Path> referenceFilePaths = FSUtils.getReferenceFilePaths(fs, familyDir); 2190 for (Path referenceFilePath : referenceFilePaths) { 2191 Path parentRegionDir = 2192 StoreFileInfo.getReferredToFile(referenceFilePath).getParent().getParent(); 2193 if (parentRegionDir.toString().endsWith(region.getEncodedName())) { 2194 LOG.warn(hri + " start and stop keys are in the range of " + region 2195 + ". The region might not be cleaned up from hdfs when region " + region 2196 + " split failed. Hence deleting from hdfs."); 2197 HRegionFileSystem.deleteRegionFromFileSystem(getConf(), fs, regionDir.getParent(), 2198 hri); 2199 return; 2200 } 2201 } 2202 } 2203 } 2204 } 2205 LOG.info("Patching {} with .regioninfo: " + hbi.getHdfsHRI(), TableName.META_TABLE_NAME); 2206 int numReplicas = admin.getDescriptor(hbi.getTableName()).getRegionReplication(); 2207 HBaseFsckRepair.fixMetaHoleOnlineAndAddReplicas(getConf(), hbi.getHdfsHRI(), 2208 admin.getClusterMetrics(EnumSet.of(Option.LIVE_SERVERS)).getLiveServerMetrics().keySet(), 2209 numReplicas); 2210 2211 tryAssignmentRepair(hbi, "Trying to reassign region..."); 2212 } 2213 2214 } else if (!inMeta && inHdfs && isDeployed) { 2215 errors.reportError(ERROR_CODE.NOT_IN_META, "Region " + descriptiveName 2216 + " not in META, but deployed on " + Joiner.on(", ").join(hbi.getDeployedOn())); 2217 debugLsr(hbi.getHdfsRegionDir()); 2218 if (hbi.getReplicaId() != RegionInfo.DEFAULT_REPLICA_ID) { 2219 // for replicas, this means that we should undeploy the region (we would have 2220 // gone over the primaries and fixed meta holes in first phase under 2221 // checkAndFixConsistency; we shouldn't get the condition !inMeta at 2222 // this stage unless unwanted replica) 2223 if (shouldFixAssignments()) { 2224 undeployRegionsForHbi(hbi); 2225 } 2226 } 2227 if (shouldFixMeta() && hbi.getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) { 2228 if (!hbi.isHdfsRegioninfoPresent()) { 2229 LOG.error("This should have been repaired in table integrity repair phase"); 2230 return; 2231 } 2232 2233 LOG.info("Patching {} with with .regioninfo: " + hbi.getHdfsHRI(), 2234 TableName.META_TABLE_NAME); 2235 int numReplicas = admin.getDescriptor(hbi.getTableName()).getRegionReplication(); 2236 HBaseFsckRepair.fixMetaHoleOnlineAndAddReplicas(getConf(), hbi.getHdfsHRI(), 2237 admin.getClusterMetrics(EnumSet.of(Option.LIVE_SERVERS)).getLiveServerMetrics().keySet(), 2238 numReplicas); 2239 tryAssignmentRepair(hbi, "Trying to fix unassigned region..."); 2240 } 2241 2242 // ========== Cases where the region is in hbase:meta ============= 2243 } else if (inMeta && inHdfs && !isDeployed && splitParent) { 2244 // check whether this is an actual error, or just transient state where parent 2245 // is not cleaned 2246 if (hbi.getMetaEntry().splitA != null && hbi.getMetaEntry().splitB != null) { 2247 // check that split daughters are there 2248 HbckRegionInfo infoA = this.regionInfoMap.get(hbi.getMetaEntry().splitA.getEncodedName()); 2249 HbckRegionInfo infoB = this.regionInfoMap.get(hbi.getMetaEntry().splitB.getEncodedName()); 2250 if (infoA != null && infoB != null) { 2251 // we already processed or will process daughters. Move on, nothing to see here. 2252 hbi.setSkipChecks(true); 2253 return; 2254 } 2255 } 2256 2257 // For Replica region, we need to do a similar check. If replica is not split successfully, 2258 // error is going to be reported against primary daughter region. 2259 if (hbi.getReplicaId() != RegionInfo.DEFAULT_REPLICA_ID) { 2260 LOG.info("Region " + descriptiveName + " is a split parent in META, in HDFS, " 2261 + "and not deployed on any region server. This may be transient."); 2262 hbi.setSkipChecks(true); 2263 return; 2264 } 2265 2266 errors.reportError(ERROR_CODE.LINGERING_SPLIT_PARENT, 2267 "Region " + descriptiveName + " is a split parent in META, in HDFS, " 2268 + "and not deployed on any region server. This could be transient, " 2269 + "consider to run the catalog janitor first!"); 2270 if (shouldFixSplitParents()) { 2271 setShouldRerun(); 2272 resetSplitParent(hbi); 2273 } 2274 } else if (inMeta && !inHdfs && !isDeployed) { 2275 errors.reportError(ERROR_CODE.NOT_IN_HDFS_OR_DEPLOYED, "Region " + descriptiveName 2276 + " found in META, but not in HDFS " + "or deployed on any region server."); 2277 if (shouldFixMeta()) { 2278 deleteMetaRegion(hbi); 2279 } 2280 } else if (inMeta && !inHdfs && isDeployed) { 2281 errors.reportError(ERROR_CODE.NOT_IN_HDFS, 2282 "Region " + descriptiveName + " found in META, but not in HDFS, " + "and deployed on " 2283 + Joiner.on(", ").join(hbi.getDeployedOn())); 2284 // We treat HDFS as ground truth. Any information in meta is transient 2285 // and equivalent data can be regenerated. So, lets unassign and remove 2286 // these problems from META. 2287 if (shouldFixAssignments()) { 2288 errors.print("Trying to fix unassigned region..."); 2289 undeployRegions(hbi); 2290 } 2291 if (shouldFixMeta()) { 2292 // wait for it to complete 2293 deleteMetaRegion(hbi); 2294 } 2295 } else if (inMeta && inHdfs && !isDeployed && shouldBeDeployed) { 2296 errors.reportError(ERROR_CODE.NOT_DEPLOYED, 2297 "Region " + descriptiveName + " not deployed on any region server."); 2298 tryAssignmentRepair(hbi, "Trying to fix unassigned region..."); 2299 } else if (inMeta && inHdfs && isDeployed && !shouldBeDeployed) { 2300 errors.reportError(ERROR_CODE.SHOULD_NOT_BE_DEPLOYED, 2301 "Region " + descriptiveName + " should not be deployed according " 2302 + "to META, but is deployed on " + Joiner.on(", ").join(hbi.getDeployedOn())); 2303 if (shouldFixAssignments()) { 2304 errors.print("Trying to close the region " + descriptiveName); 2305 setShouldRerun(); 2306 HBaseFsckRepair.fixMultiAssignment(connection, hbi.getMetaEntry().getRegionInfo(), 2307 hbi.getDeployedOn()); 2308 } 2309 } else if (inMeta && inHdfs && isMultiplyDeployed) { 2310 errors.reportError(ERROR_CODE.MULTI_DEPLOYED, 2311 "Region " + descriptiveName + " is listed in " + TableName.META_TABLE_NAME 2312 + " on region server " + hbi.getMetaEntry().regionServer + " but is multiply assigned" 2313 + " to region servers " + Joiner.on(", ").join(hbi.getDeployedOn())); 2314 // If we are trying to fix the errors 2315 if (shouldFixAssignments()) { 2316 errors.print("Trying to fix assignment error..."); 2317 setShouldRerun(); 2318 HBaseFsckRepair.fixMultiAssignment(connection, hbi.getMetaEntry().getRegionInfo(), 2319 hbi.getDeployedOn()); 2320 } 2321 } else if (inMeta && inHdfs && isDeployed && !deploymentMatchesMeta) { 2322 errors.reportError(ERROR_CODE.SERVER_DOES_NOT_MATCH_META, 2323 "Region " + descriptiveName + " listed in " + TableName.META_TABLE_NAME 2324 + " on region server " + hbi.getMetaEntry().regionServer + " but found on region server " 2325 + hbi.getDeployedOn().get(0)); 2326 // If we are trying to fix the errors 2327 if (shouldFixAssignments()) { 2328 errors.print("Trying to fix assignment error..."); 2329 setShouldRerun(); 2330 HBaseFsckRepair.fixMultiAssignment(connection, hbi.getMetaEntry().getRegionInfo(), 2331 hbi.getDeployedOn()); 2332 HBaseFsckRepair.waitUntilAssigned(admin, hbi.getHdfsHRI()); 2333 } 2334 } else { 2335 errors.reportError(ERROR_CODE.UNKNOWN, 2336 "Region " + descriptiveName + " is in an unforeseen state:" + " inMeta=" + inMeta 2337 + " inHdfs=" + inHdfs + " isDeployed=" + isDeployed + " isMultiplyDeployed=" 2338 + isMultiplyDeployed + " deploymentMatchesMeta=" + deploymentMatchesMeta 2339 + " shouldBeDeployed=" + shouldBeDeployed); 2340 } 2341 } 2342 2343 /** 2344 * Checks tables integrity. Goes over all regions and scans the tables. Collects all the pieces 2345 * for each table and checks if there are missing, repeated or overlapping ones. 2346 */ 2347 SortedMap<TableName, HbckTableInfo> checkIntegrity() throws IOException { 2348 tablesInfo = new TreeMap<>(); 2349 LOG.debug("There are " + regionInfoMap.size() + " region info entries"); 2350 for (HbckRegionInfo hbi : regionInfoMap.values()) { 2351 // Check only valid, working regions 2352 if (hbi.getMetaEntry() == null) { 2353 // this assumes that consistency check has run loadMetaEntry 2354 Path p = hbi.getHdfsRegionDir(); 2355 if (p == null) { 2356 errors.report("No regioninfo in Meta or HDFS. " + hbi); 2357 } 2358 2359 // TODO test. 2360 continue; 2361 } 2362 if (hbi.getMetaEntry().regionServer == null) { 2363 errors.detail("Skipping region because no region server: " + hbi); 2364 continue; 2365 } 2366 if (hbi.getMetaEntry().getRegionInfo().isOffline()) { 2367 errors.detail("Skipping region because it is offline: " + hbi); 2368 continue; 2369 } 2370 if (hbi.containsOnlyHdfsEdits()) { 2371 errors.detail("Skipping region because it only contains edits" + hbi); 2372 continue; 2373 } 2374 2375 // Missing regionDir or over-deployment is checked elsewhere. Include 2376 // these cases in modTInfo, so we can evaluate those regions as part of 2377 // the region chain in META 2378 // if (hbi.foundRegionDir == null) continue; 2379 // if (hbi.deployedOn.size() != 1) continue; 2380 if (hbi.getDeployedOn().isEmpty()) { 2381 continue; 2382 } 2383 2384 // We should be safe here 2385 TableName tableName = hbi.getMetaEntry().getRegionInfo().getTable(); 2386 HbckTableInfo modTInfo = tablesInfo.get(tableName); 2387 if (modTInfo == null) { 2388 modTInfo = new HbckTableInfo(tableName, this); 2389 } 2390 for (ServerName server : hbi.getDeployedOn()) { 2391 modTInfo.addServer(server); 2392 } 2393 2394 if (!hbi.isSkipChecks()) { 2395 modTInfo.addRegionInfo(hbi); 2396 } 2397 2398 tablesInfo.put(tableName, modTInfo); 2399 } 2400 2401 loadTableInfosForTablesWithNoRegion(); 2402 2403 logParallelMerge(); 2404 for (HbckTableInfo tInfo : tablesInfo.values()) { 2405 TableIntegrityErrorHandler handler = tInfo.new IntegrityFixSuggester(tInfo, errors); 2406 if (!tInfo.checkRegionChain(handler)) { 2407 errors.report("Found inconsistency in table " + tInfo.getName()); 2408 } 2409 } 2410 return tablesInfo; 2411 } 2412 2413 /** 2414 * Loads table info's for tables that may not have been included, since there are no regions 2415 * reported for the table, but table dir is there in hdfs 2416 */ 2417 private void loadTableInfosForTablesWithNoRegion() throws IOException { 2418 Map<String, TableDescriptor> allTables = new FSTableDescriptors(getConf()).getAll(); 2419 for (TableDescriptor htd : allTables.values()) { 2420 if (checkMetaOnly && !htd.isMetaTable()) { 2421 continue; 2422 } 2423 2424 TableName tableName = htd.getTableName(); 2425 if (isTableIncluded(tableName) && !tablesInfo.containsKey(tableName)) { 2426 HbckTableInfo tableInfo = new HbckTableInfo(tableName, this); 2427 tableInfo.htds.add(htd); 2428 tablesInfo.put(htd.getTableName(), tableInfo); 2429 } 2430 } 2431 } 2432 2433 /** 2434 * Merge hdfs data by moving from contained HbckRegionInfo into targetRegionDir. 2435 * @return number of file move fixes done to merge regions. 2436 */ 2437 public int mergeRegionDirs(Path targetRegionDir, HbckRegionInfo contained) throws IOException { 2438 int fileMoves = 0; 2439 String thread = Thread.currentThread().getName(); 2440 LOG.debug("[" + thread + "] Contained region dir after close and pause"); 2441 debugLsr(contained.getHdfsRegionDir()); 2442 2443 // rename the contained into the container. 2444 FileSystem fs = targetRegionDir.getFileSystem(getConf()); 2445 FileStatus[] dirs = null; 2446 try { 2447 dirs = fs.listStatus(contained.getHdfsRegionDir()); 2448 } catch (FileNotFoundException fnfe) { 2449 // region we are attempting to merge in is not present! Since this is a merge, there is 2450 // no harm skipping this region if it does not exist. 2451 if (!fs.exists(contained.getHdfsRegionDir())) { 2452 LOG.warn("[" + thread + "] HDFS region dir " + contained.getHdfsRegionDir() 2453 + " is missing. Assuming already sidelined or moved."); 2454 } else { 2455 sidelineRegionDir(fs, contained); 2456 } 2457 return fileMoves; 2458 } 2459 2460 if (dirs == null) { 2461 if (!fs.exists(contained.getHdfsRegionDir())) { 2462 LOG.warn("[" + thread + "] HDFS region dir " + contained.getHdfsRegionDir() 2463 + " already sidelined."); 2464 } else { 2465 sidelineRegionDir(fs, contained); 2466 } 2467 return fileMoves; 2468 } 2469 2470 for (FileStatus cf : dirs) { 2471 Path src = cf.getPath(); 2472 Path dst = new Path(targetRegionDir, src.getName()); 2473 2474 if (src.getName().equals(HRegionFileSystem.REGION_INFO_FILE)) { 2475 // do not copy the old .regioninfo file. 2476 continue; 2477 } 2478 2479 if (src.getName().equals(HConstants.HREGION_OLDLOGDIR_NAME)) { 2480 // do not copy the .oldlogs files 2481 continue; 2482 } 2483 2484 LOG.info("[" + thread + "] Moving files from " + src + " into containing region " + dst); 2485 // FileSystem.rename is inconsistent with directories -- if the 2486 // dst (foo/a) exists and is a dir, and the src (foo/b) is a dir, 2487 // it moves the src into the dst dir resulting in (foo/a/b). If 2488 // the dst does not exist, and the src a dir, src becomes dst. (foo/b) 2489 for (FileStatus hfile : fs.listStatus(src)) { 2490 boolean success = fs.rename(hfile.getPath(), dst); 2491 if (success) { 2492 fileMoves++; 2493 } 2494 } 2495 LOG.debug("[" + thread + "] Sideline directory contents:"); 2496 debugLsr(targetRegionDir); 2497 } 2498 2499 // if all success. 2500 sidelineRegionDir(fs, contained); 2501 LOG.info("[" + thread + "] Sidelined region dir " + contained.getHdfsRegionDir() + " into " 2502 + getSidelineDir()); 2503 debugLsr(contained.getHdfsRegionDir()); 2504 2505 return fileMoves; 2506 } 2507 2508 static class WorkItemOverlapMerge implements Callable<Void> { 2509 private TableIntegrityErrorHandler handler; 2510 Collection<HbckRegionInfo> overlapgroup; 2511 2512 WorkItemOverlapMerge(Collection<HbckRegionInfo> overlapgroup, 2513 TableIntegrityErrorHandler handler) { 2514 this.handler = handler; 2515 this.overlapgroup = overlapgroup; 2516 } 2517 2518 @Override 2519 public Void call() throws Exception { 2520 handler.handleOverlapGroup(overlapgroup); 2521 return null; 2522 } 2523 } 2524 2525 /** 2526 * Return a list of user-space table names whose metadata have not been modified in the last few 2527 * milliseconds specified by timelag if any of the REGIONINFO_QUALIFIER, SERVER_QUALIFIER, 2528 * STARTCODE_QUALIFIER, SPLITA_QUALIFIER, SPLITB_QUALIFIER have not changed in the last 2529 * milliseconds specified by timelag, then the table is a candidate to be returned. 2530 * @return tables that have not been modified recently 2531 * @throws IOException if an error is encountered 2532 */ 2533 TableDescriptor[] getTables(AtomicInteger numSkipped) { 2534 List<TableName> tableNames = new ArrayList<>(); 2535 long now = EnvironmentEdgeManager.currentTime(); 2536 2537 for (HbckRegionInfo hbi : regionInfoMap.values()) { 2538 HbckRegionInfo.MetaEntry info = hbi.getMetaEntry(); 2539 2540 // if the start key is zero, then we have found the first region of a table. 2541 // pick only those tables that were not modified in the last few milliseconds. 2542 if ( 2543 info != null && info.getRegionInfo().getStartKey().length == 0 2544 && !info.getRegionInfo().isMetaRegion() 2545 ) { 2546 if (info.modTime + timelag < now) { 2547 tableNames.add(info.getRegionInfo().getTable()); 2548 } else { 2549 numSkipped.incrementAndGet(); // one more in-flux table 2550 } 2551 } 2552 } 2553 return getTableDescriptors(tableNames); 2554 } 2555 2556 TableDescriptor[] getTableDescriptors(List<TableName> tableNames) { 2557 LOG.info("getTableDescriptors == tableNames => " + tableNames); 2558 try (Connection conn = ConnectionFactory.createConnection(getConf()); 2559 Admin admin = conn.getAdmin()) { 2560 List<TableDescriptor> tds = admin.listTableDescriptors(tableNames); 2561 return tds.toArray(new TableDescriptor[tds.size()]); 2562 } catch (IOException e) { 2563 LOG.debug("Exception getting table descriptors", e); 2564 } 2565 return new TableDescriptor[0]; 2566 } 2567 2568 /** 2569 * Gets the entry in regionInfo corresponding to the the given encoded region name. If the region 2570 * has not been seen yet, a new entry is added and returned. 2571 */ 2572 private synchronized HbckRegionInfo getOrCreateInfo(String name) { 2573 HbckRegionInfo hbi = regionInfoMap.get(name); 2574 if (hbi == null) { 2575 hbi = new HbckRegionInfo(null); 2576 regionInfoMap.put(name, hbi); 2577 } 2578 return hbi; 2579 } 2580 2581 private void checkAndFixReplication() throws ReplicationException, IOException { 2582 ReplicationChecker checker = new ReplicationChecker(getConf(), zkw, connection, errors); 2583 2584 if (!checker.checkHasDataInQueues()) { 2585 return; 2586 } 2587 2588 checker.checkUnDeletedQueues(); 2589 2590 if (checker.hasUnDeletedQueues() && this.fixReplication) { 2591 checker.fixUnDeletedQueues(); 2592 setShouldRerun(); 2593 } 2594 } 2595 2596 /** 2597 * Check values in regionInfo for hbase:meta Check if zero or more than one regions with 2598 * hbase:meta are found. If there are inconsistencies (i.e. zero or more than one regions pretend 2599 * to be holding the hbase:meta) try to fix that and report an error. 2600 * @throws IOException from HBaseFsckRepair functions 2601 */ 2602 boolean checkMetaRegion() throws IOException, KeeperException, InterruptedException { 2603 Map<Integer, HbckRegionInfo> metaRegions = new HashMap<>(); 2604 for (HbckRegionInfo value : regionInfoMap.values()) { 2605 if (value.getMetaEntry() != null && value.getMetaEntry().getRegionInfo().isMetaRegion()) { 2606 metaRegions.put(value.getReplicaId(), value); 2607 } 2608 } 2609 int metaReplication = admin.getDescriptor(TableName.META_TABLE_NAME).getRegionReplication(); 2610 boolean noProblem = true; 2611 // There will be always entries in regionInfoMap corresponding to hbase:meta & its replicas 2612 // Check the deployed servers. It should be exactly one server for each replica. 2613 for (int i = 0; i < metaReplication; i++) { 2614 HbckRegionInfo metaHbckRegionInfo = metaRegions.remove(i); 2615 List<ServerName> servers = new ArrayList<>(); 2616 if (metaHbckRegionInfo != null) { 2617 servers = metaHbckRegionInfo.getDeployedOn(); 2618 } 2619 if (servers.size() != 1) { 2620 noProblem = false; 2621 if (servers.isEmpty()) { 2622 assignMetaReplica(i); 2623 } else if (servers.size() > 1) { 2624 errors.reportError(ERROR_CODE.MULTI_META_REGION, 2625 TableName.META_TABLE_NAME + ", replicaId " + metaHbckRegionInfo.getReplicaId() 2626 + " is found on more than one region."); 2627 if (shouldFixAssignments()) { 2628 errors.print("Trying to fix a problem with " + TableName.META_TABLE_NAME 2629 + ", replicaId " + metaHbckRegionInfo.getReplicaId() + ".."); 2630 setShouldRerun(); 2631 // try fix it (treat is a dupe assignment) 2632 HBaseFsckRepair.fixMultiAssignment(connection, 2633 metaHbckRegionInfo.getMetaEntry().getRegionInfo(), servers); 2634 } 2635 } 2636 } 2637 } 2638 // unassign whatever is remaining in metaRegions. They are excess replicas. 2639 for (Map.Entry<Integer, HbckRegionInfo> entry : metaRegions.entrySet()) { 2640 noProblem = false; 2641 errors.reportError(ERROR_CODE.SHOULD_NOT_BE_DEPLOYED, 2642 TableName.META_TABLE_NAME + " replicas are deployed in excess. Configured " 2643 + metaReplication + ", deployed " + metaRegions.size()); 2644 if (shouldFixAssignments()) { 2645 errors.print("Trying to undeploy excess replica, replicaId: " + entry.getKey() + " of " 2646 + TableName.META_TABLE_NAME + ".."); 2647 setShouldRerun(); 2648 unassignMetaReplica(entry.getValue()); 2649 } 2650 } 2651 // if noProblem is false, rerun hbck with hopefully fixed META 2652 // if noProblem is true, no errors, so continue normally 2653 return noProblem; 2654 } 2655 2656 private void unassignMetaReplica(HbckRegionInfo hi) 2657 throws IOException, InterruptedException, KeeperException { 2658 undeployRegions(hi); 2659 ZKUtil.deleteNode(zkw, 2660 zkw.getZNodePaths().getZNodeForReplica(hi.getMetaEntry().getRegionInfo().getReplicaId())); 2661 } 2662 2663 private void assignMetaReplica(int replicaId) 2664 throws IOException, KeeperException, InterruptedException { 2665 errors.reportError(ERROR_CODE.NO_META_REGION, 2666 TableName.META_TABLE_NAME + ", replicaId " + replicaId + " is not found on any region."); 2667 if (shouldFixAssignments()) { 2668 errors.print("Trying to fix a problem with " + TableName.META_TABLE_NAME + ".."); 2669 setShouldRerun(); 2670 // try to fix it (treat it as unassigned region) 2671 RegionInfo h = RegionReplicaUtil 2672 .getRegionInfoForReplica(RegionInfoBuilder.FIRST_META_REGIONINFO, replicaId); 2673 HBaseFsckRepair.fixUnassigned(admin, h); 2674 HBaseFsckRepair.waitUntilAssigned(admin, h); 2675 } 2676 } 2677 2678 /** 2679 * Scan hbase:meta, adding all regions found to the regionInfo map. 2680 * @throws IOException if an error is encountered 2681 */ 2682 boolean loadMetaEntries() throws IOException { 2683 ClientMetaTableAccessor.Visitor visitor = new ClientMetaTableAccessor.Visitor() { 2684 int countRecord = 1; 2685 2686 // comparator to sort KeyValues with latest modtime 2687 final Comparator<Cell> comp = new Comparator<Cell>() { 2688 @Override 2689 public int compare(Cell k1, Cell k2) { 2690 return Long.compare(k1.getTimestamp(), k2.getTimestamp()); 2691 } 2692 }; 2693 2694 @Override 2695 public boolean visit(Result result) throws IOException { 2696 try { 2697 2698 // record the latest modification of this META record 2699 long ts = Collections.max(result.listCells(), comp).getTimestamp(); 2700 RegionLocations rl = CatalogFamilyFormat.getRegionLocations(result); 2701 if (rl == null) { 2702 emptyRegionInfoQualifiers.add(result); 2703 errors.reportError(ERROR_CODE.EMPTY_META_CELL, 2704 "Empty REGIONINFO_QUALIFIER found in " + TableName.META_TABLE_NAME); 2705 return true; 2706 } 2707 ServerName sn = null; 2708 if ( 2709 rl.getRegionLocation(RegionInfo.DEFAULT_REPLICA_ID) == null 2710 || rl.getRegionLocation(RegionInfo.DEFAULT_REPLICA_ID).getRegion() == null 2711 ) { 2712 emptyRegionInfoQualifiers.add(result); 2713 errors.reportError(ERROR_CODE.EMPTY_META_CELL, 2714 "Empty REGIONINFO_QUALIFIER found in " + TableName.META_TABLE_NAME); 2715 return true; 2716 } 2717 RegionInfo hri = rl.getRegionLocation(RegionInfo.DEFAULT_REPLICA_ID).getRegion(); 2718 if (!(isTableIncluded(hri.getTable()) || hri.isMetaRegion())) { 2719 return true; 2720 } 2721 PairOfSameType<RegionInfo> daughters = MetaTableAccessor.getDaughterRegions(result); 2722 for (HRegionLocation h : rl.getRegionLocations()) { 2723 if (h == null || h.getRegion() == null) { 2724 continue; 2725 } 2726 sn = h.getServerName(); 2727 hri = h.getRegion(); 2728 2729 HbckRegionInfo.MetaEntry m = null; 2730 if (hri.getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID) { 2731 m = new HbckRegionInfo.MetaEntry(hri, sn, ts, daughters.getFirst(), 2732 daughters.getSecond()); 2733 } else { 2734 m = new HbckRegionInfo.MetaEntry(hri, sn, ts, null, null); 2735 } 2736 HbckRegionInfo previous = regionInfoMap.get(hri.getEncodedName()); 2737 if (previous == null) { 2738 regionInfoMap.put(hri.getEncodedName(), new HbckRegionInfo(m)); 2739 } else if (previous.getMetaEntry() == null) { 2740 previous.setMetaEntry(m); 2741 } else { 2742 throw new IOException( 2743 "Two entries in " + TableName.META_TABLE_NAME + " are same " + previous); 2744 } 2745 } 2746 List<RegionInfo> mergeParents = CatalogFamilyFormat.getMergeRegions(result.rawCells()); 2747 if (mergeParents != null) { 2748 for (RegionInfo mergeRegion : mergeParents) { 2749 if (mergeRegion != null) { 2750 // This region is already being merged 2751 HbckRegionInfo hbInfo = getOrCreateInfo(mergeRegion.getEncodedName()); 2752 hbInfo.setMerged(true); 2753 } 2754 } 2755 } 2756 2757 // show proof of progress to the user, once for every 100 records. 2758 if (countRecord % 100 == 0) { 2759 errors.progress(); 2760 } 2761 countRecord++; 2762 return true; 2763 } catch (RuntimeException e) { 2764 LOG.error("Result=" + result); 2765 throw e; 2766 } 2767 } 2768 }; 2769 if (!checkMetaOnly) { 2770 // Scan hbase:meta to pick up user regions 2771 MetaTableAccessor.fullScanRegions(connection, visitor); 2772 } 2773 2774 errors.print(""); 2775 return true; 2776 } 2777 2778 /** 2779 * Prints summary of all tables found on the system. 2780 */ 2781 private void printTableSummary(SortedMap<TableName, HbckTableInfo> tablesInfo) { 2782 StringBuilder sb = new StringBuilder(); 2783 int numOfSkippedRegions; 2784 errors.print("Summary:"); 2785 for (HbckTableInfo tInfo : tablesInfo.values()) { 2786 numOfSkippedRegions = (skippedRegions.containsKey(tInfo.getName())) 2787 ? skippedRegions.get(tInfo.getName()).size() 2788 : 0; 2789 2790 if (errors.tableHasErrors(tInfo)) { 2791 errors.print("Table " + tInfo.getName() + " is inconsistent."); 2792 } else if (numOfSkippedRegions > 0) { 2793 errors.print("Table " + tInfo.getName() + " is okay (with " + numOfSkippedRegions 2794 + " skipped regions)."); 2795 } else { 2796 errors.print("Table " + tInfo.getName() + " is okay."); 2797 } 2798 errors.print(" Number of regions: " + tInfo.getNumRegions()); 2799 if (numOfSkippedRegions > 0) { 2800 Set<String> skippedRegionStrings = skippedRegions.get(tInfo.getName()); 2801 System.out.println(" Number of skipped regions: " + numOfSkippedRegions); 2802 System.out.println(" List of skipped regions:"); 2803 for (String sr : skippedRegionStrings) { 2804 System.out.println(" " + sr); 2805 } 2806 } 2807 sb.setLength(0); // clear out existing buffer, if any. 2808 sb.append(" Deployed on: "); 2809 for (ServerName server : tInfo.deployedOn) { 2810 sb.append(" " + server.toString()); 2811 } 2812 errors.print(sb.toString()); 2813 } 2814 } 2815 2816 static HbckErrorReporter getErrorReporter(final Configuration conf) 2817 throws ClassNotFoundException { 2818 Class<? extends HbckErrorReporter> reporter = conf.getClass("hbasefsck.errorreporter", 2819 PrintingErrorReporter.class, HbckErrorReporter.class); 2820 return ReflectionUtils.newInstance(reporter, conf); 2821 } 2822 2823 static class PrintingErrorReporter implements HbckErrorReporter { 2824 public int errorCount = 0; 2825 private int showProgress; 2826 // How frequently calls to progress() will create output 2827 private static final int progressThreshold = 100; 2828 2829 Set<HbckTableInfo> errorTables = new HashSet<>(); 2830 2831 // for use by unit tests to verify which errors were discovered 2832 private ArrayList<ERROR_CODE> errorList = new ArrayList<>(); 2833 2834 @Override 2835 public void clear() { 2836 errorTables.clear(); 2837 errorList.clear(); 2838 errorCount = 0; 2839 } 2840 2841 @Override 2842 public synchronized void reportError(ERROR_CODE errorCode, String message) { 2843 if (errorCode == ERROR_CODE.WRONG_USAGE) { 2844 System.err.println(message); 2845 return; 2846 } 2847 2848 errorList.add(errorCode); 2849 if (!summary) { 2850 System.out.println("ERROR: " + message); 2851 } 2852 errorCount++; 2853 showProgress = 0; 2854 } 2855 2856 @Override 2857 public synchronized void reportError(ERROR_CODE errorCode, String message, 2858 HbckTableInfo table) { 2859 errorTables.add(table); 2860 reportError(errorCode, message); 2861 } 2862 2863 @Override 2864 public synchronized void reportError(ERROR_CODE errorCode, String message, HbckTableInfo table, 2865 HbckRegionInfo info) { 2866 errorTables.add(table); 2867 String reference = "(region " + info.getRegionNameAsString() + ")"; 2868 reportError(errorCode, reference + " " + message); 2869 } 2870 2871 @Override 2872 public synchronized void reportError(ERROR_CODE errorCode, String message, HbckTableInfo table, 2873 HbckRegionInfo info1, HbckRegionInfo info2) { 2874 errorTables.add(table); 2875 String reference = 2876 "(regions " + info1.getRegionNameAsString() + " and " + info2.getRegionNameAsString() + ")"; 2877 reportError(errorCode, reference + " " + message); 2878 } 2879 2880 @Override 2881 public synchronized void reportError(String message) { 2882 reportError(ERROR_CODE.UNKNOWN, message); 2883 } 2884 2885 /** 2886 * Report error information, but do not increment the error count. Intended for cases where the 2887 * actual error would have been reported previously. 2888 */ 2889 @Override 2890 public synchronized void report(String message) { 2891 if (!summary) { 2892 System.out.println("ERROR: " + message); 2893 } 2894 showProgress = 0; 2895 } 2896 2897 @Override 2898 public synchronized int summarize() { 2899 System.out.println(Integer.toString(errorCount) + " inconsistencies detected."); 2900 if (errorCount == 0) { 2901 System.out.println("Status: OK"); 2902 return 0; 2903 } else { 2904 System.out.println("Status: INCONSISTENT"); 2905 return -1; 2906 } 2907 } 2908 2909 @Override 2910 public ArrayList<ERROR_CODE> getErrorList() { 2911 return errorList; 2912 } 2913 2914 @Override 2915 public synchronized void print(String message) { 2916 if (!summary) { 2917 System.out.println(message); 2918 } 2919 } 2920 2921 @Override 2922 public boolean tableHasErrors(HbckTableInfo table) { 2923 return errorTables.contains(table); 2924 } 2925 2926 @Override 2927 public void resetErrors() { 2928 errorCount = 0; 2929 } 2930 2931 @Override 2932 public synchronized void detail(String message) { 2933 if (details) { 2934 System.out.println(message); 2935 } 2936 showProgress = 0; 2937 } 2938 2939 @Override 2940 public synchronized void progress() { 2941 if (showProgress++ == progressThreshold) { 2942 if (!summary) { 2943 System.out.print("."); 2944 } 2945 showProgress = 0; 2946 } 2947 } 2948 } 2949 2950 /** 2951 * Contact a region server and get all information from it 2952 */ 2953 static class WorkItemRegion implements Callable<Void> { 2954 private final HBaseFsck hbck; 2955 private final ServerName rsinfo; 2956 private final HbckErrorReporter errors; 2957 private final Connection connection; 2958 2959 WorkItemRegion(HBaseFsck hbck, ServerName info, HbckErrorReporter errors, 2960 Connection connection) { 2961 this.hbck = hbck; 2962 this.rsinfo = info; 2963 this.errors = errors; 2964 this.connection = connection; 2965 } 2966 2967 @Override 2968 public synchronized Void call() throws IOException { 2969 errors.progress(); 2970 try { 2971 // list all online regions from this region server 2972 List<RegionInfo> regions = connection.getAdmin().getRegions(rsinfo); 2973 regions = filterRegions(regions); 2974 2975 if (details) { 2976 errors.detail( 2977 "RegionServer: " + rsinfo.getServerName() + " number of regions: " + regions.size()); 2978 for (RegionInfo rinfo : regions) { 2979 errors.detail(" " + rinfo.getRegionNameAsString() + " id: " + rinfo.getRegionId() 2980 + " encoded_name: " + rinfo.getEncodedName() + " start: " 2981 + Bytes.toStringBinary(rinfo.getStartKey()) + " end: " 2982 + Bytes.toStringBinary(rinfo.getEndKey())); 2983 } 2984 } 2985 2986 // check to see if the existence of this region matches the region in META 2987 for (RegionInfo r : regions) { 2988 HbckRegionInfo hbi = hbck.getOrCreateInfo(r.getEncodedName()); 2989 hbi.addServer(r, rsinfo); 2990 } 2991 } catch (IOException e) { // unable to connect to the region server. 2992 errors.reportError(ERROR_CODE.RS_CONNECT_FAILURE, 2993 "RegionServer: " + rsinfo.getServerName() + " Unable to fetch region information. " + e); 2994 throw e; 2995 } 2996 return null; 2997 } 2998 2999 private List<RegionInfo> filterRegions(List<RegionInfo> regions) { 3000 List<RegionInfo> ret = Lists.newArrayList(); 3001 for (RegionInfo hri : regions) { 3002 if (hri.isMetaRegion() || (!hbck.checkMetaOnly && hbck.isTableIncluded(hri.getTable()))) { 3003 ret.add(hri); 3004 } 3005 } 3006 return ret; 3007 } 3008 } 3009 3010 /** 3011 * Contact hdfs and get all information about specified table directory into regioninfo list. 3012 */ 3013 class WorkItemHdfsDir implements Callable<Void> { 3014 private FileStatus tableDir; 3015 private HbckErrorReporter errors; 3016 private FileSystem fs; 3017 3018 WorkItemHdfsDir(FileSystem fs, HbckErrorReporter errors, FileStatus status) { 3019 this.fs = fs; 3020 this.tableDir = status; 3021 this.errors = errors; 3022 } 3023 3024 @Override 3025 public synchronized Void call() throws InterruptedException, ExecutionException { 3026 final Vector<Exception> exceptions = new Vector<>(); 3027 3028 try { 3029 final FileStatus[] regionDirs = fs.listStatus(tableDir.getPath()); 3030 final List<Future<?>> futures = new ArrayList<>(regionDirs.length); 3031 3032 for (final FileStatus regionDir : regionDirs) { 3033 errors.progress(); 3034 final String encodedName = regionDir.getPath().getName(); 3035 // ignore directories that aren't hexadecimal 3036 if (!encodedName.toLowerCase(Locale.ROOT).matches("[0-9a-f]+")) { 3037 continue; 3038 } 3039 3040 if (!exceptions.isEmpty()) { 3041 break; 3042 } 3043 3044 futures.add(executor.submit(new Runnable() { 3045 @Override 3046 public void run() { 3047 try { 3048 LOG.debug("Loading region info from hdfs:" + regionDir.getPath()); 3049 3050 Path regioninfoFile = 3051 new Path(regionDir.getPath(), HRegionFileSystem.REGION_INFO_FILE); 3052 boolean regioninfoFileExists = fs.exists(regioninfoFile); 3053 3054 if (!regioninfoFileExists) { 3055 // As tables become larger it is more and more likely that by the time you 3056 // reach a given region that it will be gone due to region splits/merges. 3057 if (!fs.exists(regionDir.getPath())) { 3058 LOG.warn("By the time we tried to process this region dir it was already gone: " 3059 + regionDir.getPath()); 3060 return; 3061 } 3062 } 3063 3064 HbckRegionInfo hbi = HBaseFsck.this.getOrCreateInfo(encodedName); 3065 HbckRegionInfo.HdfsEntry he = new HbckRegionInfo.HdfsEntry(); 3066 synchronized (hbi) { 3067 if (hbi.getHdfsRegionDir() != null) { 3068 errors 3069 .print("Directory " + encodedName + " duplicate??" + hbi.getHdfsRegionDir()); 3070 } 3071 3072 he.regionDir = regionDir.getPath(); 3073 he.regionDirModTime = regionDir.getModificationTime(); 3074 he.hdfsRegioninfoFilePresent = regioninfoFileExists; 3075 // we add to orphan list when we attempt to read .regioninfo 3076 3077 // Set a flag if this region contains only edits 3078 // This is special case if a region is left after split 3079 he.hdfsOnlyEdits = true; 3080 FileStatus[] subDirs = fs.listStatus(regionDir.getPath()); 3081 Path ePath = WALSplitUtil.getRegionDirRecoveredEditsDir(regionDir.getPath()); 3082 for (FileStatus subDir : subDirs) { 3083 errors.progress(); 3084 String sdName = subDir.getPath().getName(); 3085 if (!sdName.startsWith(".") && !sdName.equals(ePath.getName())) { 3086 he.hdfsOnlyEdits = false; 3087 break; 3088 } 3089 } 3090 hbi.setHdfsEntry(he); 3091 } 3092 } catch (Exception e) { 3093 LOG.error("Could not load region dir", e); 3094 exceptions.add(e); 3095 } 3096 } 3097 })); 3098 } 3099 3100 // Ensure all pending tasks are complete (or that we run into an exception) 3101 for (Future<?> f : futures) { 3102 if (!exceptions.isEmpty()) { 3103 break; 3104 } 3105 try { 3106 f.get(); 3107 } catch (ExecutionException e) { 3108 LOG.error("Unexpected exec exception! Should've been caught already. (Bug?)", e); 3109 // Shouldn't happen, we already logged/caught any exceptions in the Runnable 3110 } 3111 } 3112 } catch (IOException e) { 3113 LOG.error("Cannot execute WorkItemHdfsDir for " + tableDir, e); 3114 exceptions.add(e); 3115 } finally { 3116 if (!exceptions.isEmpty()) { 3117 errors.reportError(ERROR_CODE.RS_CONNECT_FAILURE, "Table Directory: " 3118 + tableDir.getPath().getName() + " Unable to fetch all HDFS region information. "); 3119 // Just throw the first exception as an indication something bad happened 3120 // Don't need to propagate all the exceptions, we already logged them all anyway 3121 throw new ExecutionException("First exception in WorkItemHdfsDir", 3122 exceptions.firstElement()); 3123 } 3124 } 3125 return null; 3126 } 3127 } 3128 3129 /** 3130 * Contact hdfs and get all information about specified table directory into regioninfo list. 3131 */ 3132 static class WorkItemHdfsRegionInfo implements Callable<Void> { 3133 private HbckRegionInfo hbi; 3134 private HBaseFsck hbck; 3135 private HbckErrorReporter errors; 3136 3137 WorkItemHdfsRegionInfo(HbckRegionInfo hbi, HBaseFsck hbck, HbckErrorReporter errors) { 3138 this.hbi = hbi; 3139 this.hbck = hbck; 3140 this.errors = errors; 3141 } 3142 3143 @Override 3144 public synchronized Void call() throws IOException { 3145 // only load entries that haven't been loaded yet. 3146 if (hbi.getHdfsHRI() == null) { 3147 try { 3148 errors.progress(); 3149 hbi.loadHdfsRegioninfo(hbck.getConf()); 3150 } catch (IOException ioe) { 3151 String msg = "Orphan region in HDFS: Unable to load .regioninfo from table " 3152 + hbi.getTableName() + " in hdfs dir " + hbi.getHdfsRegionDir() 3153 + "! It may be an invalid format or version file. Treating as " 3154 + "an orphaned regiondir."; 3155 errors.reportError(ERROR_CODE.ORPHAN_HDFS_REGION, msg); 3156 try { 3157 hbck.debugLsr(hbi.getHdfsRegionDir()); 3158 } catch (IOException ioe2) { 3159 LOG.error("Unable to read directory " + hbi.getHdfsRegionDir(), ioe2); 3160 throw ioe2; 3161 } 3162 hbck.orphanHdfsDirs.add(hbi); 3163 throw ioe; 3164 } 3165 } 3166 return null; 3167 } 3168 } 3169 3170 /** 3171 * Display the full report from fsck. This displays all live and dead region servers, and all 3172 * known regions. 3173 */ 3174 public static void setDisplayFullReport() { 3175 details = true; 3176 } 3177 3178 public static boolean shouldDisplayFullReport() { 3179 return details; 3180 } 3181 3182 /** 3183 * Set exclusive mode. 3184 */ 3185 public static void setForceExclusive() { 3186 forceExclusive = true; 3187 } 3188 3189 /** 3190 * Only one instance of hbck can modify HBase at a time. 3191 */ 3192 public boolean isExclusive() { 3193 return fixAny || forceExclusive; 3194 } 3195 3196 /** 3197 * Set summary mode. Print only summary of the tables and status (OK or INCONSISTENT) 3198 */ 3199 static void setSummary() { 3200 summary = true; 3201 } 3202 3203 /** 3204 * Set hbase:meta check mode. Print only info about hbase:meta table deployment/state 3205 */ 3206 void setCheckMetaOnly() { 3207 checkMetaOnly = true; 3208 } 3209 3210 /** 3211 * Set region boundaries check mode. 3212 */ 3213 void setRegionBoundariesCheck() { 3214 checkRegionBoundaries = true; 3215 } 3216 3217 /** 3218 * Set replication fix mode. 3219 */ 3220 public void setFixReplication(boolean shouldFix) { 3221 fixReplication = shouldFix; 3222 fixAny |= shouldFix; 3223 } 3224 3225 public void setCleanReplicationBarrier(boolean shouldClean) { 3226 cleanReplicationBarrier = shouldClean; 3227 } 3228 3229 /** 3230 * Check if we should rerun fsck again. This checks if we've tried to fix something and we should 3231 * rerun fsck tool again. Display the full report from fsck. This displays all live and dead 3232 * region servers, and all known regions. 3233 */ 3234 void setShouldRerun() { 3235 rerun = true; 3236 } 3237 3238 public boolean shouldRerun() { 3239 return rerun; 3240 } 3241 3242 /** 3243 * Fix inconsistencies found by fsck. This should try to fix errors (if any) found by fsck 3244 * utility. 3245 */ 3246 public void setFixAssignments(boolean shouldFix) { 3247 fixAssignments = shouldFix; 3248 fixAny |= shouldFix; 3249 } 3250 3251 boolean shouldFixAssignments() { 3252 return fixAssignments; 3253 } 3254 3255 public void setFixMeta(boolean shouldFix) { 3256 fixMeta = shouldFix; 3257 fixAny |= shouldFix; 3258 } 3259 3260 boolean shouldFixMeta() { 3261 return fixMeta; 3262 } 3263 3264 public void setFixEmptyMetaCells(boolean shouldFix) { 3265 fixEmptyMetaCells = shouldFix; 3266 fixAny |= shouldFix; 3267 } 3268 3269 boolean shouldFixEmptyMetaCells() { 3270 return fixEmptyMetaCells; 3271 } 3272 3273 public void setCheckHdfs(boolean checking) { 3274 checkHdfs = checking; 3275 } 3276 3277 boolean shouldCheckHdfs() { 3278 return checkHdfs; 3279 } 3280 3281 public void setFixHdfsHoles(boolean shouldFix) { 3282 fixHdfsHoles = shouldFix; 3283 fixAny |= shouldFix; 3284 } 3285 3286 boolean shouldFixHdfsHoles() { 3287 return fixHdfsHoles; 3288 } 3289 3290 public void setFixTableOrphans(boolean shouldFix) { 3291 fixTableOrphans = shouldFix; 3292 fixAny |= shouldFix; 3293 } 3294 3295 boolean shouldFixTableOrphans() { 3296 return fixTableOrphans; 3297 } 3298 3299 public void setFixHdfsOverlaps(boolean shouldFix) { 3300 fixHdfsOverlaps = shouldFix; 3301 fixAny |= shouldFix; 3302 } 3303 3304 boolean shouldFixHdfsOverlaps() { 3305 return fixHdfsOverlaps; 3306 } 3307 3308 public void setFixHdfsOrphans(boolean shouldFix) { 3309 fixHdfsOrphans = shouldFix; 3310 fixAny |= shouldFix; 3311 } 3312 3313 boolean shouldFixHdfsOrphans() { 3314 return fixHdfsOrphans; 3315 } 3316 3317 public void setFixVersionFile(boolean shouldFix) { 3318 fixVersionFile = shouldFix; 3319 fixAny |= shouldFix; 3320 } 3321 3322 public boolean shouldFixVersionFile() { 3323 return fixVersionFile; 3324 } 3325 3326 public void setSidelineBigOverlaps(boolean sbo) { 3327 this.sidelineBigOverlaps = sbo; 3328 } 3329 3330 public boolean shouldSidelineBigOverlaps() { 3331 return sidelineBigOverlaps; 3332 } 3333 3334 public void setFixSplitParents(boolean shouldFix) { 3335 fixSplitParents = shouldFix; 3336 fixAny |= shouldFix; 3337 } 3338 3339 public void setRemoveParents(boolean shouldFix) { 3340 removeParents = shouldFix; 3341 fixAny |= shouldFix; 3342 } 3343 3344 boolean shouldFixSplitParents() { 3345 return fixSplitParents; 3346 } 3347 3348 boolean shouldRemoveParents() { 3349 return removeParents; 3350 } 3351 3352 public void setFixReferenceFiles(boolean shouldFix) { 3353 fixReferenceFiles = shouldFix; 3354 fixAny |= shouldFix; 3355 } 3356 3357 boolean shouldFixReferenceFiles() { 3358 return fixReferenceFiles; 3359 } 3360 3361 public void setFixHFileLinks(boolean shouldFix) { 3362 fixHFileLinks = shouldFix; 3363 fixAny |= shouldFix; 3364 } 3365 3366 boolean shouldFixHFileLinks() { 3367 return fixHFileLinks; 3368 } 3369 3370 public boolean shouldIgnorePreCheckPermission() { 3371 return !fixAny || ignorePreCheckPermission; 3372 } 3373 3374 public void setIgnorePreCheckPermission(boolean ignorePreCheckPermission) { 3375 this.ignorePreCheckPermission = ignorePreCheckPermission; 3376 } 3377 3378 /** 3379 * @param mm maximum number of regions to merge into a single region. 3380 */ 3381 public void setMaxMerge(int mm) { 3382 this.maxMerge = mm; 3383 } 3384 3385 public int getMaxMerge() { 3386 return maxMerge; 3387 } 3388 3389 public void setMaxOverlapsToSideline(int mo) { 3390 this.maxOverlapsToSideline = mo; 3391 } 3392 3393 public int getMaxOverlapsToSideline() { 3394 return maxOverlapsToSideline; 3395 } 3396 3397 /** 3398 * Only check/fix tables specified by the list, Empty list means all tables are included. 3399 */ 3400 boolean isTableIncluded(TableName table) { 3401 return (tablesIncluded.isEmpty()) || tablesIncluded.contains(table); 3402 } 3403 3404 public void includeTable(TableName table) { 3405 tablesIncluded.add(table); 3406 } 3407 3408 Set<TableName> getIncludedTables() { 3409 return new HashSet<>(tablesIncluded); 3410 } 3411 3412 /** 3413 * We are interested in only those tables that have not changed their state in hbase:meta during 3414 * the last few seconds specified by hbase.admin.fsck.timelag 3415 * @param seconds - the time in seconds 3416 */ 3417 public void setTimeLag(long seconds) { 3418 timelag = seconds * 1000; // convert to milliseconds 3419 } 3420 3421 /** 3422 * @param sidelineDir - HDFS path to sideline data 3423 */ 3424 public void setSidelineDir(String sidelineDir) { 3425 this.sidelineDir = new Path(sidelineDir); 3426 } 3427 3428 protected HFileCorruptionChecker createHFileCorruptionChecker(boolean sidelineCorruptHFiles) 3429 throws IOException { 3430 return new HFileCorruptionChecker(getConf(), executor, sidelineCorruptHFiles); 3431 } 3432 3433 public HFileCorruptionChecker getHFilecorruptionChecker() { 3434 return hfcc; 3435 } 3436 3437 public void setHFileCorruptionChecker(HFileCorruptionChecker hfcc) { 3438 this.hfcc = hfcc; 3439 } 3440 3441 public void setRetCode(int code) { 3442 this.retcode = code; 3443 } 3444 3445 public int getRetCode() { 3446 return retcode; 3447 } 3448 3449 protected HBaseFsck printUsageAndExit() { 3450 StringWriter sw = new StringWriter(2048); 3451 PrintWriter out = new PrintWriter(sw); 3452 out.println(""); 3453 out.println("-----------------------------------------------------------------------"); 3454 out.println("NOTE: As of HBase version 2.0, the hbck tool is significantly changed."); 3455 out.println("In general, all Read-Only options are supported and can be be used"); 3456 out.println("safely. Most -fix/ -repair options are NOT supported. Please see usage"); 3457 out.println("below for details on which options are not supported."); 3458 out.println("-----------------------------------------------------------------------"); 3459 out.println(""); 3460 out.println("Usage: fsck [opts] {only tables}"); 3461 out.println(" where [opts] are:"); 3462 out.println(" -help Display help options (this)"); 3463 out.println(" -details Display full report of all regions."); 3464 out.println(" -timelag <timeInSeconds> Process only regions that " 3465 + " have not experienced any metadata updates in the last " + " <timeInSeconds> seconds."); 3466 out.println(" -sleepBeforeRerun <timeInSeconds> Sleep this many seconds" 3467 + " before checking if the fix worked if run with -fix"); 3468 out.println(" -summary Print only summary of the tables and status."); 3469 out.println(" -metaonly Only check the state of the hbase:meta table."); 3470 out.println(" -sidelineDir <hdfs://> HDFS path to backup existing meta."); 3471 out.println( 3472 " -boundaries Verify that regions boundaries are the same between META and store files."); 3473 out.println(" -exclusive Abort if another hbck is exclusive or fixing."); 3474 3475 out.println(""); 3476 out.println(" Datafile Repair options: (expert features, use with caution!)"); 3477 out.println( 3478 " -checkCorruptHFiles Check all Hfiles by opening them to make sure they are valid"); 3479 out.println( 3480 " -sidelineCorruptHFiles Quarantine corrupted HFiles. implies -checkCorruptHFiles"); 3481 3482 out.println(""); 3483 out.println(" Replication options"); 3484 out.println(" -fixReplication Deletes replication queues for removed peers"); 3485 3486 out.println(""); 3487 out.println( 3488 " Metadata Repair options supported as of version 2.0: (expert features, use with caution!)"); 3489 out.println(" -fixVersionFile Try to fix missing hbase.version file in hdfs."); 3490 out.println(" -fixReferenceFiles Try to offline lingering reference store files"); 3491 out.println(" -fixHFileLinks Try to offline lingering HFileLinks"); 3492 out.println(" -noHdfsChecking Don't load/check region info from HDFS." 3493 + " Assumes hbase:meta region info is good. Won't check/fix any HDFS issue, e.g. hole, orphan, or overlap"); 3494 out.println(" -ignorePreCheckPermission ignore filesystem permission pre-check"); 3495 3496 out.println(""); 3497 out.println("NOTE: Following options are NOT supported as of HBase version 2.0+."); 3498 out.println(""); 3499 out.println(" UNSUPPORTED Metadata Repair options: (expert features, use with caution!)"); 3500 out.println( 3501 " -fix Try to fix region assignments. This is for backwards compatibility"); 3502 out.println(" -fixAssignments Try to fix region assignments. Replaces the old -fix"); 3503 out.println( 3504 " -fixMeta Try to fix meta problems. This assumes HDFS region info is good."); 3505 out.println(" -fixHdfsHoles Try to fix region holes in hdfs."); 3506 out.println(" -fixHdfsOrphans Try to fix region dirs with no .regioninfo file in hdfs"); 3507 out.println( 3508 " -fixTableOrphans Try to fix table dirs with no .tableinfo file in hdfs (online mode only)"); 3509 out.println(" -fixHdfsOverlaps Try to fix region overlaps in hdfs."); 3510 out.println( 3511 " -maxMerge <n> When fixing region overlaps, allow at most <n> regions to merge. (n=" 3512 + DEFAULT_MAX_MERGE + " by default)"); 3513 out.println( 3514 " -sidelineBigOverlaps When fixing region overlaps, allow to sideline big overlaps"); 3515 out.println( 3516 " -maxOverlapsToSideline <n> When fixing region overlaps, allow at most <n> regions to sideline per group. (n=" 3517 + DEFAULT_OVERLAPS_TO_SIDELINE + " by default)"); 3518 out.println(" -fixSplitParents Try to force offline split parents to be online."); 3519 out.println( 3520 " -removeParents Try to offline and sideline lingering parents and keep daughter regions."); 3521 out.println(" -fixEmptyMetaCells Try to fix hbase:meta entries not referencing any region" 3522 + " (empty REGIONINFO_QUALIFIER rows)"); 3523 3524 out.println(""); 3525 out.println(" UNSUPPORTED Metadata Repair shortcuts"); 3526 out.println(" -repair Shortcut for -fixAssignments -fixMeta -fixHdfsHoles " 3527 + "-fixHdfsOrphans -fixHdfsOverlaps -fixVersionFile -sidelineBigOverlaps -fixReferenceFiles" 3528 + "-fixHFileLinks"); 3529 out.println(" -repairHoles Shortcut for -fixAssignments -fixMeta -fixHdfsHoles"); 3530 out.println(""); 3531 out.println(" Replication options"); 3532 out.println(" -fixReplication Deletes replication queues for removed peers"); 3533 out.println(" -cleanReplicationBarrier [tableName] clean the replication barriers " 3534 + "of a specified table, tableName is required"); 3535 out.flush(); 3536 errors.reportError(ERROR_CODE.WRONG_USAGE, sw.toString()); 3537 3538 setRetCode(-2); 3539 return this; 3540 } 3541 3542 /** 3543 * Main program 3544 */ 3545 public static void main(String[] args) throws Exception { 3546 // create a fsck object 3547 Configuration conf = HBaseConfiguration.create(); 3548 Path hbasedir = CommonFSUtils.getRootDir(conf); 3549 URI defaultFs = hbasedir.getFileSystem(conf).getUri(); 3550 CommonFSUtils.setFsDefault(conf, new Path(defaultFs)); 3551 int ret = ToolRunner.run(new HBaseFsckTool(conf), args); 3552 System.exit(ret); 3553 } 3554 3555 /** 3556 * This is a Tool wrapper that gathers -Dxxx=yyy configuration settings from the command line. 3557 */ 3558 static class HBaseFsckTool extends Configured implements Tool { 3559 HBaseFsckTool(Configuration conf) { 3560 super(conf); 3561 } 3562 3563 @Override 3564 public int run(String[] args) throws Exception { 3565 HBaseFsck hbck = new HBaseFsck(getConf()); 3566 hbck.exec(hbck.executor, args); 3567 hbck.close(); 3568 return hbck.getRetCode(); 3569 } 3570 } 3571 3572 public HBaseFsck exec(ExecutorService exec, String[] args) 3573 throws KeeperException, IOException, InterruptedException, ReplicationException { 3574 long sleepBeforeRerun = DEFAULT_SLEEP_BEFORE_RERUN; 3575 3576 boolean checkCorruptHFiles = false; 3577 boolean sidelineCorruptHFiles = false; 3578 3579 // Process command-line args. 3580 for (int i = 0; i < args.length; i++) { 3581 String cmd = args[i]; 3582 if (cmd.equals("-help") || cmd.equals("-h")) { 3583 return printUsageAndExit(); 3584 } else if (cmd.equals("-details")) { 3585 setDisplayFullReport(); 3586 } else if (cmd.equals("-exclusive")) { 3587 setForceExclusive(); 3588 } else if (cmd.equals("-timelag")) { 3589 if (i == args.length - 1) { 3590 errors.reportError(ERROR_CODE.WRONG_USAGE, "HBaseFsck: -timelag needs a value."); 3591 return printUsageAndExit(); 3592 } 3593 try { 3594 long timelag = Long.parseLong(args[++i]); 3595 setTimeLag(timelag); 3596 } catch (NumberFormatException e) { 3597 errors.reportError(ERROR_CODE.WRONG_USAGE, "-timelag needs a numeric value."); 3598 return printUsageAndExit(); 3599 } 3600 } else if (cmd.equals("-sleepBeforeRerun")) { 3601 if (i == args.length - 1) { 3602 errors.reportError(ERROR_CODE.WRONG_USAGE, "HBaseFsck: -sleepBeforeRerun needs a value."); 3603 return printUsageAndExit(); 3604 } 3605 try { 3606 sleepBeforeRerun = Long.parseLong(args[++i]); 3607 } catch (NumberFormatException e) { 3608 errors.reportError(ERROR_CODE.WRONG_USAGE, "-sleepBeforeRerun needs a numeric value."); 3609 return printUsageAndExit(); 3610 } 3611 } else if (cmd.equals("-sidelineDir")) { 3612 if (i == args.length - 1) { 3613 errors.reportError(ERROR_CODE.WRONG_USAGE, "HBaseFsck: -sidelineDir needs a value."); 3614 return printUsageAndExit(); 3615 } 3616 setSidelineDir(args[++i]); 3617 } else if (cmd.equals("-fix")) { 3618 errors.reportError(ERROR_CODE.WRONG_USAGE, 3619 "This option is deprecated, please use -fixAssignments instead."); 3620 setFixAssignments(true); 3621 } else if (cmd.equals("-fixAssignments")) { 3622 setFixAssignments(true); 3623 } else if (cmd.equals("-fixMeta")) { 3624 setFixMeta(true); 3625 } else if (cmd.equals("-noHdfsChecking")) { 3626 setCheckHdfs(false); 3627 } else if (cmd.equals("-fixHdfsHoles")) { 3628 setFixHdfsHoles(true); 3629 } else if (cmd.equals("-fixHdfsOrphans")) { 3630 setFixHdfsOrphans(true); 3631 } else if (cmd.equals("-fixTableOrphans")) { 3632 setFixTableOrphans(true); 3633 } else if (cmd.equals("-fixHdfsOverlaps")) { 3634 setFixHdfsOverlaps(true); 3635 } else if (cmd.equals("-fixVersionFile")) { 3636 setFixVersionFile(true); 3637 } else if (cmd.equals("-sidelineBigOverlaps")) { 3638 setSidelineBigOverlaps(true); 3639 } else if (cmd.equals("-fixSplitParents")) { 3640 setFixSplitParents(true); 3641 } else if (cmd.equals("-removeParents")) { 3642 setRemoveParents(true); 3643 } else if (cmd.equals("-ignorePreCheckPermission")) { 3644 setIgnorePreCheckPermission(true); 3645 } else if (cmd.equals("-checkCorruptHFiles")) { 3646 checkCorruptHFiles = true; 3647 } else if (cmd.equals("-sidelineCorruptHFiles")) { 3648 sidelineCorruptHFiles = true; 3649 } else if (cmd.equals("-fixReferenceFiles")) { 3650 setFixReferenceFiles(true); 3651 } else if (cmd.equals("-fixHFileLinks")) { 3652 setFixHFileLinks(true); 3653 } else if (cmd.equals("-fixEmptyMetaCells")) { 3654 setFixEmptyMetaCells(true); 3655 } else if (cmd.equals("-repair")) { 3656 // this attempts to merge overlapping hdfs regions, needs testing 3657 // under load 3658 setFixHdfsHoles(true); 3659 setFixHdfsOrphans(true); 3660 setFixMeta(true); 3661 setFixAssignments(true); 3662 setFixHdfsOverlaps(true); 3663 setFixVersionFile(true); 3664 setSidelineBigOverlaps(true); 3665 setFixSplitParents(false); 3666 setCheckHdfs(true); 3667 setFixReferenceFiles(true); 3668 setFixHFileLinks(true); 3669 } else if (cmd.equals("-repairHoles")) { 3670 // this will make all missing hdfs regions available but may lose data 3671 setFixHdfsHoles(true); 3672 setFixHdfsOrphans(false); 3673 setFixMeta(true); 3674 setFixAssignments(true); 3675 setFixHdfsOverlaps(false); 3676 setSidelineBigOverlaps(false); 3677 setFixSplitParents(false); 3678 setCheckHdfs(true); 3679 } else if (cmd.equals("-maxOverlapsToSideline")) { 3680 if (i == args.length - 1) { 3681 errors.reportError(ERROR_CODE.WRONG_USAGE, 3682 "-maxOverlapsToSideline needs a numeric value argument."); 3683 return printUsageAndExit(); 3684 } 3685 try { 3686 int maxOverlapsToSideline = Integer.parseInt(args[++i]); 3687 setMaxOverlapsToSideline(maxOverlapsToSideline); 3688 } catch (NumberFormatException e) { 3689 errors.reportError(ERROR_CODE.WRONG_USAGE, 3690 "-maxOverlapsToSideline needs a numeric value argument."); 3691 return printUsageAndExit(); 3692 } 3693 } else if (cmd.equals("-maxMerge")) { 3694 if (i == args.length - 1) { 3695 errors.reportError(ERROR_CODE.WRONG_USAGE, "-maxMerge needs a numeric value argument."); 3696 return printUsageAndExit(); 3697 } 3698 try { 3699 int maxMerge = Integer.parseInt(args[++i]); 3700 setMaxMerge(maxMerge); 3701 } catch (NumberFormatException e) { 3702 errors.reportError(ERROR_CODE.WRONG_USAGE, "-maxMerge needs a numeric value argument."); 3703 return printUsageAndExit(); 3704 } 3705 } else if (cmd.equals("-summary")) { 3706 setSummary(); 3707 } else if (cmd.equals("-metaonly")) { 3708 setCheckMetaOnly(); 3709 } else if (cmd.equals("-boundaries")) { 3710 setRegionBoundariesCheck(); 3711 } else if (cmd.equals("-fixReplication")) { 3712 setFixReplication(true); 3713 } else if (cmd.equals("-cleanReplicationBarrier")) { 3714 setCleanReplicationBarrier(true); 3715 if (args[++i].startsWith("-")) { 3716 printUsageAndExit(); 3717 } 3718 setCleanReplicationBarrierTable(args[i]); 3719 } else if (cmd.startsWith("-")) { 3720 errors.reportError(ERROR_CODE.WRONG_USAGE, "Unrecognized option:" + cmd); 3721 return printUsageAndExit(); 3722 } else { 3723 includeTable(TableName.valueOf(cmd)); 3724 errors.print("Allow checking/fixes for table: " + cmd); 3725 } 3726 } 3727 3728 errors.print("HBaseFsck command line options: " + StringUtils.join(args, " ")); 3729 3730 // pre-check current user has FS write permission or not 3731 try { 3732 preCheckPermission(); 3733 } catch (IOException ioe) { 3734 Runtime.getRuntime().exit(-1); 3735 } 3736 3737 // do the real work of hbck 3738 connect(); 3739 3740 // after connecting to server above, we have server version 3741 // check if unsupported option is specified based on server version 3742 if (!isOptionsSupported(args)) { 3743 return printUsageAndExit(); 3744 } 3745 3746 try { 3747 // if corrupt file mode is on, first fix them since they may be opened later 3748 if (checkCorruptHFiles || sidelineCorruptHFiles) { 3749 LOG.info("Checking all hfiles for corruption"); 3750 HFileCorruptionChecker hfcc = createHFileCorruptionChecker(sidelineCorruptHFiles); 3751 setHFileCorruptionChecker(hfcc); // so we can get result 3752 Collection<TableName> tables = getIncludedTables(); 3753 Collection<Path> tableDirs = new ArrayList<>(); 3754 Path rootdir = CommonFSUtils.getRootDir(getConf()); 3755 if (tables.size() > 0) { 3756 for (TableName t : tables) { 3757 tableDirs.add(CommonFSUtils.getTableDir(rootdir, t)); 3758 } 3759 } else { 3760 tableDirs = FSUtils.getTableDirs(CommonFSUtils.getCurrentFileSystem(getConf()), rootdir); 3761 } 3762 hfcc.checkTables(tableDirs); 3763 hfcc.report(errors); 3764 } 3765 3766 // check and fix table integrity, region consistency. 3767 int code = onlineHbck(); 3768 setRetCode(code); 3769 // If we have changed the HBase state it is better to run hbck again 3770 // to see if we haven't broken something else in the process. 3771 // We run it only once more because otherwise we can easily fall into 3772 // an infinite loop. 3773 if (shouldRerun()) { 3774 try { 3775 LOG.info("Sleeping " + sleepBeforeRerun + "ms before re-checking after fix..."); 3776 Thread.sleep(sleepBeforeRerun); 3777 } catch (InterruptedException ie) { 3778 LOG.warn("Interrupted while sleeping"); 3779 return this; 3780 } 3781 // Just report 3782 setFixAssignments(false); 3783 setFixMeta(false); 3784 setFixHdfsHoles(false); 3785 setFixHdfsOverlaps(false); 3786 setFixVersionFile(false); 3787 setFixTableOrphans(false); 3788 errors.resetErrors(); 3789 code = onlineHbck(); 3790 setRetCode(code); 3791 } 3792 } finally { 3793 IOUtils.closeQuietly(this, e -> LOG.warn("", e)); 3794 } 3795 return this; 3796 } 3797 3798 private boolean isOptionsSupported(String[] args) { 3799 boolean result = true; 3800 String hbaseServerVersion = status.getHBaseVersion(); 3801 if (VersionInfo.compareVersion("2.any.any", hbaseServerVersion) < 0) { 3802 // Process command-line args. 3803 for (String arg : args) { 3804 if (unsupportedOptionsInV2.contains(arg)) { 3805 errors.reportError(ERROR_CODE.UNSUPPORTED_OPTION, 3806 "option '" + arg + "' is not " + "supported!"); 3807 result = false; 3808 break; 3809 } 3810 } 3811 } 3812 return result; 3813 } 3814 3815 public void setCleanReplicationBarrierTable(String cleanReplicationBarrierTable) { 3816 this.cleanReplicationBarrierTable = TableName.valueOf(cleanReplicationBarrierTable); 3817 } 3818 3819 public void cleanReplicationBarrier() throws IOException { 3820 if (!cleanReplicationBarrier || cleanReplicationBarrierTable == null) { 3821 return; 3822 } 3823 if (cleanReplicationBarrierTable.isSystemTable()) { 3824 errors.reportError(ERROR_CODE.INVALID_TABLE, 3825 "invalid table: " + cleanReplicationBarrierTable); 3826 return; 3827 } 3828 3829 boolean isGlobalScope = false; 3830 try { 3831 isGlobalScope = admin.getDescriptor(cleanReplicationBarrierTable).hasGlobalReplicationScope(); 3832 } catch (TableNotFoundException e) { 3833 LOG.info("we may need to clean some erroneous data due to bugs"); 3834 } 3835 3836 if (isGlobalScope) { 3837 errors.reportError(ERROR_CODE.INVALID_TABLE, 3838 "table's replication scope is global: " + cleanReplicationBarrierTable); 3839 return; 3840 } 3841 List<byte[]> regionNames = new ArrayList<>(); 3842 Scan barrierScan = new Scan(); 3843 barrierScan.setCaching(100); 3844 barrierScan.addFamily(HConstants.REPLICATION_BARRIER_FAMILY); 3845 barrierScan 3846 .withStartRow(ClientMetaTableAccessor.getTableStartRowForMeta(cleanReplicationBarrierTable, 3847 ClientMetaTableAccessor.QueryType.REGION)) 3848 .withStopRow(ClientMetaTableAccessor.getTableStopRowForMeta(cleanReplicationBarrierTable, 3849 ClientMetaTableAccessor.QueryType.REGION)); 3850 Result result; 3851 try (ResultScanner scanner = meta.getScanner(barrierScan)) { 3852 while ((result = scanner.next()) != null) { 3853 regionNames.add(result.getRow()); 3854 } 3855 } 3856 if (regionNames.size() <= 0) { 3857 errors.reportError(ERROR_CODE.INVALID_TABLE, 3858 "there is no barriers of this table: " + cleanReplicationBarrierTable); 3859 return; 3860 } 3861 ReplicationQueueStorage queueStorage = 3862 ReplicationStorageFactory.getReplicationQueueStorage(connection, getConf()); 3863 List<ReplicationPeerDescription> peerDescriptions = admin.listReplicationPeers(); 3864 if (peerDescriptions != null && peerDescriptions.size() > 0) { 3865 List<String> peers = peerDescriptions.stream() 3866 .filter( 3867 peerConfig -> peerConfig.getPeerConfig().needToReplicate(cleanReplicationBarrierTable)) 3868 .map(peerConfig -> peerConfig.getPeerId()).collect(Collectors.toList()); 3869 try { 3870 List<String> batch = new ArrayList<>(); 3871 for (String peer : peers) { 3872 for (byte[] regionName : regionNames) { 3873 batch.add(RegionInfo.encodeRegionName(regionName)); 3874 if (batch.size() % 100 == 0) { 3875 queueStorage.removeLastSequenceIds(peer, batch); 3876 batch.clear(); 3877 } 3878 } 3879 if (batch.size() > 0) { 3880 queueStorage.removeLastSequenceIds(peer, batch); 3881 batch.clear(); 3882 } 3883 } 3884 } catch (ReplicationException re) { 3885 throw new IOException(re); 3886 } 3887 } 3888 for (byte[] regionName : regionNames) { 3889 meta.delete(new Delete(regionName).addFamily(HConstants.REPLICATION_BARRIER_FAMILY)); 3890 } 3891 setShouldRerun(); 3892 } 3893 3894 /** 3895 * ls -r for debugging purposes 3896 */ 3897 void debugLsr(Path p) throws IOException { 3898 debugLsr(getConf(), p, errors); 3899 } 3900 3901 /** 3902 * ls -r for debugging purposes 3903 */ 3904 public static void debugLsr(Configuration conf, Path p) throws IOException { 3905 debugLsr(conf, p, new PrintingErrorReporter()); 3906 } 3907 3908 /** 3909 * ls -r for debugging purposes 3910 */ 3911 public static void debugLsr(Configuration conf, Path p, HbckErrorReporter errors) 3912 throws IOException { 3913 if (!LOG.isDebugEnabled() || p == null) { 3914 return; 3915 } 3916 FileSystem fs = p.getFileSystem(conf); 3917 3918 if (!fs.exists(p)) { 3919 // nothing 3920 return; 3921 } 3922 errors.print(p.toString()); 3923 3924 if (fs.isFile(p)) { 3925 return; 3926 } 3927 3928 if (fs.getFileStatus(p).isDirectory()) { 3929 FileStatus[] fss = fs.listStatus(p); 3930 for (FileStatus status : fss) { 3931 debugLsr(conf, status.getPath(), errors); 3932 } 3933 } 3934 } 3935}