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.Set;
27
28 import org.apache.hadoop.hbase.util.ByteStringer;
29 import org.apache.hadoop.hbase.classification.InterfaceAudience;
30 import org.apache.hadoop.hbase.classification.InterfaceStability;
31 import org.apache.hadoop.hbase.Cell;
32 import org.apache.hadoop.hbase.KeyValue;
33 import org.apache.hadoop.hbase.KeyValueUtil;
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 KeyValue v = KeyValueUtil.ensureKeyValue(c);
141
142 if (!v.matchingColumn(this.columnFamily, this.columnQualifier)) {
143
144 return ReturnCode.INCLUDE;
145 }
146
147 if (comparator != null
148 && doCompare(compareOp, comparator, v.getValueArray(), v.getValueOffset(),
149 v.getValueLength()))
150 return ReturnCode.SKIP;
151
152 stampSet.add(v.getTimestamp());
153 if(dropDependentColumn) {
154 return ReturnCode.SKIP;
155 }
156 return ReturnCode.INCLUDE;
157 }
158
159 @Override
160 public void filterRowCells(List<Cell> kvs) {
161 Iterator<? extends Cell> it = kvs.iterator();
162 Cell kv;
163 while(it.hasNext()) {
164 kv = it.next();
165 if(!stampSet.contains(kv.getTimestamp())) {
166 it.remove();
167 }
168 }
169 }
170
171 @Override
172 public boolean hasFilterRow() {
173 return true;
174 }
175
176 @Override
177 public boolean filterRow() {
178 return false;
179 }
180
181 @Override
182 public boolean filterRowKey(byte[] buffer, int offset, int length) {
183 return false;
184 }
185 @Override
186 public void reset() {
187 stampSet.clear();
188 }
189
190 public static Filter createFilterFromArguments(ArrayList<byte []> filterArguments) {
191 Preconditions.checkArgument(filterArguments.size() == 2 ||
192 filterArguments.size() == 3 ||
193 filterArguments.size() == 5,
194 "Expected 2, 3 or 5 but got: %s", filterArguments.size());
195 if (filterArguments.size() == 2) {
196 byte [] family = ParseFilter.removeQuotesFromByteArray(filterArguments.get(0));
197 byte [] qualifier = ParseFilter.removeQuotesFromByteArray(filterArguments.get(1));
198 return new DependentColumnFilter(family, qualifier);
199
200 } else if (filterArguments.size() == 3) {
201 byte [] family = ParseFilter.removeQuotesFromByteArray(filterArguments.get(0));
202 byte [] qualifier = ParseFilter.removeQuotesFromByteArray(filterArguments.get(1));
203 boolean dropDependentColumn = ParseFilter.convertByteArrayToBoolean(filterArguments.get(2));
204 return new DependentColumnFilter(family, qualifier, dropDependentColumn);
205
206 } else if (filterArguments.size() == 5) {
207 byte [] family = ParseFilter.removeQuotesFromByteArray(filterArguments.get(0));
208 byte [] qualifier = ParseFilter.removeQuotesFromByteArray(filterArguments.get(1));
209 boolean dropDependentColumn = ParseFilter.convertByteArrayToBoolean(filterArguments.get(2));
210 CompareOp compareOp = ParseFilter.createCompareOp(filterArguments.get(3));
211 ByteArrayComparable comparator = ParseFilter.createComparator(
212 ParseFilter.removeQuotesFromByteArray(filterArguments.get(4)));
213 return new DependentColumnFilter(family, qualifier, dropDependentColumn,
214 compareOp, comparator);
215 } else {
216 throw new IllegalArgumentException("Expected 2, 3 or 5 but got: " + filterArguments.size());
217 }
218 }
219
220
221
222
223 public byte [] toByteArray() {
224 FilterProtos.DependentColumnFilter.Builder builder =
225 FilterProtos.DependentColumnFilter.newBuilder();
226 builder.setCompareFilter(super.convert());
227 if (this.columnFamily != null) {
228 builder.setColumnFamily(ByteStringer.wrap(this.columnFamily));
229 }
230 if (this.columnQualifier != null) {
231 builder.setColumnQualifier(ByteStringer.wrap(this.columnQualifier));
232 }
233 builder.setDropDependentColumn(this.dropDependentColumn);
234 return builder.build().toByteArray();
235 }
236
237
238
239
240
241
242
243 public static DependentColumnFilter parseFrom(final byte [] pbBytes)
244 throws DeserializationException {
245 FilterProtos.DependentColumnFilter proto;
246 try {
247 proto = FilterProtos.DependentColumnFilter.parseFrom(pbBytes);
248 } catch (InvalidProtocolBufferException e) {
249 throw new DeserializationException(e);
250 }
251 final CompareOp valueCompareOp =
252 CompareOp.valueOf(proto.getCompareFilter().getCompareOp().name());
253 ByteArrayComparable valueComparator = null;
254 try {
255 if (proto.getCompareFilter().hasComparator()) {
256 valueComparator = ProtobufUtil.toComparator(proto.getCompareFilter().getComparator());
257 }
258 } catch (IOException ioe) {
259 throw new DeserializationException(ioe);
260 }
261 return new DependentColumnFilter(
262 proto.hasColumnFamily()?proto.getColumnFamily().toByteArray():null,
263 proto.hasColumnQualifier()?proto.getColumnQualifier().toByteArray():null,
264 proto.getDropDependentColumn(), valueCompareOp, valueComparator);
265 }
266
267
268
269
270
271
272 @edu.umd.cs.findbugs.annotations.SuppressWarnings(
273 value="RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE")
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 }