Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

It takes a long time to open a big pull request page #14734

Closed
ffbh123456 opened this issue Feb 18, 2021 · 35 comments · Fixed by #17991
Closed

It takes a long time to open a big pull request page #14734

ffbh123456 opened this issue Feb 18, 2021 · 35 comments · Fixed by #17991
Labels
performance/speed performance issues with slow downs

Comments

@ffbh123456
Copy link

ffbh123456 commented Feb 18, 2021

Gitea version 1.14.0+dev-449-ge0c753e77 built with GNU Make 4.3, go1.15.6 : bindata, timetzdata, sqlite, sqlite_unlock_notify

The gitea server is deployed locally. I made a pull request and changed more than 100 files and more than 1,000 lines. It took me nearly two minutes to open this pull request page.
I looked at the log, mainly because these two API return very slowly, both of which are about one minute
Are there any configuration items that can improve the speed here?
image

@lunny lunny added the performance/speed performance issues with slow downs label Feb 18, 2021
@lunny
Copy link
Member

lunny commented Feb 18, 2021

How many files and lines changed on this PR?

@tomaswarynyca
Copy link
Contributor

An example https://gitea.com/gitea/tea/pulls/316/files

I think you should put a limit to the amount of content displayed and if the user requires more by clicking on a button to load more content.

@ffbh123456
Copy link
Author

@lunny
100 file, 1000 add line, 1000 delete line, every file about 10 add line and 10 delete line.

@PhenX
Copy link

PhenX commented Feb 19, 2021

I agree that the pull request page can be very hard to use, even more when dealing with many files. One solution would be to show a tree of the modified files and show the diff when clicking on those files. We had this on bitbucket and that was really better than to have everything on the same page.
This would solve the problem for this kind of pull request, and I personally find it way better.
All my colleagues agree with this, they miss this feature.

@bartkaptur
Copy link

Same problem here. Setting DISABLE_DIFF_HIGHLIGHT = true helps, but only gets you so far. The HTML generated for a pull request is highly complicated and gets huge quickly. A new, simplified mode for this view would be useful.

@primesun
Copy link

primesun commented May 8, 2021

In my opinion the ideal solution would be to have a file tree on the pull request page, and you would click to select one file diff at a time.

@PhenX
Copy link

PhenX commented May 10, 2021

Hello, to follow up on my last message about the pull request page, I started a project built on AspNet Core (5.0, but might work easily on 3.1 or even 2.1 as the backend is rather simple, no database required, everything is done via API) and VueJS for the front end.

It uses the Gitea API to provide :

  • Authentication
  • A list of the connected user's accessible pull requests or only the ones for which he's a reviewer
  • A GUI with a tree of the PR files
  • A diff based on Monaco Editor (side by side view or unified)
  • Ability to view/add comments on the files
  • Approve / Reject / Comment buttons
  • Previous diff / next diff buttons
  • A viewed / not viewed status for each file (via localStorage)
  • All in a single page, no page reload required, etc
  • Dark theme

I'm planning to release it as open source when I think it's less buggy, but a few members of my team already use it (I do everyday).

Here is what it loooks like :
image

@zeripath
Copy link
Contributor

Yes this is a known problem.

I know how to solve it but I still haven't been able to get round to it.

We need to make the diff page in sections and farm parts of it off to Ajax and other requests.

@typeless
Copy link
Contributor

typeless commented Jun 9, 2021

I have seen this issue too.
The bottleneck appears to be in the syntax highlight library.

I sampled the stack trace when my Gitea was hanging on showing pull diffs and got the following:

goroutine 396662 [runnable]:
github.com/danwakefield/fnmatch.Match(0x2a0e726, 0x4, 0xc012b7b520, 0x17, 0x0, 0xc00c773900)
	/home/mural/src/code.gitea.io/gitea/vendor/github.com/danwakefield/fnmatch/fnmatch.go:39 +0x78c
github.com/danwakefield/fnmatch.Match(0x2a0e726, 0x4, 0xc012b7b51d, 0x1a, 0x0, 0xc00c773900)
	/home/mural/src/code.gitea.io/gitea/vendor/github.com/danwakefield/fnmatch/fnmatch.go:108 +0x33f
github.com/alecthomas/chroma/lexers/internal.Match(0xc012b7b51d, 0x1a, 0xc012b7b535, 0x2)
	/home/mural/src/code.gitea.io/gitea/vendor/github.com/alecthomas/chroma/lexers/internal/api.go:94 +0x4fb
