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