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.Serializable;
022
023import org.apache.hadoop.classification.InterfaceAudience.Public;
024import org.apache.hadoop.classification.InterfaceStability.Evolving;
025import org.apache.hadoop.classification.InterfaceStability.Stable;
026import org.apache.hadoop.yarn.api.ApplicationMasterProtocol;
027import org.apache.hadoop.yarn.util.Records;
028
029/**
030 * <p><code>ResourceRequest</code> represents the request made by an
031 * application to the <code>ResourceManager</code> to obtain various 
032 * <code>Container</code> allocations.</p>
033 * 
034 * <p>It includes:
035 *   <ul>
036 *     <li>{@link Priority} of the request.</li>
037 *     <li>
038 *       The <em>name</em> of the machine or rack on which the allocation is 
039 *       desired. A special value of <em>*</em> signifies that 
040 *       <em>any</em> host/rack is acceptable to the application.
041 *     </li>
042 *     <li>{@link Resource} required for each request.</li>
043 *     <li>
044 *       Number of containers, of above specifications, which are required 
045 *       by the application.
046 *     </li>
047 *     <li>
048 *       A boolean <em>relaxLocality</em> flag, defaulting to <code>true</code>,
049 *       which tells the <code>ResourceManager</code> if the application wants
050 *       locality to be loose (i.e. allows fall-through to rack or <em>any</em>)
051 *       or strict (i.e. specify hard constraint on resource allocation).
052 *     </li>
053 *   </ul>
054 * </p>
055 * 
056 * @see Resource
057 * @see ApplicationMasterProtocol#allocate(org.apache.hadoop.yarn.api.protocolrecords.AllocateRequest)
058 */
059@Public
060@Stable
061public abstract class ResourceRequest implements Comparable<ResourceRequest> {
062
063  @Public
064  @Stable
065  public static ResourceRequest newInstance(Priority priority, String hostName,
066      Resource capability, int numContainers) {
067    return newInstance(priority, hostName, capability, numContainers, true);
068  }
069
070  @Public
071  @Stable
072  public static ResourceRequest newInstance(Priority priority, String hostName,
073      Resource capability, int numContainers, boolean relaxLocality) {
074    return newInstance(priority, hostName, capability, numContainers,
075        relaxLocality, null);
076  }
077  
078  @Public
079  @Stable
080  public static ResourceRequest newInstance(Priority priority, String hostName,
081      Resource capability, int numContainers, boolean relaxLocality,
082      String labelExpression) {
083    ResourceRequest request = Records.newRecord(ResourceRequest.class);
084    request.setPriority(priority);
085    request.setResourceName(hostName);
086    request.setCapability(capability);
087    request.setNumContainers(numContainers);
088    request.setRelaxLocality(relaxLocality);
089    request.setNodeLabelExpression(labelExpression);
090    return request;
091  }
092
093  @Public
094  @Stable
095  public static class ResourceRequestComparator implements
096      java.util.Comparator<ResourceRequest>, Serializable {
097
098    private static final long serialVersionUID = 1L;
099
100    @Override
101    public int compare(ResourceRequest r1, ResourceRequest r2) {
102
103      // Compare priority, host and capability
104      int ret = r1.getPriority().compareTo(r2.getPriority());
105      if (ret == 0) {
106        String h1 = r1.getResourceName();
107        String h2 = r2.getResourceName();
108        ret = h1.compareTo(h2);
109      }
110      if (ret == 0) {
111        ret = r1.getCapability().compareTo(r2.getCapability());
112      }
113      return ret;
114    }
115  }
116
117  /**
118   * The constant string representing no locality.
119   * It should be used by all references that want to pass an arbitrary host
120   * name in.
121   */
122  public static final String ANY = "*";
123
124  /**
125   * Check whether the given <em>host/rack</em> string represents an arbitrary
126   * host name.
127   *
128   * @param hostName <em>host/rack</em> on which the allocation is desired
129   * @return whether the given <em>host/rack</em> string represents an arbitrary
130   * host name
131   */
132  @Public
133  @Stable
134  public static boolean isAnyLocation(String hostName) {
135    return ANY.equals(hostName);
136  }
137
138  /**
139   * Get the <code>Priority</code> of the request.
140   * @return <code>Priority</code> of the request
141   */
142  @Public
143  @Stable
144  public abstract Priority getPriority();
145
146  /**
147   * Set the <code>Priority</code> of the request
148   * @param priority <code>Priority</code> of the request
149   */
150  @Public
151  @Stable
152  public abstract void setPriority(Priority priority);
153  
154  /**
155   * Get the resource (e.g. <em>host/rack</em>) on which the allocation 
156   * is desired.
157   * 
158   * A special value of <em>*</em> signifies that <em>any</em> resource 
159   * (host/rack) is acceptable.
160   * 
161   * @return resource (e.g. <em>host/rack</em>) on which the allocation 
162   *                  is desired
163   */
164  @Public
165  @Stable
166  public abstract String getResourceName();
167
168  /**
169   * Set the resource name (e.g. <em>host/rack</em>) on which the allocation 
170   * is desired.
171   * 
172   * A special value of <em>*</em> signifies that <em>any</em> resource name
173   * (e.g. host/rack) is acceptable. 
174   * 
175   * @param resourceName (e.g. <em>host/rack</em>) on which the 
176   *                     allocation is desired
177   */
178  @Public
179  @Stable
180  public abstract void setResourceName(String resourceName);
181  
182  /**
183   * Get the <code>Resource</code> capability of the request.
184   * @return <code>Resource</code> capability of the request
185   */
186  @Public
187  @Stable
188  public abstract Resource getCapability();
189  
190  /**
191   * Set the <code>Resource</code> capability of the request
192   * @param capability <code>Resource</code> capability of the request
193   */
194  @Public
195  @Stable
196  public abstract void setCapability(Resource capability);
197
198  /**
199   * Get the number of containers required with the given specifications.
200   * @return number of containers required with the given specifications
201   */
202  @Public
203  @Stable
204  public abstract int getNumContainers();
205  
206  /**
207   * Set the number of containers required with the given specifications
208   * @param numContainers number of containers required with the given 
209   *                      specifications
210   */
211  @Public
212  @Stable
213  public abstract void setNumContainers(int numContainers);
214
215  /**
216   * Get whether locality relaxation is enabled with this
217   * <code>ResourceRequest</code>. Defaults to true.
218   * 
219   * @return whether locality relaxation is enabled with this
220   * <code>ResourceRequest</code>.
221   */
222  @Public
223  @Stable
224  public abstract boolean getRelaxLocality();
225  
226  /**
227   * <p>For a request at a network hierarchy level, set whether locality can be relaxed
228   * to that level and beyond.<p>
229   * 
230   * <p>If the flag is off on a rack-level <code>ResourceRequest</code>,
231   * containers at that request's priority will not be assigned to nodes on that
232   * request's rack unless requests specifically for those nodes have also been
233   * submitted.<p>
234   * 
235   * <p>If the flag is off on an {@link ResourceRequest#ANY}-level
236   * <code>ResourceRequest</code>, containers at that request's priority will
237   * only be assigned on racks for which specific requests have also been
238   * submitted.<p>
239   * 
240   * <p>For example, to request a container strictly on a specific node, the
241   * corresponding rack-level and any-level requests should have locality
242   * relaxation set to false.  Similarly, to request a container strictly on a
243   * specific rack, the corresponding any-level request should have locality
244   * relaxation set to false.<p>
245   * 
246   * @param relaxLocality whether locality relaxation is enabled with this
247   * <code>ResourceRequest</code>.
248   */
249  @Public
250  @Stable
251  public abstract void setRelaxLocality(boolean relaxLocality);
252  
253  /**
254   * Get node-label-expression for this Resource Request. If this is set, all
255   * containers allocated to satisfy this resource-request will be only on those
256   * nodes that satisfy this node-label-expression.
257   *  
258   * Please note that node label expression now can only take effect when the
259   * resource request has resourceName = ANY
260   * 
261   * @return node-label-expression
262   */
263  @Public
264  @Evolving
265  public abstract String getNodeLabelExpression();
266  
267  /**
268   * Set node label expression of this resource request. Now only support
269   * specifying a single node label. In the future we will support more complex
270   * node label expression specification like AND(&&), OR(||), etc.
271   * 
272   * Any please note that node label expression now can only take effect when
273   * the resource request has resourceName = ANY
274   * 
275   * @param nodelabelExpression
276   *          node-label-expression of this ResourceRequest
277   */
278  @Public
279  @Evolving
280  public abstract void setNodeLabelExpression(String nodelabelExpression);
281  
282  @Override
283  public int hashCode() {
284    final int prime = 2153;
285    int result = 2459;
286    Resource capability = getCapability();
287    String hostName = getResourceName();
288    Priority priority = getPriority();
289    result =
290        prime * result + ((capability == null) ? 0 : capability.hashCode());
291    result = prime * result + ((hostName == null) ? 0 : hostName.hashCode());
292    result = prime * result + getNumContainers();
293    result = prime * result + ((priority == null) ? 0 : priority.hashCode());
294    return result;
295  }
296
297  @Override
298  public boolean equals(Object obj) {
299    if (this == obj)
300      return true;
301    if (obj == null)
302      return false;
303    if (getClass() != obj.getClass())
304      return false;
305    ResourceRequest other = (ResourceRequest) obj;
306    Resource capability = getCapability();
307    if (capability == null) {
308      if (other.getCapability() != null)
309        return false;
310    } else if (!capability.equals(other.getCapability()))
311      return false;
312    String hostName = getResourceName();
313    if (hostName == null) {
314      if (other.getResourceName() != null)
315        return false;
316    } else if (!hostName.equals(other.getResourceName()))
317      return false;
318    if (getNumContainers() != other.getNumContainers())
319      return false;
320    Priority priority = getPriority();
321    if (priority == null) {
322      if (other.getPriority() != null)
323        return false;
324    } else if (!priority.equals(other.getPriority()))
325      return false;
326    if (getNodeLabelExpression() == null) {
327      if (other.getNodeLabelExpression() != null) {
328        return false;
329      }
330    } else {
331      // do normalize on label expression before compare
332      String label1 = getNodeLabelExpression().replaceAll("[\\t ]", "");
333      String label2 =
334          other.getNodeLabelExpression() == null ? null : other
335              .getNodeLabelExpression().replaceAll("[\\t ]", "");
336      if (!label1.equals(label2)) {
337        return false;
338      }
339    }
340    return true;
341  }
342
343  @Override
344  public int compareTo(ResourceRequest other) {
345    int priorityComparison = this.getPriority().compareTo(other.getPriority());
346    if (priorityComparison == 0) {
347      int hostNameComparison =
348          this.getResourceName().compareTo(other.getResourceName());
349      if (hostNameComparison == 0) {
350        int capabilityComparison =
351            this.getCapability().compareTo(other.getCapability());
352        if (capabilityComparison == 0) {
353          return this.getNumContainers() - other.getNumContainers();
354        } else {
355          return capabilityComparison;
356        }
357      } else {
358        return hostNameComparison;
359      }
360    } else {
361      return priorityComparison;
362    }
363  }
364}