Issue #1939 Fix deadlock at CAVE start up.

Change-Id: Ic3a0f527cdae7ee1abc32662c90d9594686d4bab

Former-commit-id: b38ba1c92e4e176364dc3967d11b98fbd66478cd
This commit is contained in:
Ron Anderson 2013-04-23 14:50:34 -05:00
parent 13940124bc
commit 6f2a6ce80c
6 changed files with 142 additions and 66 deletions

View file

@ -69,6 +69,8 @@ import com.raytheon.uf.viz.core.notification.NotificationMessage;
* ------------ ---------- ----------- -------------------------- * ------------ ---------- ----------- --------------------------
* 05/08/08 1127 randerso Initial Creation * 05/08/08 1127 randerso Initial Creation
* 09/03/08 1448 chammack Refactored notification observer interface * 09/03/08 1448 chammack Refactored notification observer interface
* 04/23/13 1939 randerso Add separate connect method to allow application
* to complete initialization before connecting to JMS
* </pre> * </pre>
* *
* @author randerso * @author randerso
@ -184,7 +186,6 @@ public class NotificationManagerJob implements ExceptionListener, IDisposable {
*/ */
protected NotificationManagerJob() { protected NotificationManagerJob() {
this.listeners = new HashMap<ListenerKey, NotificationListener>(); this.listeners = new HashMap<ListenerKey, NotificationListener>();
connect(true);
Activator.getDefault().registerDisposable(this); Activator.getDefault().registerDisposable(this);
} }
@ -411,6 +412,20 @@ public class NotificationManagerJob implements ExceptionListener, IDisposable {
} }
} }
/**
* Connect to JMS
*/
public static void connect() {
getInstance().connect(true);
}
/**
* Disconnect from JMS
*/
public static void disconnect() {
getInstance().disconnect(true);
}
private static class NotificationListener implements MessageListener { private static class NotificationListener implements MessageListener {
private Type type; private Type type;

View file

@ -27,6 +27,7 @@ import java.util.List;
import javax.xml.bind.JAXBException; import javax.xml.bind.JAXBException;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.ui.application.WorkbenchAdvisor; import org.eclipse.ui.application.WorkbenchAdvisor;
import org.osgi.framework.Bundle; import org.osgi.framework.Bundle;
@ -67,7 +68,8 @@ import com.raytheon.viz.ui.personalities.awips.CAVE;
* *
* Date Ticket# Engineer Description * Date Ticket# Engineer Description
* ------------ ---------- ----------- -------------------------- * ------------ ---------- ----------- --------------------------
* Aug 4, 2011 njensen Initial creation * Aug 4, 2011 njensen Initial creation
* Apr 23, 2013 1939 randerso Return null from initializeSerialization
* *
* </pre> * </pre>
* *
@ -192,6 +194,7 @@ public class ThinClientComponent extends CAVE implements IThinClientComponent {
} }
} }
@Override
public void stopComponent() { public void stopComponent() {
// Persist caches // Persist caches
cacheManager.storeCaches(); cacheManager.storeCaches();
@ -201,13 +204,15 @@ public class ThinClientComponent extends CAVE implements IThinClientComponent {
} }
@Override @Override
protected void initializeSerialization() { protected Job initializeSerialization() {
try { try {
SerializationUtil.getJaxbContext(); SerializationUtil.getJaxbContext();
} catch (JAXBException e) { } catch (JAXBException e) {
statusHandler.handle(Priority.CRITICAL, statusHandler.handle(Priority.CRITICAL,
"An error occured initializing Serialization", e); "An error occured initializing Serialization", e);
} }
return null;
} }
} }

View file

