Index: src/main/java/org/apache/hadoop/hbase/KeyValue.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/KeyValue.java (revision 1417249) +++ src/main/java/org/apache/hadoop/hbase/KeyValue.java (working copy) @@ -216,9 +216,6 @@ private int offset = 0; private int length = 0; - // the row cached - private volatile byte [] rowCache = null; - /** * @return True if a delete type, a {@link KeyValue.Type#Delete} or * a {KeyValue.Type#DeleteFamily} or a {@link KeyValue.Type#DeleteColumn} @@ -987,7 +984,6 @@ int tsOffset = getTimestampOffset(); System.arraycopy(now, 0, this.bytes, tsOffset, Bytes.SIZEOF_LONG); // clear cache or else getTimestamp() possibly returns an old value - timestampCache = -1L; return true; } return false; @@ -1037,28 +1033,19 @@ * @return Row in a new byte array. */ public byte [] getRow() { - if (rowCache == null) { - int o = getRowOffset(); - short l = getRowLength(); - // initialize and copy the data into a local variable - // in case multiple threads race here. - byte local[] = new byte[l]; - System.arraycopy(getBuffer(), o, local, 0, l); - rowCache = local; // volatile assign - } - return rowCache; + int o = getRowOffset(); + short l = getRowLength(); + byte result[] = new byte[l]; + System.arraycopy(getBuffer(), o, result, 0, l); + return result; } /** * * @return Timestamp */ - private long timestampCache = -1; public long getTimestamp() { - if (timestampCache == -1) { - timestampCache = getTimestamp(getKeyLength()); - } - return timestampCache; + return getTimestamp(getKeyLength()); } /** @@ -2260,21 +2247,17 @@ // HeapSize public long heapSize() { - return ClassSize.align(ClassSize.OBJECT + (2 * ClassSize.REFERENCE) + - ClassSize.align(ClassSize.ARRAY) + ClassSize.align(length) + - (3 * Bytes.SIZEOF_INT) + - ClassSize.align(ClassSize.ARRAY) + - (2 * Bytes.SIZEOF_LONG)); + return ClassSize.align(ClassSize.OBJECT + ClassSize.REFERENCE + + ClassSize.align(ClassSize.ARRAY) + ClassSize.align(length) + + (3 * Bytes.SIZEOF_INT) + Bytes.SIZEOF_LONG); } // this overload assumes that the length bytes have already been read, // and it expects the length of the KeyValue to be explicitly passed // to it. public void readFields(int length, final DataInput in) throws IOException { - this.rowCache = null; this.length = length; this.offset = 0; - this.timestampCache = -1; this.keyLength = 0; this.bytes = new byte[this.length]; in.readFully(this.bytes, 0, this.length); Index: src/main/java/org/apache/hadoop/hbase/client/Result.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/client/Result.java (revision 1417249) +++ src/main/java/org/apache/hadoop/hbase/client/Result.java (working copy) @@ -96,7 +96,7 @@ * @param kvs List of KeyValues */ public Result(List kvs) { - this(kvs.toArray(new KeyValue[0])); + this(kvs.toArray(new KeyValue[kvs.size()])); } /** Index: src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java (revision 1417249) +++ src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java (working copy) @@ -3548,8 +3548,16 @@ rpcCall.throwExceptionIfCallerDisconnected(); } - byte [] currentRow = peekRow(); - if (isStopRow(currentRow)) { + KeyValue current = this.storeHeap.peek(); + byte[] currentRow = null; + int offset = 0; + short length = 0; + if (current != null) { + currentRow = current.getBuffer(); + offset = current.getRowOffset(); + length = current.getRowLength(); + } + if (isStopRow(currentRow, offset, length)) { if (filter != null && filter.hasFilterRow()) { filter.filterRow(results); } @@ -3558,10 +3566,10 @@ } return false; - } else if (filterRowKey(currentRow)) { - nextRow(currentRow); + } else if (filterRowKey(currentRow, offset, length)) { + nextRow(currentRow, offset, length); } else { - byte [] nextRow; + KeyValue nextKv; do { this.storeHeap.next(results, limit - results.size(), metric); if (limit > 0 && results.size() == limit) { @@ -3571,9 +3579,10 @@ } return true; // we are expecting more yes, but also limited to how many we can return. } - } while (Bytes.equals(currentRow, nextRow = peekRow())); + nextKv = this.storeHeap.peek(); + } while (nextKv != null && nextKv.matchingRow(currentRow, offset, length)); - final boolean stopRow = isStopRow(nextRow); + final boolean stopRow = nextKv == null || isStopRow(nextKv.getBuffer(), nextKv.getRowOffset(), nextKv.getRowLength()); // now that we have an entire row, lets process with a filters: @@ -3588,7 +3597,7 @@ // the reasons for calling this method are: // 1. reset the filters. // 2. provide a hook to fast forward the row (used by subclasses) - nextRow(currentRow); + nextRow(currentRow, offset, length); // This row was totally filtered out, if this is NOT the last row, // we should continue on. @@ -3604,29 +3613,25 @@ return filter != null && filter.filterRow(); } - private boolean filterRowKey(byte[] row) { + private boolean filterRowKey(byte[] row, int offset, short length) { return filter != null - && filter.filterRowKey(row, 0, row.length); + && filter.filterRowKey(row, offset, length); } - protected void nextRow(byte [] currentRow) throws IOException { - while (Bytes.equals(currentRow, peekRow())) { - this.storeHeap.next(MOCKED_LIST); + protected void nextRow(byte [] currentRow, int offset, short length) throws IOException { + KeyValue next; + while((next = this.storeHeap.peek()) != null && next.matchingRow(currentRow, offset, length)) { + this.storeHeap.next(MOCKED_LIST); } results.clear(); resetFilters(); } - private byte[] peekRow() { - KeyValue kv = this.storeHeap.peek(); - return kv == null ? null : kv.getRow(); - } - - private boolean isStopRow(byte [] currentRow) { + private boolean isStopRow(byte [] currentRow, int offset, short length) { return currentRow == null || (stopRow != null && comparator.compareRows(stopRow, 0, stopRow.length, - currentRow, 0, currentRow.length) <= isScan); + currentRow, offset, length) <= isScan); } @Override Index: src/main/java/org/apache/hadoop/hbase/regionserver/ScanQueryMatcher.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/regionserver/ScanQueryMatcher.java (revision 1417249) +++ src/main/java/org/apache/hadoop/hbase/regionserver/ScanQueryMatcher.java (working copy) @@ -82,6 +82,8 @@ /* row is not private for tests */ /** Row the query is on */ byte [] row; + int rowOffset; + short rowLength; /** * Oldest put in any of the involved store files @@ -222,7 +224,7 @@ short rowLength = Bytes.toShort(bytes, offset, Bytes.SIZEOF_SHORT); offset += Bytes.SIZEOF_SHORT; - int ret = this.rowComparator.compareRows(row, 0, row.length, + int ret = this.rowComparator.compareRows(row, this.rowOffset, this.rowLength, bytes, offset, rowLength); if (ret <= -1) { return MatchCode.DONE; @@ -385,8 +387,10 @@ * Set current row * @param row */ - public void setRow(byte [] row) { + public void setRow(byte [] row, int offset, short length) { this.row = row; + this.rowOffset = offset; + this.rowLength = length; reset(); } Index: src/main/java/org/apache/hadoop/hbase/regionserver/StoreScanner.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/regionserver/StoreScanner.java (revision 1417249) +++ src/main/java/org/apache/hadoop/hbase/regionserver/StoreScanner.java (working copy) @@ -340,8 +340,11 @@ // only call setRow if the row changes; avoids confusing the query matcher // if scanning intra-row - if ((matcher.row == null) || !peeked.matchingRow(matcher.row)) { - matcher.setRow(peeked.getRow()); + byte[] row = peeked.getBuffer(); + int offset = peeked.getRowOffset(); + short length = peeked.getRowLength(); + if ((matcher.row == null) || !Bytes.equals(row, offset, length, matcher.row, matcher.rowOffset, matcher.rowLength)) { + matcher.setRow(row, offset, length); } KeyValue kv; @@ -521,9 +524,12 @@ if (kv == null) { kv = lastTopKey; } - if ((matcher.row == null) || !kv.matchingRow(matcher.row)) { + byte[] row = kv.getBuffer(); + int offset = kv.getRowOffset(); + short length = kv.getRowLength(); + if ((matcher.row == null) || !Bytes.equals(row, offset, length, matcher.row, matcher.rowOffset, matcher.rowLength)) { matcher.reset(); - matcher.setRow(kv.getRow()); + matcher.setRow(row, offset, length); } }