github.com/alecthomas/chroma/lexers.Match(...)
	/home/mural/src/code.gitea.io/gitea/vendor/github.com/alecthomas/chroma/lexers/lexers.go:51
code.gitea.io/gitea/modules/highlight.Code(0xc012b7b4a3, 0x94, 0xc014ce4781, 0x70, 0xc00b045a50, 0x40f13b)
	/home/mural/src/code.gitea.io/gitea/modules/highlight/highlight.go:77 +0x5af
code.gitea.io/gitea/services/gitdiff.(*DiffSection).GetComputedInlineDiffFor(0xc0131ed100, 0xc01349a140, 0x0, 0x0)
	/home/mural/src/code.gitea.io/gitea/services/gitdiff/gitdiff.go:551 +0x64c
reflect.Value.call(0x26a21e0, 0xc0131ed100, 0x213, 0x2a04a2d, 0x4, 0xc00c777578, 0x1, 0x1, 0xc013477cd8, 0x196, ...)
	/home/mural/src/golang.org/go1.16.3/src/reflect/value.go:476 +0x8e7
reflect.Value.Call(0x26a21e0, 0xc0131ed100, 0x213, 0xc00c777578, 0x1, 0x1, 0xc015ac5400, 0x27ae020, 0xc013477cd8)
	/home/mural/src/golang.org/go1.16.3/src/reflect/value.go:337 +0xb9
text/template.safeCall(0x26a21e0, 0xc0131ed100, 0x213, 0xc00c777578, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, ...)
	/home/mural/src/golang.org/go1.16.3/src/text/template/funcs.go:365 +0xbd
