From d9b9a759288943a56e7fd793ccf23ba331ebfc20 Mon Sep 17 00:00:00 2001 From: "Vinod Kumar Vavilapalli (I am also known as @tshooter.)" Date: Thu, 17 Dec 2015 12:13:03 -0800 Subject: [PATCH] YARN-1856. Added cgroups based memory monitoring for containers as another alternative to custom memory-monitoring. Contributed by Varun Vasudev. (cherry picked from commit 4e7d32c0db69882cde854ef581056142a997c005) --- hadoop-yarn-project/CHANGES.txt | 3 + .../hadoop/yarn/conf/YarnConfiguration.java | 24 +++ .../conf/TestYarnConfigurationFields.java | 2 + .../linux/resources/CGroupsHandler.java | 9 +- .../CGroupsMemoryResourceHandlerImpl.java | 156 ++++++++++++++++ .../resources/MemoryResourceHandler.java | 27 +++ .../resources/ResourceHandlerModule.java | 30 ++- .../TestCGroupsMemoryResourceHandlerImpl.java | 172 ++++++++++++++++++ 8 files changed, 420 insertions(+), 3 deletions(-) create mode 100644 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/CGroupsMemoryResourceHandlerImpl.java create mode 100644 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/MemoryResourceHandler.java create mode 100644 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/TestCGroupsMemoryResourceHandlerImpl.java diff --git a/hadoop-yarn-project/CHANGES.txt b/hadoop-yarn-project/CHANGES.txt index cfdb1c78a03..0e08a82e7e8 100644 --- a/hadoop-yarn-project/CHANGES.txt +++ b/hadoop-yarn-project/CHANGES.txt @@ -6,6 +6,9 @@ Release 2.9.0 - UNRELEASED NEW FEATURES + YARN-1856. Added cgroups based memory monitoring for containers as another + alternative to custom memory-monitoring. (Varun Vasudev via vinodkv) + IMPROVEMENTS YARN-4072. ApplicationHistoryServer, WebAppProxyServer, NodeManager and 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 35ad12f340d..1f50d9b40eb 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 @@ -905,6 +905,30 @@ public class YarnConfiguration extends Configuration { public static final boolean DEFAULT_NM_ENABLE_HARDWARE_CAPABILITY_DETECTION = false; + @Private + public static final String NM_MEMORY_RESOURCE_PREFIX = NM_PREFIX + + "resource.memory."; + + @Private + public static final String NM_MEMORY_RESOURCE_ENABLED = + NM_MEMORY_RESOURCE_PREFIX + "enabled"; + @Private + public static final boolean DEFAULT_NM_MEMORY_RESOURCE_ENABLED = false; + + @Private + public static final String NM_MEMORY_RESOURCE_CGROUPS_SWAPPINESS = + NM_MEMORY_RESOURCE_PREFIX + "cgroups.swappiness"; + @Private + public static final int DEFAULT_NM_MEMORY_RESOURCE_CGROUPS_SWAPPINESS = 0; + + @Private + public static final String NM_MEMORY_RESOURCE_CGROUPS_SOFT_LIMIT_PERCENTAGE = + NM_MEMORY_RESOURCE_PREFIX + "cgroups.soft-limit-percentage"; + @Private + public static final float + DEFAULT_NM_MEMORY_RESOURCE_CGROUPS_SOFT_LIMIT_PERCENTAGE = + 90.0f; + /** * Prefix for disk configurations. Work in progress: This configuration * parameter may be changed/removed in the future. 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 dec5cfb0178..41c3d871462 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 @@ -108,6 +108,8 @@ public class TestYarnConfigurationFields extends TestConfigurationFieldsBase { .add(YarnConfiguration.NM_NETWORK_RESOURCE_OUTBOUND_BANDWIDTH_YARN_MBIT); configurationPrefixToSkipCompare .add(YarnConfiguration.NM_DISK_RESOURCE_ENABLED); + configurationPrefixToSkipCompare + .add(YarnConfiguration.NM_MEMORY_RESOURCE_PREFIX); // Set by container-executor.cfg configurationPrefixToSkipCompare.add(YarnConfiguration.NM_USER_HOME_DIR); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/CGroupsHandler.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/CGroupsHandler.java index 6020bc1379f..d86c5f2375a 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/CGroupsHandler.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/CGroupsHandler.java @@ -31,10 +31,12 @@ import org.apache.hadoop.classification.InterfaceStability; @InterfaceAudience.Private @InterfaceStability.Unstable public interface CGroupsHandler { + public enum CGroupController { CPU("cpu"), NET_CLS("net_cls"), - BLKIO("blkio"); + BLKIO("blkio"), + MEMORY("memory"); private final String name; @@ -51,6 +53,11 @@ public interface CGroupsHandler { public static final String CGROUP_PARAM_CLASSID = "classid"; public static final String CGROUP_PARAM_BLKIO_WEIGHT = "weight"; + String CGROUP_PARAM_MEMORY_HARD_LIMIT_BYTES = "limit_in_bytes"; + String CGROUP_PARAM_MEMORY_SOFT_LIMIT_BYTES = "soft_limit_in_bytes"; + String CGROUP_PARAM_MEMORY_SWAPPINESS = "swappiness"; + + /** * Mounts a cgroup controller * @param controller - the controller being mounted diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/CGroupsMemoryResourceHandlerImpl.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/CGroupsMemoryResourceHandlerImpl.java new file mode 100644 index 00000000000..78113e5e8fe --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/CGroupsMemoryResourceHandlerImpl.java @@ -0,0 +1,156 @@ +/** + * 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.server.nodemanager.containermanager.linux.resources; + +import com.google.common.annotations.VisibleForTesting; +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.records.ContainerId; +import org.apache.hadoop.yarn.conf.YarnConfiguration; +import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.Container; +import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.privileged.PrivilegedOperation; + +import java.util.ArrayList; +import java.util.List; + +/** + * Handler class to handle the memory controller. YARN already ships a + * physical memory monitor in Java but it isn't as + * good as CGroups. This handler sets the soft and hard memory limits. The soft + * limit is set to 90% of the hard limit. + */ +@InterfaceAudience.Private +@InterfaceStability.Unstable +public class CGroupsMemoryResourceHandlerImpl implements MemoryResourceHandler { + + static final Log LOG = LogFactory.getLog( + CGroupsMemoryResourceHandlerImpl.class); + private static final CGroupsHandler.CGroupController MEMORY = + CGroupsHandler.CGroupController.MEMORY; + + private CGroupsHandler cGroupsHandler; + private int swappiness = 0; + // multiplier to set the soft limit - value should be between 0 and 1 + private float softLimit = 0.0f; + + CGroupsMemoryResourceHandlerImpl(CGroupsHandler cGroupsHandler) { + this.cGroupsHandler = cGroupsHandler; + } + + @Override + public List bootstrap(Configuration conf) + throws ResourceHandlerException { + boolean pmemEnabled = + conf.getBoolean(YarnConfiguration.NM_PMEM_CHECK_ENABLED, + YarnConfiguration.DEFAULT_NM_PMEM_CHECK_ENABLED); + boolean vmemEnabled = + conf.getBoolean(YarnConfiguration.NM_VMEM_CHECK_ENABLED, + YarnConfiguration.DEFAULT_NM_VMEM_CHECK_ENABLED); + if (pmemEnabled || vmemEnabled) { + String msg = "The default YARN physical and/or virtual memory health" + + " checkers as well as the CGroups memory controller are enabled. " + + "If you wish to use the Cgroups memory controller, please turn off" + + " the default physical/virtual memory checkers by setting " + + YarnConfiguration.NM_PMEM_CHECK_ENABLED + " and " + + YarnConfiguration.NM_VMEM_CHECK_ENABLED + " to false."; + throw new ResourceHandlerException(msg); + } + this.cGroupsHandler.mountCGroupController(MEMORY); + swappiness = conf + .getInt(YarnConfiguration.NM_MEMORY_RESOURCE_CGROUPS_SWAPPINESS, + YarnConfiguration.DEFAULT_NM_MEMORY_RESOURCE_CGROUPS_SWAPPINESS); + if (swappiness < 0 || swappiness > 100) { + throw new ResourceHandlerException( + "Illegal value '" + swappiness + "' for " + + YarnConfiguration.NM_MEMORY_RESOURCE_CGROUPS_SWAPPINESS + + ". Value must be between 0 and 100."); + } + float softLimitPerc = conf.getFloat( + YarnConfiguration.NM_MEMORY_RESOURCE_CGROUPS_SOFT_LIMIT_PERCENTAGE, + YarnConfiguration.DEFAULT_NM_MEMORY_RESOURCE_CGROUPS_SOFT_LIMIT_PERCENTAGE); + softLimit = softLimitPerc / 100.0f; + if (softLimitPerc < 0.0f || softLimitPerc > 100.0f) { + throw new ResourceHandlerException( + "Illegal value '" + softLimitPerc + "' " + + YarnConfiguration.NM_MEMORY_RESOURCE_CGROUPS_SOFT_LIMIT_PERCENTAGE + + ". Value must be between 0 and 100."); + } + return null; + } + + @VisibleForTesting + int getSwappiness() { + return swappiness; + } + + @Override + public List reacquireContainer(ContainerId containerId) + throws ResourceHandlerException { + return null; + } + + @Override + public List preStart(Container container) + throws ResourceHandlerException { + + String cgroupId = container.getContainerId().toString(); + //memory is in MB + long containerSoftLimit = + (long) (container.getResource().getMemory() * this.softLimit); + long containerHardLimit = container.getResource().getMemory(); + cGroupsHandler.createCGroup(MEMORY, cgroupId); + try { + cGroupsHandler.updateCGroupParam(MEMORY, cgroupId, + CGroupsHandler.CGROUP_PARAM_MEMORY_HARD_LIMIT_BYTES, + String.valueOf(containerHardLimit) + "M"); + cGroupsHandler.updateCGroupParam(MEMORY, cgroupId, + CGroupsHandler.CGROUP_PARAM_MEMORY_SOFT_LIMIT_BYTES, + String.valueOf(containerSoftLimit) + "M"); + cGroupsHandler.updateCGroupParam(MEMORY, cgroupId, + CGroupsHandler.CGROUP_PARAM_MEMORY_SWAPPINESS, + String.valueOf(swappiness)); + } catch (ResourceHandlerException re) { + cGroupsHandler.deleteCGroup(MEMORY, cgroupId); + LOG.warn("Could not update cgroup for container", re); + throw re; + } + List ret = new ArrayList<>(); + ret.add(new PrivilegedOperation( + PrivilegedOperation.OperationType.ADD_PID_TO_CGROUP, + PrivilegedOperation.CGROUP_ARG_PREFIX + + cGroupsHandler.getPathForCGroupTasks(MEMORY, cgroupId))); + return ret; + } + + @Override + public List postComplete(ContainerId containerId) + throws ResourceHandlerException { + cGroupsHandler.deleteCGroup(MEMORY, containerId.toString()); + return null; + } + + @Override + public List teardown() throws ResourceHandlerException { + return null; + } + +} diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/MemoryResourceHandler.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/MemoryResourceHandler.java new file mode 100644 index 00000000000..013a49fbb44 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/MemoryResourceHandler.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.server.nodemanager.containermanager.linux.resources; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; + +@InterfaceAudience.Private +@InterfaceStability.Unstable +public interface MemoryResourceHandler extends ResourceHandler { +} diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/ResourceHandlerModule.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/ResourceHandlerModule.java index 5dfd78c8eb2..da70536e6c6 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/ResourceHandlerModule.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/ResourceHandlerModule.java @@ -50,6 +50,8 @@ public class ResourceHandlerModule { private static volatile CGroupsHandler cGroupsHandler; private static volatile CGroupsBlkioResourceHandlerImpl cGroupsBlkioResourceHandler; + private static volatile CGroupsMemoryResourceHandlerImpl + cGroupsMemoryResourceHandler; /** * Returns an initialized, thread-safe CGroupsHandler instance. @@ -69,7 +71,7 @@ public class ResourceHandlerModule { } private static TrafficControlBandwidthHandlerImpl - getTrafficControlBandwidthHandler(Configuration conf) + getTrafficControlBandwidthHandler(Configuration conf) throws ResourceHandlerException { if (conf.getBoolean(YarnConfiguration.NM_NETWORK_RESOURCE_ENABLED, YarnConfiguration.DEFAULT_NM_NETWORK_RESOURCE_ENABLED)) { @@ -92,7 +94,7 @@ public class ResourceHandlerModule { } public static OutboundBandwidthResourceHandler - getOutboundBandwidthResourceHandler(Configuration conf) + getOutboundBandwidthResourceHandler(Configuration conf) throws ResourceHandlerException { return getTrafficControlBandwidthHandler(conf); } @@ -119,6 +121,29 @@ public class ResourceHandlerModule { return cGroupsBlkioResourceHandler; } + public static MemoryResourceHandler getMemoryResourceHandler( + Configuration conf) throws ResourceHandlerException { + if (conf.getBoolean(YarnConfiguration.NM_MEMORY_RESOURCE_ENABLED, + YarnConfiguration.DEFAULT_NM_MEMORY_RESOURCE_ENABLED)) { + return getCgroupsMemoryResourceHandler(conf); + } + return null; + } + + private static CGroupsMemoryResourceHandlerImpl + getCgroupsMemoryResourceHandler( + Configuration conf) throws ResourceHandlerException { + if (cGroupsMemoryResourceHandler == null) { + synchronized (MemoryResourceHandler.class) { + if (cGroupsMemoryResourceHandler == null) { + cGroupsMemoryResourceHandler = + new CGroupsMemoryResourceHandlerImpl(getCGroupsHandler(conf)); + } + } + } + return cGroupsMemoryResourceHandler; + } + private static void addHandlerIfNotNull(List handlerList, ResourceHandler handler) { if (handler != null) { @@ -132,6 +157,7 @@ public class ResourceHandlerModule { addHandlerIfNotNull(handlerList, getOutboundBandwidthResourceHandler(conf)); addHandlerIfNotNull(handlerList, getDiskResourceHandler(conf)); + addHandlerIfNotNull(handlerList, getMemoryResourceHandler(conf)); resourceHandlerChain = new ResourceHandlerChain(handlerList); } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/TestCGroupsMemoryResourceHandlerImpl.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/TestCGroupsMemoryResourceHandlerImpl.java new file mode 100644 index 00000000000..d98a16fb2c7 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/TestCGroupsMemoryResourceHandlerImpl.java @@ -0,0 +1,172 @@ +/** + * 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.server.nodemanager.containermanager.linux.resources; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.yarn.api.records.ContainerId; +import org.apache.hadoop.yarn.api.records.Resource; +import org.apache.hadoop.yarn.conf.YarnConfiguration; +import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.Container; +import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.privileged.PrivilegedOperation; +import org.junit.Before; +import org.junit.Test; +import org.junit.Assert; + +import java.util.List; + +import static org.mockito.Mockito.*; + +public class TestCGroupsMemoryResourceHandlerImpl { + + private CGroupsHandler mockCGroupsHandler; + private CGroupsMemoryResourceHandlerImpl cGroupsMemoryResourceHandler; + + @Before + public void setup() { + mockCGroupsHandler = mock(CGroupsHandler.class); + cGroupsMemoryResourceHandler = + new CGroupsMemoryResourceHandlerImpl(mockCGroupsHandler); + } + + @Test + public void testBootstrap() throws Exception { + Configuration conf = new YarnConfiguration(); + conf.setBoolean(YarnConfiguration.NM_PMEM_CHECK_ENABLED, false); + conf.setBoolean(YarnConfiguration.NM_VMEM_CHECK_ENABLED, false); + List ret = + cGroupsMemoryResourceHandler.bootstrap(conf); + verify(mockCGroupsHandler, times(1)) + .mountCGroupController(CGroupsHandler.CGroupController.MEMORY); + Assert.assertNull(ret); + Assert.assertEquals("Default swappiness value incorrect", 0, + cGroupsMemoryResourceHandler.getSwappiness()); + conf.setBoolean(YarnConfiguration.NM_PMEM_CHECK_ENABLED, true); + try { + cGroupsMemoryResourceHandler.bootstrap(conf); + Assert.fail("Pmem check should not be allowed to run with cgroups"); + } + catch(ResourceHandlerException re) { + // do nothing + } + conf.setBoolean(YarnConfiguration.NM_PMEM_CHECK_ENABLED, false); + conf.setBoolean(YarnConfiguration.NM_VMEM_CHECK_ENABLED, true); + try { + cGroupsMemoryResourceHandler.bootstrap(conf); + Assert.fail("Vmem check should not be allowed to run with cgroups"); + } + catch(ResourceHandlerException re) { + // do nothing + } + } + + @Test + public void testSwappinessValues() throws Exception { + Configuration conf = new YarnConfiguration(); + conf.setBoolean(YarnConfiguration.NM_PMEM_CHECK_ENABLED, false); + conf.setBoolean(YarnConfiguration.NM_VMEM_CHECK_ENABLED, false); + conf.setInt(YarnConfiguration.NM_MEMORY_RESOURCE_CGROUPS_SWAPPINESS, -1); + try { + cGroupsMemoryResourceHandler.bootstrap(conf); + Assert.fail("Negative values for swappiness should not be allowed."); + } + catch (ResourceHandlerException re) { + // do nothing + } + try { + conf.setInt(YarnConfiguration.NM_MEMORY_RESOURCE_CGROUPS_SWAPPINESS, 101); + cGroupsMemoryResourceHandler.bootstrap(conf); + Assert.fail("Values greater than 100 for swappiness" + + " should not be allowed."); + } + catch (ResourceHandlerException re) { + // do nothing + } + conf.setInt(YarnConfiguration.NM_MEMORY_RESOURCE_CGROUPS_SWAPPINESS, 60); + cGroupsMemoryResourceHandler.bootstrap(conf); + Assert.assertEquals("Swappiness value incorrect", 60, + cGroupsMemoryResourceHandler.getSwappiness()); + } + + @Test + public void testPreStart() throws Exception { + Configuration conf = new Configuration(); + conf.setBoolean(YarnConfiguration.NM_PMEM_CHECK_ENABLED, false); + conf.setBoolean(YarnConfiguration.NM_VMEM_CHECK_ENABLED, false); + cGroupsMemoryResourceHandler.bootstrap(conf); + String id = "container_01_01"; + String path = "test-path/" + id; + ContainerId mockContainerId = mock(ContainerId.class); + when(mockContainerId.toString()).thenReturn(id); + Container mockContainer = mock(Container.class); + when(mockContainer.getContainerId()).thenReturn(mockContainerId); + when(mockCGroupsHandler + .getPathForCGroupTasks(CGroupsHandler.CGroupController.MEMORY, id)) + .thenReturn(path); + int memory = 1024; + when(mockContainer.getResource()) + .thenReturn(Resource.newInstance(memory, 1)); + List ret = + cGroupsMemoryResourceHandler.preStart(mockContainer); + verify(mockCGroupsHandler, times(1)) + .createCGroup(CGroupsHandler.CGroupController.MEMORY, id); + verify(mockCGroupsHandler, times(1)) + .updateCGroupParam(CGroupsHandler.CGroupController.MEMORY, id, + CGroupsHandler.CGROUP_PARAM_MEMORY_HARD_LIMIT_BYTES, + String.valueOf(memory) + "M"); + verify(mockCGroupsHandler, times(1)) + .updateCGroupParam(CGroupsHandler.CGroupController.MEMORY, id, + CGroupsHandler.CGROUP_PARAM_MEMORY_SOFT_LIMIT_BYTES, + String.valueOf((int) (memory * 0.9)) + "M"); + verify(mockCGroupsHandler, times(1)) + .updateCGroupParam(CGroupsHandler.CGroupController.MEMORY, id, + CGroupsHandler.CGROUP_PARAM_MEMORY_SWAPPINESS, String.valueOf(0)); + Assert.assertNotNull(ret); + Assert.assertEquals(1, ret.size()); + PrivilegedOperation op = ret.get(0); + Assert.assertEquals(PrivilegedOperation.OperationType.ADD_PID_TO_CGROUP, + op.getOperationType()); + List args = op.getArguments(); + Assert.assertEquals(1, args.size()); + Assert.assertEquals(PrivilegedOperation.CGROUP_ARG_PREFIX + path, + args.get(0)); + } + + @Test + public void testReacquireContainer() throws Exception { + ContainerId containerIdMock = mock(ContainerId.class); + Assert.assertNull( + cGroupsMemoryResourceHandler.reacquireContainer(containerIdMock)); + } + + @Test + public void testPostComplete() throws Exception { + String id = "container_01_01"; + ContainerId mockContainerId = mock(ContainerId.class); + when(mockContainerId.toString()).thenReturn(id); + Assert + .assertNull(cGroupsMemoryResourceHandler.postComplete(mockContainerId)); + verify(mockCGroupsHandler, times(1)) + .deleteCGroup(CGroupsHandler.CGroupController.MEMORY, id); + } + + @Test + public void testTeardown() throws Exception { + Assert.assertNull(cGroupsMemoryResourceHandler.teardown()); + } +}