/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.hadoop.hbase.master;
import static org.apache.hadoop.hbase.HConstants.DEFAULT_HBASE_SPLIT_WAL_MAX_SPLITTER;
import static org.apache.hadoop.hbase.HConstants.HBASE_SPLIT_WAL_MAX_SPLITTER;
import static org.apache.hadoop.hbase.master.MasterWalManager.META_FILTER;
import static org.apache.hadoop.hbase.master.MasterWalManager.NON_META_FILTER;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.PathIsNotEmptyDirectoryException;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.master.procedure.MasterProcedureScheduler;
import org.apache.hadoop.hbase.master.procedure.SplitWALProcedure;
import org.apache.hadoop.hbase.procedure2.Procedure;
import org.apache.hadoop.hbase.procedure2.ProcedureEvent;
import org.apache.hadoop.hbase.procedure2.ProcedureSuspendedException;
import org.apache.hadoop.hbase.util.CommonFSUtils;
import org.apache.hadoop.hbase.wal.AbstractFSWALProvider;
import org.apache.hadoop.hbase.wal.WALSplitUtil;
import org.apache.yetus.audience.InterfaceAudience;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Create {@link SplitWALProcedure} for each WAL which need to split. Manage the workers for each
 * {@link SplitWALProcedure}.
 * Total number of workers is (number of online servers) * (HBASE_SPLIT_WAL_MAX_SPLITTER).
 * Helps assign and release workers for split tasks.
 * Provide helper method to delete split WAL file and directory.
 *
 * The user can get the SplitWALProcedures via splitWALs(crashedServer, splitMeta)
 * can get the files that need to split via getWALsToSplit(crashedServer, splitMeta)
 * can delete the splitting WAL and directory via deleteSplitWAL(wal)
 * and deleteSplitWAL(crashedServer)
 * can check if splitting WALs of a crashed server is success via isSplitWALFinished(walPath)
 * can acquire and release a worker for splitting WAL via acquireSplitWALWorker(procedure)
 * and releaseSplitWALWorker(worker, scheduler)
 *
 * This class is to replace the zk-based WAL splitting related code, {@link MasterWalManager},
 * {@link SplitLogManager}, {@link org.apache.hadoop.hbase.zookeeper.ZKSplitLog} and
 * {@link org.apache.hadoop.hbase.coordination.ZKSplitLogManagerCoordination} can be removed
 * after we switch to procedure-based WAL splitting.
 * @see SplitLogManager for the original distributed split WAL manager.
 */
@InterfaceAudience.Private
public class SplitWALManager {
  private static final Logger LOG = LoggerFactory.getLogger(SplitWALManager.class);

  private final MasterServices master;
  private final SplitWorkerAssigner splitWorkerAssigner;
  private final Path rootDir;
  private final FileSystem fs;
  private final Configuration conf;
  private final Path walArchiveDir;

  public SplitWALManager(MasterServices master) throws IOException {
    this.master = master;
    this.conf = master.getConfiguration();
    this.splitWorkerAssigner = new SplitWorkerAssigner(this.master,
        conf.getInt(HBASE_SPLIT_WAL_MAX_SPLITTER, DEFAULT_HBASE_SPLIT_WAL_MAX_SPLITTER));
    this.rootDir = master.getMasterFileSystem().getWALRootDir();
    this.fs = master.getMasterFileSystem().getWALFileSystem();
    this.walArchiveDir = new Path(this.rootDir, HConstants.HREGION_OLDLOGDIR_NAME);
  }

  public List<Procedure> splitWALs(ServerName crashedServer, boolean splitMeta)
      throws IOException {
    try {
      // 1. list all splitting files
      List<FileStatus> splittingFiles = getWALsToSplit(crashedServer, splitMeta);
      // 2. create corresponding procedures
      return createSplitWALProcedures(splittingFiles, crashedServer);
    } catch (IOException e) {
      LOG.error("Failed to create procedures for splitting WALs of {}", crashedServer, e);
      throw e;
    }
  }

  public List<FileStatus> getWALsToSplit(ServerName serverName, boolean splitMeta)
      throws IOException {
    List<Path> logDirs = master.getMasterWalManager().getLogDirs(Collections.singleton(serverName));
    List<FileStatus> fileStatuses =
      SplitLogManager.getFileList(this.conf, logDirs, splitMeta ? META_FILTER : NON_META_FILTER);
    LOG.info("{} WAL count={}, meta={}", serverName, fileStatuses.size(), splitMeta);
    return fileStatuses;
  }

  private Path getWALSplitDir(ServerName serverName) {
    Path logDir =
        new Path(this.rootDir, AbstractFSWALProvider.getWALDirectoryName(serverName.toString()));
    return logDir.suffix(AbstractFSWALProvider.SPLITTING_EXT);
  }

  /**
   * Archive processed WAL
   */
  public void archive(String wal) throws IOException {
    WALSplitUtil.moveWAL(this.fs, new Path(wal), this.walArchiveDir);
  }

