Preload policy data for batch permission checks
What does this MR do and why?
Checking whether a user can read a list of issues gets slower with every issue in the list. Each check loads that issue's project, group, membership and work item type on its own, so 96 issues cost over 400 database queries. This affects Markdown references, linked items, epic issues and the issues API.
This MR lets a policy load what its checks need for the whole list in one go, and uses that for issues. The results don't change, only how the data is loaded. A single issue skips the extra loading, since it has nothing to share.
Local measurements, 96 issues across 12 projects in 4 groups:
| Queries | Time | |
|---|---|---|
| Before | 423 | 1,148 ms |
| After | 44 | 180 ms |
Small lists of 2–4 issues from one project run a few more queries than before (27 instead of 23). From about 3 projects or 9 issues the new path is faster.
The new loading is behind the batch_permission_check_preloads flag, so it can be turned off quickly if a permission check goes wrong. Its cost is counted in the existing authz_* log fields, so the rollout can compare them with the flag on and off.
Other *_readable_by_user methods, such as merge requests and pipelines, can move to the same approach in follow-ups.
References
- Rollout issue: https://gitlab.com/gitlab-org/gitlab/-/work_items/635008
- Stacked follow-up that removes more queries per project: !263780 (merged)
Screenshots or screen recordings
Not applicable: no UI changes.
How to set up and validate locally
Nothing to check by hand. The results are the same as before, and the specs compare them with checking each issue on its own and limit the query count.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.