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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 package org
.apache
.hadoop
.hbase
.client
;
20 import static org
.hamcrest
.MatcherAssert
.assertThat
;
21 import static org
.hamcrest
.Matchers
.greaterThan
;
22 import static org
.hamcrest
.Matchers
.is
;
23 import static org
.hamcrest
.Matchers
.lessThan
;
24 import static org
.junit
.Assert
.assertArrayEquals
;
25 import java
.io
.IOException
;
26 import java
.nio
.ByteBuffer
;
27 import java
.util
.ArrayList
;
28 import java
.util
.Arrays
;
29 import java
.util
.List
;
30 import java
.util
.NoSuchElementException
;
31 import junit
.framework
.TestCase
;
32 import org
.apache
.hadoop
.hbase
.ArrayBackedTag
;
33 import org
.apache
.hadoop
.hbase
.ByteBufferKeyValue
;
34 import org
.apache
.hadoop
.hbase
.Cell
;
35 import org
.apache
.hadoop
.hbase
.CellComparator
;
36 import org
.apache
.hadoop
.hbase
.CellScanner
;
37 import org
.apache
.hadoop
.hbase
.CellUtil
;
38 import org
.apache
.hadoop
.hbase
.HBaseClassTestRule
;
39 import org
.apache
.hadoop
.hbase
.KeyValue
;
40 import org
.apache
.hadoop
.hbase
.Tag
;
41 import org
.apache
.hadoop
.hbase
.testclassification
.ClientTests
;
42 import org
.apache
.hadoop
.hbase
.testclassification
.SmallTests
;
43 import org
.apache
.hadoop
.hbase
.util
.ByteBufferUtils
;
44 import org
.apache
.hadoop
.hbase
.util
.Bytes
;
45 import org
.hamcrest
.MatcherAssert
;
46 import org
.junit
.ClassRule
;
47 import org
.junit
.experimental
.categories
.Category
;
48 import org
.slf4j
.Logger
;
49 import org
.slf4j
.LoggerFactory
;
51 @Category({SmallTests
.class, ClientTests
.class})
52 public class TestResult
extends TestCase
{
55 public static final HBaseClassTestRule CLASS_RULE
=
56 HBaseClassTestRule
.forClass(TestResult
.class);
58 private static final Logger LOG
= LoggerFactory
.getLogger(TestResult
.class.getName());
60 static KeyValue
[] genKVs(final byte[] row
, final byte[] family
,
64 KeyValue
[] kvs
= new KeyValue
[cols
];
66 for (int i
= 0; i
< cols
; i
++) {
67 kvs
[i
] = new KeyValue(
68 row
, family
, Bytes
.toBytes(i
),
70 Bytes
.add(value
, Bytes
.toBytes(i
)));
75 static final byte [] row
= Bytes
.toBytes("row");
76 static final byte [] family
= Bytes
.toBytes("family");
77 static final byte [] value
= Bytes
.toBytes("value");
78 static final byte [] qual
= Bytes
.toBytes("qual");
81 * Run some tests to ensure Result acts like a proper CellScanner.
84 public void testResultAsCellScanner() throws IOException
{
85 Cell
[] cells
= genKVs(row
, family
, value
, 1, 10);
86 Arrays
.sort(cells
, CellComparator
.getInstance());
87 Result r
= Result
.create(cells
);
89 // Assert I run over same result multiple times.
90 assertSame(r
.cellScanner(), cells
);
91 assertSame(r
.cellScanner(), cells
);
92 // Assert we are not creating new object when doing cellscanner
93 assertTrue(r
== r
.cellScanner());
96 private void assertSame(final CellScanner cellScanner
, final Cell
[] cells
) throws IOException
{
98 while (cellScanner
.advance()) {
99 assertTrue(cells
[count
].equals(cellScanner
.current()));
102 assertEquals(cells
.length
, count
);
105 public void testBasicGetColumn() throws Exception
{
106 KeyValue
[] kvs
= genKVs(row
, family
, value
, 1, 100);
108 Arrays
.sort(kvs
, CellComparator
.getInstance());
110 Result r
= Result
.create(kvs
);
112 for (int i
= 0; i
< 100; ++i
) {
113 final byte[] qf
= Bytes
.toBytes(i
);
115 List
<Cell
> ks
= r
.getColumnCells(family
, qf
);
116 assertEquals(1, ks
.size());
117 assertTrue(CellUtil
.matchingQualifier(ks
.get(0), qf
));
118 assertEquals(ks
.get(0), r
.getColumnLatestCell(family
, qf
));
122 public void testCurrentOnEmptyCell() throws IOException
{
123 Result r
= Result
.create(new Cell
[0]);
124 assertFalse(r
.advance());
125 assertNull(r
.current());
128 public void testAdvanceTwiceOnEmptyCell() throws IOException
{
129 Result r
= Result
.create(new Cell
[0]);
130 assertFalse(r
.advance());
133 fail("NoSuchElementException should have been thrown!");
134 } catch (NoSuchElementException ex
) {
135 LOG
.debug("As expected: " + ex
.getMessage());
139 public void testMultiVersionGetColumn() throws Exception
{
140 KeyValue
[] kvs1
= genKVs(row
, family
, value
, 1, 100);
141 KeyValue
[] kvs2
= genKVs(row
, family
, value
, 200, 100);
143 KeyValue
[] kvs
= new KeyValue
[kvs1
.length
+kvs2
.length
];
144 System
.arraycopy(kvs1
, 0, kvs
, 0, kvs1
.length
);
145 System
.arraycopy(kvs2
, 0, kvs
, kvs1
.length
, kvs2
.length
);
147 Arrays
.sort(kvs
, CellComparator
.getInstance());
149 Result r
= Result
.create(kvs
);
150 for (int i
= 0; i
< 100; ++i
) {
151 final byte[] qf
= Bytes
.toBytes(i
);
153 List
<Cell
> ks
= r
.getColumnCells(family
, qf
);
154 assertEquals(2, ks
.size());
155 assertTrue(CellUtil
.matchingQualifier(ks
.get(0), qf
));
156 assertEquals(200, ks
.get(0).getTimestamp());
157 assertEquals(ks
.get(0), r
.getColumnLatestCell(family
, qf
));
161 public void testBasicGetValue() throws Exception
{
162 KeyValue
[] kvs
= genKVs(row
, family
, value
, 1, 100);
164 Arrays
.sort(kvs
, CellComparator
.getInstance());
166 Result r
= Result
.create(kvs
);
168 for (int i
= 0; i
< 100; ++i
) {
169 final byte[] qf
= Bytes
.toBytes(i
);
171 assertArrayEquals(Bytes
.add(value
, Bytes
.toBytes(i
)), r
.getValue(family
, qf
));
172 assertTrue(r
.containsColumn(family
, qf
));
176 public void testMultiVersionGetValue() throws Exception
{
177 KeyValue
[] kvs1
= genKVs(row
, family
, value
, 1, 100);
178 KeyValue
[] kvs2
= genKVs(row
, family
, value
, 200, 100);
180 KeyValue
[] kvs
= new KeyValue
[kvs1
.length
+kvs2
.length
];
181 System
.arraycopy(kvs1
, 0, kvs
, 0, kvs1
.length
);
182 System
.arraycopy(kvs2
, 0, kvs
, kvs1
.length
, kvs2
.length
);
184 Arrays
.sort(kvs
, CellComparator
.getInstance());
186 Result r
= Result
.create(kvs
);
187 for (int i
= 0; i
< 100; ++i
) {
188 final byte[] qf
= Bytes
.toBytes(i
);
190 assertArrayEquals(Bytes
.add(value
, Bytes
.toBytes(i
)), r
.getValue(family
, qf
));
191 assertTrue(r
.containsColumn(family
, qf
));
195 public void testBasicLoadValue() throws Exception
{
196 KeyValue
[] kvs
= genKVs(row
, family
, value
, 1, 100);
198 Arrays
.sort(kvs
, CellComparator
.getInstance());
200 Result r
= Result
.create(kvs
);
201 ByteBuffer loadValueBuffer
= ByteBuffer
.allocate(1024);
203 for (int i
= 0; i
< 100; ++i
) {
204 final byte[] qf
= Bytes
.toBytes(i
);
206 loadValueBuffer
.clear();
207 r
.loadValue(family
, qf
, loadValueBuffer
);
208 loadValueBuffer
.flip();
209 assertEquals(loadValueBuffer
, ByteBuffer
.wrap(Bytes
.add(value
, Bytes
.toBytes(i
))));
210 assertEquals(ByteBuffer
.wrap(Bytes
.add(value
, Bytes
.toBytes(i
))),
211 r
.getValueAsByteBuffer(family
, qf
));
215 public void testMultiVersionLoadValue() throws Exception
{
216 KeyValue
[] kvs1
= genKVs(row
, family
, value
, 1, 100);
217 KeyValue
[] kvs2
= genKVs(row
, family
, value
, 200, 100);
219 KeyValue
[] kvs
= new KeyValue
[kvs1
.length
+kvs2
.length
];
220 System
.arraycopy(kvs1
, 0, kvs
, 0, kvs1
.length
);
221 System
.arraycopy(kvs2
, 0, kvs
, kvs1
.length
, kvs2
.length
);
223 Arrays
.sort(kvs
, CellComparator
.getInstance());
225 ByteBuffer loadValueBuffer
= ByteBuffer
.allocate(1024);
227 Result r
= Result
.create(kvs
);
228 for (int i
= 0; i
< 100; ++i
) {
229 final byte[] qf
= Bytes
.toBytes(i
);
231 loadValueBuffer
.clear();
232 r
.loadValue(family
, qf
, loadValueBuffer
);
233 loadValueBuffer
.flip();
234 assertEquals(loadValueBuffer
, ByteBuffer
.wrap(Bytes
.add(value
, Bytes
.toBytes(i
))));
235 assertEquals(ByteBuffer
.wrap(Bytes
.add(value
, Bytes
.toBytes(i
))),
236 r
.getValueAsByteBuffer(family
, qf
));
241 * Verify that Result.compareResults(...) behaves correctly.
243 public void testCompareResults() throws Exception
{
244 byte [] value1
= Bytes
.toBytes("value1");
245 byte [] qual
= Bytes
.toBytes("qual");
247 KeyValue kv1
= new KeyValue(row
, family
, qual
, value
);
248 KeyValue kv2
= new KeyValue(row
, family
, qual
, value1
);
250 Result r1
= Result
.create(new KeyValue
[] {kv1
});
251 Result r2
= Result
.create(new KeyValue
[] {kv2
});
252 // no exception thrown
253 Result
.compareResults(r1
, r1
);
255 // these are different (HBASE-4800)
256 Result
.compareResults(r1
, r2
);
258 } catch (Exception x
) {
259 assertTrue(x
.getMessage().startsWith("This result was different:"));
263 public void testCompareResultsWithTags() throws Exception
{
264 Tag t1
= new ArrayBackedTag((byte) 1, Bytes
.toBytes("TAG1"));
265 Tag t2
= new ArrayBackedTag((byte) 2, Bytes
.toBytes("TAG2"));
266 // Both BB backed tags KV are null
267 Result result1
= getByteBufferBackedTagResult(null);
268 Result result2
= getByteBufferBackedTagResult(null);
269 Result
.compareResults(result1
, result2
);
271 // Test both byte buffer backed tags KeyValue
272 result1
= getByteBufferBackedTagResult(t1
);
273 result2
= getByteBufferBackedTagResult(t1
);
274 Result
.compareResults(result1
, result2
);
276 // Both array backed tags KV are null
277 result1
= getArrayBackedTagResult(null);
278 result2
= getArrayBackedTagResult(null);
279 Result
.compareResults(result1
, result2
);
281 // Test both array backed tags KeyValue
282 result1
= getArrayBackedTagResult(t1
);
283 result2
= getArrayBackedTagResult(t1
);
284 Result
.compareResults(result1
, result2
);
286 // left instance of byte buffer and right instance of array backed
287 result1
= getByteBufferBackedTagResult(t1
);
288 result2
= getArrayBackedTagResult(t1
);
289 Result
.compareResults(result1
, result2
);
291 // left instance of array backed and right instance of byte buffer backed.
292 result1
= getArrayBackedTagResult(t1
);
293 result2
= getByteBufferBackedTagResult(t1
);
294 Result
.compareResults(result1
, result2
);
296 // Left BB backed null tag and right BB backed non null tag
297 result1
= getByteBufferBackedTagResult(null);
298 result2
= getByteBufferBackedTagResult(t2
);
300 Result
.compareResults(result1
, result2
);
302 } catch (Exception e
) {
306 // Left BB backed non null tag and right BB backed null tag
307 result1
= getByteBufferBackedTagResult(t1
);
308 result2
= getByteBufferBackedTagResult(null);
310 Result
.compareResults(result1
, result2
);
312 } catch (Exception e
) {
316 // Both byte buffer backed tags KV are different
317 result1
= getByteBufferBackedTagResult(t1
);
318 result2
= getByteBufferBackedTagResult(t2
);
320 Result
.compareResults(result1
, result2
);
322 } catch (Exception e
) {
326 // Left array backed non null tag and right array backed null tag
327 result1
= getArrayBackedTagResult(t1
);
328 result2
= getArrayBackedTagResult(null);
330 Result
.compareResults(result1
, result2
);
332 } catch (Exception e
) {
336 // Left array backed null tag and right array backed non null tag
337 result1
= getByteBufferBackedTagResult(null);
338 result2
= getByteBufferBackedTagResult(t2
);
340 Result
.compareResults(result1
, result2
);
342 } catch (Exception e
) {
346 // Both array backed tags KV are different
347 result1
= getArrayBackedTagResult(t1
);
348 result2
= getArrayBackedTagResult(t2
);
350 Result
.compareResults(result1
, result2
);
352 } catch (Exception e
) {
356 // left instance of byte buffer and right instance of array backed are different
357 result1
= getByteBufferBackedTagResult(t1
);
358 result2
= getArrayBackedTagResult(t2
);
360 Result
.compareResults(result1
, result2
);
362 } catch (Exception e
) {
366 // left instance of array backed and right instance of byte buffer backed are different
367 result1
= getArrayBackedTagResult(t1
);
368 result2
= getByteBufferBackedTagResult(t2
);
370 Result
.compareResults(result1
, result2
);
372 } catch (Exception e
) {
377 public void testCompareResultMemoryUsage() {
378 List
<Cell
> cells1
= new ArrayList
<>();
379 for (long i
= 0; i
< 100; i
++) {
380 cells1
.add(new KeyValue(row
, family
, Bytes
.toBytes(i
), value
));
383 List
<Cell
> cells2
= new ArrayList
<>();
384 for (long i
= 0; i
< 100; i
++) {
385 cells2
.add(new KeyValue(row
, family
, Bytes
.toBytes(i
), Bytes
.toBytes(i
)));
388 Result r1
= Result
.create(cells1
);
389 Result r2
= Result
.create(cells2
);
391 Result
.compareResults(r1
, r2
);
393 } catch (Exception x
) {
394 assertTrue(x
.getMessage().startsWith("This result was different:"));
395 assertThat(x
.getMessage().length(), is(greaterThan(100)));
399 Result
.compareResults(r1
, r2
, false);
401 } catch (Exception x
) {
402 assertEquals("This result was different: row=row", x
.getMessage());
403 assertThat(x
.getMessage().length(), is(lessThan(100)));
407 private Result
getArrayBackedTagResult(Tag tag
) {
408 List
<Tag
> tags
= null;
410 tags
= Arrays
.asList(tag
);
412 KeyValue kvCell
= new KeyValue(row
, family
, qual
, 0L, KeyValue
.Type
.Put
,
414 return Result
.create(new Cell
[] {kvCell
});
417 private Result
getByteBufferBackedTagResult(Tag tag
) {
418 List
<Tag
> tags
= null;
420 tags
= Arrays
.asList(tag
);
422 KeyValue kvCell
= new KeyValue(row
, family
, qual
, 0L, KeyValue
.Type
.Put
,
424 ByteBuffer buf
= ByteBuffer
.allocateDirect(kvCell
.getBuffer().length
);
425 ByteBufferUtils
.copyFromArrayToBuffer(buf
, kvCell
.getBuffer(), 0, kvCell
.getBuffer().length
);
426 ByteBufferKeyValue bbKV
= new ByteBufferKeyValue(buf
, 0, buf
.capacity(), 0L);
427 return Result
.create(new Cell
[] {bbKV
});
430 * Verifies that one can't modify instance of EMPTY_RESULT.
432 public void testEmptyResultIsReadonly() {
433 Result emptyResult
= Result
.EMPTY_RESULT
;
434 Result otherResult
= new Result();
437 emptyResult
.copyFrom(otherResult
);
438 fail("UnsupportedOperationException should have been thrown!");
439 } catch (UnsupportedOperationException ex
) {
440 LOG
.debug("As expected: " + ex
.getMessage());
443 emptyResult
.setExists(true);
444 fail("UnsupportedOperationException should have been thrown!");
445 } catch (UnsupportedOperationException ex
) {
446 LOG
.debug("As expected: " + ex
.getMessage());
451 * Microbenchmark that compares {@link Result#getValue} and {@link Result#loadValue} performance.
455 public void doReadBenchmark() throws Exception
{
458 final int m
= 100000000;
460 StringBuilder valueSB
= new StringBuilder();
461 for (int i
= 0; i
< 100; i
++) {
462 valueSB
.append((byte)(Math
.random() * 10));
465 StringBuilder rowSB
= new StringBuilder();
466 for (int i
= 0; i
< 50; i
++) {
467 rowSB
.append((byte)(Math
.random() * 10));
470 KeyValue
[] kvs
= genKVs(Bytes
.toBytes(rowSB
.toString()), family
,
471 Bytes
.toBytes(valueSB
.toString()), 1, n
);
472 Arrays
.sort(kvs
, CellComparator
.getInstance());
473 ByteBuffer loadValueBuffer
= ByteBuffer
.allocate(1024);
474 Result r
= Result
.create(kvs
);
476 byte[][] qfs
= new byte[n
][Bytes
.SIZEOF_INT
];
477 for (int i
= 0; i
< n
; ++i
) {
478 System
.arraycopy(qfs
[i
], 0, Bytes
.toBytes(i
), 0, Bytes
.SIZEOF_INT
);
482 for (int k
= 0; k
< 100000; k
++) {
483 for (int i
= 0; i
< n
; ++i
) {
484 r
.getValue(family
, qfs
[i
]);
485 loadValueBuffer
.clear();
486 r
.loadValue(family
, qfs
[i
], loadValueBuffer
);
487 loadValueBuffer
.flip();
492 long start
= System
.nanoTime();
493 for (int k
= 0; k
< m
; k
++) {
494 for (int i
= 0; i
< n
; ++i
) {
495 loadValueBuffer
.clear();
496 r
.loadValue(family
, qfs
[i
], loadValueBuffer
);
497 loadValueBuffer
.flip();
500 long stop
= System
.nanoTime();
501 System
.out
.println("loadValue(): " + (stop
- start
));
504 start
= System
.nanoTime();
505 for (int k
= 0; k
< m
; k
++) {
506 for (int i
= 0; i
< n
; i
++) {
507 r
.getValue(family
, qfs
[i
]);
510 stop
= System
.nanoTime();
511 System
.out
.println("getValue(): " + (stop
- start
));
515 * Calls non-functional test methods.
519 public static void main(String
[] args
) {
520 TestResult testResult
= new TestResult();
522 testResult
.doReadBenchmark();
523 } catch (Exception e
) {
524 LOG
.error("Unexpected exception", e
);