-
Bug
-
Resolution: Fixed
-
High
-
8.5.7
-
8.05
-
1
-
Severity 2 - Major
-
Issue Summary
Users, while searching for sprints in the advance search, Triggers rest API calls like below which are (nothing but autocomplete suggestions) and these are causing very HIGH CPU utilisation and load.
GET /rest/api/2/jql/autocompletedata/suggestions?fieldName=Sprint&fieldValue=A&_=1609757846274
And this is the referrer
https://<JIRA>/issues/?jql=Status%20not%20in%20(closed%2Cdone)%20and%20Sprint%20is%20not%20EMPTY%20"
All these are browser sessions.
Steps to Reproduce
N/A
Can be reproduced with more than 30k+ sprints and going to advance search and search for sprints.
Expected Results
The autocomplete shouldn't spike CPU and the response of the request should be quicker
Actual Results
CPU utlization shoots up and with an increasing number of threads going into Sprint autocomplete code, higher the spike and CPU load average.
Here is the snippet of the thread causing high CPU
The code that is invoked with the above call is
at org.apache.lucene.util.FixedBitSet.<init>(FixedBitSet.java:115) at org.apache.lucene.util.DocIdSetBuilder.upgradeToBitSet(DocIdSetBuilder.java:235) at org.apache.lucene.util.DocIdSetBuilder.grow(DocIdSetBuilder.java:178) at org.apache.lucene.util.DocIdSetBuilder.add(DocIdSetBuilder.java:156) at org.apache.lucene.search.TermInSetQuery$1.rewrite(TermInSetQuery.java:261) at org.apache.lucene.search.TermInSetQuery$1.scorer(TermInSetQuery.java:313) at org.apache.lucene.search.Weight.scorerSupplier(Weight.java:113) at org.apache.lucene.search.LRUQueryCache$CachingWrapperWeight.scorerSupplier(LRUQueryCache.java:714) at org.apache.lucene.search.BooleanWeight.scorerSupplier(BooleanWeight.java:329) at org.apache.lucene.search.LRUQueryCache$CachingWrapperWeight.scorerSupplier(LRUQueryCache.java:714) at org.apache.lucene.search.BooleanWeight.scorerSupplier(BooleanWeight.java:329) at org.apache.lucene.search.BooleanWeight.scorer(BooleanWeight.java:295) at org.apache.lucene.search.Weight.bulkScorer(Weight.java:147) at org.apache.lucene.search.BooleanWeight.bulkScorer(BooleanWeight.java:289) at org.apache.lucene.search.LRUQueryCache$CachingWrapperWeight.bulkScorer(LRUQueryCache.java:795) at org.apache.lucene.search.IndexSearcher.search(IndexSearcher.java:657) at org.apache.lucene.search.IndexSearcher.search(IndexSearcher.java:462) at com.atlassian.jira.index.DelegateSearcher.search(DelegateSearcher.java:169) at com.atlassian.jira.index.DelegateSearcher.search(DelegateSearcher.java:169) at com.atlassian.jira.index.UnmanagedIndexSearcher.search(UnmanagedIndexSearcher.java:9) at com.atlassian.jira.index.DelegateSearcher.search(DelegateSearcher.java:169) at com.atlassian.jira.index.ManagedIndexSearcher.search(ManagedIndexSearcher.java:15) at com.atlassian.jira.issue.search.providers.LuceneSearchProvider.getHitCount(LuceneSearchProvider.java:178) at com.atlassian.jira.issue.search.providers.LuceneSearchProvider.getHitCount(LuceneSearchProvider.java:145) at com.atlassian.jira.bc.issue.search.DefaultSearchService.searchCount(DefaultSearchService.java:130) at sun.reflect.GeneratedMethodAccessor1742.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at com.atlassian.plugin.util.ContextClassLoaderSettingInvocationHandler.invoke(ContextClassLoaderSettingInvocationHandler.java:26) at com.sun.proxy.$Proxy439.searchCount(Unknown Source) at sun.reflect.GeneratedMethodAccessor1742.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at com.atlassian.plugin.osgi.bridge.external.HostComponentFactoryBean$DynamicServiceInvocationHandler.invoke(HostComponentFactoryBean.java:131) at com.sun.proxy.$Proxy439.searchCount(Unknown Source) at com.atlassian.greenhopper.service.sprint.SprintPermissionServiceImpl.getIssueCountForSprint(SprintPermissionServiceImpl.java:250) at com.atlassian.greenhopper.service.sprint.SprintPermissionServiceImpl.canViewSprint(SprintPermissionServiceImpl.java:90) at com.atlassian.greenhopper.customfield.sprint.SprintResolver.checkSprintAccessible(SprintResolver.java:31) at com.atlassian.greenhopper.customfield.sprint.SprintResolver$SprintAccessible.apply(SprintResolver.java:139) at com.atlassian.greenhopper.customfield.sprint.SprintResolver$SprintAccessible.apply(SprintResolver.java:125) at com.google.common.base.Predicates$AndPredicate.apply(Predicates.java:353) at com.google.common.collect.Iterators$5.computeNext(Iterators.java:639) at com.google.common.collect.AbstractIterator.tryToComputeNext(AbstractIterator.java:141) at com.google.common.collect.AbstractIterator.hasNext(AbstractIterator.java:136) at com.google.common.collect.Iterators.addAll(Iterators.java:357) at com.google.common.collect.Lists.newArrayList(Lists.java:147) at com.google.common.collect.Lists.newArrayList(Lists.java:133) at com.atlassian.greenhopper.customfield.sprint.SprintResolver.findSprintByPredicate(SprintResolver.java:78) at com.atlassian.greenhopper.customfield.sprint.SprintResolver.findSprintByPredicate(SprintResolver.java:97) at com.atlassian.greenhopper.customfield.sprint.SprintClauseValueGenerator.getPossibleValues(SprintClauseValueGenerator.java:40)
Workaround
- One workaround could be to disable the autocomplete (which is not so pleasant workaround.)
- Another effective workaround could be to delay the requests which are sending the autocomplete suggestion. That is, adding the below JS in the announcement Banner
<script type='text/javascript'> jQuery().ready(function() { $('textarea[id="advanced-search"]').focusin( function f() { if (!window.dirtypatch){ // trying avoid adding same event listener more than once setTimeout( function() { console.log("patching AutoComplete delay"); JIRA.AutoComplete.delay = function delay(callback, l) { if (delay.t) { clearTimeout(delay.t); delay.t = undefined; } delay.t = setTimeout(callback, 1 * 1000); // default is 0.3 * 1000 }; }, 1000); // patch is applied a second after search text are is focused, // to give time for other initialization window.dirtypatch = 1; } }) }); </script>