Index: hbase-server/src/main/java/org/apache/hadoop/hbase/filter/Filter.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/filter/Filter.java (revision 1359642) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/filter/Filter.java (working copy) @@ -23,6 +23,7 @@ import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceStability; import org.apache.hadoop.hbase.KeyValue; +import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.io.Writable; import java.util.List; @@ -167,4 +168,12 @@ * not sure which key to seek to next. */ public KeyValue getNextKeyHint(final KeyValue currentKV); + + + /** + * To do the filtering sanity check before getScanner() + * @param scan + * + */ + public void sanityCheck(final Scan scan); } Index: hbase-server/src/main/java/org/apache/hadoop/hbase/filter/FilterBase.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/filter/FilterBase.java (revision 1359642) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/filter/FilterBase.java (working copy) @@ -22,6 +22,7 @@ import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceStability; import org.apache.hadoop.hbase.KeyValue; +import org.apache.hadoop.hbase.client.Scan; import java.util.List; import java.util.ArrayList; @@ -133,6 +134,14 @@ public KeyValue getNextKeyHint(KeyValue currentKV) { return null; } + + + /** + * The criteria defined in the filter is correct. + */ + @Override + public void sanityCheck(final Scan scan){ + } /** * Given the filter's arguments it constructs the filter Index: hbase-server/src/main/java/org/apache/hadoop/hbase/filter/FilterList.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/filter/FilterList.java (revision 1359642) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/filter/FilterList.java (working copy) @@ -24,6 +24,7 @@ import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.KeyValue; +import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.io.HbaseObjectWritable; import org.apache.hadoop.io.Writable; @@ -324,8 +325,16 @@ } return keyHint; } + @Override + public void sanityCheck(final Scan scan) { + for (Filter filter : filters) { + filter.sanityCheck(scan); + } + } + + @Override public String toString() { return toString(MAX_LOG_FILTERS); } Index: hbase-server/src/main/java/org/apache/hadoop/hbase/filter/SingleColumnValueFilter.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/filter/SingleColumnValueFilter.java (revision 1359642) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/filter/SingleColumnValueFilter.java (working copy) @@ -33,9 +33,11 @@ import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; -import java.util.Arrays; +import java.util.Iterator; import java.util.List; import java.util.ArrayList; +import java.util.Map; +import java.util.NavigableSet; import com.google.common.base.Preconditions; @@ -79,6 +81,8 @@ private boolean matchedColumn = false; private boolean filterIfMissing = false; private boolean latestVersionOnly = true; + + private boolean toRemoveCriteriaColumn = false; /** * Writable constructor, do not use. @@ -297,6 +301,7 @@ this.matchedColumn = in.readBoolean(); this.filterIfMissing = in.readBoolean(); this.latestVersionOnly = in.readBoolean(); + this.toRemoveCriteriaColumn = in.readBoolean(); } public void write(final DataOutput out) throws IOException { @@ -309,7 +314,60 @@ out.writeBoolean(matchedColumn); out.writeBoolean(filterIfMissing); out.writeBoolean(latestVersionOnly); + out.writeBoolean(toRemoveCriteriaColumn); } + + + /** + * If the tested columns don't include criteria column, + * add the criteria column into the scan and + * mark toRemoveCriteriaColumn as true + */ + @Override + public void sanityCheck(final Scan scan){ + checkUnspecifiedQualifier(scan); + if( this.toRemoveCriteriaColumn ) { + // The following line will add one column if it is missing in the tested set + LOG.warn("Missing filtered Qualifier : " + new String(this.columnFamily) + ":" + + new String(this.columnQualifier) + " in the criteria."); + scan.addColumn(this.columnFamily, this.columnQualifier); + } + return ; + } + + @Override + public void filterRow(List ignored) { + Iterator it = ignored.iterator(); + while(it.hasNext()){ + KeyValue kv = it.next(); + if(this.toRemoveCriteriaColumn && + kv.matchingColumn(this.columnFamily, this.columnQualifier)) { + LOG.debug("REMOVE KEY=" + kv.toString() + ", value=" + Bytes.toString(kv.getValue())); + it.remove(); + } + } + } + + @Override + public boolean hasFilterRow() { + return this.foundColumn && this.toRemoveCriteriaColumn; + } + + private void checkUnspecifiedQualifier(final Scan scan){ + Map> cols = scan.getFamilyMap(); + for( byte[] columnfamily : cols.keySet() ) { + if( (cols.get(columnfamily) != null && cols.get(columnfamily).size() != 0 ) + && Bytes.equals(this.columnFamily, columnfamily) ){ + this.toRemoveCriteriaColumn = true; + Iterator it = cols.get(columnfamily).iterator(); + while(it.hasNext()){ + if(Bytes.equals(this.columnQualifier, it.next())){ + this.toRemoveCriteriaColumn = false; + } + } + } + } + } @Override public String toString() { Index: hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java (revision 1359642) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java (working copy) @@ -3416,6 +3416,9 @@ this.maxResultSize = scan.getMaxResultSize(); this.filter = scan.getFilter(); this.batch = scan.getBatch(); + + if(this.filter!=null) filter.sanityCheck(scan); + if (Bytes.equals(scan.getStopRow(), HConstants.EMPTY_END_ROW)) { this.stopRow = null; } else {