Skip to content

Use linear version of User#ci_owned_runners

Francisco Javier López requested to merge 339198-fj-ci-owned-runners into master

What does this MR do?

In this MR, we're switching the behavior of the User#ci_owned_runners method to use the linear version. The new behavior is behind the linear_user_ci_owned_runners feature flag.

How to setup and validate locally (strongly suggested)

  1. Enable the new method behavior feature flag
    Feature.enable(:linear_user_ci_owned_runners)
  2. In rails console enable the traversal id feature flag
    Feature.enable(:use_traversal_ids)

SQL queries

The former sql query was:

SELECT ci_runners.*
FROM (
        (SELECT ci_runners.*
         FROM ci_runner_projects
         INNER JOIN ci_runners ON ci_runners.id = ci_runner_projects.runner_id
         WHERE ci_runner_projects.project_id IN
             (SELECT projects.id
              FROM projects
              INNER JOIN project_authorizations ON projects.id = project_authorizations.project_id
              WHERE project_authorizations.user_id = 1
                AND (project_authorizations.access_level >= 40)))
      UNION
        (SELECT ci_runners.*
         FROM ci_runner_namespaces
         INNER JOIN ci_runners ON ci_runners.id = ci_runner_namespaces.runner_id
         WHERE ci_runner_namespaces.namespace_id IN
             (WITH RECURSIVE base_and_descendants AS (
                                                        (SELECT namespaces.*
                                                         FROM namespaces
                                                         INNER JOIN members ON namespaces.id = members.source_id
                                                         WHERE members.type = 'GroupMember'
                                                           AND members.source_type = 'Namespace'
                                                           AND namespaces.type = 'Group'
                                                           AND members.user_id = 1
                                                           AND members.requested_at IS NULL
                                                           AND (access_level >= 10)
                                                           AND members.access_level = 50)
                                                      UNION
                                                        (SELECT namespaces.*
                                                         FROM namespaces,
                                                              base_and_descendants
                                                         WHERE namespaces.type = 'Group'
                                                           AND namespaces.parent_id = base_and_descendants.id)) SELECT id
              FROM base_and_descendants AS namespaces))) ci_runners

This is the query plan and the execution times are:

Time: 81.078 ms
  - planning: 3.800 ms
  - execution: 77.278 ms
    - I/O read: 0.000 ms
    - I/O write: 0.000 ms

Shared buffers:
  - hits: 54454 (~425.40 MiB) from the buffer pool
  - reads: 0 from the OS file cache, including disk I/O
  - dirtied: 0
  - writes: 0

The new sql query is:

SELECT "ci_runners".*
FROM (
        (SELECT ci_runners.*
         FROM "ci_runner_projects"
         INNER JOIN "ci_runners" ON "ci_runners"."id" = "ci_runner_projects"."runner_id"
         WHERE "ci_runner_projects"."project_id" IN
             (SELECT "projects"."id"
              FROM "projects"
              INNER JOIN "project_authorizations" ON "projects"."id" = "project_authorizations"."project_id"
              WHERE "project_authorizations"."user_id" = 1
                AND (project_authorizations.access_level >= 40)))
      UNION
        (SELECT ci_runners.*
         FROM "ci_runner_namespaces"
         INNER JOIN "ci_runners" ON "ci_runners"."id" = "ci_runner_namespaces"."runner_id"
         WHERE "ci_runner_namespaces"."namespace_id" IN
             (WITH "base_cte" AS MATERIALIZED
                (SELECT "namespaces"."traversal_ids", LEAD (namespaces.traversal_ids, 1) OVER (
                                                                                               ORDER BY namespaces.traversal_ids ASC) next_traversal_ids
                 FROM "namespaces"
                 INNER JOIN "members" ON "namespaces"."id" = "members"."source_id"
                 WHERE "members"."type" = 'GroupMember'
                   AND "members"."source_type" = 'Namespace'
                   AND "namespaces"."type" = 'Group'
                   AND "members"."user_id" = 1
                   AND "members"."requested_at" IS NULL
                   AND (access_level >= 10)
                   AND "members"."access_level" = 50) SELECT namespaces.traversal_ids[array_length(namespaces.traversal_ids, 1)] AS id
              FROM "base_cte",
                   "namespaces"
              WHERE "namespaces"."type" = 'Group'
                AND ("base_cte"."next_traversal_ids" IS NULL
                     OR "base_cte"."next_traversal_ids" > "namespaces"."traversal_ids")
                AND next_traversal_ids_sibling("base_cte"."traversal_ids") > "namespaces"."traversal_ids"
                AND "base_cte"."traversal_ids" <= "namespaces"."traversal_ids"))) ci_runners

This is the query plan for this query and the times are:

Time: 84.774 ms
  - planning: 3.261 ms
  - execution: 81.513 ms
    - I/O read: 0.000 ms
    - I/O write: 0.000 ms

Shared buffers:
  - hits: 51558 (~402.80 MiB) from the buffer pool
  - reads: 0 from the OS file cache, including disk I/O
  - dirtied: 0
  - writes: 0

Does this MR meet the acceptance criteria?

Conformity

Related to #339198 (closed)

Edited by Francisco Javier López

Merge request reports

Loading