Inefficient population of OfBizSearchRequestStore cache leads to instance wide slowness

XMLWordPrintable

    • 9.08
    • 7
    • Severity 3 - Minor
    • 1

      Issue Summary

      The OfBizSearchRequestStore cache is populated in an inefficient manner. While the cache is being populated, actions relying on it will be unavailable. This is apparent on first use, cache flush, or cache expiry (30 minutes after last use)

      In key, the projectBelongsToRapidView() loops over all boards and checks the board filter in order to evaluate permissions. This loop result in individual SELECT queries, which means the operation scale with the number of boards - n boards == n*2 SELECT queries

      ...
              at org.ofbiz.core.entity.jdbc.SQLProcessor.executeQuery(SQLProcessor.java:548)
              at org.ofbiz.core.entity.GenericDAO.select(GenericDAO.java:627)
              at org.ofbiz.core.entity.GenericDAO.select(GenericDAO.java:596)
              at org.ofbiz.core.entity.GenericHelperDAO.findByPrimaryKey(GenericHelperDAO.java:105)
              at org.ofbiz.core.entity.GenericDelegator.findByPrimaryKey(GenericDelegator.java:621)
              at org.ofbiz.core.entity.GenericDelegator.findByPrimaryKey(GenericDelegator.java:659)
              at com.atlassian.jira.ofbiz.DefaultOfBizDelegator.findByPrimaryKey(DefaultOfBizDelegator.java:341)
              at com.atlassian.jira.ofbiz.DefaultOfBizDelegator.findByPrimaryKey(DefaultOfBizDelegator.java:335)
              at com.atlassian.jira.ofbiz.DefaultOfBizDelegator.findById(DefaultOfBizDelegator.java:327)
              at com.atlassian.jira.ofbiz.WrappingOfBizDelegator.findById(WrappingOfBizDelegator.java:192)
              at com.atlassian.jira.issue.search.OfBizSearchRequestStore.findByPrimaryKey(OfBizSearchRequestStore.java:346)
              at com.atlassian.jira.issue.search.OfBizSearchRequestStore.getSearchRequest(OfBizSearchRequestStore.java:201)
              at com.atlassian.jira.issue.search.CachingSearchRequestStore$ByIdCacheLoader.load(CachingSearchRequestStore.java:262)
              at com.atlassian.jira.issue.search.CachingSearchRequestStore$ByIdCacheLoader.load(CachingSearchRequestStore.java:258)
              at com.atlassian.cache.ehcache.wrapper.ValueProcessorAtlassianCacheLoaderDecorator.load(ValueProcessorAtlassianCacheLoaderDecorator.java:26)
              at com.atlassian.cache.ehcache.LoadingCache.getFromLoader(LoadingCache.java:174)
              at com.atlassian.cache.ehcache.LoadingCache$$Lambda$546/0x0000000840820840.apply(Unknown Source)
              at com.atlassian.cache.ehcache.SynchronizedLoadingCacheDecorator.synchronizedLoad(SynchronizedLoadingCacheDecorator.java:29)
              at com.atlassian.cache.ehcache.LoadingCache.loadValueAndReleaseLock(LoadingCache.java:142)
              at com.atlassian.cache.ehcache.LoadingCache.get(LoadingCache.java:121)
              at com.atlassian.cache.ehcache.DelegatingCache.get(DelegatingCache.java:107)
              at com.atlassian.cache.impl.metrics.InstrumentedCache.get(InstrumentedCache.java:72)
              at com.atlassian.jira.cache.stats.CacheWithStats.get(CacheWithStats.java:46)
              at com.atlassian.jira.issue.search.CachingSearchRequestStore.getSearchRequest(CachingSearchRequestStore.java:140)
              at com.atlassian.jira.issue.search.DefaultSearchRequestManager.getSearchRequestById(DefaultSearchRequestManager.java:155)
              at jdk.internal.reflect.GeneratedMethodAccessor2808.invoke(Unknown Source)
              at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base@11.0.22/DelegatingMethodAccessorImpl.java:43)
              at java.lang.reflect.Method.invoke(java.base@11.0.22/Method.java:566)
              at com.atlassian.plugin.util.ContextClassLoaderSettingInvocationHandler.invoke(ContextClassLoaderSettingInvocationHandler.java:26)
              at com.sun.proxy.$Proxy118.getSearchRequestById(Unknown Source)
              at jdk.internal.reflect.GeneratedMethodAccessor2808.invoke(Unknown Source)
              at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base@11.0.22/DelegatingMethodAccessorImpl.java:43)
              at java.lang.reflect.Method.invoke(java.base@11.0.22/Method.java:566)
              at com.atlassian.plugin.osgi.bridge.external.HostComponentFactoryBean$DynamicServiceInvocationHandler.invoke(HostComponentFactoryBean.java:130)
              at com.sun.proxy.$Proxy118.getSearchRequestById(Unknown Source)
              at com.atlassian.greenhopper.service.rapid.view.RapidViewPermissionServiceImpl.canSeeRapidView(RapidViewPermissionServiceImpl.java:37)
              at com.atlassian.greenhopper.service.query.QueryServiceImpl.getSearchRequestWithoutSanitization(QueryServiceImpl.java:136)
              at com.atlassian.greenhopper.service.query.QueryServiceImpl.projectBelongsToRapidView(QueryServiceImpl.java:121)
              at com.atlassian.greenhopper.service.rapid.ProjectRapidViewServiceImpl.projectBelongsToRapidView(ProjectRapidViewServiceImpl.java:101)
              at com.atlassian.greenhopper.service.rapid.ProjectRapidViewServiceImpl.findRapidViewsByProject(ProjectRapidViewServiceImpl.java:55)
              at com.atlassian.greenhopper.web.conditions.ProjectHasBoardsCondition.projectHasBoards(ProjectHasBoardsCondition.java:74)
              at com.atlassian.greenhopper.web.conditions.ProjectHasBoardsCondition.shouldDisplay(ProjectHasBoardsCondition.java:51)
              at com.atlassian.plugin.web.conditions.AndCompositeCondition.shouldDisplay(AndCompositeCondition.java:17)
              at com.atlassian.plugin.web.conditions.AndCompositeCondition.shouldDisplay(AndCompositeCondition.java:17)
              at com.atlassian.plugin.web.DefaultWebInterfaceManager.filterFragmentsByCondition(DefaultWebInterfaceManager.java:184)
              at com.atlassian.plugin.web.DefaultWebInterfaceManager.getDisplayableItems(DefaultWebInterfaceManager.java:138)
              at com.atlassian.plugin.web.DefaultWebInterfaceManager.getDisplayableWebItems(DefaultWebInterfaceManager.java:229)
      ...
              at com.sun.proxy.$Proxy2948.getDisplayableWebItems(Unknown Source)
              at com.atlassian.jira.projects.page.ProjectPageServlet.getPluginProvidedDefaultPage(ProjectPageServlet.java:183)
              at com.atlassian.jira.projects.page.ProjectPageServlet.selectItemToRender(ProjectPageServlet.java:135)
              at com.atlassian.jira.projects.page.ProjectPageServlet.doGet(ProjectPageServlet.java:107)
      ...
              at javax.servlet.http.HttpServlet.service(HttpServlet.java:623)
      

      Steps to Reproduce

      1. Create a two project Jira instance (SCRUM and KANBAN)
      2. Click Projects -> SCRUM project

      Expected Results

      1. Statement like SELECT ..... WHERE id IN(....) is sent to load the cache

      Actual Results

      1. Individual SELECT query are performed for every board filter in the instance:
        ./atlassian-jira-sql.log.5:2024-05-23 02:56:47,706+0000 http-nio-8080-exec-17 url: /jira/browse/SCRUM, /jira/projects/SCRUM, /jira/plugins/servlet/projects/SCRUM; user: admin anonymous176x132x1 5vfvas /browse/SCRUM 1ms "SELECT filtername, authorname, DESCRIPTION, username, groupname, projectid, reqcontent, FAV_COUNT, filtername_lower FROM public.searchrequest WHERE ID='10001'"
        ./atlassian-jira-sql.log.5:2024-05-23 02:56:47,707+0000 http-nio-8080-exec-17 url: /jira/browse/SCRUM, /jira/projects/SCRUM, /jira/plugins/servlet/projects/SCRUM; user: admin anonymous176x132x1 5vfvas /browse/SCRUM 2ms Connection returned. borrowed : 0
        ./atlassian-jira-sql.log.5:2024-05-23 02:56:47,709+0000 http-nio-8080-exec-17 url: /jira/browse/SCRUM, /jira/projects/SCRUM, /jira/plugins/servlet/projects/SCRUM; user: admin anonymous176x132x1 5vfvas /browse/SCRUM 0ms Connection taken. borrowed : 1
        ./atlassian-jira-sql.log.5:2024-05-23 02:56:47,710+0000 http-nio-8080-exec-17 url: /jira/browse/SCRUM, /jira/projects/SCRUM, /jira/plugins/servlet/projects/SCRUM; user: admin anonymous176x132x1 5vfvas /browse/SCRUM 0ms "SELECT ID, entityid, entitytype, sharetype, PARAM1, PARAM2, RIGHTS FROM public.sharepermissions WHERE entityid='10001' AND entitytype='SearchRequest'"
        ./atlassian-jira-sql.log.5:2024-05-23 02:56:47,710+0000 http-nio-8080-exec-17 url: /jira/browse/SCRUM, /jira/projects/SCRUM, /jira/plugins/servlet/projects/SCRUM; user: admin anonymous176x132x1 5vfvas /browse/SCRUM 1ms Connection returned. borrowed : 0
        ./atlassian-jira-sql.log.5:2024-05-23 02:56:47,716+0000 http-nio-8080-exec-17 url: /jira/browse/SCRUM, /jira/projects/SCRUM, /jira/plugins/servlet/projects/SCRUM; user: admin anonymous176x132x1 5vfvas /browse/SCRUM 0ms Connection taken. borrowed : 1
        ./atlassian-jira-sql.log.5:2024-05-23 02:56:47,718+0000 http-nio-8080-exec-17 url: /jira/browse/SCRUM, /jira/projects/SCRUM, /jira/plugins/servlet/projects/SCRUM; user: admin anonymous176x132x1 5vfvas /browse/SCRUM 1ms "SELECT filtername, authorname, DESCRIPTION, username, groupname, projectid, reqcontent, FAV_COUNT, filtername_lower FROM public.searchrequest WHERE ID='10000'"
        ./atlassian-jira-sql.log.5:2024-05-23 02:56:47,718+0000 http-nio-8080-exec-17 url: /jira/browse/SCRUM, /jira/projects/SCRUM, /jira/plugins/servlet/projects/SCRUM; user: admin anonymous176x132x1 5vfvas /browse/SCRUM 2ms Connection returned. borrowed : 0
        ./atlassian-jira-sql.log.5:2024-05-23 02:56:47,718+0000 http-nio-8080-exec-17 url: /jira/browse/SCRUM, /jira/projects/SCRUM, /jira/plugins/servlet/projects/SCRUM; user: admin anonymous176x132x1 5vfvas /browse/SCRUM 0ms Connection taken. borrowed : 1
        ./atlassian-jira-sql.log.5:2024-05-23 02:56:47,719+0000 http-nio-8080-exec-17 url: /jira/browse/SCRUM, /jira/projects/SCRUM, /jira/plugins/servlet/projects/SCRUM; user: admin anonymous176x132x1 5vfvas /browse/SCRUM 1ms "SELECT ID, entityid, entitytype, sharetype, PARAM1, PARAM2, RIGHTS FROM public.sharepermissions WHERE entityid='10000' AND entitytype='SearchRequest'"
        ./atlassian-jira-sql.log.5:2024-05-23 02:56:47,719+0000 http-nio-8080-exec-17 url: /jira/browse/SCRUM, /jira/projects/SCRUM, /jira/plugins/servlet/projects/SCRUM; user: admin anonymous176x132x1 5vfvas /browse/SCRUM 1ms Connection returned. borrowed : 0
        

      select * from searchrequest

      10000	Filter for SCRUM board	admin		admin			project = SCRUM ORDER BY Rank ASC	0	filter for scrum board
      10001	Filter for KANBAN board	admin		admin			project = KANBAN ORDER BY Rank ASC	0	filter for kanban board
      

      Workaround

      Currently there is no known workaround for this behavior. A workaround will be added here when available

              Assignee:
              Anton Miniailo
              Reporter:
              Alex [Atlassian,PSE]
              Votes:
              1 Vote for this issue
              Watchers:
              7 Start watching this issue

                Created:
                Updated:
                Resolved: