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