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.exceptions;
19  
20  import org.apache.commons.logging.Log;
21  import org.apache.commons.logging.LogFactory;
22  import org.apache.hadoop.classification.InterfaceAudience;
23  import org.apache.hadoop.classification.InterfaceStability;
24  import org.apache.hadoop.hbase.HConstants;
25  import org.apache.hadoop.hbase.ServerName;
26  import org.apache.hadoop.ipc.RemoteException;
27  
28  /**
29   * Subclass if the server knows the region is now on another server.
30   * This allows the client to call the new region server without calling the master.
31   */
32  @InterfaceAudience.Private
33  @InterfaceStability.Evolving
34  public class RegionMovedException extends NotServingRegionException {
35    private static final Log LOG = LogFactory.getLog(RegionMovedException.class);
36    private static final long serialVersionUID = -7232903522310558396L;
37  
38    private final String hostname;
39    private final int port;
40    private final long startCode;
41    private final long locationSeqNum;
42  
43    private static final String HOST_FIELD = "hostname=";
44    private static final String PORT_FIELD = "port=";
45    private static final String STARTCODE_FIELD = "startCode=";
46    private static final String LOCATIONSEQNUM_FIELD = "locationSeqNum=";
47  
48  
49    public RegionMovedException(ServerName serverName, long locationSeqNum) {
50      this.hostname = serverName.getHostname();
51      this.port = serverName.getPort();
52      this.startCode = serverName.getStartcode();
53      this.locationSeqNum = locationSeqNum;
54    }
55  
56    public String getHostname() {
57      return hostname;
58    }
59  
60    public int getPort() {
61      return port;
62    }
63  
64    public ServerName getServerName(){
65      return new ServerName(hostname, port, startCode);
66    }
67  
68    public long getLocationSeqNum() {
69      return locationSeqNum;
70    }
71  
72    /**
73     * For hadoop.ipc internal call. Do NOT use.
74     * We have to parse the hostname to recreate the exception.
75     * The input is the one generated by {@link #getMessage()}
76     */
77    public RegionMovedException(String s) {
78      int posHostname = s.indexOf(HOST_FIELD) + HOST_FIELD.length();
79      int posPort = s.indexOf(PORT_FIELD) + PORT_FIELD.length();
80      int posStartCode = s.indexOf(STARTCODE_FIELD) + STARTCODE_FIELD.length();
81      int posSeqNum = s.indexOf(LOCATIONSEQNUM_FIELD) + LOCATIONSEQNUM_FIELD.length();
82  
83      String tmpHostname = null;
84      int tmpPort = -1;
85      long tmpStartCode = -1;
86      long tmpSeqNum = HConstants.NO_SEQNUM;
87      try {
88        // TODO: this whole thing is extremely brittle.
89        tmpHostname = s.substring(posHostname, s.indexOf(' ', posHostname));
90        tmpPort = Integer.parseInt(s.substring(posPort, s.indexOf(' ', posPort)));
91        tmpStartCode =  Long.parseLong(s.substring(posStartCode, s.indexOf('.', posStartCode)));
92        tmpSeqNum = Long.parseLong(s.substring(posSeqNum, s.indexOf('.', posSeqNum)));
93      } catch (Exception ignored) {
94        LOG.warn("Can't parse the hostname, port and startCode from this string: " +
95            s + ", continuing");
96      }
97  
98      hostname = tmpHostname;
99      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 
112   /**
113    * Look for a RegionMovedException in the exception:
114    *  - hadoop.ipc wrapped exceptions
115    *  - nested exceptions
116    * Returns null if we didn't find the exception or if it was not readable.
117    */
118   public static RegionMovedException find(Object exception) {
119     if (exception == null || !(exception instanceof Throwable)){
120       return null;
121     }
122 
123     Throwable cur = (Throwable)exception;
124     RegionMovedException res = null;
125 
126     while (res == null && cur != null) {
127       if (cur instanceof RegionMovedException) {
128         res = (RegionMovedException) cur;
129       } else {
130         if (cur instanceof RemoteException) {
131           RemoteException re = (RemoteException) cur;
132           Exception e = re.unwrapRemoteException(RegionMovedException.class);
133           if (e == null){
134             e = re.unwrapRemoteException();
135           }
136           // unwrapRemoteException can return the exception given as a parameter when it cannot
137           //  unwrap it. In this case, there is no need to look further
138           // noinspection ObjectEquality
139           if (e != re){
140             res =  find(e);
141           }
142         }
143         cur = cur.getCause();
144       }
145     }
146 
147     if (res != null && (res.getPort() < 0 || res.getHostname() == null)){
148       // We failed to parse the exception. Let's act as we don't find the exception.
149       return null;
150     } else {
151       return res;
152     }
153   }
154 }