Index: src/test/org/apache/hadoop/hbase/regionserver/TestExplicitColumnTracker.java =================================================================== --- src/test/org/apache/hadoop/hbase/regionserver/TestExplicitColumnTracker.java (revision 916035) +++ src/test/org/apache/hadoop/hbase/regionserver/TestExplicitColumnTracker.java (working copy) @@ -12,18 +12,19 @@ public class TestExplicitColumnTracker extends HBaseTestCase implements HConstants { - private boolean PRINT = false; + private boolean PRINT = false; + + private final byte [] col1 = Bytes.toBytes("col1"); + private final byte [] col2 = Bytes.toBytes("col2"); + private final byte [] col3 = Bytes.toBytes("col3"); + private final byte [] col4 = Bytes.toBytes("col4"); + private final byte [] col5 = Bytes.toBytes("col5"); public void testGet_SingleVersion(){ if(PRINT){ System.out.println("SingleVersion"); } - byte [] col1 = Bytes.toBytes("col1"); - byte [] col2 = Bytes.toBytes("col2"); - byte [] col3 = Bytes.toBytes("col3"); - byte [] col4 = Bytes.toBytes("col4"); - byte [] col5 = Bytes.toBytes("col5"); - + //Create tracker TreeSet columns = new TreeSet(Bytes.BYTES_COMPARATOR); //Looking for every other @@ -69,11 +70,6 @@ if(PRINT){ System.out.println("\nMultiVersion"); } - byte [] col1 = Bytes.toBytes("col1"); - byte [] col2 = Bytes.toBytes("col2"); - byte [] col3 = Bytes.toBytes("col3"); - byte [] col4 = Bytes.toBytes("col4"); - byte [] col5 = Bytes.toBytes("col5"); //Create tracker TreeSet columns = new TreeSet(Bytes.BYTES_COMPARATOR); @@ -140,5 +136,28 @@ } } } + + /** + * hbase-2259 + */ + public void testStackOverflow(){ + int maxVersions = 1; + TreeSet columns = new TreeSet(Bytes.BYTES_COMPARATOR); + for (int i = 0; i < 100000; i++) { + columns.add(Bytes.toBytes("col"+i)); + } + + ColumnTracker explicit = new ExplicitColumnTracker(columns, maxVersions); + for (int i = 0; i < 100000; i+=2) { + byte [] col = Bytes.toBytes("col"+i); + explicit.checkColumn(col, 0, col.length); + } + explicit.update(); + + for (int i = 1; i < 100000; i+=2) { + byte [] col = Bytes.toBytes("col"+i); + explicit.checkColumn(col, 0, col.length); + } + } } Index: src/java/org/apache/hadoop/hbase/regionserver/ExplicitColumnTracker.java =================================================================== --- src/java/org/apache/hadoop/hbase/regionserver/ExplicitColumnTracker.java (revision 916035) +++ src/java/org/apache/hadoop/hbase/regionserver/ExplicitColumnTracker.java (working copy) @@ -83,46 +83,50 @@ * @return MatchCode telling QueryMatcher what action to take */ public MatchCode checkColumn(byte [] bytes, int offset, int length) { - // No more columns left, we are done with this query - if(this.columns.size() == 0) { - return MatchCode.DONE; // done_row - } - - // No more columns to match against, done with storefile - if(this.column == null) { - return MatchCode.NEXT; // done_row - } - - // Compare specific column to current column - int ret = Bytes.compareTo(column.getBuffer(), column.getOffset(), - column.getLength(), bytes, offset, length); - - // Matches, decrement versions left and include - if(ret == 0) { - if(this.column.decrement() == 0) { - // Done with versions for this column - this.columns.remove(this.index); - if(this.columns.size() == this.index) { - // Will not hit any more columns in this storefile - this.column = null; - } else { - this.column = this.columns.get(this.index); - } + boolean recursive = false; + do { + // No more columns left, we are done with this query + if(this.columns.size() == 0) { + return MatchCode.DONE; // done_row } - return MatchCode.INCLUDE; - } - // Specified column is bigger than current column - // Move down current column and check again - if(ret <= -1) { - if(++this.index == this.columns.size()) { - // No more to match, do not include, done with storefile + // No more columns to match against, done with storefile + if(this.column == null) { return MatchCode.NEXT; // done_row } - this.column = this.columns.get(this.index); - return checkColumn(bytes, offset, length); - } + // Compare specific column to current column + int ret = Bytes.compareTo(column.getBuffer(), column.getOffset(), + column.getLength(), bytes, offset, length); + + // Matches, decrement versions left and include + if(ret == 0) { + if(this.column.decrement() == 0) { + // Done with versions for this column + this.columns.remove(this.index); + if(this.columns.size() == this.index) { + // Will not hit any more columns in this storefile + this.column = null; + } else { + this.column = this.columns.get(this.index); + } + } + return MatchCode.INCLUDE; + } + + // Specified column is bigger than current column + // Move down current column and check again + if(ret <= -1) { + if(++this.index == this.columns.size()) { + // No more to match, do not include, done with storefile + return MatchCode.NEXT; // done_row + } + this.column = this.columns.get(this.index); + recursive = true; + continue; + //return checkColumn(bytes, offset, length); + } + } while (recursive); // Specified column is smaller than current column // Skip return MatchCode.SKIP; // skip to next column, with hint?