hbase-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From st...@apache.org
Subject svn commit: r1171640 - in /hbase/trunk: CHANGES.txt src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java src/test/java/org/apache/hadoop/hbase/util/TestHBaseFsck.java
Date Fri, 16 Sep 2011 16:10:18 GMT
Author: stack
Date: Fri Sep 16 16:10:17 2011
New Revision: 1171640

URL: http://svn.apache.org/viewvc?rev=1171640&view=rev
Log:
HBASE-4322 [hbck] Update checkIntegrity/checkRegionChain to present more accurate region split
problem 

Modified:
    hbase/trunk/CHANGES.txt
    hbase/trunk/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java
    hbase/trunk/src/test/java/org/apache/hadoop/hbase/util/TestHBaseFsck.java

Modified: hbase/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/hbase/trunk/CHANGES.txt?rev=1171640&r1=1171639&r2=1171640&view=diff
==============================================================================
--- hbase/trunk/CHANGES.txt (original)
+++ hbase/trunk/CHANGES.txt Fri Sep 16 16:10:17 2011
@@ -272,6 +272,9 @@ Release 0.91.0 - Unreleased
                shouldn't join
    HBASE-4395  EnableTableHandler races with itself
    HBASE-4414  Region splits by size not being triggered
+   HBASE-4322  HBASE-4322 [hbck] Update checkIntegrity/checkRegionChain
+               to present more accurate region split problem 
+               (Jon Hseih)
 
   IMPROVEMENTS
    HBASE-3290  Max Compaction Size (Nicolas Spiegelberg via Stack)  

Modified: hbase/trunk/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java
URL: http://svn.apache.org/viewvc/hbase/trunk/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java?rev=1171640&r1=1171639&r2=1171640&view=diff
==============================================================================
--- hbase/trunk/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java (original)
+++ hbase/trunk/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java Fri Sep 16 16:10:17
2011
@@ -20,11 +20,20 @@
 package org.apache.hadoop.hbase.util;
 
 import java.io.IOException;
-import java.util.*;
-import java.util.concurrent.atomic.AtomicInteger;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -55,14 +64,14 @@ import org.apache.hadoop.hbase.client.Re
 import org.apache.hadoop.hbase.ipc.HRegionInterface;
 import org.apache.hadoop.hbase.regionserver.wal.HLog;
 import org.apache.hadoop.hbase.zookeeper.RootRegionTracker;
+import org.apache.hadoop.hbase.util.HBaseFsck.ErrorReporter.ERROR_CODE;
 import org.apache.hadoop.hbase.zookeeper.ZKTable;
 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
 import org.apache.zookeeper.KeeperException;
 
 import com.google.common.base.Joiner;
 import com.google.common.collect.Lists;
