View Javadoc

1   /**
2    * Copyright 2011 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase.regionserver;
21  
22  import static org.apache.hadoop.hbase.thrift.ThriftServerRunner.HBaseHandler.toBytes;
23  
24  import java.io.IOException;
25  import java.nio.ByteBuffer;
26  import java.util.List;
27  import java.util.Map;
28  
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  import org.apache.hadoop.conf.Configuration;
32  import org.apache.hadoop.hbase.HRegionLocation;
33  import org.apache.hadoop.hbase.KeyValue;
34  import org.apache.hadoop.hbase.NotServingRegionException;
35  import org.apache.hadoop.hbase.client.Get;
36  import org.apache.hadoop.hbase.client.HTable;
37  import org.apache.hadoop.hbase.client.Result;
38  import org.apache.hadoop.hbase.thrift.ThriftServerRunner;
39  import org.apache.hadoop.hbase.thrift.ThriftUtilities;
40  import org.apache.hadoop.hbase.thrift.generated.IOError;
41  import org.apache.hadoop.hbase.thrift.generated.TRowResult;
42  
43  /**
44   * HRegionThriftServer - this class starts up a Thrift server in the same
45   * JVM where the RegionServer is running. It inherits most of the
46   * functionality from the standard ThriftServer. This is good because
47   * we can maintain compatibility with applications that use the
48   * standard Thrift interface. For performance reasons, we can override
49   * methods to directly invoke calls into the HRegionServer and avoid the hop.
50   * <p>
51   * This can be enabled with <i>hbase.regionserver.export.thrift</i> set to true.
52   */
53  public class HRegionThriftServer extends Thread {
54  
55    public static final Log LOG = LogFactory.getLog(HRegionThriftServer.class);
56  
57    private final HRegionServer rs;
58    private final ThriftServerRunner serverRunner;
59  
60    /**
61     * Create an instance of the glue object that connects the
62     * RegionServer with the standard ThriftServer implementation
63     */
64    HRegionThriftServer(HRegionServer regionServer, Configuration conf)
65        throws IOException {
66      super("Region Thrift Server");
67      this.rs = regionServer;
68      this.serverRunner =
69          new ThriftServerRunner(conf, new HBaseHandlerRegion(conf));
70    }
71  
72    /**
73     * Stop ThriftServer
74     */
75    void shutdown() {
76      serverRunner.shutdown();
77    }
78  
79    @Override
80    public void run() {
81      serverRunner.run();
82    }
83  
84    /**
85     * Inherit the Handler from the standard ThriftServerRunner. This allows us
86     * to use the default implementation for most calls. We override certain calls
87     * for performance reasons
88     */
89    private class HBaseHandlerRegion extends ThriftServerRunner.HBaseHandler {
90  
91      /**
92       * Whether requests should be redirected to other RegionServers if the
93       * specified region is not hosted by this RegionServer.
94       */
95      private boolean redirect;
96  
97      HBaseHandlerRegion(final Configuration conf) throws IOException {
98        super(conf);
99        initialize(conf);
100     }
101 
102     /**
103      * Read and initialize config parameters
104      */
105     private void initialize(Configuration conf) {
106       this.redirect = conf.getBoolean("hbase.regionserver.thrift.redirect",
107           false);
108     }
109 
110     // TODO: Override more methods to short-circuit for performance
111 
112     /**
113      * Get a record. Short-circuit to get better performance.
114      */
115     @Override
116     public List<TRowResult> getRowWithColumnsTs(ByteBuffer tableName,
117                                                 ByteBuffer rowb,
118                                                 List<ByteBuffer> columns,
119                                                 long timestamp,
120       Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
121       try {
122         byte[] row = toBytes(rowb);
123         HTable table = getTable(toBytes(tableName));
124         HRegionLocation location = table.getRegionLocation(row, false);
125         byte[] regionName = location.getRegionInfo().getRegionName();
126 
127         if (columns == null) {
128           Get get = new Get(row);
129           get.setTimeRange(Long.MIN_VALUE, timestamp);
130           Result result = rs.get(regionName, get);
131           return ThriftUtilities.rowResultFromHBase(result);
132         }
133         Get get = new Get(row);
134         for(ByteBuffer column : columns) {
135           byte [][] famAndQf = KeyValue.parseColumn(toBytes(column));
136           if (famAndQf.length == 1) {
137             get.addFamily(famAndQf[0]);
138           } else {
139             get.addColumn(famAndQf[0], famAndQf[1]);
140           }
141         }
142         get.setTimeRange(Long.MIN_VALUE, timestamp);
143         Result result = rs.get(regionName, get);
144         return ThriftUtilities.rowResultFromHBase(result);
145       } catch (NotServingRegionException e) {
146         if (!redirect) {
147           LOG.warn(e.getMessage(), e);
148           throw new IOError(e.getMessage());
149         }
150         LOG.debug("ThriftServer redirecting getRowWithColumnsTs");
151         return super.getRowWithColumnsTs(tableName, rowb, columns, timestamp,
152                                          attributes);
153       } catch (IOException e) {
154         LOG.warn(e.getMessage(), e);
155         throw new IOError(e.getMessage());
156       }
157     }
158   }
159 }