org.apache.hadoop.corona.PoolSchedulable.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.corona.PoolSchedulable.java

Source

/*
 * 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.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Manages sessions in a pool for a given type.
 */
public class PoolSchedulable extends Schedulable {
    /** Logger */
    private static final Log LOG = LogFactory.getLog(PoolSchedulable.class);
    /** The configuration manager */
    private final ConfigManager configManager;
    /** A lookup table from id to the session */
    private final Map<String, SessionSchedulable> idToSession;
    /** The snapshot of the SessionSchedulables */
    private final Collection<SessionSchedulable> snapshotSessions;
    /** The queue of sessions sorted for scheduling */
    private Queue<SessionSchedulable> scheduleQueue;
    /** The queue of sessions sorted for preemption */
    private Queue<SessionSchedulable> preemptQueue;
    /** Last time the pool was above minimum allocation */
    private long lastTimeAboveMinimum;
    /** Last time the pool was above starving share */
    private long lastTimeAboveStarvingShare;
    /** Last time the pool was preempted */
    private long lastPreemptTime;
    /** A flag to indicate that the pool needs its share redistributed */
    private boolean needRedistributed;
    /** The max allocation for the pool */
    private int maximum;
    /** The minimum allocation for the pool */
    private int minimum;
    /** The weight of the pool */
    private double weight;
    /** The ratio for starving */
    private double shareStarvingRatio;
    /** Is this pool preemptable or not */
    private boolean preemptable;
    /** The minimum amount of time to wait between preemptions */
    private long minPreemptPeriod;
    /** The amount of time the pool has been starving for the share */
    private long starvingTimeForShare;
    /** The amount of time the pool has been starving for the minimum */
    private long starvingTimeForMinimum;
    /** Pool info names for this pool */
    private final PoolInfo poolInfo;
    /** Priority for this pool */
    private int priority;

    /**
     * Create a PoolSchedulable for a given pool and a resource type with a
     * provided configuration manager
     * @param poolInfo Pool info for this pool
     * @param type the resource type of this pool
     * @param configManager the configuration manager for this pool
     */
    public PoolSchedulable(PoolInfo poolInfo, ResourceType type, ConfigManager configManager) {
        super(PoolInfo.createStringFromPoolInfo(poolInfo), type);
        this.poolInfo = poolInfo;
        this.configManager = configManager;
        this.scheduleQueue = null;
        this.preemptQueue = null;
        this.snapshotSessions = new ArrayList<SessionSchedulable>();
        this.lastTimeAboveMinimum = -1L;
        this.lastTimeAboveStarvingShare = -1L;
        this.needRedistributed = true;

        // This needs to be thread safe because addSession() and getSortedSessions()
        // are called from different threads
        idToSession = new ConcurrentHashMap<String, SessionSchedulable>();
    }

    public PoolInfo getPoolInfo() {
        return poolInfo;
    }

    @Override
    public void snapshot() {
        granted = 0;
        requested = 0;
        pending = 0;
        snapshotSessions.clear();
        Set<String> toBeDeleted = new HashSet<String>();
        for (Entry<String, SessionSchedulable> entry : idToSession.entrySet()) {
            SessionSchedulable schedulable = entry.getValue();
            Session session = entry.getValue().getSession();
            synchronized (session) {
                if (session.isDeleted()) {
                    toBeDeleted.add(entry.getKey());
                } else {
                    schedulable.snapshot();
                    snapshotSessions.add(schedulable);
                    granted += schedulable.getGranted();
                    requested += schedulable.getRequested();
                    pending += schedulable.getPending();
                }
            }
        }
        if (LOG.isDebugEnabled()) {
            LOG.debug("Snapshot for pool " + getName() + ":" + getType() + " {requested = " + requested
                    + ", pending = " + pending + ", granted = " + granted + "}");
        }
        for (String id : toBeDeleted) {
            idToSession.remove(id);
        }
        snapshotConfig();
        scheduleQueue = null;
        preemptQueue = null;
        needRedistributed = true;
    }

    /**
     * Get the snapshot of the configuration from the configuration manager.
     * Synchronized on config manager to ensure that config is atomically updated
     * per pool.
     */
    private void snapshotConfig() {
        synchronized (configManager) {
            maximum = configManager.getPoolMaximum(poolInfo, getType());
            minimum = configManager.getPoolMinimum(poolInfo, getType());
            weight = configManager.getWeight(poolInfo);
            priority = configManager.getPriority(poolInfo);
            preemptable = configManager.isPoolPreemptable(poolInfo);
            shareStarvingRatio = configManager.getShareStarvingRatio();
            minPreemptPeriod = configManager.getMinPreemptPeriod();
            starvingTimeForShare = configManager.getStarvingTimeForShare();
            starvingTimeForMinimum = configManager.getStarvingTimeForMinimum();
        }
    }

    @Override
    public int getMaximum() {
        return maximum;
    }

    @Override
    public int getMinimum() {
        return minimum;
    }

    @Override
    public double getWeight() {
        return weight;
    }

    @Override
    public long getDeadline() {
        // Pools have no deadlines
        return -1L;
    }

    @Override
    public int getPriority() {
        return priority;
    }

