{"action":"created","comment":{"url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/pulls/comments/170786895","pull_request_review_id":99526236,"id":170786895,"diff_hunk":"@@ -559,33 +558,61 @@ private long writeRawLogTo(AnnotatedLargeText<?> text, long start, OutputStream\n     }\n \n     @GuardedBy(\"completed\")\n-    private transient LoadingCache<FlowNode,Optional<String>> logPrefixCache;\n-    private @CheckForNull String getLogPrefix(FlowNode node) {\n-        // TODO could also use FlowScanningUtils.fetchEnclosingBlocks(node).filter(FlowScanningUtils.hasActionPredicate(ThreadNameAction.class)),\n-        // but this would not let us cache intermediate results\n+    private transient Cache<FlowNode,Optional<String>> branchNameCache;  // TODO Consider making this a top-level FlowNode API\n+\n+    private Cache<FlowNode, Optional<String>> getBranchNameCache() {\n         synchronized (completed) {\n-            if (logPrefixCache == null) {\n-                logPrefixCache = CacheBuilder.newBuilder().weakKeys().build(new CacheLoader<FlowNode,Optional<String>>() {\n-                    @Override public @Nonnull Optional<String> load(FlowNode node) {\n-                        if (node instanceof BlockEndNode) {\n-                            return Optional.fromNullable(getLogPrefix(((BlockEndNode) node).getStartNode()));\n-                        }\n-                        ThreadNameAction threadNameAction = node.getAction(ThreadNameAction.class);\n-                        if (threadNameAction != null) {\n-                            return Optional.of(threadNameAction.getThreadName());\n-                        }\n-                        for (FlowNode parent : node.getParents()) {\n-                            String prefix = getLogPrefix(parent);\n-                            if (prefix != null) {\n-                                return Optional.of(prefix);\n-                            }\n-                        }\n-                        return Optional.absent();\n-                    }\n-                });\n+            if (branchNameCache == null) {\n+                branchNameCache = CacheBuilder.newBuilder().weakKeys().build();\n+            }\n+            return branchNameCache;\n+        }\n+    }\n+\n+    private @CheckForNull String getBranchName(FlowNode node) {\n+        Cache<FlowNode, Optional<String>> cache = getBranchNameCache();\n+\n+        Optional<String> output = cache.getIfPresent(node);\n+        if (output != null) {\n+            return output.orNull();\n+        }\n+\n+        // We must explicitly check for the current node being the start/end of a parallel branch\n+        if (node instanceof BlockEndNode) {\n+            output = Optional.fromNullable(getBranchName(((BlockEndNode) node).getStartNode()));\n+            cache.put(node, output);\n+            return output.orNull();\n+        } else if (node instanceof BlockStartNode) { // And of course this node might be the start of a parallel branch\n+            ThreadNameAction threadNameAction = node.getPersistentAction(ThreadNameAction.class);\n+            if (threadNameAction != null) {\n+                String name = threadNameAction.getThreadName();\n+                cache.put(node, Optional.of(name));\n+                return name;\n+            }\n+        }\n+\n+        // Check parent which will USUALLY result in a cache hit, but improve performance and avoid a stack overflow by not doing recursion\n+        List<FlowNode> parents = node.getParents();\n+        if (!parents.isEmpty()) {\n+            FlowNode parent = parents.get(0);","path":"src/main/java/org/jenkinsci/plugins/workflow/job/WorkflowRun.java","position":95,"original_position":95,"commit_id":"5ce467012969afa23f4822f90e3acc8e67dd5da8","original_commit_id":"5ce467012969afa23f4822f90e3acc8e67dd5da8","user":{"login":"svanoort","id":5400948,"avatar_url":"https://avatars3.githubusercontent.com/u/5400948?v=4","gravatar_id":"","url":"https://api.github.com/users/svanoort","html_url":"https://github.com/svanoort","followers_url":"https://api.github.com/users/svanoort/followers","following_url":"https://api.github.com/users/svanoort/following{/other_user}","gists_url":"https://api.github.com/users/svanoort/gists{/gist_id}","starred_url":"https://api.github.com/users/svanoort/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/svanoort/subscriptions","organizations_url":"https://api.github.com/users/svanoort/orgs","repos_url":"https://api.github.com/users/svanoort/repos","events_url":"https://api.github.com/users/svanoort/events{/privacy}","received_events_url":"https://api.github.com/users/svanoort/received_events","type":"User","site_admin":false},"body":"In practice we will never hit a case where parents > 1, because only the closing block for a Parallel will have > 1 parents, and because that's a BlockEndNode so it would be handled above.","created_at":"2018-02-27T01:00:25Z","updated_at":"2018-02-27T01:00:25Z","html_url":"https://github.com/jenkinsci/workflow-job-plugin/pull/91#discussion_r170786895","pull_request_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/pulls/91","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/pulls/comments/170786895"},"html":{"href":"https://github.com/jenkinsci/workflow-job-plugin/pull/91#discussion_r170786895"},"pull_request":{"href":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/pulls/91"}}},"pull_request":{"url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/pulls/91","id":171534765,"html_url":"https://github.com/jenkinsci/workflow-job-plugin/pull/91","diff_url":"https://github.com/jenkinsci/workflow-job-plugin/pull/91.diff","patch_url":"https://github.com/jenkinsci/workflow-job-plugin/pull/91.patch","issue_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/issues/91","number":91,"state":"open","locked":false,"title":"[JENKINS-38383] Avoid Stackoverflow and full-flowgraph scan when trying to get branch names for log prefixes","user":{"login":"svanoort","id":5400948,"avatar_url":"https://avatars3.githubusercontent.com/u/5400948?v=4","gravatar_id":"","url":"https://api.github.com/users/svanoort","html_url":"https://github.com/svanoort","followers_url":"https://api.github.com/users/svanoort/followers","following_url":"https://api.github.com/users/svanoort/following{/other_user}","gists_url":"https://api.github.com/users/svanoort/gists{/gist_id}","starred_url":"https://api.github.com/users/svanoort/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/svanoort/subscriptions","organizations_url":"https://api.github.com/users/svanoort/orgs","repos_url":"https://api.github.com/users/svanoort/repos","events_url":"https://api.github.com/users/svanoort/events{/privacy}","received_events_url":"https://api.github.com/users/svanoort/received_events","type":"User","site_admin":false},"body":"Solves [JENKINS-38383](https://issues.jenkins-ci.org/browse/JENKINS-38383) which could trigger errors upon restart with a complex Pipeline. \r\n\r\nRenames the logPrefixCache & method to better reflect what they do (get the branch name for a FlowNode). \r\n\r\nAlso subsumes https://github.com/jenkinsci/workflow-job-plugin/pull/84 in passing since it's trivial and would cause a merge conflict there anyway. ","created_at":"2018-02-27T00:54:23Z","updated_at":"2018-02-27T01:00:25Z","closed_at":null,"merged_at":null,"merge_commit_sha":"2a0166b583873cba1d764184566bef9d8a2858f4","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/pulls/91/commits","review_comments_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/pulls/91/comments","review_comment_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/pulls/comments{/number}","comments_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/issues/91/comments","statuses_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/statuses/5ce467012969afa23f4822f90e3acc8e67dd5da8","head":{"label":"svanoort:fix-prefix-bugs","ref":"fix-prefix-bugs","sha":"5ce467012969afa23f4822f90e3acc8e67dd5da8","user":{"login":"svanoort","id":5400948,"avatar_url":"https://avatars3.githubusercontent.com/u/5400948?v=4","gravatar_id":"","url":"https://api.github.com/users/svanoort","html_url":"https://github.com/svanoort","followers_url":"https://api.github.com/users/svanoort/followers","following_url":"https://api.github.com/users/svanoort/following{/other_user}","gists_url":"https://api.github.com/users/svanoort/gists{/gist_id}","starred_url":"https://api.github.com/users/svanoort/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/svanoort/subscriptions","organizations_url":"https://api.github.com/users/svanoort/orgs","repos_url":"https://api.github.com/users/svanoort/repos","events_url":"https://api.github.com/users/svanoort/events{/privacy}","received_events_url":"https://api.github.com/users/svanoort/received_events","type":"User","site_admin":false},"repo":{"id":102875636,"name":"workflow-job-plugin","full_name":"svanoort/workflow-job-plugin","owner":{"login":"svanoort","id":5400948,"avatar_url":"https://avatars3.githubusercontent.com/u/5400948?v=4","gravatar_id":"","url":"https://api.github.com/users/svanoort","html_url":"https://github.com/svanoort","followers_url":"https://api.github.com/users/svanoort/followers","following_url":"https://api.github.com/users/svanoort/following{/other_user}","gists_url":"https://api.github.com/users/svanoort/gists{/gist_id}","starred_url":"https://api.github.com/users/svanoort/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/svanoort/subscriptions","organizations_url":"https://api.github.com/users/svanoort/orgs","repos_url":"https://api.github.com/users/svanoort/repos","events_url":"https://api.github.com/users/svanoort/events{/privacy}","received_events_url":"https://api.github.com/users/svanoort/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/svanoort/workflow-job-plugin","description":null,"fork":true,"url":"https://api.github.com/repos/svanoort/workflow-job-plugin","forks_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/forks","keys_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/keys{/key_id}","collaborators_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/teams","hooks_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/hooks","issue_events_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/issues/events{/number}","events_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/events","assignees_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/assignees{/user}","branches_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/branches{/branch}","tags_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/tags","blobs_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/git/refs{/sha}","trees_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/git/trees{/sha}","statuses_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/statuses/{sha}","languages_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/languages","stargazers_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/stargazers","contributors_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/contributors","subscribers_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/subscribers","subscription_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/subscription","commits_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/commits{/sha}","git_commits_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/git/commits{/sha}","comments_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/comments{/number}","issue_comment_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/issues/comments{/number}","contents_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/contents/{+path}","compare_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/compare/{base}...{head}","merges_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/merges","archive_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/downloads","issues_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/issues{/number}","pulls_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/pulls{/number}","milestones_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/milestones{/number}","notifications_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/labels{/name}","releases_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/releases{/id}","deployments_url":"https://api.github.com/repos/svanoort/workflow-job-plugin/deployments","created_at":"2017-09-08T15:23:51Z","updated_at":"2017-09-08T15:23:53Z","pushed_at":"2018-02-27T00:52:28Z","git_url":"git://github.com/svanoort/workflow-job-plugin.git","ssh_url":"git@github.com:svanoort/workflow-job-plugin.git","clone_url":"https://github.com/svanoort/workflow-job-plugin.git","svn_url":"https://github.com/svanoort/workflow-job-plugin","homepage":"https://wiki.jenkins-ci.org/display/JENKINS/Pipeline+Job+Plugin","size":684,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":null,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"jenkinsci:master","ref":"master","sha":"023a0659bf9eb375b421ab2a777eb8bc5eaa8572","user":{"login":"jenkinsci","id":107424,"avatar_url":"https://avatars0.githubusercontent.com/u/107424?v=4","gravatar_id":"","url":"https://api.github.com/users/jenkinsci","html_url":"https://github.com/jenkinsci","followers_url":"https://api.github.com/users/jenkinsci/followers","following_url":"https://api.github.com/users/jenkinsci/following{/other_user}","gists_url":"https://api.github.com/users/jenkinsci/gists{/gist_id}","starred_url":"https://api.github.com/users/jenkinsci/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jenkinsci/subscriptions","organizations_url":"https://api.github.com/users/jenkinsci/orgs","repos_url":"https://api.github.com/users/jenkinsci/repos","events_url":"https://api.github.com/users/jenkinsci/events{/privacy}","received_events_url":"https://api.github.com/users/jenkinsci/received_events","type":"Organization","site_admin":false},"repo":{"id":55543389,"name":"workflow-job-plugin","full_name":"jenkinsci/workflow-job-plugin","owner":{"login":"jenkinsci","id":107424,"avatar_url":"https://avatars0.githubusercontent.com/u/107424?v=4","gravatar_id":"","url":"https://api.github.com/users/jenkinsci","html_url":"https://github.com/jenkinsci","followers_url":"https://api.github.com/users/jenkinsci/followers","following_url":"https://api.github.com/users/jenkinsci/following{/other_user}","gists_url":"https://api.github.com/users/jenkinsci/gists{/gist_id}","starred_url":"https://api.github.com/users/jenkinsci/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jenkinsci/subscriptions","organizations_url":"https://api.github.com/users/jenkinsci/orgs","repos_url":"https://api.github.com/users/jenkinsci/repos","events_url":"https://api.github.com/users/jenkinsci/events{/privacy}","received_events_url":"https://api.github.com/users/jenkinsci/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/jenkinsci/workflow-job-plugin","description":null,"fork":false,"url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin","forks_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/forks","keys_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/teams","hooks_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/hooks","issue_events_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/issues/events{/number}","events_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/events","assignees_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/assignees{/user}","branches_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/branches{/branch}","tags_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/tags","blobs_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/git/refs{/sha}","trees_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/statuses/{sha}","languages_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/languages","stargazers_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/stargazers","contributors_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/contributors","subscribers_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/subscribers","subscription_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/subscription","commits_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/commits{/sha}","git_commits_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/git/commits{/sha}","comments_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/comments{/number}","issue_comment_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/issues/comments{/number}","contents_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/contents/{+path}","compare_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/merges","archive_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/downloads","issues_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/issues{/number}","pulls_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/pulls{/number}","milestones_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/milestones{/number}","notifications_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/labels{/name}","releases_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/releases{/id}","deployments_url":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/deployments","created_at":"2016-04-05T20:27:07Z","updated_at":"2017-12-08T02:47:08Z","pushed_at":"2018-02-27T00:54:23Z","git_url":"git://github.com/jenkinsci/workflow-job-plugin.git","ssh_url":"git@github.com:jenkinsci/workflow-job-plugin.git","clone_url":"https://github.com/jenkinsci/workflow-job-plugin.git","svn_url":"https://github.com/jenkinsci/workflow-job-plugin","homepage":"https://wiki.jenkins-ci.org/display/JENKINS/Pipeline+Job+Plugin","size":684,"stargazers_count":8,"watchers_count":8,"language":"Java","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":48,"mirror_url":null,"archived":false,"open_issues_count":13,"license":null,"forks":48,"open_issues":13,"watchers":8,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/pulls/91"},"html":{"href":"https://github.com/jenkinsci/workflow-job-plugin/pull/91"},"issue":{"href":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/issues/91"},"comments":{"href":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/issues/91/comments"},"review_comments":{"href":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/pulls/91/comments"},"review_comment":{"href":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/pulls/91/commits"},"statuses":{"href":"https://api.github.com/repos/jenkinsci/workflow-job-plugin/statuses/5ce467012969afa23f4822f90e3acc8e67dd5da8"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"svanoort"}}