You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by te...@apache.org on 2015/04/01 15:47:37 UTC

hbase git commit: HBASE-12954 Ability impaired using HBase on multihomed hosts

Repository: hbase
Updated Branches:
  refs/heads/branch-1 394b46093 -> 4df24b8e6


HBASE-12954 Ability impaired using HBase on multihomed hosts


Project: http://git-wip-us.apache.org/repos/asf/hbase/repo
Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/4df24b8e
Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/4df24b8e
Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/4df24b8e

Branch: refs/heads/branch-1
Commit: 4df24b8e6dda59f71cbfc88ce7062a73329730de
Parents: 394b460
Author: tedyu <yu...@gmail.com>
Authored: Wed Apr 1 06:47:26 2015 -0700
Committer: tedyu <yu...@gmail.com>
Committed: Wed Apr 1 06:47:26 2015 -0700

----------------------------------------------------------------------
 .../src/main/resources/hbase-default.xml        |   7 +
 .../generated/RegionServerStatusProtos.java     | 300 ++++++++++++++++---
 .../src/main/protobuf/RegionServerStatus.proto  |   3 +
 .../hadoop/hbase/master/MasterRpcServices.java  |   5 +-
 .../hadoop/hbase/master/ServerManager.java      |  20 +-
 .../hbase/regionserver/HRegionServer.java       |  41 ++-
 .../hbase/regionserver/RSRpcServices.java       |  12 +-
 .../hbase/master/TestClockSkewDetection.java    |  32 +-
 .../regionserver/TestRegionServerHostname.java  | 103 +++++++
 9 files changed, 455 insertions(+), 68 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hbase/blob/4df24b8e/hbase-common/src/main/resources/hbase-default.xml
----------------------------------------------------------------------
diff --git a/hbase-common/src/main/resources/hbase-default.xml b/hbase-common/src/main/resources/hbase-default.xml
index df1894b..db99f12 100644
--- a/hbase-common/src/main/resources/hbase-default.xml
+++ b/hbase-common/src/main/resources/hbase-default.xml
@@ -817,6 +817,13 @@ possible configurations would overwhelm and obscure the important.
     <description>Set no delay on rpc socket connections.  See
     http://docs.oracle.com/javase/1.5.0/docs/api/java/net/Socket.html#getTcpNoDelay()</description>
   </property>
+  <property>
+    <name>hbase.regionserver.hostname</name>
+    <value></value>
+    <description>This config is for experts: don't set its value unless you really know what you are doing.
+    When set to a non-empty value, this represents the (external facing) hostname for the underlying server.
+    See https://issues.apache.org/jira/browse/HBASE-12954 for details.</description>
+  </property>
   <!-- The following properties configure authentication information for
        HBase processes when using Kerberos security.  There are no default
        values, included here for documentation purposes -->

