You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ace.apache.org by ja...@apache.org on 2014/03/05 15:59:06 UTC

svn commit: r1574516 - in /ace/trunk: org.apache.ace.client.repository/src/org/apache/ace/client/repository/stateful/impl/ run-server-allinone/ run-server-allinone/scripts/

Author: jawi
Date: Wed Mar  5 14:59:06 2014
New Revision: 1574516

URL: http://svn.apache.org/r1574516
Log:
Improved performance of the StatefulTargetRepository:

- When lots of artifacts are present, changing one of those would cause *all*
  targets to update its state, even if the target had no association whatsoever
  with the originating artifact, this causes a lots of overhead and loss of
  performance;
- made the event-handling for the stateful target repository a little more smarter
  in its decision to recalculate the state of a (stateful) target. This is now
  only done when a target actually has something to do with the entity, for
  example, because it is reachable from the given target, or is a resource
  processor for an reachable artifact;
- improved the state calculation of a stateful target a little by storing the
  reachable artifacts and the artifacts of the latest deployment version in a
  sorted set. This way, we can use a single "equals()" check, instead of a
  double "containsAll()" check.


Added:
    ace/trunk/run-server-allinone/scripts/addbundles.gogo
Modified:
    ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/stateful/impl/StatefulTargetObjectImpl.java
    ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/stateful/impl/StatefulTargetRepositoryImpl.java
    ace/trunk/run-server-allinone/server-allinone.bndrun

Modified: ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/stateful/impl/StatefulTargetObjectImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/stateful/impl/StatefulTargetObjectImpl.java?rev=1574516&r1=1574515&r2=1574516&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/stateful/impl/StatefulTargetObjectImpl.java (original)
+++ ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/stateful/impl/StatefulTargetObjectImpl.java Wed Mar  5 14:59:06 2014
@@ -29,6 +29,8 @@ import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Properties;
+import java.util.SortedSet;
+import java.util.TreeSet;
 
 import org.apache.ace.client.repository.Associatable;
 import org.apache.ace.client.repository.Association;
