blob: 857045250afaff34c1d7f65a7b51847af804a344 [file] [log] [blame]
/*
* 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.bookkeeper.tools.cli.commands.bookie;
import com.beust.jcommander.Parameter;
import com.google.common.util.concurrent.UncheckedExecutionException;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.apache.bookkeeper.bookie.BookieImpl;
import org.apache.bookkeeper.bookie.BookieShell;
import org.apache.bookkeeper.client.BKException;
import org.apache.bookkeeper.client.BookKeeper;
import org.apache.bookkeeper.client.BookKeeperAdmin;
import org.apache.bookkeeper.client.UpdateLedgerOp;
import org.apache.bookkeeper.conf.ClientConfiguration;
import org.apache.bookkeeper.conf.ServerConfiguration;
import org.apache.bookkeeper.net.BookieId;
import org.apache.bookkeeper.tools.cli.helpers.BookieCommand;
import org.apache.bookkeeper.tools.framework.CliFlags;
import org.apache.bookkeeper.tools.framework.CliSpec;
import org.apache.bookkeeper.util.MathUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Command to update ledger command.
*/
public class FlipBookieIdCommand extends BookieCommand<FlipBookieIdCommand.FlipBookieIdFlags> {
static final Logger LOG = LoggerFactory.getLogger(FlipBookieIdCommand.class);
private static final String NAME = "flip-bookie-id";
private static final String DESC = "Update bookie id in ledgers (this may take a long time).";
public FlipBookieIdCommand() {
this(new FlipBookieIdFlags());
}
private FlipBookieIdCommand(FlipBookieIdFlags flags) {
super(CliSpec.<FlipBookieIdFlags>newBuilder()
.withName(NAME)
.withDescription(DESC)
.withFlags(flags)
.build());
}
/**
* Flags for update ledger command.
*/
@Accessors(fluent = true)
@Setter
public static class FlipBookieIdFlags extends CliFlags {
@Parameter(names = { "-host", "--hostname" },
description = "Expects configuration useHostNameAsBookieID=true as the option value (default: ip address)")
private boolean hostname;
@Parameter(names = { "-s", "--updatepersec" },
description = "Number of ledgers updating per second (default: 5 per sec)")
private int updatePerSec = 5;
@Parameter(names = { "-r",
"--maxOutstandingReads" }, description = "Max outstanding reads (default: 5 * updatespersec)")
private int maxOutstandingReads = updatePerSec * 5;
@Parameter(names = {"-l", "--limit"},
description = "Maximum number of ledgers of ledgers to update (default: no limit)")
private int limit = Integer.MIN_VALUE;
@Parameter(names = { "-v", "--verbose" }, description = "Print status of the ledger updation (default: false)")
private boolean verbose;
@Parameter(names = { "-p", "--printprogress" },
description = "Print messages on every configured seconds if verbose turned on (default: 10 secs)")
private long printProgress = 10;
}
@Override
public boolean apply(ServerConfiguration conf, FlipBookieIdFlags cmdFlags) {
try {
return updateLedger(conf, cmdFlags);
} catch (Exception e) {
throw new UncheckedExecutionException(e.getMessage(), e);
}
}
private boolean updateLedger(ServerConfiguration conf, FlipBookieIdFlags flags)
throws InterruptedException, BKException, IOException {
if (!conf.getUseHostNameAsBookieID() && flags.hostname) {
LOG.error("Expects configuration useHostNameAsBookieID=true as the option value");
return false;
} else if (conf.getUseHostNameAsBookieID() && !flags.hostname) {
LOG.error("Expects configuration useHostNameAsBookieID=false as the option value'");
return false;
}
final int rate = flags.updatePerSec;
if (rate <= 0) {
LOG.error("Invalid updatespersec {}, should be > 0", rate);
return false;
}
final int maxOutstandingReads = flags.maxOutstandingReads;
if (maxOutstandingReads <= 0) {
LOG.error("Invalid maxOutstandingReads {}, should be > 0", maxOutstandingReads);
return false;
}
final int limit = flags.limit;
if (limit <= 0 && limit != Integer.MIN_VALUE) {
LOG.error("Invalid limit {}, should be > 0", limit);
return false;
}
final long printProgress;
if (flags.verbose) {
printProgress = 10;
} else {
printProgress = flags.printProgress;
}
final ClientConfiguration clientConfiguration = new ClientConfiguration();
clientConfiguration.addConfiguration(conf);
final BookKeeper bk = new BookKeeper(clientConfiguration);
final BookKeeperAdmin admin = new BookKeeperAdmin(bk);
final UpdateLedgerOp updateLedgerOp = new UpdateLedgerOp(bk, admin);
final ServerConfiguration serverConfiguration = new ServerConfiguration(conf);
final BookieId newBookieId = BookieImpl.getBookieId(serverConfiguration);
serverConfiguration.setUseHostNameAsBookieID(!flags.hostname);
final BookieId oldBookieId = BookieImpl.getBookieId(serverConfiguration);
BookieShell.UpdateLedgerNotifier progressable = new BookieShell.UpdateLedgerNotifier() {
long lastReport = System.nanoTime();
@Override
public void progress(long updated, long issued) {
if (printProgress <= 0) {
return; // disabled
}
if (TimeUnit.MILLISECONDS.toSeconds(MathUtils.elapsedMSec(lastReport)) >= printProgress) {
LOG.info("Number of ledgers issued={}, updated={}", issued, updated);
lastReport = MathUtils.nowInNano();
}
}
};
try {
updateLedgerOp.updateBookieIdInLedgers(oldBookieId, newBookieId, rate, maxOutstandingReads, limit,
progressable);
} catch (IOException e) {
LOG.error("Failed to update ledger metadata", e);
return false;
}
return true;
}
}