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 public byte [] toByteArray() {
181 FilterProtos.ColumnRangeFilter.Builder builder =
182 FilterProtos.ColumnRangeFilter.newBuilder();
183 if (this.minColumn != null) builder.setMinColumn(ByteStringer.wrap(this.minColumn));
184 builder.setMinColumnInclusive(this.minColumnInclusive);
185 if (this.maxColumn != null) builder.setMaxColumn(ByteStringer.wrap(this.maxColumn));
186 builder.setMaxColumnInclusive(this.maxColumnInclusive);
187 return builder.build().toByteArray();
188 }
189
190
191
192
193
194
195
196 public static ColumnRangeFilter parseFrom(final byte [] pbBytes)
197 throws DeserializationException {
198 FilterProtos.ColumnRangeFilter proto;
199 try {
200 proto = FilterProtos.ColumnRangeFilter.parseFrom(pbBytes);
201 } catch (InvalidProtocolBufferException e) {
202 throw new DeserializationException(e);
203 }
204 return new ColumnRangeFilter(proto.hasMinColumn()?proto.getMinColumn().toByteArray():null,
205 proto.getMinColumnInclusive(),proto.hasMaxColumn()?proto.getMaxColumn().toByteArray():null,
206 proto.getMaxColumnInclusive());
207 }
208
209
210
211
212
213
214 boolean areSerializedFieldsEqual(Filter o) {
215 if (o == this) return true;
216 if (!(o instanceof ColumnRangeFilter)) return false;
217
218 ColumnRangeFilter other = (ColumnRangeFilter)o;
219 return Bytes.equals(this.getMinColumn(),other.getMinColumn())
220 && this.getMinColumnInclusive() == other.getMinColumnInclusive()
221 && Bytes.equals(this.getMaxColumn(), other.getMaxColumn())
222 && this.getMaxColumnInclusive() == other.getMaxColumnInclusive();
223 }
224
225 @Override
226 public Cell getNextCellHint(Cell kv) {
227 return KeyValueUtil.createFirstOnRow(kv.getRowArray(), kv.getRowOffset(), kv
228 .getRowLength(), kv.getFamilyArray(), kv.getFamilyOffset(), kv
229 .getFamilyLength(), this.minColumn, 0, len(this.minColumn));
230
231 }
232
233 @Override
234 public String toString() {
235 return this.getClass().getSimpleName() + " "
236 + (this.minColumnInclusive ? "[" : "(") + Bytes.toStringBinary(this.minColumn)
237 + ", " + Bytes.toStringBinary(this.maxColumn)
238 + (this.maxColumnInclusive ? "]" : ")");
239 }
240 }