/* * Copyright 2008-2014 LinkedIn, Inc * * Licensed 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 voldemort.tools.admin.command; import java.io.IOException; import java.io.PrintStream; import java.util.List; import joptsimple.OptionParser; import joptsimple.OptionSet; import voldemort.client.protocol.admin.AdminClient; import voldemort.tools.admin.AdminParserUtils; import voldemort.tools.admin.AdminToolUtils; import com.google.common.base.Joiner; /** * Implements all cleanup commands. */ public class AdminCommandCleanup extends AbstractAdminCommand { /** * Parses command-line and directs to sub-commands. * * @param args Command-line input * @throws Exception */ public static void executeCommand(String[] args) throws Exception { String subCmd = (args.length > 0) ? args[0] : ""; args = AdminToolUtils.copyArrayCutFirst(args); if(subCmd.equals("orphaned-data")) { SubCommandCleanupOrphanedData.executeCommand(args); } else if(subCmd.equals("vector-clocks")) { SubCommandCleanupVectorClocks.executeCommand(args); } else if(subCmd.equals("slops")) { SubCommandCleanupSlops.executeCommand(args); } else { printHelp(System.out); } } /** * Prints command-line help menu. */ public static void printHelp(PrintStream stream) { stream.println(); stream.println("Voldemort Admin Tool Cleanup Commands"); stream.println("-------------------------------------"); stream.println("orphaned-data Remove orphaned data on a single node after rebalancing is done."); stream.println("vector-clocks Prune data resulting from versioned puts during rebalancing."); stream.println("slops Purge slops."); stream.println(); stream.println("To get more information on each command,"); stream.println("please try \'help cleanup <command-name>\'."); stream.println(); } /** * Parses command-line input and prints help menu. * * @throws Exception */ public static void executeHelp(String[] args, PrintStream stream) throws Exception { String subCmd = (args.length > 0) ? args[0] : ""; if(subCmd.equals("orphaned-data")) { SubCommandCleanupOrphanedData.printHelp(stream); } else if(subCmd.equals("vector-clocks")) { SubCommandCleanupVectorClocks.printHelp(stream); } else if(subCmd.equals("slops")) { SubCommandCleanupSlops.printHelp(stream); } else { printHelp(stream); } } /** * cleanup orphaned-data command */ public static class SubCommandCleanupOrphanedData extends AbstractAdminCommand { /** * Initializes parser * * @return OptionParser object with all available options */ protected static OptionParser getParser() { OptionParser parser = new OptionParser(); // help options AdminParserUtils.acceptsHelp(parser); // required options AdminParserUtils.acceptsUrl(parser); // optional options AdminParserUtils.acceptsNodeMultiple(parser); // either --node or // --all-nodes AdminParserUtils.acceptsAllNodes(parser); // either --node or // --all-nodes AdminParserUtils.acceptsConfirm(parser); return parser; } /** * Prints help menu for command. * * @param stream PrintStream object for output * @throws IOException */ public static void printHelp(PrintStream stream) throws IOException { stream.println(); stream.println("NAME"); stream.println(" cleanup orphaned-data - Remove orphaned data on a single node after"); stream.println(" rebalancing is done"); stream.println(); stream.println("SYNOPSIS"); stream.println(" cleanup orphaned-data -u <url> [-n <node-id-list> | --all-nodes] [--confirm]"); stream.println(); getParser().printHelpOn(stream); stream.println(); } /** * Parses command-line and removes orphaned data on a single node after * rebalancing is done. Previously known as "--repair-job". * * @param args Command-line input * @throws IOException * */ @SuppressWarnings("unchecked") public static void executeCommand(String[] args) throws IOException { OptionParser parser = getParser(); // declare parameters String url = null; List<Integer> nodeIds = null; Boolean allNodes = true; Boolean confirm = false; // parse command-line input OptionSet options = parser.parse(args); if(options.has(AdminParserUtils.OPT_HELP)) { printHelp(System.out); return; } // check required options and/or conflicting options AdminParserUtils.checkRequired(options, AdminParserUtils.OPT_URL); AdminParserUtils.checkOptional(options, AdminParserUtils.OPT_NODE, AdminParserUtils.OPT_ALL_NODES); // load parameters url = (String) options.valueOf(AdminParserUtils.OPT_URL); if(options.has(AdminParserUtils.OPT_NODE)) { nodeIds = (List<Integer>) options.valuesOf(AdminParserUtils.OPT_NODE); allNodes = false; } if(options.has(AdminParserUtils.OPT_CONFIRM)) { confirm = true; } // print summary System.out.println("Remove orphaned data after rebalancing"); System.out.println("Location:"); System.out.println(" bootstrap url = " + url); if(allNodes) { System.out.println(" node = all nodes"); } else { System.out.println(" node = " + Joiner.on(", ").join(nodeIds)); } // execute command if(!AdminToolUtils.askConfirm(confirm, "cleanup orphaned data")) { return; } AdminClient adminClient = AdminToolUtils.getAdminClient(url); if(allNodes) { nodeIds = AdminToolUtils.getAllNodeIds(adminClient); } AdminToolUtils.assertServerNotInRebalancingState(adminClient, nodeIds); doCleanupOrphanedData(adminClient, nodeIds); } /** * Removes orphaned data on a single node after rebalancing is done. * * @param adminClient An instance of AdminClient points to given cluster * @param nodeIds Node ids to remove orphaned data on */ public static void doCleanupOrphanedData(AdminClient adminClient, List<Integer> nodeIds) { for(Integer nodeId: nodeIds) { adminClient.storeMntOps.repairJob(nodeId); } } } /** * cleanup vector-clocks command */ public static class SubCommandCleanupVectorClocks extends AbstractAdminCommand { /** * Initializes parser * * @return OptionParser object with all available options */ protected static OptionParser getParser() { OptionParser parser = new OptionParser(); // help options AdminParserUtils.acceptsHelp(parser); // required options AdminParserUtils.acceptsStoreMultiple(parser); AdminParserUtils.acceptsUrl(parser); // optional options AdminParserUtils.acceptsNodeMultiple(parser); // either // --node or // --all-nodes AdminParserUtils.acceptsAllNodes(parser); // either --node or // --all-nodes AdminParserUtils.acceptsConfirm(parser); return parser; } /** * Prints help menu for command. * * @param stream PrintStream object for output * @throws IOException */ public static void printHelp(PrintStream stream) throws IOException { stream.println(); stream.println("NAME"); stream.println(" cleanup vector-clocks - Prune data resulting from versioned puts during"); stream.println(" rebalancing"); stream.println(); stream.println("SYNOPSIS"); stream.println(" cleanup vector-clocks -s <store-name-list> -u <url>"); stream.println(" [-n <node-id-list> | --all-nodes] [--confirm]"); stream.println(); getParser().printHelpOn(stream); stream.println(); } /** * Parses command-line and prunes data resulting from versioned puts * during rebalancing Previously known as "--prune-job". * * @param args Command-line input * @throws IOException * */ @SuppressWarnings("unchecked") public static void executeCommand(String[] args) throws IOException { OptionParser parser = getParser(); // declare parameters List<String> storeNames = null; String url = null; List<Integer> nodeIds = null; Boolean allNodes = true; Boolean confirm = false; // parse command-line input OptionSet options = parser.parse(args); if(options.has(AdminParserUtils.OPT_HELP)) { printHelp(System.out); return; } // check required options and/or conflicting options AdminParserUtils.checkRequired(options, AdminParserUtils.OPT_STORE); AdminParserUtils.checkRequired(options, AdminParserUtils.OPT_URL); AdminParserUtils.checkOptional(options, AdminParserUtils.OPT_NODE, AdminParserUtils.OPT_ALL_NODES); // load parameters storeNames = (List<String>) options.valuesOf(AdminParserUtils.OPT_STORE); url = (String) options.valueOf(AdminParserUtils.OPT_URL); if(options.has(AdminParserUtils.OPT_NODE)) { nodeIds = (List<Integer>) options.valuesOf(AdminParserUtils.OPT_NODE); allNodes = false; } if(options.has(AdminParserUtils.OPT_CONFIRM)) { confirm = true; } // print summary System.out.println("Prune data resulting from versioned puts"); System.out.println("Store:"); System.out.println(" " + Joiner.on(", ").join(storeNames)); System.out.println("Location:"); System.out.println(" bootstrap url = " + url); if(allNodes) { System.out.println(" node = all nodes"); } else { System.out.println(" node = " + Joiner.on(", ").join(nodeIds)); } // execute command if(!AdminToolUtils.askConfirm(confirm, "cleanup vector clocks")) { return; } AdminClient adminClient = AdminToolUtils.getAdminClient(url); if(allNodes) { nodeIds = AdminToolUtils.getAllNodeIds(adminClient); } AdminToolUtils.assertServerNotInRebalancingState(adminClient, nodeIds); doCleanupVectorClocks(adminClient, nodeIds, storeNames); } /** * Prunes data resulting from versioned puts during rebalancing * * @param adminClient An instance of AdminClient points to given cluster * @param nodeIds Node ids to prune vector clocks * @param storeNames List of stores to prune vector clocks */ public static void doCleanupVectorClocks(AdminClient adminClient, List<Integer> nodeIds, List<String> storeNames) { for(Integer nodeId: nodeIds) { adminClient.storeMntOps.pruneJob(nodeId, storeNames); } } } /** * cleanup slops command */ public static class SubCommandCleanupSlops extends AbstractAdminCommand { /** * Initializes parser * * @return OptionParser object with all available options */ protected static OptionParser getParser() { OptionParser parser = new OptionParser(); // help options AdminParserUtils.acceptsHelp(parser); // required options AdminParserUtils.acceptsStoreMultiple(parser); AdminParserUtils.acceptsUrl(parser); AdminParserUtils.acceptsZone(parser); // optional options AdminParserUtils.acceptsNodeMultiple(parser); // either // --node or // --all-nodes AdminParserUtils.acceptsAllNodes(parser); // either --node or // --all-nodes AdminParserUtils.acceptsConfirm(parser); return parser; } /** * Prints help menu for command. * * @param stream PrintStream object for output * @throws IOException */ public static void printHelp(PrintStream stream) throws IOException { stream.println(); stream.println("NAME"); stream.println(" cleanup slops - Purge slops"); stream.println(); stream.println("SYNOPSIS"); stream.println(" cleanup slops -s <store-name-list> -u <url> -z <zone-id>"); stream.println(" [-n <node-id-list> | --all-nodes] [--confirm]"); stream.println(); getParser().printHelpOn(stream); stream.println(); } /** * Parses command-line and purges slops; the command is previously known * as "--purge-slops". * * @param args Command-line input * @throws IOException * */ @SuppressWarnings("unchecked") public static void executeCommand(String[] args) throws IOException { OptionParser parser = getParser(); // declare parameters List<String> storeNames = null; String url = null; Integer zoneId = null; List<Integer> nodeIds = null; Boolean allNodes = true; Boolean confirm = false; // parse command-line input OptionSet options = parser.parse(args); if(options.has(AdminParserUtils.OPT_HELP)) { printHelp(System.out); return; } // check required options and/or conflicting options AdminParserUtils.checkRequired(options, AdminParserUtils.OPT_STORE); AdminParserUtils.checkRequired(options, AdminParserUtils.OPT_URL); AdminParserUtils.checkRequired(options, AdminParserUtils.OPT_ZONE); AdminParserUtils.checkOptional(options, AdminParserUtils.OPT_NODE, AdminParserUtils.OPT_ALL_NODES); // load parameters storeNames = (List<String>) options.valuesOf(AdminParserUtils.OPT_STORE); url = (String) options.valueOf(AdminParserUtils.OPT_URL); zoneId = (Integer) options.valueOf(AdminParserUtils.OPT_ZONE); if(options.has(AdminParserUtils.OPT_NODE)) { nodeIds = (List<Integer>) options.valuesOf(AdminParserUtils.OPT_NODE); allNodes = false; } if(options.has(AdminParserUtils.OPT_CONFIRM)) { confirm = true; } // print summary System.out.println("Purge slops"); System.out.println("Store:"); System.out.println(" " + Joiner.on(", ").join(storeNames)); System.out.println("Location:"); System.out.println(" zone = " + zoneId); System.out.println(" bootstrap url = " + url); if(allNodes) { System.out.println(" node = all nodes"); } else { System.out.println(" node = " + Joiner.on(",").join(nodeIds)); } // execute command if(!AdminToolUtils.askConfirm(confirm, "cleanup slops")) return; AdminClient adminClient = AdminToolUtils.getAdminClient(url); if(allNodes) { nodeIds = AdminToolUtils.getAllNodeIds(adminClient); } AdminToolUtils.assertServerNotInRebalancingState(adminClient, nodeIds); adminClient.storeMntOps.slopPurgeJob(nodeIds, zoneId, storeNames); } } }