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  
19  package org.apache.hadoop.hbase.thrift;
20  
21  import java.util.Arrays;
22  import java.util.List;
23  
24  import org.apache.commons.cli.CommandLine;
25  import org.apache.commons.cli.CommandLineParser;
26  import org.apache.commons.cli.HelpFormatter;
27  import org.apache.commons.cli.Options;
28  import org.apache.commons.cli.PosixParser;
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  import org.apache.hadoop.hbase.classification.InterfaceAudience;
32  import org.apache.hadoop.conf.Configuration;
33  import org.apache.hadoop.hbase.HBaseConfiguration;
34  import org.apache.hadoop.hbase.thrift.ThriftServerRunner.ImplType;
35  import org.apache.hadoop.hbase.util.InfoServer;
36  import org.apache.hadoop.hbase.util.VersionInfo;
37  import org.apache.hadoop.util.Shell.ExitCodeException;
38  
39  /**
40   * ThriftServer- this class starts up a Thrift server which implements the
41   * Hbase API specified in the Hbase.thrift IDL file. The server runs in an
42   * independent process.
43   */
44  @InterfaceAudience.Private
45  public class ThriftServer {
46  
47    private static final Log LOG = LogFactory.getLog(ThriftServer.class);
48  
49    private static final String MIN_WORKERS_OPTION = "minWorkers";
50    private static final String MAX_WORKERS_OPTION = "workers";
51    private static final String MAX_QUEUE_SIZE_OPTION = "queue";
52    private static final String KEEP_ALIVE_SEC_OPTION = "keepAliveSec";
53    static final String BIND_OPTION = "bind";
54    static final String COMPACT_OPTION = "compact";
55    static final String FRAMED_OPTION = "framed";
56    static final String PORT_OPTION = "port";
57  
58    private static final String DEFAULT_BIND_ADDR = "0.0.0.0";
59    private static final int DEFAULT_LISTEN_PORT = 9090;
60  
61    private Configuration conf;
62    ThriftServerRunner serverRunner;
63  
64    private InfoServer infoServer;
65  
66    private static final String READ_TIMEOUT_OPTION = "readTimeout";
67  
68    //
69    // Main program and support routines
70    //
71  
72    public ThriftServer(Configuration conf) {
73      this.conf = HBaseConfiguration.create(conf);
74    }
75  
76    private static void printUsageAndExit(Options options, int exitCode)
77        throws ExitCodeException {
78      HelpFormatter formatter = new HelpFormatter();
79      formatter.printHelp("Thrift", null, options,
80          "To start the Thrift server run 'bin/hbase-daemon.sh start thrift'\n" +
81          "To shutdown the thrift server run 'bin/hbase-daemon.sh stop " +
82          "thrift' or send a kill signal to the thrift server pid",
83          true);
84      throw new ExitCodeException(exitCode, "");
85    }
86  
87    /**
88     * Start up or shuts down the Thrift server, depending on the arguments.
89     * @param args
90     */
91     void doMain(final String[] args) throws Exception {
92       processOptions(args);
93  
94       serverRunner = new ThriftServerRunner(conf);
95  
96       // Put up info server.
97       int port = conf.getInt("hbase.thrift.info.port", 9095);
98       if (port >= 0) {
99         conf.setLong("startcode", System.currentTimeMillis());
100        String a = conf.get("hbase.thrift.info.bindAddress", "0.0.0.0");
101        infoServer = new InfoServer("thrift", a, port, false, conf);
102        infoServer.setAttribute("hbase.conf", conf);
103        infoServer.start();
104      }
105      serverRunner.run();
106   }
107 
108   /**
109    * Parse the command line options to set parameters the conf.
110    */
111   private void processOptions(final String[] args) throws Exception {
112     Options options = new Options();
113     options.addOption("b", BIND_OPTION, true, "Address to bind " +
114         "the Thrift server to. [default: " + DEFAULT_BIND_ADDR + "]");
115     options.addOption("p", PORT_OPTION, true, "Port to bind to [default: " +
116         DEFAULT_LISTEN_PORT + "]");
117     options.addOption("f", FRAMED_OPTION, false, "Use framed transport");
118     options.addOption("c", COMPACT_OPTION, false, "Use the compact protocol");
119     options.addOption("h", "help", false, "Print help information");
120     options.addOption(null, "infoport", true, "Port for web UI");
121 
122     options.addOption("m", MIN_WORKERS_OPTION, true,
123         "The minimum number of worker threads for " +
124         ImplType.THREAD_POOL.simpleClassName());
125 
126     options.addOption("w", MAX_WORKERS_OPTION, true,
127         "The maximum number of worker threads for " +
128         ImplType.THREAD_POOL.simpleClassName());
129 
130     options.addOption("q", MAX_QUEUE_SIZE_OPTION, true,
131         "The maximum number of queued requests in " +
132         ImplType.THREAD_POOL.simpleClassName());
133 
134     options.addOption("k", KEEP_ALIVE_SEC_OPTION, true,
135         "The amount of time in secods to keep a thread alive when idle in " +
136         ImplType.THREAD_POOL.simpleClassName());
137 
138     options.addOption("t", READ_TIMEOUT_OPTION, true,
139         "Amount of time in milliseconds before a server thread will timeout " +
140         "waiting for client to send data on a connected socket. Currently, " +
141         "only applies to TBoundedThreadPoolServer");
142 
143     options.addOptionGroup(ImplType.createOptionGroup());
144 
145     CommandLineParser parser = new PosixParser();
146     CommandLine cmd = parser.parse(options, args);
147 
148     // This is so complicated to please both bin/hbase and bin/hbase-daemon.
149     // hbase-daemon provides "start" and "stop" arguments
150     // hbase should print the help if no argument is provided
151     List<String> commandLine = Arrays.asList(args);
152     boolean stop = commandLine.contains("stop");
153     boolean start = commandLine.contains("start");
154     boolean invalidStartStop = (start && stop) || (!start && !stop);
155     if (cmd.hasOption("help") || invalidStartStop) {
156       if (invalidStartStop) {
157         LOG.error("Exactly one of 'start' and 'stop' has to be specified");
158       }
159       printUsageAndExit(options, 1);
160     }
161 
162     // Get port to bind to
163     try {
164       if (cmd.hasOption(PORT_OPTION)) {
165         int listenPort = Integer.parseInt(cmd.getOptionValue(PORT_OPTION));
166         conf.setInt(ThriftServerRunner.PORT_CONF_KEY, listenPort);
167       }
168     } catch (NumberFormatException e) {
169       LOG.error("Could not parse the value provided for the port option", e);
170       printUsageAndExit(options, -1);
171     }
172 
173     // check for user-defined info server port setting, if so override the conf
174     try {
175       if (cmd.hasOption("infoport")) {
176         String val = cmd.getOptionValue("infoport");
177         conf.setInt("hbase.thrift.info.port", Integer.valueOf(val));
178         LOG.debug("Web UI port set to " + val);
179       }
180     } catch (NumberFormatException e) {
181       LOG.error("Could not parse the value provided for the infoport option", e);
182       printUsageAndExit(options, -1);
183     }
184 
185     // Make optional changes to the configuration based on command-line options
186     optionToConf(cmd, MIN_WORKERS_OPTION,
187         conf, TBoundedThreadPoolServer.MIN_WORKER_THREADS_CONF_KEY);
188     optionToConf(cmd, MAX_WORKERS_OPTION,
189         conf, TBoundedThreadPoolServer.MAX_WORKER_THREADS_CONF_KEY);
190     optionToConf(cmd, MAX_QUEUE_SIZE_OPTION,
191         conf, TBoundedThreadPoolServer.MAX_QUEUED_REQUESTS_CONF_KEY);
192     optionToConf(cmd, KEEP_ALIVE_SEC_OPTION,
193         conf, TBoundedThreadPoolServer.THREAD_KEEP_ALIVE_TIME_SEC_CONF_KEY);
194     optionToConf(cmd, READ_TIMEOUT_OPTION, conf,
195         ThriftServerRunner.THRIFT_SERVER_SOCKET_READ_TIMEOUT_KEY);
196     
197     // Set general thrift server options
198     boolean compact = cmd.hasOption(COMPACT_OPTION) ||
199       conf.getBoolean(ThriftServerRunner.COMPACT_CONF_KEY, false);
200     conf.setBoolean(ThriftServerRunner.COMPACT_CONF_KEY, compact);
201     boolean framed = cmd.hasOption(FRAMED_OPTION) ||
202       conf.getBoolean(ThriftServerRunner.FRAMED_CONF_KEY, false);
203     conf.setBoolean(ThriftServerRunner.FRAMED_CONF_KEY, framed);
204     if (cmd.hasOption(BIND_OPTION)) {
205       conf.set(ThriftServerRunner.BIND_CONF_KEY, cmd.getOptionValue(BIND_OPTION));
206     }
207 
208     ImplType.setServerImpl(cmd, conf);
209   }
210 
211   public void stop() {
212     if (this.infoServer != null) {
213       LOG.info("Stopping infoServer");
214       try {
215         this.infoServer.stop();
216       } catch (Exception ex) {
217         ex.printStackTrace();
218       }
219     }
220     serverRunner.shutdown();
221   }
222 
223   private static void optionToConf(CommandLine cmd, String option,
224       Configuration conf, String destConfKey) {
225     if (cmd.hasOption(option)) {
226       String value = cmd.getOptionValue(option);
227       LOG.info("Set configuration key:" + destConfKey + " value:" + value);
228       conf.set(destConfKey, value);
229     }
230   }
231 
232   /**
233    * @param args
234    * @throws Exception
235    */
236   public static void main(String [] args) throws Exception {
237     VersionInfo.logVersion();
238     try {
239       new ThriftServer(HBaseConfiguration.create()).doMain(args);
240     } catch (ExitCodeException ex) {
241       System.exit(ex.getExitCode());
242     }
243   }
244 }