HBASE-19103 Add BigDecimalComparator for filter

Signed-off-by: Jan Hentschel <jan.hentschel@ultratendency.com>
This commit is contained in:
QilinCao 2017-10-30 20:55:11 +08:00 committed by Jan Hentschel
parent d1b6d8c906
commit 0356674cd1
6 changed files with 294 additions and 0 deletions

View File

@ -0,0 +1,116 @@
/*
*
* 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.filter;
import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.util.Objects;
import org.apache.hadoop.hbase.exceptions.DeserializationException;
import org.apache.hadoop.hbase.shaded.com.google.protobuf.InvalidProtocolBufferException;
import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
import org.apache.hadoop.hbase.shaded.protobuf.generated.ComparatorProtos;
import org.apache.hadoop.hbase.util.ByteBufferUtils;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.yetus.audience.InterfaceAudience;
/**
* A BigDecimal comparator which numerical compares against the specified byte array
*/
@InterfaceAudience.Public
public class BigDecimalComparator extends ByteArrayComparable {
private BigDecimal bigDecimal;
public BigDecimalComparator(BigDecimal value) {
super(Bytes.toBytes(value));
this.bigDecimal = value;
}
@Override
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof BigDecimalComparator)) {
return false;
}
if (this == obj) {
return true;
}
BigDecimalComparator bdc = (BigDecimalComparator) obj;
return this.bigDecimal.equals(bdc.bigDecimal);
}
@Override
public int hashCode() {
return Objects.hash(this.bigDecimal);
}
@Override
public int compareTo(byte[] value, int offset, int length) {
BigDecimal that = Bytes.toBigDecimal(value, offset, length);
return this.bigDecimal.compareTo(that);
}
@Override
public int compareTo(ByteBuffer value, int offset, int length) {
BigDecimal that = ByteBufferUtils.toBigDecimal(value, offset, length);
return this.bigDecimal.compareTo(that);
}
/**
* @return The comparator serialized using pb
*/
@Override
public byte[] toByteArray() {
ComparatorProtos.BigDecimalComparator.Builder builder =
ComparatorProtos.BigDecimalComparator.newBuilder();
builder.setComparable(ProtobufUtil.toByteArrayComparable(this.value));
return builder.build().toByteArray();
}
/**
* @param pbBytes A pb serialized {@link BigDecimalComparator} instance
* @return An instance of {@link BigDecimalComparator} made from <code>bytes</code>
* @throws DeserializationException A deserialization exception
* @see #toByteArray
*/
public static BigDecimalComparator parseFrom(final byte[] pbBytes)
throws DeserializationException {
ComparatorProtos.BigDecimalComparator proto;
try {
proto = ComparatorProtos.BigDecimalComparator.parseFrom(pbBytes);
} catch (InvalidProtocolBufferException e) {
throw new DeserializationException(e);
}
return new BigDecimalComparator(Bytes.toBigDecimal(proto.getComparable().getValue()
.toByteArray()));
}
/**
* @param other the other comparator
* @return true if and only if the fields of the comparator that are serialized are equal to the
* corresponding fields in other. Used for testing.
*/
boolean areSerializedFieldsEqual(BigDecimalComparator other) {
if (other == this) {
return true;
}
return super.areSerializedFieldsEqual(other);
}
}

View File

