View Javadoc

1   /*
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  
20  package org.apache.hadoop.hbase.filter;
21  
22  import com.google.common.base.Preconditions;
23  import org.apache.hadoop.hbase.util.ByteStringer;
24  import com.google.protobuf.InvalidProtocolBufferException;
25  
26  import org.apache.hadoop.hbase.classification.InterfaceAudience;
27  import org.apache.hadoop.hbase.classification.InterfaceStability;
28  import org.apache.hadoop.hbase.Cell;
29  import org.apache.hadoop.hbase.exceptions.DeserializationException;
30  import org.apache.hadoop.hbase.protobuf.generated.FilterProtos;
31  import org.apache.hadoop.hbase.util.Bytes;
32  
33  import java.util.ArrayList;
34  
35  /**
36   * Pass results that have same row prefix.
37   */
38  @InterfaceAudience.Public
39  @InterfaceStability.Stable
40  public class PrefixFilter extends FilterBase {
41    public static final int MAX_SKIPPED_COMPARE_ROW_NUM = 100;
42    protected byte [] prefix = null;
43    protected boolean passedPrefix = false;
44    protected boolean filterRow = true;
45    protected int skippedCompareRows = 0;
46  
47    public PrefixFilter(final byte [] prefix) {
48      this.prefix = prefix;
49    }
50  
51    public byte[] getPrefix() {
52      return prefix;
53    }
54  
55    public boolean filterRowKey(byte[] buffer, int offset, int length) {
56      if (buffer == null || this.prefix == null)
57        return true;
58      if (length < prefix.length && skippedCompareRows < MAX_SKIPPED_COMPARE_ROW_NUM) {
59        ++skippedCompareRows;
60        return true;
61      }   
62      skippedCompareRows = 0;
63      
64      // if they are equal, return false => pass row
65      // else return true, filter row
66      // if we are passed the prefix, set flag
67      int cmp = Bytes.compareTo(buffer, offset, this.prefix.length, this.prefix, 0,
68          this.prefix.length);
69      if ((!isReversed() && cmp > 0) || (isReversed() && cmp < 0)) {
70        passedPrefix = true;
71      }
72      filterRow = (cmp != 0);
73      return filterRow;
74    }
75  
76    @Override
77    public ReturnCode filterKeyValue(Cell v) {
78      if (filterRow) return ReturnCode.NEXT_ROW;
79      return ReturnCode.INCLUDE;
80    }
81  
82    public boolean filterRow() {
83      return filterRow;
84    }
85  
86    public void reset() {
87      filterRow = true;
88    }
89  
90    public boolean filterAllRemaining() {
91      return passedPrefix;
92    }
93  
94    public static Filter createFilterFromArguments(ArrayList<byte []> filterArguments) {
95      Preconditions.checkArgument(filterArguments.size() == 1,
96                                  "Expected 1 but got: %s", filterArguments.size());
97      byte [] prefix = ParseFilter.removeQuotesFromByteArray(filterArguments.get(0));
98      return new PrefixFilter(prefix);
99    }
100 
101   /**
102    * @return The filter serialized using pb
103    */
104   public byte [] toByteArray() {
105     FilterProtos.PrefixFilter.Builder builder =
106       FilterProtos.PrefixFilter.newBuilder();
107     if (this.prefix != null) builder.setPrefix(ByteStringer.wrap(this.prefix));
108     return builder.build().toByteArray();
109   }
110 
111   /**
112    * @param pbBytes A pb serialized {@link PrefixFilter} instance
113    * @return An instance of {@link PrefixFilter} made from <code>bytes</code>
114    * @throws org.apache.hadoop.hbase.exceptions.DeserializationException
115    * @see #toByteArray
116    */
117   public static PrefixFilter parseFrom(final byte [] pbBytes)
118   throws DeserializationException {
119     FilterProtos.PrefixFilter proto;
120     try {
121       proto = FilterProtos.PrefixFilter.parseFrom(pbBytes);
122     } catch (InvalidProtocolBufferException e) {
123       throw new DeserializationException(e);
124     }
125     return new PrefixFilter(proto.hasPrefix()?proto.getPrefix().toByteArray():null);
126   }
127 
128   /**
129    * @param other
130    * @return true if and only if the fields of the filter that are serialized
131    * are equal to the corresponding fields in other.  Used for testing.
132    */
133   boolean areSerializedFieldsEqual(Filter o) {
134     if (o == this) return true;
135     if (!(o instanceof PrefixFilter)) return false;
136 
137     PrefixFilter other = (PrefixFilter)o;
138     return Bytes.equals(this.getPrefix(), other.getPrefix());
139   }
140 
141   @Override
142   public String toString() {
143     return this.getClass().getSimpleName() + " " + Bytes.toStringBinary(this.prefix);
144   }
145 }