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