View Javadoc

1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  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,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  package org.apache.hadoop.hbase.regionserver.handler;
20  
21  import java.io.IOException;
22  
23  import org.apache.commons.logging.Log;
24  import org.apache.commons.logging.LogFactory;
25  import org.apache.hadoop.hbase.classification.InterfaceAudience;
26  import org.apache.hadoop.hbase.HRegionInfo;
27  import org.apache.hadoop.hbase.Server;
28  import org.apache.hadoop.hbase.ServerName;
29  import org.apache.hadoop.hbase.coordination.CloseRegionCoordination;
30  import org.apache.hadoop.hbase.executor.EventHandler;
31  import org.apache.hadoop.hbase.executor.EventType;
32  import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.RegionStateTransition.TransitionCode;
33  import org.apache.hadoop.hbase.regionserver.HRegion;
34  import org.apache.hadoop.hbase.regionserver.RegionServerServices;
35  import org.apache.hadoop.hbase.util.ConfigUtil;
36  
37  /**
38   * Handles closing of a region on a region server.
39   */
40  @InterfaceAudience.Private
41  public class CloseRegionHandler extends EventHandler {
42    // NOTE on priorities shutting down.  There are none for close. There are some
43    // for open.  I think that is right.  On shutdown, we want the meta to close
44    // before root and both to close after the user regions have closed.  What
45    // about the case where master tells us to shutdown a catalog region and we
46    // have a running queue of user regions to close?
47    private static final Log LOG = LogFactory.getLog(CloseRegionHandler.class);
48  
49    private final RegionServerServices rsServices;
50    private final HRegionInfo regionInfo;
51  
52    // If true, the hosting server is aborting.  Region close process is different
53    // when we are aborting.
54    private final boolean abort;
55    private ServerName destination;
56    private CloseRegionCoordination closeRegionCoordination;
57    private CloseRegionCoordination.CloseRegionDetails closeRegionDetails;
58    private final boolean useZKForAssignment;
59  
60    /**
61     * This method used internally by the RegionServer to close out regions.
62     * @param server
63     * @param rsServices
64     * @param regionInfo
65     * @param abort If the regionserver is aborting.
66     * @param closeRegionCoordination consensus for closing regions
67     * @param crd object carrying details about region close task.
68     */
69    public CloseRegionHandler(final Server server,
70        final RegionServerServices rsServices,
71        final HRegionInfo regionInfo, final boolean abort,
72        CloseRegionCoordination closeRegionCoordination,
73        CloseRegionCoordination.CloseRegionDetails crd) {
74      this(server, rsServices,  regionInfo, abort, closeRegionCoordination, crd,
75        EventType.M_RS_CLOSE_REGION, null);
76    }
77  
78    public CloseRegionHandler(final Server server,
79        final RegionServerServices rsServices,
80        final HRegionInfo regionInfo, final boolean abort,
81        CloseRegionCoordination closeRegionCoordination,
82        CloseRegionCoordination.CloseRegionDetails crd,
83        ServerName destination) {
84      this(server, rsServices, regionInfo, abort, closeRegionCoordination, crd,
85        EventType.M_RS_CLOSE_REGION, destination);
86    }
87  
88    public CloseRegionHandler(final Server server,
89        final RegionServerServices rsServices, HRegionInfo regionInfo,
90        boolean abort, CloseRegionCoordination closeRegionCoordination,
91        CloseRegionCoordination.CloseRegionDetails crd, EventType eventType) {
92      this(server, rsServices, regionInfo, abort, closeRegionCoordination, crd, eventType, null);
93    }
94  
95      protected CloseRegionHandler(final Server server,
96        final RegionServerServices rsServices, HRegionInfo regionInfo,
97        boolean abort, CloseRegionCoordination closeRegionCoordination,
98        CloseRegionCoordination.CloseRegionDetails crd,
99        EventType eventType, ServerName destination) {
100     super(server, eventType);
101     this.server = server;
102     this.rsServices = rsServices;
103     this.regionInfo = regionInfo;
104     this.abort = abort;
105     this.destination = destination;
106     this.closeRegionCoordination = closeRegionCoordination;
107     this.closeRegionDetails = crd;
108     useZKForAssignment = ConfigUtil.useZKForAssignment(server.getConfiguration());
109   }
110 
111   public HRegionInfo getRegionInfo() {
112     return regionInfo;
113   }
114 
115   @Override
116   public void process() {
117     try {
118       String name = regionInfo.getRegionNameAsString();
119       LOG.debug("Processing close of " + name);
120       String encodedRegionName = regionInfo.getEncodedName();
121       // Check that this region is being served here
122       HRegion region = (HRegion)rsServices.getFromOnlineRegions(encodedRegionName);
123       if (region == null) {
124         LOG.warn("Received CLOSE for region " + name + " but currently not serving - ignoring");
125         // TODO: do better than a simple warning
126         return;
127       }
128 
129       // Close the region
130       try {
131         if (useZKForAssignment && closeRegionCoordination.checkClosingState(
132             regionInfo, closeRegionDetails)) {
133           return;
134         }
135 
136         // TODO: If we need to keep updating CLOSING stamp to prevent against
137         // a timeout if this is long-running, need to spin up a thread?
138         if (region.close(abort) == null) {
139           // This region got closed.  Most likely due to a split. So instead
140           // of doing the setClosedState() below, let's just ignore cont
141           // The split message will clean up the master state.
142           LOG.warn("Can't close region: was already closed during close(): " +
143             regionInfo.getRegionNameAsString());
144           return;
145         }
146       } catch (IOException ioe) {
147         // An IOException here indicates that we couldn't successfully flush the
148         // memstore before closing. So, we need to abort the server and allow
149         // the master to split our logs in order to recover the data.
150         server.abort("Unrecoverable exception while closing region " +
151           regionInfo.getRegionNameAsString() + ", still finishing close", ioe);
152         throw new RuntimeException(ioe);
153       }
154 
155       this.rsServices.removeFromOnlineRegions(region, destination);
156       if (!useZKForAssignment) {
157         rsServices.reportRegionStateTransition(TransitionCode.CLOSED, regionInfo);
158       } else {
159         closeRegionCoordination.setClosedState(region, this.server.getServerName(),
160           closeRegionDetails);
161       }
162 
163       // Done!  Region is closed on this RS
164       LOG.debug("Closed " + region.getRegionInfo().getRegionNameAsString());
165     } finally {
166       this.rsServices.getRegionsInTransitionInRS().
167           remove(this.regionInfo.getEncodedNameAsBytes());
168     }
169   }
170 }