Issue Details (XML | Word | Printable)

Key: SPR-4664
Type: Improvement Improvement
Status: Resolved Resolved
Resolution: Fixed
Priority: Critical Critical
Assignee: Juergen Hoeller
Reporter: David.Turing
Votes: 0
Watchers: 2
Operations

If you were logged in you would be able to see more operations.
Spring Framework

AbstractFallbackTransactionAttributeSource's Map synchronization causes lock contention

Created: 06/Apr/08 09:36 PM   Updated: 18/Apr/08 08:53 PM
Component/s: SpringCORE
Affects Version/s: 2.5 final
Fix Version/s: 2.5.4

Time Tracking:
Original Estimate: 1d
Original Estimate - 1d
Remaining Estimate: 1d
Remaining Estimate - 1d
Time Spent: Not Specified
Remaining Estimate - 1d

File Attachments: 1. File threaddump-by-david.turing.rar (10 kB)

Environment: Intel IA Platform, 8 Core, JRockit 1.5 (R27.5)

Virtual Machine: BEA JRockit JVM - 5.0
Platform: BEA WebLogic - 9.2


 Description  « Hide
We are encountering the serious perfomance problem when we using Spring 2.X. CPU hit 100% when a lot of threads are doing the work below:
*************
            "[ACTIVE] ExecuteThread: '36' for queue: 'weblogic.kernel.Default (self-tuning)'" id=648 idx=0x2c0 tid=7380 prio=5 alive, daemon
          
                at java/util/HashMap.get(HashMap.java:1582)[optimized]
          
                at org/springframework/transaction/interceptor/AbstractFallbackTransactionAttributeSource.getTransactionAttribute(AbstractFallbackTransactionAttributeSource.java:89)[optimized]
          
                at org/springframework/transaction/interceptor/TransactionAttributeSourceAdvisor$TransactionAttributeSourcePointcut.matches(TransactionAttributeSourceAdvisor.java:102)[optimized]
          
                at org/springframework/aop/support/AopUtils.canApply(AopUtils.java:192)[inlined]
          
                at org/springframework/aop/support/AopUtils.canApply(AopUtils.java:231)[inlined]
          
                at org/springframework/aop/support/AopUtils.findAdvisorsThatCanApply(AopUtils.java:256)[inlined]
          
                at org/springframework/aop/framework/autoproxy/AbstractAdvisorAutoProxyCreator.findEligibleAdvisors(AbstractAdvisorAutoProxyCreator.java:68)[inlined]
          
                at org/springframework/aop/framework/autoproxy/AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(AbstractAdvisorAutoProxyCreator.java:54)[optimized]
          
                at org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:247)
          
                at org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:311)
          
                at org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1038)
          
                at org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:420)
          
                at org/springframework/beans/factory/support/AbstractBeanFactory.getBean(AbstractBeanFactory.java:264)
          
                at org/springframework/beans/factory/support/AbstractBeanFactory.getBean(AbstractBeanFactory.java:156)
          
                at org/springframework/context/support/AbstractApplicationContext.getBean(AbstractApplicationContext.java:642)
          
                at com/opensymphony/xwork2/spring/SpringObjectFactory.buildBean(SpringObjectFactory.java:125)
          
                at com/opensymphony/xwork2/ObjectFactory.buildBean(ObjectFactory.java:143)
          
                at com/opensymphony/xwork2/ObjectFactory.buildAction(ObjectFactory.java:113)
          
                at com/opensymphony/xwork2/DefaultActionInvocation.createAction(DefaultActionInvocation.java:275)
          
                at com/opensymphony/xwork2/DefaultActionInvocation.init(DefaultActionInvocation.java:365)
          
                at com/opensymphony/xwork2/DefaultActionInvocation.access$000(DefaultActionInvocation.java:38)
          
                at com/opensymphony/xwork2/DefaultActionInvocation$1.doProfiling(DefaultActionInvocation.java:83)
          
                at com/opensymphony/xwork2/util/profiling/UtilTimerStack.profile(UtilTimerStack.java:455)
          
                at com/opensymphony/xwork2/DefaultActionInvocation.<init>(DefaultActionInvocation.java:74)
          
                at com/opensymphony/xwork2/DefaultActionProxy.prepare(DefaultActionProxy.java:189)
          
                at org/apache/struts2/impl/StrutsActionProxyFactory.createActionProxy(StrutsActionProxyFactory.java:41)
          
                at org/apache/struts2/dispatcher/Dispatcher.serviceAction(Dispatcher.java:497)
          
                at org/apache/struts2/dispatcher/FilterDispatcher.doFilter(FilterDispatcher.java:421)
          
                at weblogic/servlet/internal/FilterChainImpl.doFilter(FilterChainImpl.java:42)
          
                at org/springframework/orm/hibernate3/support/OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:174)
          
                at org/springframework/web/filter/OncePerRequestFilter.doFilter(OncePerRequestFilter.java:77)
          
                at weblogic/servlet/internal/FilterChainImpl.doFilter(FilterChainImpl.java:42)
          
                at cn/com/picc/claim/common/web/SessionFilter.doFilter(SessionFilter.java:35)
          
                at weblogic/servlet/internal/FilterChainImpl.doFilter(FilterChainImpl.java:42)
          
                at org/acegisecurity/util/FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:264)
          
                at org/acegisecurity/intercept/web/FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:107)
          
                at org/acegisecurity/intercept/web/FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:72)
          
                at org/acegisecurity/util/FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:274)
          
                at org/acegisecurity/ui/ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:110)
          
                at org/acegisecurity/util/FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:274)
          
                at org/acegisecurity/providers/anonymous/AnonymousProcessingFilter.doFilter(AnonymousProcessingFilter.java:125)
          
                at org/acegisecurity/util/FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:274)
          
                at org/acegisecurity/wrapper/SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:81)
          
                at org/acegisecurity/util/FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:274)
          
                at org/acegisecurity/ui/AbstractProcessingFilter.doFilter(AbstractProcessingFilter.java:217)
          
                at org/acegisecurity/util/FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:274)
          
                at org/acegisecurity/ui/logout/LogoutFilter.doFilter(LogoutFilter.java:106)
          
                at org/acegisecurity/util/FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:274)
          
                at org/acegisecurity/context/HttpSessionContextIntegrationFilter.doFilter(HttpSessionContextIntegrationFilter.java:229)
          
                at org/acegisecurity/util/FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:274)
          
                at org/acegisecurity/util/FilterChainProxy.doFilter(FilterChainProxy.java:148)
          
                at org/acegisecurity/util/FilterToBeanProxy.doFilter(FilterToBeanProxy.java:98)
          
                at weblogic/servlet/internal/FilterChainImpl.doFilter(FilterChainImpl.java:42)
          
                at org/springframework/web/filter/CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:78)
          
                at org/springframework/web/filter/OncePerRequestFilter.doFilter(OncePerRequestFilter.java:77)
          
                at weblogic/servlet/internal/FilterChainImpl.doFilter(FilterChainImpl.java:42)
          
                at weblogic/servlet/internal/WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3229)
          
                at weblogic/security/acl/internal/AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
          
                at weblogic/security/service/SecurityManager.runAs(SecurityManager.java:121)
          
                at weblogic/servlet/internal/WebAppServletContext.securedExecute(WebAppServletContext.java:2002)
          
                at weblogic/servlet/internal/WebAppServletContext.execute(WebAppServletContext.java:1908)
          
                at weblogic/servlet/internal/ServletRequestImpl.run(ServletRequestImpl.java:1362)
          
                at weblogic/work/ExecuteThread.execute(ExecuteThread.java:209)[inlined]
          
                at weblogic/work/ExecuteThread.run(ExecuteThread.java:181)[optimized]
          
                at jrockit/vm/RNI.c2java(IIIII)V(Native Method)
          
                -- end of trace


