1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.filter;
19
20 import org.apache.hadoop.hbase.KeyValue;
21 import org.apache.hadoop.hbase.util.Bytes;
22
23 import java.io.DataOutput;
24 import java.io.IOException;
25 import java.io.DataInput;
26 import java.util.Arrays;
27 import java.util.Comparator;
28 import java.util.TreeSet;
29 import java.util.ArrayList;
30
31
32
33
34
35
36 public class MultipleColumnPrefixFilter extends FilterBase {
37 protected byte [] hint = null;
38 protected TreeSet<byte []> sortedPrefixes = createTreeSet();
39
40 public MultipleColumnPrefixFilter() {
41 super();
42 }
43
44 public MultipleColumnPrefixFilter(final byte [][] prefixes) {
45 if (prefixes != null) {
46 for (int i = 0; i < prefixes.length; i++) {
47 if (!sortedPrefixes.add(prefixes[i]))
48 throw new IllegalArgumentException ("prefixes must be distinct");
49 }
50 }
51 }
52
53 public byte [][] getPrefix() {
54 int count = 0;
55 byte [][] temp = new byte [sortedPrefixes.size()][];
56 for (byte [] prefixes : sortedPrefixes) {
57 temp [count++] = prefixes;
58 }
59 return temp;
60 }
61
62 @Override
63 public ReturnCode filterKeyValue(KeyValue kv) {
64 if (sortedPrefixes.size() == 0 || kv.getBuffer() == null) {
65 return ReturnCode.INCLUDE;
66 } else {
67 return filterColumn(kv.getBuffer(), kv.getQualifierOffset(), kv.getQualifierLength());
68 }
69 }
70
71 public ReturnCode filterColumn(byte[] buffer, int qualifierOffset, int qualifierLength) {
72 byte [] qualifier = Arrays.copyOfRange(buffer, qualifierOffset,
73 qualifierLength + qualifierOffset);
74 TreeSet<byte []> lesserOrEqualPrefixes =
75 (TreeSet<byte []>) sortedPrefixes.headSet(qualifier, true);
76
77 if (lesserOrEqualPrefixes.size() != 0) {
78 byte [] largestPrefixSmallerThanQualifier = lesserOrEqualPrefixes.last();
79
80 if (Bytes.startsWith(qualifier, largestPrefixSmallerThanQualifier)) {
81 return ReturnCode.INCLUDE;
82 }
83
84 if (lesserOrEqualPrefixes.size() == sortedPrefixes.size()) {
85 return ReturnCode.NEXT_ROW;
86 } else {
87 hint = sortedPrefixes.higher(largestPrefixSmallerThanQualifier);
88 return ReturnCode.SEEK_NEXT_USING_HINT;
89 }
90 } else {
91 hint = sortedPrefixes.first();
92 return ReturnCode.SEEK_NEXT_USING_HINT;
93 }
94 }
95
96 public static Filter createFilterFromArguments(ArrayList<byte []> filterArguments) {
97 byte [][] prefixes = new byte [filterArguments.size()][];
98 for (int i = 0 ; i < filterArguments.size(); i++) {
99 byte [] columnPrefix = ParseFilter.removeQuotesFromByteArray(filterArguments.get(i));
100 prefixes[i] = columnPrefix;
101 }
102 return new MultipleColumnPrefixFilter(prefixes);
103 }
104
105 public void write(DataOutput out) throws IOException {
106 out.writeInt(sortedPrefixes.size());
107 for (byte [] element : sortedPrefixes) {
108 Bytes.writeByteArray(out, element);
109 }
110 }
111
112 public void readFields(DataInput in) throws IOException {
113 int x = in.readInt();
114 this.sortedPrefixes = createTreeSet();
115 for (int j = 0; j < x; j++) {
116 sortedPrefixes.add(Bytes.readByteArray(in));
117 }
118 }
119
120 public KeyValue getNextKeyHint(KeyValue kv) {
121 return KeyValue.createFirstOnRow(
122 kv.getBuffer(), kv.getRowOffset(), kv.getRowLength(), kv.getBuffer(),
123 kv.getFamilyOffset(), kv.getFamilyLength(), hint, 0, hint.length);
124 }
125
126 public TreeSet<byte []> createTreeSet() {
127 return new TreeSet<byte []>(new Comparator<Object>() {
128 @Override
129 public int compare (Object o1, Object o2) {
130 if (o1 == null || o2 == null)
131 throw new IllegalArgumentException ("prefixes can't be null");
132
133 byte [] b1 = (byte []) o1;
134 byte [] b2 = (byte []) o2;
135 return Bytes.compareTo (b1, 0, b1.length, b2, 0, b2.length);
136 }
137 });
138 }
139 }