Skip to content

Commit

Permalink
Show progress during backup shell command
Browse files Browse the repository at this point in the history
  • Loading branch information
Gokturk Gezer committed Nov 8, 2019
1 parent 5957714 commit 8bce1c8
Showing 1 changed file with 73 additions and 28 deletions.
101 changes: 73 additions & 28 deletions shell/src/main/java/alluxio/cli/fsadmin/command/BackupCommand.java
Expand Up @@ -11,19 +11,20 @@

package alluxio.cli.fsadmin.command;

import alluxio.Constants;
import alluxio.annotation.PublicApi;
import alluxio.cli.CommandUtils;
import alluxio.conf.AlluxioConfiguration;
import alluxio.exception.status.AlluxioStatusException;
import alluxio.exception.status.InvalidArgumentException;
import alluxio.grpc.BackupPOptions;
import alluxio.grpc.BackupPOptions.Builder;
import alluxio.util.CommonUtils;
import alluxio.wire.BackupResponse;
import alluxio.grpc.BackupPRequest;
import alluxio.grpc.BackupState;
import alluxio.wire.BackupStatus;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.lang.StringUtils;

import java.io.IOException;

Expand All @@ -38,8 +39,16 @@ public class BackupCommand extends AbstractFsAdminCommand {
.longOpt("local")
.required(false)
.hasArg(false)
.desc("whether to write the backup to the master's local filesystem instead of the root"
+ " UFS")
.desc("whether to write the backup to the master's local filesystem"
+ " instead of the root UFS")
.build();
private static final Option ALLOW_LEADER_OPTION =
Option.builder()
.longOpt("allow-leader")
.required(false)
.hasArg(false)
.desc("whether to allow leader to take the backup when"
+ " HA cluster has no stand-by master.")
.build();
/**
* @param context fsadmin command context
Expand All @@ -56,36 +65,71 @@ public String getCommandName() {

@Override
public Options getOptions() {
return new Options().addOption(LOCAL_OPTION);
return new Options()
.addOption(LOCAL_OPTION)
.addOption(ALLOW_LEADER_OPTION);
}

@Override
public int run(CommandLine cl) throws IOException {
String[] args = cl.getArgs();
Builder opts = BackupPOptions.newBuilder();
BackupPRequest.Builder opts = BackupPRequest.newBuilder();
if (args.length >= 1) {
opts.setTargetDirectory(args[0]);
}
opts.setLocalFileSystem(cl.hasOption(LOCAL_OPTION.getLongOpt()));
// Create progress thread for showing progress while backup is in progress.
Thread progressThread = CommonUtils.createProgressThread(5 * Constants.SECOND_MS, System.out);
progressThread.start();
BackupResponse resp;
try {
resp = mMetaClient.backup(opts.build());
} finally {
progressThread.interrupt();
}
if (opts.getLocalFileSystem()) {
mPrintStream.printf("Successfully backed up journal to %s on master %s with %d entries%n",
resp.getBackupUri(), resp.getHostname(), resp.getEntryCount());
} else {
mPrintStream.printf("Successfully backed up journal to %s with %d entries%n",
resp.getBackupUri(), resp.getEntryCount());
}
opts.setOptions(
BackupPOptions.newBuilder()
.setRunAsync(true)
.setLocalFileSystem(cl.hasOption(LOCAL_OPTION.getLongOpt()))
.setAllowLeader(cl.hasOption(ALLOW_LEADER_OPTION.getLongOpt())));
// Take backup in async mode.
BackupStatus status = mMetaClient.backup(opts.build());
do {
// Backup could be after a fail-over.
if (status.getState() == BackupState.EMPTY) {
clearProgressLine();
mPrintStream.printf("Backup lost. Check Alluxio logs.%n");
return -1;
}
if (status.getState() == BackupState.COMPLETED) {
break;
} else if (status.getState() == BackupState.FAULTED) {
throw AlluxioStatusException.fromAlluxioException(status.getError());
} else {
// Generate progress line that will be replaced until backup is finished.
String progressMessage = String.format(" Backup state: %s", status.getState());
// Start showing entry count once backup started running.
if (status.getState() == BackupState.RUNNING) {
progressMessage += String.format(" | Entries processed: %d", status.getEntryCount());
}
clearProgressLine();
mPrintStream.write(progressMessage.getBytes());
mPrintStream.write("\r".getBytes());
mPrintStream.flush();
}
// Sleep 1sec before querying status again.
try {
Thread.sleep(1000);
status = mMetaClient.getBackupStatus();
} catch (InterruptedException ie) {
throw new RuntimeException("Interrupted while waiting for backup completion.");
}
} while (true);
clearProgressLine();
// Print final state.
mPrintStream.printf("Backup Host : %s%n", status.getHostname());
mPrintStream.printf("Backup URI : %s%n", status.getBackupUri());
mPrintStream.printf("Backup Entry Count : %d%n", status.getEntryCount());
return 0;
}

private void clearProgressLine() throws IOException {
final int progressLineLength = 75;
// Clear progress line.
mPrintStream.write(StringUtils.repeat(" ", progressLineLength).getBytes());
mPrintStream.write("\r".getBytes());
}

@Override
public String getUsage() {
return "backup [directory] [--local]";
Expand All @@ -97,12 +141,13 @@ public String getDescription() {
+ " directory to back up to can be overridden by specifying a directory here. The directory"
+ " path is relative to the root UFS. To write the backup to the local disk of the primary"
+ " master, use --local and specify a filesystem path. Backing up metadata"
+ " requires a pause in master metadata changes, so use this command sparingly to"
+ " avoid interfering with other users of the system.";
+ " will be delegated to secondary masters in HA cluster. Use --allow-leader for"
+ " leader to take the backup when there are no secondaries.(This will pause"
+ " metadata changes during the backup.";
}

@Override
public void validateArgs(CommandLine cl) throws InvalidArgumentException {
CommandUtils.checkNumOfArgsNoMoreThan(this, cl, 1);
CommandUtils.checkNumOfArgsNoMoreThan(this, cl, 2);
}
}

0 comments on commit 8bce1c8

Please sign in to comment.