/** 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.mapred; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; /** * Class providing access to resource manager configuration. * * Resource manager configuration involves setting up queues, and defining * various properties for the queues. These are typically read from a file * called capacity-scheduler.xml that must be in the classpath of the * application. The class provides APIs to get/set and reload the * configuration for the queues. */ class CapacitySchedulerConf { /** Default file name from which the resource manager configuration is read. */ public static final String SCHEDULER_CONF_FILE = "capacity-scheduler.xml"; private int defaultUlimitMinimum; private boolean defaultSupportPriority; private static final String QUEUE_CONF_PROPERTY_NAME_PREFIX = "mapred.capacity-scheduler.queue."; /** * If {@link JobConf#MAPRED_TASK_MAXPMEM_PROPERTY} is set to * {@link JobConf#DISABLED_MEMORY_LIMIT}, this configuration will be used to * calculate job's physical memory requirements as a percentage of the job's * virtual memory requirements set via * {@link JobConf#setMaxVirtualMemoryForTask()}. This property thus provides * default value of physical memory for job's that don't explicitly specify * physical memory requirements. * <p/> * It defaults to {@link JobConf#DISABLED_MEMORY_LIMIT} and if not explicitly * set to a valid value, scheduler will not consider physical memory for * scheduling even if virtual memory based scheduling is enabled. * * @deprecated */ @Deprecated static String DEFAULT_PERCENTAGE_OF_PMEM_IN_VMEM_PROPERTY = "mapred.capacity-scheduler.task.default-pmem-percentage-in-vmem"; /** * Configuration that provides an upper limit on the maximum physical memory * that can be specified by a job. The job configuration * {@link JobConf#MAPRED_TASK_MAXPMEM_PROPERTY} should, * by definition, be less than this value. If not, the job will be rejected * by the scheduler. If it is set to {@link JobConf#DISABLED_MEMORY_LIMIT}, * scheduler will not consider physical memory for scheduling even if virtual * memory based scheduling is enabled. * * @deprecated */ @Deprecated static final String UPPER_LIMIT_ON_TASK_PMEM_PROPERTY = "mapred.capacity-scheduler.task.limit.maxpmem"; /** * The constant which defines the default initialization thread * polling interval, denoted in milliseconds. */ private static final int INITIALIZATION_THREAD_POLLING_INTERVAL = 5000; /** * The constant which defines the maximum number of worker threads to be * spawned off for job initialization */ private static final int MAX_INITIALIZATION_WORKER_THREADS = 5; private Configuration rmConf; private int defaultMaxJobsPerUsersToInitialize; /** * Create a new ResourceManagerConf. * This method reads from the default configuration file mentioned in * {@link RM_CONF_FILE}, that must be present in the classpath of the * application. */ public CapacitySchedulerConf() { rmConf = new Configuration(false); rmConf.addResource(SCHEDULER_CONF_FILE); initializeDefaults(); } /** * Create a new ResourceManagerConf reading the specified configuration * file. * * @param configFile {@link Path} to the configuration file containing * the resource manager configuration. */ public CapacitySchedulerConf(Path configFile) { rmConf = new Configuration(false); rmConf.addResource(configFile); initializeDefaults(); } /* * Method used to initialize the default values and the queue list * which is used by the Capacity Scheduler. */ private void initializeDefaults() { defaultUlimitMinimum = rmConf.getInt( "mapred.capacity-scheduler.default-minimum-user-limit-percent", 100); defaultSupportPriority = rmConf.getBoolean( "mapred.capacity-scheduler.default-supports-priority", false); defaultMaxJobsPerUsersToInitialize = rmConf.getInt( "mapred.capacity-scheduler.default-maximum-initialized-jobs-per-user", 2); } /** * Get the percentage of the cluster for the specified queue. * * This method defaults to configured default Capacity if * no value is specified in the configuration for this queue. * If the configured capacity is negative value or greater than 100 an * {@link IllegalArgumentException} is thrown. * * If default capacity is not configured for a queue, then * system allocates capacity based on what is free at the time of * capacity scheduler start * * * @param queue name of the queue * @return percent of the cluster for the queue. */ public float getCapacity(String queue) { //Check done in order to return default capacity which can be negative //In case of both capacity and default capacity not configured. //Last check is if the configuration is specified and is marked as //negative we throw exception String raw = rmConf.getRaw(toFullPropertyName(queue, "capacity")); if(raw == null) { return -1; } float result = rmConf.getFloat(toFullPropertyName(queue, "capacity"), -1); if (result < 0.0 || result > 100.0) { throw new IllegalArgumentException("Illegal capacity for queue " + queue + " of " + result); } return result; } /** * Sets the capacity of the given queue. * * @param queue name of the queue * @param capacity percent of the cluster for the queue. */ public void setCapacity(String queue,float capacity) { rmConf.setFloat(toFullPropertyName(queue, "capacity"),capacity); } /** * Get whether priority is supported for this queue. * * If this value is false, then job priorities will be ignored in * scheduling decisions. This method defaults to <code>false</code> if * the property is not configured for this queue. * @param queue name of the queue * @return Whether this queue supports priority or not. */ public boolean isPrioritySupported(String queue) { return rmConf.getBoolean(toFullPropertyName(queue, "supports-priority"), defaultSupportPriority); } /** * Set whether priority is supported for this queue. * * * @param queue name of the queue * @param value true, if the queue must support priorities, false otherwise. */ public void setPrioritySupported(String queue, boolean value) { rmConf.setBoolean(toFullPropertyName(queue, "supports-priority"), value); } /** * Get the minimum limit of resources for any user submitting jobs in * this queue, in percentage. * * This method defaults to default user limit configured if * no value is specified in the configuration for this queue. * * Throws an {@link IllegalArgumentException} when invalid value is * configured. * * @param queue name of the queue * @return minimum limit of resources, in percentage, that will be * available for a user. * */ public int getMinimumUserLimitPercent(String queue) { int userLimit = rmConf.getInt(toFullPropertyName(queue, "minimum-user-limit-percent"), defaultUlimitMinimum); if(userLimit <= 0 || userLimit > 100) { throw new IllegalArgumentException("Invalid user limit : " + userLimit + " for queue : " + queue); } return userLimit; } /** * Set the minimum limit of resources for any user submitting jobs in * this queue, in percentage. * * @param queue name of the queue * @param value minimum limit of resources for any user submitting jobs * in this queue */ public void setMinimumUserLimitPercent(String queue, int value) { rmConf.setInt(toFullPropertyName(queue, "minimum-user-limit-percent"), value); } /** * Reload configuration by clearing the information read from the * underlying configuration file. */ public synchronized void reloadConfiguration() { rmConf.reloadConfiguration(); initializeDefaults(); } static final String toFullPropertyName(String queue, String property) { return QUEUE_CONF_PROPERTY_NAME_PREFIX + queue + "." + property; } /** * Gets the maximum number of jobs which are allowed to initialize in the * job queue. * * @param queue queue name. * @return maximum number of jobs allowed to be initialized per user. * @throws IllegalArgumentException if maximum number of users is negative * or zero. */ public int getMaxJobsPerUserToInitialize(String queue) { int maxJobsPerUser = rmConf.getInt(toFullPropertyName(queue, "maximum-initialized-jobs-per-user"), defaultMaxJobsPerUsersToInitialize); if(maxJobsPerUser <= 0) { throw new IllegalArgumentException( "Invalid maximum jobs per user configuration " + maxJobsPerUser); } return maxJobsPerUser; } /** * Sets the maximum number of jobs which are allowed to be initialized * for a user in the queue. * * @param queue queue name. * @param value maximum number of jobs allowed to be initialized per user. */ public void setMaxJobsPerUserToInitialize(String queue, int value) { rmConf.setInt(toFullPropertyName(queue, "maximum-initialized-jobs-per-user"), value); } /** * Amount of time in milliseconds which poller thread and initialization * thread would sleep before looking at the queued jobs. * * The default value if no corresponding configuration is present is * 5000 Milliseconds. * * @return time in milliseconds. * @throws IllegalArgumentException if time is negative or zero. */ public long getSleepInterval() { long sleepInterval = rmConf.getLong( "mapred.capacity-scheduler.init-poll-interval", INITIALIZATION_THREAD_POLLING_INTERVAL); if(sleepInterval <= 0) { throw new IllegalArgumentException( "Invalid initializater poller interval " + sleepInterval); } return sleepInterval; } /** * Gets maximum number of threads which are spawned to initialize jobs * in job queue in parallel. The number of threads should be always less than * or equal to number of job queues present. * * If number of threads is configured to be more than job queues present, * then number of job queues is used as number of threads used for initializing * jobs. * * So a given thread can have responsibility of initializing jobs from more * than one queue. * * The default value is 5 * * @return maximum number of threads spawned to initialize jobs in job queue * in parallel. */ public int getMaxWorkerThreads() { int maxWorkerThreads = rmConf.getInt( "mapred.capacity-scheduler.init-worker-threads", MAX_INITIALIZATION_WORKER_THREADS); if(maxWorkerThreads <= 0) { throw new IllegalArgumentException( "Invalid initializater worker thread number " + maxWorkerThreads); } return maxWorkerThreads; } /** * Set the sleep interval which initialization poller would sleep before * it looks at the jobs in the job queue. * * @param interval sleep interval */ public void setSleepInterval(long interval) { rmConf.setLong( "mapred.capacity-scheduler.init-poll-interval", interval); } /** * Sets number of threads which can be spawned to initialize jobs in * parallel. * * @param poolSize number of threads to be spawned to initialize jobs * in parallel. */ public void setMaxWorkerThreads(int poolSize) { rmConf.setInt( "mapred.capacity-scheduler.init-worker-threads", poolSize); } }