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