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.master;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.util.List;
24  
25  import org.apache.commons.cli.CommandLine;
26  import org.apache.commons.cli.GnuParser;
27  import org.apache.commons.cli.Options;
28  import org.apache.commons.cli.ParseException;
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  import org.apache.hadoop.classification.InterfaceAudience;
32  import org.apache.hadoop.conf.Configuration;
33  import org.apache.hadoop.hbase.MasterNotRunningException;
34  import org.apache.hadoop.hbase.ZNodeClearer;
35  import org.apache.hadoop.hbase.HConstants;
36  import org.apache.hadoop.hbase.LocalHBaseCluster;
37  import org.apache.hadoop.hbase.ZooKeeperConnectionException;
38  import org.apache.hadoop.hbase.client.HBaseAdmin;
39  import org.apache.hadoop.hbase.regionserver.HRegionServer;
40  import org.apache.hadoop.hbase.util.JVMClusterUtil;
41  import org.apache.hadoop.hbase.util.ServerCommandLine;
42  import org.apache.hadoop.hbase.zookeeper.MiniZooKeeperCluster;
43  import org.apache.hadoop.hbase.zookeeper.ZKUtil;
44  import org.apache.zookeeper.KeeperException;
45  
46  @InterfaceAudience.Private
47  public class HMasterCommandLine extends ServerCommandLine {
48    private static final Log LOG = LogFactory.getLog(HMasterCommandLine.class);
49  
50    private static final String USAGE =
51      "Usage: Master [opts] start|stop|clear\n" +
52      " start  Start Master. If local mode, start Master and RegionServer in same JVM\n" +
53      " stop   Start cluster shutdown; Master signals RegionServer shutdown\n" +
54      " clear  Delete the master znode in ZooKeeper after a master crashes\n "+
55      " where [opts] are:\n" +
56      "   --minRegionServers=<servers>   Minimum RegionServers needed to host user tables.\n" +
57      "   --localRegionServers=<servers> " +
58        "RegionServers to start in master process when in standalone mode.\n" +
59      "   --masters=<servers>            Masters to start in this process.\n" +
60      "   --backup                       Master should start in backup mode";
61  
62    private final Class<? extends HMaster> masterClass;
63  
64    public HMasterCommandLine(Class<? extends HMaster> masterClass) {
65      this.masterClass = masterClass;
66    }
67  
68    protected String getUsage() {
69      return USAGE;
70    }
71  
72  
73    public int run(String args[]) throws Exception {
74      Options opt = new Options();
75      opt.addOption("localRegionServers", true,
76        "RegionServers to start in master process when running standalone");
77      opt.addOption("masters", true, "Masters to start in this process");
78      opt.addOption("minRegionServers", true, "Minimum RegionServers needed to host user tables");
79      opt.addOption("backup", false, "Do not try to become HMaster until the primary fails");
80  
81      CommandLine cmd;
82      try {
83        cmd = new GnuParser().parse(opt, args);
84      } catch (ParseException e) {
85        LOG.error("Could not parse: ", e);
86        usage(null);
87        return 1;
88      }
89  
90  
91      if (cmd.hasOption("minRegionServers")) {
92        String val = cmd.getOptionValue("minRegionServers");
93        getConf().setInt("hbase.regions.server.count.min",
94                    Integer.valueOf(val));
95        LOG.debug("minRegionServers set to " + val);
96      }
97  
98      // minRegionServers used to be minServers.  Support it too.
99      if (cmd.hasOption("minServers")) {
100       String val = cmd.getOptionValue("minServers");
101       getConf().setInt("hbase.regions.server.count.min",
102                   Integer.valueOf(val));
103       LOG.debug("minServers set to " + val);
104     }
105 
106     // check if we are the backup master - override the conf if so
107     if (cmd.hasOption("backup")) {
108       getConf().setBoolean(HConstants.MASTER_TYPE_BACKUP, true);
109     }
110 
111     // How many regionservers to startup in this process (we run regionservers in same process as
112     // master when we are in local/standalone mode. Useful testing)
113     if (cmd.hasOption("localRegionServers")) {
114       String val = cmd.getOptionValue("localRegionServers");
115       getConf().setInt("hbase.regionservers", Integer.valueOf(val));
116       LOG.debug("localRegionServers set to " + val);
117     }
118     // How many masters to startup inside this process; useful testing
119     if (cmd.hasOption("masters")) {
120       String val = cmd.getOptionValue("masters");
121       getConf().setInt("hbase.masters", Integer.valueOf(val));
122       LOG.debug("masters set to " + val);
123     }
124 
125     List<String> remainingArgs = cmd.getArgList();
126     if (remainingArgs.size() != 1) {
127       usage(null);
128       return 1;
129     }
130 
131     String command = remainingArgs.get(0);
132 
133     if ("start".equals(command)) {
134       return startMaster();
135     } else if ("stop".equals(command)) {
136       return stopMaster();
137     } else if ("clear".equals(command)) {
138       return (ZNodeClearer.clear(getConf()) ? 0 : 1);
139     } else {
140       usage("Invalid command: " + command);
141       return 1;
142     }
143   }
144 
145   private int startMaster() {
146     Configuration conf = getConf();
147     try {
148       // If 'local', defer to LocalHBaseCluster instance.  Starts master
149       // and regionserver both in the one JVM.
150       if (LocalHBaseCluster.isLocal(conf)) {
151         final MiniZooKeeperCluster zooKeeperCluster = new MiniZooKeeperCluster(conf);
152         File zkDataPath = new File(conf.get(HConstants.ZOOKEEPER_DATA_DIR));
153         int zkClientPort = conf.getInt(HConstants.ZOOKEEPER_CLIENT_PORT, 0);
154         if (zkClientPort == 0) {
155           throw new IOException("No config value for "
156               + HConstants.ZOOKEEPER_CLIENT_PORT);
157         }
158         zooKeeperCluster.setDefaultClientPort(zkClientPort);
159 
160         // login the zookeeper server principal (if using security)
161         ZKUtil.loginServer(conf, "hbase.zookeeper.server.keytab.file",
162           "hbase.zookeeper.server.kerberos.principal", null);
163 
164         int clientPort = zooKeeperCluster.startup(zkDataPath);
165         if (clientPort != zkClientPort) {
166           String errorMsg = "Could not start ZK at requested port of " +
167             zkClientPort + ".  ZK was started at port: " + clientPort +
168             ".  Aborting as clients (e.g. shell) will not be able to find " +
169             "this ZK quorum.";
170           System.err.println(errorMsg);
171           throw new IOException(errorMsg);
172         }
173         conf.set(HConstants.ZOOKEEPER_CLIENT_PORT,
174                  Integer.toString(clientPort));
175         // Need to have the zk cluster shutdown when master is shutdown.
176         // Run a subclass that does the zk cluster shutdown on its way out.
177         LocalHBaseCluster cluster = new LocalHBaseCluster(conf, conf.getInt("hbase.masters", 1),
178           conf.getInt("hbase.regionservers", 1), LocalHMaster.class, HRegionServer.class);
179         ((LocalHMaster)cluster.getMaster(0)).setZKCluster(zooKeeperCluster);
180         cluster.startup();
181         waitOnMasterThreads(cluster);
182       } else {
183         logProcessInfo(getConf());
184         HMaster master = HMaster.constructMaster(masterClass, conf);
185         if (master.isStopped()) {
186           LOG.info("Won't bring the Master up as a shutdown is requested");
187           return 1;
188         }
189         master.start();
190         master.join();
191         if(master.isAborted())
192           throw new RuntimeException("HMaster Aborted");
193       }
194     } catch (Throwable t) {
195       LOG.error("Master exiting", t);
196       return 1;
197     }
198     return 0;
199   }
200 
201   private int stopMaster() {
202     HBaseAdmin adm = null;
203     try {
204       Configuration conf = getConf();
205       // Don't try more than once
206       conf.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 1);
207       adm = new HBaseAdmin(getConf());
208     } catch (MasterNotRunningException e) {
209       LOG.error("Master not running");
210       return 1;
211     } catch (ZooKeeperConnectionException e) {
212       LOG.error("ZooKeeper not available");
213       return 1;
214     } catch (IOException e) {
215       LOG.error("Got IOException: " +e.getMessage(), e);
216       return 1;
217     }
218     try {
219       adm.shutdown();
220     } catch (Throwable t) {
221       LOG.error("Failed to stop master", t);
222       return 1;
223     }
224     return 0;
225   }
226 
227   private void waitOnMasterThreads(LocalHBaseCluster cluster) throws InterruptedException{
228     List<JVMClusterUtil.MasterThread> masters = cluster.getMasters();
229     List<JVMClusterUtil.RegionServerThread> regionservers = cluster.getRegionServers();
230 
231     if (masters != null) {
232       for (JVMClusterUtil.MasterThread t : masters) {
233         t.join();
234         if(t.getMaster().isAborted()) {
235           closeAllRegionServerThreads(regionservers);
236           throw new RuntimeException("HMaster Aborted");
237         }
238       }
239     }
240   }
241 
242   private static void closeAllRegionServerThreads(List<JVMClusterUtil.RegionServerThread> regionservers) {
243     for(JVMClusterUtil.RegionServerThread t : regionservers){
244       t.getRegionServer().stop("HMaster Aborted; Bringing down regions servers");
245     }
246   }
247 
248   /*
249    * Version of master that will shutdown the passed zk cluster on its way out.
250    */
251   public static class LocalHMaster extends HMaster {
252     private MiniZooKeeperCluster zkcluster = null;
253 
254     public LocalHMaster(Configuration conf)
255     throws IOException, KeeperException, InterruptedException {
256       super(conf);
257     }
258 
259     @Override
260     public void run() {
261       super.run();
262       if (this.zkcluster != null) {
263         try {
264           this.zkcluster.shutdown();
265         } catch (IOException e) {
266           e.printStackTrace();
267         }
268       }
269     }
270 
271     void setZKCluster(final MiniZooKeeperCluster zkcluster) {
272       this.zkcluster = zkcluster;
273     }
274   }
275 }