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.client;
19  
20  import java.io.IOException;
21  import java.net.InetSocketAddress;
22  
23  import org.apache.hadoop.conf.Configuration;
24  import org.apache.hadoop.hbase.CoprocessorEnvironment;
25  import org.apache.hadoop.hbase.ServerName;
26  import org.apache.hadoop.hbase.client.HConnectionManager.HConnectionImplementation;
27  import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
28  import org.apache.hadoop.hbase.ipc.HRegionInterface;
29  import org.apache.hadoop.hbase.regionserver.HRegionServer;
30  import org.apache.hadoop.hbase.regionserver.RegionServerServices;
31  
32  /**
33   * Connection to an HTable from within a Coprocessor. Can do some nice tricks since we know we are
34   * on a regionserver.
35   * <p>
36   * This shouldn't be used by usual HBase clients - its merely in this package to maintain visibility
37   * considerations for the {@link HConnectionImplementation}.
38   */
39  @SuppressWarnings("javadoc")
40  public class CoprocessorHConnection extends HConnectionManager.HConnectionImplementation {
41  
42    /**
43     * Create an unmanaged {@link HConnection} based on the environment in which we are running the
44     * coprocessor. The {@link HConnection} must be externally cleaned up (we bypass the usual HTable
45     * cleanup mechanisms since we own everything).
46     * @param env environment hosting the {@link HConnection}
47     * @return an unmanaged {@link HConnection}.
48     * @throws IOException if we cannot create the basic connection
49     */
50    @SuppressWarnings("resource")
51    public static HConnection getConnectionForEnvironment(CoprocessorEnvironment env)
52        throws IOException {
53      Configuration conf = env.getConfiguration();
54      HConnection connection = null;
55      // this bit is a little hacky - we need to reach kind far into the internals. However, since we
56      // are in a coprocessor (which is part of the internals), this is more ok.
57      if (env instanceof RegionCoprocessorEnvironment) {
58        RegionCoprocessorEnvironment e = (RegionCoprocessorEnvironment) env;
59        RegionServerServices services = e.getRegionServerServices();
60        if (services instanceof HRegionServer) {
61          connection = new CoprocessorHConnection(conf, (HRegionServer) services);
62        }
63      }
64      // didn't create the custom HConnection, so just create the usual connection. Saves us some conf
65      // lookups, but no network accesses or anything else with excessive overhead.
66      if (connection == null) {
67        connection = HConnectionManager.createConnection(conf);
68      }
69      return connection;
70    }
71  
72    private ServerName serverName;
73    private HRegionServer server;
74  
75    CoprocessorHConnection(Configuration conf, HRegionServer server) throws IOException {
76      super(conf, false, null);
77      this.server = server;
78      this.serverName = server.getServerName();
79    }
80  
81    @Override
82    HRegionInterface getHRegionConnection(final String hostname, final int port,
83        final InetSocketAddress isa, final boolean master) throws IOException {
84      // check to see where the server is running
85      // need this isa stuff here since its what the HConnectionManager is doing too
86      boolean isRemote = false;
87      if (isa != null) {
88        isRemote = checkRemote(isa.getHostName(), isa.getPort());
89      } else {
90        isRemote = checkRemote(hostname, port);
91      }
92      // if we aren't talking to the local HRegionServer, then do the usual thing
93      if (isRemote) {
94        return super.getHRegionConnection(hostname, port, isa, master);
95      }
96  
97      // local access, so just pass the actual server, rather than a proxy
98      return this.server;
99    }
100 
101   /**
102    * Check that the hostname and port map the the server on which we are currently running
103    * @param hostName hostname to check
104    * @param port port to check
105    * @return <tt>true</tt> the connection is <b>not</b> currently running on the given host and port
106    */
107   private boolean checkRemote(String hostName, int port) {
108     return !(this.serverName.getHostname().equals(hostName) && this.serverName.getPort() == port);
109   }
110 }