org.apache.hadoop.hbase.regionserver.PriorityCompactionQueue.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.hbase.regionserver.PriorityCompactionQueue.java

Source

/**
* Copyright 2010 The Apache Software Foundation
*
* 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.hbase.regionserver;

import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * This class delegates to the BlockingQueue but wraps all HRegions in
 * compaction requests that hold the priority and the date requested.
 *
 * Implementation Note: With an elevation time of -1 there is the potential for
 * starvation of the lower priority compaction requests as long as there is a
 * constant stream of high priority requests.
 */
public class PriorityCompactionQueue implements BlockingQueue<HRegion> {
    static final Log LOG = LogFactory.getLog(PriorityCompactionQueue.class);

    /**
     * This class represents a compaction request and holds the region, priority,
     * and time submitted.
     */
    private class CompactionRequest implements Comparable<CompactionRequest> {
        private final HRegion r;
        private final int p;
        private final Date date;

        public CompactionRequest(HRegion r, int p) {
            this(r, p, null);
        }

        public CompactionRequest(HRegion r, int p, Date d) {
            if (r == null) {
                throw new NullPointerException("HRegion cannot be null");
            }

            if (d == null) {
                d = new Date();
            }

            this.r = r;
            this.p = p;
            this.date = d;
        }

        /**
         * This function will define where in the priority queue the request will
         * end up.  Those with the highest priorities will be first.  When the
         * priorities are the same it will It will first compare priority then date
         * to maintain a FIFO functionality.
         *
         * <p>Note: The date is only accurate to the millisecond which means it is
         * possible that two requests were inserted into the queue within a
         * millisecond.  When that is the case this function will break the tie
         * arbitrarily.
         */
        @Override
        public int compareTo(CompactionRequest request) {
            //NOTE: The head of the priority queue is the least element
            if (this.equals(request)) {
                return 0; //they are the same request
            }
            int compareVal;

            compareVal = p - request.p; //compare priority
            if (compareVal != 0) {
                return compareVal;
            }

            compareVal = date.compareTo(request.date);
            if (compareVal != 0) {
                return compareVal;
            }

            //break the tie arbitrarily
            return -1;
        }

        /** Gets the HRegion for the request */
        HRegion getHRegion() {
            return r;
        }

        /** Gets the priority for the request */
        int getPriority() {
            return p;
        }

        public String toString() {
            return "regionName=" + r.getRegionNameAsString() + ", priority=" + p + ", date=" + date;
        }
    }

    /** The actual blocking queue we delegate to */
    protected final BlockingQueue<CompactionRequest> queue = new PriorityBlockingQueue<CompactionRequest>();

    /** Hash map of the HRegions contained within the Compaction Queue */
    private final HashMap<HRegion, CompactionRequest> regionsInQueue = new HashMap<HRegion, CompactionRequest>();

    /** Creates a new PriorityCompactionQueue with no priority elevation time */
    public PriorityCompactionQueue() {
        LOG.debug("Create PriorityCompactionQueue");
    }

    /** If the region is not already in the queue it will add it and return a
     * new compaction request object.  If it is already present in the queue
     * then it will return null.
     * @param p If null it will use the default priority
     * @return returns a compaction request if it isn't already in the queue
     */
    protected CompactionRequest addToRegionsInQueue(HRegion r, int p) {
        CompactionRequest queuedRequest = null;
        CompactionRequest newRequest = new CompactionRequest(r, p);
        synchronized (regionsInQueue) {
            queuedRequest = regionsInQueue.get(r);
            if (queuedRequest == null || newRequest.getPriority() < queuedRequest.getPriority()) {
                LOG.trace("Inserting region in queue. " + newRequest);
                regionsInQueue.put(r, newRequest);
            } else {
                LOG.trace("Region already in queue, skipping. Queued: " + queuedRequest + ", requested: "
                        + newRequest);
                newRequest = null; // It is already present so don't add it
            }
        }

        if (newRequest != null && queuedRequest != null) {
            // Remove the lower priority request
            queue.remove(queuedRequest);
        }

        return newRequest;
    }

    /** Removes the request from the regions in queue
     * @param remove
     */
    protected CompactionRequest removeFromRegionsInQueue(CompactionRequest remove) {
        if (remove == null)
            return null;

        synchronized (regionsInQueue) {
            CompactionRequest cr = null;
            cr = regionsInQueue.remove(remove.getHRegion());
            if (cr != null && !cr.equals(remove)) {
                //Because we don't synchronize across both this.regionsInQueue and this.queue
                //a rare race condition exists where a higher priority compaction request replaces
                //the lower priority request in this.regionsInQueue but the lower priority request
                //is taken off this.queue before the higher can be added to this.queue.
                //So if we didn't remove what we were expecting we put it back on.
                regionsInQueue.put(cr.getHRegion(), cr);
            }
            if (cr == null) {
                LOG.warn("Removed a region it couldn't find in regionsInQueue: " + remove.getHRegion());
            }
            return cr;
        }
    }

