/** * Advanced use only. Add an existing delete marker to this Delete object. * * @param kv An existing KeyValue of type "delete". * @return this for invocation chaining * @throws IOException */ @SuppressWarnings("unchecked") public Delete addDeleteMarker(Cell kv) throws IOException { // TODO: Deprecate and rename 'add' so it matches how we add KVs to Puts. if (!CellUtil.isDelete(kv)) { throw new IOException( "The recently added KeyValue is not of type " + "delete. Rowkey: " + Bytes.toStringBinary(this.row)); } if (Bytes.compareTo( this.row, 0, row.length, kv.getRowArray(), kv.getRowOffset(), kv.getRowLength()) != 0) { throw new WrongRowIOException( "The row in " + kv.toString() + " doesn't match the original one " + Bytes.toStringBinary(this.row)); } byte[] family = CellUtil.cloneFamily(kv); List<Cell> list = familyMap.get(family); if (list == null) { list = new ArrayList<Cell>(); } list.add(kv); familyMap.put(family, list); return this; }
/** * This utility method creates a list of Thrift TRowResult "struct" based on an Hbase RowResult * object. The empty list is returned if the input is null. * * @param in Hbase RowResult object * @param sortColumns This boolean dictates if row data is returned in a sorted order sortColumns * = True will set TRowResult's sortedColumns member which is an ArrayList of TColumn struct * sortColumns = False will set TRowResult's columns member which is a map of columnName and * TCell struct * @return Thrift TRowResult array */ public static List<TRowResult> rowResultFromHBase(Result[] in, boolean sortColumns) { List<TRowResult> results = new ArrayList<TRowResult>(); for (Result result_ : in) { if (result_ == null || result_.isEmpty()) { continue; } TRowResult result = new TRowResult(); result.row = ByteBuffer.wrap(result_.getRow()); if (sortColumns) { result.sortedColumns = new ArrayList<TColumn>(); for (Cell kv : result_.rawCells()) { result.sortedColumns.add( new TColumn( ByteBuffer.wrap( KeyValue.makeColumn(CellUtil.cloneFamily(kv), CellUtil.cloneQualifier(kv))), new TCell(ByteBuffer.wrap(CellUtil.cloneValue(kv)), kv.getTimestamp()))); } } else { result.columns = new TreeMap<ByteBuffer, TCell>(); for (Cell kv : result_.rawCells()) { result.columns.put( ByteBuffer.wrap( KeyValue.makeColumn(CellUtil.cloneFamily(kv), CellUtil.cloneQualifier(kv))), new TCell(ByteBuffer.wrap(CellUtil.cloneValue(kv)), kv.getTimestamp())); } } results.add(result); } return results; }
@Override public ReturnCode filterKeyValue(Cell kv) { if (sortedPrefixes.size() == 0 || kv.getQualifierArray() == null) { return ReturnCode.INCLUDE; } else { return filterColumn(kv.getQualifierArray(), kv.getQualifierOffset(), kv.getQualifierLength()); } }
@Override public void process(long now, HRegion region, List<Mutation> mutations, WALEdit walEdit) throws IOException { // Override the time to avoid race-condition in the unit test caused by // inacurate timer on some machines now = myTimer.getAndIncrement(); // Scan both rows List<Cell> kvs1 = new ArrayList<Cell>(); List<Cell> kvs2 = new ArrayList<Cell>(); doScan(region, new Scan(row1, row1), kvs1); doScan(region, new Scan(row2, row2), kvs2); // Assert swapped if (swapped) { assertEquals(rowSize, kvs2.size()); assertEquals(row2Size, kvs1.size()); } else { assertEquals(rowSize, kvs1.size()); assertEquals(row2Size, kvs2.size()); } swapped = !swapped; // Add and delete keyvalues List<List<Cell>> kvs = new ArrayList<List<Cell>>(); kvs.add(kvs1); kvs.add(kvs2); byte[][] rows = new byte[][] {row1, row2}; for (int i = 0; i < kvs.size(); ++i) { for (Cell kv : kvs.get(i)) { // Delete from the current row and add to the other row Delete d = new Delete(rows[i]); KeyValue kvDelete = new KeyValue( rows[i], CellUtil.cloneFamily(kv), CellUtil.cloneQualifier(kv), kv.getTimestamp(), KeyValue.Type.Delete); d.addDeleteMarker(kvDelete); Put p = new Put(rows[1 - i]); KeyValue kvAdd = new KeyValue( rows[1 - i], CellUtil.cloneFamily(kv), CellUtil.cloneQualifier(kv), now, CellUtil.cloneValue(kv)); p.add(kvAdd); mutations.add(d); walEdit.add(kvDelete); mutations.add(p); walEdit.add(kvAdd); } } }
public ProjectedValueTuple projectResults(Tuple tuple) { byte[] bytesValue = schema.toBytes(tuple, expressions, valueSet, ptr); Cell base = tuple.getValue(0); return new ProjectedValueTuple( base.getRowArray(), base.getRowOffset(), base.getRowLength(), base.getTimestamp(), bytesValue, valueSet.getEstimatedLength()); }
@Test(timeOut = 10_000) public void testShadowCellSuffixConcatenationToQualifier() { Cell cell = new KeyValue(row, family, qualifier, 1, Bytes.toBytes("value")); byte[] suffixedQualifier = CellUtils.addShadowCellSuffix( cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength()); byte[] expectedQualifier = com.google.common.primitives.Bytes.concat(qualifier, SHADOW_CELL_SUFFIX); assertEquals(suffixedQualifier, expectedQualifier); }
@GET @Produces({MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF, MIMETYPE_PROTOBUF_IETF}) public Response get(final @Context UriInfo uriInfo) { MultivaluedMap<String, String> params = uriInfo.getQueryParameters(); servlet.getMetrics().incrementRequests(1); try { CellSetModel model = new CellSetModel(); for (String rk : params.get(ROW_KEYS_PARAM_NAME)) { RowSpec rowSpec = new RowSpec(rk); if (this.versions != null) { rowSpec.setMaxVersions(this.versions); } ResultGenerator generator = ResultGenerator.fromRowSpec( this.tableResource.getName(), rowSpec, null, !params.containsKey(NOCACHE_PARAM_NAME)); Cell value = null; RowModel rowModel = new RowModel(rk); if (generator.hasNext()) { while ((value = generator.next()) != null) { rowModel.addCell( new CellModel( CellUtil.cloneFamily(value), CellUtil.cloneQualifier(value), value.getTimestamp(), CellUtil.cloneValue(value))); } model.addRow(rowModel); } else { LOG.trace("The row : " + rk + " not found in the table."); } } if (model.getRows().size() == 0) { // If no rows found. servlet.getMetrics().incrementFailedGetRequests(1); return Response.status(Response.Status.NOT_FOUND) .type(MIMETYPE_TEXT) .entity("No rows found." + CRLF) .build(); } else { servlet.getMetrics().incrementSucessfulGetRequests(1); return Response.ok(model).build(); } } catch (Exception e) { servlet.getMetrics().incrementFailedGetRequests(1); return processException(e); } }
@Override public void postGetOp( ObserverContext<RegionCoprocessorEnvironment> e, Get get, List<Cell> results) throws IOException { if (results.size() > 0) { // Check tag presence in the 1st cell in 1st Result if (!results.isEmpty()) { Cell cell = results.get(0); tags = Tag.asList(cell.getTagsArray(), cell.getTagsOffset(), cell.getTagsLength()); } } }
/* * Private method to determine if this object's familyMap contains * the given value assigned to the given family, qualifier and timestamp * respecting the 2 boolean arguments * * @param family * @param qualifier * @param ts * @param value * @param ignoreTS * @param ignoreValue * @return returns true if the given family, qualifier timestamp and value * already has an existing KeyValue object in the family map. */ private boolean has( byte[] family, byte[] qualifier, long ts, byte[] value, boolean ignoreTS, boolean ignoreValue) { List<Cell> list = getCellList(family); if (list.size() == 0) { return false; } // Boolean analysis of ignoreTS/ignoreValue. // T T => 2 // T F => 3 (first is always true) // F T => 2 // F F => 1 if (!ignoreTS && !ignoreValue) { for (Cell cell : list) { if (CellUtil.matchingFamily(cell, family) && CellUtil.matchingQualifier(cell, qualifier) && CellUtil.matchingValue(cell, value) && cell.getTimestamp() == ts) { return true; } } } else if (ignoreValue && !ignoreTS) { for (Cell cell : list) { if (CellUtil.matchingFamily(cell, family) && CellUtil.matchingQualifier(cell, qualifier) && cell.getTimestamp() == ts) { return true; } } } else if (!ignoreValue && ignoreTS) { for (Cell cell : list) { if (CellUtil.matchingFamily(cell, family) && CellUtil.matchingQualifier(cell, qualifier) && CellUtil.matchingValue(cell, value)) { return true; } } } else { for (Cell cell : list) { if (CellUtil.matchingFamily(cell, family) && CellUtil.matchingQualifier(cell, qualifier)) { return true; } } } return false; }
@Test(dataProvider = "shadow-cell-suffixes", timeOut = 10_000) public void testShadowCellSuffixRemovalFromQualifier(byte[] shadowCellSuffixToTest) throws IOException { // Test removal from a correclty suffixed qualifier byte[] suffixedQualifier = com.google.common.primitives.Bytes.concat(qualifier, shadowCellSuffixToTest); Cell cell = new KeyValue(row, family, suffixedQualifier, 1, Bytes.toBytes("value")); byte[] resultedQualifier = CellUtils.removeShadowCellSuffix( cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength()); byte[] expectedQualifier = qualifier; assertEquals(resultedQualifier, expectedQualifier); // Test removal from a badly suffixed qualifier byte[] badlySuffixedQualifier = com.google.common.primitives.Bytes.concat(qualifier, Bytes.toBytes("BAD")); Cell badCell = new KeyValue(row, family, badlySuffixedQualifier, 1, Bytes.toBytes("value")); try { CellUtils.removeShadowCellSuffix( badCell.getQualifierArray(), badCell.getQualifierOffset(), badCell.getQualifierLength()); fail(); } catch (IllegalArgumentException e) { // Expected } }
/** * This utility method creates a list of Thrift TCell "struct" based on an Hbase Cell object. The * empty list is returned if the input is null. * * @param in Hbase Cell object * @return Thrift TCell array */ public static List<TCell> cellFromHBase(Cell in) { List<TCell> list = new ArrayList<TCell>(1); if (in != null) { list.add(new TCell(ByteBuffer.wrap(CellUtil.cloneValue(in)), in.getTimestamp())); } return list; }
/** * @param row 为主键,不能通过toString直接转换 * @param value 取出后得到jack/course:english/1436449989754/Put/vlen=2/seqid=0,不能单独取出 * @param context */ @Override public void map(ImmutableBytesWritable row, Result value, Context context) throws UnsupportedEncodingException { context.getCounter(Counters.ROWS).increment(1); System.out.println(context.getCounter(Counters.ROWS).getValue()); String s = new String(row.copyBytes(), "GB2312"); System.out.println(s); List<Cell> valuelist = value.getColumnCells("course".getBytes(), "english".getBytes()); // 得到结果为 valuelist[0] = "jack/course:english/1436449989754/Put/vlen=2/seqid=0" for (Cell cell : valuelist) { System.out.println(cell.toString()); } // System.out.println(value.getColumnCells("course".getBytes(),"english".getBytes())+"\n"); }
/** * Add the specified KeyValue to this Put operation. Operation assumes that the passed KeyValue is * immutable and its backing array will not be modified for the duration of this Put. * * @param kv individual KeyValue * @return this * @throws java.io.IOException e */ public Put add(Cell kv) throws IOException { byte[] family = CellUtil.cloneFamily(kv); List<Cell> list = getCellList(family); // Checking that the row of the kv is the same as the put int res = Bytes.compareTo( this.row, 0, row.length, kv.getRowArray(), kv.getRowOffset(), kv.getRowLength()); if (res != 0) { throw new WrongRowIOException( "The row in " + kv.toString() + " doesn't match the original one " + Bytes.toStringBinary(this.row)); } list.add(kv); familyMap.put(family, list); return this; }
protected final void trackDelete(Cell cell) { // If keepDeletedCells is true, then we only remove cells by versions or TTL during // compaction, so we do not need to track delete here. // If keepDeletedCells is TTL and the delete marker is expired, then we can make sure that the // minVerions is larger than 0(otherwise we will just return at preCheck). So here we still // need to track the delete marker to see if it masks some cells. if (keepDeletedCells == KeepDeletedCells.FALSE || (keepDeletedCells == KeepDeletedCells.TTL && cell.getTimestamp() < oldestUnexpiredTS)) { deletes.add(cell); } }
public static void main(String[] args) throws IOException { Configuration conf = HBaseConfiguration.create(); HBaseHelper helper = HBaseHelper.getHelper(conf); helper.dropTable("testtable"); helper.createTable("testtable", "colfam1", "colfam2"); System.out.println("Adding rows to table..."); helper.fillTable("testtable", 1, 10, 10, "colfam1", "colfam2"); Connection connection = ConnectionFactory.createConnection(conf); Table table = connection.getTable(TableName.valueOf("testtable")); // vv SingleColumnValueFilterExample SingleColumnValueFilter filter = new SingleColumnValueFilter( Bytes.toBytes("colfam1"), Bytes.toBytes("col-5"), CompareFilter.CompareOp.NOT_EQUAL, new SubstringComparator("val-5")); filter.setFilterIfMissing(true); Scan scan = new Scan(); scan.setFilter(filter); ResultScanner scanner = table.getScanner(scan); // ^^ SingleColumnValueFilterExample System.out.println("Results of scan:"); // vv SingleColumnValueFilterExample for (Result result : scanner) { for (Cell cell : result.rawCells()) { System.out.println( "Cell: " + cell + ", Value: " + Bytes.toString( cell.getValueArray(), cell.getValueOffset(), cell.getValueLength())); } } scanner.close(); Get get = new Get(Bytes.toBytes("row-6")); get.setFilter(filter); Result result = table.get(get); System.out.println("Result of get: "); for (Cell cell : result.rawCells()) { System.out.println( "Cell: " + cell + ", Value: " + Bytes.toString(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength())); } // ^^ SingleColumnValueFilterExample }
/** * @param cell * @param out * @param encodingCtx * @return unencoded size added * @throws IOException */ protected final int afterEncodingKeyValue( Cell cell, DataOutputStream out, HFileBlockDefaultEncodingContext encodingCtx) throws IOException { int size = 0; if (encodingCtx.getHFileContext().isIncludesTags()) { int tagsLength = cell.getTagsLength(); ByteBufferUtils.putCompressedInt(out, tagsLength); // There are some tags to be written if (tagsLength > 0) { TagCompressionContext tagCompressionContext = encodingCtx.getTagCompressionContext(); // When tag compression is enabled, tagCompressionContext will have a not null value. Write // the tags using Dictionary compression in such a case if (tagCompressionContext != null) { tagCompressionContext.compressTags( out, cell.getTagsArray(), cell.getTagsOffset(), tagsLength); } else { out.write(cell.getTagsArray(), cell.getTagsOffset(), tagsLength); } } size += tagsLength + KeyValue.TAGS_LENGTH_SIZE; } if (encodingCtx.getHFileContext().isIncludesMvcc()) { // Copy memstore timestamp from the byte buffer to the output stream. long memstoreTS = cell.getSequenceId(); WritableUtils.writeVLong(out, memstoreTS); // TODO use a writeVLong which returns the #bytes written so that 2 time parsing can be // avoided. size += WritableUtils.getVIntSize(memstoreTS); } return size; }
@Override protected boolean nextRow(ScannerContext scannerContext, Cell curRowCell) throws IOException { assert super.joinedContinuationRow == null : "Trying to go to next row during joinedHeap read."; byte[] row = new byte[curRowCell.getRowLength()]; CellUtil.copyRowTo(curRowCell, row, 0); this.storeHeap.seekToPreviousRow(KeyValueUtil.createFirstOnRow(row)); resetFilters(); // Calling the hook in CP which allows it to do a fast forward if (this.region.getCoprocessorHost() != null) { return this.region.getCoprocessorHost().postScannerFilterRow(this, curRowCell); } return true; }
@SuppressWarnings("rawtypes") ObserverAggregationCache buildAggrCache( final RegionScanner innerScanner, CoprocessorRowType type, CoprocessorProjector projector, ObserverAggregators aggregators, CoprocessorFilter filter, Stats stats) throws IOException { ObserverAggregationCache aggCache = new ObserverAggregationCache(aggregators); ObserverTuple tuple = new ObserverTuple(type); boolean hasMore = true; List<Cell> results = new ArrayList<Cell>(); while (hasMore) { results.clear(); hasMore = innerScanner.nextRaw(results); if (results.isEmpty()) continue; if (stats != null) stats.countInputRow(results); Cell cell = results.get(0); tuple.setUnderlying(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength()); if (behavior.ordinal() >= ObserverBehavior.SCAN_FILTER.ordinal()) { if (filter != null && filter.evaluate(tuple) == false) continue; if (behavior.ordinal() >= ObserverBehavior.SCAN_FILTER_AGGR.ordinal()) { AggrKey aggKey = projector.getAggrKey(results); MeasureAggregator[] bufs = aggCache.getBuffer(aggKey); aggregators.aggregate(bufs, results); aggCache.checkMemoryUsage(); } } } return aggCache; }
private static int findCommonPrefixInRowPart(Cell left, Cell right, int rowCommonPrefix) { return Bytes.findCommonPrefix( left.getRowArray(), right.getRowArray(), left.getRowLength() - rowCommonPrefix, right.getRowLength() - rowCommonPrefix, left.getRowOffset() + rowCommonPrefix, right.getRowOffset() + rowCommonPrefix); }
// Having this as static is fine but if META is having DBE then we should // change this. public static int compareCommonRowPrefix(Cell left, Cell right, int rowCommonPrefix) { return Bytes.compareTo( left.getRowArray(), left.getRowOffset() + rowCommonPrefix, left.getRowLength() - rowCommonPrefix, right.getRowArray(), right.getRowOffset() + rowCommonPrefix, right.getRowLength() - rowCommonPrefix); }
public static int compareCommonQualifierPrefix(Cell left, Cell right, int qualCommonPrefix) { return Bytes.compareTo( left.getQualifierArray(), left.getQualifierOffset() + qualCommonPrefix, left.getQualifierLength() - qualCommonPrefix, right.getQualifierArray(), right.getQualifierOffset() + qualCommonPrefix, right.getQualifierLength() - qualCommonPrefix); }
private static int findCommonPrefixInFamilyPart(Cell left, Cell right, int familyCommonPrefix) { return Bytes.findCommonPrefix( left.getFamilyArray(), right.getFamilyArray(), left.getFamilyLength() - familyCommonPrefix, right.getFamilyLength() - familyCommonPrefix, left.getFamilyOffset() + familyCommonPrefix, right.getFamilyOffset() + familyCommonPrefix); }
public static int compareCommonFamilyPrefix(Cell left, Cell right, int familyCommonPrefix) { return Bytes.compareTo( left.getFamilyArray(), left.getFamilyOffset() + familyCommonPrefix, left.getFamilyLength() - familyCommonPrefix, right.getFamilyArray(), right.getFamilyOffset() + familyCommonPrefix, right.getFamilyLength() - familyCommonPrefix); }
@Override public ReturnCode filterKeyValue(Cell kv) { // TODO have a column compare method in Cell byte[] buffer = kv.getQualifierArray(); int qualifierOffset = kv.getQualifierOffset(); int qualifierLength = kv.getQualifierLength(); int cmpMin = 1; if (this.minColumn != null) { cmpMin = Bytes.compareTo( buffer, qualifierOffset, qualifierLength, this.minColumn, 0, this.minColumn.length); } if (cmpMin < 0) { return ReturnCode.SEEK_NEXT_USING_HINT; } if (!this.minColumnInclusive && cmpMin == 0) { return ReturnCode.SKIP; } if (this.maxColumn == null) { return ReturnCode.INCLUDE; } int cmpMax = Bytes.compareTo( buffer, qualifierOffset, qualifierLength, this.maxColumn, 0, this.maxColumn.length); if (this.maxColumnInclusive && cmpMax <= 0 || !this.maxColumnInclusive && cmpMax < 0) { return ReturnCode.INCLUDE; } return ReturnCode.NEXT_ROW; }
private static int findCommonPrefixInQualifierPart( Cell left, Cell right, int qualifierCommonPrefix) { return Bytes.findCommonPrefix( left.getQualifierArray(), right.getQualifierArray(), left.getQualifierLength() - qualifierCommonPrefix, right.getQualifierLength() - qualifierCommonPrefix, left.getQualifierOffset() + qualifierCommonPrefix, right.getQualifierOffset() + qualifierCommonPrefix); }
/** * Find the column index which will replace the column name in the aggregated array and will be * restored in Reducer * * @param cell KeyValue for the column * @return column index for the specified cell or -1 if was not found */ private int findIndex(Cell cell) throws IOException { byte[] familyName = Bytes.copy(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength()); byte[] name = Bytes.copy(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength()); byte[] cfn = Bytes.add(familyName, QueryConstants.NAMESPACE_SEPARATOR_BYTES, name); if (columnIndexes.containsKey(cfn)) { return columnIndexes.get(cfn); } return -1; }
private int compareTypeBytes(Cell key, Cell right) { if (key.getFamilyLength() + key.getQualifierLength() == 0 && key.getTypeByte() == Type.Minimum.getCode()) { // left is "bigger", i.e. it appears later in the sorted order return 1; } if (right.getFamilyLength() + right.getQualifierLength() == 0 && right.getTypeByte() == Type.Minimum.getCode()) { return -1; } return 0; }
@Override public Cell getNextCellHint(Cell kv) { return KeyValueUtil.createFirstOnRow( kv.getRowArray(), kv.getRowOffset(), kv.getRowLength(), kv.getFamilyArray(), kv.getFamilyOffset(), kv.getFamilyLength(), hint, 0, hint.length); }
@Override public Cell getNextCellHint(Cell kv) { return KeyValue.createFirstOnRow( kv.getRowArray(), kv.getRowOffset(), kv.getRowLength(), kv.getFamilyArray(), kv.getFamilyOffset(), kv.getFamilyLength(), this.minColumn, 0, len(this.minColumn)); }
@Override public int seekToKeyInBlock(Cell seekCell, boolean seekBefore) { int rowCommonPrefix = 0; int familyCommonPrefix = 0; int qualCommonPrefix = 0; previous.invalidate(); do { int comp; keyOnlyKV.setKey(current.keyBuffer, 0, current.keyLength); if (current.lastCommonPrefix != 0) { // The KV format has row key length also in the byte array. The // common prefix // includes it. So we need to subtract to find out the common prefix // in the // row part alone rowCommonPrefix = Math.min(rowCommonPrefix, current.lastCommonPrefix - 2); } if (current.lastCommonPrefix <= 2) { rowCommonPrefix = 0; } rowCommonPrefix += findCommonPrefixInRowPart(seekCell, keyOnlyKV, rowCommonPrefix); comp = compareCommonRowPrefix(seekCell, keyOnlyKV, rowCommonPrefix); if (comp == 0) { comp = compareTypeBytes(seekCell, keyOnlyKV); if (comp == 0) { // Subtract the fixed row key length and the family key fixed length familyCommonPrefix = Math.max( 0, Math.min( familyCommonPrefix, current.lastCommonPrefix - (3 + keyOnlyKV.getRowLength()))); familyCommonPrefix += findCommonPrefixInFamilyPart(seekCell, keyOnlyKV, familyCommonPrefix); comp = compareCommonFamilyPrefix(seekCell, keyOnlyKV, familyCommonPrefix); if (comp == 0) { // subtract the rowkey fixed length and the family key fixed // length qualCommonPrefix = Math.max( 0, Math.min( qualCommonPrefix, current.lastCommonPrefix - (3 + keyOnlyKV.getRowLength() + keyOnlyKV.getFamilyLength()))); qualCommonPrefix += findCommonPrefixInQualifierPart(seekCell, keyOnlyKV, qualCommonPrefix); comp = compareCommonQualifierPrefix(seekCell, keyOnlyKV, qualCommonPrefix); if (comp == 0) { comp = CellComparator.compareTimestamps(seekCell, keyOnlyKV); if (comp == 0) { // Compare types. Let the delete types sort ahead of puts; // i.e. types // of higher numbers sort before those of lesser numbers. // Maximum // (255) // appears ahead of everything, and minimum (0) appears // after // everything. comp = (0xff & keyOnlyKV.getTypeByte()) - (0xff & seekCell.getTypeByte()); } } } } } if (comp == 0) { // exact match if (seekBefore) { if (!previous.isValid()) { // The caller (seekBefore) has to ensure that we are not at the // first key in the block. throw new IllegalStateException( "Cannot seekBefore if " + "positioned at the first key in the block: key=" + Bytes.toStringBinary(seekCell.getRowArray())); } moveToPrevious(); return 1; } return 0; } if (comp < 0) { // already too large, check previous if (previous.isValid()) { moveToPrevious(); } else { return HConstants.INDEX_KEY_MAGIC; // using optimized index key } return 1; } // move to next, if more data is available if (currentBuffer.hasRemaining()) { previous.copyFromNext(current); decodeNext(); current.setKey(current.keyBuffer, current.memstoreTS); } else { break; } } while (true); // we hit the end of the block, not an exact match return 1; }