You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by pd...@apache.org on 2014/09/22 23:56:32 UTC
svn commit: r1626904 - in
/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager:
./ src/org/apache/felix/dm/ src/org/apache/felix/dm/impl/
Author: pderop
Date: Mon Sep 22 21:56:31 2014
New Revision: 1626904
URL: http://svn.apache.org/r1626904
Log:
Fixed problems and finalized implementation for parallel DM.
Modified:
felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/design.txt
felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/DependencyManager.java
felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/Activator.java
felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ComponentScheduler.java
Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/design.txt
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/design.txt?rev=1626904&r1=1626903&r2=1626904&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/design.txt (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/design.txt Mon Sep 22 21:56:31 2014
@@ -21,29 +21,55 @@ This prototype demonstrates the new conc
* Added support for concurrent mode: To allow components to be handled in parallel, you can now
register in the OSGi service registry a threadpool (java.util.concurrent.Executor) service with
- a "target=org.apache.felix.dependencymanager" service property, and you also have to set the
- "org.apache.felix.dependencymanager.parallel" system property to either "*", or to a list of
- component classnames prefixes. This will allow to handle all component dependencies and all
- component lifecycle callbacks concurrently. Notice that component events are still handled
- serially. The only difference is that multiple components can be handled in parallel. See the
- org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/DispatchExecutor.java for for
- informations.
+ a "target=org.apache.felix.dependencymanager" service property. Then, the dependency manager will
+ use that threadpool for managing components. If you want to ensure that the threadpool is
+ registered in the OSGi registry before all components are started, you have two choices:
+
+- you can first use the start level service and manage to start the management agent bundle which
+ provides the threadpool before all other bundles.
+
+- If the start level service is not an option, then you can use the
+ "org.apache.felix.dependencymanager.parallel" OSGi system property. This property allows
+ to specify all component implementation class name prefixes which have to wait for the thread pool
+ before being started by Dependency Manager. This property can simply take "*", or a list of
+ package prefixes (comma separated). This property can also be used to specify some components
+ which should not be handled using a threadpool, even if one is available from the OSGi
+ registry. To do so, just use a "!" in front of a given classname prefix.
-For example:
+For example: if you want to enable parallelism for all components, just set the system property:
-- if you want to enable parallelism for all components, just set the system property:
+ org.apache.felix.dependencymanager.parallel=*
-org.apache.felix.dependencymanager.parallel=*
-
-- if you want to enable parallelism for some components whose class names is starting with foo.bar
+if you want to enable parallelism for some components whose class names is starting with foo.bar
and foo.zoo:
-org.apache.felix.dependencymanager.parallel=foo.bar, foo.zoo
+ org.apache.felix.dependencymanager.parallel=foo.bar, foo.zoo
+
+if yo want to enable parallelism for all components, except for components whose class names
+ start with "foo.notparallel", then you can use a negation prefix ("!"), like this:
+
+ org.apache.felix.dependencymanager.parallel=!foo.notparallel, *
+
+Using the above property, all components will wait for the threadpool, except components which
+implementation class names which are starting with "foo.notparallel" prefix.
+
+- Notice that if the Dependency Manager API is used for declaring a threadpool and all its related
+ dependent services, then you have to use the "org.apache.felix.dependencymanager.parallel" system
+ property in order to exclude the threadpool DM components from the list of components using the
+ threadpool. As an example, you can take a look at the org.apache.felix.dependencymanager.samples
+ project, which is declaring a threadpool using the Dependency Manager API. The sample is then
+ using the following property in the org.apache.felix.dependencymanager.samples/bnd.bnd file:
+
+ org.apache.felix.dependencymanager.parallel=\
+ '!org.apache.felix.dependencymanager.samples.tpool, *',\
+
+Here, all components except those having a package starting with
+org.apache.felix.dependencymanager.samples.tpool will wait for the threadpool before being initialized
+by Dependency Manager. But the org.apache.felix.dependencymanager.samples.tpool.ThreadPool will not
+wait for a threadpool, since *it is* the threadpool !
+
-- if yo uwant to enable parallelism for all components, except for components whose class names
- start with "foo.notparallel":
-org.apache.felix.dependencymanager.parallel=!foo.parallel, *
Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/DependencyManager.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/DependencyManager.java?rev=1626904&r1=1626903&r2=1626904&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/DependencyManager.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/DependencyManager.java Mon Sep 22 21:56:31 2014
@@ -80,7 +80,6 @@ public class DependencyManager {
private final BundleContext m_context;
private final Logger m_logger;
private final List<Component> m_components = new CopyOnWriteArrayList<>();
- private volatile Executor m_threadPool;
// service registry cache
private static ServiceRegistryCache m_serviceRegistryCache;
@@ -138,15 +137,6 @@ public class DependencyManager {
}
/**
- * Sets a threadpool to this dependency manager. All added/removed components will then be handled
- * in parallel, using the provided threadpool.
- */
- public DependencyManager setThreadPool(Executor threadPool) {
- m_threadPool = threadPool;
- return this;
- }
-
- /**
* Returns the list of currently created dependency managers.
* @return the list of currently created dependency managers
*/
@@ -188,14 +178,7 @@ public class DependencyManager {
*/
public void add(Component c) {
m_components.add(c);
- if (useComponentSchedulerFor(c)) {
- ComponentScheduler.instance().add(c);
- } else {
- if (m_threadPool != null) {
- ((ComponentContext) c).setThreadPool(m_threadPool);
- }
- ((ComponentContext) c).start();
- }
+ ComponentScheduler.instance().add(c);
}
/**
@@ -205,11 +188,7 @@ public class DependencyManager {
* @param service the service to remove
*/
public void remove(Component c) {
- if (useComponentSchedulerFor(c)) {
- ComponentScheduler.instance().remove(c);
- } else {
- ((ComponentContext) c).stop();
- }
+ ComponentScheduler.instance().remove(c);
m_components.remove(c);
}
@@ -701,44 +680,4 @@ public class DependencyManager {
return context;
}
}
-
- /**
- * Determine if the component scheduler should be used for a given component. The scheduler is used if all the
- * following conditions are true:
- * - The user has not set a threadpool using {@link #setThreadPool(Executor)}.
- * - the {@link #PARALLEL} system property is set to a comma separated list of prefix of component classnames
- * which have to be activated using the threadpool. Notice that prefixes can be negated using "!".
- *
- * When used, the scheduler will bufferize all activated DM components until a threadpool with a
- * {@link #THREADPOOL} service property is registered in the OSGi registry. And at the point where the
- * threadpool comes in, then all bufferized components will be activated using that threadpool.
- * This simple mechanism allows to avoid to use a start level service in order to wait for the threadpool before
- * activating any DM components.
- *
- * @return true if the component scheduler should be used, false if not.
- */
- private boolean useComponentSchedulerFor(Component c) {
- if (m_threadPool != null) {
- return false;
- }
-
- String parallel = m_context.getProperty(DependencyManager.PARALLEL);
- if (parallel != null) {
- for (String prefix : parallel.trim().split(",")) {
- boolean not = prefix.startsWith("!");
- if (not) {
- prefix = prefix.substring(1);
- }
- if ("*".equals(prefix)) {
- return !not;
- }
-
- if (c.getComponentDeclaration().getClassName().startsWith(prefix)) {
- return !not;
- }
- }
- }
-
- return false;
- }
}
Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/Activator.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/Activator.java?rev=1626904&r1=1626903&r2=1626904&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/Activator.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/Activator.java Mon Sep 22 21:56:31 2014
@@ -28,23 +28,18 @@ import org.osgi.framework.BundleContext;
* DependencyManager Activator. We are using this activator in order to track and use a threadpool, which can be
* optionally registered by any management agent bundle.
* The management agent can just register a <code>java.util.Executor</code> service in the service registry
- * using the "target=org.apache.felix.dependencymanager" property, and the "org.apache.felix.dependencymanager.parallel"
- * OSGi system property must also be configured to "true".
+ * using the "target=org.apache.felix.dependencymanager" property.
*
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
public class Activator extends DependencyActivatorBase {
@Override
public void init(BundleContext ctx, DependencyManager mgr) throws Exception {
- boolean parallelModeEnabled = ctx.getProperty(DependencyManager.PARALLEL) != null;
-
- if (parallelModeEnabled) {
- mgr.add(createComponent()
- .setImplementation(ComponentScheduler.instance())
- .add(createTemporalServiceDependency(10000)
- .setService(Executor.class, "(target=" + DependencyManager.THREADPOOL + ")")
- .setRequired(true)
- .setAutoConfig("m_threadPool")));
- }
+ mgr.add(createComponent()
+ .setImplementation(ComponentScheduler.instance())
+ .add(createServiceDependency()
+ .setService(Executor.class, "(target=" + DependencyManager.THREADPOOL + ")")
+ .setRequired(true)
+ .setCallbacks("bind", "unbind")));
}
}
Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ComponentScheduler.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ComponentScheduler.java?rev=1626904&r1=1626903&r2=1626904&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ComponentScheduler.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ComponentScheduler.java Mon Sep 22 21:56:31 2014
@@ -18,68 +18,97 @@
*/
package org.apache.felix.dm.impl;
-import java.util.Dictionary;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.concurrent.Executor;
import org.apache.felix.dm.Component;
import org.apache.felix.dm.ComponentDeclaration;
-import org.apache.felix.dm.DependencyManager;
import org.apache.felix.dm.context.ComponentContext;
+import org.osgi.framework.BundleContext;
/**
- * When a DependencyManager is not explicitly configured with a threadpool, and when parallel mode is enabled,
- * then added components are delegated to this class, which will cache all added components until one threadpool
- * is registered in the OSGi service registry.
- *
- * Parallel mode can be enabled by default by doing this:
- *
- * - register a threadpool (java.util.concurrent.Executor) into the OSGi service registry with the
- * "target=org.apache.felix.dependencymanager" property.
- *
- * - and set the "org.apache.felix.dependencymanager.parallel" system property to either "*" or to some component classname
- * prefixes. Note that you can specify several class name prefixes, and that some prefixes can be negated using "!".
- *
+ * The Dependency Manager delegates all components addition/removal to this class, which is in charge of tracking
+ * a threadpool from the OSGi registry in order to handle components concurrently.
+ *
+ * By default, an external management bundle may register a threadpool (java.util.concurrent.Executor) with a
+ * special "target=org.apache.felix.dependencymanager" service property. So, if the threadpool is registered, then
+ * any components added will use that threadpool.
+ *
+ * If you want to ensure that all components must wait for a threadpool, before they are actually added
+ * in a dependency manager, you can simply use the "org.apache.felix.dependencymanager.parallel" OSGi system
+ * property, which can specify the list of components which must wait for the threadpool.
+ * This property value can be a wildcard ("*"), or a list of components implementation class prefixes
+ * (comma seperated). So, all components class names starting with the specified prefixes will be cached until the
+ * threadpool becomes available.
+ * Some class name prefixes can also be negated (using "!"), in order to exclude some components from the list of
+ * components using the threadpool.
+ *
+ * Notice that if the threadpool and all the services it may depends on are also declared using the
+ * Dependency Manager API, then you have to list the package of such components with a "!" prefix, in order to
+ * indicat that those components must not wait for a threadpool (since they are part of the threadpool
+ * implementation !).
+ *
+ * Examples:
+ *
+ * org.apache.felix.dependencymanager.parallel=*
+ * -> means all components must be cached until a threadpool comes up.
+ *
+ * org.apache.felix.dependencymanager.parallel=foo.bar, foo.zoo
+ * -> means only components whose implementation class names is starting with "foo.bar" or "foo.zoo" must wait for and
+ * use a threadpool.
+ *
+ * org.apache.felix.dependencymanager.parallel=!foo.threadpool, *
+ * -> means all components must wait for and use a threadpool, except the threadpool components implementations class names
+ * (starting with foo.threadpool prefix).
+ *
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
public class ComponentScheduler {
private final static ComponentScheduler m_instance = new ComponentScheduler();
+ private final static String PARALLEL = "org.apache.felix.dependencymanager.parallel";
private volatile Executor m_threadPool;
private final Executor m_serial = new SerialExecutor(null);
- private boolean m_started;
private Set<Component> m_pending = new LinkedHashSet<>();
public static ComponentScheduler instance() {
return m_instance;
}
- protected void start() {
+ protected void bind(final Executor threadPool) {
+ m_threadPool = threadPool;
m_serial.execute(new Runnable() {
@Override
public void run() {
- m_started = true;
for (Component c : m_pending) {
- addUsingThreadPool(c);
+ ((ComponentContext) c).setThreadPool(threadPool);
+ ((ComponentContext) c).start();
}
m_pending.clear();
}
});
}
+ protected void unbind(Executor threadPool) {
+ m_threadPool = null;
+ }
+
public void add(final Component c) {
- if (!isParallelComponent(c)) {
+ if (mayStartNow(c)) {
((ComponentContext) c).start();
}
else {
+ // The component requires a threadpool: delay execution until one is available.
m_serial.execute(new Runnable() {
@Override
public void run() {
- if (!m_started) {
+ Executor threadPool = m_threadPool;
+ if (threadPool == null) {
m_pending.add(c);
}
else {
- addUsingThreadPool(c);
+ ((ComponentContext) c).setThreadPool(threadPool);
+ ((ComponentContext) c).start();
}
}
});
@@ -87,48 +116,60 @@ public class ComponentScheduler {
}
public void remove(final Component c) {
- if (!isParallelComponent(c)) {
- ((ComponentContext) c).stop();
- }
- else {
- m_serial.execute(new Runnable() {
- @Override
- public void run() {
- if (!m_started) {
- m_pending.remove(c);
- }
- else {
- ((ComponentContext) c).stop();
- }
+ m_serial.execute(new Runnable() {
+ @Override
+ public void run() {
+ if (!m_pending.remove(c)) {
+ ((ComponentContext) c).stop();
}
- });
- }
+ }
+ });
}
- private void addUsingThreadPool(Component c) {
- ((ComponentContext) c).setThreadPool(m_threadPool);
- ((ComponentContext) c).start();
+ private boolean mayStartNow(Component c) {
+ Executor threadPool = m_threadPool;
+ BundleContext ctx = c.getDependencyManager().getBundleContext();
+ String parallel = ctx.getProperty(PARALLEL);
+
+ if (threadPool == null) {
+ // No threadpool available. If a "parallel" OSGi system property is specified, we have to wait for a
+ // threadpool if the component class name is matching one of the prefixes specified in the "parallel"
+ // system property.
+ if (parallel != null && requiresThreadPool(c, parallel)) {
+ return false; // wait for a threadpool
+ } else {
+ return true; // no threadpool required, start the component now, synchronously
+ }
+ }
+ else {
+ // A threadpool is there. If the "parallel" OSGi system property not specified, we can start the component
+ // now and we'll use the threadpool for it.
+ // But if the "parallel" system property is specified, the component will use the threadpool only if it's
+ // classname is starting with one of the prefixes specified in the property.
+ if (parallel == null || requiresThreadPool(c, parallel)) {
+ ((ComponentContext) c).setThreadPool(threadPool);
+ }
+ return true; // start the component now, possibly using the threadpool (see above).
+ }
}
- private boolean isParallelComponent(Component c) {
+ private boolean requiresThreadPool(Component c, String parallel) {
// The component declared from our DM Activator can not be parallel.
ComponentDeclaration decl = c.getComponentDeclaration();
if (ComponentScheduler.class.getName().equals(decl.getName())) {
return false;
}
- // A threadpool component declared by a "management agent" using DM API cannot be itself parallel.
- String[] services = decl.getServices();
- if (services != null) {
- for (String service : services) {
- if (Executor.class.getName().equals(service)) {
- Dictionary<?, ?> props = decl.getServiceProperties();
- if (props != null && DependencyManager.THREADPOOL.equals(props.get("target"))) {
- return false;
- }
- }
+ for (String prefix : parallel.trim().split(",")) {
+ prefix = prefix.trim();
+ boolean not = prefix.startsWith("!");
+ if (not) {
+ prefix = prefix.substring(1).trim();
+ }
+ if ("*".equals(prefix) || c.getComponentDeclaration().getClassName().startsWith(prefix)) {
+ return !not;
}
}
- return true;
+ return false;
}
}