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.util.ArrayList; 023 024import org.apache.hadoop.hbase.ByteBufferExtendedCell; 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.generated.FilterProtos; 029import org.apache.hadoop.hbase.util.ByteBufferUtils; 030import org.apache.hadoop.hbase.util.Bytes; 031 032import org.apache.hbase.thirdparty.com.google.common.base.Preconditions; 033import org.apache.hbase.thirdparty.com.google.protobuf.InvalidProtocolBufferException; 034import org.apache.hbase.thirdparty.com.google.protobuf.UnsafeByteOperations; 035 036/** 037 * Pass results that have same row prefix. 038 */ 039@InterfaceAudience.Public 040public class PrefixFilter extends FilterBase { 041 protected byte [] prefix = null; 042 protected boolean passedPrefix = false; 043 protected boolean filterRow = true; 044 045 public PrefixFilter(final byte [] prefix) { 046 this.prefix = prefix; 047 } 048 049 public byte[] getPrefix() { 050 return prefix; 051 } 052 053 @Override 054 public boolean filterRowKey(Cell firstRowCell) { 055 if (firstRowCell == null || this.prefix == null) 056 return true; 057 if (filterAllRemaining()) return true; 058 int length = firstRowCell.getRowLength(); 059 if (length < prefix.length) return true; 060 // if they are equal, return false => pass row 061 // else return true, filter row 062 // if we are passed the prefix, set flag 063 int cmp; 064 if (firstRowCell instanceof ByteBufferExtendedCell) { 065 cmp = ByteBufferUtils.compareTo(((ByteBufferExtendedCell) firstRowCell).getRowByteBuffer(), 066 ((ByteBufferExtendedCell) firstRowCell).getRowPosition(), this.prefix.length, 067 this.prefix, 0, this.prefix.length); 068 } else { 069 cmp = Bytes.compareTo(firstRowCell.getRowArray(), firstRowCell.getRowOffset(), 070 this.prefix.length, this.prefix, 0, this.prefix.length); 071 } 072 if ((!isReversed() && cmp > 0) || (isReversed() && cmp < 0)) { 073 passedPrefix = true; 074 } 075 filterRow = (cmp != 0); 076 return filterRow; 077 } 078 079 @Deprecated 080 @Override 081 public ReturnCode filterKeyValue(final Cell c) { 082 return filterCell(c); 083 } 084 085 @Override 086 public ReturnCode filterCell(final Cell c) { 087 if (filterRow) return ReturnCode.NEXT_ROW; 088 return ReturnCode.INCLUDE; 089 } 090 091 @Override 092 public boolean filterRow() { 093 return filterRow; 094 } 095 096 @Override 097 public void reset() { 098 filterRow = true; 099 } 100 101 @Override 102 public boolean filterAllRemaining() { 103 return passedPrefix; 104 } 105 106 public static Filter createFilterFromArguments(ArrayList<byte []> filterArguments) { 107 Preconditions.checkArgument(filterArguments.size() == 1, 108 "Expected 1 but got: %s", filterArguments.size()); 109 byte [] prefix = ParseFilter.removeQuotesFromByteArray(filterArguments.get(0)); 110 return new PrefixFilter(prefix); 111 } 112 113 /** 114 * @return The filter serialized using pb 115 */ 116 @Override 117 public byte [] toByteArray() { 118 FilterProtos.PrefixFilter.Builder builder = 119 FilterProtos.PrefixFilter.newBuilder(); 120 if (this.prefix != null) builder.setPrefix(UnsafeByteOperations.unsafeWrap(this.prefix)); 121 return builder.build().toByteArray(); 122 } 123 124 /** 125 * @param pbBytes A pb serialized {@link PrefixFilter} instance 126 * @return An instance of {@link PrefixFilter} made from <code>bytes</code> 127 * @throws org.apache.hadoop.hbase.exceptions.DeserializationException 128 * @see #toByteArray 129 */ 130 public static PrefixFilter parseFrom(final byte [] pbBytes) 131 throws DeserializationException { 132 FilterProtos.PrefixFilter proto; 133 try { 134 proto = FilterProtos.PrefixFilter.parseFrom(pbBytes); 135 } catch (InvalidProtocolBufferException e) { 136 throw new DeserializationException(e); 137 } 138 return new PrefixFilter(proto.hasPrefix()?proto.getPrefix().toByteArray():null); 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 PrefixFilter)) return false; 150 151 PrefixFilter other = (PrefixFilter)o; 152 return Bytes.equals(this.getPrefix(), other.getPrefix()); 153 } 154 155 @Override 156 public String toString() { 157 return this.getClass().getSimpleName() + " " + Bytes.toStringBinary(this.prefix); 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 Bytes.hashCode(this.getPrefix()); 168 } 169}