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.IOException;
021import java.util.List;
022import java.util.concurrent.Callable;
023import java.util.stream.Collectors;
024
025import org.apache.hadoop.conf.Configuration;
026import org.apache.hadoop.hbase.ipc.RpcControllerFactory;
027import org.apache.yetus.audience.InterfaceAudience;
028import org.slf4j.Logger;
029import org.slf4j.LoggerFactory;
030
031import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
032import org.apache.hadoop.hbase.shaded.protobuf.RequestConverter;
033import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos;
034import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.AssignsResponse;
035import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.BypassProcedureRequest;
036import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.BypassProcedureResponse;
037import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.FixMetaRequest;
038import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.GetTableStateResponse;
039import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.HbckService.BlockingInterface;
040import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.RunHbckChoreRequest;
041import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.RunHbckChoreResponse;
042import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ScheduleServerCrashProcedureResponse;
043import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.UnassignsResponse;
044
045import org.apache.hbase.thirdparty.com.google.protobuf.ServiceException;
046
047/**
048 * Use {@link ClusterConnection#getHbck()} to obtain an instance of {@link Hbck} instead of
049 * constructing
050 * an HBaseHbck directly. This will be mostly used by hbck tool.
051 *
052 * <p>Connection should be an <i>unmanaged</i> connection obtained via
053 * {@link ConnectionFactory#createConnection(Configuration)}.</p>
054 *
055 * <p>An instance of this class is lightweight and not-thread safe. A new instance should be created
056 * by each thread. Pooling or caching of the instance is not recommended.</p>
057 *
058 * @see ConnectionFactory
059 * @see ClusterConnection
060 * @see Hbck
061 */
062@InterfaceAudience.Private
063public class HBaseHbck implements Hbck {
064  private static final Logger LOG = LoggerFactory.getLogger(HBaseHbck.class);
065
066  private boolean aborted;
067  private final BlockingInterface hbck;
068
069  private RpcControllerFactory rpcControllerFactory;
070
071  HBaseHbck(BlockingInterface hbck, RpcControllerFactory rpcControllerFactory) {
072    this.hbck = hbck;
073    this.rpcControllerFactory = rpcControllerFactory;
074  }
075
076  @Override
077  public void close() throws IOException {
078    // currently does nothing
079  }
080
081  @Override
082  public void abort(String why, Throwable e) {
083    this.aborted = true;
084    // Currently does nothing but throw the passed message and exception
085    throw new RuntimeException(why, e);
086  }
087
088  @Override
089  public boolean isAborted() {
090    return this.aborted;
091  }
092
093  /**
094   * NOTE: This is a dangerous action, as existing running procedures for the table or regions
095   * which belong to the table may get confused.
096   */
097  @Override
098  public TableState setTableStateInMeta(TableState state) throws IOException {
099    try {
100      GetTableStateResponse response = hbck.setTableStateInMeta(
101          rpcControllerFactory.newController(),
102          RequestConverter.buildSetTableStateInMetaRequest(state));
103      return TableState.convert(state.getTableName(), response.getTableState());
104    } catch (ServiceException se) {
105      LOG.debug("table={}, state={}", state.getTableName(), state.getState(), se);
106      throw new IOException(se);
107    }
108  }
109
110  @Override
111  public List<Long> assigns(List<String> encodedRegionNames, boolean override)
112      throws IOException {
113    try {
114      AssignsResponse response = this.hbck.assigns(rpcControllerFactory.newController(),
115          RequestConverter.toAssignRegionsRequest(encodedRegionNames, override));
116      return response.getPidList();
117    } catch (ServiceException se) {
118      LOG.debug(toCommaDelimitedString(encodedRegionNames), se);
119      throw new IOException(se);
120    }
121  }
122
123  @Override
124  public List<Long> unassigns(List<String> encodedRegionNames, boolean override)
125      throws IOException {
126    try {
127      UnassignsResponse response = this.hbck.unassigns(rpcControllerFactory.newController(),
128          RequestConverter.toUnassignRegionsRequest(encodedRegionNames, override));
129      return response.getPidList();
130    } catch (ServiceException se) {
131      LOG.debug(toCommaDelimitedString(encodedRegionNames), se);
132      throw new IOException(se);
133    }
134  }
135
136  private static String toCommaDelimitedString(List<String> list) {
137    return list.stream().collect(Collectors.joining(", "));
138  }
139
140  @Override
141  public List<Boolean> bypassProcedure(List<Long> pids, long waitTime, boolean override,
142      boolean recursive)
143      throws IOException {
144    BypassProcedureResponse response = ProtobufUtil.call(
145        new Callable<BypassProcedureResponse>() {
146          @Override
147          public BypassProcedureResponse call() throws Exception {
148            try {
149              return hbck.bypassProcedure(rpcControllerFactory.newController(),
150                  BypassProcedureRequest.newBuilder().addAllProcId(pids).
151                      setWaitTime(waitTime).setOverride(override).setRecursive(recursive).build());
152            } catch (Throwable t) {
153              LOG.error(pids.stream().map(i -> i.toString()).
154                  collect(Collectors.joining(", ")), t);
155              throw t;
156            }
157          }
158        });
159    return response.getBypassedList();
160  }
161
162  @Override
163  public List<Long> scheduleServerCrashProcedure(List<HBaseProtos.ServerName> serverNames)
164      throws IOException {
165    try {
166      ScheduleServerCrashProcedureResponse response =
167          this.hbck.scheduleServerCrashProcedure(rpcControllerFactory.newController(),
168            RequestConverter.toScheduleServerCrashProcedureRequest(serverNames));
169      return response.getPidList();
170    } catch (ServiceException se) {
171      LOG.debug(toCommaDelimitedString(
172        serverNames.stream().map(serverName -> ProtobufUtil.toServerName(serverName).toString())
173            .collect(Collectors.toList())),
174        se);
175      throw new IOException(se);
176    }
177  }
178
179  @Override
180  public boolean runHbckChore() throws IOException {
181    try {
182      RunHbckChoreResponse response = this.hbck.runHbckChore(rpcControllerFactory.newController(),
183          RunHbckChoreRequest.newBuilder().build());
184      return response.getRan();
185    } catch (ServiceException se) {
186      LOG.debug("Failed to run HBCK chore", se);
187      throw new IOException(se);
188    }
189  }
190
191  @Override
192  public void fixMeta() throws IOException {
193    try {
194      this.hbck.fixMeta(rpcControllerFactory.newController(), FixMetaRequest.newBuilder().build());
195    } catch (ServiceException se) {
196      throw new IOException(se);
197    }
198  }
199}