@Override
  public ScanQueryMatcher.MatchCode checkVersions(ExtendedCell cell, long timestamp, byte type,
    boolean ignoreCount) throws IOException {
    if (columnCell == null) {
      // first iteration.
      resetCell(cell);
      if (ignoreCount) {
        return ScanQueryMatcher.MatchCode.INCLUDE;
      }
      // do not count a delete marker as another version
      return checkVersion(type, timestamp);
    }
    int cmp = comparator.compareQualifiers(cell, this.columnCell);
    if (cmp == 0) {
      if (ignoreCount) {
        return ScanQueryMatcher.MatchCode.INCLUDE;
      }

      // If column matches, check if it is a duplicate timestamp
      if (sameAsPreviousTSAndType(timestamp, type)) {
        return ScanQueryMatcher.MatchCode.SKIP;
      }
      return checkVersion(type, timestamp);
    }

    resetTSAndType();

    // new col > old col
    if (cmp > 0) {
      // switched columns, lets do something.x
      resetCell(cell);
      if (ignoreCount) {
        return ScanQueryMatcher.MatchCode.INCLUDE;
      }
      return checkVersion(type, timestamp);
    }

    // new col < oldcol
    // WARNING: This means that very likely an edit for some other family
    // was incorrectly stored into the store for this one. Throw an exception,
    // because this might lead to data corruption.
    throw new IOException("ScanWildcardColumnTracker.checkColumn ran into a column actually "
      + "smaller than the previous column: " + Bytes.toStringBinary(CellUtil.cloneQualifier(cell)));
  }
{@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).
hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/querymatcher/ScanWildcardColumnTracker.java