View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.apache.hadoop.hbase.codec.prefixtree.row;
20  
21  import java.io.ByteArrayInputStream;
22  import java.io.ByteArrayOutputStream;
23  import java.io.IOException;
24  import java.nio.ByteBuffer;
25  import java.util.Collection;
26  import java.util.List;
27  
28  import org.apache.hadoop.hbase.Cell;
29  import org.apache.hadoop.hbase.KeyValue;
30  import org.apache.hadoop.hbase.KeyValueUtil;
31  import org.apache.hadoop.hbase.testclassification.SmallTests;
32  import org.apache.hadoop.hbase.codec.prefixtree.PrefixTreeBlockMeta;
33  import org.apache.hadoop.hbase.codec.prefixtree.decode.PrefixTreeArraySearcher;
34  import org.apache.hadoop.hbase.codec.prefixtree.encode.PrefixTreeEncoder;
35  import org.apache.hadoop.hbase.util.Bytes;
36  import org.junit.Assert;
37  import org.junit.Before;
38  import org.junit.Test;
39  import org.junit.experimental.categories.Category;
40  import org.junit.runner.RunWith;
41  import org.junit.runners.Parameterized;
42  import org.junit.runners.Parameterized.Parameters;
43  
44  import com.google.common.collect.Lists;
45  
46  @Category(SmallTests.class)
47  @RunWith(Parameterized.class)
48  public class TestRowEncoder {
49  
50    protected static int BLOCK_START = 7;
51  
52    @Parameters
53    public static Collection<Object[]> parameters() {
54      List<Object[]> parameters = Lists.newArrayList();
55      for (TestRowData testRows : TestRowData.InMemory.getAll()) {
56        parameters.add(new Object[] { testRows });
57      }
58      return parameters;
59    }
60  
61    protected TestRowData rows;
62    protected List<KeyValue> inputKvs;
63    protected boolean includeMemstoreTS = true;
64    protected ByteArrayOutputStream os;
65    protected PrefixTreeEncoder encoder;
66    protected int totalBytes;
67    protected PrefixTreeBlockMeta blockMetaWriter;
68    protected byte[] outputBytes;
69    protected ByteBuffer buffer;
70    protected ByteArrayInputStream is;
71    protected PrefixTreeBlockMeta blockMetaReader;
72    protected byte[] inputBytes;
73    protected PrefixTreeArraySearcher searcher;
74  
75    public TestRowEncoder(TestRowData testRows) {
76      this.rows = testRows;
77    }
78  
79    @Before
80    public void compile() throws IOException {
81      // Always run with tags. But should also ensure that KVs without tags work fine
82      os = new ByteArrayOutputStream(1 << 20);
83      encoder = new PrefixTreeEncoder(os, includeMemstoreTS);
84  
85      inputKvs = rows.getInputs();
86      for (KeyValue kv : inputKvs) {
87        encoder.write(kv);
88      }
89      encoder.flush();
90      totalBytes = encoder.getTotalBytes();
91      blockMetaWriter = encoder.getBlockMeta();
92      outputBytes = os.toByteArray();
93  
94      // start reading, but save the assertions for @Test methods
95      buffer = ByteBuffer.wrap(outputBytes);
96      blockMetaReader = new PrefixTreeBlockMeta(buffer);
97  
98      searcher = new PrefixTreeArraySearcher(blockMetaReader, blockMetaReader.getRowTreeDepth(),
99          blockMetaReader.getMaxRowLength(), blockMetaReader.getMaxQualifierLength(),
100         blockMetaReader.getMaxTagsLength());
101     searcher.initOnBlock(blockMetaReader, outputBytes, includeMemstoreTS);
102   }
103 
104   @Test
105   public void testEncoderOutput() throws IOException {
106     Assert.assertEquals(totalBytes, outputBytes.length);
107     Assert.assertEquals(blockMetaWriter, blockMetaReader);
108   }
109 
110   @Test
111   public void testForwardScanner() {
112     int counter = -1;
113     while (searcher.advance()) {
114       ++counter;
115       KeyValue inputKv = rows.getInputs().get(counter);
116       KeyValue outputKv = KeyValueUtil.copyToNewKeyValue(searcher.current());
117       assertKeyAndValueEqual(inputKv, outputKv);
118     }
119     // assert same number of cells
120     Assert.assertEquals(rows.getInputs().size(), counter + 1);
121   }
122 
123 
124   /**
125    * probably not needed since testReverseScannerWithJitter() below is more thorough
126    */
127   @Test
128   public void testReverseScanner() {
129     searcher.positionAfterLastCell();
130     int counter = -1;
131     while (searcher.previous()) {
132       ++counter;
133       int oppositeIndex = rows.getInputs().size() - counter - 1;
134       KeyValue inputKv = rows.getInputs().get(oppositeIndex);
135       KeyValue outputKv = KeyValueUtil.copyToNewKeyValue(searcher.current());
136       assertKeyAndValueEqual(inputKv, outputKv);
137     }
138     Assert.assertEquals(rows.getInputs().size(), counter + 1);
139   }
140 
141 
142   /**
143    * Exercise the nubCellsRemain variable by calling next+previous.  NubCellsRemain is basically
144    * a special fan index.
145    */
146   @Test
147   public void testReverseScannerWithJitter() {
148     searcher.positionAfterLastCell();
149     int counter = -1;
150     while (true) {
151       boolean foundCell = searcher.previous();
152       if (!foundCell) {
153         break;
154       }
155       ++counter;
156 
157       // a next+previous should cancel out
158       if (!searcher.isAfterLast()) {
159         searcher.advance();
160         searcher.previous();
161       }
162 
163       int oppositeIndex = rows.getInputs().size() - counter - 1;
164       KeyValue inputKv = rows.getInputs().get(oppositeIndex);
165       KeyValue outputKv = KeyValueUtil.copyToNewKeyValue(searcher.current());
166       assertKeyAndValueEqual(inputKv, outputKv);
167     }
168     Assert.assertEquals(rows.getInputs().size(), counter + 1);
169   }
170 
171   @Test
172   public void testIndividualBlockMetaAssertions() {
173     rows.individualBlockMetaAssertions(blockMetaReader);
174   }
175 
176 
177   /**************** helper **************************/
178 
179   protected void assertKeyAndValueEqual(Cell expected, Cell actual) {
180     // assert keys are equal (doesn't compare values)
181     Assert.assertEquals(expected, actual);
182     if (includeMemstoreTS) {
183       Assert.assertEquals(expected.getMvccVersion(), actual.getMvccVersion());
184     }
185     // assert values equal
186     Assert.assertTrue(Bytes.equals(expected.getValueArray(), expected.getValueOffset(),
187       expected.getValueLength(), actual.getValueArray(), actual.getValueOffset(),
188       actual.getValueLength()));
189   }
190 
191 }