Issue Details (XML | Word | Printable)

Key: CONFIGURATION-344
Type: Bug Bug
Status: Closed Closed
Resolution: Fixed
Priority: Critical Critical
Assignee: Oliver Heger
Reporter: Pavel Savara
Votes: 0
Watchers: 0
Operations

If you were logged in you would be able to see more operations.
Commons Configuration

Deadlock during refresh properties

Created: 30/Oct/08 11:46 AM   Updated: 26/Sep/09 02:52 PM
Return to search
Component/s: Events & Notifications, File reloading
Affects Version/s: 1.5
Fix Version/s: 1.6

Time Tracking:
Not Specified

Issue Links:
Reference
 

Resolution Date: 08/Nov/08 03:53 PM


 Description  « Hide
Hi
Commons configurations get itself stuck in deadlock when refreshing
properties using Managed reloading strategy. It seems to me it get stuck
because of fireEvent in reload method. Another access grabs lock on
synchronized (getNodeCombiner()) when trying to rebuild but Combined
configuration is one of the listeners for event es well and it gets
stuck when processing invalidate. Can anyone suggest quick fix please?
Relevant information follows.
Thanks
Pavel

Configuration:

<configuration> 
  <override>
    <system/>    
    <properties fileName="gsxweb.properties" throwExceptionOnMissing="false"
       config-name="gsxweb" config-optional="false" listDelimiter="|">
       <reloadingStrategy config-class="org.apache.commons.configuration.reloading.ManagedReloadingStrategy"/>      
    </properties>    
  </override> 
</configuration>

Our Reload code:

int ln = combinedConfiguration.getNumberOfConfigurations();
        int reloaded = 0;
        for (int i = 0; i < ln; i++) {
            Configuration conf = combinedConfiguration.getConfiguration(i);
            if (conf instanceof PropertiesConfiguration) {
                ManagedReloadingStrategy strat = null;
                ReloadingStrategy strategy = ((PropertiesConfiguration) conf).getReloadingStrategy();
                //refresh if managed strategy
                if (strategy instanceof ManagedReloadingStrategy) {
                    ((ManagedReloadingStrategy) strategy).refresh();
                //reload if file changed strategy    
                } else if (strategy instanceof FileChangedReloadingStrategy) {                    
                    ((PropertiesConfiguration) conf).reload();
                }
                reloaded++;
            }
        }
Stack trace of deadlock threads
Name: http-10980-1
State: BLOCKED on
org.apache.commons.configuration.tree.OverrideCombiner@8511bb owned by:
http-10980-6
Total blocked: 154  Total waited: 2

Stack trace: 
org.apache.commons.configuration.CombinedConfiguration.invalidate(CombinedConfiguration.java:474)
org.apache.commons.configuration.CombinedConfiguration.configurationChanged(CombinedConfiguration.java:488)
org.apache.commons.configuration.event.EventSource.fireEvent(EventSource.java:249)
org.apache.commons.configuration.AbstractFileConfiguration.fireEvent(AbstractFileConfiguration.java:911)
org.apache.commons.configuration.AbstractFileConfiguration.reload(AbstractFileConfiguration.java:828)
   - locked java.lang.Object@127e34c
org.apache.commons.configuration.AbstractFileConfiguration.isEmpty(AbstractFileConfiguration.java:927)
org.apache.commons.configuration.reloading.ManagedReloadingStrategy.refresh(ManagedReloadingStrategy.java:91)
com.gsx.properties.PropertyProviderImpl.reset(PropertyProviderImpl.java:203)
   - locked java.lang.Class@109bcda
org.apache.jsp.test.testPropertyProvider_jsp._jspService(testPropertyProvider_jsp.java:60)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:374)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)


Name: http-10980-6
State: BLOCKED on java.lang.Object@127e34c owned by: http-10980-1
Total blocked: 115  Total waited: 2

Stack trace: 
org.apache.commons.configuration.AbstractFileConfiguration.reload(AbstractFileConfiguration.java:814)
org.apache.commons.configuration.AbstractFileConfiguration.getKeys(AbstractFileConfiguration.java:939)
org.apache.commons.configuration.ConfigurationUtils.copy(ConfigurationUtils.java:139)
org.apache.commons.configuration.ConfigurationUtils.convertToHierarchical(ConfigurationUtils.java:199)
org.apache.commons.configuration.CombinedConfiguration
$ConfigData.getTransformedRoot(CombinedConfiguration.java:794)
org.apache.commons.configuration.CombinedConfiguration.constructCombinedNode(CombinedConfiguration.java:653)
org.apache.commons.configuration.CombinedConfiguration.getRootNode(CombinedConfiguration.java:504)
   - locked
