View Javadoc

1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  package org.apache.hadoop.hbase.regionserver;
20  
21  import java.io.DataInput;
22  import java.io.DataOutput;
23  import java.io.IOException;
24  
25  import org.apache.hadoop.hbase.classification.InterfaceAudience;
26  import org.apache.hadoop.hbase.KeyValue;
27  import org.apache.hadoop.hbase.KeyValue.Type;
28  import org.apache.hadoop.hbase.io.TimeRange;
29  import org.apache.hadoop.hbase.util.Bytes;
30  import org.apache.hadoop.hbase.util.Writables;
31  import org.apache.hadoop.io.Writable;
32  
33  /**
34   * Stores minimum and maximum timestamp values. Both timestamps are inclusive.
35   * Use this class at write-time ONLY. Too much synchronization to use at read time
36   * (TODO: there are two scenarios writing, once when lots of concurrency as part of memstore
37   * updates but then later we can make one as part of a compaction when there is only one thread
38   * involved -- consider making different version, the synchronized and the unsynchronized).
39   * Use {@link TimeRange} at read time instead of this. See toTimeRange() to make TimeRange to use.
40   * MemStores use this class to track minimum and maximum timestamps. The TimeRangeTracker made by
41   * the MemStore is passed to the StoreFile for it to write out as part a flush in the the file
42   * metadata. If no memstore involved -- i.e. a compaction -- then the StoreFile will calculate its
43   * own TimeRangeTracker as it appends. The StoreFile serialized TimeRangeTracker is used
44   * at read time via an instance of {@link TimeRange} to test if Cells fit the StoreFile TimeRange.
45   */
46  @InterfaceAudience.Private
47  public class TimeRangeTracker implements Writable {
48    static final long INITIAL_MIN_TIMESTAMP = Long.MAX_VALUE;
49    long minimumTimestamp = INITIAL_MIN_TIMESTAMP;
50    static final long INITIAL_MAX_TIMESTAMP = -1;
51    long maximumTimestamp = INITIAL_MAX_TIMESTAMP;
52  
53    /**
54     * Default constructor.
55     * Initializes TimeRange to be null
56     */
57    public TimeRangeTracker() {
58  
59    }
60  
61    /**
62     * Copy Constructor
63     * @param trt source TimeRangeTracker
64     */
65    public TimeRangeTracker(final TimeRangeTracker trt) {
66      this.minimumTimestamp = trt.getMin();
67      this.maximumTimestamp = trt.getMax();
68    }
69  
70    public TimeRangeTracker(long minimumTimestamp, long maximumTimestamp) {
71      this.minimumTimestamp = minimumTimestamp;
72      this.maximumTimestamp = maximumTimestamp;
73    }
74  
75    /**
76     * Update the current TimestampRange to include the timestamp from KeyValue
77     * If the Key is of type DeleteColumn or DeleteFamily, it includes the
78     * entire time range from 0 to timestamp of the key.
79     * @param kv the KeyValue to include
80     */
81    public void includeTimestamp(final KeyValue kv) {
82      includeTimestamp(kv.getTimestamp());
83      if (kv.isDeleteColumnOrFamily()) {
84        includeTimestamp(0);
85      }
86    }
87  
88    /**
89     * Update the current TimestampRange to include the timestamp from Key.
90     * If the Key is of type DeleteColumn or DeleteFamily, it includes the
91     * entire time range from 0 to timestamp of the key.
92     * @param key
93     */
94    public void includeTimestamp(final byte[] key) {
95      includeTimestamp(Bytes.toLong(key,key.length-KeyValue.TIMESTAMP_TYPE_SIZE));
96      int type = key[key.length - 1];
97      if (type == Type.DeleteColumn.getCode() ||
98          type == Type.DeleteFamily.getCode()) {
99        includeTimestamp(0);
100     }
101   }
102 
103   /**
104    * If required, update the current TimestampRange to include timestamp
105    * @param timestamp the timestamp value to include
106    */
107   synchronized void includeTimestamp(final long timestamp) {
108     if (maximumTimestamp == -1) {
109       minimumTimestamp = timestamp;
110       maximumTimestamp = timestamp;
111     }
112     else if (minimumTimestamp > timestamp) {
113       minimumTimestamp = timestamp;
114     }
115     else if (maximumTimestamp < timestamp) {
116       maximumTimestamp = timestamp;
117     }
118     return;
119   }
120 
121   /**
122    * Check if the range has any overlap with TimeRange
123    * @param tr TimeRange
124    * @return True if there is overlap, false otherwise
125    */
126   public synchronized boolean includesTimeRange(final TimeRange tr) {
127     return (this.minimumTimestamp < tr.getMax() &&
128         this.maximumTimestamp >= tr.getMin());
129   }
130 
131   /**
132    * @return the minimumTimestamp
133    */
134   public synchronized long getMin() {
135     return minimumTimestamp;
136   }
137 
138   /**
139    * @return the maximumTimestamp
140    */
141   public synchronized long getMax() {
142     return maximumTimestamp;
143   }
144 
145   public synchronized void write(final DataOutput out) throws IOException {
146     out.writeLong(minimumTimestamp);
147     out.writeLong(maximumTimestamp);
148   }
149 
150   public synchronized void readFields(final DataInput in) throws IOException {
151     this.minimumTimestamp = in.readLong();
152     this.maximumTimestamp = in.readLong();
153   }
154 
155   @Override
156   public synchronized String toString() {
157     return "[" + minimumTimestamp + "," + maximumTimestamp + "]";
158   }
159 
160   /**
161    * @return An instance of TimeRangeTracker filled w/ the content of serialized
162    * TimeRangeTracker in <code>timeRangeTrackerBytes</code>.
163    * @throws IOException
164    */
165   public static TimeRangeTracker getTimeRangeTracker(final byte [] timeRangeTrackerBytes)
166       throws IOException {
167     if (timeRangeTrackerBytes == null) return null;
168     TimeRangeTracker trt = new TimeRangeTracker();
169     Writables.copyWritable(timeRangeTrackerBytes, trt);
170     return trt;
171   }
172 
173   /**
174    * @return An instance of a TimeRange made from the serialized TimeRangeTracker passed in
175    * <code>timeRangeTrackerBytes</code>.
176    * @throws IOException
177    */
178   static TimeRange getTimeRange(final byte [] timeRangeTrackerBytes) throws IOException {
179     TimeRangeTracker trt = getTimeRangeTracker(timeRangeTrackerBytes);
180     return trt == null? null: trt.toTimeRange();
181   }
182 
183   private boolean isFreshInstance() {
184     return getMin() == INITIAL_MIN_TIMESTAMP && getMax() == INITIAL_MAX_TIMESTAMP;
185   }
186 
187   /**
188    * @return Make a TimeRange from current state of <code>this</code>.
189    */
190   TimeRange toTimeRange() throws IOException {
191     long min = getMin();
192     long max = getMax();
193     // Check for the case where the TimeRangeTracker is fresh. In that case it has
194     // initial values that are antithetical to a TimeRange... Return an uninitialized TimeRange
195     // if passed an uninitialized TimeRangeTracker.
196     if (isFreshInstance()) {
197       return new TimeRange();
198     }
199     return new TimeRange(min, max);
200   }
201 }