From: <tho...@us...> - 2014-03-04 20:46:25
|
Revision: 7911 http://sourceforge.net/p/bigdata/code/7911 Author: thompsonbry Date: 2014-03-04 20:46:21 +0000 (Tue, 04 Mar 2014) Log Message: ----------- Committing to CI for #730. I still need to test the benchmarking scripts and scale-out query. Modified Paths: -------------- branches/BIGDATA_RELEASE_1_3_0/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal-A.config branches/BIGDATA_RELEASE_1_3_0/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal-B.config branches/BIGDATA_RELEASE_1_3_0/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal-C.config branches/BIGDATA_RELEASE_1_3_0/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java branches/BIGDATA_RELEASE_1_3_0/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java branches/BIGDATA_RELEASE_1_3_0/bigdata-jini/src/test/com/bigdata/journal/jini/ha/AbstractHA3JournalServerTestCase.java branches/BIGDATA_RELEASE_1_3_0/bigdata-jini/src/test/com/bigdata/journal/jini/ha/HAJournal-A.config branches/BIGDATA_RELEASE_1_3_0/bigdata-jini/src/test/com/bigdata/journal/jini/ha/HAJournal-B.config branches/BIGDATA_RELEASE_1_3_0/bigdata-jini/src/test/com/bigdata/journal/jini/ha/HAJournal-C.config branches/BIGDATA_RELEASE_1_3_0/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/BigdataRDFServletContextListener.java branches/BIGDATA_RELEASE_1_3_0/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/ConfigParams.java branches/BIGDATA_RELEASE_1_3_0/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/NanoSparqlServer.java branches/BIGDATA_RELEASE_1_3_0/bigdata-war/src/WEB-INF/web.xml branches/BIGDATA_RELEASE_1_3_0/build.xml branches/BIGDATA_RELEASE_1_3_0/src/resources/HAJournal/HAJournal.config branches/BIGDATA_RELEASE_1_3_0/src/resources/HAJournal/log4jHA.properties branches/BIGDATA_RELEASE_1_3_0/src/resources/HAJournal/startHAServices.config branches/BIGDATA_RELEASE_1_3_0/src/resources/bin/startHAServices branches/BIGDATA_RELEASE_1_3_0/src/resources/etc/bigdata/bigdataHA.config Added Paths: ----------- branches/BIGDATA_RELEASE_1_3_0/bigdata-war/src/WEB-INF/ branches/BIGDATA_RELEASE_1_3_0/bigdata-war/src/WEB-INF/RWStore.properties branches/BIGDATA_RELEASE_1_3_0/bigdata-war/src/WEB-INF/classes/ branches/BIGDATA_RELEASE_1_3_0/bigdata-war/src/WEB-INF/classes/log4j.properties branches/BIGDATA_RELEASE_1_3_0/bigdata-war/src/WEB-INF/jetty.xml branches/BIGDATA_RELEASE_1_3_0/bigdata-war/src/index.html branches/BIGDATA_RELEASE_1_3_0/bigdata-war/src/result-to-html.xsl Removed Paths: ------------- branches/BIGDATA_RELEASE_1_3_0/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/WebAppUnassembled.java branches/BIGDATA_RELEASE_1_3_0/bigdata-war/src/html/index.html branches/BIGDATA_RELEASE_1_3_0/bigdata-war/src/html/result-to-html.xsl branches/BIGDATA_RELEASE_1_3_0/bigdata-war/src/resources/RWStore.properties branches/BIGDATA_RELEASE_1_3_0/bigdata-war/src/resources/WEB-INF/ branches/BIGDATA_RELEASE_1_3_0/bigdata-war/src/resources/log4j.properties Modified: branches/BIGDATA_RELEASE_1_3_0/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal-A.config =================================================================== --- branches/BIGDATA_RELEASE_1_3_0/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal-A.config 2014-03-04 20:38:39 UTC (rev 7910) +++ branches/BIGDATA_RELEASE_1_3_0/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal-A.config 2014-03-04 20:46:21 UTC (rev 7911) @@ -60,9 +60,6 @@ private static fedname = "benchmark"; - // NanoSparqlServer (http) port. - private static nssPort = 8090; - // write replication pipeline port (listener). private static haPort = 9090; @@ -276,20 +273,3 @@ }, bigdata.kb); } - -/* - * NanoSparqlServer configuration. - */ -com.bigdata.rdf.sail.webapp.NanoSparqlServer { - - namespace = bigdata.namespace; - - create = true; - - queryThreadPoolSize = 16; - - describeEachNamedGraph = true; - - port = bigdata.nssPort; - -} Modified: branches/BIGDATA_RELEASE_1_3_0/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal-B.config =================================================================== --- branches/BIGDATA_RELEASE_1_3_0/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal-B.config 2014-03-04 20:38:39 UTC (rev 7910) +++ branches/BIGDATA_RELEASE_1_3_0/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal-B.config 2014-03-04 20:46:21 UTC (rev 7911) @@ -275,20 +275,3 @@ }, bigdata.kb); } - -/* - * NanoSparqlServer configuration. - */ -com.bigdata.rdf.sail.webapp.NanoSparqlServer { - - namespace = bigdata.namespace; - - create = true; - - queryThreadPoolSize = 16; - - describeEachNamedGraph = true; - - port = bigdata.nssPort; - -} Modified: branches/BIGDATA_RELEASE_1_3_0/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal-C.config =================================================================== --- branches/BIGDATA_RELEASE_1_3_0/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal-C.config 2014-03-04 20:38:39 UTC (rev 7910) +++ branches/BIGDATA_RELEASE_1_3_0/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal-C.config 2014-03-04 20:46:21 UTC (rev 7911) @@ -60,9 +60,6 @@ private static fedname = "benchmark"; - // NanoSparqlServer (http) port. - private static nssPort = ConfigMath.add(8090,2); - // write replication pipeline port (listener). private static haPort = ConfigMath.add(9090,2); @@ -275,20 +272,3 @@ }, bigdata.kb); } - -/* - * NanoSparqlServer configuration. - */ -com.bigdata.rdf.sail.webapp.NanoSparqlServer { - - namespace = bigdata.namespace; - - create = true; - - queryThreadPoolSize = 16; - - describeEachNamedGraph = true; - - port = bigdata.nssPort; - -} Modified: branches/BIGDATA_RELEASE_1_3_0/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java =================================================================== --- branches/BIGDATA_RELEASE_1_3_0/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java 2014-03-04 20:38:39 UTC (rev 7910) +++ branches/BIGDATA_RELEASE_1_3_0/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java 2014-03-04 20:46:21 UTC (rev 7911) @@ -93,7 +93,6 @@ import com.bigdata.journal.ITx; import com.bigdata.journal.Journal; import com.bigdata.journal.jini.ha.HAJournalServer.HAQuorumService; -import com.bigdata.journal.jini.ha.HAJournalServer.NSSConfigurationOptions; import com.bigdata.journal.jini.ha.HAJournalServer.RunStateEnum; import com.bigdata.quorum.Quorum; import com.bigdata.resources.StoreManager.IStoreManagerCounters; @@ -2193,26 +2192,43 @@ * Misc. */ + /** + * {@inheritDoc} + * <p> + * Note: The actual port depends on how jetty was configured in + * <code>jetty.xml</code>. This returns the port associated with the + * first jetty connection. + * + * @see <a + * href="http://wiki.eclipse.org/Jetty/Tutorial/Embedding_Jetty"> + * Embedding Jetty </a> + */ @Override public int getNSSPort() { - final String COMPONENT = NSSConfigurationOptions.COMPONENT; + return server.getNSSPort(); - try { - - final Integer port = (Integer) server.config.getEntry( - COMPONENT, NSSConfigurationOptions.PORT, Integer.TYPE, - NSSConfigurationOptions.DEFAULT_PORT); - - return port; - - } catch (ConfigurationException e) { - - throw new RuntimeException(e); - - } - } +// @Override +// public int getNSSPort() { +// +// final String COMPONENT = NSSConfigurationOptions.COMPONENT; +// +// try { +// +// final Integer port = (Integer) server.config.getEntry( +// COMPONENT, NSSConfigurationOptions.PORT, Integer.TYPE, +// NSSConfigurationOptions.DEFAULT_PORT); +// +// return port; +// +// } catch (ConfigurationException e) { +// +// throw new RuntimeException(e); +// +// } +// +// } @Override public RunState getRunState() { Modified: branches/BIGDATA_RELEASE_1_3_0/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java =================================================================== --- branches/BIGDATA_RELEASE_1_3_0/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java 2014-03-04 20:38:39 UTC (rev 7910) +++ branches/BIGDATA_RELEASE_1_3_0/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java 2014-03-04 20:46:21 UTC (rev 7911) @@ -33,9 +33,7 @@ import java.nio.ByteBuffer; import java.nio.channels.ClosedByInterruptException; import java.rmi.Remote; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; @@ -59,6 +57,7 @@ import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.data.ACL; import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.webapp.WebAppContext; import com.bigdata.concurrent.FutureTaskMon; import com.bigdata.ha.HAGlue; @@ -440,28 +439,60 @@ */ boolean DEFAULT_ONLINE_DISASTER_RECOVERY = false; - } - - /** - * Configuration options for the {@link NanoSparqlServer}. - */ - public interface NSSConfigurationOptions extends ConfigParams { - - String COMPONENT = NanoSparqlServer.class.getName(); - /** - * The port at which the embedded {@link NanoSparqlServer} will respond - * to HTTP requests (default {@value #DEFAULT_PORT}). This MAY be ZERO - * (0) to use a random open port. + * The location of the <code>jetty.xml</code> file that will be used to + * configure jetty (default {@value #DEFAULT_JETTY_XML}). * - * TODO We should be able to specify the interface, not just the port. Is - * there any way to do that with jetty? + * @see <a href="https://sourceforge.net/apps/trac/bigdata/ticket/730" > + * Allow configuration of embedded NSS jetty server using + * jetty-web.xml </a> + * + * @see #DEFAULT_JETTY_XML */ - String PORT = "port"; + String JETTY_XML = "jettyXml"; - int DEFAULT_PORT = 8080; - + /** + * The default value works when deployed under the IDE with the + * <code>bigdata-war/src</code> directory on the classpath. When + * deploying outside of that context, the value needs to be set + * explicitly. + */ + String DEFAULT_JETTY_XML = "WEB-INF/jetty.xml"; + } + +// /** +// * Configuration options for the {@link NanoSparqlServer}. +// * +// * @see <a href="https://sourceforge.net/apps/trac/bigdata/ticket/730" > +// * Allow configuration of embedded NSS jetty server using jetty-web.xml +// * </a> +// */ +// @Deprecated +// public interface NSSConfigurationOptions extends ConfigParams { +// +// @Deprecated +// String COMPONENT = NanoSparqlServer.class.getName(); +// +// /** +// * The port at which the embedded {@link NanoSparqlServer} will respond +// * to HTTP requests (default {@value #DEFAULT_PORT}). This MAY be ZERO +// * (0) to use a random open port. +// * +// * @deprecated This has been replaced by the use of <code>web.xml</code> +// * and <code>jetty.xml</code>. +// * +// * @see <a href="https://sourceforge.net/apps/trac/bigdata/ticket/730" > +// * Allow configuration of embedded NSS jetty server using +// * jetty-web.xml </a> +// */ +// @Deprecated +// String PORT = "port"; +// +// @Deprecated +// int DEFAULT_PORT = 8080; +// +// } /** * The journal. @@ -4466,65 +4497,85 @@ * Note: We need to wait for a quorum meet since this will create the KB * instance if it does not exist and we can not write on the * {@link HAJournal} until we have a quorum meet. + * + * @see <a href="http://wiki.eclipse.org/Jetty/Tutorial/Embedding_Jetty"> + * Embedding Jetty </a> + * @see <a href="http://trac.bigdata.com/ticket/730" > Allow configuration + * of embedded NSS jetty server using jetty-web.xml </a> */ private void startNSS() { try { - final String COMPONENT = NSSConfigurationOptions.COMPONENT; + if (jettyServer != null && jettyServer.isRunning()) { - final String namespace = (String) config.getEntry(COMPONENT, - NSSConfigurationOptions.NAMESPACE, String.class, - NSSConfigurationOptions.DEFAULT_NAMESPACE); + throw new RuntimeException("Already running"); - final Integer queryPoolThreadSize = (Integer) config.getEntry( - COMPONENT, NSSConfigurationOptions.QUERY_THREAD_POOL_SIZE, - Integer.TYPE, - NSSConfigurationOptions.DEFAULT_QUERY_THREAD_POOL_SIZE); - - final boolean create = (Boolean) config.getEntry(COMPONENT, - NSSConfigurationOptions.CREATE, Boolean.TYPE, - NSSConfigurationOptions.DEFAULT_CREATE); - - final Integer port = (Integer) config.getEntry(COMPONENT, - NSSConfigurationOptions.PORT, Integer.TYPE, - NSSConfigurationOptions.DEFAULT_PORT); - - final String servletContextListenerClass = (String) config - .getEntry( - COMPONENT, - NSSConfigurationOptions.SERVLET_CONTEXT_LISTENER_CLASS, - String.class, - NSSConfigurationOptions.DEFAULT_SERVLET_CONTEXT_LISTENER_CLASS); - - log.warn("Starting NSS: port=" + port); - - final Map<String, String> initParams = new LinkedHashMap<String, String>(); - { - - initParams.put(ConfigParams.NAMESPACE, namespace); - - initParams.put(ConfigParams.QUERY_THREAD_POOL_SIZE, - queryPoolThreadSize.toString()); - - // Note: Create will be handled by the QuorumListener (above). - initParams.put(ConfigParams.CREATE, Boolean.toString(create)); - - initParams.put(ConfigParams.SERVLET_CONTEXT_LISTENER_CLASS, - servletContextListenerClass); - } - if (jettyServer != null && jettyServer.isRunning()) { +// if(!USE_WEB_XML) { +// +// final String COMPONENT = NSSConfigurationOptions.COMPONENT; +// +// final String namespace = (String) config.getEntry(COMPONENT, +// NSSConfigurationOptions.NAMESPACE, String.class, +// NSSConfigurationOptions.DEFAULT_NAMESPACE); +// +// final Integer queryPoolThreadSize = (Integer) config.getEntry( +// COMPONENT, NSSConfigurationOptions.QUERY_THREAD_POOL_SIZE, +// Integer.TYPE, +// NSSConfigurationOptions.DEFAULT_QUERY_THREAD_POOL_SIZE); +// +// final boolean create = (Boolean) config.getEntry(COMPONENT, +// NSSConfigurationOptions.CREATE, Boolean.TYPE, +// NSSConfigurationOptions.DEFAULT_CREATE); +// +// final Integer port = (Integer) config.getEntry(COMPONENT, +// NSSConfigurationOptions.PORT, Integer.TYPE, +// NSSConfigurationOptions.DEFAULT_PORT); +// +// final String servletContextListenerClass = (String) config +// .getEntry( +// COMPONENT, +// NSSConfigurationOptions.SERVLET_CONTEXT_LISTENER_CLASS, +// String.class, +// NSSConfigurationOptions.DEFAULT_SERVLET_CONTEXT_LISTENER_CLASS); +// +// final Map<String, String> initParams = new LinkedHashMap<String, String>(); +// { +// +// initParams.put(ConfigParams.NAMESPACE, namespace); +// +// initParams.put(ConfigParams.QUERY_THREAD_POOL_SIZE, +// queryPoolThreadSize.toString()); +// +// // Note: Create will be handled by the QuorumListener (above). +// initParams.put(ConfigParams.CREATE, Boolean.toString(create)); +// +// initParams.put(ConfigParams.SERVLET_CONTEXT_LISTENER_CLASS, +// servletContextListenerClass); +// +// } +// +// // Setup the embedded jetty server for NSS webapp. +// jettyServer = NanoSparqlServer.newInstance(port, journal, +// initParams); +// +// } else { - throw new RuntimeException("Already running"); + // The location of the jetty.xml file. + final String jettyXml = (String) config.getEntry( + ConfigurationOptions.COMPONENT, + ConfigurationOptions.JETTY_XML, String.class, + ConfigurationOptions.DEFAULT_JETTY_XML); - } + // Setup the embedded jetty server for NSS webapp. + jettyServer = NanoSparqlServer.newInstance(jettyXml, journal); - // Setup the embedded jetty server for NSS webapp. - jettyServer = NanoSparqlServer.newInstance(port, journal, - initParams); +// } + log.warn("Starting NSS"); + // Start the server. jettyServer.start(); @@ -4539,8 +4590,9 @@ final String serviceURL; { - final int actualPort = jettyServer.getConnectors()[0] - .getLocalPort(); + final int actualPort = getNSSPort(); +// final int actualPort = jettyServer.getConnectors()[0] +// .getLocalPort(); String hostAddr = NicUtil.getIpAddress("default.nic", "default", true/* loopbackOk */); @@ -4560,7 +4612,7 @@ System.out.println(msg); if (log.isInfoEnabled()) - log.info(msg); + log.warn(msg); } @@ -4573,10 +4625,49 @@ } +// /** +// * When <code>true</code>, the {@link HAJournalServer} will use +// * <code>jetty.xml</code> and <code>web.xml</code> to configure the +// * {@link NanoSparqlServer}. +// * +// * @see <a href="http://wiki.eclipse.org/Jetty/Tutorial/Embedding_Jetty"> +// * Embedding Jetty </a> +// * @see <a href="http://trac.bigdata.com/ticket/730" > Allow configuration +// * of embedded NSS jetty server using jetty-web.xml </a> +// * +// * @deprecated Once #730 is closed, get rid of this and the old code paths +// * in the method above and in the {@link NanoSparqlServer}. +// */ +// private final boolean USE_WEB_XML = true; + /** - * Conditionally create the default KB instance as identified by the - * {@link NSSConfigurationOptions}. + * The actual port depends on how jetty was configured in + * <code>jetty.xml</code>. This returns the port associated with the first + * connection for the jetty {@link Server}. * + * @return The port associated with the first connection for the jetty + * {@link Server}. + * + * @throws IllegalArgumentException + * if the jetty {@link Server} is not running. + */ + int getNSSPort() { + + final Server tmp = jettyServer; + + if (tmp == null) + throw new IllegalStateException("Server is not running"); + + return tmp.getConnectors()[0].getLocalPort(); + + } + + /** + * Conditionally create the default KB instance as identified in + * <code>web.xml</code>. + * + * @see ConfigParams + * * @throws ConfigurationException * @throws ExecutionException * @throws InterruptedException @@ -4584,16 +4675,60 @@ private void conditionalCreateDefaultKB() throws ConfigurationException, InterruptedException, ExecutionException { - final String COMPONENT = NSSConfigurationOptions.COMPONENT; + final Server server = this.jettyServer; - final String namespace = (String) config.getEntry(COMPONENT, - NSSConfigurationOptions.NAMESPACE, String.class, - NSSConfigurationOptions.DEFAULT_NAMESPACE); + if (server == null) + throw new IllegalStateException(); - final boolean create = (Boolean) config.getEntry(COMPONENT, - NSSConfigurationOptions.CREATE, Boolean.TYPE, - NSSConfigurationOptions.DEFAULT_CREATE); + /* + * TODO This currently relies on the WebAppContext's initParams. This is + * somewhat fragile, but that is where this information is declared. + */ + final WebAppContext wac = NanoSparqlServer.getWebApp(server); + if (wac == null) + throw new RuntimeException("Could not locate webapp."); + + final String namespace; + { + + String s = wac.getInitParameter(ConfigParams.NAMESPACE); + + if (s == null) + s = ConfigParams.DEFAULT_NAMESPACE; + + namespace = s; + + if (log.isInfoEnabled()) + log.info(ConfigParams.NAMESPACE + "=" + namespace); + + } + + final boolean create; + { + + final String s = wac.getInitParameter(ConfigParams.CREATE); + + if (s != null) + create = Boolean.valueOf(s); + else + create = ConfigParams.DEFAULT_CREATE; + + if (log.isInfoEnabled()) + log.info(ConfigParams.CREATE + "=" + create); + + } + +// final String COMPONENT = NSSConfigurationOptions.COMPONENT; +// +// final String namespace = (String) config.getEntry(COMPONENT, +// NSSConfigurationOptions.NAMESPACE, String.class, +// NSSConfigurationOptions.DEFAULT_NAMESPACE); +// +// final boolean create = (Boolean) config.getEntry(COMPONENT, +// NSSConfigurationOptions.CREATE, Boolean.TYPE, +// NSSConfigurationOptions.DEFAULT_CREATE); + if (create) { final Future<Void> ft = journal.getExecutorService().submit( Modified: branches/BIGDATA_RELEASE_1_3_0/bigdata-jini/src/test/com/bigdata/journal/jini/ha/AbstractHA3JournalServerTestCase.java =================================================================== --- branches/BIGDATA_RELEASE_1_3_0/bigdata-jini/src/test/com/bigdata/journal/jini/ha/AbstractHA3JournalServerTestCase.java 2014-03-04 20:38:39 UTC (rev 7910) +++ branches/BIGDATA_RELEASE_1_3_0/bigdata-jini/src/test/com/bigdata/journal/jini/ha/AbstractHA3JournalServerTestCase.java 2014-03-04 20:46:21 UTC (rev 7911) @@ -1,3202 +1,3265 @@ -/** - -Copyright (C) SYSTAP, LLC 2006-2007. All rights reserved. - -Contact: - SYSTAP, LLC - 4501 Tower Road - Greensboro, NC 27410 - lic...@bi... - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -package com.bigdata.journal.jini.ha; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.net.InetAddress; -import java.rmi.Remote; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import junit.framework.AssertionFailedError; -import net.jini.config.Configuration; -import net.jini.config.ConfigurationException; -import net.jini.config.ConfigurationProvider; -import net.jini.core.lookup.ServiceID; -import net.jini.core.lookup.ServiceItem; -import net.jini.core.lookup.ServiceTemplate; -import net.jini.discovery.DiscoveryEvent; -import net.jini.discovery.DiscoveryListener; -import net.jini.discovery.LookupDiscoveryManager; -import net.jini.lease.LeaseRenewalManager; -import net.jini.lookup.ServiceDiscoveryManager; - -import org.apache.system.SystemUtil; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.KeeperException.ConnectionLossException; -import org.apache.zookeeper.KeeperException.NodeExistsException; -import org.apache.zookeeper.KeeperException.SessionExpiredException; -import org.apache.zookeeper.WatchedEvent; -import org.apache.zookeeper.Watcher; -import org.apache.zookeeper.ZooKeeper; -import org.apache.zookeeper.ZooKeeper.States; -import org.apache.zookeeper.data.ACL; - -import com.bigdata.ha.HAGlue; -import com.bigdata.ha.HAStatusEnum; -import com.bigdata.ha.IndexManagerCallable; -import com.bigdata.ha.RunState; -import com.bigdata.ha.msg.HARootBlockRequest; -import com.bigdata.ha.msg.HASnapshotDigestRequest; -import com.bigdata.ha.msg.IHASnapshotResponse; -import com.bigdata.jini.start.IServiceListener; -import com.bigdata.jini.start.config.JavaServiceConfiguration; -import com.bigdata.jini.start.config.ServiceConfiguration; -import com.bigdata.jini.start.config.ServiceConfiguration.AbstractServiceStarter; -import com.bigdata.jini.start.config.ZookeeperClientConfig; -import com.bigdata.jini.start.process.ProcessHelper; -import com.bigdata.jini.util.ConfigMath; -import com.bigdata.jini.util.JiniUtil; -import com.bigdata.journal.IRootBlockView; -import com.bigdata.journal.StoreState; -import com.bigdata.journal.jini.ha.HAJournalServer.ConfigurationOptions; -import com.bigdata.journal.jini.ha.HAJournalTest.HAGlueTest; -import com.bigdata.quorum.AbstractQuorumClient; -import com.bigdata.quorum.AsynchronousQuorumCloseException; -import com.bigdata.quorum.Quorum; -import com.bigdata.quorum.QuorumClient; -import com.bigdata.quorum.QuorumException; -import com.bigdata.quorum.zk.ZKQuorumClient; -import com.bigdata.quorum.zk.ZKQuorumImpl; -import com.bigdata.rdf.sail.webapp.client.HttpException; -import com.bigdata.service.jini.JiniClientConfig; -import com.bigdata.service.jini.RemoteDestroyAdmin; -import com.bigdata.util.InnerCause; -import com.bigdata.util.config.NicUtil; -import com.bigdata.zookeeper.DumpZookeeper; -import com.bigdata.zookeeper.ZooHelper; - -/** - * Class layers in support to start and stop the {@link HAJournalServer} - * processes. - * - * @author <a href="mailto:tho...@us...">Bryan Thompson</a> - */ -public class AbstractHA3JournalServerTestCase extends - AbstractHAJournalServerTestCase implements DiscoveryListener { - - /** Quorum client used to monitor (or act on) the logical service quorum. */ - protected Quorum<HAGlue, QuorumClient<HAGlue>> quorum = null; - - public AbstractHA3JournalServerTestCase() { - } - - public AbstractHA3JournalServerTestCase(final String name) { - super(name); - } - - /** - * The timeout in milliseconds to await the discovery of a service if there - * is a cache miss (default {@value #DEFAULT_CACHE_MISS_TIMEOUT}). - */ - static final protected long cacheMissTimeout = 2000; - - /** - * Implementation listens for the death of the child process and can be used - * to decide when the child process is no longer executing. - */ - private static class ServiceListener implements IServiceListener { - - private volatile HAGlue haGlue; - private volatile ProcessHelper processHelper; - private volatile boolean dead = false; - private volatile int childPID = 0; - - public ServiceListener() { - - } - - public void setService(final HAGlue haGlue) { - - if (haGlue == null) - throw new IllegalArgumentException(); - - this.haGlue = haGlue; - } - - @SuppressWarnings("unused") - public HAGlue getHAGlue() { - - return haGlue; - - } - - public void add(final ProcessHelper processHelper) { - - if (processHelper == null) - throw new IllegalArgumentException(); - - this.processHelper = processHelper; - - } - - public void remove(final ProcessHelper processHelper) { - - if (processHelper == null) - throw new IllegalArgumentException(); - - if (processHelper != this.processHelper) - throw new AssertionError(); - - /* - * Note: Do not clear the [processHelper] field. - */ - - // Mark the process as known dead. - dead = true; - - } - - public ProcessHelper getProcessHelper() { - - return processHelper; - - } - - public boolean isDead() { - - return dead; - - } - - } - - /** - * Return any overrides to be specified together with the basic - * {@link Configuration}. Each override is the fully qualified name - * of a {@link Configuration} parameter together with its value. For - * example: - * <pre> - * com.bigdata.journal.jini.ha.HAJournalServer.snapshotPolicy=new NoSnapshotPolicy(); - * </pre> - */ - protected String[] getOverrides() { - - return new String[]{}; - - } - - /** - * The {@link Remote} interfaces for these services (if started and - * successfully discovered). - */ - private HAGlue serverA = null, serverB = null, serverC = null; - - /** - * {@link UUID}s for the {@link HAJournalServer}s. - */ - private UUID serverAId = UUID.randomUUID(), serverBId = UUID.randomUUID(), - serverCId = UUID.randomUUID(); - - /** - * These {@link IServiceListener}s are used to reliably detect that the - * corresponding process starts and (most importantly) that it is really - * dies once it has been shutdown or destroyed. - */ - private ServiceListener serviceListenerA = null, serviceListenerB = null; - - private ServiceListener serviceListenerC = null; - - private LookupDiscoveryManager lookupDiscoveryManager = null; - - private ServiceDiscoveryManager serviceDiscoveryManager = null; - - private HAGlueServicesClient discoveryClient = null; - -// /** -// * The {@link ZooKeeperAccessor} used by the {@link #quorum}. -// */ -// private ZooKeeperAccessor zka = null; - - /** - * The {@link ZooKeeper} instance used by the {@link #quorum}. - */ - private ZooKeeper zookeeper = null; - - private ZookeeperClientConfig zkClientConfig = null; - -// /** -// * The {@link ACL}s used by the {@link #quorum}. -// */ -// private List<ACL> acl = null; - - /** - * The {@link ZooKeeper} instance used by the {@link #quorum}. - */ - private ZooKeeper getZookeeper() { - final ZooKeeper zookeeper = this.zookeeper; - if (zookeeper == null) - throw new IllegalStateException(); - return zookeeper; - } - - /** - * Return the negotiated zookeeper session timeout in milliseconds (if - * available) and otherwise the requested zookeeper session timeout. - */ - protected int getZKSessionTimeout() { - final ZooKeeper zookeeper = this.zookeeper; - if (zookeeper != null) { - final int t = zookeeper.getSessionTimeout(); - if (t > 0) - return t; - } - ZookeeperClientConfig t = zkClientConfig; - if (t != null) { - return t.sessionTimeout; - } - return 10000; - } - - /** - * The logicalServiceId (without the zroot prefix). - */ - private String logicalServiceId = null; - - /** - * The zpath of the logical service. - */ - protected String logicalServiceZPath = null; - - @Override - protected void setUp() throws Exception { - - /* - * Destroy the test directory structure. - * - * Note: This is done before we run the test rather than after so we can - * look at the end state of the data after running the test. - */ - { - - final File testDir = getTestDir(); - - if (testDir.exists()) { - - recursiveDelete(testDir); - - } - - } - - super.setUp(); - -// /* -// * Some tests tear down the zookeeper server process. This ensures that -// * we restart that server process before running another test. -// */ -// try { -// assertZookeeperRunning(); -// } catch (AssertionFailedError ex) { -// try { -// log.warn("Forcing ZooKeeper server process restart."); -// startZookeeper(); -// } catch (RuntimeException ex2) { -// log.error(ex2, ex2); -// } -// } - - // Unique for each test. - logicalServiceId = "CI-HAJournal-" + getName() + "-" + UUID.randomUUID(); - - /* - * Read the jini/river configuration file. We need this to setup the - * clients that we will use to lookup the services that we start. - */ - final Configuration config = ConfigurationProvider - .getInstance(new String[] { SRC_PATH + "jiniClient.config" }); - - final JiniClientConfig jiniClientConfig = new JiniClientConfig( - JiniClientConfig.Options.NAMESPACE, config); - - /* - * Note: This class will perform multicast discovery if ALL_GROUPS - * is specified and otherwise requires you to specify one or more - * unicast locators (URIs of hosts running discovery services). As - * an alternative, you can use LookupDiscovery, which always does - * multicast discovery. - */ - lookupDiscoveryManager = new LookupDiscoveryManager( - jiniClientConfig.groups, jiniClientConfig.locators, - this /* DiscoveryListener */, config); - - /* - * Setup a helper class that will be notified as services join or leave - * the various registrars to which the data server is listening. - */ - serviceDiscoveryManager = new ServiceDiscoveryManager( - lookupDiscoveryManager, new LeaseRenewalManager(), config); - - // Setup discovery for HAGlue clients. - discoveryClient = new HAGlueServicesClient(serviceDiscoveryManager, - null/* serviceDiscoveryListener */, cacheMissTimeout); - - if (!isZookeeperRunning()) { - - /* - * Ensure that zookeeper is running. - * - * Note: Some unit tests will tear down the zookeeper server - * process. This ensures that the zookeeper server process is - * restarted before the next test runs. - */ - - startZookeeper(); - - } - - // Setup quorum client. - quorum = newQuorum(); - - } - - @Override - protected void tearDown() throws Exception { - - if (quorum != null && log.isInfoEnabled()) { - - /* - * Echo the final quorum state (as currently reflected). - */ - - log.info(quorum.toString()); - - } - - if (zookeeper != null && log.isInfoEnabled()) { - - /* - * Dump the final zookeeper state for the logical service. - */ - - log.info("Zookeeper State for logical service: \n" + dumpZoo()); - - } - - destroyAll(); - - if (serviceDiscoveryManager != null) { - serviceDiscoveryManager.terminate(); - serviceDiscoveryManager = null; - } - - if (lookupDiscoveryManager != null) { - lookupDiscoveryManager.terminate(); - lookupDiscoveryManager = null; - } - - if (discoveryClient != null) { - discoveryClient.terminate(); - discoveryClient = null; - } - - if (quorum != null) { - quorum.terminate(); - quorum = null; - } - - if (zookeeper != null) { - final String zroot = logicalServiceZPath; - destroyZNodes(zroot, zookeeper); - zookeeper.close(); - zookeeper = null; - zkClientConfig = null; - } - - logicalServiceId = null; - logicalServiceZPath = null; - serverAId = serverBId = serverCId = null; - - super.tearDown(); - - } - - protected void destroyAll() throws AsynchronousQuorumCloseException, - InterruptedException, TimeoutException { - /** - * The most reliable tear down is in reverse pipeline order. - * - * This may not be necessary long term but for now we want to avoid - * destroying the leader first since it can lead to problems as - * followers attempt to reform - */ - final HAGlue leader; - final File leaderServiceDir; - final ServiceListener leaderListener; - if (quorum.isQuorumMet()) { - final long token = quorum.awaitQuorum(awaitQuorumTimeout, - TimeUnit.MILLISECONDS); - /* - * Note: It is possible to resolve a proxy for a service that - * has been recently shutdown or destroyed. This is effectively - * a data race. - */ - final HAGlue t = quorum.getClient().getLeader(token); - if (t.equals(serverA)) { - leader = t; - leaderServiceDir = getServiceDirA(); - leaderListener = serviceListenerA; - } else if (t.equals(serverB)) { - leader = t; - leaderServiceDir = getServiceDirB(); - leaderListener = serviceListenerB; - } else if (t.equals(serverC)) { - leader = t; - leaderServiceDir = getServiceDirC(); - leaderListener = serviceListenerC; - } else { - if (serverA == null && serverB == null && serverC == null) { - /* - * There are no services running and nothing to shutdown. We - * probably resolved a stale proxy to the leader above. - */ - return; - } - throw new IllegalStateException( - "Leader is none of A, B, or C: leader=" + t + ", A=" - + serverA + ", B=" + serverB + ", C=" + serverC); - } - } else { - leader = null; - leaderServiceDir = null; - leaderListener = null; - } - - if (leader == null || !leader.equals(serverA)) { - destroyA(); - } - - if (leader == null || !leader.equals(serverB)) { - destroyB(); - } - - if (leader == null || !leader.equals(serverC)) { - destroyC(); - } - - // Destroy leader last - if (leader != null) { - safeDestroy(leader, leaderServiceDir, leaderListener); - - serverA = serverB = serverC = null; - serviceListenerA = serviceListenerC =serviceListenerB = null; - } - - - } - - protected UUID[] getServices(final HAGlue[] members) throws IOException { - final UUID[] services = new UUID[members.length]; - for (int m = 0; m < members.length; m++) { - services[m] = members[m].getServiceId(); - } - - return services; - } - - /** - * Waits for pipeline in expected order - * - * @param members - * @throws IOException - */ - protected void awaitPipeline(final HAGlue[] members) throws IOException { - awaitPipeline(5, TimeUnit.SECONDS, members); - } - - /** - * Waits for pipeline in expected order - * - * @param members - * @throws IOException - */ - protected void awaitPipeline(final long timeout, final TimeUnit unit, - final HAGlue[] members) throws IOException { - - final UUID[] services = getServices(members); - - assertCondition(new Runnable() { - @Override - public void run() { - try { - assertEquals(services, quorum.getPipeline()); - } catch (Exception e) { - // KB does not exist. - fail(); - } - } - - }, timeout, unit); - - } - - protected void assertReady(final HAGlue[] members) throws IOException { - - for (HAGlue member : members) { - - final HAStatusEnum status = member.getHAStatus(); - - if (log.isInfoEnabled()) - log.info(member.getServiceName() + ": " + status); - - assertFalse(HAStatusEnum.NotReady == status); - - } - - } - - /** - * Waits for joined in expected order - * - * @param members - * @throws IOException - */ - protected void awaitJoined(final HAGlue[] members) throws IOException { - - final UUID[] services = getServices(members); - - assertCondition(new Runnable() { - @Override - public void run() { - try { - assertEquals(services, quorum.getJoined()); - } catch (Exception e) { - // KB does not exist. - fail(); - } - } - - }, 5, TimeUnit.SECONDS); - - } - - /** - * Waits for members in expected order - * - * @param members - * @throws IOException - */ - protected void awaitMembers(final HAGlue[] members) throws IOException { - - final UUID[] services = getServices(members); - - assertCondition(new Runnable() { - @Override - public void run() { - try { - assertEquals(services, quorum.getMembers()); - } catch (Exception e) { - // KB does not exist. - fail(); - } - } - - }, 5, TimeUnit.SECONDS); - - } - - /** - * Start A then B then C. As each service starts, this method waits for that - * service to appear in the pipeline in the proper position. - * - * @return The ordered array of services <code>[A, B, C]</code> - */ - protected HAGlue[] startSequenceABC() throws Exception { - - startA(); - awaitPipeline(new HAGlue[] { serverA }); - - startB(); - awaitPipeline(new HAGlue[] { serverA, serverB }); - - startC(); - awaitPipeline(new HAGlue[] { serverA, serverB, serverC }); - - return new HAGlue[] { serverA, serverB, serverC }; - - } - - /* - * Utility methods to access service HALog file directories - */ - - /** - * The effective name for this test as used to name the directories in which - * we store things. - */ - protected String getEffectiveTestFileName() { - - return effectiveTestFileName; - - } - - /** - * The effective name for this test as used to name the directories in which - * we store things. - * - * TODO If there are method name collisions across the different test - * classes then the test suite name can be added to this. Also, if there are - * file naming problems, then this value can be munged before it is - * returned. - */ - private final String effectiveTestFileName = getClass().getSimpleName() - + "." + getName(); - - /** - * The directory that is the parent of each {@link HAJournalServer}'s - * individual service directory. - */ - protected File getTestDir() { - return new File(TGT_PATH, getEffectiveTestFileName()); - } - - protected File getServiceDirA() { - return new File(getTestDir(), "A"); - } - - protected File getServiceDirB() { - return new File(getTestDir(), "B"); - } - - protected File getServiceDirC() { - return new File(getTestDir(), "C"); - } - - protected File getHAJournalFileA() { - return new File(getServiceDirA(), "bigdata-ha.jnl"); - } - - protected File getHAJournalFileB() { - return new File(getServiceDirB(), "bigdata-ha.jnl"); - } - - protected File getHAJournalFileC() { - return new File(getServiceDirC(), "bigdata-ha.jnl"); - } - - protected File getHALogDirA() { - return new File(getServiceDirA(), "HALog"); - } - - protected File getHALogDirB() { - return new File(getServiceDirB(), "HALog"); - } - - protected File getHALogDirC() { - return new File(getServiceDirC(), "HALog"); - } - - protected File getSnapshotDirA() { - return new File(getServiceDirA(), "snapshot"); - } - - protected File getSnapshotDirB() { - return new File(getServiceDirB(), "snapshot"); - } - - protected File getSnapshotDirC() { - return new File(getServiceDirC(), "snapshot"); - } - - /** - * Clear out everything in zookeeper for the specified zpath. - */ - private void destroyZNodes(final String zpath, final ZooKeeper zookeeper) { - - if (log.isInfoEnabled()) - log.info("zpath=" + zpath); - - try { - - if (zookeeper.exists(zpath, false/* watch */) != null) { - - ZooHelper.destroyZNodes(zookeeper, zpath, 0/* depth */); - } - - } catch (InterruptedException ex) { - - log.warn(ex); - - } catch (SessionExpiredException ex) { - - log.warn(ex); - - } catch (ConnectionLossException ex) { - - log.warn(ex); - - } catch (Exception e) { - - throw new RuntimeException(e); - - } - - } - - /** - * Dump the zookeeper state for the logical service. - */ - protected String dumpZoo() throws KeeperException, InterruptedException { - - final StringWriter sw = new StringWriter(); - - final PrintWriter w = new PrintWriter(sw); - - final ZooKeeper zk = getZookeeper(); - try { - new DumpZookeeper(zk).dump(w, true/* showData */, - logicalServiceZPath, 0/* depth */); - } catch (KeeperException ex) { - /* - * Note: This is expected if you have shut down the zookeeper server - * process under test suite control. - */ - ex.printStackTrace(w); - } - w.flush(); - w.close(); - - sw.flush(); - - return sw.toString(); - - } - - /** - * Safely destroy the service. - * - * @param haGlue - * The service. - */ - protected void safeDestroy(final HAGlue haGlue, final File serviceDir, - final ServiceListener serviceListener) { - - if (log.isInfoEnabled()) - log.info("Destroying service: " + haGlue + ", serviceDir=" - + serviceDir); - - if (haGlue == null) { - - tidyServiceDirectory(serviceDir); // ensure empty - - return; - - } - - try { - - final UUID serviceId = haGlue.getServiceUUID(); - - haGlue.destroy(); - - awaitServiceGone(serviceId, haGlue, serviceDir, serviceListener); - - } catch (Throwable t) { - - if (InnerCause.isInnerCause(t, java.net.ConnectException.class)) { - - log.warn("Service is down (RMI not allowed): " + t); - - } else { - - // Some other problem. - log.error(t, t); - - } - - { - - if (serviceListener != null && serviceListener.childPID != 0) { - - final int childPID = serviceListener.childPID; - - log.warn("Attempting to signal service: " + serviceDir - + ", pid=" + childPID); - - // Try to request a thread dump. - if (trySignal(SignalEnum.QUIT, childPID)) { - - // Give the child a moment to respond. - try { - Thread.sleep(2000/* ms */); - } catch (InterruptedException e) { - // Propagate the interrupt. - Thread.currentThread().interrupt(); - } - - } - - // Sure kill on the child. - trySignal(SignalEnum.KILL, childPID); - - } - - } - - // try and ensure serviceDir is tidied in any event - // Remove *.jnl, HALog/*, snapshot/* - log.warn("Need to clear directory explicitly: " + serviceDir.getAbsolutePath()); - - tidyServiceDirectory(serviceDir); - } - - } - - private void tidyServiceDirectory(final File serviceDir) { - if (serviceDir == null || !serviceDir.exists()) - return; - - for (File file : serviceDir.listFiles()) { - final String name = file.getName(); - - if (name.endsWith(".jnl") || name.equals("snapshot") - || name.equals("HALog")) { - recursiveDelete(file); - } - } - } - - /** - * Some signals understood by Java. - * - * @author <a href="mailto:tho...@us...">Bryan - * Thompson</a> - */ - protected enum SignalEnum { - /** Heap dump. */ - INT(2,"INT"), - /** Thread dump (^C). */ - QUIT(3,"QUIT"), - /** Sure kill. */ - KILL(9,"KILL"); - private final int code; - private final String symbol; - private SignalEnum(int code, String symbol) { - this.code = code; - this.symbol = symbol; - } - public int code() { - return code; - } - public String symbol() { - return symbol; - } - }; - - /** - * Attempt to signal a process (presumably a child process). - * - * @param signalEnum - * The signal. - * @param pid - * The pid of the process. - * - * @return true unless an exception was encountered (a <code>true</code> - * return is not a sure indicator of success). - */ - static protected boolean trySignal(final SignalEnum signalEnum, - final int pid) { - - final String cmd = "kill -" + signalEnum.symbol() + " " + pid; - - log.warn("SIGNAL: " + cmd); - - try { - - Runtime.getRuntime().exec(cmd); - - return true; - - } catch (IOException e) { - - log.error("FAILED: " + cmd, e); - - return false; - - } - - } - - protected void destroyA() { - safeDestroy(serverA, getServiceDirA(), serviceListenerA); - serverA = null; - serviceListenerA = null; - } - - protected void destroyB() { - safeDestroy(serverB, getServiceDirB(), serviceListenerB); - serverB = null; - serviceListenerB = null; - } - - protected void destroyC() { - safeDestroy(serverC, getServiceDirC(), serviceListenerC); - serverC = null; - serviceListenerC = null; - } - - protected void shutdownA() throws IOException { - safeShutdown(serverA, getServiceDirA(), serviceListenerA, true); - - serverA = null; - serviceListenerA = null; - } - - protected void shutdownB() throws IOException { - safeShutdown(serverB, getServiceDirB(), serviceListenerB, true); - - serverB = null; - serviceListenerB = null; - } - - protected void shutdownC() throws IOException { - safeShutdown(serverC, getServiceDirC(), serviceListenerC, true); - - serverC = null; - serviceListenerC = null; - } - - protected void kill(final HAGlue service) throws IOException { - - final int pid = ((HAGlueTest) service).getPID(); - - trySignal(SignalEnum.KILL, pid); - - } - - /** - * NOTE: This relies on equals() being valid for Proxies which isn't - * necessarily something we should rely on - */ - protected void shutdown(final HAGlue service) throws IOException { - if (service == null) { - throw new IllegalArgumentException(); - } - - if (service.equals(serverA)) { - shutdownA(); - } else if (service.equals(serverB)) { - shutdownB(); - } else if (service.equals(serverC)) { - shutdownC(); - } else { - throw new IllegalArgumentException("Unable to match service: " - + service + " possible problem with equals() on Proxy"); - } - } - - protected void shutdownLeader() throws AsynchronousQuorumCloseException, - InterruptedException, TimeoutException, IOException { - - final long token = quorum.awaitQuorum(awaitQuorumTimeout, - TimeUnit.MILLISECONDS); - - final HAGlue leader = quorum.getClient().getLeader(token); - - shutdown(leader); - - } - - protected class SafeShutdownTask implements Callable<Void> { - - private final HAGlue haGlue; - private final File serviceDir; - private final ServiceListener serviceListener; - private final boolean now; - - public SafeShutdownTask(final HAGlue haGlue, final File serviceDir, - final ServiceListener serviceListener) { - - this(haGlue, serviceDir, serviceListener, false/* now */); - - } - - public SafeShutdownTask(final HAGlue haGlue, final File serviceDir, - final ServiceListener serviceListener, final boolean now) { - - this.haGlue = haGlue; - this.serviceDir = serviceDir; - this.serviceListener = serviceListener; - this.now = now; - - } - - @Override - public Void call() { - - safeShutdown(haGlue, serviceDir, serviceListener, now); - - return null; - - } - - } - - protected class SafeShutdownATask extends SafeShutdownTask { - - public SafeShutdownATask() { - this(false/* now */); - } - - public SafeShutdownATask(final boolean now) { - super(serverA, getServiceDirA(), serviceListenerA, now); - } - - } - - protected class SafeShutdownBTask extends SafeShutdownTask { - - public SafeShutdownBTask() { - this(false/* now */); - } - - public SafeShutdownBTask(final boolean now) { - super(serverB, getServiceDirB(), serviceListenerB, now); - } - - } - - protected class SafeShutdownCTask extends SafeShutdownTask { - - public SafeShutdownCTask() { - this(false/* now */); - } - - public SafeShutdownCTask(final boolean now) { - super(serverC, getServiceDirC(), serviceListenerC, now); - } - - } - - /** - * Debug class to explicitly ask one service to remove another. - * - * This emulates the behaviour of the service in receiving correct notification - * of a target service failure -for example after a wire pull or sure kill. - * - */ - protected static class ForceRemoveService extends IndexManagerCallable<Void> { - - private static final long serialVersionUID = 1L; - private final UUID service; - - ForceRemoveService(final UUID service) { - this.service = service; - } - - @Override - public Void call() throws Exception { - - final HAJournal ha = (HAJournal) this.getIndexManager(); - - ha.getQuorum().getActor().forceRemoveService(service); - - return null; - } - - } - - private void safeShutdown(final HAGlue haGlue, final File serviceDir, - final ServiceListener serviceListener) { - - safeShutdown(haGlue, serviceDir, serviceListener, false/* now */); - - } - - private void safeShutdown(final HAGlue haGlue, final File serviceDir, - final ServiceListener serviceListener, final boolean now) { - - if (haGlue == null) - return; - - try { - - final UUID serviceId = haGlue.getServiceUUID(); - - // Shutdown the remote service. - if (now) - ((RemoteDestroyAdmin) haGlue).shutdownNow(); - else - ((RemoteDestroyAdmin) haGlue).shutdown(); - - awaitServiceGone(serviceId, haGlue, serviceDir, serviceListener); - - } catch (Throwable t) { - - if (InnerCause.isInnerCause(t, java.net.ConnectException.class)) { - - log.warn("Service is down: " + t); - - } else { - - // Some other problem. - log.error(t, t); - - } - - } - - } - - /** - * Await positive indication that the service is shutdown. This can mean - * looking for the service {@link RunState} change, looking for the service - * to no longer be discoverable, looking for the service to no longer accept - * RMI requests, etc. - * <p> - * Note: If the child does not shutdown normally, then this will force a - * kill of the child process and throw out an {@link AssertionFailedError}. - * This {@link AssertionFailedError} is a good indication that there is a - * problem with the process shutdown / destroy logic. You should obtain - * thread dumps when this happens and examine them for the root cause of the - * process failing to terminate normally. - */ - private void awaitServiceGone(final UUID serviceId, final HAGlue haGlue, - final File serviceDir, final ServiceListener serviceListener) { - - assertCondition(new Runnable() { - @Override - public void run() { - try { - haGlue.getRunState(); - fail();// still answering RMI requests. - } catch (IOException e) { - // Service is down. - return; - } - } - }); - - assertCondition(new Runnable() { - @Override - ... [truncated message content] |