From 5af9852397c203a4c0e18434d4f438b577025086 Mon Sep 17 00:00:00 2001 From: Michael Stack Date: Fri, 21 Aug 2020 09:25:24 -0700 Subject: [PATCH] HBASE-24918 Make RegionInfo#UNDEFINED IA.Private (#2289) Mark RegionInfo#UNDEFINED IA.Private and deprecated; it is for internal use only and likely to be removed in hbase4. Move MutableRegionInfo out of RegionInfoBuilder and have it as a stanadlone task; a nice-to-have. Signed-off-by: Viraj Jasani Signed-off-by: Bharath Vissapragada Signed-off-by: Duo Zhang --- .../hbase/client/MutableRegionInfo.java | 336 ++++++++++++++++++ .../hadoop/hbase/client/RegionInfo.java | 13 +- .../hbase/client/RegionInfoBuilder.java | 313 ---------------- 3 files changed, 344 insertions(+), 318 deletions(-) create mode 100644 hbase-client/src/main/java/org/apache/hadoop/hbase/client/MutableRegionInfo.java diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MutableRegionInfo.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MutableRegionInfo.java new file mode 100644 index 00000000000..5d48991cf20 --- /dev/null +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MutableRegionInfo.java @@ -0,0 +1,336 @@ +/* + * 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 + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase.client; +import java.util.Arrays; +import org.apache.hadoop.hbase.HConstants; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.util.Bytes; +import org.apache.yetus.audience.InterfaceAudience; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * An implementation of RegionInfo that adds mutable methods so can build a RegionInfo instance. + * Package private. Use {@link RegionInfoBuilder} creating instances of {@link RegionInfo}s. + */ +@InterfaceAudience.Private +class MutableRegionInfo implements RegionInfo { + private static final Logger LOG = LoggerFactory.getLogger(MutableRegionInfo.class); + private static final int MAX_REPLICA_ID = 0xFFFF; + + /** + * The new format for a region name contains its encodedName at the end. + * The encoded name also serves as the directory name for the region + * in the filesystem. + * + * New region name format: + * <tablename>,,<startkey>,<regionIdTimestamp>.<encodedName>. + * where, + * <encodedName> is a hex version of the MD5 hash of + * <tablename>,<startkey>,<regionIdTimestamp> + * + * The old region name format: + * <tablename>,<startkey>,<regionIdTimestamp> + * For region names in the old format, the encoded name is a 32-bit + * JenkinsHash integer value (in its decimal notation, string form). + *

