001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.filter;
019
020import java.util.Objects;
021import java.util.Set;
022import java.util.TreeSet;
023import org.apache.hadoop.hbase.Cell;
024import org.apache.hadoop.hbase.CellUtil;
025import org.apache.hadoop.hbase.exceptions.DeserializationException;
026import org.apache.hadoop.hbase.util.Bytes;
027import org.apache.yetus.audience.InterfaceAudience;
028
029import org.apache.hbase.thirdparty.com.google.protobuf.ByteString;
030import org.apache.hbase.thirdparty.com.google.protobuf.InvalidProtocolBufferException;
031import org.apache.hbase.thirdparty.com.google.protobuf.UnsafeByteOperations;
032
033import org.apache.hadoop.hbase.shaded.protobuf.generated.FilterProtos;
034
035/**
036 * The filter looks for the given columns in KeyValue. Once there is a match for any one of the
037 * columns, it returns ReturnCode.NEXT_ROW for remaining KeyValues in the row.
038 * <p>
039 * Note : It may emit KVs which do not have the given columns in them, if these KVs happen to occur
040 * before a KV which does have a match. Given this caveat, this filter is only useful for special
041 * cases like org.apache.hadoop.hbase.mapreduce.RowCounter.
042 * <p>
043 * @deprecated Deprecated in 2.0.0 and will be removed in 3.0.0.
044 * @see <a href="https://issues.apache.org/jira/browse/HBASE-13347">HBASE-13347</a>
045 */
046@InterfaceAudience.Public
047@Deprecated
048public class FirstKeyValueMatchingQualifiersFilter extends FirstKeyOnlyFilter {
049
050  private Set<byte[]> qualifiers;
051
052  /**
053   * Constructor which takes a set of columns. As soon as first KeyValue matching any of these
054   * columns is found, filter moves to next row.
055   * @param qualifiers the set of columns to me matched.
056   */
057  public FirstKeyValueMatchingQualifiersFilter(Set<byte[]> qualifiers) {
058    this.qualifiers = qualifiers;
059  }
060
061  @Deprecated
062  @Override
063  public ReturnCode filterKeyValue(final Cell c) {
064    return filterCell(c);
065  }
066
067  @Override
068  public ReturnCode filterCell(final Cell c) {
069    if (hasFoundKV()) {
070      return ReturnCode.NEXT_ROW;
071    } else if (hasOneMatchingQualifier(c)) {
072      setFoundKV(true);
073    }
074    return ReturnCode.INCLUDE;
075  }
076
077  private boolean hasOneMatchingQualifier(Cell c) {
078    for (byte[] q : qualifiers) {
079      if (CellUtil.matchingQualifier(c, q)) {
080        return true;
081      }
082    }
083    return false;
084  }
085
086  /** Returns The filter serialized using pb */
087  @Override
088  public byte[] toByteArray() {
089    FilterProtos.FirstKeyValueMatchingQualifiersFilter.Builder builder =
090      FilterProtos.FirstKeyValueMatchingQualifiersFilter.newBuilder();
091    for (byte[] qualifier : qualifiers) {
092      if (qualifier != null) builder.addQualifiers(UnsafeByteOperations.unsafeWrap(qualifier));
093    }
094    return builder.build().toByteArray();
095  }
096
097  /**
098   * @param pbBytes A pb serialized {@link FirstKeyValueMatchingQualifiersFilter} instance
099   * @return An instance of {@link FirstKeyValueMatchingQualifiersFilter} made from
100   *         <code>bytes</code>
101   * @see #toByteArray
102   */
103  public static FirstKeyValueMatchingQualifiersFilter parseFrom(final byte[] pbBytes)
104    throws DeserializationException {
105    FilterProtos.FirstKeyValueMatchingQualifiersFilter proto;
106    try {
107      proto = FilterProtos.FirstKeyValueMatchingQualifiersFilter.parseFrom(pbBytes);
108    } catch (InvalidProtocolBufferException e) {
109      throw new DeserializationException(e);
110    }
111
112    TreeSet<byte[]> qualifiers = new TreeSet<>(Bytes.BYTES_COMPARATOR);
113    for (ByteString qualifier : proto.getQualifiersList()) {
114      qualifiers.add(qualifier.toByteArray());
115    }
116    return new FirstKeyValueMatchingQualifiersFilter(qualifiers);
117  }
118
119  /**
120   * @param o the other filter to compare with
121   * @return true if and only if the fields of the filter that are serialized are equal to the
122   *         corresponding fields in other. Used for testing.
123   */
124  @Override
125  boolean areSerializedFieldsEqual(Filter o) {
126    if (o == this) return true;
127    if (!(o instanceof FirstKeyValueMatchingQualifiersFilter)) return false;
128
129    FirstKeyValueMatchingQualifiersFilter other = (FirstKeyValueMatchingQualifiersFilter) o;
130    return this.qualifiers.equals(other.qualifiers);
131  }
132
133  @Override
134  public boolean equals(Object obj) {
135    return obj instanceof Filter && areSerializedFieldsEqual((Filter) obj);
136  }
137
138  @Override
139  public int hashCode() {
140    return Objects.hash(this.qualifiers);
141  }
142}