org.apache.hadoop.hbase.master.handler.DispatchMergingRegionHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.hbase.master.handler.DispatchMergingRegionHandler.java

Source

/**
 * Copyright 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.master.handler;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.RegionLoad;
import org.apache.hadoop.hbase.ServerLoad;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.exceptions.RegionOpeningException;
import org.apache.hadoop.hbase.executor.EventHandler;
import org.apache.hadoop.hbase.executor.EventType;
import org.apache.hadoop.hbase.master.CatalogJanitor;
import org.apache.hadoop.hbase.master.MasterServices;
import org.apache.hadoop.hbase.master.RegionPlan;
import org.apache.hadoop.hbase.master.RegionStates;
import org.apache.hadoop.hbase.master.ServerManager;
import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;

/**
 * Handles MERGE regions request on master: move the regions together(on the
 * same regionserver) and send MERGE RPC to regionserver.
 *
 * NOTE:The real merge is executed on the regionserver
 *
 */
@InterfaceAudience.Private
public class DispatchMergingRegionHandler extends EventHandler {
    private static final Log LOG = LogFactory.getLog(DispatchMergingRegionHandler.class);
    private final MasterServices masterServices;
    private final CatalogJanitor catalogJanitor;
    private HRegionInfo region_a;
    private HRegionInfo region_b;
    private final boolean forcible;
    private final int timeout;

    public DispatchMergingRegionHandler(final MasterServices services, final CatalogJanitor catalogJanitor,
            final HRegionInfo region_a, final HRegionInfo region_b, final boolean forcible) {
        super(services, EventType.C_M_MERGE_REGION);
        this.masterServices = services;
        this.catalogJanitor = catalogJanitor;
        this.region_a = region_a;
        this.region_b = region_b;
        this.forcible = forcible;
        this.timeout = server.getConfiguration().getInt("hbase.master.regionmerge.timeout", 120 * 1000);
    }

    @Override
    public void process() throws IOException {
        boolean regionAHasMergeQualifier = !catalogJanitor.cleanMergeQualifier(region_a);
        if (regionAHasMergeQualifier || !catalogJanitor.cleanMergeQualifier(region_b)) {
            LOG.info("Skip merging regions " + region_a.getRegionNameAsString() + ", "
                    + region_b.getRegionNameAsString() + ", because region "
                    + (regionAHasMergeQualifier ? region_a.getEncodedName() : region_b.getEncodedName())
                    + " has merge qualifier");
            return;
        }

        RegionStates regionStates = masterServices.getAssignmentManager().getRegionStates();
        ServerName region_a_location = regionStates.getRegionServerOfRegion(region_a);
        ServerName region_b_location = regionStates.getRegionServerOfRegion(region_b);
        if (region_a_location == null || region_b_location == null) {
            LOG.info("Skip merging regions " + region_a.getRegionNameAsString() + ", "
                    + region_b.getRegionNameAsString() + ", because region "
                    + (region_a_location == null ? region_a.getEncodedName() : region_b.getEncodedName())
                    + " is not online now");
            return;
        }
        long startTime = EnvironmentEdgeManager.currentTimeMillis();
        boolean onSameRS = region_a_location.equals(region_b_location);

        // Make sure regions are on the same regionserver before send merge
        // regions request to regionserver
        if (!onSameRS) {
            // Move region_b to region a's location, switch region_a and region_b if
            // region_a's load lower than region_b's, so we will always move lower
            // load region
            RegionLoad loadOfRegionA = getRegionLoad(region_a_location, region_a);
            RegionLoad loadOfRegionB = getRegionLoad(region_b_location, region_b);
            if (loadOfRegionA != null && loadOfRegionB != null
                    && loadOfRegionA.getRequestsCount() < loadOfRegionB.getRequestsCount()) {
                // switch region_a and region_b
                HRegionInfo tmpRegion = this.region_a;
                this.region_a = this.region_b;
                this.region_b = tmpRegion;
                ServerName tmpLocation = region_a_location;
                region_a_location = region_b_location;
                region_b_location = tmpLocation;
            }

            RegionPlan regionPlan = new RegionPlan(region_b, region_b_location, region_a_location);
            LOG.info("Moving regions to same server for merge: " + regionPlan.toString());
            masterServices.getAssignmentManager().balance(regionPlan);
            while (!masterServices.isStopped()) {
                try {
                    Thread.sleep(20);
                    // Make sure check RIT first, then get region location, otherwise
                    // we would make a wrong result if region is online between getting
                    // region location and checking RIT
                    boolean isRIT = regionStates.isRegionInTransition(region_b);
                    region_b_location = masterServices.getAssignmentManager().getRegionStates()
                            .getRegionServerOfRegion(region_b);
                    onSameRS = region_a_location.equals(region_b_location);
                    if (onSameRS || !isRIT) {
                        // Regions are on the same RS, or region_b is not in
                        // RegionInTransition any more
                        break;
                    }
                    if ((EnvironmentEdgeManager.currentTimeMillis() - startTime) > timeout)
                        break;
                } catch (InterruptedException e) {
                    InterruptedIOException iioe = new InterruptedIOException();
                    iioe.initCause(e);
                    throw iioe;
                }
            }
        }

        if (onSameRS) {
            startTime = EnvironmentEdgeManager.currentTimeMillis();
            while (!masterServices.isStopped()) {
                try {
                    masterServices.getServerManager().sendRegionsMerge(region_a_location, region_a, region_b,
                            forcible);
                    LOG.info(
                            "Sent merge to server " + region_a_location + " for region " + region_a.getEncodedName()
                                    + "," + region_b.getEncodedName() + ", focible=" + forcible);
                    break;
                } catch (RegionOpeningException roe) {
                    if ((EnvironmentEdgeManager.currentTimeMillis() - startTime) > timeout) {
                        LOG.warn("Failed sending merge to " + region_a_location + " after " + timeout + "ms", roe);
                        break;
                    }
                    // Do a retry since region should be online on RS immediately
                } catch (IOException ie) {
                    LOG.warn("Failed sending merge to " + region_a_location + " for region "
                            + region_a.getEncodedName() + "," + region_b.getEncodedName() + ", focible=" + forcible,
                            ie);
                    break;
                }
            }
        } else {
            LOG.info("Cancel merging regions " + region_a.getRegionNameAsString() + ", "
                    + region_b.getRegionNameAsString() + ", because can't move them together after "
                    + (EnvironmentEdgeManager.currentTimeMillis() - startTime) + "ms");
        }
    }

    private RegionLoad getRegionLoad(ServerName sn, HRegionInfo hri) {
        ServerManager serverManager = masterServices.getServerManager();
        ServerLoad load = serverManager.getLoad(sn);
        if (load != null) {
            Map<byte[], RegionLoad> regionsLoad = load.getRegionsLoad();
            if (regionsLoad != null) {
                return regionsLoad.get(hri.getRegionName());
            }
        }
        return null;
    }
}