1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.hadoop.hbase.filter;
21
22 import static org.apache.hadoop.hbase.util.Bytes.len;
23
24 import com.google.common.base.Preconditions;
25 import org.apache.hadoop.hbase.util.ByteStringer;
26 import com.google.protobuf.InvalidProtocolBufferException;
27
28 import org.apache.hadoop.hbase.classification.InterfaceAudience;
29 import org.apache.hadoop.hbase.classification.InterfaceStability;
30 import org.apache.hadoop.hbase.Cell;
31 import org.apache.hadoop.hbase.KeyValueUtil;
32 import org.apache.hadoop.hbase.exceptions.DeserializationException;
33 import org.apache.hadoop.hbase.protobuf.generated.FilterProtos;
34 import org.apache.hadoop.hbase.util.Bytes;
35
36 import java.util.ArrayList;
37
38
39
40
41
42
43
44
45
46
47
48
49
50 @InterfaceAudience.Public
51 @InterfaceStability.Stable
52 public class ColumnRangeFilter extends FilterBase {
53 protected byte[] minColumn = null;
54 protected boolean minColumnInclusive = true;
55 protected byte[] maxColumn = null;
56 protected boolean maxColumnInclusive = false;
57
58
59
60
61
62
63
64
65
66
67
68 public ColumnRangeFilter(final byte[] minColumn, boolean minColumnInclusive,
69 final byte[] maxColumn, boolean maxColumnInclusive) {
70 this.minColumn = minColumn;
71 this.minColumnInclusive = minColumnInclusive;
72 this.maxColumn = maxColumn;
73 this.maxColumnInclusive = maxColumnInclusive;
74 }
75
76
77
78
79 public boolean isMinColumnInclusive() {
80 return minColumnInclusive;
81 }
82
83
84
85
86 public boolean isMaxColumnInclusive() {
87 return maxColumnInclusive;
88 }
89
90
91
92
93 public byte[] getMinColumn() {
94 return this.minColumn;
95 }
96
97
98
99
100 public boolean getMinColumnInclusive() {
101 return this.minColumnInclusive;
102 }
103
104
105
106
107 public byte[] getMaxColumn() {
108 return this.maxColumn;
109 }
110
111
112
113
114 public boolean getMaxColumnInclusive() {
115 return this.maxColumnInclusive;
116 }
117
118 @Override
119 public ReturnCode filterKeyValue(Cell kv) {
120
121 byte[] buffer = kv.getQualifierArray();
122 int qualifierOffset = kv.getQualifierOffset();
123 int qualifierLength = kv.getQualifierLength();
124 int cmpMin = 1;
125
126 if (this.minColumn != null) {
127 cmpMin = Bytes.compareTo(buffer, qualifierOffset, qualifierLength,
128 this.minColumn, 0, this.minColumn.length);
129 }
130
131 if (cmpMin < 0) {
132 return ReturnCode.SEEK_NEXT_USING_HINT;
133 }
134
135 if (!this.minColumnInclusive && cmpMin == 0) {
136 return ReturnCode.NEXT_COL;
137 }
138
139 if (this.maxColumn == null) {
140 return ReturnCode.INCLUDE;
141 }
142
143 int cmpMax = Bytes.compareTo(buffer, qualifierOffset, qualifierLength,
144 this.maxColumn, 0, this.maxColumn.length);
145
146 if ((this.maxColumnInclusive && cmpMax <= 0) ||
147 (!this.maxColumnInclusive && cmpMax < 0)) {
148 return ReturnCode.INCLUDE;
149 }
150
151 return ReturnCode.NEXT_ROW;
152 }
153
154
155
156 @Override
157 public Cell transformCell(Cell v) {
158 return v;
159 }
160
161 public static Filter createFilterFromArguments(ArrayList<byte []> filterArguments) {
162 Preconditions.checkArgument(filterArguments.size() == 4,
163 "Expected 4 but got: %s", filterArguments.size());
164 byte [] minColumn = ParseFilter.removeQuotesFromByteArray(filterArguments.get(0));
165 boolean minColumnInclusive = ParseFilter.convertByteArrayToBoolean(filterArguments.get(1));
166 byte [] maxColumn = ParseFilter.removeQuotesFromByteArray(filterArguments.get(2));
167 boolean maxColumnInclusive = ParseFilter.convertByteArrayToBoolean(filterArguments.get(3));
168
169 if (minColumn.length == 0)
170 minColumn = null;
171 if (maxColumn.length == 0)
172 maxColumn = null;
173 return new ColumnRangeFilter(minColumn, minColumnInclusive,
174 maxColumn, maxColumnInclusive);
175 }
176
177
178
179
180 @Override
181 public byte [] toByteArray() {
182 FilterProtos.ColumnRangeFilter.Builder builder =
183 FilterProtos.ColumnRangeFilter.newBuilder();
184 if (this.minColumn != null) builder.setMinColumn(ByteStringer.wrap(this.minColumn));
185 builder.setMinColumnInclusive(this.minColumnInclusive);
186 if (this.maxColumn != null) builder.setMaxColumn(ByteStringer.wrap(this.maxColumn));
187 builder.setMaxColumnInclusive(this.maxColumnInclusive);
188 return builder.build().toByteArray();
189 }
190
191
192
193
194
195
196
197 public static ColumnRangeFilter parseFrom(final byte [] pbBytes)
198 throws DeserializationException {
199 FilterProtos.ColumnRangeFilter proto;
200 try {
201 proto = FilterProtos.ColumnRangeFilter.parseFrom(pbBytes);
202 } catch (InvalidProtocolBufferException e) {
203 throw new DeserializationException(e);
204 }
205 return new ColumnRangeFilter(proto.hasMinColumn()?proto.getMinColumn().toByteArray():null,
206 proto.getMinColumnInclusive(),proto.hasMaxColumn()?proto.getMaxColumn().toByteArray():null,
207 proto.getMaxColumnInclusive());
208 }
209
210
211
212
213
214
215 @Override
216 boolean areSerializedFieldsEqual(Filter o) {
217 if (o == this) {
218 return true;
219 }
220 if (!(o instanceof ColumnRangeFilter)) {
221 return false;
222 }
223 ColumnRangeFilter other = (ColumnRangeFilter) o;
224 return Bytes.equals(this.getMinColumn(), other.getMinColumn())
225 && this.getMinColumnInclusive() == other.getMinColumnInclusive()
226 && Bytes.equals(this.getMaxColumn(), other.getMaxColumn())
227 && this.getMaxColumnInclusive() == other.getMaxColumnInclusive();
228 }
229
230 @Override
231 public Cell getNextCellHint(Cell kv) {
232 return KeyValueUtil.createFirstOnRow(kv.getRowArray(), kv.getRowOffset(), kv
233 .getRowLength(), kv.getFamilyArray(), kv.getFamilyOffset(), kv
234 .getFamilyLength(), this.minColumn, 0, len(this.minColumn));
235
236 }
237
238 @Override
239 public String toString() {
240 return this.getClass().getSimpleName() + " "
241 + (this.minColumnInclusive ? "[" : "(") + Bytes.toStringBinary(this.minColumn)
242 + ", " + Bytes.toStringBinary(this.maxColumn)
243 + (this.maxColumnInclusive ? "]" : ")");
244 }
245 }