    public boolean add(HRegion e, int p) {
        CompactionRequest request = this.addToRegionsInQueue(e, p);
        if (request != null) {
            boolean result = queue.add(request);
            return result;
        } else {
            return false;
        }
    }

    @Override
    public boolean add(HRegion e) {
        return add(e, e.getCompactPriority());
    }

    public boolean offer(HRegion e, int p) {
        CompactionRequest request = this.addToRegionsInQueue(e, p);
        return (request != null) ? queue.offer(request) : false;
    }

    @Override
    public boolean offer(HRegion e) {
        return offer(e, e.getCompactPriority());
    }

    public void put(HRegion e, int p) throws InterruptedException {
        CompactionRequest request = this.addToRegionsInQueue(e, p);
        if (request != null) {
            queue.put(request);
        }
    }

    @Override
    public void put(HRegion e) throws InterruptedException {
        put(e, e.getCompactPriority());
    }

    public boolean offer(HRegion e, int p, long timeout, TimeUnit unit) throws InterruptedException {
        CompactionRequest request = this.addToRegionsInQueue(e, p);
        return (request != null) ? queue.offer(request, timeout, unit) : false;
    }

    @Override
    public boolean offer(HRegion e, long timeout, TimeUnit unit) throws InterruptedException {
        return offer(e, e.getCompactPriority(), timeout, unit);
    }

    @Override
    public HRegion take() throws InterruptedException {
        CompactionRequest cr = queue.take();
        if (cr != null) {
            removeFromRegionsInQueue(cr);
            return cr.getHRegion();
        }
        return null;
    }

    @Override
    public HRegion poll(long timeout, TimeUnit unit) throws InterruptedException {
        CompactionRequest cr = queue.poll(timeout, unit);
        if (cr != null) {
            removeFromRegionsInQueue(cr);
            return cr.getHRegion();
        }
        return null;
    }

    @Override
    public boolean remove(Object r) {
        if (r instanceof CompactionRequest) {
            CompactionRequest cr = removeFromRegionsInQueue((CompactionRequest) r);
            if (cr != null) {
                return queue.remove(cr);
            }
        }

        return false;
    }

    @Override
    public HRegion remove() {
        CompactionRequest cr = queue.remove();
        if (cr != null) {
            removeFromRegionsInQueue(cr);
            return cr.getHRegion();
        }
        return null;
    }

    @Override
    public HRegion poll() {
        CompactionRequest cr = queue.poll();
        if (cr != null) {
            removeFromRegionsInQueue(cr);
            return cr.getHRegion();
        }
        return null;
    }

    @Override
    public int remainingCapacity() {
        return queue.remainingCapacity();
    }

    @Override
    public boolean contains(Object r) {
        if (r instanceof HRegion) {
            synchronized (regionsInQueue) {
                return regionsInQueue.containsKey((HRegion) r);
            }
        } else if (r instanceof CompactionRequest) {
            return queue.contains(r);
        }
        return false;
    }

    @Override
    public HRegion element() {
        CompactionRequest cr = queue.element();
        return (cr != null) ? cr.getHRegion() : null;
    }

    @Override
    public HRegion peek() {
        CompactionRequest cr = queue.peek();
        return (cr != null) ? cr.getHRegion() : null;
    }

    @Override
    public int size() {
        return queue.size();
    }

    @Override
    public boolean isEmpty() {
        return queue.isEmpty();
    }

    @Override
    public void clear() {
        regionsInQueue.clear();
        queue.clear();
    }

    // Unimplemented methods, collection methods

    @Override
    public Iterator<HRegion> iterator() {
        throw new UnsupportedOperationException("Not supported.");
    }

    @Override
    public Object[] toArray() {
        throw new UnsupportedOperationException("Not supported.");
    }

    @Override
    public <T> T[] toArray(T[] a) {
        throw new UnsupportedOperationException("Not supported.");
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        throw new UnsupportedOperationException("Not supported.");
    }

    @Override
    public boolean addAll(Collection<? extends HRegion> c) {
        throw new UnsupportedOperationException("Not supported.");
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        throw new UnsupportedOperationException("Not supported.");
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        throw new UnsupportedOperationException("Not supported.");
    }

    @Override
    public int drainTo(Collection<? super HRegion> c) {
        throw new UnsupportedOperationException("Not supported.");
    }

    @Override
    public int drainTo(Collection<? super HRegion> c, int maxElements) {
        throw new UnsupportedOperationException("Not supported.");
    }
}