Index: hbase-protocol/src/main/protobuf/hbase.proto =================================================================== --- hbase-protocol/src/main/protobuf/hbase.proto (revision 1450944) +++ hbase-protocol/src/main/protobuf/hbase.proto (working copy) @@ -176,7 +176,7 @@ /** * A range of time. Both from and to are Java time * stamp in milliseconds. If you don't specify a time - * range, it means all time. By default, if not + * range, it means all time. By default, if not * specified, from = 0, and to = Long.MAX_VALUE */ message TimeRange { @@ -285,3 +285,7 @@ required int64 longMsg = 1; } + +message BigDecimalMsg { + required bytes bigdecimalMsg = 1; +} \ No newline at end of file Index: hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/HBaseProtos.java =================================================================== --- hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/HBaseProtos.java (revision 1450944) +++ hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/HBaseProtos.java (working copy) @@ -12441,6 +12441,388 @@ // @@protoc_insertion_point(class_scope:LongMsg) } + public interface BigDecimalMsgOrBuilder + extends com.google.protobuf.MessageOrBuilder { + + // required bytes bigdecimalMsg = 1; + boolean hasBigdecimalMsg(); + com.google.protobuf.ByteString getBigdecimalMsg(); + } + public static final class BigDecimalMsg extends + com.google.protobuf.GeneratedMessage + implements BigDecimalMsgOrBuilder { + // Use BigDecimalMsg.newBuilder() to construct. + private BigDecimalMsg(Builder builder) { + super(builder); + } + private BigDecimalMsg(boolean noInit) {} + + private static final BigDecimalMsg defaultInstance; + public static BigDecimalMsg getDefaultInstance() { + return defaultInstance; + } + + public BigDecimalMsg getDefaultInstanceForType() { + return defaultInstance; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.internal_static_BigDecimalMsg_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.internal_static_BigDecimalMsg_fieldAccessorTable; + } + + private int bitField0_; + // required bytes bigdecimalMsg = 1; + public static final int BIGDECIMALMSG_FIELD_NUMBER = 1; + private com.google.protobuf.ByteString bigdecimalMsg_; + public boolean hasBigdecimalMsg() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + public com.google.protobuf.ByteString getBigdecimalMsg() { + return bigdecimalMsg_; + } + + private void initFields() { + bigdecimalMsg_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized != -1) return isInitialized == 1; + + if (!hasBigdecimalMsg()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeBytes(1, bigdecimalMsg_); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(1, bigdecimalMsg_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg)) { + return super.equals(obj); + } + org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg other = (org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg) obj; + + boolean result = true; + result = result && (hasBigdecimalMsg() == other.hasBigdecimalMsg()); + if (hasBigdecimalMsg()) { + result = result && getBigdecimalMsg() + .equals(other.getBigdecimalMsg()); + } + result = result && + getUnknownFields().equals(other.getUnknownFields()); + return result; + } + + @java.lang.Override + public int hashCode() { + int hash = 41; + hash = (19 * hash) + getDescriptorForType().hashCode(); + if (hasBigdecimalMsg()) { + hash = (37 * hash) + BIGDECIMALMSG_FIELD_NUMBER; + hash = (53 * hash) + getBigdecimalMsg().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + return hash; + } + + public static org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg parseFrom(java.io.InputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + public static org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input, extensionRegistry)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder + implements org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsgOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.internal_static_BigDecimalMsg_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.internal_static_BigDecimalMsg_fieldAccessorTable; + } + + // Construct using org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder(BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + } + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + bigdecimalMsg_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000001); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg.getDescriptor(); + } + + public org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg getDefaultInstanceForType() { + return org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg.getDefaultInstance(); + } + + public org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg build() { + org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + private org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg buildParsed() + throws com.google.protobuf.InvalidProtocolBufferException { + org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException( + result).asInvalidProtocolBufferException(); + } + return result; + } + + public org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg buildPartial() { + org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg result = new org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.bigdecimalMsg_ = bigdecimalMsg_; + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg) { + return mergeFrom((org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg other) { + if (other == org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg.getDefaultInstance()) return this; + if (other.hasBigdecimalMsg()) { + setBigdecimalMsg(other.getBigdecimalMsg()); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public final boolean isInitialized() { + if (!hasBigdecimalMsg()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder( + this.getUnknownFields()); + while (true) { + int tag = input.readTag(); + switch (tag) { + case 0: + this.setUnknownFields(unknownFields.build()); + onChanged(); + return this; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + this.setUnknownFields(unknownFields.build()); + onChanged(); + return this; + } + break; + } + case 10: { + bitField0_ |= 0x00000001; + bigdecimalMsg_ = input.readBytes(); + break; + } + } + } + } + + private int bitField0_; + + // required bytes bigdecimalMsg = 1; + private com.google.protobuf.ByteString bigdecimalMsg_ = com.google.protobuf.ByteString.EMPTY; + public boolean hasBigdecimalMsg() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + public com.google.protobuf.ByteString getBigdecimalMsg() { + return bigdecimalMsg_; + } + public Builder setBigdecimalMsg(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + bigdecimalMsg_ = value; + onChanged(); + return this; + } + public Builder clearBigdecimalMsg() { + bitField0_ = (bitField0_ & ~0x00000001); + bigdecimalMsg_ = getDefaultInstance().getBigdecimalMsg(); + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:BigDecimalMsg) + } + + static { + defaultInstance = new BigDecimalMsg(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:BigDecimalMsg) + } + private static com.google.protobuf.Descriptors.Descriptor internal_static_TableSchema_descriptor; private static @@ -12531,6 +12913,11 @@ private static com.google.protobuf.GeneratedMessage.FieldAccessorTable internal_static_LongMsg_fieldAccessorTable; + private static com.google.protobuf.Descriptors.Descriptor + internal_static_BigDecimalMsg_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_BigDecimalMsg_fieldAccessorTable; public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { @@ -12588,8 +12975,9 @@ "(\003:\0010\022.\n\004type\030\004 \001(\0162\031.SnapshotDescriptio" + "n.Type:\005FLUSH\022\017\n\007version\030\005 \001(\005\"\037\n\004Type\022\014" + "\n\010DISABLED\020\000\022\t\n\005FLUSH\020\001\"\n\n\010EmptyMsg\"\032\n\007L" + - "ongMsg\022\017\n\007longMsg\030\001 \002(\003*r\n\013CompareType\022\010" + - "\n\004LESS\020\000\022\021\n\rLESS_OR_EQUAL\020\001\022\t\n\005EQUAL\020\002\022\r", + "ongMsg\022\017\n\007longMsg\030\001 \002(\003\"&\n\rBigDecimalMsg" + + "\022\025\n\rbigdecimalMsg\030\001 \002(\014*r\n\013CompareType\022\010", + "\n\004LESS\020\000\022\021\n\rLESS_OR_EQUAL\020\001\022\t\n\005EQUAL\020\002\022\r" + "\n\tNOT_EQUAL\020\003\022\024\n\020GREATER_OR_EQUAL\020\004\022\013\n\007G" + "REATER\020\005\022\t\n\005NO_OP\020\006*_\n\007KeyType\022\013\n\007MINIMU" + "M\020\000\022\007\n\003PUT\020\004\022\n\n\006DELETE\020\010\022\021\n\rDELETE_COLUM" + @@ -12746,6 +13134,14 @@ new java.lang.String[] { "LongMsg", }, org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.LongMsg.class, org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.LongMsg.Builder.class); + internal_static_BigDecimalMsg_descriptor = + getDescriptor().getMessageTypes().get(18); + internal_static_BigDecimalMsg_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_BigDecimalMsg_descriptor, + new java.lang.String[] { "BigdecimalMsg", }, + org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg.class, + org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg.Builder.class); return null; } }; Index: hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestBigDecimalColumnInterpreter.java =================================================================== --- hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestBigDecimalColumnInterpreter.java (revision 0) +++ hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestBigDecimalColumnInterpreter.java (revision 0) @@ -0,0 +1,711 @@ +/* + * 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.coprocessor; + +import static org.junit.Assert.assertEquals; +import java.math.BigDecimal; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.*; +import org.apache.hadoop.hbase.client.HTable; +import org.apache.hadoop.hbase.client.Put; +import org.apache.hadoop.hbase.client.Scan; +import org.apache.hadoop.hbase.client.coprocessor.AggregationClient; +import org.apache.hadoop.hbase.client.coprocessor.BigDecimalColumnInterpreter; +import org.apache.hadoop.hbase.filter.Filter; +import org.apache.hadoop.hbase.filter.PrefixFilter; +import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg; +import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.EmptyMsg; +import org.apache.hadoop.hbase.util.Bytes; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +/** + * A test class to test BigDecimalColumnInterpreter for AggregationsProtocol + */ +@Category(MediumTests.class) +public class TestBigDecimalColumnInterpreter { + protected static Log myLog = LogFactory.getLog(TestBigDecimalColumnInterpreter.class); + + /** + * Creating the test infrastructure. + */ + private static final byte[] TEST_TABLE = Bytes.toBytes("TestTable"); + private static final byte[] TEST_FAMILY = Bytes.toBytes("TestFamily"); + private static final byte[] TEST_QUALIFIER = Bytes.toBytes("TestQualifier"); + private static final byte[] TEST_MULTI_CQ = Bytes.toBytes("TestMultiCQ"); + + private static byte[] ROW = Bytes.toBytes("testRow"); + private static final int ROWSIZE = 20; + private static final int rowSeperator1 = 5; + private static final int rowSeperator2 = 12; + private static byte[][] ROWS = makeN(ROW, ROWSIZE); + + private static HBaseTestingUtility util = new HBaseTestingUtility(); + private static Configuration conf = util.getConfiguration(); + + /** + * A set up method to start the test cluster. AggregateProtocolImpl is registered and will be + * loaded during region startup. + * @throws Exception + */ + @BeforeClass + public static void setupBeforeClass() throws Exception { + + conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY, + "org.apache.hadoop.hbase.coprocessor.AggregateImplementation"); + + util.startMiniCluster(2); + HTable table = util.createTable(TEST_TABLE, TEST_FAMILY); + util.createMultiRegions(util.getConfiguration(), table, TEST_FAMILY, new byte[][] { + HConstants.EMPTY_BYTE_ARRAY, ROWS[rowSeperator1], ROWS[rowSeperator2] }); + /** + * The testtable has one CQ which is always populated and one variable CQ for each row rowkey1: + * CF:CQ CF:CQ1 rowKey2: CF:CQ CF:CQ2 + */ + for (int i = 0; i < ROWSIZE; i++) { + Put put = new Put(ROWS[i]); + put.setWriteToWAL(false); + BigDecimal bd = new BigDecimal(i); + put.add(TEST_FAMILY, TEST_QUALIFIER, Bytes.toBytes(bd)); + table.put(put); + Put p2 = new Put(ROWS[i]); + put.setWriteToWAL(false); + p2.add(TEST_FAMILY, Bytes.add(TEST_MULTI_CQ, Bytes.toBytes(bd)), + Bytes.toBytes(bd.multiply(new BigDecimal("0.10")))); + table.put(p2); + } + table.close(); + } + + /** + * Shutting down the cluster + * @throws Exception + */ + @AfterClass + public static void tearDownAfterClass() throws Exception { + util.shutdownMiniCluster(); + } + + /** + * an infrastructure method to prepare rows for the testtable. + * @param base + * @param n + * @return + */ + private static byte[][] makeN(byte[] base, int n) { + byte[][] ret = new byte[n][]; + for (int i = 0; i < n; i++) { + ret[i] = Bytes.add(base, Bytes.toBytes(i)); + } + return ret; + } + + /** + * ****************** Test cases for Median ********************** + */ + /** + * @throws Throwable + */ + @Test + public void testMedianWithValidRange() throws Throwable { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.addColumn(TEST_FAMILY, TEST_QUALIFIER); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + BigDecimal median = aClient.median(TEST_TABLE, ci, scan); + assertEquals(new BigDecimal("8.00"), median); + } + + /** + * ***************Test cases for Maximum ******************* + */ + + /** + * give max for the entire table. + * @throws Throwable + */ + @Test + public void testMaxWithValidRange() throws Throwable { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.addColumn(TEST_FAMILY, TEST_QUALIFIER); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + BigDecimal maximum = aClient.max(TEST_TABLE, ci, scan); + assertEquals(new BigDecimal("19.00"), maximum); + } + + /** + * @throws Throwable + */ + @Test + public void testMaxWithValidRange2() throws Throwable { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.addColumn(TEST_FAMILY, TEST_QUALIFIER); + scan.setStartRow(ROWS[5]); + scan.setStopRow(ROWS[15]); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + BigDecimal max = aClient.max(TEST_TABLE, ci, scan); + assertEquals(new BigDecimal("14.00"), max); + } + + @Test + public void testMaxWithValidRangeWithNoCQ() throws Throwable { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.addFamily(TEST_FAMILY); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + BigDecimal maximum = aClient.max(TEST_TABLE, ci, scan); + assertEquals(new BigDecimal("19.00"), maximum); + } + + @Test + public void testMaxWithValidRange2WithNoCQ() throws Throwable { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.addFamily(TEST_FAMILY); + scan.setStartRow(ROWS[6]); + scan.setStopRow(ROWS[7]); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + BigDecimal max = aClient.max(TEST_TABLE, ci, scan); + assertEquals(new BigDecimal("6.00"), max); + } + + @Test + public void testMaxWithValidRangeWithNullCF() { + AggregationClient aClient = new AggregationClient(conf); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + Scan scan = new Scan(); + BigDecimal max = null; + try { + max = aClient.max(TEST_TABLE, ci, scan); + } catch (Throwable e) { + max = null; + } + assertEquals(null, max);// CP will throw an IOException about the + // null column family, and max will be set to 0 + } + + @Test + public void testMaxWithInvalidRange() { + AggregationClient aClient = new AggregationClient(conf); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + Scan scan = new Scan(); + scan.setStartRow(ROWS[4]); + scan.setStopRow(ROWS[2]); + scan.addColumn(TEST_FAMILY, TEST_QUALIFIER); + BigDecimal max = new BigDecimal(Long.MIN_VALUE); + ; + try { + max = aClient.max(TEST_TABLE, ci, scan); + } catch (Throwable e) { + max = BigDecimal.ZERO; + } + assertEquals(BigDecimal.ZERO, max);// control should go to the catch block + } + + @Test + public void testMaxWithInvalidRange2() throws Throwable { + BigDecimal max = new BigDecimal(Long.MIN_VALUE); + Scan scan = new Scan(); + scan.addColumn(TEST_FAMILY, TEST_QUALIFIER); + scan.setStartRow(ROWS[4]); + scan.setStopRow(ROWS[4]); + try { + AggregationClient aClient = new AggregationClient(conf); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + max = aClient.max(TEST_TABLE, ci, scan); + } catch (Exception e) { + max = BigDecimal.ZERO; + } + assertEquals(BigDecimal.ZERO, max);// control should go to the catch block + } + + @Test + public void testMaxWithFilter() throws Throwable { + BigDecimal max = BigDecimal.ZERO; + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.addColumn(TEST_FAMILY, TEST_QUALIFIER); + Filter f = new PrefixFilter(Bytes.toBytes("foo:bar")); + scan.setFilter(f); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + max = aClient.max(TEST_TABLE, ci, scan); + assertEquals(null, max); + } + + /** + * **************************Test cases for Minimum *********************** + */ + + /** + * @throws Throwable + */ + @Test + public void testMinWithValidRange() throws Throwable { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.addColumn(TEST_FAMILY, TEST_QUALIFIER); + scan.setStartRow(HConstants.EMPTY_START_ROW); + scan.setStopRow(HConstants.EMPTY_END_ROW); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + BigDecimal min = aClient.min(TEST_TABLE, ci, scan); + assertEquals(new BigDecimal("0.00"), min); + } + + /** + * @throws Throwable + */ + @Test + public void testMinWithValidRange2() throws Throwable { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.addColumn(TEST_FAMILY, TEST_QUALIFIER); + scan.setStartRow(ROWS[5]); + scan.setStopRow(ROWS[15]); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + BigDecimal min = aClient.min(TEST_TABLE, ci, scan); + assertEquals(new BigDecimal("5.00"), min); + } + + @Test + public void testMinWithValidRangeWithNoCQ() throws Throwable { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.addFamily(TEST_FAMILY); + scan.setStartRow(HConstants.EMPTY_START_ROW); + scan.setStopRow(HConstants.EMPTY_END_ROW); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + BigDecimal min = aClient.min(TEST_TABLE, ci, scan); + assertEquals(new BigDecimal("0.00"), min); + } + + @Test + public void testMinWithValidRange2WithNoCQ() throws Throwable { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.addFamily(TEST_FAMILY); + scan.setStartRow(ROWS[6]); + scan.setStopRow(ROWS[7]); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + BigDecimal min = aClient.min(TEST_TABLE, ci, scan); + assertEquals(new BigDecimal("0.60"), min); + } + + @Test + public void testMinWithValidRangeWithNullCF() { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.setStartRow(ROWS[5]); + scan.setStopRow(ROWS[15]); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + BigDecimal min = null; + try { + min = aClient.min(TEST_TABLE, ci, scan); + } catch (Throwable e) { + } + assertEquals(null, min);// CP will throw an IOException about the + // null column family, and max will be set to 0 + } + + @Test + public void testMinWithInvalidRange() { + AggregationClient aClient = new AggregationClient(conf); + BigDecimal min = null; + Scan scan = new Scan(); + scan.addFamily(TEST_FAMILY); + scan.setStartRow(ROWS[4]); + scan.setStopRow(ROWS[2]); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + try { + min = aClient.min(TEST_TABLE, ci, scan); + } catch (Throwable e) { + } + assertEquals(null, min);// control should go to the catch block + } + + @Test + public void testMinWithInvalidRange2() { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.addFamily(TEST_FAMILY); + scan.setStartRow(ROWS[6]); + scan.setStopRow(ROWS[6]); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + BigDecimal min = null; + try { + min = aClient.min(TEST_TABLE, ci, scan); + } catch (Throwable e) { + } + assertEquals(null, min);// control should go to the catch block + } + + @Test + public void testMinWithFilter() throws Throwable { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.addColumn(TEST_FAMILY, TEST_QUALIFIER); + Filter f = new PrefixFilter(Bytes.toBytes("foo:bar")); + scan.setFilter(f); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + BigDecimal min = null; + min = aClient.min(TEST_TABLE, ci, scan); + assertEquals(null, min); + } + + /** + * *************** Test cases for Sum ********************* + */ + /** + * @throws Throwable + */ + @Test + public void testSumWithValidRange() throws Throwable { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.addColumn(TEST_FAMILY, TEST_QUALIFIER); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + BigDecimal sum = aClient.sum(TEST_TABLE, ci, scan); + assertEquals(new BigDecimal("190.00"), sum); + } + + /** + * @throws Throwable + */ + @Test + public void testSumWithValidRange2() throws Throwable { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.addColumn(TEST_FAMILY, TEST_QUALIFIER); + scan.setStartRow(ROWS[5]); + scan.setStopRow(ROWS[15]); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + BigDecimal sum = aClient.sum(TEST_TABLE, ci, scan); + assertEquals(new BigDecimal("95.00"), sum); + } + + @Test + public void testSumWithValidRangeWithNoCQ() throws Throwable { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.addFamily(TEST_FAMILY); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + BigDecimal sum = aClient.sum(TEST_TABLE, ci, scan); + assertEquals(new BigDecimal("209.00"), sum); // 190 + 19 + } + + @Test + public void testSumWithValidRange2WithNoCQ() throws Throwable { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.addFamily(TEST_FAMILY); + scan.setStartRow(ROWS[6]); + scan.setStopRow(ROWS[7]); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + BigDecimal sum = aClient.sum(TEST_TABLE, ci, scan); + assertEquals(new BigDecimal("6.60"), sum); // 6 + 60 + } + + @Test + public void testSumWithValidRangeWithNullCF() { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.setStartRow(ROWS[6]); + scan.setStopRow(ROWS[7]); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + BigDecimal sum = null; + try { + sum = aClient.sum(TEST_TABLE, ci, scan); + } catch (Throwable e) { + } + assertEquals(null, sum);// CP will throw an IOException about the + // null column family, and max will be set to 0 + } + + @Test + public void testSumWithInvalidRange() { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.addFamily(TEST_FAMILY); + scan.setStartRow(ROWS[6]); + scan.setStopRow(ROWS[2]); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + BigDecimal sum = null; + try { + sum = aClient.sum(TEST_TABLE, ci, scan); + } catch (Throwable e) { + } + assertEquals(null, sum);// control should go to the catch block + } + + @Test + public void testSumWithFilter() throws Throwable { + AggregationClient aClient = new AggregationClient(conf); + Filter f = new PrefixFilter(Bytes.toBytes("foo:bar")); + Scan scan = new Scan(); + scan.addFamily(TEST_FAMILY); + scan.setFilter(f); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + BigDecimal sum = null; + sum = aClient.sum(TEST_TABLE, ci, scan); + assertEquals(null, sum); + } + + /** + * ****************************** Test Cases for Avg ************** + */ + /** + * @throws Throwable + */ + @Test + public void testAvgWithValidRange() throws Throwable { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.addColumn(TEST_FAMILY, TEST_QUALIFIER); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + double avg = aClient.avg(TEST_TABLE, ci, scan); + assertEquals(9.5, avg, 0); + } + + /** + * @throws Throwable + */ + @Test + public void testAvgWithValidRange2() throws Throwable { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.addColumn(TEST_FAMILY, TEST_QUALIFIER); + scan.setStartRow(ROWS[5]); + scan.setStopRow(ROWS[15]); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + double avg = aClient.avg(TEST_TABLE, ci, scan); + assertEquals(9.5, avg, 0); + } + + @Test + public void testAvgWithValidRangeWithNoCQ() throws Throwable { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.addFamily(TEST_FAMILY); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + double avg = aClient.avg(TEST_TABLE, ci, scan); + assertEquals(10.45, avg, 0.01); + } + + @Test + public void testAvgWithValidRange2WithNoCQ() throws Throwable { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.addFamily(TEST_FAMILY); + scan.setStartRow(ROWS[6]); + scan.setStopRow(ROWS[7]); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + double avg = aClient.avg(TEST_TABLE, ci, scan); + assertEquals(6 + 0.60, avg, 0); + } + + @Test + public void testAvgWithValidRangeWithNullCF() { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + Double avg = null; + try { + avg = aClient.avg(TEST_TABLE, ci, scan); + } catch (Throwable e) { + } + assertEquals(null, avg);// CP will throw an IOException about the + // null column family, and max will be set to 0 + } + + @Test + public void testAvgWithInvalidRange() { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.addColumn(TEST_FAMILY, TEST_QUALIFIER); + scan.setStartRow(ROWS[5]); + scan.setStopRow(ROWS[1]); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + Double avg = null; + try { + avg = aClient.avg(TEST_TABLE, ci, scan); + } catch (Throwable e) { + } + assertEquals(null, avg);// control should go to the catch block + } + + @Test + public void testAvgWithFilter() throws Throwable { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.addColumn(TEST_FAMILY, TEST_QUALIFIER); + Filter f = new PrefixFilter(Bytes.toBytes("foo:bar")); + scan.setFilter(f); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + Double avg = null; + avg = aClient.avg(TEST_TABLE, ci, scan); + assertEquals(Double.NaN, avg, 0); + } + + /** + * ****************** Test cases for STD ********************** + */ + /** + * @throws Throwable + */ + @Test + public void testStdWithValidRange() throws Throwable { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.addColumn(TEST_FAMILY, TEST_QUALIFIER); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + double std = aClient.std(TEST_TABLE, ci, scan); + assertEquals(5.766, std, 0.05d); + } + + /** + * need to change this + * @throws Throwable + */ + @Test + public void testStdWithValidRange2() throws Throwable { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.addColumn(TEST_FAMILY, TEST_QUALIFIER); + scan.setStartRow(ROWS[5]); + scan.setStopRow(ROWS[15]); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + double std = aClient.std(TEST_TABLE, ci, scan); + assertEquals(2.87, std, 0.05d); + } + + /** + * need to change this + * @throws Throwable + */ + @Test + public void testStdWithValidRangeWithNoCQ() throws Throwable { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.addFamily(TEST_FAMILY); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + double std = aClient.std(TEST_TABLE, ci, scan); + assertEquals(6.342, std, 0.05d); + } + + @Test + public void testStdWithValidRange2WithNoCQ() throws Throwable { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.addFamily(TEST_FAMILY); + scan.setStartRow(ROWS[6]); + scan.setStopRow(ROWS[7]); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + double std = aClient.std(TEST_TABLE, ci, scan); + System.out.println("std is:" + std); + assertEquals(0, std, 0.05d); + } + + @Test + public void testStdWithValidRangeWithNullCF() { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.setStartRow(ROWS[6]); + scan.setStopRow(ROWS[17]); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + Double std = null; + try { + std = aClient.std(TEST_TABLE, ci, scan); + } catch (Throwable e) { + } + assertEquals(null, std);// CP will throw an IOException about the + // null column family, and max will be set to 0 + } + + @Test + public void testStdWithInvalidRange() { + AggregationClient aClient = new AggregationClient(conf); + Scan scan = new Scan(); + scan.addFamily(TEST_FAMILY); + scan.setStartRow(ROWS[6]); + scan.setStopRow(ROWS[1]); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + Double std = null; + try { + std = aClient.std(TEST_TABLE, ci, scan); + } catch (Throwable e) { + } + assertEquals(null, std);// control should go to the catch block + } + + @Test + public void testStdWithFilter() throws Throwable { + AggregationClient aClient = new AggregationClient(conf); + Filter f = new PrefixFilter(Bytes.toBytes("foo:bar")); + Scan scan = new Scan(); + scan.addFamily(TEST_FAMILY); + scan.setFilter(f); + final ColumnInterpreter ci = + new BigDecimalColumnInterpreter(); + Double std = null; + std = aClient.std(TEST_TABLE, ci, scan); + assertEquals(Double.NaN, std, 0); + } + +} \ No newline at end of file Index: hbase-server/src/main/java/org/apache/hadoop/hbase/client/coprocessor/BigDecimalColumnInterpreter.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/client/coprocessor/BigDecimalColumnInterpreter.java (revision 0) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/client/coprocessor/BigDecimalColumnInterpreter.java (revision 0) @@ -0,0 +1,146 @@ +/* + * + * 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.coprocessor; + +import com.google.protobuf.ByteString; +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.math.BigDecimal; +import java.math.RoundingMode; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.hbase.KeyValue; +import org.apache.hadoop.hbase.coprocessor.ColumnInterpreter; +import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BigDecimalMsg; +import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.EmptyMsg; +import org.apache.hadoop.hbase.util.Bytes; + +/** + * ColumnInterpreter for doing Aggregation's with BigDecimal columns. This class + * is required at the RegionServer also. + * + */ +@InterfaceAudience.Public +@InterfaceStability.Evolving +public class BigDecimalColumnInterpreter extends ColumnInterpreter { + + @Override + public BigDecimal getValue(byte[] colFamily, byte[] colQualifier, KeyValue kv) + throws IOException { + if (kv == null || kv.getValue() == null) { + return null; + } + return Bytes.toBigDecimal(kv.getValue()).setScale(2, RoundingMode.HALF_EVEN); + } + + @Override + public BigDecimal add(BigDecimal bd1, BigDecimal bd2) { + if (bd1 == null ^ bd2 == null) { + return (bd1 == null) ? bd2 : bd1; // either of one is null. + } + if (bd1 == null) { + return null; + } + return bd1.add(bd2); + } + + @Override + public int compare(final BigDecimal bd1, final BigDecimal bd2) { + if (bd1 == null ^ bd2 == null) { + return bd1 == null ? -1 : 1; // either of one is null. + } + if (bd1 == null) { + return 0; // both are null + } + return bd1.compareTo(bd2); // natural ordering. + } + + @Override + public BigDecimal getMaxValue() { + return BigDecimal.valueOf(Double.MAX_VALUE); + } + + @Override + public BigDecimal increment(BigDecimal bd) { + return bd == null ? null : (bd.add(BigDecimal.ONE)); + } + + @Override + public BigDecimal multiply(BigDecimal bd1, BigDecimal bd2) { + return (bd1 == null || bd2 == null) ? null : bd1.multiply(bd2) + .setScale(2,RoundingMode.HALF_EVEN); + } + + @Override + public BigDecimal getMinValue() { + return BigDecimal.valueOf(Double.MIN_VALUE); + } + + @Override + public double divideForAvg(BigDecimal bd1, Long l2) { + return (l2 == null || bd1 == null) ? Double.NaN : (bd1.doubleValue() / l2 + .doubleValue()); + } + + @Override + public BigDecimal castToReturnType(BigDecimal bd) { + return bd; + } + + @Override + public BigDecimal castToCellType(BigDecimal bd) { + return bd; + } + + @Override + public EmptyMsg getRequestData() { + return EmptyMsg.getDefaultInstance(); + } + + @Override + public void initialize(EmptyMsg msg) { + //nothing + } + + @Override + public BigDecimalMsg getProtoForCellType(BigDecimal t) { + BigDecimalMsg.Builder builder = BigDecimalMsg.newBuilder(); + return builder.setBigdecimalMsg(ByteString.copyFrom(Bytes.toBytes(t))).build(); + } + + @Override + public BigDecimalMsg getProtoForPromotedType(BigDecimal s) { + BigDecimalMsg.Builder builder = BigDecimalMsg.newBuilder(); + return builder.setBigdecimalMsg(ByteString.copyFrom(Bytes.toBytes(s))).build(); + } + + @Override + public BigDecimal getPromotedValueFromProto(BigDecimalMsg r) { + return Bytes.toBigDecimal(r.getBigdecimalMsg().toByteArray()); + } + + @Override + public BigDecimal getCellValueFromProto(BigDecimalMsg q) { + return Bytes.toBigDecimal(q.getBigdecimalMsg().toByteArray()); + } +}