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.hdfs.protocol;
019
020import java.util.Date;
021
022import org.apache.commons.lang.builder.EqualsBuilder;
023import org.apache.commons.lang.builder.HashCodeBuilder;
024import org.apache.hadoop.classification.InterfaceAudience;
025import org.apache.hadoop.classification.InterfaceStability;
026import org.apache.hadoop.fs.Path;
027
028import com.google.common.base.Preconditions;
029import org.apache.hadoop.hdfs.DFSUtilClient;
030
031/**
032 * Describes a path-based cache directive.
033 */
034@InterfaceStability.Evolving
035@InterfaceAudience.Public
036public class CacheDirectiveInfo {
037  /**
038   * A builder for creating new CacheDirectiveInfo instances.
039   */
040  public static class Builder {
041    private Long id;
042    private Path path;
043    private Short replication;
044    private String pool;
045    private Expiration expiration;
046
047    /**
048     * Builds a new CacheDirectiveInfo populated with the set properties.
049     * 
050     * @return New CacheDirectiveInfo.
051     */
052    public CacheDirectiveInfo build() {
053      return new CacheDirectiveInfo(id, path, replication, pool, expiration);
054    }
055
056    /**
057     * Creates an empty builder.
058     */
059    public Builder() {
060    }
061
062    /**
063     * Creates a builder with all elements set to the same values as the
064     * given CacheDirectiveInfo.
065     */
066    public Builder(CacheDirectiveInfo directive) {
067      this.id = directive.getId();
068      this.path = directive.getPath();
069      this.replication = directive.getReplication();
070      this.pool = directive.getPool();
071      this.expiration = directive.getExpiration();
072    }
073
074    /**
075     * Sets the id used in this request.
076     * 
077     * @param id The id used in this request.
078     * @return This builder, for call chaining.
079     */
080    public Builder setId(Long id) {
081      this.id = id;
082      return this;
083    }
084
085    /**
086     * Sets the path used in this request.
087     * 
088     * @param path The path used in this request.
089     * @return This builder, for call chaining.
090     */
091    public Builder setPath(Path path) {
092      this.path = path;
093      return this;
094    }
095
096    /**
097     * Sets the replication used in this request.
098     * 
099     * @param replication The replication used in this request.
100     * @return This builder, for call chaining.
101     */
102    public Builder setReplication(Short replication) {
103      this.replication = replication;
104      return this;
105    }
106
107    /**
108     * Sets the pool used in this request.
109     * 
110     * @param pool The pool used in this request.
111     * @return This builder, for call chaining.
112     */
113    public Builder setPool(String pool) {
114      this.pool = pool;
115      return this;
116    }
117
118    /**
119     * Sets when the CacheDirective should expire. A
120     * {@link CacheDirectiveInfo.Expiration} can specify either an absolute or
121     * relative expiration time.
122     * 
123     * @param expiration when this CacheDirective should expire
124     * @return This builder, for call chaining
125     */
126    public Builder setExpiration(Expiration expiration) {
127      this.expiration = expiration;
128      return this;
129    }
130  }
131
132  /**
133   * Denotes a relative or absolute expiration time for a CacheDirective. Use
134   * factory methods {@link CacheDirectiveInfo.Expiration#newAbsolute(Date)} and
135   * {@link CacheDirectiveInfo.Expiration#newRelative(long)} to create an
136   * Expiration.
137   * <p>
138   * In either case, the server-side clock is used to determine when a
139   * CacheDirective expires.
140   */
141  public static class Expiration {
142
143    /**
144     * The maximum value we accept for a relative expiry.
145     */
146    public static final long MAX_RELATIVE_EXPIRY_MS =
147        Long.MAX_VALUE / 4; // This helps prevent weird overflow bugs
148
149    /**
150     * An relative Expiration that never expires.
151     */
152    public static final Expiration NEVER = newRelative(MAX_RELATIVE_EXPIRY_MS);
153
154    /**
155     * Create a new relative Expiration.
156     * <p>
157     * Use {@link Expiration#NEVER} to indicate an Expiration that never
158     * expires.
159     * 
160     * @param ms how long until the CacheDirective expires, in milliseconds
161     * @return A relative Expiration
162     */
163    public static Expiration newRelative(long ms) {
164      return new Expiration(ms, true);
165    }
166
167    /**
168     * Create a new absolute Expiration.
169     * <p>
170     * Use {@link Expiration#NEVER} to indicate an Expiration that never
171     * expires.
172     * 
173     * @param date when the CacheDirective expires
174     * @return An absolute Expiration
175     */
176    public static Expiration newAbsolute(Date date) {
177      return new Expiration(date.getTime(), false);
178    }
179
180    /**
181     * Create a new absolute Expiration.
182     * <p>
183     * Use {@link Expiration#NEVER} to indicate an Expiration that never
184     * expires.
185     * 
186     * @param ms when the CacheDirective expires, in milliseconds since the Unix
187     *          epoch.
188     * @return An absolute Expiration
189     */
190    public static Expiration newAbsolute(long ms) {
191      return new Expiration(ms, false);
192    }
193
194    private final long ms;
195    private final boolean isRelative;
196
197    private Expiration(long ms, boolean isRelative) {
198      if (isRelative) {
199        Preconditions.checkArgument(ms <= MAX_RELATIVE_EXPIRY_MS,
200            "Expiration time is too far in the future!");
201      }
202      this.ms = ms;
203      this.isRelative = isRelative;
204    }
205
206    /**
207     * @return true if Expiration was specified as a relative duration, false if
208     *         specified as an absolute time.
209     */
210    public boolean isRelative() {
211      return isRelative;
212    }
213
214    /**
215     * @return The raw underlying millisecond value, either a relative duration
216     *         or an absolute time as milliseconds since the Unix epoch.
217     */
218    public long getMillis() {
219      return ms;
220    }
221
222    /**
223     * @return Expiration time as a {@link Date} object. This converts a
224     *         relative Expiration into an absolute Date based on the local
225     *         clock.
226     */
227    public Date getAbsoluteDate() {
228      return new Date(getAbsoluteMillis());
229    }
230
231    /**
232     * @return Expiration time in milliseconds from the Unix epoch. This
233     *         converts a relative Expiration into an absolute time based on the
234     *         local clock.
235     */
236    public long getAbsoluteMillis() {
237      if (!isRelative) {
238        return ms;
239      } else {
240        return new Date().getTime() + ms;
241      }
242    }
243
244    @Override
245    public String toString() {
246      if (isRelative) {
247        return DFSUtilClient.durationToString(ms);
248      }
249      return DFSUtilClient.dateToIso8601String(new Date(ms));
250    }
251  }
252
253  private final Long id;
254  private final Path path;
255  private final Short replication;
256  private final String pool;
257  private final Expiration expiration;
258
259  CacheDirectiveInfo(Long id, Path path, Short replication, String pool,
260      Expiration expiration) {
261    this.id = id;
262    this.path = path;
263    this.replication = replication;
264    this.pool = pool;
265    this.expiration = expiration;
266  }
267
268  /**
269   * @return The ID of this directive.
270   */
271  public Long getId() {
272    return id;
273  }
274
275  /**
276   * @return The path used in this request.
277   */
278  public Path getPath() {
279    return path;
280  }
281
282  /**
283   * @return The number of times the block should be cached.
284   */
285  public Short getReplication() {
286    return replication;
287  }
288
289  /**
290   * @return The pool used in this request.
291   */
292  public String getPool() {
293    return pool;
294  }
295
296  /**
297   * @return When this directive expires.
298   */
299  public Expiration getExpiration() {
300    return expiration;
301  }
302
303  @Override
304  public boolean equals(Object o) {
305    if (o == null) {
306      return false;
307    }
308    if (getClass() != o.getClass()) {
309      return false;
310    }
311    CacheDirectiveInfo other = (CacheDirectiveInfo)o;
312    return new EqualsBuilder().append(getId(), other.getId()).
313        append(getPath(), other.getPath()).
314        append(getReplication(), other.getReplication()).
315        append(getPool(), other.getPool()).
316        append(getExpiration(), other.getExpiration()).
317        isEquals();
318  }
319
320  @Override
321  public int hashCode() {
322    return new HashCodeBuilder().append(id).
323        append(path).
324        append(replication).
325        append(pool).
326        append(expiration).
327        hashCode();
328  }
329
330  @Override
331  public String toString() {
332    StringBuilder builder = new StringBuilder();
333    builder.append("{");
334    String prefix = "";
335    if (id != null) {
336      builder.append(prefix).append("id: ").append(id);
337      prefix = ", ";
338    }
339    if (path != null) {
340      builder.append(prefix).append("path: ").append(path);
341      prefix = ", ";
342    }
343    if (replication != null) {
344      builder.append(prefix).append("replication: ").append(replication);
345      prefix = ", ";
346    }
347    if (pool != null) {
348      builder.append(prefix).append("pool: ").append(pool);
349      prefix = ", ";
350    }
351    if (expiration != null) {
352      builder.append(prefix).append("expiration: ").append(expiration);
353      prefix = ", ";
354    }
355    builder.append("}");
356    return builder.toString();
357  }
358};