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 public Cell getNextCellHint(Cell currentCell) throws IOException {
128 if (!canHint) {
129 return null;
130 }
131
132 Long nextTimestampObject = timestamps.lower(currentCell.getTimestamp());
133
134 if (nextTimestampObject == null) {
135
136
137
138
139
140
141
142 return KeyValueUtil.createLastOnRowCol(currentCell);
143 }
144
145
146
147
148 long nextTimestamp = nextTimestampObject;
149 return KeyValueUtil.createFirstOnRowColTS(currentCell, nextTimestamp);
150 }
151
152
153
154 @Override
155 public Cell transformCell(Cell v) {
156 return v;
157 }
158
159 public static Filter createFilterFromArguments(ArrayList<byte []> filterArguments) {
160 ArrayList<Long> timestamps = new ArrayList<Long>();
161 for (int i = 0; i<filterArguments.size(); i++) {
162 long timestamp = ParseFilter.convertByteArrayToLong(filterArguments.get(i));
163 timestamps.add(timestamp);
164 }
165 return new TimestampsFilter(timestamps);
166 }
167
168
169
170
171 public byte[] toByteArray() {
172 FilterProtos.TimestampsFilter.Builder builder =
173 FilterProtos.TimestampsFilter.newBuilder();
174 builder.addAllTimestamps(this.timestamps);
175 builder.setCanHint(canHint);
176 return builder.build().toByteArray();
177 }
178
179
180
181
182
183
184
185 public static TimestampsFilter parseFrom(final byte[] pbBytes)
186 throws DeserializationException {
187 FilterProtos.TimestampsFilter proto;
188 try {
189 proto = FilterProtos.TimestampsFilter.parseFrom(pbBytes);
190 } catch (InvalidProtocolBufferException e) {
191 throw new DeserializationException(e);
192 }
193 return new TimestampsFilter(proto.getTimestampsList(),
194 proto.hasCanHint() && proto.getCanHint());
195 }
196
197
198
199
200
201
202 boolean areSerializedFieldsEqual(Filter o) {
203 if (o == this) return true;
204 if (!(o instanceof TimestampsFilter)) return false;
205
206 TimestampsFilter other = (TimestampsFilter)o;
207 return this.getTimestamps().equals(other.getTimestamps());
208 }
209
210 @Override
211 public String toString() {
212 return toString(MAX_LOG_TIMESTAMPS);
213 }
214
215 protected String toString(int maxTimestamps) {
216 StringBuilder tsList = new StringBuilder();
217
218 int count = 0;
219 for (Long ts : this.timestamps) {
220 if (count >= maxTimestamps) {
221 break;
222 }
223 ++count;
224 tsList.append(ts.toString());
225 if (count < this.timestamps.size() && count < maxTimestamps) {
226 tsList.append(", ");
227 }
228 }
229
230 return String.format("%s (%d/%d): [%s] canHint: [%b]", this.getClass().getSimpleName(),
231 count, this.timestamps.size(), tsList.toString(), canHint);
232 }
233 }