001/**
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *     http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019package org.apache.hadoop.hbase.filter;
020
021import java.io.IOException;
022import java.util.ArrayList;
023import java.util.Iterator;
024import java.util.List;
025
026import org.apache.hadoop.hbase.Cell;
027import org.apache.hadoop.hbase.CellUtil;
028import org.apache.hadoop.hbase.CompareOperator;
029import org.apache.yetus.audience.InterfaceAudience;
030import org.apache.hadoop.hbase.exceptions.DeserializationException;
031import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
032import org.apache.hadoop.hbase.shaded.protobuf.generated.FilterProtos;
033import org.apache.hbase.thirdparty.com.google.protobuf.InvalidProtocolBufferException;
034
035/**
036 * A {@link Filter} that checks a single column value, but does not emit the
037 * tested column. This will enable a performance boost over
038 * {@link SingleColumnValueFilter}, if the tested column value is not actually
039 * needed as input (besides for the filtering itself).
040 */
041@InterfaceAudience.Public
042public class SingleColumnValueExcludeFilter extends SingleColumnValueFilter {
043  /**
044   * Constructor for binary compare of the value of a single column. If the
045   * column is found and the condition passes, all columns of the row will be
046   * emitted; except for the tested column value. If the column is not found or
047   * the condition fails, the row will not be emitted.
048   *
049   * @param family name of column family
050   * @param qualifier name of column qualifier
051   * @param op operator
052   * @param value value to compare column values against
053   */
054  public SingleColumnValueExcludeFilter(byte[] family, byte[] qualifier,
055                                        CompareOperator op, byte[] value) {
056    super(family, qualifier, op, value);
057  }
058
059  /**
060   * Constructor for binary compare of the value of a single column. If the
061   * column is found and the condition passes, all columns of the row will be
062   * emitted; except for the tested column value. If the condition fails, the
063   * row will not be emitted.
064   * <p>
065   * Use the filterIfColumnMissing flag to set whether the rest of the columns
066   * in a row will be emitted if the specified column to check is not found in
067   * the row.
068   *
069   * @param family name of column family
070   * @param qualifier name of column qualifier
071   * @param op operator
072   * @param comparator Comparator to use.
073   */
074  public SingleColumnValueExcludeFilter(byte[] family, byte[] qualifier,
075                                        CompareOperator op, ByteArrayComparable comparator) {
076    super(family, qualifier, op, comparator);
077  }
078
079  /**
080   * Constructor for protobuf deserialization only.
081   * @param family
082   * @param qualifier
083   * @param op
084   * @param comparator
085   * @param filterIfMissing
086   * @param latestVersionOnly
087   */
088  protected SingleColumnValueExcludeFilter(final byte[] family, final byte[] qualifier,
089      final CompareOperator op, ByteArrayComparable comparator, final boolean filterIfMissing,
090      final boolean latestVersionOnly) {
091    super(family, qualifier, op, comparator, filterIfMissing, latestVersionOnly);
092  }
093
094  // We cleaned result row in FilterRow to be consistent with scanning process.
095  @Override
096  public boolean hasFilterRow() {
097   return true;
098  }
099
100  // Here we remove from row all key values from testing column
101  @Override
102  public void filterRowCells(List<Cell> kvs) {
103    Iterator<? extends Cell> it = kvs.iterator();
104    while (it.hasNext()) {
105      // If the current column is actually the tested column,
106      // we will skip it instead.
107      if (CellUtil.matchingColumn(it.next(), this.columnFamily, this.columnQualifier)) {
108        it.remove();
109      }
110    }
111  }
112
113  public static Filter createFilterFromArguments(ArrayList<byte []> filterArguments) {
114    SingleColumnValueFilter tempFilter = (SingleColumnValueFilter)
115      SingleColumnValueFilter.createFilterFromArguments(filterArguments);
116    SingleColumnValueExcludeFilter filter = new SingleColumnValueExcludeFilter (
117      tempFilter.getFamily(), tempFilter.getQualifier(),
118      tempFilter.getCompareOperator(), tempFilter.getComparator());
119
120    if (filterArguments.size() == 6) {
121      filter.setFilterIfMissing(tempFilter.getFilterIfMissing());
122      filter.setLatestVersionOnly(tempFilter.getLatestVersionOnly());
123    }
124    return filter;
125  }
126
127  /**
128   * @return The filter serialized using pb
129   */
130  @Override
131  public byte [] toByteArray() {
132    FilterProtos.SingleColumnValueExcludeFilter.Builder builder =
133      FilterProtos.SingleColumnValueExcludeFilter.newBuilder();
134    builder.setSingleColumnValueFilter(super.convert());
135    return builder.build().toByteArray();
136  }
137
138  /**
139   * @param pbBytes A pb serialized {@link SingleColumnValueExcludeFilter} instance
140   * @return An instance of {@link SingleColumnValueExcludeFilter} made from <code>bytes</code>
141   * @throws DeserializationException
142   * @see #toByteArray
143   */
144  public static SingleColumnValueExcludeFilter parseFrom(final byte [] pbBytes)
145  throws DeserializationException {
146    FilterProtos.SingleColumnValueExcludeFilter proto;
147    try {
148      proto = FilterProtos.SingleColumnValueExcludeFilter.parseFrom(pbBytes);
149    } catch (InvalidProtocolBufferException e) {
150      throw new DeserializationException(e);
151    }
152
153    FilterProtos.SingleColumnValueFilter parentProto = proto.getSingleColumnValueFilter();
154    final CompareOperator compareOp =
155      CompareOperator.valueOf(parentProto.getCompareOp().name());
156    final ByteArrayComparable comparator;
157    try {
158      comparator = ProtobufUtil.toComparator(parentProto.getComparator());
159    } catch (IOException ioe) {
160      throw new DeserializationException(ioe);
161    }
162
163    return new SingleColumnValueExcludeFilter(parentProto.hasColumnFamily() ? parentProto
164        .getColumnFamily().toByteArray() : null, parentProto.hasColumnQualifier() ? parentProto
165        .getColumnQualifier().toByteArray() : null, compareOp, comparator, parentProto
166        .getFilterIfMissing(), parentProto.getLatestVersionOnly());
167  }
168
169  /**
170   * @return true if and only if the fields of the filter that are serialized
171   * are equal to the corresponding fields in other.  Used for testing.
172   */
173  @Override
174  boolean areSerializedFieldsEqual(Filter o) {
175    if (o == this) return true;
176    if (!(o instanceof SingleColumnValueExcludeFilter)) return false;
177
178    return super.areSerializedFieldsEqual(o);
179  }
180
181  @Override
182  public boolean equals(Object obj) {
183    return obj instanceof Filter && areSerializedFieldsEqual((Filter) obj);
184  }
185
186  @Override
187  public int hashCode() {
188    return super.hashCode();
189  }
190}