View Javadoc

1   /**
2    * Copyright The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one or more
5    * contributor license agreements. See the NOTICE file distributed with this
6    * work for additional information regarding copyright ownership. The ASF
7    * licenses this file to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   *
11   * http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16   * License for the specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.hadoop.hbase.master.handler;
20  
21  import java.io.IOException;
22  import java.io.InterruptedIOException;
23  
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  import org.apache.hadoop.classification.InterfaceAudience;
27  import org.apache.hadoop.hbase.HRegionInfo;
28  import org.apache.hadoop.hbase.RegionLoad;
29  import org.apache.hadoop.hbase.ServerName;
30  import org.apache.hadoop.hbase.executor.EventHandler;
31  import org.apache.hadoop.hbase.executor.EventType;
32  import org.apache.hadoop.hbase.master.CatalogJanitor;
33  import org.apache.hadoop.hbase.master.MasterServices;
34  import org.apache.hadoop.hbase.master.RegionPlan;
35  import org.apache.hadoop.hbase.master.RegionStates;
36  import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
37  
38  /**
39   * Handles MERGE regions request on master: move the regions together(on the
40   * same regionserver) and send MERGE RPC to regionserver.
41   *
42   * NOTE:The real merge is executed on the regionserver
43   *
44   */
45  @InterfaceAudience.Private
46  public class DispatchMergingRegionHandler extends EventHandler {
47    private static final Log LOG = LogFactory.getLog(DispatchMergingRegionHandler.class);
48    private final MasterServices masterServices;
49    private final CatalogJanitor catalogJanitor;
50    private HRegionInfo region_a;
51    private HRegionInfo region_b;
52    private final boolean forcible;
53    private final int timeout;
54  
55    public DispatchMergingRegionHandler(final MasterServices services,
56        final CatalogJanitor catalogJanitor, final HRegionInfo region_a,
57        final HRegionInfo region_b, final boolean forcible) {
58      super(services, EventType.C_M_MERGE_REGION);
59      this.masterServices = services;
60      this.catalogJanitor = catalogJanitor;
61      this.region_a = region_a;
62      this.region_b = region_b;
63      this.forcible = forcible;
64      this.timeout = server.getConfiguration().getInt(
65          "hbase.master.regionmerge.timeout", 30 * 1000);
66    }
67  
68    @Override
69    public void process() throws IOException {
70      boolean regionAHasMergeQualifier = !catalogJanitor.cleanMergeQualifier(region_a);
71      if (regionAHasMergeQualifier
72          || !catalogJanitor.cleanMergeQualifier(region_b)) {
73        LOG.info("Skip merging regions " + region_a.getRegionNameAsString()
74            + ", " + region_b.getRegionNameAsString() + ", because region "
75            + (regionAHasMergeQualifier ? region_a.getEncodedName() : region_b
76                .getEncodedName()) + " has merge qualifier");
77        return;
78      }
79  
80      RegionStates regionStates = masterServices.getAssignmentManager()
81          .getRegionStates();
82      ServerName region_a_location = regionStates.getRegionServerOfRegion(region_a);
83      ServerName region_b_location = regionStates.getRegionServerOfRegion(region_b);
84      if (region_a_location == null || region_b_location == null) {
85        LOG.info("Skip merging regions " + region_a.getRegionNameAsString()
86            + ", " + region_b.getRegionNameAsString() + ", because region "
87            + (region_a_location == null ? region_a.getEncodedName() : region_b
88                .getEncodedName()) + " is not online now");
89        return;
90      }
91      long startTime = EnvironmentEdgeManager.currentTimeMillis();
92      boolean onSameRS = region_a_location.equals(region_b_location);
93  
94      // Make sure regions are on the same regionserver before send merge
95      // regions request to regionserver
96      if (!onSameRS) {
97        // Move region_b to region a's location, switch region_a and region_b if
98        // region_a's load lower than region_b's, so we will always move lower
99        // load region
100       RegionLoad loadOfRegionA = masterServices.getServerManager()
101           .getLoad(region_a_location).getRegionsLoad()
102           .get(region_a.getRegionName());
103       RegionLoad loadOfRegionB = masterServices.getServerManager()
104           .getLoad(region_b_location).getRegionsLoad()
105           .get(region_b.getRegionName());
106       if (loadOfRegionA != null && loadOfRegionB != null
107           && loadOfRegionA.getRequestsCount() < loadOfRegionB
108               .getRequestsCount()) {
109         // switch region_a and region_b
110         HRegionInfo tmpRegion = this.region_a;
111         this.region_a = this.region_b;
112         this.region_b = tmpRegion;
113         ServerName tmpLocation = region_a_location;
114         region_a_location = region_b_location;
115         region_b_location = tmpLocation;
116       }
117 
118       RegionPlan regionPlan = new RegionPlan(region_b, region_b_location,
119           region_a_location);
120       masterServices.getAssignmentManager().balance(regionPlan);
121       while (!masterServices.isStopped()) {
122         try {
123           Thread.sleep(20);
124           region_b_location = masterServices.getAssignmentManager()
125               .getRegionStates().getRegionServerOfRegion(region_b);
126           onSameRS = region_a_location.equals(region_b_location);
127           if (onSameRS || !regionStates.isRegionInTransition(region_b)) {
128             // Regions are on the same RS, or region_b is not in
129             // RegionInTransition any more
130             break;
131           }
132           if ((EnvironmentEdgeManager.currentTimeMillis() - startTime) > timeout) break;
133         } catch (InterruptedException e) {
134           InterruptedIOException iioe = new InterruptedIOException();
135           iioe.initCause(e);
136           throw iioe;
137         }
138       }
139     }
140 
141     if (onSameRS) {
142       try{
143         masterServices.getServerManager().sendRegionsMerge(region_a_location,
144             region_a, region_b, forcible);
145         LOG.info("Successfully send MERGE REGIONS RPC to server "
146             + region_a_location.toString() + " for region "
147             + region_a.getRegionNameAsString() + ","
148             + region_b.getRegionNameAsString() + ", focible=" + forcible);
149       } catch (IOException ie) {
150         LOG.info("Failed send MERGE REGIONS RPC to server "
151             + region_a_location.toString() + " for region "
152             + region_a.getRegionNameAsString() + ","
153             + region_b.getRegionNameAsString() + ", focible=" + forcible + ", "
154             + ie.getMessage());
155       }
156     } else {
157       LOG.info("Cancel merging regions " + region_a.getRegionNameAsString()
158           + ", " + region_b.getRegionNameAsString()
159           + ", because can't move them together after "
160           + (EnvironmentEdgeManager.currentTimeMillis() - startTime) + "ms");
161     }
162   }
163 
164 }