View Javadoc

1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  
20  package org.apache.hadoop.hbase.client;
21  
22  import java.io.IOException;
23  import java.net.ConnectException;
24  import java.net.SocketTimeoutException;
25  
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  import org.apache.hadoop.hbase.classification.InterfaceAudience;
29  import org.apache.hadoop.hbase.HRegionInfo;
30  import org.apache.hadoop.hbase.HRegionLocation;
31  import org.apache.hadoop.hbase.NotServingRegionException;
32  import org.apache.hadoop.hbase.TableName;
33  import org.apache.hadoop.hbase.exceptions.RegionMovedException;
34  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.ClientService;
35  import org.apache.hadoop.hbase.util.Bytes;
36  
37  /**
38   * Implementations call a RegionServer and implement {@link #call()}.
39   * Passed to a {@link RpcRetryingCaller} so we retry on fail.
40   * @param <T> the class that the ServerCallable handles
41   */
42  @InterfaceAudience.Private
43  public abstract class RegionServerCallable<T> implements RetryingCallable<T> {
44    // Public because used outside of this package over in ipc.
45    static final Log LOG = LogFactory.getLog(RegionServerCallable.class);
46    protected final HConnection connection;
47    protected final TableName tableName;
48    protected final byte[] row;
49    protected HRegionLocation location;
50    private ClientService.BlockingInterface stub;
51    protected boolean serverHasMoreResultsContext;
52    protected boolean serverHasMoreResults;
53  
54    protected final static int MIN_WAIT_DEAD_SERVER = 10000;
55  
56    /**
57     * @param connection Connection to use.
58     * @param tableName Table name to which <code>row</code> belongs.
59     * @param row The row we want in <code>tableName</code>.
60     */
61    public RegionServerCallable(HConnection connection, TableName tableName, byte [] row) {
62      this.connection = connection;
63      this.tableName = tableName;
64      this.row = row;
65    }
66  
67    /**
68     * Prepare for connection to the server hosting region with row from tablename.  Does lookup
69     * to find region location and hosting server.
70     * @param reload Set this to true if connection should re-find the region
71     * @throws IOException e
72     */
73    public void prepare(final boolean reload) throws IOException {
74      this.location = connection.getRegionLocation(tableName, row, reload);
75      if (this.location == null) {
76        throw new IOException("Failed to find location, tableName=" + tableName +
77          ", row=" + Bytes.toString(row) + ", reload=" + reload);
78      }
79      setStub(getConnection().getClient(getLocation().getServerName()));
80    }
81  
82    /**
83     * @return {@link HConnection} instance used by this Callable.
84     */
85    HConnection getConnection() {
86      return this.connection;
87    }
88  
89    protected ClientService.BlockingInterface getStub() {
90      return this.stub;
91    }
92  
93    void setStub(final ClientService.BlockingInterface stub) {
94      this.stub = stub;
95    }
96  
97    protected HRegionLocation getLocation() {
98      return this.location;
99    }
100 
101   protected void setLocation(final HRegionLocation location) {
102     this.location = location;
103   }
104 
105   public TableName getTableName() {
106     return this.tableName;
107   }
108 
109   public byte [] getRow() {
110     return this.row;
111   }
112 
113   @Override
114   public void throwable(Throwable t, boolean retrying) {
115     if (t instanceof SocketTimeoutException ||
116         t instanceof ConnectException ||
117         t instanceof RetriesExhaustedException ||
118         (location != null && getConnection().isDeadServer(location.getServerName()))) {
119       // if thrown these exceptions, we clear all the cache entries that
120       // map to that slow/dead server; otherwise, let cache miss and ask
121       // hbase:meta again to find the new location
122       if (this.location != null) getConnection().clearCaches(location.getServerName());
123     } else if (t instanceof RegionMovedException) {
124       getConnection().updateCachedLocations(tableName, row, t, location);
125     } else if (t instanceof NotServingRegionException && !retrying) {
126       // Purge cache entries for this specific region from hbase:meta cache
127       // since we don't call connect(true) when number of retries is 1.
128       getConnection().deleteCachedRegionLocation(location);
129     }
130   }
131 
132   @Override
133   public String getExceptionMessageAdditionalDetail() {
134     return "row '" + Bytes.toString(row) + "' on table '" + tableName + "' at " + location;
135   }
136 
137   @Override
138   public long sleep(long pause, int tries) {
139     // Tries hasn't been bumped up yet so we use "tries + 1" to get right pause time
140     long sleep = ConnectionUtils.getPauseTime(pause, tries + 1);
141     if (sleep < MIN_WAIT_DEAD_SERVER
142         && (location == null || getConnection().isDeadServer(location.getServerName()))) {
143       sleep = ConnectionUtils.addJitter(MIN_WAIT_DEAD_SERVER, 0.10f);
144     }
145     return sleep;
146   }
147 
148   /**
149    * @return the HRegionInfo for the current region
150    */
151   public HRegionInfo getHRegionInfo() {
152     if (this.location == null) {
153       return null;
154     }
155     return this.location.getRegionInfo();
156   }
157 
158   /**
159    * Should the client attempt to fetch more results from this region
160    * @return True if the client should attempt to fetch more results, false otherwise.
161    */
162   protected boolean getServerHasMoreResults() {
163     assert serverHasMoreResultsContext;
164     return this.serverHasMoreResults;
165   }
166 
167   protected void setServerHasMoreResults(boolean serverHasMoreResults) {
168     this.serverHasMoreResults = serverHasMoreResults;
169   }
170 
171   /**
172    * Did the server respond with information about whether more results might exist.
173    * Not guaranteed to respond with older server versions
174    * @return True if the server responded with information about more results.
175    */
176   protected boolean hasMoreResultsContext() {
177     return serverHasMoreResultsContext;
178   }
179 
180   protected void setHasMoreResultsContext(boolean serverHasMoreResultsContext) {
181     this.serverHasMoreResultsContext = serverHasMoreResultsContext;
182   }
183 }