org.apache.hadoop.hbase.master.GeneralBulkAssigner.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.hbase.master.GeneralBulkAssigner.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.hbase.master;

import java.lang.Thread.UncaughtExceptionHandler;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.Server;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.master.RegionState.State;

/**
 * Run bulk assign.  Does one RCP per regionserver passing a
 * batch of regions using {@link GeneralBulkAssigner.SingleServerBulkAssigner}.
 */
@InterfaceAudience.Private
public class GeneralBulkAssigner extends BulkAssigner {
    private static final Log LOG = LogFactory.getLog(GeneralBulkAssigner.class);

    private Map<ServerName, List<HRegionInfo>> failedPlans = new ConcurrentHashMap<ServerName, List<HRegionInfo>>();
    private ExecutorService pool;

    final Map<ServerName, List<HRegionInfo>> bulkPlan;
    final AssignmentManager assignmentManager;
    final boolean waitTillAllAssigned;

    public GeneralBulkAssigner(final Server server, final Map<ServerName, List<HRegionInfo>> bulkPlan,
            final AssignmentManager am, final boolean waitTillAllAssigned) {
        super(server);
        this.bulkPlan = bulkPlan;
        this.assignmentManager = am;
        this.waitTillAllAssigned = waitTillAllAssigned;
    }

    @Override
    protected String getThreadNamePrefix() {
        return this.server.getServerName() + "-GeneralBulkAssigner";
    }

    @Override
    protected void populatePool(ExecutorService pool) {
        this.pool = pool; // shut it down later in case some assigner hangs
        for (Map.Entry<ServerName, List<HRegionInfo>> e : this.bulkPlan.entrySet()) {
            pool.execute(new SingleServerBulkAssigner(e.getKey(), e.getValue(), this.assignmentManager,
                    this.failedPlans));
        }
    }

    /**
     *
     * @param timeout How long to wait.
     * @return true if done.
     */
    @Override
    protected boolean waitUntilDone(final long timeout) throws InterruptedException {
        Set<HRegionInfo> regionSet = new HashSet<HRegionInfo>();
        for (List<HRegionInfo> regionList : bulkPlan.values()) {
            regionSet.addAll(regionList);
        }

        pool.shutdown(); // no more task allowed
        int serverCount = bulkPlan.size();
        int regionCount = regionSet.size();
        long startTime = System.currentTimeMillis();
        long rpcWaitTime = startTime + timeout;
        while (!server.isStopped() && !pool.isTerminated() && rpcWaitTime > System.currentTimeMillis()) {
            if (failedPlans.isEmpty()) {
                pool.awaitTermination(100, TimeUnit.MILLISECONDS);
            } else {
                reassignFailedPlans();
            }
        }
        if (!pool.isTerminated()) {
            LOG.warn("bulk assigner is still running after " + (System.currentTimeMillis() - startTime)
                    + "ms, shut it down now");
            // some assigner hangs, can't wait any more, shutdown the pool now
            List<Runnable> notStarted = pool.shutdownNow();
            if (notStarted != null && !notStarted.isEmpty()) {
                server.abort("some single server assigner hasn't started yet" + " when the bulk assigner timed out",
                        null);
                return false;
            }
        }

        int reassigningRegions = 0;
        if (!failedPlans.isEmpty() && !server.isStopped()) {
            reassigningRegions = reassignFailedPlans();
        }

        Configuration conf = server.getConfiguration();
        long perRegionOpenTimeGuesstimate = conf.getLong("hbase.bulk.assignment.perregion.open.time", 1000);
        long endTime = Math.max(System.currentTimeMillis(), rpcWaitTime)
                + perRegionOpenTimeGuesstimate * (reassigningRegions + 1);
        RegionStates regionStates = assignmentManager.getRegionStates();
        // We're not synchronizing on regionsInTransition now because we don't use any iterator.
        while (!regionSet.isEmpty() && !server.isStopped() && endTime > System.currentTimeMillis()) {
            Iterator<HRegionInfo> regionInfoIterator = regionSet.iterator();
            while (regionInfoIterator.hasNext()) {
                HRegionInfo hri = regionInfoIterator.next();
                if (regionStates.isRegionOnline(hri) || regionStates.isRegionInState(hri, State.SPLITTING,
                        State.SPLIT, State.MERGING, State.MERGED)) {
                    regionInfoIterator.remove();
                }
            }
            if (!waitTillAllAssigned) {
                // No need to wait, let assignment going on asynchronously
                break;
            }
            if (!regionSet.isEmpty()) {
                regionStates.waitForUpdate(100);
            }
        }

        if (LOG.isDebugEnabled()) {
            long elapsedTime = System.currentTimeMillis() - startTime;
            String status = "successfully";
            if (!regionSet.isEmpty()) {
                status = "with " + regionSet.size() + " regions still in transition";
            }
            LOG.debug("bulk assigning total " + regionCount + " regions to " + serverCount + " servers, took "
                    + elapsedTime + "ms, " + status);
        }
        return regionSet.isEmpty();
    }

