1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.codec.prefixtree.row;
20
21 import java.io.ByteArrayOutputStream;
22 import java.io.IOException;
23 import java.nio.ByteBuffer;
24 import java.util.Collection;
25 import java.util.List;
26
27 import org.apache.hadoop.hbase.Cell;
28 import org.apache.hadoop.hbase.CellComparator;
29 import org.apache.hadoop.hbase.KeyValue;
30 import org.apache.hadoop.hbase.KeyValueUtil;
31 import org.apache.hadoop.hbase.codec.prefixtree.decode.DecoderFactory;
32 import org.apache.hadoop.hbase.codec.prefixtree.encode.PrefixTreeEncoder;
33 import org.apache.hadoop.hbase.codec.prefixtree.scanner.CellScannerPosition;
34 import org.apache.hadoop.hbase.codec.prefixtree.scanner.CellSearcher;
35 import org.apache.hadoop.hbase.util.CollectionUtils;
36 import org.junit.Assert;
37 import org.junit.Test;
38 import org.junit.runner.RunWith;
39 import org.junit.runners.Parameterized;
40 import org.junit.runners.Parameterized.Parameters;
41
42 @RunWith(Parameterized.class)
43 public class TestPrefixTreeSearcher {
44
45 protected static int BLOCK_START = 7;
46
47 @Parameters
48 public static Collection<Object[]> parameters() {
49 return new TestRowData.InMemory().getAllAsObjectArray();
50 }
51
52 protected TestRowData rows;
53 protected ByteBuffer block;
54
55 public TestPrefixTreeSearcher(TestRowData testRows) throws IOException {
56 this.rows = testRows;
57 ByteArrayOutputStream os = new ByteArrayOutputStream(1 << 20);
58 PrefixTreeEncoder kvBuilder = new PrefixTreeEncoder(os, true);
59 for (KeyValue kv : rows.getInputs()) {
60 kvBuilder.write(kv);
61 }
62 kvBuilder.flush();
63 byte[] outputBytes = os.toByteArray();
64 this.block = ByteBuffer.wrap(outputBytes);
65 }
66
67
68 @Test
69 public void testScanForwards() throws IOException {
70 CellSearcher searcher = null;
71 try {
72 searcher = DecoderFactory.checkOut(block, true);
73
74 int i = -1;
75 while (searcher.advance()) {
76 ++i;
77 KeyValue inputCell = rows.getInputs().get(i);
78 Cell outputCell = searcher.current();
79
80
81 Assert.assertEquals(inputCell, outputCell);
82 Assert.assertEquals(outputCell, inputCell);
83 Assert.assertTrue(CellComparator.equals(inputCell, outputCell));
84 }
85 Assert.assertEquals(rows.getInputs().size(), i + 1);
86 } finally {
87 DecoderFactory.checkIn(searcher);
88 }
89 }
90
91
92 @Test
93 public void testScanBackwards() throws IOException {
94 CellSearcher searcher = null;
95 try {
96 searcher = DecoderFactory.checkOut(block, true);
97 searcher.positionAfterLastCell();
98 int i = -1;
99 while (searcher.previous()) {
100 ++i;
101 int oppositeIndex = rows.getInputs().size() - i - 1;
102 KeyValue inputKv = rows.getInputs().get(oppositeIndex);
103 KeyValue outputKv = KeyValueUtil.copyToNewKeyValue(searcher.current());
104 Assert.assertEquals(inputKv, outputKv);
105 }
106 Assert.assertEquals(rows.getInputs().size(), i + 1);
107 } finally {
108 DecoderFactory.checkIn(searcher);
109 }
110 }
111
112
113 @Test
114 public void testRandomSeekHits() throws IOException {
115 CellSearcher searcher = null;
116 try {
117 searcher = DecoderFactory.checkOut(block, true);
118 for (KeyValue kv : rows.getInputs()) {
119 boolean hit = searcher.positionAt(kv);
120 Assert.assertTrue(hit);
121 Cell foundKv = searcher.current();
122 Assert.assertTrue(CellComparator.equals(kv, foundKv));
123 }
124 } finally {
125 DecoderFactory.checkIn(searcher);
126 }
127 }
128
129 @Test
130 public void testRandomSeekMisses() throws IOException {
131 CellSearcher searcher = null;
132 List<Integer> rowStartIndexes = rows.getRowStartIndexes();
133 try {
134 searcher = DecoderFactory.checkOut(block, true);
135
136
137 for(boolean beforeVsAfterOnMiss : new boolean[]{true, false}){
138 for (int i=0; i < rows.getInputs().size(); ++i) {
139 KeyValue kv = rows.getInputs().get(i);
140
141
142 KeyValue inputNextRow = KeyValueUtil.createFirstKeyInNextRow(kv);
143
144 CellScannerPosition position = beforeVsAfterOnMiss
145 ? searcher.positionAtOrBefore(inputNextRow)
146 : searcher.positionAtOrAfter(inputNextRow);
147 boolean isFirstInRow = rowStartIndexes.contains(i);
148 if(isFirstInRow){
149 int rowIndex = rowStartIndexes.indexOf(i);
150 if(rowIndex < rowStartIndexes.size() - 1){
151 if(beforeVsAfterOnMiss){
152 Assert.assertEquals(CellScannerPosition.BEFORE, position);
153 }else{
154 Assert.assertEquals(CellScannerPosition.AFTER, position);
155 }
156
157 int expectedInputIndex = beforeVsAfterOnMiss
158 ? rowStartIndexes.get(rowIndex + 1) - 1
159 : rowStartIndexes.get(rowIndex + 1);
160 Assert.assertEquals(rows.getInputs().get(expectedInputIndex), searcher.current());
161 }
162 }
163
164
165 KeyValue inputPreviousKv = KeyValueUtil.previousKey(kv);
166 boolean hit = searcher.positionAt(inputPreviousKv);
167 Assert.assertFalse(hit);
168 position = searcher.positionAtOrAfter(inputPreviousKv);
169 if(CollectionUtils.isLastIndex(rows.getInputs(), i)){
170 Assert.assertTrue(CellScannerPosition.AFTER_LAST == position);
171 }else{
172 Assert.assertTrue(CellScannerPosition.AFTER == position);
173
174
175
176 Assert.assertEquals(rows.getInputs().get(i+1), searcher.current());
177 }
178 }
179 }
180 } finally {
181 DecoderFactory.checkIn(searcher);
182 }
183 }
184
185
186 @Test
187 public void testRandomSeekIndividualAssertions() throws IOException {
188 CellSearcher searcher = null;
189 try {
190 searcher = DecoderFactory.checkOut(block, true);
191 rows.individualSearcherAssertions(searcher);
192 } finally {
193 DecoderFactory.checkIn(searcher);
194 }
195 }
196 }