001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.exceptions; 019 020import org.apache.hadoop.hbase.HConstants; 021import org.apache.hadoop.hbase.NotServingRegionException; 022import org.apache.hadoop.hbase.ServerName; 023import org.apache.yetus.audience.InterfaceAudience; 024import org.apache.yetus.audience.InterfaceStability; 025import org.slf4j.Logger; 026import org.slf4j.LoggerFactory; 027 028/** 029 * Subclass if the server knows the region is now on another server. 030 * This allows the client to call the new region server without calling the master. 031 */ 032@InterfaceAudience.Private 033@InterfaceStability.Evolving 034public class RegionMovedException extends NotServingRegionException { 035 private static final Logger LOG = LoggerFactory.getLogger(RegionMovedException.class); 036 private static final long serialVersionUID = -7232903522310558396L; 037 038 private final String hostname; 039 private final int port; 040 private final long startCode; 041 private final long locationSeqNum; 042 043 private static final String HOST_FIELD = "hostname="; 044 private static final String PORT_FIELD = "port="; 045 private static final String STARTCODE_FIELD = "startCode="; 046 private static final String LOCATIONSEQNUM_FIELD = "locationSeqNum="; 047 048 049 public RegionMovedException(ServerName serverName, long locationSeqNum) { 050 this.hostname = serverName.getHostname(); 051 this.port = serverName.getPort(); 052 this.startCode = serverName.getStartcode(); 053 this.locationSeqNum = locationSeqNum; 054 } 055 056 public String getHostname() { 057 return hostname; 058 } 059 060 public int getPort() { 061 return port; 062 } 063 064 public ServerName getServerName(){ 065 return ServerName.valueOf(hostname, port, startCode); 066 } 067 068 public long getLocationSeqNum() { 069 return locationSeqNum; 070 } 071 072 /** 073 * For hadoop.ipc internal call. Do NOT use. 074 * We have to parse the hostname to recreate the exception. 075 * The input is the one generated by {@link #getMessage()} 076 */ 077 public RegionMovedException(String s) { 078 int posHostname = s.indexOf(HOST_FIELD) + HOST_FIELD.length(); 079 int posPort = s.indexOf(PORT_FIELD) + PORT_FIELD.length(); 080 int posStartCode = s.indexOf(STARTCODE_FIELD) + STARTCODE_FIELD.length(); 081 int posSeqNum = s.indexOf(LOCATIONSEQNUM_FIELD) + LOCATIONSEQNUM_FIELD.length(); 082 083 String tmpHostname = null; 084 int tmpPort = -1; 085 long tmpStartCode = -1; 086 long tmpSeqNum = HConstants.NO_SEQNUM; 087 try { 088 // TODO: this whole thing is extremely brittle. 089 tmpHostname = s.substring(posHostname, s.indexOf(' ', posHostname)); 090 tmpPort = Integer.parseInt(s.substring(posPort, s.indexOf(' ', posPort))); 091 tmpStartCode = Long.parseLong(s.substring(posStartCode, s.indexOf('.', posStartCode))); 092 tmpSeqNum = Long.parseLong(s.substring(posSeqNum, s.indexOf('.', posSeqNum))); 093 } catch (Exception ignored) { 094 LOG.warn("Can't parse the hostname, port and startCode from this string: " + 095 s + ", continuing"); 096 } 097 098 hostname = tmpHostname; 099 port = tmpPort; 100 startCode = tmpStartCode; 101 locationSeqNum = tmpSeqNum; 102 } 103 104 @Override 105 public String getMessage() { 106 // TODO: deserialization above depends on this. That is bad, but also means this 107 // should be modified carefully. 108 return "Region moved to: " + HOST_FIELD + hostname + " " + PORT_FIELD + port + " " + 109 STARTCODE_FIELD + startCode + ". As of " + LOCATIONSEQNUM_FIELD + locationSeqNum + "."; 110 } 111}