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.ArrayList; 022import java.util.Objects; 023import org.apache.hadoop.hbase.Cell; 024import org.apache.hadoop.hbase.CompareOperator; 025import org.apache.hadoop.hbase.PrivateCellUtil; 026import org.apache.hadoop.hbase.util.Bytes; 027import org.apache.yetus.audience.InterfaceAudience; 028 029import org.apache.hbase.thirdparty.com.google.common.base.Preconditions; 030 031import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 032import org.apache.hadoop.hbase.shaded.protobuf.generated.FilterProtos; 033import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos; 034import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.CompareType; 035 036/** 037 * This is a generic filter to be used to filter by comparison. It takes an operator (equal, 038 * greater, not equal, etc) and a byte [] comparator. 039 * <p> 040 * To filter by row key, use {@link RowFilter}. 041 * <p> 042 * To filter by column family, use {@link FamilyFilter}. 043 * <p> 044 * To filter by column qualifier, use {@link QualifierFilter}. 045 * <p> 046 * To filter by value, use {@link ValueFilter}. 047 * <p> 048 * These filters can be wrapped with {@link SkipFilter} and {@link WhileMatchFilter} to add more 049 * control. 050 * <p> 051 * Multiple filters can be combined using {@link FilterList}. 052 */ 053@InterfaceAudience.Public 054public abstract class CompareFilter extends FilterBase { 055 protected CompareOperator op; 056 protected ByteArrayComparable comparator; 057 058 /** 059 * Constructor. 060 * @param op the compare op for row matching 061 * @param comparator the comparator for row matching 062 */ 063 public CompareFilter(final CompareOperator op, final ByteArrayComparable comparator) { 064 this.op = op; 065 this.comparator = comparator; 066 } 067 068 public CompareOperator getCompareOperator() { 069 return op; 070 } 071 072 /** 073 * @return the comparator 074 */ 075 public ByteArrayComparable getComparator() { 076 return comparator; 077 } 078 079 @Override 080 public boolean filterRowKey(Cell cell) throws IOException { 081 // Impl in FilterBase might do unnecessary copy for Off heap backed Cells. 082 return false; 083 } 084 085 protected boolean compareRow(final CompareOperator op, final ByteArrayComparable comparator, 086 final Cell cell) { 087 if (op == CompareOperator.NO_OP) { 088 return true; 089 } 090 int compareResult = PrivateCellUtil.compareRow(cell, comparator); 091 return compare(op, compareResult); 092 } 093 094 protected boolean compareFamily(final CompareOperator op, final ByteArrayComparable comparator, 095 final Cell cell) { 096 if (op == CompareOperator.NO_OP) { 097 return true; 098 } 099 int compareResult = PrivateCellUtil.compareFamily(cell, comparator); 100 return compare(op, compareResult); 101 } 102 103 protected boolean compareQualifier(final CompareOperator op, final ByteArrayComparable comparator, 104 final Cell cell) { 105 // We do not call through to the non-deprecated method for perf reasons. 106 if (op == CompareOperator.NO_OP) { 107 return true; 108 } 109 int compareResult = PrivateCellUtil.compareQualifier(cell, comparator); 110 return compare(op, compareResult); 111 } 112 113 protected boolean compareValue(final CompareOperator op, final ByteArrayComparable comparator, 114 final Cell cell) { 115 if (op == CompareOperator.NO_OP) { 116 return true; 117 } 118 int compareResult = PrivateCellUtil.compareValue(cell, comparator); 119 return compare(op, compareResult); 120 } 121 122 static boolean compare(final CompareOperator op, int compareResult) { 123 switch (op) { 124 case LESS: 125 return compareResult <= 0; 126 case LESS_OR_EQUAL: 127 return compareResult < 0; 128 case EQUAL: 129 return compareResult != 0; 130 case NOT_EQUAL: 131 return compareResult == 0; 132 case GREATER_OR_EQUAL: 133 return compareResult > 0; 134 case GREATER: 135 return compareResult >= 0; 136 default: 137 throw new RuntimeException("Unknown Compare op " + op.name()); 138 } 139 } 140 141 // returns an array of heterogeneous objects 142 public static ArrayList<Object> extractArguments(ArrayList<byte[]> filterArguments) { 143 Preconditions.checkArgument(filterArguments.size() == 2, "Expected 2 but got: %s", 144 filterArguments.size()); 145 CompareOperator op = ParseFilter.createCompareOperator(filterArguments.get(0)); 146 ByteArrayComparable comparator = 147 ParseFilter.createComparator(ParseFilter.removeQuotesFromByteArray(filterArguments.get(1))); 148 149 if (comparator instanceof RegexStringComparator || comparator instanceof SubstringComparator) { 150 if (op != CompareOperator.EQUAL && op != CompareOperator.NOT_EQUAL) { 151 throw new IllegalArgumentException("A regexstring comparator and substring comparator" 152 + " can only be used with EQUAL and NOT_EQUAL"); 153 } 154 } 155 ArrayList<Object> arguments = new ArrayList<>(2); 156 arguments.add(op); 157 arguments.add(comparator); 158 return arguments; 159 } 160 161 /** 162 * @return A pb instance to represent this instance. 163 */ 164 FilterProtos.CompareFilter convert() { 165 FilterProtos.CompareFilter.Builder builder = FilterProtos.CompareFilter.newBuilder(); 166 HBaseProtos.CompareType compareOp = CompareType.valueOf(this.op.name()); 167 builder.setCompareOp(compareOp); 168 if (this.comparator != null) builder.setComparator(ProtobufUtil.toComparator(this.comparator)); 169 return builder.build(); 170 } 171 172 /** 173 * n * @return true if and only if the fields of the filter that are serialized are equal to the 174 * corresponding fields in other. Used for testing. 175 */ 176 @Override 177 boolean areSerializedFieldsEqual(Filter o) { 178 if (o == this) return true; 179 if (!(o instanceof CompareFilter)) return false; 180 CompareFilter other = (CompareFilter) o; 181 return this.getCompareOperator().equals(other.getCompareOperator()) 182 && (this.getComparator() == other.getComparator() 183 || this.getComparator().areSerializedFieldsEqual(other.getComparator())); 184 } 185 186 @Override 187 public String toString() { 188 return String.format("%s (%s, %s)", this.getClass().getSimpleName(), this.op.name(), 189 Bytes.toStringBinary(this.comparator.getValue())); 190 } 191 192 @Override 193 public boolean equals(Object obj) { 194 return obj instanceof Filter && areSerializedFieldsEqual((Filter) obj); 195 } 196 197 @Override 198 public int hashCode() { 199 return Objects.hash(this.getComparator(), this.getCompareOperator()); 200 } 201}