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