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