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