-
-import static org.apache.hadoop.hbase.util.HBaseFsck.ErrorReporter.ERROR_CODE;
+import com.google.common.collect.Multimap;
 
 /**
  * Check consistency among the in-memory states of the master and the
@@ -544,7 +553,6 @@ public class HBaseFsck {
         modTInfo.addServer(server);
       }
 
-      //modTInfo.addEdge(hbi.metaEntry.getStartKey(), hbi.metaEntry.getEndKey());
       modTInfo.addRegionInfo(hbi);
 
       tablesInfo.put(tableName, modTInfo);
@@ -563,15 +571,36 @@ public class HBaseFsck {
   private class TInfo {
     String tableName;
     TreeSet <ServerName> deployedOn;
-    List<HbckInfo> regions = new ArrayList<HbckInfo>();
+
+    List<HbckInfo> backwards = new ArrayList<HbckInfo>();
+    RegionSplitCalculator<HbckInfo> sc = new RegionSplitCalculator<HbckInfo>(cmp);
 
     TInfo(String name) {
       this.tableName = name;
       deployedOn = new TreeSet <ServerName>();
     }
 
-    public void addRegionInfo (HbckInfo r) {
-      regions.add(r);
+    public void addRegionInfo(HbckInfo hir) {
+      if (Bytes.equals(hir.getEndKey(), HConstants.EMPTY_END_ROW)) {
+        // end key is absolute end key, just add it.
+        sc.add(hir);
+        return;
+      }
+
+      // if not the absolute end key, check for cycle 
+      if (Bytes.compareTo(hir.getStartKey(), hir.getEndKey()) > 0) {
+        errors.reportError(
+            ERROR_CODE.REGION_CYCLE,
+            String.format("The endkey for this region comes before the "
+                + "startkey, startkey=%s, endkey=%s",
+                Bytes.toStringBinary(hir.getStartKey()),
+                Bytes.toStringBinary(hir.getEndKey())), this, hir);
+        backwards.add(hir);
+        return;
+      }
+
+      // main case, add to split calculator
+      sc.add(hir);
     }
 
     public void addServer(ServerName server) {
@@ -583,7 +612,7 @@ public class HBaseFsck {
     }
 
     public int getNumRegions() {
-      return regions.size();
+      return sc.getStarts().size();
     }
 
     /**
@@ -592,66 +621,59 @@ public class HBaseFsck {
      * @return false if there are errors
      */
     public boolean checkRegionChain() {
-      Collections.sort(regions);
-      HbckInfo last = null;
+      
       int originalErrorsCount = errors.getErrorList().size();
+      Multimap<byte[], HbckInfo> regions = sc.calcCoverage();
+      SortedSet<byte[]> splits = sc.getSplits();
 
-      for (HbckInfo r : regions) {
-        if (last == null) {
-          // This is the first region, check that the start key is empty
-          if (! Bytes.equals(r.metaEntry.getStartKey(), HConstants.EMPTY_BYTE_ARRAY)) {
+      byte[] prevKey = null;
+      for (byte[] key: splits) {
+        Collection<HbckInfo> ranges = regions.get(key);
+        if (prevKey == null && !Bytes.equals(key, HConstants.EMPTY_BYTE_ARRAY)) {
+          for (HbckInfo rng : ranges) {
             errors.reportError(ERROR_CODE.FIRST_REGION_STARTKEY_NOT_EMPTY,
                 "First region should start with an empty key.",
-                this, r);
+                this, rng);
           }
-        } else {
-
-          // Check if endKey < startKey
-          // Previous implementation of this code checked for a cycle in the
-          // region chain.  A cycle would imply that the endKey comes before
-          // the startKey (i.e. endKey < startKey).
-          if (! Bytes.equals(r.metaEntry.getEndKey(), HConstants.EMPTY_BYTE_ARRAY)) {
-            // continue with this check if this is not the last region
-            int cmpRegionKeys = Bytes.compareTo(r.metaEntry.getStartKey(),
-                r.metaEntry.getEndKey());
-            if (cmpRegionKeys > 0) {
-              errors.reportError(ERROR_CODE.REGION_CYCLE,
-                  String.format("The endkey for this region comes before the "
-                      + "startkey, startkey=%s, endkey=%s",
-                      Bytes.toStringBinary(r.metaEntry.getStartKey()),
-                      Bytes.toStringBinary(r.metaEntry.getEndKey())),
-                  this, r, last);
-            }
-          }
-
-          // Check if the startkeys are different
-          if (Bytes.equals(r.metaEntry.getStartKey(), last.metaEntry.getStartKey())) {
+        }
+        
+        // Check if the startkeys are different
+        if (ranges.size() > 1) {
+          ArrayList<HbckInfo> subRange = new ArrayList<HbckInfo>(ranges);
+          // this dumb and n^2 but this shouldn't happen often
+          for (HbckInfo r1 : ranges) {
+            subRange.remove(r1);
+            for (HbckInfo r2 : subRange) {
+              if (Bytes.compareTo(r1.getStartKey(), r2.getStartKey())==0) {
+            // dup start key
+            errors.reportError(ERROR_CODE.DUPE_STARTKEYS,
+              "Multiple regions have the same startkey: "
+                  + Bytes.toStringBinary(key), this, r1);
             errors.reportError(ERROR_CODE.DUPE_STARTKEYS,
-                "Two regions have the same startkey: "
-                    + Bytes.toStringBinary(r.metaEntry.getStartKey()),
-                this, r, last);
-          } else {
-            // Check that the startkey is the same as the previous end key
-            int cmp = Bytes.compareTo(r.metaEntry.getStartKey(),
-                last.metaEntry.getEndKey());
-            if (cmp > 0) {
-              // hole
-              errors.reportError(ERROR_CODE.HOLE_IN_REGION_CHAIN,
-                  "There is a hole in the region chain.",
-                  this, r, last);
-            } else if (cmp < 0) {
-              // overlap
-              errors.reportError(ERROR_CODE.OVERLAP_IN_REGION_CHAIN,
-                  "There is an overlap in the region chain.",
-                  this, r, last);
+                "Multiple regions have the same startkey: "
+                    + Bytes.toStringBinary(key), this, r2);
+              } else {
+            // overlap
+            errors.reportError(ERROR_CODE.OVERLAP_IN_REGION_CHAIN,
+                "There is an overlap in the region chain.",
+                this, r1);
+              }
             }
           }
-
         }
-
-        last = r;
+        
+        if (ranges.size() == 0) {
+          byte[] holeStopKey = sc.getSplits().higher(key);
+          // if higher key is null we reached the top.
+          if (holeStopKey != null) {
+            // hole
+            errors.reportError(ERROR_CODE.HOLE_IN_REGION_CHAIN,
+                "There is a hole in the region chain between "
+                + Bytes.toString(key) + " and " + Bytes.toString(holeStopKey));
+          }
+        }
+        prevKey = key;
       }
-
       return errors.getErrorList().size() == originalErrorsCount;
     }
 
@@ -833,7 +855,7 @@ public class HBaseFsck {
   /**
    * Stores the entries scanned from META
    */
-  private static class MetaEntry extends HRegionInfo {
+  static class MetaEntry extends HRegionInfo {
     ServerName regionServer;   // server hosting this region
     long modTime;          // timestamp of most recent modification metadata
 
@@ -847,7 +869,7 @@ public class HBaseFsck {
   /**
    * Maintain information about a particular region.
    */
-  static class HbckInfo implements Comparable {
+  static class HbckInfo implements KeyRange {
     boolean onlyEdits = false;
     MetaEntry metaEntry = null;
     FileStatus foundRegionDir = null;
@@ -872,16 +894,53 @@ public class HBaseFsck {
     }
 
     @Override
-    public int compareTo(Object o) {
-      HbckInfo other = (HbckInfo) o;
-      int startComparison = Bytes.compareTo(this.metaEntry.getStartKey(), other.metaEntry.getStartKey());
-      if (startComparison != 0)
-        return startComparison;
-      else
-        return Bytes.compareTo(this.metaEntry.getEndKey(), other.metaEntry.getEndKey());
+    public byte[] getStartKey() {
+      return this.metaEntry.getStartKey();
+    }
+
+    @Override
+    public byte[] getEndKey() {
+      return this.metaEntry.getEndKey();
     }
   }
 
+  final static Comparator<HbckInfo> cmp = new Comparator<HbckInfo>() {
+    @Override
+    public int compare(HbckInfo l, HbckInfo r) {
+      if (l == r) {
+        // same instance
+        return 0;
+      }
+
+      int tableCompare = RegionSplitCalculator.BYTES_COMPARATOR.compare(
+          l.metaEntry.getTableName(), r.metaEntry.getTableName());
+      if (tableCompare != 0) {
+        return tableCompare;
+      }
+
+      int startComparison = RegionSplitCalculator.BYTES_COMPARATOR.compare(
+          l.metaEntry.getStartKey(), r.metaEntry.getStartKey());
+      if (startComparison != 0) {
+        return startComparison;
+      }
+
+      // Special case for absolute endkey
+      byte[] endKey = r.metaEntry.getEndKey();
+      endKey = (endKey.length == 0) ? null : endKey;
+      byte[] endKey2 = l.metaEntry.getEndKey();
+      endKey2 = (endKey2.length == 0) ? null : endKey2;
+      int endComparison = RegionSplitCalculator.BYTES_COMPARATOR.compare(
+          endKey2,  endKey);
+
+      if (endComparison != 0) {
+        return endComparison;
+      }
+
+      // use modTime as tiebreaker.
+      return (int) (l.metaEntry.modTime - r.metaEntry.modTime);
+    }
+  };
+
   /**
    * Prints summary of all tables found on the system.
    */
@@ -1102,7 +1161,7 @@ public class HBaseFsck {
   }
 
   /**
-   * Contact hdfs and get all information about spcified table directory.
+   * Contact hdfs and get all information about specified table directory.
    */
   static class WorkItemHdfsDir implements Runnable {
     private HBaseFsck hbck;
@@ -1324,4 +1383,3 @@ public class HBaseFsck {
     Runtime.getRuntime().exit(code);
   }
 }
-

Modified: hbase/trunk/src/test/java/org/apache/hadoop/hbase/util/TestHBaseFsck.java
URL: http://svn.apache.org/viewvc/hbase/trunk/src/test/java/org/apache/hadoop/hbase/util/TestHBaseFsck.java?rev=1171640&r1=1171639&r2=1171640&view=diff
==============================================================================
--- hbase/trunk/src/test/java/org/apache/hadoop/hbase/util/TestHBaseFsck.java (original)
+++ hbase/trunk/src/test/java/org/apache/hadoop/hbase/util/TestHBaseFsck.java Fri Sep 16 16:10:17
2011
@@ -24,16 +24,23 @@ import static org.junit.Assert.assertEqu
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.hbase.HBaseTestingUtility;
 import org.apache.hadoop.hbase.HColumnDescriptor;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.HRegionInfo;
+import org.apache.hadoop.hbase.HServerAddress;
 import org.apache.hadoop.hbase.HTableDescriptor;
+
 import org.apache.hadoop.hbase.ServerName;
+import org.apache.hadoop.hbase.client.Delete;
 import org.apache.hadoop.hbase.client.HBaseAdmin;
 import org.apache.hadoop.hbase.client.HTable;
 import org.apache.hadoop.hbase.client.Put;
@@ -146,6 +153,49 @@ public class TestHBaseFsck {
     return hri;
   }
 
+  public void dumpMeta(HTableDescriptor htd) throws IOException {
+    List<byte[]> metaRows = TEST_UTIL.getMetaTableRows(htd.getName());
+    for (byte[] row : metaRows) {
+      LOG.info(Bytes.toString(row));
+    }
+  }
+
+  private void deleteRegion(Configuration conf, final HTableDescriptor htd, 
+      byte[] startKey, byte[] endKey) throws IOException {
+
+    LOG.info("Before delete:");
+    dumpMeta(htd);
+
+    Map<HRegionInfo, HServerAddress> hris = tbl.getRegionsInfo();
+    for (Entry<HRegionInfo, HServerAddress> e: hris.entrySet()) {
+      HRegionInfo hri = e.getKey();
+      HServerAddress hsa = e.getValue();
+      if (Bytes.compareTo(hri.getStartKey(), startKey) == 0 
+          && Bytes.compareTo(hri.getEndKey(), endKey) == 0) {
+
+        LOG.info("RegionName: " +hri.getRegionNameAsString());
+        byte[] deleteRow = hri.getRegionName();
+        TEST_UTIL.getHBaseAdmin().unassign(deleteRow, true);
+
+        LOG.info("deleting hdfs data: " + hri.toString() + hsa.toString());
+        Path rootDir = new Path(conf.get(HConstants.HBASE_DIR));
+        FileSystem fs = rootDir.getFileSystem(conf);
+        Path p = new Path(rootDir + "/" + htd.getNameAsString(), hri.getEncodedName());
+        fs.delete(p, true);
+
+        HTable meta = new HTable(conf, HConstants.META_TABLE_NAME);
+        Delete delete = new Delete(deleteRow);
+        meta.delete(delete);
+      }
+      LOG.info(hri.toString() + hsa.toString());
+    }
+
+    TEST_UTIL.getMetaTableRows(htd.getName());
+    LOG.info("After delete:");
+    dumpMeta(htd);
+
+  }
+
   /**
    * Setup a clean table before we start mucking with it.
    * 
@@ -213,7 +263,8 @@ public class TestHBaseFsck {
           .waitForAssignment(hriDupe);
 
       assertErrors(doFsck(false),
-          new ERROR_CODE[] { ERROR_CODE.DUPE_STARTKEYS });
+          new ERROR_CODE[] { ERROR_CODE.DUPE_STARTKEYS,
+            ERROR_CODE.DUPE_STARTKEYS});
     } finally {
       deleteTable(table);
     }
@@ -253,10 +304,14 @@ public class TestHBaseFsck {
 
       // Mess it up by leaving a hole in the meta data
       HRegionInfo hriHole = createRegion(conf, tbl.getTableDescriptor(),
-          Bytes.toBytes("D"), Bytes.toBytes("E"));
+          Bytes.toBytes("D"), Bytes.toBytes(""));
       TEST_UTIL.getHBaseCluster().getMaster().assignRegion(hriHole);
       TEST_UTIL.getHBaseCluster().getMaster().getAssignmentManager()
           .waitForAssignment(hriHole);
+
+      TEST_UTIL.getHBaseAdmin().disableTable(table);
+      deleteRegion(conf, tbl.getTableDescriptor(), Bytes.toBytes("C"), Bytes.toBytes(""));
+      TEST_UTIL.getHBaseAdmin().enableTable(table);
       assertErrors(doFsck(false),
           new ERROR_CODE[] { ERROR_CODE.HOLE_IN_REGION_CHAIN });
     } finally {



Mime
View raw message