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.ServerName;
027import org.apache.hadoop.hbase.ipc.RpcControllerFactory;
028import org.apache.yetus.audience.InterfaceAudience;
029import org.slf4j.Logger;
030import org.slf4j.LoggerFactory;
031
032import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
033import org.apache.hadoop.hbase.shaded.protobuf.RequestConverter;
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 an HBaseHbck directly.
050 *
051 * <p>Connection should be an <i>unmanaged</i> connection obtained via
052 * {@link ConnectionFactory#createConnection(Configuration)}.</p>
053 *
054 * <p>NOTE: The methods in here can do damage to a cluster if applied in the wrong sequence or at
055 * the wrong time. Use with caution. For experts only. These methods are only for the
056 * extreme case where the cluster has been damaged or has achieved an inconsistent state because
057 * of some unforeseen circumstance or bug and requires manual intervention.
058 *
059 * <p>An instance of this class is lightweight and not-thread safe. A new instance should be created
060 * by each thread. Pooling or caching of the instance is not recommended.</p>
061 *
062 * @see ConnectionFactory
063 * @see ClusterConnection
064 * @see Hbck
065 */
066@InterfaceAudience.Private
067public class HBaseHbck implements Hbck {
068  private static final Logger LOG = LoggerFactory.getLogger(HBaseHbck.class);
069
070  private boolean aborted;
071  private final BlockingInterface hbck;
072
073  private RpcControllerFactory rpcControllerFactory;
074
075  HBaseHbck(BlockingInterface hbck, RpcControllerFactory rpcControllerFactory) {
076    this.hbck = hbck;
077    this.rpcControllerFactory = rpcControllerFactory;
078  }
079
080  @Override
081  public void close() throws IOException {
082    // currently does nothing
083  }
084
085  @Override
086  public void abort(String why, Throwable e) {
087    this.aborted = true;
088    // Currently does nothing but throw the passed message and exception
089    throw new RuntimeException(why, e);
090  }
091
092  @Override
093  public boolean isAborted() {
094    return this.aborted;
095  }
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> scheduleServerCrashProcedures(List<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}