org.apache.commons.configuration.tree.OverrideCombiner@8511bb
org.apache.commons.configuration.HierarchicalConfiguration.fetchNodeList(HierarchicalConfiguration.java:925)
org.apache.commons.configuration.HierarchicalConfiguration.getProperty(HierarchicalConfiguration.java:327)
org.apache.commons.configuration.CombinedConfiguration.getProperty(CombinedConfiguration.java:578)
org.apache.commons.configuration.AbstractConfiguration.resolveContainerStore(AbstractConfiguration.java:1155)
org.apache.commons.configuration.AbstractConfiguration.getString(AbstractConfiguration.java:1034)
org.apache.jsp.test.testPropertyProvider_jsp._jspService(testPropertyProvider_jsp.java:69)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:374)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)


 All   Comments   Work Log   Change History   Subversion Commits      Sort Order: Ascending order - Click to sort in descending order
Pavel Savara added a comment - 30/Oct/08 12:49 PM
Here is my quick dirty fix,
Because getNodeCombiner() is public method i can grab lock in my code first before try to do reloading.

synchronized (combinedConfiguration.getNodeCombiner()){
//do the reloading
}

It means locks are grabbed always in the same order so deadlock can't happen.

Best
Pavel


Oliver Heger added a comment - 05/Nov/08 09:28 PM
This is indeed a classic deadlock scenario. I can reproduce the problem with a unit test.

While testing I found another problem related to reloading strategies. I created CONFIGURATION-347 for this issue.


Oliver Heger made changes - 08/Nov/08 03:22 PM
Field Original Value New Value
Assignee Oliver Heger [ oliver.heger@t-online.de ]
Repository Revision Date User Message
ASF #712401 Sat Nov 08 15:29:56 UTC 2008 oheger CONFIGURATION-344: Reduced synchronization in CombinedConfiguration when accessing and constructing the combined root node. This fixes a potential deadlock related to reload operations in child configurations.
Files Changed
MODIFY /commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/CombinedConfiguration.java
MODIFY /commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestCombinedConfiguration.java
MODIFY /commons/proper/configuration/trunk/xdocs/changes.xml
MODIFY /commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractFileConfiguration.java

Oliver Heger added a comment - 08/Nov/08 03:53 PM
A fix was applied to trunk in revision 712401.

So far, accessing the root node of the combined configuration was synchronized because it had to be re-constructed if something had changed. This fix removes this synchronization and - to ensure proper visibility - adds the volatile modifier to the root node field. If now multiple threads want to access the combined configuration, there may be a race condition causing the root node to be constructed multiple times. However, this does not impact the results of queries or have other undesired side effects.

When testing I found out that reloading operations are indeed problematic when multiple threads are involved. The unit test case uses a synthetic reloading strategy that forces a reload on every access. AbstractFileConfiguration overrides all access methods to ensure that reload() is invoked as in the following example:

public Object getProperty(String key)
    {
        reload();
        return super.getProperty(key);
    }

If there are multiple concurrent reloads or property accesses in sequence - as in the test I created -, the following race condition can happen:

  • One thread executes reload() and then is going to enter getProperty().
  • Another thread wants to read a property and enters reload(). Because reload() is guarded by a lock, the thread has to wait.
  • As soon as the first thread leaves reload() the second can proceed and initiates the reload operation.
  • While trying to read a property the first thread sees an invalid state because a reload operation is in progress.

To get my test running I changed the implementation of getProperty() in the following way:

public Object getProperty(String key)
    {
        synchronized (reloadLock)
        {
            reload();
            return super.getProperty(key);
        }
    }

So the whole property read operation is now guarded by the lock. To be on the safe side this change would have to be applied for the other methods, too. But I think, the architecture of the reloading implementation should better be re-worked in the next major release. Note that it is very unlikely that multiple reloads happen in short intervals because the available reloading strategies have a refresh delay.


Oliver Heger made changes - 08/Nov/08 03:53 PM
Resolution Fixed [ 1 ]
Fix Version/s 1.6 [ 12312450 ]
Status Open [ 1 ] Resolved [ 5 ]
Emmanuel Bourg made changes - 23/Jun/09 12:38 PM
Description Hi
Commons configurations get itself stuck in deadlock when refreshing
properties using Managed reloading strategy. It seems to me it get stuck
because of fireEvent in reload method. Another access grabs lock on
synchronized (getNodeCombiner()) when trying to rebuild but Combined
configuration is one of the listeners for event es well and it gets
stuck when processing invalidate. Can anyone suggest quick fix please?
Relevant information follows.
Thanks
Pavel