text/template.(*state).evalCall(0xc00b046ec8, 0x27ae020, 0xc013477cd8, 0x196, 0x26a21e0, 0xc0131ed100, 0x213, 0x3f94dd0, 0xc00b227050, 0xc005f94969, ...)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:725 +0x689
text/template.(*state).evalField(0xc00b046ec8, 0x27ae020, 0xc013477cd8, 0x196, 0xc005f94969, 0x18, 0x3f94dd0, 0xc00b227050, 0xc0084472a0, 0x2, ...)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:609 +0xbf1
text/template.(*state).evalFieldChain(0xc00b046ec8, 0x27ae020, 0xc013477cd8, 0x196, 0x26a21e0, 0xc013313400, 0x196, 0x3f94dd0, 0xc00b227050, 0xc008447290, ...)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:570 +0x225
text/template.(*state).evalVariableNode(0xc00b046ec8, 0x27ae020, 0xc013477cd8, 0x196, 0xc00b227050, 0xc0084472a0, 0x2, 0x2, 0x2698d20, 0x56a2da8, ...)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:558 +0x2cc
text/template.(*state).evalCommand(0xc00b046ec8, 0x27ae020, 0xc013477cd8, 0x196, 0xc00b226ff0, 0x2698d20, 0x56a2da8, 0x99, 0xc00b046ec8, 0x6, ...)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:473 +0x825
text/template.(*state).evalPipeline(0xc00b046ec8, 0x27ae020, 0xc013477cd8, 0x196, 0xc00ae9bec0, 0x0, 0x0, 0x0)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:436 +0x125
text/template.(*state).walk(0xc00b046ec8, 0x27ae020, 0xc013477cd8, 0x196, 0x3f948c0, 0xc00b2270b0)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:255 +0x38a
text/template.(*state).walk(0xc00b046ec8, 0x27ae020, 0xc013477cd8, 0x196, 0x3f94b90, 0xc00b226270)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:264 +0x13c
text/template.(*state).walkIfOrWith(0xc00b046ec8, 0xa, 0x27ae020, 0xc013477cd8, 0x196, 0xc00b1ff8c0, 0xc00b5b49f0, 0xc00b226270)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:297 +0x265
text/template.(*state).walk(0xc00b046ec8, 0x27ae020, 0xc013477cd8, 0x196, 0x3f94b48, 0xc00981e880)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:261 +0x285
text/template.(*state).walk(0xc00b046ec8, 0x27ae020, 0xc013477cd8, 0x196, 0x3f94b90, 0xc00b45c7b0)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:264 +0x13c
text/template.(*state).walkIfOrWith(0xc00b046ec8, 0xa, 0x27ae020, 0xc013477cd8, 0x196, 0xc00b1fe9c0, 0xc00b45c7b0, 0x0)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:294 +0x206
text/template.(*state).walk(0xc00b046ec8, 0x27ae020, 0xc013477cd8, 0x196, 0x3f94b48, 0xc00981eb00)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:261 +0x285
text/template.(*state).walk(0xc00b046ec8, 0x27ae020, 0xc013477cd8, 0x196, 0x3f94b90, 0xc00b45c5d0)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:264 +0x13c
text/template.(*state).walkRange.func1(0x25a3b40, 0xc00c76f3b8, 0x82, 0x27ae020, 0xc013477cd8, 0x196)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:351 +0x125
text/template.(*state).walkRange(0xc00b046ec8, 0x26a21e0, 0xc013313400, 0x196, 0xc00981eb80)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:360 +0x2f8
text/template.(*state).walk(0xc00b046ec8, 0x26a21e0, 0xc013313400, 0x196, 0x3f94cb0, 0xc00981eb80)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:267 +0x445
text/template.(*state).walk(0xc00b046ec8, 0x26a21e0, 0xc013313400, 0x196, 0x3f94b90, 0xc00b45c480)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:264 +0x13c
text/template.(*state).walkRange.func1(0x25a3b40, 0x54e4740, 0x82, 0x26a21e0, 0xc013313400, 0x196)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:351 +0x125
text/template.(*state).walkRange(0xc00b046ec8, 0x267f400, 0xc017687098, 0x95, 0xc00981ec00)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:360 +0x2f8
text/template.(*state).walk(0xc00b046ec8, 0x267f400, 0xc017687098, 0x95, 0x3f94cb0, 0xc00981ec00)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:267 +0x445
text/template.(*state).walk(0xc00b046ec8, 0x267f400, 0xc017687098, 0x95, 0x3f94b90, 0xc00b45c270)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:264 +0x13c
text/template.(*state).walkTemplate(0xc00b047a50, 0x26a2160, 0xc0138f9d80, 0x196, 0xc00515cc40)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:418 +0x225
text/template.(*state).walk(0xc00b047a50, 0x26a2160, 0xc0138f9d80, 0x196, 0x3f94d40, 0xc00515cc40)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:269 +0x205
text/template.(*state).walk(0xc00b047a50, 0x26a2160, 0xc0138f9d80, 0x196, 0x3f94b90, 0xc01e97e450)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:264 +0x13c
text/template.(*state).walkIfOrWith(0xc00b047a50, 0xa, 0x26a2160, 0xc0138f9d80, 0x196, 0xc00a10f020, 0xc01e97e330, 0xc01e97e450)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:297 +0x265
text/template.(*state).walk(0xc00b047a50, 0x26a2160, 0xc0138f9d80, 0x196, 0x3f94b48, 0xc00515cd40)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:261 +0x285
text/template.(*state).walk(0xc00b047a50, 0x26a2160, 0xc0138f9d80, 0x196, 0x3f94b90, 0xc01e97e240)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:264 +0x13c
text/template.(*state).walkIfOrWith(0xc00b047a50, 0xa, 0x26a2160, 0xc0138f9d80, 0x196, 0xc00a10ef60, 0xc01e97e0c0, 0xc01e97e240)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:297 +0x265
text/template.(*state).walk(0xc00b047a50, 0x26a2160, 0xc0138f9d80, 0x196, 0x3f94b48, 0xc00515ce40)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:261 +0x285
text/template.(*state).walk(0xc00b047a50, 0x26a2160, 0xc0138f9d80, 0x196, 0x3f94b90, 0xc00d9a32f0)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:264 +0x13c
text/template.(*state).walkIfOrWith(0xc00b047a50, 0xa, 0x26a2160, 0xc0138f9d80, 0x196, 0xc009e47980, 0xc006632e40, 0xc00d9a32f0)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:297 +0x265
text/template.(*state).walk(0xc00b047a50, 0x26a2160, 0xc0138f9d80, 0x196, 0x3f94b48, 0xc004fafc80)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:261 +0x285
text/template.(*state).walk(0xc00b047a50, 0x26a2160, 0xc0138f9d80, 0x196, 0x3f94b90, 0xc006632d50)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:264 +0x13c
text/template.(*state).walkRange.func1(0x25a3b40, 0x54e48c0, 0x82, 0x26a2160, 0xc0138f9d80, 0x196)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:351 +0x125
text/template.(*state).walkRange(0xc00b047a50, 0x267f400, 0xc00e1d6e70, 0x15, 0xc004fafd00)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:360 +0x2f8
text/template.(*state).walk(0xc00b047a50, 0x267f400, 0xc00e1d6e70, 0x15, 0x3f94cb0, 0xc004fafd00)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:267 +0x445
text/template.(*state).walk(0xc00b047a50, 0x267f400, 0xc00e1d6e70, 0x15, 0x3f94b90, 0xc009373dd0)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:264 +0x13c
text/template.(*state).walkIfOrWith(0xc00b047a50, 0xa, 0x267f400, 0xc00e1d6e70, 0x15, 0xc009e47080, 0xc009373860, 0xc009373dd0)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:297 +0x265
text/template.(*state).walk(0xc00b047a50, 0x267f400, 0xc00e1d6e70, 0x15, 0x3f94b48, 0xc006bc6440)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:261 +0x285
text/template.(*state).walk(0xc00b047a50, 0x267f400, 0xc00e1d6e70, 0x15, 0x3f94b90, 0xc0093737d0)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:264 +0x13c
text/template.(*state).walkTemplate(0xc00b048168, 0x267f400, 0xc00e1d6e70, 0x15, 0xc00caed680)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:418 +0x225
text/template.(*state).walk(0xc00b048168, 0x267f400, 0xc00e1d6e70, 0x15, 0x3f94d40, 0xc00caed680)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:269 +0x205
text/template.(*state).walk(0xc00b048168, 0x267f400, 0xc00e1d6e70, 0x15, 0x3f94b90, 0xc00c0465a0)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:264 +0x13c
text/template.(*state).walkIfOrWith(0xc00b048168, 0xa, 0x267f400, 0xc00e1d6e70, 0x15, 0xc00c0390e0, 0xc00c0462d0, 0xc00c0465a0)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:297 +0x265
text/template.(*state).walk(0xc00b048168, 0x267f400, 0xc00e1d6e70, 0x15, 0x3f94b48, 0xc00caed6c0)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:261 +0x285
text/template.(*state).walk(0xc00b048168, 0x267f400, 0xc00e1d6e70, 0x15, 0x3f94b90, 0xc00c046210)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:264 +0x13c
text/template.(*state).walkIfOrWith(0xc00b048168, 0xa, 0x267f400, 0xc00e1d6e70, 0x15, 0xc00c038fc0, 0xc00c046210, 0xc00c101c80)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:294 +0x206
text/template.(*state).walk(0xc00b048168, 0x267f400, 0xc00e1d6e70, 0x15, 0x3f94b48, 0xc00caed8c0)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:261 +0x285
text/template.(*state).walk(0xc00b048168, 0x267f400, 0xc00e1d6e70, 0x15, 0x3f94b90, 0xc00c0460c0)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:264 +0x13c
text/template.(*state).walkIfOrWith(0xc00b048168, 0xa, 0x267f400, 0xc00e1d6e70, 0x15, 0xc00c088a20, 0xc00c08ab40, 0xc00c0460c0)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:297 +0x265
text/template.(*state).walk(0xc00b048168, 0x267f400, 0xc00e1d6e70, 0x15, 0x3f94b48, 0xc00caed900)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:261 +0x285
text/template.(*state).walk(0xc00b048168, 0x267f400, 0xc00e1d6e70, 0x15, 0x3f94b90, 0xc00c020f30)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:264 +0x13c
text/template.(*Template).execute(0xc00c9c67c0, 0x3f52860, 0xc00f0e22a0, 0x267f400, 0xc00e1d6e70, 0x0, 0x0)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:220 +0x1c6
text/template.(*Template).Execute(...)
	/home/mural/src/golang.org/go1.16.3/src/text/template/exec.go:203
