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