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.hbase.classification.InterfaceAudience;
23  import org.apache.hadoop.hbase.classification.InterfaceStability;
24  import org.apache.hadoop.hbase.HConstants;
25  import org.apache.hadoop.hbase.NotServingRegionException;
26  import org.apache.hadoop.hbase.ServerName;
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 ServerName.valueOf(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 }