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.master.procedure; 019import java.io.IOException; 020import org.apache.hadoop.fs.Path; 021import org.apache.hadoop.hbase.ServerName; 022import org.apache.hadoop.hbase.master.SplitWALManager; 023import org.apache.hadoop.hbase.procedure2.ProcedureStateSerializer; 024import org.apache.hadoop.hbase.procedure2.ProcedureSuspendedException; 025import org.apache.hadoop.hbase.procedure2.ProcedureUtil; 026import org.apache.hadoop.hbase.procedure2.ProcedureYieldException; 027import org.apache.hadoop.hbase.procedure2.StateMachineProcedure; 028import org.apache.hadoop.hbase.util.RetryCounter; 029import org.apache.hadoop.hbase.wal.AbstractFSWALProvider; 030import org.apache.yetus.audience.InterfaceAudience; 031import org.slf4j.Logger; 032import org.slf4j.LoggerFactory; 033import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting; 034import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 035import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProcedureProtos; 036import org.apache.hadoop.hbase.shaded.protobuf.generated.ProcedureProtos; 037 038/** 039 * The procedure is to split a WAL. It will get an available region server and 040 * schedule a {@link SplitWALRemoteProcedure} to actually send the request to region 041 * server to split this WAL. 042 * It also check if the split wal task really succeed. If the WAL still exists, it will 043 * schedule another region server to split this WAL. 044 */ 045@InterfaceAudience.Private 046public class SplitWALProcedure 047 extends StateMachineProcedure<MasterProcedureEnv, MasterProcedureProtos.SplitWALState> 048 implements ServerProcedureInterface { 049 private static final Logger LOG = LoggerFactory.getLogger(SplitWALProcedure.class); 050 private String walPath; 051 private ServerName worker; 052 private ServerName crashedServer; 053 private RetryCounter retryCounter; 054 055 public SplitWALProcedure() { 056 } 057 058 public SplitWALProcedure(String walPath, ServerName crashedServer) { 059 this.walPath = walPath; 060 this.crashedServer = crashedServer; 061 } 062 063 @Override 064 protected Flow executeFromState(MasterProcedureEnv env, MasterProcedureProtos.SplitWALState state) 065 throws ProcedureSuspendedException, ProcedureYieldException, InterruptedException { 066 SplitWALManager splitWALManager = env.getMasterServices().getSplitWALManager(); 067 switch (state) { 068 case ACQUIRE_SPLIT_WAL_WORKER: 069 worker = splitWALManager.acquireSplitWALWorker(this); 070 setNextState(MasterProcedureProtos.SplitWALState.DISPATCH_WAL_TO_WORKER); 071 return Flow.HAS_MORE_STATE; 072 case DISPATCH_WAL_TO_WORKER: 073 assert worker != null; 074 addChildProcedure(new SplitWALRemoteProcedure(worker, crashedServer, walPath)); 075 setNextState(MasterProcedureProtos.SplitWALState.RELEASE_SPLIT_WORKER); 076 return Flow.HAS_MORE_STATE; 077 case RELEASE_SPLIT_WORKER: 078 boolean finished; 079 try { 080 finished = splitWALManager.isSplitWALFinished(walPath); 081 } catch (IOException ioe) { 082 if (retryCounter == null) { 083 retryCounter = ProcedureUtil.createRetryCounter(env.getMasterConfiguration()); 084 } 085 long backoff = retryCounter.getBackoffTimeAndIncrementAttempts(); 086 LOG.warn("Failed to check whether splitting wal {} success, wait {} seconds to retry", 087 walPath, backoff / 1000, ioe); 088 setTimeout(Math.toIntExact(backoff)); 089 setState(ProcedureProtos.ProcedureState.WAITING_TIMEOUT); 090 skipPersistence(); 091 throw new ProcedureSuspendedException(); 092 } 093 splitWALManager.releaseSplitWALWorker(worker, env.getProcedureScheduler()); 094 if (!finished) { 095 LOG.warn("Failed to split wal {} by server {}, retry...", walPath, worker); 096 setNextState(MasterProcedureProtos.SplitWALState.ACQUIRE_SPLIT_WAL_WORKER); 097 return Flow.HAS_MORE_STATE; 098 } 099 ServerCrashProcedure.updateProgress(env, getParentProcId()); 100 return Flow.NO_MORE_STATE; 101 default: 102 throw new UnsupportedOperationException("unhandled state=" + state); 103 } 104 } 105 106 @Override 107 protected void rollbackState(MasterProcedureEnv env, 108 MasterProcedureProtos.SplitWALState splitOneWalState) 109 throws IOException, InterruptedException { 110 if (splitOneWalState == getInitialState()) { 111 return; 112 } 113 throw new UnsupportedOperationException(); 114 } 115 116 @Override 117 protected MasterProcedureProtos.SplitWALState getState(int stateId) { 118 return MasterProcedureProtos.SplitWALState.forNumber(stateId); 119 } 120 121 @Override 122 protected int getStateId(MasterProcedureProtos.SplitWALState state) { 123 return state.getNumber(); 124 } 125 126 @Override 127 protected MasterProcedureProtos.SplitWALState getInitialState() { 128 return MasterProcedureProtos.SplitWALState.ACQUIRE_SPLIT_WAL_WORKER; 129 } 130 131 @Override 132 protected void serializeStateData(ProcedureStateSerializer serializer) throws IOException { 133 super.serializeStateData(serializer); 134 MasterProcedureProtos.SplitWALData.Builder builder = 135 MasterProcedureProtos.SplitWALData.newBuilder(); 136 builder.setWalPath(walPath).setCrashedServer(ProtobufUtil.toServerName(crashedServer)); 137 if (worker != null) { 138 builder.setWorker(ProtobufUtil.toServerName(worker)); 139 } 140 serializer.serialize(builder.build()); 141 } 142 143 @Override 144 protected void deserializeStateData(ProcedureStateSerializer serializer) throws IOException { 145 super.deserializeStateData(serializer); 146 MasterProcedureProtos.SplitWALData data = 147 serializer.deserialize(MasterProcedureProtos.SplitWALData.class); 148 walPath = data.getWalPath(); 149 crashedServer = ProtobufUtil.toServerName(data.getCrashedServer()); 150 if (data.hasWorker()) { 151 worker = ProtobufUtil.toServerName(data.getWorker()); 152 } 153 } 154 155 @Override 156 protected synchronized boolean setTimeoutFailure(MasterProcedureEnv env) { 157 setState(ProcedureProtos.ProcedureState.RUNNABLE); 158 env.getProcedureScheduler().addFront(this); 159 return false; 160 } 161 162 public String getWAL() { 163 return walPath; 164 } 165 166 @VisibleForTesting 167 public ServerName getWorker(){ 168 return worker; 169 } 170 171 @Override 172 public ServerName getServerName() { 173 return this.crashedServer; 174 } 175 176 @Override 177 public boolean hasMetaTableRegion() { 178 return AbstractFSWALProvider.isMetaFile(new Path(walPath)); 179 } 180 181 @Override 182 public ServerOperationType getServerOperationType() { 183 return ServerOperationType.SPLIT_WAL; 184 } 185 186 @Override 187 protected void afterReplay(MasterProcedureEnv env){ 188 if (worker != null) { 189 if (env != null && env.getMasterServices() != null && 190 env.getMasterServices().getSplitWALManager() != null) { 191 env.getMasterServices().getSplitWALManager().addUsedSplitWALWorker(worker); 192 } 193 } 194 } 195 196 @Override protected void toStringClassDetails(StringBuilder builder) { 197 builder.append(getProcName()); 198 if (this.worker != null) { 199 builder.append(", worker="); 200 builder.append(this.worker); 201 } 202 if (this.retryCounter != null) { 203 builder.append(", retry="); 204 builder.append(this.retryCounter); 205 } 206 } 207 208 @Override public String getProcName() { 209 return getClass().getSimpleName() + " " + getWALNameFromStrPath(getWAL()); 210 } 211 212 /** 213 * @return Return the WAL filename when given a Path-as-a-string; i.e. return the last path 214 * component only. 215 */ 216 static String getWALNameFromStrPath(String path) { 217 int slashIndex = path.lastIndexOf('/'); 218 return slashIndex != -1? path.substring(slashIndex + 1): path; 219 } 220}