1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.filter;
20
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.HashSet;
24 import java.util.Iterator;
25 import java.util.List;
26 import java.util.Objects;
27 import java.util.Set;
28
29 import org.apache.hadoop.hbase.util.ByteStringer;
30 import org.apache.hadoop.hbase.classification.InterfaceAudience;
31 import org.apache.hadoop.hbase.classification.InterfaceStability;
32 import org.apache.hadoop.hbase.Cell;
33 import org.apache.hadoop.hbase.CellUtil;
34 import org.apache.hadoop.hbase.exceptions.DeserializationException;
35 import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
36 import org.apache.hadoop.hbase.protobuf.generated.FilterProtos;
37 import org.apache.hadoop.hbase.util.Bytes;
38
39 import com.google.common.base.Preconditions;
40 import com.google.protobuf.InvalidProtocolBufferException;
41
42
43
44
45
46
47
48
49 @InterfaceAudience.Public
50 @InterfaceStability.Stable
51 public class DependentColumnFilter extends CompareFilter {
52
53 protected byte[] columnFamily;
54 protected byte[] columnQualifier;
55 protected boolean dropDependentColumn;
56
57 protected Set<Long> stampSet = new HashSet<Long>();
58
59
60
61
62
63
64
65
66
67
68
69
70
71 public DependentColumnFilter(final byte [] family, final byte[] qualifier,
72 final boolean dropDependentColumn, final CompareOp valueCompareOp,
73 final ByteArrayComparable valueComparator) {
74
75 super(valueCompareOp, valueComparator);
76 this.columnFamily = family;
77 this.columnQualifier = qualifier;
78 this.dropDependentColumn = dropDependentColumn;
79 }
80
81
82
83
84
85
86
87
88
89 public DependentColumnFilter(final byte [] family, final byte [] qualifier) {
90 this(family, qualifier, false);
91 }
92
93
94
95
96
97
98
99
100
101
102 public DependentColumnFilter(final byte [] family, final byte [] qualifier,
103 final boolean dropDependentColumn) {
104 this(family, qualifier, dropDependentColumn, CompareOp.NO_OP, null);
105 }
106
107
108
109
110 public byte[] getFamily() {
111 return this.columnFamily;
112 }
113
114
115
116
117 public byte[] getQualifier() {
118 return this.columnQualifier;
119 }
120
121
122
123
124 public boolean dropDependentColumn() {
125 return this.dropDependentColumn;
126 }
127
128 public boolean getDropDependentColumn() {
129 return this.dropDependentColumn;
130 }
131
132 @Override
133 public boolean filterAllRemaining() {
134 return false;
135 }
136
137 @Override
138 public ReturnCode filterKeyValue(Cell c) {
139
140 if (!CellUtil.matchingColumn(c, this.columnFamily, this.columnQualifier)) {
141
142 return ReturnCode.INCLUDE;
143 }
144
145 if (comparator != null
146 && doCompare(compareOp, comparator, c.getValueArray(), c.getValueOffset(),
147 c.getValueLength()))
148 return ReturnCode.SKIP;
149
150 stampSet.add(c.getTimestamp());
151 if(dropDependentColumn) {
152 return ReturnCode.SKIP;
153 }
154 return ReturnCode.INCLUDE;
155 }
156
157 @Override
158 public void filterRowCells(List<Cell> kvs) {
159 Iterator<? extends Cell> it = kvs.iterator();
160 Cell kv;
161 while(it.hasNext()) {
162 kv = it.next();
163 if(!stampSet.contains(kv.getTimestamp())) {
164 it.remove();
165 }
166 }
167 }
168
169 @Override
170 public boolean hasFilterRow() {
171 return true;
172 }
173
174 @Override
175 public boolean filterRow() {
176 return false;
177 }
178
179 @Override
180 public boolean filterRowKey(byte[] buffer, int offset, int length) {
181 return false;
182 }
183 @Override
184 public void reset() {
185 stampSet.clear();
186 }
187
188 public static Filter createFilterFromArguments(ArrayList<byte []> filterArguments) {
189 Preconditions.checkArgument(filterArguments.size() == 2 ||
190 filterArguments.size() == 3 ||
191 filterArguments.size() == 5,
192 "Expected 2, 3 or 5 but got: %s", filterArguments.size());
193 if (filterArguments.size() == 2) {
194 byte [] family = ParseFilter.removeQuotesFromByteArray(filterArguments.get(0));
195 byte [] qualifier = ParseFilter.removeQuotesFromByteArray(filterArguments.get(1));
196 return new DependentColumnFilter(family, qualifier);
197
198 } else if (filterArguments.size() == 3) {
199 byte [] family = ParseFilter.removeQuotesFromByteArray(filterArguments.get(0));
200 byte [] qualifier = ParseFilter.removeQuotesFromByteArray(filterArguments.get(1));
201 boolean dropDependentColumn = ParseFilter.convertByteArrayToBoolean(filterArguments.get(2));
202 return new DependentColumnFilter(family, qualifier, dropDependentColumn);
203
204 } else if (filterArguments.size() == 5) {
205 byte [] family = ParseFilter.removeQuotesFromByteArray(filterArguments.get(0));
206 byte [] qualifier = ParseFilter.removeQuotesFromByteArray(filterArguments.get(1));
207 boolean dropDependentColumn = ParseFilter.convertByteArrayToBoolean(filterArguments.get(2));
208 CompareOp compareOp = ParseFilter.createCompareOp(filterArguments.get(3));
209 ByteArrayComparable comparator = ParseFilter.createComparator(
210 ParseFilter.removeQuotesFromByteArray(filterArguments.get(4)));
211 return new DependentColumnFilter(family, qualifier, dropDependentColumn,
212 compareOp, comparator);
213 } else {
214 throw new IllegalArgumentException("Expected 2, 3 or 5 but got: " + filterArguments.size());
215 }
216 }
217
218
219
220
221 @Override
222 public byte [] toByteArray() {
223 FilterProtos.DependentColumnFilter.Builder builder =
224 FilterProtos.DependentColumnFilter.newBuilder();
225 builder.setCompareFilter(super.convert());
226 if (this.columnFamily != null) {
227 builder.setColumnFamily(ByteStringer.wrap(this.columnFamily));
228 }
229 if (this.columnQualifier != null) {
230 builder.setColumnQualifier(ByteStringer.wrap(this.columnQualifier));
231 }
232 builder.setDropDependentColumn(this.dropDependentColumn);
233 return builder.build().toByteArray();
234 }
235
236
237
238
239
240
241
242 public static DependentColumnFilter parseFrom(final byte [] pbBytes)
243 throws DeserializationException {
244 FilterProtos.DependentColumnFilter proto;
245 try {
246 proto = FilterProtos.DependentColumnFilter.parseFrom(pbBytes);
247 } catch (InvalidProtocolBufferException e) {
248 throw new DeserializationException(e);
249 }
250 final CompareOp valueCompareOp =
251 CompareOp.valueOf(proto.getCompareFilter().getCompareOp().name());
252 ByteArrayComparable valueComparator = null;
253 try {
254 if (proto.getCompareFilter().hasComparator()) {
255 valueComparator = ProtobufUtil.toComparator(proto.getCompareFilter().getComparator());
256 }
257 } catch (IOException ioe) {
258 throw new DeserializationException(ioe);
259 }
260 return new DependentColumnFilter(
261 proto.hasColumnFamily()?proto.getColumnFamily().toByteArray():null,
262 proto.hasColumnQualifier()?proto.getColumnQualifier().toByteArray():null,
263 proto.getDropDependentColumn(), valueCompareOp, valueComparator);
264 }
265
266
267
268
269
270
271 @edu.umd.cs.findbugs.annotations.SuppressWarnings(
272 value="RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE")
273 @Override
274 boolean areSerializedFieldsEqual(Filter o) {
275 if (o == this) return true;
276 if (!(o instanceof DependentColumnFilter)) return false;
277
278 DependentColumnFilter other = (DependentColumnFilter)o;
279 return other != null && super.areSerializedFieldsEqual(other)
280 && Bytes.equals(this.getFamily(), other.getFamily())
281 && Bytes.equals(this.getQualifier(), other.getQualifier())
282 && this.dropDependentColumn() == other.dropDependentColumn();
283 }
284
285 @Override
286 public String toString() {
287 return String.format("%s (%s, %s, %s, %s, %s)",
288 this.getClass().getSimpleName(),
289 Bytes.toStringBinary(this.columnFamily),
290 Bytes.toStringBinary(this.columnQualifier),
291 this.dropDependentColumn,
292 this.compareOp.name(),
293 this.comparator != null ? Bytes.toStringBinary(this.comparator.getValue()) : "null");
294 }
295
296 @Override
297 public boolean equals(Object obj) {
298 return obj instanceof Filter && areSerializedFieldsEqual((Filter) obj);
299 }
300
301 @Override
302 public int hashCode() {
303 return Objects.hash(Bytes.hashCode(getFamily()), Bytes.hashCode(getQualifier()),
304 dropDependentColumn(), getComparator(), getOperator());
305 }
306 }