diff options
10 files changed, 212 insertions, 31 deletions
diff --git a/bundles/org.eclipse.osgi.tests/.settings/org.eclipse.pde.prefs b/bundles/org.eclipse.osgi.tests/.settings/org.eclipse.pde.prefs new file mode 100644 index 000000000..2174e4fd5 --- /dev/null +++ b/bundles/org.eclipse.osgi.tests/.settings/org.eclipse.pde.prefs @@ -0,0 +1,34 @@ +compilers.f.unresolved-features=1 +compilers.f.unresolved-plugins=1 +compilers.incompatible-environment=1 +compilers.p.build=1 +compilers.p.build.bin.includes=1 +compilers.p.build.encodings=2 +compilers.p.build.java.compiler=2 +compilers.p.build.java.compliance=1 +compilers.p.build.missing.output=2 +compilers.p.build.output.library=1 +compilers.p.build.source.library=1 +compilers.p.build.src.includes=1 +compilers.p.deprecated=1 +compilers.p.discouraged-class=1 +compilers.p.internal=1 +compilers.p.missing-packages=2 +compilers.p.missing-version-export-package=2 +compilers.p.missing-version-import-package=2 +compilers.p.missing-version-require-bundle=2 +compilers.p.no-required-att=0 +compilers.p.no.automatic.module=1 +compilers.p.not-externalized-att=2 +compilers.p.service.component.without.lazyactivation=1 +compilers.p.unknown-attribute=1 +compilers.p.unknown-class=1 +compilers.p.unknown-element=1 +compilers.p.unknown-identifier=1 +compilers.p.unknown-resource=1 +compilers.p.unresolved-ex-points=0 +compilers.p.unresolved-import=0 +compilers.s.create-docs=false +compilers.s.doc-folder=doc +compilers.s.open-tags=1 +eclipse.preferences.version=1 diff --git a/bundles/org.eclipse.osgi.tests/META-INF/MANIFEST.MF b/bundles/org.eclipse.osgi.tests/META-INF/MANIFEST.MF index 2524696c8..7b8f8cef6 100644 --- a/bundles/org.eclipse.osgi.tests/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.osgi.tests/META-INF/MANIFEST.MF @@ -2,15 +2,14 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Core OSGi Tests Bundle-SymbolicName: org.eclipse.osgi.tests;singleton:=true -Bundle-Version: 3.13.600.qualifier +Bundle-Version: 3.15.0.qualifier Bundle-Vendor: Eclipse.org -Bundle-Localization: plugin Require-Bundle: org.eclipse.core.runtime, org.eclipse.core.tests.harness, org.eclipse.test.performance, org.junit -Eclipse-LazyStart: true +Bundle-ActivationPolicy: lazy Bundle-Activator: org.eclipse.osgi.tests.OSGiTestsActivator Import-Package: org.osgi.service.event; resolution:="optional" Export-Package: org.eclipse.osgi.tests.bundles, diff --git a/bundles/org.eclipse.osgi.tests/pom.xml b/bundles/org.eclipse.osgi.tests/pom.xml index 8c07556e5..8ea1c04f2 100644 --- a/bundles/org.eclipse.osgi.tests/pom.xml +++ b/bundles/org.eclipse.osgi.tests/pom.xml @@ -19,7 +19,7 @@ </parent> <groupId>org.eclipse.osgi</groupId> <artifactId>org.eclipse.osgi.tests</artifactId> - <version>3.13.600-SNAPSHOT</version> + <version>3.15.0-SNAPSHOT</version> <packaging>eclipse-test-plugin</packaging> <properties> diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/SystemBundleTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/SystemBundleTests.java index 301eb47e4..b159cddff 100755 --- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/SystemBundleTests.java +++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/SystemBundleTests.java @@ -69,6 +69,7 @@ import org.eclipse.core.runtime.adaptor.EclipseStarter; import org.eclipse.equinox.log.ExtendedLogReaderService; import org.eclipse.equinox.log.ExtendedLogService; import org.eclipse.equinox.log.test.TestListener2; +import org.eclipse.osgi.container.Module; import org.eclipse.osgi.framework.util.FilePath; import org.eclipse.osgi.internal.debug.Debug; import org.eclipse.osgi.internal.framework.EquinoxConfiguration; @@ -3581,38 +3582,53 @@ public class SystemBundleTests extends AbstractBundleTests { } public void testStartLevelMultiThreadExplicit4() throws IOException, InterruptedException { - doTestStartLevelMultiThread(4); + doTestStartLevelMultiThread(4, false); } public void testStartLevelMultiThreadExplicit1() throws IOException, InterruptedException { - doTestStartLevelMultiThread(1); + doTestStartLevelMultiThread(1, false); } public void testStartLevelMultiThreadAvailableProcessors() throws IOException, InterruptedException { - doTestStartLevelMultiThread(0); + doTestStartLevelMultiThread(0, false); } - private void doTestStartLevelMultiThread(int expectedCount) throws IOException, InterruptedException { + public void testStartLevelRestrictMultiThreadExplicit4() throws IOException, InterruptedException { + doTestStartLevelMultiThread(4, true); + } + + private void doTestStartLevelMultiThread(int expectedCount, final boolean restrictParallel) throws IOException, InterruptedException { File config = OSGiTestsActivator.getContext().getDataFile(getName()); //$NON-NLS-1$ Map<String, String> configuration = new HashMap(); configuration.put(Constants.FRAMEWORK_STORAGE, config.getAbsolutePath()); configuration.put(EquinoxConfiguration.PROP_EQUINOX_START_LEVEL_THREAD_COUNT, String.valueOf(expectedCount)); + if (restrictParallel) { + configuration.put(EquinoxConfiguration.PROP_EQUINOX_START_LEVEL_RESTRICT_PARALLEL, "true"); + } if (expectedCount <= 0) { expectedCount = Runtime.getRuntime().availableProcessors(); } Equinox equinox = null; - final int numBundles = 40; + final int numBundles = 60; final File[] testBundleFiles = createBundles(new File(config, "testBundles"), numBundles); try { equinox = new Equinox(configuration); equinox.start(); + FrameworkWiring fwkWiring = equinox.adapt(FrameworkWiring.class); for (int i = 0; i < numBundles; i++) { Bundle b = equinox.getBundleContext().installBundle("reference:file:///" + testBundleFiles[i].getAbsolutePath()); - if (i < 20) { + if (i < 30) { b.adapt(BundleStartLevel.class).setStartLevel(5); } else { b.adapt(BundleStartLevel.class).setStartLevel(10); } + Module m = b.adapt(Module.class); + assertFalse("Wrong initial value for parallelActivation", m.isParallelActivated()); + if (b.getBundleId() % 2 == 0) { + b.adapt(Module.class).setParallelActivation(true); + assertTrue("Wrong value for parallelActivation", m.isParallelActivated()); + } + fwkWiring.resolveBundles(Collections.singleton(b)); b.start(); } @@ -3643,16 +3659,35 @@ public class SystemBundleTests extends AbstractBundleTests { waitForStartLevel.await(20, TimeUnit.SECONDS); assertEquals("Did not finish start level setting.", 0, waitForStartLevel.getCount()); - assertEquals("Wrong number of start threads.", expectedCount, startingThreads.size()); + if (restrictParallel && expectedCount > 1) { + // when restricting parallel start the restricted bundles will start on + // the dispatching thread adding one more thread + assertEquals("Wrong number of start threads.", expectedCount + 1, startingThreads.size()); + } else { + assertEquals("Wrong number of start threads.", expectedCount, startingThreads.size()); + } assertEquals("Wrong number of started bundles.", numBundles, startingBundles.size()); ListIterator<Bundle> itr = startingBundles.listIterator(); while (itr.hasNext()) { - Bundle b2 = itr.next(); if (itr.hasPrevious()) { Bundle b1 = itr.previous(); itr.next(); - assertTrue("Wrong order to starting bundle.", b1.adapt(BundleStartLevel.class).getStartLevel() <= b2.adapt(BundleStartLevel.class).getStartLevel()); + Bundle b2 = itr.next(); + + int b1sl = b1.adapt(BundleStartLevel.class).getStartLevel(); + int b2sl = b2.adapt(BundleStartLevel.class).getStartLevel(); + assertTrue("Wrong order to start bundles: " + b1 + " - " + b2, b1sl <= b2sl); + if (restrictParallel && b1sl == b2sl) { + boolean b1pa = b1.adapt(Module.class).isParallelActivated(); + boolean b2pa = b2.adapt(Module.class).isParallelActivated(); + assertTrue("Wrong order to start bundles: " + b1 + " - " + b2, b1pa || (!b1pa && !b2pa)); + if (!b1pa) { + assertTrue("Wrong order to start bundles: " + b1 + " - " + b2, b1.getBundleId() < b2.getBundleId()); + } + } + } else { + itr.next(); } } } catch (BundleException e) { @@ -3671,6 +3706,63 @@ public class SystemBundleTests extends AbstractBundleTests { } } + public void testParallelActivationPersistence() throws IOException, BundleException { + File config = OSGiTestsActivator.getContext().getDataFile(getName()); //$NON-NLS-1$ + Map<String, String> configuration = new HashMap(); + configuration.put(Constants.FRAMEWORK_STORAGE, config.getAbsolutePath()); + final int numBundles = 4; + final File[] testBundleFiles = createBundles(new File(config, "testParallelPersistence"), numBundles); + Equinox equinox = null; + try { + equinox = new Equinox(configuration); + equinox.start(); + FrameworkWiring fwkWiring = equinox.adapt(FrameworkWiring.class); + for (int i = 0; i < numBundles; i++) { + Bundle b = equinox.getBundleContext().installBundle("reference:file:///" + testBundleFiles[i].getAbsolutePath()); + Module m = b.adapt(Module.class); + assertFalse("Wrong initial value for parallelActivation", m.isParallelActivated()); + if (b.getBundleId() % 2 == 0) { + b.adapt(Module.class).setParallelActivation(true); + assertTrue("Wrong value for parallelActivation", m.isParallelActivated()); + } + fwkWiring.resolveBundles(Collections.singleton(b)); + b.start(); + } + equinox.stop(); + try { + equinox.waitForStop(1000); + } catch (InterruptedException e) { + fail("Unexpected interrupted exception", e); //$NON-NLS-1$ + } + equinox = null; + equinox = new Equinox(configuration); + equinox.start(); + Bundle[] bundles = equinox.getBundleContext().getBundles(); + assertEquals("Wrong number of bundles on restart.", numBundles + 1, bundles.length); + for (Bundle b : bundles) { + if (b.getBundleId() == 0) { + continue; + } + if (b.getBundleId() % 2 == 0) { + assertTrue("Wrong value for parallelActivation", b.adapt(Module.class).isParallelActivated()); + } else { + assertFalse("Wrong value for parallelActivation", b.adapt(Module.class).isParallelActivated()); + } + } + } finally { + try { + if (equinox != null) { + equinox.stop(); + equinox.waitForStop(1000); + } + } catch (BundleException e) { + fail("Failed to stop framework.", e); + } catch (InterruptedException e) { + fail("Failed to stop framework.", e); + } + } + } + public void testBundleIDLock() { File config = OSGiTestsActivator.getContext().getDataFile(getName()); //$NON-NLS-1$ Map<String, Object> configuration = new HashMap<String, Object>(); diff --git a/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF b/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF index fc081bfdb..768511155 100644 --- a/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2 Export-Package: org.eclipse.core.runtime.adaptor;x-friends:="org.eclipse.core.runtime", org.eclipse.core.runtime.internal.adaptor;x-internal:=true, org.eclipse.equinox.log;version="1.1";uses:="org.osgi.framework,org.osgi.service.log", - org.eclipse.osgi.container;version="1.4"; + org.eclipse.osgi.container;version="1.5"; uses:="org.eclipse.osgi.report.resolution, org.osgi.framework.wiring, org.osgi.framework.startlevel, @@ -101,7 +101,7 @@ Bundle-Activator: org.eclipse.osgi.internal.framework.SystemBundleActivator Bundle-Description: %systemBundle Bundle-Copyright: %copyright Bundle-Vendor: %eclipse.org -Bundle-Version: 3.14.100.qualifier +Bundle-Version: 3.15.0.qualifier Bundle-Localization: systembundle Bundle-DocUrl: http://www.eclipse.org Eclipse-ExtensibleAPI: true diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/Module.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/Module.java index 3d6cfbf5b..4a8d7e723 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/Module.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/Module.java @@ -151,7 +151,12 @@ public abstract class Module implements BundleReference, BundleStartLevel, Compa /** * The module has been set to use its activation policy. */ - USE_ACTIVATION_POLICY + USE_ACTIVATION_POLICY, + /** + * The module has been set for parallel activation from start-level + * @since 3.15 + */ + PARALLEL_ACTIVATION } /** @@ -693,11 +698,37 @@ public abstract class Module implements BundleReference, BundleStartLevel, Compa private void persistStopOptions(StopOptions... options) { if (StopOptions.TRANSIENT.isContained(options)) return; - settings.clear(); + settings.remove(Settings.USE_ACTIVATION_POLICY); + settings.remove(Settings.AUTO_START); + revisions.getContainer().moduleDatabase.persistSettings(settings, this); + } + + /** + * Set if this module should be activated in parallel with other modules that have + * the same {@link #getStartLevel() start level}. + * @param parallelActivation true if the module should be started in parallel; false otherwise + * @since 3.15 + */ + public void setParallelActivation(boolean parallelActivation) { + if (parallelActivation) { + settings.add(Settings.PARALLEL_ACTIVATION); + } else { + settings.remove(Settings.PARALLEL_ACTIVATION); + } revisions.getContainer().moduleDatabase.persistSettings(settings, this); } /** + * Returns if this module should be activated in parallel with other modules that have + * the same {@link #getStartLevel() start level}. + * @return true if the module should be started in parallel; false otherwise + * @since 3.15 + */ + public boolean isParallelActivated() { + return settings.contains(Settings.PARALLEL_ACTIVATION); + } + + /** * The container is done with the revision and it has been completely removed. * This method allows the resources behind the revision to be cleaned up. * @param revision the revision to clean up diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleContainer.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleContainer.java index 319b21f5d..c248ff4e2 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleContainer.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleContainer.java @@ -131,6 +131,8 @@ public final class ModuleContainer implements DebugOptionsListener { private final boolean autoStartOnResolve; + final boolean restrictParallelStart; + boolean DEBUG_MONITOR_LAZY = false; boolean DEBUG_BUNDLE_START_TIME = false; @@ -169,6 +171,7 @@ public final class ModuleContainer implements DebugOptionsListener { autoStartOnResolveProp = Boolean.toString(true); } this.autoStartOnResolve = Boolean.parseBoolean(autoStartOnResolveProp); + this.restrictParallelStart = Boolean.parseBoolean(adaptor.getProperty(EquinoxConfiguration.PROP_EQUINOX_START_LEVEL_RESTRICT_PARALLEL)); } /** @@ -1713,7 +1716,9 @@ public final class ModuleContainer implements DebugOptionsListener { long currentTimestamp = Long.MIN_VALUE; if (newStartLevel > currentSL) { List<Module> lazyStart = null; + List<Module> lazyStartParallel = null; List<Module> eagerStart = null; + List<Module> eagerStartParallel = null; for (int i = currentSL; i < newStartLevel; i++) { int toStartLevel = i + 1; activeStartLevel.set(toStartLevel); @@ -1725,14 +1730,16 @@ public final class ModuleContainer implements DebugOptionsListener { try { sorted = moduleDatabase.getSortedModules(Sort.BY_START_LEVEL); lazyStart = new ArrayList<>(sorted.size()); + lazyStartParallel = new ArrayList<>(sorted.size()); eagerStart = new ArrayList<>(sorted.size()); - separateModulesByActivationPolicy(sorted, lazyStart, eagerStart); + eagerStartParallel = new ArrayList<>(sorted.size()); + separateModulesByActivationPolicy(sorted, lazyStart, lazyStartParallel, eagerStart, eagerStartParallel); currentTimestamp = moduleDatabase.getTimestamp(); } finally { moduleDatabase.readUnlock(); } } - incStartLevel(toStartLevel, lazyStart, eagerStart); + incStartLevel(toStartLevel, lazyStart, lazyStartParallel, eagerStart, eagerStartParallel); } } else { for (int i = currentSL; i > newStartLevel; i--) { @@ -1765,26 +1772,38 @@ public final class ModuleContainer implements DebugOptionsListener { } } - private void incStartLevel(int toStartLevel, List<Module> lazyStart, List<Module> eagerStart) { - incStartLevel(toStartLevel, lazyStart); - incStartLevel(toStartLevel, eagerStart); + private void incStartLevel(int toStartLevel, List<Module> lazyStart, List<Module> lazyStartParallel, List<Module> eagerStart, List<Module> eagerStartParallel) { + // start lazy activated first + // start parallel bundles first + incStartLevel(toStartLevel, lazyStartParallel, true); + incStartLevel(toStartLevel, lazyStart, false); + incStartLevel(toStartLevel, eagerStartParallel, true); + incStartLevel(toStartLevel, eagerStart, false); } - private void separateModulesByActivationPolicy(List<Module> sortedModules, List<Module> lazyStart, List<Module> eagerStart) { + private void separateModulesByActivationPolicy(List<Module> sortedModules, List<Module> lazyStart, List<Module> lazyStartParallel, List<Module> eagerStart, List<Module> eagerStartParallel) { for (Module module : sortedModules) { - if (module.isLazyActivate()) { - lazyStart.add(module); + if (!restrictParallelStart || module.isParallelActivated()) { + if (module.isLazyActivate()) { + lazyStartParallel.add(module); + } else { + eagerStartParallel.add(module); + } } else { - eagerStart.add(module); + if (module.isLazyActivate()) { + lazyStart.add(module); + } else { + eagerStart.add(module); + } } } } - private void incStartLevel(final int toStartLevel, List<Module> candidatesToStart) { + private void incStartLevel(final int toStartLevel, List<Module> candidatesToStart, boolean inParallel) { if (candidatesToStart.isEmpty()) { return; } - List<Module> toStart = new ArrayList<>(); + final List<Module> toStart = new ArrayList<>(); for (final Module module : candidatesToStart) { if (isRefreshingSystemModule()) { return; @@ -1807,7 +1826,12 @@ public final class ModuleContainer implements DebugOptionsListener { if (toStart.isEmpty()) { return; } - final Executor executor = adaptor.getStartLevelExecutor(); + final Executor executor = inParallel ? adaptor.getStartLevelExecutor() : new Executor() { + @Override + public void execute(Runnable command) { + command.run(); + } + }; final CountDownLatch done = new CountDownLatch(toStart.size()); for (final Module module : toStart) { executor.execute(new Runnable() { diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleDatabase.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleDatabase.java index 6d7cfc4f5..a25ed24f1 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleDatabase.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleDatabase.java @@ -957,7 +957,7 @@ public class ModuleDatabase { } private static class Persistence { - private static final int VERSION = 2; + private static final int VERSION = 3; private static final byte NULL = 0; private static final byte OBJECT = 1; private static final byte INDEX = 2; diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/EquinoxConfiguration.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/EquinoxConfiguration.java index cdf363c88..a6f8da3a6 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/EquinoxConfiguration.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/EquinoxConfiguration.java @@ -227,6 +227,7 @@ public class EquinoxConfiguration implements EnvironmentInfo { public static final String PROP_RESOLVER_THREAD_COUNT = "equinox.resolver.thead.count"; //$NON-NLS-1$ public static final String PROP_EQUINOX_RESOLVER_THREAD_COUNT = "equinox.resolver.thread.count"; //$NON-NLS-1$ public static final String PROP_EQUINOX_START_LEVEL_THREAD_COUNT = "equinox.start.level.thread.count"; //$NON-NLS-1$ + public static final String PROP_EQUINOX_START_LEVEL_RESTRICT_PARALLEL = "equinox.start.level.restrict.parallel"; //$NON-NLS-1$ public static final String PROP_RESOLVER_REVISION_BATCH_SIZE = "equinox.resolver.revision.batch.size"; //$NON-NLS-1$ public static final String PROP_RESOLVER_BATCH_TIMEOUT = "equinox.resolver.batch.timeout"; //$NON-NLS-1$ diff --git a/bundles/org.eclipse.osgi/pom.xml b/bundles/org.eclipse.osgi/pom.xml index 9ae03a65b..dffff72d5 100644 --- a/bundles/org.eclipse.osgi/pom.xml +++ b/bundles/org.eclipse.osgi/pom.xml @@ -19,7 +19,7 @@ </parent> <groupId>org.eclipse.osgi</groupId> <artifactId>org.eclipse.osgi</artifactId> - <version>3.14.100-SNAPSHOT</version> + <version>3.15.0-SNAPSHOT</version> <packaging>eclipse-plugin</packaging> <build> |