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 org.junit.jupiter.api.Assertions.assertEquals;
021import static org.junit.jupiter.api.Assertions.assertFalse;
022import static org.junit.jupiter.api.Assertions.assertTrue;
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.jupiter.api.Test;
033
034@org.junit.jupiter.api.Tag(MiscTests.TAG)
035@org.junit.jupiter.api.Tag(SmallTests.TAG)
036public class TestByteBufferKeyValue {
037
038  private static final String QUAL2 = "qual2";
039  private static final String FAM2 = "fam2";
040  private static final String QUAL1 = "qual1";
041  private static final String FAM1 = "fam1";
042  private static final String ROW1 = "row1";
043  private static final byte[] row1 = Bytes.toBytes(ROW1);
044  private static final byte[] fam1 = Bytes.toBytes(FAM1);
045  private static final byte[] fam2 = Bytes.toBytes(FAM2);
046  private static final byte[] qual1 = Bytes.toBytes(QUAL1);
047  private static final byte[] qual2 = Bytes.toBytes(QUAL2);
048  private static final Tag t1 = new ArrayBackedTag((byte) 1, Bytes.toBytes("TAG1"));
049  private static final Tag t2 = new ArrayBackedTag((byte) 2, Bytes.toBytes("TAG2"));
050  private static final ArrayList<Tag> tags = new ArrayList<Tag>();
051  static {
052    tags.add(t1);
053    tags.add(t2);
054  }
055
056  @Test
057  public void testCompare() {
058    Cell cell1 = getOffheapCell(row1, fam1, qual1);
059    Cell cell2 = getOffheapCell(row1, fam1, qual2);
060    assertTrue(CellComparatorImpl.COMPARATOR.compare(cell1, cell2) < 0);
061    Cell cell3 = getOffheapCell(row1, Bytes.toBytes("wide_family"), qual2);
062    assertTrue(CellComparatorImpl.COMPARATOR.compare(cell1, cell3) < 0);
063    Cell cell4 = getOffheapCell(row1, Bytes.toBytes("f"), qual2);
064    assertTrue(CellComparatorImpl.COMPARATOR.compare(cell1, cell4) > 0);
065    CellComparator comparator = CellComparator.getInstance();
066    assertTrue(comparator.compare(cell1, cell2) < 0);
067    assertTrue(comparator.compare(cell1, cell3) < 0);
068    assertTrue(comparator.compare(cell1, cell4) > 0);
069    ByteBuffer buf = ByteBuffer.allocate(row1.length);
070    ByteBufferUtils.copyFromArrayToBuffer(buf, row1, 0, row1.length);
071
072    ConcurrentSkipListMap<ByteBufferKeyValue, ByteBufferKeyValue> map =
073      new ConcurrentSkipListMap<>(comparator);
074    map.put((ByteBufferKeyValue) cell1, (ByteBufferKeyValue) cell1);
075    map.put((ByteBufferKeyValue) cell2, (ByteBufferKeyValue) cell2);
076    map.put((ByteBufferKeyValue) cell3, (ByteBufferKeyValue) cell3);
077    map.put((ByteBufferKeyValue) cell1, (ByteBufferKeyValue) cell1);
078    map.put((ByteBufferKeyValue) cell1, (ByteBufferKeyValue) cell4);
079    assertEquals(3, map.size());
080    assertTrue(map.containsKey(cell1));
081    assertTrue(map.containsKey(cell2));
082    assertTrue(map.containsKey(cell3));
083    assertEquals(cell4, map.get(cell1));
084    assertEquals(cell2, map.get(cell2));
085    assertEquals(cell3, map.get(cell3));
086  }
087
088  private static Cell getOffheapCell(byte[] row, byte[] family, byte[] qualifier) {
089    KeyValue kvCell = new KeyValue(row, family, qualifier, 0L, KeyValue.Type.Put, row);
090    ByteBuffer buf = ByteBuffer.allocateDirect(kvCell.getBuffer().length);
091    ByteBufferUtils.copyFromArrayToBuffer(buf, kvCell.getBuffer(), 0, kvCell.getBuffer().length);
092    return new ByteBufferKeyValue(buf, 0, buf.capacity(), 0L);
093  }
094
095  @Test
096  public void testByteBufferBackedKeyValue() throws Exception {
097    KeyValue kvCell = new KeyValue(row1, fam1, qual1, 0L, KeyValue.Type.Put, row1);
098    ByteBuffer buf = ByteBuffer.allocateDirect(kvCell.getBuffer().length);
099    ByteBufferUtils.copyFromArrayToBuffer(buf, kvCell.getBuffer(), 0, kvCell.getBuffer().length);
100    ByteBufferExtendedCell offheapKV = new ByteBufferKeyValue(buf, 0, buf.capacity(), 0L);
101    assertEquals(ROW1, ByteBufferUtils.toStringBinary(offheapKV.getRowByteBuffer(),
102      offheapKV.getRowPosition(), offheapKV.getRowLength()));
103    assertEquals(FAM1, ByteBufferUtils.toStringBinary(offheapKV.getFamilyByteBuffer(),
104      offheapKV.getFamilyPosition(), offheapKV.getFamilyLength()));
105    assertEquals(QUAL1, ByteBufferUtils.toStringBinary(offheapKV.getQualifierByteBuffer(),
106      offheapKV.getQualifierPosition(), offheapKV.getQualifierLength()));
107    assertEquals(ROW1, ByteBufferUtils.toStringBinary(offheapKV.getValueByteBuffer(),
108      offheapKV.getValuePosition(), offheapKV.getValueLength()));
109    assertEquals(0L, offheapKV.getTimestamp());
110    assertEquals(KeyValue.Type.Put.getCode(), offheapKV.getTypeByte());
111
112    // Use the array() APIs
113    assertEquals(ROW1, Bytes.toStringBinary(offheapKV.getRowArray(), offheapKV.getRowOffset(),
114      offheapKV.getRowLength()));
115    assertEquals(FAM1, Bytes.toStringBinary(offheapKV.getFamilyArray(), offheapKV.getFamilyOffset(),
116      offheapKV.getFamilyLength()));
117    assertEquals(QUAL1, Bytes.toStringBinary(offheapKV.getQualifierArray(),
118      offheapKV.getQualifierOffset(), offheapKV.getQualifierLength()));
119    assertEquals(ROW1, Bytes.toStringBinary(offheapKV.getValueArray(), offheapKV.getValueOffset(),
120      offheapKV.getValueLength()));
121    assertEquals(0L, offheapKV.getTimestamp());
122    assertEquals(KeyValue.Type.Put.getCode(), offheapKV.getTypeByte());
123
124    kvCell = new KeyValue(row1, fam2, qual2, 0L, KeyValue.Type.Put, row1);
125    buf = ByteBuffer.allocateDirect(kvCell.getBuffer().length);
126    ByteBufferUtils.copyFromArrayToBuffer(buf, kvCell.getBuffer(), 0, kvCell.getBuffer().length);
127    offheapKV = new ByteBufferKeyValue(buf, 0, buf.capacity(), 0L);
128    assertEquals(FAM2, ByteBufferUtils.toStringBinary(offheapKV.getFamilyByteBuffer(),
129      offheapKV.getFamilyPosition(), offheapKV.getFamilyLength()));
130    assertEquals(QUAL2, ByteBufferUtils.toStringBinary(offheapKV.getQualifierByteBuffer(),
131      offheapKV.getQualifierPosition(), offheapKV.getQualifierLength()));
132    byte[] nullQualifier = new byte[0];
133    kvCell = new KeyValue(row1, fam1, nullQualifier, 0L, KeyValue.Type.Put, row1);
134    buf = ByteBuffer.allocateDirect(kvCell.getBuffer().length);
135    ByteBufferUtils.copyFromArrayToBuffer(buf, kvCell.getBuffer(), 0, kvCell.getBuffer().length);
136    offheapKV = new ByteBufferKeyValue(buf, 0, buf.capacity(), 0L);
137    assertEquals(ROW1, ByteBufferUtils.toStringBinary(offheapKV.getRowByteBuffer(),
138      offheapKV.getRowPosition(), offheapKV.getRowLength()));
139    assertEquals(FAM1, ByteBufferUtils.toStringBinary(offheapKV.getFamilyByteBuffer(),
140      offheapKV.getFamilyPosition(), offheapKV.getFamilyLength()));
141    assertEquals("", ByteBufferUtils.toStringBinary(offheapKV.getQualifierByteBuffer(),
142      offheapKV.getQualifierPosition(), offheapKV.getQualifierLength()));
143    assertEquals(ROW1, ByteBufferUtils.toStringBinary(offheapKV.getValueByteBuffer(),
144      offheapKV.getValuePosition(), offheapKV.getValueLength()));
145    assertEquals(0L, offheapKV.getTimestamp());
146    assertEquals(KeyValue.Type.Put.getCode(), offheapKV.getTypeByte());
147  }
148
149  @Test
150  public void testByteBufferBackedKeyValueWithTags() throws Exception {
151    KeyValue kvCell = new KeyValue(row1, fam1, qual1, 0L, KeyValue.Type.Put, row1, tags);
152    ByteBuffer buf = ByteBuffer.allocateDirect(kvCell.getBuffer().length);
153    ByteBufferUtils.copyFromArrayToBuffer(buf, kvCell.getBuffer(), 0, kvCell.getBuffer().length);
154    ByteBufferKeyValue offheapKV = new ByteBufferKeyValue(buf, 0, buf.capacity(), 0L);
155    assertEquals(ROW1, ByteBufferUtils.toStringBinary(offheapKV.getRowByteBuffer(),
156      offheapKV.getRowPosition(), offheapKV.getRowLength()));
157    assertEquals(FAM1, ByteBufferUtils.toStringBinary(offheapKV.getFamilyByteBuffer(),
158      offheapKV.getFamilyPosition(), offheapKV.getFamilyLength()));
159    assertEquals(QUAL1, ByteBufferUtils.toStringBinary(offheapKV.getQualifierByteBuffer(),
160      offheapKV.getQualifierPosition(), offheapKV.getQualifierLength()));
161    assertEquals(ROW1, ByteBufferUtils.toStringBinary(offheapKV.getValueByteBuffer(),
162      offheapKV.getValuePosition(), offheapKV.getValueLength()));
163    assertEquals(0L, offheapKV.getTimestamp());
164    assertEquals(KeyValue.Type.Put.getCode(), offheapKV.getTypeByte());
165    // change tags to handle both onheap and offheap stuff
166    List<Tag> resTags = PrivateCellUtil.getTags(offheapKV);
167    Tag tag1 = resTags.get(0);
168    assertEquals(t1.getType(), tag1.getType());
169    assertEquals(Tag.getValueAsString(t1), Tag.getValueAsString(tag1));
170    Tag tag2 = resTags.get(1);
171    assertEquals(tag2.getType(), tag2.getType());
172    assertEquals(Tag.getValueAsString(t2), Tag.getValueAsString(tag2));
173    Tag tag3 = PrivateCellUtil.getTag(offheapKV, (byte) 2).get();
174    assertEquals(Tag.getValueAsString(t2), Tag.getValueAsString(tag3));
175    assertFalse(PrivateCellUtil.getTag(offheapKV, (byte) 3).isPresent());
176  }
177
178  @Test
179  public void testGetKeyMethods() throws Exception {
180    KeyValue kvCell = new KeyValue(row1, fam1, qual1, 0L, KeyValue.Type.Put, row1, tags);
181    ByteBuffer buf = ByteBuffer.allocateDirect(kvCell.getKeyLength());
182    ByteBufferUtils.copyFromArrayToBuffer(buf, kvCell.getBuffer(), kvCell.getKeyOffset(),
183      kvCell.getKeyLength());
184    ByteBufferExtendedCell offheapKeyOnlyKV = new ByteBufferKeyOnlyKeyValue(buf, 0, buf.capacity());
185    assertEquals(ROW1, ByteBufferUtils.toStringBinary(offheapKeyOnlyKV.getRowByteBuffer(),
186      offheapKeyOnlyKV.getRowPosition(), offheapKeyOnlyKV.getRowLength()));
187    assertEquals(FAM1, ByteBufferUtils.toStringBinary(offheapKeyOnlyKV.getFamilyByteBuffer(),
188      offheapKeyOnlyKV.getFamilyPosition(), offheapKeyOnlyKV.getFamilyLength()));
189    assertEquals(QUAL1, ByteBufferUtils.toStringBinary(offheapKeyOnlyKV.getQualifierByteBuffer(),
190      offheapKeyOnlyKV.getQualifierPosition(), offheapKeyOnlyKV.getQualifierLength()));
191    assertEquals(0L, offheapKeyOnlyKV.getTimestamp());
192    assertEquals(KeyValue.Type.Put.getCode(), offheapKeyOnlyKV.getTypeByte());
193  }
194}