blob: 99ef018ade1e83312f09ab6c9f9d4459786fd21e [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.ignite.internal.commandline;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import org.apache.ignite.internal.client.GridClient;
import org.apache.ignite.internal.client.GridClientConfiguration;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.T2;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.internal.visor.misc.VisorClusterNode;
import org.apache.ignite.internal.visor.misc.VisorWalTask;
import org.apache.ignite.internal.visor.misc.VisorWalTaskArg;
import org.apache.ignite.internal.visor.misc.VisorWalTaskOperation;
import org.apache.ignite.internal.visor.misc.VisorWalTaskResult;
import static org.apache.ignite.IgniteSystemProperties.IGNITE_ENABLE_EXPERIMENTAL_COMMAND;
import static org.apache.ignite.internal.commandline.CommandArgIterator.isCommandOrOption;
import static org.apache.ignite.internal.commandline.CommandHandler.UTILITY_NAME;
import static org.apache.ignite.internal.commandline.CommandList.WAL;
import static org.apache.ignite.internal.commandline.CommandLogger.DOUBLE_INDENT;
import static org.apache.ignite.internal.commandline.CommandLogger.INDENT;
import static org.apache.ignite.internal.commandline.CommandLogger.optional;
import static org.apache.ignite.internal.commandline.CommonArgParser.CMD_AUTO_CONFIRMATION;
import static org.apache.ignite.internal.commandline.TaskExecutor.executeTask;
/**
* Wal commands.
*/
public class WalCommands implements Command<T2<String, String>> {
/** */
static final String WAL_PRINT = "print";
/** */
static final String WAL_DELETE = "delete";
/** */
private Logger logger;
/**
* Wal action.
*/
private String walAct;
/**
* Wal arguments.
*/
private String walArgs;
/** {@inheritDoc} */
@Override public void printUsage(Logger logger) {
if (!experimentalEnabled())
return;
Command.usage(logger, "Print absolute paths of unused archived wal segments on each node:", WAL,
WAL_PRINT, "[consistentId1,consistentId2,....,consistentIdN]");
Command.usage(logger, "Delete unused archived wal segments on each node:", WAL, WAL_DELETE,
"[consistentId1,consistentId2,....,consistentIdN]", optional(CMD_AUTO_CONFIRMATION));
}
/**
* Execute WAL command.
*
* @param clientCfg Client configuration.
* @throws Exception If failed to execute wal action.
*/
@Override public Object execute(GridClientConfiguration clientCfg, Logger logger) throws Exception {
if (experimentalEnabled()) {
this.logger = logger;
try (GridClient client = Command.startClient(clientCfg)) {
switch (walAct) {
case WAL_DELETE:
deleteUnusedWalSegments(client, walArgs, clientCfg);
break;
case WAL_PRINT:
default:
printUnusedWalSegments(client, walArgs, clientCfg);
break;
}
}
} else {
logger.warning(String.format("For use experimental command add %s=true to JVM_OPTS in %s",
IGNITE_ENABLE_EXPERIMENTAL_COMMAND, UTILITY_NAME));
}
return null;
}
/** {@inheritDoc} */
@Override public String confirmationPrompt() {
if (WAL_DELETE.equals(walAct))
return "Warning: the command will delete unused WAL segments.";
return null;
}
/** {@inheritDoc} */
@Override public void parseArguments(CommandArgIterator argIter) {
String str = argIter.nextArg("Expected arguments for " + WAL.text());
String walAct = str.toLowerCase();
if (WAL_PRINT.equals(walAct) || WAL_DELETE.equals(walAct)) {
String walArgs = (str = argIter.peekNextArg()) != null && !isCommandOrOption(str)
? argIter.nextArg("Unexpected argument for " + WAL.text() + ": " + walAct)
: "";
if (experimentalEnabled()) {
this.walAct = walAct;
this.walArgs = walArgs;
}
}
else
throw new IllegalArgumentException("Unexpected action " + walAct + " for " + WAL.text());
}
/**
* @return Tuple where first string is wal action, second - wal arguments.
*/
@Override public T2<String, String> arg() {
return new T2<>(walAct, walArgs);
}
/**
* Execute delete unused WAL segments task.
* @param client Client.
* @param walArgs WAL args.
* @param clientCfg Client configuration.
*/
private void deleteUnusedWalSegments(
GridClient client,
String walArgs,
GridClientConfiguration clientCfg
) throws Exception {
VisorWalTaskResult res = executeTask(client, VisorWalTask.class,
walArg(VisorWalTaskOperation.DELETE_UNUSED_WAL_SEGMENTS, walArgs), clientCfg);
printDeleteWalSegments0(res);
}
/**
* Execute print unused WAL segments task.
* @param client Client.
* @param walArgs Wal args.
* @param clientCfg Client configuration.
*/
private void printUnusedWalSegments(
GridClient client,
String walArgs,
GridClientConfiguration clientCfg
) throws Exception {
VisorWalTaskResult res = executeTask(client, VisorWalTask.class,
walArg(VisorWalTaskOperation.PRINT_UNUSED_WAL_SEGMENTS, walArgs), clientCfg);
printUnusedWalSegments0(res);
}
/**
* Prepare WAL task argument.
*
* @param op Operation.
* @param s Argument from command line.
* @return Task argument.
*/
private VisorWalTaskArg walArg(VisorWalTaskOperation op, String s) {
List<String> consistentIds = null;
if (!F.isEmpty(s)) {
consistentIds = new ArrayList<>();
for (String consistentId : s.split(","))
consistentIds.add(consistentId.trim());
}
switch (op) {
case DELETE_UNUSED_WAL_SEGMENTS:
case PRINT_UNUSED_WAL_SEGMENTS:
return new VisorWalTaskArg(op, consistentIds);
default:
return new VisorWalTaskArg(VisorWalTaskOperation.PRINT_UNUSED_WAL_SEGMENTS, consistentIds);
}
}
/**
* Print list of unused wal segments.
*
* @param taskRes Task result with baseline topology.
*/
private void printUnusedWalSegments0(VisorWalTaskResult taskRes) {
logger.info("Unused wal segments per node:");
logger.info("");
Map<String, Collection<String>> res = taskRes.results();
Map<String, Exception> failRes = taskRes.exceptions();
Map<String, VisorClusterNode> nodesInfo = taskRes.getNodesInfo();
for (Map.Entry<String, Collection<String>> entry : res.entrySet()) {
VisorClusterNode node = nodesInfo.get(entry.getKey());
logger.info("Node=" + node.getConsistentId());
logger.info(DOUBLE_INDENT + "addresses " + U.addressesAsString(node.getAddresses(), node.getHostNames()));
for (String fileName : entry.getValue())
logger.info(INDENT + fileName);
logger.info("");
}
for (Map.Entry<String, Exception> entry : failRes.entrySet()) {
VisorClusterNode node = nodesInfo.get(entry.getKey());
logger.info("Node=" + node.getConsistentId());
logger.info(DOUBLE_INDENT + "addresses " + U.addressesAsString(node.getAddresses(), node.getHostNames()));
logger.info(INDENT + "failed with error: " + entry.getValue().getMessage());
logger.info("");
}
}
/**
* Print list of unused wal segments.
*
* @param taskRes Task result with baseline topology.
*/
private void printDeleteWalSegments0(VisorWalTaskResult taskRes) {
logger.info("WAL segments deleted for nodes:");
logger.info("");
Map<String, Collection<String>> res = taskRes.results();
Map<String, Exception> errors = taskRes.exceptions();
Map<String, VisorClusterNode> nodesInfo = taskRes.getNodesInfo();
for (Map.Entry<String, Collection<String>> entry : res.entrySet()) {
VisorClusterNode node = nodesInfo.get(entry.getKey());
logger.info("Node=" + node.getConsistentId());
logger.info(DOUBLE_INDENT + "addresses " + U.addressesAsString(node.getAddresses(), node.getHostNames()));
logger.info("");
}
for (Map.Entry<String, Exception> entry : errors.entrySet()) {
VisorClusterNode node = nodesInfo.get(entry.getKey());
logger.info("Node=" + node.getConsistentId());
logger.info(DOUBLE_INDENT + "addresses " + U.addressesAsString(node.getAddresses(), node.getHostNames()));
logger.info(INDENT + "failed with error: " + entry.getValue().getMessage());
logger.info("");
}
}
/** {@inheritDoc} */
@Override public String name() {
return WAL.toCommandName();
}
/** {@inheritDoc} */
@Override public boolean experimental() {
return true;
}
}