html/template.(*Template).ExecuteTemplate(0xc0067ce450, 0x3f52860, 0xc00f0e22a0, 0x2b227cb, 0x11, 0x267f400, 0xc00e1d6e70, 0x18, 0xc00bbd8bd0)
	/home/mural/src/golang.org/go1.16.3/src/html/template/template.go:139 +0xab
github.com/unrolled/render.HTML.Render(0xc00bbd8bd0, 0x18, 0xc8, 0x2b227cb, 0x11, 0xc0067ce450, 0x3f70af8, 0xc005d11ce0, 0x7fa1b77475f0, 0xc00e17ba80, ...)
	/home/mural/src/code.gitea.io/gitea/vendor/github.com/unrolled/render/engine.go:94 +0xb1
github.com/unrolled/render.(*Render).Render(0xc004722f00, 0x7fa1b77475f0, 0xc00e17ba80, 0x3f59340, 0xc00ce2d940, 0x267f400, 0xc00e1d6e70, 0x0, 0x0)
	/home/mural/src/code.gitea.io/gitea/vendor/github.com/unrolled/render/render.go:377 +0x6c
github.com/unrolled/render.(*Render).HTML(0xc004722f00, 0x7fa1b77475f0, 0xc00e17ba80, 0xc8, 0x2b227cb, 0x11, 0x267f400, 0xc00e1d6e70, 0x0, 0x0, ...)
	/home/mural/src/code.gitea.io/gitea/vendor/github.com/unrolled/render/render.go:433 +0x325