    /**
     * 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;
    }

    /**
     * Add a session to the pool
     * @param id the id of the session
     * @param session the session to add to the pool
     */
    public void addSession(String id, Session session) {
        synchronized (session) {
            SessionSchedulable schedulable = new SessionSchedulable(session, getType());
            idToSession.put(id, schedulable);
        }
    }

    /**
     * Get the queue of sessions sorted for scheduling
     * @return the queue of sessions sorted for scheduling
     */
    public Queue<SessionSchedulable> getScheduleQueue() {
        if (scheduleQueue == null) {
            scheduleQueue = createSessionQueue(configManager.getPoolComparator(poolInfo));
        }
        return scheduleQueue;
    }

    /**
     * Get the queue of sessions sorted for preemption
     * @return the queue of sessions sorted for preemption
     */
    public Queue<SessionSchedulable> getPreemptQueue() {
        if (preemptQueue == null) {

            ScheduleComparator comparator = null;
            switch (configManager.getPoolComparator(poolInfo)) {
            case FIFO:
                comparator = ScheduleComparator.FIFO_PREEMPT;
                break;
            case FAIR:
                comparator = ScheduleComparator.FAIR_PREEMPT;
                break;
            case DEADLINE:
                comparator = ScheduleComparator.DEADLINE_PREEMPT;
                break;
            default:
                throw new IllegalArgumentException("Unknown comparator");
            }

            preemptQueue = createSessionQueue(comparator);
        }
        return preemptQueue;
    }

    /**
     * Get the queue of sessions in the pool sorted by comparator
     * @param comparator the comparator to use when sorting sessions
     * @return the queue of the sessions sorted by a given comparator
     */
    public Queue<SessionSchedulable> createSessionQueue(ScheduleComparator comparator) {
        int initCapacity = snapshotSessions.size() == 0 ? 1 : snapshotSessions.size();
        Queue<SessionSchedulable> sessionQueue = new PriorityQueue<SessionSchedulable>(initCapacity, comparator);
        sessionQueue.addAll(snapshotSessions);
        return sessionQueue;
    }

    /**
     * Distribute the pool's share between the sessions in the pool
     */
    public void distributeShare() {
        if (needRedistributed) {
            ScheduleComparator comparator = configManager.getPoolComparator(poolInfo);
            Schedulable.distributeShare(getShare(), snapshotSessions, comparator);
        }
        needRedistributed = false;
    }

    /**
     * Check if the pool is starving now or not
     * @param now current timestampe
     * @return true if the pool is starving now, false otherwise
     */
    public boolean isStarving(long now) {
        double starvingShare = getShare() * shareStarvingRatio;
        if (getGranted() >= Math.ceil(starvingShare)) {
            lastTimeAboveStarvingShare = now;
        }

        if (getGranted() >= Math.min(getShare(), getMinimum())) {
            lastTimeAboveMinimum = now;
        }
        if (now - lastPreemptTime < getMinPreemptPeriod()) {
            // Prevent duplicate preemption
            return false;
        }
        if (LOG.isDebugEnabled()) {
            LOG.debug("Pool:" + getName() + " lastTimeAboveMinimum:" + lastTimeAboveMinimum
                    + " lastTimeAboveStarvingShare:" + lastTimeAboveStarvingShare + " minimumStarvingTime:"
                    + getMinimumStarvingTime(now) + " shareStarvingTime:" + getShareStarvingTime(now)
                    + " starvingTime:" + getStarvingTime(now));
        }
        if (getMinimumStarvingTime(now) >= 0) {
            LOG.info("Pool:" + getName() + " for type:" + getType() + " is starving min:" + getMinimum()
                    + " granted:" + getGranted());
            lastPreemptTime = now;
            return true;
        }
        if (getShareStarvingTime(now) >= 0) {
            LOG.info("Pool:" + getName() + " for type:" + getType() + " is starving share:" + getShare()
                    + " starvingRatio:" + shareStarvingRatio + " starvingShare:" + starvingShare + " granted:"
                    + getGranted());
            lastPreemptTime = now;
            return true;
        }
        return false;
    }

    /**
     * Get the amount of time the pool was starving for either its min share
     * or its share
     * @param now the current timestamp
     * @return the amount of time the pool was starving
     */
    public long getStarvingTime(long now) {
        long starvingTime = Math.max(getMinimumStarvingTime(now), getShareStarvingTime(now));
        return starvingTime;
    }

    /**
     * @return The minimum time between preemptions.
     */
    public long getMinPreemptPeriod() {
        return minPreemptPeriod;
    }

    /**
     * Get the amount of time the pool was starving for its min share
     * @param now the current timestamp
     * @return the amount of time the pool was starving for the min share
     */
    private long getMinimumStarvingTime(long now) {
        return (now - lastTimeAboveMinimum) - starvingTimeForMinimum;
    }

    /**
     * Get the amount of time the pool was starving for its share
     * @param now the current timestamp
     * @return the amount of time the pool was starving for share
     */
    private long getShareStarvingTime(long now) {
        return (now - lastTimeAboveStarvingShare) - starvingTimeForShare;
    }

    /**
     * Is the pool preemptable or not
     * @return true if the pool is preemptable false otherwise
     */
    public boolean isPreemptable() {
        return preemptable;
    }
}