From 1e29d1a114dbae3661b2a7f9d867bd4a59d44864 Mon Sep 17 00:00:00 2001 From: Nick Dimiduk Date: Tue, 16 Jul 2013 14:45:03 -0700 Subject: [PATCH 2/2] HBASE-8693 [example] Use DataType API to build regionNames This is an example of using the HDataType classes to manage HRegionInfo's regionName. It could probably be taken a step further to manage the MD5Hash as a LegacyBytesFixedLength, then the size of the allocated buffer could be calculated with HREGIONINFO_NEW_CODEC$encodedLength() instead of by hand. --- .../java/org/apache/hadoop/hbase/HRegionInfo.java | 77 ++++++++++++---------- .../hadoop/hbase/regionserver/TestHRegionInfo.java | 4 +- 2 files changed, 45 insertions(+), 36 deletions(-) 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 d057ce3..d9473df 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 @@ -25,6 +25,7 @@ import java.io.DataOutput; import java.io.EOFException; import java.io.IOException; import java.io.SequenceInputStream; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -39,6 +40,10 @@ import org.apache.hadoop.hbase.exceptions.DeserializationException; import org.apache.hadoop.hbase.protobuf.ProtobufUtil; import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos; import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionInfo; +import org.apache.hadoop.hbase.types.LegacyBytes; +import org.apache.hadoop.hbase.types.LegacyBytesTerminated; +import org.apache.hadoop.hbase.types.Struct; +import org.apache.hadoop.hbase.types.StructBuilder; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.JenkinsHash; import org.apache.hadoop.hbase.util.MD5Hash; @@ -82,19 +87,19 @@ public class HRegionInfo implements Comparable { public static final byte VERSION = 1; private static final Log LOG = LogFactory.getLog(HRegionInfo.class); - /** + /* * 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> + * is a hex version of the MD5 hash of + * ,, * * 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). *

@@ -114,6 +119,24 @@ public class HRegionInfo implements Comparable { /** A non-capture group so that this can be embedded. */ public static final String ENCODED_REGION_NAME_REGEX = "(?:[a-f0-9]+)"; + /** An HDataType for serializing the new format. */ + protected static final Struct HREGIONINFO_NEW_CODEC = + // this differs from the ",," described above + new StructBuilder() + .add(new LegacyBytesTerminated(",")) + .add(new LegacyBytesTerminated(",")) + .add(new LegacyBytesTerminated(new byte[] { ENC_SEPARATOR })) + .add(new LegacyBytesTerminated(new byte[] { ENC_SEPARATOR })) + .toStruct(); + + /** An HDataType for serializing the old format. */ + protected static final Struct HREGIONINFO_OLD_CODEC = + new StructBuilder() + .add(new LegacyBytesTerminated(",")) + .add(new LegacyBytesTerminated(",")) + .add(new LegacyBytes()) + .toStruct(); + /** * Does region name contain its encoded name? * @param regionName region name @@ -139,9 +162,8 @@ public class HRegionInfo implements Comparable { if (hasEncodedName(regionName)) { // region is in new format: // ,,/encodedName/ - encodedName = Bytes.toString(regionName, - regionName.length - MD5_HEX_LENGTH - 1, - MD5_HEX_LENGTH); + ByteBuffer buff = ByteBuffer.wrap(regionName); + encodedName = (String) HREGIONINFO_NEW_CODEC.read(buff, 3); } else { // old format region name. First META region also // use this format.EncodedName is the JenkinsHash value. @@ -212,7 +234,6 @@ public class HRegionInfo implements Comparable { * first meta regions */ private HRegionInfo(long regionId, byte[] tableName) { - super(); this.regionId = regionId; this.tableName = tableName.clone(); // Note: First Meta regions names are still in old format @@ -226,9 +247,7 @@ public class HRegionInfo implements Comparable { * @deprecated Used by Writables and Writables are going away. */ @Deprecated - public HRegionInfo() { - super(); - } + public HRegionInfo() {} public HRegionInfo(final byte[] tableName) { this(tableName, null, null); @@ -280,7 +299,6 @@ public class HRegionInfo implements Comparable { final byte[] endKey, final boolean split, final long regionid) throws IllegalArgumentException { - super(); if (tableName == null) { throw new IllegalArgumentException("tableName cannot be null"); } @@ -306,7 +324,6 @@ public class HRegionInfo implements Comparable { * @param other */ public HRegionInfo(HRegionInfo other) { - super(); this.endKey = other.getEndKey(); this.offLine = other.isOffline(); this.regionId = other.getRegionId(); @@ -360,20 +377,15 @@ public class HRegionInfo implements Comparable { */ public static byte [] createRegionName(final byte [] tableName, final byte [] startKey, final byte [] id, boolean newFormat) { - byte [] b = new byte [tableName.length + 2 + id.length + + ByteBuffer b = ByteBuffer.allocate(tableName.length + 2 + id.length + (startKey == null? 0: startKey.length) + - (newFormat ? (MD5_HEX_LENGTH + 2) : 0)]; - - int offset = tableName.length; - System.arraycopy(tableName, 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; + (newFormat ? (MD5_HEX_LENGTH + 2) : 0)); + + Object[] fields = new Object[newFormat ? 4 : 3]; + fields[0] = tableName; + fields[1] = null != startKey ? startKey : new byte[0]; + fields[2] = id; + HREGIONINFO_OLD_CODEC.write(b, newFormat ? Arrays.copyOf(fields, 3) : fields); if (newFormat) { // @@ -383,7 +395,7 @@ public class HRegionInfo implements Comparable { // 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); + String md5Hash = MD5Hash.getMD5AsHex(b.array(), 0, b.position()); byte [] md5HashBytes = Bytes.toBytes(md5Hash); if (md5HashBytes.length != MD5_HEX_LENGTH) { @@ -392,13 +404,12 @@ public class HRegionInfo implements Comparable { } // now append the bytes '..' to the end - b[offset++] = ENC_SEPARATOR; - System.arraycopy(md5HashBytes, 0, b, offset, MD5_HEX_LENGTH); - offset += MD5_HEX_LENGTH; - b[offset++] = ENC_SEPARATOR; + fields[3] = md5HashBytes; + b.clear(); + HREGIONINFO_NEW_CODEC.write(b, fields); } - return b; + return b.array(); } /** diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestHRegionInfo.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestHRegionInfo.java index 8e06d7d..c95e4c2 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestHRegionInfo.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestHRegionInfo.java @@ -20,20 +20,18 @@ package org.apache.hadoop.hbase.regionserver; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.IOException; import org.apache.hadoop.fs.FileStatus; -import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; -import org.apache.hadoop.hbase.exceptions.DeserializationException; import org.apache.hadoop.hbase.HBaseTestingUtility; import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.HTableDescriptor; import org.apache.hadoop.hbase.SmallTests; +import org.apache.hadoop.hbase.exceptions.DeserializationException; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.MD5Hash; import org.junit.Test; -- 1.8.3.2