+ * **NOTE** + * + * The first hbase:meta region, and regions created by an older + * version of HBase (0.20 or prior) will continue to use the + * old region name format. + */ + + // This flag is in the parent of a split while the parent is still referenced by daughter + // regions. We USED to set this flag when we disabled a table but now table state is kept up in + // zookeeper as of 0.90.0 HBase. And now in DisableTableProcedure, finally we will create bunch + // of UnassignProcedures and at the last of the procedure we will set the region state to + // CLOSED, and will not change the offLine flag. + private boolean offLine; + private boolean split; + private final long regionId; + private final int replicaId; + private final byte[] regionName; + private final byte[] startKey; + private final byte[] endKey; + private final int hashCode; + private final String encodedName; + private final byte[] encodedNameAsBytes; + private final TableName tableName; + + private static int generateHashCode(final TableName tableName, final byte[] startKey, + final byte[] endKey, final long regionId, + final int replicaId, boolean offLine, byte[] regionName) { + int result = Arrays.hashCode(regionName); + result = (int) (result ^ regionId); + result ^= Arrays.hashCode(checkStartKey(startKey)); + result ^= Arrays.hashCode(checkEndKey(endKey)); + result ^= Boolean.valueOf(offLine).hashCode(); + result ^= Arrays.hashCode(tableName.getName()); + result ^= replicaId; + return result; + } + + private static byte[] checkStartKey(byte[] startKey) { + return startKey == null? HConstants.EMPTY_START_ROW: startKey; + } + + private static byte[] checkEndKey(byte[] endKey) { + return endKey == null? HConstants.EMPTY_END_ROW: endKey; + } + + private static TableName checkTableName(TableName tableName) { + if (tableName == null) { + throw new IllegalArgumentException("TableName cannot be null"); + } + return tableName; + } + + private static int checkReplicaId(int regionId) { + if (regionId > MAX_REPLICA_ID) { + throw new IllegalArgumentException("ReplicaId cannot be greater than" + MAX_REPLICA_ID); + } + return regionId; + } + + /** + * Package private constructor used constructing MutableRegionInfo for the first meta regions + */ + MutableRegionInfo(long regionId, TableName tableName, int replicaId) { + this(tableName, HConstants.EMPTY_START_ROW, HConstants.EMPTY_END_ROW, false, regionId, + replicaId, false); + } + + MutableRegionInfo(final TableName tableName, final byte[] startKey, final byte[] endKey, + final boolean split, final long regionId, final int replicaId, boolean offLine) { + this.tableName = checkTableName(tableName); + this.startKey = checkStartKey(startKey); + this.endKey = checkEndKey(endKey); + this.split = split; + this.regionId = regionId; + this.replicaId = checkReplicaId(replicaId); + this.offLine = offLine; + this.regionName = RegionInfo.createRegionName(this.tableName, this.startKey, this.regionId, + this.replicaId, !this.tableName.equals(TableName.META_TABLE_NAME)); + this.encodedName = RegionInfo.encodeRegionName(this.regionName); + this.hashCode = generateHashCode(this.tableName, this.startKey, this.endKey, this.regionId, + this.replicaId, this.offLine, this.regionName); + this.encodedNameAsBytes = Bytes.toBytes(this.encodedName); + } + + /** + * @return Return a short, printable name for this region (usually encoded name) for us logging. + */ + @Override + public String getShortNameToLog() { + return RegionInfo.prettyPrint(this.getEncodedName()); + } + + /** @return the regionId */ + @Override + public long getRegionId(){ + return regionId; + } + + + /** + * @return the regionName as an array of bytes. + * @see #getRegionNameAsString() + */ + @Override + public byte[] getRegionName() { + return regionName; + } + + /** + * @return Region name as a String for use in logging, etc. + */ + @Override + public String getRegionNameAsString() { + return RegionInfo.getRegionNameAsString(this, this.regionName); + } + + /** @return the encoded region name */ + @Override + public String getEncodedName() { + return this.encodedName; + } + + @Override + public byte[] getEncodedNameAsBytes() { + return this.encodedNameAsBytes; + } + + /** @return the startKey */ + @Override + public byte[] getStartKey() { + return startKey; + } + + /** @return the endKey */ + @Override + public byte[] getEndKey() { + return endKey; + } + + /** + * Get current table name of the region + * @return TableName + */ + @Override + public TableName getTable() { + return this.tableName; + } + + /** + * Returns true if the given inclusive range of rows is fully contained + * by this region. For example, if the region is foo,a,g and this is + * passed ["b","c"] or ["a","c"] it will return true, but if this is passed + * ["b","z"] it will return false. + * @throws IllegalArgumentException if the range passed is invalid (ie. end < start) + */ + @Override + public boolean containsRange(byte[] rangeStartKey, byte[] rangeEndKey) { + if (Bytes.compareTo(rangeStartKey, rangeEndKey) > 0) { + throw new IllegalArgumentException( + "Invalid range: " + Bytes.toStringBinary(rangeStartKey) + + " > " + Bytes.toStringBinary(rangeEndKey)); + } + + boolean firstKeyInRange = Bytes.compareTo(rangeStartKey, startKey) >= 0; + boolean lastKeyInRange = + Bytes.compareTo(rangeEndKey, endKey) < 0 || + Bytes.equals(endKey, HConstants.EMPTY_BYTE_ARRAY); + return firstKeyInRange && lastKeyInRange; + } + + /** + * Return true if the given row falls in this region. + */ + @Override + public boolean containsRow(byte[] row) { + return Bytes.compareTo(row, startKey) >= 0 && + (Bytes.compareTo(row, endKey) < 0 || + Bytes.equals(endKey, HConstants.EMPTY_BYTE_ARRAY)); + } + + /** @return true if this region is a meta region */ + @Override + public boolean isMetaRegion() { + return tableName.equals(TableName.META_TABLE_NAME); + } + + /** + * @return True if has been split and has daughters. + */ + @Override + public boolean isSplit() { + return this.split; + } + + /** + * @param split set split status + * @return MutableRegionInfo + */ + public MutableRegionInfo setSplit(boolean split) { + this.split = split; + return this; + } + + /** + * @return True if this region is offline. + */ + @Override + public boolean isOffline() { + return this.offLine; + } + + /** + * The parent of a region split is offline while split daughters hold + * references to the parent. Offlined regions are closed. + * @param offLine Set online/offline status. + * @return MutableRegionInfo + */ + public MutableRegionInfo setOffline(boolean offLine) { + this.offLine = offLine; + return this; + } + + /** + * @return True if this is a split parent region. + */ + @Override + public boolean isSplitParent() { + if (!isSplit()) { + return false; + } + if (!isOffline()) { + LOG.warn("Region is split but NOT offline: " + getRegionNameAsString()); + } + return true; + } + + /** + * Returns the region replica id + * @return returns region replica id + */ + @Override + public int getReplicaId() { + return replicaId; + } + + /** + * @see Object#toString() + */ + @Override + public String toString() { + return "{ENCODED => " + getEncodedName() + ", " + + HConstants.NAME + " => '" + Bytes.toStringBinary(this.regionName) + + "', STARTKEY => '" + + Bytes.toStringBinary(this.startKey) + "', ENDKEY => '" + + Bytes.toStringBinary(this.endKey) + "'" + + (isOffline()? ", OFFLINE => true": "") + + (isSplit()? ", SPLIT => true": "") + + ((replicaId > 0)? ", REPLICA_ID => " + replicaId : "") + "}"; + } + + /** + * @see Object#equals(Object) + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null) { + return false; + } + if (!(o instanceof RegionInfo)) { + return false; + } + return compareTo((RegionInfo)o) == 0; + } + + /** + * @see Object#hashCode() + */ + @Override + public int hashCode() { + return this.hashCode; + } +} diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RegionInfo.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RegionInfo.java index dbda4a53cb8..7a3a9af227f 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RegionInfo.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RegionInfo.java @@ -19,7 +19,6 @@ package org.apache.hadoop.hbase.client; import edu.umd.cs.findbugs.annotations.CheckForNull; - import java.io.DataInputStream; import java.io.IOException; import java.util.ArrayList; @@ -27,7 +26,6 @@ import java.util.Arrays; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; - import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.exceptions.DeserializationException; @@ -38,7 +36,6 @@ import org.apache.hadoop.hbase.util.JenkinsHash; import org.apache.hadoop.hbase.util.MD5Hash; import org.apache.hadoop.io.DataInputBuffer; import org.apache.yetus.audience.InterfaceAudience; - import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos; @@ -69,7 +66,13 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos; */ @InterfaceAudience.Public public interface RegionInfo extends Comparable { + /** + * @deprecated since 2.3.2/3.0.0; to be removed in 4.0.0 with no replacement (for internal use). + */ + @Deprecated + @InterfaceAudience.Private RegionInfo UNDEFINED = RegionInfoBuilder.newBuilder(TableName.valueOf("__UNDEFINED__")).build(); + /** * Separator used to demarcate the encodedName in a region name * in the new format. See description on new format above. @@ -585,8 +588,8 @@ public interface RegionInfo extends Comparable { * @return the MOB {@link RegionInfo}. */ static RegionInfo createMobRegionInfo(TableName tableName) { - return RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes(".mob")).setRegionId(0).build(); + return RegionInfoBuilder.newBuilder(tableName).setStartKey(Bytes.toBytes(".mob")). + setRegionId(0).build(); } /** diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RegionInfoBuilder.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RegionInfoBuilder.java index 34221f39cd1..8f045e0588e 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RegionInfoBuilder.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RegionInfoBuilder.java @@ -17,10 +17,8 @@ */ package org.apache.hadoop.hbase.client; -import java.util.Arrays; import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.TableName; -import org.apache.hadoop.hbase.util.Bytes; import org.apache.yetus.audience.InterfaceAudience; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,8 +30,6 @@ public class RegionInfoBuilder { /** A non-capture group so that this can be embedded. */ public static final String ENCODED_REGION_NAME_REGEX = "(?:[a-f0-9]+)"; - private static final int MAX_REPLICA_ID = 0xFFFF; - //TODO: Move NO_HASH to HStoreFile which is really the only place it is used. public static final String NO_HASH = null; @@ -114,313 +110,4 @@ public class RegionInfoBuilder { regionId, replicaId, offLine); } - /** - * An implementation of RegionInfo that adds mutable methods so can build a RegionInfo instance. - */ - @InterfaceAudience.Private - static class MutableRegionInfo implements RegionInfo { - /** - * The new format for a region name contains its encodedName at the end. - * The encoded name also serves as the directory name for the region - * in the filesystem. - * - * New region name format: - * <tablename>,,<startkey>,<regionIdTimestamp>.<encodedName>. - * where, - * <encodedName> is a hex version of the MD5 hash of - * <tablename>,<startkey>,<regionIdTimestamp> - * - * The old region name format: - * <tablename>,<startkey>,<regionIdTimestamp> - * For region names in the old format, the encoded name is a 32-bit - * JenkinsHash integer value (in its decimal notation, string form). - *

