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 @Deprecated 078 @Override 079 public ReturnCode filterKeyValue(final Cell c) throws IOException { 080 return filterCell(c); 081 } 082 083 @Override 084 public ReturnCode filterCell(final Cell c) throws IOException { 085 ReturnCode rc = filter.filterCell(c); 086 changeFR(rc != ReturnCode.INCLUDE); 087 return rc; 088 } 089 090 @Override 091 public Cell transformCell(Cell v) throws IOException { 092 return filter.transformCell(v); 093 } 094 095 @Override 096 public boolean filterRow() { 097 return filterRow; 098 } 099 100 @Override 101 public boolean hasFilterRow() { 102 return true; 103 } 104 105 /** Returns The filter serialized using pb */ 106 @Override 107 public byte[] toByteArray() throws IOException { 108 FilterProtos.SkipFilter.Builder builder = FilterProtos.SkipFilter.newBuilder(); 109 builder.setFilter(ProtobufUtil.toFilter(this.filter)); 110 return builder.build().toByteArray(); 111 } 112 113 /** 114 * Parse a serialized representation of {@link SkipFilter} 115 * @param pbBytes A pb serialized {@link SkipFilter} instance 116 * @return An instance of {@link SkipFilter} made from <code>bytes</code> 117 * @throws DeserializationException if an error occurred 118 * @see #toByteArray 119 */ 120 public static SkipFilter parseFrom(final byte[] pbBytes) throws DeserializationException { 121 FilterProtos.SkipFilter proto; 122 try { 123 proto = FilterProtos.SkipFilter.parseFrom(pbBytes); 124 } catch (InvalidProtocolBufferException e) { 125 throw new DeserializationException(e); 126 } 127 try { 128 return new SkipFilter(ProtobufUtil.toFilter(proto.getFilter())); 129 } catch (IOException ioe) { 130 throw new DeserializationException(ioe); 131 } 132 } 133 134 /** 135 * Returns true if and only if the fields of the filter that are serialized are equal to the 136 * corresponding fields in other. Used for testing. 137 */ 138 @Override 139 boolean areSerializedFieldsEqual(Filter o) { 140 if (o == this) { 141 return true; 142 } 143 if (!(o instanceof SkipFilter)) { 144 return false; 145 } 146 SkipFilter other = (SkipFilter) o; 147 return getFilter().areSerializedFieldsEqual(other.getFilter()); 148 } 149 150 @Override 151 public boolean isFamilyEssential(byte[] name) throws IOException { 152 return filter.isFamilyEssential(name); 153 } 154 155 @Override 156 public String toString() { 157 return this.getClass().getSimpleName() + " " + this.filter.toString(); 158 } 159 160 @Override 161 public boolean equals(Object obj) { 162 return obj instanceof Filter && areSerializedFieldsEqual((Filter) obj); 163 } 164 165 @Override 166 public int hashCode() { 167 return Objects.hash(this.filter); 168 } 169}