Index: hbase-server/src/test/java/org/apache/hadoop/hbase/schema/TestFixedLengthRowKey.java =================================================================== --- hbase-server/src/test/java/org/apache/hadoop/hbase/schema/TestFixedLengthRowKey.java (revision 0) +++ hbase-server/src/test/java/org/apache/hadoop/hbase/schema/TestFixedLengthRowKey.java (revision 0) @@ -0,0 +1,82 @@ +/** + * + * 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.schema; + +import org.junit.Assert; +import org.junit.Test; + +public class TestFixedLengthRowKey { + + private int hashVal = 4; + private int intVal = 5; + private long longVal = 6; + private byte byteVal = '7'; + private byte[] bytesVal = {'1', '2', '3', '4', '6', '7'}; // arbitrary set of bytes + + @Test + public void testCreate() throws Exception { + + RowKeySchema schema = new RowKeySchema.Builder() + .add(RowKeySchema.MD5_HASH) + .add(RowKeySchema.INT) + .add(RowKeySchema.LONG) + .add(RowKeySchema.BYTE) + .add(new RowKeyBytesElement(bytesVal.length)) + .build(); + + FixedLengthRowKey rowkey = schema.createFixedLengthRowKey(); + rowkey.setInt(0, hashVal); // this will hash the int because the schema definition says so. + rowkey.setInt(1, intVal); + rowkey.setLong(2, longVal); + rowkey.setByte(3, byteVal); + rowkey.setBytes(4, bytesVal); + + byte bytes[] = rowkey.getBytes(); + Assert.assertEquals("key length", schema.getRowKeyLength(), bytes.length); + + Assert.assertEquals("e0", rowkey.getBytes(0).length, RowKeySchema.MD5_HASH.getLength()); + Assert.assertEquals("e1", rowkey.getInt(1), intVal); + Assert.assertEquals("e2", rowkey.getLong(2), longVal); + Assert.assertEquals("e3", rowkey.getByte(3), byteVal); + Assert.assertEquals("e4", rowkey.getBytes(4).length, bytesVal.length); + } + + @Test + public void testNegativeCreate() { + + RowKeySchema schema = new RowKeySchema.Builder() + .add(RowKeySchema.MD5_HASH) + .add(RowKeySchema.INT) + .add(RowKeySchema.LONG) + .build(); + + boolean passed = true; + try { + FixedLengthRowKey rowkey = schema.createFixedLengthRowKey(); + rowkey.setLong(1, longVal); // trying to set 'long' on an element that is sized for an int. + } catch (Exception e) { + // we are expecting a sizing exception because we are + // setting a long onto an element sized for an int. + passed = false; + } + if (passed) { + Assert.fail("Test did not fail!"); + } + } +} Index: hbase-server/src/main/java/org/apache/hadoop/hbase/schema/FixedLengthRowKey.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/schema/FixedLengthRowKey.java (revision 0) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/schema/FixedLengthRowKey.java (revision 0) @@ -0,0 +1,257 @@ +/** + * + * 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.schema; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import org.apache.hadoop.hbase.util.Bytes; +import org.apache.hadoop.hbase.util.MurmurHash; + +/** + * A stateful utility class for creating and reading rowkeys for HBase tables, particularly composite keys. + * FixedLengthRowKey creates fixed length keys without the need for delimeters in between key elements + * (i.e., parts of the rowkey), which is a best practice in HBase. + * FixedLengthRowKey instances are instantiated from an associated RowKeySchema, which defines the row key + * elements and their lengths.
+ *
+ *    RowKeySchema schema = new RowKeySchema.Builder()
+ *   .add(RowKeySchema.MD5_HASH)
+ *   .add(RowKeySchema.INT)
+ *   .add(RowKeySchema.LONG)
+ *   .add(RowKeySchema.BYTE)
+ *   .add(new RowKeyBytesElement(bytesVal.length)) 
+ *   .build();
+ *   
+ *   FixedLengthRowKey rowkey = schema.createFixedLengthRowKey();
+ *   rowkey.setInt(0, hashVal);  // this will hash the int because the schema definition says so.
+ *   rowkey.setInt(1, intVal);
+ *   rowkey.setLong(2, longVal);
+ *   rowkey.setByte(3, byteVal);
+ *   rowkey.setBytes(4, bytesVal);
+ * 
+ * In the example above, the rowkey consists of 5 key elements: an MD5 hash, followed by an int, followed by a long, + * followed by a byte, followed by an arbitrary number of fixed bytes supplied by the user. + * The FixedLengthRowKey instance is used to set the values of the key elements (setInt, setLong), and then obtaining + * the constructed byte=array to be used as the rowkey in the table. + *

+ * FixedLengthRowKey instances should NOT be considered thread-safe, particularly for MD5 hashing. + *

+ * FixedLengthRowKey instances can be re-used by calling reset() and will conform to the RowKeySchema specified on creation. + * This can be used when reading a number of rows from HBase in sequence, for example: + *
+ *
+ *   for (   ) {
+ *     byte[] row = result.getRow();
+ *     rowkey.setBytes(row);
+ *     int i = rowkey.getInt(1);
+ *   }
+ * 
+ * + * @see org.apache.hadoop.hbase.schema.RowKeySchema + * + */ +public class FixedLengthRowKey { + + private static final String MD5 = "MD5"; + private byte bytes[] = null; + private MessageDigest digest = null; + private MurmurHash murmur = null; + private RowKeySchema schema = null; + private RowKeyDataConverter converter = null; + + /** + * + * @param schema RowKeySchema instance that describes the format of the rowkey + */ + public FixedLengthRowKey(RowKeySchema schema) { + this.schema = schema; + this.converter = schema.getDataConverter(); + bytes = new byte[schema.getRowKeyLength()]; + } + + /** + * This method is used to set the entire backing byte array. Use this, for example, + * when a RowKey instance is used to read/process elements of a rowkey obtained from a table. + * + * The byte array must be consistent with the RowKeySchema that created this RowKey instance. + * + * @param bytes + */ + public void setBytes(byte[] bytes) { + this.bytes = bytes; + } + + /** + * Returns a byte at the specified key element position. + * + * @param elementPosition zero-based index of key element + * @return byte + */ + public byte getByte(int elementPosition) { + return bytes[schema.getRowKeyStartPosition(elementPosition)]; + } + + /** + * Returns an int at the specified key element position. + * + * @param elementPosition zero-based index of key element + * @return int + */ + public int getInt(int elementPosition) { + return converter.toInt(getBytes(elementPosition)); + } + + /** + * Returns a long at the specified key element position. + * + * @param elementPosition zero-based index of key element + * @return long + */ + public long getLong(int elementPosition) { + return converter.toLong(getBytes(elementPosition)); + } + + /** + * + * Returns the byte array at the specified key element position. + * + * @param elementPosition zero-based index of key element + * @return byte array + */ + public byte[] getBytes(int elementPosition) { + int elementLength = schema.getElementLength(elementPosition); + byte[] b = new byte[elementLength]; + System.arraycopy(bytes, schema.getRowKeyStartPosition(elementPosition), b, 0, elementLength); + return b; + } + + /** + * Addds a byte to the rowkey at the specified key element position. + * + * @param elementPosition zero-based index of key element + * @param b byte + */ + public void setByte(int elementPosition, byte b) { + byte tb[] = new byte[1]; + tb[0] = b; + setBytes(elementPosition, tb); + } + + /** + * Adds an int to the rowkey at the specified key element position + * + * @param elementPosition zero-based index of key element + * @param i (int) + */ + public void setInt(int elementPosition, int i) { + setBytes(elementPosition, converter.toBytes(i)); + } + + /** + * Adds a long to the rowkey at the specified key element position + * + * @param elementPosition zero-based index of key element + * @param l (long) + */ + public void setLong(int elementPosition, long l) { + setBytes(elementPosition, converter.toBytes(l)); + } + + /** + * Adds a bytearray to the rowkey at the specified key element position + * + * @param elementPosition zero-based index of key element + * @param b (bytes) + */ + public void setBytes(int elementPosition, byte[] b) { + RowKeyElement element = schema.getElement(elementPosition); + if (!(element instanceof RowKeyHashElement)) { + int elementLength = schema.getElementLength(elementPosition); + if (elementLength != b.length) { + throw new RuntimeException("KeyElement wrong size! keyElement:" + elementPosition + " expected " + + elementLength + " was " + b.length); + } + System.arraycopy(b, 0, bytes, schema.getRowKeyStartPosition(elementPosition), b.length); + } else if (element instanceof RowKeyMD5Element) { + setMD5Hash(elementPosition, b); + } else if (element instanceof RowKeyMurmurElement) { + setMurmurHash(elementPosition, b); + } + } + + /** + * Adds an array of bytes, which will be MD5 hashed, to the rowkey at the specified key element position + * + * @param elementPosition zero-based index of key element + * @param b (bytes that will be hashed) + */ + protected void setMurmurHash(int elementPosition, byte[] b) { + if (murmur == null) { + murmur = new MurmurHash(); + } + int n = murmur.hash(b); + byte mb[] = Bytes.toBytes(n); + int elementLength = schema.getElementLength(elementPosition); + if (elementLength != mb.length) { + throw new RuntimeException("KeyElement wrong size! keyElement:" + elementPosition + " expected " + + elementLength + " was " + mb.length); + } + System.arraycopy(mb, 0, bytes, schema.getRowKeyStartPosition(elementPosition), mb.length); + } + + /** + * Adds an array of bytes, which will be MD5 hashed, to the rowkey at the specified key element position + * + * @param elementPosition zero-based index of key element + * @param b (bytes that will be hashed) + */ + protected void setMD5Hash(int elementPosition, byte[] b) { + if (digest == null) { + try { + digest = MessageDigest.getInstance(MD5); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + byte[] dig = digest.digest(b); + int elementLength = schema.getElementLength(elementPosition); + if (elementLength != dig.length) { + throw new RuntimeException("KeyElement wrong size! keyElement:" + elementPosition + " expected " + + elementLength + " was " + dig.length); + } + System.arraycopy(dig, 0, bytes, schema.getRowKeyStartPosition(elementPosition), dig.length); + } + + /** + * + * @return byte array backing the RowKey. 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 by the RowKeySchema + * when the RowKey was constructed + */ + public void reset() { + bytes = new byte[schema.getRowKeyLength()]; + } + +} Index: hbase-server/src/main/java/org/apache/hadoop/hbase/schema/RowKeyByteElement.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/schema/RowKeyByteElement.java (revision 0) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/schema/RowKeyByteElement.java (revision 0) @@ -0,0 +1,33 @@ +/** + * + * 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.schema; + +import org.apache.hadoop.hbase.util.Bytes; + +/** + * RowKeySchema element that indicates that the value is a byte. + * + */ +public class RowKeyByteElement extends RowKeyElement { + + @Override + public int getLength() { + return Bytes.SIZEOF_BYTE; + } +} Index: hbase-server/src/main/java/org/apache/hadoop/hbase/schema/RowKeyBytesElement.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/schema/RowKeyBytesElement.java (revision 0) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/schema/RowKeyBytesElement.java (revision 0) @@ -0,0 +1,39 @@ +/** + * + * 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.schema; + +/** + * + * RowKeySchema element that indicates that the value is an byte-array of configured length, + * with the contents being defined by the caller. + * + */ +public class RowKeyBytesElement extends RowKeyElement { + + private int bytes = 0; + + public RowKeyBytesElement(int bytes) { + this.bytes = bytes; + } + + @Override + public int getLength() { + return bytes; + } +} Index: hbase-server/src/main/java/org/apache/hadoop/hbase/schema/RowKeyDataConverter.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/schema/RowKeyDataConverter.java (revision 0) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/schema/RowKeyDataConverter.java (revision 0) @@ -0,0 +1,46 @@ +/** + * + * 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.schema; + +import org.apache.hadoop.hbase.util.Bytes; + +/** + * RowKeyDataConverter is a strategy pattern for datatype conversion that is used + * within FixedLengthRowKey. + * + */ +public class RowKeyDataConverter { + + public long toLong(byte[] b) { + return Bytes.toLong(b); + } + + public byte[] toBytes(long l) { + return Bytes.toBytes(l); + } + + public byte[] toBytes(int i) { + return Bytes.toBytes(i); + } + + public int toInt(byte[] b) { + return Bytes.toInt(b); + } + +} Index: hbase-server/src/main/java/org/apache/hadoop/hbase/schema/RowKeyElement.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/schema/RowKeyElement.java (revision 0) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/schema/RowKeyElement.java (revision 0) @@ -0,0 +1,29 @@ +/** + * + * 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.schema; + +/** + * Base class for RowKeySchema elements + * + */ +public abstract class RowKeyElement { + + public abstract int getLength(); + +} Index: hbase-server/src/main/java/org/apache/hadoop/hbase/schema/RowKeyHashElement.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/schema/RowKeyHashElement.java (revision 0) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/schema/RowKeyHashElement.java (revision 0) @@ -0,0 +1,28 @@ +/** + * + * 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.schema; + +/** + * Abstract RowKeySchema element indicating that values are to be hashed. + * + */ +public abstract class RowKeyHashElement extends RowKeyElement { + + +} Index: hbase-server/src/main/java/org/apache/hadoop/hbase/schema/RowKeyIntElement.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/schema/RowKeyIntElement.java (revision 0) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/schema/RowKeyIntElement.java (revision 0) @@ -0,0 +1,33 @@ +/** + * + * 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.schema; + +import org.apache.hadoop.hbase.util.Bytes; + +/** + * RowKeySchema element that indicates that the value is a int. + * + */ +public class RowKeyIntElement extends RowKeyElement { + + @Override + public int getLength() { + return Bytes.SIZEOF_INT; + } +} \ No newline at end of file Index: hbase-server/src/main/java/org/apache/hadoop/hbase/schema/RowKeyLongElement.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/schema/RowKeyLongElement.java (revision 0) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/schema/RowKeyLongElement.java (revision 0) @@ -0,0 +1,33 @@ +/** + * + * 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.schema; + +import org.apache.hadoop.hbase.util.Bytes; + +/** + * RowKeySchema element that indicates that the value is a long. + * + */ +public class RowKeyLongElement extends RowKeyElement { + + @Override + public int getLength() { + return Bytes.SIZEOF_LONG; + } +} Index: hbase-server/src/main/java/org/apache/hadoop/hbase/schema/RowKeyMD5Element.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/schema/RowKeyMD5Element.java (revision 0) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/schema/RowKeyMD5Element.java (revision 0) @@ -0,0 +1,31 @@ +/** + * + * 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.schema; + +/** + * RowKeySchema element that indicates that the value should be MD5 hashed. + * + */ +public class RowKeyMD5Element extends RowKeyHashElement { + + @Override + public int getLength() { + return 16; + } +} Index: hbase-server/src/main/java/org/apache/hadoop/hbase/schema/RowKeyMurmurElement.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/schema/RowKeyMurmurElement.java (revision 0) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/schema/RowKeyMurmurElement.java (revision 0) @@ -0,0 +1,33 @@ +/** + * + * 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.schema; + +import org.apache.hadoop.hbase.util.Bytes; + +/** + * RowKeySchema element that indicates that the value should be Murmur hashed. + * + */ +public class RowKeyMurmurElement extends RowKeyHashElement { + + @Override + public int getLength() { + return Bytes.SIZEOF_INT; + } +} Index: hbase-server/src/main/java/org/apache/hadoop/hbase/schema/RowKeySchema.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/schema/RowKeySchema.java (revision 0) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/schema/RowKeySchema.java (revision 0) @@ -0,0 +1,163 @@ +/** + * + * 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.schema; + +import java.util.ArrayList; +import java.util.List; + +/** + * Utility class used to define the schema of a RowKey. + * An instance of RowKeySchema is created by defining an array of integers representing the + * lengths of the key elements (i.e., parts) of the rowkey.
+ * + *
+ *    RowKeySchema schema = new RowKeySchema.Builder()
+ *   .add(RowKeySchema.MD5_HASH)
+ *   .add(RowKeySchema.INT)
+ *   .add(RowKeySchema.LONG)
+ *   .add(RowKeySchema.BYTE)
+ *   .add(new RowKeyBytesElement(bytesVal.length)) 
+ *   .build();
+ *   
+ *   FixedLengthRowKey rowkey = schema.createFixedLengthRowKey();
+ * 
+ *
+ * In the example above, the rowkey consists of 5 key elements: an MD5 hash, followed by an int, followed by a long, + * followed by a byte, followed by an arbitrary number of fixed bytes supplied by the user. + * + *
+ * @see org.apache.hbase.schema.FixedLengthRowKey + * + */ +public class RowKeySchema { + + public static final RowKeyByteElement BYTE = new RowKeyByteElement(); + public static final RowKeyIntElement INT = new RowKeyIntElement(); + public static final RowKeyLongElement LONG = new RowKeyLongElement(); + public static final RowKeyMD5Element MD5_HASH = new RowKeyMD5Element(); + public static final RowKeyMurmurElement MURMUR_HASH = new RowKeyMurmurElement(); + + private List elements = new ArrayList(); + + private int rowKeyLength = 0; + private int[] startPositions = null; + + private RowKeyDataConverter converter = null; + + protected RowKeySchema(Builder builder) { + converter = builder.getDataConverter(); + elements.addAll(builder.getElements()); + startPositions = new int[elements.size()]; + + for (int i = 0; i < elements.size(); i++) { + startPositions[i] = rowKeyLength; + rowKeyLength += elements.get(i).getLength(); + } + } + + /** + * + * @param keyElement zero-based index of a key element in this schema. + * @return length of byte array of the key element specified. + */ + public RowKeyElement getElement(int keyElement) { + return elements.get(keyElement); + } + + /** + * + * @param keyElement zero-based index of a key element in this schema. + * @return length of byte array of the key element specified. + */ + public int getElementLength(int keyElement) { + return elements.get(keyElement).getLength(); + } + + /** + * + * @return number of key elements (components) in this schema. + */ + public int getNumberOfElements() { + return elements.size(); + } + + /** + * + * @return total length of the rowkey based on this schema + */ + public int getRowKeyLength() { + return rowKeyLength; + } + + /** + * + * @return FixedLengthRowKey instance that conforms to this schema + */ + public FixedLengthRowKey createFixedLengthRowKey() { + return new FixedLengthRowKey(this); + } + + /** + * + * @param keyElement zero-based index of the specified key element in this schema + * @return start position in the backing byte-array for this key element. + */ + public int getRowKeyStartPosition(int keyElement) { + return startPositions[keyElement]; + } + + /** + * + * @return RowKeyDataConverter + */ + public RowKeyDataConverter getDataConverter() { + return converter; + } + + /** + * Builder pattern for creating RowKeySchema instances + * + */ + public static class Builder { + + private List elements = new ArrayList(); + private RowKeyDataConverter converter = new RowKeyDataConverter(); + + public List getElements() { + return elements; + } + + public Builder add(RowKeyElement element) { + elements.add(element); + return this; + } + + public void set(RowKeyDataConverter converter) { + this.converter = converter; + } + + public RowKeyDataConverter getDataConverter() { + return this.converter; + } + + public RowKeySchema build() { + return new RowKeySchema(this); + } + } +}