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.classification.InterfaceAudience;
29 import org.apache.hadoop.classification.InterfaceStability;
30 import org.apache.hadoop.hbase.Cell;
31 import org.apache.hadoop.hbase.KeyValue;
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.SKIP;
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 public static Filter createFilterFromArguments(ArrayList<byte []> filterArguments) {
155 Preconditions.checkArgument(filterArguments.size() == 4,
156 "Expected 4 but got: %s", filterArguments.size());
157 byte [] minColumn = ParseFilter.removeQuotesFromByteArray(filterArguments.get(0));
158 boolean minColumnInclusive = ParseFilter.convertByteArrayToBoolean(filterArguments.get(1));
159 byte [] maxColumn = ParseFilter.removeQuotesFromByteArray(filterArguments.get(2));
160 boolean maxColumnInclusive = ParseFilter.convertByteArrayToBoolean(filterArguments.get(3));
161
162 if (minColumn.length == 0)
163 minColumn = null;
164 if (maxColumn.length == 0)
165 maxColumn = null;
166 return new ColumnRangeFilter(minColumn, minColumnInclusive,
167 maxColumn, maxColumnInclusive);
168 }
169
170
171
172
173 public byte [] toByteArray() {
174 FilterProtos.ColumnRangeFilter.Builder builder =
175 FilterProtos.ColumnRangeFilter.newBuilder();
176 if (this.minColumn != null) builder.setMinColumn(ByteStringer.wrap(this.minColumn));
177 builder.setMinColumnInclusive(this.minColumnInclusive);
178 if (this.maxColumn != null) builder.setMaxColumn(ByteStringer.wrap(this.maxColumn));
179 builder.setMaxColumnInclusive(this.maxColumnInclusive);
180 return builder.build().toByteArray();
181 }
182
183
184
185
186
187
188
189 public static ColumnRangeFilter parseFrom(final byte [] pbBytes)
190 throws DeserializationException {
191 FilterProtos.ColumnRangeFilter proto;
192 try {
193 proto = FilterProtos.ColumnRangeFilter.parseFrom(pbBytes);
194 } catch (InvalidProtocolBufferException e) {
195 throw new DeserializationException(e);
196 }
197 return new ColumnRangeFilter(proto.hasMinColumn()?proto.getMinColumn().toByteArray():null,
198 proto.getMinColumnInclusive(),proto.hasMaxColumn()?proto.getMaxColumn().toByteArray():null,
199 proto.getMaxColumnInclusive());
200 }
201
202
203
204
205
206
207 boolean areSerializedFieldsEqual(Filter o) {
208 if (o == this) return true;
209 if (!(o instanceof ColumnRangeFilter)) return false;
210
211 ColumnRangeFilter other = (ColumnRangeFilter)o;
212 return Bytes.equals(this.getMinColumn(),other.getMinColumn())
213 && this.getMinColumnInclusive() == other.getMinColumnInclusive()
214 && Bytes.equals(this.getMaxColumn(), other.getMaxColumn())
215 && this.getMaxColumnInclusive() == other.getMaxColumnInclusive();
216 }
217
218 @Override
219 public Cell getNextCellHint(Cell kv) {
220 return KeyValue.createFirstOnRow(kv.getRowArray(), kv.getRowOffset(), kv
221 .getRowLength(), kv.getFamilyArray(), kv.getFamilyOffset(), kv
222 .getFamilyLength(), this.minColumn, 0, len(this.minColumn));
223
224 }
225
226 @Override
227 public String toString() {
228 return this.getClass().getSimpleName() + " "
229 + (this.minColumnInclusive ? "[" : "(") + Bytes.toStringBinary(this.minColumn)
230 + ", " + Bytes.toStringBinary(this.maxColumn)
231 + (this.maxColumnInclusive ? "]" : ")");
232 }
233 }