Configuration:
<configuration>
  <override>
    <system/>
    <properties fileName="gsxweb.properties" throwExceptionOnMissing="false"
       config-name="gsxweb" config-optional="false" listDelimiter="|">
       <reloadingStrategy config-class="org.apache.commons.configuration.reloading.ManagedReloadingStrategy"/>
    </properties>
  </override>
</configuration>

Our Reload code:
int ln = combinedConfiguration.getNumberOfConfigurations();
       int reloaded = 0;
        for (int i = 0; i < ln; i++) {
            Configuration conf = combinedConfiguration.getConfiguration(i);
            if (conf instanceof PropertiesConfiguration) {
                ManagedReloadingStrategy strat = null;
                ReloadingStrategy strategy = ((PropertiesConfiguration) conf).getReloadingStrategy();
                //refresh if managed strategy
                if (strategy instanceof ManagedReloadingStrategy) {
                    ((ManagedReloadingStrategy) strategy).refresh();
                //reload if file changed strategy
                } else if (strategy instanceof FileChangedReloadingStrategy) {
                    ((PropertiesConfiguration) conf).reload();
                }
                reloaded++;
            }
        }

Stack trace of deadlock threads
Name: http-10980-1
State: BLOCKED on
org.apache.commons.configuration.tree.OverrideCombiner@8511bb owned by:
http-10980-6
Total blocked: 154 Total waited: 2

Stack trace:
org.apache.commons.configuration.CombinedConfiguration.invalidate(CombinedConfiguration.java:474)
org.apache.commons.configuration.CombinedConfiguration.configurationChanged(CombinedConfiguration.java:488)
org.apache.commons.configuration.event.EventSource.fireEvent(EventSource.java:249)
org.apache.commons.configuration.AbstractFileConfiguration.fireEvent(AbstractFileConfiguration.java:911)
org.apache.commons.configuration.AbstractFileConfiguration.reload(AbstractFileConfiguration.java:828)
   - locked java.lang.Object@127e34c
org.apache.commons.configuration.AbstractFileConfiguration.isEmpty(AbstractFileConfiguration.java:927)
org.apache.commons.configuration.reloading.ManagedReloadingStrategy.refresh(ManagedReloadingStrategy.java:91)
com.gsx.properties.PropertyProviderImpl.reset(PropertyProviderImpl.java:203)
   - locked java.lang.Class@109bcda
org.apache.jsp.test.testPropertyProvider_jsp._jspService(testPropertyProvider_jsp.java:60)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:374)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)


Name: http-10980-6
State: BLOCKED on java.lang.Object@127e34c owned by: http-10980-1
Total blocked: 115 Total waited: 2

Stack trace:
org.apache.commons.configuration.AbstractFileConfiguration.reload(AbstractFileConfiguration.java:814)
org.apache.commons.configuration.AbstractFileConfiguration.getKeys(AbstractFileConfiguration.java:939)
org.apache.commons.configuration.ConfigurationUtils.copy(ConfigurationUtils.java:139)
org.apache.commons.configuration.ConfigurationUtils.convertToHierarchical(ConfigurationUtils.java:199)
org.apache.commons.configuration.CombinedConfiguration
$ConfigData.getTransformedRoot(CombinedConfiguration.java:794)
org.apache.commons.configuration.CombinedConfiguration.constructCombinedNode(CombinedConfiguration.java:653)
org.apache.commons.configuration.CombinedConfiguration.getRootNode(CombinedConfiguration.java:504)
   - locked
org.apache.commons.configuration.tree.OverrideCombiner@8511bb
org.apache.commons.configuration.HierarchicalConfiguration.fetchNodeList(HierarchicalConfiguration.java:925)
org.apache.commons.configuration.HierarchicalConfiguration.getProperty(HierarchicalConfiguration.java:327)
org.apache.commons.configuration.CombinedConfiguration.getProperty(CombinedConfiguration.java:578)
org.apache.commons.configuration.AbstractConfiguration.resolveContainerStore(AbstractConfiguration.java:1155)
org.apache.commons.configuration.AbstractConfiguration.getString(AbstractConfiguration.java:1034)
org.apache.jsp.test.testPropertyProvider_jsp._jspService(testPropertyProvider_jsp.java:69)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:374)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
Hi
Commons configurations get itself stuck in deadlock when refreshing
properties using Managed reloading strategy. It seems to me it get stuck
because of fireEvent in reload method. Another access grabs lock on
synchronized (getNodeCombiner()) when trying to rebuild but Combined
configuration is one of the listeners for event es well and it gets
stuck when processing invalidate. Can anyone suggest quick fix please?
Relevant information follows.
Thanks
Pavel

