HBASE-11865 Result implements CellScannable; rather it should BE a CellScanner

This commit is contained in:
stack 2014-08-31 00:11:35 -07:00
parent 651b6bab49
commit 5719e4098b
2 changed files with 61 additions and 11 deletions

View File

@ -58,20 +58,23 @@ import org.apache.hadoop.hbase.util.Bytes;
* *
* To get the latest value for a specific family and qualifier use {@link #getValue(byte[], byte[])}. * To get the latest value for a specific family and qualifier use {@link #getValue(byte[], byte[])}.
* *
* A Result is backed by an array of {@link KeyValue} objects, each representing * A Result is backed by an array of {@link Cell} objects, each representing
* an HBase cell defined by the row, family, qualifier, timestamp, and value.<p> * an HBase cell defined by the row, family, qualifier, timestamp, and value.<p>
* *
* The underlying {@link KeyValue} objects can be accessed through the method {@link #listCells()}. * The underlying {@link Cell} objects can be accessed through the method {@link #listCells()}.
* Each KeyValue can then be accessed through * This will create a List from the internal Cell []. Better is to exploit the fact that
* {@link KeyValue#getRow()}, {@link KeyValue#getFamily()}, {@link KeyValue#getQualifier()}, * a new Result instance is a primed {@link CellScanner}; just call {@link #advance()} and
* {@link KeyValue#getTimestamp()}, and {@link KeyValue#getValue()}.<p> * {@link #current()} to iterate over Cells as you would any {@link CellScanner}.
* Call {@link #cellScanner()} to reset should you need to iterate the same Result over again
* ({@link CellScanner}s are one-shot).
* *
* If you need to overwrite a Result with another Result instance -- as in the old 'mapred' RecordReader next * If you need to overwrite a Result with another Result instance -- as in the old 'mapred'
* invocations -- then create an empty Result with the null constructor and in then use {@link #copyFrom(Result)} * RecordReader next invocations -- then create an empty Result with the null constructor and
* in then use {@link #copyFrom(Result)}
*/ */
@InterfaceAudience.Public @InterfaceAudience.Public
@InterfaceStability.Stable @InterfaceStability.Stable
public class Result implements CellScannable { public class Result implements CellScannable, CellScanner {
private Cell[] cells; private Cell[] cells;
private Boolean exists; // if the query was just to check existence. private Boolean exists; // if the query was just to check existence.
private boolean stale = false; private boolean stale = false;
@ -86,6 +89,13 @@ public class Result implements CellScannable {
private static final int PAD_WIDTH = 128; private static final int PAD_WIDTH = 128;
public static final Result EMPTY_RESULT = new Result(); public static final Result EMPTY_RESULT = new Result();
private final static int INITIAL_CELLSCANNER_INDEX = -1;
/**
* Index for where we are when Result is acting as a {@link CellScanner}.
*/
private int cellScannerIndex = INITIAL_CELLSCANNER_INDEX;
/** /**
* Creates an empty Result w/ no KeyValue payload; returns null if you call {@link #rawCells()}. * Creates an empty Result w/ no KeyValue payload; returns null if you call {@link #rawCells()}.
* Use this to represent no results if <code>null</code> won't do or in old 'mapred' as oppposed to 'mapreduce' package * Use this to represent no results if <code>null</code> won't do or in old 'mapred' as oppposed to 'mapreduce' package
@ -827,7 +837,21 @@ public class Result implements CellScannable {
@Override @Override
public CellScanner cellScanner() { public CellScanner cellScanner() {
return CellUtil.createCellScanner(this.cells); // Reset
this.cellScannerIndex = INITIAL_CELLSCANNER_INDEX;
return this;
}
@Override
public Cell current() {
if (cells == null) return null;
return (cellScannerIndex < 0)? null: this.cells[cellScannerIndex];
}
@Override
public boolean advance() {
if (cells == null) return false;
return ++cellScannerIndex < this.cells.length;
} }
public Boolean getExists() { public Boolean getExists() {
@ -846,5 +870,4 @@ public class Result implements CellScannable {
public boolean isStale() { public boolean isStale() {
return stale; return stale;
} }
}
}

View File

@ -21,6 +21,7 @@ package org.apache.hadoop.hbase.client;
import static org.apache.hadoop.hbase.HBaseTestCase.assertByteEquals; import static org.apache.hadoop.hbase.HBaseTestCase.assertByteEquals;
import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -30,6 +31,7 @@ import junit.framework.TestCase;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hbase.Cell; import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellScanner;
import org.apache.hadoop.hbase.CellUtil; import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.SmallTests; import org.apache.hadoop.hbase.SmallTests;
@ -60,6 +62,31 @@ public class TestResult extends TestCase {
static final byte [] family = Bytes.toBytes("family"); static final byte [] family = Bytes.toBytes("family");
static final byte [] value = Bytes.toBytes("value"); static final byte [] value = Bytes.toBytes("value");
/**
* Run some tests to ensure Result acts like a proper CellScanner.
* @throws IOException
*/
public void testResultAsCellScanner() throws IOException {
Cell [] cells = genKVs(row, family, value, 1, 10);
Arrays.sort(cells, KeyValue.COMPARATOR);
Result r = Result.create(cells);
assertSame(r, cells);
// Assert I run over same result multiple times.
assertSame(r.cellScanner(), cells);
assertSame(r.cellScanner(), cells);
// Assert we are not creating new object when doing cellscanner
assertTrue(r == r.cellScanner());
}
private void assertSame(final CellScanner cellScanner, final Cell [] cells) throws IOException {
int count = 0;
while (cellScanner.advance()) {
assertTrue(cells[count].equals(cellScanner.current()));
count++;
}
assertEquals(cells.length, count);
}
public void testBasicGetColumn() throws Exception { public void testBasicGetColumn() throws Exception {
KeyValue [] kvs = genKVs(row, family, value, 1, 100); KeyValue [] kvs = genKVs(row, family, value, 1, 100);