You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by an...@apache.org on 2013/12/23 07:45:38 UTC

svn commit: r1553075 - /hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java

Author: anoopsamjohn
Date: Mon Dec 23 06:45:37 2013
New Revision: 1553075

URL: http://svn.apache.org/r1553075
Log:
HBASE-9346 HBCK should provide an option to check if regions boundaries are the same in META and in stores. (Jean Marc)

Modified:
    hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java

Modified: hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java?rev=1553075&r1=1553074&r2=1553075&view=diff
==============================================================================
--- hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java (original)
+++ hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java Mon Dec 23 06:45:37 2013
@@ -93,8 +93,8 @@ import org.apache.hadoop.hbase.regionser
 import org.apache.hadoop.hbase.regionserver.HRegionFileSystem;
 import org.apache.hadoop.hbase.regionserver.StoreFileInfo;
 import org.apache.hadoop.hbase.regionserver.wal.HLogUtil;
-import org.apache.hadoop.hbase.security.User;
 import org.apache.hadoop.hbase.security.UserProvider;
+import org.apache.hadoop.hbase.util.Bytes.ByteArrayComparator;
 import org.apache.hadoop.hbase.util.HBaseFsck.ErrorReporter.ERROR_CODE;
 import org.apache.hadoop.hbase.util.hbck.HFileCorruptionChecker;
 import org.apache.hadoop.hbase.util.hbck.TableIntegrityErrorHandler;
@@ -215,6 +215,7 @@ public class HBaseFsck extends Configure
   private boolean rerun = false; // if we tried to fix something, rerun hbck
   private static boolean summary = false; // if we want to print less output
   private boolean checkMetaOnly = false;
+  private boolean checkRegionBoundaries = false;
   private boolean ignorePreCheckPermission = false; // if pre-check permission
 
   /*********
@@ -479,6 +480,10 @@ public class HBaseFsck extends Configure
       admin.setBalancerRunning(oldBalancer, false);
     }
 
+    if (checkRegionBoundaries) {
+      checkRegionBoundaries();
+    }
+
     offlineReferenceFileRepair();
 
     checkAndFixTableLocks();
@@ -488,6 +493,112 @@ public class HBaseFsck extends Configure
     return errors.summarize();
   }
 
+  public static byte[] keyOnly (byte[] b) {
+    if (b == null)
+      return b;
+    int rowlength = Bytes.toShort(b, 0);
+    byte[] result = new byte[rowlength];
+    System.arraycopy(b, Bytes.SIZEOF_SHORT, result, 0, rowlength);
+    return result;
+  }
+
+  private static class RegionBoundariesInformation {
+    public byte [] regionName;
+    public byte [] metaFirstKey;
+    public byte [] metaLastKey;
+    public byte [] storesFirstKey;
+    public byte [] storesLastKey;
+    public String toString () {
+      return "regionName=" + Bytes.toStringBinary(regionName) +
+             "\nmetaFirstKey=" + Bytes.toStringBinary(metaFirstKey) +
+             "\nmetaLastKey=" + Bytes.toStringBinary(metaLastKey) +
+             "\nstoresFirstKey=" + Bytes.toStringBinary(storesFirstKey) +
+             "\nstoresLastKey=" + Bytes.toStringBinary(storesLastKey);
+    }
+  }
+
+  public void checkRegionBoundaries() {
+    try {
+      ByteArrayComparator comparator = new ByteArrayComparator();
+      List<HRegionInfo> regions = MetaScanner.listAllRegions(getConf(), false);
+      final RegionBoundariesInformation currentRegionBoundariesInformation =
+          new RegionBoundariesInformation();
+      for (HRegionInfo regionInfo : regions) {
+        currentRegionBoundariesInformation.regionName = regionInfo.getRegionName();
+        // For each region, get the start and stop key from the META and compare them to the
+        // same information from the Stores.
+        Path path = new Path(getConf().get(HConstants.HBASE_DIR) + "/"
+            + Bytes.toString(regionInfo.getTable().getName()) + "/"
+            + regionInfo.getEncodedName() + "/");
+        FileSystem fs = path.getFileSystem(getConf());
+        FileStatus[] files = fs.listStatus(path);
+        // For all the column families in this region...
+        byte[] storeFirstKey = null;
+        byte[] storeLastKey = null;
+        for (FileStatus file : files) {
+          String fileName = file.getPath().toString();
+          fileName = fileName.substring(fileName.lastIndexOf("/") + 1);
+          if (!fileName.startsWith(".") && !fileName.endsWith("recovered.edits")) {
+            FileStatus[] storeFiles = fs.listStatus(file.getPath());
+            // For all the stores in this column family.
+            for (FileStatus storeFile : storeFiles) {
+              HFile.Reader reader = HFile.createReader(fs, storeFile.getPath(), new CacheConfig(
+                  getConf()), getConf());
+              if ((reader.getFirstKey() != null)
+                  && ((storeFirstKey == null) || (comparator.compare(storeFirstKey,
+                      reader.getFirstKey()) > 0))) {
+                storeFirstKey = reader.getFirstKey();
+              }
+              if ((reader.getLastKey() != null)
+                  && ((storeLastKey == null) || (comparator.compare(storeLastKey,
+                      reader.getLastKey())) < 0)) {
+                storeLastKey = reader.getLastKey();
+              }
+              reader.close();
+            }
+          }
+        }
+        currentRegionBoundariesInformation.metaFirstKey = regionInfo.getStartKey();
+        currentRegionBoundariesInformation.metaLastKey = regionInfo.getEndKey();
+        currentRegionBoundariesInformation.storesFirstKey = keyOnly(storeFirstKey);
+        currentRegionBoundariesInformation.storesLastKey = keyOnly(storeLastKey);
+        if (currentRegionBoundariesInformation.metaFirstKey.length == 0)
+          currentRegionBoundariesInformation.metaFirstKey = null;
+        if (currentRegionBoundariesInformation.metaLastKey.length == 0)
+          currentRegionBoundariesInformation.metaLastKey = null;
+
+        // For a region to be correct, we need the META start key to be smaller or equal to the
+        // smallest start key from all the stores, and the start key from the next META entry to
+        // be bigger than the last key from all the current stores. First region start key is null;
+        // Last region end key is null; some regions can be empty and not have any store.
+
+        boolean valid = true;
+        // Checking start key.
+        if ((currentRegionBoundariesInformation.storesFirstKey != null)
+            && (currentRegionBoundariesInformation.metaFirstKey != null)) {
+          valid = valid
+              && comparator.compare(currentRegionBoundariesInformation.storesFirstKey,
+                currentRegionBoundariesInformation.metaFirstKey) >= 0;
+        }
+        // Checking stop key.
+        if ((currentRegionBoundariesInformation.storesLastKey != null)
+            && (currentRegionBoundariesInformation.metaLastKey != null)) {
+          valid = valid
+              && comparator.compare(currentRegionBoundariesInformation.storesLastKey,
+                currentRegionBoundariesInformation.metaLastKey) < 0;
+        }
+        if (!valid) {
+          errors.reportError(ERROR_CODE.BOUNDARIES_ERROR, "Found issues with regions boundaries",
+            tablesInfo.get(regionInfo.getTable()));
+          LOG.warn("Region's boundaries not alligned between stores and META for:");
+          LOG.warn(currentRegionBoundariesInformation);
+        }
+      }
+    } catch (IOException e) {
+      LOG.error(e);
+    }
+  }
+
   /**
    * Iterates through the list of all orphan/invalid regiondirs.
    */
