View Javadoc

1   /*
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  
20  package org.apache.hadoop.hbase.client;
21  
22  import static org.apache.hadoop.hbase.HBaseTestCase.assertByteEquals;
23  
24  import java.io.IOException;
25  import java.nio.ByteBuffer;
26  import java.util.Arrays;
27  import java.util.List;
28  
29  import junit.framework.TestCase;
30  
31  import org.apache.commons.logging.Log;
32  import org.apache.commons.logging.LogFactory;
33  import org.apache.hadoop.hbase.Cell;
34  import org.apache.hadoop.hbase.CellScanner;
35  import org.apache.hadoop.hbase.CellUtil;
36  import org.apache.hadoop.hbase.KeyValue;
37  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos;
38  import org.apache.hadoop.hbase.testclassification.SmallTests;
39  import org.apache.hadoop.hbase.util.Bytes;
40  import org.junit.experimental.categories.Category;
41  
42  @Category(SmallTests.class)
43  public class TestResult extends TestCase {
44  
45    private static final Log LOG = LogFactory.getLog(TestResult.class.getName());
46  
47    static KeyValue[] genKVs(final byte[] row, final byte[] family,
48                             final byte[] value,
49                      final long timestamp,
50                      final int cols) {
51      KeyValue [] kvs = new KeyValue[cols];
52  
53      for (int i = 0; i < cols ; i++) {
54        kvs[i] = new KeyValue(
55            row, family, Bytes.toBytes(i),
56            timestamp,
57            Bytes.add(value, Bytes.toBytes(i)));
58      }
59      return kvs;
60    }
61  
62    static final byte [] row = Bytes.toBytes("row");
63    static final byte [] family = Bytes.toBytes("family");
64    static final byte [] value = Bytes.toBytes("value");
65  
66    /**
67     * Run some tests to ensure Result acts like a proper CellScanner.
68     * @throws IOException
69     */
70    public void testResultAsCellScanner() throws IOException {
71      Cell [] cells = genKVs(row, family, value, 1, 10);
72      Arrays.sort(cells, KeyValue.COMPARATOR);
73      Result r = Result.create(cells);
74      assertSame(r, cells);
75      // Assert I run over same result multiple times.
76      assertSame(r.cellScanner(), cells);
77      assertSame(r.cellScanner(), cells);
78      // Assert we are not creating new object when doing cellscanner
79      assertTrue(r == r.cellScanner());
80    }
81  
82    private void assertSame(final CellScanner cellScanner, final Cell [] cells) throws IOException {
83      int count = 0;
84      while (cellScanner.advance()) {
85        assertTrue(cells[count].equals(cellScanner.current()));
86        count++;
87      }
88      assertEquals(cells.length, count);
89    }
90  
91    public void testBasicGetColumn() throws Exception {
92      KeyValue [] kvs = genKVs(row, family, value, 1, 100);
93  
94      Arrays.sort(kvs, KeyValue.COMPARATOR);
95  
96      Result r = Result.create(kvs);
97  
98      for (int i = 0; i < 100; ++i) {
99        final byte[] qf = Bytes.toBytes(i);
100 
101       List<Cell> ks = r.getColumnCells(family, qf);
102       assertEquals(1, ks.size());
103       assertTrue(CellUtil.matchingQualifier(ks.get(0), qf));
104       assertEquals(ks.get(0), r.getColumnLatestCell(family, qf));
105     }
106   }
107 
108   public void testMultiVersionGetColumn() throws Exception {
109     KeyValue [] kvs1 = genKVs(row, family, value, 1, 100);
110     KeyValue [] kvs2 = genKVs(row, family, value, 200, 100);
111 
112     KeyValue [] kvs = new KeyValue[kvs1.length+kvs2.length];
113     System.arraycopy(kvs1, 0, kvs, 0, kvs1.length);
114     System.arraycopy(kvs2, 0, kvs, kvs1.length, kvs2.length);
115 
116     Arrays.sort(kvs, KeyValue.COMPARATOR);
117 
118     Result r = Result.create(kvs);
119     for (int i = 0; i < 100; ++i) {
120       final byte[] qf = Bytes.toBytes(i);
121 
122       List<Cell> ks = r.getColumnCells(family, qf);
123       assertEquals(2, ks.size());
124       assertTrue(CellUtil.matchingQualifier(ks.get(0), qf));
125       assertEquals(200, ks.get(0).getTimestamp());
126       assertEquals(ks.get(0), r.getColumnLatestCell(family, qf));
127     }
128   }
129 
130   public void testBasicGetValue() throws Exception {
131     KeyValue [] kvs = genKVs(row, family, value, 1, 100);
132 
133     Arrays.sort(kvs, KeyValue.COMPARATOR);
134 
135     Result r = Result.create(kvs);
136 
137     for (int i = 0; i < 100; ++i) {
138       final byte[] qf = Bytes.toBytes(i);
139 
140       assertByteEquals(Bytes.add(value, Bytes.toBytes(i)), r.getValue(family, qf));
141       assertTrue(r.containsColumn(family, qf));
142     }
143   }
144 
145   public void testMultiVersionGetValue() throws Exception {
146     KeyValue [] kvs1 = genKVs(row, family, value, 1, 100);
147     KeyValue [] kvs2 = genKVs(row, family, value, 200, 100);
148 
149     KeyValue [] kvs = new KeyValue[kvs1.length+kvs2.length];
150     System.arraycopy(kvs1, 0, kvs, 0, kvs1.length);
151     System.arraycopy(kvs2, 0, kvs, kvs1.length, kvs2.length);
152 
153     Arrays.sort(kvs, KeyValue.COMPARATOR);
154 
155     Result r = Result.create(kvs);
156     for (int i = 0; i < 100; ++i) {
157       final byte[] qf = Bytes.toBytes(i);
158 
159       assertByteEquals(Bytes.add(value, Bytes.toBytes(i)), r.getValue(family, qf));
160       assertTrue(r.containsColumn(family, qf));
161     }
162   }
163 
164   public void testBasicLoadValue() throws Exception {
165     KeyValue [] kvs = genKVs(row, family, value, 1, 100);
166 
167     Arrays.sort(kvs, KeyValue.COMPARATOR);
168 
169     Result r = Result.create(kvs);
170     ByteBuffer loadValueBuffer = ByteBuffer.allocate(1024);
171 
172     for (int i = 0; i < 100; ++i) {
173       final byte[] qf = Bytes.toBytes(i);
174 
175       loadValueBuffer.clear();
176       r.loadValue(family, qf, loadValueBuffer);
177       loadValueBuffer.flip();
178       assertEquals(ByteBuffer.wrap(Bytes.add(value, Bytes.toBytes(i))), loadValueBuffer);
179       assertEquals(ByteBuffer.wrap(Bytes.add(value, Bytes.toBytes(i))),
180           r.getValueAsByteBuffer(family, qf));
181     }
182   }
183 
184   public void testMultiVersionLoadValue() throws Exception {
185     KeyValue [] kvs1 = genKVs(row, family, value, 1, 100);
186     KeyValue [] kvs2 = genKVs(row, family, value, 200, 100);
187 
188     KeyValue [] kvs = new KeyValue[kvs1.length+kvs2.length];
189     System.arraycopy(kvs1, 0, kvs, 0, kvs1.length);
190     System.arraycopy(kvs2, 0, kvs, kvs1.length, kvs2.length);
191 
192     Arrays.sort(kvs, KeyValue.COMPARATOR);
193 
194     ByteBuffer loadValueBuffer = ByteBuffer.allocate(1024);
195 
196     Result r = Result.create(kvs);
197     for (int i = 0; i < 100; ++i) {
198       final byte[] qf = Bytes.toBytes(i);
199 
200       loadValueBuffer.clear();
201       r.loadValue(family, qf, loadValueBuffer);
202       loadValueBuffer.flip();
203       assertEquals(ByteBuffer.wrap(Bytes.add(value, Bytes.toBytes(i))), loadValueBuffer);
204       assertEquals(ByteBuffer.wrap(Bytes.add(value, Bytes.toBytes(i))),
205           r.getValueAsByteBuffer(family, qf));
206     }
207   }
208 
209   /**
210    * Verify that Result.compareResults(...) behaves correctly.
211    */
212   public void testCompareResults() throws Exception {
213     byte [] value1 = Bytes.toBytes("value1");
214     byte [] qual = Bytes.toBytes("qual");
215 
216     KeyValue kv1 = new KeyValue(row, family, qual, value);
217     KeyValue kv2 = new KeyValue(row, family, qual, value1);
218 
219     Result r1 = Result.create(new KeyValue[] {kv1});
220     Result r2 = Result.create(new KeyValue[] {kv2});
221     // no exception thrown
222     Result.compareResults(r1, r1);
223     try {
224       // these are different (HBASE-4800)
225       Result.compareResults(r1, r2);
226       fail();
227     } catch (Exception x) {
228       assertTrue(x.getMessage().startsWith("This result was different:"));
229     }
230   }
231 
232   /**
233    * Verifies that one can't modify instance of EMPTY_RESULT.
234    */
235   public void testEmptyResultIsReadonly() {
236     Result emptyResult = Result.EMPTY_RESULT;
237     Result otherResult = new Result();
238 
239     try {
240       emptyResult.copyFrom(otherResult);
241       fail("UnsupportedOperationException should have been thrown!");
242     } catch (UnsupportedOperationException ex) {
243       LOG.debug("As expected: " + ex.getMessage());
244     }
245     try {
246       emptyResult.addResults(ClientProtos.RegionLoadStats.getDefaultInstance());
247       fail("UnsupportedOperationException should have been thrown!");
248     } catch (UnsupportedOperationException ex) {
249       LOG.debug("As expected: " + ex.getMessage());
250     }
251     try {
252       emptyResult.setExists(true);
253       fail("UnsupportedOperationException should have been thrown!");
254     } catch (UnsupportedOperationException ex) {
255       LOG.debug("As expected: " + ex.getMessage());
256     }
257   }
258 
259   /**
260    * Microbenchmark that compares {@link Result#getValue} and {@link Result#loadValue} performance.
261    *
262    * @throws Exception
263    */
264   public void doReadBenchmark() throws Exception {
265 
266     final int n = 5;
267     final int m = 100000000;
268 
269     StringBuilder valueSB = new StringBuilder();
270     for (int i = 0; i < 100; i++) {
271       valueSB.append((byte)(Math.random() * 10));
272     }
273 
274     StringBuilder rowSB = new StringBuilder();
275     for (int i = 0; i < 50; i++) {
276       rowSB.append((byte)(Math.random() * 10));
277     }
278 
279     KeyValue [] kvs = genKVs(Bytes.toBytes(rowSB.toString()), family,
280         Bytes.toBytes(valueSB.toString()), 1, n);
281     Arrays.sort(kvs, KeyValue.COMPARATOR);
282     ByteBuffer loadValueBuffer = ByteBuffer.allocate(1024);
283     Result r = Result.create(kvs);
284 
285     byte[][] qfs = new byte[n][Bytes.SIZEOF_INT];
286     for (int i = 0; i < n; ++i) {
287       System.arraycopy(qfs[i], 0, Bytes.toBytes(i), 0, Bytes.SIZEOF_INT);
288     }
289 
290     // warm up
291     for (int k = 0; k < 100000; k++) {
292       for (int i = 0; i < n; ++i) {
293         r.getValue(family, qfs[i]);
294         loadValueBuffer.clear();
295         r.loadValue(family, qfs[i], loadValueBuffer);
296         loadValueBuffer.flip();
297       }
298     }
299 
300     System.gc();
301     long start = System.nanoTime();
302     for (int k = 0; k < m; k++) {
303       for (int i = 0; i < n; ++i) {
304         loadValueBuffer.clear();
305         r.loadValue(family, qfs[i], loadValueBuffer);
306         loadValueBuffer.flip();
307       }
308     }
309     long stop = System.nanoTime();
310     System.out.println("loadValue(): " + (stop - start));
311 
312     System.gc();
313     start = System.nanoTime();
314     for (int k = 0; k < m; k++) {
315       for (int i = 0; i < n; i++) {
316         r.getValue(family, qfs[i]);
317       }
318     }
319     stop = System.nanoTime();
320     System.out.println("getValue():  " + (stop - start));
321   }
322 
323   /**
324    * Calls non-functional test methods.
325    *
326    * @param args
327    */
328   public static void main(String[] args) {
329     TestResult testResult = new TestResult();
330     try {
331       testResult.doReadBenchmark();
332     } catch (Exception e) {
333       LOG.error("Unexpected exception", e);
334     }
335   }
336 }