Issue #1939 Fix deadlock at CAVE start up.

Change-Id: Ic3a0f527cdae7ee1abc32662c90d9594686d4bab

Former-commit-id: 2c2e2b4baa [formerly 6f2a6ce80c] [formerly fcc157a91b [formerly b38ba1c92e4e176364dc3967d11b98fbd66478cd]]
Former-commit-id: fcc157a91b
Former-commit-id: 3ea6817796
This commit is contained in:
Ron Anderson 2013-04-23 14:50:34 -05:00
parent 2fbb05b3f7
commit 1d00b3d37a
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
* 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>
*
* @author randerso
@ -184,7 +186,6 @@ public class NotificationManagerJob implements ExceptionListener, IDisposable {
*/
protected NotificationManagerJob() {
this.listeners = new HashMap<ListenerKey, NotificationListener>();
connect(true);
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 Type type;

View file

@ -27,6 +27,7 @@ import java.util.List;
import javax.xml.bind.JAXBException;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.ui.application.WorkbenchAdvisor;
import org.osgi.framework.Bundle;
@ -67,7 +68,8 @@ import com.raytheon.viz.ui.personalities.awips.CAVE;
*
* 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>
*
@ -192,6 +194,7 @@ public class ThinClientComponent extends CAVE implements IThinClientComponent {
}
}
@Override
public void stopComponent() {
// Persist caches
cacheManager.storeCaches();
@ -201,13 +204,15 @@ public class ThinClientComponent extends CAVE implements IThinClientComponent {
}
@Override
protected void initializeSerialization() {
protected Job initializeSerialization() {
try {
SerializationUtil.getJaxbContext();
} catch (JAXBException e) {
statusHandler.handle(Priority.CRITICAL,
"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.Priority;
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.ui.dialogs.AlertVisualization;
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.LocalizationInitializer;
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.viz.alerts.jobs.AutoUpdater;
import com.raytheon.viz.alerts.jobs.MenuUpdater;
@ -90,6 +93,8 @@ import com.raytheon.viz.core.units.UnitRegistrar;
* mode is off.
* Jan 09, 2013 #1442 rferrel Changes to notify SimultedTime listeners.
* 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>
*
@ -139,7 +144,8 @@ public abstract class AbstractCAVEComponent implements IStandaloneComponent {
UnitRegistrar.registerUnits();
CAVEMode.performStartupDuties();
long t0 = System.currentTimeMillis();
ITimer timer = TimeUtil.getTimer();
timer.start();
Display display = null;
int modes = getRuntimeModes();
@ -166,7 +172,7 @@ public abstract class AbstractCAVEComponent implements IStandaloneComponent {
}
UFStatus.setHandlerFactory(new VizStatusHandlerFactory());
initializeSerialization();
Job serializationJob = initializeSerialization();
initializeDataStoreFactory();
initializeObservers();
@ -204,12 +210,22 @@ public abstract class AbstractCAVEComponent implements IStandaloneComponent {
WorkbenchAdvisor workbenchAdvisor = null;
// A component was passed as command line arg
// launch cave normally, should cave be registered as component?
long t1 = System.currentTimeMillis();
System.out.println("Localization time: " + (t1 - t0) + "ms");
try {
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) {
workbenchAdvisor = getWorkbenchAdvisor();
} else if (!nonui) {
@ -220,6 +236,7 @@ public abstract class AbstractCAVEComponent implements IStandaloneComponent {
if (workbenchAdvisor instanceof HiddenWorkbenchAdvisor == false) {
startInternal(componentName);
}
if (workbenchAdvisor != null) {
returnCode = PlatformUI.createAndRunWorkbench(display,
workbenchAdvisor);
@ -239,6 +256,15 @@ public abstract class AbstractCAVEComponent implements IStandaloneComponent {
// catch any exceptions to ensure rest of finally block
// executes
}
try {
// disconnect from JMS
NotificationManagerJob.disconnect();
} catch (RuntimeException e) {
// catch any exceptions to ensure rest of finally block
// executes
}
if (av != null) {
av.dispose();
}
@ -368,8 +394,8 @@ public abstract class AbstractCAVEComponent implements IStandaloneComponent {
!LocalizationManager.internalAlertServer).run();
}
protected void initializeSerialization() {
new Job("Loading Serialization") {
protected Job initializeSerialization() {
Job job = new Job("Loading Serialization") {
@Override
protected IStatus run(IProgressMonitor monitor) {
@ -382,7 +408,9 @@ public abstract class AbstractCAVEComponent implements IStandaloneComponent {
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.50=-Dedex.tmp=${TEMP_DIR}
wrapper.java.additional.51=-Dncf.bandwidth.manager.service=${NCF_BANDWIDTH_MANAGER_SERVICE}
wrapper.java.additional.52=-DinitializeHibernatables=true
# Initial Java Heap Size (in MB)
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.GridLocation
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.sample.SampleData
com.raytheon.uf.common.dataplugin.gfe.server.lock.Lock

View file

@ -14,7 +14,7 @@
* Omaha, NE 68106
* 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.
**/
package com.raytheon.uf.common.serialization;
@ -31,6 +31,7 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.ServiceConfigurationError;
import java.util.Set;
@ -56,6 +57,9 @@ import com.raytheon.uf.common.serialization.jaxb.JaxbDummyObject;
* Aug 11, 2008 njensen Initial creation
* Aug 31, 2009 2924 rjpeter Added Embeddable.
* 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>
*
* @author njensen
@ -82,8 +86,6 @@ public class SerializableManager implements IJaxbableClassesLocator {
*/
@SuppressWarnings(value = { "unchecked" })
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
// during runtime, i.e. hot deploy of a new plugin
hibernatables.clear();
@ -96,23 +98,37 @@ public class SerializableManager implements IJaxbableClassesLocator {
.getResources(
"META-INF/services/"
+ 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
// about 50% and 3 threads cuts down another 5% or so, 4 threads
// shows no benefit over 2. These results are system specific.
int numThreads = 3;
Thread[] threads = new Thread[numThreads];
for (int i = 1; i < numThreads; i++) {
threads[i] = new LoadSerializableClassesThread(urls, clazzSet,
hibernatables);
LoadSerializableClassesThread[] threads = new LoadSerializableClassesThread[numThreads];
for (int i = 0; i < numThreads; i++) {
threads[i] = new LoadSerializableClassesThread(urls,
doHibernate);
threads[i].start();
}
threads[0] = new LoadSerializableClassesThread(urls, clazzSet,
hibernatables);
// Run this one on the current thread since its not doing anything
// but waiting and this avoids overhead of starting a new thread
threads[0].run();
for (int i = 1; i < numThreads; i++) {
threads[i].join();
for (LoadSerializableClassesThread thread : threads) {
thread.join();
clazzSet.addAll(thread.getClazzList());
if (doHibernate) {
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) {
e.printStackTrace();
@ -127,6 +143,7 @@ public class SerializableManager implements IJaxbableClassesLocator {
System.out.println("Total time spent loading classes: "
+ (System.currentTimeMillis() - realStartTime) + "ms");
}
private static void fail(Class service, String msg, Throwable cause)
@ -153,25 +170,28 @@ public class SerializableManager implements IJaxbableClassesLocator {
return -1;
}
int ci = ln.indexOf('#');
if (ci >= 0)
if (ci >= 0) {
ln = ln.substring(0, ci);
}
ln = ln.trim();
int n = ln.length();
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");
}
int cp = ln.codePointAt(0);
if (!Character.isJavaIdentifierStart(cp))
if (!Character.isJavaIdentifierStart(cp)) {
fail(service, u, lc, "Illegal provider-class name: " + ln);
}
for (int i = Character.charCount(cp); i < n; i += Character
.charCount(cp)) {
cp = ln.codePointAt(i);
if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
if (!Character.isJavaIdentifierPart(cp) && (cp != '.')) {
fail(service, u, lc, "Illegal provider-class name: " + ln);
}
}
if (!names.contains(ln))
names.add(ln);
names.add(ln);
}
return lc + 1;
}
@ -233,30 +253,42 @@ public class SerializableManager implements IJaxbableClassesLocator {
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;
public LoadSerializableClassesThread(Enumeration<URL> urls,
Set<Class<ISerializableObject>> clazzSet,
Map<String, List<Class<ISerializableObject>>> hibernatables) {
boolean doHibernate) {
this.urls = urls;
this.clazzSet = clazzSet;
this.hibernatables = hibernatables;
this.doHibernate = doHibernate;
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
public void run() {
try {
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>();
URL u = getNextUrl();
while (u != null) {
InputStream in = null;
BufferedReader r = null;
names.clear();
pluginHibernateSet.clear();
String path = u.getPath();
int endIndex = path.indexOf(".jar");
if (endIndex < 0) {
@ -276,24 +308,31 @@ public class SerializableManager implements IJaxbableClassesLocator {
"utf-8"));
int lc = 1;
while ((lc = parseLine(ISerializableObject.class, u, r,
lc, names)) >= 0)
lc, names)) >= 0) {
;
}
} catch (IOException x) {
fail(ISerializableObject.class,
"Error reading configuration file", x);
} finally {
try {
if (r != null)
if (r != null) {
r.close();
if (in != null)
}
if (in != null) {
in.close();
}
} catch (IOException y) {
fail(ISerializableObject.class,
"Error closing configuration file", y);
}
}
Iterator<String> iter = names.iterator();
if (doHibernate) {
pluginHibernateSet.clear();
}
Iterator<String> iter = names.iterator();
while (iter.hasNext()) {
String clazz = iter.next();
try {
@ -303,18 +342,20 @@ public class SerializableManager implements IJaxbableClassesLocator {
boolean added = false;
if (c.getAnnotation(XmlAccessorType.class) != null
|| c.getAnnotation(XmlRegistry.class) != null) {
addToClazzSet(c);
clazzList.add(c);
added = true;
}
if (c.getAnnotation(Entity.class) != null
|| c.getAnnotation(Embeddable.class) != null) {
pluginHibernateSet.add(c);
added = true;
if (doHibernate) {
if (c.getAnnotation(Entity.class) != null
|| c.getAnnotation(Embeddable.class) != null) {
pluginHibernateSet.add(c);
added = true;
}
}
long time = (System.currentTimeMillis() - t0);
if (!added) {
if (doHibernate && !added) {
System.out
.println("Class: "
+ clazz
@ -329,8 +370,10 @@ public class SerializableManager implements IJaxbableClassesLocator {
}
}
if (pluginHibernateSet.size() > 0) {
addToHibernatables(pluginFQN, pluginHibernateSet);
if (doHibernate && pluginHibernateSet.size() > 0) {
hibernatables.put(pluginFQN,
new ArrayList<Class<ISerializableObject>>(
pluginHibernateSet));
}
u = getNextUrl();
}
@ -347,20 +390,5 @@ public class SerializableManager implements IJaxbableClassesLocator {
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));
}
}
}
}