  public void deleteWALDir(ServerName serverName) throws IOException {
    Path splitDir = getWALSplitDir(serverName);
    try {
      if (!fs.delete(splitDir, false)) {
        LOG.warn("Failed delete {}, contains {}", splitDir, fs.listFiles(splitDir, true));
      }
    } catch (PathIsNotEmptyDirectoryException e) {
      FileStatus [] files = CommonFSUtils.listStatus(fs, splitDir);
      LOG.warn("PathIsNotEmptyDirectoryException {}",
        Arrays.stream(files).map(f -> f.getPath()).collect(Collectors.toList()));
      throw e;
    }
  }

  public boolean isSplitWALFinished(String walPath) throws IOException {
    return !fs.exists(new Path(rootDir, walPath));
  }

  List<Procedure> createSplitWALProcedures(List<FileStatus> splittingWALs,
      ServerName crashedServer) {
    return splittingWALs.stream()
        .map(wal -> new SplitWALProcedure(wal.getPath().toString(), crashedServer))
        .collect(Collectors.toList());
  }

  /**
   * Acquire a split WAL worker
   * @param procedure split WAL task
   * @return an available region server which could execute this task
   * @throws ProcedureSuspendedException if there is no available worker,
   *         it will throw this exception to WAIT the procedure.
   */
  public ServerName acquireSplitWALWorker(Procedure<?> procedure)
      throws ProcedureSuspendedException {
    Optional<ServerName> worker = splitWorkerAssigner.acquire();
    if (worker.isPresent()) {
      LOG.debug("Acquired split WAL worker={}", worker.get());
      return worker.get();
    }
    splitWorkerAssigner.suspend(procedure);
    throw new ProcedureSuspendedException();
  }

  /**
   * After the worker finished the split WAL task, it will release the worker, and wake up all the
   * suspend procedures in the ProcedureEvent
   * @param worker worker which is about to release
   * @param scheduler scheduler which is to wake up the procedure event
   */
  public void releaseSplitWALWorker(ServerName worker, MasterProcedureScheduler scheduler) {
    LOG.debug("Release split WAL worker={}", worker);
    splitWorkerAssigner.release(worker);
    splitWorkerAssigner.wake(scheduler);
  }

  /**
   * When master restart, there will be a new splitWorkerAssigner. But if there are splitting WAL
   * tasks running on the region server side, they will not be count by the new splitWorkerAssigner.
   * Thus we should add the workers of running tasks to the assigner when we load the procedures
   * from MasterProcWALs.
   * @param worker region server which is executing a split WAL task
   */
  public void addUsedSplitWALWorker(ServerName worker){
    splitWorkerAssigner.addUsedWorker(worker);
  }

  /**
   * help assign and release a worker for each WAL splitting task
   * For each worker, concurrent running splitting task should be no more than maxSplitTasks
   * If a task failed to acquire a worker, it will suspend and wait for workers available
   *
   */
  private static final class SplitWorkerAssigner implements ServerListener {
    private int maxSplitTasks;
    private final ProcedureEvent<?> event;
    private Map<ServerName, Integer> currentWorkers = new HashMap<>();
    private MasterServices master;

    public SplitWorkerAssigner(MasterServices master, int maxSplitTasks) {
      this.maxSplitTasks = maxSplitTasks;
      this.master = master;
      this.event = new ProcedureEvent<>("split-WAL-worker-assigning");
      // ServerManager might be null in a test context where we are mocking; allow for this
      ServerManager sm = this.master.getServerManager();
      if (sm != null) {
        sm.registerListener(this);
      }
    }

    public synchronized Optional<ServerName> acquire() {
      List<ServerName> serverList = master.getServerManager().getOnlineServersList();
      Collections.shuffle(serverList);
      Optional<ServerName> worker = serverList.stream().filter(
        serverName -> !currentWorkers.containsKey(serverName) || currentWorkers.get(serverName) > 0)
          .findAny();
      if (worker.isPresent()) {
        currentWorkers.compute(worker.get(), (serverName,
            availableWorker) -> availableWorker == null ? maxSplitTasks - 1 : availableWorker - 1);
      }
      return worker;
    }

    public synchronized void release(ServerName serverName) {
      currentWorkers.compute(serverName, (k, v) -> v == null ? null : v + 1);
    }

    public void suspend(Procedure<?> proc) {
      event.suspend();
      event.suspendIfNotReady(proc);
    }

    public void wake(MasterProcedureScheduler scheduler) {
      if (!event.isReady()) {
        event.wake(scheduler);
      }
    }

    @Override
    public void serverAdded(ServerName worker) {
      this.wake(master.getMasterProcedureExecutor().getEnvironment().getProcedureScheduler());
    }

    public synchronized void addUsedWorker(ServerName worker) {
      // load used worker when master restart
      currentWorkers.compute(worker, (serverName,
          availableWorker) -> availableWorker == null ? maxSplitTasks - 1 : availableWorker - 1);
    }
  }
}
