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 java.io.DataInput;
23 import java.io.DataOutput;
24 import java.io.IOException;
25 import java.util.HashSet;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.Set;
29 import java.util.ArrayList;
30
31 import org.apache.hadoop.hbase.KeyValue;
32 import org.apache.hadoop.hbase.util.Bytes;
33
34 import com.google.common.base.Preconditions;
35
36
37
38
39
40
41
42
43 public class DependentColumnFilter extends CompareFilter {
44
45 protected byte[] columnFamily;
46 protected byte[] columnQualifier;
47 protected boolean dropDependentColumn;
48
49 protected Set<Long> stampSet = new HashSet<Long>();
50
51
52
53
54 public DependentColumnFilter() {
55 }
56
57
58
59
60
61
62
63
64
65
66
67
68
69 public DependentColumnFilter(final byte [] family, final byte[] qualifier,
70 final boolean dropDependentColumn, final CompareOp valueCompareOp,
71 final WritableByteArrayComparable valueComparator) {
72
73 super(valueCompareOp, valueComparator);
74 this.columnFamily = family;
75 this.columnQualifier = qualifier;
76 this.dropDependentColumn = dropDependentColumn;
77 }
78
79
80
81
82
83
84
85
86
87 public DependentColumnFilter(final byte [] family, final byte [] qualifier) {
88 this(family, qualifier, false);
89 }
90
91
92
93
94
95
96
97
98
99
100 public DependentColumnFilter(final byte [] family, final byte [] qualifier,
101 final boolean dropDependentColumn) {
102 this(family, qualifier, dropDependentColumn, CompareOp.NO_OP, null);
103 }
104
105
106
107
108 public byte[] getFamily() {
109 return this.columnFamily;
110 }
111
112
113
114
115 public byte[] getQualifier() {
116 return this.columnQualifier;
117 }
118
119
120
121
122 public boolean dropDependentColumn() {
123 return this.dropDependentColumn;
124 }
125
126 public boolean getDropDependentColumn() {
127 return this.dropDependentColumn;
128 }
129
130 @Override
131 public boolean filterAllRemaining() {
132 return false;
133 }
134
135 @Override
136 public ReturnCode filterKeyValue(KeyValue v) {
137
138 if (!v.matchingColumn(this.columnFamily, this.columnQualifier)) {
139
140 return ReturnCode.INCLUDE;
141 }
142
143 if (comparator != null
144 && doCompare(compareOp, comparator, v.getBuffer(), v.getValueOffset(),
145 v.getValueLength()))
146 return ReturnCode.SKIP;
147
148 stampSet.add(v.getTimestamp());
149 if(dropDependentColumn) {
150 return ReturnCode.SKIP;
151 }
152 return ReturnCode.INCLUDE;
153 }
154
155 @Override
156 public void filterRow(List<KeyValue> kvs) {
157 Iterator<KeyValue> it = kvs.iterator();
158 KeyValue kv;
159 while(it.hasNext()) {
160 kv = it.next();
161 if(!stampSet.contains(kv.getTimestamp())) {
162 it.remove();
163 }
164 }
165 }
166
167 @Override
168 public boolean hasFilterRow() {
169 return true;
170 }
171
172 @Override
173 public boolean filterRow() {
174 return false;
175 }
176
177 @Override
178 public boolean filterRowKey(byte[] buffer, int offset, int length) {
179 return false;
180 }
181 @Override
182 public void reset() {
183 stampSet.clear();
184 }
185
186 public static Filter createFilterFromArguments(ArrayList<byte []> filterArguments) {
187 Preconditions.checkArgument(filterArguments.size() == 2 ||
188 filterArguments.size() == 3 ||
189 filterArguments.size() == 5,
190 "Expected 2, 3 or 5 but got: %s", filterArguments.size());
191 if (filterArguments.size() == 2) {
192 byte [] family = ParseFilter.removeQuotesFromByteArray(filterArguments.get(0));
193 byte [] qualifier = ParseFilter.removeQuotesFromByteArray(filterArguments.get(1));
194 return new DependentColumnFilter(family, qualifier);
195
196 } else if (filterArguments.size() == 3) {
197 byte [] family = ParseFilter.removeQuotesFromByteArray(filterArguments.get(0));
198 byte [] qualifier = ParseFilter.removeQuotesFromByteArray(filterArguments.get(1));
199 boolean dropDependentColumn = ParseFilter.convertByteArrayToBoolean(filterArguments.get(2));
200 return new DependentColumnFilter(family, qualifier, dropDependentColumn);
201
202 } else if (filterArguments.size() == 5) {
203 byte [] family = ParseFilter.removeQuotesFromByteArray(filterArguments.get(0));
204 byte [] qualifier = ParseFilter.removeQuotesFromByteArray(filterArguments.get(1));
205 boolean dropDependentColumn = ParseFilter.convertByteArrayToBoolean(filterArguments.get(2));
206 CompareOp compareOp = ParseFilter.createCompareOp(filterArguments.get(3));
207 WritableByteArrayComparable comparator = ParseFilter.createComparator(
208 ParseFilter.removeQuotesFromByteArray(filterArguments.get(4)));
209 return new DependentColumnFilter(family, qualifier, dropDependentColumn,
210 compareOp, comparator);
211 } else {
212 throw new IllegalArgumentException("Expected 2, 3 or 5 but got: " + filterArguments.size());
213 }
214 }
215
216 @Override
217 public void readFields(DataInput in) throws IOException {
218 super.readFields(in);
219 this.columnFamily = Bytes.readByteArray(in);
220 if(this.columnFamily.length == 0) {
221 this.columnFamily = null;
222 }
223
224 this.columnQualifier = Bytes.readByteArray(in);
225 if(this.columnQualifier.length == 0) {
226 this.columnQualifier = null;
227 }
228
229 this.dropDependentColumn = in.readBoolean();
230 }
231
232 @Override
233 public void write(DataOutput out) throws IOException {
234 super.write(out);
235 Bytes.writeByteArray(out, this.columnFamily);
236 Bytes.writeByteArray(out, this.columnQualifier);
237 out.writeBoolean(this.dropDependentColumn);
238 }
239
240 @Override
241 public String toString() {
242 return String.format("%s (%s, %s, %s, %s, %s)",
243 this.getClass().getSimpleName(),
244 Bytes.toStringBinary(this.columnFamily),
245 Bytes.toStringBinary(this.columnQualifier),
246 this.dropDependentColumn,
247 this.compareOp.name(),
248 Bytes.toStringBinary(this.comparator.getValue()));
249 }
250 }