    @Override
    protected long getTimeoutOnRIT() {
        // Guess timeout.  Multiply the max number of regions on a server
        // by how long we think one region takes opening.
        Configuration conf = server.getConfiguration();
        long perRegionOpenTimeGuesstimate = conf.getLong("hbase.bulk.assignment.perregion.open.time", 1000);
        int maxRegionsPerServer = 1;
        for (List<HRegionInfo> regionList : bulkPlan.values()) {
            int size = regionList.size();
            if (size > maxRegionsPerServer) {
                maxRegionsPerServer = size;
            }
        }
        long timeout = perRegionOpenTimeGuesstimate * maxRegionsPerServer
                + conf.getLong("hbase.regionserver.rpc.startup.waittime", 60000)
                + conf.getLong("hbase.bulk.assignment.perregionserver.rpc.waittime", 30000) * bulkPlan.size();
        LOG.debug("Timeout-on-RIT=" + timeout);
        return timeout;
    }

    @Override
    protected UncaughtExceptionHandler getUncaughtExceptionHandler() {
        return new UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                LOG.warn("Assigning regions in " + t.getName(), e);
            }
        };
    }

    private int reassignFailedPlans() {
        List<HRegionInfo> reassigningRegions = new ArrayList<HRegionInfo>();
        for (Map.Entry<ServerName, List<HRegionInfo>> e : failedPlans.entrySet()) {
            LOG.info("Failed assigning " + e.getValue().size() + " regions to server " + e.getKey()
                    + ", reassigning them");
            reassigningRegions.addAll(failedPlans.remove(e.getKey()));
        }
        RegionStates regionStates = assignmentManager.getRegionStates();
        for (HRegionInfo region : reassigningRegions) {
            if (!regionStates.isRegionOnline(region)) {
                assignmentManager.invokeAssign(region);
            }
        }
        return reassigningRegions.size();
    }

    /**
     * Manage bulk assigning to a server.
     */
    static class SingleServerBulkAssigner implements Runnable {
        private final ServerName regionserver;
        private final List<HRegionInfo> regions;
        private final AssignmentManager assignmentManager;
        private final Map<ServerName, List<HRegionInfo>> failedPlans;

        SingleServerBulkAssigner(final ServerName regionserver, final List<HRegionInfo> regions,
                final AssignmentManager am, final Map<ServerName, List<HRegionInfo>> failedPlans) {
            this.regionserver = regionserver;
            this.regions = regions;
            this.assignmentManager = am;
            this.failedPlans = failedPlans;
        }

        @Override
        public void run() {
            try {
                if (!assignmentManager.assign(regionserver, regions)) {
                    failedPlans.put(regionserver, regions);
                }
            } catch (Throwable t) {
                LOG.warn("Failed bulking assigning " + regions.size() + " region(s) to "
                        + regionserver.getServerName() + ", and continue to bulk assign others", t);
                failedPlans.put(regionserver, regions);
            }
        }
    }
}