diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Result.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Result.java index ed8619d464c..e9ab6cd9b09 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Result.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Result.java @@ -791,7 +791,8 @@ public class Result implements CellScannable, CellScanner { Cell[] replicatedKVs = res2.rawCells(); for (int i = 0; i < res1.size(); i++) { if (!ourKVs[i].equals(replicatedKVs[i]) || - !CellUtil.matchingValue(ourKVs[i], replicatedKVs[i])) { + !CellUtil.matchingValue(ourKVs[i], replicatedKVs[i]) || + !CellUtil.matchingTags(ourKVs[i], replicatedKVs[i])) { throw new Exception("This result was different: " + res1.toString() + " compared to " + res2.toString()); } diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/CellUtil.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/CellUtil.java index c3b65e32c11..7533073edbd 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/CellUtil.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/CellUtil.java @@ -570,6 +570,10 @@ public final class CellUtil { buf.length); } + public static boolean matchingTags(final Cell left, final Cell right) { + return PrivateCellUtil.matchingTags(left, right, left.getTagsLength(), right.getTagsLength()); + } + /** * @return True if a delete type, a {@link KeyValue.Type#Delete} or a * {KeyValue.Type#DeleteFamily} or a diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/PrivateCellUtil.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/PrivateCellUtil.java index a86ca105912..99e38e751fa 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/PrivateCellUtil.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/PrivateCellUtil.java @@ -812,6 +812,31 @@ public final class PrivateCellUtil { return a.getTypeByte() == b.getTypeByte(); } + public static boolean matchingTags(final Cell left, final Cell right, int llength, + int rlength) { + if (left instanceof ByteBufferExtendedCell && right instanceof ByteBufferExtendedCell) { + ByteBufferExtendedCell leftBBCell = (ByteBufferExtendedCell) left; + ByteBufferExtendedCell rightBBCell = (ByteBufferExtendedCell) right; + return ByteBufferUtils.equals( + leftBBCell.getTagsByteBuffer(), leftBBCell.getTagsPosition(), llength, + rightBBCell.getTagsByteBuffer(),rightBBCell.getTagsPosition(), rlength); + } + if (left instanceof ByteBufferExtendedCell) { + ByteBufferExtendedCell leftBBCell = (ByteBufferExtendedCell) left; + return ByteBufferUtils.equals( + leftBBCell.getTagsByteBuffer(), leftBBCell.getTagsPosition(), llength, + right.getTagsArray(), right.getTagsOffset(), rlength); + } + if (right instanceof ByteBufferExtendedCell) { + ByteBufferExtendedCell rightBBCell = (ByteBufferExtendedCell) right; + return ByteBufferUtils.equals( + rightBBCell.getTagsByteBuffer(), rightBBCell.getTagsPosition(), rlength, + left.getTagsArray(), left.getTagsOffset(), llength); + } + return Bytes.equals(left.getTagsArray(), left.getTagsOffset(), llength, + right.getTagsArray(), right.getTagsOffset(), rlength); + } + /** * @return True if a delete type, a {@link KeyValue.Type#Delete} or a {KeyValue.Type#DeleteFamily} * or a {@link KeyValue.Type#DeleteColumn} KeyValue type. diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestResult.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestResult.java index e2a2333cdf1..30e9855883d 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestResult.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestResult.java @@ -25,14 +25,18 @@ import java.util.Arrays; import java.util.List; import java.util.NoSuchElementException; import junit.framework.TestCase; +import org.apache.hadoop.hbase.ArrayBackedTag; +import org.apache.hadoop.hbase.ByteBufferKeyValue; import org.apache.hadoop.hbase.Cell; import org.apache.hadoop.hbase.CellComparator; import org.apache.hadoop.hbase.CellScanner; import org.apache.hadoop.hbase.CellUtil; import org.apache.hadoop.hbase.HBaseClassTestRule; import org.apache.hadoop.hbase.KeyValue; +import org.apache.hadoop.hbase.Tag; import org.apache.hadoop.hbase.testclassification.ClientTests; import org.apache.hadoop.hbase.testclassification.SmallTests; +import org.apache.hadoop.hbase.util.ByteBufferUtils; import org.apache.hadoop.hbase.util.Bytes; import org.junit.ClassRule; import org.junit.experimental.categories.Category; @@ -66,6 +70,7 @@ public class TestResult extends TestCase { static final byte [] row = Bytes.toBytes("row"); static final byte [] family = Bytes.toBytes("family"); static final byte [] value = Bytes.toBytes("value"); + static final byte [] qual = Bytes.toBytes("qual"); /** * Run some tests to ensure Result acts like a proper CellScanner. @@ -250,6 +255,142 @@ public class TestResult extends TestCase { } } + public void testCompareResultsWithTags() throws Exception { + Tag t1 = new ArrayBackedTag((byte) 1, Bytes.toBytes("TAG1")); + Tag t2 = new ArrayBackedTag((byte) 2, Bytes.toBytes("TAG2")); + // Both BB backed tags KV are null + Result result1 = getByteBufferBackedTagResult(null); + Result result2 = getByteBufferBackedTagResult(null); + Result.compareResults(result1, result2); + + // Test both byte buffer backed tags KeyValue + result1 = getByteBufferBackedTagResult(t1); + result2 = getByteBufferBackedTagResult(t1); + Result.compareResults(result1, result2); + + // Both array backed tags KV are null + result1 = getArrayBackedTagResult(null); + result2 = getArrayBackedTagResult(null); + Result.compareResults(result1, result2); + + // Test both array backed tags KeyValue + result1 = getArrayBackedTagResult(t1); + result2 = getArrayBackedTagResult(t1); + Result.compareResults(result1, result2); + + // left instance of byte buffer and right instance of array backed + result1 = getByteBufferBackedTagResult(t1); + result2 = getArrayBackedTagResult(t1); + Result.compareResults(result1, result2); + + // left instance of array backed and right instance of byte buffer backed. + result1 = getArrayBackedTagResult(t1); + result2 = getByteBufferBackedTagResult(t1); + Result.compareResults(result1, result2); + + // Left BB backed null tag and right BB backed non null tag + result1 = getByteBufferBackedTagResult(null); + result2 = getByteBufferBackedTagResult(t2); + try { + Result.compareResults(result1, result2); + fail(); + } catch (Exception e) { + // Expected + } + + // Left BB backed non null tag and right BB backed null tag + result1 = getByteBufferBackedTagResult(t1); + result2 = getByteBufferBackedTagResult(null); + try { + Result.compareResults(result1, result2); + fail(); + } catch (Exception e) { + // Expected + } + + // Both byte buffer backed tags KV are different + result1 = getByteBufferBackedTagResult(t1); + result2 = getByteBufferBackedTagResult(t2); + try { + Result.compareResults(result1, result2); + fail(); + } catch (Exception e) { + // Expected + } + + // Left array backed non null tag and right array backed null tag + result1 = getArrayBackedTagResult(t1); + result2 = getArrayBackedTagResult(null); + try { + Result.compareResults(result1, result2); + fail(); + } catch (Exception e) { + // Expected + } + + // Left array backed null tag and right array backed non null tag + result1 = getByteBufferBackedTagResult(null); + result2 = getByteBufferBackedTagResult(t2); + try { + Result.compareResults(result1, result2); + fail(); + } catch (Exception e) { + // Expected + } + + // Both array backed tags KV are different + result1 = getArrayBackedTagResult(t1); + result2 = getArrayBackedTagResult(t2); + try { + Result.compareResults(result1, result2); + fail(); + } catch (Exception e) { + // Expected + } + + // left instance of byte buffer and right instance of array backed are different + result1 = getByteBufferBackedTagResult(t1); + result2 = getArrayBackedTagResult(t2); + try { + Result.compareResults(result1, result2); + fail(); + } catch (Exception e) { + // Expected + } + + // left instance of array backed and right instance of byte buffer backed are different + result1 = getArrayBackedTagResult(t1); + result2 = getByteBufferBackedTagResult(t2); + try { + Result.compareResults(result1, result2); + fail(); + } catch (Exception e) { + // Expected + } + } + + private Result getArrayBackedTagResult(Tag tag) { + List tags = null; + if (tag != null) { + tags = Arrays.asList(tag); + } + KeyValue kvCell = new KeyValue(row, family, qual, 0L, KeyValue.Type.Put, + value, tags); + return Result.create(new Cell[] {kvCell}); + } + + private Result getByteBufferBackedTagResult(Tag tag) { + List tags = null; + if (tag != null) { + tags = Arrays.asList(tag); + } + KeyValue kvCell = new KeyValue(row, family, qual, 0L, KeyValue.Type.Put, + value, tags); + ByteBuffer buf = ByteBuffer.allocateDirect(kvCell.getBuffer().length); + ByteBufferUtils.copyFromArrayToBuffer(buf, kvCell.getBuffer(), 0, kvCell.getBuffer().length); + ByteBufferKeyValue bbKV = new ByteBufferKeyValue(buf, 0, buf.capacity(), 0L); + return Result.create(new Cell[] {bbKV}); + } /** * Verifies that one can't modify instance of EMPTY_RESULT. */