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