-
Type:
Bug
-
Resolution: Fixed
-
Priority:
Low
-
Affects Version/s: 9.8.1, 9.12.0
-
Component/s: AgileBoard
-
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
- Create a two project Jira instance (SCRUM and KANBAN)
- Click Projects -> SCRUM project
Expected Results
- Statement like SELECT ..... WHERE id IN(....) is sent to load the cache
Actual Results
- 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