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 /** Returns the comparator */ 073 public ByteArrayComparable getComparator() { 074 return comparator; 075 } 076 077 @Override 078 public boolean filterRowKey(Cell cell) throws IOException { 079 // Impl in FilterBase might do unnecessary copy for Off heap backed Cells. 080 return false; 081 } 082 083 protected boolean compareRow(final CompareOperator op, final ByteArrayComparable comparator, 084 final Cell cell) { 085 if (op == CompareOperator.NO_OP) { 086 return true; 087 } 088 int compareResult = PrivateCellUtil.compareRow(cell, comparator); 089 return compare(op, compareResult); 090 } 091 092 protected boolean compareFamily(final CompareOperator op, final ByteArrayComparable comparator, 093 final Cell cell) { 094 if (op == CompareOperator.NO_OP) { 095 return true; 096 } 097 int compareResult = PrivateCellUtil.compareFamily(cell, comparator); 098 return compare(op, compareResult); 099 } 100 101 protected boolean compareQualifier(final CompareOperator op, final ByteArrayComparable comparator, 102 final Cell cell) { 103 // We do not call through to the non-deprecated method for perf reasons. 104 if (op == CompareOperator.NO_OP) { 105 return true; 106 } 107 int compareResult = PrivateCellUtil.compareQualifier(cell, comparator); 108 return compare(op, compareResult); 109 } 110 111 protected boolean compareValue(final CompareOperator op, final ByteArrayComparable comparator, 112 final Cell cell) { 113 if (op == CompareOperator.NO_OP) { 114 return true; 115 } 116 int compareResult = PrivateCellUtil.compareValue(cell, comparator); 117 return compare(op, compareResult); 118 } 119 120 static boolean compare(final CompareOperator op, int compareResult) { 121 switch (op) { 122 case LESS: 123 return compareResult <= 0; 124 case LESS_OR_EQUAL: 125 return compareResult < 0; 126 case EQUAL: 127 return compareResult != 0; 128 case NOT_EQUAL: 129 return compareResult == 0; 130 case GREATER_OR_EQUAL: 131 return compareResult > 0; 132 case GREATER: 133 return compareResult >= 0; 134 default: 135 throw new RuntimeException("Unknown Compare op " + op.name()); 136 } 137 } 138 139 /** Returns an array of heterogeneous objects */ 140 public static ArrayList<Object> extractArguments(ArrayList<byte[]> filterArguments) { 141 Preconditions.checkArgument(filterArguments.size() == 2, "Expected 2 but got: %s", 142 filterArguments.size()); 143 CompareOperator op = ParseFilter.createCompareOperator(filterArguments.get(0)); 144 ByteArrayComparable comparator = 145 ParseFilter.createComparator(ParseFilter.removeQuotesFromByteArray(filterArguments.get(1))); 146 147 if (comparator instanceof RegexStringComparator || comparator instanceof SubstringComparator) { 148 if (op != CompareOperator.EQUAL && op != CompareOperator.NOT_EQUAL) { 149 throw new IllegalArgumentException("A regexstring comparator and substring comparator" 150 + " can only be used with EQUAL and NOT_EQUAL"); 151 } 152 } 153 ArrayList<Object> arguments = new ArrayList<>(2); 154 arguments.add(op); 155 arguments.add(comparator); 156 return arguments; 157 } 158 159 /** Returns A pb instance to represent this instance. */ 160 FilterProtos.CompareFilter convert() { 161 FilterProtos.CompareFilter.Builder builder = FilterProtos.CompareFilter.newBuilder(); 162 HBaseProtos.CompareType compareOp = CompareType.valueOf(this.op.name()); 163 builder.setCompareOp(compareOp); 164 if (this.comparator != null) builder.setComparator(ProtobufUtil.toComparator(this.comparator)); 165 return builder.build(); 166 } 167 168 /** 169 * Returns true if and only if the fields of the filter that are serialized are equal to the 170 * corresponding fields in other. Used for testing. 171 */ 172 @Override 173 boolean areSerializedFieldsEqual(Filter o) { 174 if (o == this) { 175 return true; 176 } 177 if (!(o instanceof CompareFilter)) { 178 return false; 179 } 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}