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 */
018package org.apache.hadoop.hbase.client;
019
020import java.io.Closeable;
021import java.io.IOException;
022import org.apache.hadoop.hbase.TableName;
023import org.apache.hadoop.hbase.ipc.HBaseRpcController;
024import org.apache.hadoop.hbase.ipc.RpcControllerFactory;
025import org.apache.hadoop.hbase.util.Bytes;
026import org.apache.yetus.audience.InterfaceAudience;
027
028import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
029
030/**
031 * A RetryingCallable for Master RPC operations. Implement the #rpcCall method. It will be retried
032 * on error. See its javadoc and the javadoc of #call(int). See {@link HBaseAdmin} for examples of
033 * how this is used. To get at the rpcController that has been created and configured to make this
034 * rpc call, use getRpcController(). We are trying to contain all protobuf references including
035 * references to rpcController so we don't pollute codebase with protobuf references; keep the
036 * protobuf references contained and only present in a few classes rather than all about the code
037 * base.
038 * <p>
039 * Like {@link RegionServerCallable} only in here, we can safely be PayloadCarryingRpcController all
040 * the time. This is not possible in the similar {@link RegionServerCallable} Callable because it
041 * 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
085   * {@link Exception} to {@link IOException}. It also does setup of an rpcController and calls
086   * through to the rpcCall() method which callers are expected to implement. If rpcController is an
087   * instance of 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 and
107   * 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 code
110   * base.
111   */
112  protected abstract V rpcCall() throws Exception;
113
114  HBaseRpcController getRpcController() {
115    return this.rpcController;
116  }
117
118  void setPriority(final int priority) {
119    if (this.rpcController != null) {
120      this.rpcController.setPriority(priority);
121    }
122  }
123
124  void setPriority(final TableName tableName) {
125    if (this.rpcController != null) {
126      this.rpcController.setPriority(tableName);
127    }
128  }
129
130  /**
131   * @param regionName RegionName. If hbase:meta, we'll set high priority.
132   */
133  void setPriority(final byte[] regionName) {
134    if (isMetaRegion(regionName)) {
135      setPriority(TableName.META_TABLE_NAME);
136    }
137  }
138
139  private static boolean isMetaRegion(final byte[] regionName) {
140    return Bytes.equals(regionName, RegionInfoBuilder.FIRST_META_REGIONINFO.getRegionName())
141      || Bytes.equals(regionName, RegionInfoBuilder.FIRST_META_REGIONINFO.getEncodedNameAsBytes());
142  }
143}