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}