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