modules/core/domain/src/main/java/org/rhq/core/domain/measurement/Availability.java | 10 + modules/enterprise/agent/src/etc/java-service-wrapper/rhq-agent-wrapper.conf | 4 modules/enterprise/agent/src/etc/rhq-agent-wrapper.bat | 4 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/AvailabilityManagerBean.java | 51 +++++++--- 4 files changed, 53 insertions(+), 16 deletions(-)
New commits: commit 719e2c127f24f7467ecc3a371d9797f6598880c0 Author: Jay Shaughnessy jshaughn@redhat.com Date: Thu Dec 5 09:34:19 2013 -0500
[1038256] Windows 2008 - Invalid agent service after upgrade (on remote agent machine) This problem resulted from the work in Bug 1016609, when we introduced the use of RHQ_JAVA_EXE_FILE_PATH and deprecated the use of RHQ_AGENT_JAVA_EXE_FILE_PATH (among several simplifications of our env properties). The issue with that change was the fact that existing windows agent services (remote agents, not handled by rhqctl) included set.RHQ_AGENT_JAVA_EXE_FILE_PATH in the service "path to executable", for use by the service wrapper. But the new rhq-agent-wrapper.conf expected RHQ_JAVA_EXE_FILE_PATH to be set when formulating its command string.
This was only an issue for existing agents that would be auto-upgraded. Agent auto-upgrade does not update the existing service, it only restarts it after the agent update. So, the "path to executable" remains unchanged and therefore passes only the legacy property. Note that auto-upgrade does the right thing, it should *not* replace the service in order to update its definition. Doing this could lose the RUN_AS password, which may have been set interactively when the agent was initially installed.
The solution should be good, the rhq-agent-wrapper.conf has been reverted to use RHQ_AGENT_JAVA_EXE_FILE_PATH. We still completely support the new RHQ env properties, like RHQ_JAVA_EXE_FILE_PATH, but will supply the legacy property at service install time. That gives up backward compatibility while keeping the use of RHQ_AGENT_JAVA_EXE_FILE_PATH internal.
diff --git a/modules/enterprise/agent/src/etc/java-service-wrapper/rhq-agent-wrapper.conf b/modules/enterprise/agent/src/etc/java-service-wrapper/rhq-agent-wrapper.conf index 3f3712e..a510ea9 100644 --- a/modules/enterprise/agent/src/etc/java-service-wrapper/rhq-agent-wrapper.conf +++ b/modules/enterprise/agent/src/etc/java-service-wrapper/rhq-agent-wrapper.conf @@ -33,7 +33,7 @@ # set.RHQ_AGENT_PASSWORD - the password of the user that is to # run the service. Only used if # RHQ_AGENT_PASSWORD_PROMPT is FALSE. -# set.RHQ_JAVA_EXE_FILE_PATH - Java executable +# set.RHQ_AGENT_JAVA_EXE_FILE_PATH - Java executable #*****************************************************************************
# Load in the specific environment for the RHQ agent instance to start @@ -43,7 +43,7 @@ # Start Properties #***************************************************************************** # Java JVM Executable (quotes not needed) -wrapper.java.command=%RHQ_JAVA_EXE_FILE_PATH% +wrapper.java.command=%RHQ_AGENT_JAVA_EXE_FILE_PATH%
# Java Main class. This class must implement the WrapperListener interface. (quotes not needed) wrapper.java.mainclass=org.tanukisoftware.wrapper.WrapperSimpleApp diff --git a/modules/enterprise/agent/src/etc/rhq-agent-wrapper.bat b/modules/enterprise/agent/src/etc/rhq-agent-wrapper.bat index 90e9666..657f701 100644 --- a/modules/enterprise/agent/src/etc/rhq-agent-wrapper.bat +++ b/modules/enterprise/agent/src/etc/rhq-agent-wrapper.bat @@ -146,7 +146,9 @@ if /i "%1"=="install" ( if not defined RHQ_AGENT_PASSWORD_PROMPT set RHQ_AGENT_PASSWORD_PROMPT=true )
- "%RHQ_AGENT_WRAPPER_EXE_FILE_PATH%" -i "%RHQ_AGENT_WRAPPER_CONF_FILE_PATH%" "set.RHQ_AGENT_HOME=%RHQ_AGENT_HOME%" "set.RHQ_AGENT_INSTANCE_NAME=%RHQ_AGENT_INSTANCE_NAME%" "set.RHQ_JAVA_EXE_FILE_PATH=%RHQ_JAVA_EXE_FILE_PATH%" "set.RHQ_AGENT_OS_PLATFORM=%RHQ_AGENT_OS_PLATFORM%" "set.RHQ_AGENT_WRAPPER_LOG_DIR_PATH=%RHQ_AGENT_WRAPPER_LOG_DIR_PATH%" !_WRAPPER_NTSERVICE_ACCOUNT! %_DEBUG_OPTS% + rem note that we set RHQ_AGENT_JAVA_EXE_FILE_PATH on purpose. The services use this legacy env var, as opposed to + rem RHQ_JAVA_EXE_FILE_PATH, to be backward compatible with existing services that get auto-upgraded. + "%RHQ_AGENT_WRAPPER_EXE_FILE_PATH%" -i "%RHQ_AGENT_WRAPPER_CONF_FILE_PATH%" "set.RHQ_AGENT_HOME=%RHQ_AGENT_HOME%" "set.RHQ_AGENT_INSTANCE_NAME=%RHQ_AGENT_INSTANCE_NAME%" "set.RHQ_AGENT_JAVA_EXE_FILE_PATH=%RHQ_JAVA_EXE_FILE_PATH%" "set.RHQ_AGENT_OS_PLATFORM=%RHQ_AGENT_OS_PLATFORM%" "set.RHQ_AGENT_WRAPPER_LOG_DIR_PATH=%RHQ_AGENT_WRAPPER_LOG_DIR_PATH%" !_WRAPPER_NTSERVICE_ACCOUNT! %_DEBUG_OPTS% if ERRORLEVEL 1 goto error goto done )
commit 544dc80ce4c22e399d3ca607108896feb6ebd5b6 Author: Jay Shaughnessy jshaughn@redhat.com Date: Wed Dec 4 13:36:49 2013 -0500
[1037616] Pull calls to find current availability out of the processing loop Optimization work based on BZ-supplied patch. For a batch of Availabilities being processed, pull latest availabilities for the resources in one DB round trip as opposed to once for each resource. Still beiong careful to repair issues when no, or multiple, latest entries are found.
diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/measurement/Availability.java b/modules/core/domain/src/main/java/org/rhq/core/domain/measurement/Availability.java index 2297af9..a44a2ff 100644 --- a/modules/core/domain/src/main/java/org/rhq/core/domain/measurement/Availability.java +++ b/modules/core/domain/src/main/java/org/rhq/core/domain/measurement/Availability.java @@ -64,6 +64,11 @@ import org.rhq.core.domain.resource.Resource; + " WHERE av.resource.id = :resourceId " // + " AND av.endTime IS NULL " // + "ORDER BY av.startTime ASC "), // this order by is on purpose - for handling NonUniqueResultException problems + @NamedQuery(name = Availability.FIND_LATEST_BY_RESOURCE_IDS, query = "" // + + " SELECT av " // + + " FROM Availability av " // + + " WHERE av.resource.id IN :resourceIds " // + + " AND av.endTime IS NULL "), // @NamedQuery(name = Availability.FIND_BY_RESOURCE, query = "" // + " SELECT av " // + " FROM Availability av " // @@ -88,7 +93,7 @@ import org.rhq.core.domain.resource.Resource; + "SELECT new org.rhq.core.domain.resource.composite.ResourceIdWithAvailabilityComposite(av.resource.id, av) " // + " FROM Availability av " // + " WHERE av.resource.agent.id = :agentId " // - + " AND av.resource.parentResource IS NOT NULL " // + + " AND av.resource.parentResource IS NOT NULL " // + " AND ((av.availabilityType <> :availabilityType AND av.availabilityType <> :disabled AND :availabilityType IS NOT NULL) " // + " OR (av.availabilityType IS NOT NULL AND :availabilityType IS NULL) " // + " OR (av.availabilityType IS NULL AND :availabilityType IS NOT NULL)) " // @@ -139,6 +144,7 @@ public class Availability implements Serializable { private static final long serialVersionUID = 1L;
public static final String FIND_CURRENT_BY_RESOURCE = "Availability.findCurrentByResource"; + public static final String FIND_LATEST_BY_RESOURCE_IDS = "Availability.findLatestByResourceIds"; public static final String FIND_BY_RESOURCE = "Availability.findByResource"; public static final String FIND_BY_RESOURCE_NO_SORT = "Availability.findByResourceNoSort"; public static final String FIND_PLATFORM_COMPOSITE_BY_AGENT_AND_NONMATCHING_TYPE = "Availability.findPlatformCompositeByAgentAndNonmatchingType"; @@ -199,7 +205,7 @@ public class Availability implements Serializable { * * @param resource * @param startTime if null set to current time - * @param type if null this will be set to UNKNOWN + * @param type if null this will be set to UNKNOWN */ public Availability(Resource resource, Long startTime, AvailabilityType type) { if (resource == null) { diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/AvailabilityManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/AvailabilityManagerBean.java index 76fe117..e54b167 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/AvailabilityManagerBean.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/AvailabilityManagerBean.java @@ -25,6 +25,7 @@ import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map;
import javax.ejb.EJB; import javax.ejb.Stateless; @@ -93,13 +94,15 @@ public class AvailabilityManagerBean implements AvailabilityManagerLocal, Availa
static {
+ // The value of 200 has been settled upon after testing several batch sizes. If changed it still must be less + // than 1000 for Oracle IN clause limitation reasons. int mergeBatchSize = 200; try { mergeBatchSize = Integer.parseInt(System.getProperty("rhq.server.availability.merge.batch.size", "200")); } catch (Throwable t) { // } - MERGE_BATCH_SIZE = mergeBatchSize; + MERGE_BATCH_SIZE = (mergeBatchSize > 999) ? 999 : mergeBatchSize; }
@PersistenceContext(unitName = RHQConstants.PERSISTENCE_UNIT_NAME) @@ -811,8 +814,28 @@ public class AvailabilityManagerBean implements AvailabilityManagerLocal, Availa
// We will alert only on the avails for enabled resources. Keep track of any that are disabled. List<Availability> disabledAvailabilities = new ArrayList<Availability>(); - Query q = entityManager.createNamedQuery(Availability.FIND_CURRENT_BY_RESOURCE); - int count = 0; + + Query q = entityManager.createNamedQuery(Availability.FIND_LATEST_BY_RESOURCE_IDS); + List<Integer> resourceIds = new ArrayList<Integer>(availabilities.size()); + for (Availability reported : availabilities) { + resourceIds.add(reported.getResource().getId()); + } + q.setParameter("resourceIds", resourceIds); + List<Availability> latestAvailabilitiesList = q.getResultList(); + resourceIds.clear(); // perhaps helps GC + + // populate Map of resourceIds to latestAvailability + // there should be a single latest avail per resource. mark any situation where we have multiple + Object nonUniqueMarker = new Object(); + Map<Integer, Object> latestAvailabilities = new HashMap(availabilities.size() + 100); + for (Availability latestAvailability : latestAvailabilitiesList) { + Integer resourceId = latestAvailability.getResource().getId(); + if (latestAvailabilities.containsKey(resourceId)) { + latestAvailabilities.put(resourceId, nonUniqueMarker); + } else { + latestAvailabilities.put(resourceId, latestAvailability); + } + }
for (Availability reported : availabilities) {
@@ -820,13 +843,12 @@ public class AvailabilityManagerBean implements AvailabilityManagerLocal, Availa reported.setEndTime(null);
// get the latest avail for the reported resource - q.setParameter("resourceId", reported.getResource().getId()); + //q.setParameter("resourceId", reported.getResource().getId()); + Integer resourceId = reported.getResource().getId(); + Object latestObject = latestAvailabilities.get(resourceId); Availability latest = null;
- try { - latest = (Availability) q.getSingleResult(); - - } catch (NoResultException nre) { + if (null == latestObject) { // this is like NoResultException // This should not happen unless the Resource in the report is stale, which can happen in certain // sync scenarios. A Resource is given its initial Availability/ResourceAvailability when it is // persisted so it is guaranteed to have Availability, so, the Resource must not exist. At least @@ -873,7 +895,7 @@ public class AvailabilityManagerBean implements AvailabilityManagerLocal, Availa continue; } } - } catch (NonUniqueResultException nure) { + } else if (latestObject == nonUniqueMarker) { // this is like NonUniqueResultException // This condition should never happen. In my world of la-la land, I've done everything // correctly so this never happens. But, due to the asynchronous nature of things, // I have to believe that this still might happen (albeit rarely). If it does happen, @@ -881,10 +903,13 @@ public class AvailabilityManagerBean implements AvailabilityManagerLocal, Availa // has 2 or more availabilities with endTime of null, we need to delete all but the // latest one (the one whose start time is the latest). This should correct the // problem and allow us to continue processing availability reports for that resource - log.warn("Resource [" + reported.getResource() + "] has multiple availabilities without an endtime [" - + nure.getMessage() + "] - will attempt to remove the extra ones\n" + mergeInfo.toString(false)); + log.warn("Resource [" + reported.getResource() + + "] has multiple availabilities without an endtime - will attempt to remove the extra ones\n" + + mergeInfo.toString(false));
try { + q = entityManager.createNamedQuery(Availability.FIND_CURRENT_BY_RESOURCE); + q.setParameter("resourceId", resourceId);
List<Availability> latestList = q.getResultList();
@@ -906,6 +931,8 @@ public class AvailabilityManagerBean implements AvailabilityManagerLocal, Availa + "]", t); continue; } + } else { + latest = (Availability) latestObject; }
AvailabilityType latestType = latest.getAvailabilityType(); @@ -953,6 +980,8 @@ public class AvailabilityManagerBean implements AvailabilityManagerLocal, Availa } }
+ latestAvailabilities.clear(); // perhaps helps GC + // notify alert condition cache manager for all reported avails for for enabled resources availabilities.removeAll(disabledAvailabilities); notifyAlertConditionCacheManager("mergeAvailabilityReport",
rhq-commits@lists.fedorahosted.org