/* * RHQ Management Platform * Copyright (C) 2005-2008 Red Hat, Inc. * All rights reserved. * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.rhq.enterprise.server.cloud.instance; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.annotation.Resource; import javax.ejb.EJB; import javax.ejb.Stateless; import javax.ejb.Timeout; import javax.ejb.Timer; import javax.ejb.TimerConfig; import javax.ejb.TimerService; import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.rhq.enterprise.server.alert.engine.AlertConditionCacheManagerLocal; /** * Each server has partitioned alerts condition cache data. This session bean exists * to check whether or not the something has changed in the system that would require * the cache to asynchronously reload itself. * * @author Joseph Marques */ @Stateless public class CacheConsistencyManagerBean implements CacheConsistencyManagerLocal { private final Log log = LogFactory.getLog(CacheConsistencyManagerBean.class); @Resource TimerService timerService; @EJB ServerManagerLocal serverManager; @EJB AlertConditionCacheManagerLocal cacheManager; @EJB CacheConsistencyManagerLocal cacheConsistencyManager; @Override public void scheduleServerCacheReloader() { /* each time the webapp is reloaded, it would create * duplicate events if we don't cancel the existing ones */ Collection<Timer> timers = timerService.getTimers(); for (Timer existingTimer : timers) { log.debug("Found timer - attempting to cancel: " + existingTimer.toString()); try { existingTimer.cancel(); } catch (Exception e) { log.warn("Failed in attempting to cancel timer: " + existingTimer.toString()); } } timerService.createIntervalTimer(30000L, 30000L, new TimerConfig(null, false)); } @Override @Timeout public void handleHeartbeatTimer(Timer timer) { try { cacheConsistencyManager.reloadServerCacheIfNeededNSTx(); } catch (Throwable t) { log.error("Failed to reload server cache if needed - will try again later. Cause: " + t); } } @Override @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) public void reloadServerCacheIfNeededNSTx() { // try reload the global cache separate from the agent caches for purposes of isolated failures reloadGlobalCacheIfNeeded(); reloadAgentCachesAsNeeded(); } private void reloadGlobalCacheIfNeeded() { try { boolean hadServerStatus = serverManager.getAndClearServerStatus(); if (hadServerStatus == false) { if (log.isDebugEnabled()) { log.debug("Global cache does not need reloading"); } return; } long startTime = System.currentTimeMillis(); cacheManager.reloadGlobalCache(); long endTime = System.currentTimeMillis(); String serverName = serverManager.getIdentity(); log.info(serverName + " took [" + (endTime - startTime) + "]ms to reload global cache"); } catch (Throwable t) { if (log.isDebugEnabled()) { log.debug("Failed to reload global cache", t); } else { log.error("Failed to reload global cache, cause: " + t.getMessage()); } } } private void reloadAgentCachesAsNeeded() { /* * catch absolutely everything, so that even if this REQUIRES_NEW transaction rollback, * it doesn't rollback the caller (where we reschedule the TIMER to trigger this job again */ List<Integer> agentIds = new ArrayList<Integer>(); try { agentIds = serverManager.getAndClearAgentsWithStatus(); // do nothing if nothing to do if (agentIds.size() == 0) { if (log.isDebugEnabled()) { log.debug("No agent caches need reloading"); } return; } // otherwise print informational messages for poor-man's verification purposes long startTime = System.currentTimeMillis(); for (Integer nextAgentId : agentIds) { log.debug("Agent[id=" + nextAgentId + "] is stale "); cacheManager.reloadCachesForAgent(nextAgentId); } long endTime = System.currentTimeMillis(); String serverName = serverManager.getIdentity(); if (log.isDebugEnabled()) { log.debug(serverName + " took [" + (endTime - startTime) + "]ms to reload cache for the follow agentIds: " + agentIds + " agents"); } else { log.info(serverName + " took [" + (endTime - startTime) + "]ms to reload cache for " + agentIds.size() + " agents"); } } catch (Throwable t) { if (log.isDebugEnabled()) { log.debug("Failed to reload caches for the following agents: " + agentIds, t); } else { log.error("Failed to reload caches for the following agents: " + agentIds + ", cause: " + t.getMessage()); } } } }