Author: scottmf Date: 2009-10-22 10:48:08 -0700 (Thu, 22 Oct 2009) New Revision: 13894 URL: http://svn.hyperic.org/?view=rev&root=Hyperic+HQ&revision=13894 Added: trunk/src/org/hyperic/hq/events/server/session/RegisteredTriggerStartupListener.java Modified: trunk/etc/startup_classes.txt trunk/src/org/hyperic/hq/events/ext/RegisteredTriggers.java trunk/src/org/hyperic/hq/events/server/session/EventLogDAO.java trunk/src/org/hyperic/hq/ha/server/mbean/HAService.java trunk/src/org/hyperic/hq/product/server/mbean/ProductPluginDeployer.java Log: [HHQ-3475] added initializeTriggers to the startup routines, reworked the logic in EventLogDAO.getUnfixedAlertFiredEventLogs() so that it can handle multiple unfixed alerts per alertDef Modified: trunk/etc/startup_classes.txt =================================================================== --- trunk/etc/startup_classes.txt 2009-10-22 17:30:23 UTC (rev 13893) +++ trunk/etc/startup_classes.txt 2009-10-22 17:48:08 UTC (rev 13894) @@ -1,4 +1,5 @@ org.hyperic.hq.product.server.session.ProductStartupListener +org.hyperic.hq.events.server.session.RegisteredTriggerStartupListener org.hyperic.hq.authz.server.session.GroupingStartupListener org.hyperic.hq.authz.server.session.AuthzStartupListener org.hyperic.hq.common.server.session.CommonStartupListener @@ -14,4 +15,4 @@ org.hyperic.hq.bizapp.server.session.BossStartupListener org.hyperic.hq.ha.server.session.HAStartupListener org.hyperic.hq.events.server.session.HeartBeatServiceStartupListener -org.hyperic.hq.events.server.session.HQDBHealthStartupListener \ No newline at end of file +org.hyperic.hq.events.server.session.HQDBHealthStartupListener Modified: trunk/src/org/hyperic/hq/events/ext/RegisteredTriggers.java =================================================================== --- trunk/src/org/hyperic/hq/events/ext/RegisteredTriggers.java 2009-10-22 17:30:23 UTC (rev 13893) +++ trunk/src/org/hyperic/hq/events/ext/RegisteredTriggers.java 2009-10-22 17:48:08 UTC (rev 13894) @@ -1,18 +1,26 @@ /* - * NOTE: This copyright doesnot cover user programs that use HQ program services - * by normal system calls through the application program interfaces provided as - * part of the Hyperic Plug-in Development Kit or the Hyperic Client Development - * Kit - this is merely considered normal use of the program, and doesnot fall - * under the heading of "derived work". Copyright (C) [2004, 2005, 2006], - * Hyperic, Inc. This file is part of HQ. HQ is free software; you can - * redistribute it and/or modify it under the terms version 2 of the GNU General - * Public License as published by the Free Software Foundation. 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. + * NOTE: This copyright does *not* cover user programs that use HQ + * program services by normal system calls through the application + * program interfaces provided as part of the Hyperic Plug-in Development + * Kit or the Hyperic Client Development Kit - this is merely considered + * normal use of the program, and does *not* fall under the heading of + * "derived work". + * + * Copyright (C) [2004-2009], Hyperic, Inc. + * This file is part of HQ. + * + * HQ is free software; you can redistribute it and/or modify + * it under the terms version 2 of the GNU General Public License as + * published by the Free Software Foundation. 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. */ /* @@ -27,14 +35,14 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.hyperic.hq.events.AbstractEvent; import org.hyperic.hq.events.server.session.AlertRegulator; import org.hyperic.hq.events.server.session.RegisteredTriggerManagerEJBImpl; -import org.hyperic.hq.events.shared.RegisteredTriggerManagerLocal; - - /** * Repository of in memory triggers for event processing * @author jhickey @@ -46,13 +54,16 @@ private static final Object INIT_LOCK = new Object(); - private static RegisteredTriggers INSTANCE; + private static RegisteredTriggers INSTANCE = new RegisteredTriggers(); - private boolean initialized = false; + // use AtomicBoolean so that simple ops like reset() don't hang + private final AtomicBoolean initialized = new AtomicBoolean(false); private Object triggerUpdateLock = new Object(); private Map triggers = new ConcurrentHashMap(); + + private static final Log log = LogFactory.getLog(RegisteredTriggers.class); RegisteredTriggers() { @@ -62,18 +73,22 @@ return this.triggers; } - void init() { + private void init() { synchronized (INIT_LOCK) { this.triggers = new ConcurrentHashMap(); RegisteredTriggerManagerEJBImpl.getOne().initializeTriggers(); - initialized = true; + initialized.set(true); } } void setInitialized(boolean initialized) { - synchronized (INIT_LOCK) { - this.initialized = initialized; + if (!initialized) { + log.info("Resetting Triggers"); + if (log.isDebugEnabled()) { + log.debug("Stack Trace For Trigger Reset", new Throwable()); + } } + this.initialized.set(initialized); } public Collection getInterestedTriggers(Class eventClass, Integer instanceId) { @@ -172,34 +187,31 @@ } public boolean isInitialized() { + return initialized.get(); + } + + /** + * Will block if the Triggers are not initialized. + */ + public static RegisteredTriggers getAndInitialize() { + RegisteredTriggers instance = getInstance(); + if (instance.isInitialized()) { + return instance; + } synchronized (INIT_LOCK) { - return initialized; + if (!instance.isInitialized()) { + instance.init(); + } } + return instance; } - - private static RegisteredTriggers getAndInitialize() { - synchronized (INIT_LOCK) { - RegisteredTriggers instance = getInstance(); - if(!instance.isInitialized()) { - instance.init(); - } - return instance; - } - } public static RegisteredTriggers getInstance() { - synchronized (INIT_LOCK) { - if (INSTANCE == null) { - INSTANCE = new RegisteredTriggers(); - } - } return INSTANCE; } public static void reset() { - synchronized (INIT_LOCK) { - getInstance().setInitialized(false); - } + getInstance().setInitialized(false); } public static Collection getInterestedTriggers(AbstractEvent event) { Modified: trunk/src/org/hyperic/hq/events/server/session/EventLogDAO.java =================================================================== --- trunk/src/org/hyperic/hq/events/server/session/EventLogDAO.java 2009-10-22 17:30:23 UTC (rev 13893) +++ trunk/src/org/hyperic/hq/events/server/session/EventLogDAO.java 2009-10-22 17:48:08 UTC (rev 13894) @@ -27,6 +27,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -217,6 +218,9 @@ return res; } + /** + * @return 0 if there are no unfixed alerts + */ private final long getOldestUnfixedAlertTime() { Object o = getSession() .createQuery("select min(ctime) from Alert where fixed = '0'") @@ -229,14 +233,15 @@ /** * @return {@link Map} of {@link Integer} = AlertDefitionId to - * {@link Object[]} <br> - * [0] {@link Integer} AlertDefId, <br> - * [1] {@link Integer} AlertId + * {@link Map} of <br> + * key {@link AlertInfo} <br> + * value {@link Integer} AlertId */ private final Map getUnfixedAlertInfoAfter(long ctime) { final String hql = new StringBuilder(128) - .append("SELECT alertDefinition.id, id ") - .append("FROM Alert WHERE ctime >= :ctime and fixed = '0'") + .append("SELECT alertDefinition.id, id, ctime ") + .append("FROM Alert WHERE ctime >= :ctime and fixed = '0' ") + .append("ORDER BY ctime") .toString(); final List list = getSession() .createQuery(hql) @@ -245,11 +250,50 @@ final Map alerts = new HashMap(list.size()); for (final Iterator it=list.iterator(); it.hasNext(); ) { final Object[] obj = (Object[]) it.next(); - alerts.put(obj[0], obj); + Map tmp; + if (null == (tmp = (Map)alerts.get(obj[0]))) { + tmp = new HashMap(); + alerts.put(obj[0], tmp); + } + final AlertInfo ai = new AlertInfo((Integer)obj[0], (Long)obj[2]); + tmp.put(ai, (Integer)obj[1]); } return alerts; } + private class AlertInfo { + private final Integer _alertDefId; + private final Long _ctime; + AlertInfo(Integer alertDefId, Long ctime) { + _alertDefId = alertDefId; + _ctime = ctime; + } + AlertInfo(Integer alertDefId, long ctime) { + _alertDefId = alertDefId; + _ctime = new Long(ctime); + } + Integer getAlertDefId() { + return _alertDefId; + } + Long getCtime() { + return _ctime; + } + public boolean equals(Object rhs) { + if (rhs == this) { + return true; + } + if (rhs instanceof AlertInfo) { + AlertInfo obj = (AlertInfo)rhs; + return obj.getCtime().equals(_ctime) && + obj.getAlertDefId().equals(_alertDefId); + } + return false; + } + public int hashCode() { + return 17*_alertDefId.hashCode() + _ctime.hashCode(); + } + } + /** * Find unfixed AlertFiredEvent event logs for each alert definition in the list * @@ -261,6 +305,9 @@ Map findUnfixedAlertFiredEventLogs() { final Map rtn = new HashMap(); final long ctime = getOldestUnfixedAlertTime(); + if (ctime == 0) { + return Collections.EMPTY_MAP; + } final Map alerts = getUnfixedAlertInfoAfter(ctime); final String hql = new StringBuilder(256) .append("FROM EventLog ") @@ -277,25 +324,20 @@ if (log == null || log.getInstanceId() == null) { continue; } - final Object[] obj = (Object[])alerts.get(log.getInstanceId()); - if (obj == null) { + final Map objs = (Map)alerts.get(log.getInstanceId()); + if (objs == null) { continue; } - final Integer alertDefId = (Integer)obj[0]; - final Integer alertId = (Integer)obj[1]; - AlertFiredEvent latestEvent; - boolean updateMap = false; - if (null != (latestEvent = (AlertFiredEvent)rtn.get(alertDefId)) && - log.getTimestamp() > latestEvent.getTimestamp()) { - updateMap = true; - } else { - updateMap = true; + final Integer alertDefId = log.getInstanceId(); + final long timestamp = log.getTimestamp(); + final Integer alertId = + (Integer)objs.get(new AlertInfo(alertDefId, timestamp)); + if (alertId == null) { + continue; } - if (updateMap) { - AlertFiredEvent alertFired = - createAlertFiredEvent(alertDefId, alertId, log); - rtn.put(alertDefId, alertFired); - } + AlertFiredEvent alertFired = + createAlertFiredEvent(alertDefId, alertId, log); + rtn.put(alertDefId, alertFired); } return rtn; } Added: trunk/src/org/hyperic/hq/events/server/session/RegisteredTriggerStartupListener.java =================================================================== --- trunk/src/org/hyperic/hq/events/server/session/RegisteredTriggerStartupListener.java (rev 0) +++ trunk/src/org/hyperic/hq/events/server/session/RegisteredTriggerStartupListener.java 2009-10-22 17:48:08 UTC (rev 13894) @@ -0,0 +1,71 @@ +/* + * NOTE: This copyright does *not* cover user programs that use HQ + * program services by normal system calls through the application + * program interfaces provided as part of the Hyperic Plug-in Development + * Kit or the Hyperic Client Development Kit - this is merely considered + * normal use of the program, and does *not* fall under the heading of + * "derived work". + * + * Copyright (C) [2004-2009], Hyperic, Inc. + * This file is part of HQ. + * + * HQ is free software; you can redistribute it and/or modify + * it under the terms version 2 of the GNU General Public License as + * published by the Free Software Foundation. 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 org.hyperic.hq.events.server.session; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.hyperic.hq.application.StartupListener; +import org.hyperic.hq.events.ext.RegisteredTriggers; +import org.hyperic.hq.hibernate.SessionManager; +import org.hyperic.hq.hibernate.SessionManager.SessionRunner; + +public class RegisteredTriggerStartupListener implements StartupListener { + + private static final Log _log = + LogFactory.getLog(RegisteredTriggerStartupListener.class); + private static Thread initTriggerRunner; + + public void hqStarted() { + final SessionRunner runner = new SessionRunner() { + public String getName() { + return "TriggersInitializationStartup"; + } + public void run() throws Exception { + RegisteredTriggers.getAndInitialize(); + } + }; + initTriggerRunner = new Thread("Trigger Init") { + public void run() { + try { + final long start = System.currentTimeMillis(); + _log.info("Starting Trigger Initialization"); + SessionManager.runInSession(runner); + final long end = System.currentTimeMillis(); + _log.info("Finished Trigger Initialization, took " + + (end-start)/1000 + " seconds"); + } catch (Exception e) { + _log.error(e, e); + } + } + }; + initTriggerRunner.start(); + } + + public static Thread getRunnerThread() { + return initTriggerRunner; + } + +} Modified: trunk/src/org/hyperic/hq/ha/server/mbean/HAService.java =================================================================== --- trunk/src/org/hyperic/hq/ha/server/mbean/HAService.java 2009-10-22 17:30:23 UTC (rev 13893) +++ trunk/src/org/hyperic/hq/ha/server/mbean/HAService.java 2009-10-22 17:48:08 UTC (rev 13894) @@ -42,6 +42,7 @@ implements HAServiceMBean { private static Log _log = LogFactory.getLog(HAService.class); + private static boolean isFirstPass = true; /** * @jmx:managed-operation @@ -50,7 +51,13 @@ MBeanServer server = MBeanUtil.getMBeanServer(); //Reset in-memory triggers - RegisteredTriggers.reset(); + if (!isFirstPass) { + // RegisteredTriggers already does a startup initialization + // don't want to reset that. + RegisteredTriggers.reset(); + } else { + isFirstPass = false; + } _log.info("Starting HA Services"); Modified: trunk/src/org/hyperic/hq/product/server/mbean/ProductPluginDeployer.java =================================================================== --- trunk/src/org/hyperic/hq/product/server/mbean/ProductPluginDeployer.java 2009-10-22 17:30:23 UTC (rev 13893) +++ trunk/src/org/hyperic/hq/product/server/mbean/ProductPluginDeployer.java 2009-10-22 17:48:08 UTC (rev 13894) @@ -62,6 +62,7 @@ import org.hyperic.hq.application.HQApp; import org.hyperic.hq.bizapp.server.session.SystemAudit; import org.hyperic.hq.common.SystemException; +import org.hyperic.hq.events.server.session.RegisteredTriggerStartupListener; import org.hyperic.hq.hqu.rendit.RenditServer; import org.hyperic.hq.product.PluginException; import org.hyperic.hq.product.PluginInfo; @@ -226,6 +227,7 @@ .getPluginsDeployedCaller().pluginsDeployed(_plugins); _plugins.clear(); + waitForTriggerInit(); startConcurrentStatsCollector(); //generally means we are done deploying plugins at startup. @@ -244,6 +246,17 @@ } } + private void waitForTriggerInit() { + Thread thread = RegisteredTriggerStartupListener.getRunnerThread(); + while (thread.isAlive()) { + _log.info("waiting for Trigger Initialization to complete"); + try { + thread.join(10000); + } catch (InterruptedException e) { + } + } + } + private void startConcurrentStatsCollector() { String prop = System.getProperty("hq.unittest.run"); System.out.println(prop); |