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     */
018    package org.apache.hadoop.hdfs.protocol;
019    
020    import java.util.Date;
021    
022    import org.apache.commons.lang.builder.EqualsBuilder;
023    import org.apache.commons.lang.builder.HashCodeBuilder;
024    import org.apache.hadoop.classification.InterfaceAudience;
025    import org.apache.hadoop.classification.InterfaceStability;
026    import org.apache.hadoop.fs.Path;
027    import org.apache.hadoop.hdfs.DFSUtil;
028    
029    import com.google.common.base.Preconditions;
030    
031    /**
032     * Describes a path-based cache directive.
033     */
034    @InterfaceStability.Evolving
035    @InterfaceAudience.Public
036    public 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 DFSUtil.durationToString(ms);
248          }
249          return DFSUtil.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    };