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
019package org.apache.hadoop.yarn.api.records;
020
021import java.io.IOException;
022import java.text.NumberFormat;
023
024import org.apache.hadoop.classification.InterfaceAudience.Private;
025import org.apache.hadoop.classification.InterfaceAudience.Public;
026import org.apache.hadoop.classification.InterfaceStability.Unstable;
027import org.apache.hadoop.yarn.util.Records;
028
029/**
030 * <p>
031 * {@link ReservationId} represents the <em>globally unique</em> identifier for
032 * a reservation.
033 * </p>
034 * 
035 * <p>
036 * The globally unique nature of the identifier is achieved by using the
037 * <em>cluster timestamp</em> i.e. start-time of the {@code ResourceManager}
038 * along with a monotonically increasing counter for the reservation.
039 * </p>
040 */
041@Public
042@Unstable
043public abstract class ReservationId implements Comparable<ReservationId> {
044
045  @Private
046  @Unstable
047  public static final String reserveIdStrPrefix = "reservation_";
048  protected long clusterTimestamp;
049  protected long id;
050
051  @Private
052  @Unstable
053  public static ReservationId newInstance(long clusterTimestamp, long id) {
054    ReservationId reservationId = Records.newRecord(ReservationId.class);
055    reservationId.setClusterTimestamp(clusterTimestamp);
056    reservationId.setId(id);
057    reservationId.build();
058    return reservationId;
059  }
060
061  /**
062   * Get the long identifier of the {@link ReservationId} which is unique for
063   * all Reservations started by a particular instance of the
064   * {@code ResourceManager}.
065   * 
066   * @return long identifier of the {@link ReservationId}
067   */
068  @Public
069  @Unstable
070  public abstract long getId();
071
072  @Private
073  @Unstable
074  protected abstract void setId(long id);
075
076  /**
077   * Get the <em>start time</em> of the {@code ResourceManager} which is used to
078   * generate globally unique {@link ReservationId}.
079   * 
080   * @return <em>start time</em> of the {@code ResourceManager}
081   */
082  @Public
083  @Unstable
084  public abstract long getClusterTimestamp();
085
086  @Private
087  @Unstable
088  protected abstract void setClusterTimestamp(long clusterTimestamp);
089
090  protected abstract void build();
091
092  static final ThreadLocal<NumberFormat> reservIdFormat =
093      new ThreadLocal<NumberFormat>() {
094        @Override
095        public NumberFormat initialValue() {
096          NumberFormat fmt = NumberFormat.getInstance();
097          fmt.setGroupingUsed(false);
098          fmt.setMinimumIntegerDigits(4);
099          return fmt;
100        }
101      };
102
103  @Override
104  public int compareTo(ReservationId other) {
105    if (this.getClusterTimestamp() - other.getClusterTimestamp() == 0) {
106      return getId() > getId() ? 1 : getId() < getId() ? -1 : 0;
107    } else {
108      return this.getClusterTimestamp() > other.getClusterTimestamp() ? 1
109          : this.getClusterTimestamp() < other.getClusterTimestamp() ? -1 : 0;
110    }
111  }
112
113  @Override
114  public String toString() {
115    return reserveIdStrPrefix + this.getClusterTimestamp() + "_"
116        + reservIdFormat.get().format(getId());
117  }
118
119  /**
120   * Parse the string argument as a {@link ReservationId}
121   *
122   * @param reservationId the string representation of the {@link ReservationId}
123   * @return the {@link ReservationId} corresponding to the input string if
124   *         valid, null if input is null
125   * @throws IOException if unable to parse the input string
126   */
127  @Public
128  @Unstable
129  public static ReservationId parseReservationId(String reservationId)
130      throws IOException {
131    if (reservationId == null) {
132      return null;
133    }
134    if (!reservationId.startsWith(reserveIdStrPrefix)) {
135      throw new IOException("The specified reservation id is invalid: "
136          + reservationId);
137    }
138    String[] resFields = reservationId.split("_");
139    if (resFields.length != 3) {
140      throw new IOException("The specified reservation id is not parseable: "
141          + reservationId);
142    }
143    return newInstance(Long.parseLong(resFields[1]),
144        Long.parseLong(resFields[2]));
145  }
146
147  @Override
148  public int hashCode() {
149    // generated by eclipse
150    final int prime = 31;
151    int result = 1;
152    result =
153        prime * result
154            + (int) (getClusterTimestamp() ^ (getClusterTimestamp() >>> 32));
155    result = prime * result + (int) (getId() ^ (getId() >>> 32));
156    return result;
157  }
158
159  @Override
160  public boolean equals(Object obj) {
161    // generated by eclipse
162    if (this == obj)
163      return true;
164    if (obj == null)
165      return false;
166    if (getClass() != obj.getClass())
167      return false;
168    ReservationId other = (ReservationId) obj;
169    if (getClusterTimestamp() != other.getClusterTimestamp())
170      return false;
171    if (getId() != other.getId())
172      return false;
173    return true;
174  }
175
176}