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 java.util.Optional;
022import org.apache.hadoop.fs.Path;
023import org.apache.hadoop.hbase.DoNotRetryIOException;
024import org.apache.hadoop.hbase.ServerName;
025import org.apache.hadoop.hbase.procedure2.ProcedureStateSerializer;
026import org.apache.hadoop.hbase.procedure2.RemoteProcedureDispatcher;
027import org.apache.hadoop.hbase.regionserver.SplitWALCallable;
028import org.apache.hadoop.hbase.wal.AbstractFSWALProvider;
029import org.apache.yetus.audience.InterfaceAudience;
030import org.slf4j.Logger;
031import org.slf4j.LoggerFactory;
032
033import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
034import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProcedureProtos;
035
036/**
037 * A remote procedure which is used to send split WAL request to region server. It will return null
038 * if the task succeeded or return a DoNotRetryIOException. {@link SplitWALProcedure} will help
039 * handle the situation that encounters DoNotRetryIOException. Otherwise it will retry until
040 * success.
041 */
042@InterfaceAudience.Private
043public class SplitWALRemoteProcedure extends ServerRemoteProcedure
044  implements ServerProcedureInterface {
045  private static final Logger LOG = LoggerFactory.getLogger(SplitWALRemoteProcedure.class);
046  private String walPath;
047  private ServerName crashedServer;
048
049  public SplitWALRemoteProcedure() {
050  }
051
052  public SplitWALRemoteProcedure(ServerName worker, ServerName crashedServer, String wal) {
053    this.targetServer = worker;
054    this.crashedServer = crashedServer;
055    this.walPath = wal;
056  }
057
058  @Override
059  protected void rollback(MasterProcedureEnv env) throws IOException, InterruptedException {
060    throw new UnsupportedOperationException();
061  }
062
063  @Override
064  protected boolean abort(MasterProcedureEnv env) {
065    return false;
066  }
067
068  @Override
069  protected void serializeStateData(ProcedureStateSerializer serializer) throws IOException {
070    MasterProcedureProtos.SplitWALRemoteData.Builder builder =
071      MasterProcedureProtos.SplitWALRemoteData.newBuilder();
072    builder.setWalPath(walPath).setWorker(ProtobufUtil.toServerName(targetServer))
073      .setCrashedServer(ProtobufUtil.toServerName(crashedServer));
074    serializer.serialize(builder.build());
075  }
076
077  @Override
078  protected void deserializeStateData(ProcedureStateSerializer serializer) throws IOException {
079    MasterProcedureProtos.SplitWALRemoteData data =
080      serializer.deserialize(MasterProcedureProtos.SplitWALRemoteData.class);
081    walPath = data.getWalPath();
082    targetServer = ProtobufUtil.toServerName(data.getWorker());
083    crashedServer = ProtobufUtil.toServerName(data.getCrashedServer());
084  }
085
086  @Override
087  public Optional<RemoteProcedureDispatcher.RemoteOperation> remoteCallBuild(MasterProcedureEnv env,
088    ServerName serverName) {
089    return Optional.of(new RSProcedureDispatcher.ServerOperation(this, getProcId(),
090      SplitWALCallable.class, MasterProcedureProtos.SplitWALParameter.newBuilder()
091        .setWalPath(walPath).build().toByteArray()));
092  }
093
094  @Override
095  protected void complete(MasterProcedureEnv env, Throwable error) {
096    if (error == null) {
097      try {
098        env.getMasterServices().getSplitWALManager().archive(walPath);
099      } catch (IOException e) {
100        LOG.warn("Failed split of {}; ignore...", walPath, e);
101      }
102      succ = true;
103    } else {
104      if (error instanceof DoNotRetryIOException) {
105        LOG.warn("Sent {} to wrong server {}, try another", walPath, targetServer, error);
106        succ = true;
107      } else {
108        LOG.warn("Failed split of {}, retry...", walPath, error);
109        succ = false;
110      }
111    }
112  }
113
114  public String getWAL() {
115    return this.walPath;
116  }
117
118  @Override
119  public ServerName getServerName() {
120    // return the crashed server is to use the queue of root ServerCrashProcedure
121    return this.crashedServer;
122  }
123
124  @Override
125  public boolean hasMetaTableRegion() {
126    return AbstractFSWALProvider.isMetaFile(new Path(walPath));
127  }
128
129  @Override
130  public ServerOperationType getServerOperationType() {
131    return ServerOperationType.SPLIT_WAL_REMOTE;
132  }
133
134  @Override
135  protected void toStringClassDetails(StringBuilder builder) {
136    builder.append(getProcName());
137    if (this.targetServer != null) {
138      builder.append(", worker=");
139      builder.append(this.targetServer);
140    }
141  }
142
143  @Override
144  public String getProcName() {
145    return getClass().getSimpleName() + " " + SplitWALProcedure.getWALNameFromStrPath(getWAL());
146  }
147}