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.hadoop.hbase.shaded.protobuf.ProtobufUtil;
028import org.apache.hadoop.hbase.shaded.protobuf.RequestConverter;
029import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos;
030import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos;
031import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.GetTableStateResponse;
032import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.HbckService.BlockingInterface;
033
034import org.apache.hbase.thirdparty.com.google.protobuf.ServiceException;
035
036import org.apache.yetus.audience.InterfaceAudience;
037
038import org.slf4j.Logger;
039import org.slf4j.LoggerFactory;
040
041
042/**
043 * Use {@link ClusterConnection#getHbck()} to obtain an instance of {@link Hbck} instead of
044 * constructing an HBaseHbck directly.
045 *
046 * <p>Connection should be an <i>unmanaged</i> connection obtained via
047 * {@link ConnectionFactory#createConnection(Configuration)}.</p>
048 *
049 * <p>NOTE: The methods in here can do damage to a cluster if applied in the wrong sequence or at
050 * the wrong time. Use with caution. For experts only. These methods are only for the
051 * extreme case where the cluster has been damaged or has achieved an inconsistent state because
052 * of some unforeseen circumstance or bug and requires manual intervention.
053 *
054 * <p>An instance of this class is lightweight and not-thread safe. A new instance should be created
055 * by each thread. Pooling or caching of the instance is not recommended.</p>
056 *
057 * @see ConnectionFactory
058 * @see ClusterConnection
059 * @see Hbck
060 */
061@InterfaceAudience.Private
062public class HBaseHbck implements Hbck {
063  private static final Logger LOG = LoggerFactory.getLogger(HBaseHbck.class);
064
065  private boolean aborted;
066  private final BlockingInterface hbck;
067
068  private RpcControllerFactory rpcControllerFactory;
069
070  HBaseHbck(BlockingInterface hbck, RpcControllerFactory rpcControllerFactory) {
071    this.hbck = hbck;
072    this.rpcControllerFactory = rpcControllerFactory;
073  }
074
075  @Override
076  public void close() throws IOException {
077    // currently does nothing
078  }
079
080  @Override
081  public void abort(String why, Throwable e) {
082    this.aborted = true;
083    // Currently does nothing but throw the passed message and exception
084    throw new RuntimeException(why, e);
085  }
086
087  @Override
088  public boolean isAborted() {
089    return this.aborted;
090  }
091
092  @Override
093  public TableState setTableStateInMeta(TableState state) throws IOException {
094    try {
095      GetTableStateResponse response = hbck.setTableStateInMeta(
096          rpcControllerFactory.newController(),
097          RequestConverter.buildSetTableStateInMetaRequest(state));
098      return TableState.convert(state.getTableName(), response.getTableState());
099    } catch (ServiceException se) {
100      LOG.debug("table={}, state={}", state.getTableName(), state.getState(), se);
101      throw new IOException(se);
102    }
103  }
104
105  @Override
106  public List<Long> assigns(List<String> encodedRegionNames, boolean override)
107      throws IOException {
108    try {
109      MasterProtos.AssignsResponse response =
110          this.hbck.assigns(rpcControllerFactory.newController(),
111              RequestConverter.toAssignRegionsRequest(encodedRegionNames, override));
112      return response.getPidList();
113    } catch (ServiceException se) {
114      LOG.debug(toCommaDelimitedString(encodedRegionNames), se);
115      throw new IOException(se);
116    }
117  }
118
119  @Override
120  public List<Long> unassigns(List<String> encodedRegionNames, boolean override)
121      throws IOException {
122    try {
123      MasterProtos.UnassignsResponse response =
124          this.hbck.unassigns(rpcControllerFactory.newController(),
125              RequestConverter.toUnassignRegionsRequest(encodedRegionNames, override));
126      return response.getPidList();
127    } catch (ServiceException se) {
128      LOG.debug(toCommaDelimitedString(encodedRegionNames), se);
129      throw new IOException(se);
130    }
131  }
132
133  private static String toCommaDelimitedString(List<String> list) {
134    return list.stream().collect(Collectors.joining(", "));
135  }
136
137  @Override
138  public List<Boolean> bypassProcedure(List<Long> pids, long waitTime, boolean override,
139      boolean recursive)
140      throws IOException {
141    MasterProtos.BypassProcedureResponse response = ProtobufUtil.call(
142        new Callable<MasterProtos.BypassProcedureResponse>() {
143          @Override
144          public MasterProtos.BypassProcedureResponse call() throws Exception {
145            try {
146              return hbck.bypassProcedure(rpcControllerFactory.newController(),
147                  MasterProtos.BypassProcedureRequest.newBuilder().addAllProcId(pids).
148                      setWaitTime(waitTime).setOverride(override).setRecursive(recursive).build());
149            } catch (Throwable t) {
150              LOG.error(pids.stream().map(i -> i.toString()).
151                  collect(Collectors.joining(", ")), t);
152              throw t;
153            }
154          }
155        });
156    return response.getBypassedList();
157  }
158
159  @Override
160  public List<Long> scheduleServerCrashProcedure(List<HBaseProtos.ServerName> serverNames)
161      throws IOException {
162    try {
163      MasterProtos.ScheduleServerCrashProcedureResponse response =
164          this.hbck.scheduleServerCrashProcedure(rpcControllerFactory.newController(),
165            RequestConverter.toScheduleServerCrashProcedureRequest(serverNames));
166      return response.getPidList();
167    } catch (ServiceException se) {
168      LOG.debug(toCommaDelimitedString(
169        serverNames.stream().map(serverName -> ProtobufUtil.toServerName(serverName).toString())
170            .collect(Collectors.toList())),
171        se);
172      throw new IOException(se);
173    }
174  }
175}