001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.io;
019
020import org.apache.yetus.audience.InterfaceAudience;
021
022/**
023 * Represents an interval of version timestamps. Presumes timestamps between
024 * {@link #INITIAL_MIN_TIMESTAMP} and {@link #INITIAL_MAX_TIMESTAMP} only. Gets freaked out if
025 * passed a timestamp that is < {@link #INITIAL_MIN_TIMESTAMP},
026 * <p/>
027 * Evaluated according to minStamp &lt;= timestamp &lt; maxStamp or [minStamp,maxStamp) in interval
028 * notation.
029 * <p/>
030 * Can be returned and read by clients. Should not be directly created by clients. Thus, all
031 * constructors are purposely @InterfaceAudience.Private.
032 * <p/>
033 * Immutable. Thread-safe.
034 */
035@InterfaceAudience.Public
036public final class TimeRange {
037  public static final long INITIAL_MIN_TIMESTAMP = 0L;
038  public static final long INITIAL_MAX_TIMESTAMP = Long.MAX_VALUE;
039  private static final TimeRange ALL_TIME =
040    new TimeRange(INITIAL_MIN_TIMESTAMP, INITIAL_MAX_TIMESTAMP);
041
042  public static TimeRange allTime() {
043    return ALL_TIME;
044  }
045
046  public static TimeRange at(long ts) {
047    if (ts < 0 || ts == Long.MAX_VALUE) {
048      throw new IllegalArgumentException("invalid ts:" + ts);
049    }
050    return new TimeRange(ts, ts + 1);
051  }
052
053  /**
054   * Represents the time interval [minStamp, Long.MAX_VALUE)
055   * @param minStamp the minimum timestamp value, inclusive
056   */
057  public static TimeRange from(long minStamp) {
058    check(minStamp, INITIAL_MAX_TIMESTAMP);
059    return new TimeRange(minStamp, INITIAL_MAX_TIMESTAMP);
060  }
061
062  /**
063   * Represents the time interval [0, maxStamp)
064   * @param maxStamp the minimum timestamp value, exclusive
065   */
066  public static TimeRange until(long maxStamp) {
067    check(INITIAL_MIN_TIMESTAMP, maxStamp);
068    return new TimeRange(INITIAL_MIN_TIMESTAMP, maxStamp);
069  }
070
071  /**
072   * Represents the time interval [minStamp, maxStamp)
073   * @param minStamp the minimum timestamp, inclusive
074   * @param maxStamp the maximum timestamp, exclusive
075   */
076  public static TimeRange between(long minStamp, long maxStamp) {
077    check(minStamp, maxStamp);
078    return new TimeRange(minStamp, maxStamp);
079  }
080
081  private final long minStamp;
082  private final long maxStamp;
083  private final boolean allTime;
084
085  /**
086   * Represents interval [minStamp, maxStamp)
087   * @param minStamp the minimum timestamp, inclusive
088   * @param maxStamp the maximum timestamp, exclusive
089   * @throws IllegalArgumentException if either <0,
090   */
091  private TimeRange(long minStamp, long maxStamp) {
092    this.minStamp = minStamp;
093    this.maxStamp = maxStamp;
094    this.allTime = isAllTime(minStamp, maxStamp);
095  }
096
097  private static boolean isAllTime(long minStamp, long maxStamp) {
098    return minStamp == INITIAL_MIN_TIMESTAMP && maxStamp == INITIAL_MAX_TIMESTAMP;
099  }
100
101  private static void check(long minStamp, long maxStamp) {
102    if (minStamp < 0 || maxStamp < 0) {
103      throw new IllegalArgumentException(
104        "Timestamp cannot be negative. minStamp:" + minStamp + ", maxStamp:" + maxStamp);
105    }
106    if (maxStamp < minStamp) {
107      throw new IllegalArgumentException("maxStamp is smaller than minStamp");
108    }
109  }
110
111  /** Returns the smallest timestamp that should be considered */
112  public long getMin() {
113    return minStamp;
114  }
115
116  /** Returns the biggest timestamp that should be considered */
117  public long getMax() {
118    return maxStamp;
119  }
120
121  /**
122   * Check if it is for all time
123   * @return true if it is for all time
124   */
125  public boolean isAllTime() {
126    return allTime;
127  }
128
129  /**
130   * Check if the specified timestamp is within this TimeRange.
131   * <p/>
132   * Returns true if within interval [minStamp, maxStamp), false if not.
133   * @param timestamp timestamp to check
134   * @return true if within TimeRange, false if not
135   */
136  public boolean withinTimeRange(long timestamp) {
137    assert timestamp >= 0;
138    if (this.allTime) {
139      return true;
140    }
141    // check if >= minStamp
142    return (minStamp <= timestamp && timestamp < maxStamp);
143  }
144
145  /**
146   * Check if the range has any overlap with TimeRange
147   * @param tr TimeRange
148   * @return True if there is overlap, false otherwise
149   */
150  // This method came from TimeRangeTracker. We used to go there for this function but better
151  // to come here to the immutable, unsynchronized datastructure at read time.
152  public boolean includesTimeRange(final TimeRange tr) {
153    if (this.allTime) {
154      return true;
155    }
156    assert tr.getMin() >= 0;
157    return getMin() < tr.getMax() && getMax() >= tr.getMin();
158  }
159
160  /**
161   * Check if the specified timestamp is within or after this TimeRange.
162   * <p>
163   * Returns true if greater than minStamp, false if not.
164   * @param timestamp timestamp to check
165   * @return true if within or after TimeRange, false if not
166   */
167  public boolean withinOrAfterTimeRange(long timestamp) {
168    assert timestamp >= 0;
169    if (allTime) {
170      return true;
171    }
172    // check if >= minStamp
173    return timestamp >= minStamp;
174  }
175
176  /**
177   * Compare the timestamp to timerange.
178   * @return -1 if timestamp is less than timerange, 0 if timestamp is within timerange, 1 if
179   *         timestamp is greater than timerange
180   */
181  public int compare(long timestamp) {
182    assert timestamp >= 0;
183    if (this.allTime) {
184      return 0;
185    }
186    if (timestamp < minStamp) {
187      return -1;
188    }
189    return timestamp >= maxStamp ? 1 : 0;
190  }
191
192  @Override
193  public String toString() {
194    StringBuilder sb = new StringBuilder();
195    sb.append("maxStamp=");
196    sb.append(this.maxStamp);
197    sb.append(", minStamp=");
198    sb.append(this.minStamp);
199    return sb.toString();
200  }
201}