Index: /Users/irubin/Documents/workspace/hadoop-trunk/src/contrib/hbase/src/java/org/apache/hadoop/hbase/filter/StopRowFilter.java =================================================================== --- /Users/irubin/Documents/workspace/hadoop-trunk/src/contrib/hbase/src/java/org/apache/hadoop/hbase/filter/StopRowFilter.java (revision 0) +++ /Users/irubin/Documents/workspace/hadoop-trunk/src/contrib/hbase/src/java/org/apache/hadoop/hbase/filter/StopRowFilter.java (revision 0) @@ -0,0 +1,137 @@ +/** + * Copyright 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase.filter; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.util.TreeMap; + +import org.apache.hadoop.io.Text; + +/** + * Implementation of RowFilterInterface that never filters out a row until a + * row equals a specified stopRowKey. From that point on the filter will + * filter out every row (unless reset). + */ +public class StopRowFilter implements RowFilterInterface { + + private Text stopRowKey; + private boolean filterAllRemaining = false; + + /** + * Default constructor, filters nothing. Required though for RPC + * deserialization. + */ + public StopRowFilter() { + super(); + } + + /** + * Constructor that takes a stopRowKey on which to filter all remaining + * + * @param stopRowKey rowKey to filter on. + */ + public StopRowFilter(final Text stopRowKey) { + this.stopRowKey = stopRowKey; + } + + public Text getStopRowKey() { + return this.stopRowKey; + } + + /** + * + * {@inheritDoc} + */ + public void validate(@SuppressWarnings("unused") final Text[] columns) { + // Doesn't filter columns + } + + /** + * + * {@inheritDoc} + */ + public void reset() { + this.filterAllRemaining = false; + } + + /** + * + * {@inheritDoc} + */ + public void acceptedRow(@SuppressWarnings("unused") final Text key) { + // doesn't care + } + + /** + * + * {@inheritDoc} + */ + public boolean filterAllRemaining() { + return this.filterAllRemaining; + } + + /** + * + * {@inheritDoc} + */ + public boolean filter(final Text rowKey) { + changeFAR(this.stopRowKey.compareTo(rowKey) <= 0); + return filterAllRemaining(); + } + + /** + * Because StopRowFilter does not examine column information, this method + * defaults to calling the rowKey-only version of filter. + */ + public boolean filter(@SuppressWarnings("unused") final Text rowKey, + @SuppressWarnings("unused") final Text colKey, + @SuppressWarnings("unused") final byte[] data) { + return filter(rowKey); + } + + /** + * Because StopRowFilter does not examine column information, this method + * defaults to calling filterAllRemaining(). + * + * @param columns + */ + public boolean filterNotNull(@SuppressWarnings("unused") + final TreeMap columns) { + return filterAllRemaining(); + } + + /** + * + * {@inheritDoc} + */ + public void readFields(DataInput in) throws IOException { + stopRowKey = new Text(in.readLine()); + } + + /** + * + * {@inheritDoc} + */ + public void write(DataOutput out) throws IOException { + out.writeChars(stopRowKey.toString()); + } + + private void changeFAR(boolean value) { + this.filterAllRemaining = this.filterAllRemaining || value; + } +} Index: /Users/irubin/Documents/workspace/hadoop-trunk/src/contrib/hbase/src/java/org/apache/hadoop/hbase/filter/WhileMatchRowFilter.java =================================================================== --- /Users/irubin/Documents/workspace/hadoop-trunk/src/contrib/hbase/src/java/org/apache/hadoop/hbase/filter/WhileMatchRowFilter.java (revision 0) +++ /Users/irubin/Documents/workspace/hadoop-trunk/src/contrib/hbase/src/java/org/apache/hadoop/hbase/filter/WhileMatchRowFilter.java (revision 0) @@ -0,0 +1,118 @@ +/** + * Copyright 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase.filter; + +import java.util.Map; +import java.util.TreeMap; + +import org.apache.hadoop.io.Text; + +/** + * Implementation of RowFilterInterface that acts as RegExpRowFilter until a + * row fails to match the regex (until the row is filtered). Once this + * happens, filterAllRemaining() will return true and every subsequent row will + * be filtered regardless of regex matching. + */ +public class WhileMatchRowFilter extends RegExpRowFilter { + + private boolean filterAllRemaining = false; + + /** + * Default constructor, filters nothing. Required though for RPC + * deserialization. + */ + public WhileMatchRowFilter() { + super(); + } + + /** + * Constructor that takes a row key regular expression to filter on. + * + * @param rowKeyRegExp + */ + public WhileMatchRowFilter(final String rowKeyRegExp) { + super(rowKeyRegExp); + } + + /** + * Constructor that takes a row key regular expression and a map of columnKey- + * data pairs to filter on. + * + * @param rowKeyRegExp + * @param columnFilter + */ + public WhileMatchRowFilter(final String rowKeyRegExp, + final Map columnFilter) { + super(rowKeyRegExp, columnFilter); + } + + /** + * + * {@inheritDoc} + */ + public void reset() { + this.filterAllRemaining = false; + } + + /** + * Returns true once a rowKey has failed to match the regex in a call to + * filter. Until then it returns false. + * + * @return true/false whether the rowKey has thus far failed to match a regex. + */ + public boolean filterAllRemaining() { + return this.filterAllRemaining; + } + + /** + * + * {@inheritDoc} + */ + public boolean filter(final Text rowKey) { + // A precaution in case filterAllRemaining isn't called by the client + changeFAR(super.filter(rowKey)); + return filterAllRemaining(); + } + + /** + * + * {@inheritDoc} + */ + public boolean filter(final Text rowKey, final Text colKey, + final byte[] data) { + changeFAR(super.filter(rowKey, colKey, data)); + return filterAllRemaining(); + } + + /** + * + * {@inheritDoc} + */ + public boolean filterNotNull(final TreeMap columns) { + changeFAR(super.filterNotNull(columns)); + return filterAllRemaining(); + } + + /** + * Change filterAllRemaining from false to true if value is true, otherwise + * leave as is. + * + * @param value + */ + private void changeFAR(boolean value) { + this.filterAllRemaining = this.filterAllRemaining || value; + } +} Index: /Users/irubin/Documents/workspace/hadoop-trunk/src/contrib/hbase/src/test/org/apache/hadoop/hbase/filter/TestStopRowFilter.java =================================================================== --- /Users/irubin/Documents/workspace/hadoop-trunk/src/contrib/hbase/src/test/org/apache/hadoop/hbase/filter/TestStopRowFilter.java (revision 0) +++ /Users/irubin/Documents/workspace/hadoop-trunk/src/contrib/hbase/src/test/org/apache/hadoop/hbase/filter/TestStopRowFilter.java (revision 0) @@ -0,0 +1,49 @@ +/** + * Copyright 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase.filter; + +import org.apache.hadoop.io.Text; + +import junit.framework.TestCase; + +public class TestStopRowFilter extends TestCase { + private final Text STOP_ROW = new Text("stop_row"); + private final Text GOOD_ROW = new Text("good_row"); + private final Text PAST_STOP_ROW = new Text("zzzzzz"); + + public void testStopRowIdentification() throws Exception { + StopRowFilter filter = new StopRowFilter(STOP_ROW); + tryAllMethods(filter, false); + filter.filter(STOP_ROW); + tryAllMethods(filter, true); + filter.reset(); + tryAllMethods(filter, false); + filter.filter(PAST_STOP_ROW); + tryAllMethods(filter, true); + } + + private void tryAllMethods(RowFilterInterface filter, boolean assertTrue) + throws Exception { + assertFalse(invertIfTrue(assertTrue, filter.filterAllRemaining())); + assertFalse(invertIfTrue(assertTrue, filter.filter(GOOD_ROW))); + assertFalse(invertIfTrue(assertTrue, filter.filter(GOOD_ROW, null, null))); + assertFalse(invertIfTrue(assertTrue, filter.filterNotNull(null))); + } + + private boolean invertIfTrue(boolean invert, boolean data) { + return invert? !data : data; + } +} Index: /Users/irubin/Documents/workspace/hadoop-trunk/src/contrib/hbase/src/test/org/apache/hadoop/hbase/filter/TestWhileMatchRowFilter.java =================================================================== --- /Users/irubin/Documents/workspace/hadoop-trunk/src/contrib/hbase/src/test/org/apache/hadoop/hbase/filter/TestWhileMatchRowFilter.java (revision 0) +++ /Users/irubin/Documents/workspace/hadoop-trunk/src/contrib/hbase/src/test/org/apache/hadoop/hbase/filter/TestWhileMatchRowFilter.java (revision 0) @@ -0,0 +1,124 @@ +/** + * Copyright 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase.filter; + +import java.util.Map; + +import org.apache.hadoop.hbase.HConstants; +import org.apache.hadoop.io.Text; + +public class TestWhileMatchRowFilter extends TestRegExpRowFilter { + + @Override + protected void setUp() throws Exception { + super.setUp(); + this.filter = new WhileMatchRowFilter(HOST_PREFIX + ".*", colvalues); + } + + public void testRegexOnRow() throws Exception { + super.testRegexOnRow(); + assertTrue(filter.filterAllRemaining()); + assertTrue("Failed with character " + FIRST_CHAR, + filter.filter(createRow(FIRST_CHAR))); + } + + public void testRegexOnRowAndColumn() throws Exception { + for (char c = FIRST_CHAR; c <= LAST_CHAR; c++) { + Text t = createRow(c); + for (Map.Entry e: this.colvalues.entrySet()) { + assertFalse("Failed on " + c, + this.filter.filter(t, e.getKey(), e.getValue())); + } + } + // Try a row and column I know will pass. + char c = 'c'; + Text r = createRow(c); + Text col = new Text(Character.toString(c)); + assertFalse("Failed with character " + c, + filter.filter(r, col, GOOD_BYTES)); + assertFalse(filter.filterAllRemaining()); + + // Do same but with bad bytes. + assertTrue("Failed with character " + c, + filter.filter(r, col, "badbytes".getBytes())); + filterAllIsTrue(filter); + + // Do with good bytes but bad column name. Should not filter out. + assertFalse("Failed with character " + c, + filter.filter(r, new Text("badcolumn"), GOOD_BYTES)); + assertFalse(filter.filterAllRemaining()); + + // Good column, good bytes but bad row. + assertTrue("Failed with character " + c, + filter.filter(new Text("bad row"), new Text("badcolumn"), GOOD_BYTES)); + filterAllIsTrue(filter); + } + + public void testFilterNotNull() throws Exception { + // Modify the filter to expect certain columns to be null: + // Expecting a row WITH columnKeys: a-d, WITHOUT columnKey: e + ((WhileMatchRowFilter)filter).setColumnFilter(new Text(new String( + new char[] { LAST_CHAR })), null); + + char secondToLast = (char)(LAST_CHAR - 1); + char thirdToLast = (char)(LAST_CHAR - 2); + + // Modify the row to be missing an expected columnKey (d) + colvalues.remove(new Text(new String(new char[] { secondToLast }))); + + // Try a row that is missing an expected columnKey. + // Testing row with columnKeys: a-c + assertTrue("Failed with last columnKey " + thirdToLast, filter. + filterNotNull(colvalues)); + filterAllIsTrue(filter); + + // Try a row that has all expected columnKeys, and NO null-expected + // columnKeys. + // Testing row with columnKeys: a-d + colvalues.put(new Text(new String(new char[] { secondToLast })), + GOOD_BYTES); + assertFalse("Failed with last columnKey " + secondToLast, filter. + filterNotNull(colvalues)); + assertFalse(filter.filterAllRemaining()); + + // Try a row that has all expected columnKeys AND a null-expected columnKey. + // Testing row with columnKeys: a-e + colvalues.put(new Text(new String(new char[] { LAST_CHAR })), GOOD_BYTES); + assertTrue("Failed with last columnKey " + LAST_CHAR, filter. + filterNotNull(colvalues)); + filterAllIsTrue(filter); + + // Try a row that has all expected columnKeys and a null-expected columnKey + // that maps to a null value. + // Testing row with columnKeys: a-e, e maps to null + colvalues.put(new Text(new String(new char[] { LAST_CHAR })), + HConstants.DELETE_BYTES.get()); + assertFalse("Failed with last columnKey " + LAST_CHAR + " mapping to null.", + filter.filterNotNull(colvalues)); + assertFalse(filter.filterAllRemaining()); + } + + private Text createRow(final char c) { + return new Text(HOST_PREFIX + Character.toString(c)); + } + + private void filterAllIsTrue(RowFilterInterface filter) throws Exception { + // Make sure filterAllRemaining is true, then reset for further testing. + assertTrue("FilterAllRemaining should be true after failed test.", + filter.filterAllRemaining()); + filter.reset(); + } +}