@ -50,6 +50,8 @@ import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority; import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.common.time.SimulatedTime; import com.raytheon.uf.common.time.SimulatedTime;
import com.raytheon.uf.common.time.util.ITimer;
import com.raytheon.uf.common.time.util.TimeUtil;
import com.raytheon.uf.viz.alertviz.SystemStatusHandler; import com.raytheon.uf.viz.alertviz.SystemStatusHandler;
import com.raytheon.uf.viz.alertviz.ui.dialogs.AlertVisualization; import com.raytheon.uf.viz.alertviz.ui.dialogs.AlertVisualization;
import com.raytheon.uf.viz.application.ProgramArguments; import com.raytheon.uf.viz.application.ProgramArguments;
@ -60,6 +62,7 @@ import com.raytheon.uf.viz.core.localization.CAVELocalizationNotificationObserve
import com.raytheon.uf.viz.core.localization.LocalizationConstants; import com.raytheon.uf.viz.core.localization.LocalizationConstants;
import com.raytheon.uf.viz.core.localization.LocalizationInitializer; import com.raytheon.uf.viz.core.localization.LocalizationInitializer;
import com.raytheon.uf.viz.core.localization.LocalizationManager; import com.raytheon.uf.viz.core.localization.LocalizationManager;
import com.raytheon.uf.viz.core.notification.jobs.NotificationManagerJob;
import com.raytheon.uf.viz.core.status.VizStatusHandlerFactory; import com.raytheon.uf.viz.core.status.VizStatusHandlerFactory;
import com.raytheon.viz.alerts.jobs.AutoUpdater; import com.raytheon.viz.alerts.jobs.AutoUpdater;
import com.raytheon.viz.alerts.jobs.MenuUpdater; import com.raytheon.viz.alerts.jobs.MenuUpdater;
@ -90,6 +93,8 @@ import com.raytheon.viz.core.units.UnitRegistrar;
* mode is off. * mode is off.
* Jan 09, 2013 #1442 rferrel Changes to notify SimultedTime listeners. * Jan 09, 2013 #1442 rferrel Changes to notify SimultedTime listeners.
* Apr 17, 2013 1786 mpduff startComponent now sets StatusHandlerFactory * Apr 17, 2013 1786 mpduff startComponent now sets StatusHandlerFactory
* Apr 23, 2013 #1939 randerso Allow serialization to complete initialization
* before connecting to JMS to avoid deadlock
* *
* </pre> * </pre>
* *
@ -139,7 +144,8 @@ public abstract class AbstractCAVEComponent implements IStandaloneComponent {
UnitRegistrar.registerUnits(); UnitRegistrar.registerUnits();
CAVEMode.performStartupDuties(); CAVEMode.performStartupDuties();
long t0 = System.currentTimeMillis(); ITimer timer = TimeUtil.getTimer();
timer.start();
Display display = null; Display display = null;
int modes = getRuntimeModes(); int modes = getRuntimeModes();
@ -166,7 +172,7 @@ public abstract class AbstractCAVEComponent implements IStandaloneComponent {
} }
UFStatus.setHandlerFactory(new VizStatusHandlerFactory()); UFStatus.setHandlerFactory(new VizStatusHandlerFactory());
initializeSerialization(); Job serializationJob = initializeSerialization();
initializeDataStoreFactory(); initializeDataStoreFactory();
initializeObservers(); initializeObservers();
@ -204,12 +210,22 @@ public abstract class AbstractCAVEComponent implements IStandaloneComponent {
WorkbenchAdvisor workbenchAdvisor = null; WorkbenchAdvisor workbenchAdvisor = null;
// A component was passed as command line arg // A component was passed as command line arg
// launch cave normally, should cave be registered as component? // launch cave normally, should cave be registered as component?
long t1 = System.currentTimeMillis();
System.out.println("Localization time: " + (t1 - t0) + "ms");
try { try {
initializeSimulatedTime(); initializeSimulatedTime();
// wait for serialization initialization to complete before
// opening JMS connection to avoid deadlock in class loaders
if (serializationJob != null) {
serializationJob.join();
}
// open JMS connection to allow alerts to be received
NotificationManagerJob.connect();
timer.stop();
System.out.println("Initialization time: " + timer.getElapsedTime()
+ "ms");
if (cave) { if (cave) {
workbenchAdvisor = getWorkbenchAdvisor(); workbenchAdvisor = getWorkbenchAdvisor();
} else if (!nonui) { } else if (!nonui) {
@ -220,6 +236,7 @@ public abstract class AbstractCAVEComponent implements IStandaloneComponent {
if (workbenchAdvisor instanceof HiddenWorkbenchAdvisor == false) { if (workbenchAdvisor instanceof HiddenWorkbenchAdvisor == false) {
startInternal(componentName); startInternal(componentName);
} }
if (workbenchAdvisor != null) { if (workbenchAdvisor != null) {
returnCode = PlatformUI.createAndRunWorkbench(display, returnCode = PlatformUI.createAndRunWorkbench(display,
workbenchAdvisor); workbenchAdvisor);
@ -239,6 +256,15 @@ public abstract class AbstractCAVEComponent implements IStandaloneComponent {
// catch any exceptions to ensure rest of finally block // catch any exceptions to ensure rest of finally block
// executes // executes
} }
try {
// disconnect from JMS
NotificationManagerJob.disconnect();
} catch (RuntimeException e) {
// catch any exceptions to ensure rest of finally block
// executes
}
if (av != null) { if (av != null) {
av.dispose(); av.dispose();
} }
@ -368,8 +394,8 @@ public abstract class AbstractCAVEComponent implements IStandaloneComponent {
!LocalizationManager.internalAlertServer).run(); !LocalizationManager.internalAlertServer).run();
} }
protected void initializeSerialization() { protected Job initializeSerialization() {
new Job("Loading Serialization") { Job job = new Job("Loading Serialization") {
@Override @Override
protected IStatus run(IProgressMonitor monitor) { protected IStatus run(IProgressMonitor monitor) {
@ -382,7 +408,9 @@ public abstract class AbstractCAVEComponent implements IStandaloneComponent {
return Status.OK_STATUS; return Status.OK_STATUS;
} }
}.schedule(); };
job.schedule();
return job;
} }
/** /**

View file

@ -147,6 +147,7 @@ wrapper.java.additional.48=-Dhttp.port=${HTTP_PORT}
wrapper.java.additional.49=-Dedex.arch=${EDEX_BITS}-bit wrapper.java.additional.49=-Dedex.arch=${EDEX_BITS}-bit
wrapper.java.additional.50=-Dedex.tmp=${TEMP_DIR} wrapper.java.additional.50=-Dedex.tmp=${TEMP_DIR}
wrapper.java.additional.51=-Dncf.bandwidth.manager.service=${NCF_BANDWIDTH_MANAGER_SERVICE} wrapper.java.additional.51=-Dncf.bandwidth.manager.service=${NCF_BANDWIDTH_MANAGER_SERVICE}
wrapper.java.additional.52=-DinitializeHibernatables=true
# Initial Java Heap Size (in MB) # Initial Java Heap Size (in MB)
wrapper.java.initmemory=${INIT_MEM} wrapper.java.initmemory=${INIT_MEM}

View file

@ -3,7 +3,6 @@ com.raytheon.uf.common.dataplugin.gfe.db.objects.DatabaseID
com.raytheon.uf.common.dataplugin.gfe.db.objects.GFERecord com.raytheon.uf.common.dataplugin.gfe.db.objects.GFERecord
com.raytheon.uf.common.dataplugin.gfe.db.objects.GridLocation com.raytheon.uf.common.dataplugin.gfe.db.objects.GridLocation
com.raytheon.uf.common.dataplugin.gfe.db.objects.ParmID com.raytheon.uf.common.dataplugin.gfe.db.objects.ParmID
com.raytheon.uf.common.dataplugin.gfe.db.objects.GridLocation
com.raytheon.uf.common.dataplugin.gfe.reference.ReferenceData com.raytheon.uf.common.dataplugin.gfe.reference.ReferenceData
com.raytheon.uf.common.dataplugin.gfe.sample.SampleData com.raytheon.uf.common.dataplugin.gfe.sample.SampleData
com.raytheon.uf.common.dataplugin.gfe.server.lock.Lock com.raytheon.uf.common.dataplugin.gfe.server.lock.Lock

View file

@ -14,7 +14,7 @@
* Omaha, NE 68106 * Omaha, NE 68106
* 402.291.0100 * 402.291.0100
* *
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for * See the AWIPS II Master Rights File ("Master Rights File.p df") for
* further licensing information. * further licensing information.
**/ **/
package com.raytheon.uf.common.serialization; package com.raytheon.uf.common.serialization;
@ -31,6 +31,7 @@ import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.ServiceConfigurationError; import java.util.ServiceConfigurationError;
import java.util.Set; import java.util.Set;
@ -56,6 +57,9 @@ import com.raytheon.uf.common.serialization.jaxb.JaxbDummyObject;
* Aug 11, 2008 njensen Initial creation * Aug 11, 2008 njensen Initial creation
* Aug 31, 2009 2924 rjpeter Added Embeddable. * Aug 31, 2009 2924 rjpeter Added Embeddable.
* Feb 07, 2013 1543 djohnson Implement IJaxbableClassesLocator. * Feb 07, 2013 1543 djohnson Implement IJaxbableClassesLocator.
* Apr 24, 2013 1939 randerso Clean up code and attempt to improve speed.
* Added initializeHibernatables flag to disable
* processing hibernatables on CAVE
* </pre> * </pre>
* *
* @author njensen * @author njensen
@ -82,8 +86,6 @@ public class SerializableManager implements IJaxbableClassesLocator {
*/ */
@SuppressWarnings(value = { "unchecked" }) @SuppressWarnings(value = { "unchecked" })
private synchronized void initialize() { private synchronized void initialize() {
ClassLoader cl = getClass().getClassLoader();
long t0 = System.currentTimeMillis(), total = 0;
// this is here in case in the future we want to re-initialize the lists // this is here in case in the future we want to re-initialize the lists
// during runtime, i.e. hot deploy of a new plugin // during runtime, i.e. hot deploy of a new plugin
hibernatables.clear(); hibernatables.clear();
@ -96,23 +98,37 @@ public class SerializableManager implements IJaxbableClassesLocator {
.getResources( .getResources(
"META-INF/services/" "META-INF/services/"
+ ISerializableObject.class.getName()); + ISerializableObject.class.getName());
// doHibernate will be false in CAVE since they are not needed
boolean doHibernate = Boolean.getBoolean("initializeHibernatables");
// In testing 1 thread is slowest, 2 threads cuts the time down // In testing 1 thread is slowest, 2 threads cuts the time down
// about 50% and 3 threads cuts down another 5% or so, 4 threads // about 50% and 3 threads cuts down another 5% or so, 4 threads
// shows no benefit over 2. These results are system specific. // shows no benefit over 2. These results are system specific.
int numThreads = 3; int numThreads = 3;
Thread[] threads = new Thread[numThreads]; LoadSerializableClassesThread[] threads = new LoadSerializableClassesThread[numThreads];
for (int i = 1; i < numThreads; i++) { for (int i = 0; i < numThreads; i++) {
threads[i] = new LoadSerializableClassesThread(urls, clazzSet, threads[i] = new LoadSerializableClassesThread(urls,
hibernatables); doHibernate);
threads[i].start(); threads[i].start();
} }
threads[0] = new LoadSerializableClassesThread(urls, clazzSet,
hibernatables); for (LoadSerializableClassesThread thread : threads) {
// Run this one on the current thread since its not doing anything thread.join();
// but waiting and this avoids overhead of starting a new thread clazzSet.addAll(thread.getClazzList());
threads[0].run();
for (int i = 1; i < numThreads; i++) { if (doHibernate) {
threads[i].join(); for (Entry<String, List<Class<ISerializableObject>>> entry : thread
.getHibernatables().entrySet()) {
List<Class<ISerializableObject>> list = hibernatables
.get(entry.getKey());
if (list == null) {
list = new ArrayList<Class<ISerializableObject>>();
hibernatables.put(entry.getKey(), list);
}
list.addAll(entry.getValue());
}
}
} }
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
@ -127,6 +143,7 @@ public class SerializableManager implements IJaxbableClassesLocator {
System.out.println("Total time spent loading classes: " System.out.println("Total time spent loading classes: "
+ (System.currentTimeMillis() - realStartTime) + "ms"); + (System.currentTimeMillis() - realStartTime) + "ms");
} }
private static void fail(Class service, String msg, Throwable cause) private static void fail(Class service, String msg, Throwable cause)
@ -153,25 +170,28 @@ public class SerializableManager implements IJaxbableClassesLocator {
return -1; return -1;
} }
int ci = ln.indexOf('#'); int ci = ln.indexOf('#');
if (ci >= 0) if (ci >= 0) {
ln = ln.substring(0, ci); ln = ln.substring(0, ci);
}
ln = ln.trim(); ln = ln.trim();
int n = ln.length(); int n = ln.length();
if (n != 0) { if (n != 0) {
if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0)) if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0)) {
fail(service, u, lc, "Illegal configuration-file syntax"); fail(service, u, lc, "Illegal configuration-file syntax");
}
int cp = ln.codePointAt(0); int cp = ln.codePointAt(0);
if (!Character.isJavaIdentifierStart(cp)) if (!Character.isJavaIdentifierStart(cp)) {
fail(service, u, lc, "Illegal provider-class name: " + ln); fail(service, u, lc, "Illegal provider-class name: " + ln);
}
for (int i = Character.charCount(cp); i < n; i += Character for (int i = Character.charCount(cp); i < n; i += Character
.charCount(cp)) { .charCount(cp)) {
cp = ln.codePointAt(i); cp = ln.codePointAt(i);
if (!Character.isJavaIdentifierPart(cp) && (cp != '.')) if (!Character.isJavaIdentifierPart(cp) && (cp != '.')) {
fail(service, u, lc, "Illegal provider-class name: " + ln); fail(service, u, lc, "Illegal provider-class name: " + ln);
}
} }
if (!names.contains(ln)) names.add(ln);
names.add(ln);
} }
return lc + 1; return lc + 1;
} }
@ -233,30 +253,42 @@ public class SerializableManager implements IJaxbableClassesLocator {
private final Enumeration<URL> urls; private final Enumeration<URL> urls;
private final Set<Class<ISerializableObject>> clazzSet; private final boolean doHibernate;
private final List<Class<ISerializableObject>> clazzList;
private final Map<String, List<Class<ISerializableObject>>> hibernatables; private final Map<String, List<Class<ISerializableObject>>> hibernatables;
public LoadSerializableClassesThread(Enumeration<URL> urls, public LoadSerializableClassesThread(Enumeration<URL> urls,
Set<Class<ISerializableObject>> clazzSet, boolean doHibernate) {
Map<String, List<Class<ISerializableObject>>> hibernatables) {
this.urls = urls; this.urls = urls;
this.clazzSet = clazzSet; this.doHibernate = doHibernate;
this.hibernatables = hibernatables; this.clazzList = new ArrayList<Class<ISerializableObject>>(500);
this.hibernatables = new HashMap<String, List<Class<ISerializableObject>>>();
}
public List<Class<ISerializableObject>> getClazzList() {
return clazzList;
}
public Map<String, List<Class<ISerializableObject>>> getHibernatables() {
return hibernatables;
} }
@Override @Override
public void run() { public void run() {
try { try {
ClassLoader cl = getClass().getClassLoader(); ClassLoader cl = getClass().getClassLoader();
Set<Class<ISerializableObject>> pluginHibernateSet = new HashSet<Class<ISerializableObject>>(); Set<Class<ISerializableObject>> pluginHibernateSet = null;
if (doHibernate) {
pluginHibernateSet = new HashSet<Class<ISerializableObject>>();
}
List<String> names = new ArrayList<String>(); List<String> names = new ArrayList<String>();
URL u = getNextUrl(); URL u = getNextUrl();
while (u != null) { while (u != null) {
InputStream in = null; InputStream in = null;
BufferedReader r = null; BufferedReader r = null;
names.clear(); names.clear();
pluginHibernateSet.clear();
String path = u.getPath(); String path = u.getPath();
int endIndex = path.indexOf(".jar"); int endIndex = path.indexOf(".jar");
if (endIndex < 0) { if (endIndex < 0) {
@ -276,24 +308,31 @@ public class SerializableManager implements IJaxbableClassesLocator {
"utf-8")); "utf-8"));
int lc = 1; int lc = 1;
while ((lc = parseLine(ISerializableObject.class, u, r, while ((lc = parseLine(ISerializableObject.class, u, r,
lc, names)) >= 0) lc, names)) >= 0) {
; ;
}
} catch (IOException x) { } catch (IOException x) {
fail(ISerializableObject.class, fail(ISerializableObject.class,
"Error reading configuration file", x); "Error reading configuration file", x);
} finally { } finally {
try { try {
if (r != null) if (r != null) {
r.close(); r.close();
if (in != null) }
if (in != null) {
in.close(); in.close();
}
} catch (IOException y) { } catch (IOException y) {
fail(ISerializableObject.class, fail(ISerializableObject.class,
"Error closing configuration file", y); "Error closing configuration file", y);
} }
} }
Iterator<String> iter = names.iterator();
if (doHibernate) {
pluginHibernateSet.clear();
}
Iterator<String> iter = names.iterator();
while (iter.hasNext()) { while (iter.hasNext()) {
String clazz = iter.next(); String clazz = iter.next();
try { try {
@ -303,18 +342,20 @@ public class SerializableManager implements IJaxbableClassesLocator {
boolean added = false; boolean added = false;
if (c.getAnnotation(XmlAccessorType.class) != null if (c.getAnnotation(XmlAccessorType.class) != null
|| c.getAnnotation(XmlRegistry.class) != null) { || c.getAnnotation(XmlRegistry.class) != null) {
addToClazzSet(c); clazzList.add(c);
added = true; added = true;
} }
if (c.getAnnotation(Entity.class) != null if (doHibernate) {
|| c.getAnnotation(Embeddable.class) != null) { if (c.getAnnotation(Entity.class) != null
pluginHibernateSet.add(c); || c.getAnnotation(Embeddable.class) != null) {
added = true; pluginHibernateSet.add(c);
added = true;
}
} }
long time = (System.currentTimeMillis() - t0); long time = (System.currentTimeMillis() - t0);
if (!added) { if (doHibernate && !added) {
System.out System.out
.println("Class: " .println("Class: "
+ clazz + clazz
@ -329,8 +370,10 @@ public class SerializableManager implements IJaxbableClassesLocator {
} }
} }
if (pluginHibernateSet.size() > 0) { if (doHibernate && pluginHibernateSet.size() > 0) {
addToHibernatables(pluginFQN, pluginHibernateSet); hibernatables.put(pluginFQN,
new ArrayList<Class<ISerializableObject>>(
pluginHibernateSet));
} }
u = getNextUrl(); u = getNextUrl();
} }
@ -347,20 +390,5 @@ public class SerializableManager implements IJaxbableClassesLocator {
return null; return null;
} }
} }
private void addToClazzSet(Class<ISerializableObject> clazz) {
synchronized (clazzSet) {
clazzSet.add(clazz);
}
}
private void addToHibernatables(String pluginFQN,
Set<Class<ISerializableObject>> pluginHibernateSet) {
synchronized (hibernatables) {
hibernatables.put(pluginFQN,
new ArrayList<Class<ISerializableObject>>(
pluginHibernateSet));
}
}
} }
} }