modules/core/arquillian-integration/container/src/main/java/org/rhq/test/arquillian/FakeServerInventory.java
| 46 -
modules/core/client-api/src/main/java/org/rhq/core/clientapi/agent/discovery/DiscoveryAgentService.java
| 19
modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/discovery/DiscoveryServerService.java
| 3
modules/core/domain/src/main/java/org/rhq/core/domain/discovery/PlatformSyncInfo.java
| 73 +-
modules/core/domain/src/main/java/org/rhq/core/domain/discovery/ResourceSyncInfo.java
| 140 ++--
modules/core/domain/src/main/java/org/rhq/core/domain/discovery/SyncInfo.java
| 98 --
modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/AbstractIgnoreTypesInventoryManagerBaseTest.java
| 36 -
modules/core/plugin-container/src/main/java/org/rhq/core/pc/StandaloneContainer.java
| 3
modules/core/plugin-container/src/main/java/org/rhq/core/pc/drift/sync/RuntimeSynchronizer.java
| 2
modules/core/plugin-container/src/main/java/org/rhq/core/pc/inventory/InventoryManager.java
| 329 ++++------
modules/core/plugin-container/src/test/java/org/rhq/core/pc/upgrade/AbstractResourceUpgradeHandlingTest.java
| 4
modules/core/plugin-container/src/test/java/org/rhq/core/pc/upgrade/FakeServerInventory.java
| 48 -
modules/core/plugin-container/src/test/java/org/rhq/core/pc/upgrade/ResourceUpgradeTest.java
| 20
modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBeanTest.java
| 28
modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/configuration/LargeGroupPluginConfigurationTest.java
| 17
modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/discovery/DiscoveryBossBeanTest.java
| 65 +
modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/test/TestAgentClient.java
| 18
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossBean.java
| 87 ++
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossLocal.java
| 7
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryServerServiceImpl.java
| 5
20 files changed, 553 insertions(+), 495 deletions(-)
New commits:
commit b71b50566d781cebacf3301d5692f87a23a495a5
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Wed Dec 18 09:28:48 2013 -0500
[1023451] [perf] Large retained heap during inventory report merge (causing OOMs)
Note - this is related work, not necessarily a solution to this problem.
This commit builds on the "chunking" work introduced earlier. This work
replaces the tree structure, previously used to pass sync info between
agent and server, with flat collections. This allows us to replace the
costly Hibernate-based tree building approach with more comprehensive queries
that reduce the number of DB round trips dramatically.
Notes:
- This commit fixed an issue with the previous work regarding the handling
of top level services.
- The ResourceSyncInfo class is now even lighter weight, parent-child info is
removed.
- PlatformSyncInfo is now a POJO.
- The handling of unknown resources (agent side) changed significantly
because it had depended on the previous tree structure.
- mocks again had to be updated
diff --git
a/modules/core/arquillian-integration/container/src/main/java/org/rhq/test/arquillian/FakeServerInventory.java
b/modules/core/arquillian-integration/container/src/main/java/org/rhq/test/arquillian/FakeServerInventory.java
index 74a0acc..60f61c1 100644
---
a/modules/core/arquillian-integration/container/src/main/java/org/rhq/test/arquillian/FakeServerInventory.java
+++
b/modules/core/arquillian-integration/container/src/main/java/org/rhq/test/arquillian/FakeServerInventory.java
@@ -19,7 +19,6 @@
package org.rhq.test.arquillian;
-import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
@@ -248,10 +247,10 @@ public class FakeServerInventory {
};
}
- public synchronized Answer<ResourceSyncInfo> getResourceSyncInfo() {
- return new Answer<ResourceSyncInfo>() {
+ public synchronized Answer<Collection<ResourceSyncInfo>>
getResourceSyncInfo() {
+ return new Answer<Collection<ResourceSyncInfo>>() {
@Override
- public ResourceSyncInfo answer(InvocationOnMock invocation) throws Throwable
{
+ public Collection<ResourceSyncInfo> answer(InvocationOnMock invocation)
throws Throwable {
synchronized (FakeServerInventory.this) {
Integer resourceId = (Integer) invocation.getArguments()[0];
@@ -622,37 +621,29 @@ public class FakeServerInventory {
return platform == null ? null :
PlatformSyncInfo.buildPlatformSyncInfo(platform);
}
- private ResourceSyncInfo getResourceSyncInfo(Resource resource) {
+ private Collection<ResourceSyncInfo> getResourceSyncInfo(Resource resource) {
return resource == null ? null : convert(resource);
}
- private static ResourceSyncInfo convert(Resource root) {
- return convertInternal(root, true, new HashMap<String,
ResourceSyncInfo>());
+ private static Collection<ResourceSyncInfo> convert(Resource root) {
+ Set<ResourceSyncInfo> result = new HashSet<ResourceSyncInfo>();
+ convertInternal(root, result);
+ return result;
}
- private static ResourceSyncInfo convertInternal(Resource root, boolean
isTopLevelServer,
- Map<String, ResourceSyncInfo> intermediateResults) {
+ private static void convertInternal(Resource root, Collection<ResourceSyncInfo>
result) {
- ResourceSyncInfo ret = intermediateResults.get(root.getUuid());
+ ResourceSyncInfo rootSyncInfo = ResourceSyncInfo.buildResourceSyncInfo(root);
- if (ret != null) {
- return ret;
+ if (result.contains(rootSyncInfo)) {
+ return;
}
try {
- ret = ResourceSyncInfo.buildResourceSyncInfo(root);
- intermediateResults.put(root.getUuid(), ret);
+ result.add(rootSyncInfo);
- Integer parentId = root.getParentResource() == null ? null :
root.getParentResource().getId();
- getPrivateField(ResourceSyncInfo.class, "parentId").set(ret,
parentId);
-
- Set<ResourceSyncInfo> children = new
LinkedHashSet<ResourceSyncInfo>();
for (Resource child : root.getChildResources()) {
- ResourceSyncInfo syncChild = convertInternal(child, false,
intermediateResults);
-
- children.add(syncChild);
+ convertInternal(child, result);
}
- getPrivateField(ResourceSyncInfo.class, "childSyncInfos").set(ret,
children);
- return ret;
} catch (Exception e) {
throw new IllegalStateException("Failed to convert resource " +
root
@@ -660,15 +651,6 @@ public class FakeServerInventory {
}
}
- private static Field getPrivateField(Class<?> clazz, String fieldName) throws
NoSuchFieldException {
- Field field = clazz.getDeclaredField(fieldName);
- if (!field.isAccessible()) {
- field.setAccessible(true);
- }
-
- return field;
- }
-
private void throwIfFailing() {
if (failing) {
throw new RuntimeException("Fake server inventory is in the failing
mode.");
diff --git
a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/agent/discovery/DiscoveryAgentService.java
b/modules/core/client-api/src/main/java/org/rhq/core/clientapi/agent/discovery/DiscoveryAgentService.java
index e3313f0..4c2a821 100644
---
a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/agent/discovery/DiscoveryAgentService.java
+++
b/modules/core/client-api/src/main/java/org/rhq/core/clientapi/agent/discovery/DiscoveryAgentService.java
@@ -22,6 +22,8 @@
*/
package org.rhq.core.clientapi.agent.discovery;
+import java.util.Collection;
+
import org.jetbrains.annotations.NotNull;
import org.rhq.core.clientapi.agent.PluginContainerException;
@@ -29,8 +31,8 @@ import org.rhq.core.clientapi.server.discovery.InventoryReport;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.discovery.AvailabilityReport;
import org.rhq.core.domain.discovery.MergeResourceResponse;
+import org.rhq.core.domain.discovery.PlatformSyncInfo;
import org.rhq.core.domain.discovery.ResourceSyncInfo;
-import org.rhq.core.domain.measurement.Availability;
import org.rhq.core.domain.measurement.AvailabilityType;
import org.rhq.core.domain.resource.Resource;
import org.rhq.core.domain.resource.ResourceError;
@@ -56,11 +58,20 @@ public interface DiscoveryAgentService {
throws InvalidPluginConfigurationClientException, PluginContainerException;
/**
- * Called to inform the agent of a status change for the resource represented by
syncInfo. The agent processes the syncInfo for the resource and initiates a status update
for its sub-tree.
+ * Called by the server when requesting a full platform sync. The provided info will
guide the subsequent
+ * agent-initiated sync.
+ *
+ * @param syncInfo for the platform to be synchronized with the server.
+ */
+ void synchronizePlatform(PlatformSyncInfo syncInfo);
+
+ /**
+ * Called by the server to update the agent with changed for specified top level
server. The agent will
+ * synchronize its inventory for the server and its subtree given the provided
information.
*
- * @param syncInfo for the root of the tree to be updated.
+ * @param syncInfo for the top level server to be synchronized with the server.
*/
- void synchronizeInventory(ResourceSyncInfo syncInfo);
+ void synchronizeServer(int resourceId, Collection<ResourceSyncInfo>
toplevelServerSyncInfo);
/**
* Access to the current inventory managed by the plugin container.
diff --git
a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/discovery/DiscoveryServerService.java
b/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/discovery/DiscoveryServerService.java
index df2a286..4280305 100644
---
a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/discovery/DiscoveryServerService.java
+++
b/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/discovery/DiscoveryServerService.java
@@ -22,6 +22,7 @@
*/
package org.rhq.core.clientapi.server.discovery;
+import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -73,7 +74,7 @@ public interface DiscoveryServerService {
@LimitedConcurrency(CONCURRENCY_LIMIT_INVENTORY_REPORT)
@Timeout(0L)
// should be something like 1000L * 60 * 30 but until we can be assured we never take
longer, disable timeout
- ResourceSyncInfo getResourceSyncInfo(int resourceId);
+ Collection<ResourceSyncInfo> getResourceSyncInfo(int resourceId);
/**
* Merges a new availability report from the agent into the server. This updates the
availability statuses of known
diff --git
a/modules/core/domain/src/main/java/org/rhq/core/domain/discovery/PlatformSyncInfo.java
b/modules/core/domain/src/main/java/org/rhq/core/domain/discovery/PlatformSyncInfo.java
index 951f542..3d989f3 100644
---
a/modules/core/domain/src/main/java/org/rhq/core/domain/discovery/PlatformSyncInfo.java
+++
b/modules/core/domain/src/main/java/org/rhq/core/domain/discovery/PlatformSyncInfo.java
@@ -23,52 +23,69 @@
package org.rhq.core.domain.discovery;
import java.io.Serializable;
-import java.util.Collection;
-import java.util.Collections;
+import java.util.HashSet;
import java.util.Set;
-import javax.persistence.Entity;
-import javax.persistence.FetchType;
-import javax.persistence.OneToMany;
-import javax.persistence.Table;
-
-import org.rhq.core.domain.resource.InventoryStatus;
import org.rhq.core.domain.resource.Resource;
+import org.rhq.core.domain.resource.ResourceCategory;
/**
- * @author Ian Springer
+ * This immutable POJO returns the information necessary for the agent to perform a
complete sync with the server
+ * inventory. It does not provide *all* of the sync info, only the platform and its top
level *service* hierarchy. It
+ * expects the agent to call back to the server for each of the platform's top level
servers and therefore provides
+ * only the top level server Ids.
+ *
* @author Jay Shaughnessy
*/
-@Entity
-@Table(name = "RHQ_RESOURCE")
-public class PlatformSyncInfo extends SyncInfo implements Serializable {
+public class PlatformSyncInfo implements Serializable {
private static final long serialVersionUID = 1L;
- @OneToMany(mappedBy = "parentResource", fetch = FetchType.EAGER)
- private Set<Resource> topLevelServers;
+ private ResourceSyncInfo platform;
+ private Set<ResourceSyncInfo> services;
+ private Set<Integer> topLevelServerIds;
+
+ public PlatformSyncInfo(ResourceSyncInfo platform, Set<ResourceSyncInfo>
services, Set<Integer> topLevelServerIds) {
+ super();
+ this.platform = platform;
+ this.services = services;
+ this.topLevelServerIds = topLevelServerIds;
+ }
+
+ /**
+ * @return just the platform sync info
+ */
+ public ResourceSyncInfo getPlatform() {
+ return platform;
+ }
- // JPA requires public or protected no-param constructor; Externalizable requires
public no-param constructor.
- public PlatformSyncInfo() {
+ /**
+ * @return the sync info for the platform hierarchy excluding the platform itself and
the top level servers
+ */
+ public Set<ResourceSyncInfo> getServices() {
+ return services;
}
- public Collection<Resource> getTopLevelServers() {
- return topLevelServers;
+ /**
+ * @return just the type level server ids, so that the agent can call back for sync
info on each top level server
+ */
+ public Set<Integer> getTopLevelServerIds() {
+ return topLevelServerIds;
}
// for testing
public static PlatformSyncInfo buildPlatformSyncInfo(Resource platform) {
- Set<Resource> toplevelServers = platform.getChildResources();
+ Set<Integer> toplevelServerIds = new HashSet<Integer>();
+ for (Resource r : platform.getChildResources()) {
+ if (r.getResourceType().getCategory().equals(ResourceCategory.SERVER)) {
+ toplevelServerIds.add(r.getId());
+ }
+ }
- PlatformSyncInfo syncInfo = new PlatformSyncInfo(platform.getId(),
platform.getUuid(), platform.getMtime(),
- platform.getInventoryStatus(), (null == toplevelServers ?
Collections.EMPTY_SET : toplevelServers));
+ ResourceSyncInfo resSyncInfo = ResourceSyncInfo.buildResourceSyncInfo(platform);
- return syncInfo;
- }
+ PlatformSyncInfo syncInfo = new PlatformSyncInfo(resSyncInfo, new
HashSet<ResourceSyncInfo>(1),
+ toplevelServerIds);
- // for testing
- private PlatformSyncInfo(int id, String uuid, long mtime, InventoryStatus istatus,
Set<Resource> children) {
- super(id, uuid, mtime, istatus);
- this.topLevelServers = children;
+ return syncInfo;
}
-
}
diff --git
a/modules/core/domain/src/main/java/org/rhq/core/domain/discovery/ResourceSyncInfo.java
b/modules/core/domain/src/main/java/org/rhq/core/domain/discovery/ResourceSyncInfo.java
index e9cb222..b1fb366 100644
---
a/modules/core/domain/src/main/java/org/rhq/core/domain/discovery/ResourceSyncInfo.java
+++
b/modules/core/domain/src/main/java/org/rhq/core/domain/discovery/ResourceSyncInfo.java
@@ -23,85 +23,131 @@
package org.rhq.core.domain.discovery;
import java.io.Serializable;
-import java.util.Collection;
-import java.util.HashSet;
import javax.persistence.Column;
import javax.persistence.Entity;
-import javax.persistence.FetchType;
-import javax.persistence.OneToMany;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
import javax.persistence.Table;
import org.rhq.core.domain.resource.InventoryStatus;
import org.rhq.core.domain.resource.Resource;
/**
- * Sync info for any non-platform resource.
+ * Sync info for a resource. This is a lightweight "Resource" entity that
contains only the information required
+ * to perform Inventory Sync between the Agent and Server.
*
- * @author Ian Springer
* @author Jay Shaughnessy
*/
@Entity
+@NamedQueries({
+ @NamedQuery(name = ResourceSyncInfo.QUERY_SERVICE_CHILDREN, query = "" //
+ + "SELECT r " //
+ + " FROM ResourceSyncInfo r " //
+ + " WHERE r.id IN ( SELECT rr.id FROM Resource rr WHERE rr.parentResource.id
IN ( :parentIds )) " //
+ + ""),
+ @NamedQuery(name = ResourceSyncInfo.QUERY_TOP_LEVEL_SERVER, query = "" //
+ + "SELECT rsi " //
+ + " FROM ResourceSyncInfo rsi " //
+ + " WHERE rsi.id = :resourceId " //
+ + " OR rsi.id IN (SELECT rr.id FROM Resource rr WHERE
rr.parentResource.id = :resourceId) "
+ + " OR rsi.id IN (SELECT rr.id FROM Resource rr WHERE
rr.parentResource.parentResource.id = :resourceId) "
+ + " OR rsi.id IN (SELECT rr.id FROM Resource rr WHERE
rr.parentResource.parentResource.parentResource.id = :resourceId) "
+ + " OR rsi.id IN (SELECT rr.id FROM Resource rr WHERE
rr.parentResource.parentResource.parentResource.parentResource.id = :resourceId) "
+ + " OR rsi.id IN (SELECT rr.id FROM Resource rr WHERE
rr.parentResource.parentResource.parentResource.parentResource.parentResource.id =
:resourceId) "
+ + " ") })
@Table(name = "RHQ_RESOURCE")
-public class ResourceSyncInfo extends SyncInfo implements Serializable {
+public class ResourceSyncInfo implements Serializable {
private static final long serialVersionUID = 1L;
- @Column(name = "PARENT_RESOURCE_ID")
- private Integer parentId;
-
- @OneToMany(mappedBy = "parentId", fetch = FetchType.EAGER)
- private Collection<ResourceSyncInfo> childSyncInfos;
+ /** Sync info for platform service children (for building up hierarchy that excludes
the top level servers */
+ public static final String QUERY_SERVICE_CHILDREN =
"ResourceSyncInfo.platformServiceChildren";
+ /** Sync info rooted at the specified top level server and including all of it's
hierarchy (up to 5 levels below
+ * the top level server. note that we support up to 6 levels below platform but we
are starting one level down) */
+ public static final String QUERY_TOP_LEVEL_SERVER =
"ResourceSyncInfo.topLevelServer";
+
+ /**
+ * Server-assigned id
+ */
+ @Column(name = "ID", nullable = false)
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private int id;
+
+ /**
+ * Agent-assigned uuid
+ */
+ @Column(name = "UUID")
+ private String uuid;
+
+ /**
+ * Last modified time
+ */
+ @Column(name = "MTIME")
+ private long mtime;
+
+ @Column(name = "INVENTORY_STATUS")
+ @Enumerated(EnumType.STRING)
+ private InventoryStatus inventoryStatus;
// JPA requires public or protected no-param constructor; Externalizable requires
public no-param constructor.
public ResourceSyncInfo() {
}
- public Collection<ResourceSyncInfo> getChildSyncInfos() {
- return childSyncInfos;
+ public int getId() {
+ return id;
}
- // for testing
- public static ResourceSyncInfo buildResourceSyncInfo(Resource resource) {
- Collection<ResourceSyncInfo> children;
-
- if (resource.getChildResources() != null) {
- children = new
HashSet<ResourceSyncInfo>(resource.getChildResources().size());
- for (Resource child : resource.getChildResources()) {
- children.add(buildResourceSyncInfo(child));
- }
- } else {
- children = new HashSet<ResourceSyncInfo>(0);
- }
-
- return buildResourceSyncInfo(resource, children);
+ public String getUuid() {
+ return uuid;
}
- // for testing
- public static ResourceSyncInfo buildResourceSyncInfo(Resource resource,
Collection<ResourceSyncInfo> children) {
-
- ResourceSyncInfo syncInfo = new ResourceSyncInfo(resource.getId(),
resource.getUuid(), resource.getMtime(),
- resource.getInventoryStatus(), children);
-
- return syncInfo;
+ public long getMtime() {
+ return mtime;
}
-
- public static ResourceSyncInfo buildResourceSyncInfo(SyncInfo syncInfo) {
-
- return buildResourceSyncInfo(syncInfo, ((Collection<ResourceSyncInfo>)
null));
+ public InventoryStatus getInventoryStatus() {
+ return inventoryStatus;
}
- public static ResourceSyncInfo buildResourceSyncInfo(SyncInfo syncInfo,
Collection<ResourceSyncInfo> children) {
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((uuid == null) ? 0 : uuid.hashCode());
+ return result;
+ }
- ResourceSyncInfo resourceSyncInfo = new ResourceSyncInfo(syncInfo.getId(),
syncInfo.getUuid(),
- syncInfo.getMtime(), syncInfo.getInventoryStatus(), children);
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ ResourceSyncInfo other = (ResourceSyncInfo) obj;
+ if (uuid == null) {
+ if (other.uuid != null)
+ return false;
+ } else if (!uuid.equals(other.uuid))
+ return false;
+ return true;
+ }
- return resourceSyncInfo;
+ protected ResourceSyncInfo(int id, String uuid, long mtime, InventoryStatus istatus)
{
+ this.id = id;
+ this.uuid = uuid;
+ this.mtime = mtime;
+ this.inventoryStatus = istatus;
}
- private ResourceSyncInfo(int id, String uuid, long mtime, InventoryStatus istatus,
- Collection<ResourceSyncInfo> children) {
- super(id, uuid, mtime, istatus);
- this.childSyncInfos = children;
+ static public ResourceSyncInfo buildResourceSyncInfo(Resource res) {
+ return new ResourceSyncInfo(res.getId(), res.getUuid(), res.getMtime(),
res.getInventoryStatus());
}
}
diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/discovery/SyncInfo.java
b/modules/core/domain/src/main/java/org/rhq/core/domain/discovery/SyncInfo.java
deleted file mode 100644
index 370d84f..0000000
--- a/modules/core/domain/src/main/java/org/rhq/core/domain/discovery/SyncInfo.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2013 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, version 2, as
- * published by the Free Software Foundation, and/or the GNU Lesser
- * General Public License, version 2.1, also 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 and the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License
- * and the GNU Lesser General Public License along with this program;
- * if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.rhq.core.domain.discovery;
-
-import java.io.Serializable;
-
-import javax.persistence.Column;
-import javax.persistence.EnumType;
-import javax.persistence.Enumerated;
-import javax.persistence.GeneratedValue;
-import javax.persistence.GenerationType;
-import javax.persistence.Id;
-import javax.persistence.MappedSuperclass;
-
-import org.rhq.core.domain.resource.InventoryStatus;
-
-/**
- * This is the abstract base class for SyncInfo, which may be for a platform or a [top
level server] resource.
- *
- * @author Ian Springer
- * @author Jay Shaughnessy
- */
-@MappedSuperclass
-public abstract class SyncInfo implements Serializable {
- private static final long serialVersionUID = 1L;
-
- /**
- * Server-assigned id
- */
- @Column(name = "ID", nullable = false)
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- private int id;
-
- /**
- * Agent-assigned uuid
- */
- @Column(name = "UUID")
- private String uuid;
-
- /**
- * Last modified time
- */
- @Column(name = "MTIME")
- private long mtime;
-
- @Column(name = "INVENTORY_STATUS")
- @Enumerated(EnumType.STRING)
- private InventoryStatus inventoryStatus;
-
- // JPA requires public or protected no-param constructor; Externalizable requires
public no-param constructor.
- public SyncInfo() {
- }
-
- public int getId() {
- return id;
- }
-
- public String getUuid() {
- return uuid;
- }
-
- public long getMtime() {
- return mtime;
- }
-
- public InventoryStatus getInventoryStatus() {
- return inventoryStatus;
- }
-
- protected SyncInfo(int id, String uuid, long mtime, InventoryStatus istatus) {
- this.id = id;
- this.uuid = uuid;
- this.mtime = mtime;
- this.inventoryStatus = istatus;
- }
-
-}
diff --git
a/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/AbstractIgnoreTypesInventoryManagerBaseTest.java
b/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/AbstractIgnoreTypesInventoryManagerBaseTest.java
index 4591dfc..cb799de 100644
---
a/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/AbstractIgnoreTypesInventoryManagerBaseTest.java
+++
b/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/AbstractIgnoreTypesInventoryManagerBaseTest.java
@@ -22,8 +22,10 @@ import static org.mockito.Matchers.any;
import static org.mockito.Mockito.when;
import java.io.File;
+import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -217,17 +219,43 @@ public abstract class AbstractIgnoreTypesInventoryManagerBaseTest
extends Arquil
return;
}
- protected Answer<ResourceSyncInfo> getResourceSyncInfo() {
- return new Answer<ResourceSyncInfo>() {
+ protected Answer<Collection<ResourceSyncInfo>> getResourceSyncInfo() {
+ return new Answer<Collection<ResourceSyncInfo>>() {
@Override
- public ResourceSyncInfo answer(InvocationOnMock invocation) throws Throwable
{
+ public Collection<ResourceSyncInfo> answer(InvocationOnMock invocation)
throws Throwable {
Integer resourceId = (Integer) invocation.getArguments()[0];
- ResourceSyncInfo result =
ResourceSyncInfo.buildResourceSyncInfo(simulatedInventory.get(resourceId));
+ Collection<ResourceSyncInfo> result =
convert(simulatedInventory.get(resourceId));
return result;
}
};
}
+ private static Collection<ResourceSyncInfo> convert(Resource root) {
+ Set<ResourceSyncInfo> result = new HashSet<ResourceSyncInfo>();
+ convertInternal(root, result);
+ return result;
+ }
+
+ private static void convertInternal(Resource root, Collection<ResourceSyncInfo>
result) {
+
+ ResourceSyncInfo rootSyncInfo = ResourceSyncInfo.buildResourceSyncInfo(root);
+
+ if (result.contains(rootSyncInfo)) {
+ return;
+ }
+ try {
+ result.add(rootSyncInfo);
+
+ for (Resource child : root.getChildResources()) {
+ convertInternal(child, result);
+ }
+
+ } catch (Exception e) {
+ throw new IllegalStateException("Failed to convert resource " +
root
+ + " to a ResourceSyncInfo. This should not happen.", e);
+ }
+ }
+
protected void validateFullInventory() {
System.out.println("Validating full inventory...");
diff --git
a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/StandaloneContainer.java
b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/StandaloneContainer.java
index 33cf21a..849541d 100644
---
a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/StandaloneContainer.java
+++
b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/StandaloneContainer.java
@@ -25,6 +25,7 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
@@ -903,7 +904,7 @@ public class StandaloneContainer {
}
@Override
- public ResourceSyncInfo getResourceSyncInfo(int resourceId) {
+ public Collection<ResourceSyncInfo> getResourceSyncInfo(int resourceId) {
return null;
}
diff --git
a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/drift/sync/RuntimeSynchronizer.java
b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/drift/sync/RuntimeSynchronizer.java
index 679db62..1708072 100644
---
a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/drift/sync/RuntimeSynchronizer.java
+++
b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/drift/sync/RuntimeSynchronizer.java
@@ -45,7 +45,7 @@ import org.rhq.core.pc.drift.ScheduleQueue;
* <br/><br/>
* Note that inventory sync happens regularly after the plugin container is initialized.
* Discovery scans are performed at fixed intervals. The results of a discovery scan are
- * reported to the server, and the server sends back {@link
org.rhq.core.domain.discovery.ResourceSyncInfo resource sync info}
+ * reported to the server, and the server sends back {@link
org.rhq.core.domain.discovery.OldResourceSyncInfo resource sync info}
* which is then used to sync with the local inventory.
*/
class RuntimeSynchronizer implements DriftSynchronizer {
diff --git
a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/inventory/InventoryManager.java
b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/inventory/InventoryManager.java
index b809f6f..24dcb44 100644
---
a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/inventory/InventoryManager.java
+++
b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/inventory/InventoryManager.java
@@ -228,6 +228,7 @@ public class InventoryManager extends AgentService implements
ContainerService,
/**
* @see ContainerService#initialize()
*/
+ @Override
public void initialize() {
inventoryLock.writeLock().lock();
@@ -290,6 +291,7 @@ public class InventoryManager extends AgentService implements
ContainerService,
/**
* @see ContainerService#shutdown()
*/
+ @Override
public void shutdown() {
PluginContainer pluginContainer = PluginContainer.getInstance();
pluginContainer.shutdownExecutorService(this.inventoryThreadPoolExecutor, true);
@@ -626,10 +628,12 @@ public class InventoryManager extends AgentService implements
ContainerService,
}
}
+ @Override
public void setConfiguration(PluginContainerConfiguration configuration) {
this.configuration = configuration;
}
+ @Override
public void updatePluginConfiguration(int resourceId, Configuration
newPluginConfiguration)
throws InvalidPluginConfigurationClientException, PluginContainerException {
ResourceContainer container = getResourceContainer(resourceId);
@@ -673,11 +677,13 @@ public class InventoryManager extends AgentService implements
ContainerService,
}
}
+ @Override
@NotNull
public InventoryReport executeServerScanImmediately() {
return submit(serverScanExecutor);
}
+ @Override
@NotNull
public InventoryReport executeServiceScanImmediately() {
return submit(serviceScanExecutor);
@@ -689,6 +695,7 @@ public class InventoryManager extends AgentService implements
ContainerService,
return submit(discoveryExecutor);
}
+ @Override
public void executeServiceScanDeferred() {
inventoryThreadPoolExecutor.submit((Callable<InventoryReport>)
this.serviceScanExecutor);
}
@@ -705,6 +712,7 @@ public class InventoryManager extends AgentService implements
ContainerService,
* @param changedOnlyReport
* @return The report, for inspection
*/
+ @Override
public AvailabilityReport executeAvailabilityScanImmediately(boolean
changedOnlyReport) {
return executeAvailabilityScanImmediately(changedOnlyReport, false);
}
@@ -745,6 +753,7 @@ public class InventoryManager extends AgentService implements
ContainerService,
}
}
+ @Override
@NotNull
public AvailabilityReport getCurrentAvailability(Resource resource, boolean
changesOnly) {
try {
@@ -790,6 +799,7 @@ public class InventoryManager extends AgentService implements
ContainerService,
configuration.getServerServices().getDiscoveryServerService().setResourceEnablement(resourceId,
setEnabled);
}
+ @Override
public MergeResourceResponse manuallyAddResource(ResourceType resourceType, int
parentResourceId,
Configuration pluginConfiguration, int ownerSubjectId) throws
InvalidPluginConfigurationClientException,
PluginContainerException {
@@ -1202,36 +1212,45 @@ public class InventoryManager extends AgentService implements
ContainerService,
/**
* Performs a full platform sync so that resources passed in are reflected in the
agent's inventory.
*
- * @param platformSyncInfo sync info on the platform and references to the top level
servers
+ * @param platformSyncInfo sync info on the platform and references to the top level
servers. not null.
*/
private void syncPlatform(PlatformSyncInfo platformSyncInfo) {
final Set<String> allServerSideUuids = new HashSet<String>();
boolean hadSyncedResources = false;
+ ResourceSyncInfo platformResourceSyncInfo = platformSyncInfo.getPlatform();
- // always sync the platform because it does not get included in the top level
server sync
- allServerSideUuids.add(platformSyncInfo.getUuid());
- ResourceSyncInfo platformResourceSyncInfo =
ResourceSyncInfo.buildResourceSyncInfo(platformSyncInfo);
- log.info("Sync Starting: Platform [" + platformResourceSyncInfo.getId()
+ "]");
- hadSyncedResources = syncResource(platformResourceSyncInfo) ||
hadSyncedResources;
- log.info("Sync Complete: Platform [" + platformResourceSyncInfo.getId()
+ "]. Local inventory changed: ["
+ // sync the platform because it does not get included in the top level server
sync
+ allServerSideUuids.add(platformResourceSyncInfo.getUuid());
+ // sync the top level service hierarchy
+ addAllUuids(platformSyncInfo.getServices(), allServerSideUuids);
+
+ // Add the platform sync info to the service hierarchy in order to process in one
batch
+ Collection<ResourceSyncInfo> syncInfos = platformSyncInfo.getServices();
+ syncInfos.add(platformResourceSyncInfo);
+
+ log.info("Sync Starting: Platform [" +
platformSyncInfo.getPlatform().getId() + "] and top level services.");
+ hadSyncedResources = syncResources(platformResourceSyncInfo.getId(), syncInfos)
|| hadSyncedResources;
+ log.info("Sync Complete: Platform [" +
platformSyncInfo.getPlatform().getId() + "]. Local inventory changed: ["
+ hadSyncedResources + "]");
+ syncInfos = null; // release to GC
+
// then sync the top level servers by calling back to the server for the sync
info for each. We
// do this one at a time to avoid forcing the whole inventory into active memory
at one time during the sync.
- Collection<Resource> topLevelServers =
platformSyncInfo.getTopLevelServers();
- if (null != topLevelServers) {
+ Collection<Integer> topLevelServerIds =
platformSyncInfo.getTopLevelServerIds();
+ if (null != topLevelServerIds) {
DiscoveryServerService service =
configuration.getServerServices().getDiscoveryServerService();
- for (Resource topLevelServer : topLevelServers) {
- ResourceSyncInfo topLevelServerSyncInfo =
service.getResourceSyncInfo(topLevelServer.getId());
- if (null != topLevelServerSyncInfo) {
- //topLevelServerSyncInfo =
ResourceSyncInfo.buildResourceSyncInfo(platformSyncInfo,
- // topLevelServerSyncInfo);
- getAllUuids(topLevelServerSyncInfo, allServerSideUuids);
- log.info("Sync Starting: Top Level Server [" +
topLevelServerSyncInfo.getId() + "]");
- hadSyncedResources = syncResource(topLevelServerSyncInfo) ||
hadSyncedResources;
- log.info("Sync Complete: Top Level Server [" +
topLevelServerSyncInfo.getId()
- + "] Local inventory changed: [" + hadSyncedResources +
"]");
+ for (Integer topLevelServerId : topLevelServerIds) {
+ syncInfos = service.getResourceSyncInfo(topLevelServerId);
+ if (null != syncInfos) {
+ addAllUuids(syncInfos, allServerSideUuids);
+ log.info("Sync Starting: Top Level Server [" +
topLevelServerId + "]");
+ hadSyncedResources = syncResources(topLevelServerId, syncInfos) ||
hadSyncedResources;
+ log.info("Sync Complete: Top Level Server [" +
topLevelServerId + "] Local inventory changed: ["
+ + hadSyncedResources + "]");
+
+ syncInfos = null; // release to GC
}
}
}
@@ -1261,13 +1280,9 @@ public class InventoryManager extends AgentService implements
ContainerService,
}
}
- private void getAllUuids(ResourceSyncInfo syncInfo, Set<String>
allServerSideUuids) {
- allServerSideUuids.add(syncInfo.getUuid());
-
- if (null != syncInfo.getChildSyncInfos()) {
- for (ResourceSyncInfo child : syncInfo.getChildSyncInfos()) {
- getAllUuids(child, allServerSideUuids);
- }
+ private void addAllUuids(Collection<ResourceSyncInfo> syncInfos,
Set<String> allServerSideUuids) {
+ for (ResourceSyncInfo syncInfo : syncInfos) {
+ allServerSideUuids.add(syncInfo.getUuid());
}
}
@@ -1278,7 +1293,7 @@ public class InventoryManager extends AgentService implements
ContainerService,
* @param syncInfo the resources' sync data
* @return true if any resources needed synchronization, false otherwise
*/
- private boolean syncResource(ResourceSyncInfo syncInfo) {
+ private boolean syncResources(int rootResourceId, Collection<ResourceSyncInfo>
syncInfos) {
boolean result = false;
final long startTime = System.currentTimeMillis();
final Set<Resource> syncedResources = new LinkedHashSet<Resource>();
@@ -1292,7 +1307,7 @@ public class InventoryManager extends AgentService implements
ContainerService,
try {
log.debug("Processing Server sync info...");
- processSyncInfo(syncInfo, syncedResources, unknownResourceSyncInfos,
modifiedResourceIds,
+ processSyncInfo(syncInfos, syncedResources, unknownResourceSyncInfos,
modifiedResourceIds,
deletedResourceIds, newlyCommittedResources, ignoredResources);
if (log.isDebugEnabled()) {
@@ -1318,7 +1333,7 @@ public class InventoryManager extends AgentService implements
ContainerService,
result = !(syncedResources.isEmpty() &&
unknownResourceSyncInfos.isEmpty() && modifiedResourceIds.isEmpty());
} catch (Throwable t) {
- log.warn("Failed to synchronize local inventory with Server inventory
for Resource [" + syncInfo.getId()
+ log.warn("Failed to synchronize local inventory with Server inventory
for Resource [" + rootResourceId
+ "] and its descendants: " + t.getMessage());
// convert to runtime exception so as not to change the api
throw new RuntimeException(t);
@@ -1327,13 +1342,19 @@ public class InventoryManager extends AgentService implements
ContainerService,
return result;
}
- public void synchronizeInventory(ResourceSyncInfo resourceSyncInfo) {
- log.info("Synchronizing local inventory with Server inventory for Resource
[" + resourceSyncInfo.getId()
- + "] and its descendants...");
+ @Override
+ public void synchronizePlatform(PlatformSyncInfo syncInfo) {
+ syncPlatform(syncInfo);
+ performServiceScan(syncInfo.getPlatform().getId()); // NOTE: This will block (the
initial scan blocks).
+ // TODO: (jshaughn) should we also request a full avail scan?
+ }
- // Get the latest resource data rooted at the given id.
- syncResource(resourceSyncInfo); // this method assumes we only get a single
resource and its children (BZ 887411)
- performServiceScan(resourceSyncInfo.getId()); // NOTE: This will block (the
initial scan blocks).
+ @Override
+ public void synchronizeServer(int resourceId, Collection<ResourceSyncInfo>
topLevelServerSyncInfo) {
+ log.info("Synchronizing local inventory with Server inventory for Resource
[" + resourceId
+ + "] and its descendants...");
+ syncResources(resourceId, topLevelServerSyncInfo);
+ performServiceScan(resourceId); // NOTE: This will block (the initial scan
blocks).
// TODO: (jshaughn) should we also request a full avail scan?
}
@@ -1397,6 +1418,7 @@ public class InventoryManager extends AgentService implements
ContainerService,
return resourceContainer.getResourceComponent();
}
+ @Override
public void uninventoryResource(int resourceId) {
ResourceContainer resourceContainer = getResourceContainer(resourceId);
if (resourceContainer == null) {
@@ -1542,6 +1564,7 @@ public class InventoryManager extends AgentService implements
ContainerService,
return parentContainerResource.getChildResources();
}
+ @Override
public Resource getPlatform() {
return platform;
}
@@ -2541,6 +2564,7 @@ public class InventoryManager extends AgentService implements
ContainerService,
return mgr;
}
+ @Override
public void requestFullAvailabilityReport() {
if (null != availabilityExecutor) {
availabilityExecutor.sendFullReportNextTime();
@@ -2684,10 +2708,12 @@ public class InventoryManager extends AgentService implements
ContainerService,
}
}
+ @Override
public void enableServiceScans(int serverResourceId, Configuration config) {
throw new UnsupportedOperationException("not implemented yet"); //
TODO: Implement this method.
}
+ @Override
public void disableServiceScans(int serverResourceId) {
throw new UnsupportedOperationException("not implemented yet"); //
TODO: Implement this method.
}
@@ -2905,84 +2931,79 @@ public class InventoryManager extends AgentService implements
ContainerService,
return versionUpdated;
}
- private void processSyncInfo(ResourceSyncInfo syncInfo, Set<Resource>
syncedResources,
+ private void processSyncInfo(Collection<ResourceSyncInfo> syncInfos,
Set<Resource> syncedResources,
Set<ResourceSyncInfo> unknownResourceSyncInfos, Set<Integer>
modifiedResourceIds,
Set<Integer> deletedResourceIds, Set<Resource>
newlyCommittedResources, Set<Resource> ignoredResources) {
- if (InventoryStatus.DELETED == syncInfo.getInventoryStatus()) {
- // A previously deleted resource still being reported by the server. Support
for this option can
- // be removed if the server is ever modified to not report deleted resources.
It is happening currently
- // because deleted resources are kept to support resource history. The
deleted resources are rightfully not
- // in the PC inventory, and so must be handled separately, and not as unknown
resources.
- deletedResourceIds.add(syncInfo.getId());
- } else {
- ResourceContainer container = getResourceContainer(syncInfo.getUuid());
- if (container == null) {
- // Either a manually added Resource or just something we haven't
discovered.
- // If this unknown resource is to be ignored, then don't bother to do
anything.
- if (InventoryStatus.IGNORED != syncInfo.getInventoryStatus()) {
- unknownResourceSyncInfos.add(syncInfo);
- log.info("Got unknown resource: " + syncInfo.getId());
- } else {
- log.info("Got an unknown but ignored resource - ignoring it:
" + syncInfo.getId());
- }
+ for (ResourceSyncInfo syncInfo : syncInfos) {
+ if (InventoryStatus.DELETED == syncInfo.getInventoryStatus()) {
+ // A previously deleted resource still being reported by the server.
Support for this option can
+ // be removed if the server is ever modified to not report deleted
resources. It is happening currently
+ // because deleted resources are kept to support resource history. The
deleted resources are rightfully not
+ // in the PC inventory, and so must be handled separately, and not as
unknown resources.
+ deletedResourceIds.add(syncInfo.getId());
} else {
- Resource resource = container.getResource();
- // Ensure the Resource classloader is initialized on the Resource
container.
- initResourceContainer(resource);
-
- if (log.isDebugEnabled()) {
- log.debug("Local Resource: id=" + resource.getId() +
", status=" + resource.getInventoryStatus()
- + ", mtime=" + resource.getMtime());
- log.debug("Sync Resource: " + syncInfo.getId() + ",
status=" + syncInfo.getInventoryStatus()
- + ", mtime=" + syncInfo.getMtime());
- }
-
- final boolean ignoreResource = (InventoryStatus.IGNORED ==
syncInfo.getInventoryStatus());
- final boolean ignoreResourceType =
this.pluginManager.getMetadataManager()
- .isDisabledOrIgnoredResourceType(resource.getResourceType());
- if (ignoreResource || ignoreResourceType) {
- // a resource or its type has been tagged to be ignored - we need to
remove it from our inventory
- ignoredResources.add(resource);
+ ResourceContainer container = getResourceContainer(syncInfo.getUuid());
+ if (container == null) {
+ // Either a manually added Resource or just something we haven't
discovered.
+ // If this unknown resource is to be ignored, then don't bother
to do anything.
+ if (InventoryStatus.IGNORED != syncInfo.getInventoryStatus()) {
+ unknownResourceSyncInfos.add(syncInfo);
+ log.info("Got unknown resource: " + syncInfo.getId());
+ } else {
+ log.info("Got an unknown but ignored resource - ignoring it:
" + syncInfo.getId());
+ }
} else {
- if (resource.getInventoryStatus() != InventoryStatus.COMMITTED
- && syncInfo.getInventoryStatus() ==
InventoryStatus.COMMITTED) {
- newlyCommittedResources.add(resource);
+ Resource resource = container.getResource();
+ // Ensure the Resource classloader is initialized on the Resource
container.
+ initResourceContainer(resource);
+
+ if (log.isDebugEnabled()) {
+ log.debug("Local Resource: id=" + resource.getId() +
", status="
+ + resource.getInventoryStatus() + ", mtime=" +
resource.getMtime());
+ log.debug("Sync Resource: " + syncInfo.getId() +
", status=" + syncInfo.getInventoryStatus()
+ + ", mtime=" + syncInfo.getMtime());
}
- if (resource.getId() == 0) {
- // This must be a Resource we just reported to the server. Just
update its id, mtime, and status.
- resource.setId(syncInfo.getId());
- resource.setMtime(syncInfo.getMtime());
- resource.setInventoryStatus(syncInfo.getInventoryStatus());
- refreshResourceComponentState(container, true);
- syncedResources.add(resource);
+ final boolean ignoreResource = (InventoryStatus.IGNORED ==
syncInfo.getInventoryStatus());
+ final boolean ignoreResourceType =
this.pluginManager.getMetadataManager()
+ .isDisabledOrIgnoredResourceType(resource.getResourceType());
+ if (ignoreResource || ignoreResourceType) {
+ // a resource or its type has been tagged to be ignored - we need
to remove it from our inventory
+ ignoredResources.add(resource);
} else {
- // It's a resource that was already synced at least once.
- if (resource.getId() != syncInfo.getId()) {
- // This really should never happen, but check for it just to
be bulletproof.
- log.error("PC Resource id (" + resource.getId() +
") does not match Server Resource id ("
- + syncInfo.getId() + ") for Resource with uuid
" + resource.getUuid() + ": " + resource);
- modifiedResourceIds.add(syncInfo.getId());
+ if (resource.getInventoryStatus() != InventoryStatus.COMMITTED
+ && syncInfo.getInventoryStatus() ==
InventoryStatus.COMMITTED) {
+ newlyCommittedResources.add(resource);
}
- // See if it's been modified on the Server since the last
time we synced.
- else if (resource.getMtime() < syncInfo.getMtime()) {
- modifiedResourceIds.add(resource.getId());
+
+ if (resource.getId() == 0) {
+ // This must be a Resource we just reported to the server.
Just update its id, mtime, and status.
+ resource.setId(syncInfo.getId());
+ resource.setMtime(syncInfo.getMtime());
+ resource.setInventoryStatus(syncInfo.getInventoryStatus());
+ refreshResourceComponentState(container, true);
+ syncedResources.add(resource);
} else {
- // Only try to start up the component if the Resource has
*not* been modified on the Server.
- // Otherwise, hold off until we've synced the Resource
with the Server.
- refreshResourceComponentState(container, false);
+ // It's a resource that was already synced at least
once.
+ if (resource.getId() != syncInfo.getId()) {
+ // This really should never happen, but check for it just
to be bulletproof.
+ log.error("PC Resource id (" +
resource.getId()
+ + ") does not match Server Resource id (" +
syncInfo.getId()
+ + ") for Resource with uuid " +
resource.getUuid() + ": " + resource);
+ modifiedResourceIds.add(syncInfo.getId());
+ }
+ // See if it's been modified on the Server since the last
time we synced.
+ else if (resource.getMtime() < syncInfo.getMtime()) {
+ modifiedResourceIds.add(resource.getId());
+ } else {
+ // Only try to start up the component if the Resource has
*not* been modified on the Server.
+ // Otherwise, hold off until we've synced the
Resource with the Server.
+ refreshResourceComponentState(container, false);
+ }
}
}
}
-
- // Recurse...
- if (null != syncInfo.getChildSyncInfos()) {
- for (ResourceSyncInfo childSyncInfo : syncInfo.getChildSyncInfos())
{
- processSyncInfo(childSyncInfo, syncedResources,
unknownResourceSyncInfos, modifiedResourceIds,
- deletedResourceIds, newlyCommittedResources,
ignoredResources);
- }
- }
}
}
}
@@ -3037,46 +3058,20 @@ public class InventoryManager extends AgentService implements
ContainerService,
}
private Set<Resource> getResourcesFromSyncInfos(Set<ResourceSyncInfo>
syncInfos) {
-
- final StopWatch stopWatch = new StopWatch();
- final int syncInfosSize = syncInfos.size();
- final Set<Resource> result = new HashSet<Resource>(syncInfosSize);
-
- for (ResourceSyncInfo syncInfo : syncInfos) {
- Resource resource = getResourceFromSyncInfo(syncInfo);
- result.add(resource);
- }
-
- if (log.isDebugEnabled()) {
- log.debug("Time to build resource tree from [" + syncInfosSize +
"] sync infos=" + stopWatch.getElapsed());
- }
-
- return result;
- }
-
- private Resource getResourceFromSyncInfo(ResourceSyncInfo syncInfo) {
- final boolean isDebugEnabled = log.isDebugEnabled();
- final StopWatch stopWatch = new StopWatch();
- String marker = null;
-
/////
- // First we need to do a breadth first traversal of the sync info tree and build
a list of all resource IDs.
-
- if (isDebugEnabled) {
- marker = "a. Breadth-first retrieval of sync info tree";
- stopWatch.markTimeBegin(marker);
- }
-
- List<Integer> resourceIdList = treeToBreadthFirstList(syncInfo);
- int fullResourceTreeSize = resourceIdList.size();
- if (isDebugEnabled) {
- stopWatch.markTimeEnd(marker);
+ // First we need to get a list of the unknown resource ids
+ List<Integer> resourceIdList = new
ArrayList<Integer>(syncInfos.size());
+ for (ResourceSyncInfo syncInfo : syncInfos) {
+ resourceIdList.add(syncInfo.getId());
}
/////
// Now we need to loop over batches of the resource ID list - asking the server
for their resource representations.
// When we get the resources from the server, we put them in our resourceMap,
keyed on ID.
+ final boolean isDebugEnabled = log.isDebugEnabled();
+ final StopWatch stopWatch = new StopWatch();
+ String marker = null;
Map<Integer, Resource> resourceMap = new HashMap<Integer,
Resource>(resourceIdList.size());
int batchNumber = 0;
while (!resourceIdList.isEmpty()) {
@@ -3091,7 +3086,7 @@ public class InventoryManager extends AgentService implements
ContainerService,
// This usage of .clear() will remove the processed resources from the
backing list.
String markerPrefix = null;
if (isDebugEnabled) {
- markerPrefix = String.format("b. Batch [%03d] (%d): ",
batchNumber, fullResourceTreeSize);
+ markerPrefix = String.format("a. Batch [%03d] (%d): ",
batchNumber, syncInfos.size());
marker = String.format("%sGet resource ID sublist - %d of %d
remaining", markerPrefix, end, size);
stopWatch.markTimeBegin(marker);
}
@@ -3136,61 +3131,39 @@ public class InventoryManager extends AgentService implements
ContainerService,
}
}
- if (fullResourceTreeSize != resourceMap.size()) {
- log.warn("Expected [" + fullResourceTreeSize + "] but found
[" + resourceMap.size()
+ if (syncInfos.size() != resourceMap.size()) {
+ log.warn("Expected [" + syncInfos.size() + "] but found
[" + resourceMap.size()
+ "] resources when fetching from server");
}
/////
// We now have all the resources associated with all sync infos in a map.
- // We need to build the full resource tree using the sync info as the blueprint
for how to order the resources in a tree.
+ // We need to build the full resource tree using the resource parent info as the
blueprint for how to
+ // link the resources in the tree.
if (isDebugEnabled) {
- marker = "c. Build the full resource tree";
+ marker = "b. Build the resource hierarchies";
stopWatch.markTimeBegin(marker);
}
- Resource result = syncInfoTreeToResourceTree(syncInfo, resourceMap);
- resourceMap.clear();
-
- if (isDebugEnabled) {
- stopWatch.markTimeEnd(marker);
-
- log.debug("Full resource tree built from sync info - performance: "
+ stopWatch);
- }
-
- return result;
- }
-
- private Resource syncInfoTreeToResourceTree(ResourceSyncInfo syncInfo,
Map<Integer, Resource> resourceMap) {
- Resource result = resourceMap.get(syncInfo.getId());
-
- if (null == result || null == syncInfo.getChildSyncInfos()) {
- return result;
- }
-
- for (ResourceSyncInfo child : syncInfo.getChildSyncInfos()) {
- Resource childResource = syncInfoTreeToResourceTree(child, resourceMap);
- if (null != childResource) {
- result.addChildResource(childResource);
+ // The root resources to be merged (i.e. the resources whose parents are not in
the map)
+ Set<Resource> result = new HashSet<Resource>();
+ for (Resource resource : resourceMap.values()) {
+ if (null == resource.getParentResource()) {
+ result.add(resource); // the platform, make sure we have this
+ continue;
+ }
+ Resource parent = resourceMap.get(resource.getParentResource().getId());
+ if (null != parent) {
+ parent.addChildResource(resource);
+ } else {
+ result.add(resource);
}
}
- return result;
- }
-
- private List<Integer> treeToBreadthFirstList(ResourceSyncInfo syncInfo) {
- List<Integer> result = new ArrayList<Integer>();
+ if (isDebugEnabled) {
+ stopWatch.markTimeEnd(marker);
- LinkedList<ResourceSyncInfo> queue = new
LinkedList<ResourceSyncInfo>();
- queue.add(syncInfo);
- while (!queue.isEmpty()) {
- ResourceSyncInfo node = queue.remove();
- result.add(node.getId());
- if (null != node.getChildSyncInfos()) {
- for (ResourceSyncInfo child : node.getChildSyncInfos()) {
- queue.add(child);
- }
- }
+ log.debug("Resource trees built from map - performance: " +
stopWatch);
}
return result;
@@ -3500,6 +3473,7 @@ public class InventoryManager extends AgentService implements
ContainerService,
*/
class ResourceGotActivatedListener implements InventoryEventListener {
+ @Override
public void resourceActivated(Resource resource) {
if (resource != null && resource.getId() > 0) {
if (log.isDebugEnabled()) {
@@ -3514,14 +3488,17 @@ public class InventoryManager extends AgentService implements
ContainerService,
removeInventoryEventListener(this);
}
+ @Override
public void resourceDeactivated(Resource resource) {
// nothing to do
}
+ @Override
public void resourcesAdded(Set<Resource> resources) {
// nothing to do
}
+ @Override
public void resourcesRemoved(Set<Resource> resources) {
// nothing to do
}
diff --git
a/modules/core/plugin-container/src/test/java/org/rhq/core/pc/upgrade/AbstractResourceUpgradeHandlingTest.java
b/modules/core/plugin-container/src/test/java/org/rhq/core/pc/upgrade/AbstractResourceUpgradeHandlingTest.java
index cfa6fa7..e9a3c05 100644
---
a/modules/core/plugin-container/src/test/java/org/rhq/core/pc/upgrade/AbstractResourceUpgradeHandlingTest.java
+++
b/modules/core/plugin-container/src/test/java/org/rhq/core/pc/upgrade/AbstractResourceUpgradeHandlingTest.java
@@ -56,6 +56,10 @@ public abstract class AbstractResourceUpgradeHandlingTest extends
ResourceUpgrad
expectations.with(Expectations.any(InventoryReport.class)));
expectations.will(inventory.mergeInventoryReport(InventoryStatus.COMMITTED));
+ expectations.allowing(ss.getDiscoveryServerService()).getResourceSyncInfo(
+ expectations.with(Expectations.any(Integer.class)));
+ expectations.will(inventory.getResourceSyncInfo());
+
expectations.allowing(ss.getDiscoveryServerService()).upgradeResources(
expectations.with(Expectations.any(Set.class)));
expectations.will(inventory.upgradeResources());
diff --git
a/modules/core/plugin-container/src/test/java/org/rhq/core/pc/upgrade/FakeServerInventory.java
b/modules/core/plugin-container/src/test/java/org/rhq/core/pc/upgrade/FakeServerInventory.java
index 5a18d65..2bcb7aa 100644
---
a/modules/core/plugin-container/src/test/java/org/rhq/core/pc/upgrade/FakeServerInventory.java
+++
b/modules/core/plugin-container/src/test/java/org/rhq/core/pc/upgrade/FakeServerInventory.java
@@ -19,7 +19,6 @@
package org.rhq.core.pc.upgrade;
-import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -132,12 +131,12 @@ public class FakeServerInventory {
throwIfFailing();
Integer resourceId = (Integer) invocation.getParameter(0);
-
- for (Resource c : platform.getChildResources()) {
- if (c.getId() == resourceId) {
- return getResourceSyncInfo(c);
+ for (Resource r : resourceStore.values()) {
+ if (resourceId.equals(r.getId())) {
+ return convert(r);
}
}
+
return null;
}
}
@@ -422,37 +421,29 @@ public class FakeServerInventory {
return platform == null ? null :
PlatformSyncInfo.buildPlatformSyncInfo(platform);
}
- private ResourceSyncInfo getResourceSyncInfo(Resource resource) {
+ private Collection<ResourceSyncInfo> getResourceSyncInfo(Resource resource) {
return resource == null ? null : convert(resource);
}
- private static ResourceSyncInfo convert(Resource root) {
- return convertInternal(root, true, new HashMap<String,
ResourceSyncInfo>());
+ private static Collection<ResourceSyncInfo> convert(Resource root) {
+ Set<ResourceSyncInfo> result = new HashSet<ResourceSyncInfo>();
+ convertInternal(root, result);
+ return result;
}
- private static ResourceSyncInfo convertInternal(Resource root, boolean
isTopLevelServer,
- Map<String, ResourceSyncInfo> intermediateResults) {
+ private static void convertInternal(Resource root, Collection<ResourceSyncInfo>
result) {
- ResourceSyncInfo ret = intermediateResults.get(root.getUuid());
+ ResourceSyncInfo rootSyncInfo = ResourceSyncInfo.buildResourceSyncInfo(root);
- if (ret != null) {
- return ret;
+ if (result.contains(rootSyncInfo)) {
+ return;
}
try {
- ret = ResourceSyncInfo.buildResourceSyncInfo(root);
- intermediateResults.put(root.getUuid(), ret);
-
- Integer parentId = root.getParentResource() == null ? null :
root.getParentResource().getId();
- getPrivateField(ResourceSyncInfo.class, "parentId").set(ret,
parentId);
+ result.add(rootSyncInfo);
- Set<ResourceSyncInfo> children = new
LinkedHashSet<ResourceSyncInfo>();
for (Resource child : root.getChildResources()) {
- ResourceSyncInfo syncChild = convertInternal(child, false,
intermediateResults);
-
- children.add(syncChild);
+ convertInternal(child, result);
}
- getPrivateField(ResourceSyncInfo.class, "childSyncInfos").set(ret,
children);
- return ret;
} catch (Exception e) {
throw new IllegalStateException("Failed to convert resource " +
root
@@ -460,15 +451,6 @@ public class FakeServerInventory {
}
}
- private static Field getPrivateField(Class<?> clazz, String fieldName) throws
NoSuchFieldException {
- Field field = clazz.getDeclaredField(fieldName);
- if (!field.isAccessible()) {
- field.setAccessible(true);
- }
-
- return field;
- }
-
private static Resource findResource(Resource root, Resource template,
Comparator<Resource> comparator) {
if (root == null)
return null;
diff --git
a/modules/core/plugin-container/src/test/java/org/rhq/core/pc/upgrade/ResourceUpgradeTest.java
b/modules/core/plugin-container/src/test/java/org/rhq/core/pc/upgrade/ResourceUpgradeTest.java
index 176f0a4..5572adf 100644
---
a/modules/core/plugin-container/src/test/java/org/rhq/core/pc/upgrade/ResourceUpgradeTest.java
+++
b/modules/core/plugin-container/src/test/java/org/rhq/core/pc/upgrade/ResourceUpgradeTest.java
@@ -42,7 +42,7 @@ import org.rhq.test.pc.PluginContainerSetup;
import org.rhq.test.pc.PluginContainerTest;
/**
- *
+ *
*
* @author Lukas Krejci
*/
@@ -91,6 +91,9 @@ public class ResourceUpgradeTest extends ResourceUpgradeTestBase {
allowing(ss.getDiscoveryServerService()).mergeInventoryReport(with(any(InventoryReport.class)));
will(inv.mergeInventoryReport(InventoryStatus.COMMITTED));
+
allowing(ss.getDiscoveryServerService()).getResourceSyncInfo(with(any(Integer.class)));
+ will(inv.getResourceSyncInfo());
+
oneOf(ss.getDiscoveryServerService()).upgradeResources(with(any(Set.class)));
will(inv.upgradeResources());
}
@@ -159,6 +162,9 @@ public class ResourceUpgradeTest extends ResourceUpgradeTestBase {
allowing(ss.getDiscoveryServerService()).mergeInventoryReport(with(any(InventoryReport.class)));
will(inv.mergeInventoryReport(InventoryStatus.COMMITTED));
+
allowing(ss.getDiscoveryServerService()).getResourceSyncInfo(with(any(Integer.class)));
+ will(inv.getResourceSyncInfo());
+
never(ss.getDiscoveryServerService()).upgradeResources(with(any(Set.class)));
}
});
@@ -208,6 +214,9 @@ public class ResourceUpgradeTest extends ResourceUpgradeTestBase {
allowing(ss.getDiscoveryServerService()).mergeInventoryReport(with(any(InventoryReport.class)));
will(inv.mergeInventoryReport(InventoryStatus.COMMITTED));
+
allowing(ss.getDiscoveryServerService()).getResourceSyncInfo(with(any(Integer.class)));
+ will(inv.getResourceSyncInfo());
+
never(ss.getDiscoveryServerService()).upgradeResources(with(any(Set.class)));
}
});
@@ -258,6 +267,9 @@ public class ResourceUpgradeTest extends ResourceUpgradeTestBase {
allowing(ss.getDiscoveryServerService()).mergeInventoryReport(with(any(InventoryReport.class)));
will(inv.mergeInventoryReport(InventoryStatus.COMMITTED));
+
allowing(ss.getDiscoveryServerService()).getResourceSyncInfo(with(any(Integer.class)));
+ will(inv.getResourceSyncInfo());
+
oneOf(ss.getDiscoveryServerService()).upgradeResources(with(any(Set.class)));
will(inv.upgradeResources());
}
@@ -297,6 +309,9 @@ public class ResourceUpgradeTest extends ResourceUpgradeTestBase {
allowing(ss.getDiscoveryServerService()).mergeInventoryReport(with(any(InventoryReport.class)));
will(inv.mergeInventoryReport(requiredInventoryStatus));
+
+
allowing(ss.getDiscoveryServerService()).getResourceSyncInfo(with(any(Integer.class)));
+ will(inv.getResourceSyncInfo());
}
});
@@ -334,6 +349,9 @@ public class ResourceUpgradeTest extends ResourceUpgradeTestBase {
allowing(ss.getDiscoveryServerService()).mergeInventoryReport(with(any(InventoryReport.class)));
will(serverInventory.mergeInventoryReport(InventoryStatus.COMMITTED));
+
allowing(ss.getDiscoveryServerService()).getResourceSyncInfo(with(any(Integer.class)));
+ will(serverInventory.getResourceSyncInfo());
+
oneOf(ss.getDiscoveryServerService()).upgradeResources(with(any(Set.class)));
will(serverInventory.upgradeResources());
}
diff --git
a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBeanTest.java
b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBeanTest.java
index 35fa7f1..4de1380 100644
---
a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBeanTest.java
+++
b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBeanTest.java
@@ -20,6 +20,7 @@ package org.rhq.enterprise.server.configuration;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -35,7 +36,6 @@ import org.rhq.core.clientapi.agent.discovery.DiscoveryAgentService;
import org.rhq.core.clientapi.agent.discovery.InvalidPluginConfigurationClientException;
import org.rhq.core.clientapi.server.configuration.ConfigurationUpdateResponse;
import org.rhq.core.clientapi.server.discovery.InventoryReport;
-import org.rhq.core.communications.command.annotation.Asynchronous;
import org.rhq.core.domain.auth.Subject;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.ConfigurationUpdateStatus;
@@ -50,8 +50,8 @@ import
org.rhq.core.domain.configuration.group.GroupPluginConfigurationUpdate;
import org.rhq.core.domain.criteria.ResourceConfigurationUpdateCriteria;
import org.rhq.core.domain.discovery.AvailabilityReport;
import org.rhq.core.domain.discovery.MergeResourceResponse;
+import org.rhq.core.domain.discovery.PlatformSyncInfo;
import org.rhq.core.domain.discovery.ResourceSyncInfo;
-import org.rhq.core.domain.measurement.Availability;
import org.rhq.core.domain.resource.Agent;
import org.rhq.core.domain.resource.Resource;
import org.rhq.core.domain.resource.ResourceType;
@@ -227,7 +227,7 @@ public class ConfigurationManagerBeanTest extends AbstractEJB3Test {
inProgress =
configurationManager.isResourceConfigurationUpdateInProgress(overlord, resourceId);
if (inProgress) {
- // history2 should be history1 since the update is not complete
+ // history2 should be history1 since the update is not complete
assert history2 != null;
assert history2.getId() == history1.getId();
myprop = history2.getConfiguration().getSimple("myboolean");
@@ -235,7 +235,7 @@ public class ConfigurationManagerBeanTest extends AbstractEJB3Test {
assert "true".equals(myprop.getStringValue());
myprop = history2.getConfiguration().getSimple("mysleep"); //
this wasn't in the first config
assert myprop == null;
- // record that this test case ran, we expect it will if the agent delay
is there
+ // record that this test case ran, we expect it will if the agent delay
is there
inProgressTested = true;
} else {
// update is complete, history 2 should be different
@@ -284,7 +284,7 @@ public class ConfigurationManagerBeanTest extends AbstractEJB3Test {
assert "true".equals(myprop.getStringValue());
// now update to config2 - the "agent" will sleep for a bit before it
completes
- // so we will have an INPROGRESS configuration for a few seconds before it goes
to SUCCESS
+ // so we will have an INPROGRESS configuration for a few seconds before it goes
to SUCCESS
configurationManager.updateResourceConfiguration(overlord, resourceId,
configuration2);
// now update to config3 - this should fail as you can't update while there
is one in progress
@@ -306,7 +306,7 @@ public class ConfigurationManagerBeanTest extends AbstractEJB3Test {
inProgress =
configurationManager.isResourceConfigurationUpdateInProgress(overlord, resourceId);
if (inProgress) {
- // history2 should be history1 since the update is not complete
+ // history2 should be history1 since the update is not complete
assert history2 != null;
assert history2.getId() == history1.getId();
myprop =
history2.getConfiguration().getSimple("myboolean");
@@ -314,7 +314,7 @@ public class ConfigurationManagerBeanTest extends AbstractEJB3Test {
assert "true".equals(myprop.getStringValue());
myprop = history2.getConfiguration().getSimple("mysleep");
// this wasn't in the first config
assert myprop == null;
- // record that this test case ran, we expect it will if the agent
delay is there
+ // record that this test case ran, we expect it will if the agent
delay is there
inProgressTested = true;
} else {
// update is complete, history 2 should be different
@@ -741,7 +741,7 @@ public class ConfigurationManagerBeanTest extends AbstractEJB3Test {
}
/** Exercise the ConfigurationManagerBean getOptionsForConfigurationDefinition.
- *
+ *
* @throws Exception
*/
@Test(enabled = ENABLE_TESTS)
@@ -1219,10 +1219,6 @@ public class ConfigurationManagerBeanTest extends AbstractEJB3Test
{
public void uninventoryResource(int resourceId) {
}
- @Asynchronous(guaranteedDelivery = true)
- public void synchronizeInventory(ResourceSyncInfo syncInfo) {
- }
-
public Configuration validate(Configuration configuration, int resourceId,
boolean isStructured)
throws PluginContainerException {
return null;
@@ -1232,5 +1228,13 @@ public class ConfigurationManagerBeanTest extends AbstractEJB3Test
{
public void requestFullAvailabilityReport() {
return;
}
+
+ @Override
+ public void synchronizePlatform(PlatformSyncInfo syncInfo) {
+ }
+
+ @Override
+ public void synchronizeServer(int resourceId, Collection<ResourceSyncInfo>
toplevelServerSyncInfo) {
+ }
}
}
diff --git
a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/configuration/LargeGroupPluginConfigurationTest.java
b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/configuration/LargeGroupPluginConfigurationTest.java
index 13343d8..b5e0dba 100644
---
a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/configuration/LargeGroupPluginConfigurationTest.java
+++
b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/configuration/LargeGroupPluginConfigurationTest.java
@@ -18,6 +18,7 @@
*/
package org.rhq.enterprise.server.configuration;
+import java.util.Collection;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -34,8 +35,8 @@ import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.ConfigurationUpdateStatus;
import org.rhq.core.domain.discovery.AvailabilityReport;
import org.rhq.core.domain.discovery.MergeResourceResponse;
+import org.rhq.core.domain.discovery.PlatformSyncInfo;
import org.rhq.core.domain.discovery.ResourceSyncInfo;
-import org.rhq.core.domain.measurement.Availability;
import org.rhq.core.domain.resource.Resource;
import org.rhq.core.domain.resource.ResourceType;
import org.rhq.enterprise.server.authz.PermissionException;
@@ -112,7 +113,7 @@ public class LargeGroupPluginConfigurationTest extends
LargeGroupTestBase {
int groupUpdateId =
configurationManager.scheduleGroupPluginConfigurationUpdate(env.normalSubject,
env.compatibleGroup.getId(), existingMap);
- // group plugin configuration update has been kicked off, wait for the mock
agents to each complete their update
+ // group plugin configuration update has been kicked off, wait for the mock
agents to each complete their update
System.out.print("Waiting for mock agents");
assert latch.await(5, TimeUnit.MINUTES) : "agents should not have taken this
long";
System.out.println(" Mock agents are done.");
@@ -222,10 +223,6 @@ public class LargeGroupPluginConfigurationTest extends
LargeGroupTestBase {
}
@Override
- public void synchronizeInventory(ResourceSyncInfo syncInfo) {
- }
-
- @Override
public void uninventoryResource(int resourceId) {
}
@@ -241,5 +238,13 @@ public class LargeGroupPluginConfigurationTest extends
LargeGroupTestBase {
public void requestFullAvailabilityReport() {
return;
}
+
+ @Override
+ public void synchronizePlatform(PlatformSyncInfo syncInfo) {
+ }
+
+ @Override
+ public void synchronizeServer(int resourceId, Collection<ResourceSyncInfo>
toplevelServerSyncInfo) {
+ }
}
}
diff --git
a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/discovery/DiscoveryBossBeanTest.java
b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/discovery/DiscoveryBossBeanTest.java
index 9cf9f98..eb3cf20 100644
---
a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/discovery/DiscoveryBossBeanTest.java
+++
b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/discovery/DiscoveryBossBeanTest.java
@@ -205,10 +205,12 @@ public class DiscoveryBossBeanTest extends AbstractEJB3Test {
assert results != null;
assert results.getIgnoredResourceTypes() == null : "nothing should have been
ignored in this test";
assertNotNull(results.getPlatformSyncInfo());
- ResourceSyncInfo syncInfo =
discoveryBoss.getResourceSyncInfo(results.getPlatformSyncInfo().getId());
- assert syncInfo != null;
+ Collection<ResourceSyncInfo> syncInfos =
discoveryBoss.getResourceSyncInfo(results.getPlatformSyncInfo()
+ .getPlatform().getId());
+ assert syncInfos != null;
+ assert !syncInfos.isEmpty();
- platform.setId(syncInfo.getId());
+ platform.setId(results.getPlatformSyncInfo().getPlatform().getId());
// Now submit the server and its children as an update report
inventoryReport = new InventoryReport(agent);
@@ -251,16 +253,19 @@ public class DiscoveryBossBeanTest extends AbstractEJB3Test {
assert results != null;
assert results.getIgnoredResourceTypes() == null : "nothing should have been
ignored in this test";
assertNotNull(results.getPlatformSyncInfo());
- ResourceSyncInfo syncInfo =
discoveryBoss.getResourceSyncInfo(results.getPlatformSyncInfo().getId());
- assert syncInfo != null;
+ assertNotNull(results.getPlatformSyncInfo().getTopLevelServerIds());
+ assertTrue(!results.getPlatformSyncInfo().getTopLevelServerIds().isEmpty());
+ Integer resourceId =
results.getPlatformSyncInfo().getTopLevelServerIds().iterator().next();
+ Collection<ResourceSyncInfo> syncInfos =
discoveryBoss.getResourceSyncInfo(resourceId);
+ assert syncInfos != null;
+ assert !syncInfos.isEmpty();
- ResourceSyncInfo serverSyncInfo =
syncInfo.getChildSyncInfos().iterator().next();
Resource resource1 =
discoveryBoss.manuallyAddResource(subjectManager.getOverlord(), serviceType2.getId(),
- serverSyncInfo.getId(), new Configuration());
+ resourceId, new Configuration());
try {
Resource resource2 =
discoveryBoss.manuallyAddResource(subjectManager.getOverlord(), serviceType2.getId(),
- serverSyncInfo.getId(), new Configuration());
+ resourceId, new Configuration());
fail("Manually adding a singleton that already existed succeeded: "
+ resource2);
} catch (EJBException e) {
assertEquals(String.valueOf(e.getCause()), RuntimeException.class,
e.getCause().getClass());
@@ -295,15 +300,15 @@ public class DiscoveryBossBeanTest extends AbstractEJB3Test {
assert platformSyncInfo != null;
// Check merge result
- assertEquals(InventoryStatus.NEW, platformSyncInfo.getInventoryStatus());
- assertEquals(platform.getChildResources().size(),
platformSyncInfo.getTopLevelServers().size());
+ assertEquals(InventoryStatus.NEW,
platformSyncInfo.getPlatform().getInventoryStatus());
+ assertEquals(platform.getChildResources().size(),
platformSyncInfo.getTopLevelServerIds().size());
// Collect the resource ids generated for the platform and the servers
- int platformId = platformSyncInfo.getId();
+ int platformId = platformSyncInfo.getPlatform().getId();
List<Integer> serverIds = new LinkedList<Integer>();
- for (Resource serverSyncInfo : platformSyncInfo.getTopLevelServers()) {
- serverIds.add(serverSyncInfo.getId());
+ for (Integer serverId : platformSyncInfo.getTopLevelServerIds()) {
+ serverIds.add(serverId);
}
int[] arrayOfServerIds = ArrayUtils.unwrapCollection(serverIds);
@@ -368,8 +373,8 @@ public class DiscoveryBossBeanTest extends AbstractEJB3Test {
assert mergeResults.getIgnoredResourceTypes().contains(new
ResourceTypeFlyweight(serverType));
// Check merge result - make sure we should not see any children under the
platform (it should have been ignored)
- assertEquals(InventoryStatus.NEW, platformSyncInfo.getInventoryStatus());
- assertEquals(platformSyncInfo.getTopLevelServers().size(), 0);
+ assertEquals(InventoryStatus.NEW,
platformSyncInfo.getPlatform().getInventoryStatus());
+ assertEquals(platformSyncInfo.getTopLevelServerIds().size(), 0);
}
@Test(groups = "integration.ejb3")
@@ -428,10 +433,10 @@ public class DiscoveryBossBeanTest extends AbstractEJB3Test {
assert platformSyncInfo != null;
// Collect the resource ids generated for the platform and the servers
- int platformId = platformSyncInfo.getId();
+ int platformId = platformSyncInfo.getPlatform().getId();
List<Integer> serverIds = new LinkedList<Integer>();
- for (Resource serverSyncInfo : platformSyncInfo.getTopLevelServers()) {
- serverIds.add(serverSyncInfo.getId());
+ for (Integer serverId : platformSyncInfo.getTopLevelServerIds()) {
+ serverIds.add(serverId);
}
int[] arrayOfServerIds = ArrayUtils.unwrapCollection(serverIds);
@@ -469,8 +474,8 @@ public class DiscoveryBossBeanTest extends AbstractEJB3Test {
assertEquals(mergeResults.getIgnoredResourceTypes().size(), 1);
assert mergeResults.getIgnoredResourceTypes().contains(new
ResourceTypeFlyweight(serverType));
- assertEquals(InventoryStatus.COMMITTED, platformSyncInfo.getInventoryStatus());
// notice platform is committed now
- assertEquals(platformSyncInfo.getTopLevelServers().size(), 0); // notice there
are no server children now
+ assertEquals(InventoryStatus.COMMITTED,
platformSyncInfo.getPlatform().getInventoryStatus()); // notice platform is committed now
+ assertEquals(platformSyncInfo.getTopLevelServerIds().size(), 0); // notice there
are no server children now
}
@Test(groups = "integration.ejb3")
@@ -501,11 +506,11 @@ public class DiscoveryBossBeanTest extends AbstractEJB3Test {
assert platformSyncInfo != null;
// Check merge result
- assertEquals(InventoryStatus.COMMITTED, platformSyncInfo.getInventoryStatus());
- assertEquals(storagePlatform.getChildResources().size(),
platformSyncInfo.getTopLevelServers().size());
+ assertEquals(InventoryStatus.COMMITTED,
platformSyncInfo.getPlatform().getInventoryStatus());
+ assertEquals(storagePlatform.getChildResources().size(),
platformSyncInfo.getTopLevelServerIds().size());
storageNode = resourceManager.getResourceById(subjectManager.getOverlord(),
platformSyncInfo
- .getTopLevelServers().iterator().next().getId());
+ .getTopLevelServerIds().iterator().next());
assertNotNull(storageNode);
assertEquals(InventoryStatus.COMMITTED, storageNode.getInventoryStatus());
}
@@ -533,8 +538,7 @@ public class DiscoveryBossBeanTest extends AbstractEJB3Test {
// Then simulate a create resource request
final String userSuppliedResourceName = prefix("User Supplied Resource
Name");
final String newResourceKey = prefix("Created Resource Key");
- Resource serverSyncInfo =
firstDiscoverySyncInfo.getTopLevelServers().iterator().next();
- final int serverResourceId = serverSyncInfo.getId();
+ final int serverResourceId =
firstDiscoverySyncInfo.getTopLevelServerIds().iterator().next();
executeInTransaction(false, new TransactionCallback() {
@Override
@@ -568,10 +572,13 @@ public class DiscoveryBossBeanTest extends AbstractEJB3Test {
// Check that the resource ends with the user supplied name in inventory
- ResourceSyncInfo topLevelServerSyncInfo =
discoveryBoss.getResourceSyncInfo(secondDiscoverySyncInfo
- .getTopLevelServers().iterator().next().getId());
- ResourceSyncInfo service1SyncInfo =
topLevelServerSyncInfo.getChildSyncInfos().iterator().next();
- Resource service1Resource = getEntityManager().find(Resource.class,
service1SyncInfo.getId());
+ Integer toplevelServerId =
secondDiscoverySyncInfo.getTopLevelServerIds().iterator().next();
+ Collection<ResourceSyncInfo> topLevelServerSyncInfo =
discoveryBoss.getResourceSyncInfo(toplevelServerId);
+ assert topLevelServerSyncInfo.size() == 2;
+ Iterator<ResourceSyncInfo> iter = topLevelServerSyncInfo.iterator();
+ Integer childId = iter.next().getId();
+ childId = childId.equals(toplevelServerId) ? iter.next().getId() : childId;
+ Resource service1Resource = getEntityManager().find(Resource.class, childId);
assertEquals(userSuppliedResourceName, service1Resource.getName());
}
diff --git
a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/test/TestAgentClient.java
b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/test/TestAgentClient.java
index 0c3a86e..93e2220 100644
---
a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/test/TestAgentClient.java
+++
b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/test/TestAgentClient.java
@@ -19,6 +19,7 @@
package org.rhq.enterprise.server.test;
import java.io.InputStream;
+import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -53,17 +54,16 @@ import org.rhq.core.clientapi.server.content.DeletePackagesRequest;
import org.rhq.core.clientapi.server.content.DeployPackagesRequest;
import org.rhq.core.clientapi.server.content.RetrievePackageBitsRequest;
import org.rhq.core.clientapi.server.discovery.InventoryReport;
-import org.rhq.core.communications.command.annotation.Asynchronous;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.content.transfer.DeployPackageStep;
import org.rhq.core.domain.content.transfer.ResourcePackageDetails;
import org.rhq.core.domain.discovery.AvailabilityReport;
import org.rhq.core.domain.discovery.MergeResourceResponse;
+import org.rhq.core.domain.discovery.PlatformSyncInfo;
import org.rhq.core.domain.discovery.ResourceSyncInfo;
import org.rhq.core.domain.drift.DriftDefinition;
import org.rhq.core.domain.drift.DriftFile;
import org.rhq.core.domain.drift.DriftSnapshot;
-import org.rhq.core.domain.measurement.Availability;
import org.rhq.core.domain.measurement.MeasurementData;
import org.rhq.core.domain.measurement.MeasurementScheduleRequest;
import org.rhq.core.domain.measurement.ResourceMeasurementScheduleRequest;
@@ -333,12 +333,6 @@ public class TestAgentClient implements AgentClient,
BundleAgentService, DriftAg
throws InvalidPluginConfigurationClientException, PluginContainerException {
}
- @Asynchronous(guaranteedDelivery = true)
- @Override
- public void synchronizeInventory(ResourceSyncInfo syncInfo) {
- return;
- }
-
@Override
public void createResource(CreateResourceRequest request) throws
PluginContainerException {
}
@@ -421,4 +415,12 @@ public class TestAgentClient implements AgentClient,
BundleAgentService, DriftAg
public void requestFullAvailabilityReport() {
return;
}
+
+ @Override
+ public void synchronizePlatform(PlatformSyncInfo syncInfo) {
+ }
+
+ @Override
+ public void synchronizeServer(int resourceId, Collection<ResourceSyncInfo>
toplevelServerSyncInfo) {
+ }
}
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossBean.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossBean.java
index 71e2e3f..656abd2 100644
---
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossBean.java
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossBean.java
@@ -24,6 +24,7 @@ import static org.rhq.core.util.StringUtil.isBlank;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.EnumSet;
@@ -271,14 +272,78 @@ public class DiscoveryBossBean implements DiscoveryBossLocal,
DiscoveryBossRemot
return null;
}
- PlatformSyncInfo result = entityManager.find(PlatformSyncInfo.class,
platform.getId());
+ Set<Resource> toplevelServices = new HashSet<Resource>();
+ Set<Integer> topLevelServerIds = new HashSet<Integer>();
+
+ for (Resource platformChild : platform.getChildResources()) {
+ switch (platformChild.getResourceType().getCategory()) {
+ case SERVER:
+ topLevelServerIds.add(platformChild.getId());
+ break;
+ case SERVICE:
+ toplevelServices.add(platformChild);
+ break;
+ default:
+ break;
+ }
+ }
+
+ ResourceSyncInfo platformSyncInfo =
ResourceSyncInfo.buildResourceSyncInfo(platform);
+ Set<ResourceSyncInfo> topLevelServiceSyncInfo =
getToplevelServiceSyncInfo(toplevelServices);
+ PlatformSyncInfo result = new PlatformSyncInfo(platformSyncInfo,
topLevelServiceSyncInfo, topLevelServerIds);
+
return result;
}
+ /**
+ * At the time of writing (4.10) platform top level services don't have children
so this will be quick, but
+ * write it to handle any future children. In general this will still be a
relatively small number of resources.
+ *
+ * @param topLevelServices
+ * @return The top level service hierarchy sync info
+ */
+ private Set<ResourceSyncInfo> getToplevelServiceSyncInfo(Set<Resource>
topLevelServices) {
+ Set<ResourceSyncInfo> result = new
HashSet<ResourceSyncInfo>(topLevelServices.size());
+ Set<Integer> topLevelServiceIds = new HashSet<Integer>();
+
+ for (Resource topLevelService : topLevelServices) {
+ result.add(ResourceSyncInfo.buildResourceSyncInfo(topLevelService));
+ topLevelServiceIds.add(topLevelService.getId());
+ }
+
+ getToplevelServiceSyncInfoHierarchy(topLevelServiceIds, result);
+
+ return result;
+ }
+
+ private void getToplevelServiceSyncInfoHierarchy(Set<Integer> parentIds,
Set<ResourceSyncInfo> result) {
+ if (parentIds.isEmpty()) {
+ return;
+ }
+
+ Query q =
entityManager.createNamedQuery(ResourceSyncInfo.QUERY_SERVICE_CHILDREN);
+ q.setParameter("parentIds", parentIds);
+ List<ResourceSyncInfo> childSyncInfos = q.getResultList();
+
+ if (!childSyncInfos.isEmpty()) {
+ result.addAll(childSyncInfos);
+
+ Set<Integer> childIds = new
HashSet<Integer>(childSyncInfos.size());
+ for (ResourceSyncInfo childSyncInfo : childSyncInfos) {
+ childIds.add(childSyncInfo.getId());
+ }
+ getToplevelServiceSyncInfoHierarchy(childIds, result);
+ }
+ }
+
@Override
- public ResourceSyncInfo getResourceSyncInfo(int resourceId) {
- // [PERF] this is expensive, it let's hibernate grab the whole hierarchy via
eager fetch of children.
- ResourceSyncInfo result = entityManager.find(ResourceSyncInfo.class,
resourceId);
+ public Collection<ResourceSyncInfo> getResourceSyncInfo(int resourceId) {
+ // [PERF] this is an expensive query that can return a large collection. But
it's faster than the old way of
+ // letting hibernate grab the whole hierarchy via eager fetch of children...
+ Query q =
entityManager.createNamedQuery(ResourceSyncInfo.QUERY_TOP_LEVEL_SERVER);
+ q.setParameter("resourceId", resourceId);
+
+ Collection<ResourceSyncInfo> result = q.getResultList();
return result;
}
@@ -360,7 +425,7 @@ public class DiscoveryBossBean implements DiscoveryBossLocal,
DiscoveryBossRemot
servers = attachedServers;
// Update and persist the actual inventory statuses
- // This is done is a separate transaction to stop failures in the agent from
rolling back the transaction
+ // This is done in a separate transaction to stop failures in the agent from
rolling back the transaction
discoveryBoss.updateInventoryStatusInNewTransaction(user, platforms, servers,
status);
scheduleAgentInventoryOperationJob(platforms, servers);
@@ -422,7 +487,7 @@ public class DiscoveryBossBean implements DiscoveryBossLocal,
DiscoveryBossRemot
}
/**
- * Synchronize the agents inventory status for platforms, and then the servers,
+ * Synchronize the agent's inventory status for platforms, and then the servers,
* omitting servers under synced platforms since they will have been handled
* already. On status change request an agent sync on the affected resources.
* The agent will sync status and determine what other sync work needs to be
@@ -438,8 +503,9 @@ public class DiscoveryBossBean implements DiscoveryBossLocal,
DiscoveryBossRemot
AgentClient agentClient = agentManager.getAgentClient(platform.getAgent());
if (agentClient != null) {
try {
- syncInfo = entityManager.find(ResourceSyncInfo.class,
platform.getId());
-
agentClient.getDiscoveryAgentService().synchronizeInventory(syncInfo);
+ //syncInfo = entityManager.find(ResourceSyncInfo.class,
platform.getId());
+ PlatformSyncInfo platformSyncInfo =
getPlatformSyncInfo(platform.getAgent());
+
agentClient.getDiscoveryAgentService().synchronizePlatform(platformSyncInfo);
} catch (Exception e) {
LOG.warn("Could not perform commit synchronization with agent
for platform [" + platform.getName()
+ "]", e);
@@ -455,8 +521,9 @@ public class DiscoveryBossBean implements DiscoveryBossLocal,
DiscoveryBossRemot
AgentClient agentClient =
agentManager.getAgentClient(server.getAgent());
if (agentClient != null) {
try {
- syncInfo = entityManager.find(ResourceSyncInfo.class,
server.getId());
-
agentClient.getDiscoveryAgentService().synchronizeInventory(syncInfo);
+ //syncInfo = entityManager.find(ResourceSyncInfo.class,
server.getId());
+ Collection<ResourceSyncInfo> syncInfos =
getResourceSyncInfo(server.getId());
+
agentClient.getDiscoveryAgentService().synchronizeServer(server.getId(), syncInfos);
} catch (Exception e) {
LOG.warn("Could not perform commit synchronization with
agent for server [" + server.getName()
+ "]", e);
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossLocal.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossLocal.java
index 7ed9445..85b55f0 100644
---
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossLocal.java
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossLocal.java
@@ -18,6 +18,7 @@
*/
package org.rhq.enterprise.server.discovery;
+import java.util.Collection;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
@@ -87,9 +88,11 @@ public interface DiscoveryBossLocal extends DiscoveryBossRemote {
/**
* @param resourceid the root resourceId on which we want to sync
- * @return null if resource not found, otherwise the entire tree rooted at the
specified resource
+ * @return null if resource not found, otherwise the entire tree rooted at the
specified resource, as an
+ * unordered collection. Although not strictly a Set (to save on computation) this
collection should not
+ * contain duplicates.
*/
- ResourceSyncInfo getResourceSyncInfo(int resourceId);
+ Collection<ResourceSyncInfo> getResourceSyncInfo(int resourceId);
/**
* Returns a map of platforms (the keys) and their servers (the values) that are in
the auto-discovery queue but not
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryServerServiceImpl.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryServerServiceImpl.java
index 533948b..8fd2cf2 100644
---
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryServerServiceImpl.java
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryServerServiceImpl.java
@@ -19,6 +19,7 @@
package org.rhq.enterprise.server.discovery;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -121,10 +122,10 @@ public class DiscoveryServerServiceImpl implements
DiscoveryServerService {
}
@Override
- public ResourceSyncInfo getResourceSyncInfo(int resourceId) {
+ public Collection<ResourceSyncInfo> getResourceSyncInfo(int resourceId) {
long start = System.currentTimeMillis();
DiscoveryBossLocal discoveryBoss = LookupUtil.getDiscoveryBoss();
- ResourceSyncInfo results;
+ Collection<ResourceSyncInfo> results;
results = discoveryBoss.getResourceSyncInfo(resourceId);