diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-jobclient/src/main/java/org/apache/hadoop/mapred/ResourceMgrDelegate.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-jobclient/src/main/java/org/apache/hadoop/mapred/ResourceMgrDelegate.java
index 62aa4972929..94f741a03e6 100644
--- a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-jobclient/src/main/java/org/apache/hadoop/mapred/ResourceMgrDelegate.java
+++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-jobclient/src/main/java/org/apache/hadoop/mapred/ResourceMgrDelegate.java
@@ -66,6 +66,8 @@
import org.apache.hadoop.yarn.api.records.NodeState;
import org.apache.hadoop.yarn.api.records.Priority;
import org.apache.hadoop.yarn.api.records.QueueUserACLInfo;
+import org.apache.hadoop.yarn.api.records.Resource;
+import org.apache.hadoop.yarn.api.records.ResourceTypeInfo;
import org.apache.hadoop.yarn.api.records.SignalContainerCommand;
import org.apache.hadoop.yarn.api.records.YarnApplicationState;
import org.apache.hadoop.yarn.api.records.YarnClusterMetrics;
@@ -517,4 +519,22 @@ public void killApplication(ApplicationId appId, String diagnostics)
throws YarnException, IOException {
client.killApplication(appId, diagnostics);
}
+
+ @Override
+ public Map getResourceProfiles()
+ throws YarnException, IOException {
+ return client.getResourceProfiles();
+ }
+
+ @Override
+ public Resource getResourceProfile(String profile)
+ throws YarnException, IOException {
+ return client.getResourceProfile(profile);
+ }
+
+ @Override
+ public List getResourceTypeInfo()
+ throws YarnException, IOException {
+ return client.getResourceTypeInfo();
+ }
}
diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-jobclient/src/test/java/org/apache/hadoop/mapred/TestClientRedirect.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-jobclient/src/test/java/org/apache/hadoop/mapred/TestClientRedirect.java
index 65eac654845..a9b4626581b 100644
--- a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-jobclient/src/test/java/org/apache/hadoop/mapred/TestClientRedirect.java
+++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-jobclient/src/test/java/org/apache/hadoop/mapred/TestClientRedirect.java
@@ -72,6 +72,10 @@
import org.apache.hadoop.yarn.api.protocolrecords.CancelDelegationTokenResponse;
import org.apache.hadoop.yarn.api.protocolrecords.FailApplicationAttemptRequest;
import org.apache.hadoop.yarn.api.protocolrecords.FailApplicationAttemptResponse;
+import org.apache.hadoop.yarn.api.protocolrecords.GetAllResourceProfilesRequest;
+import org.apache.hadoop.yarn.api.protocolrecords.GetAllResourceProfilesResponse;
+import org.apache.hadoop.yarn.api.protocolrecords.GetAllResourceTypeInfoRequest;
+import org.apache.hadoop.yarn.api.protocolrecords.GetAllResourceTypeInfoResponse;
import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationAttemptReportRequest;
import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationAttemptReportResponse;
import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationAttemptsRequest;
@@ -104,6 +108,8 @@
import org.apache.hadoop.yarn.api.protocolrecords.GetQueueInfoResponse;
import org.apache.hadoop.yarn.api.protocolrecords.GetQueueUserAclsInfoRequest;
import org.apache.hadoop.yarn.api.protocolrecords.GetQueueUserAclsInfoResponse;
+import org.apache.hadoop.yarn.api.protocolrecords.GetResourceProfileRequest;
+import org.apache.hadoop.yarn.api.protocolrecords.GetResourceProfileResponse;
import org.apache.hadoop.yarn.api.protocolrecords.KillApplicationRequest;
import org.apache.hadoop.yarn.api.protocolrecords.KillApplicationResponse;
import org.apache.hadoop.yarn.api.protocolrecords.MoveApplicationAcrossQueuesRequest;
@@ -494,6 +500,26 @@ public UpdateApplicationTimeoutsResponse updateApplicationTimeouts(
throws YarnException, IOException {
return null;
}
+
+ @Override
+ public GetAllResourceProfilesResponse getResourceProfiles(
+ GetAllResourceProfilesRequest request)
+ throws YarnException, IOException {
+ return null;
+ }
+
+ @Override
+ public GetResourceProfileResponse getResourceProfile(
+ GetResourceProfileRequest request) throws YarnException, IOException {
+ return null;
+ }
+
+ @Override
+ public GetAllResourceTypeInfoResponse getResourceTypeInfo(
+ GetAllResourceTypeInfoRequest request)
+ throws YarnException, IOException {
+ return null;
+ }
}
class HistoryService extends AMService implements HSClientProtocol {
diff --git a/hadoop-yarn-project/hadoop-yarn/dev-support/findbugs-exclude.xml b/hadoop-yarn-project/hadoop-yarn/dev-support/findbugs-exclude.xml
index 6825a36ebdd..a5b40210ff4 100644
--- a/hadoop-yarn-project/hadoop-yarn/dev-support/findbugs-exclude.xml
+++ b/hadoop-yarn-project/hadoop-yarn/dev-support/findbugs-exclude.xml
@@ -154,6 +154,10 @@
+
+
+
+
@@ -599,4 +603,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/ams/ApplicationMasterServiceProcessor.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/ams/ApplicationMasterServiceProcessor.java
index b7d925a6592..8e76a11dc27 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/ams/ApplicationMasterServiceProcessor.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/ams/ApplicationMasterServiceProcessor.java
@@ -52,11 +52,13 @@ void init(ApplicationMasterServiceContext amsContext,
* @param request Register Request.
* @param response Register Response.
* @throws IOException IOException.
+ * @throws YarnException in critical situation where invalid
+ * profiles/resources are added.
*/
- void registerApplicationMaster(
- ApplicationAttemptId applicationAttemptId,
+ void registerApplicationMaster(ApplicationAttemptId applicationAttemptId,
RegisterApplicationMasterRequest request,
- RegisterApplicationMasterResponse response) throws IOException;
+ RegisterApplicationMasterResponse response)
+ throws IOException, YarnException;
/**
* Allocate call.
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/ApplicationClientProtocol.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/ApplicationClientProtocol.java
index 394454f20bc..8456a8ec59f 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/ApplicationClientProtocol.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/ApplicationClientProtocol.java
@@ -65,6 +65,12 @@
import org.apache.hadoop.yarn.api.protocolrecords.SignalContainerResponse;
import org.apache.hadoop.yarn.api.protocolrecords.SubmitApplicationRequest;
import org.apache.hadoop.yarn.api.protocolrecords.SubmitApplicationResponse;
+import org.apache.hadoop.yarn.api.protocolrecords.GetAllResourceProfilesRequest;
+import org.apache.hadoop.yarn.api.protocolrecords.GetAllResourceProfilesResponse;
+import org.apache.hadoop.yarn.api.protocolrecords.GetAllResourceTypeInfoRequest;
+import org.apache.hadoop.yarn.api.protocolrecords.GetAllResourceTypeInfoResponse;
+import org.apache.hadoop.yarn.api.protocolrecords.GetResourceProfileRequest;
+import org.apache.hadoop.yarn.api.protocolrecords.GetResourceProfileResponse;
import org.apache.hadoop.yarn.api.records.ApplicationAttemptId;
import org.apache.hadoop.yarn.api.records.ApplicationId;
import org.apache.hadoop.yarn.api.records.ApplicationSubmissionContext;
@@ -75,6 +81,7 @@
import org.apache.hadoop.yarn.api.records.YarnClusterMetrics;
import org.apache.hadoop.yarn.exceptions.ApplicationNotFoundException;
import org.apache.hadoop.yarn.exceptions.YarnException;
+import org.apache.hadoop.yarn.exceptions.YARNFeatureNotEnabledException;
/**
* The protocol between clients and the ResourceManager
@@ -589,4 +596,50 @@ SignalContainerResponse signalToContainer(
public UpdateApplicationTimeoutsResponse updateApplicationTimeouts(
UpdateApplicationTimeoutsRequest request)
throws YarnException, IOException;
+
+ /**
+ *
+ * The interface used by clients to get all the resource profiles that are
+ * available on the ResourceManager.
+ *
+ * @param request request to get all the resource profiles
+ * @return Response containing a map of the profile name to Resource
+ * capabilities
+ * @throws YARNFeatureNotEnabledException if resource-profile is disabled
+ * @throws YarnException if any error happens inside YARN
+ * @throws IOException in case of other errors
+ */
+ @Public
+ @Unstable
+ GetAllResourceProfilesResponse getResourceProfiles(
+ GetAllResourceProfilesRequest request) throws YarnException, IOException;
+
+ /**
+ *
+ * The interface to get the details for a specific resource profile.
+ *
+ * @param request request to get the details of a resource profile
+ * @return Response containing the details for a particular resource profile
+ * @throws YARNFeatureNotEnabledException if resource-profile is disabled
+ * @throws YarnException if any error happens inside YARN
+ * @throws IOException in case of other errors
+ */
+ @Public
+ @Unstable
+ GetResourceProfileResponse getResourceProfile(
+ GetResourceProfileRequest request) throws YarnException, IOException;
+
+ /**
+ *
+ * The interface to get the details for a specific resource profile.
+ *
+ * @param request request to get the details of a resource profile
+ * @return Response containing the details for a particular resource profile
+ * @throws YarnException if any error happens inside YARN
+ * @throws IOException in case of other errors
+ */
+ @Public
+ @Unstable
+ GetAllResourceTypeInfoResponse getResourceTypeInfo(
+ GetAllResourceTypeInfoRequest request) throws YarnException, IOException;
}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/GetAllResourceProfilesRequest.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/GetAllResourceProfilesRequest.java
new file mode 100644
index 00000000000..0bb9bf805d9
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/GetAllResourceProfilesRequest.java
@@ -0,0 +1,35 @@
+/**
+ * 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.protocolrecords;
+
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.yarn.util.Records;
+
+/**
+ * Request class for getting all the resource profiles from the RM.
+ */
+@InterfaceAudience.Public
+@InterfaceStability.Unstable
+public abstract class GetAllResourceProfilesRequest {
+
+ public static GetAllResourceProfilesRequest newInstance() {
+ return Records.newRecord(GetAllResourceProfilesRequest.class);
+ }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/GetAllResourceProfilesResponse.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/GetAllResourceProfilesResponse.java
new file mode 100644
index 00000000000..547770890d5
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/GetAllResourceProfilesResponse.java
@@ -0,0 +1,60 @@
+/**
+ * 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.protocolrecords;
+
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.yarn.api.records.Resource;
+import org.apache.hadoop.yarn.util.Records;
+
+import java.util.Map;
+
+/**
+ * Response class for getting all the resource profiles from the RM.
+ */
+@InterfaceAudience.Public
+@InterfaceStability.Unstable
+public abstract class GetAllResourceProfilesResponse {
+
+ public static GetAllResourceProfilesResponse newInstance() {
+ return Records.newRecord(GetAllResourceProfilesResponse.class);
+ }
+
+ public abstract void setResourceProfiles(Map profiles);
+
+ public abstract Map getResourceProfiles();
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (other == null || !(other instanceof GetAllResourceProfilesResponse)) {
+ return false;
+ }
+ return ((GetAllResourceProfilesResponse) other).getResourceProfiles()
+ .equals(this.getResourceProfiles());
+ }
+
+ @Override
+ public int hashCode() {
+ return this.getResourceProfiles().hashCode();
+ }
+
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/GetAllResourceTypeInfoRequest.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/GetAllResourceTypeInfoRequest.java
new file mode 100644
index 00000000000..3bda4f54ec5
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/GetAllResourceTypeInfoRequest.java
@@ -0,0 +1,35 @@
+/**
+ * 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.protocolrecords;
+
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.yarn.util.Records;
+
+/**
+ * Request class for getting all the resource profiles from the RM.
+ */
+@InterfaceAudience.Public
+@InterfaceStability.Unstable
+public abstract class GetAllResourceTypeInfoRequest {
+
+ public static GetAllResourceTypeInfoRequest newInstance() {
+ return Records.newRecord(GetAllResourceTypeInfoRequest.class);
+ }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/GetAllResourceTypeInfoResponse.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/GetAllResourceTypeInfoResponse.java
new file mode 100644
index 00000000000..b57b96df3fd
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/GetAllResourceTypeInfoResponse.java
@@ -0,0 +1,60 @@
+/**
+ * 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.protocolrecords;
+
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.yarn.api.records.ResourceTypeInfo;
+import org.apache.hadoop.yarn.util.Records;
+
+import java.util.List;
+
+/**
+ * Response class for getting all the resource profiles from the RM.
+ */
+@InterfaceAudience.Public
+@InterfaceStability.Unstable
+public abstract class GetAllResourceTypeInfoResponse {
+
+ public static GetAllResourceTypeInfoResponse newInstance() {
+ return Records.newRecord(GetAllResourceTypeInfoResponse.class);
+ }
+
+ public abstract void setResourceTypeInfo(List resourceTypes);
+
+ public abstract List getResourceTypeInfo();
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (other == null || !(other instanceof GetAllResourceTypeInfoResponse)) {
+ return false;
+ }
+ return ((GetAllResourceTypeInfoResponse) other).getResourceTypeInfo()
+ .equals(this.getResourceTypeInfo());
+ }
+
+ @Override
+ public int hashCode() {
+ return this.getResourceTypeInfo().hashCode();
+ }
+
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/GetResourceProfileRequest.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/GetResourceProfileRequest.java
new file mode 100644
index 00000000000..3655be946da
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/GetResourceProfileRequest.java
@@ -0,0 +1,59 @@
+/**
+ * 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.protocolrecords;
+
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.yarn.util.Records;
+
+/**
+ * Request class for getting the details for a particular resource profile.
+ */
+@InterfaceAudience.Public
+@InterfaceStability.Unstable
+public abstract class GetResourceProfileRequest {
+
+ public static GetResourceProfileRequest newInstance(String profile) {
+ GetResourceProfileRequest request =
+ Records.newRecord(GetResourceProfileRequest.class);
+ request.setProfileName(profile);
+ return request;
+ }
+
+ public abstract void setProfileName(String profileName);
+
+ public abstract String getProfileName();
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (other == null || !(other instanceof GetResourceProfileRequest)) {
+ return false;
+ }
+ return this.getProfileName()
+ .equals(((GetResourceProfileRequest) other).getProfileName());
+ }
+
+ @Override
+ public int hashCode() {
+ return getProfileName().hashCode();
+ }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/GetResourceProfileResponse.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/GetResourceProfileResponse.java
new file mode 100644
index 00000000000..a010644a792
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/GetResourceProfileResponse.java
@@ -0,0 +1,68 @@
+/**
+ * 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.protocolrecords;
+
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.yarn.api.records.Resource;
+import org.apache.hadoop.yarn.util.Records;
+
+/**
+ * Response class for getting the details for a particular resource profile.
+ */
+@InterfaceAudience.Public
+@InterfaceStability.Unstable
+public abstract class GetResourceProfileResponse {
+
+ public static GetResourceProfileResponse newInstance() {
+ return Records.newRecord(GetResourceProfileResponse.class);
+ }
+
+ /**
+ * Get the resources that will be allocated if the profile was used.
+ *
+ * @return the resources that will be allocated if the profile was used.
+ */
+ public abstract Resource getResource();
+
+ /**
+ * Set the resources that will be allocated if the profile is used.
+ *
+ * @param r Set the resources that will be allocated if the profile is used.
+ */
+ public abstract void setResource(Resource r);
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+
+ if (other == null || !(other instanceof GetResourceProfileResponse)) {
+ return false;
+ }
+ return this.getResource()
+ .equals(((GetResourceProfileResponse) other).getResource());
+ }
+
+ @Override
+ public int hashCode() {
+ return getResource().hashCode();
+ }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/RegisterApplicationMasterResponse.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/RegisterApplicationMasterResponse.java
index 0b886dd5c90..8fa8563e2d3 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/RegisterApplicationMasterResponse.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/RegisterApplicationMasterResponse.java
@@ -204,4 +204,12 @@ public abstract void setContainersFromPreviousAttempts(
@Unstable
public abstract void setSchedulerResourceTypes(
EnumSet types);
+
+ @Public
+ @Unstable
+ public abstract Map getResourceProfiles();
+
+ @Private
+ @Unstable
+ public abstract void setResourceProfiles(Map profiles);
}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/ResourceTypes.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/ResourceTypes.java
new file mode 100644
index 00000000000..dbd9c37ceec
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/ResourceTypes.java
@@ -0,0 +1,27 @@
+/**
+ * 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.protocolrecords;
+
+/**
+ * Enum which represents the resource type. Currently, the only type allowed is
+ * COUNTABLE.
+ */
+public enum ResourceTypes {
+ COUNTABLE
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/ApplicationResourceUsageReport.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/ApplicationResourceUsageReport.java
index 3cf8f3defa3..d2e33ff9bca 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/ApplicationResourceUsageReport.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/ApplicationResourceUsageReport.java
@@ -24,6 +24,8 @@
import org.apache.hadoop.classification.InterfaceStability.Unstable;
import org.apache.hadoop.yarn.util.Records;
+import java.util.Map;
+
/**
* Contains various scheduling metrics to be reported by UI and CLI.
*/
@@ -35,9 +37,9 @@
@Unstable
public static ApplicationResourceUsageReport newInstance(
int numUsedContainers, int numReservedContainers, Resource usedResources,
- Resource reservedResources, Resource neededResources, long memorySeconds,
- long vcoreSeconds, float queueUsagePerc, float clusterUsagePerc,
- long preemptedMemorySeconds, long preemptedVcoresSeconds) {
+ Resource reservedResources, Resource neededResources,
+ Map resourceSecondsMap, float queueUsagePerc,
+ float clusterUsagePerc, Map preemtedResourceSecondsMap) {
ApplicationResourceUsageReport report =
Records.newRecord(ApplicationResourceUsageReport.class);
report.setNumUsedContainers(numUsedContainers);
@@ -45,12 +47,10 @@ public static ApplicationResourceUsageReport newInstance(
report.setUsedResources(usedResources);
report.setReservedResources(reservedResources);
report.setNeededResources(neededResources);
- report.setMemorySeconds(memorySeconds);
- report.setVcoreSeconds(vcoreSeconds);
+ report.setResourceSecondsMap(resourceSecondsMap);
report.setQueueUsagePercentage(queueUsagePerc);
report.setClusterUsagePercentage(clusterUsagePerc);
- report.setPreemptedMemorySeconds(preemptedMemorySeconds);
- report.setPreemptedVcoreSeconds(preemptedVcoresSeconds);
+ report.setPreemptedResourceSecondsMap(preemtedResourceSecondsMap);
return report;
}
@@ -229,4 +229,47 @@ public static ApplicationResourceUsageReport newInstance(
@Public
@Unstable
public abstract long getPreemptedVcoreSeconds();
+
+ /**
+ * Get the aggregated number of resources that the application has
+ * allocated times the number of seconds the application has been running.
+ * @return map containing the resource name and aggregated resource-seconds
+ */
+ @Public
+ @Unstable
+ public abstract Map getResourceSecondsMap();
+
+ /**
+ * Set the aggregated number of resources that the application has
+ * allocated times the number of seconds the application has been running.
+ * @param resourceSecondsMap map containing the resource name and aggregated
+ * resource-seconds
+ */
+ @Private
+ @Unstable
+ public abstract void setResourceSecondsMap(
+ Map resourceSecondsMap);
+
+
+ /**
+ * Get the aggregated number of resources preempted that the application has
+ * allocated times the number of seconds the application has been running.
+ * @return map containing the resource name and aggregated preempted
+ * resource-seconds
+ */
+ @Public
+ @Unstable
+ public abstract Map getPreemptedResourceSecondsMap();
+
+ /**
+ * Set the aggregated number of resources preempted that the application has
+ * allocated times the number of seconds the application has been running.
+ * @param preemptedResourceSecondsMap map containing the resource name and
+ * aggregated preempted resource-seconds
+ */
+ @Private
+ @Unstable
+ public abstract void setPreemptedResourceSecondsMap(
+ Map preemptedResourceSecondsMap);
+
}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/ProfileCapability.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/ProfileCapability.java
new file mode 100644
index 00000000000..2cb46704716
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/ProfileCapability.java
@@ -0,0 +1,174 @@
+/**
+ * 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 com.google.common.base.Preconditions;
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.yarn.util.Records;
+
+import java.util.Map;
+
+/**
+ * Class to capture capability requirements when using resource profiles. The
+ * ProfileCapability is meant to be used as part of the ResourceRequest. A
+ * profile capability has two pieces - the resource profile name and the
+ * overrides. The resource profile specifies the name of the resource profile
+ * to be used and the capability override is the overrides desired on specific
+ * resource types.
+ *
+ * For example, if you have a resource profile "small" that maps to
+ * {@literal <4096M, 2 cores, 1 gpu>} and you set the capability override to
+ * {@literal <8192M, 0 cores, 0 gpu>}, then the actual resource allocation on
+ * the ResourceManager will be {@literal <8192M, 2 cores, 1 gpu>}.
+ *
+ * Note that the conversion from the ProfileCapability to the Resource class
+ * with the actual resource requirements will be done by the ResourceManager,
+ * which has the actual profile to Resource mapping.
+ *
+ */
+@InterfaceAudience.Public
+@InterfaceStability.Unstable
+public abstract class ProfileCapability {
+
+ public static final String DEFAULT_PROFILE = "default";
+
+ public static ProfileCapability newInstance(Resource override) {
+ return newInstance(DEFAULT_PROFILE, override);
+ }
+
+ public static ProfileCapability newInstance(String profile) {
+ Preconditions
+ .checkArgument(profile != null, "The profile name cannot be null");
+ ProfileCapability obj = Records.newRecord(ProfileCapability.class);
+ obj.setProfileName(profile);
+ obj.setProfileCapabilityOverride(Resource.newInstance(0, 0));
+ return obj;
+ }
+
+ public static ProfileCapability newInstance(String profile,
+ Resource override) {
+ Preconditions
+ .checkArgument(profile != null, "The profile name cannot be null");
+ ProfileCapability obj = Records.newRecord(ProfileCapability.class);
+ obj.setProfileName(profile);
+ obj.setProfileCapabilityOverride(override);
+ return obj;
+ }
+
+ /**
+ * Get the profile name.
+ * @return the profile name
+ */
+ public abstract String getProfileName();
+
+ /**
+ * Get the profile capability override.
+ * @return Resource object containing the override.
+ */
+ public abstract Resource getProfileCapabilityOverride();
+
+ /**
+ * Set the resource profile name.
+ * @param profileName the resource profile name
+ */
+ public abstract void setProfileName(String profileName);
+
+ /**
+ * Set the capability override to override specific resource types on the
+ * resource profile.
+ *
+ * For example, if you have a resource profile "small" that maps to
+ * {@literal <4096M, 2 cores, 1 gpu>} and you set the capability override to
+ * {@literal <8192M, 0 cores, 0 gpu>}, then the actual resource allocation on
+ * the ResourceManager will be {@literal <8192M, 2 cores, 1 gpu>}.
+ *
+ * Note that the conversion from the ProfileCapability to the Resource class
+ * with the actual resource requirements will be done by the ResourceManager,
+ * which has the actual profile to Resource mapping.
+ *
+ * @param r Resource object containing the capability override
+ */
+ public abstract void setProfileCapabilityOverride(Resource r);
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (other == null || !(other instanceof ProfileCapability)) {
+ return false;
+ }
+ return ((ProfileCapability) other).getProfileName()
+ .equals(this.getProfileName()) && ((ProfileCapability) other)
+ .getProfileCapabilityOverride()
+ .equals(this.getProfileCapabilityOverride());
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 2153;
+ int result = 2459;
+ String name = getProfileName();
+ Resource override = getProfileCapabilityOverride();
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ result = prime * result + ((override == null) ? 0 : override.hashCode());
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "{ profile: " + this.getProfileName() + ", capabilityOverride: "
+ + this.getProfileCapabilityOverride() + " }";
+ }
+
+ /**
+ * Get a representation of the capability as a Resource object.
+ * @param capability the capability we wish to convert
+ * @param resourceProfilesMap map of profile name to Resource object
+ * @return Resource object representing the capability
+ */
+ public static Resource toResource(ProfileCapability capability,
+ Map resourceProfilesMap) {
+ Preconditions
+ .checkArgument(capability != null, "Capability cannot be null");
+ Preconditions.checkArgument(resourceProfilesMap != null,
+ "Resource profiles map cannot be null");
+ Resource none = Resource.newInstance(0, 0);
+ Resource resource = Resource.newInstance(0, 0);
+ String profileName = capability.getProfileName();
+ if (profileName.isEmpty()) {
+ profileName = DEFAULT_PROFILE;
+ }
+ if (resourceProfilesMap.containsKey(profileName)) {
+ resource = Resource.newInstance(resourceProfilesMap.get(profileName));
+ }
+
+ if (capability.getProfileCapabilityOverride() != null &&
+ !capability.getProfileCapabilityOverride().equals(none)) {
+ for (ResourceInformation entry : capability
+ .getProfileCapabilityOverride().getResources()) {
+ if (entry != null && entry.getValue() >= 0) {
+ resource.setResourceInformation(entry.getName(), entry);
+ }
+ }
+ }
+ return resource;
+ }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/Resource.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/Resource.java
index 0fd41a2f20b..8ad64671757 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/Resource.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/Resource.java
@@ -18,12 +18,19 @@
package org.apache.hadoop.yarn.api.records;
+import java.util.Arrays;
+
import org.apache.commons.lang.NotImplementedException;
+import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceAudience.Public;
+import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.classification.InterfaceStability.Evolving;
import org.apache.hadoop.classification.InterfaceStability.Stable;
import org.apache.hadoop.yarn.api.ApplicationMasterProtocol;
-
+import org.apache.hadoop.yarn.api.records.impl.BaseResource;
+import org.apache.hadoop.yarn.exceptions.ResourceNotFoundException;
+import org.apache.hadoop.yarn.util.Records;
+import org.apache.hadoop.yarn.util.resource.ResourceUtils;
/**
* Resource models a set of computer resources in the
@@ -38,10 +45,10 @@
* the average number of threads it expects to have runnable at a time.
*
* Virtual cores take integer values and thus currently CPU-scheduling is
- * very coarse. A complementary axis for CPU requests that represents processing
- * power will likely be added in the future to enable finer-grained resource
- * configuration.
- *
+ * very coarse. A complementary axis for CPU requests that represents
+ * processing power will likely be added in the future to enable finer-grained
+ * resource configuration.
+ *
* Typically, applications request Resource of suitable
* capability to run their component tasks.
*
@@ -52,64 +59,85 @@
@Stable
public abstract class Resource implements Comparable {
- private static class SimpleResource extends Resource {
- private long memory;
- private long vcores;
- SimpleResource(long memory, long vcores) {
- this.memory = memory;
- this.vcores = vcores;
- }
- @Override
- public int getMemory() {
- return (int)memory;
- }
- @Override
- public void setMemory(int memory) {
- this.memory = memory;
- }
- @Override
- public long getMemorySize() {
- return memory;
- }
- @Override
- public void setMemorySize(long memory) {
- this.memory = memory;
- }
- @Override
- public int getVirtualCores() {
- return (int)vcores;
- }
- @Override
- public void setVirtualCores(int vcores) {
- this.vcores = vcores;
- }
- }
+ protected static final String MEMORY = ResourceInformation.MEMORY_MB.getName();
+ protected static final String VCORES = ResourceInformation.VCORES.getName();
+
+ // Number of mandatory resources, this is added to avoid invoke
+ // MandatoryResources.values().length, since values() internally will
+ // copy array, etc.
+ protected static final int NUM_MANDATORY_RESOURCES = 2;
+
+ protected static final int MEMORY_INDEX = 0;
+ protected static final int VCORES_INDEX = 1;
@Public
@Stable
public static Resource newInstance(int memory, int vCores) {
- return new SimpleResource(memory, vCores);
+ if (ResourceUtils.getNumberOfKnownResourceTypes() > 2) {
+ Resource ret = Records.newRecord(Resource.class);
+ ret.setMemorySize(memory);
+ ret.setVirtualCores(vCores);
+ return ret;
+ }
+ return new BaseResource(memory, vCores);
}
@Public
@Stable
public static Resource newInstance(long memory, int vCores) {
- return new SimpleResource(memory, vCores);
+ if (ResourceUtils.getNumberOfKnownResourceTypes() > 2) {
+ Resource ret = Records.newRecord(Resource.class);
+ ret.setMemorySize(memory);
+ ret.setVirtualCores(vCores);
+ return ret;
+ }
+ return new BaseResource(memory, vCores);
+ }
+
+ @InterfaceAudience.Private
+ @InterfaceStability.Unstable
+ public static Resource newInstance(Resource resource) {
+ Resource ret = Resource.newInstance(resource.getMemorySize(),
+ resource.getVirtualCores());
+ if (ResourceUtils.getNumberOfKnownResourceTypes() > 2) {
+ Resource.copy(resource, ret);
+ }
+ return ret;
+ }
+
+ @InterfaceAudience.Private
+ @InterfaceStability.Unstable
+ public static void copy(Resource source, Resource dest) {
+ for (ResourceInformation entry : source.getResources()) {
+ dest.setResourceInformation(entry.getName(), entry);
+ }
}
/**
* This method is DEPRECATED:
* Use {@link Resource#getMemorySize()} instead
*
- * Get memory of the resource.
- * @return memory of the resource
+ * Get memory of the resource. Note - while memory has
+ * never had a unit specified, all YARN configurations have specified memory
+ * in MB. The assumption has been that the daemons and applications are always
+ * using the same units. With the introduction of the ResourceInformation
+ * class we have support for units - so this function will continue to return
+ * memory but in the units of MB
+ *
+ * @return memory(in MB) of the resource
*/
@Public
@Deprecated
public abstract int getMemory();
/**
- * Get memory of the resource.
+ * Get memory of the resource. Note - while memory has
+ * never had a unit specified, all YARN configurations have specified memory
+ * in MB. The assumption has been that the daemons and applications are always
+ * using the same units. With the introduction of the ResourceInformation
+ * class we have support for units - so this function will continue to return
+ * memory but in the units of MB
+ *
* @return memory of the resource
*/
@Public
@@ -120,8 +148,14 @@ public long getMemorySize() {
}
/**
- * Set memory of the resource.
- * @param memory memory of the resource
+ * Set memory of the resource. Note - while memory has
+ * never had a unit specified, all YARN configurations have specified memory
+ * in MB. The assumption has been that the daemons and applications are always
+ * using the same units. With the introduction of the ResourceInformation
+ * class we have support for units - so this function will continue to set
+ * memory but the assumption is that the value passed is in units of MB.
+ *
+ * @param memory memory(in MB) of the resource
*/
@Public
@Deprecated
@@ -138,72 +172,279 @@ public void setMemorySize(long memory) {
"This method is implemented by ResourcePBImpl");
}
-
/**
* Get number of virtual cpu cores of the resource.
*
* Virtual cores are a unit for expressing CPU parallelism. A node's capacity
- * should be configured with virtual cores equal to its number of physical cores.
- * A container should be requested with the number of cores it can saturate, i.e.
- * the average number of threads it expects to have runnable at a time.
- *
+ * should be configured with virtual cores equal to its number of physical
+ * cores. A container should be requested with the number of cores it can
+ * saturate, i.e. the average number of threads it expects to have runnable
+ * at a time.
+ *
* @return num of virtual cpu cores of the resource
*/
@Public
@Evolving
public abstract int getVirtualCores();
-
+
/**
* Set number of virtual cpu cores of the resource.
*
* Virtual cores are a unit for expressing CPU parallelism. A node's capacity
- * should be configured with virtual cores equal to its number of physical cores.
- * A container should be requested with the number of cores it can saturate, i.e.
- * the average number of threads it expects to have runnable at a time.
- *
+ * should be configured with virtual cores equal to its number of physical
+ * cores. A container should be requested with the number of cores it can
+ * saturate, i.e. the average number of threads it expects to have runnable
+ * at a time.
+ *
* @param vCores number of virtual cpu cores of the resource
*/
@Public
@Evolving
public abstract void setVirtualCores(int vCores);
- @Override
- public int hashCode() {
- final int prime = 263167;
+ /**
+ * Get ResourceInformation for all resources.
+ *
+ * @return Map of resource name to ResourceInformation
+ */
+ @InterfaceAudience.Private
+ @InterfaceStability.Unstable
+ public abstract ResourceInformation[] getResources();
+
+ /**
+ * Get ResourceInformation for a specified resource.
+ *
+ * @param resource name of the resource
+ * @return the ResourceInformation object for the resource
+ * @throws ResourceNotFoundException if the resource can't be found
+ */
+ @Public
+ @InterfaceStability.Unstable
+ public ResourceInformation getResourceInformation(String resource)
+ throws ResourceNotFoundException {
+ Integer index = ResourceUtils.getResourceTypeIndex().get(resource);
+ ResourceInformation[] resources = getResources();
+ if (index != null) {
+ return resources[index];
+ }
+ throw new ResourceNotFoundException("Unknown resource '" + resource
+ + "'. Known resources are " + Arrays.toString(resources));
+ }
+
+ /**
+ * Get ResourceInformation for a specified resource from a given index.
+ *
+ * @param index
+ * of the resource
+ * @return the ResourceInformation object for the resource
+ * @throws ResourceNotFoundException
+ * if the resource can't be found
+ */
+ @InterfaceAudience.Private
+ @InterfaceStability.Unstable
+ public ResourceInformation getResourceInformation(int index)
+ throws ResourceNotFoundException {
+ ResourceInformation ri = null;
+ try {
+ ResourceInformation[] resources = getResources();
+ ri = resources[index];
+ } catch (ArrayIndexOutOfBoundsException e) {
+ checkIndexAndThrowExceptionWhenArrayOutOfBound(index);
+ }
+ return ri;
+ }
+
+ /**
+ * Get the value for a specified resource. No information about the units is
+ * returned.
+ *
+ * @param resource name of the resource
+ * @return the value for the resource
+ * @throws ResourceNotFoundException if the resource can't be found
+ */
+ @Public
+ @InterfaceStability.Unstable
+ public long getResourceValue(String resource)
+ throws ResourceNotFoundException {
+ return getResourceInformation(resource).getValue();
+ }
+
+ /**
+ * Set the ResourceInformation object for a particular resource.
+ *
+ * @param resource the resource for which the ResourceInformation is provided
+ * @param resourceInformation ResourceInformation object
+ * @throws ResourceNotFoundException if the resource is not found
+ */
+ @Public
+ @InterfaceStability.Unstable
+ public void setResourceInformation(String resource,
+ ResourceInformation resourceInformation)
+ throws ResourceNotFoundException {
+ if (resource.equals(MEMORY)) {
+ this.setMemorySize(resourceInformation.getValue());
+ return;
+ }
+ if (resource.equals(VCORES)) {
+ this.setVirtualCores((int) resourceInformation.getValue());
+ return;
+ }
+ ResourceInformation storedResourceInfo = getResourceInformation(resource);
+ ResourceInformation.copy(resourceInformation, storedResourceInfo);
+ }
+
+ /**
+ * Set the ResourceInformation object for a particular resource.
+ *
+ * @param index
+ * the resource index for which the ResourceInformation is provided
+ * @param resourceInformation
+ * ResourceInformation object
+ * @throws ResourceNotFoundException
+ * if the resource is not found
+ */
+ @InterfaceAudience.Private
+ @InterfaceStability.Unstable
+ public void setResourceInformation(int index,
+ ResourceInformation resourceInformation)
+ throws ResourceNotFoundException {
+ ResourceInformation[] resources = getResources();
+ if (index < 0 || index >= resources.length) {
+ throw new ResourceNotFoundException("Unknown resource at index '" + index
+ + "'. Valid resources are " + Arrays.toString(resources));
+ }
+ ResourceInformation.copy(resourceInformation, resources[index]);
+ }
- int result = (int) (939769357
- + getMemorySize()); // prime * result = 939769357 initially
- result = prime * result + getVirtualCores();
- return result;
+ /**
+ * Set the value of a resource in the ResourceInformation object. The unit of
+ * the value is assumed to be the one in the ResourceInformation object.
+ *
+ * @param resource the resource for which the value is provided.
+ * @param value the value to set
+ * @throws ResourceNotFoundException if the resource is not found
+ */
+ @Public
+ @InterfaceStability.Unstable
+ public void setResourceValue(String resource, long value)
+ throws ResourceNotFoundException {
+ if (resource.equals(MEMORY)) {
+ this.setMemorySize(value);
+ return;
+ }
+ if (resource.equals(VCORES)) {
+ this.setVirtualCores((int)value);
+ return;
+ }
+
+ ResourceInformation storedResourceInfo = getResourceInformation(resource);
+ storedResourceInfo.setValue(value);
+ }
+
+ /**
+ * Set the value of a resource in the ResourceInformation object. The unit of
+ * the value is assumed to be the one in the ResourceInformation object.
+ *
+ * @param index
+ * the resource index for which the value is provided.
+ * @param value
+ * the value to set
+ * @throws ResourceNotFoundException
+ * if the resource is not found
+ */
+ @InterfaceAudience.Private
+ @InterfaceStability.Unstable
+ public void setResourceValue(int index, long value)
+ throws ResourceNotFoundException {
+ try {
+ ResourceInformation[] resources = getResources();
+ resources[index].setValue(value);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ checkIndexAndThrowExceptionWhenArrayOutOfBound(index);
+ }
+ }
+
+ private void checkIndexAndThrowExceptionWhenArrayOutOfBound(int index) {
+ if (index < 0) {
+ throw new ResourceNotFoundException("Specified index must >= 0");
+ } else {
+ throw new ResourceNotFoundException(
+ "Specified index beyond known #resource-types");
+ }
}
@Override
public boolean equals(Object obj) {
- if (this == obj)
+ if (this == obj) {
return true;
- if (obj == null)
+ }
+ if (obj == null) {
return false;
- if (!(obj instanceof Resource))
+ }
+ if (!(obj instanceof Resource)) {
return false;
+ }
Resource other = (Resource) obj;
- if (getMemorySize() != other.getMemorySize() ||
- getVirtualCores() != other.getVirtualCores()) {
+ if (getMemorySize() != other.getMemorySize()
+ || getVirtualCores() != other.getVirtualCores()) {
return false;
}
+
+ if (ResourceUtils.getNumberOfKnownResourceTypes()
+ <= NUM_MANDATORY_RESOURCES) {
+ return true;
+ }
+
+ ResourceInformation[] myVectors = getResources();
+ ResourceInformation[] otherVectors = other.getResources();
+
+ if (myVectors.length != otherVectors.length) {
+ return false;
+ }
+
+ for (int i = 0; i < myVectors.length; i++) {
+ ResourceInformation a = myVectors[i];
+ ResourceInformation b = otherVectors[i];
+ if ((a != b) && ((a == null) || !a.equals(b))) {
+ return false;
+ }
+ }
return true;
}
@Override
public int compareTo(Resource other) {
+ ResourceInformation[] thisResources = this.getResources();
+ ResourceInformation[] otherResources = other.getResources();
+
+ // compare memory and vcores first(in that order) to preserve
+ // existing behaviour
long diff = this.getMemorySize() - other.getMemorySize();
if (diff == 0) {
diff = this.getVirtualCores() - other.getVirtualCores();
}
- return diff == 0 ? 0 : (diff > 0 ? 1 : -1);
- }
+ if (diff == 0) {
+ diff = thisResources.length - otherResources.length;
+ if (diff == 0) {
+ int maxLength = ResourceUtils.getResourceTypesArray().length;
+ for (int i = 0; i < maxLength; i++) {
+ // For memory and vcores, we can skip the loop as it's already
+ // compared.
+ if (i < 2) {
+ continue;
+ }
- @Override
- public String toString() {
- return "";
+ ResourceInformation entry = thisResources[i];
+ ResourceInformation otherEntry = otherResources[i];
+ if (entry.getName().equals(otherEntry.getName())) {
+ diff = entry.compareTo(otherEntry);
+ if (diff != 0) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ return Long.compare(diff, 0);
}
}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/ResourceInformation.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/ResourceInformation.java
new file mode 100644
index 00000000000..76990def094
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/ResourceInformation.java
@@ -0,0 +1,291 @@
+/**
+ * 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 org.apache.curator.shaded.com.google.common.reflect.ClassPath;
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.yarn.api.protocolrecords.ResourceTypes;
+import org.apache.hadoop.yarn.util.UnitsConversionUtil;
+
+/**
+ * Class to encapsulate information about a Resource - the name of the resource,
+ * the units(milli, micro, etc), the type(countable), and the value.
+ */
+public class ResourceInformation implements Comparable {
+
+ private String name;
+ private String units;
+ private ResourceTypes resourceType;
+ private long value;
+ private long minimumAllocation;
+ private long maximumAllocation;
+
+ public static final String MEMORY_URI = "memory-mb";
+ public static final String VCORES_URI = "vcores";
+
+ public static final ResourceInformation MEMORY_MB =
+ ResourceInformation.newInstance(MEMORY_URI, "Mi");
+ public static final ResourceInformation VCORES =
+ ResourceInformation.newInstance(VCORES_URI);
+
+ /**
+ * Get the name for the resource.
+ *
+ * @return resource name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Set the name for the resource.
+ *
+ * @param rName name for the resource
+ */
+ public void setName(String rName) {
+ this.name = rName;
+ }
+
+ /**
+ * Get units for the resource.
+ *
+ * @return units for the resource
+ */
+ public String getUnits() {
+ return units;
+ }
+
+ /**
+ * Set the units for the resource.
+ *
+ * @param rUnits units for the resource
+ */
+ public void setUnits(String rUnits) {
+ if (!UnitsConversionUtil.KNOWN_UNITS.contains(rUnits)) {
+ throw new IllegalArgumentException(
+ "Unknown unit '" + rUnits + "'. Known units are "
+ + UnitsConversionUtil.KNOWN_UNITS);
+ }
+ this.units = rUnits;
+ }
+
+ /**
+ * Checking if a unit included by KNOWN_UNITS is an expensive operation. This
+ * can be avoided in critical path in RM.
+ * @param rUnits
+ */
+ @InterfaceAudience.Private
+ public void setUnitsWithoutValidation(String rUnits) {
+ this.units = rUnits;
+ }
+
+ /**
+ * Get the resource type.
+ *
+ * @return the resource type
+ */
+ public ResourceTypes getResourceType() {
+ return resourceType;
+ }
+
+ /**
+ * Set the resource type.
+ *
+ * @param type the resource type
+ */
+ public void setResourceType(ResourceTypes type) {
+ this.resourceType = type;
+ }
+
+ /**
+ * Get the value for the resource.
+ *
+ * @return the resource value
+ */
+ public long getValue() {
+ return value;
+ }
+
+ /**
+ * Set the value for the resource.
+ *
+ * @param rValue the resource value
+ */
+ public void setValue(long rValue) {
+ this.value = rValue;
+ }
+
+ /**
+ * Get the minimum allocation for the resource.
+ *
+ * @return the minimum allocation for the resource
+ */
+ public long getMinimumAllocation() {
+ return minimumAllocation;
+ }
+
+ /**
+ * Set the minimum allocation for the resource.
+ *
+ * @param minimumAllocation the minimum allocation for the resource
+ */
+ public void setMinimumAllocation(long minimumAllocation) {
+ this.minimumAllocation = minimumAllocation;
+ }
+
+ /**
+ * Get the maximum allocation for the resource.
+ *
+ * @return the maximum allocation for the resource
+ */
+ public long getMaximumAllocation() {
+ return maximumAllocation;
+ }
+
+ /**
+ * Set the maximum allocation for the resource.
+ *
+ * @param maximumAllocation the maximum allocation for the resource
+ */
+ public void setMaximumAllocation(long maximumAllocation) {
+ this.maximumAllocation = maximumAllocation;
+ }
+
+ /**
+ * Create a new instance of ResourceInformation from another object.
+ *
+ * @param other the object from which the new object should be created
+ * @return the new ResourceInformation object
+ */
+ public static ResourceInformation newInstance(ResourceInformation other) {
+ ResourceInformation ret = new ResourceInformation();
+ copy(other, ret);
+ return ret;
+ }
+
+ public static ResourceInformation newInstance(String name, String units,
+ long value, ResourceTypes type, long minimumAllocation,
+ long maximumAllocation) {
+ ResourceInformation ret = new ResourceInformation();
+ ret.setName(name);
+ ret.setResourceType(type);
+ ret.setUnits(units);
+ ret.setValue(value);
+ ret.setMinimumAllocation(minimumAllocation);
+ ret.setMaximumAllocation(maximumAllocation);
+ return ret;
+ }
+
+ public static ResourceInformation newInstance(String name, String units,
+ long value) {
+ return ResourceInformation
+ .newInstance(name, units, value, ResourceTypes.COUNTABLE, 0L,
+ Long.MAX_VALUE);
+ }
+
+ public static ResourceInformation newInstance(String name, String units) {
+ return ResourceInformation
+ .newInstance(name, units, 0L, ResourceTypes.COUNTABLE, 0L,
+ Long.MAX_VALUE);
+ }
+
+ public static ResourceInformation newInstance(String name, long value) {
+ return ResourceInformation
+ .newInstance(name, "", value, ResourceTypes.COUNTABLE, 0L,
+ Long.MAX_VALUE);
+ }
+
+ public static ResourceInformation newInstance(String name) {
+ return ResourceInformation.newInstance(name, "");
+ }
+
+ /**
+ * Copies the content of the source ResourceInformation object to the
+ * destination object, overwriting all properties of the destination object.
+ * @param src Source ResourceInformation object
+ * @param dst Destination ResourceInformation object
+ */
+
+ public static void copy(ResourceInformation src, ResourceInformation dst) {
+ dst.setName(src.getName());
+ dst.setResourceType(src.getResourceType());
+ dst.setUnits(src.getUnits());
+ dst.setValue(src.getValue());
+ dst.setMinimumAllocation(src.getMinimumAllocation());
+ dst.setMaximumAllocation(src.getMaximumAllocation());
+ }
+
+ @Override
+ public String toString() {
+ return "name: " + this.name + ", units: " + this.units + ", type: "
+ + resourceType + ", value: " + value + ", minimum allocation: "
+ + minimumAllocation + ", maximum allocation: " + maximumAllocation;
+ }
+
+ public String getShorthandRepresentation() {
+ return "" + this.value + this.units;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof ResourceInformation)) {
+ return false;
+ }
+ ResourceInformation r = (ResourceInformation) obj;
+ if (!this.name.equals(r.getName())
+ || !this.resourceType.equals(r.getResourceType())) {
+ return false;
+ }
+ if (this.units.equals(r.units)) {
+ return this.value == r.value;
+ }
+ return (UnitsConversionUtil.compare(this.units, this.value, r.units,
+ r.value) == 0);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 263167;
+ int result =
+ 939769357 + name.hashCode(); // prime * result = 939769357 initially
+ result = prime * result + resourceType.hashCode();
+ result = prime * result + units.hashCode();
+ result = prime * result + Long.hashCode(value);
+ return result;
+ }
+
+ @Override
+ public int compareTo(ResourceInformation other) {
+ int diff = this.name.compareTo(other.name);
+ if (diff == 0) {
+ diff = UnitsConversionUtil
+ .compare(this.units, this.value, other.units, other.value);
+ if (diff == 0) {
+ diff = this.resourceType.compareTo(other.resourceType);
+ }
+ }
+ return diff;
+ }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/ResourceRequest.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/ResourceRequest.java
index 5bedc879ee3..21fa15f14aa 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/ResourceRequest.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/ResourceRequest.java
@@ -21,6 +21,7 @@
import java.io.Serializable;
import org.apache.hadoop.classification.InterfaceAudience.Public;
+import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.classification.InterfaceStability.Evolving;
import org.apache.hadoop.classification.InterfaceStability.Stable;
import org.apache.hadoop.classification.InterfaceStability.Unstable;
@@ -98,7 +99,22 @@ public static ResourceRequest newInstance(Priority priority, String hostName,
.resourceName(hostName).capability(capability)
.numContainers(numContainers).relaxLocality(relaxLocality)
.nodeLabelExpression(labelExpression)
- .executionTypeRequest(executionTypeRequest).build();
+ .executionTypeRequest(executionTypeRequest).profileCapability(null)
+ .build();
+ }
+
+ @Public
+ @Unstable
+ 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
@@ -124,6 +140,7 @@ private ResourceRequestBuilder() {
resourceRequest.setRelaxLocality(true);
resourceRequest.setExecutionTypeRequest(
ExecutionTypeRequest.newInstance());
+ resourceRequest.setProfileCapability(null);
}
/**
@@ -238,6 +255,21 @@ public ResourceRequestBuilder allocationRequestId(
}
/**
+ * Set the resourceProfile of the request.
+ * @see ResourceRequest#setProfileCapability(ProfileCapability)
+ * @param profileCapability
+ * profileCapability of the request
+ * @return {@link ResourceRequestBuilder}
+ */
+ @Public
+ @InterfaceStability.Unstable
+ public ResourceRequestBuilder profileCapability(
+ ProfileCapability profileCapability) {
+ resourceRequest.setProfileCapability(profileCapability);
+ return this;
+ }
+
+ /**
* Return generated {@link ResourceRequest} object.
* @return {@link ResourceRequest}
*/
@@ -454,6 +486,14 @@ public ExecutionTypeRequest getExecutionTypeRequest() {
@Evolving
public abstract void setNodeLabelExpression(String nodelabelExpression);
+ @Public
+ @InterfaceStability.Unstable
+ public abstract ProfileCapability getProfileCapability();
+
+ @Public
+ @InterfaceStability.Unstable
+ public abstract void setProfileCapability(ProfileCapability p);
+
/**
* Get the optional ID corresponding to this allocation request. This
* ID is an identifier for different {@code ResourceRequest}s from the same
@@ -529,12 +569,14 @@ public int hashCode() {
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;
}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/ResourceTypeInfo.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/ResourceTypeInfo.java
new file mode 100644
index 00000000000..b6f7f147658
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/ResourceTypeInfo.java
@@ -0,0 +1,197 @@
+/**
+ * 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 org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.yarn.api.protocolrecords.ResourceTypes;
+import org.apache.hadoop.yarn.util.Records;
+
+/**
+ * Class to encapsulate information about a ResourceType - the name of the
+ * resource, the units(milli, micro, etc), the type(countable).
+ */
+public abstract class ResourceTypeInfo implements Comparable {
+
+ /**
+ * Get the name for the resource.
+ *
+ * @return resource name
+ */
+ public abstract String getName();
+
+ /**
+ * Set the name for the resource.
+ *
+ * @param rName
+ * name for the resource
+ */
+ public abstract void setName(String rName);
+
+ /**
+ * Get units for the resource.
+ *
+ * @return units for the resource
+ */
+ public abstract String getDefaultUnit();
+
+ /**
+ * Set the units for the resource.
+ *
+ * @param rUnits
+ * units for the resource
+ */
+ public abstract void setDefaultUnit(String rUnits);
+
+ /**
+ * Get the resource type.
+ *
+ * @return the resource type
+ */
+ public abstract ResourceTypes getResourceType();
+
+ /**
+ * Set the resource type.
+ *
+ * @param type
+ * the resource type
+ */
+ public abstract void setResourceType(ResourceTypes type);
+
+ /**
+ * Create a new instance of ResourceTypeInfo from another object.
+ *
+ * @param other
+ * the object from which the new object should be created
+ * @return the new ResourceTypeInfo object
+ */
+ @InterfaceAudience.Public
+ @InterfaceStability.Unstable
+ public static ResourceTypeInfo newInstance(ResourceTypeInfo other) {
+ ResourceTypeInfo resourceType = Records.newRecord(ResourceTypeInfo.class);
+ copy(other, resourceType);
+ return resourceType;
+ }
+
+ /**
+ * Create a new instance of ResourceTypeInfo from name, units and type.
+ *
+ * @param name name of resource type
+ * @param units units of resource type
+ * @param type such as countable, etc.
+ * @return the new ResourceTypeInfo object
+ */
+ @InterfaceAudience.Public
+ @InterfaceStability.Unstable
+ public static ResourceTypeInfo newInstance(String name, String units,
+ ResourceTypes type) {
+ ResourceTypeInfo resourceType = Records.newRecord(ResourceTypeInfo.class);
+ resourceType.setName(name);
+ resourceType.setResourceType(type);
+ resourceType.setDefaultUnit(units);
+ return resourceType;
+ }
+
+ /**
+ * Create a new instance of ResourceTypeInfo from name, units.
+ *
+ * @param name name of resource type
+ * @param units units of resource type
+ * @return the new ResourceTypeInfo object
+ */
+ @InterfaceAudience.Public
+ @InterfaceStability.Unstable
+ public static ResourceTypeInfo newInstance(String name, String units) {
+ return ResourceTypeInfo.newInstance(name, units, ResourceTypes.COUNTABLE);
+ }
+
+ /**
+ * Create a new instance of ResourceTypeInfo from name.
+ *
+ * @param name name of resource type
+ * @return the new ResourceTypeInfo object
+ */
+ @InterfaceAudience.Public
+ @InterfaceStability.Unstable
+ public static ResourceTypeInfo newInstance(String name) {
+ return ResourceTypeInfo.newInstance(name, "");
+ }
+
+ /**
+ * Copies the content of the source ResourceTypeInfo object to the
+ * destination object, overwriting all properties of the destination object.
+ *
+ * @param src
+ * Source ResourceTypeInfo object
+ * @param dst
+ * Destination ResourceTypeInfo object
+ */
+
+ public static void copy(ResourceTypeInfo src, ResourceTypeInfo dst) {
+ dst.setName(src.getName());
+ dst.setResourceType(src.getResourceType());
+ dst.setDefaultUnit(src.getDefaultUnit());
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("");
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof ResourceTypeInfo)) {
+ return false;
+ }
+ ResourceTypeInfo r = (ResourceTypeInfo) obj;
+ return this.getName().equals(r.getName())
+ && this.getResourceType().equals(r.getResourceType())
+ && this.getDefaultUnit().equals(r.getDefaultUnit());
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 47;
+ int result = prime + getName().hashCode();
+ result = prime * result + getResourceType().hashCode();
+ return result;
+ }
+
+ @Override
+ public int compareTo(ResourceTypeInfo other) {
+ int diff = this.getName().compareTo(other.getName());
+ if (diff == 0) {
+ diff = this.getDefaultUnit().compareTo(other.getDefaultUnit());
+ if (diff == 0) {
+ diff = this.getResourceType().compareTo(other.getResourceType());
+ }
+ }
+ return diff;
+ }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/impl/BaseResource.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/impl/BaseResource.java
new file mode 100644
index 00000000000..40e8fa4e7da
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/impl/BaseResource.java
@@ -0,0 +1,158 @@
+/**
+ * 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.impl;
+
+import org.apache.hadoop.classification.InterfaceAudience.Public;
+import org.apache.hadoop.classification.InterfaceStability.Unstable;
+import org.apache.hadoop.yarn.api.protocolrecords.ResourceTypes;
+import org.apache.hadoop.yarn.api.records.Resource;
+import org.apache.hadoop.yarn.api.records.ResourceInformation;
+
+import java.util.Arrays;
+
+import static org.apache.hadoop.yarn.api.records.ResourceInformation.MEMORY_MB;
+
+/**
+ *
+ * BaseResource extends Resource to handle base resources such
+ * as memory and CPU.
+ * TODO: We have a long term plan to use AbstractResource when additional
+ * resource types are to be handled as well.
+ *
+ *
+ *
+ * Currently it models both memory and CPU.
+ *
+ *
+ *
+ * The unit for memory is megabytes. CPU is modeled with virtual cores (vcores),
+ * a unit for expressing parallelism. A node's capacity should be configured
+ * with virtual cores equal to its number of physical cores. A container should
+ * be requested with the number of cores it can saturate, i.e. the average
+ * number of threads it expects to have runnable at a time.
+ *
+ *
+ *
+ * Virtual cores take integer values and thus currently CPU-scheduling is very
+ * coarse. A complementary axis for CPU requests that represents processing
+ * power will likely be added in the future to enable finer-grained resource
+ * configuration.
+ *
+ *
+ * @see Resource
+ */
+@Public
+@Unstable
+public class BaseResource extends Resource {
+
+ private ResourceInformation memoryResInfo;
+ private ResourceInformation vcoresResInfo;
+ protected ResourceInformation[] resources = null;
+
+ public BaseResource() {
+ // Base constructor.
+ }
+
+ public BaseResource(long memory, long vcores) {
+ this.memoryResInfo = BaseResource.newDefaultMemoryInformation(memory);
+ this.vcoresResInfo = BaseResource.newDefaultVCoresInformation(vcores);
+
+ resources = new ResourceInformation[NUM_MANDATORY_RESOURCES];
+ resources[MEMORY_INDEX] = memoryResInfo;
+ resources[VCORES_INDEX] = vcoresResInfo;
+ }
+
+ public static ResourceInformation newDefaultMemoryInformation(long value) {
+ ResourceInformation ri = new ResourceInformation();
+ ri.setName(ResourceInformation.MEMORY_URI);
+ ri.setValue(value);
+ ri.setResourceType(ResourceTypes.COUNTABLE);
+ ri.setUnitsWithoutValidation(MEMORY_MB.getUnits());
+ ri.setMinimumAllocation(0);
+ ri.setMaximumAllocation(Long.MAX_VALUE);
+ return ri;
+ }
+
+ public static ResourceInformation newDefaultVCoresInformation(long value) {
+ ResourceInformation ri = new ResourceInformation();
+ ri.setName(ResourceInformation.VCORES_URI);
+ ri.setValue(value);
+ ri.setResourceType(ResourceTypes.COUNTABLE);
+ ri.setUnitsWithoutValidation("");
+ ri.setMinimumAllocation(0);
+ ri.setMaximumAllocation(Long.MAX_VALUE);
+ return ri;
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ public int getMemory() {
+ return (int) memoryResInfo.getValue();
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ public void setMemory(int memory) {
+ this.memoryResInfo.setValue(memory);
+ }
+
+ @Override
+ public long getMemorySize() {
+ return memoryResInfo.getValue();
+ }
+
+ @Override
+ public void setMemorySize(long memory) {
+ this.memoryResInfo.setValue(memory);
+ }
+
+ @Override
+ public int getVirtualCores() {
+ return (int) vcoresResInfo.getValue();
+ }
+
+ @Override
+ public void setVirtualCores(int vcores) {
+ this.vcoresResInfo.setValue(vcores);
+ }
+
+ @Override
+ public ResourceInformation[] getResources() {
+ return resources;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("");
+ return sb.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 263167;
+
+ int result = (int) (939769357
+ + getMemorySize()); // prime * result = 939769357 initially
+ result = prime * result + getVirtualCores();
+ return result;
+ }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/impl/package-info.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/impl/package-info.java
new file mode 100644
index 00000000000..b2420bc50f8
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/impl/package-info.java
@@ -0,0 +1,26 @@
+/*
+ * 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.impl contains classes
+ * which define basic resources.
+ */
+@InterfaceAudience.Public
+@InterfaceStability.Unstable
+package org.apache.hadoop.yarn.api.records.impl;
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
\ No newline at end of file
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java
index 49448217e9c..c8c61ff2477 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java
@@ -61,8 +61,27 @@
public static final String CORE_SITE_CONFIGURATION_FILE = "core-site.xml";
@Private
+ public static final String RESOURCE_TYPES_CONFIGURATION_FILE =
+ "resource-types.xml";
+
+ @Private
+ public static final String NODE_RESOURCES_CONFIGURATION_FILE =
+ "node-resources.xml";
+
+ @Private
public static final List RM_CONFIGURATION_FILES =
Collections.unmodifiableList(Arrays.asList(
+ RESOURCE_TYPES_CONFIGURATION_FILE,
+ DR_CONFIGURATION_FILE,
+ CS_CONFIGURATION_FILE,
+ HADOOP_POLICY_CONFIGURATION_FILE,
+ YARN_SITE_CONFIGURATION_FILE,
+ CORE_SITE_CONFIGURATION_FILE));
+
+ @Private
+ public static final List NM_CONFIGURATION_FILES =
+ Collections.unmodifiableList(Arrays.asList(
+ NODE_RESOURCES_CONFIGURATION_FILE,
DR_CONFIGURATION_FILE,
CS_CONFIGURATION_FILE,
HADOOP_POLICY_CONFIGURATION_FILE,
@@ -106,6 +125,16 @@ private static void addDeprecatedKeys() {
public static final String YARN_PREFIX = "yarn.";
+ /////////////////////////////
+ // Resource types configs
+ ////////////////////////////
+
+ public static final String RESOURCE_TYPES =
+ YarnConfiguration.YARN_PREFIX + "resource-types";
+
+ public static final String NM_RESOURCES_PREFIX =
+ YarnConfiguration.NM_PREFIX + "resource-type.";
+
/** Delay before deleting resource to ease debugging of NM issues */
public static final String DEBUG_NM_DELETE_DELAY_SEC =
YarnConfiguration.NM_PREFIX + "delete.debug-delay-sec";
@@ -850,6 +879,29 @@ public static boolean isAclEnabled(Configuration conf) {
public static final String RM_PROXY_USER_PREFIX = RM_PREFIX + "proxyuser.";
/**
+ * Enable/disable resource profiles.
+ */
+ @Public
+ @Unstable
+ public static final String RM_RESOURCE_PROFILES_ENABLED =
+ RM_PREFIX + "resource-profiles.enabled";
+ @Public
+ @Unstable
+ public static final boolean DEFAULT_RM_RESOURCE_PROFILES_ENABLED = false;
+
+ /**
+ * File containing resource profiles.
+ */
+ @Public
+ @Unstable
+ public static final String RM_RESOURCE_PROFILES_SOURCE_FILE =
+ RM_PREFIX + "resource-profiles.source-file";
+ @Public
+ @Unstable
+ public static final String DEFAULT_RM_RESOURCE_PROFILES_SOURCE_FILE =
+ "resource-profiles.json";
+
+ /**
* Timeout in seconds for YARN node graceful decommission.
* This is the maximal time to wait for running containers and applications
* to complete before transition a DECOMMISSIONING node into DECOMMISSIONED.
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/exceptions/ResourceNotFoundException.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/exceptions/ResourceNotFoundException.java
new file mode 100644
index 00000000000..b5fece7dc8c
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/exceptions/ResourceNotFoundException.java
@@ -0,0 +1,45 @@
+/**
+ * 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.exceptions;
+
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+
+/**
+ * This exception is thrown when details of an unknown resource type
+ * are requested.
+ */
+@InterfaceAudience.Public
+@InterfaceStability.Unstable
+public class ResourceNotFoundException extends YarnRuntimeException {
+
+ private static final long serialVersionUID = 10081982L;
+
+ public ResourceNotFoundException(String message) {
+ super(message);
+ }
+
+ public ResourceNotFoundException(Throwable cause) {
+ super(cause);
+ }
+
+ public ResourceNotFoundException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/exceptions/ResourceProfilesNotEnabledException.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/exceptions/ResourceProfilesNotEnabledException.java
new file mode 100644
index 00000000000..558e075bea5
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/exceptions/ResourceProfilesNotEnabledException.java
@@ -0,0 +1,43 @@
+/**
+ * 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.exceptions;
+
+/**
+ * This exception is thrown when the client requests information about
+ * ResourceProfiles in the
+ * {@link org.apache.hadoop.yarn.api.ApplicationClientProtocol} but resource
+ * profiles is not enabled on the RM.
+ *
+ */
+public class ResourceProfilesNotEnabledException extends YarnException {
+
+ private static final long serialVersionUID = 13498237L;
+
+ public ResourceProfilesNotEnabledException(Throwable cause) {
+ super(cause);
+ }
+
+ public ResourceProfilesNotEnabledException(String message) {
+ super(message);
+ }
+
+ public ResourceProfilesNotEnabledException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/exceptions/YARNFeatureNotEnabledException.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/exceptions/YARNFeatureNotEnabledException.java
new file mode 100644
index 00000000000..62340fea363
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/exceptions/YARNFeatureNotEnabledException.java
@@ -0,0 +1,45 @@
+/**
+ * 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.exceptions;
+
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+
+/**
+ * This exception is thrown when a feature is being used which is not enabled
+ * yet.
+ */
+@InterfaceAudience.Public
+@InterfaceStability.Unstable
+public class YARNFeatureNotEnabledException extends YarnException {
+ private static final long serialVersionUID = 898023752676L;
+
+ public YARNFeatureNotEnabledException(Throwable cause) {
+ super(cause);
+ }
+
+ public YARNFeatureNotEnabledException(String message) {
+ super(message);
+ }
+
+ public YARNFeatureNotEnabledException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/util/UnitsConversionUtil.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/util/UnitsConversionUtil.java
new file mode 100644
index 00000000000..7a212e163d9
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/util/UnitsConversionUtil.java
@@ -0,0 +1,221 @@
+/**
+ * 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.util;
+
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+
+import java.math.BigInteger;
+import java.util.*;
+
+/**
+ * A util to convert values in one unit to another. Units refers to whether
+ * the value is expressed in pico, nano, etc.
+ */
+@InterfaceAudience.Private
+@InterfaceStability.Unstable
+public class UnitsConversionUtil {
+
+ /**
+ * Helper class for encapsulating conversion values.
+ */
+ public static class Converter {
+ private long numerator;
+ private long denominator;
+
+ Converter(long n, long d) {
+ this.numerator = n;
+ this.denominator = d;
+ }
+ }
+
+ private static final String[] UNITS = {"p", "n", "u", "m", "", "k", "M", "G",
+ "T", "P", "Ki", "Mi", "Gi", "Ti", "Pi"};
+ private static final List SORTED_UNITS = Arrays.asList(UNITS);
+ public static final Set KNOWN_UNITS = createKnownUnitsSet();
+ private static final Converter PICO =
+ new Converter(1L, 1000L * 1000L * 1000L * 1000L);
+ private static final Converter NANO =
+ new Converter(1L, 1000L * 1000L * 1000L);
+ private static final Converter MICRO = new Converter(1L, 1000L * 1000L);
+ private static final Converter MILLI = new Converter(1L, 1000L);
+ private static final Converter BASE = new Converter(1L, 1L);
+ private static final Converter KILO = new Converter(1000L, 1L);
+ private static final Converter MEGA = new Converter(1000L * 1000L, 1L);
+ private static final Converter GIGA =
+ new Converter(1000L * 1000L * 1000L, 1L);
+ private static final Converter TERA =
+ new Converter(1000L * 1000L * 1000L * 1000L, 1L);
+ private static final Converter PETA =
+ new Converter(1000L * 1000L * 1000L * 1000L * 1000L, 1L);
+
+ private static final Converter KILO_BINARY = new Converter(1024L, 1L);
+ private static final Converter MEGA_BINARY = new Converter(1024L * 1024L, 1L);
+ private static final Converter GIGA_BINARY =
+ new Converter(1024L * 1024L * 1024L, 1L);
+ private static final Converter TERA_BINARY =
+ new Converter(1024L * 1024L * 1024L * 1024L, 1L);
+ private static final Converter PETA_BINARY =
+ new Converter(1024L * 1024L * 1024L * 1024L * 1024L, 1L);
+
+ private static Set createKnownUnitsSet() {
+ Set ret = new HashSet<>();
+ ret.addAll(Arrays.asList(UNITS));
+ return ret;
+ }
+
+ private static Converter getConverter(String unit) {
+ switch (unit) {
+ case "p":
+ return PICO;
+ case "n":
+ return NANO;
+ case "u":
+ return MICRO;
+ case "m":
+ return MILLI;
+ case "":
+ return BASE;
+ case "k":
+ return KILO;
+ case "M":
+ return MEGA;
+ case "G":
+ return GIGA;
+ case "T":
+ return TERA;
+ case "P":
+ return PETA;
+ case "Ki":
+ return KILO_BINARY;
+ case "Mi":
+ return MEGA_BINARY;
+ case "Gi":
+ return GIGA_BINARY;
+ case "Ti":
+ return TERA_BINARY;
+ case "Pi":
+ return PETA_BINARY;
+ default:
+ throw new IllegalArgumentException(
+ "Unknown unit '" + unit + "'. Known units are " + KNOWN_UNITS);
+ }
+ }
+
+ /**
+ * Converts a value from one unit to another. Supported units can be obtained
+ * by inspecting the KNOWN_UNITS set.
+ *
+ * @param fromUnit the unit of the from value
+ * @param toUnit the target unit
+ * @param fromValue the value you wish to convert
+ * @return the value in toUnit
+ */
+ public static long convert(String fromUnit, String toUnit, long fromValue) {
+ if (toUnit == null || fromUnit == null) {
+ throw new IllegalArgumentException("One or more arguments are null");
+ }
+
+ if (fromUnit.equals(toUnit)) {
+ return fromValue;
+ }
+ Converter fc = getConverter(fromUnit);
+ Converter tc = getConverter(toUnit);
+ long numerator = fc.numerator * tc.denominator;
+ long denominator = fc.denominator * tc.numerator;
+ long numeratorMultiplierLimit = Long.MAX_VALUE / numerator;
+ if (numerator < denominator) {
+ if (numeratorMultiplierLimit < fromValue) {
+ String overflowMsg =
+ "Converting " + fromValue + " from '" + fromUnit + "' to '" + toUnit
+ + "' will result in an overflow of Long";
+ throw new IllegalArgumentException(overflowMsg);
+ }
+ return (fromValue * numerator) / denominator;
+ }
+ if (numeratorMultiplierLimit > fromValue) {
+ return (numerator * fromValue) / denominator;
+ }
+ long tmp = numerator / denominator;
+ if ((Long.MAX_VALUE / tmp) < fromValue) {
+ String overflowMsg =
+ "Converting " + fromValue + " from '" + fromUnit + "' to '" + toUnit
+ + "' will result in an overflow of Long";
+ throw new IllegalArgumentException(overflowMsg);
+ }
+ return fromValue * tmp;
+ }
+
+ /**
+ * Compare a value in a given unit with a value in another unit. The return
+ * value is equivalent to the value returned by compareTo.
+ *
+ * @param unitA first unit
+ * @param valueA first value
+ * @param unitB second unit
+ * @param valueB second value
+ * @return +1, 0 or -1 depending on whether the relationship is greater than,
+ * equal to or lesser than
+ */
+ public static int compare(String unitA, long valueA, String unitB,
+ long valueB) {
+ if (unitA == null || unitB == null || !KNOWN_UNITS.contains(unitA)
+ || !KNOWN_UNITS.contains(unitB)) {
+ throw new IllegalArgumentException("Units cannot be null");
+ }
+ if (!KNOWN_UNITS.contains(unitA)) {
+ throw new IllegalArgumentException("Unknown unit '" + unitA + "'");
+ }
+ if (!KNOWN_UNITS.contains(unitB)) {
+ throw new IllegalArgumentException("Unknown unit '" + unitB + "'");
+ }
+ if (unitA.equals(unitB)) {
+ return Long.compare(valueA, valueB);
+ }
+ Converter unitAC = getConverter(unitA);
+ Converter unitBC = getConverter(unitB);
+ int unitAPos = SORTED_UNITS.indexOf(unitA);
+ int unitBPos = SORTED_UNITS.indexOf(unitB);
+ try {
+ long tmpA = valueA;
+ long tmpB = valueB;
+ if (unitAPos < unitBPos) {
+ tmpB = convert(unitB, unitA, valueB);
+ } else {
+ tmpA = convert(unitA, unitB, valueA);
+ }
+ return Long.compare(tmpA, tmpB);
+ } catch (IllegalArgumentException ie) {
+ BigInteger tmpA = BigInteger.valueOf(valueA);
+ BigInteger tmpB = BigInteger.valueOf(valueB);
+ if (unitAPos < unitBPos) {
+ tmpB = tmpB.multiply(BigInteger.valueOf(unitBC.numerator));
+ tmpB = tmpB.multiply(BigInteger.valueOf(unitAC.denominator));
+ tmpB = tmpB.divide(BigInteger.valueOf(unitBC.denominator));
+ tmpB = tmpB.divide(BigInteger.valueOf(unitAC.numerator));
+ } else {
+ tmpA = tmpA.multiply(BigInteger.valueOf(unitAC.numerator));
+ tmpA = tmpA.multiply(BigInteger.valueOf(unitBC.denominator));
+ tmpA = tmpA.divide(BigInteger.valueOf(unitAC.denominator));
+ tmpA = tmpA.divide(BigInteger.valueOf(unitBC.numerator));
+ }
+ return tmpA.compareTo(tmpB);
+ }
+ }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/util/resource/ResourceUtils.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/util/resource/ResourceUtils.java
new file mode 100644
index 00000000000..94c2e97e9f0
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/util/resource/ResourceUtils.java
@@ -0,0 +1,585 @@
+/**
+ * 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.util.resource;
+
+import com.google.common.annotations.VisibleForTesting;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.yarn.api.protocolrecords.ResourceTypes;
+import org.apache.hadoop.yarn.api.records.Resource;
+import org.apache.hadoop.yarn.api.records.ResourceInformation;
+import org.apache.hadoop.yarn.api.records.ResourceTypeInfo;
+import org.apache.hadoop.yarn.conf.ConfigurationProvider;
+import org.apache.hadoop.yarn.conf.ConfigurationProviderFactory;
+import org.apache.hadoop.yarn.conf.YarnConfiguration;
+import org.apache.hadoop.yarn.exceptions.YarnException;
+import org.apache.hadoop.yarn.exceptions.YarnRuntimeException;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Helper class to read the resource-types to be supported by the system.
+ */
+@InterfaceAudience.Public
+@InterfaceStability.Unstable
+public class ResourceUtils {
+
+ public static final String UNITS = ".units";
+ public static final String TYPE = ".type";
+ public static final String MINIMUM_ALLOCATION = ".minimum-allocation";
+ public static final String MAXIMUM_ALLOCATION = ".maximum-allocation";
+
+ private static final String MEMORY = ResourceInformation.MEMORY_MB.getName();
+ private static final String VCORES = ResourceInformation.VCORES.getName();
+
+ private static final Set DISALLOWED_NAMES = new HashSet<>();
+ static {
+ DISALLOWED_NAMES.add("memory");
+ DISALLOWED_NAMES.add(MEMORY);
+ DISALLOWED_NAMES.add(VCORES);
+ }
+
+ private static volatile boolean initializedResources = false;
+ private static final Map RESOURCE_NAME_TO_INDEX =
+ new ConcurrentHashMap();
+ private static volatile Map resourceTypes;
+ private static volatile String[] resourceNamesArray;
+ private static volatile ResourceInformation[] resourceTypesArray;
+ private static volatile boolean initializedNodeResources = false;
+ private static volatile Map readOnlyNodeResources;
+ private static volatile int numKnownResourceTypes = -1;
+
+ static final Log LOG = LogFactory.getLog(ResourceUtils.class);
+
+ private ResourceUtils() {
+ }
+
+ private static void checkMandatatoryResources(
+ Map resourceInformationMap)
+ throws YarnRuntimeException {
+ if (resourceInformationMap.containsKey(MEMORY)) {
+ ResourceInformation memInfo = resourceInformationMap.get(MEMORY);
+ String memUnits = ResourceInformation.MEMORY_MB.getUnits();
+ ResourceTypes memType = ResourceInformation.MEMORY_MB.getResourceType();
+ if (!memInfo.getUnits().equals(memUnits) || !memInfo.getResourceType()
+ .equals(memType)) {
+ throw new YarnRuntimeException(
+ "Attempt to re-define mandatory resource 'memory-mb'. It can only"
+ + " be of type 'COUNTABLE' and have units 'Mi'.");
+ }
+ }
+
+ if (resourceInformationMap.containsKey(VCORES)) {
+ ResourceInformation vcoreInfo = resourceInformationMap.get(VCORES);
+ String vcoreUnits = ResourceInformation.VCORES.getUnits();
+ ResourceTypes vcoreType = ResourceInformation.VCORES.getResourceType();
+ if (!vcoreInfo.getUnits().equals(vcoreUnits) || !vcoreInfo
+ .getResourceType().equals(vcoreType)) {
+ throw new YarnRuntimeException(
+ "Attempt to re-define mandatory resource 'vcores'. It can only be"
+ + " of type 'COUNTABLE' and have units ''(no units).");
+ }
+ }
+ }
+
+ private static void addManadtoryResources(
+ Map res) {
+ ResourceInformation ri;
+ if (!res.containsKey(MEMORY)) {
+ LOG.info("Adding resource type - name = " + MEMORY + ", units = "
+ + ResourceInformation.MEMORY_MB.getUnits() + ", type = "
+ + ResourceTypes.COUNTABLE);
+ ri = ResourceInformation
+ .newInstance(MEMORY,
+ ResourceInformation.MEMORY_MB.getUnits());
+ res.put(MEMORY, ri);
+ }
+ if (!res.containsKey(VCORES)) {
+ LOG.info("Adding resource type - name = " + VCORES + ", units = , type = "
+ + ResourceTypes.COUNTABLE);
+ ri =
+ ResourceInformation.newInstance(VCORES);
+ res.put(VCORES, ri);
+ }
+ }
+
+ private static void setMinimumAllocationForMandatoryResources(
+ Map res, Configuration conf) {
+ String[][] resourceTypesKeys = {
+ {ResourceInformation.MEMORY_MB.getName(),
+ YarnConfiguration.RM_SCHEDULER_MINIMUM_ALLOCATION_MB,
+ String.valueOf(
+ YarnConfiguration.DEFAULT_RM_SCHEDULER_MINIMUM_ALLOCATION_MB),
+ ResourceInformation.MEMORY_MB.getName()},
+ {ResourceInformation.VCORES.getName(),
+ YarnConfiguration.RM_SCHEDULER_MINIMUM_ALLOCATION_VCORES,
+ String.valueOf(
+ YarnConfiguration.DEFAULT_RM_SCHEDULER_MINIMUM_ALLOCATION_VCORES),
+ ResourceInformation.VCORES.getName()}};
+ for (String[] arr : resourceTypesKeys) {
+ String resourceTypesKey =
+ YarnConfiguration.RESOURCE_TYPES + "." + arr[0] + MINIMUM_ALLOCATION;
+ long minimumResourceTypes = conf.getLong(resourceTypesKey, -1);
+ long minimumConf = conf.getLong(arr[1], -1);
+ long minimum;
+ if (minimumResourceTypes != -1) {
+ minimum = minimumResourceTypes;
+ if (minimumConf != -1) {
+ LOG.warn("Using minimum allocation for memory specified in "
+ + "resource-types config file with key "
+ + minimumResourceTypes + ", ignoring minimum specified using "
+ + arr[1]);
+ }
+ } else {
+ minimum = conf.getLong(arr[1], Long.parseLong(arr[2]));
+ }
+ ResourceInformation ri = res.get(arr[3]);
+ ri.setMinimumAllocation(minimum);
+ }
+ }
+
+ private static void setMaximumAllocationForMandatoryResources(
+ Map res, Configuration conf) {
+ String[][] resourceTypesKeys = {
+ {ResourceInformation.MEMORY_MB.getName(),
+ YarnConfiguration.RM_SCHEDULER_MAXIMUM_ALLOCATION_MB,
+ String.valueOf(
+ YarnConfiguration.DEFAULT_RM_SCHEDULER_MAXIMUM_ALLOCATION_MB),
+ ResourceInformation.MEMORY_MB.getName()},
+ {ResourceInformation.VCORES.getName(),
+ YarnConfiguration.RM_SCHEDULER_MAXIMUM_ALLOCATION_VCORES,
+ String.valueOf(
+ YarnConfiguration.DEFAULT_RM_SCHEDULER_MAXIMUM_ALLOCATION_VCORES),
+ ResourceInformation.VCORES.getName()}};
+ for (String[] arr : resourceTypesKeys) {
+ String resourceTypesKey =
+ YarnConfiguration.RESOURCE_TYPES + "." + arr[0] + MAXIMUM_ALLOCATION;
+ long maximumResourceTypes = conf.getLong(resourceTypesKey, -1);
+ long maximumConf = conf.getLong(arr[1], -1);
+ long maximum;
+ if (maximumResourceTypes != -1) {
+ maximum = maximumResourceTypes;
+ if (maximumConf != -1) {
+ LOG.warn("Using maximum allocation for memory specified in "
+ + "resource-types config file with key "
+ + maximumResourceTypes + ", ignoring maximum specified using "
+ + arr[1]);
+ }
+ } else {
+ maximum = conf.getLong(arr[1], Long.parseLong(arr[2]));
+ }
+ ResourceInformation ri = res.get(arr[3]);
+ ri.setMaximumAllocation(maximum);
+ }
+ }
+
+ @VisibleForTesting
+ static void initializeResourcesMap(Configuration conf) {
+
+ Map resourceInformationMap = new HashMap<>();
+ String[] resourceNames = conf.getStrings(YarnConfiguration.RESOURCE_TYPES);
+
+ if (resourceNames != null && resourceNames.length != 0) {
+ for (String resourceName : resourceNames) {
+ String resourceUnits = conf.get(
+ YarnConfiguration.RESOURCE_TYPES + "." + resourceName + UNITS, "");
+ String resourceTypeName = conf.get(
+ YarnConfiguration.RESOURCE_TYPES + "." + resourceName + TYPE,
+ ResourceTypes.COUNTABLE.toString());
+ Long minimumAllocation = conf.getLong(
+ YarnConfiguration.RESOURCE_TYPES + "." + resourceName
+ + MINIMUM_ALLOCATION, 0L);
+ Long maximumAllocation = conf.getLong(
+ YarnConfiguration.RESOURCE_TYPES + "." + resourceName
+ + MAXIMUM_ALLOCATION, Long.MAX_VALUE);
+ if (resourceName == null || resourceName.isEmpty()
+ || resourceUnits == null || resourceTypeName == null) {
+ throw new YarnRuntimeException(
+ "Incomplete configuration for resource type '" + resourceName
+ + "'. One of name, units or type is configured incorrectly.");
+ }
+ if (DISALLOWED_NAMES.contains(resourceName)) {
+ throw new YarnRuntimeException(
+ "Resource type cannot be named '" + resourceName
+ + "'. That name is disallowed.");
+ }
+ ResourceTypes resourceType = ResourceTypes.valueOf(resourceTypeName);
+ LOG.info("Adding resource type - name = " + resourceName + ", units = "
+ + resourceUnits + ", type = " + resourceTypeName);
+ if (resourceInformationMap.containsKey(resourceName)) {
+ throw new YarnRuntimeException(
+ "Error in config, key '" + resourceName + "' specified twice");
+ }
+ resourceInformationMap.put(resourceName, ResourceInformation
+ .newInstance(resourceName, resourceUnits, 0L, resourceType,
+ minimumAllocation, maximumAllocation));
+ }
+ }
+ checkMandatatoryResources(resourceInformationMap);
+ addManadtoryResources(resourceInformationMap);
+ setMinimumAllocationForMandatoryResources(resourceInformationMap, conf);
+ setMaximumAllocationForMandatoryResources(resourceInformationMap, conf);
+ resourceTypes = Collections.unmodifiableMap(resourceInformationMap);
+ updateKnownResources();
+ updateResourceTypeIndex();
+ }
+
+ private static void updateKnownResources() {
+ // Update resource names.
+ resourceNamesArray = new String[resourceTypes.size()];
+ resourceTypesArray = new ResourceInformation[resourceTypes.size()];
+
+ int index = 2;
+ for (ResourceInformation resInfo : resourceTypes.values()) {
+ if (resInfo.getName().equals(MEMORY)) {
+ resourceTypesArray[0] = ResourceInformation
+ .newInstance(resourceTypes.get(MEMORY));
+ resourceNamesArray[0] = MEMORY;
+ } else if (resInfo.getName().equals(VCORES)) {
+ resourceTypesArray[1] = ResourceInformation
+ .newInstance(resourceTypes.get(VCORES));
+ resourceNamesArray[1] = VCORES;
+ } else {
+ resourceTypesArray[index] = ResourceInformation.newInstance(resInfo);
+ resourceNamesArray[index] = resInfo.getName();
+ index++;
+ }
+ }
+ }
+
+ private static void updateResourceTypeIndex() {
+ RESOURCE_NAME_TO_INDEX.clear();
+
+ for (int index = 0; index < resourceTypesArray.length; index++) {
+ ResourceInformation resInfo = resourceTypesArray[index];
+ RESOURCE_NAME_TO_INDEX.put(resInfo.getName(), index);
+ }
+ }
+
+ /**
+ * Get associate index of resource types such memory, cpu etc.
+ * This could help to access each resource types in a resource faster.
+ * @return Index map for all Resource Types.
+ */
+ public static Map getResourceTypeIndex() {
+ return RESOURCE_NAME_TO_INDEX;
+ }
+
+ /**
+ * Get the resource types to be supported by the system.
+ * @return A map of the resource name to a ResouceInformation object
+ * which contains details such as the unit.
+ */
+ public static Map getResourceTypes() {
+ return getResourceTypes(null,
+ YarnConfiguration.RESOURCE_TYPES_CONFIGURATION_FILE);
+ }
+
+ /**
+ * Get resource names array, this is mostly for performance perspective. Never
+ * modify returned array.
+ *
+ * @return resourceNamesArray
+ */
+ public static String[] getResourceNamesArray() {
+ initializeResourceTypesIfNeeded(null,
+ YarnConfiguration.RESOURCE_TYPES_CONFIGURATION_FILE);
+ return resourceNamesArray;
+ }
+
+ public static ResourceInformation[] getResourceTypesArray() {
+ initializeResourceTypesIfNeeded(null,
+ YarnConfiguration.RESOURCE_TYPES_CONFIGURATION_FILE);
+ return resourceTypesArray;
+ }
+
+ public static int getNumberOfKnownResourceTypes() {
+ if (numKnownResourceTypes < 0) {
+ initializeResourceTypesIfNeeded(null,
+ YarnConfiguration.RESOURCE_TYPES_CONFIGURATION_FILE);
+ }
+ return numKnownResourceTypes;
+ }
+
+ private static Map getResourceTypes(
+ Configuration conf) {
+ return getResourceTypes(conf,
+ YarnConfiguration.RESOURCE_TYPES_CONFIGURATION_FILE);
+ }
+
+ private static void initializeResourceTypesIfNeeded(Configuration conf,
+ String resourceFile) {
+ if (!initializedResources) {
+ synchronized (ResourceUtils.class) {
+ if (!initializedResources) {
+ if (conf == null) {
+ conf = new YarnConfiguration();
+ }
+ try {
+ addResourcesFileToConf(resourceFile, conf);
+ LOG.debug("Found " + resourceFile + ", adding to configuration");
+ initializeResourcesMap(conf);
+ initializedResources = true;
+ } catch (FileNotFoundException fe) {
+ LOG.info("Unable to find '" + resourceFile
+ + "'. Falling back to memory and vcores as resources.");
+ initializeResourcesMap(conf);
+ initializedResources = true;
+ }
+ }
+ }
+ }
+ numKnownResourceTypes = resourceTypes.size();
+ }
+
+ private static Map getResourceTypes(
+ Configuration conf, String resourceFile) {
+ initializeResourceTypesIfNeeded(conf, resourceFile);
+ return resourceTypes;
+ }
+
+ private static InputStream getConfInputStream(String resourceFile,
+ Configuration conf) throws IOException, YarnException {
+
+ ConfigurationProvider provider =
+ ConfigurationProviderFactory.getConfigurationProvider(conf);
+ try {
+ provider.init(conf);
+ } catch (Exception e) {
+ throw new IOException(e);
+ }
+
+ InputStream ris = provider.getConfigurationInputStream(conf, resourceFile);
+ if (ris == null) {
+ if (conf.getResource(resourceFile) == null) {
+ throw new FileNotFoundException("Unable to find " + resourceFile);
+ }
+ throw new IOException(
+ "Unable to open resource types file '" + resourceFile
+ + "'. Using provider " + provider);
+ }
+ return ris;
+ }
+
+ private static void addResourcesFileToConf(String resourceFile,
+ Configuration conf) throws FileNotFoundException {
+ try {
+ InputStream ris = getConfInputStream(resourceFile, conf);
+ LOG.debug("Found " + resourceFile + ", adding to configuration");
+ conf.addResource(ris);
+ } catch (FileNotFoundException fe) {
+ throw fe;
+ } catch (IOException ie) {
+ LOG.fatal("Exception trying to read resource types configuration '"
+ + resourceFile + "'.", ie);
+ throw new YarnRuntimeException(ie);
+ } catch (YarnException ye) {
+ LOG.fatal("YARN Exception trying to read resource types configuration '"
+ + resourceFile + "'.", ye);
+ throw new YarnRuntimeException(ye);
+ }
+ }
+
+ @VisibleForTesting
+ synchronized static void resetResourceTypes() {
+ initializedResources = false;
+ }
+
+ @VisibleForTesting
+ public static Map
+ resetResourceTypes(Configuration conf) {
+ synchronized (ResourceUtils.class) {
+ initializedResources = false;
+ }
+ return getResourceTypes(conf);
+ }
+
+ public static String getUnits(String resourceValue) {
+ String units;
+ for (int i = 0; i < resourceValue.length(); i++) {
+ if (Character.isAlphabetic(resourceValue.charAt(i))) {
+ units = resourceValue.substring(i);
+ if (StringUtils.isAlpha(units)) {
+ return units;
+ }
+ }
+ }
+ return "";
+ }
+
+ /**
+ * Function to get the resources for a node. This function will look at the
+ * file {@link YarnConfiguration#NODE_RESOURCES_CONFIGURATION_FILE} to
+ * determine the node resources.
+ *
+ * @param conf configuration file
+ * @return a map to resource name to the ResourceInformation object. The map
+ * is guaranteed to have entries for memory and vcores
+ */
+ public static Map getNodeResourceInformation(
+ Configuration conf) {
+ if (!initializedNodeResources) {
+ synchronized (ResourceUtils.class) {
+ if (!initializedNodeResources) {
+ Map nodeResources = initializeNodeResourceInformation(
+ conf);
+ addManadtoryResources(nodeResources);
+ checkMandatatoryResources(nodeResources);
+ setMinimumAllocationForMandatoryResources(nodeResources, conf);
+ setMaximumAllocationForMandatoryResources(nodeResources, conf);
+ readOnlyNodeResources = Collections.unmodifiableMap(nodeResources);
+ initializedNodeResources = true;
+ }
+ }
+ }
+ return readOnlyNodeResources;
+ }
+
+ private static Map initializeNodeResourceInformation(
+ Configuration conf) {
+ Map nodeResources = new HashMap<>();
+ try {
+ addResourcesFileToConf(
+ YarnConfiguration.NODE_RESOURCES_CONFIGURATION_FILE, conf);
+ for (Map.Entry entry : conf) {
+ String key = entry.getKey();
+ String value = entry.getValue();
+ if (key.startsWith(YarnConfiguration.NM_RESOURCES_PREFIX)) {
+ addResourceInformation(key, value, nodeResources);
+ }
+ }
+ } catch (FileNotFoundException fe) {
+ LOG.info("Couldn't find node resources file");
+ }
+ return nodeResources;
+ }
+
+ private static void addResourceInformation(String prop, String value,
+ Map nodeResources) {
+ String[] parts = prop.split("\\.");
+ LOG.info("Found resource entry " + prop);
+ if (parts.length == 4) {
+ String resourceType = parts[3];
+ if (!nodeResources.containsKey(resourceType)) {
+ nodeResources
+ .put(resourceType, ResourceInformation.newInstance(resourceType));
+ }
+ String units = getUnits(value);
+ Long resourceValue =
+ Long.valueOf(value.substring(0, value.length() - units.length()));
+ nodeResources.get(resourceType).setValue(resourceValue);
+ nodeResources.get(resourceType).setUnits(units);
+ LOG.debug("Setting value for resource type " + resourceType + " to "
+ + resourceValue + " with units " + units);
+ }
+ }
+
+ @VisibleForTesting
+ synchronized public static void resetNodeResources() {
+ initializedNodeResources = false;
+ }
+
+ public static Resource getResourceTypesMinimumAllocation() {
+ Resource ret = Resource.newInstance(0, 0);
+ for (ResourceInformation entry : resourceTypesArray) {
+ String name = entry.getName();
+ if (name.equals(ResourceInformation.MEMORY_MB.getName())) {
+ ret.setMemorySize(entry.getMinimumAllocation());
+ } else if (name.equals(ResourceInformation.VCORES.getName())) {
+ Long tmp = entry.getMinimumAllocation();
+ if (tmp > Integer.MAX_VALUE) {
+ tmp = (long) Integer.MAX_VALUE;
+ }
+ ret.setVirtualCores(tmp.intValue());
+ } else {
+ ret.setResourceValue(name, entry.getMinimumAllocation());
+ }
+ }
+ return ret;
+ }
+
+ /**
+ * Get a Resource object with for the maximum allocation possible.
+ * @return a Resource object with the maximum allocation for the scheduler
+ */
+ public static Resource getResourceTypesMaximumAllocation() {
+ Resource ret = Resource.newInstance(0, 0);
+ for (ResourceInformation entry : resourceTypesArray) {
+ String name = entry.getName();
+ if (name.equals(ResourceInformation.MEMORY_MB.getName())) {
+ ret.setMemorySize(entry.getMaximumAllocation());
+ } else if (name.equals(ResourceInformation.VCORES.getName())) {
+ Long tmp = entry.getMaximumAllocation();
+ if (tmp > Integer.MAX_VALUE) {
+ tmp = (long) Integer.MAX_VALUE;
+ }
+ ret.setVirtualCores(tmp.intValue());
+ continue;
+ } else {
+ ret.setResourceValue(name, entry.getMaximumAllocation());
+ }
+ }
+ return ret;
+ }
+
+ /**
+ * Get default unit by given resource type.
+ * @param resourceType resourceType
+ * @return default unit
+ */
+ public static String getDefaultUnit(String resourceType) {
+ ResourceInformation ri = getResourceTypes().get(resourceType);
+ if (null != ri) {
+ return ri.getUnits();
+ }
+ return "";
+ }
+
+ /**
+ * Get all resource types information from known resource types.
+ * @return List of ResourceTypeInfo
+ */
+ public static List getResourcesTypeInfo() {
+ List array = new ArrayList<>();
+ // Add all resource types
+ Collection resourcesInfo =
+ ResourceUtils.getResourceTypes().values();
+ for (ResourceInformation resourceInfo : resourcesInfo) {
+ array.add(ResourceTypeInfo
+ .newInstance(resourceInfo.getName(), resourceInfo.getUnits(),
+ resourceInfo.getResourceType()));
+ }
+ return array;
+ }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/util/resource/package-info.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/util/resource/package-info.java
new file mode 100644
index 00000000000..1e925d7d57c
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/util/resource/package-info.java
@@ -0,0 +1,26 @@
+/*
+ * 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.util.resource contains classes
+ * which is used as utility class for resource profile computations.
+ */
+@InterfaceAudience.Public
+@InterfaceStability.Unstable
+package org.apache.hadoop.yarn.util.resource;
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
\ No newline at end of file
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/proto/applicationclient_protocol.proto b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/proto/applicationclient_protocol.proto
index ba79db09a6f..81adef19335 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/proto/applicationclient_protocol.proto
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/proto/applicationclient_protocol.proto
@@ -61,4 +61,7 @@ service ApplicationClientProtocolService {
rpc updateApplicationPriority (UpdateApplicationPriorityRequestProto) returns (UpdateApplicationPriorityResponseProto);
rpc signalToContainer(SignalContainerRequestProto) returns (SignalContainerResponseProto);
rpc updateApplicationTimeouts (UpdateApplicationTimeoutsRequestProto) returns (UpdateApplicationTimeoutsResponseProto);
+ rpc getResourceProfiles(GetAllResourceProfilesRequestProto) returns (GetAllResourceProfilesResponseProto);
+ rpc getResourceProfile(GetResourceProfileRequestProto) returns (GetResourceProfileResponseProto);
+ rpc getResourceTypeInfo(GetAllResourceTypeInfoRequestProto) returns (GetAllResourceTypeInfoResponseProto);
}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/proto/yarn_protos.proto b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/proto/yarn_protos.proto
index c5f485fc3f7..9933e9ea8e9 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/proto/yarn_protos.proto
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/proto/yarn_protos.proto
@@ -53,9 +53,27 @@ message ContainerIdProto {
optional int64 id = 3;
}
+enum ResourceTypesProto {
+ COUNTABLE = 0;
+}
+
+message ResourceInformationProto {
+ required string key = 1;
+ optional int64 value = 2;
+ optional string units = 3;
+ optional ResourceTypesProto type = 4;
+}
+
+message ResourceTypeInfoProto {
+ required string name = 1;
+ optional string units = 2;
+ optional ResourceTypesProto type = 3;
+}
+
message ResourceProto {
optional int64 memory = 1;
optional int32 virtual_cores = 2;
+ repeated ResourceInformationProto resource_value_map = 3;
}
message ResourceUtilizationProto {
@@ -69,6 +87,15 @@ message ResourceOptionProto {
optional int32 over_commit_timeout = 2;
}
+message ResourceProfileEntry {
+ required string name = 1;
+ required ResourceProto resources = 2;
+}
+
+message ResourceProfilesProto {
+ repeated ResourceProfileEntry resource_profiles_map = 1;
+}
+
message NodeResourceMapProto {
optional NodeIdProto node_id = 1;
optional ResourceOptionProto resource_option = 2;
@@ -174,6 +201,11 @@ message LocalResourceProto {
optional bool should_be_uploaded_to_shared_cache = 7;
}
+message StringLongMapProto {
+ required string key = 1;
+ required int64 value = 2;
+}
+
message ApplicationResourceUsageReportProto {
optional int32 num_used_containers = 1;
optional int32 num_reserved_containers = 2;
@@ -186,6 +218,8 @@ message ApplicationResourceUsageReportProto {
optional float cluster_usage_percentage = 9;
optional int64 preempted_memory_seconds = 10;
optional int64 preempted_vcore_seconds = 11;
+ repeated StringLongMapProto application_resource_usage_map = 12;
+ repeated StringLongMapProto application_preempted_resource_usage_map = 13;
}
message ApplicationReportProto {
@@ -310,6 +344,11 @@ enum ExecutionTypeProto {
////////////////////////////////////////////////////////////////////////
////// From AM_RM_Protocol /////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
+message ProfileCapabilityProto {
+ required string profile = 1;
+ required ResourceProto profileCapabilityOverride = 2;
+}
+
message ResourceRequestProto {
optional PriorityProto priority = 1;
optional string resource_name = 2;
@@ -319,6 +358,7 @@ message ResourceRequestProto {
optional string node_label_expression = 6;
optional ExecutionTypeRequestProto execution_type_request = 7;
optional int64 allocation_request_id = 8 [default = 0];
+ optional ProfileCapabilityProto profile = 9;
}
message ExecutionTypeRequestProto {
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/proto/yarn_service_protos.proto b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/proto/yarn_service_protos.proto
index 7a7f03503ca..3da4ee7298a 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/proto/yarn_service_protos.proto
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/proto/yarn_service_protos.proto
@@ -48,6 +48,7 @@ message RegisterApplicationMasterResponseProto {
optional string queue = 5;
repeated NMTokenProto nm_tokens_from_previous_attempts = 6;
repeated SchedulerResourceTypes scheduler_resource_types = 7;
+ optional ResourceProfilesProto resource_profiles = 8;
}
message FinishApplicationMasterRequestProto {
@@ -279,6 +280,28 @@ message UpdateApplicationTimeoutsResponseProto {
repeated ApplicationUpdateTimeoutMapProto application_timeouts = 1;
}
+message GetAllResourceProfilesRequestProto {
+}
+
+message GetAllResourceProfilesResponseProto {
+ required ResourceProfilesProto resource_profiles = 1;
+}
+
+message GetResourceProfileRequestProto {
+ required string profile = 1;
+}
+
+message GetResourceProfileResponseProto {
+ required ResourceProto resources = 1;
+}
+
+message GetAllResourceTypeInfoRequestProto {
+}
+
+message GetAllResourceTypeInfoResponseProto {
+ repeated ResourceTypeInfoProto resource_type_info = 1;
+}
+
//////////////////////////////////////////////////////
/////// client_NM_Protocol ///////////////////////////
//////////////////////////////////////////////////////
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/test/java/org/apache/hadoop/yarn/conf/TestResourceInformation.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/test/java/org/apache/hadoop/yarn/conf/TestResourceInformation.java
new file mode 100644
index 00000000000..66bf3204bf6
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/test/java/org/apache/hadoop/yarn/conf/TestResourceInformation.java
@@ -0,0 +1,73 @@
+/**
+ * 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.conf;
+
+import org.apache.hadoop.yarn.api.records.ResourceInformation;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Test class to verify various resource informations in a given resource.
+ */
+public class TestResourceInformation {
+
+ @Test
+ public void testName() {
+ String name = "yarn.io/test";
+ ResourceInformation ri = ResourceInformation.newInstance(name);
+ Assert.assertEquals("Resource name incorrect", name, ri.getName());
+ }
+
+ @Test
+ public void testUnits() {
+ String name = "yarn.io/test";
+ String units = "m";
+ ResourceInformation ri = ResourceInformation.newInstance(name, units);
+ Assert.assertEquals("Resource name incorrect", name, ri.getName());
+ Assert.assertEquals("Resource units incorrect", units, ri.getUnits());
+ units = "z";
+ try {
+ ResourceInformation.newInstance(name, units);
+ Assert.fail(units + "is not a valid unit");
+ } catch (IllegalArgumentException ie) {
+ // do nothing
+ }
+ }
+
+ @Test
+ public void testValue() {
+ String name = "yarn.io/test";
+ long value = 1L;
+ ResourceInformation ri = ResourceInformation.newInstance(name, value);
+ Assert.assertEquals("Resource name incorrect", name, ri.getName());
+ Assert.assertEquals("Resource value incorrect", value, ri.getValue());
+ }
+
+ @Test
+ public void testResourceInformation() {
+ String name = "yarn.io/test";
+ long value = 1L;
+ String units = "m";
+ ResourceInformation ri =
+ ResourceInformation.newInstance(name, units, value);
+ Assert.assertEquals("Resource name incorrect", name, ri.getName());
+ Assert.assertEquals("Resource value incorrect", value, ri.getValue());
+ Assert.assertEquals("Resource units incorrect", units, ri.getUnits());
+ }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/test/java/org/apache/hadoop/yarn/conf/TestYarnConfigurationFields.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/test/java/org/apache/hadoop/yarn/conf/TestYarnConfigurationFields.java
index bd7bf93566f..ce1239d4281 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/test/java/org/apache/hadoop/yarn/conf/TestYarnConfigurationFields.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/test/java/org/apache/hadoop/yarn/conf/TestYarnConfigurationFields.java
@@ -141,6 +141,10 @@ public void initializeMemberVariables() {
// Used as Java command line properties, not XML
configurationPrefixToSkipCompare.add("yarn.app.container");
+ // Ignore default file name for resource profiles
+ configurationPropsToSkipCompare
+ .add(YarnConfiguration.DEFAULT_RM_RESOURCE_PROFILES_SOURCE_FILE);
+
// Ignore NodeManager "work in progress" variables
configurationPrefixToSkipCompare
.add(YarnConfiguration.NM_NETWORK_RESOURCE_ENABLED);
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/test/java/org/apache/hadoop/yarn/util/TestUnitsConversionUtil.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/test/java/org/apache/hadoop/yarn/util/TestUnitsConversionUtil.java
new file mode 100644
index 00000000000..a412faebed8
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/test/java/org/apache/hadoop/yarn/util/TestUnitsConversionUtil.java
@@ -0,0 +1,139 @@
+/**
+ * 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.util;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Test class to handle all test cases needed to verify basic unit conversion
+ * scenarios.
+ */
+public class TestUnitsConversionUtil {
+
+ @Test
+ public void testUnitsConversion() {
+ int value = 5;
+ String fromUnit = "";
+ long test = value;
+ Assert.assertEquals("pico test failed",
+ value * 1000L * 1000L * 1000L * 1000L,
+ UnitsConversionUtil.convert(fromUnit, "p", test));
+ Assert.assertEquals("nano test failed",
+ value * 1000L * 1000L * 1000L,
+ UnitsConversionUtil.convert(fromUnit, "n", test));
+ Assert
+ .assertEquals("micro test failed", value * 1000L * 1000L,
+ UnitsConversionUtil.convert(fromUnit, "u", test));
+ Assert.assertEquals("milli test failed", value * 1000L,
+ UnitsConversionUtil.convert(fromUnit, "m", test));
+
+ test = value * 1000L * 1000L * 1000L * 1000L * 1000L;
+ fromUnit = "";
+ Assert.assertEquals("kilo test failed", test / 1000L,
+ UnitsConversionUtil.convert(fromUnit, "k", test));
+
+ Assert
+ .assertEquals("mega test failed", test / (1000L * 1000L),
+ UnitsConversionUtil.convert(fromUnit, "M", test));
+ Assert.assertEquals("giga test failed",
+ test / (1000L * 1000L * 1000L),
+ UnitsConversionUtil.convert(fromUnit, "G", test));
+ Assert.assertEquals("tera test failed",
+ test / (1000L * 1000L * 1000L * 1000L),
+ UnitsConversionUtil.convert(fromUnit, "T", test));
+ Assert.assertEquals("peta test failed",
+ test / (1000L * 1000L * 1000L * 1000L * 1000L),
+ UnitsConversionUtil.convert(fromUnit, "P", test));
+
+ Assert.assertEquals("nano to pico test failed", value * 1000L,
+ UnitsConversionUtil.convert("n", "p", value));
+
+ Assert.assertEquals("mega to giga test failed", value,
+ UnitsConversionUtil.convert("M", "G", value * 1000L));
+
+ Assert.assertEquals("Mi to Gi test failed", value,
+ UnitsConversionUtil.convert("Mi", "Gi", value * 1024L));
+
+ Assert.assertEquals("Mi to Ki test failed", value * 1024,
+ UnitsConversionUtil.convert("Mi", "Ki", value));
+
+ Assert.assertEquals("Ki to base units test failed", 5 * 1024,
+ UnitsConversionUtil.convert("Ki", "", 5));
+
+ Assert.assertEquals("Mi to k test failed", 1073741,
+ UnitsConversionUtil.convert("Mi", "k", 1024));
+
+ Assert.assertEquals("M to Mi test failed", 953,
+ UnitsConversionUtil.convert("M", "Mi", 1000));
+ }
+
+ @Test
+ public void testOverflow() {
+ long test = 5 * 1000L * 1000L * 1000L * 1000L * 1000L;
+ try {
+ UnitsConversionUtil.convert("P", "p", test);
+ Assert.fail("this operation should result in an overflow");
+ } catch (IllegalArgumentException ie) {
+ // do nothing
+ }
+ try {
+ UnitsConversionUtil.convert("m", "p", Long.MAX_VALUE - 1);
+ Assert.fail("this operation should result in an overflow");
+ } catch (IllegalArgumentException ie) {
+ // do nothing
+ }
+ }
+
+ @Test
+ public void testCompare() {
+ String unitA = "P";
+ long valueA = 1;
+ String unitB = "p";
+ long valueB = 2;
+ Assert.assertEquals(1,
+ UnitsConversionUtil.compare(unitA, valueA, unitB, valueB));
+ Assert.assertEquals(-1,
+ UnitsConversionUtil.compare(unitB, valueB, unitA, valueA));
+ Assert.assertEquals(0,
+ UnitsConversionUtil.compare(unitA, valueA, unitA, valueA));
+ Assert.assertEquals(-1,
+ UnitsConversionUtil.compare(unitA, valueA, unitA, valueB));
+ Assert.assertEquals(1,
+ UnitsConversionUtil.compare(unitA, valueB, unitA, valueA));
+
+ unitB = "T";
+ Assert.assertEquals(1,
+ UnitsConversionUtil.compare(unitA, valueA, unitB, valueB));
+ Assert.assertEquals(-1,
+ UnitsConversionUtil.compare(unitB, valueB, unitA, valueA));
+ Assert.assertEquals(0,
+ UnitsConversionUtil.compare(unitA, valueA, unitB, 1000L));
+
+ unitA = "p";
+ unitB = "n";
+ Assert.assertEquals(-1,
+ UnitsConversionUtil.compare(unitA, valueA, unitB, valueB));
+ Assert.assertEquals(1,
+ UnitsConversionUtil.compare(unitB, valueB, unitA, valueA));
+ Assert.assertEquals(0,
+ UnitsConversionUtil.compare(unitA, 1000L, unitB, valueA));
+
+ }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-distributedshell/src/main/java/org/apache/hadoop/yarn/applications/distributedshell/ApplicationMaster.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-distributedshell/src/main/java/org/apache/hadoop/yarn/applications/distributedshell/ApplicationMaster.java
index a02af709116..c167862e58e 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-distributedshell/src/main/java/org/apache/hadoop/yarn/applications/distributedshell/ApplicationMaster.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-distributedshell/src/main/java/org/apache/hadoop/yarn/applications/distributedshell/ApplicationMaster.java
@@ -87,6 +87,7 @@
import org.apache.hadoop.yarn.api.records.LocalResourceVisibility;
import org.apache.hadoop.yarn.api.records.NodeReport;
import org.apache.hadoop.yarn.api.records.Priority;
+import org.apache.hadoop.yarn.api.records.ProfileCapability;
import org.apache.hadoop.yarn.api.records.Resource;
import org.apache.hadoop.yarn.api.records.ResourceRequest;
import org.apache.hadoop.yarn.api.records.URL;
@@ -103,6 +104,7 @@
import org.apache.hadoop.yarn.client.api.async.impl.NMClientAsyncImpl;
import org.apache.hadoop.yarn.conf.YarnConfiguration;
import org.apache.hadoop.yarn.exceptions.YarnException;
+import org.apache.hadoop.yarn.exceptions.YarnRuntimeException;
import org.apache.hadoop.yarn.security.AMRMTokenIdentifier;
import org.apache.hadoop.yarn.util.SystemClock;
import org.apache.hadoop.yarn.util.TimelineServiceHelper;
@@ -231,12 +233,18 @@
@VisibleForTesting
protected int numTotalContainers = 1;
// Memory to request for the container on which the shell command will run
- private long containerMemory = 10;
+ private static final long DEFAULT_CONTAINER_MEMORY = 10;
+ private long containerMemory = DEFAULT_CONTAINER_MEMORY;
// VirtualCores to request for the container on which the shell command will run
- private int containerVirtualCores = 1;
+ private static final int DEFAULT_CONTAINER_VCORES = 1;
+ private int containerVirtualCores = DEFAULT_CONTAINER_VCORES;
// Priority of the request
private int requestPriority;
+ // Resource profile for the container
+ private String containerResourceProfile = "";
+ Map resourceProfiles;
+
// Counter for completed containers ( complete denotes successful or failed )
private AtomicInteger numCompletedContainers = new AtomicInteger();
// Allocated container count so that we know how many containers has the RM
@@ -407,6 +415,8 @@ public boolean init(String[] args) throws ParseException, IOException {
"Amount of memory in MB to be requested to run the shell command");
opts.addOption("container_vcores", true,
"Amount of virtual cores to be requested to run the shell command");
+ opts.addOption("container_resource_profile", true,
+ "Resource profile to be requested to run the shell command");
opts.addOption("num_containers", true,
"No. of containers on which the shell command needs to be executed");
opts.addOption("priority", true, "Application Priority. Default 0");
@@ -548,9 +558,11 @@ public boolean init(String[] args) throws ParseException, IOException {
}
containerMemory = Integer.parseInt(cliParser.getOptionValue(
- "container_memory", "10"));
+ "container_memory", "-1"));
containerVirtualCores = Integer.parseInt(cliParser.getOptionValue(
- "container_vcores", "1"));
+ "container_vcores", "-1"));
+ containerResourceProfile =
+ cliParser.getOptionValue("container_resource_profile", "");
numTotalContainers = Integer.parseInt(cliParser.getOptionValue(
"num_containers", "1"));
if (numTotalContainers == 0) {
@@ -669,6 +681,7 @@ public void run() throws YarnException, IOException, InterruptedException {
RegisterApplicationMasterResponse response = amRMClient
.registerApplicationMaster(appMasterHostname, appMasterRpcPort,
appMasterTrackingUrl);
+ resourceProfiles = response.getResourceProfiles();
// Dump out information about cluster capability as seen by the
// resource manager
long maxMem = response.getMaximumResourceCapability().getMemorySize();
@@ -1216,12 +1229,8 @@ private ContainerRequest setupContainerAskForRM() {
Priority pri = Priority.newInstance(requestPriority);
// Set up resource type requirements
- // For now, memory and CPU are supported so we set memory and cpu requirements
- Resource capability = Resource.newInstance(containerMemory,
- containerVirtualCores);
-
- ContainerRequest request = new ContainerRequest(capability, null, null,
- pri);
+ ContainerRequest request =
+ new ContainerRequest(createProfileCapability(), null, null, pri);
LOG.info("Requested container ask: " + request.toString());
return request;
}
@@ -1485,4 +1494,36 @@ public TimelinePutResponse run() throws Exception {
}
}
+ private ProfileCapability createProfileCapability()
+ throws YarnRuntimeException {
+ if (containerMemory < -1 || containerMemory == 0) {
+ throw new YarnRuntimeException("Value of AM memory '" + containerMemory
+ + "' has to be greater than 0");
+ }
+ if (containerVirtualCores < -1 || containerVirtualCores == 0) {
+ throw new YarnRuntimeException(
+ "Value of AM vcores '" + containerVirtualCores
+ + "' has to be greater than 0");
+ }
+
+ Resource resourceCapability =
+ Resource.newInstance(containerMemory, containerVirtualCores);
+ if (resourceProfiles == null) {
+ containerMemory = containerMemory == -1 ? DEFAULT_CONTAINER_MEMORY :
+ containerMemory;
+ containerVirtualCores =
+ containerVirtualCores == -1 ? DEFAULT_CONTAINER_VCORES :
+ containerVirtualCores;
+ resourceCapability.setMemorySize(containerMemory);
+ resourceCapability.setVirtualCores(containerVirtualCores);
+ }
+
+ String profileName = containerResourceProfile;
+ if ("".equals(containerResourceProfile) && resourceProfiles != null) {
+ profileName = "default";
+ }
+ ProfileCapability capability =
+ ProfileCapability.newInstance(profileName, resourceCapability);
+ return capability;
+ }
}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-distributedshell/src/main/java/org/apache/hadoop/yarn/applications/distributedshell/Client.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-distributedshell/src/main/java/org/apache/hadoop/yarn/applications/distributedshell/Client.java
index eedb5016e4f..1a973049fc7 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-distributedshell/src/main/java/org/apache/hadoop/yarn/applications/distributedshell/Client.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-distributedshell/src/main/java/org/apache/hadoop/yarn/applications/distributedshell/Client.java
@@ -66,10 +66,12 @@
import org.apache.hadoop.yarn.api.records.NodeReport;
import org.apache.hadoop.yarn.api.records.NodeState;
import org.apache.hadoop.yarn.api.records.Priority;
+import org.apache.hadoop.yarn.api.records.ProfileCapability;
import org.apache.hadoop.yarn.api.records.QueueACL;
import org.apache.hadoop.yarn.api.records.QueueInfo;
import org.apache.hadoop.yarn.api.records.QueueUserACLInfo;
import org.apache.hadoop.yarn.api.records.Resource;
+import org.apache.hadoop.yarn.api.records.ResourceRequest;
import org.apache.hadoop.yarn.api.records.URL;
import org.apache.hadoop.yarn.api.records.YarnApplicationState;
import org.apache.hadoop.yarn.api.records.YarnClusterMetrics;
@@ -79,8 +81,9 @@
import org.apache.hadoop.yarn.client.api.YarnClientApplication;
import org.apache.hadoop.yarn.client.util.YarnClientUtils;
import org.apache.hadoop.yarn.conf.YarnConfiguration;
+import org.apache.hadoop.yarn.exceptions.YARNFeatureNotEnabledException;
import org.apache.hadoop.yarn.exceptions.YarnException;
-import org.apache.hadoop.yarn.util.ConverterUtils;
+import org.apache.hadoop.yarn.util.resource.Resources;
import org.apache.hadoop.yarn.util.timeline.TimelineUtils;
/**
@@ -119,6 +122,11 @@
public class Client {
private static final Log LOG = LogFactory.getLog(Client.class);
+
+ private static final int DEFAULT_AM_MEMORY = 100;
+ private static final int DEFAULT_AM_VCORES = 1;
+ private static final int DEFAULT_CONTAINER_MEMORY = 10;
+ private static final int DEFAULT_CONTAINER_VCORES = 1;
// Configuration
private Configuration conf;
@@ -130,9 +138,12 @@
// Queue for App master
private String amQueue = "";
// Amt. of memory resource to request for to run the App Master
- private long amMemory = 100;
+ private long amMemory = DEFAULT_AM_MEMORY;
// Amt. of virtual core resource to request for to run the App Master
- private int amVCores = 1;
+ private int amVCores = DEFAULT_AM_VCORES;
+
+ // AM resource profile
+ private String amResourceProfile = "";
// Application master jar file
private String appMasterJar = "";
@@ -151,9 +162,11 @@
private int shellCmdPriority = 0;
// Amt of memory to request for container in which shell script will be executed
- private int containerMemory = 10;
+ private long containerMemory = DEFAULT_CONTAINER_MEMORY;
// Amt. of virtual cores to request for container in which shell script will be executed
- private int containerVirtualCores = 1;
+ private int containerVirtualCores = DEFAULT_CONTAINER_VCORES;
+ // container resource profile
+ private String containerResourceProfile = "";
// No. of containers in which the shell script needs to be executed
private int numContainers = 1;
private String nodeLabelExpression = null;
@@ -256,6 +269,7 @@ public Client(Configuration conf) throws Exception {
opts.addOption("master_memory", true, "Amount of memory in MB to be requested to run the application master");
opts.addOption("master_vcores", true, "Amount of virtual cores to be requested to run the application master");
opts.addOption("jar", true, "Jar file containing the application master");
+ opts.addOption("master_resource_profile", true, "Resource profile for the application master");
opts.addOption("shell_command", true, "Shell command to be executed by " +
"the Application Master. Can only specify either --shell_command " +
"or --shell_script");
@@ -269,6 +283,7 @@ public Client(Configuration conf) throws Exception {
opts.addOption("shell_cmd_priority", true, "Priority for the shell command containers");
opts.addOption("container_memory", true, "Amount of memory in MB to be requested to run the shell command");
opts.addOption("container_vcores", true, "Amount of virtual cores to be requested to run the shell command");
+ opts.addOption("container_resource_profile", true, "Resource profile for the shell command");
opts.addOption("num_containers", true, "No. of containers on which the shell command needs to be executed");
opts.addOption("log_properties", true, "log4j.properties file");
opts.addOption("keep_containers_across_application_attempts", false,
@@ -372,17 +387,11 @@ public boolean init(String[] args) throws ParseException {
appName = cliParser.getOptionValue("appname", "DistributedShell");
amPriority = Integer.parseInt(cliParser.getOptionValue("priority", "0"));
amQueue = cliParser.getOptionValue("queue", "default");
- amMemory = Integer.parseInt(cliParser.getOptionValue("master_memory", "100"));
- amVCores = Integer.parseInt(cliParser.getOptionValue("master_vcores", "1"));
-
- if (amMemory < 0) {
- throw new IllegalArgumentException("Invalid memory specified for application master, exiting."
- + " Specified memory=" + amMemory);
- }
- if (amVCores < 0) {
- throw new IllegalArgumentException("Invalid virtual cores specified for application master, exiting."
- + " Specified virtual cores=" + amVCores);
- }
+ amMemory =
+ Integer.parseInt(cliParser.getOptionValue("master_memory", "-1"));
+ amVCores =
+ Integer.parseInt(cliParser.getOptionValue("master_vcores", "-1"));
+ amResourceProfile = cliParser.getOptionValue("master_resource_profile", "");
if (!cliParser.hasOption("jar")) {
throw new IllegalArgumentException("No jar file specified for application master");
@@ -423,17 +432,18 @@ public boolean init(String[] args) throws ParseException {
}
shellCmdPriority = Integer.parseInt(cliParser.getOptionValue("shell_cmd_priority", "0"));
- containerMemory = Integer.parseInt(cliParser.getOptionValue("container_memory", "10"));
- containerVirtualCores = Integer.parseInt(cliParser.getOptionValue("container_vcores", "1"));
- numContainers = Integer.parseInt(cliParser.getOptionValue("num_containers", "1"));
-
-
- if (containerMemory < 0 || containerVirtualCores < 0 || numContainers < 1) {
- throw new IllegalArgumentException("Invalid no. of containers or container memory/vcores specified,"
- + " exiting."
- + " Specified containerMemory=" + containerMemory
- + ", containerVirtualCores=" + containerVirtualCores
- + ", numContainer=" + numContainers);
+ containerMemory =
+ Integer.parseInt(cliParser.getOptionValue("container_memory", "-1"));
+ containerVirtualCores =
+ Integer.parseInt(cliParser.getOptionValue("container_vcores", "-1"));
+ containerResourceProfile =
+ cliParser.getOptionValue("container_resource_profile", "");
+ numContainers =
+ Integer.parseInt(cliParser.getOptionValue("num_containers", "1"));
+
+ if (numContainers < 1) {
+ throw new IllegalArgumentException("Invalid no. of containers specified,"
+ + " exiting. Specified numContainer=" + numContainers);
}
nodeLabelExpression = cliParser.getOptionValue("node_label_expression", null);
@@ -540,6 +550,32 @@ public boolean run() throws IOException, YarnException {
prepareTimelineDomain();
}
+ Map profiles;
+ try {
+ profiles = yarnClient.getResourceProfiles();
+ } catch (YARNFeatureNotEnabledException re) {
+ profiles = null;
+ }
+
+ List appProfiles = new ArrayList<>(2);
+ appProfiles.add(amResourceProfile);
+ appProfiles.add(containerResourceProfile);
+ for (String appProfile : appProfiles) {
+ if (appProfile != null && !appProfile.isEmpty()) {
+ if (profiles == null) {
+ String message = "Resource profiles is not enabled";
+ LOG.error(message);
+ throw new IOException(message);
+ }
+ if (!profiles.containsKey(appProfile)) {
+ String message = "Unknown resource profile '" + appProfile
+ + "'. Valid resource profiles are " + profiles.keySet();
+ LOG.error(message);
+ throw new IOException(message);
+ }
+ }
+ }
+
// Get a new application id
YarnClientApplication app = yarnClient.createApplication();
GetNewApplicationResponse appResponse = app.getNewApplicationResponse();
@@ -573,6 +609,13 @@ public boolean run() throws IOException, YarnException {
ApplicationSubmissionContext appContext = app.getApplicationSubmissionContext();
ApplicationId appId = appContext.getApplicationId();
+ // Set up resource type requirements
+ // For now, both memory and vcores are supported, so we set memory and
+ // vcores requirements
+ setAMResourceCapability(appContext, amMemory, amVCores, amResourceProfile,
+ amPriority, profiles);
+ setContainerResources(containerMemory, containerVirtualCores, profiles);
+
appContext.setKeepContainersAcrossApplicationAttempts(keepContainers);
appContext.setApplicationName(appName);
@@ -696,8 +739,16 @@ public boolean run() throws IOException, YarnException {
// Set class name
vargs.add(appMasterMainClass);
// Set params for Application Master
- vargs.add("--container_memory " + String.valueOf(containerMemory));
- vargs.add("--container_vcores " + String.valueOf(containerVirtualCores));
+ if (containerMemory > 0) {
+ vargs.add("--container_memory " + String.valueOf(containerMemory));
+ }
+ if (containerVirtualCores > 0) {
+ vargs.add("--container_vcores " + String.valueOf(containerVirtualCores));
+ }
+ if (containerResourceProfile != null && !containerResourceProfile
+ .isEmpty()) {
+ vargs.add("--container_resource_profile " + containerResourceProfile);
+ }
vargs.add("--num_containers " + String.valueOf(numContainers));
if (null != nodeLabelExpression) {
appContext.setNodeLabelExpression(nodeLabelExpression);
@@ -730,12 +781,6 @@ public boolean run() throws IOException, YarnException {
ContainerLaunchContext amContainer = ContainerLaunchContext.newInstance(
localResources, env, commands, null, null, null);
- // Set up resource type requirements
- // For now, both memory and vcores are supported, so we set memory and
- // vcores requirements
- Resource capability = Resource.newInstance(amMemory, amVCores);
- appContext.setResource(capability);
-
// Service data is a binary blob that can be passed to the application
// Not needed in this scenario
// amContainer.setServiceData(serviceData);
@@ -933,4 +978,65 @@ private void prepareTimelineDomain() {
timelineClient.stop();
}
}
+
+ private void setAMResourceCapability(ApplicationSubmissionContext appContext,
+ long memory, int vcores, String profile, int priority,
+ Map profiles) throws IllegalArgumentException {
+ if (memory < -1 || memory == 0) {
+ throw new IllegalArgumentException("Invalid memory specified for"
+ + " application master, exiting. Specified memory=" + memory);
+ }
+ if (vcores < -1 || vcores == 0) {
+ throw new IllegalArgumentException("Invalid virtual cores specified for"
+ + " application master, exiting. Specified virtual cores=" + vcores);
+ }
+ String tmp = profile;
+ if (profile.isEmpty()) {
+ tmp = "default";
+ }
+ if (appContext.getAMContainerResourceRequests() == null) {
+ List amResourceRequests = new ArrayList();
+ amResourceRequests
+ .add(ResourceRequest.newInstance(Priority.newInstance(priority), "*",
+ Resources.clone(Resources.none()), 1));
+ appContext.setAMContainerResourceRequests(amResourceRequests);
+ }
+
+ if (appContext.getAMContainerResourceRequests().get(0)
+ .getProfileCapability() == null) {
+ appContext.getAMContainerResourceRequests().get(0).setProfileCapability(
+ ProfileCapability.newInstance(tmp, Resource.newInstance(0, 0)));
+ }
+ Resource capability = Resource.newInstance(0, 0);
+ // set amMemory because it's used to set Xmx param
+ if (profiles == null) {
+ amMemory = memory == -1 ? DEFAULT_AM_MEMORY : memory;
+ amVCores = vcores == -1 ? DEFAULT_AM_VCORES : vcores;
+ capability.setMemorySize(amMemory);
+ capability.setVirtualCores(amVCores);
+ } else {
+ amMemory = memory == -1 ? profiles.get(tmp).getMemorySize() : memory;
+ amVCores = vcores == -1 ? profiles.get(tmp).getVirtualCores() : vcores;
+ capability.setMemorySize(memory);
+ capability.setVirtualCores(vcores);
+ }
+ appContext.getAMContainerResourceRequests().get(0).getProfileCapability()
+ .setProfileCapabilityOverride(capability);
+ }
+
+ private void setContainerResources(long memory, int vcores,
+ Map profiles) throws IllegalArgumentException {
+ if (memory < -1 || memory == 0) {
+ throw new IllegalArgumentException(
+ "Container memory '" + memory + "' has to be greated than 0");
+ }
+ if (vcores < -1 || vcores == 0) {
+ throw new IllegalArgumentException(
+ "Container vcores '" + vcores + "' has to be greated than 0");
+ }
+ if (profiles == null) {
+ containerMemory = memory == -1 ? DEFAULT_CONTAINER_MEMORY : memory;
+ containerVirtualCores = vcores == -1 ? DEFAULT_CONTAINER_VCORES : vcores;
+ }
+ }
}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-distributedshell/src/test/java/org/apache/hadoop/yarn/applications/distributedshell/TestDistributedShell.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-distributedshell/src/test/java/org/apache/hadoop/yarn/applications/distributedshell/TestDistributedShell.java
index fc270cb79f2..b541cae9997 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-distributedshell/src/test/java/org/apache/hadoop/yarn/applications/distributedshell/TestDistributedShell.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-distributedshell/src/test/java/org/apache/hadoop/yarn/applications/distributedshell/TestDistributedShell.java
@@ -1122,6 +1122,7 @@ public void testDSShellWithInvalidArgs() throws Exception {
"1"
};
client.init(args);
+ client.run();
Assert.fail("Exception is expected");
} catch (IllegalArgumentException e) {
Assert.assertTrue("The throw exception is not expected",
@@ -1349,4 +1350,32 @@ private int verifyContainerLog(int containerNum,
}
return numOfWords;
}
+
+ @Test
+ public void testDistributedShellResourceProfiles() throws Exception {
+ String[][] args = {
+ {"--jar", APPMASTER_JAR, "--num_containers", "1", "--shell_command",
+ Shell.WINDOWS ? "dir" : "ls", "--container_resource_profile",
+ "maximum" },
+ {"--jar", APPMASTER_JAR, "--num_containers", "1", "--shell_command",
+ Shell.WINDOWS ? "dir" : "ls", "--master_resource_profile",
+ "default" },
+ {"--jar", APPMASTER_JAR, "--num_containers", "1", "--shell_command",
+ Shell.WINDOWS ? "dir" : "ls", "--master_resource_profile",
+ "default", "--container_resource_profile", "maximum" }
+ };
+
+ for (int i = 0; i < args.length; ++i) {
+ LOG.info("Initializing DS Client");
+ Client client = new Client(new Configuration(yarnCluster.getConfig()));
+ Assert.assertTrue(client.init(args[i]));
+ LOG.info("Running DS Client");
+ try {
+ client.run();
+ Assert.fail("Client run should throw error");
+ } catch (Exception e) {
+ continue;
+ }
+ }
+ }
}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/pom.xml b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/pom.xml
index b83bff83e73..8cbf4c40e40 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/pom.xml
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/pom.xml
@@ -144,6 +144,7 @@
src/test/resources/application_1440536969523_0001.har/part-0
src/test/resources/application_1440536969523_0001.har/_masterindex
src/test/resources/application_1440536969523_0001.har/_SUCCESS
+ src/test/resources/resource-profiles.json
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/api/AMRMClient.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/api/AMRMClient.java
index 60e305f4ff4..674124654e8 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/api/AMRMClient.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/api/AMRMClient.java
@@ -39,6 +39,7 @@
import org.apache.hadoop.yarn.api.records.ExecutionTypeRequest;
import org.apache.hadoop.yarn.api.records.FinalApplicationStatus;
import org.apache.hadoop.yarn.api.records.Priority;
+import org.apache.hadoop.yarn.api.records.ProfileCapability;
import org.apache.hadoop.yarn.api.records.Resource;
import org.apache.hadoop.yarn.api.records.UpdateContainerRequest;
import org.apache.hadoop.yarn.client.api.impl.AMRMClientImpl;
@@ -126,6 +127,7 @@ protected void serviceInit(Configuration conf) throws Exception {
private String nodeLabelsExpression;
private ExecutionTypeRequest executionTypeRequest =
ExecutionTypeRequest.newInstance();
+ private String resourceProfile;
/**
* Instantiates a {@link ContainerRequest} with the given constraints and
@@ -172,6 +174,26 @@ public ContainerRequest(Resource capability, String[] nodes,
this(capability, nodes, racks, priority, allocationRequestId, true, null,
ExecutionTypeRequest.newInstance());
}
+ /**
+ * Instantiates a {@link ContainerRequest} with the given constraints and
+ * locality relaxation enabled.
+ *
+ * @param capability
+ * The {@link ProfileCapability} to be requested for each container.
+ * @param nodes
+ * Any hosts to request that the containers are placed on.
+ * @param racks
+ * Any racks to request that the containers are placed on. The
+ * racks corresponding to any hosts requested will be automatically
+ * added to this list.
+ * @param priority
+ * The priority at which to request the containers. Higher
+ * priorities have lower numerical values.
+ */
+ public ContainerRequest(ProfileCapability capability, String[] nodes,
+ String[] racks, Priority priority) {
+ this(capability, nodes, racks, priority, 0, true, null);
+ }
/**
* Instantiates a {@link ContainerRequest} with the given constraints.
@@ -200,6 +222,29 @@ public ContainerRequest(Resource capability, String[] nodes,
* Instantiates a {@link ContainerRequest} with the given constraints.
*
* @param capability
+ * The {@link ProfileCapability} to be requested for each container.
+ * @param nodes
+ * Any hosts to request that the containers are placed on.
+ * @param racks
+ * Any racks to request that the containers are placed on. The
+ * racks corresponding to any hosts requested will be automatically
+ * added to this list.
+ * @param priority
+ * The priority at which to request the containers. Higher
+ * priorities have lower numerical values.
+ * @param relaxLocality
+ * If true, containers for this request may be assigned on hosts
+ * and racks other than the ones explicitly requested.
+ */
+ public ContainerRequest(ProfileCapability capability, String[] nodes,
+ String[] racks, Priority priority, boolean relaxLocality) {
+ this(capability, nodes, racks, priority, 0, relaxLocality, null);
+ }
+
+ /**
+ * Instantiates a {@link ContainerRequest} with the given constraints.
+ *
+ * @param capability
* The {@link Resource} to be requested for each container.
* @param nodes
* Any hosts to request that the containers are placed on.
@@ -286,6 +331,59 @@ public ContainerRequest(Resource capability, String[] nodes, String[] racks,
relaxLocality, nodeLabelsExpression,
ExecutionTypeRequest.newInstance());
}
+
+ public ContainerRequest(ProfileCapability capability, String[] nodes,
+ String[] racks, Priority priority, long allocationRequestId,
+ boolean relaxLocality, String nodeLabelsExpression) {
+ this(capability, nodes, racks, priority, allocationRequestId,
+ relaxLocality, nodeLabelsExpression,
+ ExecutionTypeRequest.newInstance());
+ }
+
+ /**
+ * Instantiates a {@link ContainerRequest} with the given constraints.
+ *
+ * @param capability
+ * The {@link Resource} to be requested for each container.
+ * @param nodes
+ * Any hosts to request that the containers are placed on.
+ * @param racks
+ * Any racks to request that the containers are placed on. The
+ * racks corresponding to any hosts requested will be automatically
+ * added to this list.
+ * @param priority
+ * The priority at which to request the containers. Higher
+ * priorities have lower numerical values.
+ * @param allocationRequestId
+ * The allocationRequestId of the request. To be used as a tracking
+ * id to match Containers allocated against this request. Will
+ * default to 0 if not specified.
+ * @param relaxLocality
+ * If true, containers for this request may be assigned on hosts
+ * and racks other than the ones explicitly requested.
+ * @param nodeLabelsExpression
+ * Set node labels to allocate resource, now we only support
+ * asking for only a single node label
+ * @param executionTypeRequest
+ * Set the execution type of the container request.
+ */
+ public ContainerRequest(Resource capability, String[] nodes, String[] racks,
+ Priority priority, long allocationRequestId, boolean relaxLocality,
+ String nodeLabelsExpression,
+ ExecutionTypeRequest executionTypeRequest) {
+ this(capability, nodes, racks, priority, allocationRequestId,
+ relaxLocality, nodeLabelsExpression, executionTypeRequest,
+ ProfileCapability.DEFAULT_PROFILE);
+ }
+
+ public ContainerRequest(ProfileCapability capability, String[] nodes,
+ String[] racks, Priority priority, long allocationRequestId,
+ boolean relaxLocality, String nodeLabelsExpression,
+ ExecutionTypeRequest executionTypeRequest) {
+ this(capability.getProfileCapabilityOverride(), nodes, racks, priority,
+ allocationRequestId, relaxLocality, nodeLabelsExpression,
+ executionTypeRequest, capability.getProfileName());
+ }
/**
* Instantiates a {@link ContainerRequest} with the given constraints.
@@ -313,11 +411,13 @@ public ContainerRequest(Resource capability, String[] nodes, String[] racks,
* asking for only a single node label
* @param executionTypeRequest
* Set the execution type of the container request.
+ * @param profile
+ * Set the resource profile for the container request
*/
public ContainerRequest(Resource capability, String[] nodes, String[] racks,
Priority priority, long allocationRequestId, boolean relaxLocality,
String nodeLabelsExpression,
- ExecutionTypeRequest executionTypeRequest) {
+ ExecutionTypeRequest executionTypeRequest, String profile) {
this.allocationRequestId = allocationRequestId;
this.capability = capability;
this.nodes = (nodes != null ? ImmutableList.copyOf(nodes) : null);
@@ -326,6 +426,7 @@ public ContainerRequest(Resource capability, String[] nodes, String[] racks,
this.relaxLocality = relaxLocality;
this.nodeLabelsExpression = nodeLabelsExpression;
this.executionTypeRequest = executionTypeRequest;
+ this.resourceProfile = profile;
sanityCheck();
}
@@ -377,6 +478,10 @@ public ExecutionTypeRequest getExecutionTypeRequest() {
return executionTypeRequest;
}
+ public String getResourceProfile() {
+ return resourceProfile;
+ }
+
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Capability[").append(capability).append("]");
@@ -384,6 +489,7 @@ public String toString() {
sb.append("AllocationRequestId[").append(allocationRequestId).append("]");
sb.append("ExecutionTypeRequest[").append(executionTypeRequest)
.append("]");
+ sb.append("Resource Profile[").append(resourceProfile).append("]");
return sb.toString();
}
@@ -636,6 +742,15 @@ public abstract void requestContainerUpdate(
" AMRMClient is expected to implement this !!");
}
+
+ @InterfaceStability.Evolving
+ public List extends Collection> getMatchingRequests(
+ Priority priority, String resourceName, ExecutionType executionType,
+ ProfileCapability capability) {
+ throw new UnsupportedOperationException("The sub-class extending" +
+ " AMRMClient is expected to implement this !!");
+ }
+
/**
* Get outstanding ContainerRequests matching the given
* allocationRequestId. These ContainerRequests should have been added via
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/api/YarnClient.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/api/YarnClient.java
index 8c68a31ffe2..60e7813e422 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/api/YarnClient.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/api/YarnClient.java
@@ -61,6 +61,8 @@
import org.apache.hadoop.yarn.api.records.QueueUserACLInfo;
import org.apache.hadoop.yarn.api.records.ReservationDefinition;
import org.apache.hadoop.yarn.api.records.ReservationId;
+import org.apache.hadoop.yarn.api.records.Resource;
+import org.apache.hadoop.yarn.api.records.ResourceTypeInfo;
import org.apache.hadoop.yarn.api.records.SignalContainerCommand;
import org.apache.hadoop.yarn.api.records.Token;
import org.apache.hadoop.yarn.api.records.YarnApplicationState;
@@ -70,6 +72,7 @@
import org.apache.hadoop.yarn.exceptions.ApplicationIdNotProvidedException;
import org.apache.hadoop.yarn.exceptions.ApplicationNotFoundException;
import org.apache.hadoop.yarn.exceptions.ContainerNotFoundException;
+import org.apache.hadoop.yarn.exceptions.YARNFeatureNotEnabledException;
import org.apache.hadoop.yarn.exceptions.YarnException;
import org.apache.hadoop.yarn.security.AMRMTokenIdentifier;
@@ -855,4 +858,46 @@ public UpdateApplicationTimeoutsResponse updateApplicationTimeouts(
throw new UnsupportedOperationException("The sub-class extending "
+ YarnClient.class.getName() + " is expected to implement this !");
}
+
+ /**
+ *
+ * Get the resource profiles available in the RM.
+ *
+ * @return a Map of the resource profile names to their capabilities
+ * @throws YARNFeatureNotEnabledException if resource-profile is disabled
+ * @throws YarnException if any error happens inside YARN
+ * @throws IOException in case of other errors
+ */
+ @Public
+ @Unstable
+ public abstract Map getResourceProfiles()
+ throws YarnException, IOException;
+
+ /**
+ *
+ * Get the details of a specific resource profile from the RM.
+ *
+ * @param profile the profile name
+ * @return resource profile name with its capabilities
+ * @throws YARNFeatureNotEnabledException if resource-profile is disabled
+ * @throws YarnException if any error happens inside YARN
+ * @throws IOException in case of other others
+ */
+ @Public
+ @Unstable
+ public abstract Resource getResourceProfile(String profile)
+ throws YarnException, IOException;
+
+ /**
+ *
+ * Get available resource types supported by RM.
+ *
+ * @return list of supported resource types with detailed information
+ * @throws YarnException if any issue happens inside YARN
+ * @throws IOException in case of other others
+ */
+ @Public
+ @Unstable
+ public abstract List getResourceTypeInfo()
+ throws YarnException, IOException;
}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/api/impl/AMRMClientImpl.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/api/impl/AMRMClientImpl.java
index 7a21bc61ab0..a41ab6ad714 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/api/impl/AMRMClientImpl.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/api/impl/AMRMClientImpl.java
@@ -19,7 +19,6 @@
package org.apache.hadoop.yarn.client.api.impl;
import java.io.IOException;
-import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -59,6 +58,7 @@
import org.apache.hadoop.yarn.api.records.FinalApplicationStatus;
import org.apache.hadoop.yarn.api.records.NMToken;
import org.apache.hadoop.yarn.api.records.Priority;
+import org.apache.hadoop.yarn.api.records.ProfileCapability;
import org.apache.hadoop.yarn.api.records.Resource;
import org.apache.hadoop.yarn.api.records.ResourceBlacklistRequest;
import org.apache.hadoop.yarn.api.records.ResourceRequest;
@@ -105,56 +105,56 @@
protected final Set blacklistedNodes = new HashSet();
protected final Set blacklistAdditions = new HashSet();
protected final Set blacklistRemovals = new HashSet();
+
+ protected Map resourceProfilesMap;
static class ResourceRequestInfo {
ResourceRequest remoteRequest;
LinkedHashSet containerRequests;
-
+
ResourceRequestInfo(Long allocationRequestId, Priority priority,
- String resourceName, Resource capability, boolean relaxLocality) {
+ String resourceName, Resource capability, boolean relaxLocality,
+ String resourceProfile) {
+ ProfileCapability profileCapability = ProfileCapability
+ .newInstance(resourceProfile, capability);
remoteRequest = ResourceRequest.newBuilder().priority(priority)
.resourceName(resourceName).capability(capability).numContainers(0)
- .allocationRequestId(allocationRequestId)
- .relaxLocality(relaxLocality).build();
+ .allocationRequestId(allocationRequestId).relaxLocality(relaxLocality)
+ .profileCapability(profileCapability).build();
containerRequests = new LinkedHashSet();
}
}
/**
- * Class compares Resource by memory then cpu in reverse order
+ * Class compares Resource by memory, then cpu and then the remaining resource
+ * types in reverse order.
*/
- static class ResourceReverseMemoryThenCpuComparator implements
- Comparator, Serializable {
- static final long serialVersionUID = 12345L;
- @Override
- public int compare(Resource arg0, Resource arg1) {
- long mem0 = arg0.getMemorySize();
- long mem1 = arg1.getMemorySize();
- long cpu0 = arg0.getVirtualCores();
- long cpu1 = arg1.getVirtualCores();
- if(mem0 == mem1) {
- if(cpu0 == cpu1) {
- return 0;
- }
- if(cpu0 < cpu1) {
- return 1;
- }
- return -1;
- }
- if(mem0 < mem1) {
- return 1;
- }
- return -1;
- }
+ static class ProfileCapabilityComparator
+ implements Comparator {
+
+ HashMap resourceProfilesMap;
+
+ public ProfileCapabilityComparator(
+ HashMap resourceProfileMap) {
+ this.resourceProfilesMap = resourceProfileMap;
+ }
+
+ public int compare(T arg0, T arg1) {
+ Resource resource0 =
+ ProfileCapability.toResource(arg0, resourceProfilesMap);
+ Resource resource1 =
+ ProfileCapability.toResource(arg1, resourceProfilesMap);
+ return resource1.compareTo(resource0);
+ }
}
- static boolean canFit(Resource arg0, Resource arg1) {
- long mem0 = arg0.getMemorySize();
- long mem1 = arg1.getMemorySize();
- long cpu0 = arg0.getVirtualCores();
- long cpu1 = arg1.getVirtualCores();
-
- return (mem0 <= mem1 && cpu0 <= cpu1);
+ boolean canFit(ProfileCapability arg0, ProfileCapability arg1) {
+ Resource resource0 =
+ ProfileCapability.toResource(arg0, resourceProfilesMap);
+ Resource resource1 =
+ ProfileCapability.toResource(arg1, resourceProfilesMap);
+ return Resources.fitsIn(resource0, resource1);
+
}
private final Map> remoteRequests =
@@ -233,6 +233,7 @@ public RegisterApplicationMasterResponse registerApplicationMaster(
return registerApplicationMaster();
}
+ @SuppressWarnings("unchecked")
private RegisterApplicationMasterResponse registerApplicationMaster()
throws YarnException, IOException {
RegisterApplicationMasterRequest request =
@@ -245,6 +246,7 @@ private RegisterApplicationMasterResponse registerApplicationMaster()
if (!response.getNMTokensFromPreviousAttempts().isEmpty()) {
populateNMTokens(response.getNMTokensFromPreviousAttempts());
}
+ this.resourceProfilesMap = response.getResourceProfiles();
}
return response;
}
@@ -416,13 +418,15 @@ public AllocateResponse allocate(float progressIndicator)
for(ResourceRequest r : ask) {
// create a copy of ResourceRequest as we might change it while the
// RPC layer is using it to send info across
- ResourceRequest rr = ResourceRequest.newBuilder()
- .priority(r.getPriority()).resourceName(r.getResourceName())
- .capability(r.getCapability()).numContainers(r.getNumContainers())
- .relaxLocality(r.getRelaxLocality())
- .nodeLabelExpression(r.getNodeLabelExpression())
- .executionTypeRequest(r.getExecutionTypeRequest())
- .allocationRequestId(r.getAllocationRequestId()).build();
+ ResourceRequest rr =
+ ResourceRequest.newBuilder().priority(r.getPriority())
+ .resourceName(r.getResourceName()).capability(r.getCapability())
+ .numContainers(r.getNumContainers())
+ .relaxLocality(r.getRelaxLocality())
+ .nodeLabelExpression(r.getNodeLabelExpression())
+ .executionTypeRequest(r.getExecutionTypeRequest())
+ .allocationRequestId(r.getAllocationRequestId())
+ .profileCapability(r.getProfileCapability()).build();
askList.add(rr);
}
return askList;
@@ -504,6 +508,8 @@ public void unregisterApplicationMaster(FinalApplicationStatus appStatus,
public synchronized void addContainerRequest(T req) {
Preconditions.checkArgument(req != null,
"Resource request can not be null.");
+ ProfileCapability profileCapability = ProfileCapability
+ .newInstance(req.getResourceProfile(), req.getCapability());
Set dedupedRacks = new HashSet();
if (req.getRacks() != null) {
dedupedRacks.addAll(req.getRacks());
@@ -516,6 +522,8 @@ public synchronized void addContainerRequest(T req) {
Set inferredRacks = resolveRacks(req.getNodes());
inferredRacks.removeAll(dedupedRacks);
+ checkResourceProfile(req.getResourceProfile());
+
// check that specific and non-specific requests cannot be mixed within a
// priority
checkLocalityRelaxationConflict(req.getAllocationRequestId(),
@@ -540,26 +548,26 @@ public synchronized void addContainerRequest(T req) {
}
for (String node : dedupedNodes) {
addResourceRequest(req.getPriority(), node,
- req.getExecutionTypeRequest(), req.getCapability(), req, true,
+ req.getExecutionTypeRequest(), profileCapability, req, true,
req.getNodeLabelExpression());
}
}
for (String rack : dedupedRacks) {
addResourceRequest(req.getPriority(), rack, req.getExecutionTypeRequest(),
- req.getCapability(), req, true, req.getNodeLabelExpression());
+ profileCapability, req, true, req.getNodeLabelExpression());
}
// Ensure node requests are accompanied by requests for
// corresponding rack
for (String rack : inferredRacks) {
addResourceRequest(req.getPriority(), rack, req.getExecutionTypeRequest(),
- req.getCapability(), req, req.getRelaxLocality(),
+ profileCapability, req, req.getRelaxLocality(),
req.getNodeLabelExpression());
}
// Off-switch
addResourceRequest(req.getPriority(), ResourceRequest.ANY,
- req.getExecutionTypeRequest(), req.getCapability(), req,
+ req.getExecutionTypeRequest(), profileCapability, req,
req.getRelaxLocality(), req.getNodeLabelExpression());
}
@@ -567,6 +575,8 @@ public synchronized void addContainerRequest(T req) {
public synchronized void removeContainerRequest(T req) {
Preconditions.checkArgument(req != null,
"Resource request can not be null.");
+ ProfileCapability profileCapability = ProfileCapability
+ .newInstance(req.getResourceProfile(), req.getCapability());
Set allRacks = new HashSet();
if (req.getRacks() != null) {
allRacks.addAll(req.getRacks());
@@ -577,17 +587,17 @@ public synchronized void removeContainerRequest(T req) {
if (req.getNodes() != null) {
for (String node : new HashSet(req.getNodes())) {
decResourceRequest(req.getPriority(), node,
- req.getExecutionTypeRequest(), req.getCapability(), req);
+ req.getExecutionTypeRequest(), profileCapability, req);
}
}
for (String rack : allRacks) {
decResourceRequest(req.getPriority(), rack,
- req.getExecutionTypeRequest(), req.getCapability(), req);
+ req.getExecutionTypeRequest(), profileCapability, req);
}
decResourceRequest(req.getPriority(), ResourceRequest.ANY,
- req.getExecutionTypeRequest(), req.getCapability(), req);
+ req.getExecutionTypeRequest(), profileCapability, req);
}
@Override
@@ -686,6 +696,17 @@ public synchronized int getClusterNodeCount() {
public synchronized List extends Collection> getMatchingRequests(
Priority priority, String resourceName, ExecutionType executionType,
Resource capability) {
+ ProfileCapability profileCapability =
+ ProfileCapability.newInstance(capability);
+ return getMatchingRequests(priority, resourceName, executionType,
+ profileCapability);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public synchronized List extends Collection> getMatchingRequests(
+ Priority priority, String resourceName, ExecutionType executionType,
+ ProfileCapability capability) {
Preconditions.checkArgument(capability != null,
"The Resource to be requested should not be null ");
Preconditions.checkArgument(priority != null,
@@ -695,22 +716,22 @@ public synchronized int getClusterNodeCount() {
RemoteRequestsTable remoteRequestsTable = getTable(0);
if (null != remoteRequestsTable) {
- List> matchingRequests =
- remoteRequestsTable.getMatchingRequests(priority, resourceName,
- executionType, capability);
+ List> matchingRequests = remoteRequestsTable
+ .getMatchingRequests(priority, resourceName, executionType,
+ capability);
if (null != matchingRequests) {
// If no exact match. Container may be larger than what was requested.
// get all resources <= capability. map is reverse sorted.
for (ResourceRequestInfo resReqInfo : matchingRequests) {
- if (canFit(resReqInfo.remoteRequest.getCapability(), capability) &&
- !resReqInfo.containerRequests.isEmpty()) {
+ if (canFit(resReqInfo.remoteRequest.getProfileCapability(),
+ capability) && !resReqInfo.containerRequests.isEmpty()) {
list.add(resReqInfo.containerRequests);
}
}
}
}
// no match found
- return list;
+ return list;
}
private Set resolveRacks(List nodes) {
@@ -758,6 +779,15 @@ private void checkLocalityRelaxationConflict(Long allocationReqId,
}
}
}
+
+ private void checkResourceProfile(String profile) {
+ if (resourceProfilesMap != null && !resourceProfilesMap.isEmpty()
+ && !resourceProfilesMap.containsKey(profile)) {
+ throw new InvalidContainerRequestException(
+ "Invalid profile name, valid profile names are " + resourceProfilesMap
+ .keySet());
+ }
+ }
/**
* Valid if a node label expression specified on container request is valid or
@@ -845,12 +875,16 @@ private void addResourceRequestToAsk(ResourceRequest remoteRequest) {
}
private void addResourceRequest(Priority priority, String resourceName,
- ExecutionTypeRequest execTypeReq, Resource capability, T req,
+ ExecutionTypeRequest execTypeReq, ProfileCapability capability, T req,
boolean relaxLocality, String labelExpression) {
RemoteRequestsTable remoteRequestsTable =
getTable(req.getAllocationRequestId());
if (remoteRequestsTable == null) {
remoteRequestsTable = new RemoteRequestsTable();
+ if (this.resourceProfilesMap instanceof HashMap) {
+ remoteRequestsTable.setResourceComparator(
+ new ProfileCapabilityComparator((HashMap) resourceProfilesMap));
+ }
putTable(req.getAllocationRequestId(), remoteRequestsTable);
}
@SuppressWarnings("unchecked")
@@ -863,6 +897,7 @@ private void addResourceRequest(Priority priority, String resourceName,
addResourceRequestToAsk(resourceRequestInfo.remoteRequest);
if (LOG.isDebugEnabled()) {
+ LOG.debug("Adding request to ask " + resourceRequestInfo.remoteRequest);
LOG.debug("addResourceRequest:" + " applicationId="
+ " priority=" + priority.getPriority()
+ " resourceName=" + resourceName + " numContainers="
@@ -872,7 +907,7 @@ private void addResourceRequest(Priority priority, String resourceName,
}
private void decResourceRequest(Priority priority, String resourceName,
- ExecutionTypeRequest execTypeReq, Resource capability, T req) {
+ ExecutionTypeRequest execTypeReq, ProfileCapability capability, T req) {
RemoteRequestsTable remoteRequestsTable =
getTable(req.getAllocationRequestId());
if (remoteRequestsTable != null) {
@@ -882,7 +917,7 @@ private void decResourceRequest(Priority priority, String resourceName,
execTypeReq, capability, req);
// send the ResourceRequest to RM even if is 0 because it needs to
// override a previously sent value. If ResourceRequest was not sent
- // previously then sending 0 ought to be a no-op on RM
+ // previously then sending 0 aught to be a no-op on RM
if (resourceRequestInfo != null) {
addResourceRequestToAsk(resourceRequestInfo.remoteRequest);
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/api/impl/RemoteRequestsTable.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/api/impl/RemoteRequestsTable.java
index 110ca799436..135e1db2939 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/api/impl/RemoteRequestsTable.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/api/impl/RemoteRequestsTable.java
@@ -23,7 +23,7 @@
import org.apache.hadoop.yarn.api.records.ExecutionType;
import org.apache.hadoop.yarn.api.records.ExecutionTypeRequest;
import org.apache.hadoop.yarn.api.records.Priority;
-import org.apache.hadoop.yarn.api.records.Resource;
+import org.apache.hadoop.yarn.api.records.ProfileCapability;
import java.util.Collection;
import java.util.HashMap;
@@ -35,43 +35,42 @@
import org.apache.hadoop.yarn.api.records.ResourceRequest;
import org.apache.hadoop.yarn.client.api.impl.AMRMClientImpl.ResourceRequestInfo;
-import org.apache.hadoop.yarn.client.api.impl.AMRMClientImpl.ResourceReverseMemoryThenCpuComparator;
+import org.apache.hadoop.yarn.client.api.impl.AMRMClientImpl.ProfileCapabilityComparator;
class RemoteRequestsTable implements Iterable{
private static final Log LOG = LogFactory.getLog(RemoteRequestsTable.class);
- static ResourceReverseMemoryThenCpuComparator resourceComparator =
- new ResourceReverseMemoryThenCpuComparator();
+ private ProfileCapabilityComparator resourceComparator;
/**
* Nested Iterator that iterates over just the ResourceRequestInfo
* object.
*/
class RequestInfoIterator implements Iterator {
- private Iterator