View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.coordination;
19  
20  import org.apache.commons.logging.Log;
21  import org.apache.commons.logging.LogFactory;
22  import org.apache.hadoop.hbase.classification.InterfaceAudience;
23  import org.apache.hadoop.hbase.CoordinatedStateManager;
24  import org.apache.hadoop.hbase.HRegionInfo;
25  import org.apache.hadoop.hbase.ServerName;
26  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos;
27  import org.apache.hadoop.hbase.regionserver.HRegion;
28  import org.apache.hadoop.hbase.zookeeper.ZKAssign;
29  import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
30  import org.apache.zookeeper.KeeperException;
31  
32  import java.io.IOException;
33  
34  /**
35   * ZK-based implementation of {@link CloseRegionCoordination}.
36   */
37  @InterfaceAudience.Private
38  public class ZkCloseRegionCoordination implements CloseRegionCoordination {
39    private static final Log LOG = LogFactory.getLog(ZkCloseRegionCoordination.class);
40  
41    private final static int FAILED_VERSION = -1;
42  
43    private CoordinatedStateManager csm;
44    private final ZooKeeperWatcher watcher;
45  
46    public ZkCloseRegionCoordination(CoordinatedStateManager csm, ZooKeeperWatcher watcher) {
47      this.csm = csm;
48      this.watcher = watcher;
49    }
50  
51    /**
52     * In ZK-based version we're checking for bad znode state, e.g. if we're
53     * trying to delete the znode, and it's not ours (version doesn't match).
54     */
55    @Override
56    public boolean checkClosingState(HRegionInfo regionInfo, CloseRegionDetails crd) {
57      ZkCloseRegionDetails zkCrd = (ZkCloseRegionDetails) crd;
58  
59      try {
60        return zkCrd.isPublishStatusInZk() && !ZKAssign.checkClosingState(watcher,
61          regionInfo, ((ZkCloseRegionDetails) crd).getExpectedVersion());
62      } catch (KeeperException ke) {
63         csm.getServer().abort("Unrecoverable exception while checking state with zk " +
64            regionInfo.getRegionNameAsString() + ", still finishing close", ke);
65          throw new RuntimeException(ke);
66      }
67    }
68  
69    /**
70     * In ZK-based version we do some znodes transitioning.
71     */
72    @Override
73    public void setClosedState(HRegion region, ServerName sn, CloseRegionDetails crd) {
74      ZkCloseRegionDetails zkCrd = (ZkCloseRegionDetails) crd;
75      String name = region.getRegionInfo().getRegionNameAsString();
76  
77      if (zkCrd.isPublishStatusInZk()) {
78        if (setClosedState(region,sn, zkCrd)) {
79          LOG.debug("Set closed state in zk for " + name + " on " + sn);
80        } else {
81          LOG.debug("Set closed state in zk UNSUCCESSFUL for " + name + " on " + sn);
82        }
83      }
84    }
85  
86    /**
87     * Parse ZK-related fields from request.
88     */
89    @Override
90    public CloseRegionDetails parseFromProtoRequest(AdminProtos.CloseRegionRequest request) {
91      ZkCloseRegionCoordination.ZkCloseRegionDetails zkCrd =
92        new ZkCloseRegionCoordination.ZkCloseRegionDetails();
93      zkCrd.setPublishStatusInZk(request.getTransitionInZK());
94      int versionOfClosingNode = -1;
95      if (request.hasVersionOfClosingNode()) {
96        versionOfClosingNode = request.getVersionOfClosingNode();
97      }
98      zkCrd.setExpectedVersion(versionOfClosingNode);
99  
100     return zkCrd;
101   }
102 
103   /**
104    * No ZK tracking will be performed for that case.
105    * This method should be used when we want to construct CloseRegionDetails,
106    * but don't want any coordination on that (when it's initiated by regionserver),
107    * so no znode state transitions will be performed.
108    */
109   @Override
110   public CloseRegionDetails getDetaultDetails() {
111     ZkCloseRegionCoordination.ZkCloseRegionDetails zkCrd =
112       new ZkCloseRegionCoordination.ZkCloseRegionDetails();
113     zkCrd.setPublishStatusInZk(false);
114     zkCrd.setExpectedVersion(FAILED_VERSION);
115 
116     return zkCrd;
117   }
118 
119   /**
120    * Transition ZK node to CLOSED
121    * @param region HRegion instance being closed
122    * @param sn ServerName on which task runs
123    * @param zkCrd  details about region closing operation.
124    * @return If the state is set successfully
125    */
126   private boolean setClosedState(final HRegion region,
127                                  ServerName sn,
128                                  ZkCloseRegionDetails zkCrd) {
129     final int expectedVersion = zkCrd.getExpectedVersion();
130 
131     try {
132       if (ZKAssign.transitionNodeClosed(watcher, region.getRegionInfo(),
133         sn, expectedVersion) == FAILED_VERSION) {
134         LOG.warn("Completed the CLOSE of a region but when transitioning from " +
135           " CLOSING to CLOSED got a version mismatch, someone else clashed " +
136           "so now unassigning");
137         region.close();
138         return false;
139       }
140     } catch (NullPointerException e) {
141       // I've seen NPE when table was deleted while close was running in unit tests.
142       LOG.warn("NPE during close -- catching and continuing...", e);
143       return false;
144     } catch (KeeperException e) {
145       LOG.error("Failed transitioning node from CLOSING to CLOSED", e);
146       return false;
147     } catch (IOException e) {
148       LOG.error("Failed to close region after failing to transition", e);
149       return false;
150     }
151     return true;
152   }
153 
154   /**
155    * ZK-based implementation. Has details about whether the state transition should be
156    * reflected in ZK, as well as expected version of znode.
157    */
158   public static class ZkCloseRegionDetails implements CloseRegionCoordination.CloseRegionDetails {
159 
160     /**
161      * True if we are to update zk about the region close; if the close
162      * was orchestrated by master, then update zk.  If the close is being run by
163      * the regionserver because its going down, don't update zk.
164      * */
165     private boolean publishStatusInZk;
166 
167     /**
168      * The version of znode to compare when RS transitions the znode from
169      * CLOSING state.
170      */
171     private int expectedVersion = FAILED_VERSION;
172 
173     public ZkCloseRegionDetails() {
174     }
175 
176     public ZkCloseRegionDetails(boolean publishStatusInZk, int expectedVersion) {
177       this.publishStatusInZk = publishStatusInZk;
178       this.expectedVersion = expectedVersion;
179     }
180 
181     public boolean isPublishStatusInZk() {
182       return publishStatusInZk;
183     }
184 
185     public void setPublishStatusInZk(boolean publishStatusInZk) {
186       this.publishStatusInZk = publishStatusInZk;
187     }
188 
189     public int getExpectedVersion() {
190       return expectedVersion;
191     }
192 
193     public void setExpectedVersion(int expectedVersion) {
194       this.expectedVersion = expectedVersion;
195     }
196   }
197 }