001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase;
019
020import static junit.framework.TestCase.assertTrue;
021import static org.junit.Assert.assertEquals;
022import static org.junit.Assert.assertFalse;
023
024import java.nio.ByteBuffer;
025import java.util.ArrayList;
026import java.util.List;
027import java.util.concurrent.ConcurrentSkipListMap;
028import org.apache.hadoop.hbase.testclassification.MiscTests;
029import org.apache.hadoop.hbase.testclassification.SmallTests;
030import org.apache.hadoop.hbase.util.ByteBufferUtils;
031import org.apache.hadoop.hbase.util.Bytes;
032import org.junit.ClassRule;
033import org.junit.Test;
034import org.junit.experimental.categories.Category;
035
036@Category({ MiscTests.class, SmallTests.class })
037public class TestByteBufferKeyValue {
038
039  @ClassRule
040  public static final HBaseClassTestRule CLASS_RULE =
041    HBaseClassTestRule.forClass(TestByteBufferKeyValue.class);
042
043  private static final String QUAL2 = "qual2";
044  private static final String FAM2 = "fam2";
045  private static final String QUAL1 = "qual1";
046  private static final String FAM1 = "fam1";
047  private static final String ROW1 = "row1";
048  private static final byte[] row1 = Bytes.toBytes(ROW1);
049  private static final byte[] fam1 = Bytes.toBytes(FAM1);
050  private static final byte[] fam2 = Bytes.toBytes(FAM2);
051  private static final byte[] qual1 = Bytes.toBytes(QUAL1);
052  private static final byte[] qual2 = Bytes.toBytes(QUAL2);
053  private static final Tag t1 = new ArrayBackedTag((byte) 1, Bytes.toBytes("TAG1"));
054  private static final Tag t2 = new ArrayBackedTag((byte) 2, Bytes.toBytes("TAG2"));
055  private static final ArrayList<Tag> tags = new ArrayList<Tag>();
056  static {
057    tags.add(t1);
058    tags.add(t2);
059  }
060
061  @Test
062  public void testCompare() {
063    Cell cell1 = getOffheapCell(row1, fam1, qual1);
064    Cell cell2 = getOffheapCell(row1, fam1, qual2);
065    assertTrue(CellComparatorImpl.COMPARATOR.compare(cell1, cell2) < 0);
066    Cell cell3 = getOffheapCell(row1, Bytes.toBytes("wide_family"), qual2);
067    assertTrue(CellComparatorImpl.COMPARATOR.compare(cell1, cell3) < 0);
068    Cell cell4 = getOffheapCell(row1, Bytes.toBytes("f"), qual2);
069    assertTrue(CellComparatorImpl.COMPARATOR.compare(cell1, cell4) > 0);
070    CellComparator comparator = CellComparator.getInstance();
071    assertTrue(comparator.compare(cell1, cell2) < 0);
072    assertTrue(comparator.compare(cell1, cell3) < 0);
073    assertTrue(comparator.compare(cell1, cell4) > 0);
074    ByteBuffer buf = ByteBuffer.allocate(row1.length);
075    ByteBufferUtils.copyFromArrayToBuffer(buf, row1, 0, row1.length);
076
077    ConcurrentSkipListMap<ByteBufferKeyValue, ByteBufferKeyValue> map =
078      new ConcurrentSkipListMap<>(comparator);
079    map.put((ByteBufferKeyValue) cell1, (ByteBufferKeyValue) cell1);
080    map.put((ByteBufferKeyValue) cell2, (ByteBufferKeyValue) cell2);
081    map.put((ByteBufferKeyValue) cell3, (ByteBufferKeyValue) cell3);
082    map.put((ByteBufferKeyValue) cell1, (ByteBufferKeyValue) cell1);
083    map.put((ByteBufferKeyValue) cell1, (ByteBufferKeyValue) cell4);
084    assertEquals(3, map.size());
085    assertTrue(map.containsKey(cell1));
086    assertTrue(map.containsKey(cell2));
087    assertTrue(map.containsKey(cell3));
088    assertEquals(cell4, map.get(cell1));
089    assertEquals(cell2, map.get(cell2));
090    assertEquals(cell3, map.get(cell3));
091  }
092
093  private static Cell getOffheapCell(byte[] row, byte[] family, byte[] qualifier) {
094    KeyValue kvCell = new KeyValue(row, family, qualifier, 0L, KeyValue.Type.Put, row);
095    ByteBuffer buf = ByteBuffer.allocateDirect(kvCell.getBuffer().length);
096    ByteBufferUtils.copyFromArrayToBuffer(buf, kvCell.getBuffer(), 0, kvCell.getBuffer().length);
097    return new ByteBufferKeyValue(buf, 0, buf.capacity(), 0L);
098  }
099
100  @Test
101  public void testByteBufferBackedKeyValue() throws Exception {
102    KeyValue kvCell = new KeyValue(row1, fam1, qual1, 0L, KeyValue.Type.Put, row1);
103    ByteBuffer buf = ByteBuffer.allocateDirect(kvCell.getBuffer().length);
104    ByteBufferUtils.copyFromArrayToBuffer(buf, kvCell.getBuffer(), 0, kvCell.getBuffer().length);
105    ByteBufferExtendedCell offheapKV = new ByteBufferKeyValue(buf, 0, buf.capacity(), 0L);
106    assertEquals(ROW1, ByteBufferUtils.toStringBinary(offheapKV.getRowByteBuffer(),
107      offheapKV.getRowPosition(), offheapKV.getRowLength()));
108    assertEquals(FAM1, ByteBufferUtils.toStringBinary(offheapKV.getFamilyByteBuffer(),
109      offheapKV.getFamilyPosition(), offheapKV.getFamilyLength()));
110    assertEquals(QUAL1, ByteBufferUtils.toStringBinary(offheapKV.getQualifierByteBuffer(),
111      offheapKV.getQualifierPosition(), offheapKV.getQualifierLength()));
112    assertEquals(ROW1, ByteBufferUtils.toStringBinary(offheapKV.getValueByteBuffer(),
113      offheapKV.getValuePosition(), offheapKV.getValueLength()));
114    assertEquals(0L, offheapKV.getTimestamp());
115    assertEquals(KeyValue.Type.Put.getCode(), offheapKV.getTypeByte());
116
117    // Use the array() APIs
118    assertEquals(ROW1, Bytes.toStringBinary(offheapKV.getRowArray(), offheapKV.getRowOffset(),
119      offheapKV.getRowLength()));
120    assertEquals(FAM1, Bytes.toStringBinary(offheapKV.getFamilyArray(), offheapKV.getFamilyOffset(),
121      offheapKV.getFamilyLength()));
122    assertEquals(QUAL1, Bytes.toStringBinary(offheapKV.getQualifierArray(),
123      offheapKV.getQualifierOffset(), offheapKV.getQualifierLength()));
124    assertEquals(ROW1, Bytes.toStringBinary(offheapKV.getValueArray(), offheapKV.getValueOffset(),
125      offheapKV.getValueLength()));
126    assertEquals(0L, offheapKV.getTimestamp());
127    assertEquals(KeyValue.Type.Put.getCode(), offheapKV.getTypeByte());
128
129    kvCell = new KeyValue(row1, fam2, qual2, 0L, KeyValue.Type.Put, row1);
130    buf = ByteBuffer.allocateDirect(kvCell.getBuffer().length);
131    ByteBufferUtils.copyFromArrayToBuffer(buf, kvCell.getBuffer(), 0, kvCell.getBuffer().length);
132    offheapKV = new ByteBufferKeyValue(buf, 0, buf.capacity(), 0L);
133    assertEquals(FAM2, ByteBufferUtils.toStringBinary(offheapKV.getFamilyByteBuffer(),
134      offheapKV.getFamilyPosition(), offheapKV.getFamilyLength()));
135    assertEquals(QUAL2, ByteBufferUtils.toStringBinary(offheapKV.getQualifierByteBuffer(),
136      offheapKV.getQualifierPosition(), offheapKV.getQualifierLength()));
137    byte[] nullQualifier = new byte[0];
138    kvCell = new KeyValue(row1, fam1, nullQualifier, 0L, KeyValue.Type.Put, row1);
139    buf = ByteBuffer.allocateDirect(kvCell.getBuffer().length);
140    ByteBufferUtils.copyFromArrayToBuffer(buf, kvCell.getBuffer(), 0, kvCell.getBuffer().length);
141    offheapKV = new ByteBufferKeyValue(buf, 0, buf.capacity(), 0L);
142    assertEquals(ROW1, ByteBufferUtils.toStringBinary(offheapKV.getRowByteBuffer(),
143      offheapKV.getRowPosition(), offheapKV.getRowLength()));
144    assertEquals(FAM1, ByteBufferUtils.toStringBinary(offheapKV.getFamilyByteBuffer(),
145      offheapKV.getFamilyPosition(), offheapKV.getFamilyLength()));
146    assertEquals("", ByteBufferUtils.toStringBinary(offheapKV.getQualifierByteBuffer(),
147      offheapKV.getQualifierPosition(), offheapKV.getQualifierLength()));
148    assertEquals(ROW1, ByteBufferUtils.toStringBinary(offheapKV.getValueByteBuffer(),
149      offheapKV.getValuePosition(), offheapKV.getValueLength()));
150    assertEquals(0L, offheapKV.getTimestamp());
151    assertEquals(KeyValue.Type.Put.getCode(), offheapKV.getTypeByte());
152  }
153
154  @Test
155  public void testByteBufferBackedKeyValueWithTags() throws Exception {
156    KeyValue kvCell = new KeyValue(row1, fam1, qual1, 0L, KeyValue.Type.Put, row1, tags);
157    ByteBuffer buf = ByteBuffer.allocateDirect(kvCell.getBuffer().length);
158    ByteBufferUtils.copyFromArrayToBuffer(buf, kvCell.getBuffer(), 0, kvCell.getBuffer().length);
159    ByteBufferKeyValue offheapKV = new ByteBufferKeyValue(buf, 0, buf.capacity(), 0L);
160    assertEquals(ROW1, ByteBufferUtils.toStringBinary(offheapKV.getRowByteBuffer(),
161      offheapKV.getRowPosition(), offheapKV.getRowLength()));
162    assertEquals(FAM1, ByteBufferUtils.toStringBinary(offheapKV.getFamilyByteBuffer(),
163      offheapKV.getFamilyPosition(), offheapKV.getFamilyLength()));
164    assertEquals(QUAL1, ByteBufferUtils.toStringBinary(offheapKV.getQualifierByteBuffer(),
165      offheapKV.getQualifierPosition(), offheapKV.getQualifierLength()));
166    assertEquals(ROW1, ByteBufferUtils.toStringBinary(offheapKV.getValueByteBuffer(),
167      offheapKV.getValuePosition(), offheapKV.getValueLength()));
168    assertEquals(0L, offheapKV.getTimestamp());
169    assertEquals(KeyValue.Type.Put.getCode(), offheapKV.getTypeByte());
170    // change tags to handle both onheap and offheap stuff
171    List<Tag> resTags = PrivateCellUtil.getTags(offheapKV);
172    Tag tag1 = resTags.get(0);
173    assertEquals(t1.getType(), tag1.getType());
174    assertEquals(Tag.getValueAsString(t1), Tag.getValueAsString(tag1));
175    Tag tag2 = resTags.get(1);
176    assertEquals(tag2.getType(), tag2.getType());
177    assertEquals(Tag.getValueAsString(t2), Tag.getValueAsString(tag2));
178    Tag tag3 = PrivateCellUtil.getTag(offheapKV, (byte) 2).get();
179    assertEquals(Tag.getValueAsString(t2), Tag.getValueAsString(tag3));
180    assertFalse(PrivateCellUtil.getTag(offheapKV, (byte) 3).isPresent());
181  }
182
183  @Test
184  public void testGetKeyMethods() throws Exception {
185    KeyValue kvCell = new KeyValue(row1, fam1, qual1, 0L, KeyValue.Type.Put, row1, tags);
186    ByteBuffer buf = ByteBuffer.allocateDirect(kvCell.getKeyLength());
187    ByteBufferUtils.copyFromArrayToBuffer(buf, kvCell.getBuffer(), kvCell.getKeyOffset(),
188      kvCell.getKeyLength());
189    ByteBufferExtendedCell offheapKeyOnlyKV = new ByteBufferKeyOnlyKeyValue(buf, 0, buf.capacity());
190    assertEquals(ROW1, ByteBufferUtils.toStringBinary(offheapKeyOnlyKV.getRowByteBuffer(),
191      offheapKeyOnlyKV.getRowPosition(), offheapKeyOnlyKV.getRowLength()));
192    assertEquals(FAM1, ByteBufferUtils.toStringBinary(offheapKeyOnlyKV.getFamilyByteBuffer(),
193      offheapKeyOnlyKV.getFamilyPosition(), offheapKeyOnlyKV.getFamilyLength()));
194    assertEquals(QUAL1, ByteBufferUtils.toStringBinary(offheapKeyOnlyKV.getQualifierByteBuffer(),
195      offheapKeyOnlyKV.getQualifierPosition(), offheapKeyOnlyKV.getQualifierLength()));
196    assertEquals(0L, offheapKeyOnlyKV.getTimestamp());
197    assertEquals(KeyValue.Type.Put.getCode(), offheapKeyOnlyKV.getTypeByte());
198  }
199}