diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/MaxAMPercentages.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/MaxAMPercentages.java new file mode 100644 index 0000000..425eb0e --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/MaxAMPercentages.java @@ -0,0 +1,54 @@ +/** + * 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.Private; +import org.apache.hadoop.classification.InterfaceAudience.Public; +import org.apache.hadoop.classification.InterfaceStability.Stable; +import org.apache.hadoop.classification.InterfaceStability.Unstable; +import org.apache.hadoop.yarn.util.Records; + +public abstract class MaxAMPercentages { + + @Public + @Unstable + public static MaxAMPercentages newInstance(String nodeLabel, + float amLimitPercentage) { + MaxAMPercentages maxAMPercentages = Records.newRecord(MaxAMPercentages.class); + maxAMPercentages.setNodeLabel(nodeLabel); + maxAMPercentages.setAmLimitPercentage(amLimitPercentage); + return maxAMPercentages; + } + + @Public + @Stable + public abstract String getNodeLabel(); + + @Private + @Unstable + public abstract void setNodeLabel(String nodeLabel); + + @Public + @Stable + public abstract float getAmLimitPercentage(); + + @Private + @Unstable + public abstract void setAmLimitPercentage(float percentage); +} diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/QueueInfo.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/QueueInfo.java index 7816feb..d244869 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/QueueInfo.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/QueueInfo.java @@ -19,6 +19,7 @@ package org.apache.hadoop.yarn.api.records; import java.util.List; +import java.util.Map; import java.util.Set; import org.apache.hadoop.classification.InterfaceAudience.Private; @@ -72,6 +73,24 @@ public static QueueInfo newInstance(String queueName, float capacity, return queueInfo; } + @Private + @Unstable + public static QueueInfo newInstance(String queueName, float capacity, + float maximumCapacity, float currentCapacity, + List childQueues, List applications, + QueueState queueState, Set accessibleNodeLabels, + String defaultNodeLabelExpression, QueueStatistics queueStatistics, + boolean preemptionDisabled, List maxAMPercentages) { + QueueInfo queueInfo = QueueInfo.newInstance(queueName, capacity, + maximumCapacity, currentCapacity, + childQueues, applications, + queueState, accessibleNodeLabels, + defaultNodeLabelExpression, queueStatistics, + preemptionDisabled); + queueInfo.setMaxAMPercentages(maxAMPercentages); + return queueInfo; + } + /** * Get the name of the queue. * @return name of the queue @@ -219,4 +238,22 @@ public abstract void setDefaultNodeLabelExpression( @Private @Unstable public abstract void setPreemptionDisabled(boolean preemptionDisabled); + + /** + * Get the per-node-label maximum AM resource limits of the queue. + * @return per-node-label maximum AM percentages of the queue. + */ + @Public + @Stable + public abstract List getMaxAMPercentages(); + + /** + * Set the per-node-label maximum AM resource limit of the queue. + * @param maxAMPercentages + * the per-node-label maximum AM resource limits + */ + @Private + @Unstable + public abstract void setMaxAMPercentages( + List maxAMPercentages); } 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 a6dbf3c..64f2498 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 @@ -463,6 +463,12 @@ message QueueInfoProto { optional string defaultNodeLabelExpression = 9; optional QueueStatisticsProto queueStatistics = 10; optional bool preemptionDisabled = 11; + repeated MaxAMPercentagesProto maxAMPercentages = 12; +} + +message MaxAMPercentagesProto { + required string nodeLabel = 1; + required float amLimitPercentage = 2; } enum QueueACLProto { diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/cli/QueueCLI.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/cli/QueueCLI.java index 330b081..1c03cc5 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/cli/QueueCLI.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/cli/QueueCLI.java @@ -22,6 +22,7 @@ import java.io.PrintWriter; import java.nio.charset.Charset; import java.text.DecimalFormat; +import java.util.List; import java.util.Set; import org.apache.commons.cli.CommandLine; @@ -32,6 +33,7 @@ import org.apache.hadoop.classification.InterfaceAudience.Private; import org.apache.hadoop.classification.InterfaceStability.Unstable; import org.apache.hadoop.util.ToolRunner; +import org.apache.hadoop.yarn.api.records.MaxAMPercentages; import org.apache.hadoop.yarn.api.records.NodeLabel; import org.apache.hadoop.yarn.api.records.QueueInfo; import org.apache.hadoop.yarn.exceptions.YarnException; @@ -158,5 +160,8 @@ private void printQueueInfo(PrintWriter writer, QueueInfo queueInfo) { writer.print("\tPreemption : "); writer.println(preemptStatus ? "disabled" : "enabled"); } + + writer.print("\tMaxAMPercentages : "); + writer.println(queueInfo.getMaxAMPercentages()); } } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/test/java/org/apache/hadoop/yarn/client/cli/TestYarnCLI.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/test/java/org/apache/hadoop/yarn/client/cli/TestYarnCLI.java index 7cf9788..3c5d5bf 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/test/java/org/apache/hadoop/yarn/client/cli/TestYarnCLI.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/test/java/org/apache/hadoop/yarn/client/cli/TestYarnCLI.java @@ -1699,7 +1699,7 @@ public void testGetQueueInfo() throws Exception { nodeLabels.add("GPU"); nodeLabels.add("JDK_7"); QueueInfo queueInfo = QueueInfo.newInstance("queueA", 0.4f, 0.8f, 0.5f, - null, null, QueueState.RUNNING, nodeLabels, "GPU", null, false); + null, null, QueueState.RUNNING, nodeLabels, "GPU", null, false, null); when(client.getQueueInfo(any(String.class))).thenReturn(queueInfo); int result = cli.run(new String[] { "-status", "queueA" }); assertEquals(0, result); @@ -1715,6 +1715,7 @@ public void testGetQueueInfo() throws Exception { pw.println("\tDefault Node Label expression : " + "GPU"); pw.println("\tAccessible Node Labels : " + "JDK_7,GPU"); pw.println("\tPreemption : " + "enabled"); + pw.println("\tMaxAMPercentages : " + "[]"); pw.close(); String queueInfoStr = baos.toString("UTF-8"); Assert.assertEquals(queueInfoStr, sysOutStream.toString()); @@ -1800,7 +1801,7 @@ public void testGetQueueInfoPreemptionDisabled() throws Exception { public void testGetQueueInfoWithEmptyNodeLabel() throws Exception { QueueCLI cli = createAndGetQueueCLI(); QueueInfo queueInfo = QueueInfo.newInstance("queueA", 0.4f, 0.8f, 0.5f, - null, null, QueueState.RUNNING, null, null, null, true); + null, null, QueueState.RUNNING, null, null, null, true, null); when(client.getQueueInfo(any(String.class))).thenReturn(queueInfo); int result = cli.run(new String[] { "-status", "queueA" }); assertEquals(0, result); @@ -1817,6 +1818,7 @@ public void testGetQueueInfoWithEmptyNodeLabel() throws Exception { + NodeLabel.DEFAULT_NODE_LABEL_PARTITION); pw.println("\tAccessible Node Labels : "); pw.println("\tPreemption : " + "disabled"); + pw.println("\tMaxAMPercentages : " + "[]"); pw.close(); String queueInfoStr = baos.toString("UTF-8"); Assert.assertEquals(queueInfoStr, sysOutStream.toString()); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/records/impl/pb/MaxAMPercentagesPBImpl.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/records/impl/pb/MaxAMPercentagesPBImpl.java new file mode 100644 index 0000000..08848d8 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/records/impl/pb/MaxAMPercentagesPBImpl.java @@ -0,0 +1,98 @@ +/** + * 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.pb; + +import org.apache.hadoop.yarn.api.records.MaxAMPercentages; +import org.apache.hadoop.yarn.proto.YarnProtos.MaxAMPercentagesProto; +import org.apache.hadoop.yarn.proto.YarnProtos.MaxAMPercentagesProtoOrBuilder; + +import com.google.protobuf.TextFormat; + +public class MaxAMPercentagesPBImpl extends MaxAMPercentages { + + MaxAMPercentagesProto proto = MaxAMPercentagesProto.getDefaultInstance(); + MaxAMPercentagesProto.Builder builder = null; + boolean viaProto = false; + + public MaxAMPercentagesPBImpl() { + builder = MaxAMPercentagesProto.newBuilder(); + } + + public MaxAMPercentagesPBImpl(MaxAMPercentagesProto proto) { + this.proto = proto; + viaProto = true; + } + + public MaxAMPercentagesProto getProto() { + proto = viaProto ? proto : builder.build(); + viaProto = true; + return proto; + } + + @Override + public String getNodeLabel() { + MaxAMPercentagesProtoOrBuilder p = viaProto? proto : builder; + return (p.hasNodeLabel()) ? p.getNodeLabel() : null; + } + + @Override + public void setNodeLabel(String nodeLabel) { + maybeInitBuilder(); + builder.setNodeLabel(nodeLabel); + } + + @Override + public float getAmLimitPercentage() { + MaxAMPercentagesProtoOrBuilder p = viaProto? proto : builder; + return (p.hasAmLimitPercentage()) ? p.getAmLimitPercentage() : -1f; + } + + @Override + public void setAmLimitPercentage(float percentage) { + maybeInitBuilder(); + builder.setAmLimitPercentage(percentage); + } + + private void maybeInitBuilder() { + if (viaProto || builder == null) { + builder = MaxAMPercentagesProto.newBuilder(proto); + } + viaProto = false; + } + + @Override + public String toString() { + return TextFormat.shortDebugString(getProto()); + } + + @Override + public int hashCode() { + return getProto().hashCode(); + } + + @Override + public boolean equals(Object other) { + if (other == null) + return false; + if (other.getClass().isAssignableFrom(this.getClass())) { + return this.getProto().equals(this.getClass().cast(other).getProto()); + } + return false; + } +} diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/records/impl/pb/QueueInfoPBImpl.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/records/impl/pb/QueueInfoPBImpl.java index 605cab1..c1d5b24 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/records/impl/pb/QueueInfoPBImpl.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/records/impl/pb/QueueInfoPBImpl.java @@ -22,15 +22,18 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Set; import org.apache.hadoop.classification.InterfaceAudience.Private; import org.apache.hadoop.classification.InterfaceStability.Unstable; import org.apache.hadoop.yarn.api.records.ApplicationReport; +import org.apache.hadoop.yarn.api.records.MaxAMPercentages; import org.apache.hadoop.yarn.api.records.QueueInfo; import org.apache.hadoop.yarn.api.records.QueueState; import org.apache.hadoop.yarn.api.records.QueueStatistics; import org.apache.hadoop.yarn.proto.YarnProtos.ApplicationReportProto; +import org.apache.hadoop.yarn.proto.YarnProtos.MaxAMPercentagesProto; import org.apache.hadoop.yarn.proto.YarnProtos.QueueInfoProto; import org.apache.hadoop.yarn.proto.YarnProtos.QueueInfoProtoOrBuilder; import org.apache.hadoop.yarn.proto.YarnProtos.QueueStateProto; @@ -49,7 +52,8 @@ List applicationsList; List childQueuesList; Set accessibleNodeLabels; - + List maxAMPercentages; + public QueueInfoPBImpl() { builder = QueueInfoProto.newBuilder(); } @@ -279,6 +283,39 @@ public void remove() { builder.addAllChildQueues(iterable); } + private void addMaxAMPercentagesToProto() { + maybeInitBuilder(); + builder.clearMaxAMPercentages(); + if (maxAMPercentages == null) { + return; + } + Iterable iterable = new Iterable() { + @Override + public Iterator iterator() { + return new Iterator () { + + Iterator iter = maxAMPercentages.iterator(); + + @Override + public boolean hasNext() { + return iter.hasNext(); + } + + @Override + public MaxAMPercentagesProto next() { + return convertToProtoFormat(iter.next()); + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + }; + builder.addAllMaxAMPercentages(iterable); + } + private void mergeLocalToBuilder() { if (this.childQueuesList != null) { addChildQueuesInfoToProto(); @@ -290,6 +327,9 @@ private void mergeLocalToBuilder() { builder.clearAccessibleNodeLabels(); builder.addAllAccessibleNodeLabels(this.accessibleNodeLabels); } + if (this.maxAMPercentages != null) { + addMaxAMPercentagesToProto(); + } } private void mergeLocalToProto() { @@ -331,7 +371,15 @@ private QueueState convertFromProtoFormat(QueueStateProto q) { private QueueStateProto convertToProtoFormat(QueueState queueState) { return ProtoUtils.convertToProtoFormat(queueState); } - + + private MaxAMPercentagesPBImpl convertFromProtoFormat(MaxAMPercentagesProto m) { + return new MaxAMPercentagesPBImpl(m); + } + + private MaxAMPercentagesProto convertToProtoFormat(MaxAMPercentages m) { + return ((MaxAMPercentagesPBImpl)m).getProto(); + } + @Override public void setAccessibleNodeLabels(Set nodeLabels) { maybeInitBuilder(); @@ -408,4 +456,30 @@ public void setPreemptionDisabled(boolean preemptionDisabled) { maybeInitBuilder(); builder.setPreemptionDisabled(preemptionDisabled); } + + private void initMaxAMPercentages() { + if (this.maxAMPercentages != null ) { + return; + } + QueueInfoProtoOrBuilder p = viaProto? proto : builder; + List list = p.getMaxAMPercentagesList(); + maxAMPercentages = new ArrayList<>(); + for (MaxAMPercentagesProto m : list) { + maxAMPercentages.add(convertFromProtoFormat(m)); + } + } + + @Override + public List getMaxAMPercentages() { + initMaxAMPercentages(); + return this.maxAMPercentages; + } + + @Override + public void setMaxAMPercentages(List maxAMPercentages) { + if (maxAMPercentages == null) { + builder.clearMaxAMPercentages(); + } + this.maxAMPercentages = maxAMPercentages; + } } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/api/TestPBImplRecords.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/api/TestPBImplRecords.java index 10323d5..eb4c27a 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/api/TestPBImplRecords.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/api/TestPBImplRecords.java @@ -114,6 +114,7 @@ import org.apache.hadoop.yarn.api.records.ExecutionTypeRequest; import org.apache.hadoop.yarn.api.records.LocalResource; import org.apache.hadoop.yarn.api.records.LogAggregationContext; +import org.apache.hadoop.yarn.api.records.MaxAMPercentages; import org.apache.hadoop.yarn.api.records.NMToken; import org.apache.hadoop.yarn.api.records.NodeId; import org.apache.hadoop.yarn.api.records.NodeLabel; @@ -399,6 +400,7 @@ public static void setup() throws Exception { generateByNewInstance(RollbackResponse.class); generateByNewInstance(CommitResponse.class); generateByNewInstance(ApplicationTimeout.class); + generateByNewInstance(MaxAMPercentages.class); } @Test diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/AbstractCSQueue.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/AbstractCSQueue.java index e9ef319..0c98bfa 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/AbstractCSQueue.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/AbstractCSQueue.java @@ -19,9 +19,11 @@ package org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity; import java.io.IOException; +import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -36,6 +38,7 @@ import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.security.authorize.AccessControlList; import org.apache.hadoop.yarn.api.records.ApplicationId; +import org.apache.hadoop.yarn.api.records.MaxAMPercentages; import org.apache.hadoop.yarn.api.records.Priority; import org.apache.hadoop.yarn.api.records.QueueACL; import org.apache.hadoop.yarn.api.records.QueueInfo; @@ -411,6 +414,7 @@ protected QueueInfo getQueueInfo() { queueInfo.setCurrentCapacity(getUsedCapacity()); queueInfo.setQueueStatistics(getQueueStatistics()); queueInfo.setPreemptionDisabled(preemptionDisabled); + queueInfo.setMaxAMPercentages(getMaxAMPercentages()); return queueInfo; } @@ -441,7 +445,26 @@ public QueueStatistics getQueueStatistics() { stats.setReservedContainers(getMetrics().getReservedContainers()); return stats; } - + + public List getMaxAMPercentages() { + List maxAMPercentages = new ArrayList<>(); + Set nodeLabels = getNodeLabelsForQueue(); + for (String nodeLabel : nodeLabels) { + MaxAMPercentages maxAMPercentage = recordFactory.newRecordInstance( + MaxAMPercentages.class); + float maxAMResourcePercentage = + queueCapacities.getMaxAMResourcePercentage(nodeLabel); + maxAMPercentage.setAmLimitPercentage(maxAMResourcePercentage); + if (nodeLabel == RMNodeLabelsManager.NO_LABEL) { + maxAMPercentage.setNodeLabel(RMNodeLabelsManager.ANY); + } else { + maxAMPercentage.setNodeLabel(nodeLabel); + } + maxAMPercentages.add(maxAMPercentage); + } + return maxAMPercentages; + } + @Private public Resource getMaximumAllocation() { return maximumAllocation;