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 com.google.protobuf.ByteString;
24  import com.google.protobuf.InvalidProtocolBufferException;
25  import org.apache.hadoop.classification.InterfaceAudience;
26  import org.apache.hadoop.classification.InterfaceStability;
27  import org.apache.hadoop.hbase.KeyValue;
28  import org.apache.hadoop.hbase.exceptions.DeserializationException;
29  import org.apache.hadoop.hbase.protobuf.generated.FilterProtos;
30  import org.apache.hadoop.hbase.util.Bytes;
31  
32  import java.util.ArrayList;
33  
34  /**
35   * This filter is used for selecting only those keys with columns that matches
36   * a particular prefix. For example, if prefix is 'an', it will pass keys with
37   * columns like 'and', 'anti' but not keys with columns like 'ball', 'act'.
38   */
39  @InterfaceAudience.Public
40  @InterfaceStability.Stable
41  public class ColumnPrefixFilter extends FilterBase {
42    protected byte [] prefix = null;
43  
44    public ColumnPrefixFilter(final byte [] prefix) {
45      this.prefix = prefix;
46    }
47  
48    public byte[] getPrefix() {
49      return prefix;
50    }
51  
52    @Override
53    public ReturnCode filterKeyValue(KeyValue kv) {
54      if (this.prefix == null || kv.getBuffer() == null) {
55        return ReturnCode.INCLUDE;
56      } else {
57        return filterColumn(kv.getBuffer(), kv.getQualifierOffset(), kv.getQualifierLength());
58      }
59    }
60  
61    public ReturnCode filterColumn(byte[] buffer, int qualifierOffset, int qualifierLength) {
62      if (qualifierLength < prefix.length) {
63        int cmp = Bytes.compareTo(buffer, qualifierOffset, qualifierLength, this.prefix, 0,
64            qualifierLength);
65        if (cmp <= 0) {
66          return ReturnCode.SEEK_NEXT_USING_HINT;
67        } else {
68          return ReturnCode.NEXT_ROW;
69        }
70      } else {
71        int cmp = Bytes.compareTo(buffer, qualifierOffset, this.prefix.length, this.prefix, 0,
72            this.prefix.length);
73        if (cmp < 0) {
74          return ReturnCode.SEEK_NEXT_USING_HINT;
75        } else if (cmp > 0) {
76          return ReturnCode.NEXT_ROW;
77        } else {
78          return ReturnCode.INCLUDE;
79        }
80      }
81    }
82  
83    public static Filter createFilterFromArguments(ArrayList<byte []> filterArguments) {
84      Preconditions.checkArgument(filterArguments.size() == 1,
85                                  "Expected 1 but got: %s", filterArguments.size());
86      byte [] columnPrefix = ParseFilter.removeQuotesFromByteArray(filterArguments.get(0));
87      return new ColumnPrefixFilter(columnPrefix);
88    }
89  
90    /**
91     * @return The filter serialized using pb
92     */
93    public byte [] toByteArray() {
94      FilterProtos.ColumnPrefixFilter.Builder builder =
95        FilterProtos.ColumnPrefixFilter.newBuilder();
96      if (this.prefix != null) builder.setPrefix(ByteString.copyFrom(this.prefix));
97      return builder.build().toByteArray();
98    }
99  
100   /**
101    * @param pbBytes A pb serialized {@link ColumnPrefixFilter} instance
102    * @return An instance of {@link ColumnPrefixFilter} made from <code>bytes</code>
103    * @throws org.apache.hadoop.hbase.exceptions.DeserializationException
104    * @see #toByteArray
105    */
106   public static ColumnPrefixFilter parseFrom(final byte [] pbBytes)
107   throws DeserializationException {
108     FilterProtos.ColumnPrefixFilter proto;
109     try {
110       proto = FilterProtos.ColumnPrefixFilter.parseFrom(pbBytes);
111     } catch (InvalidProtocolBufferException e) {
112       throw new DeserializationException(e);
113     }
114     return new ColumnPrefixFilter(proto.getPrefix().toByteArray());
115   }
116 
117   /**
118    * @param other
119    * @return true if and only if the fields of the filter that are serialized
120    * are equal to the corresponding fields in other.  Used for testing.
121    */
122   boolean areSerializedFieldsEqual(Filter o) {
123    if (o == this) return true;
124    if (!(o instanceof ColumnPrefixFilter)) return false;
125 
126    ColumnPrefixFilter other = (ColumnPrefixFilter)o;
127     return Bytes.equals(this.getPrefix(), other.getPrefix());
128   }
129 
130   public KeyValue getNextKeyHint(KeyValue kv) {
131     return KeyValue.createFirstOnRow(
132         kv.getBuffer(), kv.getRowOffset(), kv.getRowLength(), kv.getBuffer(),
133         kv.getFamilyOffset(), kv.getFamilyLength(), prefix, 0, prefix.length);
134   }
135 
136   @Override
137   public String toString() {
138     return this.getClass().getSimpleName() + " " + Bytes.toStringBinary(this.prefix);
139   }
140 }