Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Thread Pinning in Repositories#cacheRepositoryFactory() #3126

Closed
AntipovAndrey opened this issue Jul 25, 2024 · 1 comment
Closed

Thread Pinning in Repositories#cacheRepositoryFactory() #3126

AntipovAndrey opened this issue Jul 25, 2024 · 1 comment
Assignees
Labels
type: bug A general bug

Comments

@AntipovAndrey
Copy link

There is a rare thread pinning happens on the first Spring MVC API request to the app.
It traces here:

private synchronized void cacheRepositoryFactory(String name) {
RepositoryFactoryInformation repositoryFactoryInformation = beanFactory.get().getBean(name,

Thread[#95,ForkJoinPool-1-worker-2,5,CarrierThreads]
    java.base/java.lang.VirtualThread$VThreadContinuation.onPinned(VirtualThread.java:183)
    java.base/jdk.internal.vm.Continuation.onPinned0(Continuation.java:393)
    java.base/java.lang.VirtualThread.park(VirtualThread.java:582)
    java.base/java.lang.System$2.parkVirtualThread(System.java:2639)
    java.base/jdk.internal.misc.VirtualThreads.park(VirtualThreads.java:54)
    java.base/java.util.concurrent.locks.LockSupport.park(LockSupport.java:219)
    java.base/java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:754)
    java.base/java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:990)
    java.base/java.util.concurrent.locks.ReentrantLock$Sync.lock(ReentrantLock.java:153)
    java.base/java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:322)
    org.springframework.util.ConcurrentReferenceHashMap$Segment.restructure(ConcurrentReferenceHashMap.java:583)
    org.springframework.util.ConcurrentReferenceHashMap$Segment.restructureIfNecessary(ConcurrentReferenceHashMap.java:577)
    org.springframework.util.ConcurrentReferenceHashMap$Segment.doTask(ConcurrentReferenceHashMap.java:520)
    org.springframework.util.ConcurrentReferenceHashMap.doTask(ConcurrentReferenceHashMap.java:420)
    org.springframework.util.ConcurrentReferenceHashMap.put(ConcurrentReferenceHashMap.java:283)
    org.springframework.util.ConcurrentReferenceHashMap.putIfAbsent(ConcurrentReferenceHashMap.java:278)
    java.base/java.util.concurrent.ConcurrentMap.computeIfAbsent(ConcurrentMap.java:331)
    org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepositoryInformation(RepositoryFactorySupport.java:445)
    org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepositoryInformation(RepositoryFactorySupport.java:411)
    org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getRepositoryInformation(RepositoryFactoryBeanSupport.java:231)
    org.springframework.data.repository.support.Repositories.cacheRepositoryFactory(Repositories.java:107) <== monitors:1
    org.springframework.data.repository.support.Repositories.populateRepositoryFactoryInformation(Repositories.java:98)
    org.springframework.data.repository.support.Repositories.<init>(Repositories.java:91)
    org.springframework.data.repository.support.DomainClassConverter.lambda$setApplicationContext$2(DomainClassConverter.java:98)
    org.springframework.data.util.Lazy.getNullable(Lazy.java:135)
    org.springframework.data.util.Lazy.get(Lazy.java:113)
    org.springframework.data.repository.support.DomainClassConverter.getConverter(DomainClassConverter.java:91)
    org.springframework.data.repository.support.DomainClassConverter.matches(DomainClassConverter.java:83)
    org.springframework.core.convert.support.GenericConversionService$ConvertersForPair.getConverter(GenericConversionService.java:628)
    org.springframework.core.convert.support.GenericConversionService$Converters.getRegisteredConverter(GenericConversionService.java:526)
    org.springframework.core.convert.support.GenericConversionService$Converters.find(GenericConversionService.java:510)
    org.springframework.core.convert.support.GenericConversionService.getConverter(GenericConversionService.java:233)
    org.springframework.core.convert.support.GenericConversionService.canConvert(GenericConversionService.java:141)
    org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:129)
    org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:80)
    org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:53)
    org.springframework.validation.DataBinder.convertIfNecessary(DataBinder.java:860)
    org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.convertIfNecessary(AbstractNamedValueMethodArgumentResolver.java:294)
    org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:137)
    org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:122)
    org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:224)
    org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:178)
    org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:926)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:831)
    org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089)
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979)
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903)
    jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
    jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
    org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195)
    org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
    org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
    org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
    org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:108)
    org.springframework.security.web.FilterChainProxy.lambda$doFilterInternal$3(FilterChainProxy.java:231)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:365)
    org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:100)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
    org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:126)
    org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:120)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
    org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:100)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
    org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:110)
    org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:101)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
    org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:179)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
    org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
    org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter.doFilterInternal(DefaultLogoutPageGeneratingFilter.java:58)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
    org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter.doFilter(DefaultLoginPageGeneratingFilter.java:189)
    org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter.doFilter(DefaultLoginPageGeneratingFilter.java:175)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
    org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:227)
    org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:221)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
    org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter.doFilterInternal(OAuth2AuthorizationRequestRedirectFilter.java:198)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
    org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107)
    org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
    org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
    org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)
    org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
    org.springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:82)
    org.springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:69)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
    org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
    org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
    org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233)
    org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191)
    org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113)
    org.springframework.web.servlet.handler.HandlerMappingIntrospector.lambda$createCacheFilter$3(HandlerMappingIntrospector.java:195)
    org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113)
    org.springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:74)
    org.springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration$CompositeFilterChainProxy.doFilter(WebMvcSecurityConfiguration.java:230)
    org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:352)
    org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:268)
    org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
    org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
    org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
    org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
    org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
    org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
    org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
    org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
    org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
    org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
    org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482)
    org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
    org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
    org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
    org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
    org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:389)
    org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
    org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:904)
    org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741)
    org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
    java.base/java.lang.VirtualThread.run(VirtualThread.java:309)
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jul 25, 2024
@mp911de mp911de self-assigned this Jul 26, 2024
@mp911de mp911de added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged labels Jul 26, 2024
@mp911de mp911de changed the title [Virtual Threads] Thread Pinning in Repositories#cacheRepositoryFactory() Thread Pinning in Repositories#cacheRepositoryFactory() Jul 26, 2024
@mp911de
Copy link
Member

mp911de commented Jul 26, 2024

Thanks for the report. We don't really have a need to synchronize the method as it is invoked in the constructor without involving additional concurrency. We can simply remove synchronized without side effects.

@mp911de mp911de added this to the 3.2.9 (2023.1.9) milestone Jul 26, 2024
mp911de added a commit that referenced this issue Jul 26, 2024
We now no longer declare cacheRepositoryFactory as synchronized to avoid locking. Additionally, simplify the flow and reuse computed values as much as possible.

Closes #3126
mp911de added a commit that referenced this issue Jul 26, 2024
We now no longer declare cacheRepositoryFactory as synchronized to avoid locking. Additionally, simplify the flow and reuse computed values as much as possible.

Closes #3126
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

No branches or pull requests

3 participants