| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.hadoop.yarn.api.records; |
| |
| import java.io.Serializable; |
| |
| import org.apache.hadoop.classification.InterfaceAudience.Public; |
| import org.apache.hadoop.classification.InterfaceStability.Evolving; |
| import org.apache.hadoop.classification.InterfaceStability.Stable; |
| import org.apache.hadoop.classification.InterfaceStability.Unstable; |
| import org.apache.hadoop.yarn.api.ApplicationMasterProtocol; |
| import org.apache.hadoop.yarn.util.Records; |
| |
| /** |
| * {@code ResourceRequest} represents the request made |
| * by an application to the {@code ResourceManager} |
| * to obtain various {@code Container} allocations. |
| * <p> |
| * It includes: |
| * <ul> |
| * <li>{@link Priority} of the request.</li> |
| * <li> |
| * The <em>name</em> of the host or rack on which the allocation is |
| * desired. A special value of <em>*</em> signifies that |
| * <em>any</em> host/rack is acceptable to the application. |
| * </li> |
| * <li>{@link Resource} required for each request.</li> |
| * <li> |
| * Number of containers, of above specifications, which are required |
| * by the application. |
| * </li> |
| * <li> |
| * A boolean <em>relaxLocality</em> flag, defaulting to {@code true}, |
| * which tells the {@code ResourceManager} if the application wants |
| * locality to be loose (i.e. allows fall-through to rack or <em>any</em>) |
| * or strict (i.e. specify hard constraint on resource allocation). |
| * </li> |
| * </ul> |
| * |
| * @see Resource |
| * @see ApplicationMasterProtocol#allocate(org.apache.hadoop.yarn.api.protocolrecords.AllocateRequest) |
| */ |
| @Public |
| @Stable |
| public abstract class ResourceRequest extends AbstractResourceRequest |
| implements Comparable<ResourceRequest>{ |
| |
| @Public |
| @Stable |
| public static ResourceRequest newInstance(Priority priority, String hostName, |
| Resource capability, int numContainers) { |
| return ResourceRequest.newBuilder().priority(priority) |
| .resourceName(hostName).capability(capability) |
| .numContainers(numContainers).build(); |
| } |
| |
| @Public |
| @Stable |
| public static ResourceRequest newInstance(Priority priority, String hostName, |
| Resource capability, int numContainers, boolean relaxLocality) { |
| return ResourceRequest.newBuilder().priority(priority) |
| .resourceName(hostName).capability(capability) |
| .numContainers(numContainers).relaxLocality(relaxLocality).build(); |
| } |
| |
| @Public |
| @Stable |
| public static ResourceRequest newInstance(Priority priority, String hostName, |
| Resource capability, int numContainers, boolean relaxLocality, |
| String labelExpression) { |
| return ResourceRequest.newBuilder().priority(priority) |
| .resourceName(hostName).capability(capability) |
| .numContainers(numContainers).relaxLocality(relaxLocality) |
| .nodeLabelExpression(labelExpression).build(); |
| } |
| |
| @Public |
| @Evolving |
| public static ResourceRequest newInstance(Priority priority, String hostName, |
| Resource capability, int numContainers, boolean relaxLocality, String |
| labelExpression, ExecutionTypeRequest executionTypeRequest) { |
| return ResourceRequest.newBuilder().priority(priority) |
| .resourceName(hostName).capability(capability) |
| .numContainers(numContainers).relaxLocality(relaxLocality) |
| .nodeLabelExpression(labelExpression) |
| .executionTypeRequest(executionTypeRequest).profileCapability(null) |
| .build(); |
| } |
| |
| @Public |
| @Evolving |
| public static ResourceRequest newInstance(Priority priority, String hostName, |
| Resource capability, int numContainers, boolean relaxLocality, |
| String labelExpression, ExecutionTypeRequest executionTypeRequest, |
| ProfileCapability profile) { |
| return ResourceRequest.newBuilder().priority(priority) |
| .resourceName(hostName).capability(capability) |
| .numContainers(numContainers).relaxLocality(relaxLocality) |
| .nodeLabelExpression(labelExpression) |
| .executionTypeRequest(executionTypeRequest).profileCapability(profile) |
| .build(); |
| } |
| |
| @Public |
| @Unstable |
| public static ResourceRequestBuilder newBuilder() { |
| return new ResourceRequestBuilder(); |
| } |
| |
| /** |
| * Class to construct instances of {@link ResourceRequest} with specific |
| * options. |
| */ |
| @Public |
| @Stable |
| public static final class ResourceRequestBuilder { |
| private ResourceRequest resourceRequest = |
| Records.newRecord(ResourceRequest.class); |
| |
| private ResourceRequestBuilder() { |
| resourceRequest.setResourceName(ANY); |
| resourceRequest.setNumContainers(1); |
| resourceRequest.setPriority(Priority.newInstance(0)); |
| resourceRequest.setRelaxLocality(true); |
| resourceRequest.setExecutionTypeRequest( |
| ExecutionTypeRequest.newInstance()); |
| resourceRequest.setProfileCapability(null); |
| } |
| |
| /** |
| * Set the <code>priority</code> of the request. |
| * @see ResourceRequest#setPriority(Priority) |
| * @param priority <code>priority</code> of the request |
| * @return {@link ResourceRequestBuilder} |
| */ |
| @Public |
| @Stable |
| public ResourceRequestBuilder priority(Priority priority) { |
| resourceRequest.setPriority(priority); |
| return this; |
| } |
| |
| /** |
| * Set the <code>resourceName</code> of the request. |
| * @see ResourceRequest#setResourceName(String) |
| * @param resourceName <code>resourceName</code> of the request |
| * @return {@link ResourceRequestBuilder} |
| */ |
| @Public |
| @Stable |
| public ResourceRequestBuilder resourceName(String resourceName) { |
| resourceRequest.setResourceName(resourceName); |
| return this; |
| } |
| |
| /** |
| * Set the <code>capability</code> of the request. |
| * @see ResourceRequest#setCapability(Resource) |
| * @param capability <code>capability</code> of the request |
| * @return {@link ResourceRequestBuilder} |
| */ |
| @Public |
| @Stable |
| public ResourceRequestBuilder capability(Resource capability) { |
| resourceRequest.setCapability(capability); |
| return this; |
| } |
| |
| /** |
| * Set the <code>numContainers</code> of the request. |
| * @see ResourceRequest#setNumContainers(int) |
| * @param numContainers <code>numContainers</code> of the request |
| * @return {@link ResourceRequestBuilder} |
| */ |
| @Public |
| @Stable |
| public ResourceRequestBuilder numContainers(int numContainers) { |
| resourceRequest.setNumContainers(numContainers); |
| return this; |
| } |
| |
| /** |
| * Set the <code>relaxLocality</code> of the request. |
| * @see ResourceRequest#setRelaxLocality(boolean) |
| * @param relaxLocality <code>relaxLocality</code> of the request |
| * @return {@link ResourceRequestBuilder} |
| */ |
| @Public |
| @Stable |
| public ResourceRequestBuilder relaxLocality(boolean relaxLocality) { |
| resourceRequest.setRelaxLocality(relaxLocality); |
| return this; |
| } |
| |
| /** |
| * Set the <code>nodeLabelExpression</code> of the request. |
| * @see ResourceRequest#setNodeLabelExpression(String) |
| * @param nodeLabelExpression |
| * <code>nodeLabelExpression</code> of the request |
| * @return {@link ResourceRequestBuilder} |
| */ |
| @Public |
| @Evolving |
| public ResourceRequestBuilder nodeLabelExpression( |
| String nodeLabelExpression) { |
| resourceRequest.setNodeLabelExpression(nodeLabelExpression); |
| return this; |
| } |
| |
| /** |
| * Set the <code>executionTypeRequest</code> of the request. |
| * @see ResourceRequest#setExecutionTypeRequest( |
| * ExecutionTypeRequest) |
| * @param executionTypeRequest |
| * <code>executionTypeRequest</code> of the request |
| * @return {@link ResourceRequestBuilder} |
| */ |
| @Public |
| @Evolving |
| public ResourceRequestBuilder executionTypeRequest( |
| ExecutionTypeRequest executionTypeRequest) { |
| resourceRequest.setExecutionTypeRequest(executionTypeRequest); |
| return this; |
| } |
| |
| /** |
| * Set the <code>allocationRequestId</code> of the request. |
| * @see ResourceRequest#setAllocationRequestId(long) |
| * @param allocationRequestId |
| * <code>allocationRequestId</code> of the request |
| * @return {@link ResourceRequestBuilder} |
| */ |
| @Public |
| @Evolving |
| public ResourceRequestBuilder allocationRequestId( |
| long allocationRequestId) { |
| resourceRequest.setAllocationRequestId(allocationRequestId); |
| return this; |
| } |
| |
| /** |
| * Set the <code>resourceProfile</code> of the request. |
| * @see ResourceRequest#setProfileCapability(ProfileCapability) |
| * @param profileCapability |
| * <code>profileCapability</code> of the request |
| * @return {@link ResourceRequestBuilder} |
| */ |
| @Public |
| @Evolving |
| public ResourceRequestBuilder profileCapability( |
| ProfileCapability profileCapability) { |
| resourceRequest.setProfileCapability(profileCapability); |
| return this; |
| } |
| |
| /** |
| * Return generated {@link ResourceRequest} object. |
| * @return {@link ResourceRequest} |
| */ |
| @Public |
| @Stable |
| public ResourceRequest build() { |
| return resourceRequest; |
| } |
| } |
| |
| @Public |
| @Stable |
| public static class ResourceRequestComparator implements |
| java.util.Comparator<ResourceRequest>, Serializable { |
| |
| private static final long serialVersionUID = 1L; |
| |
| @Override |
| public int compare(ResourceRequest r1, ResourceRequest r2) { |
| |
| // Compare priority, host and capability |
| int ret = r1.getPriority().compareTo(r2.getPriority()); |
| if (ret == 0) { |
| ret = Long.compare( |
| r1.getAllocationRequestId(), r2.getAllocationRequestId()); |
| } |
| if (ret == 0) { |
| String h1 = r1.getResourceName(); |
| String h2 = r2.getResourceName(); |
| ret = h1.compareTo(h2); |
| } |
| if (ret == 0) { |
| ret = r1.getExecutionTypeRequest() |
| .compareTo(r2.getExecutionTypeRequest()); |
| } |
| if (ret == 0) { |
| ret = r1.getCapability().compareTo(r2.getCapability()); |
| } |
| return ret; |
| } |
| } |
| |
| /** |
| * The constant string representing no locality. |
| * It should be used by all references that want to pass an arbitrary host |
| * name in. |
| */ |
| public static final String ANY = "*"; |
| |
| /** |
| * Check whether the given <em>host/rack</em> string represents an arbitrary |
| * host name. |
| * |
| * @param hostName <em>host/rack</em> on which the allocation is desired |
| * @return whether the given <em>host/rack</em> string represents an arbitrary |
| * host name |
| */ |
| @Public |
| @Stable |
| public static boolean isAnyLocation(String hostName) { |
| return ANY.equals(hostName); |
| } |
| |
| /** |
| * Get the <code>Priority</code> of the request. |
| * @return <code>Priority</code> of the request |
| */ |
| @Public |
| @Stable |
| public abstract Priority getPriority(); |
| |
| /** |
| * Set the <code>Priority</code> of the request |
| * @param priority <code>Priority</code> of the request |
| */ |
| @Public |
| @Stable |
| public abstract void setPriority(Priority priority); |
| |
| /** |
| * Get the resource (e.g. <em>host/rack</em>) on which the allocation |
| * is desired. |
| * |
| * A special value of <em>*</em> signifies that <em>any</em> resource |
| * (host/rack) is acceptable. |
| * |
| * @return resource (e.g. <em>host/rack</em>) on which the allocation |
| * is desired |
| */ |
| @Public |
| @Stable |
| public abstract String getResourceName(); |
| |
| /** |
| * Set the resource name (e.g. <em>host/rack</em>) on which the allocation |
| * is desired. |
| * |
| * A special value of <em>*</em> signifies that <em>any</em> resource name |
| * (e.g. host/rack) is acceptable. |
| * |
| * @param resourceName (e.g. <em>host/rack</em>) on which the |
| * allocation is desired |
| */ |
| @Public |
| @Stable |
| public abstract void setResourceName(String resourceName); |
| |
| /** |
| * Get the number of containers required with the given specifications. |
| * @return number of containers required with the given specifications |
| */ |
| @Public |
| @Stable |
| public abstract int getNumContainers(); |
| |
| /** |
| * Set the number of containers required with the given specifications |
| * @param numContainers number of containers required with the given |
| * specifications |
| */ |
| @Public |
| @Stable |
| public abstract void setNumContainers(int numContainers); |
| |
| /** |
| * Get whether locality relaxation is enabled with this |
| * <code>ResourceRequest</code>. Defaults to true. |
| * |
| * @return whether locality relaxation is enabled with this |
| * <code>ResourceRequest</code>. |
| */ |
| @Public |
| @Stable |
| public abstract boolean getRelaxLocality(); |
| |
| /** |
| * Set the <code>ExecutionTypeRequest</code> of the requested container. |
| * |
| * @param execSpec |
| * ExecutionTypeRequest of the requested container |
| */ |
| @Public |
| @Evolving |
| public void setExecutionTypeRequest(ExecutionTypeRequest execSpec) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| /** |
| * Get whether locality relaxation is enabled with this |
| * <code>ResourceRequest</code>. Defaults to true. |
| * |
| * @return whether locality relaxation is enabled with this |
| * <code>ResourceRequest</code>. |
| */ |
| @Public |
| @Evolving |
| public ExecutionTypeRequest getExecutionTypeRequest() { |
| throw new UnsupportedOperationException(); |
| } |
| |
| /** |
| * <p>For a request at a network hierarchy level, set whether locality can be relaxed |
| * to that level and beyond.<p> |
| * |
| * <p>If the flag is off on a rack-level <code>ResourceRequest</code>, |
| * containers at that request's priority will not be assigned to nodes on that |
| * request's rack unless requests specifically for those nodes have also been |
| * submitted.<p> |
| * |
| * <p>If the flag is off on an {@link ResourceRequest#ANY}-level |
| * <code>ResourceRequest</code>, containers at that request's priority will |
| * only be assigned on racks for which specific requests have also been |
| * submitted.<p> |
| * |
| * <p>For example, to request a container strictly on a specific node, the |
| * corresponding rack-level and any-level requests should have locality |
| * relaxation set to false. Similarly, to request a container strictly on a |
| * specific rack, the corresponding any-level request should have locality |
| * relaxation set to false.<p> |
| * |
| * @param relaxLocality whether locality relaxation is enabled with this |
| * <code>ResourceRequest</code>. |
| */ |
| @Public |
| @Stable |
| public abstract void setRelaxLocality(boolean relaxLocality); |
| |
| /** |
| * Get node-label-expression for this Resource Request. If this is set, all |
| * containers allocated to satisfy this resource-request will be only on those |
| * nodes that satisfy this node-label-expression. |
| * |
| * Please note that node label expression now can only take effect when the |
| * resource request has resourceName = ANY |
| * |
| * @return node-label-expression |
| */ |
| @Public |
| @Evolving |
| public abstract String getNodeLabelExpression(); |
| |
| /** |
| * Set node label expression of this resource request. Now only support |
| * specifying a single node label. In the future we will support more complex |
| * node label expression specification like {@code AND(&&), OR(||)}, etc. |
| * |
| * Any please note that node label expression now can only take effect when |
| * the resource request has resourceName = ANY |
| * |
| * @param nodelabelExpression |
| * node-label-expression of this ResourceRequest |
| */ |
| @Public |
| @Evolving |
| public abstract void setNodeLabelExpression(String nodelabelExpression); |
| |
| @Public |
| @Evolving |
| public abstract ProfileCapability getProfileCapability(); |
| |
| @Public |
| @Evolving |
| public abstract void setProfileCapability(ProfileCapability p); |
| |
| /** |
| * Get the optional <em>ID</em> corresponding to this allocation request. This |
| * ID is an identifier for different {@code ResourceRequest}s from the <b>same |
| * application</b>. The allocated {@code Container}(s) received as part of the |
| * {@code AllocateResponse} response will have the ID corresponding to the |
| * original {@code ResourceRequest} for which the RM made the allocation. |
| * <p> |
| * The scheduler may return multiple {@code AllocateResponse}s corresponding |
| * to the same ID as and when scheduler allocates {@code Container}(s). |
| * <b>Applications</b> can continue to completely ignore the returned ID in |
| * the response and use the allocation for any of their outstanding requests. |
| * <p> |
| * If one wishes to replace an entire {@code ResourceRequest} corresponding to |
| * a specific ID, they can simply cancel the corresponding {@code |
| * ResourceRequest} and submit a new one afresh. |
| * |
| * @return the <em>ID</em> corresponding to this allocation request. |
| */ |
| @Public |
| @Evolving |
| public long getAllocationRequestId() { |
| throw new UnsupportedOperationException(); |
| } |
| |
| /** |
| * Set the optional <em>ID</em> corresponding to this allocation request. This |
| * ID is an identifier for different {@code ResourceRequest}s from the <b>same |
| * application</b>. The allocated {@code Container}(s) received as part of the |
| * {@code AllocateResponse} response will have the ID corresponding to the |
| * original {@code ResourceRequest} for which the RM made the allocation. |
| * <p> |
| * The scheduler may return multiple {@code AllocateResponse}s corresponding |
| * to the same ID as and when scheduler allocates {@code Container}(s). |
| * <b>Applications</b> can continue to completely ignore the returned ID in |
| * the response and use the allocation for any of their outstanding requests. |
| * <p> |
| * If one wishes to replace an entire {@code ResourceRequest} corresponding to |
| * a specific ID, they can simply cancel the corresponding {@code |
| * ResourceRequest} and submit a new one afresh. |
| * <p> |
| * If the ID is not set, scheduler will continue to work as previously and all |
| * allocated {@code Container}(s) will have the default ID, -1. |
| * |
| * @param allocationRequestID the <em>ID</em> corresponding to this allocation |
| * request. |
| */ |
| @Public |
| @Evolving |
| public void setAllocationRequestId(long allocationRequestID) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public int hashCode() { |
| final int prime = 2153; |
| int result = 2459; |
| Resource capability = getCapability(); |
| String hostName = getResourceName(); |
| Priority priority = getPriority(); |
| ProfileCapability profile = getProfileCapability(); |
| result = |
| prime * result + ((capability == null) ? 0 : capability.hashCode()); |
| result = prime * result + ((hostName == null) ? 0 : hostName.hashCode()); |
| result = prime * result + getNumContainers(); |
| result = prime * result + ((priority == null) ? 0 : priority.hashCode()); |
| result = prime * result + Long.valueOf(getAllocationRequestId()).hashCode(); |
| result = prime * result + ((profile == null) ? 0 : profile.hashCode()); |
| return result; |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (this == obj) |
| return true; |
| if (obj == null) |
| return false; |
| if (getClass() != obj.getClass()) |
| return false; |
| ResourceRequest other = (ResourceRequest) obj; |
| Resource capability = getCapability(); |
| if (capability == null) { |
| if (other.getCapability() != null) |
| return false; |
| } else if (!capability.equals(other.getCapability())) |
| return false; |
| String hostName = getResourceName(); |
| if (hostName == null) { |
| if (other.getResourceName() != null) |
| return false; |
| } else if (!hostName.equals(other.getResourceName())) |
| return false; |
| if (getNumContainers() != other.getNumContainers()) |
| return false; |
| Priority priority = getPriority(); |
| if (priority == null) { |
| if (other.getPriority() != null) |
| return false; |
| } else if (!priority.equals(other.getPriority())) |
| return false; |
| ExecutionTypeRequest execTypeRequest = getExecutionTypeRequest(); |
| if (execTypeRequest == null) { |
| if (other.getExecutionTypeRequest() != null) { |
| return false; |
| } |
| } else if (!execTypeRequest.getExecutionType() |
| .equals(other.getExecutionTypeRequest().getExecutionType())) { |
| return false; |
| } |
| |
| if (getAllocationRequestId() != other.getAllocationRequestId()) { |
| return false; |
| } |
| |
| if (getNodeLabelExpression() == null) { |
| if (other.getNodeLabelExpression() != null) { |
| return false; |
| } |
| } else { |
| // do normalize on label expression before compare |
| String label1 = getNodeLabelExpression().replaceAll("[\\t ]", ""); |
| String label2 = |
| other.getNodeLabelExpression() == null ? null : other |
| .getNodeLabelExpression().replaceAll("[\\t ]", ""); |
| if (!label1.equals(label2)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| @Override |
| public int compareTo(ResourceRequest other) { |
| int priorityComparison = this.getPriority().compareTo(other.getPriority()); |
| if (priorityComparison == 0) { |
| int hostNameComparison = |
| this.getResourceName().compareTo(other.getResourceName()); |
| if (hostNameComparison == 0) { |
| int execTypeReqComparison = this.getExecutionTypeRequest() |
| .compareTo(other.getExecutionTypeRequest()); |
| if (execTypeReqComparison == 0) { |
| int capabilityComparison = |
| this.getCapability().compareTo(other.getCapability()); |
| if (capabilityComparison == 0) { |
| int numContainerComparison = |
| this.getNumContainers() - other.getNumContainers(); |
| if (numContainerComparison == 0) { |
| return Long.compare(getAllocationRequestId(), |
| other.getAllocationRequestId()); |
| } else { |
| return numContainerComparison; |
| } |
| } else { |
| return capabilityComparison; |
| } |
| } else { |
| return execTypeReqComparison; |
| } |
| } else { |
| return hostNameComparison; |
| } |
| } else { |
| return priorityComparison; |
| } |
| } |
| } |