Java tutorial
/* * Copyright 2013 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.store.readonly.swapper; import java.io.File; import java.io.StringReader; import java.util.List; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import joptsimple.OptionParser; import joptsimple.OptionSet; import org.apache.commons.io.FileUtils; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import org.apache.log4j.Logger; import voldemort.client.ClientConfig; import voldemort.client.protocol.admin.AdminClient; import voldemort.client.protocol.admin.AdminClientConfig; import voldemort.cluster.Cluster; import voldemort.utils.CmdUtils; import voldemort.utils.Time; import voldemort.utils.VoldemortIOUtils; import voldemort.xml.ClusterMapper; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableSet; /** * A helper class to invoke the FETCH and SWAP operations on a remote store via * HTTP. * * */ public abstract class StoreSwapper { private static final Logger logger = Logger.getLogger(StoreSwapper.class); protected final Cluster cluster; protected final ExecutorService executor; public StoreSwapper(Cluster cluster, ExecutorService executor) { super(); this.cluster = cluster; this.executor = executor; } public void swapStoreData(String storeName, String basePath, long pushVersion) { List<String> fetched = invokeFetch(storeName, basePath, pushVersion); invokeSwap(storeName, fetched); } public abstract List<String> invokeFetch(String storeName, String basePath, long pushVersion); public abstract void invokeSwap(String storeName, List<String> fetchFiles); public abstract void invokeRollback(String storeName, long pushVersion); public static void main(String[] args) throws Exception { OptionParser parser = new OptionParser(); parser.accepts("help", "print usage information"); parser.accepts("cluster", "[REQUIRED] the voldemort cluster.xml file ").withRequiredArg() .describedAs("cluster.xml"); parser.accepts("name", "[REQUIRED] the name of the store to swap").withRequiredArg() .describedAs("store-name"); parser.accepts("servlet-path", "the path for the read-only management servlet").withRequiredArg() .describedAs("path"); parser.accepts("file", "[REQUIRED] uri of a directory containing the new store files").withRequiredArg() .describedAs("uri"); parser.accepts("timeout", "http timeout for the fetch in ms").withRequiredArg().describedAs("timeout ms") .ofType(Integer.class); parser.accepts("rollback", "Rollback store to older version"); parser.accepts("admin", "Use admin services. Default = false"); parser.accepts("push-version", "[REQUIRED] Version of push to fetch / rollback-to").withRequiredArg() .ofType(Long.class); OptionSet options = parser.parse(args); if (options.has("help")) { parser.printHelpOn(System.out); System.exit(0); } Set<String> missing = CmdUtils.missing(options, "cluster", "name", "file", "push-version"); if (missing.size() > 0) { if (!(missing.equals(ImmutableSet.of("file")) && (options.has("rollback")))) { System.err.println("Missing required arguments: " + Joiner.on(", ").join(missing)); parser.printHelpOn(System.err); System.exit(1); } } String clusterXml = (String) options.valueOf("cluster"); String storeName = (String) options.valueOf("name"); String mgmtPath = CmdUtils.valueOf(options, "servlet-path", "read-only/mgmt"); String filePath = (String) options.valueOf("file"); int timeoutMs = CmdUtils.valueOf(options, "timeout", (int) (3 * Time.SECONDS_PER_HOUR * Time.MS_PER_SECOND)); boolean useAdminServices = options.has("admin"); boolean rollbackStore = options.has("rollback"); Long pushVersion = (Long) options.valueOf("push-version"); String clusterStr = FileUtils.readFileToString(new File(clusterXml)); Cluster cluster = new ClusterMapper().readCluster(new StringReader(clusterStr)); ExecutorService executor = Executors.newFixedThreadPool(cluster.getNumberOfNodes()); StoreSwapper swapper = null; AdminClient adminClient = null; DefaultHttpClient httpClient = null; if (useAdminServices) { adminClient = new AdminClient(cluster, new AdminClientConfig(), new ClientConfig()); swapper = new AdminStoreSwapper(cluster, executor, adminClient, timeoutMs); } else { int numConnections = cluster.getNumberOfNodes() + 3; ThreadSafeClientConnManager connectionManager = new ThreadSafeClientConnManager(); httpClient = new DefaultHttpClient(connectionManager); HttpParams clientParams = httpClient.getParams(); connectionManager.setMaxTotal(numConnections); connectionManager.setDefaultMaxPerRoute(numConnections); HttpConnectionParams.setSoTimeout(clientParams, timeoutMs); swapper = new HttpStoreSwapper(cluster, executor, httpClient, mgmtPath); } try { long start = System.currentTimeMillis(); if (rollbackStore) { swapper.invokeRollback(storeName, pushVersion.longValue()); } else { swapper.swapStoreData(storeName, filePath, pushVersion.longValue()); } long end = System.currentTimeMillis(); logger.info("Succeeded on all nodes in " + ((end - start) / Time.MS_PER_SECOND) + " seconds."); } finally { if (useAdminServices && adminClient != null) adminClient.close(); executor.shutdownNow(); executor.awaitTermination(1, TimeUnit.SECONDS); VoldemortIOUtils.closeQuietly(httpClient); } System.exit(0); } }