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.client;
20  
21  import java.io.IOException;
22  import java.lang.management.ManagementFactory;
23  import java.net.Inet4Address;
24  import java.net.Inet6Address;
25  import java.net.InetAddress;
26  import java.net.NetworkInterface;
27  import java.util.Enumeration;
28  
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.hbase.util.Bytes;
33  
34  /**
35   * The class that is able to determine some unique strings for the client,
36   * such as an IP address, PID, and composite deterministic ID.
37   */
38  @InterfaceAudience.Private
39  class ClientIdGenerator {
40    static final Log LOG = LogFactory.getLog(ClientIdGenerator.class);
41  
42    /**
43     * @return a unique ID incorporating IP address, PID, TID and timer. Might be an overkill...
44     * Note though that new UUID in java by default is just a random number.
45     */
46    public static byte[] generateClientId() {
47      byte[] selfBytes = getIpAddressBytes();
48      Long pid = getPid();
49      long tid = Thread.currentThread().getId();
50      long ts = System.currentTimeMillis();
51  
52      byte[] id = new byte[selfBytes.length + ((pid != null ? 1 : 0) + 2) * Bytes.SIZEOF_LONG];
53      int offset = Bytes.putBytes(id, 0, selfBytes, 0, selfBytes.length);
54      if (pid != null) {
55        offset = Bytes.putLong(id, offset, pid);
56      }
57      offset = Bytes.putLong(id, offset, tid);
58      offset = Bytes.putLong(id, offset, ts);
59      assert offset == id.length;
60      return id;
61    }
62  
63    /**
64     * @return PID of the current process, if it can be extracted from JVM name, or null.
65     */
66    public static Long getPid() {
67      String name = ManagementFactory.getRuntimeMXBean().getName();
68      String[] nameParts = name.split("@");
69      if (nameParts.length == 2) { // 12345@somewhere
70        try {
71          return Long.parseLong(nameParts[0]);
72        } catch (NumberFormatException ex) {
73          LOG.warn("Failed to get PID from [" + name + "]", ex);
74        }
75      } else {
76        LOG.warn("Don't know how to get PID from [" + name + "]");
77      }
78      return null;
79    }
80  
81    /**
82     * @return Some IPv4/IPv6 address available on the current machine that is up, not virtual
83     *         and not a loopback address. Empty array if none can be found or error occured.
84     */
85    public static byte[] getIpAddressBytes() {
86      try {
87        // Before we connect somewhere, we cannot be sure about what we'd be bound to; however,
88        // we only connect when the message where client ID is, is long constructed. Thus,
89        // just use whichever IP address we can find.
90        Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
91        while (interfaces.hasMoreElements()) {
92          NetworkInterface current = interfaces.nextElement();
93          if (!current.isUp() || current.isLoopback() || current.isVirtual()) continue;
94          Enumeration<InetAddress> addresses = current.getInetAddresses();
95          while (addresses.hasMoreElements()) {
96            InetAddress addr = addresses.nextElement();
97            if (addr.isLoopbackAddress()) continue;
98            if (addr instanceof Inet4Address || addr instanceof Inet6Address) {
99              return addr.getAddress();
100           }
101         }
102       }
103     } catch (IOException ex) {
104       LOG.warn("Failed to get IP address bytes", ex);
105     }
106     return new byte[0];
107   }
108 }