code.gitea.io/gitea/modules/context.(*Context).HTML(0xc01fa77200, 0xc8, 0x2b227cb, 0x11)
	/home/mural/src/code.gitea.io/gitea/modules/context/context.go:189 +0x270
code.gitea.io/gitea/routers/repo.CompareDiff(0xc01fa77200)
	/home/mural/src/code.gitea.io/gitea/routers/repo/compare.go:677 +0xd70
code.gitea.io/gitea/modules/web.Wrap.func1(0x3f78d28, 0xc00e17ba80, 0xc00e1d4700)
	/home/mural/src/code.gitea.io/gitea/modules/web/route.go:64 +0x1dc
net/http.HandlerFunc.ServeHTTP(0xc007858e80, 0x3f78d28, 0xc00e17ba80, 0xc00e1d4700)
	/home/mural/src/golang.org/go1.16.3/src/net/http/server.go:2069 +0x44
github.com/go-chi/chi.(*Mux).routeHTTP(0xc007844d80, 0x3f78d28, 0xc00e17ba80, 0xc00e1d4700)
	/home/mural/src/code.gitea.io/gitea/vendor/github.com/go-chi/chi/mux.go:436 +0x28b
net/http.HandlerFunc.ServeHTTP(0xc00755df00, 0x3f78d28, 0xc00e17ba80, 0xc00e1d4700)
	/home/mural/src/golang.org/go1.16.3/src/net/http/server.go:2069 +0x44
code.gitea.io/gitea/modules/web.Middle.func1.1(0x3f78d28, 0xc00e17ba80, 0xc00e1d4700)
	/home/mural/src/code.gitea.io/gitea/modules/web/route.go:103 +0x137
net/http.HandlerFunc.ServeHTTP(0xc0078427c0, 0x3f78d28, 0xc00e17ba80, 0xc00e1d4700)
	/home/mural/src/golang.org/go1.16.3/src/net/http/server.go:2069 +0x44
code.gitea.io/gitea/modules/web.Middle.func1.1(0x3f78d28, 0xc00e17ba80, 0xc00e1d4700)
	/home/mural/src/code.gitea.io/gitea/modules/web/route.go:103 +0x137
net/http.HandlerFunc.ServeHTTP(0xc0078427e0, 0x3f78d28, 0xc00e17ba80, 0xc00e1d4700)
	/home/mural/src/golang.org/go1.16.3/src/net/http/server.go:2069 +0x44
code.gitea.io/gitea/modules/web.Middle.func1.1(0x3f78d28, 0xc00e17ba80, 0xc00e1d4700)
	/home/mural/src/code.gitea.io/gitea/modules/web/route.go:103 +0x137
net/http.HandlerFunc.ServeHTTP(0xc007842800, 0x3f78d28, 0xc00e17ba80, 0xc00e1d4700)
	/home/mural/src/golang.org/go1.16.3/src/net/http/server.go:2069 +0x44
github.com/go-chi/chi/middleware.GetHead.func1(0x3f78d28, 0xc00e17ba80, 0xc00e1d4700)
	/home/mural/src/code.gitea.io/gitea/vendor/github.com/go-chi/chi/middleware/get_head.go:37 +0x182
net/http.HandlerFunc.ServeHTTP(0xc003c41248, 0x3f78d28, 0xc00e17ba80, 0xc00e1d4700)
	/home/mural/src/golang.org/go1.16.3/src/net/http/server.go:2069 +0x44
code.gitea.io/gitea/modules/context.Contexter.func1.1(0x3f78d28, 0xc00e17ba80, 0xc00e1d4600)
	/home/mural/src/code.gitea.io/gitea/modules/context/context.go:751 +0x1dca
net/http.HandlerFunc.ServeHTTP(0xc0078474a0, 0x3f78d28, 0xc00e17ba80, 0xc00e1d4600)
	/home/mural/src/golang.org/go1.16.3/src/net/http/server.go:2069 +0x44
