Repository: accumulo Updated Branches: refs/heads/master aac52a82e -> 6b94344d4
ACCUMULO-2817 Added decode(byte[], int, int) to Lexicoder and Encoder implementations, but not to the interfaces themselves. * Added AbstractEncoder and AbstractLexicoder to refactor common 'decode' functionality. * Refactored existing implementations of Lexicoder to extend AbstractLexicoder, and Encoders to extend AbstractEncoder. Signed-off-by: Josh Elser <els...@apache.org> Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/6b94344d Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/6b94344d Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/6b94344d Branch: refs/heads/master Commit: 6b94344d43fb08896cafdf83f907f7a4237b4dc0 Parents: aac52a8 Author: matt dailey <matthew.dail...@gmail.com> Authored: Tue Feb 17 18:58:50 2015 -0500 Committer: Josh Elser <els...@apache.org> Committed: Wed Feb 25 21:54:16 2015 -0500 ---------------------------------------------------------------------- .../core/client/lexicoder/AbstractEncoder.java | 60 +++++++++++++ .../client/lexicoder/BigIntegerLexicoder.java | 21 ++--- .../core/client/lexicoder/BytesLexicoder.java | 20 ++++- .../core/client/lexicoder/DateLexicoder.java | 8 +- .../core/client/lexicoder/DoubleLexicoder.java | 8 +- .../core/client/lexicoder/IntegerLexicoder.java | 8 +- .../core/client/lexicoder/ListLexicoder.java | 14 +-- .../core/client/lexicoder/LongLexicoder.java | 4 +- .../core/client/lexicoder/PairLexicoder.java | 11 +-- .../core/client/lexicoder/ReverseLexicoder.java | 15 ++-- .../core/client/lexicoder/StringLexicoder.java | 8 +- .../core/client/lexicoder/TextLexicoder.java | 9 +- .../client/lexicoder/UIntegerLexicoder.java | 16 ++-- .../core/client/lexicoder/ULongLexicoder.java | 16 ++-- .../core/client/lexicoder/UUIDLexicoder.java | 13 +-- .../lexicoder/impl/AbstractLexicoder.java | 23 +++++ .../core/client/lexicoder/impl/ByteUtils.java | 13 ++- .../accumulo/core/iterators/LongCombiner.java | 27 ++++-- .../core/iterators/user/BigDecimalCombiner.java | 7 +- .../iterators/user/SummingArrayCombiner.java | 14 +-- .../lexicoder/BigIntegerLexicoderTest.java | 12 ++- .../client/lexicoder/BytesLexicoderTest.java | 28 ++++++ .../client/lexicoder/DateLexicoderTest.java | 30 +++++++ .../client/lexicoder/DoubleLexicoderTest.java | 14 ++- .../client/lexicoder/IntegerLexicoderTest.java | 12 ++- .../core/client/lexicoder/LexicoderTest.java | 31 +++++-- .../client/lexicoder/ListLexicoderTest.java | 33 ++++--- .../client/lexicoder/LongLexicoderTest.java | 13 ++- .../client/lexicoder/PairLexicoderTest.java | 12 ++- .../client/lexicoder/ReverseLexicoderTest.java | 15 +++- .../client/lexicoder/StringLexicoderTest.java | 28 ++++++ .../client/lexicoder/TextLexicoderTest.java | 28 ++++++ .../client/lexicoder/UIntegerLexicoderTest.java | 12 ++- .../client/lexicoder/ULongLexicoderTest.java | 13 ++- .../client/lexicoder/UUIDLexicoderTest.java | 9 +- .../lexicoder/impl/AbstractLexicoderTest.java | 94 ++++++++++++++++++++ .../client/lexicoder/impl/ByteUtilsTest.java | 71 +++++++++++++++ .../core/iterators/user/CombinerTest.java | 4 + .../server/replication/StatusCombiner.java | 24 ++++- 39 files changed, 682 insertions(+), 116 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/AbstractEncoder.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/AbstractEncoder.java b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/AbstractEncoder.java new file mode 100644 index 0000000..b266e53 --- /dev/null +++ b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/AbstractEncoder.java @@ -0,0 +1,60 @@ +/* + * 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.accumulo.core.client.lexicoder; + +import com.google.common.base.Preconditions; +import org.apache.accumulo.core.iterators.ValueFormatException; + +/** + * AbstractEncoder is an {@link org.apache.accumulo.core.client.lexicoder.Encoder} that implements all of Encoder's + * methods validating the input, but has those methods defer logic to to a new method, + * {@link #decodeUnchecked(byte[], int, int)}. + * @since 1.7.0 + */ +public abstract class AbstractEncoder<T> implements Encoder<T> { + + /** + * Decodes a byte array without checking if the offset and len exceed the bounds of the actual array. + */ + protected abstract T decodeUnchecked(byte[] b, int offset, int len) throws ValueFormatException; + + /** + * Calls {@link #decodeUnchecked(byte[], int, int)} as {@code decodeUnchecked(b, 0, b.length);}. + */ + @Override + public T decode(byte[] b) { + Preconditions.checkNotNull(b, "cannot decode null byte array"); + return decodeUnchecked(b, 0, b.length); + } + + /** + * Checks if the byte array is null, or if parameters exceed the bounds of the byte array, + * then calls {@link #decodeUnchecked(byte[], int, int)}. + * + * @throws java.lang.NullPointerException if {@code b} is null + * @throws java.lang.IllegalArgumentException if {@code offset + len} exceeds the length of {@code b} + */ + public T decode(byte[] b, int offset, int len) { + Preconditions.checkNotNull(b, "cannot decode null byte array"); + Preconditions.checkArgument(offset >= 0, "offset %s cannot be negative", offset); + Preconditions.checkArgument(len >= 0, "length %s cannot be negative", len); + Preconditions.checkArgument(offset + len < b.length, "offset + length %s exceeds byte array length %s", + (offset + len), b.length); + + return decodeUnchecked(b, offset, len); + } +} http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/BigIntegerLexicoder.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/BigIntegerLexicoder.java b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/BigIntegerLexicoder.java index 838e3cd..577e33e 100644 --- a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/BigIntegerLexicoder.java +++ b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/BigIntegerLexicoder.java @@ -16,21 +16,22 @@ */ package org.apache.accumulo.core.client.lexicoder; +import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder; +import org.apache.accumulo.core.client.lexicoder.impl.FixedByteArrayOutputStream; +import org.apache.accumulo.core.iterators.ValueFormatException; + import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.math.BigInteger; -import org.apache.accumulo.core.client.lexicoder.impl.FixedByteArrayOutputStream; -import org.apache.accumulo.core.iterators.ValueFormatException; - /** * A lexicoder to encode/decode a BigInteger to/from bytes that maintain its native Java sort order. * * @since 1.6.0 */ -public class BigIntegerLexicoder implements Lexicoder<BigInteger> { +public class BigIntegerLexicoder extends AbstractLexicoder<BigInteger> implements Lexicoder<BigInteger> { @Override public byte[] encode(BigInteger v) { @@ -63,15 +64,15 @@ public class BigIntegerLexicoder implements Lexicoder<BigInteger> { } @Override - public BigInteger decode(byte[] b) throws ValueFormatException { + protected BigInteger decodeUnchecked(byte[] b, int offset, int origLen) throws ValueFormatException { try { - DataInputStream dis = new DataInputStream(new ByteArrayInputStream(b)); - int len = dis.readInt(); - len = len ^ 0x80000000; - len = Math.abs(len); + DataInputStream dis = new DataInputStream(new ByteArrayInputStream(b, offset, origLen)); + int newLen = dis.readInt(); + newLen = newLen ^ 0x80000000; + newLen = Math.abs(newLen); - byte[] bytes = new byte[len]; + byte[] bytes = new byte[newLen]; dis.readFully(bytes); bytes[0] = (byte) (0x80 ^ bytes[0]); http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/BytesLexicoder.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/BytesLexicoder.java b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/BytesLexicoder.java index e018e0c..8e0f5e2 100644 --- a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/BytesLexicoder.java +++ b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/BytesLexicoder.java @@ -16,13 +16,15 @@ */ package org.apache.accumulo.core.client.lexicoder; +import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder; + /** * For each of the methods, this lexicoder just passes the input through untouched. It is meant to be combined with other lexicoders like the * {@link ReverseLexicoder}. * * @since 1.6.0 */ -public class BytesLexicoder implements Lexicoder<byte[]> { +public class BytesLexicoder extends AbstractLexicoder<byte[]> implements Lexicoder<byte[]> { @Override public byte[] encode(byte[] data) { @@ -31,7 +33,23 @@ public class BytesLexicoder implements Lexicoder<byte[]> { @Override public byte[] decode(byte[] data) { + // overrides AbstractLexicoder since this simply returns the array return data; } + /** + * If offset == 0 and len == data.length, returns data. Otherwise, returns a new + * byte array with contents starting at data[offset] with length len. + */ + @Override + protected byte[] decodeUnchecked(byte[] data, int offset, int len) { + if (offset == 0 && len == data.length) { + return data; + } + + byte[] copy = new byte[len]; + System.arraycopy(data, offset, copy, 0, len); + return copy; + } + } http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/DateLexicoder.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/DateLexicoder.java b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/DateLexicoder.java index 8533bfe..2d17d37 100644 --- a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/DateLexicoder.java +++ b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/DateLexicoder.java @@ -16,6 +16,8 @@ */ package org.apache.accumulo.core.client.lexicoder; +import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder; + import java.util.Date; /** @@ -23,7 +25,7 @@ import java.util.Date; * * @since 1.6.0 */ -public class DateLexicoder implements Lexicoder<Date> { +public class DateLexicoder extends AbstractLexicoder<Date> implements Lexicoder<Date> { private LongLexicoder longEncoder = new LongLexicoder(); @@ -33,8 +35,8 @@ public class DateLexicoder implements Lexicoder<Date> { } @Override - public Date decode(byte[] data) { - return new Date(longEncoder.decode(data)); + protected Date decodeUnchecked(byte[] data, int offset, int len) { + return new Date(longEncoder.decodeUnchecked(data, offset, len)); } } http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/DoubleLexicoder.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/DoubleLexicoder.java b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/DoubleLexicoder.java index 6310645..14413c0 100644 --- a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/DoubleLexicoder.java +++ b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/DoubleLexicoder.java @@ -16,12 +16,14 @@ */ package org.apache.accumulo.core.client.lexicoder; +import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder; + /** * A lexicoder for preserving the native Java sort order of Double values. * * @since 1.6.0 */ -public class DoubleLexicoder implements Lexicoder<Double> { +public class DoubleLexicoder extends AbstractLexicoder<Double> implements Lexicoder<Double> { private ULongLexicoder longEncoder = new ULongLexicoder(); @@ -37,8 +39,8 @@ public class DoubleLexicoder implements Lexicoder<Double> { } @Override - public Double decode(byte[] data) { - long l = longEncoder.decode(data); + protected Double decodeUnchecked(byte[] data, int offset, int len) { + long l = longEncoder.decodeUnchecked(data, offset, len); if (l < 0) l = l ^ 0x8000000000000000l; else http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/IntegerLexicoder.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/IntegerLexicoder.java b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/IntegerLexicoder.java index 12b515a..f96b41d 100644 --- a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/IntegerLexicoder.java +++ b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/IntegerLexicoder.java @@ -16,13 +16,15 @@ */ package org.apache.accumulo.core.client.lexicoder; +import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder; + /** * A lexicoder for signed integers. The encoding sorts Integer.MIN_VALUE first and Integer.MAX_VALUE last. The encoding sorts -2 before -1. It corresponds to * the sort order of Integer. * * @since 1.6.0 */ -public class IntegerLexicoder implements Lexicoder<Integer> { +public class IntegerLexicoder extends AbstractLexicoder<Integer> implements Lexicoder<Integer> { private UIntegerLexicoder uil = new UIntegerLexicoder(); @@ -32,8 +34,8 @@ public class IntegerLexicoder implements Lexicoder<Integer> { } @Override - public Integer decode(byte[] data) { - return uil.decode(data) ^ 0x80000000; + protected Integer decodeUnchecked(byte[] data, int offset, int len) { + return uil.decodeUnchecked(data, offset, len) ^ 0x80000000; } } http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/ListLexicoder.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/ListLexicoder.java b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/ListLexicoder.java index 5ecee88..a92f4c6 100644 --- a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/ListLexicoder.java +++ b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/ListLexicoder.java @@ -16,20 +16,22 @@ */ package org.apache.accumulo.core.client.lexicoder; +import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder; + +import java.util.ArrayList; +import java.util.List; + import static org.apache.accumulo.core.client.lexicoder.impl.ByteUtils.concat; import static org.apache.accumulo.core.client.lexicoder.impl.ByteUtils.escape; import static org.apache.accumulo.core.client.lexicoder.impl.ByteUtils.split; import static org.apache.accumulo.core.client.lexicoder.impl.ByteUtils.unescape; -import java.util.ArrayList; -import java.util.List; - /** * A lexicoder to encode/decode a Java List to/from a byte array where the concatenation of each encoded element sorts lexicographically. * * @since 1.6.0 */ -public class ListLexicoder<LT> implements Lexicoder<List<LT>> { +public class ListLexicoder<LT> extends AbstractLexicoder<List<LT>> implements Lexicoder<List<LT>> { private Lexicoder<LT> lexicoder; @@ -53,9 +55,9 @@ public class ListLexicoder<LT> implements Lexicoder<List<LT>> { } @Override - public List<LT> decode(byte[] b) { + protected List<LT> decodeUnchecked(byte[] b, int offset, int len) { - byte[][] escapedElements = split(b); + byte[][] escapedElements = split(b, offset, len); ArrayList<LT> ret = new ArrayList<LT>(escapedElements.length); for (byte[] escapedElement : escapedElements) { http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/LongLexicoder.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/LongLexicoder.java b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/LongLexicoder.java index f70a83c..ec850a3 100644 --- a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/LongLexicoder.java +++ b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/LongLexicoder.java @@ -29,7 +29,7 @@ public class LongLexicoder extends ULongLexicoder { } @Override - public Long decode(byte[] data) { - return super.decode(data) ^ 0x8000000000000000l; + protected Long decodeUnchecked(byte[] data, int offset, int len) { + return super.decodeUnchecked(data, offset, len) ^ 0x8000000000000000l; } } http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/PairLexicoder.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/PairLexicoder.java b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/PairLexicoder.java index 22af289..dff946f 100644 --- a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/PairLexicoder.java +++ b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/PairLexicoder.java @@ -16,13 +16,14 @@ */ package org.apache.accumulo.core.client.lexicoder; +import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder; +import org.apache.accumulo.core.util.ComparablePair; + import static org.apache.accumulo.core.client.lexicoder.impl.ByteUtils.concat; import static org.apache.accumulo.core.client.lexicoder.impl.ByteUtils.escape; import static org.apache.accumulo.core.client.lexicoder.impl.ByteUtils.split; import static org.apache.accumulo.core.client.lexicoder.impl.ByteUtils.unescape; -import org.apache.accumulo.core.util.ComparablePair; - /** * This class is a lexicoder that sorts a ComparablePair. Each item in the pair is encoded with the given lexicoder and concatenated together. This makes it * easy to construct a sortable key based on two components. There are many examples of this- but a key/value relationship is a great one. @@ -48,7 +49,7 @@ import org.apache.accumulo.core.util.ComparablePair; * @since 1.6.0 */ -public class PairLexicoder<A extends Comparable<A>,B extends Comparable<B>> implements Lexicoder<ComparablePair<A,B>> { +public class PairLexicoder<A extends Comparable<A>,B extends Comparable<B>> extends AbstractLexicoder<ComparablePair<A,B>> implements Lexicoder<ComparablePair<A,B>> { private Lexicoder<A> firstLexicoder; private Lexicoder<B> secondLexicoder; @@ -64,9 +65,9 @@ public class PairLexicoder<A extends Comparable<A>,B extends Comparable<B>> impl } @Override - public ComparablePair<A,B> decode(byte[] data) { + protected ComparablePair<A,B> decodeUnchecked(byte[] data, int offset, int len) { - byte[][] fields = split(data); + byte[][] fields = split(data, offset, len); if (fields.length != 2) { throw new RuntimeException("Data does not have 2 fields, it has " + fields.length); } http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/ReverseLexicoder.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/ReverseLexicoder.java b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/ReverseLexicoder.java index 1a6999b..3a422d5 100644 --- a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/ReverseLexicoder.java +++ b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/ReverseLexicoder.java @@ -16,6 +16,8 @@ */ package org.apache.accumulo.core.client.lexicoder; +import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder; + import static org.apache.accumulo.core.client.lexicoder.impl.ByteUtils.escape; import static org.apache.accumulo.core.client.lexicoder.impl.ByteUtils.unescape; @@ -27,7 +29,7 @@ import static org.apache.accumulo.core.client.lexicoder.impl.ByteUtils.unescape; * @since 1.6.0 */ -public class ReverseLexicoder<T> implements Lexicoder<T> { +public class ReverseLexicoder<T> extends AbstractLexicoder<T> implements Lexicoder<T> { private Lexicoder<T> lexicoder; @@ -53,11 +55,14 @@ public class ReverseLexicoder<T> implements Lexicoder<T> { } @Override - public T decode(byte[] data) { - byte ret[] = new byte[data.length - 1]; + protected T decodeUnchecked(byte[] data, int offset, int len) { + byte ret[] = new byte[len - 1]; - for (int i = 0; i < ret.length; i++) - ret[i] = (byte) (0xff - (0xff & data[i])); + int dataIndex; + for (int i = 0; i < ret.length; i++) { + dataIndex = offset + i; + ret[i] = (byte) (0xff - (0xff & data[dataIndex])); + } return lexicoder.decode(unescape(ret)); } http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/StringLexicoder.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/StringLexicoder.java b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/StringLexicoder.java index 9d5e07e..f7b1877 100644 --- a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/StringLexicoder.java +++ b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/StringLexicoder.java @@ -16,6 +16,8 @@ */ package org.apache.accumulo.core.client.lexicoder; +import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder; + import static java.nio.charset.StandardCharsets.UTF_8; /** @@ -25,7 +27,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; * @since 1.6.0 */ -public class StringLexicoder implements Lexicoder<String> { +public class StringLexicoder extends AbstractLexicoder<String> implements Lexicoder<String> { @Override public byte[] encode(String data) { @@ -33,8 +35,8 @@ public class StringLexicoder implements Lexicoder<String> { } @Override - public String decode(byte[] data) { - return new String(data, UTF_8); + protected String decodeUnchecked(byte[] data, int offset, int len) { + return new String(data, offset, len, UTF_8); } } http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/TextLexicoder.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/TextLexicoder.java b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/TextLexicoder.java index 08837a5..bb29857 100644 --- a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/TextLexicoder.java +++ b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/TextLexicoder.java @@ -16,6 +16,7 @@ */ package org.apache.accumulo.core.client.lexicoder; +import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder; import org.apache.accumulo.core.util.TextUtil; import org.apache.hadoop.io.Text; @@ -26,7 +27,7 @@ import org.apache.hadoop.io.Text; * @since 1.6.0 */ -public class TextLexicoder implements Lexicoder<Text> { +public class TextLexicoder extends AbstractLexicoder<Text> implements Lexicoder<Text> { @Override public byte[] encode(Text data) { @@ -34,8 +35,10 @@ public class TextLexicoder implements Lexicoder<Text> { } @Override - public Text decode(byte[] data) { - return new Text(data); + protected Text decodeUnchecked(byte[] data, int offset, int len) { + Text text = new Text(); + text.set(data, offset, len); + return text; } } http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/UIntegerLexicoder.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/UIntegerLexicoder.java b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/UIntegerLexicoder.java index f8842a9..e99c3b1 100644 --- a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/UIntegerLexicoder.java +++ b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/UIntegerLexicoder.java @@ -16,13 +16,15 @@ */ package org.apache.accumulo.core.client.lexicoder; +import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder; + /** * A lexicoder for an unsigned integer. It sorts 0 before -1 and does not preserve the native sort order of a Java integer because Java does not contain an * unsigned integer. If Java had an unsigned integer type, this would correspond to its sort order. * * @since 1.6.0 */ -public class UIntegerLexicoder implements Lexicoder<Integer> { +public class UIntegerLexicoder extends AbstractLexicoder<Integer> implements Lexicoder<Integer> { @Override public byte[] encode(Integer i) { @@ -52,22 +54,22 @@ public class UIntegerLexicoder implements Lexicoder<Integer> { } @Override - public Integer decode(byte[] data) { + protected Integer decodeUnchecked(byte[] data, int offset, int len) { - if (data[0] < 0 || data[0] > 8) - throw new IllegalArgumentException("Unexpected length " + (0xff & data[0])); + if (data[offset] < 0 || data[offset] > 8) + throw new IllegalArgumentException("Unexpected length " + (0xff & data[offset])); int i = 0; int shift = 0; - for (int idx = data.length - 1; idx >= 1; idx--) { + for (int idx = (offset + len) - 1; idx >= offset + 1; idx--) { i += (data[idx] & 0xffl) << shift; shift += 8; } // fill in 0xff prefix - if (data[0] > 4) - i |= -1 << ((8 - data[0]) << 3); + if (data[offset] > 4) + i |= -1 << ((8 - data[offset]) << 3); return i; } http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/ULongLexicoder.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/ULongLexicoder.java b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/ULongLexicoder.java index a3dcab5..a69ed34 100644 --- a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/ULongLexicoder.java +++ b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/ULongLexicoder.java @@ -16,13 +16,15 @@ */ package org.apache.accumulo.core.client.lexicoder; +import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder; + /** * Unsigned long lexicoder. The lexicographic encoding sorts first 0l and -1l last. This encoding does not correspond to the sort of Long because it does not * consider the sign bit. If Java had an unsigned long type, this encoder would correspond to its sort order. * * @since 1.6.0 */ -public class ULongLexicoder implements Lexicoder<Long> { +public class ULongLexicoder extends AbstractLexicoder<Long> implements Lexicoder<Long> { @Override public byte[] encode(Long l) { @@ -52,22 +54,22 @@ public class ULongLexicoder implements Lexicoder<Long> { } @Override - public Long decode(byte[] data) { + protected Long decodeUnchecked(byte[] data, int offset, int len) { long l = 0; int shift = 0; - if (data[0] < 0 || data[0] > 16) - throw new IllegalArgumentException("Unexpected length " + (0xff & data[0])); + if (data[offset] < 0 || data[offset] > 16) + throw new IllegalArgumentException("Unexpected length " + (0xff & data[offset])); - for (int i = data.length - 1; i >= 1; i--) { + for (int i = (offset + len) - 1; i >= offset + 1; i--) { l += (data[i] & 0xffl) << shift; shift += 8; } // fill in 0xff prefix - if (data[0] > 8) - l |= -1l << ((16 - data[0]) << 3); + if (data[offset] > 8) + l |= -1l << ((16 - data[offset]) << 3); return l; } http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/UUIDLexicoder.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/UUIDLexicoder.java b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/UUIDLexicoder.java index 43fa1a4..98ee467 100644 --- a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/UUIDLexicoder.java +++ b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/UUIDLexicoder.java @@ -16,21 +16,22 @@ */ package org.apache.accumulo.core.client.lexicoder; +import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder; +import org.apache.accumulo.core.client.lexicoder.impl.FixedByteArrayOutputStream; +import org.apache.accumulo.core.iterators.ValueFormatException; + import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.UUID; -import org.apache.accumulo.core.client.lexicoder.impl.FixedByteArrayOutputStream; -import org.apache.accumulo.core.iterators.ValueFormatException; - /** * A lexicoder for a UUID that maintains its lexicographic sorting order. * * @since 1.6.0 */ -public class UUIDLexicoder implements Lexicoder<UUID> { +public class UUIDLexicoder extends AbstractLexicoder<UUID> implements Lexicoder<UUID> { /** * @see <a href="http://www.ietf.org/rfc/rfc4122.txt"> RFC 4122: A Universally Unique IDentifier (UUID) URN Namespace, "Rules for Lexical Equivalence" in @@ -54,9 +55,9 @@ public class UUIDLexicoder implements Lexicoder<UUID> { } @Override - public UUID decode(byte[] b) throws ValueFormatException { + protected UUID decodeUnchecked(byte[] b, int offset, int len) throws ValueFormatException { try { - DataInputStream in = new DataInputStream(new ByteArrayInputStream(b)); + DataInputStream in = new DataInputStream(new ByteArrayInputStream(b, offset, len)); return new UUID(in.readLong() ^ 0x8000000000000000l, in.readLong() ^ 0x8000000000000000l); } catch (IOException e) { throw new RuntimeException(e); http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/impl/AbstractLexicoder.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/impl/AbstractLexicoder.java b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/impl/AbstractLexicoder.java new file mode 100644 index 0000000..e568f25 --- /dev/null +++ b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/impl/AbstractLexicoder.java @@ -0,0 +1,23 @@ +/* + * 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.accumulo.core.client.lexicoder.impl; + +import org.apache.accumulo.core.client.lexicoder.AbstractEncoder; +import org.apache.accumulo.core.client.lexicoder.Lexicoder; + +public abstract class AbstractLexicoder<T> extends AbstractEncoder<T> implements Lexicoder<T> { +} http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/impl/ByteUtils.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/impl/ByteUtils.java b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/impl/ByteUtils.java index 4973de8..b168807 100644 --- a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/impl/ByteUtils.java +++ b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/impl/ByteUtils.java @@ -90,19 +90,26 @@ public class ByteUtils { * Splits a byte array by 0x00 */ public static byte[][] split(byte[] data) { + return split(data, 0, data.length); + } + + /** + * Splits a byte array by 0x00 + */ + public static byte[][] split(byte[] data, int dataOffset, int len) { ArrayList<Integer> offsets = new ArrayList<Integer>(); - for (int i = 0; i < data.length; i++) { + for (int i = dataOffset; i < (dataOffset + len); i++) { if (data[i] == 0x00) { offsets.add(i); } } - offsets.add(data.length); + offsets.add(dataOffset + len); byte[][] ret = new byte[offsets.size()][]; - int index = 0; + int index = dataOffset; for (int i = 0; i < offsets.size(); i++) { ret[i] = new byte[offsets.get(i) - index]; System.arraycopy(data, index, ret[i], 0, ret[i].length); http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/iterators/LongCombiner.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/iterators/LongCombiner.java b/core/src/main/java/org/apache/accumulo/core/iterators/LongCombiner.java index ad98968..2a225fd 100644 --- a/core/src/main/java/org/apache/accumulo/core/iterators/LongCombiner.java +++ b/core/src/main/java/org/apache/accumulo/core/iterators/LongCombiner.java @@ -26,6 +26,7 @@ import java.io.IOException; import java.util.Map; import org.apache.accumulo.core.client.IteratorSetting; +import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder; import org.apache.accumulo.core.data.Key; import org.apache.accumulo.core.data.Value; import org.apache.hadoop.io.WritableUtils; @@ -117,7 +118,7 @@ public abstract class LongCombiner extends TypedValueCombiner<Long> { /** * An Encoder that uses a variable-length encoding for Longs. It uses WritableUtils.writeVLong and WritableUtils.readVLong for encoding and decoding. */ - public static class VarLenEncoder implements Encoder<Long> { + public static class VarLenEncoder extends AbstractLexicoder<Long> implements Encoder<Long> { @Override public byte[] encode(Long v) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); @@ -133,8 +134,8 @@ public abstract class LongCombiner extends TypedValueCombiner<Long> { } @Override - public Long decode(byte[] b) { - DataInputStream dis = new DataInputStream(new ByteArrayInputStream(b)); + protected Long decodeUnchecked(byte[] b, int offset, int len) { + DataInputStream dis = new DataInputStream(new ByteArrayInputStream(b, offset, len)); try { return WritableUtils.readVLong(dis); } catch (IOException e) { @@ -146,7 +147,7 @@ public abstract class LongCombiner extends TypedValueCombiner<Long> { /** * An Encoder that uses an 8-byte encoding for Longs. */ - public static class FixedLenEncoder implements Encoder<Long> { + public static class FixedLenEncoder extends AbstractLexicoder<Long> implements Encoder<Long> { @Override public byte[] encode(Long l) { byte[] b = new byte[8]; @@ -162,31 +163,39 @@ public abstract class LongCombiner extends TypedValueCombiner<Long> { } @Override - public Long decode(byte[] b) { - return decode(b, 0); + protected Long decodeUnchecked(byte[] b, int offset, int len) { + return decodeStatic(b, offset, len); } + // refactor? it's public, so cannot remove public static long decode(byte[] b, int offset) { if (b.length < offset + 8) throw new ValueFormatException("trying to convert to long, but byte array isn't long enough, wanted " + (offset + 8) + " found " + b.length); return (((long) b[offset + 0] << 56) + ((long) (b[offset + 1] & 255) << 48) + ((long) (b[offset + 2] & 255) << 40) + ((long) (b[offset + 3] & 255) << 32) + ((long) (b[offset + 4] & 255) << 24) + ((b[offset + 5] & 255) << 16) + ((b[offset + 6] & 255) << 8) + ((b[offset + 7] & 255) << 0)); } + + public static long decodeStatic(byte[] b, int offset, int len) { + if (b.length < offset + 8 || len < 8) + throw new ValueFormatException("trying to convert to long, but byte array isn't long enough, wanted " + (offset + 8) + " found " + len); + return (((long) b[offset + 0] << 56) + ((long) (b[offset + 1] & 255) << 48) + ((long) (b[offset + 2] & 255) << 40) + ((long) (b[offset + 3] & 255) << 32) + + ((long) (b[offset + 4] & 255) << 24) + ((b[offset + 5] & 255) << 16) + ((b[offset + 6] & 255) << 8) + ((b[offset + 7] & 255) << 0)); + } } /** * An Encoder that uses a String representation of Longs. It uses Long.toString and Long.parseLong for encoding and decoding. */ - public static class StringEncoder implements Encoder<Long> { + public static class StringEncoder extends AbstractLexicoder<Long> implements Encoder<Long> { @Override public byte[] encode(Long v) { return Long.toString(v).getBytes(UTF_8); } @Override - public Long decode(byte[] b) { + protected Long decodeUnchecked(byte[] b, int offset, int len) { try { - return Long.parseLong(new String(b, UTF_8)); + return Long.parseLong(new String(b, offset, len, UTF_8)); } catch (NumberFormatException nfe) { throw new ValueFormatException(nfe); } http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/iterators/user/BigDecimalCombiner.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/iterators/user/BigDecimalCombiner.java b/core/src/main/java/org/apache/accumulo/core/iterators/user/BigDecimalCombiner.java index 86c9e73..3a6dbcb 100644 --- a/core/src/main/java/org/apache/accumulo/core/iterators/user/BigDecimalCombiner.java +++ b/core/src/main/java/org/apache/accumulo/core/iterators/user/BigDecimalCombiner.java @@ -23,6 +23,7 @@ import java.math.BigDecimal; import java.util.Iterator; import java.util.Map; +import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder; import org.apache.accumulo.core.data.Key; import org.apache.accumulo.core.data.Value; import org.apache.accumulo.core.iterators.IteratorEnvironment; @@ -100,16 +101,16 @@ public abstract class BigDecimalCombiner extends TypedValueCombiner<BigDecimal> * Provides the ability to encode scientific notation. * */ - public static class BigDecimalEncoder implements org.apache.accumulo.core.iterators.TypedValueCombiner.Encoder<BigDecimal> { + public static class BigDecimalEncoder extends AbstractLexicoder<BigDecimal> implements org.apache.accumulo.core.iterators.TypedValueCombiner.Encoder<BigDecimal> { @Override public byte[] encode(BigDecimal v) { return v.toString().getBytes(UTF_8); } @Override - public BigDecimal decode(byte[] b) throws ValueFormatException { + protected BigDecimal decodeUnchecked(byte[] b, int offset, int len) throws ValueFormatException { try { - return new BigDecimal(new String(b, UTF_8)); + return new BigDecimal(new String(b, offset, len, UTF_8)); } catch (NumberFormatException nfe) { throw new ValueFormatException(nfe); } http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/iterators/user/SummingArrayCombiner.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/iterators/user/SummingArrayCombiner.java b/core/src/main/java/org/apache/accumulo/core/iterators/user/SummingArrayCombiner.java index 2217d13..04c0af1 100644 --- a/core/src/main/java/org/apache/accumulo/core/iterators/user/SummingArrayCombiner.java +++ b/core/src/main/java/org/apache/accumulo/core/iterators/user/SummingArrayCombiner.java @@ -30,6 +30,8 @@ import java.util.List; import java.util.Map; import org.apache.accumulo.core.client.IteratorSetting; +import org.apache.accumulo.core.client.lexicoder.AbstractEncoder; +import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder; import org.apache.accumulo.core.data.Key; import org.apache.accumulo.core.data.Value; import org.apache.accumulo.core.iterators.IteratorEnvironment; @@ -140,7 +142,7 @@ public class SummingArrayCombiner extends TypedValueCombiner<List<Long>> { return true; } - public abstract static class DOSArrayEncoder<V> implements Encoder<List<V>> { + public abstract static class DOSArrayEncoder<V> extends AbstractLexicoder<List<V>> implements Encoder<List<V>> { public abstract void write(DataOutputStream dos, V v) throws IOException; public abstract V read(DataInputStream dis) throws IOException; @@ -161,8 +163,8 @@ public class SummingArrayCombiner extends TypedValueCombiner<List<Long>> { } @Override - public List<V> decode(byte[] b) { - DataInputStream dis = new DataInputStream(new ByteArrayInputStream(b)); + protected List<V> decodeUnchecked(byte[] b, int offset, int origLen) { + DataInputStream dis = new DataInputStream(new ByteArrayInputStream(b, offset, origLen)); try { int len = WritableUtils.readVInt(dis); List<V> vl = new ArrayList<V>(len); @@ -200,7 +202,7 @@ public class SummingArrayCombiner extends TypedValueCombiner<List<Long>> { } } - public static class StringArrayEncoder implements Encoder<List<Long>> { + public static class StringArrayEncoder extends AbstractEncoder<List<Long>> implements Encoder<List<Long>> { @Override public byte[] encode(List<Long> la) { if (la.size() == 0) @@ -214,8 +216,8 @@ public class SummingArrayCombiner extends TypedValueCombiner<List<Long>> { } @Override - public List<Long> decode(byte[] b) { - String[] longstrs = new String(b, UTF_8).split(","); + protected List<Long> decodeUnchecked(byte[] b, int offset, int len) { + String[] longstrs = new String(b, offset, len, UTF_8).split(","); List<Long> la = new ArrayList<Long>(longstrs.length); for (String s : longstrs) { if (s.length() == 0) http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/BigIntegerLexicoderTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/BigIntegerLexicoderTest.java b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/BigIntegerLexicoderTest.java index 9d453e3..9165fe5 100644 --- a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/BigIntegerLexicoderTest.java +++ b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/BigIntegerLexicoderTest.java @@ -16,13 +16,15 @@ */ package org.apache.accumulo.core.client.lexicoder; +import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoderTest; + import java.math.BigInteger; import java.util.Arrays; /** * */ -public class BigIntegerLexicoderTest extends LexicoderTest { +public class BigIntegerLexicoderTest extends AbstractLexicoderTest { public void testSortOrder() { assertSortOrder(new BigIntegerLexicoder(), Arrays.asList(new BigInteger("-1"), new BigInteger("0"), new BigInteger("1"), new BigInteger("-257"), new BigInteger("-256"), new BigInteger("-255"), new BigInteger("255"), new BigInteger("256"), new BigInteger("257"), new BigInteger("65534"), @@ -33,4 +35,12 @@ public class BigIntegerLexicoderTest extends LexicoderTest { new BigInteger("128"), new BigInteger("129"), new BigInteger("-126"), new BigInteger("-127"), new BigInteger("-128"), new BigInteger("-129"))); } + + public void testDecode() { + assertDecodes(new BigIntegerLexicoder(), new BigInteger("-2147483649")); + assertDecodes(new BigIntegerLexicoder(), new BigInteger("-1")); + assertDecodes(new BigIntegerLexicoder(), BigInteger.ZERO); + assertDecodes(new BigIntegerLexicoder(), BigInteger.ONE); + assertDecodes(new BigIntegerLexicoder(), new BigInteger("2147483647")); + } } http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/BytesLexicoderTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/BytesLexicoderTest.java b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/BytesLexicoderTest.java new file mode 100644 index 0000000..3f5b991 --- /dev/null +++ b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/BytesLexicoderTest.java @@ -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.accumulo.core.client.lexicoder; + +import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoderTest; + +public class BytesLexicoderTest extends AbstractLexicoderTest { + + public void testDecodes() { + BytesLexicoder lexicoder = new BytesLexicoder(); + assertDecodesB(lexicoder, new byte[0]); + assertDecodesB(lexicoder, "accumulo".getBytes()); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/DateLexicoderTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/DateLexicoderTest.java b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/DateLexicoderTest.java new file mode 100644 index 0000000..98d3ed1 --- /dev/null +++ b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/DateLexicoderTest.java @@ -0,0 +1,30 @@ +/* + * 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.accumulo.core.client.lexicoder; + +import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoderTest; + +import java.util.Date; + +public class DateLexicoderTest extends AbstractLexicoderTest { + + public void testDecode() throws Exception { + assertDecodes(new DateLexicoder(), new Date()); + assertDecodes(new DateLexicoder(), new Date(0)); + assertDecodes(new DateLexicoder(), new Date(Long.MAX_VALUE)); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/DoubleLexicoderTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/DoubleLexicoderTest.java b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/DoubleLexicoderTest.java index fc37f04..1b082b4 100644 --- a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/DoubleLexicoderTest.java +++ b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/DoubleLexicoderTest.java @@ -16,12 +16,14 @@ */ package org.apache.accumulo.core.client.lexicoder; +import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoderTest; + import java.util.Arrays; /** * */ -public class DoubleLexicoderTest extends LexicoderTest { +public class DoubleLexicoderTest extends AbstractLexicoderTest { public void testSortOrder() { assertSortOrder(new DoubleLexicoder(), Arrays.asList(Double.MIN_VALUE, Double.MAX_VALUE, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, 0.0, 0.01, 0.001, 1.0, -1.0, -1.1, -1.01, Math.nextUp(Double.NEGATIVE_INFINITY), Math.nextAfter(0.0, Double.NEGATIVE_INFINITY), @@ -29,4 +31,14 @@ public class DoubleLexicoderTest extends LexicoderTest { Math.pow(10.0, -30.0))); } + + public void testDecode() { + assertDecodes(new DoubleLexicoder(), Double.MIN_VALUE); + assertDecodes(new DoubleLexicoder(), -1.0); + assertDecodes(new DoubleLexicoder(), -Math.pow(10.0, -30.0)); + assertDecodes(new DoubleLexicoder(), 0.0); + assertDecodes(new DoubleLexicoder(), Math.pow(10.0, -30.0)); + assertDecodes(new DoubleLexicoder(), 1.0); + assertDecodes(new DoubleLexicoder(), Double.MAX_VALUE); + } } http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/IntegerLexicoderTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/IntegerLexicoderTest.java b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/IntegerLexicoderTest.java index 0af4792..4ca9235 100644 --- a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/IntegerLexicoderTest.java +++ b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/IntegerLexicoderTest.java @@ -16,11 +16,21 @@ */ package org.apache.accumulo.core.client.lexicoder; +import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoderTest; + import java.util.Arrays; -public class IntegerLexicoderTest extends LexicoderTest { +public class IntegerLexicoderTest extends AbstractLexicoderTest { public void testSortOrder() { assertSortOrder(new IntegerLexicoder(), Arrays.asList(Integer.MIN_VALUE, 0xff123456, 0xffff3456, 0xffffff56, -1, 0, 1, 0x12, 0x1234, 0x123456, 0x1234678, Integer.MAX_VALUE)); } + + public void testDecode() { + assertDecodes(new IntegerLexicoder(), Integer.MIN_VALUE); + assertDecodes(new IntegerLexicoder(), -1); + assertDecodes(new IntegerLexicoder(), 0); + assertDecodes(new IntegerLexicoder(), 1); + assertDecodes(new IntegerLexicoder(), Integer.MAX_VALUE); + } } http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/LexicoderTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/LexicoderTest.java b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/LexicoderTest.java index 4b798b6..6d06f97 100644 --- a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/LexicoderTest.java +++ b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/LexicoderTest.java @@ -16,19 +16,18 @@ */ package org.apache.accumulo.core.client.lexicoder; +import junit.framework.TestCase; +import org.apache.accumulo.core.util.TextUtil; +import org.apache.hadoop.io.Text; + import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; -import junit.framework.TestCase; - -import org.apache.accumulo.core.util.TextUtil; -import org.apache.hadoop.io.Text; - public abstract class LexicoderTest extends TestCase { - void assertEqualsB(byte[] ba1, byte[] ba2) { + protected void assertEqualsB(byte[] ba1, byte[] ba2) { assertEquals(new Text(ba2), new Text(ba1)); } @@ -61,4 +60,24 @@ public abstract class LexicoderTest extends TestCase { assertSortOrder(lexicoder, null, data); } + public static final byte[] START_PAD = "start".getBytes(); + public static final byte[] END_PAD = "end".getBytes(); + + /** Asserts a value can be encoded and decoded back to original value */ + public static <T> void assertDecodes(Lexicoder<T> lexicoder, T expected) { + byte[] encoded = lexicoder.encode(expected); + + // decode full array + T result = lexicoder.decode(encoded); + assertEquals(expected, result); + } + + public void assertDecodesB(Lexicoder<byte[]> lexicoder, byte[] expected) { + byte[] encoded = lexicoder.encode(expected); + + // decode full array + byte[] result = lexicoder.decode(encoded); + assertEqualsB(expected, result); + } + } http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/ListLexicoderTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/ListLexicoderTest.java b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/ListLexicoderTest.java index 60a9f79..41084e6 100644 --- a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/ListLexicoderTest.java +++ b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/ListLexicoderTest.java @@ -16,35 +16,40 @@ */ package org.apache.accumulo.core.client.lexicoder; +import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoderTest; +import org.apache.accumulo.core.util.TextUtil; +import org.apache.hadoop.io.Text; + import java.util.ArrayList; import java.util.List; import java.util.TreeSet; -import org.apache.accumulo.core.util.TextUtil; -import org.apache.hadoop.io.Text; +public class ListLexicoderTest extends AbstractLexicoderTest { + + private List<Long> data1 = new ArrayList<Long>(); + private List<Long> data2 = new ArrayList<Long>(); + private List<Long> data3 = new ArrayList<Long>(); + private List<Long> data4 = new ArrayList<Long>(); + private List<Long> data5 = new ArrayList<Long>(); + + public void setUp() { -public class ListLexicoderTest extends LexicoderTest { - public void testSortOrder() { - List<Long> data1 = new ArrayList<Long>(); data1.add(1l); data1.add(2l); - List<Long> data2 = new ArrayList<Long>(); data2.add(1l); - List<Long> data3 = new ArrayList<Long>(); data3.add(1l); data3.add(3l); - List<Long> data4 = new ArrayList<Long>(); data4.add(1l); data4.add(2l); data4.add(3l); - List<Long> data5 = new ArrayList<Long>(); data5.add(2l); data5.add(1l); - + } + public void testSortOrder() { List<List<Long>> data = new ArrayList<List<Long>>(); // add list in expected sort order @@ -71,4 +76,12 @@ public class ListLexicoderTest extends LexicoderTest { assertEquals(data, unenc); } + + public void testDecodes() { + assertDecodes(new ListLexicoder<Long>(new LongLexicoder()), data1); + assertDecodes(new ListLexicoder<Long>(new LongLexicoder()), data2); + assertDecodes(new ListLexicoder<Long>(new LongLexicoder()), data3); + assertDecodes(new ListLexicoder<Long>(new LongLexicoder()), data4); + assertDecodes(new ListLexicoder<Long>(new LongLexicoder()), data5); + } } http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/LongLexicoderTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/LongLexicoderTest.java b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/LongLexicoderTest.java index bf9a3a7..c1e2d41 100644 --- a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/LongLexicoderTest.java +++ b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/LongLexicoderTest.java @@ -16,13 +16,24 @@ */ package org.apache.accumulo.core.client.lexicoder; +import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoderTest; + import java.util.Arrays; -public class LongLexicoderTest extends LexicoderTest { +public class LongLexicoderTest extends AbstractLexicoderTest { public void testSortOrder() { assertSortOrder(new LongLexicoder(), Arrays.asList(Long.MIN_VALUE, 0xff1234567890abcdl, 0xffff1234567890abl, 0xffffff567890abcdl, 0xffffffff7890abcdl, 0xffffffffff90abcdl, 0xffffffffffffabcdl, 0xffffffffffffffcdl, -1l, 0l, 0x01l, 0x1234l, 0x123456l, 0x12345678l, 0x1234567890l, 0x1234567890abl, 0x1234567890abcdl, 0x1234567890abcdefl, Long.MAX_VALUE)); } + + public void testDecodes() { + assertDecodes(new LongLexicoder(), Long.MIN_VALUE); + assertDecodes(new LongLexicoder(), -1l); + assertDecodes(new LongLexicoder(), 0l); + assertDecodes(new LongLexicoder(), 1l); + assertDecodes(new LongLexicoder(), 2l); + assertDecodes(new LongLexicoder(), Long.MAX_VALUE); + } } http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/PairLexicoderTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/PairLexicoderTest.java b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/PairLexicoderTest.java index 434a603..0979801 100644 --- a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/PairLexicoderTest.java +++ b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/PairLexicoderTest.java @@ -16,14 +16,15 @@ */ package org.apache.accumulo.core.client.lexicoder; -import java.util.Arrays; - +import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoderTest; import org.apache.accumulo.core.util.ComparablePair; +import java.util.Arrays; + /** * */ -public class PairLexicoderTest extends LexicoderTest { +public class PairLexicoderTest extends AbstractLexicoderTest { public void testSortOrder() { PairLexicoder<String,String> plexc = new PairLexicoder<String,String>(new StringLexicoder(), new StringLexicoder()); @@ -36,4 +37,9 @@ public class PairLexicoderTest extends LexicoderTest { assertSortOrder(plexc2, Arrays.asList(new ComparablePair<Long,String>(0x100l, "a"), new ComparablePair<Long,String>(0x100l, "ab"), new ComparablePair<Long,String>(0xf0l, "a"), new ComparablePair<Long,String>(0xf0l, "ab"))); } + + public void testDecodes() { + PairLexicoder<String,String> plexc = new PairLexicoder<String,String>(new StringLexicoder(), new StringLexicoder()); + assertDecodes(plexc, new ComparablePair<String,String>("a", "b")); + } } http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/ReverseLexicoderTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/ReverseLexicoderTest.java b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/ReverseLexicoderTest.java index bde8a3f..a49409f 100644 --- a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/ReverseLexicoderTest.java +++ b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/ReverseLexicoderTest.java @@ -16,6 +16,9 @@ */ package org.apache.accumulo.core.client.lexicoder; +import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoderTest; +import org.junit.Test; + import java.io.UnsupportedEncodingException; import java.util.Arrays; import java.util.Calendar; @@ -23,9 +26,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.Date; -import org.junit.Test; - -public class ReverseLexicoderTest extends LexicoderTest { +public class ReverseLexicoderTest extends AbstractLexicoderTest { public void testSortOrder() { Comparator<Long> comp = Collections.reverseOrder(); assertSortOrder(new ReverseLexicoder<Long>(new LongLexicoder()), comp, Arrays.asList(Long.MIN_VALUE, 0xff1234567890abcdl, 0xffff1234567890abl, @@ -62,4 +63,12 @@ public class ReverseLexicoderTest extends LexicoderTest { System.out.println(date); } + + public void testDecodes() { + assertDecodes(new ReverseLexicoder<Long>(new LongLexicoder()), Long.MIN_VALUE); + assertDecodes(new ReverseLexicoder<Long>(new LongLexicoder()), -1l); + assertDecodes(new ReverseLexicoder<Long>(new LongLexicoder()), 0l); + assertDecodes(new ReverseLexicoder<Long>(new LongLexicoder()), 1l); + assertDecodes(new ReverseLexicoder<Long>(new LongLexicoder()), Long.MAX_VALUE); + } } http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/StringLexicoderTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/StringLexicoderTest.java b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/StringLexicoderTest.java new file mode 100644 index 0000000..686ee46 --- /dev/null +++ b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/StringLexicoderTest.java @@ -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.accumulo.core.client.lexicoder; + +import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoderTest; + +public class StringLexicoderTest extends AbstractLexicoderTest { + + public void testDecode() throws Exception { + assertDecodes(new StringLexicoder(), ""); + assertDecodes(new StringLexicoder(), "0"); + assertDecodes(new StringLexicoder(), "accumulo"); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/TextLexicoderTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/TextLexicoderTest.java b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/TextLexicoderTest.java new file mode 100644 index 0000000..74558de --- /dev/null +++ b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/TextLexicoderTest.java @@ -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.accumulo.core.client.lexicoder; + +import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoderTest; +import org.apache.hadoop.io.Text; + +public class TextLexicoderTest extends AbstractLexicoderTest { + + public void testDecode() throws Exception { + assertDecodes(new TextLexicoder(), new Text("")); + assertDecodes(new TextLexicoder(), new Text("accumulo")); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/UIntegerLexicoderTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/UIntegerLexicoderTest.java b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/UIntegerLexicoderTest.java index bd59237..8c33d98 100644 --- a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/UIntegerLexicoderTest.java +++ b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/UIntegerLexicoderTest.java @@ -16,7 +16,9 @@ */ package org.apache.accumulo.core.client.lexicoder; -public class UIntegerLexicoderTest extends LexicoderTest { +import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoderTest; + +public class UIntegerLexicoderTest extends AbstractLexicoderTest { public void testEncoding() { UIntegerLexicoder uil = new UIntegerLexicoder(); @@ -30,4 +32,12 @@ public class UIntegerLexicoderTest extends LexicoderTest { assertEqualsB(uil.encode(0xffffff04), new byte[] {0x07, 0x04}); assertEqualsB(uil.encode(-1), new byte[] {0x08}); } + + public void testDecode() { + assertDecodes(new UIntegerLexicoder(), Integer.MIN_VALUE); + assertDecodes(new UIntegerLexicoder(), -1); + assertDecodes(new UIntegerLexicoder(), 0); + assertDecodes(new UIntegerLexicoder(), 1); + assertDecodes(new UIntegerLexicoder(), Integer.MAX_VALUE); + } } http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/ULongLexicoderTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/ULongLexicoderTest.java b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/ULongLexicoderTest.java index acf0fb3..bca8b1d 100644 --- a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/ULongLexicoderTest.java +++ b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/ULongLexicoderTest.java @@ -16,9 +16,11 @@ */ package org.apache.accumulo.core.client.lexicoder; +import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoderTest; + import java.util.Arrays; -public class ULongLexicoderTest extends LexicoderTest { +public class ULongLexicoderTest extends AbstractLexicoderTest { public void testEncoding() { ULongLexicoder ull = new ULongLexicoder(); @@ -50,4 +52,13 @@ public class ULongLexicoderTest extends LexicoderTest { Arrays.asList(0l, 0x01l, 0x1234l, 0x123456l, 0x12345678l, 0x1234567890l, 0x1234567890abl, 0x1234567890abcdl, 0x1234567890abcdefl, Long.MAX_VALUE)); } + public void testDecodes() { + assertDecodes(new ULongLexicoder(), Long.MIN_VALUE); + assertDecodes(new ULongLexicoder(), -1l); + assertDecodes(new ULongLexicoder(), 0l); + assertDecodes(new ULongLexicoder(), 1l); + assertDecodes(new ULongLexicoder(), 2l); + assertDecodes(new ULongLexicoder(), Long.MAX_VALUE); + } + } http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/UUIDLexicoderTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/UUIDLexicoderTest.java b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/UUIDLexicoderTest.java index 26c1476..60c89a3 100644 --- a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/UUIDLexicoderTest.java +++ b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/UUIDLexicoderTest.java @@ -16,11 +16,13 @@ */ package org.apache.accumulo.core.client.lexicoder; +import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoderTest; + import java.util.ArrayList; import java.util.Arrays; import java.util.UUID; -public class UUIDLexicoderTest extends LexicoderTest { +public class UUIDLexicoderTest extends AbstractLexicoderTest { public void testSortOrder() { assertSortOrder(new UUIDLexicoder(), @@ -36,4 +38,9 @@ public class UUIDLexicoderTest extends LexicoderTest { assertSortOrder(new UUIDLexicoder(), uuids); } + + public void testDecodes() { + assertDecodes(new UUIDLexicoder(), UUID.randomUUID()); + + } } http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/impl/AbstractLexicoderTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/impl/AbstractLexicoderTest.java b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/impl/AbstractLexicoderTest.java new file mode 100644 index 0000000..502d132 --- /dev/null +++ b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/impl/AbstractLexicoderTest.java @@ -0,0 +1,94 @@ +/* + * 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.accumulo.core.client.lexicoder.impl; + +import org.apache.accumulo.core.client.lexicoder.LexicoderTest; +import org.apache.commons.lang.ArrayUtils; + +/** + * Assists in Testing classes that extend {@link org.apache.accumulo.core.client.lexicoder.AbstractEncoder}. It + * references methods not formally defined in the {@link org.apache.accumulo.core.client.lexicoder.Lexicoder} interface. + * @since 1.7.0 + */ +public abstract class AbstractLexicoderTest extends LexicoderTest { + + public static <T> void assertDecodes(AbstractLexicoder<T> lexicoder, T expected) { + LexicoderTest.assertDecodes(lexicoder, expected); + + byte[] encoded = lexicoder.encode(expected); + + assertOutOfBoundsFails(lexicoder, encoded); + + // munge bytes at start and end, then use offset and length to decode + final byte[] combined = ArrayUtils.addAll(ArrayUtils.addAll(START_PAD, encoded), END_PAD); + + int offset = START_PAD.length; + int len = encoded.length; + T result = lexicoder.decode(combined, offset, len); + assertEquals(expected, result); + } + + public void assertDecodesB(AbstractLexicoder<byte[]> lexicoder, byte[] expected) { + super.assertDecodesB(lexicoder, expected); + + byte[] encoded = lexicoder.encode(expected); + + assertOutOfBoundsFails(lexicoder, encoded); + + // munge bytes at start and end, then use offset and length to decode + final byte[] combined = ArrayUtils.addAll(ArrayUtils.addAll(START_PAD, encoded), END_PAD); + + int offset = START_PAD.length; + int len = encoded.length; + byte[] result = lexicoder.decode(combined, offset, len); + assertEqualsB(expected, result); + } + + protected static <T> void assertOutOfBoundsFails(AbstractLexicoder<T> lexicoder, byte[] encoded) { + // decode null; should fail + try { + lexicoder.decode(null, 0, encoded.length); + fail("Should throw on null bytes."); + } catch (NullPointerException e) {} + + // decode out of bounds, expect an exception + try { + lexicoder.decode(encoded, 0, encoded.length + 1); + fail("Should throw on exceeding length."); + } catch (IllegalArgumentException e) {} + + try { + lexicoder.decode(encoded, -1, encoded.length); + fail("Should throw on negative offset."); + } catch (IllegalArgumentException e) {} + + try { + lexicoder.decode(encoded, encoded.length, 0); + fail("Should throw on offset==length."); + } catch (IllegalArgumentException e) {} + + try { + lexicoder.decode(encoded, 0, -1); + fail("Should throw on negative length."); + } catch (IllegalArgumentException e) {} + + try { + lexicoder.decode(encoded, 1, -1); + fail("Should throw on negative length, even if (offset+len) is within bounds."); + } catch (IllegalArgumentException e) {} + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/impl/ByteUtilsTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/impl/ByteUtilsTest.java b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/impl/ByteUtilsTest.java new file mode 100644 index 0000000..1304797 --- /dev/null +++ b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/impl/ByteUtilsTest.java @@ -0,0 +1,71 @@ +/* + * 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.accumulo.core.client.lexicoder.impl; + +import org.junit.Assert; +import org.junit.Test; + +public class ByteUtilsTest { + + private final byte[] empty = new byte[0]; + private final byte[] noSplits = "nosplits".getBytes(); + private final byte[] splitAt5 = ("1234" + (char)0x00 + "56789").getBytes(); + + @Test + public void testSplit() throws Exception { + byte[][] result; + + // always returns the original array itself + result = ByteUtils.split(empty); + Assert.assertEquals(1, result.length); + Assert.assertArrayEquals(empty, result[0]); + + result = ByteUtils.split(noSplits); + Assert.assertEquals(1, result.length); + Assert.assertArrayEquals(noSplits, result[0]); + + result = ByteUtils.split(splitAt5); + Assert.assertEquals(2, result.length); + Assert.assertArrayEquals("1234".getBytes(), result[0]); + Assert.assertArrayEquals("56789".getBytes(), result[1]); + } + + public void testSplitWithOffset() { + int offset; + byte[][] result; + + // still see both splits + offset = 4; + result = ByteUtils.split(splitAt5, offset, splitAt5.length - offset); + Assert.assertEquals(2, result.length); + Assert.assertArrayEquals(empty, result[0]); + Assert.assertArrayEquals("56789".getBytes(), result[1]); + + // should only see 1 split at this offset + offset = 5; + result = ByteUtils.split(splitAt5, offset, splitAt5.length - offset); + Assert.assertEquals(1, result.length); + Assert.assertArrayEquals("56789".getBytes(), result[0]); + + // still one split, but smaller ending + offset = 5; + int len = splitAt5.length - offset - 1; + result = ByteUtils.split(splitAt5, offset, len); + Assert.assertEquals(1, result.length); + Assert.assertArrayEquals("5678".getBytes(), result[0]); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/iterators/user/CombinerTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/accumulo/core/iterators/user/CombinerTest.java b/core/src/test/java/org/apache/accumulo/core/iterators/user/CombinerTest.java index cdac2fb..26326a5 100644 --- a/core/src/test/java/org/apache/accumulo/core/iterators/user/CombinerTest.java +++ b/core/src/test/java/org/apache/accumulo/core/iterators/user/CombinerTest.java @@ -746,6 +746,10 @@ public class CombinerTest { return new ArrayList<Long>(); } + public List<Long> decode(byte[] b, int offset, int len) { + return new ArrayList<Long>(); + } + } @Test http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/server/base/src/main/java/org/apache/accumulo/server/replication/StatusCombiner.java ---------------------------------------------------------------------- diff --git a/server/base/src/main/java/org/apache/accumulo/server/replication/StatusCombiner.java b/server/base/src/main/java/org/apache/accumulo/server/replication/StatusCombiner.java index 5317c4d..e4c90a4 100644 --- a/server/base/src/main/java/org/apache/accumulo/server/replication/StatusCombiner.java +++ b/server/base/src/main/java/org/apache/accumulo/server/replication/StatusCombiner.java @@ -20,6 +20,8 @@ import java.io.IOException; import java.util.Iterator; import java.util.Map; +import com.google.common.base.Preconditions; +import org.apache.accumulo.core.client.lexicoder.AbstractEncoder; import org.apache.accumulo.core.data.Key; import org.apache.accumulo.core.data.Value; import org.apache.accumulo.core.iterators.IteratorEnvironment; @@ -41,7 +43,7 @@ import com.google.protobuf.InvalidProtocolBufferException; public class StatusCombiner extends TypedValueCombiner<Status> { private static final Logger log = Logger.getLogger(StatusCombiner.class); - public static class StatusEncoder implements Encoder<Status> { + public static class StatusEncoder extends AbstractEncoder<Status> implements Encoder<Status> { private static final Logger log = Logger.getLogger(StatusEncoder.class); @Override @@ -50,7 +52,9 @@ public class StatusCombiner extends TypedValueCombiner<Status> { } @Override - public Status decode(byte[] b) throws ValueFormatException { + public Status decode(byte[] b) { + // Override super because it calls decodeUnchecked, which is not as performant + Preconditions.checkNotNull(b, "cannot decode null byte array"); try { return Status.parseFrom(b); } catch (InvalidProtocolBufferException e) { @@ -58,6 +62,22 @@ public class StatusCombiner extends TypedValueCombiner<Status> { throw new ValueFormatException(e); } } + + /** + * Makes a copy of the subarray of {@code b}, then passes it through {@link Status#parseFrom(byte[])} + */ + @Override + protected Status decodeUnchecked(byte[] b, int offset, int len) throws ValueFormatException { + try { + // have to make a copy because Status lacks the method to do this efficiently + byte[] boundedArr = new byte[len]; + System.arraycopy(b, offset, boundedArr, 0, len); + return Status.parseFrom(boundedArr); + } catch (InvalidProtocolBufferException e) { + log.error("Failed to parse Status protocol buffer", e); + throw new ValueFormatException(e); + } + } } @Override