001/*
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *     http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019package org.apache.hadoop.hbase.master.procedure;
020
021import java.io.IOException;
022import java.util.Optional;
023import org.apache.hadoop.fs.Path;
024import org.apache.hadoop.hbase.DoNotRetryIOException;
025import org.apache.hadoop.hbase.ServerName;
026import org.apache.hadoop.hbase.procedure2.ProcedureStateSerializer;
027import org.apache.hadoop.hbase.procedure2.RemoteProcedureDispatcher;
028import org.apache.hadoop.hbase.regionserver.SplitWALCallable;
029import org.apache.hadoop.hbase.wal.AbstractFSWALProvider;
030import org.apache.yetus.audience.InterfaceAudience;
031import org.slf4j.Logger;
032import org.slf4j.LoggerFactory;
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.
038 * It will return null if the task succeeded or return a DoNotRetryIOException.
039 * {@link SplitWALProcedure} will help handle the situation that encounters
040 * DoNotRetryIOException. Otherwise it will retry until 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
090        .of(new RSProcedureDispatcher.ServerOperation(this, getProcId(), SplitWALCallable.class,
091            MasterProcedureProtos.SplitWALParameter.newBuilder().setWalPath(walPath).build()
092                .toByteArray()));
093  }
094
095  @Override
096  protected void complete(MasterProcedureEnv env, Throwable error) {
097    if (error == null) {
098      try {
099        env.getMasterServices().getSplitWALManager().deleteSplitWAL(walPath);
100      } catch (IOException e) {
101        LOG.warn("Failed split of {}; ignore...", walPath, e);
102      }
103      succ = true;
104    } else {
105      if (error instanceof DoNotRetryIOException) {
106        LOG.warn("Sent {} to wrong server {}, try another", walPath, targetServer, error);
107        succ = true;
108      } else {
109        LOG.warn("Failed split of {}, retry...", walPath, error);
110        succ = false;
111      }
112    }
113  }
114
115  public String getWAL() {
116    return this.walPath;
117  }
118
119  @Override
120  public ServerName getServerName() {
121    // return the crashed server is to use the queue of root ServerCrashProcedure
122    return this.crashedServer;
123  }
124
125  @Override
126  public boolean hasMetaTableRegion() {
127    return AbstractFSWALProvider.isMetaFile(new Path(walPath));
128  }
129
130  @Override
131  public ServerOperationType getServerOperationType() {
132    return ServerOperationType.SPLIT_WAL_REMOTE;
133  }
134
135  @Override 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 public String getProcName() {
144    return getClass().getSimpleName() + " " + SplitWALProcedure.getWALNameFromStrPath(getWAL());
145  }
146}