You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by la...@apache.org on 2013/09/10 06:58:57 UTC

svn commit: r1521356 - in /hbase/branches/0.94/src: main/java/org/apache/hadoop/hbase/regionserver/ test/java/org/apache/hadoop/hbase/filter/ test/java/org/apache/hadoop/hbase/regionserver/

Author: larsh
Date: Tue Sep 10 04:58:57 2013
New Revision: 1521356

URL: http://svn.apache.org/r1521356
Log:
HBASE-8930 REAPPLY with testfix

Added:
    hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/filter/TestInvocationRecordFilter.java
Modified:
    hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/ColumnTracker.java
    hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/ExplicitColumnTracker.java
    hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/ScanQueryMatcher.java
    hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/ScanWildcardColumnTracker.java
    hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/regionserver/TestExplicitColumnTracker.java
    hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/regionserver/TestScanWildcardColumnTracker.java

Modified: hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/ColumnTracker.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/ColumnTracker.java?rev=1521356&r1=1521355&r2=1521356&view=diff
==============================================================================
--- hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/ColumnTracker.java (original)
+++ hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/ColumnTracker.java Tue Sep 10 04:58:57 2013
@@ -47,25 +47,46 @@ import org.apache.hadoop.hbase.regionser
  * This class is NOT thread-safe as queries are never multi-threaded
  */
 public interface ColumnTracker {
+
   /**
-   * Keeps track of the number of versions for the columns asked for
+   * Checks if the column is present in the list of requested columns by returning the match code
+   * instance. It does not check against the number of versions for the columns asked for. To do the
+   * version check, one has to call {@link #checkVersions(byte[], int, int, long, byte, boolean)}
+   * method based on the return type (INCLUDE) of this method. The values that can be returned by
+   * this method are {@link MatchCode#INCLUDE}, {@link MatchCode#SEEK_NEXT_COL} and
+   * {@link MatchCode#SEEK_NEXT_ROW}.
    * @param bytes
    * @param offset
    * @param length
-   * @param ttl The timeToLive to enforce.
    * @param type The type of the KeyValue
-   * @param ignoreCount indicates if the KV needs to be excluded while counting
-   *   (used during compactions. We only count KV's that are older than all the
-   *   scanners' read points.)
    * @return The match code instance.
-   * @throws IOException in case there is an internal consistency problem
-   *      caused by a data corruption.
+   * @throws IOException in case there is an internal consistency problem caused by a data
+   *           corruption.
    */
-  public ScanQueryMatcher.MatchCode checkColumn(byte[] bytes, int offset,
-      int length, long ttl, byte type, boolean ignoreCount)
+  ScanQueryMatcher.MatchCode checkColumn(byte[] bytes, int offset, int length, byte type)
       throws IOException;
 
   /**
+   * Keeps track of the number of versions for the columns asked for. It assumes that the user has
+   * already checked if the keyvalue needs to be included by calling the
+   * {@link #checkColumn(byte[], int, int, byte)} method. The enum values returned by this method
+   * are {@link MatchCode#SKIP}, {@link MatchCode#INCLUDE},
+   * {@link MatchCode#INCLUDE_AND_SEEK_NEXT_COL} and {@link MatchCode#INCLUDE_AND_SEEK_NEXT_ROW}.
+   * Implementations which include all the columns could just return {@link MatchCode#INCLUDE} in
+   * the {@link #checkColumn(byte[], int, int, byte)} method and perform all the operations in this
+   * checkVersions method.
+   * @param type the type of the key value (Put/Delete)
+   * @param ttl The timeToLive to enforce.
+   * @param ignoreCount indicates if the KV needs to be excluded while counting (used during
+   *          compactions. We only count KV's that are older than all the scanners' read points.)
+   * @return the scan query matcher match code instance
+   * @throws IOException in case there is an internal consistency problem caused by a data
+   *           corruption.
+   */
+  ScanQueryMatcher.MatchCode checkVersions(byte[] bytes, int offset, int length, long ttl,
+      byte type, boolean ignoreCount) throws IOException;
+
+  /**
    * Resets the Matcher
    */
   public void reset();

Modified: hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/ExplicitColumnTracker.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/ExplicitColumnTracker.java?rev=1521356&r1=1521355&r2=1521356&view=diff
==============================================================================
--- hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/ExplicitColumnTracker.java (original)
+++ hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/ExplicitColumnTracker.java Tue Sep 10 04:58:57 2013
@@ -106,7 +106,7 @@ public class ExplicitColumnTracker imple
    */
   @Override
   public ScanQueryMatcher.MatchCode checkColumn(byte [] bytes, int offset,
-      int length, long timestamp, byte type, boolean ignoreCount) {
+      int length, byte type) {
     // delete markers should never be passed to an
     // *Explicit*ColumnTracker
     assert !KeyValue.isDelete(type);
@@ -125,34 +125,9 @@ public class ExplicitColumnTracker imple
       int ret = Bytes.compareTo(column.getBuffer(), column.getOffset(),
           column.getLength(), bytes, offset, length);
 
-      // Column Matches. If it is not a duplicate key, increment the version count
-      // and include.
+      // Column Matches. Return include code. The caller would call checkVersions
+      // to limit the number of versions.
       if(ret == 0) {
-        if (ignoreCount) return ScanQueryMatcher.MatchCode.INCLUDE;
-
-        //If column matches, check if it is a duplicate timestamp
-        if (sameAsPreviousTS(timestamp)) {
-          //If duplicate, skip this Key
-          return ScanQueryMatcher.MatchCode.SKIP;
-        }
-        int count = this.column.increment();
-        if(count >= maxVersions || (count >= minVersions && isExpired(timestamp))) {
-          // Done with versions for this column
-          ++this.index;
-          resetTS();
-          if (done()) {
-            // We have served all the requested columns.
-            this.column = null;
-            return ScanQueryMatcher.MatchCode.INCLUDE_AND_SEEK_NEXT_ROW;
-          } else {
-            // We are done with current column; advance to next column
-            // of interest.
-            this.column = this.columns.get(this.index);
-            return ScanQueryMatcher.MatchCode.INCLUDE_AND_SEEK_NEXT_COL;
-          }
-        } else {
-          setTS(timestamp);
-        }
         return ScanQueryMatcher.MatchCode.INCLUDE;
       }
 
@@ -180,6 +155,35 @@ public class ExplicitColumnTracker imple
     } while(true);
   }
 
