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.io.IOException; 021import java.util.Objects; 022import org.apache.hadoop.hbase.Cell; 023import org.apache.hadoop.hbase.exceptions.DeserializationException; 024import org.apache.yetus.audience.InterfaceAudience; 025 026import org.apache.hbase.thirdparty.com.google.protobuf.InvalidProtocolBufferException; 027 028import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 029import org.apache.hadoop.hbase.shaded.protobuf.generated.FilterProtos; 030 031/** 032 * A wrapper filter that filters an entire row if any of the Cell checks do not pass. 033 * <p> 034 * For example, if all columns in a row represent weights of different things, with the values being 035 * the actual weights, and we want to filter out the entire row if any of its weights are zero. In 036 * this case, we want to prevent rows from being emitted if a single key is filtered. Combine this 037 * filter with a {@link ValueFilter}: 038 * </p> 039 * <p> 040 * <code> 041 * scan.setFilter(new SkipFilter(new ValueFilter(CompareOp.NOT_EQUAL, 042 * new BinaryComparator(Bytes.toBytes(0)))); 043 * </code> Any row which contained a column whose value was 0 will be filtered out (since 044 * ValueFilter will not pass that Cell). Without this filter, the other non-zero valued columns in 045 * the row would still be emitted. 046 * </p> 047 */ 048@InterfaceAudience.Public 049public class SkipFilter extends FilterBase { 050 private boolean filterRow = false; 051 private Filter filter; 052 053 public SkipFilter(Filter filter) { 054 this.filter = filter; 055 } 056 057 public Filter getFilter() { 058 return filter; 059 } 060 061 @Override 062 public void reset() throws IOException { 063 filter.reset(); 064 filterRow = false; 065 } 066 067 private void changeFR(boolean value) { 068 filterRow = filterRow || value; 069 } 070 071 @Override 072 public boolean filterRowKey(Cell cell) throws IOException { 073 // Impl in FilterBase might do unnecessary copy for Off heap backed Cells. 074 return false; 075 } 076 077 @Override 078 public ReturnCode filterCell(final Cell c) throws IOException { 079 ReturnCode rc = filter.filterCell(c); 080 changeFR(rc != ReturnCode.INCLUDE); 081 return rc; 082 } 083 084 @Override 085 public Cell transformCell(Cell v) throws IOException { 086 return filter.transformCell(v); 087 } 088 089 @Override 090 public boolean filterRow() { 091 return filterRow; 092 } 093 094 @Override 095 public boolean hasFilterRow() { 096 return true; 097 } 098 099 /** 100 * @return The filter serialized using pb 101 */ 102 @Override 103 public byte[] toByteArray() throws IOException { 104 FilterProtos.SkipFilter.Builder builder = FilterProtos.SkipFilter.newBuilder(); 105 builder.setFilter(ProtobufUtil.toFilter(this.filter)); 106 return builder.build().toByteArray(); 107 } 108 109 /** 110 * @param pbBytes A pb serialized {@link SkipFilter} instance 111 * @return An instance of {@link SkipFilter} made from <code>bytes</code> n * @see #toByteArray 112 */ 113 public static SkipFilter parseFrom(final byte[] pbBytes) throws DeserializationException { 114 FilterProtos.SkipFilter proto; 115 try { 116 proto = FilterProtos.SkipFilter.parseFrom(pbBytes); 117 } catch (InvalidProtocolBufferException e) { 118 throw new DeserializationException(e); 119 } 120 try { 121 return new SkipFilter(ProtobufUtil.toFilter(proto.getFilter())); 122 } catch (IOException ioe) { 123 throw new DeserializationException(ioe); 124 } 125 } 126 127 /** 128 * @param o the other filter to compare with 129 * @return true if and only if the fields of the filter that are serialized are equal to the 130 * corresponding fields in other. Used for testing. 131 */ 132 @Override 133 boolean areSerializedFieldsEqual(Filter o) { 134 if (o == this) return true; 135 if (!(o instanceof SkipFilter)) return false; 136 137 SkipFilter other = (SkipFilter) o; 138 return getFilter().areSerializedFieldsEqual(other.getFilter()); 139 } 140 141 @Override 142 public boolean isFamilyEssential(byte[] name) throws IOException { 143 return filter.isFamilyEssential(name); 144 } 145 146 @Override 147 public String toString() { 148 return this.getClass().getSimpleName() + " " + this.filter.toString(); 149 } 150 151 @Override 152 public boolean equals(Object obj) { 153 return obj instanceof Filter && areSerializedFieldsEqual((Filter) obj); 154 } 155 156 @Override 157 public int hashCode() { 158 return Objects.hash(this.filter); 159 } 160}