You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by bd...@apache.org on 2015/07/09 13:05:59 UTC
svn commit: r1690063 - in /sling/whiteboard/bdelacretaz/startup-stuff:
it-startup/src/test/java/org/apache/sling/launchpad/it/startup/
startup-sequencer/src/main/java/org/apache/sling/startup/sequencer/
startup-sequencer/src/main/java/org/apache/sling/...
Author: bdelacretaz
Date: Thu Jul 9 11:05:58 2015
New Revision: 1690063
URL: http://svn.apache.org/r1690063
Log:
SLING-4851 - it works! Each test bundle's SlowActivator now finishes within the same start level where the bundle was asynchronously installed via the OSGi installer
Modified:
sling/whiteboard/bdelacretaz/startup-stuff/it-startup/src/test/java/org/apache/sling/launchpad/it/startup/AsyncInstaller.java
sling/whiteboard/bdelacretaz/startup-stuff/it-startup/src/test/java/org/apache/sling/launchpad/it/startup/IncrementalStartupIT.java
sling/whiteboard/bdelacretaz/startup-stuff/it-startup/src/test/java/org/apache/sling/launchpad/it/startup/P.java
sling/whiteboard/bdelacretaz/startup-stuff/it-startup/src/test/java/org/apache/sling/launchpad/it/startup/SlowActivator.java
sling/whiteboard/bdelacretaz/startup-stuff/startup-sequencer/src/main/java/org/apache/sling/startup/sequencer/StartLevelChangeBarrier.java
sling/whiteboard/bdelacretaz/startup-stuff/startup-sequencer/src/main/java/org/apache/sling/startup/sequencer/impl/StartLevelControllerImpl.java
Modified: sling/whiteboard/bdelacretaz/startup-stuff/it-startup/src/test/java/org/apache/sling/launchpad/it/startup/AsyncInstaller.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/bdelacretaz/startup-stuff/it-startup/src/test/java/org/apache/sling/launchpad/it/startup/AsyncInstaller.java?rev=1690063&r1=1690062&r2=1690063&view=diff
==============================================================================
--- sling/whiteboard/bdelacretaz/startup-stuff/it-startup/src/test/java/org/apache/sling/launchpad/it/startup/AsyncInstaller.java (original)
+++ sling/whiteboard/bdelacretaz/startup-stuff/it-startup/src/test/java/org/apache/sling/launchpad/it/startup/AsyncInstaller.java Thu Jul 9 11:05:58 2015
@@ -24,6 +24,7 @@ import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Dictionary;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
@@ -31,16 +32,21 @@ import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.sling.installer.api.InstallableResource;
import org.apache.sling.installer.api.OsgiInstaller;
+import org.apache.sling.startup.sequencer.StartLevelChangeBarrier;
import org.ops4j.pax.tinybundles.core.TinyBundles;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.FrameworkEvent;
import org.osgi.framework.FrameworkListener;
+import org.osgi.framework.ServiceRegistration;
import org.osgi.service.startlevel.StartLevel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -48,7 +54,7 @@ import org.slf4j.LoggerFactory;
/** Asynchronously installs test bundles when start levels change,
* to verify the Sling incremental startup mechanism.
*/
-class AsyncInstaller implements FrameworkListener {
+class AsyncInstaller implements FrameworkListener, StartLevelChangeBarrier {
private final Logger log = LoggerFactory.getLogger(getClass());
private final BundleContext bundleContext;
@@ -60,6 +66,13 @@ class AsyncInstaller implements Framewor
private final Random random = new Random(42);
private final AtomicInteger counter = new AtomicInteger();
private int lastStartLevel = -1;
+ private final List<ServiceRegistration> toCleanup = new ArrayList<ServiceRegistration>();
+
+ /** Map of InstallableResource keyed by start level - the test bundles to install */
+ private final Map<Integer, List<InstallableResource>> resourceMap = new HashMap<Integer, List<InstallableResource>>();
+
+ /** Map of CountDownLatch keyed by start level - the latches that our bundle activators decrement */
+ private final ConcurrentMap<Integer, CountDownLatch> latchMap = new ConcurrentHashMap<Integer, CountDownLatch>();
/** TinyBundles.add(...) has trouble with classloaders in our environment, so
* add classes via the classpath resources mechanism.
@@ -90,8 +103,30 @@ class AsyncInstaller implements Framewor
startLevelService = s;
installer = inst;
bundleContext.addFrameworkListener(this);
+ toCleanup.add(bundleContext.registerService(StartLevelChangeBarrier.class.getName(), this, null));
+ toCleanup.add(bundleContext.registerService(ConcurrentMap.class.getName(), latchMap, null));
+ }
+
+ void cleanup() {
+ for(ServiceRegistration reg : toCleanup) {
+ reg.unregister();
+ }
}
+ @Override
+ public synchronized CountDownLatch getStartLevelLatch(int startLevel) {
+ // Simulate some resource discovery latency
+ WaitFor.randomWait(156);
+
+ // Create bundles for specified start level if needed,
+ // add their latch to the latch map and return it
+ final List<InstallableResource> res = getOrCreateInstallableResources(startLevel);
+ final CountDownLatch latch = new CountDownLatch(res.size());
+ latchMap.put(startLevel, latch);
+ log.info("Returning CountDownLatch({}) for start level {}", latch.getCount(), startLevel);
+ return latch;
+ }
+
private InputStream getTestBundleStream(String bundleSymbolicName) throws Exception {
final EmbeddedClass activator = new EmbeddedClass(SlowActivator.class);
final EmbeddedClass waitFor = new EmbeddedClass(WaitFor.class);
@@ -103,26 +138,42 @@ class AsyncInstaller implements Framewor
.build(TinyBundles.withBnd());
}
- void installMoreBundles() throws Exception {
- final int n = (int)(random.nextFloat() * P.MAX_BUNDLES_PER_LEVEL);
- final int startLevel = startLevelService.getStartLevel();
- log.info("Installing {} test bundles at start level {}", n, startLevel);
-
- for(int i=0; i < n; i++) {
- final String bsn = bundleNamePrefix + startLevel + "." + counter.incrementAndGet();
- final InputStream is = getTestBundleStream(bsn);
- final Dictionary<String, Object> dict = new Hashtable<String, Object>();
- dict.put(InstallableResource.BUNDLE_START_LEVEL, startLevel);
- resources.add(new InstallableResource(bsn, is, dict, bsn, "bundle", 100));
- installedBundles.add(bsn);
+ synchronized void installBundles(int startLevel) throws Exception {
+ // Simulate some latency
+ WaitFor.randomWait(93);
+
+ final List<InstallableResource> res = getOrCreateInstallableResources(startLevel);
+ log.info("Installing {} InstallableResource (bundles) for start level {}", res.size(), startLevel);
+ for(InstallableResource r : res) {
+ installedBundles.add(r.getId());
}
-
- // Simulate some resource discovery latency
- WaitFor.randomWait(156);
+ resources.addAll(res);
installer.registerResources(getClass().getSimpleName(), resources.toArray(new InstallableResource[]{}));
log.info("A total of {} InstallableResources are now registered", resources.size());
}
+ synchronized List<InstallableResource> getOrCreateInstallableResources(int startLevel) {
+ List<InstallableResource> res = resourceMap.get(startLevel);
+ if(res == null) {
+ try {
+ final int n = (int)(random.nextFloat() * P.MAX_BUNDLES_PER_LEVEL) + 1;
+ log.info("Preparing {} InstallableResources for start level {}", n, startLevel);
+ res = new ArrayList<InstallableResource>();
+ resourceMap.put(startLevel, res);
+ for(int i=0; i < n; i++) {
+ final String bsn = bundleNamePrefix + startLevel + "." + counter.incrementAndGet();
+ final InputStream is = getTestBundleStream(bsn);
+ final Dictionary<String, Object> dict = new Hashtable<String, Object>();
+ dict.put(InstallableResource.BUNDLE_START_LEVEL, startLevel);
+ res.add(new InstallableResource(bsn, is, dict, bsn, "bundle", 100));
+ }
+ } catch(Exception e) {
+ throw new RuntimeException("Exception creating test bundles", e);
+ }
+ }
+ return res;
+ }
+
boolean isTestBundle(Bundle b) {
return b.getSymbolicName().startsWith(bundleNamePrefix);
}
@@ -181,9 +232,7 @@ class AsyncInstaller implements Framewor
final int level = startLevelService.getStartLevel();
log.info("Start level is now {}", level);
try {
- // Simulate some resource discovery latency
- WaitFor.randomWait(56);
- installMoreBundles();
+ installBundles(startLevelService.getStartLevel());
} catch(Exception e) {
log.error("Installing bundles failed", e);
}
Modified: sling/whiteboard/bdelacretaz/startup-stuff/it-startup/src/test/java/org/apache/sling/launchpad/it/startup/IncrementalStartupIT.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/bdelacretaz/startup-stuff/it-startup/src/test/java/org/apache/sling/launchpad/it/startup/IncrementalStartupIT.java?rev=1690063&r1=1690062&r2=1690063&view=diff
==============================================================================
--- sling/whiteboard/bdelacretaz/startup-stuff/it-startup/src/test/java/org/apache/sling/launchpad/it/startup/IncrementalStartupIT.java (original)
+++ sling/whiteboard/bdelacretaz/startup-stuff/it-startup/src/test/java/org/apache/sling/launchpad/it/startup/IncrementalStartupIT.java Thu Jul 9 11:05:58 2015
@@ -43,7 +43,7 @@ public class IncrementalStartupIT {
private final Logger log = LoggerFactory.getLogger(getClass());
public static final int DEFAULT_TIMEOUT = 5;
private Map<String, Integer> startLevelMap;
- private ServiceRegistration startLevelReportReg;
+ private ServiceRegistration startLevelMapReg;
@Inject
protected BundleContext bundleContext;
@@ -80,25 +80,21 @@ public class IncrementalStartupIT {
private void setupReports() {
startLevelMap = new HashMap<String, Integer>();
- log.info("Registering StartLevelReport service");
- startLevelReportReg = bundleContext.registerService(Map.class.getName(), startLevelMap, null);
+ startLevelMapReg = bundleContext.registerService(Map.class.getName(), startLevelMap, null);
}
private void cleanup() {
- if(startLevelReportReg != null) {
- log.info("Unregistering StartLevelReport service");
- startLevelReportReg.unregister();
- startLevelReportReg = null;
+ if(startLevelMapReg != null) {
+ startLevelMapReg.unregister();
+ startLevelMapReg = null;
}
}
@Test
- public void allBundlesActive() throws Exception {
+ public void testInstallAndActivate() throws Exception {
setupReports();
+ final AsyncInstaller ai = new AsyncInstaller(bundleContext, installer, startLevel);
try {
- final AsyncInstaller ai = new AsyncInstaller(bundleContext, installer, startLevel);
- ai.installMoreBundles();
-
final int from = startLevel.getStartLevel();
final int to = from + P.START_LEVEL_CHANGE;
for(int i=from; i <= to; i++) {
@@ -123,7 +119,8 @@ public class IncrementalStartupIT {
};
// No need for a WaitFor here, if the previous test passes all bundles
- // are started
+ // are started. This checks whether our (intentionally slow) test bundle activators
+ // finish excuting before the next start level change
new WaitFor(DEFAULT_TIMEOUT) {
protected boolean condition() {
final Collection<String> issues = ai.getActivatorIssues(startLevelMap);
@@ -135,6 +132,7 @@ public class IncrementalStartupIT {
}
};
} finally {
+ ai.cleanup();
cleanup();
}
}
Modified: sling/whiteboard/bdelacretaz/startup-stuff/it-startup/src/test/java/org/apache/sling/launchpad/it/startup/P.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/bdelacretaz/startup-stuff/it-startup/src/test/java/org/apache/sling/launchpad/it/startup/P.java?rev=1690063&r1=1690062&r2=1690063&view=diff
==============================================================================
--- sling/whiteboard/bdelacretaz/startup-stuff/it-startup/src/test/java/org/apache/sling/launchpad/it/startup/P.java (original)
+++ sling/whiteboard/bdelacretaz/startup-stuff/it-startup/src/test/java/org/apache/sling/launchpad/it/startup/P.java Thu Jul 9 11:05:58 2015
@@ -31,8 +31,8 @@ import org.ops4j.pax.exam.options.Defaul
/** Test parameters and configuration */
public class P {
- public static final int START_LEVEL_CHANGE = 5;
- public static final int MAX_BUNDLES_PER_LEVEL = 3;
+ public static final int START_LEVEL_CHANGE = 17;
+ public static final int MAX_BUNDLES_PER_LEVEL = 39;
public static final int MAX_WAIT_BETWEEN_LEVELS = 200;
public static Option[] paxConfig() {
Modified: sling/whiteboard/bdelacretaz/startup-stuff/it-startup/src/test/java/org/apache/sling/launchpad/it/startup/SlowActivator.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/bdelacretaz/startup-stuff/it-startup/src/test/java/org/apache/sling/launchpad/it/startup/SlowActivator.java?rev=1690063&r1=1690062&r2=1690063&view=diff
==============================================================================
--- sling/whiteboard/bdelacretaz/startup-stuff/it-startup/src/test/java/org/apache/sling/launchpad/it/startup/SlowActivator.java (original)
+++ sling/whiteboard/bdelacretaz/startup-stuff/it-startup/src/test/java/org/apache/sling/launchpad/it/startup/SlowActivator.java Thu Jul 9 11:05:58 2015
@@ -19,6 +19,8 @@
package org.apache.sling.launchpad.it.startup;
import java.util.Map;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CountDownLatch;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
@@ -43,6 +45,7 @@ public class SlowActivator implements Bu
WaitFor.sleep(msec);
+ // Get the current start level
int level = -1;
{
final ServiceReference ref = context.getServiceReference(StartLevel.class.getName());
@@ -54,6 +57,7 @@ public class SlowActivator implements Bu
}
}
+ // Save our start level info to the test report map
{
final ServiceReference ref = context.getServiceReference(Map.class.getName());
try {
@@ -63,6 +67,24 @@ public class SlowActivator implements Bu
} finally {
context.ungetService(ref);
}
+ }
+
+ // And signal that we're done executing
+ {
+ final ServiceReference ref = context.getServiceReference(ConcurrentMap.class.getName());
+ try {
+ @SuppressWarnings("unchecked")
+ final Map<Integer, CountDownLatch> latchMap = (Map<Integer, CountDownLatch> )context.getService(ref);
+ final CountDownLatch cdl = latchMap.get(level);
+ if(cdl == null) {
+ log.warn("CountDownLatch not found for start level {}", level);
+ } else {
+ log.info("Activator done, decrementing CountDownLatch for level {}: {}", level, bsn);
+ cdl.countDown();
+ }
+ } finally {
+ context.ungetService(ref);
+ }
}
}
Modified: sling/whiteboard/bdelacretaz/startup-stuff/startup-sequencer/src/main/java/org/apache/sling/startup/sequencer/StartLevelChangeBarrier.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/bdelacretaz/startup-stuff/startup-sequencer/src/main/java/org/apache/sling/startup/sequencer/StartLevelChangeBarrier.java?rev=1690063&r1=1690062&r2=1690063&view=diff
==============================================================================
--- sling/whiteboard/bdelacretaz/startup-stuff/startup-sequencer/src/main/java/org/apache/sling/startup/sequencer/StartLevelChangeBarrier.java (original)
+++ sling/whiteboard/bdelacretaz/startup-stuff/startup-sequencer/src/main/java/org/apache/sling/startup/sequencer/StartLevelChangeBarrier.java Thu Jul 9 11:05:58 2015
@@ -34,7 +34,4 @@ public interface StartLevelChangeBarrier
* @return a latch or null if none is needed for this level
*/
CountDownLatch getStartLevelLatch(int startLevel);
-
- /** The textual description of this barrier */
- String getDescription();
}
Modified: sling/whiteboard/bdelacretaz/startup-stuff/startup-sequencer/src/main/java/org/apache/sling/startup/sequencer/impl/StartLevelControllerImpl.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/bdelacretaz/startup-stuff/startup-sequencer/src/main/java/org/apache/sling/startup/sequencer/impl/StartLevelControllerImpl.java?rev=1690063&r1=1690062&r2=1690063&view=diff
==============================================================================
--- sling/whiteboard/bdelacretaz/startup-stuff/startup-sequencer/src/main/java/org/apache/sling/startup/sequencer/impl/StartLevelControllerImpl.java (original)
+++ sling/whiteboard/bdelacretaz/startup-stuff/startup-sequencer/src/main/java/org/apache/sling/startup/sequencer/impl/StartLevelControllerImpl.java Thu Jul 9 11:05:58 2015
@@ -18,8 +18,13 @@
*/
package org.apache.sling.startup.sequencer.impl;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.sling.startup.sequencer.StartLevelChangeBarrier;
import org.apache.sling.startup.sequencer.StartLevelController;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.service.startlevel.StartLevel;
import org.slf4j.Logger;
@@ -33,6 +38,9 @@ public class StartLevelControllerImpl im
private final Logger log = LoggerFactory.getLogger(getClass());
private final BundleContext bundleContext;
+ // TODO configurable
+ public static final int LATCH_TIMEOUT_MSEC = 30 * 1000;
+
public StartLevelControllerImpl(BundleContext ctx) {
this.bundleContext = ctx;
}
@@ -43,13 +51,58 @@ public class StartLevelControllerImpl im
throw new IllegalStateException("StartLevel service not found");
}
final StartLevel sl = (StartLevel)bundleContext.getService(ref);
+ final int currentLevel = sl.getStartLevel();
+ final int delta = targetLevel - currentLevel;
try {
- // TODO increment levels one by one and wait at each step
- log.info("Setting start level to {}", targetLevel);
- sl.setStartLevel(targetLevel);
+ if(delta == 0) {
+ log.info("Start level is already {}, change ignored", targetLevel);
+ } else if(delta < 0) {
+ log.info("Start level goes down {} -> {}, immediate change without sequencing", currentLevel, targetLevel);
+ } else {
+ log.info("Start level goes up {} -> {}, will use sequencing", currentLevel, targetLevel);
+ for(int level = currentLevel + 1; level <= targetLevel; level++) {
+ sl.setStartLevel(level);
+ waitForLatches(level);
+ }
+ }
} finally {
bundleContext.ungetService(ref);
}
}
+
+ private void waitForLatches(int startLevel) {
+ ServiceReference [] refs = null;
+ try {
+ refs = bundleContext.getServiceReferences(StartLevelChangeBarrier.class.getName(), null);
+ if(refs == null) {
+ log.info("No StartLevelChangeBarrier services found, won't wait");
+ } else {
+ for(ServiceReference ref : refs) {
+ final StartLevelChangeBarrier b = (StartLevelChangeBarrier)bundleContext.getService(ref);
+ final CountDownLatch cdl = b.getStartLevelLatch(startLevel);
+ if(cdl == null) {
+ log.info("No CountDownLatch provided by {} at start level {}", b, startLevel);
+ } else {
+ log.info("Waiting on CountDownLatch({}) provided by {} at start level {}",
+ new Object[] {cdl.getCount(), b, startLevel});
+ try {
+ cdl.await(LATCH_TIMEOUT_MSEC, TimeUnit.MILLISECONDS);
+ log.info("Done waiting, {} = {}", cdl, cdl.getCount());
+ } catch(InterruptedException iex) {
+ log.warn("InterruptedException while awaiting {}", cdl);
+ }
+ }
+ }
+ }
+ } catch (InvalidSyntaxException e) {
+ throw new RuntimeException("InvalidSyntaxException - should not happen??");
+ } finally {
+ if(refs != null) {
+ for(ServiceReference ref : refs) {
+ bundleContext.ungetService(ref);
+ }
+ }
+ }
+ }
}