View Javadoc

1   /*
2    * Copyright 2010 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  
21  package org.apache.hadoop.hbase.filter;
22  
23  import org.apache.hadoop.hbase.KeyValue;
24  import org.apache.hadoop.hbase.util.Bytes;
25  
26  import java.io.DataOutput;
27  import java.io.IOException;
28  import java.io.DataInput;
29  import java.util.ArrayList;
30  
31  import com.google.common.base.Preconditions;
32  
33  /**
34   * This filter is used for selecting only those keys with columns that matches
35   * a particular prefix. For example, if prefix is 'an', it will pass keys with
36   * columns like 'and', 'anti' but not keys with columns like 'ball', 'act'.
37   */
38  public class ColumnPrefixFilter extends FilterBase {
39    protected byte [] prefix = null;
40  
41    public ColumnPrefixFilter() {
42      super();
43    }
44  
45    public ColumnPrefixFilter(final byte [] prefix) {
46      this.prefix = prefix;
47    }
48  
49    public byte[] getPrefix() {
50      return prefix;
51    }
52  
53    @Override
54    public ReturnCode filterKeyValue(KeyValue kv) {
55      if (this.prefix == null || kv.getBuffer() == null) {
56        return ReturnCode.INCLUDE;
57      } else {
58        return filterColumn(kv.getBuffer(), kv.getQualifierOffset(), kv.getQualifierLength());
59      }
60    }
61  
62    public ReturnCode filterColumn(byte[] buffer, int qualifierOffset, int qualifierLength) {
63      if (qualifierLength < prefix.length) {
64        int cmp = Bytes.compareTo(buffer, qualifierOffset, qualifierLength, this.prefix, 0,
65            qualifierLength);
66        if (cmp <= 0) {
67          return ReturnCode.SEEK_NEXT_USING_HINT;
68        } else {
69          return ReturnCode.NEXT_ROW;
70        }
71      } else {
72        int cmp = Bytes.compareTo(buffer, qualifierOffset, this.prefix.length, this.prefix, 0,
73            this.prefix.length);
74        if (cmp < 0) {
75          return ReturnCode.SEEK_NEXT_USING_HINT;
76        } else if (cmp > 0) {
77          return ReturnCode.NEXT_ROW;
78        } else {
79          return ReturnCode.INCLUDE;
80        }
81      }
82    }
83  
84    public static Filter createFilterFromArguments(ArrayList<byte []> filterArguments) {
85      Preconditions.checkArgument(filterArguments.size() == 1,
86                                  "Expected 1 but got: %s", filterArguments.size());
87      byte [] columnPrefix = ParseFilter.removeQuotesFromByteArray(filterArguments.get(0));
88      return new ColumnPrefixFilter(columnPrefix);
89    }
90  
91    public void write(DataOutput out) throws IOException {
92      Bytes.writeByteArray(out, this.prefix);
93    }
94  
95    public void readFields(DataInput in) throws IOException {
96      this.prefix = Bytes.readByteArray(in);
97    }
98  
99    public KeyValue getNextKeyHint(KeyValue kv) {
100     return KeyValue.createFirstOnRow(
101         kv.getBuffer(), kv.getRowOffset(), kv.getRowLength(), kv.getBuffer(),
102         kv.getFamilyOffset(), kv.getFamilyLength(), prefix, 0, prefix.length);
103   }
104 
105   @Override
106   public String toString() {
107     return this.getClass().getSimpleName() + " " + Bytes.toStringBinary(this.prefix);
108   }
109 }