FELIX-3891 wait a while for concurrent registration/unregistration requests to complete
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1453150 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
index 1fadcf5..75bce30 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
@@ -174,7 +174,7 @@
{
try
{
- if (!m_stateLock.tryLock( getActivator().getConfiguration().lockTimeout(), TimeUnit.MILLISECONDS ) )
+ if (!m_stateLock.tryLock( getLockTimeout(), TimeUnit.MILLISECONDS ) )
{
dumpThreads();
throw new IllegalStateException( "Could not obtain lock" );
@@ -187,6 +187,11 @@
}
}
+ private long getLockTimeout()
+ {
+ return getActivator().getConfiguration().lockTimeout();
+ }
+
final void releaseWriteLock( String source )
{
m_stateLock.unlock();
@@ -720,6 +725,12 @@
{
AbstractComponentManager.this.log(level, message, arguments, ex);
}
+
+ @Override
+ long getTimeout()
+ {
+ return getLockTimeout();
+ }
};
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/RegistrationManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/RegistrationManager.java
index 10f7395..8412249 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/RegistrationManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/RegistrationManager.java
@@ -3,6 +3,8 @@
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@@ -11,9 +13,40 @@
abstract class RegistrationManager<T>
{
enum RegState {unregistered, registered};
+ private static class RegStateWrapper
+ {
+ private final CountDownLatch latch = new CountDownLatch(1);
+ private final RegState regState;
+
+ RegStateWrapper( RegState regState )
+ {
+ this.regState = regState;
+ }
+
+ public RegState getRegState()
+ {
+ return regState;
+ }
+
+ public CountDownLatch getLatch()
+ {
+ return latch;
+ }
+
+ public int hashCode()
+ {
+ return regState.hashCode();
+ }
+
+ public boolean equals(Object other)
+ {
+ return other instanceof RegStateWrapper && regState == ((RegStateWrapper)other).getRegState();
+ }
+
+ }
private final Lock registrationLock = new ReentrantLock();
//Deque, ArrayDeque if we had java 6
- private final List<RegState> opqueue = new ArrayList<RegState>();
+ private final List<RegStateWrapper> opqueue = new ArrayList<RegStateWrapper>();
private volatile T m_serviceRegistration;
/**
@@ -24,6 +57,7 @@
*/
boolean changeRegistration( RegState desired, String[] services )
{
+ RegStateWrapper rsw = null;
registrationLock.lock();
try
{
@@ -34,11 +68,13 @@
return false; //already in desired state
}
}
- else if (opqueue.get( opqueue.size() - 1 ) == desired)
+ else if (opqueue.get( opqueue.size() - 1 ).getRegState() == desired)
{
+ rsw = opqueue.get( opqueue.size() - 1 );
return false; //another thread will do our work.
}
- opqueue.add( desired );
+ rsw = new RegStateWrapper( desired );
+ opqueue.add( rsw );
if (opqueue.size() > 1)
{
return false; //some other thread will do it later
@@ -48,9 +84,9 @@
{
log( LogService.LOG_DEBUG, "registration change queue {0}", new Object[]
{opqueue}, null );
- desired = opqueue.get( 0 );
+ RegStateWrapper next = opqueue.get( 0 );
T serviceRegistration = m_serviceRegistration;
- if ( desired == RegState.unregistered)
+ if ( next.getRegState() == RegState.unregistered)
{
m_serviceRegistration = null;
}
@@ -58,7 +94,7 @@
registrationLock.unlock();
try
{
- if (desired == RegState.registered)
+ if (next.getRegState() == RegState.registered)
{
serviceRegistration = register(services );
@@ -81,10 +117,11 @@
{
registrationLock.lock();
opqueue.remove(0);
- if ( desired == RegState.registered)
+ if ( next.getRegState() == RegState.registered)
{
m_serviceRegistration = serviceRegistration;
}
+ next.getLatch().countDown();
}
}
while (!opqueue.isEmpty());
@@ -93,6 +130,22 @@
finally
{
registrationLock.unlock();
+ if (rsw != null)
+ {
+ try
+ {
+ if ( !rsw.getLatch().await( getTimeout(), TimeUnit.MILLISECONDS ))
+ {
+ log( LogService.LOG_ERROR, "Timeout waiting for reg change to complete {0}", new Object[]
+ {rsw.getRegState()}, null);
+ }
+ }
+ catch ( InterruptedException e )
+ {
+ log( LogService.LOG_ERROR, "Interrupted exception waiting for reg change to complete {0}", new Object[]
+ {rsw.getRegState()}, null);
+ }
+ }
}
}
@@ -103,6 +156,8 @@
abstract void log( int level, String message, Object[] arguments, Throwable ex );
+ abstract long getTimeout();
+
T getServiceRegistration()
{
return m_serviceRegistration;
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/manager/RegistrationManagerTest.java b/scr/src/test/java/org/apache/felix/scr/impl/manager/RegistrationManagerTest.java
index 1229b56..296f66d 100644
--- a/scr/src/test/java/org/apache/felix/scr/impl/manager/RegistrationManagerTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/impl/manager/RegistrationManagerTest.java
@@ -108,6 +108,13 @@
}
}
+
+ @Override
+ long getTimeout()
+ {
+ // TODO Auto-generated method stub
+ return 10;
+ }
}
}