@ -73,3 +73,7 @@ message RegexStringComparator {
message SubstringComparator {
required string substr = 1;
}
message BigDecimalComparator {
required ByteArrayComparable comparable = 1;
}

View File

@ -72,3 +72,7 @@ message RegexStringComparator {
message SubstringComparator {
required string substr = 1;
}
message BigDecimalComparator {
required ByteArrayComparable comparable = 1;
}

View File

@ -0,0 +1,118 @@
/*
* 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.filter;
import java.math.BigDecimal;
import org.apache.hadoop.hbase.testclassification.FilterTests;
import org.apache.hadoop.hbase.testclassification.SmallTests;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.Assert;
import org.junit.Test;
import org.junit.experimental.categories.Category;
@Category({ FilterTests.class, SmallTests.class })
public class TestBigDecimalComparator {
@Test
public void testObjectEquals() {
BigDecimal bd = new BigDecimal(Double.MIN_VALUE);
// Check that equals returns true for identical objects
final BigDecimalComparator bdc = new BigDecimalComparator(bd);
Assert.assertTrue(bdc.equals(bdc));
Assert.assertEquals(bdc.hashCode(), bdc.hashCode());
// Check that equals returns true for the same object
final BigDecimalComparator bdc1 = new BigDecimalComparator(bd);
final BigDecimalComparator bdc2 = new BigDecimalComparator(bd);
Assert.assertTrue(bdc1.equals(bdc2));
Assert.assertEquals(bdc1.hashCode(), bdc2.hashCode());
// Check that equals returns false for different objects
final BigDecimalComparator bdc3 = new BigDecimalComparator(bd);
final BigDecimalComparator bdc4 = new BigDecimalComparator(new BigDecimal(Long.MIN_VALUE));
Assert.assertFalse(bdc3.equals(bdc4));
Assert.assertNotEquals(bdc3.hashCode(), bdc4.hashCode());
// Check that equals returns false for a different type
final BigDecimalComparator bdc5 = new BigDecimalComparator(bd);
Assert.assertFalse(bdc5.equals(0));
}
@Test
public void testEqualsValue() {
// given
BigDecimal bd1 = new BigDecimal(Double.MAX_VALUE);
BigDecimal bd2 = new BigDecimal(Double.MIN_VALUE);
byte[] value1 = Bytes.toBytes(bd1);
byte[] value2 = Bytes.toBytes(bd2);
BigDecimalComparator comparator1 = new BigDecimalComparator(bd1);
BigDecimalComparator comparator2 = new BigDecimalComparator(bd2);
// when
int comp1 = comparator1.compareTo(value1);
int comp2 = comparator2.compareTo(value2);
// then
Assert.assertEquals(0, comp1);
Assert.assertEquals(0, comp2);
}
@Test
public void testGreaterThanValue() {
// given
byte[] val1 = Bytes.toBytes(new BigDecimal("1000000000000000000000000000000.9999999999999999"));
byte[] val2 = Bytes.toBytes(new BigDecimal(0));
byte[] val3 = Bytes.toBytes(new BigDecimal(Double.MIN_VALUE));
BigDecimal bd = new BigDecimal(Double.MAX_VALUE);
BigDecimalComparator comparator = new BigDecimalComparator(bd);
// when
int comp1 = comparator.compareTo(val1);
int comp2 = comparator.compareTo(val2);
int comp3 = comparator.compareTo(val3);
// then
Assert.assertEquals(1, comp1);
Assert.assertEquals(1, comp2);
Assert.assertEquals(1, comp3);
}
@Test
public void testLessThanValue() {
// given
byte[] val1 = Bytes.toBytes(new BigDecimal("-1000000000000000000000000000000"));
byte[] val2 = Bytes.toBytes(new BigDecimal(0));
byte[] val3 = Bytes.toBytes(new BigDecimal(1));
BigDecimal bd = new BigDecimal("-1000000000000000000000000000000.0000000000000001");
BigDecimalComparator comparator = new BigDecimalComparator(bd);
// when
int comp1 = comparator.compareTo(val1);
int comp2 = comparator.compareTo(val2);
int comp3 = comparator.compareTo(val3);
// then
Assert.assertEquals(-1, comp1);
Assert.assertEquals(-1, comp2);
Assert.assertEquals(-1, comp3);
}
}

View File

@ -22,6 +22,7 @@ package org.apache.hadoop.hbase.filter;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.math.BigDecimal;
import java.util.regex.Pattern;
import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
@ -86,4 +87,12 @@ public class TestComparatorSerialization {
ProtobufUtil.toComparator(ProtobufUtil.toComparator(substringComparator))));
}
@Test
public void testBigDecimalComparator() throws Exception {
BigDecimal bigDecimal = new BigDecimal(Double.MIN_VALUE);
BigDecimalComparator bigDecimalComparator = new BigDecimalComparator(bigDecimal);
assertTrue(bigDecimalComparator.areSerializedFieldsEqual(ProtobufUtil.toComparator(ProtobufUtil
.toComparator(bigDecimalComparator))));
}
}

View File

@ -42,6 +42,7 @@ import static org.mockito.Mockito.when;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.math.BigDecimal;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Arrays;
@ -113,6 +114,7 @@ import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.client.Table;
import org.apache.hadoop.hbase.client.TableDescriptor;
import org.apache.hadoop.hbase.exceptions.FailedSanityCheckException;
import org.apache.hadoop.hbase.filter.BigDecimalComparator;
import org.apache.hadoop.hbase.filter.BinaryComparator;
import org.apache.hadoop.hbase.filter.ColumnCountGetFilter;
import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
@ -1783,6 +1785,8 @@ public class TestHRegion {
byte[] qf1 = Bytes.toBytes("qualifier");
byte[] val1 = Bytes.toBytes("value1");
byte[] val2 = Bytes.toBytes("value2");
BigDecimal bd1 = new BigDecimal(Double.MAX_VALUE);
BigDecimal bd2 = new BigDecimal(Double.MIN_VALUE);
// Setting up region
this.region = initHRegion(tableName, method, CONF, fam1);
@ -1803,6 +1807,25 @@ public class TestHRegion {
res = region.checkAndMutate(row1, fam1, qf1, CompareOperator.EQUAL, new BinaryComparator(val2),
put, true);
assertEquals(false, res);
// Putting data in key
put = new Put(row1);
put.addColumn(fam1, qf1, Bytes.toBytes(bd1));
region.put(put);
// checkAndPut with wrong value
res =
region.checkAndMutate(row1, fam1, qf1, CompareOperator.EQUAL, new BigDecimalComparator(
bd2), put, true);
assertEquals(false, res);
// checkAndDelete with wrong value
delete = new Delete(row1);
delete.addFamily(fam1);
res =
region.checkAndMutate(row1, fam1, qf1, CompareOperator.EQUAL, new BigDecimalComparator(
bd2), put, true);
assertEquals(false, res);
} finally {
HBaseTestingUtility.closeRegionAndWAL(this.region);
this.region = null;
@ -1815,6 +1838,7 @@ public class TestHRegion {
byte[] fam1 = Bytes.toBytes("fam1");
byte[] qf1 = Bytes.toBytes("qualifier");
byte[] val1 = Bytes.toBytes("value1");
BigDecimal bd1 = new BigDecimal(Double.MIN_VALUE);
// Setting up region
this.region = initHRegion(tableName, method, CONF, fam1);
@ -1835,6 +1859,25 @@ public class TestHRegion {
res = region.checkAndMutate(row1, fam1, qf1, CompareOperator.EQUAL, new BinaryComparator(val1),
delete, true);
assertEquals(true, res);
// Putting data in key
put = new Put(row1);
put.addColumn(fam1, qf1, Bytes.toBytes(bd1));
region.put(put);
// checkAndPut with correct value
res =
region.checkAndMutate(row1, fam1, qf1, CompareOperator.EQUAL, new BigDecimalComparator(
bd1), put, true);
assertEquals(true, res);
// checkAndDelete with correct value
delete = new Delete(row1);
delete.addColumn(fam1, qf1);
res =
region.checkAndMutate(row1, fam1, qf1, CompareOperator.EQUAL, new BigDecimalComparator(
bd1), delete, true);
assertEquals(true, res);
} finally {
HBaseTestingUtility.closeRegionAndWAL(this.region);
this.region = null;