http://git-wip-us.apache.org/repos/asf/hbase/blob/4df24b8e/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/RegionServerStatusProtos.java
----------------------------------------------------------------------
diff --git a/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/RegionServerStatusProtos.java b/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/RegionServerStatusProtos.java
index 1a4e1a5..a8cd58a 100644
--- a/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/RegionServerStatusProtos.java
+++ b/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/RegionServerStatusProtos.java
@@ -64,6 +64,33 @@ public final class RegionServerStatusProtos {
      * </pre>
      */
     long getServerCurrentTime();
+
+    // optional string use_this_hostname_instead = 4;
+    /**
+     * <code>optional string use_this_hostname_instead = 4;</code>
+     *
+     * <pre>
+     ** hostname for region server, optional 
+     * </pre>
+     */
+    boolean hasUseThisHostnameInstead();
+    /**
+     * <code>optional string use_this_hostname_instead = 4;</code>
+     *
+     * <pre>
+     ** hostname for region server, optional 
+     * </pre>
+     */
+    java.lang.String getUseThisHostnameInstead();
+    /**
+     * <code>optional string use_this_hostname_instead = 4;</code>
+     *
+     * <pre>
+     ** hostname for region server, optional 
+     * </pre>
+     */
+    com.google.protobuf.ByteString
+        getUseThisHostnameInsteadBytes();
   }
   /**
    * Protobuf type {@code RegionServerStartupRequest}
@@ -131,6 +158,11 @@ public final class RegionServerStatusProtos {
               serverCurrentTime_ = input.readUInt64();
               break;
             }
+            case 34: {
+              bitField0_ |= 0x00000008;
+              useThisHostnameInstead_ = input.readBytes();
+              break;
+            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -243,10 +275,66 @@ public final class RegionServerStatusProtos {
       return serverCurrentTime_;
     }
 
+    // optional string use_this_hostname_instead = 4;
+    public static final int USE_THIS_HOSTNAME_INSTEAD_FIELD_NUMBER = 4;
+    private java.lang.Object useThisHostnameInstead_;
+    /**
+     * <code>optional string use_this_hostname_instead = 4;</code>
+     *
+     * <pre>
+     ** hostname for region server, optional 
+     * </pre>
+     */
+    public boolean hasUseThisHostnameInstead() {
+      return ((bitField0_ & 0x00000008) == 0x00000008);
+    }
+    /**
+     * <code>optional string use_this_hostname_instead = 4;</code>
+     *
+     * <pre>
+     ** hostname for region server, optional 
+     * </pre>
+     */
+    public java.lang.String getUseThisHostnameInstead() {
+      java.lang.Object ref = useThisHostnameInstead_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        if (bs.isValidUtf8()) {
+          useThisHostnameInstead_ = s;
+        }
+        return s;
+      }
+    }
+    /**
+     * <code>optional string use_this_hostname_instead = 4;</code>
+     *
+     * <pre>
+     ** hostname for region server, optional 
+     * </pre>
+     */
+    public com.google.protobuf.ByteString
+        getUseThisHostnameInsteadBytes() {
+      java.lang.Object ref = useThisHostnameInstead_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        useThisHostnameInstead_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
     private void initFields() {
       port_ = 0;
       serverStartCode_ = 0L;
       serverCurrentTime_ = 0L;
+      useThisHostnameInstead_ = "";
     }
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
@@ -281,6 +369,9 @@ public final class RegionServerStatusProtos {
       if (((bitField0_ & 0x00000004) == 0x00000004)) {
         output.writeUInt64(3, serverCurrentTime_);
       }
+      if (((bitField0_ & 0x00000008) == 0x00000008)) {
+        output.writeBytes(4, getUseThisHostnameInsteadBytes());
+      }
       getUnknownFields().writeTo(output);
     }
 
@@ -302,6 +393,10 @@ public final class RegionServerStatusProtos {
         size += com.google.protobuf.CodedOutputStream
           .computeUInt64Size(3, serverCurrentTime_);
       }
+      if (((bitField0_ & 0x00000008) == 0x00000008)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(4, getUseThisHostnameInsteadBytes());
+      }
       size += getUnknownFields().getSerializedSize();
       memoizedSerializedSize = size;
       return size;
@@ -340,6 +435,11 @@ public final class RegionServerStatusProtos {
         result = result && (getServerCurrentTime()
             == other.getServerCurrentTime());
       }
+      result = result && (hasUseThisHostnameInstead() == other.hasUseThisHostnameInstead());
+      if (hasUseThisHostnameInstead()) {
+        result = result && getUseThisHostnameInstead()
+            .equals(other.getUseThisHostnameInstead());
+      }
       result = result &&
           getUnknownFields().equals(other.getUnknownFields());
       return result;
@@ -365,6 +465,10 @@ public final class RegionServerStatusProtos {
         hash = (37 * hash) + SERVER_CURRENT_TIME_FIELD_NUMBER;
         hash = (53 * hash) + hashLong(getServerCurrentTime());
       }
+      if (hasUseThisHostnameInstead()) {
+        hash = (37 * hash) + USE_THIS_HOSTNAME_INSTEAD_FIELD_NUMBER;
+        hash = (53 * hash) + getUseThisHostnameInstead().hashCode();
+      }
       hash = (29 * hash) + getUnknownFields().hashCode();
       memoizedHashCode = hash;
       return hash;
@@ -480,6 +584,8 @@ public final class RegionServerStatusProtos {
         bitField0_ = (bitField0_ & ~0x00000002);
         serverCurrentTime_ = 0L;
         bitField0_ = (bitField0_ & ~0x00000004);
+        useThisHostnameInstead_ = "";
+        bitField0_ = (bitField0_ & ~0x00000008);
         return this;
       }
 
@@ -520,6 +626,10 @@ public final class RegionServerStatusProtos {
           to_bitField0_ |= 0x00000004;
         }
         result.serverCurrentTime_ = serverCurrentTime_;
+        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {
+          to_bitField0_ |= 0x00000008;
+        }
+        result.useThisHostnameInstead_ = useThisHostnameInstead_;
         result.bitField0_ = to_bitField0_;
         onBuilt();
         return result;
@@ -545,6 +655,11 @@ public final class RegionServerStatusProtos {
         if (other.hasServerCurrentTime()) {
           setServerCurrentTime(other.getServerCurrentTime());
         }
+        if (other.hasUseThisHostnameInstead()) {
+          bitField0_ |= 0x00000008;
+          useThisHostnameInstead_ = other.useThisHostnameInstead_;
+          onChanged();
+        }
         this.mergeUnknownFields(other.getUnknownFields());
         return this;
       }
@@ -731,6 +846,104 @@ public final class RegionServerStatusProtos {
         return this;
       }
 
+      // optional string use_this_hostname_instead = 4;
+      private java.lang.Object useThisHostnameInstead_ = "";
+      /**
+       * <code>optional string use_this_hostname_instead = 4;</code>
+       *
+       * <pre>
+       ** hostname for region server, optional 
+       * </pre>
+       */
+      public boolean hasUseThisHostnameInstead() {
+        return ((bitField0_ & 0x00000008) == 0x00000008);
+      }
+      /**
+       * <code>optional string use_this_hostname_instead = 4;</code>
+       *
+       * <pre>
+       ** hostname for region server, optional 
+       * </pre>
+       */
+      public java.lang.String getUseThisHostnameInstead() {
+        java.lang.Object ref = useThisHostnameInstead_;
+        if (!(ref instanceof java.lang.String)) {
+          java.lang.String s = ((com.google.protobuf.ByteString) ref)
+              .toStringUtf8();
+          useThisHostnameInstead_ = s;
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>optional string use_this_hostname_instead = 4;</code>
+       *
+       * <pre>
+       ** hostname for region server, optional 
+       * </pre>
+       */
+      public com.google.protobuf.ByteString
+          getUseThisHostnameInsteadBytes() {
+        java.lang.Object ref = useThisHostnameInstead_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          useThisHostnameInstead_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>optional string use_this_hostname_instead = 4;</code>
+       *
+       * <pre>
+       ** hostname for region server, optional 
+       * </pre>
+       */
+      public Builder setUseThisHostnameInstead(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000008;
+        useThisHostnameInstead_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string use_this_hostname_instead = 4;</code>
+       *
+       * <pre>
+       ** hostname for region server, optional 
+       * </pre>
+       */
+      public Builder clearUseThisHostnameInstead() {
+        bitField0_ = (bitField0_ & ~0x00000008);
+        useThisHostnameInstead_ = getDefaultInstance().getUseThisHostnameInstead();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string use_this_hostname_instead = 4;</code>
+       *
+       * <pre>
+       ** hostname for region server, optional 
+       * </pre>
+       */
+      public Builder setUseThisHostnameInsteadBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000008;
+        useThisHostnameInstead_ = value;
+        onChanged();
+        return this;
+      }
+
       // @@protoc_insertion_point(builder_scope:RegionServerStartupRequest)
     }
 
@@ -8891,48 +9104,49 @@ public final class RegionServerStatusProtos {
   static {
     java.lang.String[] descriptorData = {
       "\n\030RegionServerStatus.proto\032\013HBase.proto\032" +
-      "\023ClusterStatus.proto\"b\n\032RegionServerStar" +
-      "tupRequest\022\014\n\004port\030\001 \002(\r\022\031\n\021server_start" +
-      "_code\030\002 \002(\004\022\033\n\023server_current_time\030\003 \002(\004" +
-      "\"C\n\033RegionServerStartupResponse\022$\n\013map_e" +
-      "ntries\030\001 \003(\0132\017.NameStringPair\"S\n\031RegionS" +
-      "erverReportRequest\022\033\n\006server\030\001 \002(\0132\013.Ser" +
-      "verName\022\031\n\004load\030\002 \001(\0132\013.ServerLoad\"\034\n\032Re" +
-      "gionServerReportResponse\"O\n\031ReportRSFata" +
-      "lErrorRequest\022\033\n\006server\030\001 \002(\0132\013.ServerNa",
-      "me\022\025\n\rerror_message\030\002 \002(\t\"\034\n\032ReportRSFat" +
-      "alErrorResponse\"6\n\037GetLastFlushedSequenc" +
-      "eIdRequest\022\023\n\013region_name\030\001 \002(\014\"~\n GetLa" +
-      "stFlushedSequenceIdResponse\022 \n\030last_flus" +
-      "hed_sequence_id\030\001 \002(\004\0228\n\036store_last_flus" +
-      "hed_sequence_id\030\002 \003(\0132\020.StoreSequenceId\"" +
-      "\322\002\n\025RegionStateTransition\022>\n\017transition_" +
-      "code\030\001 \002(\0162%.RegionStateTransition.Trans" +
-      "itionCode\022 \n\013region_info\030\002 \003(\0132\013.RegionI" +
-      "nfo\022\024\n\014open_seq_num\030\003 \001(\004\"\300\001\n\016Transition",
-      "Code\022\n\n\006OPENED\020\000\022\017\n\013FAILED_OPEN\020\001\022\n\n\006CLO" +
-      "SED\020\002\022\022\n\016READY_TO_SPLIT\020\003\022\022\n\016READY_TO_ME" +
-      "RGE\020\004\022\016\n\nSPLIT_PONR\020\005\022\016\n\nMERGE_PONR\020\006\022\t\n" +
-      "\005SPLIT\020\007\022\n\n\006MERGED\020\010\022\022\n\016SPLIT_REVERTED\020\t" +
-      "\022\022\n\016MERGE_REVERTED\020\n\"m\n\"ReportRegionStat" +
-      "eTransitionRequest\022\033\n\006server\030\001 \002(\0132\013.Ser" +
-      "verName\022*\n\ntransition\030\002 \003(\0132\026.RegionStat" +
-      "eTransition\"<\n#ReportRegionStateTransiti" +
-      "onResponse\022\025\n\rerror_message\030\001 \001(\t2\326\003\n\031Re" +
-      "gionServerStatusService\022P\n\023RegionServerS",
-      "tartup\022\033.RegionServerStartupRequest\032\034.Re" +
-      "gionServerStartupResponse\022M\n\022RegionServe" +
-      "rReport\022\032.RegionServerReportRequest\032\033.Re" +
-      "gionServerReportResponse\022M\n\022ReportRSFata" +
-      "lError\022\032.ReportRSFatalErrorRequest\032\033.Rep" +
-      "ortRSFatalErrorResponse\022_\n\030GetLastFlushe" +
-      "dSequenceId\022 .GetLastFlushedSequenceIdRe" +
-      "quest\032!.GetLastFlushedSequenceIdResponse" +
-      "\022h\n\033ReportRegionStateTransition\022#.Report" +
-      "RegionStateTransitionRequest\032$.ReportReg",
-      "ionStateTransitionResponseBN\n*org.apache" +
-      ".hadoop.hbase.protobuf.generatedB\030Region" +
-      "ServerStatusProtosH\001\210\001\001\240\001\001"
+      "\023ClusterStatus.proto\"\205\001\n\032RegionServerSta" +
+      "rtupRequest\022\014\n\004port\030\001 \002(\r\022\031\n\021server_star" +
+      "t_code\030\002 \002(\004\022\033\n\023server_current_time\030\003 \002(" +
+      "\004\022!\n\031use_this_hostname_instead\030\004 \001(\t\"C\n\033" +
+      "RegionServerStartupResponse\022$\n\013map_entri" +
+      "es\030\001 \003(\0132\017.NameStringPair\"S\n\031RegionServe" +
+      "rReportRequest\022\033\n\006server\030\001 \002(\0132\013.ServerN" +
+      "ame\022\031\n\004load\030\002 \001(\0132\013.ServerLoad\"\034\n\032Region" +
+      "ServerReportResponse\"O\n\031ReportRSFatalErr",
+      "orRequest\022\033\n\006server\030\001 \002(\0132\013.ServerName\022\025" +
+      "\n\rerror_message\030\002 \002(\t\"\034\n\032ReportRSFatalEr" +
+      "rorResponse\"6\n\037GetLastFlushedSequenceIdR" +
+      "equest\022\023\n\013region_name\030\001 \002(\014\"~\n GetLastFl" +
+      "ushedSequenceIdResponse\022 \n\030last_flushed_" +
+      "sequence_id\030\001 \002(\004\0228\n\036store_last_flushed_" +
+      "sequence_id\030\002 \003(\0132\020.StoreSequenceId\"\322\002\n\025" +
+      "RegionStateTransition\022>\n\017transition_code" +
+      "\030\001 \002(\0162%.RegionStateTransition.Transitio" +
+      "nCode\022 \n\013region_info\030\002 \003(\0132\013.RegionInfo\022",
+      "\024\n\014open_seq_num\030\003 \001(\004\"\300\001\n\016TransitionCode" +
+      "\022\n\n\006OPENED\020\000\022\017\n\013FAILED_OPEN\020\001\022\n\n\006CLOSED\020" +
+      "\002\022\022\n\016READY_TO_SPLIT\020\003\022\022\n\016READY_TO_MERGE\020" +
+      "\004\022\016\n\nSPLIT_PONR\020\005\022\016\n\nMERGE_PONR\020\006\022\t\n\005SPL" +
+      "IT\020\007\022\n\n\006MERGED\020\010\022\022\n\016SPLIT_REVERTED\020\t\022\022\n\016" +
+      "MERGE_REVERTED\020\n\"m\n\"ReportRegionStateTra" +
+      "nsitionRequest\022\033\n\006server\030\001 \002(\0132\013.ServerN" +
+      "ame\022*\n\ntransition\030\002 \003(\0132\026.RegionStateTra" +
+      "nsition\"<\n#ReportRegionStateTransitionRe" +
+      "sponse\022\025\n\rerror_message\030\001 \001(\t2\326\003\n\031Region",
+      "ServerStatusService\022P\n\023RegionServerStart" +
+      "up\022\033.RegionServerStartupRequest\032\034.Region" +
+      "ServerStartupResponse\022M\n\022RegionServerRep" +
+      "ort\022\032.RegionServerReportRequest\032\033.Region" +
+      "ServerReportResponse\022M\n\022ReportRSFatalErr" +
+      "or\022\032.ReportRSFatalErrorRequest\032\033.ReportR" +
+      "SFatalErrorResponse\022_\n\030GetLastFlushedSeq" +
+      "uenceId\022 .GetLastFlushedSequenceIdReques" +
+      "t\032!.GetLastFlushedSequenceIdResponse\022h\n\033" +
+      "ReportRegionStateTransition\022#.ReportRegi",
+      "onStateTransitionRequest\032$.ReportRegionS" +
+      "tateTransitionResponseBN\n*org.apache.had" +
+      "oop.hbase.protobuf.generatedB\030RegionServ" +
+      "erStatusProtosH\001\210\001\001\240\001\001"
     };
     com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
       new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
@@ -8944,7 +9158,7 @@ public final class RegionServerStatusProtos {
           internal_static_RegionServerStartupRequest_fieldAccessorTable = new
             com.google.protobuf.GeneratedMessage.FieldAccessorTable(
               internal_static_RegionServerStartupRequest_descriptor,
-              new java.lang.String[] { "Port", "ServerStartCode", "ServerCurrentTime", });
+              new java.lang.String[] { "Port", "ServerStartCode", "ServerCurrentTime", "UseThisHostnameInstead", });
           internal_static_RegionServerStartupResponse_descriptor =
             getDescriptor().getMessageTypes().get(1);
           internal_static_RegionServerStartupResponse_fieldAccessorTable = new

http://git-wip-us.apache.org/repos/asf/hbase/blob/4df24b8e/hbase-protocol/src/main/protobuf/RegionServerStatus.proto
----------------------------------------------------------------------
diff --git a/hbase-protocol/src/main/protobuf/RegionServerStatus.proto b/hbase-protocol/src/main/protobuf/RegionServerStatus.proto
index 855c2a1..33de501 100644
--- a/hbase-protocol/src/main/protobuf/RegionServerStatus.proto
+++ b/hbase-protocol/src/main/protobuf/RegionServerStatus.proto
@@ -36,6 +36,9 @@ message RegionServerStartupRequest {
 
   /** Current time of the region server in ms */
   required uint64 server_current_time = 3;
+
+  /** hostname for region server, optional */
+  optional string use_this_hostname_instead = 4;
 }
 
 message RegionServerStartupResponse {

http://git-wip-us.apache.org/repos/asf/hbase/blob/4df24b8e/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java
index 88ff74c..98f7507 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java
@@ -301,8 +301,9 @@ public class MasterRpcServices extends RSRpcServices
       master.checkServiceStarted();
       InetAddress ia = master.getRemoteInetAddress(
         request.getPort(), request.getServerStartCode());
-      ServerName rs = master.serverManager.regionServerStartup(ia, request.getPort(),
-        request.getServerStartCode(), request.getServerCurrentTime());
+      // if regionserver passed hostname to use,
+      // then use it instead of doing a reverse DNS lookup
+      ServerName rs = master.serverManager.regionServerStartup(request, ia);
 
       // Send back some config info
       RegionServerStartupResponse.Builder resp = createConfigurationSubset();

http://git-wip-us.apache.org/repos/asf/hbase/blob/4df24b8e/hbase-server/src/main/java/org/apache/hadoop/hbase/master/ServerManager.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/ServerManager.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/ServerManager.java
index ab0bcdb..5c8bd34 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/ServerManager.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/ServerManager.java
@@ -63,6 +63,7 @@ import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.AdminService;
 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.OpenRegionRequest;
 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.OpenRegionResponse;
 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.ServerInfo;
+import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.RegionServerStartupRequest;
 import org.apache.hadoop.hbase.protobuf.generated.ClusterStatusProtos.RegionStoreSequenceIds;
 import org.apache.hadoop.hbase.protobuf.generated.ClusterStatusProtos.StoreSequenceId;
 import org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos.SplitLogTask.RecoveryMode;
@@ -241,16 +242,13 @@ public class ServerManager {
 
   /**
    * Let the server manager know a new regionserver has come online
-   * @param ia The remote address
-   * @param port The remote port
-   * @param serverStartcode
-   * @param serverCurrentTime The current time of the region server in ms
+   * @param request the startup request
+   * @param ia the InetAddress from which request is received
    * @return The ServerName we know this server as.
    * @throws IOException
    */
-  ServerName regionServerStartup(final InetAddress ia, final int port,
-    final long serverStartcode, long serverCurrentTime)
-  throws IOException {
+  ServerName regionServerStartup(RegionServerStartupRequest request, InetAddress ia)
+      throws IOException {
     // Test for case where we get a region startup message from a regionserver
     // that has been quickly restarted but whose znode expiration handler has
     // not yet run, or from a server whose fail we are currently processing.
@@ -258,8 +256,12 @@ public class ServerManager {
     // is, reject the server and trigger its expiration. The next time it comes
     // in, it should have been removed from serverAddressToServerInfo and queued
     // for processing by ProcessServerShutdown.
-    ServerName sn = ServerName.valueOf(ia.getHostName(), port, serverStartcode);
-    checkClockSkew(sn, serverCurrentTime);
+
+    final String hostname = request.hasUseThisHostnameInstead() ?
+        request.getUseThisHostnameInstead() :ia.getHostName();
+    ServerName sn = ServerName.valueOf(hostname, request.getPort(),
+      request.getServerStartCode());
+    checkClockSkew(sn, request.getServerCurrentTime());
     checkIsDead(sn, "STARTUP");
     if (!checkAndRecordNewServer(sn, ServerLoad.EMPTY_SERVERLOAD)) {
       LOG.warn("THIS SHOULD NOT HAPPEN, RegionServerStartup"

http://git-wip-us.apache.org/repos/asf/hbase/blob/4df24b8e/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java
index a091d23..af457ec 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java
@@ -395,6 +395,16 @@ public class HRegionServer extends HasThread implements
    */
   protected ServerName serverName;
 
+  /*
+   * hostname specified by hostname config
+   */
+  private String useThisHostnameInstead;
+
+  // key to the config parameter of server hostname
+  // the specification of server hostname is optional. The hostname should be resolvable from
+  // both master and region server
+  final static String HOSTNAME_KEY = "hbase.regionserver.hostname";
+
   /**
    * This servers startcode.
    */
@@ -513,7 +523,9 @@ public class HRegionServer extends HasThread implements
 
     rpcServices = createRpcServices();
     this.startcode = System.currentTimeMillis();
-    String hostName = rpcServices.isa.getHostName();
+    useThisHostnameInstead = conf.get(HOSTNAME_KEY);
+    String hostName = shouldUseThisHostnameInstead() ? useThisHostnameInstead :
+      rpcServices.isa.getHostName();
     serverName = ServerName.valueOf(hostName, rpcServices.isa.getPort(), startcode);
 
     rpcControllerFactory = RpcControllerFactory.instantiate(this.conf);
@@ -577,6 +589,13 @@ public class HRegionServer extends HasThread implements
     this.choreService = new ChoreService(getServerName().toString());
   }
 
+  /*
+   * Returns true if configured hostname should be used
+   */
+  protected boolean shouldUseThisHostnameInstead() {
+    return useThisHostnameInstead != null && !useThisHostnameInstead.isEmpty();
+  }
+
   protected void login(UserProvider user, String host) throws IOException {
     user.login("hbase.regionserver.keytab.file",
       "hbase.regionserver.kerberos.principal", host);
@@ -627,7 +646,7 @@ public class HRegionServer extends HasThread implements
 
     coprocessorServiceHandlers.put(serviceDesc.getFullName(), instance);
     if (LOG.isDebugEnabled()) {
-      LOG.debug("Registered regionserver coprocessor service: service=" + serviceDesc.getFullName());
+      LOG.debug("Registered regionserver coprocessor service: service="+serviceDesc.getFullName());
     }
     return true;
   }
@@ -1274,9 +1293,18 @@ public class HRegionServer extends HasThread implements
           String hostnameFromMasterPOV = e.getValue();
           this.serverName = ServerName.valueOf(hostnameFromMasterPOV,
             rpcServices.isa.getPort(), this.startcode);
-          if (!hostnameFromMasterPOV.equals(rpcServices.isa.getHostName())) {
-            LOG.info("Master passed us a different hostname to use; was=" +
-              rpcServices.isa.getHostName() + ", but now=" + hostnameFromMasterPOV);
+          if (shouldUseThisHostnameInstead() &&
+              !hostnameFromMasterPOV.equals(useThisHostnameInstead)) {
+            String msg = "Master passed us a different hostname to use; was=" +
+                this.useThisHostnameInstead + ", but now=" + hostnameFromMasterPOV;
+            LOG.error(msg);
+            throw new IOException(msg);
+          }
+          if (!shouldUseThisHostnameInstead() &&
+              !hostnameFromMasterPOV.equals(rpcServices.isa.getHostName())) {
+            String msg = "Master passed us a different hostname to use; was=" +
+                rpcServices.isa.getHostName() + ", but now=" + hostnameFromMasterPOV;
+            LOG.error(msg);
           }
           continue;
         }
@@ -2168,6 +2196,9 @@ public class HRegionServer extends HasThread implements
       long now = EnvironmentEdgeManager.currentTime();
       int port = rpcServices.isa.getPort();
       RegionServerStartupRequest.Builder request = RegionServerStartupRequest.newBuilder();
+      if (shouldUseThisHostnameInstead()) {
+        request.setUseThisHostnameInstead(useThisHostnameInstead);
+      }
       request.setPort(port);
       request.setServerStartCode(this.startcode);
       request.setServerCurrentTime(now);

http://git-wip-us.apache.org/repos/asf/hbase/blob/4df24b8e/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RSRpcServices.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RSRpcServices.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RSRpcServices.java
index bb446d1..9b47c75 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RSRpcServices.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RSRpcServices.java
@@ -826,9 +826,15 @@ public class RSRpcServices implements HBaseRPCErrorHandler,
   }
 
   public static String getHostname(Configuration conf) throws UnknownHostException {
-    return Strings.domainNamePointerToHostName(DNS.getDefaultHost(
-            conf.get("hbase.regionserver.dns.interface", "default"),
-            conf.get("hbase.regionserver.dns.nameserver", "default")));
+    String hostname = conf.get(HRegionServer.HOSTNAME_KEY);
+    if (hostname == null || hostname.isEmpty()) {
+      return Strings.domainNamePointerToHostName(DNS.getDefaultHost(
+        conf.get("hbase.regionserver.dns.interface", "default"),
+        conf.get("hbase.regionserver.dns.nameserver", "default")));
+    } else {
+      LOG.info("hostname is configured to be " + hostname);
+      return hostname;
+    }
   }
 
   RegionScanner getScanner(long scannerId) {

http://git-wip-us.apache.org/repos/asf/hbase/blob/4df24b8e/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestClockSkewDetection.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestClockSkewDetection.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestClockSkewDetection.java
index d9ec036..963f36e 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestClockSkewDetection.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestClockSkewDetection.java
@@ -32,6 +32,7 @@ import org.apache.hadoop.hbase.HBaseConfiguration;
 import org.apache.hadoop.hbase.Server;
 import org.apache.hadoop.hbase.ServerName;
 import org.apache.hadoop.hbase.client.ClusterConnection;
+import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.RegionServerStartupRequest;
 import org.apache.hadoop.hbase.testclassification.SmallTests;
 import org.apache.hadoop.hbase.zookeeper.MetaTableLocator;
 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
@@ -102,7 +103,11 @@ public class TestClockSkewDetection {
 
     LOG.debug("regionServerStartup 1");
     InetAddress ia1 = InetAddress.getLocalHost();
-    sm.regionServerStartup(ia1, 1234, -1, System.currentTimeMillis());
+    RegionServerStartupRequest.Builder request = RegionServerStartupRequest.newBuilder();
+    request.setPort(1234);
+    request.setServerStartCode(-1);
+    request.setServerCurrentTime(System.currentTimeMillis());
+    sm.regionServerStartup(request.build(), ia1);
 
     final Configuration c = HBaseConfiguration.create();
     long maxSkew = c.getLong("hbase.master.maxclockskew", 30000);
@@ -113,7 +118,11 @@ public class TestClockSkewDetection {
       LOG.debug("Test: Master Time > Region Server Time");
       LOG.debug("regionServerStartup 2");
       InetAddress ia2 = InetAddress.getLocalHost();
-      sm.regionServerStartup(ia2, 1235, -1, System.currentTimeMillis() - maxSkew * 2);
+      request = RegionServerStartupRequest.newBuilder();
+      request.setPort(1235);
+      request.setServerStartCode(-1);
+      request.setServerCurrentTime(System.currentTimeMillis() - maxSkew * 2);
+      sm.regionServerStartup(request.build(), ia2);
       fail("HMaster should have thrown a ClockOutOfSyncException but didn't.");
     } catch(ClockOutOfSyncException e) {
       //we want an exception
@@ -125,7 +134,11 @@ public class TestClockSkewDetection {
       LOG.debug("Test: Master Time < Region Server Time");
       LOG.debug("regionServerStartup 3");
       InetAddress ia3 = InetAddress.getLocalHost();
-      sm.regionServerStartup(ia3, 1236, -1, System.currentTimeMillis() + maxSkew * 2);
+      request = RegionServerStartupRequest.newBuilder();
+      request.setPort(1236);
+      request.setServerStartCode(-1);
+      request.setServerCurrentTime(System.currentTimeMillis() + maxSkew * 2);
+      sm.regionServerStartup(request.build(), ia3);
       fail("HMaster should have thrown a ClockOutOfSyncException but didn't.");
     } catch (ClockOutOfSyncException e) {
       // we want an exception
@@ -135,13 +148,20 @@ public class TestClockSkewDetection {
     // make sure values above warning threshold but below max threshold don't kill
     LOG.debug("regionServerStartup 4");
     InetAddress ia4 = InetAddress.getLocalHost();
-    sm.regionServerStartup(ia4, 1237, -1, System.currentTimeMillis() - warningSkew * 2);
+    request = RegionServerStartupRequest.newBuilder();
+    request.setPort(1237);
+    request.setServerStartCode(-1);
+    request.setServerCurrentTime(System.currentTimeMillis() - warningSkew * 2);
+    sm.regionServerStartup(request.build(), ia4);
 
     // make sure values above warning threshold but below max threshold don't kill
     LOG.debug("regionServerStartup 5");
     InetAddress ia5 = InetAddress.getLocalHost();
-    sm.regionServerStartup(ia5, 1238, -1, System.currentTimeMillis() + warningSkew * 2);
-
+    request = RegionServerStartupRequest.newBuilder();
+    request.setPort(1238);
+    request.setServerStartCode(-1);
+    request.setServerCurrentTime(System.currentTimeMillis() + warningSkew * 2);
+    sm.regionServerStartup(request.build(), ia5);
   }
 
 }

http://git-wip-us.apache.org/repos/asf/hbase/blob/4df24b8e/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestRegionServerHostname.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestRegionServerHostname.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestRegionServerHostname.java
new file mode 100644
index 0000000..436bf02
--- /dev/null
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestRegionServerHostname.java
@@ -0,0 +1,103 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.regionserver;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.util.Enumeration;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.hbase.HBaseTestingUtility;
+import org.apache.hadoop.hbase.testclassification.MediumTests;
+import org.apache.hadoop.hbase.util.Threads;
+import org.apache.hadoop.hbase.zookeeper.ZKUtil;
+import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+/**
+ * Tests for the hostname specification by region server
+ */
+@Category({MediumTests.class})
+public class TestRegionServerHostname {
+  private static final Log LOG = LogFactory.getLog(TestRegionServerHostname.class);
+  private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
+
+  @Test (timeout=30000)
+  public void testInvalidRegionServerHostnameAbortsServer() throws Exception {
+    final int NUM_MASTERS = 1;
+    final int NUM_RS = 1;
+    String invalidHostname = "hostAddr";
+    TEST_UTIL.getConfiguration().set(HRegionServer.HOSTNAME_KEY, invalidHostname);
+    try {
+      TEST_UTIL.startMiniCluster(NUM_MASTERS, NUM_RS);
+    } catch (IOException ioe) {
+      Throwable t1 = ioe.getCause();
+      Throwable t2 = t1.getCause();
+      assertTrue(t2.getMessage().contains("Failed resolve of " + invalidHostname));
+      return;
+    } finally {
+      TEST_UTIL.shutdownMiniCluster();
+    }
+    assertTrue("Failed to validate against invalid hostname", false);
+  }
+
+  @Test(timeout=120000)
+  public void testRegionServerHostname() throws Exception {
+    final int NUM_MASTERS = 1;
+    final int NUM_RS = 1;
+    Enumeration<NetworkInterface> netInterfaceList = NetworkInterface.getNetworkInterfaces();
+
+    while (netInterfaceList.hasMoreElements()) {
+      NetworkInterface ni = netInterfaceList.nextElement();
+      Enumeration<InetAddress> addrList = ni.getInetAddresses();
+      // iterate through host addresses and use each as hostname
+      while (addrList.hasMoreElements()) {
+        InetAddress addr = addrList.nextElement();
+        if (addr.isLoopbackAddress() || addr.isLinkLocalAddress() || addr.isMulticastAddress()
+            || !ni.getDisplayName().startsWith("e")) {
+          continue;
+        }
+        String hostName = addr.getHostName();
+        LOG.info("Found " + hostName + " on " + ni);
+        
+        TEST_UTIL.getConfiguration().set(HRegionServer.HOSTNAME_KEY, hostName);
+        TEST_UTIL.startMiniCluster(NUM_MASTERS, NUM_RS);
+        try {
+          ZooKeeperWatcher zkw = TEST_UTIL.getZooKeeperWatcher();
+          List<String> servers = ZKUtil.listChildrenNoWatch(zkw, zkw.rsZNode);
+          while (servers == null) {
+            Threads.sleep(10);
+          }
+          assertTrue(servers.size() == NUM_RS);
+          for (String server : servers) {
+            assertTrue(server.startsWith(hostName+","));
+          }
+          zkw.close();
+        } finally {
+          TEST_UTIL.shutdownMiniCluster();
+        }
+      }
+    }
+  }
+}