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 2016/12/30 14:17:39 UTC
svn commit: r1776574 - in
/felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm:
DependencyManager.java impl/ComponentImpl.java impl/InvocationUtil.java
Author: pderop
Date: Fri Dec 30 14:17:39 2016
New Revision: 1776574
URL: http://svn.apache.org/viewvc?rev=1776574&view=rev
Log:
FELIX-5471: Make sure dependency remove event is always handled synchronously, even if a threadpool is used.
Modified:
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/DependencyManager.java
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ComponentImpl.java
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/InvocationUtil.java
Modified: felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/DependencyManager.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/DependencyManager.java?rev=1776574&r1=1776573&r2=1776574&view=diff
==============================================================================
--- felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/DependencyManager.java (original)
+++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/DependencyManager.java Fri Dec 30 14:17:39 2016
@@ -70,6 +70,19 @@ public class DependencyManager {
public static final String SERVICEREGISTRY_CACHE_INDICES = "org.apache.felix.dependencymanager.filterindex";
public static final String METHOD_CACHE_SIZE = "org.apache.felix.dependencymanager.methodcache";
+ /**
+ * Max time we can wait for execution of some tasks which must be handled synchronously through the internal component
+ * executor (which can be a threadpool).
+ * Typically, this timeout is used when a component is stopped or if a dependency is being unbound from a given
+ * component.
+ */
+ public static final String SCHEDULE_TIMEOUT = "org.apache.felix.dependencymanager.scheduletimeout";
+
+ /**
+ * Default value for the SCHEDULE_TIMEOUT parameter, in millis.
+ */
+ public static volatile long SCHEDUME_TIMEOUT_VAL = 30000;
+
private final BundleContext m_context;
private final Logger m_logger;
private final ConcurrentHashMap<Component, Component> m_components = new ConcurrentHashMap<>();
@@ -102,6 +115,14 @@ public class DependencyManager {
}
}
}
+
+ String scheduleTimeout = bundleContext.getProperty(SCHEDULE_TIMEOUT);
+ if (scheduleTimeout != null) {
+ try {
+ SCHEDUME_TIMEOUT_VAL = Long.valueOf(scheduleTimeout);
+ } catch (NumberFormatException e) {
+ }
+ }
}
}
catch (BundleException e) {
Modified: felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ComponentImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ComponentImpl.java?rev=1776574&r1=1776573&r2=1776574&view=diff
==============================================================================
--- felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ComponentImpl.java (original)
+++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ComponentImpl.java Fri Dec 30 14:17:39 2016
@@ -43,7 +43,11 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
@@ -279,9 +283,11 @@ public class ComponentImpl implements Co
*/
private boolean m_startCalled;
- // Used to track the last state we delivered to any state listeners.
+ /**
+ * Used to track the last state we delivered to any state listeners.
+ */
private ComponentState m_lastStateDeliveredToListeners = ComponentState.INACTIVE;
-
+
/**
* Default component declaration implementation.
*/
@@ -419,22 +425,12 @@ public class ComponentImpl implements Co
@Override
public void stop() {
if (m_active.compareAndSet(true, false)) {
- Executor executor = getExecutor();
-
- // First, declare the task that will stop our component in our executor.
- final Runnable stopTask = () -> {
- m_isStarted = false;
- handleChange();
- };
-
// Now, we have to schedule our stopTask in our component executor. If the executor is a parallel
// dispatcher, then try to invoke our stop task synchronously (it does not make sense to try to stop a component asynchronously).
-
- if (executor instanceof DispatchExecutor) {
- ((DispatchExecutor) executor).execute(stopTask, false /* try to execute synchronously, not using threadpool */);
- } else {
- executor.execute(stopTask);
- }
+ schedule(true /* synchronously */, () -> {
+ m_isStarted = false;
+ handleChange();
+ });
}
}
@@ -460,8 +456,12 @@ public class ComponentImpl implements Co
public void handleEvent(final DependencyContext dc, final EventType type, final Event... event) {
// since this method can be invoked by anyone from any thread, we need to
// pass on the event to a runnable that we execute using the component's
- // executor
- getExecutor().execute(() -> {
+ // executor. There is one corner case: if this is a REMOVE event, we must try to stay synchronous
+ // because if the remove event corresponds to a service being unregistered, then we must try to stop
+ // our component depending on the lost service before the lost service is actually stopped.
+ boolean synchronously = (type == EventType.REMOVED);
+
+ schedule(synchronously, () -> {
try {
switch (type) {
case ADDED:
@@ -1678,4 +1678,18 @@ public class ComponentImpl implements Co
result.append(")");
}
}
+
+ private void schedule(boolean synchronously, Runnable task) {
+ if (synchronously) {
+ FutureTask<Void> future = new FutureTask<Void>(task, null);
+ getExecutor().execute(future);
+ try {
+ future.get(DependencyManager.SCHEDUME_TIMEOUT_VAL, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException | ExecutionException | TimeoutException e) {
+ m_logger.warn("task could not be scheduled timely in component %s (exception:%s)", this, e.toString());
+ }
+ } else {
+ getExecutor().execute(task);
+ }
+ }
}
Modified: felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/InvocationUtil.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/InvocationUtil.java?rev=1776574&r1=1776573&r2=1776574&view=diff
==============================================================================
--- felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/InvocationUtil.java (original)
+++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/InvocationUtil.java Fri Dec 30 14:17:39 2016
@@ -59,11 +59,6 @@ public class InvocationUtil {
public interface ConfigurationHandler {
public void handle() throws Exception;
}
-
- /**
- * Max time to wait until a configuration update callback has returned.
- */
- private final static int UPDATED_MAXWAIT = 30000; // max time to wait until a CM update has completed
/**
* Invokes a callback method on an instance. The code will search for a callback method with
@@ -239,7 +234,7 @@ public class InvocationUtil {
queue.execute(ft);
try {
- Exception err = ft.get(UPDATED_MAXWAIT, TimeUnit.MILLISECONDS);
+ Exception err = ft.get(DependencyManager.SCHEDUME_TIMEOUT_VAL, TimeUnit.MILLISECONDS);
if (err != null) {
throw err;
}