From: <pn...@hy...> - 2009-12-21 05:58:36
|
Author: pnguyen Date: 2009-12-20 21:58:21 -0800 (Sun, 20 Dec 2009) New Revision: 14109 URL: http://svn.hyperic.org/?view=rev&root=Hyperic+HQ&revision=14109 Removed: trunk/src/org/hyperic/hq/appdef/server/session/AsyncDeleteAgentCache.java Modified: trunk/src/org/hyperic/hq/appdef/shared/ResourcesCleanupZevent.java trunk/src/org/hyperic/hq/bizapp/server/session/AppdefBossEJBImpl.java trunk/src/org/hyperic/hq/measurement/server/session/MeasurementManagerEJBImpl.java trunk/src/org/hyperic/hq/measurement/server/session/MeasurementProcessorEJBImpl.java Log: [HHQ-3598] Eliminate the AsyncDeleteAgentCache singleton class. Inject the same info as a ZeventPayload into the ResourcesCleanupZevent. Unschedule the metrics from the agent in one batch call instead of multiple calls during the async delete process to improve performance. Deleted: trunk/src/org/hyperic/hq/appdef/server/session/AsyncDeleteAgentCache.java =================================================================== --- trunk/src/org/hyperic/hq/appdef/server/session/AsyncDeleteAgentCache.java 2009-12-20 09:15:15 UTC (rev 14108) +++ trunk/src/org/hyperic/hq/appdef/server/session/AsyncDeleteAgentCache.java 2009-12-21 05:58:21 UTC (rev 14109) @@ -1,92 +0,0 @@ -/* - * 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.appdef.server.session; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.hyperic.hq.appdef.shared.AppdefEntityID; - -/** - * This class is used during the aynchronous delete process - * to unschedule metrics. It is an in-memory map of resources - * and its agent because that info no longer exists in the DB. - */ -public class AsyncDeleteAgentCache { - private Log log = LogFactory.getLog(AsyncDeleteAgentCache.class); - - private final Map _cache; - - private static final AsyncDeleteAgentCache singleton = - new AsyncDeleteAgentCache(); - - private AsyncDeleteAgentCache() { - _cache = Collections.synchronizedMap(new HashMap()); - } - - /** - * - * @param key The AppdefEntityID of the async deleted resource - * @return Integer The agentId of the async deleted resource - */ - public Integer get(AppdefEntityID key) { - return (Integer) _cache.get(key); - } - - /** - * - * @param key The AppdefEntityID of the async deleted resource - * @param Integer The agentId of the async deleted resource - */ - public void put(AppdefEntityID key, Integer value) { - _cache.put(key, value); - } - - public void remove(AppdefEntityID key) { - _cache.remove(key); - } - - public void clear() { - _cache.clear(); - } - - public int getSize() { - return _cache.size(); - } - - public String toString() { - return _cache.toString(); - } - - public static AsyncDeleteAgentCache getInstance() { - return singleton; - } - -} Modified: trunk/src/org/hyperic/hq/appdef/shared/ResourcesCleanupZevent.java =================================================================== --- trunk/src/org/hyperic/hq/appdef/shared/ResourcesCleanupZevent.java 2009-12-20 09:15:15 UTC (rev 14108) +++ trunk/src/org/hyperic/hq/appdef/shared/ResourcesCleanupZevent.java 2009-12-21 05:58:21 UTC (rev 14109) @@ -6,7 +6,7 @@ * normal use of the program, and does *not* fall under the heading of * "derived work". * - * Copyright (C) [2004-2008], Hyperic, Inc. + * Copyright (C) [2004-2009], Hyperic, Inc. * This file is part of HQ. * * HQ is free software; you can redistribute it and/or modify @@ -25,7 +25,10 @@ package org.hyperic.hq.appdef.shared; +import java.util.Map; + import org.hyperic.hq.zevents.Zevent; +import org.hyperic.hq.zevents.ZeventPayload; public class ResourcesCleanupZevent extends Zevent { @@ -33,4 +36,45 @@ super(null, null); } + /** + * @param agentCache {@link Map} of {@link Integer} of agentIds + * to {@link List} of {@link AppdefEntityID}s + */ + public ResourcesCleanupZevent(Map agentCache) { + super(null, new ResourcesCleanupZeventPayload(agentCache)); + } + + /** + * @return {@link Map} of {@link Integer} of agentIds + * to {@link List} of {@link AppdefEntityID}s + */ + public Map getAgents() { + Map agents = null; + if (getPayload() != null) { + agents = ((ResourcesCleanupZeventPayload)getPayload()).getAgents(); + } + return agents; + } + + private static class ResourcesCleanupZeventPayload + implements ZeventPayload + { + private Map agentCache; + + /** + * @param agentCache {@link Map} of {@link Integer} of agentIds + * to {@link List} of {@link AppdefEntityID}s + */ + public ResourcesCleanupZeventPayload(Map agentCache) { + this.agentCache = agentCache; + } + + /** + * @return {@link Map} of {@link Integer} of agentIds + * to {@link List} of {@link AppdefEntityID}s + */ + public Map getAgents() { + return this.agentCache; + } + } } Modified: trunk/src/org/hyperic/hq/bizapp/server/session/AppdefBossEJBImpl.java =================================================================== --- trunk/src/org/hyperic/hq/bizapp/server/session/AppdefBossEJBImpl.java 2009-12-20 09:15:15 UTC (rev 14108) +++ trunk/src/org/hyperic/hq/bizapp/server/session/AppdefBossEJBImpl.java 2009-12-21 05:58:21 UTC (rev 14109) @@ -58,7 +58,6 @@ import org.hyperic.hq.appdef.server.session.AppdefResourceType; import org.hyperic.hq.appdef.server.session.Application; import org.hyperic.hq.appdef.server.session.ApplicationType; -import org.hyperic.hq.appdef.server.session.AsyncDeleteAgentCache; import org.hyperic.hq.appdef.server.session.CPropResource; import org.hyperic.hq.appdef.server.session.CPropResourceSortField; import org.hyperic.hq.appdef.server.session.Cprop; @@ -1341,16 +1340,21 @@ } AppdefEntityID[] removed = resMan.removeResourcePerms( subject, res, false); + Map agentCache = null; try { final Integer id = aeid.getId(); switch (aeid.getType()) { case AppdefEntityConstants.APPDEF_TYPE_SERVER : final ServerManagerLocal sMan = getServerManager(); - removeServer(subject, sMan.findServerById(id)); + Server server = sMan.findServerById(id); + agentCache = buildAsyncDeleteAgentCache(server); + removeServer(subject, server); break; case AppdefEntityConstants.APPDEF_TYPE_PLATFORM: final PlatformManagerLocal pMan = getPlatformManager(); - removePlatform(subject, pMan.findPlatformById(id)); + Platform platform = pMan.findPlatformById(id); + agentCache = buildAsyncDeleteAgentCache(platform); + removePlatform(subject, platform); break; case AppdefEntityConstants.APPDEF_TYPE_SERVICE : final ServiceManagerLocal svcMan = getServiceManager(); @@ -1378,7 +1382,7 @@ } ZeventManager.getInstance().enqueueEventAfterCommit( - new ResourcesCleanupZevent()); + new ResourcesCleanupZevent(agentCache)); return removed; } @@ -1388,52 +1392,36 @@ * Method is "NotSupported" since all the resource deletes may take longer * than the jboss transaction timeout. No need for a transaction in this * context. + * + * @param agentCache {@link Map} of {@link Integer} of agentIds + * to {@link List} of {@link AppdefEntityID}s + * * @ejb:transaction type="NotSupported" * @ejb:interface-method */ - public void removeDeletedResources() + public void removeDeletedResources(Map agentCache) throws ApplicationException, VetoException, RemoveException { final boolean debug = log.isDebugEnabled(); final StopWatch watch = new StopWatch(); final AuthzSubject subject = getAuthzSubjectManager().findSubjectById(AuthzConstants.overlordId); - AsyncDeleteAgentCache cache = AsyncDeleteAgentCache.getInstance(); - if (debug) { - log.debug("AsyncDeleteAgentCache start size=" + cache.getSize()); - } - + watch.markTimeBegin("unscheduleMeasurementsForAsyncDelete"); + unscheduleMeasurementsForAsyncDelete(agentCache); + watch.markTimeEnd("unscheduleMeasurementsForAsyncDelete"); + + // Look through services, servers, platforms, applications, and groups watch.markTimeBegin("removeApplications"); Collection applications = getApplicationManager().findDeletedApplications(); - for (Iterator it = applications.iterator(); it.hasNext(); ) { - try { - getOne()._removeApplicationInNewTran( - subject, (Application)it.next()); - } catch (Exception e) { - log.error("Unable to remove application: " + e, e); - } - } + removeApplications(subject, applications); watch.markTimeEnd("removeApplications"); - if (debug) { - log.debug("Removed " + applications.size() + " applications"); - } watch.markTimeBegin("removeResourceGroups"); Collection groups = getResourceGroupManager().findDeletedGroups(); - for (Iterator it = groups.iterator(); it.hasNext(); ) { - try { - getOne()._removeGroupInNewTran(subject, (ResourceGroup)it.next()); - } catch (Exception e) { - log.error("Unable to remove group: " + e, e); - } - } + removeResourceGroups(subject, groups); watch.markTimeEnd("removeResourceGroups"); - if (debug) { - log.debug("Removed " + groups.size() + " resource groups"); - } - // Look through services, servers, platforms, applications, and groups watch.markTimeBegin("removeServices"); Collection services = getServiceManager().findDeletedServices(); removeServices(subject, services); @@ -1451,13 +1439,69 @@ if (debug) { log.debug("removeDeletedResources: " + watch); - log.debug("AsyncDeleteAgentCache end size=" + cache.getSize()); - if (cache.getSize() > 0) { - log.debug("AsyncDeleteAgentCache " + cache); + } + } + + /** + * Disable measurements and unschedule from the agent in bulk + * with the agent cache info because the resources have been + * de-referenced from the agent + * + * @param agentCache {@link Map} of {@link Integer} of agentIds + * to {@link List} of {@link AppdefEntityID}s + */ + private void unscheduleMeasurementsForAsyncDelete(Map agentCache) { + if (agentCache == null) { + return; + } + + try { + AuthzSubject subject = + getAuthzSubjectManager().findSubjectById(AuthzConstants.overlordId); + + for (Iterator j = agentCache.keySet().iterator(); j.hasNext(); ) { + Integer agentId = (Integer)j.next(); + Agent agent = getAgentManager().getAgent(agentId); + List resources = (List) agentCache.get(agentId); + + getMetricManager().disableMeasurements( + subject, + agent, + (AppdefEntityID[]) resources.toArray(new AppdefEntityID[0]), + true); } + } catch (Exception e) { + log.error("Error unscheduling measurements during async delete", e); } } + private final void removeApplications(AuthzSubject subject, Collection applications) { + for (Iterator it = applications.iterator(); it.hasNext(); ) { + try { + getOne()._removeApplicationInNewTran( + subject, (Application)it.next()); + } catch (Exception e) { + log.error("Unable to remove application: " + e, e); + } + } + if (log.isDebugEnabled()) { + log.debug("Removed " + applications.size() + " applications"); + } + } + + private final void removeResourceGroups(AuthzSubject subject, Collection groups) { + for (Iterator it = groups.iterator(); it.hasNext(); ) { + try { + getOne()._removeGroupInNewTran(subject, (ResourceGroup)it.next()); + } catch (Exception e) { + log.error("Unable to remove group: " + e, e); + } + } + if (log.isDebugEnabled()) { + log.debug("Removed " + groups.size() + " resource groups"); + } + } + private final void removePlatforms(AuthzSubject subject, Collection platforms) { for (final Iterator it = platforms.iterator(); it.hasNext(); ) { final Platform platform = (Platform)it.next(); @@ -1569,11 +1613,6 @@ StopWatch watch = new StopWatch(); try { - // Update cache for asynchronous delete process - if (debug) watch.markTimeBegin("buildAsyncDeleteAgentCache"); - buildAsyncDeleteAgentCache(platform); - if (debug) watch.markTimeEnd("buildAsyncDeleteAgentCache"); - // Disable all measurements for this platform. We don't actually // remove the measurements here to avoid delays in deleting // resources. @@ -1630,11 +1669,6 @@ StopWatch watch = new StopWatch(); try { - // Update cache for asynchronous delete process - if (debug) watch.markTimeBegin("buildAsyncDeleteAgentCache"); - buildAsyncDeleteAgentCache(server); - if (debug) watch.markTimeEnd("buildAsyncDeleteAgentCache"); - // now remove the measurements if (debug) watch.markTimeBegin("disableMeasurements"); getMetricManager().disableMeasurements( @@ -1675,57 +1709,96 @@ } } - private void buildAsyncDeleteAgentCache(Server server) { - AsyncDeleteAgentCache cache = AsyncDeleteAgentCache.getInstance(); + /** + * @param server The server being deleted + * + * @return {@link Map} of {@link Integer} of agentIds + * to {@link List} of {@link AppdefEntityID}s + */ + private Map buildAsyncDeleteAgentCache(Server server) { + Map cache = new HashMap(); try { Agent agent = findResourceAgent(server.getEntityId()); + List resources = new ArrayList(); for (Iterator i=server.getServices().iterator(); i.hasNext(); ) { Service s = (Service)i.next(); - AppdefEntityID eid = s.getEntityId(); - cache.put(eid, agent.getId()); + resources.add(s.getEntityId()); } - } catch (AgentNotFoundException anfe) { - if (cache.get(server.getEntityId()) == null) { - if (!server.getServerType().isVirtual()) { - log.warn("Unable to build AsyncDeleteAgentCache for server[id=" - + server.getId() - + ", name=" + server.getName() + "]: " - + anfe.getMessage()); - } - } else { - log.debug("Platform has been asynchronously deleted: " - + anfe.getMessage()); - } + cache.put(agent.getId(), resources); } catch (Exception e) { log.warn("Unable to build AsyncDeleteAgentCache for server[id=" + server.getId() + ", name=" + server.getName() + "]: " + e.getMessage()); } + + return cache; } - private void buildAsyncDeleteAgentCache(Platform platform) { - AsyncDeleteAgentCache cache = AsyncDeleteAgentCache.getInstance(); + /** + * @param platform The platform being deleted + * + * @return {@link Map} of {@link Integer} of agentIds + * to {@link List} of {@link AppdefEntityID}s + */ + private Map buildAsyncDeleteAgentCache(Platform platform) { + Map cache = new HashMap(); try { Agent agent = platform.getAgent(); + List resources = new ArrayList(); for (Iterator i=platform.getServers().iterator(); i.hasNext(); ) { Server s = (Server)i.next(); if (!s.getServerType().isVirtual()) { - AppdefEntityID eid = s.getEntityId(); - cache.put(eid, agent.getId()); + resources.add(s.getEntityId()); } - buildAsyncDeleteAgentCache(s); - } + List services = (List) buildAsyncDeleteAgentCache(s).get(agent.getId()); + resources.addAll(services); + } + cache.put(agent.getId(), resources); } catch (Exception e) { log.warn("Unable to build AsyncDeleteAgentCache for platform[id=" + platform.getId() + ", name=" + platform.getName() + "]: " - + e.getMessage()); } + + e.getMessage()); + } + + return cache; } + + /** + * @param zevents {@link List} of {@link ResourcesCleanupZevent} + * + * @return {@link Map} of {@link Integer} of agentIds + * to {@link List} of {@link AppdefEntityID}s + */ + private Map buildAsyncDeleteAgentCache(List zevents) { + Map masterCache = new HashMap(); + + for (Iterator i = zevents.iterator(); i.hasNext();) { + ResourcesCleanupZevent z = (ResourcesCleanupZevent) i.next(); + if (z.getAgents() != null) { + Map cache = z.getAgents(); + + for (Iterator j = cache.keySet().iterator(); j.hasNext(); ) { + Integer agentId = (Integer)j.next(); + List newResources = (List) cache.get(agentId); + List resources = (List) masterCache.get(agentId); + if (resources == null) { + resources = newResources; + } else { + resources.addAll(newResources); + } + masterCache.put(agentId, resources); + } + } + } + + return masterCache; + } /** * Used only during the asynchronous delete process. @@ -4085,15 +4158,14 @@ events.add (ResourcesCleanupZevent.class); ZeventManager.getInstance().addBufferedListener(events, new ZeventListener() { - public void processEvents(List events) { - for (Iterator i = events.iterator(); i.hasNext();) { + public void processEvents(List zevents) { + if (zevents != null && !zevents.isEmpty()) { try { - getOne().removeDeletedResources(); + Map agentCache = buildAsyncDeleteAgentCache(zevents); + getOne().removeDeletedResources(agentCache); } catch (Exception e) { log.error("removeDeletedResources() failed", e); - } - // Only need to run this once - break; + } } } Modified: trunk/src/org/hyperic/hq/measurement/server/session/MeasurementManagerEJBImpl.java =================================================================== --- trunk/src/org/hyperic/hq/measurement/server/session/MeasurementManagerEJBImpl.java 2009-12-20 09:15:15 UTC (rev 14108) +++ trunk/src/org/hyperic/hq/measurement/server/session/MeasurementManagerEJBImpl.java 2009-12-21 05:58:21 UTC (rev 14109) @@ -45,6 +45,7 @@ import org.apache.commons.logging.LogFactory; import org.hyperic.hq.appdef.Agent; import org.hyperic.hq.appdef.AppService; +import org.hyperic.hq.appdef.server.session.AgentManagerEJBImpl; import org.hyperic.hq.appdef.server.session.AppdefResource; import org.hyperic.hq.appdef.server.session.Application; import org.hyperic.hq.appdef.server.session.ApplicationManagerEJBImpl; @@ -55,6 +56,7 @@ import org.hyperic.hq.appdef.server.session.ResourceZevent; import org.hyperic.hq.appdef.server.session.Server; import org.hyperic.hq.appdef.server.session.Service; +import org.hyperic.hq.appdef.shared.AgentNotFoundException; import org.hyperic.hq.appdef.shared.AppdefEntityID; import org.hyperic.hq.appdef.shared.AppdefEntityNotFoundException; import org.hyperic.hq.appdef.shared.AppdefEntityValue; @@ -1135,14 +1137,52 @@ */ public void disableMeasurements(AuthzSubject subject, AppdefEntityID agentId, AppdefEntityID[] ids) + throws PermissionException, AgentNotFoundException { + + Agent agent = AgentManagerEJBImpl.getOne().getAgent(agentId); + + disableMeasurements(subject, agent, ids, false); + } + + /** + * Disable all measurements for the given resources. + * + * @param agent The agent for the given resources + * @param ids The list of entitys to unschedule + * @param isAsyncDelete Indicates whether it is for async delete + * @ejb:interface-method + * + * NOTE: This method requires all entity ids to be monitored by the same + * agent as specified by the agent + */ + public void disableMeasurements(AuthzSubject subject, Agent agent, + AppdefEntityID[] ids, boolean isAsyncDelete) throws PermissionException { - + MeasurementDAO dao = getMeasurementDAO(); for (int i = 0; i < ids.length; i++) { checkModifyPermission(subject.getId(), ids[i]); - - List mcol = dao.findEnabledByResource(getResource(ids[i])); + List mcol = null; + Resource res = getResource(ids[i]); + if (isAsyncDelete) { + // For asynchronous deletes, we need to get all measurements + // because some disabled measurements are not unscheduled + // from the agent (like during the maintenance window) and + // we need to unschedule these measurements + mcol = findMeasurements(subject, res); + } else { + mcol = dao.findEnabledByResource(res); + } + if (mcol.isEmpty()) { + if (log.isDebugEnabled()) { + log.debug("No measurements to disable for resource[" + + ids[i] + + "], isAsyncDelete=" + isAsyncDelete); + } + continue; + } + Integer[] mids = new Integer[mcol.size()]; Iterator it = mcol.iterator(); for (int j = 0; it.hasNext(); j++) { @@ -1159,8 +1199,9 @@ // Unscheduling of all metrics for a resource could indicate that // the resource is getting removed. Send the unschedule synchronously // so that all the necessary plumbing is in place. - try { - MeasurementProcessorEJBImpl.getOne().unschedule(agentId, ids); + try { + MeasurementProcessorEJBImpl.getOne().unschedule( + agent.getAgentToken(), ids); } catch (MeasurementUnscheduleException e) { log.error("Unable to disable measurements", e); } Modified: trunk/src/org/hyperic/hq/measurement/server/session/MeasurementProcessorEJBImpl.java =================================================================== --- trunk/src/org/hyperic/hq/measurement/server/session/MeasurementProcessorEJBImpl.java 2009-12-20 09:15:15 UTC (rev 14108) +++ trunk/src/org/hyperic/hq/measurement/server/session/MeasurementProcessorEJBImpl.java 2009-12-21 05:58:21 UTC (rev 14109) @@ -41,7 +41,6 @@ import org.hyperic.hq.agent.AgentRemoteException; import org.hyperic.hq.appdef.Agent; import org.hyperic.hq.appdef.server.session.AgentManagerEJBImpl; -import org.hyperic.hq.appdef.server.session.AsyncDeleteAgentCache; import org.hyperic.hq.appdef.shared.AgentManagerLocal; import org.hyperic.hq.appdef.shared.AgentNotFoundException; import org.hyperic.hq.appdef.shared.AppdefEntityID; @@ -119,33 +118,20 @@ */ private Map getAgentMap(List aeids) { AgentManagerLocal aMan = AgentManagerEJBImpl.getOne(); - AsyncDeleteAgentCache cache = AsyncDeleteAgentCache.getInstance(); Map rtn = new HashMap(aeids.size()); List tmp; for (Iterator it=aeids.iterator(); it.hasNext(); ) { AppdefEntityID eid = (AppdefEntityID)it.next(); - Integer agentId = null; + Integer agentId; try { agentId = aMan.getAgent(eid).getId(); - } catch (AgentNotFoundException e) { - // HHQ-3585: It may be in an asynchronous - // delete state, so check the cache - agentId = cache.get(eid); - - if (agentId == null) { - log.warn(e.getMessage()); - } else { - // No longer needed, remove from cache - cache.remove(eid); - } - } - - if (agentId != null) { if (null == (tmp = (List)rtn.get(agentId))) { tmp = new ArrayList(); rtn.put(agentId, tmp); } tmp.add(eid); + } catch (AgentNotFoundException e) { + log.warn(e.getMessage()); } } return rtn; @@ -215,6 +201,12 @@ private void unschedule(Agent a, AppdefEntityID[] entIds) throws MeasurementUnscheduleException, MonitorAgentException { + + if (log.isDebugEnabled()) { + log.debug("unschedule agentId=" + a.getId() + + ", numOfResources=" + entIds.length); + } + SRNManagerLocal srnManager = getSRNManager(); for (int i = 0; i < entIds.length; i++) { try { |