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 com.google.common.base.Splitter; 022 023import java.text.NumberFormat; 024import java.util.Iterator; 025import java.util.NoSuchElementException; 026 027import org.apache.hadoop.classification.InterfaceAudience.Private; 028import org.apache.hadoop.classification.InterfaceAudience.Public; 029import org.apache.hadoop.classification.InterfaceStability.Stable; 030import org.apache.hadoop.classification.InterfaceStability.Unstable; 031import org.apache.hadoop.yarn.util.Records; 032 033/** 034 * <p><code>ContainerId</code> represents a globally unique identifier 035 * for a {@link Container} in the cluster.</p> 036 */ 037@Public 038@Stable 039public abstract class ContainerId implements Comparable<ContainerId>{ 040 public static final long CONTAINER_ID_BITMASK = 0xffffffffffL; 041 private static final Splitter _SPLITTER = Splitter.on('_').trimResults(); 042 private static final String CONTAINER_PREFIX = "container"; 043 private static final String EPOCH_PREFIX = "e"; 044 045 @Private 046 @Unstable 047 public static ContainerId newContainerId(ApplicationAttemptId appAttemptId, 048 long containerId) { 049 ContainerId id = Records.newRecord(ContainerId.class); 050 id.setContainerId(containerId); 051 id.setApplicationAttemptId(appAttemptId); 052 id.build(); 053 return id; 054 } 055 056 @Private 057 @Deprecated 058 @Unstable 059 public static ContainerId newInstance(ApplicationAttemptId appAttemptId, 060 int containerId) { 061 ContainerId id = Records.newRecord(ContainerId.class); 062 id.setContainerId(containerId); 063 id.setApplicationAttemptId(appAttemptId); 064 id.build(); 065 return id; 066 } 067 068 /** 069 * Get the <code>ApplicationAttemptId</code> of the application to which the 070 * <code>Container</code> was assigned. 071 * <p> 072 * Note: If containers are kept alive across application attempts via 073 * {@link ApplicationSubmissionContext#setKeepContainersAcrossApplicationAttempts(boolean)} 074 * the <code>ContainerId</code> does not necessarily contain the current 075 * running application attempt's <code>ApplicationAttemptId</code> This 076 * container can be allocated by previously exited application attempt and 077 * managed by the current running attempt thus have the previous application 078 * attempt's <code>ApplicationAttemptId</code>. 079 * </p> 080 * 081 * @return <code>ApplicationAttemptId</code> of the application to which the 082 * <code>Container</code> was assigned 083 */ 084 @Public 085 @Stable 086 public abstract ApplicationAttemptId getApplicationAttemptId(); 087 088 @Private 089 @Unstable 090 protected abstract void setApplicationAttemptId(ApplicationAttemptId atId); 091 092 /** 093 * Get the lower 32 bits of identifier of the <code>ContainerId</code>, 094 * which doesn't include epoch. Note that this method will be marked as 095 * deprecated, so please use <code>getContainerId</code> instead. 096 * @return lower 32 bits of identifier of the <code>ContainerId</code> 097 */ 098 @Public 099 @Deprecated 100 @Stable 101 public abstract int getId(); 102 103 /** 104 * Get the identifier of the <code>ContainerId</code>. Upper 24 bits are 105 * reserved as epoch of cluster, and lower 40 bits are reserved as 106 * sequential number of containers. 107 * @return identifier of the <code>ContainerId</code> 108 */ 109 @Public 110 @Unstable 111 public abstract long getContainerId(); 112 113 @Private 114 @Unstable 115 protected abstract void setContainerId(long id); 116 117 118 // TODO: fail the app submission if attempts are more than 10 or something 119 private static final ThreadLocal<NumberFormat> appAttemptIdAndEpochFormat = 120 new ThreadLocal<NumberFormat>() { 121 @Override 122 public NumberFormat initialValue() { 123 NumberFormat fmt = NumberFormat.getInstance(); 124 fmt.setGroupingUsed(false); 125 fmt.setMinimumIntegerDigits(2); 126 return fmt; 127 } 128 }; 129 // TODO: Why thread local? 130 // ^ NumberFormat instances are not threadsafe 131 private static final ThreadLocal<NumberFormat> containerIdFormat = 132 new ThreadLocal<NumberFormat>() { 133 @Override 134 public NumberFormat initialValue() { 135 NumberFormat fmt = NumberFormat.getInstance(); 136 fmt.setGroupingUsed(false); 137 fmt.setMinimumIntegerDigits(6); 138 return fmt; 139 } 140 }; 141 142 @Override 143 public int hashCode() { 144 // Generated by IntelliJ IDEA 13.1. 145 int result = (int) (getContainerId() ^ (getContainerId() >>> 32)); 146 result = 31 * result + getApplicationAttemptId().hashCode(); 147 return result; 148 } 149 150 @Override 151 public boolean equals(Object obj) { 152 if (this == obj) 153 return true; 154 if (obj == null) 155 return false; 156 if (getClass() != obj.getClass()) 157 return false; 158 ContainerId other = (ContainerId) obj; 159 if (!this.getApplicationAttemptId().equals(other.getApplicationAttemptId())) 160 return false; 161 if (this.getContainerId() != other.getContainerId()) 162 return false; 163 return true; 164 } 165 166 @Override 167 public int compareTo(ContainerId other) { 168 if (this.getApplicationAttemptId().compareTo( 169 other.getApplicationAttemptId()) == 0) { 170 return Long.valueOf(getContainerId()) 171 .compareTo(Long.valueOf(other.getContainerId())); 172 } else { 173 return this.getApplicationAttemptId().compareTo( 174 other.getApplicationAttemptId()); 175 } 176 } 177 178 /** 179 * @return A string representation of containerId. The format is 180 * container_e*epoch*_*clusterTimestamp*_*appId*_*attemptId*_*containerId* 181 * when epoch is larger than 0 182 * (e.g. container_e17_1410901177871_0001_01_000005). 183 * *epoch* is increased when RM restarts or fails over. 184 * When epoch is 0, epoch is omitted 185 * (e.g. container_1410901177871_0001_01_000005). 186 */ 187 @Override 188 public String toString() { 189 StringBuilder sb = new StringBuilder(); 190 sb.append(CONTAINER_PREFIX + "_"); 191 long epoch = getContainerId() >> 40; 192 if (epoch > 0) { 193 sb.append(EPOCH_PREFIX) 194 .append(appAttemptIdAndEpochFormat.get().format(epoch)).append("_");; 195 } 196 ApplicationId appId = getApplicationAttemptId().getApplicationId(); 197 sb.append(appId.getClusterTimestamp()).append("_"); 198 sb.append(ApplicationId.appIdFormat.get().format(appId.getId())) 199 .append("_"); 200 sb.append( 201 appAttemptIdAndEpochFormat.get().format( 202 getApplicationAttemptId().getAttemptId())).append("_"); 203 sb.append(containerIdFormat.get() 204 .format(CONTAINER_ID_BITMASK & getContainerId())); 205 return sb.toString(); 206 } 207 208 @Public 209 @Unstable 210 public static ContainerId fromString(String containerIdStr) { 211 Iterator<String> it = _SPLITTER.split(containerIdStr).iterator(); 212 if (!it.next().equals(CONTAINER_PREFIX)) { 213 throw new IllegalArgumentException("Invalid ContainerId prefix: " 214 + containerIdStr); 215 } 216 try { 217 String epochOrClusterTimestampStr = it.next(); 218 long epoch = 0; 219 ApplicationAttemptId appAttemptID = null; 220 if (epochOrClusterTimestampStr.startsWith(EPOCH_PREFIX)) { 221 String epochStr = epochOrClusterTimestampStr; 222 epoch = Integer.parseInt(epochStr.substring(EPOCH_PREFIX.length())); 223 appAttemptID = toApplicationAttemptId(it); 224 } else { 225 String clusterTimestampStr = epochOrClusterTimestampStr; 226 long clusterTimestamp = Long.parseLong(clusterTimestampStr); 227 appAttemptID = toApplicationAttemptId(clusterTimestamp, it); 228 } 229 long id = Long.parseLong(it.next()); 230 long cid = (epoch << 40) | id; 231 ContainerId containerId = ContainerId.newContainerId(appAttemptID, cid); 232 return containerId; 233 } catch (NumberFormatException n) { 234 throw new IllegalArgumentException("Invalid ContainerId: " 235 + containerIdStr, n); 236 } catch (NoSuchElementException e) { 237 throw new IllegalArgumentException("Invalid ContainerId: " 238 + containerIdStr, e); 239 } 240 } 241 242 private static ApplicationAttemptId toApplicationAttemptId( 243 Iterator<String> it) throws NumberFormatException { 244 return toApplicationAttemptId(Long.parseLong(it.next()), it); 245 } 246 247 private static ApplicationAttemptId toApplicationAttemptId( 248 long clusterTimestamp, Iterator<String> it) throws NumberFormatException { 249 ApplicationId appId = ApplicationId.newInstance(clusterTimestamp, 250 Integer.parseInt(it.next())); 251 ApplicationAttemptId appAttemptId = 252 ApplicationAttemptId.newInstance(appId, Integer.parseInt(it.next())); 253 return appAttemptId; 254 } 255 256 protected abstract void build(); 257}