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 java.io.IOException;
21 import java.util.ArrayList;
22 import java.util.Comparator;
23 import java.util.TreeSet;
24
25 import org.apache.hadoop.hbase.Cell;
26 import org.apache.hadoop.hbase.CellUtil;
27 import org.apache.hadoop.hbase.classification.InterfaceAudience;
28 import org.apache.hadoop.hbase.classification.InterfaceStability;
29 import org.apache.hadoop.hbase.exceptions.DeserializationException;
30 import org.apache.hadoop.hbase.protobuf.generated.FilterProtos;
31 import org.apache.hadoop.hbase.util.ByteStringer;
32 import org.apache.hadoop.hbase.util.Bytes;
33
34 import com.google.protobuf.InvalidProtocolBufferException;
35
36
37
38
39
40
41 @InterfaceAudience.Public
42 @InterfaceStability.Stable
43 public class MultipleColumnPrefixFilter extends FilterBase {
44 protected byte [] hint = null;
45 protected TreeSet<byte []> sortedPrefixes = createTreeSet();
46 private final static int MAX_LOG_PREFIXES = 5;
47
48 public MultipleColumnPrefixFilter(final byte [][] prefixes) {
49 if (prefixes != null) {
50 for (int i = 0; i < prefixes.length; i++) {
51 if (!sortedPrefixes.add(prefixes[i]))
52 throw new IllegalArgumentException ("prefixes must be distinct");
53 }
54 }
55 }
56
57 public byte [][] getPrefix() {
58 int count = 0;
59 byte [][] temp = new byte [sortedPrefixes.size()][];
60 for (byte [] prefixes : sortedPrefixes) {
61 temp [count++] = prefixes;
62 }
63 return temp;
64 }
65
66 @Override
67 public boolean filterRowKey(Cell cell) throws IOException {
68
69 return false;
70 }
71
72 @Override
73 public ReturnCode filterKeyValue(Cell kv) {
74 if (sortedPrefixes.size() == 0) {
75 return ReturnCode.INCLUDE;
76 } else {
77 return filterColumn(kv);
78 }
79 }
80
81 public ReturnCode filterColumn(Cell cell) {
82 byte [] qualifier = CellUtil.cloneQualifier(cell);
83 TreeSet<byte []> lesserOrEqualPrefixes =
84 (TreeSet<byte []>) sortedPrefixes.headSet(qualifier, true);
85
86 if (lesserOrEqualPrefixes.size() != 0) {
87 byte [] largestPrefixSmallerThanQualifier = lesserOrEqualPrefixes.last();
88
89 if (Bytes.startsWith(qualifier, largestPrefixSmallerThanQualifier)) {
90 return ReturnCode.INCLUDE;
91 }
92
93 if (lesserOrEqualPrefixes.size() == sortedPrefixes.size()) {
94 return ReturnCode.NEXT_ROW;
95 } else {
96 hint = sortedPrefixes.higher(largestPrefixSmallerThanQualifier);
97 return ReturnCode.SEEK_NEXT_USING_HINT;
98 }
99 } else {
100 hint = sortedPrefixes.first();
101 return ReturnCode.SEEK_NEXT_USING_HINT;
102 }
103 }
104
105 public static Filter createFilterFromArguments(ArrayList<byte []> filterArguments) {
106 byte [][] prefixes = new byte [filterArguments.size()][];
107 for (int i = 0 ; i < filterArguments.size(); i++) {
108 byte [] columnPrefix = ParseFilter.removeQuotesFromByteArray(filterArguments.get(i));
109 prefixes[i] = columnPrefix;
110 }
111 return new MultipleColumnPrefixFilter(prefixes);
112 }
113
114
115
116
117 public byte [] toByteArray() {
118 FilterProtos.MultipleColumnPrefixFilter.Builder builder =
119 FilterProtos.MultipleColumnPrefixFilter.newBuilder();
120 for (byte [] element : sortedPrefixes) {
121 if (element != null) builder.addSortedPrefixes(ByteStringer.wrap(element));
122 }
123 return builder.build().toByteArray();
124 }
125
126
127
128
129
130
131
132 public static MultipleColumnPrefixFilter parseFrom(final byte [] pbBytes)
133 throws DeserializationException {
134 FilterProtos.MultipleColumnPrefixFilter proto;
135 try {
136 proto = FilterProtos.MultipleColumnPrefixFilter.parseFrom(pbBytes);
137 } catch (InvalidProtocolBufferException e) {
138 throw new DeserializationException(e);
139 }
140 int numPrefixes = proto.getSortedPrefixesCount();
141 byte [][] prefixes = new byte[numPrefixes][];
142 for (int i = 0; i < numPrefixes; ++i) {
143 prefixes[i] = proto.getSortedPrefixes(i).toByteArray();
144 }
145
146 return new MultipleColumnPrefixFilter(prefixes);
147 }
148
149
150
151
152
153
154 boolean areSerializedFieldsEqual(Filter o) {
155 if (o == this) return true;
156 if (!(o instanceof MultipleColumnPrefixFilter)) return false;
157
158 MultipleColumnPrefixFilter other = (MultipleColumnPrefixFilter)o;
159 return this.sortedPrefixes.equals(other.sortedPrefixes);
160 }
161
162 @Override
163 public Cell getNextCellHint(Cell cell) {
164 return CellUtil.createFirstOnRowCol(cell, hint, 0, hint.length);
165 }
166
167 public TreeSet<byte []> createTreeSet() {
168 return new TreeSet<byte []>(new Comparator<Object>() {
169 @Override
170 public int compare (Object o1, Object o2) {
171 if (o1 == null || o2 == null)
172 throw new IllegalArgumentException ("prefixes can't be null");
173
174 byte [] b1 = (byte []) o1;
175 byte [] b2 = (byte []) o2;
176 return Bytes.compareTo (b1, 0, b1.length, b2, 0, b2.length);
177 }
178 });
179 }
180
181 @Override
182 public String toString() {
183 return toString(MAX_LOG_PREFIXES);
184 }
185
186 protected String toString(int maxPrefixes) {
187 StringBuilder prefixes = new StringBuilder();
188
189 int count = 0;
190 for (byte[] ba : this.sortedPrefixes) {
191 if (count >= maxPrefixes) {
192 break;
193 }
194 ++count;
195 prefixes.append(Bytes.toStringBinary(ba));
196 if (count < this.sortedPrefixes.size() && count < maxPrefixes) {
197 prefixes.append(", ");
198 }
199 }
200
201 return String.format("%s (%d/%d): [%s]", this.getClass().getSimpleName(),
202 count, this.sortedPrefixes.size(), prefixes.toString());
203 }
204 }