Uploaded image for project: 'Jira Software Data Center'
  1. Jira Software Data Center
  2. JSWSERVER-20452

Epic Link query causes timeouts

XMLWordPrintable

      Problem Definition

      While Jira 8 has made great strides in performance, there remain a few operations that are regularly 5+ seconds. I'm singling out Epic Link query performance because I'm noticing this is one of our top-ranked common operations. This can cause delays and block stories from being created when the Epic Link is a required field on the create screen.

      Steps to reproduce

      You can experience this when you:

      1. Edit an Issue
      2. fill out the `E_pic Link_` value
        • Jira will generate the XHR request -/rest/greenhopper/1.0/epics

      Suggested Solution

      Epic data loads within 3 seconds.

      Notes

      • Data from the access logs:
        5.719 /rest/greenhopper/1.0/epics?searchQuery=&projectKey=XXX&maxResults=100&hideDone=true&_=1582316504312
        5.830 /rest/greenhopper/1.0/epics?searchQuery=&projectKey=XXX&maxResults=100&hideDone=true&_=1582317208392
        5.832 /rest/greenhopper/1.0/epics?searchQuery=&projectKey=XXX&maxResults=100&hideDone=false&_=1582305640419
        5.861 /rest/greenhopper/1.0/epics?searchQuery=&projectKey=XXX&maxResults=100&hideDone=true&_=1582318961711
        5.916 /rest/greenhopper/1.0/epics?searchQuery=&projectKey=XXX&maxResults=100&hideDone=true&_=1582305972667
        5.948 /rest/greenhopper/1.0/epics?searchQuery=&projectKey=XXX&maxResults=100&hideDone=true&_=1582297025081
        5.963 /rest/greenhopper/1.0/epics?searchQuery=&projectKey=XXX&maxResults=100&hideDone=false&_=1582311915016
        6.012 /rest/greenhopper/1.0/epics?searchQuery=&projectKey=XXX&maxResults=100&hideDone=true&_=1582314026469
        6.161 /rest/greenhopper/1.0/epics?searchQuery=&projectKey=XXX&maxResults=100&hideDone=true&_=1582314877488
        6.313 /rest/greenhopper/1.0/epics?searchQuery=&projectKey=XXX&maxResults=100&hideDone=true?searchQuery=&projectKey=XXX&maxResults=10&hideDone=true
        6.440 /rest/greenhopper/1.0/epics?searchQuery=&projectKey=XXX&maxResults=100&hideDone=true?searchQuery=&projectKey=XXX&maxResults=100&hideDone=true
        
      • Here are our Epic Statistics. Total Epics: 28K
        • issuetype=Epic and statusCategory = Done : count: 14k
        • issuetype=Epic and statusCategory != Done : count: 14k

      Some sample thread dumps in case they are helpful

      • Snippet1
        "http-nio-8082-exec-107" #2634 daemon prio=5 os_prio=0 tid=0x00007f5dbca36800 nid=0x54fe runnable [0x00007f5d5cc0b000]
           java.lang.Thread.State: RUNNABLE
        	at java.util.ArrayList.indexOf(ArrayList.java:321)
        	at java.util.ArrayList.contains(ArrayList.java:304)
        	at com.atlassian.greenhopper.service.issue.callback.EpicLabelAndKeyMatchingCallback.lambda$orderEpicByName$5(EpicLabelAndKeyMatchingCallback.java:252)
        	at com.atlassian.greenhopper.service.issue.callback.EpicLabelAndKeyMatchingCallback$$Lambda$8850/1016207412.apply(Unknown Source)
        	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
        	at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382)
        	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
        	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
        	at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
        	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
        	at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:566)
        	at com.atlassian.greenhopper.service.issue.callback.EpicLabelAndKeyMatchingCallback.orderEpicByName(EpicLabelAndKeyMatchingCallback.java:253)
        	at com.atlassian.greenhopper.service.issue.callback.EpicLabelAndKeyMatchingCallback.getIssues(EpicLabelAndKeyMatchingCallback.java:233)
        	at com.atlassian.greenhopper.service.issuelink.EpicPickerServiceImpl.listEpicNames(EpicPickerServiceImpl.java:69)
        	at com.atlassian.greenhopper.web.rapid.issue.issuelink.EpicResource$4.call(EpicResource.java:225)
        	at com.atlassian.greenhopper.web.rapid.issue.issuelink.EpicResource$4.call(EpicResource.java:218)
        	at com.atlassian.greenhopper.web.util.RestCall.response(RestCall.java:42)
        	at com.atlassian.greenhopper.web.AbstractResource.createResponse(AbstractResource.java:111)
        	at com.atlassian.greenhopper.web.AbstractResource.responseWithoutAccessCheck(AbstractResource.java:105)
        ..
        
      • Snippet2
        "http-nio-8082-exec-107" #2634 daemon prio=5 os_prio=0 tid=0x00007f5dbca36800 nid=0x54fe runnable [0x00007f5d5cc0b000]
           java.lang.Thread.State: RUNNABLE
        	at java.util.ArrayList.indexOf(ArrayList.java:321)
        	at java.util.ArrayList.contains(ArrayList.java:304)
        	at com.atlassian.greenhopper.service.issue.callback.EpicLabelAndKeyMatchingCallback.lambda$orderEpicByName$5(EpicLabelAndKeyMatchingCallback.java:252)
        	at com.atlassian.greenhopper.service.issue.callback.EpicLabelAndKeyMatchingCallback$$Lambda$8850/1016207412.apply(Unknown Source)
        	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
        	at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382)
        	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
        	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
        	at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
        	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
        	at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:566)
        	at com.atlassian.greenhopper.service.issue.callback.EpicLabelAndKeyMatchingCallback.orderEpicByName(EpicLabelAndKeyMatchingCallback.java:253)
        	at com.atlassian.greenhopper.service.issue.callback.EpicLabelAndKeyMatchingCallback.getIssues(EpicLabelAndKeyMatchingCallback.java:233)
        	at com.atlassian.greenhopper.service.issuelink.EpicPickerServiceImpl.listEpicNames(EpicPickerServiceImpl.java:69)
        	at com.atlassian.greenhopper.web.rapid.issue.issuelink.EpicResource$4.call(EpicResource.java:225)
        	at com.atlassian.greenhopper.web.rapid.issue.issuelink.EpicResource$4.call(EpicResource.java:218)
        	at com.atlassian.greenhopper.web.util.RestCall.response(RestCall.java:42)
        	at com.atlassian.greenhopper.web.AbstractResource.createResponse(AbstractResource.java:111)
        	at com.atlassian.greenhopper.web.AbstractResource.responseWithoutAccessCheck(AbstractResource.java:105)
        ...
        

      Code samples

      • com.atlassian.greenhopper.web.rapid.issue.issuelink.EpicResource#listEpics
        /**
         * Resource for changing epic-issue links.
         */
        @Path("epics")
        @AnonymousAllowed
        @Consumes({MediaType.APPLICATION_JSON})
        @Produces({MediaType.APPLICATION_JSON})
        
        ...
        public Response listEpics(@QueryParam("searchQuery") final String searchQuery, @QueryParam("maxResults") final int maxResults, @QueryParam("projectKey") final String projectKeys, @QueryParam("hideDone") final boolean hideDone, @QueryParam("query") final String query, @QueryParam("filterEpicsByGivenProjects") final boolean filterEpicByGivenProjects)
         ...
        
                        List<EpicNamesResult> epicNamesResults = check(epicPickerService.listEpicNames(user, searchTerm, maxResults, projectKeys, hideDone, filterEpicByGivenProjects));
        
                        FindEpicNamesResponse response = new FindEpicNamesResponse();
                        for (EpicNamesResult epicResult : epicNamesResults)
                        {
                            EpicNameListModel list = new EpicNameListModel(epicResult.getListDescriptor());
                            for (EpicModel epicName : epicResult.getNames())
                            {
                                String key = epicName.getEpicKey();
                                String label = epicName.getEpicName();
                                label = epicLabelProvider.getEpicLabel(key, label);
                                list.epicNames.add(new EpicNameModel(key, label, epicName.isDone()));
                            }
                            response.epicLists.add(list);
                            response.total = epicResult.getTotal();
                        }
        
                        return createOkResponse(response);
                    }
                });
            }
        

        Workaround:

        There is no workaround currently for this issue

              snatkovskyi Stanislav Natkovskyi (Inactive)
              a38518e05741 David Yu
              Votes:
              25 Vote for this issue
              Watchers:
              37 Start watching this issue

                Created:
                Updated:
                Resolved: