@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator

When building audit queries, prefilter possible "authorPHID" values

Summary:
Ref T13244. See PHI1057. Currently, if you're a member of a lot of projects/packages, you can end up with a very large `commit.authorPHID IN (...)` clause in part of the "Active Audits" query, since your `alice` token in "Responsible Users: alice" expands into every package and project you can audit on behalf of.

It's impossible for a commit to be authored by anything but a user, and evidence in PHI1057 suggests this giant `IN (...)` list can prevent MySQL from making effective utilization of the `<authorPHID, auditStatus, ...>` key on the table.

Prefilter the list of PHIDs to only PHIDs which can possibly author a commit.

(We'll also eventually need to convert the `authorPHIDs` into `identityPHIDs` anyway, for T12164, and this moves us slightly toward that.)

Test Plan: Loaded "Active Audits" before and after change, saw a more streamlined and sensible `authorPHID IN (...)` clause afterwards.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13244

Differential Revision: https://secure.phabricator.com/D20129

+44 -7
+44 -7
src/applications/diffusion/query/DiffusionCommitQuery.php
··· 202 202 $table = $this->newResultObject(); 203 203 $conn = $table->establishConnection('r'); 204 204 205 + $empty_exception = null; 205 206 $subqueries = array(); 206 207 if ($this->responsiblePHIDs) { 207 208 $base_authors = $this->authorPHIDs; ··· 222 223 223 224 $this->authorPHIDs = $all_authors; 224 225 $this->auditorPHIDs = $base_auditors; 225 - $subqueries[] = $this->buildStandardPageQuery( 226 - $conn, 227 - $table->getTableName()); 226 + try { 227 + $subqueries[] = $this->buildStandardPageQuery( 228 + $conn, 229 + $table->getTableName()); 230 + } catch (PhabricatorEmptyQueryException $ex) { 231 + $empty_exception = $ex; 232 + } 228 233 229 234 $this->authorPHIDs = $base_authors; 230 235 $this->auditorPHIDs = $all_auditors; 231 - $subqueries[] = $this->buildStandardPageQuery( 232 - $conn, 233 - $table->getTableName()); 236 + try { 237 + $subqueries[] = $this->buildStandardPageQuery( 238 + $conn, 239 + $table->getTableName()); 240 + } catch (PhabricatorEmptyQueryException $ex) { 241 + $empty_exception = $ex; 242 + } 234 243 } else { 235 244 $subqueries[] = $this->buildStandardPageQuery( 236 245 $conn, 237 246 $table->getTableName()); 247 + } 248 + 249 + if (!$subqueries) { 250 + throw $empty_exception; 238 251 } 239 252 240 253 if (count($subqueries) > 1) { ··· 642 655 } 643 656 644 657 if ($this->authorPHIDs !== null) { 658 + $author_phids = $this->authorPHIDs; 659 + if ($author_phids) { 660 + $author_phids = $this->selectPossibleAuthors($author_phids); 661 + if (!$author_phids) { 662 + throw new PhabricatorEmptyQueryException( 663 + pht('Author PHIDs contain no possible authors.')); 664 + } 665 + } 666 + 645 667 $where[] = qsprintf( 646 668 $conn, 647 669 'commit.authorPHID IN (%Ls)', 648 - $this->authorPHIDs); 670 + $author_phids); 649 671 } 650 672 651 673 if ($this->epochMin !== null) { ··· 932 954 'name' => pht('Commit Date (Oldest First)'), 933 955 ), 934 956 ) + $parent; 957 + } 958 + 959 + private function selectPossibleAuthors(array $phids) { 960 + // See PHI1057. Select PHIDs which might possibly be commit authors from 961 + // a larger list of PHIDs. This primarily filters out packages and projects 962 + // from "Responsible Users: ..." queries. Our goal in performing this 963 + // filtering is to improve the performance of the final query. 964 + 965 + foreach ($phids as $key => $phid) { 966 + if (phid_get_type($phid) !== PhabricatorPeopleUserPHIDType::TYPECONST) { 967 + unset($phids[$key]); 968 + } 969 + } 970 + 971 + return $phids; 935 972 } 936 973 937 974