- * **NOTE** - * - * The first hbase:meta region, and regions created by an older - * version of HBase (0.20 or prior) will continue to use the - * old region name format. - */ - - // This flag is in the parent of a split while the parent is still referenced by daughter - // regions. We USED to set this flag when we disabled a table but now table state is kept up in - // zookeeper as of 0.90.0 HBase. And now in DisableTableProcedure, finally we will create bunch - // of UnassignProcedures and at the last of the procedure we will set the region state to - // CLOSED, and will not change the offLine flag. - private boolean offLine = false; - private boolean split = false; - private final long regionId; - private final int replicaId; - private final byte[] regionName; - private final byte[] startKey; - private final byte[] endKey; - private final int hashCode; - private final String encodedName; - private final byte[] encodedNameAsBytes; - private final TableName tableName; - - private static int generateHashCode(final TableName tableName, final byte[] startKey, - final byte[] endKey, final long regionId, - final int replicaId, boolean offLine, byte[] regionName) { - int result = Arrays.hashCode(regionName); - result = (int) (result ^ regionId); - result ^= Arrays.hashCode(checkStartKey(startKey)); - result ^= Arrays.hashCode(checkEndKey(endKey)); - result ^= Boolean.valueOf(offLine).hashCode(); - result ^= Arrays.hashCode(tableName.getName()); - result ^= replicaId; - return result; - } - - private static byte[] checkStartKey(byte[] startKey) { - return startKey == null? HConstants.EMPTY_START_ROW: startKey; - } - - private static byte[] checkEndKey(byte[] endKey) { - return endKey == null? HConstants.EMPTY_END_ROW: endKey; - } - - private static TableName checkTableName(TableName tableName) { - if (tableName == null) { - throw new IllegalArgumentException("TableName cannot be null"); - } - return tableName; - } - - private static int checkReplicaId(int regionId) { - if (regionId > MAX_REPLICA_ID) { - throw new IllegalArgumentException("ReplicaId cannot be greater than" + MAX_REPLICA_ID); - } - return regionId; - } - - /** - * Private constructor used constructing MutableRegionInfo for the - * first meta regions - */ - private MutableRegionInfo(long regionId, TableName tableName, int replicaId) { - this(tableName, HConstants.EMPTY_START_ROW, HConstants.EMPTY_END_ROW, false, regionId, - replicaId, false); - } - - MutableRegionInfo(final TableName tableName, final byte[] startKey, final byte[] endKey, - final boolean split, final long regionId, final int replicaId, boolean offLine) { - this.tableName = checkTableName(tableName); - this.startKey = checkStartKey(startKey); - this.endKey = checkEndKey(endKey); - this.split = split; - this.regionId = regionId; - this.replicaId = checkReplicaId(replicaId); - this.offLine = offLine; - this.regionName = RegionInfo.createRegionName(this.tableName, this.startKey, this.regionId, - this.replicaId, !this.tableName.equals(TableName.META_TABLE_NAME)); - this.encodedName = RegionInfo.encodeRegionName(this.regionName); - this.hashCode = generateHashCode(this.tableName, this.startKey, this.endKey, this.regionId, - this.replicaId, this.offLine, this.regionName); - this.encodedNameAsBytes = Bytes.toBytes(this.encodedName); - } - - /** - * @return Return a short, printable name for this region - * (usually encoded name) for us logging. - */ - @Override - public String getShortNameToLog() { - return RegionInfo.prettyPrint(this.getEncodedName()); - } - - /** @return the regionId */ - @Override - public long getRegionId(){ - return regionId; - } - - - /** - * @return the regionName as an array of bytes. - * @see #getRegionNameAsString() - */ - @Override - public byte[] getRegionName() { - return regionName; - } - - /** - * @return Region name as a String for use in logging, etc. - */ - @Override - public String getRegionNameAsString() { - return RegionInfo.getRegionNameAsString(this, this.regionName); - } - - /** @return the encoded region name */ - @Override - public String getEncodedName() { - return this.encodedName; - } - - @Override - public byte[] getEncodedNameAsBytes() { - return this.encodedNameAsBytes; - } - - /** @return the startKey */ - @Override - public byte[] getStartKey() { - return startKey; - } - - /** @return the endKey */ - @Override - public byte[] getEndKey() { - return endKey; - } - - /** - * Get current table name of the region - * @return TableName - */ - @Override - public TableName getTable() { - return this.tableName; - } - - /** - * Returns true if the given inclusive range of rows is fully contained - * by this region. For example, if the region is foo,a,g and this is - * passed ["b","c"] or ["a","c"] it will return true, but if this is passed - * ["b","z"] it will return false. - * @throws IllegalArgumentException if the range passed is invalid (ie. end < start) - */ - @Override - public boolean containsRange(byte[] rangeStartKey, byte[] rangeEndKey) { - if (Bytes.compareTo(rangeStartKey, rangeEndKey) > 0) { - throw new IllegalArgumentException( - "Invalid range: " + Bytes.toStringBinary(rangeStartKey) + - " > " + Bytes.toStringBinary(rangeEndKey)); - } - - boolean firstKeyInRange = Bytes.compareTo(rangeStartKey, startKey) >= 0; - boolean lastKeyInRange = - Bytes.compareTo(rangeEndKey, endKey) < 0 || - Bytes.equals(endKey, HConstants.EMPTY_BYTE_ARRAY); - return firstKeyInRange && lastKeyInRange; - } - - /** - * Return true if the given row falls in this region. - */ - @Override - public boolean containsRow(byte[] row) { - return Bytes.compareTo(row, startKey) >= 0 && - (Bytes.compareTo(row, endKey) < 0 || - Bytes.equals(endKey, HConstants.EMPTY_BYTE_ARRAY)); - } - - /** @return true if this region is a meta region */ - @Override - public boolean isMetaRegion() { - return tableName.equals(FIRST_META_REGIONINFO.getTable()); - } - - /** - * @return True if has been split and has daughters. - */ - @Override - public boolean isSplit() { - return this.split; - } - - /** - * @param split set split status - * @return MutableRegionInfo - */ - public MutableRegionInfo setSplit(boolean split) { - this.split = split; - return this; - } - - /** - * @return True if this region is offline. - */ - @Override - public boolean isOffline() { - return this.offLine; - } - - /** - * The parent of a region split is offline while split daughters hold - * references to the parent. Offlined regions are closed. - * @param offLine Set online/offline status. - * @return MutableRegionInfo - */ - public MutableRegionInfo setOffline(boolean offLine) { - this.offLine = offLine; - return this; - } - - /** - * @return True if this is a split parent region. - */ - @Override - public boolean isSplitParent() { - if (!isSplit()) { - return false; - } - if (!isOffline()) { - LOG.warn("Region is split but NOT offline: " + getRegionNameAsString()); - } - return true; - } - - /** - * Returns the region replica id - * @return returns region replica id - */ - @Override - public int getReplicaId() { - return replicaId; - } - - /** - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - return "{ENCODED => " + getEncodedName() + ", " + - HConstants.NAME + " => '" + Bytes.toStringBinary(this.regionName) - + "', STARTKEY => '" + - Bytes.toStringBinary(this.startKey) + "', ENDKEY => '" + - Bytes.toStringBinary(this.endKey) + "'" + - (isOffline()? ", OFFLINE => true": "") + - (isSplit()? ", SPLIT => true": "") + - ((replicaId > 0)? ", REPLICA_ID => " + replicaId : "") + "}"; - } - - /** - * @param o - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null) { - return false; - } - if (!(o instanceof RegionInfo)) { - return false; - } - return compareTo((RegionInfo)o) == 0; - } - - /** - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - return this.hashCode; - } - } }