Skip epics confidentiality check when param is false
What does this MR do and why?
We can avoid the expensive operation of checking confidentiality access for subgroups if the request only expects public epics (confidential filter is set to false).
Database changes
previous query
SELECT "epics".*
FROM "epics"
WHERE "epics"."group_id" IN
(SELECT "namespaces"."id"
FROM "namespaces"
WHERE "namespaces"."type" = 'Group'
AND (traversal_ids @> ('{22}'))
AND "namespaces"."visibility_level" IN (10, 20))
AND ("epics"."confidential" = FALSE
OR "epics"."confidential" = TRUE
AND "epics"."group_id" IN
(SELECT "namespaces"."id"
FROM "namespaces"
WHERE "namespaces"."type" = 'Group'
AND "namespaces"."id" IN
(SELECT "namespaces"."id"
FROM "namespaces"
WHERE "namespaces"."type" = 'Group'
AND (traversal_ids @> ('{22}')))
AND (id IN (
(SELECT "namespaces"."id"
FROM "namespaces"
WHERE "namespaces"."type" = 'Group'
AND (traversal_ids && ARRAY
(SELECT "members"."source_id"
FROM "members" LEFT OUTER
JOIN "users"
ON "users"."id" = "members"."user_id"
WHERE "members"."type" = 'GroupMember'
AND "members"."source_type" = 'Namespace'
AND "users"."state" = 'active'
AND "members"."state" = 0
AND "members"."requested_at" IS NULL
AND "members"."invite_token" IS NULL
AND (members.access_level > 5)
AND "members"."source_id" IN
(SELECT "namespaces"."id"
FROM "namespaces"
WHERE "namespaces"."type" = 'Group'
AND (traversal_ids @> ('{22}')))
AND (access_level >= 15)
AND "members"."user_id" = 95)))
UNION
::~(SELECT "namespaces"."id"
FROM "namespaces"
WHERE "namespaces"."type" = 'Group'
AND (traversal_ids && ARRAY
(SELECT "group_group_links"."shared_group_id"
FROM "group_group_links"
WHERE "group_group_links"."shared_group_id" IN
(SELECT "namespaces"."id"
FROM "namespaces"
WHERE "namespaces"."type" = 'Group'
AND (traversal_ids @> ('{22}')))
AND (group_access >= 15)
AND "group_group_links"."shared_with_group_id" IN
(SELECT "members"."source_id"
FROM "members"
WHERE "members"."type" = 'GroupMember'
AND "members"."source_type" = 'Namespace'
AND "members"."user_id" = 95
AND "members"."user_id" IS NOT NULL
AND "members"."state" = 0
AND "members"."requested_at" IS NULL
AND (members.access_level > 5)))::bigint[]))))))
AND "epics"."confidential" = FALSE
ORDER BY "epics"."created_at" DESC LIMIT 20 OFFSET 0
new query
SELECT "epics".*
FROM "epics"
WHERE "epics"."group_id" IN
(SELECT "namespaces"."id"
FROM "namespaces"
WHERE "namespaces"."type" = 'Group'
AND (traversal_ids @> ('{22}'))
AND "namespaces"."visibility_level" IN (10, 20))
AND "epics"."confidential" = FALSE
AND "epics"."confidential" = FALSE
ORDER BY "epics"."created_at" DESC LIMIT 20 OFFSET 0
| Query plan before | Query plan after |
|---|---|
| console.postgres.ai (internal) | console.postgres.ai (internal) |
References
Related to #558778 (closed)
Screen recording
epics_finder_with_confidential
How to replicate
- Create a public group and add two epics, one confidential and one non-confidential
- Use rails console to verify that the finder skips the confidentiality check when
confidential: falseand includes it whenconfidentialistrueor not present
Click to expand
> group, non_member = Group.last, User.last
> EpicsFinder.new(non_member, group_id: group.id, confidential: false, include_descendant_groups: true).execute
#=>
SELECT "epics".* FROM "epics" WHERE "epics"."group_id" IN (SELECT "namespaces"."id" FROM "namespaces" WHERE "namespaces"."type" = 'Group' AND (traversal_ids @> ('{24}'))) AND "epics"."confidential" = TRUE ORDER BY "epics"."id" DESC
> EpicsFinder.new(non_member, group_id: group.id, confidential: true, include_descendant_groups: true).execute
#=>
SELECT "epics".* FROM "epics" WHERE "epics"."group_id" IN (SELECT "namespaces"."id" FROM "namespaces" WHERE "namespaces"."type" = 'Group' AND (traversal_ids @> ('{24}')) AND "namespaces"."visibility_level" IN (10, 20)) AND ("epics"."confidential" = FALSE OR "epics"."confidential" = TRUE AND "epics"."group_id" IN (SELECT "namespaces"."id" FROM "namespaces" WHERE "namespaces"."type" = 'Group' AND "namespaces"."id" IN (SELECT "namespaces"."id" FROM "namespaces" WHERE "namespaces"."type" = 'Group' AND (traversal_ids @> ('{24}'))) AND (id IN ((SELECT "namespaces"."id" FROM "namespaces" WHERE "namespaces"."type" = 'Group' AND (traversal_ids && ARRAY(SELECT "members"."source_id" FROM "members" LEFT OUTER JOIN "users" ON "users"."id" = "members"."user_id" WHERE "members"."type" = 'GroupMember' AND "members"."source_type" = 'Namespace' AND "users"."state" = 'active' AND "members"."state" = 0 AND "members"."requested_at" IS NULL AND "members"."invite_token" IS NULL AND (members.access_level > 5) AND "members"."source_id" IN (SELECT "namespaces"."id" FROM "namespaces" WHERE "namespaces"."type" = 'Group' AND (traversal_ids @> ('{24}'))) AND (access_level >= 15) AND "members"."user_id" = 95)))
UNION
(SELECT "namespaces"."id" FROM "namespaces" WHERE "namespaces"."type" = 'Group' AND (traversal_ids && ARRAY(SELECT "group_group_links"."shared_group_id" FROM "group_group_links" WHERE "group_group_links"."shared_group_id" IN (SELECT "namespaces"."id" FROM "namespaces" WHERE "namespaces"."type" = 'Group' AND (traversal_ids @> ('{24}'))) AND (group_access >= 15) AND "group_group_links"."shared_with_group_id" IN (SELECT "members"."source_id" FROM "members" WHERE "members"."type" = 'GroupMember' AND "members"."source_type" = 'Namespace' AND "members"."user_id" = 95 AND "members"."user_id" IS NOT NULL AND "members"."state" = 0 AND "members"."requested_at" IS NULL AND (members.access_level > 5)))::bigint[])))))) AND "epics"."confidential" = TRUE ORDER BY "epics"."created_at" DESC LIMIT 20 OFFSET 0
- Alternately, login with a user that is not a member of the group and make a REST request to fetch all non-confidential epics for the group, for example, visiting the URL
https://{gdk_root}/api/v4/groups/{group_path}/epics?confidential=false - Observe the logs with
tail -f log/development.login thegitlabdirectory and verify the SQL query forSELECT "epics".* FROM "epics"
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.
Edited by Eugenia Grieff