Index: hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestRowKeyBuilder.java =================================================================== --- hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestRowKeyBuilder.java (revision 0) +++ hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestRowKeyBuilder.java (revision 0) @@ -0,0 +1,93 @@ +/* + * 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.util; + +import java.nio.ByteBuffer; + +import org.apache.hadoop.hbase.util.Bytes; +import org.junit.Assert; +import org.junit.Test; +import org.apache.hadoop.hbase.SmallTests; +import org.junit.experimental.categories.Category; + +@Category(SmallTests.class) +public class TestRowKeyBuilder { + + private int a = 5; + private long b = 6; + + + @Test + public void testInt() { + RowKey key = RowKey.create(RowKey.SIZEOF_INT); + key.add(a); + + byte bytes[] = key.getBytes(); + Assert.assertEquals("key length", RowKey.SIZEOF_INT, bytes.length); + + byte aBytes[] = Bytes.toBytes(a); + compareArrays(bytes, aBytes); + } + + @Test + public void testLong() { + RowKey key = RowKey.create(RowKey.SIZEOF_LONG); + key.add(b); + + byte bytes[] = key.getBytes(); + Assert.assertEquals("key length", RowKey.SIZEOF_LONG, bytes.length); + + byte aBytes[] = Bytes.toBytes(b); + compareArrays(bytes, aBytes); + } + + @Test + public void testHash() throws Exception { + RowKey key = RowKey.create(RowKey.SIZEOF_MD5_HASH); + key.addHash(a); + + byte bytes[] = key.getBytes(); + Assert.assertEquals("key length", RowKey.SIZEOF_MD5_HASH, bytes.length); + } + + @Test + public void testHashComposite() throws Exception { + // + // this tests creating a composite key with an MD5 hash in the lead position, followed by a long. + // + int expectedLength = RowKey.SIZEOF_MD5_HASH + RowKey.SIZEOF_LONG; + + RowKey key = RowKey.create(expectedLength); + key.addHash(b); + key.add(b); + + byte bytes[] = key.getBytes(); + Assert.assertEquals("key length", expectedLength, bytes.length); + } + + + private void compareArrays(byte a[], byte[] b) { + if (a.length != b.length) { + Assert.fail("Byte arrays not the same length"); + } + for (int i = 0; i < a.length; i++) { + if (a[i] != b[i]) { + Assert.fail("Byte arrays not the same at position " + i); + } + } + } +} Index: hbase-common/src/main/java/org/apache/hadoop/hbase/util/RowKeyBuilder.java =================================================================== --- hbase-common/src/main/java/org/apache/hadoop/hbase/util/RowKeyBuilder.java (revision 0) +++ hbase-common/src/main/java/org/apache/hadoop/hbase/util/RowKeyBuilder.java (revision 0) @@ -0,0 +1,168 @@ +/** + * + * 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.util; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import org.apache.hadoop.hbase.util.Bytes; + +/** + * A stateful utility class for creating rowkeys for HBase tables, particularly composite keys.
+ * The length of the key must be known upon construction of each RowKeyBuilder instance and will not auto-expand. + * RowKeyBuilder instances can be constructed and used as follows: + *
+ *   RowKeyBuilder key = RowKeyBuilder.create(RowKey.SIZEOF_MD5_HASH + RowKey.SIZEOF_LONG);
+ *   key.addHash(a);
+ *   key.add(b);
+ *   byte bytes[] = key.getBytes();    
+ * 
+ * The above example specifies that the key is comprised of an MD5 hash followed by a long. + * + */ +public class RowKeyBuilder { + + private static final String MD5 = "MD5"; + + public static final int SIZEOF_MD5_HASH = 16; + public static final int SIZEOF_BYTE = Bytes.SIZEOF_BYTE; + public static final int SIZEOF_INT = Bytes.SIZEOF_INT; + public static final int SIZEOF_LONG = Bytes.SIZEOF_LONG; + + private byte bytes[] = null; + int pos = 0; + private MessageDigest digest = null; + + private RowKeyBuilder(int length) { + bytes = new byte[length]; + } + + /** + * Addds a byte to the rowkey. + * + * @param b byte + */ + public void add(byte b) { + add(b); + } + + /** + * Adds an int to the rowkey + * + * @param i (int) + */ + public void add(int i) { + add(Bytes.toBytes(i)); + } + + /** + * Adds a long to the rowkey + * + * @param l (long) + */ + public void add(long l) { + add(Bytes.toBytes(l)); + } + + /** + * Adds a bytearray to the rowkey + * + * @param b (bytes) + */ + public void add(byte[] b) { + System.arraycopy(b, 0, bytes, pos, b.length); + pos += b.length; + } + + /** + * Adds an int, which will be MD5 hashed, to the rowkey. + * + * @param i (int that will be hashed) + * @throws NoSuchAlgorithmException + */ + public void addHash(int i) throws NoSuchAlgorithmException { + addHash(Bytes.toBytes(i)); + } + + /** + * Adds a long, which will be MD5 hashed, to the rowkey. + * + * @param l (long that will be hashed) + * @throws NoSuchAlgorithmException + */ + public void addHash(long l) throws NoSuchAlgorithmException { + addHash(Bytes.toBytes(l)); + } + + /** + * Adds a String, which will be MD5 hashed, to the rowkey. + * + * @param s (String that will be hashed) + * @throws NoSuchAlgorithmException + */ + public void addHash(String s) throws NoSuchAlgorithmException { + addHash(s.getBytes()); + } + + /** + * Adds an array of bytes, which will be MD5 hashed, to the rowkey. + * + * @param b (bytes that will be hashed) + * @throws NoSuchAlgorithmException + */ + public void addHash(byte[] b) throws NoSuchAlgorithmException { + if (digest == null) { + digest = MessageDigest.getInstance(MD5); + } + byte[] dig = digest.digest(b); + add(dig); + } + + /** + * + * @return byte array backing the RowKeyBuilder. These are the bytes that can be used as the rowkey in your HBase table. + */ + public byte[] getBytes() { + return bytes; + } + + /** + * Resets and empties the backing byte array to the same length originally specified when constructed. + */ + public void reset() { + int l = bytes.length; + bytes = new byte[l]; + } + + /** + * Factory method for creating a RowKeyBuilder instance. The length of the key must be known upon construction of each + * RowKeyBuilder instance and will not auto-resize. RowKeyBuilder instances can be created as follows: + *
+   *   RowKeyBuilder key = RowKeyBuilder.create(RowKey.SIZEOF_MD5_HASH + RowKey.SIZEOF_LONG);
+   * 
+ * The above example specifies that the key is to be comprised of an MD5 hash followed by a long. + * + * @param length The total length of the RowKey + * @return RowKeyBuilder + */ + public static RowKeyBuilder create(int length) { + return new RowKeyBuilder(length); + } + +}