+  @Override
+  public ScanQueryMatcher.MatchCode checkVersions(byte[] bytes, int offset, int length,
+      long timestamp, byte type, boolean ignoreCount) {
+    assert !KeyValue.isDelete(type);
+    if (ignoreCount) return ScanQueryMatcher.MatchCode.INCLUDE;
+    // Check if it is a duplicate timestamp
+    if (sameAsPreviousTS(timestamp)) {
+      // If duplicate, skip this Key
+      return ScanQueryMatcher.MatchCode.SKIP;
+    }
+    int count = this.column.increment();
+    if (count >= maxVersions || (count >= minVersions && isExpired(timestamp))) {
+      // Done with versions for this column
+      ++this.index;
+      resetTS();
+      if (done()) {
+        // We have served all the requested columns.
+        this.column = null;
+        return ScanQueryMatcher.MatchCode.INCLUDE_AND_SEEK_NEXT_ROW;
+      }
+      // We are done with current column; advance to next column
+      // of interest.
+      this.column = this.columns.get(this.index);
+      return ScanQueryMatcher.MatchCode.INCLUDE_AND_SEEK_NEXT_COL;
+    }
+    setTS(timestamp);
+    return ScanQueryMatcher.MatchCode.INCLUDE;
+  }
+
   // Called between every row.
   public void reset() {
     this.index = 0;

Modified: hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/ScanQueryMatcher.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/ScanQueryMatcher.java?rev=1521356&r1=1521355&r2=1521356&view=diff
==============================================================================
--- hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/ScanQueryMatcher.java (original)
+++ hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/ScanQueryMatcher.java Tue Sep 10 04:58:57 2013
@@ -340,42 +340,60 @@ public class ScanQueryMatcher {
       return columns.getNextRowOrNextColumn(bytes, offset, qualLength);
     }
 
-    /**
-     * Filters should be checked before checking column trackers. If we do
-     * otherwise, as was previously being done, ColumnTracker may increment its
-     * counter for even that KV which may be discarded later on by Filter. This
-     * would lead to incorrect results in certain cases.
-     */
-    ReturnCode filterResponse = ReturnCode.SKIP;
-    if (filter != null) {
-      filterResponse = filter.filterKeyValue(kv);
-      if (filterResponse == ReturnCode.SKIP) {
-        return MatchCode.SKIP;
-      } else if (filterResponse == ReturnCode.NEXT_COL) {
-        return columns.getNextRowOrNextColumn(bytes, offset, qualLength);
-      } else if (filterResponse == ReturnCode.NEXT_ROW) {
-        stickyNextRow = true;
-        return MatchCode.SEEK_NEXT_ROW;
-      } else if (filterResponse == ReturnCode.SEEK_NEXT_USING_HINT) {
-        return MatchCode.SEEK_NEXT_USING_HINT;
+    // STEP 1: Check if the column is part of the requested columns
+    MatchCode colChecker = columns.checkColumn(bytes, offset, qualLength, type);
+    if (colChecker == MatchCode.INCLUDE) {
+      ReturnCode filterResponse = ReturnCode.SKIP;
+      // STEP 2: Yes, the column is part of the requested columns. Check if filter is present
+      if (filter != null) {
+        // STEP 3: Filter the key value and return if it filters out
+        filterResponse = filter.filterKeyValue(kv);
+        switch (filterResponse) {
+        case SKIP:
+          return MatchCode.SKIP;
+        case NEXT_COL:
+          return columns.getNextRowOrNextColumn(bytes, offset, qualLength);
+        case NEXT_ROW:
+          stickyNextRow = true;
+          return MatchCode.SEEK_NEXT_ROW;
+        case SEEK_NEXT_USING_HINT:
+          return MatchCode.SEEK_NEXT_USING_HINT;
+        default:
+          //It means it is either include or include and seek next
+          break;
+        }
       }
+      /*
+       * STEP 4: Reaching this step means the column is part of the requested columns and either
+       * the filter is null or the filter has returned INCLUDE or INCLUDE_AND_NEXT_COL response.
+       * Now check the number of versions needed. This method call returns SKIP, INCLUDE,
+       * INCLUDE_AND_SEEK_NEXT_ROW, INCLUDE_AND_SEEK_NEXT_COL.
+       *
+       * FilterResponse            ColumnChecker               Desired behavior
+       * INCLUDE                   SKIP                        row has already been included, SKIP.
+       * INCLUDE                   INCLUDE                     INCLUDE
+       * INCLUDE                   INCLUDE_AND_SEEK_NEXT_COL   INCLUDE_AND_SEEK_NEXT_COL
+       * INCLUDE                   INCLUDE_AND_SEEK_NEXT_ROW   INCLUDE_AND_SEEK_NEXT_ROW
+       * INCLUDE_AND_SEEK_NEXT_COL SKIP                        row has already been included, SKIP.
+       * INCLUDE_AND_SEEK_NEXT_COL INCLUDE                     INCLUDE_AND_SEEK_NEXT_COL
+       * INCLUDE_AND_SEEK_NEXT_COL INCLUDE_AND_SEEK_NEXT_COL   INCLUDE_AND_SEEK_NEXT_COL
+       * INCLUDE_AND_SEEK_NEXT_COL INCLUDE_AND_SEEK_NEXT_ROW   INCLUDE_AND_SEEK_NEXT_ROW
+       *
+       * In all the above scenarios, we return the column checker return value except for
+       * FilterResponse (INCLUDE_AND_SEEK_NEXT_COL) and ColumnChecker(INCLUDE)
+       */
+      colChecker =
+          columns.checkVersions(bytes, offset, qualLength, timestamp, type,
+            kv.getMemstoreTS() > maxReadPointToTrackVersions);
+      //Optimize with stickyNextRow
+      stickyNextRow = colChecker == MatchCode.INCLUDE_AND_SEEK_NEXT_ROW ? true : stickyNextRow;
+      return (filterResponse == ReturnCode.INCLUDE_AND_NEXT_COL &&
+          colChecker == MatchCode.INCLUDE) ? MatchCode.INCLUDE_AND_SEEK_NEXT_COL
+          : colChecker;
     }
-
-    MatchCode colChecker = columns.checkColumn(bytes, offset, qualLength,
-        timestamp, type, kv.getMemstoreTS() > maxReadPointToTrackVersions);
-    /*
-     * According to current implementation, colChecker can only be
-     * SEEK_NEXT_COL, SEEK_NEXT_ROW, SKIP or INCLUDE. Therefore, always return
-     * the MatchCode. If it is SEEK_NEXT_ROW, also set stickyNextRow.
-     */
-    if (colChecker == MatchCode.SEEK_NEXT_ROW) {
-      stickyNextRow = true;
-    } else if (filter != null && colChecker == MatchCode.INCLUDE &&
-               filterResponse == ReturnCode.INCLUDE_AND_NEXT_COL) {
-      return MatchCode.INCLUDE_AND_SEEK_NEXT_COL;
-    }
+    stickyNextRow = (colChecker == MatchCode.SEEK_NEXT_ROW) ? true
+        : stickyNextRow;
     return colChecker;
-
   }
 
   public boolean moreRowsMayExistAfter(KeyValue kv) {
@@ -454,6 +472,16 @@ public class ScanQueryMatcher {
         null, 0, 0);
   }
 
+  // Used only for testing purposes
+  static MatchCode checkColumn(ColumnTracker columnTracker, byte[] bytes, int offset, int length,
+      long ttl, byte type, boolean ignoreCount) throws IOException {
+    MatchCode matchCode = columnTracker.checkColumn(bytes, offset, length, type);
+    if (matchCode == MatchCode.INCLUDE) {
+      return columnTracker.checkVersions(bytes, offset, length, ttl, type, ignoreCount);
+    }
+    return matchCode;
+  }
+
   /**
    * {@link #match} return codes.  These instruct the scanner moving through
    * memstores and StoreFiles what to do with the current KeyValue.

Modified: hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/ScanWildcardColumnTracker.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/ScanWildcardColumnTracker.java?rev=1521356&r1=1521355&r2=1521356&view=diff
==============================================================================
--- hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/ScanWildcardColumnTracker.java (original)
+++ hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/ScanWildcardColumnTracker.java Tue Sep 10 04:58:57 2013
@@ -61,13 +61,22 @@ public class ScanWildcardColumnTracker i
   /**
    * {@inheritDoc}
    * This receives puts *and* deletes.
-   * Deletes do not count as a version, but rather take the version
-   * of the previous put (so eventually all but the last can be reclaimed).
    */
   @Override
-  public MatchCode checkColumn(byte[] bytes, int offset, int length,
-      long timestamp, byte type, boolean ignoreCount) throws IOException {
-    
+  public MatchCode checkColumn(byte[] bytes, int offset, int length, byte type)
+      throws IOException {
+    return MatchCode.INCLUDE;
+  }
+
+  /**
+   * {@inheritDoc}
+   * This receives puts *and* deletes. Deletes do not count as a version, but rather
+   * take the version of the previous put (so eventually all but the last can be reclaimed).
+   */
+  @Override
+  public MatchCode checkVersions(byte[] bytes, int offset, int length, long timestamp, byte type,
+      boolean ignoreCount) throws IOException {
+
     if (columnBuffer == null) {
       // first iteration.
       resetBuffer(bytes, offset, length);

Added: hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/filter/TestInvocationRecordFilter.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/filter/TestInvocationRecordFilter.java?rev=1521356&view=auto
==============================================================================
--- hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/filter/TestInvocationRecordFilter.java (added)
+++ hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/filter/TestInvocationRecordFilter.java Tue Sep 10 04:58:57 2013
@@ -0,0 +1,192 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.ArrayList;
+import java.util.List;
+
+import org.apache.hadoop.hbase.HBaseTestingUtility;
+import org.apache.hadoop.hbase.HColumnDescriptor;
+import org.apache.hadoop.hbase.HRegionInfo;
+import org.apache.hadoop.hbase.HTableDescriptor;
+import org.apache.hadoop.hbase.KeyValue;
+import org.apache.hadoop.hbase.SmallTests;
+import org.apache.hadoop.hbase.client.Get;
+import org.apache.hadoop.hbase.client.Put;
+import org.apache.hadoop.hbase.client.Scan;
+import org.apache.hadoop.hbase.regionserver.HRegion;
+import org.apache.hadoop.hbase.regionserver.InternalScanner;
+import org.apache.hadoop.hbase.regionserver.wal.HLog;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+/**
+ * Test the invocation logic of the filters. A filter must be invoked only for
+ * the columns that are requested for.
+ */
+@Category(SmallTests.class)
+public class TestInvocationRecordFilter {
+
+  private static final byte[] TABLE_NAME_BYTES = Bytes
+      .toBytes("invocationrecord");
+  private static final byte[] FAMILY_NAME_BYTES = Bytes.toBytes("mycf");
+
+  private static final byte[] ROW_BYTES = Bytes.toBytes("row");
+  private static final String QUALIFIER_PREFIX = "qualifier";
+  private static final String VALUE_PREFIX = "value";
+
+  private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
+  private HRegion region;
+
+  @Before
+  public void setUp() throws Exception {
+    HTableDescriptor htd = new HTableDescriptor(TABLE_NAME_BYTES);
+    htd.addFamily(new HColumnDescriptor(FAMILY_NAME_BYTES));
+    HRegionInfo info = new HRegionInfo(TABLE_NAME_BYTES, null, null, false);
+    this.region = HRegion.createHRegion(info, TEST_UTIL.getDataTestDir(),
+        TEST_UTIL.getConfiguration(), htd);
+
+    Put put = new Put(ROW_BYTES);
+    for (int i = 0; i < 10; i += 2) {
+      // puts 0, 2, 4, 6 and 8
+      put.add(FAMILY_NAME_BYTES, Bytes.toBytes(QUALIFIER_PREFIX + i), i,
+          Bytes.toBytes(VALUE_PREFIX + i));
+    }
+    this.region.put(put);
+    this.region.flushcache();
+  }
+
+  @Test
+  public void testFilterInvocation() throws Exception {
+    List<Integer> selectQualifiers = new ArrayList<Integer>();
+    List<Integer> expectedQualifiers = new ArrayList<Integer>();
+
+    selectQualifiers.add(-1);
+    verifyInvocationResults(selectQualifiers.toArray(new Integer[0]),
+        expectedQualifiers.toArray(new Integer[0]));
+
+    selectQualifiers.clear();
+
+    selectQualifiers.add(0);
+    expectedQualifiers.add(0);
+    verifyInvocationResults(selectQualifiers.toArray(new Integer[0]),
+        expectedQualifiers.toArray(new Integer[0]));
+
+    selectQualifiers.add(3);
+    verifyInvocationResults(selectQualifiers.toArray(new Integer[0]),
+        expectedQualifiers.toArray(new Integer[0]));
+
+    selectQualifiers.add(4);
+    expectedQualifiers.add(4);
+    verifyInvocationResults(selectQualifiers.toArray(new Integer[0]),
+        expectedQualifiers.toArray(new Integer[0]));
+
+    selectQualifiers.add(5);
+    verifyInvocationResults(selectQualifiers.toArray(new Integer[0]),
+        expectedQualifiers.toArray(new Integer[0]));
+
+    selectQualifiers.add(8);
+    expectedQualifiers.add(8);
+    verifyInvocationResults(selectQualifiers.toArray(new Integer[0]),
+        expectedQualifiers.toArray(new Integer[0]));
+  }
+
+  public void verifyInvocationResults(Integer[] selectQualifiers,
+      Integer[] expectedQualifiers) throws Exception {
+    Get get = new Get(ROW_BYTES);
+    for (int i = 0; i < selectQualifiers.length; i++) {
+      get.addColumn(FAMILY_NAME_BYTES,
+          Bytes.toBytes(QUALIFIER_PREFIX + selectQualifiers[i]));
+    }
+
+    get.setFilter(new InvocationRecordFilter());
+
+    List<KeyValue> expectedValues = new ArrayList<KeyValue>();
+    for (int i = 0; i < expectedQualifiers.length; i++) {
+      expectedValues.add(new KeyValue(ROW_BYTES, FAMILY_NAME_BYTES, Bytes
+          .toBytes(QUALIFIER_PREFIX + expectedQualifiers[i]),
+          expectedQualifiers[i], Bytes.toBytes(VALUE_PREFIX
+              + expectedQualifiers[i])));
+    }
+
+    Scan scan = new Scan(get);
+    List<KeyValue> actualValues = new ArrayList<KeyValue>();
+    List<KeyValue> temp = new ArrayList<KeyValue>();
+    InternalScanner scanner = this.region.getScanner(scan);
+    while (scanner.next(temp)) {
+      actualValues.addAll(temp);
+      temp.clear();
+    }
+    actualValues.addAll(temp);
+    Assert.assertTrue("Actual values " + actualValues
+        + " differ from the expected values:" + expectedValues,
+        expectedValues.equals(actualValues));
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    HLog hlog = region.getLog();
+    region.close();
+    hlog.closeAndDelete();
+  }
+
+  /**
+   * Filter which gives the list of keyvalues for which the filter is invoked.
+   */
+  private static class InvocationRecordFilter extends FilterBase {
+
+    private List<KeyValue> visitedKeyValues = new ArrayList<KeyValue>();
+
+    public void reset() {
+      visitedKeyValues.clear();
+    }
+
+    public ReturnCode filterKeyValue(KeyValue ignored) {
+      visitedKeyValues.add(ignored);
+      return ReturnCode.INCLUDE;
+    }
+
+    public void filterRow(List<KeyValue> kvs) {
+      kvs.clear();
+      kvs.addAll(visitedKeyValues);
+    }
+
+    public boolean hasFilterRow() {
+      return true;
+    }
+
+    @Override
+    public void readFields(DataInput arg0) throws IOException {
+      //do nothing
+    }
+
+    @Override
+    public void write(DataOutput arg0) throws IOException {
+      //do nothing
+    }
+  }
+}
\ No newline at end of file

Modified: hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/regionserver/TestExplicitColumnTracker.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/regionserver/TestExplicitColumnTracker.java?rev=1521356&r1=1521355&r2=1521356&view=diff
==============================================================================
--- hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/regionserver/TestExplicitColumnTracker.java (original)
+++ hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/regionserver/TestExplicitColumnTracker.java Tue Sep 10 04:58:57 2013
@@ -56,7 +56,7 @@ public class TestExplicitColumnTracker e
     long timestamp = 0;
     //"Match"
     for(byte [] col : scannerColumns){
-      result.add(exp.checkColumn(col, 0, col.length, ++timestamp,
+      result.add(ScanQueryMatcher.checkColumn(exp, col, 0, col.length, ++timestamp,
           KeyValue.Type.Put.getCode(), false));
     }
 
@@ -169,14 +169,14 @@ public class TestExplicitColumnTracker e
         Long.MIN_VALUE);
     for (int i = 0; i < 100000; i+=2) {
       byte [] col = Bytes.toBytes("col"+i);
-      explicit.checkColumn(col, 0, col.length, 1, KeyValue.Type.Put.getCode(),
+      ScanQueryMatcher.checkColumn(explicit, col, 0, col.length, 1, KeyValue.Type.Put.getCode(),
           false);
     }
     explicit.reset();
 
     for (int i = 1; i < 100000; i+=2) {
       byte [] col = Bytes.toBytes("col"+i);
-      explicit.checkColumn(col, 0, col.length, 1, KeyValue.Type.Put.getCode(),
+      ScanQueryMatcher.checkColumn(explicit, col, 0, col.length, 1, KeyValue.Type.Put.getCode(),
           false);
     }
   }

Modified: hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/regionserver/TestScanWildcardColumnTracker.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/regionserver/TestScanWildcardColumnTracker.java?rev=1521356&r1=1521355&r2=1521356&view=diff
==============================================================================
--- hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/regionserver/TestScanWildcardColumnTracker.java (original)
+++ hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/regionserver/TestScanWildcardColumnTracker.java Tue Sep 10 04:58:57 2013
@@ -55,7 +55,7 @@ public class TestScanWildcardColumnTrack
     List<ScanQueryMatcher.MatchCode> actual = new ArrayList<MatchCode>();
 
     for(byte [] qualifier : qualifiers) {
-      ScanQueryMatcher.MatchCode mc = tracker.checkColumn(qualifier, 0,
+      ScanQueryMatcher.MatchCode mc = ScanQueryMatcher.checkColumn(tracker, qualifier, 0,
           qualifier.length, 1, KeyValue.Type.Put.getCode(), false);
       actual.add(mc);
     }
@@ -88,7 +88,7 @@ public class TestScanWildcardColumnTrack
 
     long timestamp = 0;
     for(byte [] qualifier : qualifiers) {
-      MatchCode mc = tracker.checkColumn(qualifier, 0, qualifier.length,
+      MatchCode mc = ScanQueryMatcher.checkColumn(tracker, qualifier, 0, qualifier.length,
           ++timestamp, KeyValue.Type.Put.getCode(), false);
       actual.add(mc);
     }
@@ -112,7 +112,7 @@ public class TestScanWildcardColumnTrack
 
     try {
       for(byte [] qualifier : qualifiers) {
-        tracker.checkColumn(qualifier, 0, qualifier.length, 1,
+        ScanQueryMatcher.checkColumn(tracker, qualifier, 0, qualifier.length, 1,
             KeyValue.Type.Put.getCode(), false);
       }
     } catch (Exception e) {