1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.filter;
19
20 import com.google.common.base.Preconditions;
21 import com.google.protobuf.InvalidProtocolBufferException;
22 import java.io.IOException;
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.Objects;
26 import java.util.TreeSet;
27
28 import org.apache.hadoop.hbase.Cell;
29 import org.apache.hadoop.hbase.KeyValueUtil;
30 import org.apache.hadoop.hbase.classification.InterfaceAudience;
31 import org.apache.hadoop.hbase.classification.InterfaceStability;
32 import org.apache.hadoop.hbase.exceptions.DeserializationException;
33 import org.apache.hadoop.hbase.protobuf.generated.FilterProtos;
34
35
36
37
38
39
40
41
42
43
44 @InterfaceAudience.Public
45 @InterfaceStability.Stable
46 public class TimestampsFilter extends FilterBase {
47
48 private final boolean canHint;
49 TreeSet<Long> timestamps;
50 private static final int MAX_LOG_TIMESTAMPS = 5;
51
52
53
54 long minTimeStamp = Long.MAX_VALUE;
55
56
57
58
59
60 public TimestampsFilter(List<Long> timestamps) {
61 this(timestamps, false);
62 }
63
64
65
66
67
68
69
70
71
72
73
74
75 public TimestampsFilter(List<Long> timestamps, boolean canHint) {
76 for (Long timestamp : timestamps) {
77 Preconditions.checkArgument(timestamp >= 0, "must be positive %s", timestamp);
78 }
79 this.canHint = canHint;
80 this.timestamps = new TreeSet<Long>(timestamps);
81 init();
82 }
83
84
85
86
87 public List<Long> getTimestamps() {
88 List<Long> list = new ArrayList<Long>(timestamps.size());
89 list.addAll(timestamps);
90 return list;
91 }
92
93 private void init() {
94 if (this.timestamps.size() > 0) {
95 minTimeStamp = this.timestamps.first();
96 }
97 }
98
99
100
101
102
103 public long getMin() {
104 return minTimeStamp;
105 }
106
107 @Override
108 public ReturnCode filterKeyValue(Cell v) {
109 if (this.timestamps.contains(v.getTimestamp())) {
110 return ReturnCode.INCLUDE;
111 } else if (v.getTimestamp() < minTimeStamp) {
112
113
114 return ReturnCode.NEXT_COL;
115 }
116 return canHint ? ReturnCode.SEEK_NEXT_USING_HINT : ReturnCode.SKIP;
117 }
118
119
120
121
122
123
124
125
126
127
128 @Override
129 public Cell getNextCellHint(Cell currentCell) throws IOException {
130 if (!canHint) {
131 return null;
132 }
133
134 Long nextTimestampObject = timestamps.lower(currentCell.getTimestamp());
135
136 if (nextTimestampObject == null) {
137
138
139
140
141
142
143
144 return KeyValueUtil.createLastOnRowCol(currentCell);
145 }
146
147
148
149
150 long nextTimestamp = nextTimestampObject;
151 return KeyValueUtil.createFirstOnRowColTS(currentCell, nextTimestamp);
152 }
153
154
155
156 @Override
157 public Cell transformCell(Cell v) {
158 return v;
159 }
160
161 public static Filter createFilterFromArguments(ArrayList<byte []> filterArguments) {
162 ArrayList<Long> timestamps = new ArrayList<Long>();
163 for (int i = 0; i<filterArguments.size(); i++) {
164 long timestamp = ParseFilter.convertByteArrayToLong(filterArguments.get(i));
165 timestamps.add(timestamp);
166 }
167 return new TimestampsFilter(timestamps);
168 }
169
170
171
172
173 @Override
174 public byte[] toByteArray() {
175 FilterProtos.TimestampsFilter.Builder builder =
176 FilterProtos.TimestampsFilter.newBuilder();
177 builder.addAllTimestamps(this.timestamps);
178 builder.setCanHint(canHint);
179 return builder.build().toByteArray();
180 }
181
182
183
184
185
186
187
188 public static TimestampsFilter parseFrom(final byte[] pbBytes)
189 throws DeserializationException {
190 FilterProtos.TimestampsFilter proto;
191 try {
192 proto = FilterProtos.TimestampsFilter.parseFrom(pbBytes);
193 } catch (InvalidProtocolBufferException e) {
194 throw new DeserializationException(e);
195 }
196 return new TimestampsFilter(proto.getTimestampsList(),
197 proto.hasCanHint() && proto.getCanHint());
198 }
199
200
201
202
203
204
205 @Override
206 boolean areSerializedFieldsEqual(Filter o) {
207 if (o == this) return true;
208 if (!(o instanceof TimestampsFilter)) return false;
209
210 TimestampsFilter other = (TimestampsFilter)o;
211 return this.getTimestamps().equals(other.getTimestamps());
212 }
213
214 @Override
215 public String toString() {
216 return toString(MAX_LOG_TIMESTAMPS);
217 }
218
219 protected String toString(int maxTimestamps) {
220 StringBuilder tsList = new StringBuilder();
221
222 int count = 0;
223 for (Long ts : this.timestamps) {
224 if (count >= maxTimestamps) {
225 break;
226 }
227 ++count;
228 tsList.append(ts.toString());
229 if (count < this.timestamps.size() && count < maxTimestamps) {
230 tsList.append(", ");
231 }
232 }
233
234 return String.format("%s (%d/%d): [%s] canHint: [%b]", this.getClass().getSimpleName(),
235 count, this.timestamps.size(), tsList.toString(), canHint);
236 }
237
238 @Override
239 public boolean equals(Object obj) {
240 return obj instanceof Filter && areSerializedFieldsEqual((Filter) obj);
241 }
242
243 @Override
244 public int hashCode() {
245 return Objects.hash(getTimestamps());
246 }
247 }