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