github.com/go-chi/chi.(*Mux).ServeHTTP(0xc007844d80, 0x3f78d28, 0xc00e17ba80, 0xc00e1d4600)
	/home/mural/src/code.gitea.io/gitea/vendor/github.com/go-chi/chi/mux.go:70 +0x5ab
github.com/go-chi/chi.(*Mux).Mount.func1(0x3f78d28, 0xc00e17ba80, 0xc00e1d4600)
	/home/mural/src/code.gitea.io/gitea/vendor/github.com/go-chi/chi/mux.go:311 +0x17c
net/http.HandlerFunc.ServeHTTP(0xc0078dfd40, 0x3f78d28, 0xc00e17ba80, 0xc00e1d4600)
	/home/mural/src/golang.org/go1.16.3/src/net/http/server.go:2069 +0x44
github.com/go-chi/chi.(*Mux).routeHTTP(0xc004728f00, 0x3f78d28, 0xc00e17ba80, 0xc00e1d4600)
	/home/mural/src/code.gitea.io/gitea/vendor/github.com/go-chi/chi/mux.go:436 +0x28b
net/http.HandlerFunc.ServeHTTP(0xc005c8db90, 0x3f78d28, 0xc00e17ba80, 0xc00e1d4600)
	/home/mural/src/golang.org/go1.16.3/src/net/http/server.go:2069 +0x44
code.gitea.io/gitea/routers/routes.Recovery.func1.1(0x3f78d28, 0xc00e17ba80, 0xc00e1d4600)
	/home/mural/src/code.gitea.io/gitea/routers/routes/base.go:211 +0x91
net/http.HandlerFunc.ServeHTTP(0xc005ca92c0, 0x3f78d28, 0xc00e17ba80, 0xc00e1d4600)
	/home/mural/src/golang.org/go1.16.3/src/net/http/server.go:2069 +0x44
gitea.com/go-chi/session.Sessioner.func1.1(0x3f78d28, 0xc00e17ba80, 0xc00e1d4500)
	/home/mural/src/code.gitea.io/gitea/vendor/gitea.com/go-chi/session/session.go:256 +0x24f
net/http.HandlerFunc.ServeHTTP(0xc005ca92e0, 0x3f78d28, 0xc00e17ba80, 0xc00e1d4500)
	/home/mural/src/golang.org/go1.16.3/src/net/http/server.go:2069 +0x44
code.gitea.io/gitea/modules/public.AssetsHandler.func1.1(0x3f78d28, 0xc00e17ba80, 0xc00e1d4500)
	/home/mural/src/code.gitea.io/gitea/modules/public/public.go:42 +0x8f
net/http.HandlerFunc.ServeHTTP(0xc005cd0ab0, 0x3f78d28, 0xc00e17ba80, 0xc00e1d4500)
	/home/mural/src/golang.org/go1.16.3/src/net/http/server.go:2069 +0x44
github.com/go-chi/chi.(*Mux).ServeHTTP(0xc004728f00, 0x3f78d28, 0xc00e17ba80, 0xc00e1d4500)
	/home/mural/src/code.gitea.io/gitea/vendor/github.com/go-chi/chi/mux.go:70 +0x5ab
github.com/go-chi/chi.(*Mux).Mount.func1(0x3f78d28, 0xc00e17ba80, 0xc00e1d4500)
	/home/mural/src/code.gitea.io/gitea/vendor/github.com/go-chi/chi/mux.go:311 +0x17c
net/http.HandlerFunc.ServeHTTP(0xc0078dfd60, 0x3f78d28, 0xc00e17ba80, 0xc00e1d4500)
	/home/mural/src/golang.org/go1.16.3/src/net/http/server.go:2069 +0x44
created by net/http.(*Server).Serve
	/home/mural/src/golang.org/go1.16.3/src/net/http/server.go:3013 +0x39b

圖片

@typeless
Copy link
Contributor

Looking at https://github.com/alecthomas/chroma/blob/7e282be4957c2cb4edeb4562f56d707427393192/lexers/internal/api.go#L91-L98, I am afraid it's noticeably expensive to search for a lexer for every line of code.

See also

return template.HTML(highlight.Code(diffSection.FileName, diffLine.Content[1:]))

@typeless
Copy link
Contributor