Configuration:
{code:xml}
<configuration>
  <override>
    <system/>
    <properties fileName="gsxweb.properties" throwExceptionOnMissing="false"
       config-name="gsxweb" config-optional="false" listDelimiter="|">
       <reloadingStrategy config-class="org.apache.commons.configuration.reloading.ManagedReloadingStrategy"/>
    </properties>
  </override>
</configuration>
{code}

Our Reload code:

{code:java}
        int ln = combinedConfiguration.getNumberOfConfigurations();
        int reloaded = 0;
        for (int i = 0; i < ln; i++) {
            Configuration conf = combinedConfiguration.getConfiguration(i);
            if (conf instanceof PropertiesConfiguration) {
                ManagedReloadingStrategy strat = null;
                ReloadingStrategy strategy = ((PropertiesConfiguration) conf).getReloadingStrategy();
                //refresh if managed strategy
                if (strategy instanceof ManagedReloadingStrategy) {
                    ((ManagedReloadingStrategy) strategy).refresh();
                //reload if file changed strategy
                } else if (strategy instanceof FileChangedReloadingStrategy) {
                    ((PropertiesConfiguration) conf).reload();
                }
                reloaded++;
            }
        }
{code}

{code}
Stack trace of deadlock threads
Name: http-10980-1
State: BLOCKED on
org.apache.commons.configuration.tree.OverrideCombiner@8511bb owned by:
http-10980-6
Total blocked: 154 Total waited: 2

Stack trace:
org.apache.commons.configuration.CombinedConfiguration.invalidate(CombinedConfiguration.java:474)
org.apache.commons.configuration.CombinedConfiguration.configurationChanged(CombinedConfiguration.java:488)
org.apache.commons.configuration.event.EventSource.fireEvent(EventSource.java:249)
org.apache.commons.configuration.AbstractFileConfiguration.fireEvent(AbstractFileConfiguration.java:911)
org.apache.commons.configuration.AbstractFileConfiguration.reload(AbstractFileConfiguration.java:828)
   - locked java.lang.Object@127e34c
org.apache.commons.configuration.AbstractFileConfiguration.isEmpty(AbstractFileConfiguration.java:927)
org.apache.commons.configuration.reloading.ManagedReloadingStrategy.refresh(ManagedReloadingStrategy.java:91)
com.gsx.properties.PropertyProviderImpl.reset(PropertyProviderImpl.java:203)
   - locked java.lang.Class@109bcda
org.apache.jsp.test.testPropertyProvider_jsp._jspService(testPropertyProvider_jsp.java:60)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:374)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)


Name: http-10980-6
State: BLOCKED on java.lang.Object@127e34c owned by: http-10980-1
Total blocked: 115 Total waited: 2

Stack trace:
org.apache.commons.configuration.AbstractFileConfiguration.reload(AbstractFileConfiguration.java:814)
org.apache.commons.configuration.AbstractFileConfiguration.getKeys(AbstractFileConfiguration.java:939)
org.apache.commons.configuration.ConfigurationUtils.copy(ConfigurationUtils.java:139)
org.apache.commons.configuration.ConfigurationUtils.convertToHierarchical(ConfigurationUtils.java:199)
org.apache.commons.configuration.CombinedConfiguration
$ConfigData.getTransformedRoot(CombinedConfiguration.java:794)
org.apache.commons.configuration.CombinedConfiguration.constructCombinedNode(CombinedConfiguration.java:653)
org.apache.commons.configuration.CombinedConfiguration.getRootNode(CombinedConfiguration.java:504)
   - locked
org.apache.commons.configuration.tree.OverrideCombiner@8511bb
org.apache.commons.configuration.HierarchicalConfiguration.fetchNodeList(HierarchicalConfiguration.java:925)
org.apache.commons.configuration.HierarchicalConfiguration.getProperty(HierarchicalConfiguration.java:327)
org.apache.commons.configuration.CombinedConfiguration.getProperty(CombinedConfiguration.java:578)
org.apache.commons.configuration.AbstractConfiguration.resolveContainerStore(AbstractConfiguration.java:1155)
org.apache.commons.configuration.AbstractConfiguration.getString(AbstractConfiguration.java:1034)
org.apache.jsp.test.testPropertyProvider_jsp._jspService(testPropertyProvider_jsp.java:69)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:374)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
{code}
Oliver Heger made changes - 22/Aug/09 07:36 PM
Status Resolved [ 5 ] Closed [ 6 ]
Oliver Heger made changes - 26/Sep/09 02:52 PM
Link This issue relates to CONFIGURATION-390 [ CONFIGURATION-390 ]