@@ -246,7 +248,7 @@ public class StatefulTargetObjectImpl im
 
     private void determineStoreState(DeploymentVersionObject deploymentVersionObject) {
         synchronized (m_lock) {
-            List<String> fromShop = new ArrayList<String>();
+            SortedSet<String> fromShop = new TreeSet<String>();
             ArtifactObject[] artifactsFromShop = m_repository.getNecessaryArtifacts(getID());
             DeploymentVersionObject mostRecentVersion;
             if (deploymentVersionObject == null) {
@@ -265,13 +267,11 @@ public class StatefulTargetObjectImpl im
                 return;
             }
 
-            // TODO in the artifacts we get from the shop, there seem to be some duplicates
-            // which does not influence the algorithm below, but we might want to optimize this
             for (ArtifactObject ao : artifactsFromShop) {
                 fromShop.add(ao.getURL());
             }
 
-            List<String> fromDeployment = new ArrayList<String>();
+            SortedSet<String> fromDeployment = new TreeSet<String>();
             for (DeploymentArtifact da : getArtifactsFromDeployment()) {
                 fromDeployment.add(da.getDirective(DeploymentArtifact.DIRECTIVE_KEY_BASEURL));
             }
@@ -279,7 +279,7 @@ public class StatefulTargetObjectImpl im
             if ((mostRecentVersion == null) && fromShop.isEmpty()) {
                 setStoreState(StoreState.New);
             }
-            else if (fromShop.containsAll(fromDeployment) && fromDeployment.containsAll(fromShop)) {
+            else if (fromShop.equals(fromDeployment)) {
                 // great, we have the same artifacts. But... do they need to be reprocessed?
                 // this might be the case when the target has new tags that affect templates
                 for (ArtifactObject ao : artifactsFromShop) {

Modified: ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/stateful/impl/StatefulTargetRepositoryImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/stateful/impl/StatefulTargetRepositoryImpl.java?rev=1574516&r1=1574515&r2=1574516&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/stateful/impl/StatefulTargetRepositoryImpl.java (original)
+++ ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/stateful/impl/StatefulTargetRepositoryImpl.java Wed Mar  5 14:59:06 2014
@@ -38,9 +38,12 @@ import org.apache.ace.client.repository.
 import org.apache.ace.client.repository.RepositoryUtil;
 import org.apache.ace.client.repository.SessionFactory;
 import org.apache.ace.client.repository.helper.bundle.BundleHelper;
+import org.apache.ace.client.repository.object.Artifact2FeatureAssociation;
 import org.apache.ace.client.repository.object.ArtifactObject;
 import org.apache.ace.client.repository.object.DeploymentArtifact;
 import org.apache.ace.client.repository.object.DeploymentVersionObject;
+import org.apache.ace.client.repository.object.Distribution2TargetAssociation;
+import org.apache.ace.client.repository.object.Feature2DistributionAssociation;
 import org.apache.ace.client.repository.object.TargetObject;
 import org.apache.ace.client.repository.object.FeatureObject;
 import org.apache.ace.client.repository.object.DistributionObject;
@@ -609,8 +612,8 @@ public class StatefulTargetRepositoryImp
     }
 
     /**
-     * Returns a map of all resource processors that are available. If there are multiple versions
-     * of a specific processor, it will only return the latest version.
+     * Returns a map of all resource processors that are available. If there are multiple versions of a specific
+     * processor, it will only return the latest version.
      * 
      * @return a map of all resource processors, indexed by processor ID
      */
@@ -742,7 +745,7 @@ public class StatefulTargetRepositoryImp
      */
     private static String nextVersion(String version) {
         try {
-            // in case the given version is null or empty, v will be '0.0.0'... 
+            // in case the given version is null or empty, v will be '0.0.0'...
             Version v = Version.parseVersion(version);
             Version result = new Version(v.getMajor() + 1, 0, 0);
             return result.toString();
@@ -771,6 +774,15 @@ public class StatefulTargetRepositoryImp
                     }
                 }
             }
+            else if (TargetObject.PRIVATE_TOPIC_CHANGED.equals(topic)) {
+                synchronized (m_repository) {
+                    String id = ((TargetObject) event.getProperty(RepositoryObject.EVENT_ENTITY)).getID();
+                    StatefulTargetObjectImpl stoi = getStatefulTargetObject(id);
+                    if (stoi != null) {
+                        stoi.determineStatus();
+                    }
+                }
+            }
             else if (TargetObject.PRIVATE_TOPIC_REMOVED.equals(topic)) {
                 synchronized (m_repository) {
                     String id = ((TargetObject) event.getProperty(RepositoryObject.EVENT_ENTITY)).getID();
@@ -794,12 +806,19 @@ public class StatefulTargetRepositoryImp
                     }
                 }
             }
-            else {
+            else if (!RepositoryAdmin.PRIVATE_TOPIC_LOGIN.equals(topic) && !RepositoryAdmin.PRIVATE_TOPIC_REFRESH.equals(topic)) {
                 // Something else has changed; however, the entire shop may have an influence on
-                // any target, so recheck everything.
-                synchronized (m_repository) {
-                    for (StatefulTargetObjectImpl stoi : m_repository.values()) {
-                        stoi.determineStatus();
+                // any target, so recheck everything that is reachable from the entity...
+
+                RepositoryObject entity = (RepositoryObject) event.getProperty(RepositoryObject.EVENT_ENTITY);
+                if (entity != null) {
+                    synchronized (m_repository) {
+                        for (StatefulTargetObjectImpl stoi : m_repository.values()) {
+                            // Check whether the entity is reachable from this target...
+                            if (isReachableFrom(stoi, entity)) {
+                                stoi.determineStatus();
+                            }
+                        }
                     }
                 }
             }
@@ -813,6 +832,78 @@ public class StatefulTargetRepositoryImp
         }
     }
 
+    /**
+     * Determines whether a given entity is reachable from a given stateful target, by traversing all its associations.
+     * 
+     * @param target
+     *            the stateful target object to check;
+     * @param entity
+     *            the entity to test.
+     * @return <code>true</code> if the given entity is reachable from the given target, <code>false</code> otherwise.
+     */
+    private boolean isReachableFrom(StatefulTargetObjectImpl target, RepositoryObject entity) {
+        if (entity instanceof DistributionObject) {
+            return target.isAssociated(entity, DistributionObject.class);
+        }
+        else if (entity instanceof Distribution2TargetAssociation) {
+            return ((Distribution2TargetAssociation) entity).getRight().contains(target.getTargetObject());
+        }
+        else if (entity instanceof FeatureObject) {
+            for (DistributionObject dist : target.getDistributions()) {
+                if (dist.isAssociated(entity, FeatureObject.class)) {
+                    return true;
+                }
+            }
+        }
+        else if (entity instanceof Feature2DistributionAssociation) {
+            List<DistributionObject> associatedDistributions = ((Feature2DistributionAssociation) entity).getRight();
+            for (DistributionObject dist : target.getDistributions()) {
+                if (associatedDistributions.contains(dist)) {
+                    return true;
+                }
+            }
+        }
+        else if (entity instanceof ArtifactObject) {
+            List<ArtifactObject> reachableArtifacts = new ArrayList<ArtifactObject>();
+            for (DistributionObject dist : target.getDistributions()) {
+                for (FeatureObject feat : dist.getFeatures()) {
+                    if (feat.isAssociated(entity, ArtifactObject.class)) {
+                        return true;
+                    }
+                    else {
+                        // Keep a list of reachable artifacts while we're at it, used below...
+                        reachableArtifacts.addAll(feat.getArtifacts());
+                    }
+                }
+            }
+
+            // Not found as regular artifact, maybe we've got a resource processor?
+            String resourceProcessorPID = entity.getAttribute(BundleHelper.KEY_RESOURCE_PROCESSOR_PID);
+            if (resourceProcessorPID != null) {
+                for (ArtifactObject reachableArtifact : reachableArtifacts) {
+                    if (resourceProcessorPID.equals(reachableArtifact.getProcessorPID())) {
+                        return true;
+                    }
+                }
+            }
+        }
+        else if (entity instanceof Artifact2FeatureAssociation) {
+            for (DistributionObject dist : target.getDistributions()) {
+                List<FeatureObject> associatedFeatures = ((Artifact2FeatureAssociation) entity).getRight();
+                for (FeatureObject feat : dist.getFeatures()) {
+                    if (associatedFeatures.contains(feat)) {
+                        return true;
+                    }
+                }
+            }
+        }
+        else {
+            // Uhoh, this actually shouldn't happen...
+            m_log.log(LogService.LOG_WARNING, "Unhandled entity in reachability check for stateful target: " + entity.getDefinition());
+        }
+        return false;
+    }
+
     boolean needsNewVersion(ArtifactObject artifact, String targetID, String version) {
         return m_artifactRepository.needsNewVersion(artifact, getTargetObject(targetID), targetID, version);
     }

Added: ace/trunk/run-server-allinone/scripts/addbundles.gogo
URL: http://svn.apache.org/viewvc/ace/trunk/run-server-allinone/scripts/addbundles.gogo?rev=1574516&view=auto
==============================================================================
--- ace/trunk/run-server-allinone/scripts/addbundles.gogo (added)
+++ ace/trunk/run-server-allinone/scripts/addbundles.gogo Wed Mar  5 14:59:06 2014
@@ -0,0 +1,33 @@
+#
+# Creates an additional 100 bundles and 10 configuration files
+#
+
+# install test bundle with additional Gogo commands needed later on in this script
+pwd = (cd) getAbsolutePath
+start 'file:'$pwd'/../org.apache.ace.test/generated/org.apache.ace.test.jar'
+
+# create a workspace
+w = (cw)
+
+# create 100 bundle artifacts and link them to the 10 features...
+a = 0
+while {(lt $a 10)} {
+	each [0 1 2 3 4 5 6 7 8 9] {
+		echo 'Creating bundle artifact-extra-'$a$it' ...'
+		# generate artifacts and associate them
+        $w ca (gba 'artifact-extra-2-'$it'-'$a) true
+		$w ca2f '(bundle-symbolicname=artifact-extra-2-'$it'-'$a')' '(name=feature-'$it')'
+	}
+	a = (inc $a)
+}
+
+each [0 1 2 3 4 5 6 7 8 9] {
+	echo 'Creating config-'$it'.xml ...'
+	c = (gca 'config-extra-2-'$it 'common' 'prop'$it'1' 'prop'$it'2' 'prop'$it'3')
+	$w ca $c true
+	$w ca2f '(artifactName=config-extra-2-'$it'.xml)' '(name=feature-'$it')'
+}
+
+# commit and delete the workspace
+$w commit
+rw $w

Modified: ace/trunk/run-server-allinone/server-allinone.bndrun
URL: http://svn.apache.org/viewvc/ace/trunk/run-server-allinone/server-allinone.bndrun?rev=1574516&r1=1574515&r2=1574516&view=diff
==============================================================================
--- ace/trunk/run-server-allinone/server-allinone.bndrun (original)
+++ ace/trunk/run-server-allinone/server-allinone.bndrun Wed Mar  5 14:59:06 2014
@@ -77,7 +77,7 @@
 	launch.storage.dir=bundle-cache
 
 # Add some extra memory to the VM
--runvm: -Xmx1G
+-runvm: -Xmx1G -agentpath:/Applications/YourKit_Java_Profiler_2013_build_13072.app/bin/mac/libyjpagent.jnilib
 
 # Enable Yourkit profiling
 #-runvm: -Xmx1G -agentpath:/Applications/YourKit_Java_Profiler_12.0.5.app/bin/mac/libyjpagent.jnilib
\ No newline at end of file