Infinite scrolling pagination (https://www.digitalocean.com/community/tutorials/vuejs-implementing-infinite-scroll) might be a relatively simple way to address this if it doesn't require redesigning the UI.

@zeripath
Copy link
Contributor

Looking at https://github.com/alecthomas/chroma/blob/7e282be4957c2cb4edeb4562f56d707427393192/lexers/internal/api.go#L91-L98, I am afraid it's noticeably expensive to search for a lexer for every line of code.

I guess that shows where we can seriously improve then...

The lexer detection should be run on the old file and run on the new file once and then reused.

@typeless
Copy link
Contributor

@zeripath
#16180 helps to some extent, yet it's still suboptimal.
For the record, I have a PR that translates into 40MB of HTML and takes 10mins to generate (73 added files, btw). It seems to be stuck in html/template forever. Given the scenario, I think AJAX would probably make more difference in fixing this problem.

@zeripath
Copy link
Contributor

Yeah

@zeripath
Copy link
Contributor

Agh I just read that pr. We need to change it. I don't think we can use arccache - it should be twoqueue I think

@typeless
Copy link
Contributor

typeless commented Jun 24, 2021

Agh I just read that pr. We need to change it. I don't think we can use arccache - it should be twoqueue I think

Can you elaborate on their differences in this use case?

@zeripath
Copy link
Contributor

the issue is ARCCache is patent encumbered and known to be patent encumbered. We can't/shouldn't use that until the ARCCache patents expire - which it's potentially not until 2024 although someone says it's 2022.

@zeripath
Copy link
Contributor

We should use a TwoQueue as the documentation for that library suggests which is equivalent but without the patent problem.

@typeless
Copy link
Contributor

@zeripath I see. I'll submit a pr later.

@leeN
Copy link

leeN commented Nov 15, 2021

This (sadly) makes Gitea more or less unusable for managing forks of large projects. We have forked a large open source project with a very active upstream so merging in new versions will easily pull in 15k+ new commits and 50k changed files.

Even trying to create a pull request via the web view hangs forever, commenting on it is pretty much impossible too :/

Gitea Version: 1.15.6
OS: Linux
Storage: SSDs (Raid1)
DB: Postgres

@lunny
Copy link
Member

lunny commented Nov 15, 2021

This (sadly) makes Gitea more or less unusable for managing forks of large projects. We have forked a large open source project with a very active upstream so merging in new versions will easily pull in 15k+ new commits and 50k changed files.

Even trying to create a pull request via the web view hangs forever, commenting on it is pretty much impossible too :/

Gitea Version: 1.15.6 OS: Linux Storage: SSDs (Raid1) DB: Postgres

I'm interested in what's the open source project.

@leeN
Copy link

leeN commented Nov 15, 2021

I'm interested in what's the open source project.

Firefox, I merged in all changes between version 80 and 84 into our fork and the pull request page loads forever.

@leeN
Copy link

leeN commented Nov 16, 2021

As a point of reference, I opened it on the Github Upstream repo. This took like 1s to load compared with the infinite loading time with Gitea.

@lunny
Copy link
Member

lunny commented Nov 16, 2021

Yeah, because github will hide the changes. If you cannot view the changes, the PR cannot be reviewed manually.

@leeN
Copy link

leeN commented Nov 16, 2021

Yeah, because github will hide the changes. If you cannot view the changes, the PR cannot be reviewed manually.

I completely agree that it is impossible to review change sets that large in the web UI. If the UI doesn't render at all however, commenting on the pull request becomes impossible too as the comment box is rendered after all commits have loaded. This makes giving feedback based on checking out the PR locally via Gitea kinda impossible :)

I'm well aware that this is an edge case, but the option to hide the commits/changes similar to Github, if the change set is too large, would be a super helpful addition to Gitea :)

@lunny
Copy link
Member

lunny commented Nov 17, 2021

OKay. So we can add an option to hide the file changes in the web UI but allow to create the PR successfully.

@leeN
Copy link

leeN commented Nov 17, 2021

That would be fantastic! :)

@NicolasPA
Copy link

Similarly to the idea of having a tree of files that can be clicked to show the diff for one file, it would also be very useful to be able to select only one or more commits of the PR, which would also reduce the amount of diff displayed. This is the "Changes from" menu in Github:
image

@zeripath
Copy link
Contributor

AHA!

I bet you have some broken git repositories! I've just discovered that git cat-file --batch and git cat-file --batch-check will both hang until stdin is closed if the underlying "repository" is not a git repository. This is an infuriatingly bad behaviour which means we'll need to run git rev-parse on repository "open" to prevent the problem.

