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  
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  import org.apache.hadoop.hbase.HConstants;
27  import org.apache.hadoop.hbase.classification.InterfaceAudience;
28  import org.apache.hadoop.hbase.HRegionInfo;
29  import org.apache.hadoop.hbase.HRegionLocation;
30  import org.apache.hadoop.hbase.TableName;
31  import org.apache.hadoop.hbase.TableNotEnabledException;
32  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.ClientService;
33  import org.apache.hadoop.hbase.util.Bytes;
34  
35  /**
36   * Implementations call a RegionServer and implement {@link #call(int)}.
37   * Passed to a {@link RpcRetryingCaller} so we retry on fail.
38   * TODO: this class is actually tied to one region, because most of the paths make use of
39   *       the regioninfo part of location when building requests. The only reason it works for
40   *       multi-region requests (e.g. batch) is that they happen to not use the region parts.
41   *       This could be done cleaner (e.g. having a generic parameter and 2 derived classes,
42   *       RegionCallable and actual RegionServerCallable with ServerName.
43   * @param <T> the class that the ServerCallable handles
44   */
45  @InterfaceAudience.Private
46  public abstract class RegionServerCallable<T> implements RetryingCallable<T> {
47    // Public because used outside of this package over in ipc.
48    private static final Log LOG = LogFactory.getLog(RegionServerCallable.class);
49    protected final Connection connection;
50    protected final TableName tableName;
51    protected final byte[] row;
52    protected HRegionLocation location;
53    private ClientService.BlockingInterface stub;
54    protected int priority;
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(Connection connection, TableName tableName, byte [] row) {
62      this(connection, tableName, row, HConstants.NORMAL_QOS);
63    }
64  
65    public RegionServerCallable(Connection connection, TableName tableName, byte [] row, int priority) {
66      this.connection = connection;
67      this.tableName = tableName;
68      this.row = row;
69      this.priority = priority;
70    }
71  
72    /**
73     * Prepare for connection to the server hosting region with row from tablename.  Does lookup
74     * to find region location and hosting server.
75     * @param reload Set to true to re-check the table state
76     * @throws IOException e
77     */
78    @Override
79    public void prepare(final boolean reload) throws IOException {
80      // check table state if this is a retry
81      if (reload && tableName != null &&
82          !tableName.equals(TableName.META_TABLE_NAME) &&
83          getConnection().isTableDisabled(tableName)) {
84        throw new TableNotEnabledException(tableName.getNameAsString() + " is disabled.");
85      }
86      try (RegionLocator regionLocator = connection.getRegionLocator(tableName)) {
87        this.location = regionLocator.getRegionLocation(row);
88      }
89      if (this.location == null) {
90        throw new IOException("Failed to find location, tableName=" + tableName +
91          ", row=" + Bytes.toString(row) + ", reload=" + reload);
92      }
93      setStub(getConnection().getClient(this.location.getServerName()));
94    }
95  
96    /**
97     * @return {@link HConnection} instance used by this Callable.
98     */
99    HConnection getConnection() {
100     return (HConnection) this.connection;
101   }
102 
103   protected ClientService.BlockingInterface getStub() {
104     return this.stub;
105   }
106 
107   void setStub(final ClientService.BlockingInterface stub) {
108     this.stub = stub;
109   }
110 
111   protected HRegionLocation getLocation() {
112     return this.location;
113   }
114 
115   protected void setLocation(final HRegionLocation location) {
116     this.location = location;
117   }
118 
119   public TableName getTableName() {
120     return this.tableName;
121   }
122 
123   public byte [] getRow() {
124     return this.row;
125   }
126 
127   public int getPriority() {
128     return priority;
129   }
130 
131   @Override
132   public void throwable(Throwable t, boolean retrying) {
133     if (location != null) {
134       getConnection().updateCachedLocations(tableName, location.getRegionInfo().getRegionName(),
135           row, t, location.getServerName());
136     }
137   }
138 
139   @Override
140   public String getExceptionMessageAdditionalDetail() {
141     return "row '" + Bytes.toString(row) + "' on table '" + tableName + "' at " + location;
142   }
143 
144   @Override
145   public long sleep(long pause, int tries) {
146     return ConnectionUtils.getPauseTime(pause, tries);
147   }
148 
149   /**
150    * @return the HRegionInfo for the current region
151    */
152   public HRegionInfo getHRegionInfo() {
153     if (this.location == null) {
154       return null;
155     }
156     return this.location.getRegionInfo();
157   }
158 }