View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.filter;
19  
20  import java.util.ArrayList;
21  import java.util.List;
22  import java.util.TreeSet;
23  
24  import org.apache.hadoop.hbase.Cell;
25  import org.apache.hadoop.hbase.classification.InterfaceAudience;
26  import org.apache.hadoop.hbase.classification.InterfaceStability;
27  import org.apache.hadoop.hbase.exceptions.DeserializationException;
28  import org.apache.hadoop.hbase.protobuf.generated.FilterProtos;
29  
30  import com.google.common.base.Preconditions;
31  import com.google.protobuf.InvalidProtocolBufferException;
32  
33  /**
34   * Filter that returns only cells whose timestamp (version) is
35   * in the specified list of timestamps (versions).
36   * <p>
37   * Note: Use of this filter overrides any time range/time stamp
38   * options specified using {@link org.apache.hadoop.hbase.client.Get#setTimeRange(long, long)},
39   * {@link org.apache.hadoop.hbase.client.Scan#setTimeRange(long, long)}, {@link org.apache.hadoop.hbase.client.Get#setTimeStamp(long)},
40   * or {@link org.apache.hadoop.hbase.client.Scan#setTimeStamp(long)}.
41   */
42  @InterfaceAudience.Public
43  @InterfaceStability.Stable
44  public class TimestampsFilter extends FilterBase {
45  
46    TreeSet<Long> timestamps;
47    private static final int MAX_LOG_TIMESTAMPS = 5;
48  
49    // Used during scans to hint the scan to stop early
50    // once the timestamps fall below the minTimeStamp.
51    long minTimeStamp = Long.MAX_VALUE;
52  
53    /**
54     * Constructor for filter that retains only those
55     * cells whose timestamp (version) is in the specified
56     * list of timestamps.
57     *
58     * @param timestamps
59     */
60    public TimestampsFilter(List<Long> timestamps) {
61      for (Long timestamp : timestamps) {
62        Preconditions.checkArgument(timestamp >= 0, "must be positive %s", timestamp);
63      }
64      this.timestamps = new TreeSet<Long>(timestamps);
65      init();
66    }
67  
68    /**
69     * @return the list of timestamps
70     */
71    public List<Long> getTimestamps() {
72      List<Long> list = new ArrayList<Long>(timestamps.size());
73      list.addAll(timestamps);
74      return list;
75    }
76  
77    private void init() {
78      if (this.timestamps.size() > 0) {
79        minTimeStamp = this.timestamps.first();
80      }
81    }
82  
83    /**
84     * Gets the minimum timestamp requested by filter.
85     * @return  minimum timestamp requested by filter.
86     */
87    public long getMin() {
88      return minTimeStamp;
89    }
90  
91    @Override
92    public ReturnCode filterKeyValue(Cell v) {
93      if (this.timestamps.contains(v.getTimestamp())) {
94        return ReturnCode.INCLUDE;
95      } else if (v.getTimestamp() < minTimeStamp) {
96        // The remaining versions of this column are guaranteed
97        // to be lesser than all of the other values.
98        return ReturnCode.NEXT_COL;
99      }
100     return ReturnCode.SKIP;
101   }
102 
103   public static Filter createFilterFromArguments(ArrayList<byte []> filterArguments) {
104     ArrayList<Long> timestamps = new ArrayList<Long>();
105     for (int i = 0; i<filterArguments.size(); i++) {
106       long timestamp = ParseFilter.convertByteArrayToLong(filterArguments.get(i));
107       timestamps.add(timestamp);
108     }
109     return new TimestampsFilter(timestamps);
110   }
111 
112   /**
113    * @return The filter serialized using pb
114    */
115   public byte [] toByteArray() {
116     FilterProtos.TimestampsFilter.Builder builder =
117       FilterProtos.TimestampsFilter.newBuilder();
118     builder.addAllTimestamps(this.timestamps);
119     return builder.build().toByteArray();
120   }
121 
122   /**
123    * @param pbBytes A pb serialized {@link TimestampsFilter} instance
124    * @return An instance of {@link TimestampsFilter} made from <code>bytes</code>
125    * @throws DeserializationException
126    * @see #toByteArray
127    */
128   public static TimestampsFilter parseFrom(final byte [] pbBytes)
129   throws DeserializationException {
130     FilterProtos.TimestampsFilter proto;
131     try {
132       proto = FilterProtos.TimestampsFilter.parseFrom(pbBytes);
133     } catch (InvalidProtocolBufferException e) {
134       throw new DeserializationException(e);
135     }
136     return new TimestampsFilter(proto.getTimestampsList());
137   }
138 
139   /**
140    * @param other
141    * @return true if and only if the fields of the filter that are serialized
142    * are equal to the corresponding fields in other.  Used for testing.
143    */
144   boolean areSerializedFieldsEqual(Filter o) {
145     if (o == this) return true;
146     if (!(o instanceof TimestampsFilter)) return false;
147 
148     TimestampsFilter other = (TimestampsFilter)o;
149     return this.getTimestamps().equals(other.getTimestamps());
150   }
151 
152   @Override
153   public String toString() {
154     return toString(MAX_LOG_TIMESTAMPS);
155   }
156 
157   protected String toString(int maxTimestamps) {
158     StringBuilder tsList = new StringBuilder();
159 
160     int count = 0;
161     for (Long ts : this.timestamps) {
162       if (count >= maxTimestamps) {
163         break;
164       }
165       ++count;
166       tsList.append(ts.toString());
167       if (count < this.timestamps.size() && count < maxTimestamps) {
168         tsList.append(", ");
169       }
170     }
171 
172     return String.format("%s (%d/%d): [%s]", this.getClass().getSimpleName(),
173         count, this.timestamps.size(), tsList.toString());
174   }
175 }