/*
* 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.corona;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
/**
* Represents a group of pools
*/
public class PoolGroupSchedulable extends Schedulable {
/** The set of all pools into this group */
private final ConcurrentHashMap<PoolInfo, PoolSchedulable> nameToMap =
new ConcurrentHashMap<PoolInfo, PoolSchedulable>();
/** Dynamic configuration */
private final ConfigManager configManager;
/** The list of pool snapshots used for scheduling */
private Collection<PoolSchedulable> snapshotPools;
/** The queue of pools for scheduling */
private Queue<PoolSchedulable> scheduleQueue;
/** The queue of pools for preemption */
private Queue<PoolSchedulable> preemptQueue;
/** The max allocation for the pool group */
private int maximum;
/** The minimum allocation for the pool group */
private int minimum;
/** A flag to indicate that the pool group needs its share redistributed */
private boolean needRedistributed;
/** Pool info or this pool group (null pool name) */
private final PoolInfo poolInfo;
/**
* Constructs a pool group
*
* @param name Name of the pool group
* @param type Type of the resource of this pool group
* @param configManager Dynamic configuration
*/
public PoolGroupSchedulable(
String name, ResourceType type, ConfigManager configManager) {
super(name, type);
poolInfo = new PoolInfo(name, null);
this.configManager = configManager;
this.needRedistributed = true;
}
public PoolInfo getPoolInfo() {
return poolInfo;
}
/**
* Get the snapshot of the configuration from the configuration manager
*/
private void snapshotConfig() {
maximum = configManager.getPoolGroupMaximum(getName(), getType());
minimum = configManager.getPoolGroupMinimum(getName(), getType());
}
@Override
public void snapshot() {
snapshotPools = new ArrayList<PoolSchedulable>(nameToMap.values());
granted = 0;
requested = 0;
pending = 0;
for (PoolSchedulable pool : snapshotPools) {
pool.snapshot();
granted += pool.getGranted();
requested += pool.getRequested();
pending += pool.getPending();
}
snapshotConfig();
scheduleQueue = null;
preemptQueue = null;
needRedistributed = true;
}
/**
* Get the queue of pools sorted for scheduling
* @return the queue of pools sorted for scheduling
*/
public Queue<PoolSchedulable> getScheduleQueue() {
if (scheduleQueue == null) {
ScheduleComparator sc = configManager.getPoolGroupComparator(getName());
scheduleQueue = createPoolQueue(sc);
}
return scheduleQueue;
}
/**
* Get the queue of the pool sorted for preemption
* @return the queue of pool sorted for preemption
*/
public Queue<PoolSchedulable> getPreemptQueue() {
// TODO: For now, we support only one kind of scheduling.
// Also note that FAIR is PRIORITY with equal priorities (by default)
ScheduleComparator sPreempt = null;
if (preemptQueue == null) {
ScheduleComparator sc = configManager.getPoolGroupComparator(getName());
if (sc == ScheduleComparator.PRIORITY) {
sPreempt = ScheduleComparator.PRIORITY_PREEMPT;
} else {
throw new IllegalArgumentException("Unknown/misconfigured poolgroup");
}
preemptQueue = createPoolQueue(sPreempt);
}
return preemptQueue;
}
/**
* Put all the pools into the priority queue sorted by a comparator
* @param comparator the comparator to sort all the pools in the queue by
* @return the queue of the pools sorted by a comparator
*/
private Queue<PoolSchedulable> createPoolQueue(
ScheduleComparator comparator) {
int initCapacity =
snapshotPools.size() == 0 ? 1 : snapshotPools.size();
Queue<PoolSchedulable> poolQueue =
new PriorityQueue<PoolSchedulable>(initCapacity, comparator);
poolQueue.addAll(snapshotPools);
return poolQueue;
}
@Override
public long getDeadline() {
// No deadline for pool groups
return 0;
}
@Override
public int getPriority() {
// No priority for pool groups
return 0;
}
@Override
public int getMaximum() {
return maximum;
}
@Override
public int getMinimum() {
return minimum;
}
/**
* Check if the pool's share has reached its maximum share
* @return true if the pool's share has reached its maximum, false
* otherwise
*/
public boolean reachedMaximum() {
return granted >= getMaximum() || granted >= requested;
}
/**
* Distribute the pool's share between the sessions in the pool
*/
public void distributeShare() {
if (needRedistributed) {
ScheduleComparator sc = configManager.getPoolGroupComparator(getName());
Schedulable.distributeShare(getShare(), snapshotPools, sc);
}
needRedistributed = false;
}
/**
* Get a pool, creating it if it does not exist. Note that these
* pools are never removed.
*
* @param poolInfo Pool info used
* @return Pool that existed or was created
*/
public PoolSchedulable getPool(PoolInfo poolInfo) {
PoolSchedulable pool = nameToMap.get(poolInfo);
if (pool == null) {
pool = new PoolSchedulable(poolInfo, getType(), configManager);
PoolSchedulable prevPool = nameToMap.putIfAbsent(poolInfo, pool);
if (prevPool != null) {
pool = prevPool;
}
}
return pool;
}
/**
* Get a snapshot of the pools that is generated from snapshot().
*
* @return An unmodifiable snapshot of the pools.
*/
public Collection<PoolSchedulable> getPools() {
return Collections.unmodifiableCollection(snapshotPools);
}
}