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