@@ -2992,7 +3103,7 @@ public class HBaseFsck extends Configure
       FIRST_REGION_STARTKEY_NOT_EMPTY, LAST_REGION_ENDKEY_NOT_EMPTY, DUPE_STARTKEYS,
       HOLE_IN_REGION_CHAIN, OVERLAP_IN_REGION_CHAIN, REGION_CYCLE, DEGENERATE_REGION,
       ORPHAN_HDFS_REGION, LINGERING_SPLIT_PARENT, NO_TABLEINFO_FILE, LINGERING_REFERENCE_HFILE,
-      WRONG_USAGE, EMPTY_META_CELL, EXPIRED_TABLE_LOCK
+      WRONG_USAGE, EMPTY_META_CELL, EXPIRED_TABLE_LOCK, BOUNDARIES_ERROR
     }
     void clear();
     void report(String message);
@@ -3344,6 +3455,13 @@ public class HBaseFsck extends Configure
   }
 
   /**
+   * Set region boundaries check mode.
+   */
+  void setRegionBoundariesCheck() {
+    checkRegionBoundaries = true;
+  }
+
+  /**
    * Set table locks fix mode.
    * Delete table locks held for a long time
    */
@@ -3560,6 +3678,7 @@ public class HBaseFsck extends Configure
     out.println("   -summary Print only summary of the tables and status.");
     out.println("   -metaonly Only check the state of the hbase:meta table.");
     out.println("   -sidelineDir <hdfs://> HDFS path to backup existing meta.");
+    out.println("   -boundaries Verify that regions boundaries are the same between META and store files.");
 
     out.println("");
     out.println("  Metadata Repair options: (expert features, use with caution!)");
@@ -3774,6 +3893,8 @@ public class HBaseFsck extends Configure
         setSummary();
       } else if (cmd.equals("-metaonly")) {
         setCheckMetaOnly();
+      } else if (cmd.equals("-boundaries")) {
+        setRegionBoundariesCheck();
       } else if (cmd.equals("-fixTableLocks")) {
         setFixTableLocks(true);
       } else if (cmd.startsWith("-")) {