From 9438e2ccdff7776e8597e173813be49d57298838 Mon Sep 17 00:00:00 2001 From: Umesh Agashe Date: Wed, 4 Apr 2018 15:00:06 -0700 Subject: [PATCH] HBASE-18792 Disabled destructive (mostly write) operations in hbck for HBase 2.0+ HBase server versioned is checked after connecting to the server and then following operations are not allowed: -fix, -fixAssignments, -fixMeta, -fixHdfsHoles, -fixHdfsOrphans, -fixTableOrphans, -fixHdfsOverlaps, -maxMerge -sidelineBigOverlaps, -maxOverlapsToSideline, -fixSplitParents, -removeParents, -fixEmptyMetaCells -repair, -repairHoles --- .../org/apache/hadoop/hbase/util/VersionInfo.java | 52 ++++++++++++++-------- .../org/apache/hadoop/hbase/util/HBaseFsck.java | 43 +++++++++++++++++- 2 files changed, 74 insertions(+), 21 deletions(-) diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/VersionInfo.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/VersionInfo.java index ae5b40377922178ca41038929d6b97190e5db967..ca95d3e1f326528ee88fb3bb0ebaa45aca609943 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/VersionInfo.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/VersionInfo.java @@ -1,4 +1,4 @@ -/** +/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information @@ -37,7 +37,7 @@ public class VersionInfo { // If between two dots there is not a number, we regard it as a very large number so it is // higher than any numbers in the version. - private static int VERY_LARGE_NUMBER = 100000; + private static final int VERY_LARGE_NUMBER = 100000; /** * Get the hbase version. @@ -120,39 +120,53 @@ public class VersionInfo { return 0; } - String s1[] = v1.split("\\.|-");//1.2.3-hotfix -> [1, 2, 3, hotfix] - String s2[] = v2.split("\\.|-"); + Object[] v1Comps = getVersionComponents(v1); //1.2.3-hotfix -> [1, 2, 3, hotfix] + Object[] v2Comps = getVersionComponents(v2); int index = 0; - while (index < s1.length && index < s2.length) { - int va = VERY_LARGE_NUMBER, vb = VERY_LARGE_NUMBER; - try { - va = Integer.parseInt(s1[index]); - } catch (Exception ingore) { - } - try { - vb = Integer.parseInt(s2[index]); - } catch (Exception ingore) { - } + while (index < v1Comps.length && index < v2Comps.length) { + int va = v1Comps[index] instanceof Integer ? (Integer)v1Comps[index] : VERY_LARGE_NUMBER; + int vb = v2Comps[index] instanceof Integer ? (Integer)v2Comps[index] : VERY_LARGE_NUMBER; + if (va != vb) { return va - vb; } if (va == VERY_LARGE_NUMBER) { - // compare as String - int c = s1[index].compareTo(s2[index]); + // here, va and vb components must be same and Strings, compare as String + int c = ((String)v1Comps[index]).compareTo((String)v2Comps[index]); if (c != 0) { return c; } } index++; } - if (index < s1.length) { - // s1 is longer + if (index < v1Comps.length) { + // v1 is longer return 1; } - //s2 is longer + //v2 is longer return -1; } + /** + * Returns the version components as Integer and String objects + * Examples: "1.2.3" returns [1, 2, 3], "4.5.6-SNAPSHOT" returns [4, 5, 6, "SNAPSHOT"] + * @return the components of the version string + */ + static Object[] getVersionComponents(final String version) { + assert(version != null); + Object[] strComps = version.split("[\\.-]"); + assert(strComps.length > 0); + + Object[] comps = new Object[strComps.length]; + for (int i = 0; i < strComps.length; ++i) { + try { + comps[i] = Integer.parseInt((String) strComps[i]); + } catch (NumberFormatException e) { + comps[i] = strComps[i]; + } + } + return comps; + } public static void main(String[] args) { writeTo(System.out); diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java index d0fa17da7d02b7724629c5576cb3f4259113f8f8..e2f6a964d33a6fafe26c7fc08f4d9a4b4ab64e44 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java @@ -1,4 +1,4 @@ -/** +/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information @@ -139,6 +139,7 @@ import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.util.ReflectionUtils; import org.apache.hadoop.util.Tool; import org.apache.hadoop.util.ToolRunner; +import com.google.common.collect.Sets; import org.apache.zookeeper.KeeperException; import com.google.common.base.Joiner; @@ -238,6 +239,12 @@ public class HBaseFsck extends Configured implements Closeable { // successful private final AtomicBoolean hbckLockCleanup = new AtomicBoolean(false); + // Unsupported options in HBase 2.0+ + private static final Set unsupportedOptionsInV2 = Sets.newHashSet("-fix", + "-fixAssignments", "-fixMeta", "-fixHdfsHoles", "-fixHdfsOrphans", "-fixTableOrphans", + "-fixHdfsOverlaps", "-sidelineBigOverlaps", "-fixSplitParents", "-removeParents", + "-fixEmptyMetaCells", "-repair", "-repairHoles", "-maxOverlapsToSideline", "-maxMerge"); + /*********** * Options ***********/ @@ -4113,7 +4120,8 @@ public class HBaseFsck extends Configured implements Closeable { HOLE_IN_REGION_CHAIN, OVERLAP_IN_REGION_CHAIN, REGION_CYCLE, DEGENERATE_REGION, ORPHAN_HDFS_REGION, LINGERING_SPLIT_PARENT, NO_TABLEINFO_FILE, LINGERING_REFERENCE_HFILE, LINGERING_HFILELINK, WRONG_USAGE, EMPTY_META_CELL, EXPIRED_TABLE_LOCK, - ORPHANED_ZK_TABLE_ENTRY, BOUNDARIES_ERROR, UNDELETED_REPLICATION_QUEUE, DUPE_ENDKEYS + ORPHANED_ZK_TABLE_ENTRY, BOUNDARIES_ERROR, UNDELETED_REPLICATION_QUEUE, DUPE_ENDKEYS, + UNSUPPORTED_OPTION } void clear(); void report(String message); @@ -4855,6 +4863,12 @@ public class HBaseFsck extends Configured implements Closeable { out.println(" Replication options"); out.println(" -fixReplication Deletes replication queues for removed peers"); + out.println(""); + out.println("NOTE: As of HBase Server version 2.0, following options are not supported:"); + out.println("-fix, -fixAssignments, -fixMeta, -fixHdfsHoles, -fixHdfsOrphans, " + + "-fixTableOrphans, -fixHdfsOverlaps, -maxMerge, -sidelineBigOverlaps,"); + out.println("-maxOverlapsToSideline, -fixSplitParents, -removeParents, -fixEmptyMetaCells, " + + "-repair, -repairHoles"); out.flush(); errors.reportError(ERROR_CODE.WRONG_USAGE, sw.toString()); @@ -5071,6 +5085,12 @@ public class HBaseFsck extends Configured implements Closeable { // do the real work of hbck connect(); + // after connecting to server above, we have server version + // check if unsupported option is specified based on server version + if (!isOptionsSupported(args)) { + return printUsageAndExit(); + } + try { // if corrupt file mode is on, first fix them since they may be opened later if (checkCorruptHFiles || sidelineCorruptHFiles) { @@ -5123,6 +5143,25 @@ public class HBaseFsck extends Configured implements Closeable { return this; } + private boolean isOptionsSupported(String[] args) { + boolean result = true; + String hbaseServerVersion = status.getHBaseVersion(); + Object[] versionComponents = VersionInfo.getVersionComponents(hbaseServerVersion); + if (versionComponents[0] instanceof Integer && ((Integer)versionComponents[0]) >= 2) { + // Process command-line args. + for (String arg : args) { + if (unsupportedOptionsInV2.contains(arg)) { + errors.reportError(ERROR_CODE.UNSUPPORTED_OPTION, + "Server version is " + hbaseServerVersion + ". Option '" + arg + + "' is not supportted!"); + result = false; + break; + } + } + } + return result; + } + /** * ls -r for debugging purposes */ -- 2.16.1