You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by bu...@apache.org on 2017/09/24 00:34:11 UTC
[11/47] hbase git commit: HBASE-17980 Any HRegionInfo we give out
should be immutable
HBASE-17980 Any HRegionInfo we give out should be immutable
Signed-off-by: Michael Stack <st...@apache.org>
Project: http://git-wip-us.apache.org/repos/asf/hbase/repo
Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/58988cb5
Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/58988cb5
Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/58988cb5
Branch: refs/heads/HBASE-18467
Commit: 58988cb53c6287dc82a7a6242b1fe3f50dbf9dfb
Parents: a4277f3
Author: brandboat <br...@gmail.com>
Authored: Wed Sep 13 21:00:18 2017 +0800
Committer: Michael Stack <st...@apache.org>
Committed: Thu Sep 14 14:25:07 2017 -0700
----------------------------------------------------------------------
.../org/apache/hadoop/hbase/HRegionInfo.java | 579 +++++---------
.../org/apache/hadoop/hbase/client/Admin.java | 25 +
.../apache/hadoop/hbase/client/HBaseAdmin.java | 37 +-
.../hbase/client/ImmutableHRegionInfo.java | 49 ++
.../apache/hadoop/hbase/client/RegionInfo.java | 751 +++++++++++++++++++
.../hadoop/hbase/client/RegionInfoBuilder.java | 624 +++++++++++++++
.../hadoop/hbase/client/RegionInfoDisplay.java | 135 ++++
.../hadoop/hbase/client/RegionReplicaUtil.java | 32 +
.../hbase/client/UnmodifyableHRegionInfo.java | 2 +-
.../hbase/shaded/protobuf/ProtobufUtil.java | 64 ++
.../hbase/zookeeper/MetaTableLocator.java | 5 +-
.../hbase/client/TestImmutableHRegionInfo.java | 61 ++
.../hbase/client/TestRegionInfoDisplay.java | 129 ++++
.../master/AssignmentManagerStatusTmpl.jamon | 4 +-
.../hbase/master/assignment/RegionStates.java | 35 +-
.../apache/hadoop/hbase/MetaMockingUtil.java | 13 -
.../master/assignment/TestRegionStates.java | 24 +-
.../regionserver/TestRegionInfoBuilder.java | 323 ++++++++
18 files changed, 2445 insertions(+), 447 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/hbase/blob/58988cb5/hbase-client/src/main/java/org/apache/hadoop/hbase/HRegionInfo.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/HRegionInfo.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/HRegionInfo.java
index 2e735a0..cc88733 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/HRegionInfo.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/HRegionInfo.java
@@ -28,22 +28,17 @@ import java.util.stream.Collectors;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.client.RegionInfoBuilder;
import org.apache.yetus.audience.InterfaceAudience;
-import org.apache.hadoop.hbase.client.RegionReplicaUtil;
+import org.apache.hadoop.hbase.client.RegionInfo;
import org.apache.hadoop.hbase.KeyValue.KVComparator;
import org.apache.hadoop.hbase.exceptions.DeserializationException;
import org.apache.hadoop.hbase.master.RegionState;
-import org.apache.hadoop.hbase.shaded.com.google.protobuf.UnsafeByteOperations;
import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos;
-import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.RegionInfo;
-import org.apache.hadoop.hbase.util.ByteArrayHashKey;
import org.apache.hadoop.hbase.util.Bytes;
-import org.apache.hadoop.hbase.util.HashKey;
-import org.apache.hadoop.hbase.util.JenkinsHash;
-import org.apache.hadoop.hbase.util.MD5Hash;
+import org.apache.hadoop.hbase.client.RegionInfoDisplay;
import org.apache.hadoop.io.DataInputBuffer;
-import org.apache.hadoop.util.StringUtils;
/**
* Information about a region. A region is a range of keys in the whole keyspace of a table, an
@@ -74,10 +69,12 @@ import org.apache.hadoop.util.StringUtils;
* correspond to multiple HRegionInfo's. These HRI's share the same fields however except the
* replicaId field. If the replicaId is not set, it defaults to 0, which is compatible with the
* previous behavior of a range corresponding to 1 region.
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0.
+ * use {@link RegionInfoBuilder} to build {@link RegionInfo}.
*/
+@Deprecated
@InterfaceAudience.Public
-public class HRegionInfo implements Comparable<HRegionInfo> {
-
+public class HRegionInfo implements RegionInfo, Comparable<HRegionInfo> {
private static final Log LOG = LogFactory.getLog(HRegionInfo.class);
/**
@@ -103,62 +100,20 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
* old region name format.
*/
- /** Separator used to demarcate the encodedName in a region name
- * in the new format. See description on new format above.
- */
- private static final int ENC_SEPARATOR = '.';
- public static final int MD5_HEX_LENGTH = 32;
-
/** A non-capture group so that this can be embedded. */
- public static final String ENCODED_REGION_NAME_REGEX = "(?:[a-f0-9]+)";
-
- // to keep appended int's sorted in string format. Only allows 2 bytes to be
- // sorted for replicaId
- public static final String REPLICA_ID_FORMAT = "%04X";
-
- public static final byte REPLICA_ID_DELIMITER = (byte)'_';
+ public static final String ENCODED_REGION_NAME_REGEX = RegionInfoBuilder.ENCODED_REGION_NAME_REGEX;
private static final int MAX_REPLICA_ID = 0xFFFF;
- public static final int DEFAULT_REPLICA_ID = 0;
-
- public static final String INVALID_REGION_NAME_FORMAT_MESSAGE = "Invalid regionName format";
-
- /**
- * Does region name contain its encoded name?
- * @param regionName region name
- * @return boolean indicating if this a new format region
- * name which contains its encoded name.
- */
- private static boolean hasEncodedName(final byte[] regionName) {
- // check if region name ends in ENC_SEPARATOR
- if ((regionName.length >= 1)
- && (regionName[regionName.length - 1] == ENC_SEPARATOR)) {
- // region name is new format. it contains the encoded name.
- return true;
- }
- return false;
- }
/**
* @param regionName
* @return the encodedName
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use {@link org.apache.hadoop.hbase.client.RegionInfo#encodeRegionName(byte[])}.
*/
+ @Deprecated
public static String encodeRegionName(final byte [] regionName) {
- String encodedName;
- if (hasEncodedName(regionName)) {
- // region is in new format:
- // <tableName>,<startKey>,<regionIdTimeStamp>/encodedName/
- encodedName = Bytes.toString(regionName,
- regionName.length - MD5_HEX_LENGTH - 1,
- MD5_HEX_LENGTH);
- } else {
- // old format region name. First hbase:meta region also
- // use this format.EncodedName is the JenkinsHash value.
- HashKey<byte[]> key = new ByteArrayHashKey(regionName, 0, regionName.length);
- int hashVal = Math.abs(JenkinsHash.getInstance().hash(key, 0));
- encodedName = String.valueOf(hashVal);
- }
- return encodedName;
+ return RegionInfo.encodeRegionName(regionName);
}
/**
@@ -168,17 +123,24 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
return prettyPrint(this.getEncodedName());
}
+ /**
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use {@link org.apache.hadoop.hbase.client.RegionInfo#getShortNameToLog(RegionInfo...)}.
+ */
+ @Deprecated
public static String getShortNameToLog(HRegionInfo...hris) {
- return getShortNameToLog(Arrays.asList(hris));
+ return RegionInfo.getShortNameToLog(Arrays.asList(hris));
}
/**
* @return Return a String of short, printable names for <code>hris</code>
* (usually encoded name) for us logging.
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use {@link org.apache.hadoop.hbase.client.RegionInfo#getShortNameToLog(List)})}.
*/
+ @Deprecated
public static String getShortNameToLog(final List<HRegionInfo> hris) {
- return hris.stream().map(hri -> hri.getShortNameToLog()).
- collect(Collectors.toList()).toString();
+ return RegionInfo.getShortNameToLog(hris.stream().collect(Collectors.toList()));
}
/**
@@ -186,12 +148,13 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
* @param encodedRegionName The encoded regionname.
* @return <code>hbase:meta</code> if passed <code>1028785192</code> else returns
* <code>encodedRegionName</code>
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use {@link RegionInfo#prettyPrint(String)}.
*/
+ @Deprecated
+ @InterfaceAudience.Private
public static String prettyPrint(final String encodedRegionName) {
- if (encodedRegionName.equals("1028785192")) {
- return encodedRegionName + "/hbase:meta";
- }
- return encodedRegionName;
+ return RegionInfo.prettyPrint(encodedRegionName);
}
private byte [] endKey = HConstants.EMPTY_BYTE_ARRAY;
@@ -212,9 +175,11 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
// Current TableName
private TableName tableName = null;
- final static String DISPLAY_KEYS_KEY = "hbase.display.keys";
- public final static byte[] HIDDEN_END_KEY = Bytes.toBytes("hidden-end-key");
- public final static byte[] HIDDEN_START_KEY = Bytes.toBytes("hidden-start-key");
+
+ // Duplicated over in RegionInfoDisplay
+ final static String DISPLAY_KEYS_KEY = RegionInfoDisplay.DISPLAY_KEYS_KEY;
+ public final static byte[] HIDDEN_END_KEY = RegionInfoDisplay.HIDDEN_END_KEY;
+ public final static byte[] HIDDEN_START_KEY = RegionInfoDisplay.HIDDEN_START_KEY;
/** HRegionInfo for first meta region */
// TODO: How come Meta regions still do not have encoded region names? Fix.
@@ -232,7 +197,6 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
this.hashCode = result;
}
-
/**
* Private constructor used constructing HRegionInfo for the
* first meta regions
@@ -354,8 +318,8 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
this.startKey = other.getStartKey();
this.hashCode = other.hashCode();
this.encodedName = other.getEncodedName();
- this.tableName = other.tableName;
- this.replicaId = other.replicaId;
+ this.tableName = other.getTable();
+ this.replicaId = other.getReplicaId();
}
public HRegionInfo(HRegionInfo other, int replicaId) {
@@ -372,10 +336,14 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
* @param newFormat should we create the region name in the new format
* (such that it contains its encoded name?).
* @return Region name made of passed tableName, startKey and id
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use {@link RegionInfo#createRegionName(TableName, byte[], long, boolean)}.
*/
+ @Deprecated
+ @InterfaceAudience.Private
public static byte [] createRegionName(final TableName tableName,
final byte [] startKey, final long regionid, boolean newFormat) {
- return createRegionName(tableName, startKey, Long.toString(regionid), newFormat);
+ return RegionInfo.createRegionName(tableName, startKey, Long.toString(regionid), newFormat);
}
/**
@@ -386,10 +354,14 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
* @param newFormat should we create the region name in the new format
* (such that it contains its encoded name?).
* @return Region name made of passed tableName, startKey and id
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use {@link RegionInfo#createRegionName(TableName, byte[], String, boolean)}.
*/
+ @Deprecated
+ @InterfaceAudience.Private
public static byte [] createRegionName(final TableName tableName,
final byte [] startKey, final String id, boolean newFormat) {
- return createRegionName(tableName, startKey, Bytes.toBytes(id), newFormat);
+ return RegionInfo.createRegionName(tableName, startKey, Bytes.toBytes(id), newFormat);
}
/**
@@ -401,10 +373,14 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
* @param newFormat should we create the region name in the new format
* (such that it contains its encoded name?).
* @return Region name made of passed tableName, startKey, id and replicaId
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use {@link RegionInfo#createRegionName(TableName, byte[], long, int, boolean)}.
*/
+ @Deprecated
+ @InterfaceAudience.Private
public static byte [] createRegionName(final TableName tableName,
final byte [] startKey, final long regionid, int replicaId, boolean newFormat) {
- return createRegionName(tableName, startKey, Bytes.toBytes(Long.toString(regionid)),
+ return RegionInfo.createRegionName(tableName, startKey, Bytes.toBytes(Long.toString(regionid)),
replicaId, newFormat);
}
@@ -416,10 +392,14 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
* @param newFormat should we create the region name in the new format
* (such that it contains its encoded name?).
* @return Region name made of passed tableName, startKey and id
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use {@link RegionInfo#createRegionName(TableName, byte[], byte[], boolean)}.
*/
+ @Deprecated
+ @InterfaceAudience.Private
public static byte [] createRegionName(final TableName tableName,
final byte [] startKey, final byte [] id, boolean newFormat) {
- return createRegionName(tableName, startKey, id, DEFAULT_REPLICA_ID, newFormat);
+ return RegionInfo.createRegionName(tableName, startKey, id, DEFAULT_REPLICA_ID, newFormat);
}
/**
* Make a region name of passed parameters.
@@ -429,94 +409,38 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
* @param replicaId
* @param newFormat should we create the region name in the new format
* @return Region name made of passed tableName, startKey, id and replicaId
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use {@link RegionInfo#createRegionName(TableName, byte[], byte[], int, boolean)}.
*/
+ @Deprecated
+ @InterfaceAudience.Private
public static byte [] createRegionName(final TableName tableName,
final byte [] startKey, final byte [] id, final int replicaId, boolean newFormat) {
- int len = tableName.getName().length + 2 + id.length +
- (startKey == null? 0: startKey.length);
- if (newFormat) {
- len += MD5_HEX_LENGTH + 2;
- }
- byte[] replicaIdBytes = null;
- // Special casing: replicaId is only appended if replicaId is greater than
- // 0. This is because all regions in meta would have to be migrated to the new
- // name otherwise
- if (replicaId > 0) {
- // use string representation for replica id
- replicaIdBytes = Bytes.toBytes(String.format(REPLICA_ID_FORMAT, replicaId));
- len += 1 + replicaIdBytes.length;
- }
-
- byte [] b = new byte [len];
-
- int offset = tableName.getName().length;
- System.arraycopy(tableName.getName(), 0, b, 0, offset);
- b[offset++] = HConstants.DELIMITER;
- if (startKey != null && startKey.length > 0) {
- System.arraycopy(startKey, 0, b, offset, startKey.length);
- offset += startKey.length;
- }
- b[offset++] = HConstants.DELIMITER;
- System.arraycopy(id, 0, b, offset, id.length);
- offset += id.length;
-
- if (replicaIdBytes != null) {
- b[offset++] = REPLICA_ID_DELIMITER;
- System.arraycopy(replicaIdBytes, 0, b, offset, replicaIdBytes.length);
- offset += replicaIdBytes.length;
- }
-
- if (newFormat) {
- //
- // Encoded name should be built into the region name.
- //
- // Use the region name thus far (namely, <tablename>,<startKey>,<id>_<replicaId>)
- // to compute a MD5 hash to be used as the encoded name, and append
- // it to the byte buffer.
- //
- String md5Hash = MD5Hash.getMD5AsHex(b, 0, offset);
- byte [] md5HashBytes = Bytes.toBytes(md5Hash);
-
- if (md5HashBytes.length != MD5_HEX_LENGTH) {
- LOG.error("MD5-hash length mismatch: Expected=" + MD5_HEX_LENGTH +
- "; Got=" + md5HashBytes.length);
- }
-
- // now append the bytes '.<encodedName>.' to the end
- b[offset++] = ENC_SEPARATOR;
- System.arraycopy(md5HashBytes, 0, b, offset, MD5_HEX_LENGTH);
- offset += MD5_HEX_LENGTH;
- b[offset++] = ENC_SEPARATOR;
- }
-
- return b;
+ return RegionInfo.createRegionName(tableName, startKey, id, replicaId, newFormat);
}
/**
* Gets the table name from the specified region name.
* @param regionName to extract the table name from
* @return Table name
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use {@link org.apache.hadoop.hbase.client.RegionInfo#getTable(byte[])}.
*/
+ @Deprecated
public static TableName getTable(final byte [] regionName) {
- int offset = -1;
- for (int i = 0; i < regionName.length; i++) {
- if (regionName[i] == HConstants.DELIMITER) {
- offset = i;
- break;
- }
- }
- byte[] buff = new byte[offset];
- System.arraycopy(regionName, 0, buff, 0, offset);
- return TableName.valueOf(buff);
+ return RegionInfo.getTable(regionName);
}
/**
* Gets the start key from the specified region name.
* @param regionName
* @return Start key.
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use {@link org.apache.hadoop.hbase.client.RegionInfo#getStartKey(byte[])}.
*/
+ @Deprecated
public static byte[] getStartKey(final byte[] regionName) throws IOException {
- return parseRegionName(regionName)[1];
+ return RegionInfo.getStartKey(regionName);
}
/**
@@ -524,88 +448,27 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
* @param regionName
* @return Array of byte[] containing tableName, startKey and id
* @throws IOException
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use {@link RegionInfo#parseRegionName(byte[])}.
*/
+ @Deprecated
+ @InterfaceAudience.Private
public static byte [][] parseRegionName(final byte [] regionName)
throws IOException {
- // Region name is of the format:
- // tablename,startkey,regionIdTimestamp[_replicaId][.encodedName.]
- // startkey can contain the delimiter (',') so we parse from the start and end
-
- // parse from start
- int offset = -1;
- for (int i = 0; i < regionName.length; i++) {
- if (regionName[i] == HConstants.DELIMITER) {
- offset = i;
- break;
- }
- }
- if (offset == -1) {
- throw new IOException(INVALID_REGION_NAME_FORMAT_MESSAGE
- + ": " + Bytes.toStringBinary(regionName));
- }
- byte[] tableName = new byte[offset];
- System.arraycopy(regionName, 0, tableName, 0, offset);
- offset = -1;
-
- int endOffset = regionName.length;
- // check whether regionName contains encodedName
- if (regionName.length > MD5_HEX_LENGTH + 2
- && regionName[regionName.length-1] == ENC_SEPARATOR
- && regionName[regionName.length-MD5_HEX_LENGTH-2] == ENC_SEPARATOR) {
- endOffset = endOffset - MD5_HEX_LENGTH - 2;
- }
-
- // parse from end
- byte[] replicaId = null;
- int idEndOffset = endOffset;
- for (int i = endOffset - 1; i > 0; i--) {
- if (regionName[i] == REPLICA_ID_DELIMITER) { //replicaId may or may not be present
- replicaId = new byte[endOffset - i - 1];
- System.arraycopy(regionName, i + 1, replicaId, 0,
- endOffset - i - 1);
- idEndOffset = i;
- // do not break, continue to search for id
- }
- if (regionName[i] == HConstants.DELIMITER) {
- offset = i;
- break;
- }
- }
- if (offset == -1) {
- throw new IOException(INVALID_REGION_NAME_FORMAT_MESSAGE
- + ": " + Bytes.toStringBinary(regionName));
- }
- byte [] startKey = HConstants.EMPTY_BYTE_ARRAY;
- if(offset != tableName.length + 1) {
- startKey = new byte[offset - tableName.length - 1];
- System.arraycopy(regionName, tableName.length + 1, startKey, 0,
- offset - tableName.length - 1);
- }
- byte [] id = new byte[idEndOffset - offset - 1];
- System.arraycopy(regionName, offset + 1, id, 0,
- idEndOffset - offset - 1);
- byte [][] elements = new byte[replicaId == null ? 3 : 4][];
- elements[0] = tableName;
- elements[1] = startKey;
- elements[2] = id;
- if (replicaId != null) {
- elements[3] = replicaId;
- }
-
- return elements;
+ return RegionInfo.parseRegionName(regionName);
}
+ /**
+ *
+ * @param regionName
+ * @return if region name is encoded.
+ * @throws IOException
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use {@link org.apache.hadoop.hbase.client.RegionInfo#isEncodedRegionName(byte[])}.
+ */
+ @Deprecated
public static boolean isEncodedRegionName(byte[] regionName) throws IOException {
- try {
- HRegionInfo.parseRegionName(regionName);
- return false;
- } catch (IOException e) {
- if (StringUtils.stringifyException(e)
- .contains(HRegionInfo.INVALID_REGION_NAME_FORMAT_MESSAGE)) {
- return true;
- }
- throw e;
- }
+ return RegionInfo.isEncodedRegionName(regionName);
}
/** @return the regionId */
@@ -625,7 +488,7 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
* @return Region name as a String for use in logging, etc.
*/
public String getRegionNameAsString() {
- if (hasEncodedName(this.regionName)) {
+ if (RegionInfo.hasEncodedName(this.regionName)) {
// new format region names already have their encoded name.
return Bytes.toStringBinary(this.regionName);
}
@@ -639,7 +502,7 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
/** @return the encoded region name */
public synchronized String getEncodedName() {
if (this.encodedName == null) {
- this.encodedName = encodeRegionName(this.regionName);
+ this.encodedName = RegionInfo.encodeRegionName(this.regionName);
}
return this.encodedName;
}
@@ -819,53 +682,7 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
@Override
public int compareTo(HRegionInfo o) {
- if (o == null) {
- return 1;
- }
-
- // Are regions of same table?
- int result = this.tableName.compareTo(o.tableName);
- if (result != 0) {
- return result;
- }
-
- // Compare start keys.
- result = Bytes.compareTo(this.startKey, o.startKey);
- if (result != 0) {
- return result;
- }
-
- // Compare end keys.
- result = Bytes.compareTo(this.endKey, o.endKey);
-
- if (result != 0) {
- if (this.getStartKey().length != 0
- && this.getEndKey().length == 0) {
- return 1; // this is last region
- }
- if (o.getStartKey().length != 0
- && o.getEndKey().length == 0) {
- return -1; // o is the last region
- }
- return result;
- }
-
- // regionId is usually milli timestamp -- this defines older stamps
- // to be "smaller" than newer stamps in sort order.
- if (this.regionId > o.regionId) {
- return 1;
- } else if (this.regionId < o.regionId) {
- return -1;
- }
-
- int replicaDiff = this.getReplicaId() - o.getReplicaId();
- if (replicaDiff != 0) return replicaDiff;
-
- if (this.offLine == o.offLine)
- return 0;
- if (this.offLine == true) return -1;
-
- return 1;
+ return RegionInfo.COMPARATOR.compare(this, o);
}
/**
@@ -883,7 +700,7 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
*
* @return the converted RegionInfo
*/
- RegionInfo convert() {
+ HBaseProtos.RegionInfo convert() {
return convert(this);
}
@@ -892,58 +709,47 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
*
* @param info the HRegionInfo to convert
* @return the converted RegionInfo
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use toProtoRegionInfo(org.apache.hadoop.hbase.client.RegionInfo)
+ * in org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil.
*/
- public static RegionInfo convert(final HRegionInfo info) {
- if (info == null) return null;
- RegionInfo.Builder builder = RegionInfo.newBuilder();
- builder.setTableName(ProtobufUtil.toProtoTableName(info.getTable()));
- builder.setRegionId(info.getRegionId());
- if (info.getStartKey() != null) {
- builder.setStartKey(UnsafeByteOperations.unsafeWrap(info.getStartKey()));
- }
- if (info.getEndKey() != null) {
- builder.setEndKey(UnsafeByteOperations.unsafeWrap(info.getEndKey()));
- }
- builder.setOffline(info.isOffline());
- builder.setSplit(info.isSplit());
- builder.setReplicaId(info.getReplicaId());
- return builder.build();
+ @Deprecated
+ @InterfaceAudience.Private
+ public static HBaseProtos.RegionInfo convert(final HRegionInfo info) {
+ return ProtobufUtil.toProtoRegionInfo(info);
}
/**
* Convert a RegionInfo to a HRegionInfo
*
* @param proto the RegionInfo to convert
- * @return the converted HRegionInfho
+ * @return the converted HRegionInfo
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use toRegionInfo(HBaseProtos.RegionInfo)
+ * in org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil.
*/
- public static HRegionInfo convert(final RegionInfo proto) {
- if (proto == null) return null;
- TableName tableName =
- ProtobufUtil.toTableName(proto.getTableName());
- if (tableName.equals(TableName.META_TABLE_NAME)) {
- return RegionReplicaUtil.getRegionInfoForReplica(FIRST_META_REGIONINFO,
- proto.getReplicaId());
- }
- long regionId = proto.getRegionId();
- int replicaId = proto.hasReplicaId() ? proto.getReplicaId() : DEFAULT_REPLICA_ID;
- byte[] startKey = null;
- byte[] endKey = null;
- if (proto.hasStartKey()) {
- startKey = proto.getStartKey().toByteArray();
- }
- if (proto.hasEndKey()) {
- endKey = proto.getEndKey().toByteArray();
- }
- boolean split = false;
- if (proto.hasSplit()) {
- split = proto.getSplit();
- }
- HRegionInfo hri = new HRegionInfo(
- tableName,
- startKey,
- endKey, split, regionId, replicaId);
- if (proto.hasOffline()) {
- hri.setOffline(proto.getOffline());
+ @Deprecated
+ @InterfaceAudience.Private
+ public static HRegionInfo convert(final HBaseProtos.RegionInfo proto) {
+ RegionInfo ri = ProtobufUtil.toRegionInfo(proto);
+ // This is hack of what is in RegionReplicaUtil but it is doing translation of
+ // RegionInfo into HRegionInfo which is what is wanted here.
+ HRegionInfo hri;
+ if (ri.isMetaRegion()) {
+ hri = ri.getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID ?
+ HRegionInfo.FIRST_META_REGIONINFO :
+ new HRegionInfo(ri.getRegionId(), ri.getTable(), ri.getReplicaId());
+ } else {
+ hri = new HRegionInfo(
+ ri.getTable(),
+ ri.getStartKey(),
+ ri.getEndKey(),
+ ri.isSplit(),
+ ri.getRegionId(),
+ ri.getReplicaId());
+ if (proto.hasOffline()) {
+ hri.setOffline(proto.getOffline());
+ }
}
return hri;
}
@@ -951,17 +757,22 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
/**
* @return This instance serialized as protobuf w/ a magic pb prefix.
* @see #parseFrom(byte[])
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use {@link org.apache.hadoop.hbase.client.RegionInfo#toByteArray(RegionInfo)}.
*/
+ @Deprecated
public byte [] toByteArray() {
- byte [] bytes = convert().toByteArray();
- return ProtobufUtil.prependPBMagic(bytes);
+ return RegionInfo.toByteArray(this);
}
/**
* @return A deserialized {@link HRegionInfo}
* or null if we failed deserialize or passed bytes null
* @see #toByteArray()
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use {@link org.apache.hadoop.hbase.client.RegionInfo#parseFromOrNull(byte[])}.
*/
+ @Deprecated
public static HRegionInfo parseFromOrNull(final byte [] bytes) {
if (bytes == null) return null;
return parseFromOrNull(bytes, 0, bytes.length);
@@ -971,7 +782,10 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
* @return A deserialized {@link HRegionInfo} or null
* if we failed deserialize or passed bytes null
* @see #toByteArray()
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use {@link org.apache.hadoop.hbase.client.RegionInfo#parseFromOrNull(byte[], int, int)}.
*/
+ @Deprecated
public static HRegionInfo parseFromOrNull(final byte [] bytes, int offset, int len) {
if (bytes == null || len <= 0) return null;
try {
@@ -986,6 +800,8 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
* @return A deserialized {@link HRegionInfo}
* @throws DeserializationException
* @see #toByteArray()
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use {@link org.apache.hadoop.hbase.client.RegionInfo#parseFrom(byte[])}.
*/
public static HRegionInfo parseFrom(final byte [] bytes) throws DeserializationException {
if (bytes == null) return null;
@@ -999,7 +815,10 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
* @return A deserialized {@link HRegionInfo}
* @throws DeserializationException
* @see #toByteArray()
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use {@link org.apache.hadoop.hbase.client.RegionInfo#parseFrom(byte[], int, int)}.
*/
+ @Deprecated
public static HRegionInfo parseFrom(final byte [] bytes, int offset, int len)
throws DeserializationException {
if (ProtobufUtil.isPBMagicPrefix(bytes, offset, len)) {
@@ -1023,9 +842,12 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
* @return This instance serialized as a delimited protobuf w/ a magic pb prefix.
* @throws IOException
* @see #toByteArray()
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use {@link RegionInfo#toDelimitedByteArray(RegionInfo)}.
*/
+ @Deprecated
public byte [] toDelimitedByteArray() throws IOException {
- return ProtobufUtil.toDelimitedByteArray(convert());
+ return RegionInfo.toDelimitedByteArray(this);
}
/**
@@ -1034,14 +856,15 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
* @param state
* @param conf
* @return descriptive string
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use RegionInfoDisplay#getDescriptiveNameFromRegionStateForDisplay(RegionState, Configuration)
+ * over in hbase-server module.
*/
+ @Deprecated
+ @InterfaceAudience.Private
public static String getDescriptiveNameFromRegionStateForDisplay(RegionState state,
Configuration conf) {
- if (conf.getBoolean(DISPLAY_KEYS_KEY, true)) return state.toDescriptiveString();
- String descriptiveStringFromState = state.toDescriptiveString();
- int idx = descriptiveStringFromState.lastIndexOf(" state=");
- String regionName = getRegionNameAsStringForDisplay(state.getRegion(), conf);
- return regionName + descriptiveStringFromState.substring(idx);
+ return RegionInfoDisplay.getDescriptiveNameFromRegionStateForDisplay(state, conf);
}
/**
@@ -1049,11 +872,14 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
* @param hri
* @param conf
* @return the endkey
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use RegionInfoDisplay#getEndKeyForDisplay(RegionInfo, Configuration)
+ * over in hbase-server module.
*/
+ @Deprecated
+ @InterfaceAudience.Private
public static byte[] getEndKeyForDisplay(HRegionInfo hri, Configuration conf) {
- boolean displayKey = conf.getBoolean(DISPLAY_KEYS_KEY, true);
- if (displayKey) return hri.getEndKey();
- return HIDDEN_END_KEY;
+ return RegionInfoDisplay.getEndKeyForDisplay(hri, conf);
}
/**
@@ -1061,11 +887,14 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
* @param hri
* @param conf
* @return the startkey
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use RegionInfoDisplay#getStartKeyForDisplay(RegionInfo, Configuration)
+ * over in hbase-server module.
*/
+ @Deprecated
+ @InterfaceAudience.Private
public static byte[] getStartKeyForDisplay(HRegionInfo hri, Configuration conf) {
- boolean displayKey = conf.getBoolean(DISPLAY_KEYS_KEY, true);
- if (displayKey) return hri.getStartKey();
- return HIDDEN_START_KEY;
+ return RegionInfoDisplay.getStartKeyForDisplay(hri, conf);
}
/**
@@ -1073,9 +902,14 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
* @param hri
* @param conf
* @return region name as String
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use RegionInfoDisplay#getRegionNameAsStringForDisplay(RegionInfo, Configuration)
+ * over in hbase-server module.
*/
+ @Deprecated
+ @InterfaceAudience.Private
public static String getRegionNameAsStringForDisplay(HRegionInfo hri, Configuration conf) {
- return Bytes.toStringBinary(getRegionNameForDisplay(hri, conf));
+ return RegionInfoDisplay.getRegionNameAsStringForDisplay(hri, conf);
}
/**
@@ -1083,47 +917,14 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
* @param hri
* @param conf
* @return region name bytes
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use RegionInfoDisplay#getRegionNameForDisplay(RegionInfo, Configuration)
+ * over in hbase-server module.
*/
+ @Deprecated
+ @InterfaceAudience.Private
public static byte[] getRegionNameForDisplay(HRegionInfo hri, Configuration conf) {
- boolean displayKey = conf.getBoolean(DISPLAY_KEYS_KEY, true);
- if (displayKey || hri.getTable().equals(TableName.META_TABLE_NAME)) {
- return hri.getRegionName();
- } else {
- // create a modified regionname with the startkey replaced but preserving
- // the other parts including the encodedname.
- try {
- byte[][]regionNameParts = parseRegionName(hri.getRegionName());
- regionNameParts[1] = HIDDEN_START_KEY; //replace the real startkey
- int len = 0;
- // get the total length
- for (byte[] b : regionNameParts) {
- len += b.length;
- }
- byte[] encodedRegionName =
- Bytes.toBytes(encodeRegionName(hri.getRegionName()));
- len += encodedRegionName.length;
- //allocate some extra bytes for the delimiters and the last '.'
- byte[] modifiedName = new byte[len + regionNameParts.length + 1];
- int lengthSoFar = 0;
- int loopCount = 0;
- for (byte[] b : regionNameParts) {
- System.arraycopy(b, 0, modifiedName, lengthSoFar, b.length);
- lengthSoFar += b.length;
- if (loopCount++ == 2) modifiedName[lengthSoFar++] = REPLICA_ID_DELIMITER;
- else modifiedName[lengthSoFar++] = HConstants.DELIMITER;
- }
- // replace the last comma with '.'
- modifiedName[lengthSoFar - 1] = ENC_SEPARATOR;
- System.arraycopy(encodedRegionName, 0, modifiedName, lengthSoFar,
- encodedRegionName.length);
- lengthSoFar += encodedRegionName.length;
- modifiedName[lengthSoFar] = ENC_SEPARATOR;
- return modifiedName;
- } catch (IOException e) {
- //LOG.warn("Encountered exception " + e);
- throw new RuntimeException(e);
- }
- }
+ return RegionInfoDisplay.getRegionNameForDisplay(hri, conf);
}
/**
@@ -1132,7 +933,11 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
* @param in
* @return An instance of HRegionInfo.
* @throws IOException
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use {@link RegionInfo#parseFrom(DataInputStream)}.
*/
+ @Deprecated
+ @InterfaceAudience.Private
public static HRegionInfo parseFrom(final DataInputStream in) throws IOException {
// I need to be able to move back in the stream if this is not a pb serialization so I can
// do the Writable decoding instead.
@@ -1161,22 +966,13 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
* @return This instance serialized as a delimited protobuf w/ a magic pb prefix.
* @throws IOException
* @see #toByteArray()
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use {@link RegionInfo#toDelimitedByteArray(RegionInfo...)}.
*/
+ @Deprecated
+ @InterfaceAudience.Private
public static byte[] toDelimitedByteArray(HRegionInfo... infos) throws IOException {
- byte[][] bytes = new byte[infos.length][];
- int size = 0;
- for (int i = 0; i < infos.length; i++) {
- bytes[i] = infos[i].toDelimitedByteArray();
- size += bytes[i].length;
- }
-
- byte[] result = new byte[size];
- int offset = 0;
- for (byte[] b : bytes) {
- System.arraycopy(b, 0, result, offset, b.length);
- offset += b.length;
- }
- return result;
+ return RegionInfo.toDelimitedByteArray(infos);
}
/**
@@ -1186,7 +982,10 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
* @param offset the start offset into the byte[] buffer
* @param length how far we should read into the byte[] buffer
* @return All the hregioninfos that are in the byte array. Keeps reading till we hit the end.
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use {@link RegionInfo#parseDelimitedFrom(byte[], int, int)}.
*/
+ @Deprecated
public static List<HRegionInfo> parseDelimitedFrom(final byte[] bytes, final int offset,
final int length) throws IOException {
if (bytes == null) {
@@ -1211,21 +1010,11 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
* @param regionA
* @param regionB
* @return true if two regions are adjacent
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use {@link org.apache.hadoop.hbase.client.RegionInfo#areAdjacent(RegionInfo, RegionInfo)}.
*/
+ @Deprecated
public static boolean areAdjacent(HRegionInfo regionA, HRegionInfo regionB) {
- if (regionA == null || regionB == null) {
- throw new IllegalArgumentException(
- "Can't check whether adjacent for null region");
- }
- HRegionInfo a = regionA;
- HRegionInfo b = regionB;
- if (Bytes.compareTo(a.getStartKey(), b.getStartKey()) > 0) {
- a = regionB;
- b = regionA;
- }
- if (Bytes.compareTo(a.getEndKey(), b.getStartKey()) == 0) {
- return true;
- }
- return false;
+ return RegionInfo.areAdjacent(regionA, regionB);
}
}
http://git-wip-us.apache.org/repos/asf/hbase/blob/58988cb5/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java
index 0a82a6b..2a92409 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java
@@ -811,10 +811,22 @@ public interface Admin extends Abortable, Closeable {
/**
* Get all the online regions on a region server.
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * (<a href="https://issues.apache.org/jira/browse/HBASE-17980">HBASE-17980</a>).
+ * Use {@link #getRegions(ServerName sn)}.
*/
+ @Deprecated
List<HRegionInfo> getOnlineRegions(ServerName sn) throws IOException;
/**
+ * Get all the online regions on a region server.
+ *
+ * @return List of {@link RegionInfo}
+ * @throws java.io.IOException
+ */
+ List<RegionInfo> getRegions(ServerName serverName) throws IOException;
+
+ /**
* Flush a table. Synchronous operation.
*
* @param tableName table to flush
@@ -1510,10 +1522,23 @@ public interface Admin extends Abortable, Closeable {
* @param tableName the name of the table
* @return List of {@link HRegionInfo}.
* @throws IOException
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * (<a href="https://issues.apache.org/jira/browse/HBASE-17980">HBASE-17980</a>).
+ * Use {@link #getRegions(TableName)}.
*/
+ @Deprecated
List<HRegionInfo> getTableRegions(TableName tableName)
throws IOException;
+ /**
+ * Get the regions of a given table.
+ *
+ * @param tableName the name of the table
+ * @return List of {@link RegionInfo}.
+ * @throws IOException
+ */
+ List<RegionInfo> getRegions(TableName tableName) throws IOException;
+
@Override
void close() throws IOException;
http://git-wip-us.apache.org/repos/asf/hbase/blob/58988cb5/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java
index 4e17335..fac3ef1 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java
@@ -397,6 +397,16 @@ public class HBaseAdmin implements Admin {
});
}
+ @Override
+ public List<RegionInfo> getRegions(final ServerName sn) throws IOException {
+ return getOnlineRegions(sn).stream().collect(Collectors.toList());
+ }
+
+ @Override
+ public List<RegionInfo> getRegions(final TableName tableName) throws IOException {
+ return getTableRegions(tableName).stream().collect(Collectors.toList());
+ }
+
private static class AbortProcedureFuture extends ProcedureFuture<Boolean> {
private boolean isAbortInProgress;
@@ -1143,12 +1153,24 @@ public class HBaseAdmin implements Admin {
unassign(hri.getRegionName(), true);
}
+ /**
+ *
+ * @param sn
+ * @return List of {@link HRegionInfo}.
+ * @throws IOException
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use {@link #getRegions(ServerName)}.
+ */
+ @Deprecated
@Override
public List<HRegionInfo> getOnlineRegions(final ServerName sn) throws IOException {
AdminService.BlockingInterface admin = this.connection.getAdmin(sn);
// TODO: There is no timeout on this controller. Set one!
HBaseRpcController controller = rpcControllerFactory.newController();
- return ProtobufUtil.getOnlineRegions(controller, admin);
+ List<HRegionInfo> onlineRegions = ProtobufUtil.getOnlineRegions(controller, admin);
+ return onlineRegions == null ? null : onlineRegions.stream()
+ .map(hri -> new ImmutableHRegionInfo(hri))
+ .collect(Collectors.toList());
}
@Override
@@ -2340,6 +2362,15 @@ public class HBaseAdmin implements Admin {
}
}
+ /**
+ *
+ * @param tableName
+ * @return List of {@link HRegionInfo}.
+ * @throws IOException
+ * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
+ * Use {@link #getRegions(TableName)}.
+ */
+ @Deprecated
@Override
public List<HRegionInfo> getTableRegions(final TableName tableName)
throws IOException {
@@ -2356,7 +2387,9 @@ public class HBaseAdmin implements Admin {
} finally {
zookeeper.close();
}
- return regions;
+ return regions == null ? null : regions.stream()
+ .map(hri -> new ImmutableHRegionInfo(hri))
+ .collect(Collectors.toList());
}
@Override
http://git-wip-us.apache.org/repos/asf/hbase/blob/58988cb5/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ImmutableHRegionInfo.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ImmutableHRegionInfo.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ImmutableHRegionInfo.java
new file mode 100644
index 0000000..16329c8
--- /dev/null
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ImmutableHRegionInfo.java
@@ -0,0 +1,49 @@
+/**
+ *
+ * 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 org.apache.hadoop.hbase.HRegionInfo;
+import org.apache.yetus.audience.InterfaceAudience;
+
+/**
+ * Read-only Region info.
+ */
+@Deprecated // deprecated for hbase 2.0, remove for hbase 3.0. see HRegionInfo.
+@InterfaceAudience.Private
+public class ImmutableHRegionInfo extends HRegionInfo {
+
+ /*
+ * Creates an immutable copy of an HRegionInfo.
+ *
+ * @param other
+ */
+ public ImmutableHRegionInfo(HRegionInfo other) {
+ super(other);
+ }
+
+ @Override
+ public void setSplit(boolean split) {
+ throw new UnsupportedOperationException("HRegionInfo is read-only");
+ }
+
+ @Override
+ public void setOffline(boolean offline) {
+ throw new UnsupportedOperationException("HRegionInfo is read-only");
+ }
+}
http://git-wip-us.apache.org/repos/asf/hbase/blob/58988cb5/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RegionInfo.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..3646722
--- /dev/null
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RegionInfo.java
@@ -0,0 +1,751 @@
+/**
+ *
+ * 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 org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.exceptions.DeserializationException;
+import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.hadoop.hbase.util.MD5Hash;
+import org.apache.hadoop.io.DataInputBuffer;
+import org.apache.hadoop.util.StringUtils;
+import org.apache.yetus.audience.InterfaceAudience;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.apache.hadoop.hbase.util.ByteArrayHashKey;
+import org.apache.hadoop.hbase.util.HashKey;
+import org.apache.hadoop.hbase.util.JenkinsHash;
+
+/**
+ * Information about a region. A region is a range of keys in the whole keyspace
+ * of a table, an identifier (a timestamp) for differentiating between subset
+ * ranges (after region split) and a replicaId for differentiating the instance
+ * for the same range and some status information about the region.
+ *
+ * The region has a unique name which consists of the following fields:
+ * <ul>
+ * <li> tableName : The name of the table </li>
+ * <li> startKey : The startKey for the region. </li>
+ * <li> regionId : A timestamp when the region is created. </li>
+ * <li> replicaId : An id starting from 0 to differentiate replicas of the
+ * same region range but hosted in separated servers. The same region range can
+ * be hosted in multiple locations.</li>
+ * <li> encodedName : An MD5 encoded string for the region name.</li>
+ * </ul>
+ *
+ * <br> Other than the fields in the region name, region info contains:
+ * <ul>
+ * <li> endKey : the endKey for the region (exclusive) </li>
+ * <li> split : Whether the region is split </li>
+ * <li> offline : Whether the region is offline </li>
+ * </ul>
+ *
+ */
+@InterfaceAudience.Public
+public interface RegionInfo {
+ /**
+ * Separator used to demarcate the encodedName in a region name
+ * in the new format. See description on new format above.
+ */
+ @InterfaceAudience.Private
+ int ENC_SEPARATOR = '.';
+
+ @InterfaceAudience.Private
+ int MD5_HEX_LENGTH = 32;
+
+ @InterfaceAudience.Private
+ int DEFAULT_REPLICA_ID = 0;
+
+ /**
+ * to keep appended int's sorted in string format. Only allows 2 bytes
+ * to be sorted for replicaId.
+ */
+ @InterfaceAudience.Private
+ String REPLICA_ID_FORMAT = "%04X";
+
+ @InterfaceAudience.Private
+ byte REPLICA_ID_DELIMITER = (byte)'_';
+
+ @InterfaceAudience.Private
+ String INVALID_REGION_NAME_FORMAT_MESSAGE = "Invalid regionName format";
+
+ @InterfaceAudience.Private
+ Comparator<RegionInfo> COMPARATOR
+ = (RegionInfo lhs, RegionInfo rhs) -> {
+ if (rhs == null) {
+ return 1;
+ }
+
+ // Are regions of same table?
+ int result = lhs.getTable().compareTo(rhs.getTable());
+ if (result != 0) {
+ return result;
+ }
+
+ // Compare start keys.
+ result = Bytes.compareTo(lhs.getStartKey(), rhs.getStartKey());
+ if (result != 0) {
+ return result;
+ }
+
+ // Compare end keys.
+ result = Bytes.compareTo(lhs.getEndKey(), rhs.getEndKey());
+
+ if (result != 0) {
+ if (lhs.getStartKey().length != 0
+ && lhs.getEndKey().length == 0) {
+ return 1; // this is last region
+ }
+ if (rhs.getStartKey().length != 0
+ && rhs.getEndKey().length == 0) {
+ return -1; // o is the last region
+ }
+ return result;
+ }
+
+ // regionId is usually milli timestamp -- this defines older stamps
+ // to be "smaller" than newer stamps in sort order.
+ if (lhs.getRegionId() > rhs.getRegionId()) {
+ return 1;
+ } else if (lhs.getRegionId() < rhs.getRegionId()) {
+ return -1;
+ }
+
+ int replicaDiff = lhs.getReplicaId() - rhs.getReplicaId();
+ if (replicaDiff != 0) return replicaDiff;
+
+ if (lhs.isOffline() == rhs.isOffline())
+ return 0;
+ if (lhs.isOffline() == true) return -1;
+
+ return 1;
+ };
+
+
+ /**
+ * @return Return a short, printable name for this region
+ * (usually encoded name) for us logging.
+ */
+ String getShortNameToLog();
+
+ /**
+ * @return the regionId.
+ */
+ long getRegionId();
+
+ /**
+ * @return the regionName as an array of bytes.
+ * @see #getRegionNameAsString()
+ */
+ byte [] getRegionName();
+
+ /**
+ * @return Region name as a String for use in logging, etc.
+ */
+ String getRegionNameAsString();
+
+ /**
+ * @return the encoded region name.
+ */
+ String getEncodedName();
+
+ /**
+ * @return the encoded region name as an array of bytes.
+ */
+ byte [] getEncodedNameAsBytes();
+
+ /**
+ * @return the startKey.
+ */
+ byte [] getStartKey();
+
+ /**
+ * @return the endKey.
+ */
+ byte [] getEndKey();
+
+ /**
+ * @return current table name of the region
+ */
+ TableName getTable();
+
+ /**
+ * @return returns region replica id
+ */
+ int getReplicaId();
+
+ /**
+ * @return True if has been split and has daughters.
+ */
+ boolean isSplit();
+
+ /**
+ * @return True if this region is offline.
+ */
+ boolean isOffline();
+
+ /**
+ * @return True if this is a split parent region.
+ */
+ boolean isSplitParent();
+
+ /**
+ * @return true if this region is from hbase:meta.
+ */
+ boolean isMetaTable();
+
+ /**
+ * @return true if this region is from a system table.
+ */
+ boolean isSystemTable();
+
+ /**
+ * @return true if this region is a meta region.
+ */
+ boolean isMetaRegion();
+
+ /**
+ * @param rangeStartKey
+ * @param rangeEndKey
+ * @return 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)
+ */
+ boolean containsRange(byte[] rangeStartKey, byte[] rangeEndKey);
+
+ /**
+ * @param row
+ * @return true if the given row falls in this region.
+ */
+ boolean containsRow(byte[] row);
+
+ /**
+ * Does region name contain its encoded name?
+ * @param regionName region name
+ * @return boolean indicating if this a new format region
+ * name which contains its encoded name.
+ */
+ @InterfaceAudience.Private
+ static boolean hasEncodedName(final byte[] regionName) {
+ // check if region name ends in ENC_SEPARATOR
+ return (regionName.length >= 1) &&
+ (regionName[regionName.length - 1] == RegionInfo.ENC_SEPARATOR);
+ }
+
+ /**
+ * @return the encodedName
+ */
+ @InterfaceAudience.Private
+ static String encodeRegionName(final byte [] regionName) {
+ String encodedName;
+ if (hasEncodedName(regionName)) {
+ // region is in new format:
+ // <tableName>,<startKey>,<regionIdTimeStamp>/encodedName/
+ encodedName = Bytes.toString(regionName,
+ regionName.length - MD5_HEX_LENGTH - 1,
+ MD5_HEX_LENGTH);
+ } else {
+ // old format region name. First hbase:meta region also
+ // use this format.EncodedName is the JenkinsHash value.
+ HashKey<byte[]> key = new ByteArrayHashKey(regionName, 0, regionName.length);
+ int hashVal = Math.abs(JenkinsHash.getInstance().hash(key, 0));
+ encodedName = String.valueOf(hashVal);
+ }
+ return encodedName;
+ }
+
+ /**
+ * @return Return a String of short, printable names for <code>hris</code>
+ * (usually encoded name) for us logging.
+ */
+ static String getShortNameToLog(RegionInfo...hris) {
+ return getShortNameToLog(Arrays.asList(hris));
+ }
+
+ /**
+ * @return Return a String of short, printable names for <code>hris</code>
+ * (usually encoded name) for us logging.
+ */
+ static String getShortNameToLog(final List<RegionInfo> ris) {
+ return ris.stream().map(ri -> ri.getShortNameToLog()).
+ collect(Collectors.toList()).toString();
+ }
+
+ /**
+ * Gets the table name from the specified region name.
+ * @param regionName to extract the table name from
+ * @return Table name
+ */
+ @InterfaceAudience.Private
+ // This method should never be used. Its awful doing parse from bytes.
+ // It is fallback in case we can't get the tablename any other way. Could try removing it.
+ // Keeping it Audience Private so can remove at later date.
+ static TableName getTable(final byte [] regionName) {
+ int offset = -1;
+ for (int i = 0; i < regionName.length; i++) {
+ if (regionName[i] == HConstants.DELIMITER) {
+ offset = i;
+ break;
+ }
+ }
+ byte[] buff = new byte[offset];
+ System.arraycopy(regionName, 0, buff, 0, offset);
+ return TableName.valueOf(buff);
+ }
+
+ /**
+ * Gets the start key from the specified region name.
+ * @param regionName
+ * @return Start key.
+ * @throws java.io.IOException
+ */
+ static byte[] getStartKey(final byte[] regionName) throws IOException {
+ return parseRegionName(regionName)[1];
+ }
+
+ @InterfaceAudience.Private
+ static boolean isEncodedRegionName(byte[] regionName) throws IOException {
+ try {
+ parseRegionName(regionName);
+ return false;
+ } catch (IOException e) {
+ if (StringUtils.stringifyException(e)
+ .contains(INVALID_REGION_NAME_FORMAT_MESSAGE)) {
+ return true;
+ }
+ throw e;
+ }
+ }
+
+ /**
+ * @param bytes
+ * @return A deserialized {@link RegionInfo}
+ * or null if we failed deserialize or passed bytes null
+ */
+ @InterfaceAudience.Private
+ static RegionInfo parseFromOrNull(final byte [] bytes) {
+ if (bytes == null) return null;
+ return parseFromOrNull(bytes, 0, bytes.length);
+ }
+
+ /**
+ * @param bytes
+ * @param offset
+ * @param len
+ * @return A deserialized {@link RegionInfo} or null
+ * if we failed deserialize or passed bytes null
+ */
+ @InterfaceAudience.Private
+ static RegionInfo parseFromOrNull(final byte [] bytes, int offset, int len) {
+ if (bytes == null || len <= 0) return null;
+ try {
+ return parseFrom(bytes, offset, len);
+ } catch (DeserializationException e) {
+ return null;
+ }
+ }
+
+ /**
+ * @param bytes A pb RegionInfo serialized with a pb magic prefix.
+ * @return A deserialized {@link RegionInfo}
+ * @throws DeserializationException
+ */
+ @InterfaceAudience.Private
+ static RegionInfo parseFrom(final byte [] bytes) throws DeserializationException {
+ if (bytes == null) return null;
+ return parseFrom(bytes, 0, bytes.length);
+ }
+
+ /**
+ * @param bytes A pb RegionInfo serialized with a pb magic prefix.
+ * @param offset starting point in the byte array
+ * @param len length to read on the byte array
+ * @return A deserialized {@link RegionInfo}
+ * @throws DeserializationException
+ */
+ @InterfaceAudience.Private
+ static RegionInfo parseFrom(final byte [] bytes, int offset, int len)
+ throws DeserializationException {
+ if (ProtobufUtil.isPBMagicPrefix(bytes, offset, len)) {
+ int pblen = ProtobufUtil.lengthOfPBMagic();
+ try {
+ HBaseProtos.RegionInfo.Builder builder = HBaseProtos.RegionInfo.newBuilder();
+ ProtobufUtil.mergeFrom(builder, bytes, pblen + offset, len - pblen);
+ HBaseProtos.RegionInfo ri = builder.build();
+ return ProtobufUtil.toRegionInfo(ri);
+ } catch (IOException e) {
+ throw new DeserializationException(e);
+ }
+ } else {
+ throw new DeserializationException("PB encoded RegionInfo expected");
+ }
+ }
+
+ /**
+ * Check whether two regions are adjacent
+ * @param regionA
+ * @param regionB
+ * @return true if two regions are adjacent
+ */
+ static boolean areAdjacent(RegionInfo regionA, RegionInfo regionB) {
+ if (regionA == null || regionB == null) {
+ throw new IllegalArgumentException(
+ "Can't check whether adjacent for null region");
+ }
+ RegionInfo a = regionA;
+ RegionInfo b = regionB;
+ if (Bytes.compareTo(a.getStartKey(), b.getStartKey()) > 0) {
+ a = regionB;
+ b = regionA;
+ }
+ if (Bytes.compareTo(a.getEndKey(), b.getStartKey()) == 0) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @param ri
+ * @return This instance serialized as protobuf w/ a magic pb prefix.
+ * @see #parseFrom(byte[])
+ */
+ static byte [] toByteArray(RegionInfo ri) {
+ byte [] bytes = ProtobufUtil.toProtoRegionInfo(ri).toByteArray();
+ return ProtobufUtil.prependPBMagic(bytes);
+ }
+
+ /**
+ * Use logging.
+ * @param encodedRegionName The encoded regionname.
+ * @return <code>hbase:meta</code> if passed <code>1028785192</code> else returns
+ * <code>encodedRegionName</code>
+ */
+ static String prettyPrint(final String encodedRegionName) {
+ if (encodedRegionName.equals("1028785192")) {
+ return encodedRegionName + "/hbase:meta";
+ }
+ return encodedRegionName;
+ }
+
+ /**
+ * Make a region name of passed parameters.
+ * @param tableName
+ * @param startKey Can be null
+ * @param regionid Region id (Usually timestamp from when region was created).
+ * @param newFormat should we create the region name in the new format
+ * (such that it contains its encoded name?).
+ * @return Region name made of passed tableName, startKey and id
+ */
+ static byte [] createRegionName(final TableName tableName, final byte[] startKey,
+ final long regionid, boolean newFormat) {
+ return createRegionName(tableName, startKey, Long.toString(regionid), newFormat);
+ }
+
+ /**
+ * Make a region name of passed parameters.
+ * @param tableName
+ * @param startKey Can be null
+ * @param id Region id (Usually timestamp from when region was created).
+ * @param newFormat should we create the region name in the new format
+ * (such that it contains its encoded name?).
+ * @return Region name made of passed tableName, startKey and id
+ */
+ static byte [] createRegionName(final TableName tableName,
+ final byte[] startKey, final String id, boolean newFormat) {
+ return createRegionName(tableName, startKey, Bytes.toBytes(id), newFormat);
+ }
+
+ /**
+ * Make a region name of passed parameters.
+ * @param tableName
+ * @param startKey Can be null
+ * @param regionid Region id (Usually timestamp from when region was created).
+ * @param replicaId
+ * @param newFormat should we create the region name in the new format
+ * (such that it contains its encoded name?).
+ * @return Region name made of passed tableName, startKey, id and replicaId
+ */
+ static byte [] createRegionName(final TableName tableName,
+ final byte[] startKey, final long regionid, int replicaId, boolean newFormat) {
+ return createRegionName(tableName, startKey, Bytes.toBytes(Long.toString(regionid)),
+ replicaId, newFormat);
+ }
+
+ /**
+ * Make a region name of passed parameters.
+ * @param tableName
+ * @param startKey Can be null
+ * @param id Region id (Usually timestamp from when region was created).
+ * @param newFormat should we create the region name in the new format
+ * (such that it contains its encoded name?).
+ * @return Region name made of passed tableName, startKey and id
+ */
+ static byte [] createRegionName(final TableName tableName,
+ final byte[] startKey, final byte[] id, boolean newFormat) {
+ return createRegionName(tableName, startKey, id, DEFAULT_REPLICA_ID, newFormat);
+ }
+
+ /**
+ * Make a region name of passed parameters.
+ * @param tableName
+ * @param startKey Can be null
+ * @param id Region id (Usually timestamp from when region was created).
+ * @param replicaId
+ * @param newFormat should we create the region name in the new format
+ * @return Region name made of passed tableName, startKey, id and replicaId
+ */
+ static byte [] createRegionName(final TableName tableName,
+ final byte[] startKey, final byte[] id, final int replicaId, boolean newFormat) {
+ int len = tableName.getName().length + 2 + id.length + (startKey == null? 0: startKey.length);
+ if (newFormat) {
+ len += MD5_HEX_LENGTH + 2;
+ }
+ byte[] replicaIdBytes = null;
+ // Special casing: replicaId is only appended if replicaId is greater than
+ // 0. This is because all regions in meta would have to be migrated to the new
+ // name otherwise
+ if (replicaId > 0) {
+ // use string representation for replica id
+ replicaIdBytes = Bytes.toBytes(String.format(REPLICA_ID_FORMAT, replicaId));
+ len += 1 + replicaIdBytes.length;
+ }
+
+ byte [] b = new byte [len];
+
+ int offset = tableName.getName().length;
+ System.arraycopy(tableName.getName(), 0, b, 0, offset);
+ b[offset++] = HConstants.DELIMITER;
+ if (startKey != null && startKey.length > 0) {
+ System.arraycopy(startKey, 0, b, offset, startKey.length);
+ offset += startKey.length;
+ }
+ b[offset++] = HConstants.DELIMITER;
+ System.arraycopy(id, 0, b, offset, id.length);
+ offset += id.length;
+
+ if (replicaIdBytes != null) {
+ b[offset++] = REPLICA_ID_DELIMITER;
+ System.arraycopy(replicaIdBytes, 0, b, offset, replicaIdBytes.length);
+ offset += replicaIdBytes.length;
+ }
+
+ if (newFormat) {
+ //
+ // Encoded name should be built into the region name.
+ //
+ // Use the region name thus far (namely, <tablename>,<startKey>,<id>_<replicaId>)
+ // to compute a MD5 hash to be used as the encoded name, and append
+ // it to the byte buffer.
+ //
+ String md5Hash = MD5Hash.getMD5AsHex(b, 0, offset);
+ byte [] md5HashBytes = Bytes.toBytes(md5Hash);
+
+ if (md5HashBytes.length != MD5_HEX_LENGTH) {
+ System.out.println("MD5-hash length mismatch: Expected=" + MD5_HEX_LENGTH +
+ "; Got=" + md5HashBytes.length);
+ }
+
+ // now append the bytes '.<encodedName>.' to the end
+ b[offset++] = ENC_SEPARATOR;
+ System.arraycopy(md5HashBytes, 0, b, offset, MD5_HEX_LENGTH);
+ offset += MD5_HEX_LENGTH;
+ b[offset++] = ENC_SEPARATOR;
+ }
+
+ return b;
+ }
+
+ /**
+ * Separate elements of a regionName.
+ * @param regionName
+ * @return Array of byte[] containing tableName, startKey and id
+ * @throws IOException
+ */
+ static byte [][] parseRegionName(final byte[] regionName)
+ throws IOException {
+ // Region name is of the format:
+ // tablename,startkey,regionIdTimestamp[_replicaId][.encodedName.]
+ // startkey can contain the delimiter (',') so we parse from the start and end
+
+ // parse from start
+ int offset = -1;
+ for (int i = 0; i < regionName.length; i++) {
+ if (regionName[i] == HConstants.DELIMITER) {
+ offset = i;
+ break;
+ }
+ }
+ if (offset == -1) {
+ throw new IOException(INVALID_REGION_NAME_FORMAT_MESSAGE
+ + ": " + Bytes.toStringBinary(regionName));
+ }
+ byte[] tableName = new byte[offset];
+ System.arraycopy(regionName, 0, tableName, 0, offset);
+ offset = -1;
+
+ int endOffset = regionName.length;
+ // check whether regionName contains encodedName
+ if (regionName.length > MD5_HEX_LENGTH + 2
+ && regionName[regionName.length-1] == ENC_SEPARATOR
+ && regionName[regionName.length-MD5_HEX_LENGTH-2] == ENC_SEPARATOR) {
+ endOffset = endOffset - MD5_HEX_LENGTH - 2;
+ }
+
+ // parse from end
+ byte[] replicaId = null;
+ int idEndOffset = endOffset;
+ for (int i = endOffset - 1; i > 0; i--) {
+ if (regionName[i] == REPLICA_ID_DELIMITER) { //replicaId may or may not be present
+ replicaId = new byte[endOffset - i - 1];
+ System.arraycopy(regionName, i + 1, replicaId, 0,
+ endOffset - i - 1);
+ idEndOffset = i;
+ // do not break, continue to search for id
+ }
+ if (regionName[i] == HConstants.DELIMITER) {
+ offset = i;
+ break;
+ }
+ }
+ if (offset == -1) {
+ throw new IOException(INVALID_REGION_NAME_FORMAT_MESSAGE
+ + ": " + Bytes.toStringBinary(regionName));
+ }
+ byte [] startKey = HConstants.EMPTY_BYTE_ARRAY;
+ if(offset != tableName.length + 1) {
+ startKey = new byte[offset - tableName.length - 1];
+ System.arraycopy(regionName, tableName.length + 1, startKey, 0,
+ offset - tableName.length - 1);
+ }
+ byte [] id = new byte[idEndOffset - offset - 1];
+ System.arraycopy(regionName, offset + 1, id, 0,
+ idEndOffset - offset - 1);
+ byte [][] elements = new byte[replicaId == null ? 3 : 4][];
+ elements[0] = tableName;
+ elements[1] = startKey;
+ elements[2] = id;
+ if (replicaId != null) {
+ elements[3] = replicaId;
+ }
+ return elements;
+ }
+
+ /**
+ * Serializes given RegionInfo's as a byte array. Use this instead of
+ * {@link RegionInfo#toByteArray(RegionInfo)} when
+ * writing to a stream and you want to use the pb mergeDelimitedFrom (w/o the delimiter, pb reads
+ * to EOF which may not be what you want). {@link #parseDelimitedFrom(byte[], int, int)} can
+ * be used to read back the instances.
+ * @param infos RegionInfo objects to serialize
+ * @return This instance serialized as a delimited protobuf w/ a magic pb prefix.
+ * @throws IOException
+ */
+ static byte[] toDelimitedByteArray(RegionInfo... infos) throws IOException {
+ byte[][] bytes = new byte[infos.length][];
+ int size = 0;
+ for (int i = 0; i < infos.length; i++) {
+ bytes[i] = toDelimitedByteArray(infos[i]);
+ size += bytes[i].length;
+ }
+
+ byte[] result = new byte[size];
+ int offset = 0;
+ for (byte[] b : bytes) {
+ System.arraycopy(b, 0, result, offset, b.length);
+ offset += b.length;
+ }
+ return result;
+ }
+
+ /**
+ * Use this instead of {@link RegionInfo#toByteArray(RegionInfo)} when writing to a stream and you want to use
+ * the pb mergeDelimitedFrom (w/o the delimiter, pb reads to EOF which may not be what you want).
+ * @param ri
+ * @return This instance serialized as a delimied protobuf w/ a magic pb prefix.
+ * @throws IOException
+ */
+ static byte [] toDelimitedByteArray(RegionInfo ri) throws IOException {
+ return ProtobufUtil.toDelimitedByteArray(ProtobufUtil.toProtoRegionInfo(ri));
+ }
+
+ /**
+ * Parses an RegionInfo instance from the passed in stream.
+ * Presumes the RegionInfo was serialized to the stream with
+ * {@link #toDelimitedByteArray(RegionInfo)}.
+ * @param in
+ * @return An instance of RegionInfo.
+ * @throws IOException
+ */
+ static RegionInfo parseFrom(final DataInputStream in) throws IOException {
+ // I need to be able to move back in the stream if this is not a pb
+ // serialization so I can do the Writable decoding instead.
+ int pblen = ProtobufUtil.lengthOfPBMagic();
+ byte [] pbuf = new byte[pblen];
+ if (in.markSupported()) { //read it with mark()
+ in.mark(pblen);
+ }
+
+ //assumption: if Writable serialization, it should be longer than pblen.
+ int read = in.read(pbuf);
+ if (read != pblen) throw new IOException("read=" + read + ", wanted=" + pblen);
+ if (ProtobufUtil.isPBMagicPrefix(pbuf)) {
+ return ProtobufUtil.toRegionInfo(HBaseProtos.RegionInfo.parseDelimitedFrom(in));
+ } else {
+ throw new IOException("PB encoded RegionInfo expected");
+ }
+ }
+
+ /**
+ * Parses all the RegionInfo instances from the passed in stream until EOF. Presumes the
+ * RegionInfo's were serialized to the stream with oDelimitedByteArray()
+ * @param bytes serialized bytes
+ * @param offset the start offset into the byte[] buffer
+ * @param length how far we should read into the byte[] buffer
+ * @return All the RegionInfos that are in the byte array. Keeps reading till we hit the end.
+ * @throws IOException
+ */
+ static List<RegionInfo> parseDelimitedFrom(final byte[] bytes, final int offset,
+ final int length) throws IOException {
+ if (bytes == null) {
+ throw new IllegalArgumentException("Can't build an object with empty bytes array");
+ }
+ DataInputBuffer in = new DataInputBuffer();
+ List<RegionInfo> ris = new ArrayList<>();
+ try {
+ in.reset(bytes, offset, length);
+ while (in.available() > 0) {
+ RegionInfo ri = parseFrom(in);
+ ris.add(ri);
+ }
+ } finally {
+ in.close();
+ }
+ return ris;
+ }
+}
\ No newline at end of file