zeripath added a commit that referenced this issue Dec 16, 2021
…and other fixes (#17991)

This PR contains multiple fixes. The most important of which is:

* Prevent hang in git cat-file if the repository is not a valid repository 
    
    Unfortunately it appears that if git cat-file is run in an invalid
    repository it will hang until stdin is closed. This will result in
    deadlocked /pulls pages and dangling git cat-file calls if a broken
    repository is tried to be reviewed or pulls exists for a broken
    repository.

    Fix #14734
    Fix #9271
    Fix #16113

Otherwise there are a few small other fixes included which this PR was initially intending to fix:

* Fix panic on partial compares due to missing PullRequestWorkInProgressPrefixes
* Fix links on pulls pages  due to regression from #17551 - by making most /issues routes match /pulls too - Fix #17983
* Fix links on feeds pages due to another regression from #17551 but also fix issue with syncing tags - Fix #17943
* Add missing locale entries for oauth group claims
* Prevent NPEs if ColorFormat is called on nil users, repos or teams.
@lunny lunny reopened this Dec 17, 2021
Chianina pushed a commit to Chianina/gitea that referenced this issue Mar 28, 2022
…and other fixes (go-gitea#17991)

This PR contains multiple fixes. The most important of which is:

* Prevent hang in git cat-file if the repository is not a valid repository 
    
    Unfortunately it appears that if git cat-file is run in an invalid
    repository it will hang until stdin is closed. This will result in
    deadlocked /pulls pages and dangling git cat-file calls if a broken
    repository is tried to be reviewed or pulls exists for a broken
    repository.

    Fix go-gitea#14734
    Fix go-gitea#9271
    Fix go-gitea#16113

Otherwise there are a few small other fixes included which this PR was initially intending to fix:

* Fix panic on partial compares due to missing PullRequestWorkInProgressPrefixes
* Fix links on pulls pages  due to regression from go-gitea#17551 - by making most /issues routes match /pulls too - Fix go-gitea#17983
* Fix links on feeds pages due to another regression from go-gitea#17551 but also fix issue with syncing tags - Fix go-gitea#17943
* Add missing locale entries for oauth group claims
* Prevent NPEs if ColorFormat is called on nil users, repos or teams.
@gempir
Copy link
Contributor

gempir commented Feb 22, 2023

FYI for readers: These settings have the most impact on the performance of the files changed page.

DISABLE_DIFF_HIGHLIGHT
MAX_GIT_DIFF_LINES
MAX_GIT_DIFF_LINE_CHARACTERS
MAX_GIT_DIFF_FILES

play around with them and figure out what works for you. I still think Bitbucket Server always had a really great concept for loading diffs, since it only ever had a single file open and you could just click in the file picker to the next one.

Rarely did I want to scroll through multiple files, since when are files vertically aligned to each other, they are always in a file system not a vertical line.

Is there lexer problem still relevant? Does it still look into the lexer for each line? I might want to have a look into that if so.

@gempir
Copy link
Contributor

gempir commented Feb 22, 2023

An alternative Idea could be building a Diff Viewer completely separate from the current one and implementing it purely in vuejs.

Syntax Highlighting has to be figured out then, but I think overall it could lead to a more customizable experience than the current server-client hybrid.

Although I really wish gitea could support vuejs SSR somehow, I'm not familiar enough with vuejs to judge if that's easy enough to implement.

@thigg
Copy link
Contributor

thigg commented Apr 18, 2023

That would be a great hotfix to allow to show only one file at a time. I imagine it would be easy to implement and a very stable fallback mechanism until infinite scrolling etc stabilized. (reviewing large PRs got better recently but it is still very annoying)

Can someone outline what would have to be done for that?

@lunny
Copy link
Member

lunny commented Apr 18, 2023

I think #16829 has resolve this problem. You can set

[git]
MAX_GIT_DIFF_FILES = 

to limit the files loaded every time. And click Load More button on the bottom to load another page.

@lunny
Copy link
Member

lunny commented Jul 3, 2023

Closed since loading files could be configured and there is a Load More button.

@lunny lunny closed this as completed Jul 3, 2023
@thigg
Copy link
Contributor

thigg commented Jul 3, 2023

I tried this with the current deployment on try: https://try.gitea.io/thigg/podqast/pulls/1/files
with 85k additions and 12k deletions and even though the site is loading in a matter of 10s of seconds I can not really type comments in there as there is a several seconds lag between typing and seeing the letter on the screen.

@lunny should this be a separate/new issue?

I agree that you should not have PRs this big... but if you get into the situation for some reason, it would be nice if at least gitea would not get in your way too.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 18, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
performance/speed performance issues with slow downs
Projects
None yet
Development

Successfully merging a pull request may close this issue.