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   * Parses a serialized representation of {@link FirstKeyValueMatchingQualifiersFilter}
099   * @param pbBytes A pb serialized {@link FirstKeyValueMatchingQualifiersFilter} instance
100   * @return An instance of {@link FirstKeyValueMatchingQualifiersFilter} made from
101   *         <code>bytes</code>
102   * @throws DeserializationException if an error occurred
103   * @see #toByteArray
104   */
105  public static FirstKeyValueMatchingQualifiersFilter parseFrom(final byte[] pbBytes)
106    throws DeserializationException {
107    FilterProtos.FirstKeyValueMatchingQualifiersFilter proto;
108    try {
109      proto = FilterProtos.FirstKeyValueMatchingQualifiersFilter.parseFrom(pbBytes);
110    } catch (InvalidProtocolBufferException e) {
111      throw new DeserializationException(e);
112    }
113
114    TreeSet<byte[]> qualifiers = new TreeSet<>(Bytes.BYTES_COMPARATOR);
115    for (ByteString qualifier : proto.getQualifiersList()) {
116      qualifiers.add(qualifier.toByteArray());
117    }
118    return new FirstKeyValueMatchingQualifiersFilter(qualifiers);
119  }
120
121  /**
122   * @param o the other filter to compare with
123   * @return true if and only if the fields of the filter that are serialized are equal to the
124   *         corresponding fields in other. Used for testing.
125   */
126  @Override
127  boolean areSerializedFieldsEqual(Filter o) {
128    if (o == this) return true;
129    if (!(o instanceof FirstKeyValueMatchingQualifiersFilter)) return false;
130
131    FirstKeyValueMatchingQualifiersFilter other = (FirstKeyValueMatchingQualifiersFilter) o;
132    return this.qualifiers.equals(other.qualifiers);
133  }
134
135  @Override
136  public boolean equals(Object obj) {
137    return obj instanceof Filter && areSerializedFieldsEqual((Filter) obj);
138  }
139
140  @Override
141  public int hashCode() {
142    return Objects.hash(this.qualifiers);
143  }
144}