You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ss...@apache.org on 2017/12/21 16:24:43 UTC
[sling-org-apache-sling-testing-osgi-mock] 01/01: performance
improvement: avoid endless looping through all references for lookup of
dynamic and static-greedy service references and cache the lookups measured
with a non-trivial project with 318 mock-based unit tests the improvement
was up to 5% on test execution time
This is an automated email from the ASF dual-hosted git repository.
sseifert pushed a commit to branch feature/cache-service-referenceinfos
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git
commit 567a2c67603e9d337881368e720498e03257992b
Author: sseifert <ss...@pro-vision.de>
AuthorDate: Thu Dec 21 17:24:29 2017 +0100
performance improvement: avoid endless looping through all references for lookup of dynamic and static-greedy service references and cache the lookups
measured with a non-trivial project with 318 mock-based unit tests the improvement was up to 5% on test execution time
i'm not sure if it's worth to apply this optimization as the code gets a bit more complex and more prone to threading issues
---
.../sling/testing/mock/osgi/MockBundleContext.java | 79 ++++++++++++++++++++--
.../sling/testing/mock/osgi/OsgiServiceUtil.java | 57 ----------------
2 files changed, 73 insertions(+), 63 deletions(-)
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/MockBundleContext.java b/src/main/java/org/apache/sling/testing/mock/osgi/MockBundleContext.java
index 0340a55..08e10ba 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/MockBundleContext.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockBundleContext.java
@@ -21,9 +21,11 @@ package org.apache.sling.testing.mock.osgi;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Dictionary;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Queue;
@@ -32,12 +34,16 @@ import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentSkipListSet;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.felix.framework.FilterImpl;
+import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.OsgiMetadata;
import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.Reference;
+import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.ReferencePolicy;
+import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.ReferencePolicyOption;
import org.apache.sling.testing.mock.osgi.OsgiServiceUtil.ReferenceInfo;
import org.apache.sling.testing.mock.osgi.OsgiServiceUtil.ServiceInfo;
import org.osgi.framework.Bundle;
@@ -66,6 +72,8 @@ class MockBundleContext implements BundleContext {
private final MockBundle bundle;
private final SortedSet<MockServiceRegistration> registeredServices = new ConcurrentSkipListSet<MockServiceRegistration>();
+ private final ConcurrentMap<String,List<ReferenceInfo>> registeredServicesDynamicReferences = new ConcurrentHashMap<>();
+ private final ConcurrentMap<String,List<ReferenceInfo>> registeredServicesStaticGreedyReferences = new ConcurrentHashMap<>();
private final Map<ServiceListener, Filter> serviceListeners = new ConcurrentHashMap<ServiceListener, Filter>();
private final Queue<BundleListener> bundleListeners = new ConcurrentLinkedQueue<BundleListener>();
private final ConfigurationAdmin configAdmin = new MockConfigurationAdmin();
@@ -119,7 +127,7 @@ class MockBundleContext implements BundleContext {
public ServiceRegistration registerService(final String[] clazzes, final Object service, final Dictionary properties) {
Dictionary<String, Object> mergedPropertes = MapMergeUtil.propertiesMergeWithOsgiMetadata(service, configAdmin, properties);
MockServiceRegistration registration = new MockServiceRegistration(this.bundle, clazzes, service, mergedPropertes, this);
- this.registeredServices.add(registration);
+ addToRegisteredServices(registration);
handleRefsUpdateOnRegister(registration);
notifyServiceListeners(ServiceEvent.REGISTERED, registration.getReference());
return registration;
@@ -131,6 +139,65 @@ class MockBundleContext implements BundleContext {
return registerService(clazz.getName(), factory, properties);
}
+ private void addToRegisteredServices(MockServiceRegistration registration) {
+ this.registeredServices.add(registration);
+
+ // add dynamic and static greedy references to cache
+ OsgiMetadata metadata = OsgiMetadataUtil.getMetadata(registration.getService().getClass());
+ if (metadata != null) {
+ for (Reference reference : metadata.getReferences()) {
+ if (reference.getPolicy() == ReferencePolicy.DYNAMIC) {
+ addReferenceInfo(this.registeredServicesDynamicReferences, registration, reference);
+ }
+ else if (reference.getPolicy() == ReferencePolicy.STATIC && reference.getPolicyOption() == ReferencePolicyOption.GREEDY) {
+ addReferenceInfo(this.registeredServicesStaticGreedyReferences, registration, reference);
+ }
+ }
+ }
+ }
+
+ private void addReferenceInfo(ConcurrentMap<String,List<ReferenceInfo>> map, MockServiceRegistration registration, Reference reference) {
+ String serviceInterface = reference.getInterfaceType();
+ map.putIfAbsent(serviceInterface, new ArrayList<ReferenceInfo>());
+ List<ReferenceInfo> references = map.get(serviceInterface);
+ references.add(new ReferenceInfo(registration, reference));
+ }
+
+ private void remveFromRegisteredServices(MockServiceRegistration registration) {
+ this.registeredServices.remove(registration);
+
+ // remove from reference caches
+ removeReferenceInfos(this.registeredServicesDynamicReferences, registration);
+ removeReferenceInfos(this.registeredServicesStaticGreedyReferences, registration);
+ }
+
+ private void removeReferenceInfos(ConcurrentMap<String,List<ReferenceInfo>> map, MockServiceRegistration registration) {
+ for (List<ReferenceInfo> referenceInfos : map.values()) {
+ synchronized (referenceInfos) {
+ Iterator<ReferenceInfo> referenceInfoIterator = referenceInfos.iterator();
+ while (referenceInfoIterator.hasNext()) {
+ ReferenceInfo referenceInfo = referenceInfoIterator.next();
+ if (referenceInfo.getServiceRegistration() == registration) {
+ referenceInfoIterator.remove();
+ }
+ }
+ }
+ }
+ }
+
+ private List<ReferenceInfo> getMatchingReferences(ConcurrentMap<String,List<ReferenceInfo>> referenceInfoMaps,
+ MockServiceRegistration<?> registration) {
+
+ List<ReferenceInfo> references = new ArrayList<ReferenceInfo>();
+ for (String serviceInterface : registration.getClasses()) {
+ List<ReferenceInfo> lookedUpReferences = referenceInfoMaps.get(serviceInterface);
+ if (lookedUpReferences != null) {
+ references.addAll(lookedUpReferences);
+ }
+ }
+ return references;
+ }
+
/**
* Check for already registered services that may be affected by the service registration - either
* adding by additional optional references, or creating a conflict in the dependencies.
@@ -139,7 +206,7 @@ class MockBundleContext implements BundleContext {
private void handleRefsUpdateOnRegister(MockServiceRegistration registration) {
// handle DYNAMIC references to this registration
- List<ReferenceInfo> affectedDynamicReferences = OsgiServiceUtil.getMatchingDynamicReferences(registeredServices, registration);
+ List<ReferenceInfo> affectedDynamicReferences = getMatchingReferences(this.registeredServicesDynamicReferences, registration);
for (ReferenceInfo referenceInfo : affectedDynamicReferences) {
Reference reference = referenceInfo.getReference();
if (reference.matchesTargetFilter(registration.getReference())) {
@@ -160,7 +227,7 @@ class MockBundleContext implements BundleContext {
}
// handle STATIC+GREEDY references to this registration
- List<ReferenceInfo> affectedStaticGreedyReferences = OsgiServiceUtil.getMatchingStaticGreedyReferences(registeredServices, registration);
+ List<ReferenceInfo> affectedStaticGreedyReferences = getMatchingReferences(this.registeredServicesStaticGreedyReferences, registration);
for (ReferenceInfo referenceInfo : affectedStaticGreedyReferences) {
Reference reference = referenceInfo.getReference();
switch (reference.getCardinality()) {
@@ -179,7 +246,7 @@ class MockBundleContext implements BundleContext {
}
void unregisterService(MockServiceRegistration registration) {
- this.registeredServices.remove(registration);
+ remveFromRegisteredServices(registration);
handleRefsUpdateOnUnregister(registration);
notifyServiceListeners(ServiceEvent.UNREGISTERING, registration.getReference());
}
@@ -218,7 +285,7 @@ class MockBundleContext implements BundleContext {
private void handleRefsUpdateOnUnregister(MockServiceRegistration registration) {
// handle DYNAMIC references to this registration
- List<ReferenceInfo> affectedDynamicReferences = OsgiServiceUtil.getMatchingDynamicReferences(registeredServices, registration);
+ List<ReferenceInfo> affectedDynamicReferences = getMatchingReferences(this.registeredServicesDynamicReferences, registration);
for (ReferenceInfo referenceInfo : affectedDynamicReferences) {
Reference reference = referenceInfo.getReference();
if (reference.matchesTargetFilter(registration.getReference())) {
@@ -241,7 +308,7 @@ class MockBundleContext implements BundleContext {
}
// handle STATIC+GREEDY references to this registration
- List<ReferenceInfo> affectedStaticGreedyReferences = OsgiServiceUtil.getMatchingStaticGreedyReferences(registeredServices, registration);
+ List<ReferenceInfo> affectedStaticGreedyReferences = getMatchingReferences(this.registeredServicesStaticGreedyReferences, registration);
for (ReferenceInfo referenceInfo : affectedStaticGreedyReferences) {
Reference reference = referenceInfo.getReference();
switch (reference.getCardinality()) {
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtil.java b/src/main/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtil.java
index b3fd20c..9bdbd4a 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtil.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtil.java
@@ -27,15 +27,12 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.SortedSet;
import org.apache.commons.lang3.StringUtils;
import org.apache.felix.scr.impl.inject.Annotations;
import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.FieldCollectionType;
import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.OsgiMetadata;
import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.Reference;
-import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.ReferencePolicy;
-import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.ReferencePolicyOption;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
@@ -621,60 +618,6 @@ final class OsgiServiceUtil {
return matchingServices;
}
- /**
- * Collects all references of any registered service that match with any of the exported interfaces of the given service registration
- * and are defined as DYNAMIC.
- * @param registeredServices Registered Services
- * @param registration Service registration
- * @return List of references
- */
- public static List<ReferenceInfo> getMatchingDynamicReferences(SortedSet<MockServiceRegistration> registeredServices,
- MockServiceRegistration<?> registration) {
- List<ReferenceInfo> references = new ArrayList<ReferenceInfo>();
- for (MockServiceRegistration existingRegistration : registeredServices) {
- OsgiMetadata metadata = OsgiMetadataUtil.getMetadata(existingRegistration.getService().getClass());
- if (metadata != null) {
- for (Reference reference : metadata.getReferences()) {
- if (reference.getPolicy() == ReferencePolicy.DYNAMIC) {
- for (String serviceInterface : registration.getClasses()) {
- if (StringUtils.equals(serviceInterface, reference.getInterfaceType())) {
- references.add(new ReferenceInfo(existingRegistration, reference));
- }
- }
- }
- }
- }
- }
- return references;
- }
-
- /**
- * Collects all references of any registered service that match with any of the exported interfaces of the given service registration
- * and are defined as STATIC + GREEDY.
- * @param registeredServices Registered Services
- * @param registration Service registration
- * @return List of references
- */
- public static List<ReferenceInfo> getMatchingStaticGreedyReferences(SortedSet<MockServiceRegistration> registeredServices,
- MockServiceRegistration<?> registration) {
- List<ReferenceInfo> references = new ArrayList<ReferenceInfo>();
- for (MockServiceRegistration existingRegistration : registeredServices) {
- OsgiMetadata metadata = OsgiMetadataUtil.getMetadata(existingRegistration.getService().getClass());
- if (metadata != null) {
- for (Reference reference : metadata.getReferences()) {
- if (reference.getPolicy() == ReferencePolicy.STATIC && reference.getPolicyOption() == ReferencePolicyOption.GREEDY) {
- for (String serviceInterface : registration.getClasses()) {
- if (StringUtils.equals(serviceInterface, reference.getInterfaceType())) {
- references.add(new ReferenceInfo(existingRegistration, reference));
- }
- }
- }
- }
- }
- }
- return references;
- }
-
static class ServiceInfo {
private final Object serviceInstance;
--
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.