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 */
018
019package org.apache.hadoop.hbase.client;
020
021import java.io.Closeable;
022import java.io.IOException;
023import org.apache.hadoop.hbase.TableName;
024import org.apache.hadoop.hbase.ipc.HBaseRpcController;
025import org.apache.hadoop.hbase.ipc.RpcControllerFactory;
026import org.apache.hadoop.hbase.util.Bytes;
027import org.apache.yetus.audience.InterfaceAudience;
028
029import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
030
031/**
032 * A RetryingCallable for Master RPC operations.
033 * Implement the #rpcCall method. It will be retried on error. See its javadoc and the javadoc of
034 * #call(int). See {@link HBaseAdmin} for examples of how this is used. To get at the
035 * rpcController that has been created and configured to make this rpc call, use getRpcController().
036 * We are trying to contain all protobuf references including references to rpcController so we
037 * don't pollute codebase with protobuf references; keep the protobuf references contained and only
038 * present in a few classes rather than all about the code base.
039 * <p>Like {@link RegionServerCallable} only in here, we can safely be PayloadCarryingRpcController
040 * all the time. This is not possible in the similar {@link RegionServerCallable} Callable because
041 * it has to deal with Coprocessor Endpoints.
042 * @param <V> return type
043 */
044@InterfaceAudience.Private
045abstract class MasterCallable<V> implements RetryingCallable<V>, Closeable {
046  protected final ClusterConnection connection;
047  protected MasterKeepAliveConnection master;
048  private final HBaseRpcController rpcController;
049
050  MasterCallable(final Connection connection, final RpcControllerFactory rpcConnectionFactory) {
051    this.connection = (ClusterConnection) connection;
052    this.rpcController = rpcConnectionFactory.newController();
053  }
054
055  @Override
056  public void prepare(boolean reload) throws IOException {
057    this.master = this.connection.getMaster();
058  }
059
060  @Override
061  public void close() throws IOException {
062    // The above prepare could fail but this would still be called though masterAdmin is null
063    if (this.master != null) {
064      this.master.close();
065      this.master = null;
066    }
067  }
068
069  @Override
070  public void throwable(Throwable t, boolean retrying) {
071  }
072
073  @Override
074  public String getExceptionMessageAdditionalDetail() {
075    return "";
076  }
077
078  @Override
079  public long sleep(long pause, int tries) {
080    return ConnectionUtils.getPauseTime(pause, tries);
081  }
082
083  /**
084   * Override that changes the {@link java.util.concurrent.Callable#call()} Exception from {@link Exception} to
085   * {@link IOException}. It also does setup of an rpcController and calls through to the rpcCall()
086   * method which callers are expected to implement. If rpcController is an instance of
087   * PayloadCarryingRpcController, we will set a timeout on it.
088   */
089  @Override
090  // Same trick as in RegionServerCallable so users don't have to copy/paste so much boilerplate
091  // and so we contain references to protobuf. We can't set priority on the rpcController as
092  // we do in RegionServerCallable because we don't always have a Table when we call.
093  public V call(int callTimeout) throws IOException {
094    try {
095      if (this.rpcController != null) {
096        this.rpcController.reset();
097        this.rpcController.setCallTimeout(callTimeout);
098      }
099      return rpcCall();
100    } catch (Exception e) {
101      throw ProtobufUtil.handleRemoteException(e);
102    }
103  }
104
105  /**
106   * Run the RPC call. Implement this method. To get at the rpcController that has been created
107   * and configured to make this rpc call, use getRpcController(). We are trying to contain
108   * rpcController references so we don't pollute codebase with protobuf references; keep the
109   * protobuf references contained and only present in a few classes rather than all about the
110   * code base.
111   * @throws Exception
112   */
113  protected abstract V rpcCall() throws Exception;
114
115  HBaseRpcController getRpcController() {
116    return this.rpcController;
117  }
118
119  void setPriority(final int priority) {
120    if (this.rpcController != null) {
121      this.rpcController.setPriority(priority);
122    }
123  }
124
125  void setPriority(final TableName tableName) {
126    if (this.rpcController != null) {
127      this.rpcController.setPriority(tableName);
128    }
129  }
130
131  /**
132   * @param regionName RegionName. If hbase:meta, we'll set high priority.
133   */
134  void setPriority(final byte[] regionName) {
135    if (isMetaRegion(regionName)) {
136      setPriority(TableName.META_TABLE_NAME);
137    }
138  }
139
140  private static boolean isMetaRegion(final byte[] regionName) {
141    return Bytes.equals(regionName, RegionInfoBuilder.FIRST_META_REGIONINFO.getRegionName()) ||
142      Bytes.equals(regionName, RegionInfoBuilder.FIRST_META_REGIONINFO.getEncodedNameAsBytes());
143  }
144}