001/** 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 */ 019package org.apache.hadoop.hbase.client; 020 021import java.io.IOException; 022import java.lang.management.ManagementFactory; 023 024import org.apache.yetus.audience.InterfaceAudience; 025import org.slf4j.Logger; 026import org.slf4j.LoggerFactory; 027import org.apache.hadoop.hbase.util.Addressing; 028import org.apache.hadoop.hbase.util.Bytes; 029 030/** 031 * The class that is able to determine some unique strings for the client, 032 * such as an IP address, PID, and composite deterministic ID. 033 */ 034@InterfaceAudience.Private 035final class ClientIdGenerator { 036 private static final Logger LOG = LoggerFactory.getLogger(ClientIdGenerator.class); 037 038 private ClientIdGenerator() {} 039 040 /** 041 * @return a unique ID incorporating IP address, PID, TID and timer. Might be an overkill... 042 * Note though that new UUID in java by default is just a random number. 043 */ 044 public static byte[] generateClientId() { 045 byte[] selfBytes = getIpAddressBytes(); 046 Long pid = getPid(); 047 long tid = Thread.currentThread().getId(); 048 long ts = System.currentTimeMillis(); 049 050 byte[] id = new byte[selfBytes.length + ((pid != null ? 1 : 0) + 2) * Bytes.SIZEOF_LONG]; 051 int offset = Bytes.putBytes(id, 0, selfBytes, 0, selfBytes.length); 052 if (pid != null) { 053 offset = Bytes.putLong(id, offset, pid); 054 } 055 offset = Bytes.putLong(id, offset, tid); 056 offset = Bytes.putLong(id, offset, ts); 057 assert offset == id.length; 058 return id; 059 } 060 061 /** 062 * @return PID of the current process, if it can be extracted from JVM name, or null. 063 */ 064 public static Long getPid() { 065 String name = ManagementFactory.getRuntimeMXBean().getName(); 066 String[] nameParts = name.split("@"); 067 if (nameParts.length == 2) { // 12345@somewhere 068 try { 069 return Long.parseLong(nameParts[0]); 070 } catch (NumberFormatException ex) { 071 LOG.warn("Failed to get PID from [" + name + "]", ex); 072 } 073 } else { 074 LOG.warn("Don't know how to get PID from [" + name + "]"); 075 } 076 return null; 077 } 078 079 /** 080 * @return Some IPv4/IPv6 address available on the current machine that is up, not virtual 081 * and not a loopback address. Empty array if none can be found or error occurred. 082 */ 083 public static byte[] getIpAddressBytes() { 084 try { 085 return Addressing.getIpAddress().getAddress(); 086 } catch (IOException ex) { 087 LOG.warn("Failed to get IP address bytes", ex); 088 } 089 return new byte[0]; 090 } 091}