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    
019    package org.apache.hadoop.yarn.api.records;
020    
021    import java.io.IOException;
022    import java.text.NumberFormat;
023    
024    import org.apache.hadoop.classification.InterfaceAudience.Private;
025    import org.apache.hadoop.classification.InterfaceAudience.Public;
026    import org.apache.hadoop.classification.InterfaceStability.Unstable;
027    import 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
043    public 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    }