felix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From pde...@apache.org
Subject svn commit: r1776574 - in /felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm: DependencyManager.java impl/ComponentImpl.java impl/InvocationUtil.java
Date Fri, 30 Dec 2016 14:17:39 GMT
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;
             }



Mime
View raw message