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;
019
020import java.io.IOException;
021import org.apache.hadoop.hbase.ServerName;
022import org.apache.hadoop.hbase.procedure2.ProcedureStateSerializer;
023import org.apache.hadoop.hbase.procedure2.ProcedureSuspendedException;
024import org.apache.hadoop.hbase.procedure2.ProcedureUtil;
025import org.apache.hadoop.hbase.procedure2.ProcedureYieldException;
026import org.apache.hadoop.hbase.procedure2.StateMachineProcedure;
027import org.apache.hadoop.hbase.util.RetryCounter;
028import org.apache.yetus.audience.InterfaceAudience;
029import org.slf4j.Logger;
030import org.slf4j.LoggerFactory;
031
032import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProcedureProtos.SwitchRpcThrottleState;
033import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProcedureProtos.SwitchRpcThrottleStateData;
034import org.apache.hadoop.hbase.shaded.protobuf.generated.ProcedureProtos;
035
036/**
037 * The procedure to switch rpc throttle
038 */
039@InterfaceAudience.Private
040public class SwitchRpcThrottleProcedure
041  extends StateMachineProcedure<MasterProcedureEnv, SwitchRpcThrottleState>
042  implements GlobalProcedureInterface {
043
044  private static Logger LOG = LoggerFactory.getLogger(SwitchRpcThrottleProcedure.class);
045
046  private boolean rpcThrottleEnabled;
047  private ProcedurePrepareLatch syncLatch;
048  private ServerName serverName;
049  private RetryCounter retryCounter;
050
051  public SwitchRpcThrottleProcedure() {
052  }
053
054  public SwitchRpcThrottleProcedure(boolean rpcThrottleEnabled, ServerName serverName,
055    final ProcedurePrepareLatch syncLatch) {
056    this.syncLatch = syncLatch;
057    this.rpcThrottleEnabled = rpcThrottleEnabled;
058    this.serverName = serverName;
059  }
060
061  @Override
062  protected Flow executeFromState(MasterProcedureEnv env, SwitchRpcThrottleState state)
063    throws ProcedureSuspendedException, ProcedureYieldException, InterruptedException {
064    switch (state) {
065      case UPDATE_SWITCH_RPC_THROTTLE_STORAGE:
066        try {
067          switchThrottleState(env, rpcThrottleEnabled);
068        } catch (IOException e) {
069          if (retryCounter == null) {
070            retryCounter = ProcedureUtil.createRetryCounter(env.getMasterConfiguration());
071          }
072          long backoff = retryCounter.getBackoffTimeAndIncrementAttempts();
073          LOG.warn("Failed to store rpc throttle value {}, sleep {} secs and retry",
074            rpcThrottleEnabled, backoff / 1000, e);
075          setTimeout(Math.toIntExact(backoff));
076          setState(ProcedureProtos.ProcedureState.WAITING_TIMEOUT);
077          skipPersistence();
078          throw new ProcedureSuspendedException();
079        }
080        setNextState(SwitchRpcThrottleState.SWITCH_RPC_THROTTLE_ON_RS);
081        return Flow.HAS_MORE_STATE;
082      case SWITCH_RPC_THROTTLE_ON_RS:
083        SwitchRpcThrottleRemoteProcedure[] subProcedures =
084          env.getMasterServices().getServerManager().getOnlineServersList().stream()
085            .map(sn -> new SwitchRpcThrottleRemoteProcedure(sn, rpcThrottleEnabled))
086            .toArray(SwitchRpcThrottleRemoteProcedure[]::new);
087        addChildProcedure(subProcedures);
088        setNextState(SwitchRpcThrottleState.POST_SWITCH_RPC_THROTTLE);
089        return Flow.HAS_MORE_STATE;
090      case POST_SWITCH_RPC_THROTTLE:
091        ProcedurePrepareLatch.releaseLatch(syncLatch, this);
092        return Flow.NO_MORE_STATE;
093      default:
094        throw new UnsupportedOperationException("unhandled state=" + state);
095    }
096  }
097
098  @Override
099  protected void rollbackState(MasterProcedureEnv env, SwitchRpcThrottleState state)
100    throws IOException, InterruptedException {
101  }
102
103  @Override
104  protected SwitchRpcThrottleState getState(int stateId) {
105    return SwitchRpcThrottleState.forNumber(stateId);
106  }
107
108  @Override
109  protected int getStateId(SwitchRpcThrottleState throttleState) {
110    return throttleState.getNumber();
111  }
112
113  @Override
114  protected SwitchRpcThrottleState getInitialState() {
115    return SwitchRpcThrottleState.UPDATE_SWITCH_RPC_THROTTLE_STORAGE;
116  }
117
118  @Override
119  protected SwitchRpcThrottleState getCurrentState() {
120    return super.getCurrentState();
121  }
122
123  @Override
124  protected void serializeStateData(ProcedureStateSerializer serializer) throws IOException {
125    super.serializeStateData(serializer);
126    serializer.serialize(
127      SwitchRpcThrottleStateData.newBuilder().setRpcThrottleEnabled(rpcThrottleEnabled).build());
128  }
129
130  @Override
131  protected void deserializeStateData(ProcedureStateSerializer serializer) throws IOException {
132    super.deserializeStateData(serializer);
133    SwitchRpcThrottleStateData data = serializer.deserialize(SwitchRpcThrottleStateData.class);
134    rpcThrottleEnabled = data.getRpcThrottleEnabled();
135  }
136
137  @Override
138  public String getGlobalId() {
139    return getClass().getSimpleName();
140  }
141
142  private void switchThrottleState(MasterProcedureEnv env, boolean rpcThrottleEnabled)
143    throws IOException {
144    env.getMasterServices().getRpcThrottleStateStore().set(rpcThrottleEnabled);
145  }
146
147  @Override
148  public void toStringClassDetails(StringBuilder sb) {
149    sb.append(getClass().getSimpleName());
150    sb.append(" server=");
151    sb.append(serverName);
152    sb.append(", rpcThrottleEnabled=");
153    sb.append(rpcThrottleEnabled);
154  }
155}