|
From: <rm...@hy...> - 2007-03-25 04:25:37
|
Author: rmorgan Date: 2007-03-24 20:25:34 -0800 (Sat, 24 Mar 2007) New Revision: 3877 URL: http://svn.hyperic.org/?view=rev&root=Hyperic+HQ&revision=3877 Added: trunk/src/org/hyperic/hq/livedata/server/session/LiveDataExecutor.java trunk/src/org/hyperic/hq/livedata/server/session/LiveDataExecutorCommand.java trunk/src/org/hyperic/hq/livedata/shared/LiveDataCommand.java Modified: trunk/src/org/hyperic/hq/bizapp/client/shell/ClientShellEntityFetcher.java trunk/src/org/hyperic/hq/bizapp/client/shell/ClientShell_livedata_get.java trunk/src/org/hyperic/hq/bizapp/server/session/LiveDataBossEJBImpl.java trunk/src/org/hyperic/hq/livedata/agent/client/LiveDataClient.java trunk/src/org/hyperic/hq/livedata/server/session/LiveDataManagerEJBImpl.java trunk/src/org/hyperic/hq/livedata/shared/LiveDataResult.java Log: Add batch processing for livedata commands. Commands are bucketed by agent connection and executed in parallel using a ThreadPoolExecutor. Modified: trunk/src/org/hyperic/hq/bizapp/client/shell/ClientShellEntityFetcher.java =================================================================== --- trunk/src/org/hyperic/hq/bizapp/client/shell/ClientShellEntityFetcher.java 2007-03-25 04:24:27 UTC (rev 3876) +++ trunk/src/org/hyperic/hq/bizapp/client/shell/ClientShellEntityFetcher.java 2007-03-25 04:25:34 UTC (rev 3877) @@ -119,6 +119,7 @@ import org.hyperic.hq.scheduler.ScheduleValue; import org.hyperic.hq.livedata.shared.LiveDataException; import org.hyperic.hq.livedata.shared.LiveDataResult; +import org.hyperic.hq.livedata.shared.LiveDataCommand; import org.hyperic.util.ConfigPropertyException; import org.hyperic.util.StringUtil; import org.hyperic.util.config.ConfigResponse; @@ -1160,21 +1161,32 @@ return (0 == numInvalid); } - public LiveDataResult getLiveData(AppdefEntityID id, String command, - ConfigResponse config) + public LiveDataResult getLiveData(LiveDataCommand command) throws NamingException, ClientShellAuthenticationException, - PermissionException, AgentConnectionException, RemoteException, - AgentRemoteException, AgentNotFoundException, LiveDataException, - AppdefEntityNotFoundException, SessionTimeoutException, - SessionNotFoundException + PermissionException, RemoteException, AgentNotFoundException, + LiveDataException, AppdefEntityNotFoundException, + SessionTimeoutException, SessionNotFoundException { LiveDataBoss boss; boss = this.bossManager.getLiveDataBoss(); - return boss.getLiveData(auth.getAuthToken(), id, command, config); + return boss.getLiveData(auth.getAuthToken(), command); } + public LiveDataResult[] getLiveData(LiveDataCommand[] commands) + throws NamingException, ClientShellAuthenticationException, + PermissionException, RemoteException, AgentNotFoundException, + LiveDataException, AppdefEntityNotFoundException, + SessionTimeoutException, SessionNotFoundException + { + LiveDataBoss boss; + + boss = this.bossManager.getLiveDataBoss(); + + return boss.getLiveData(auth.getAuthToken(), commands); + } + public String[] getLiveDataCommands(AppdefEntityID id) throws RemoteException, NamingException, ClientShellAuthenticationException, PluginException, Modified: trunk/src/org/hyperic/hq/bizapp/client/shell/ClientShell_livedata_get.java =================================================================== --- trunk/src/org/hyperic/hq/bizapp/client/shell/ClientShell_livedata_get.java 2007-03-25 04:24:27 UTC (rev 3876) +++ trunk/src/org/hyperic/hq/bizapp/client/shell/ClientShell_livedata_get.java 2007-03-25 04:25:34 UTC (rev 3877) @@ -32,7 +32,10 @@ import org.hyperic.util.config.ConfigSchema; import org.hyperic.hq.appdef.shared.AppdefEntityID; import org.hyperic.hq.livedata.shared.LiveDataResult; +import org.hyperic.hq.livedata.shared.LiveDataCommand; +import java.io.PrintStream; + public class ClientShell_livedata_get extends ShellCommandBase { private static final int[] PARAM_VALID_RESOURCE = { @@ -64,13 +67,16 @@ ConfigResponse response = ((ClientShell)this.getShell()).processConfigSchema(schema); - LiveDataResult res = _entityFetcher.getLiveData(id, args[2], - response); + LiveDataCommand cmd = new LiveDataCommand(id, args[2], response); + LiveDataResult res = _entityFetcher.getLiveData(cmd); - this.getShell().getOutStream().println("Printing XML output from " + - args[2] + " command:"); - this.getShell().getOutStream().println(res.getXMLResult()); - + PrintStream ps = this.getShell().getOutStream(); + ps.println("Printing XML output from " + args[2] + " command:"); + if (res.hasError()) { + ps.println("Error: " + res.getErrorMessage()); + } else { + ps.println(res.getXMLResult()); + } } catch (Exception e) { throw new ShellCommandExecException(e); } Modified: trunk/src/org/hyperic/hq/bizapp/server/session/LiveDataBossEJBImpl.java =================================================================== --- trunk/src/org/hyperic/hq/bizapp/server/session/LiveDataBossEJBImpl.java 2007-03-25 04:24:27 UTC (rev 3876) +++ trunk/src/org/hyperic/hq/bizapp/server/session/LiveDataBossEJBImpl.java 2007-03-25 04:25:34 UTC (rev 3877) @@ -35,6 +35,7 @@ import org.hyperic.hq.livedata.shared.LiveDataException; import org.hyperic.hq.livedata.shared.LiveDataManagerLocal; import org.hyperic.hq.livedata.shared.LiveDataResult; +import org.hyperic.hq.livedata.shared.LiveDataCommand; import org.hyperic.hq.livedata.server.session.LiveDataManagerEJBImpl; import org.hyperic.hq.product.PluginException; import org.hyperic.hq.auth.shared.SessionManager; @@ -76,19 +77,33 @@ * * @ejb:interface-method */ - public LiveDataResult getLiveData(int sessionId, AppdefEntityID id, - String command, ConfigResponse config) - throws PermissionException, AgentConnectionException, - AgentRemoteException, AgentNotFoundException, - AppdefEntityNotFoundException, LiveDataException, - SessionTimeoutException, SessionNotFoundException + public LiveDataResult getLiveData(int sessionId, LiveDataCommand command) + throws PermissionException, AgentNotFoundException, + AppdefEntityNotFoundException, LiveDataException, + SessionTimeoutException, SessionNotFoundException { AuthzSubjectValue subject = _manager.getSubject(sessionId); LiveDataManagerLocal manager = LiveDataManagerEJBImpl.getOne(); - return manager.getData(subject, id, command, config); + return manager.getData(subject, command); } /** + * Get live data for the given commands + * + * @ejb:interface-method + */ + public LiveDataResult[] getLiveData(int sessionId, + LiveDataCommand[] commands) + throws PermissionException, AgentNotFoundException, + AppdefEntityNotFoundException, LiveDataException, + SessionTimeoutException, SessionNotFoundException + { + AuthzSubjectValue subject = _manager.getSubject(sessionId); + LiveDataManagerLocal manager = LiveDataManagerEJBImpl.getOne(); + return manager.getData(subject, commands); + } + + /** * Get the commands for a given resource. * * @ejb:interface-method Modified: trunk/src/org/hyperic/hq/livedata/agent/client/LiveDataClient.java =================================================================== --- trunk/src/org/hyperic/hq/livedata/agent/client/LiveDataClient.java 2007-03-25 04:24:27 UTC (rev 3876) +++ trunk/src/org/hyperic/hq/livedata/agent/client/LiveDataClient.java 2007-03-25 04:25:34 UTC (rev 3877) @@ -28,40 +28,37 @@ import org.hyperic.hq.livedata.agent.LiveDataCommandsAPI; import org.hyperic.hq.livedata.agent.commands.LiveData_args; import org.hyperic.hq.livedata.agent.commands.LiveData_result; -import org.hyperic.hq.livedata.shared.LiveDataException; import org.hyperic.hq.livedata.shared.LiveDataResult; import org.hyperic.hq.agent.client.AgentConnection; -import org.hyperic.hq.agent.AgentConnectionException; -import org.hyperic.hq.agent.AgentRemoteException; import org.hyperic.hq.agent.AgentRemoteValue; import org.hyperic.util.config.ConfigResponse; public class LiveDataClient { private LiveDataCommandsAPI _api; - private AgentConnection _agentConnection; + private AgentConnection _conn; public LiveDataClient(AgentConnection agentConnection) { - _agentConnection = agentConnection; + _conn = agentConnection; _api = new LiveDataCommandsAPI(); } public LiveDataResult getData(String type, String command, ConfigResponse config) - throws AgentConnectionException, AgentRemoteException, - LiveDataException { - LiveData_args args = new LiveData_args(); + try { + LiveData_args args = new LiveData_args(); - args.setConfig(type, command, config); + args.setConfig(type, command, config); - AgentRemoteValue res = - _agentConnection.sendCommand(LiveDataCommandsAPI.command_getData, - _api.getVersion(), args); - LiveData_result val = new LiveData_result(res); - - String xml = val.getResult(); - - return new LiveDataResult(xml); + AgentRemoteValue res = + _conn.sendCommand(LiveDataCommandsAPI.command_getData, + _api.getVersion(), args); + LiveData_result val = new LiveData_result(res); + String xml = val.getResult(); + return new LiveDataResult(xml); + } catch (Exception e) { + return new LiveDataResult(e, e.getMessage()); + } } } Added: trunk/src/org/hyperic/hq/livedata/server/session/LiveDataExecutor.java =================================================================== --- trunk/src/org/hyperic/hq/livedata/server/session/LiveDataExecutor.java (rev 0) +++ trunk/src/org/hyperic/hq/livedata/server/session/LiveDataExecutor.java 2007-03-25 04:25:34 UTC (rev 3877) @@ -0,0 +1,93 @@ +/* + * 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, 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. + */ + +package org.hyperic.hq.livedata.server.session; + +import edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor; +import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit; +import edu.emory.mathcs.backport.java.util.concurrent.LinkedBlockingQueue; +import org.hyperic.hq.livedata.agent.client.LiveDataClient; +import org.hyperic.hq.livedata.shared.LiveDataResult; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; + +public class LiveDataExecutor extends ThreadPoolExecutor { + + private static Log _log = LogFactory.getLog(LiveDataExecutor.class); + + private static final int THREAD_MIN = 1; + private static final int THREAD_MAX = 30; + + private List _results; + + public LiveDataExecutor() { + super(THREAD_MIN, THREAD_MAX, 1, TimeUnit.HOURS, + new LinkedBlockingQueue()); + _results = new ArrayList(); + } + + public void getData(LiveDataClient client, List commands) { + execute(new LiveDataGatherer(client, commands)); + } + + public LiveDataResult[] getResult() { + try { + awaitTermination(1, TimeUnit.MINUTES); + } catch (InterruptedException e) { + _log.warn("Executor interrputed!"); + } + + _log.debug("Returning results for " + _results.size() + " elements"); + return (LiveDataResult[])_results.toArray(new LiveDataResult[0]); + } + + private class LiveDataGatherer implements Runnable { + + private LiveDataClient _client; + private List _commands; + + LiveDataGatherer(LiveDataClient client, List commands) { + _client = client; + _commands = commands; + } + + public void run() { + _log.debug("Starting gather thread..."); + for (Iterator i = _commands.iterator(); i.hasNext(); ) { + LiveDataExecutorCommand cmd = (LiveDataExecutorCommand)i.next(); + _log.debug("Running cmd '" + cmd + "' in thread " + + Thread.currentThread().getName()); + LiveDataResult res = _client.getData(cmd.getType(), + cmd.getCommand(), + cmd.getConfig()); + _results.add(res); + } + } + } +} Added: trunk/src/org/hyperic/hq/livedata/server/session/LiveDataExecutorCommand.java =================================================================== --- trunk/src/org/hyperic/hq/livedata/server/session/LiveDataExecutorCommand.java (rev 0) +++ trunk/src/org/hyperic/hq/livedata/server/session/LiveDataExecutorCommand.java 2007-03-25 04:25:34 UTC (rev 3877) @@ -0,0 +1,53 @@ +/* + * 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, 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. + */ + +package org.hyperic.hq.livedata.server.session; + +import org.hyperic.util.config.ConfigResponse; + +class LiveDataExecutorCommand { + private String _type; + private String _command; + private ConfigResponse _config; + + public LiveDataExecutorCommand(String type, String command, + ConfigResponse config) { + _type = type; + _command = command; + _config = config; + } + + public String getType() { + return _type; + } + + public String getCommand() { + return _command; + } + + public ConfigResponse getConfig() { + return _config; + } +} Modified: trunk/src/org/hyperic/hq/livedata/server/session/LiveDataManagerEJBImpl.java =================================================================== --- trunk/src/org/hyperic/hq/livedata/server/session/LiveDataManagerEJBImpl.java 2007-03-25 04:24:27 UTC (rev 3876) +++ trunk/src/org/hyperic/hq/livedata/server/session/LiveDataManagerEJBImpl.java 2007-03-25 04:25:34 UTC (rev 3877) @@ -43,18 +43,22 @@ import org.hyperic.hq.appdef.server.session.ConfigManagerEJBImpl; import org.hyperic.hq.authz.shared.PermissionException; import org.hyperic.hq.authz.shared.AuthzSubjectValue; -import org.hyperic.hq.agent.AgentConnectionException; -import org.hyperic.hq.agent.AgentRemoteException; import org.hyperic.hq.common.SystemException; import org.hyperic.hq.livedata.shared.LiveDataManagerLocal; import org.hyperic.hq.livedata.shared.LiveDataManagerUtil; import org.hyperic.hq.livedata.shared.LiveDataException; import org.hyperic.hq.livedata.shared.LiveDataResult; +import org.hyperic.hq.livedata.shared.LiveDataCommand; +import org.hyperic.hq.agent.client.AgentConnection; import org.hyperic.util.config.ConfigResponse; import org.hyperic.util.config.ConfigSchema; import javax.ejb.SessionContext; import javax.ejb.SessionBean; +import java.util.HashMap; +import java.util.ArrayList; +import java.util.List; +import java.util.Iterator; /** * @ejb:bean name="LiveDataManager" @@ -98,44 +102,100 @@ /** * Live data subsystem uses measurement configs. */ - private ConfigResponse getMeasurementConfig(AuthzSubjectValue subject, - AppdefEntityID id) + private ConfigResponse getConfig(AuthzSubjectValue subject, + LiveDataCommand command) throws LiveDataException { ConfigManagerLocal cManager = ConfigManagerEJBImpl.getOne(); try { - return cManager.getMergedConfigResponse(subject, - ProductPlugin.TYPE_MEASUREMENT, - id, true); + AppdefEntityID id = command.getAppdefEntityID(); + ConfigResponse config = command.getConfig(); + ConfigResponse mConfig = cManager. + getMergedConfigResponse(subject, ProductPlugin.TYPE_MEASUREMENT, + id, true); + config.merge(mConfig, false); + return config; } catch (Exception e) { throw new LiveDataException(e); } } /** - * Get live data for a given resource. + * Get the appdef type for a given entity id. + */ + private String getType(AuthzSubjectValue subject, LiveDataCommand cmd) + throws AppdefEntityNotFoundException, PermissionException + { + AppdefEntityID id = cmd.getAppdefEntityID(); + AppdefEntityValue val = new AppdefEntityValue(id, subject); + AppdefResourceTypeValue typeVal = val.getResourceTypeValue(); + return typeVal.getName(); + } + + /** + * Run the given live data command. * * @ejb:interface-method */ public LiveDataResult getData(AuthzSubjectValue subject, - AppdefEntityID id, String command, - ConfigResponse config) + LiveDataCommand cmd) throws PermissionException, AgentNotFoundException, - AgentConnectionException, AgentRemoteException, - AppdefEntityNotFoundException, LiveDataException + AppdefEntityNotFoundException, LiveDataException { - LiveDataClient client = - new LiveDataClient(AgentConnectionUtil.getClient(id)); + AppdefEntityID id = cmd.getAppdefEntityID(); + AgentConnection conn = AgentConnectionUtil.getClient(id); + LiveDataClient client = new LiveDataClient(conn); - ConfigResponse measurementConfig = getMeasurementConfig(subject, id); + ConfigResponse config = getConfig(subject, cmd); + String type = getType(subject, cmd); - config.merge(measurementConfig, false); - - AppdefEntityValue val = new AppdefEntityValue(id, subject); - AppdefResourceTypeValue tVal = val.getResourceTypeValue(); + return client.getData(type, cmd.getCommand(), config); + } - return client.getData(tVal.getName(), command, config); + /** + * Run a list of live data commands in batch. + * + * @ejb:interface-method + */ + public LiveDataResult[] getData(AuthzSubjectValue subject, + LiveDataCommand[] commands) + throws PermissionException, AppdefEntityNotFoundException, + AgentNotFoundException, LiveDataException + { + HashMap buckets = new HashMap(); + + for (int i = 0; i < commands.length; i++) { + LiveDataCommand cmd = commands[i]; + AppdefEntityID id = cmd.getAppdefEntityID(); + AgentConnection conn = AgentConnectionUtil.getClient(id); + + ConfigResponse config = getConfig(subject, cmd); + String type = getType(subject, cmd); + + LiveDataExecutorCommand exec = + new LiveDataExecutorCommand(type, cmd.getCommand(), config); + + List queue = (List)buckets.get(conn); + if (queue == null) { + queue = new ArrayList(); + queue.add(exec); + buckets.put(conn, queue); + } else { + queue.add(exec); + } + } + + LiveDataExecutor executor = new LiveDataExecutor(); + for (Iterator i = buckets.keySet().iterator(); i.hasNext(); ) { + AgentConnection conn = (AgentConnection)i.next(); + List cmds = (List)buckets.get(conn); + executor.getData(new LiveDataClient(conn), cmds); + } + + executor.shutdown(); + + return executor.getResult(); } /** Added: trunk/src/org/hyperic/hq/livedata/shared/LiveDataCommand.java =================================================================== --- trunk/src/org/hyperic/hq/livedata/shared/LiveDataCommand.java (rev 0) +++ trunk/src/org/hyperic/hq/livedata/shared/LiveDataCommand.java 2007-03-25 04:25:34 UTC (rev 3877) @@ -0,0 +1,61 @@ +/* + * 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, 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. + */ + +package org.hyperic.hq.livedata.shared; + +import org.hyperic.util.config.ConfigResponse; +import org.hyperic.hq.appdef.shared.AppdefEntityID; + +import java.io.Serializable; + +public class LiveDataCommand implements Serializable { + + private AppdefEntityID _id; + private String _command; + private ConfigResponse _config; + + public LiveDataCommand(AppdefEntityID id, String command, + ConfigResponse config) { + _id = id; + _command = command; + _config = config; + } + + public AppdefEntityID getAppdefEntityID() { + return _id; + } + + public String getCommand() { + return _command; + } + + public ConfigResponse getConfig() { + return _config; + } + + public String toString() { + return _id + ":" + _command; + } +} Modified: trunk/src/org/hyperic/hq/livedata/shared/LiveDataResult.java =================================================================== --- trunk/src/org/hyperic/hq/livedata/shared/LiveDataResult.java 2007-03-25 04:24:27 UTC (rev 3876) +++ trunk/src/org/hyperic/hq/livedata/shared/LiveDataResult.java 2007-03-25 04:25:34 UTC (rev 3877) @@ -9,12 +9,22 @@ */ public class LiveDataResult implements Serializable { + private boolean _error; + private Throwable _cause; + private String _errorMsg; private String _xml; public LiveDataResult(String xml) { + _error = false; _xml = xml; } + public LiveDataResult(Throwable t, String errorMsg) { + _error = true; + _errorMsg = errorMsg; + _cause = t; + } + /** * Get the raw XML result for this request. */ @@ -29,4 +39,26 @@ XStream xstream = new XStream(); return xstream.fromXML(_xml); } + + /** + * Get the error (if it exists) for this command. Not always guaranteed + * to be non-null if hasError() is true. + */ + public Throwable getCause() { + return _cause; + } + + /** + * Get the error string for this result. + */ + public String getErrorMessage() { + return _errorMsg; + } + + /** + * True if an error occured collecting the live data + */ + public boolean hasError() { + return _error; + } } |