private void testRowsFilteredMetric(Scan baseScan) throws Exception {
    testRowsFilteredMetric(baseScan, null, 0);

    // Row filter doesn't match any row key. All rows should be filtered
    Filter filter =
      new RowFilter(CompareOperator.EQUAL, new BinaryComparator(Bytes.toBytes("xyz")));
    testRowsFilteredMetric(baseScan, filter, ROWS.length);

    // Filter will return results containing only the first key. Number of entire rows filtered
    // should be 0.
    filter = new FirstKeyOnlyFilter();
    testRowsFilteredMetric(baseScan, filter, 0);

    // Column prefix will find some matching qualifier on each row. Number of entire rows filtered
    // should be 0
    filter = new ColumnPrefixFilter(QUALIFIERS[0]);
    testRowsFilteredMetric(baseScan, filter, 0);

    // Column prefix will NOT find any matching qualifier on any row. All rows should be filtered
    filter = new ColumnPrefixFilter(Bytes.toBytes("xyz"));
    testRowsFilteredMetric(baseScan, filter, ROWS.length);

    // Matching column value should exist in each row. No rows should be filtered.
    filter = new SingleColumnValueFilter(FAMILIES[0], QUALIFIERS[0], CompareOperator.EQUAL, VALUE);
    testRowsFilteredMetric(baseScan, filter, 0);

    // No matching column value should exist in any row. Filter all rows
    filter =
      new SingleColumnValueFilter(FAMILIES[0], QUALIFIERS[0], CompareOperator.NOT_EQUAL, VALUE);
    testRowsFilteredMetric(baseScan, filter, ROWS.length);

    List<Filter> filters = new ArrayList<>();
    filters.add(new RowFilter(CompareOperator.EQUAL, new BinaryComparator(ROWS[0])));
    filters.add(new RowFilter(CompareOperator.EQUAL, new BinaryComparator(ROWS[3])));
    int numberOfMatchingRowFilters = filters.size();
    filter = new FilterList(Operator.MUST_PASS_ONE, filters);
    testRowsFilteredMetric(baseScan, filter, ROWS.length - numberOfMatchingRowFilters);
    filters.clear();

    // Add a single column value exclude filter for each column... The net effect is that all
    // columns will be excluded when scanning on the server side. This will result in an empty cell
    // array in RegionScanner#nextInternal which should be interpreted as a row being filtered.
    for (int family = 0; family < FAMILIES.length; family++) {
      for (int qualifier = 0; qualifier < QUALIFIERS.length; qualifier++) {
        filters.add(new SingleColumnValueExcludeFilter(FAMILIES[family], QUALIFIERS[qualifier],
          CompareOperator.EQUAL, VALUE));
      }
    }
    filter = new FilterList(Operator.MUST_PASS_ONE, filters);
    testRowsFilteredMetric(baseScan, filter, ROWS.length);
  }
@return The approximate heap size of a cell in the test table. All cells should have
        approximately the same heap size, so the value is cached to avoid repeating the
        calculation
@throws Exception on unexpected failure
hbase-server/src/test/java/org/apache/hadoop/hbase/TestServerSideScanMetricsFromClientSide.java