********************************

And we check source of AbstractFallbackTransactionAttributeSource.java, we found Spring are using HashMap with Synchronized for thread safe purpose.
This won't be a problem if there are less threads, but when there are lots of threads doing getTransactionAttribute(), CPU will hit 100%.

Why not use JDK 1.5 's CurrentHashMap?

Accoring to Doug Lea, this won't be a bug of JDK, and could be fixed with our way of using HashMap.
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6423457




 All   Comments   Work Log   Change History   FishEye   Related Builds      Sort Order: Ascending order - Click to sort in descending order
David.Turing added a comment - 06/Apr/08 09:42 PM
Here are the source code of AbstractFallbackTransactionAttributeSource(spring 2.5.1).
the attributeCache are the cause of our 100% CPU, Restart WebLogic Instance could solved this case, and we are not sure we could reproduce the case , it was sometimes meet in product enviroment..


/**
* Cache of TransactionAttributes, keyed by DefaultCacheKey (Method + target Class).
* <p>As this base class is not marked Serializable, the cache will be recreated
* after serialization - provided that the concrete subclass is Serializable.
*/
final Map attributeCache = new HashMap();

/**
* Determine the transaction attribute for this method invocation.
* <p>Defaults to the class's transaction attribute if no method attribute is found.
* @param method the method for the current invocation (never <code>null</code>)
* @param targetClass the target class for this invocation (may be <code>null</code>)
* @return TransactionAttribute for this method, or <code>null</code> if the method
* is not transactional
*/
public TransactionAttribute getTransactionAttribute(Method method, Class targetClass) {
// First, see if we have a cached value.
Object cacheKey = getCacheKey(method, targetClass);
synchronized (this.attributeCache) {
Object cached = this.attributeCache.get(cacheKey);
if (cached != null) {
// Value will either be canonical value indicating there is no transaction attribute,
// or an actual transaction attribute.
if (cached == NULL_TRANSACTION_ATTRIBUTE) {
return null;
}
else {
return (TransactionAttribute) cached;
}
}
else {
// We need to work it out.
TransactionAttribute txAtt = computeTransactionAttribute(method, targetClass);
// Put it in the cache.
if (txAtt == null) {
this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Adding transactional method [" + method.getName() + "] with attribute [" + txAtt + "]");
}
this.attributeCache.put(cacheKey, txAtt);
}
return txAtt;
}
}
}

David.Turing added a comment - 06/Apr/08 09:45 PM
This is the thread dump, there are lots of thread accesing the HashMap of attributeCache, which making the CPU 100%.
It is most like softCache problem on Sun HotSpot.

Juergen Hoeller added a comment - 15/Apr/08 05:29 PM
Thanks for raising this! I've revised AbstractFallbackTransactionAttributeSource accordingly, using a concurrent Map for the attribute cache in order to avoid lock contention.

This will be available in the next 2.5.4 snapshot (http://static.springframework.org/downloads/nightly/snapshot-download.php?project=SPR). Please give it a try and let me know whether it works for you...

Juergen

David.Turing added a comment - 18/Apr/08 08:53 PM
Thanks, Juergen Hoeller . You could close this case.