@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
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

When computing revision ownership, cache some intermediate results for performance

Summary:
Ref T12319. With large datasets, the computation of which packages own paths in a revision is needlessly slow.

Improve performance through caching:

- Cache which paths belong to each repository.
- Cache the split fragments of each path.
- Cache the path fragment counts.
- Micro-optimize accessing `$this->path`.

Test Plan:
- Used `bin/lipsum` to generate 4,000 packages with 150,000 paths.
- Created a revision affecting 100 paths in `phabricator/` (these paths mostly overlap with `bin/lipsum` path rules, since Lipsum uses Phabricator-like rules to generate paths).
- Before optimizations, this revision spent about 5.5 seconds computing paths.
- After optimizations, it spends about 275ms.

{F3423414}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T12319

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

+41 -13
+8 -7
src/applications/owners/query/PhabricatorOwnersPackageQuery.php
··· 353 353 $packages = $this->controlResults; 354 354 $weak_dominion = PhabricatorOwnersPackage::DOMINION_WEAK; 355 355 356 + $path_fragments = PhabricatorOwnersPackage::splitPath($path); 357 + $fragment_count = count($path_fragments); 358 + 356 359 $matches = array(); 357 360 foreach ($packages as $package_id => $package) { 358 361 $best_match = null; ··· 365 368 continue; 366 369 } 367 370 368 - foreach ($package->getPaths() as $package_path) { 369 - if ($package_path->getRepositoryPHID() != $repository_phid) { 370 - // If this path is for some other repository, skip it. 371 - continue; 372 - } 373 - 374 - $strength = $package_path->getPathMatchStrength($path); 371 + $repository_paths = $package->getPathsForRepository($repository_phid); 372 + foreach ($repository_paths as $package_path) { 373 + $strength = $package_path->getPathMatchStrength( 374 + $path_fragments, 375 + $fragment_count); 375 376 if ($strength > $best_match) { 376 377 $best_match = $strength; 377 378 $include = !$package_path->getExcluded();
+22
src/applications/owners/storage/PhabricatorOwnersPackage.php
··· 26 26 private $paths = self::ATTACHABLE; 27 27 private $owners = self::ATTACHABLE; 28 28 private $customFields = self::ATTACHABLE; 29 + private $pathRepositoryMap = array(); 29 30 30 31 const STATUS_ACTIVE = 'active'; 31 32 const STATUS_ARCHIVED = 'archived'; ··· 369 370 public function attachPaths(array $paths) { 370 371 assert_instances_of($paths, 'PhabricatorOwnersPath'); 371 372 $this->paths = $paths; 373 + 374 + // Drop this cache if we're attaching new paths. 375 + $this->pathRepositoryMap = array(); 376 + 372 377 return $this; 373 378 } 374 379 375 380 public function getPaths() { 376 381 return $this->assertAttached($this->paths); 382 + } 383 + 384 + public function getPathsForRepository($repository_phid) { 385 + if (isset($this->pathRepositoryMap[$repository_phid])) { 386 + return $this->pathRepositoryMap[$repository_phid]; 387 + } 388 + 389 + $map = array(); 390 + foreach ($this->getPaths() as $path) { 391 + if ($path->getRepositoryPHID() == $repository_phid) { 392 + $map[] = $path; 393 + } 394 + } 395 + 396 + $this->pathRepositoryMap[$repository_phid] = $map; 397 + 398 + return $this->pathRepositoryMap[$repository_phid]; 377 399 } 378 400 379 401 public function attachOwners(array $owners) {
+11 -6
src/applications/owners/storage/PhabricatorOwnersPath.php
··· 7 7 protected $path; 8 8 protected $excluded; 9 9 10 + private $fragments; 11 + private $fragmentCount; 12 + 10 13 protected function getConfiguration() { 11 14 return array( 12 15 self::CONFIG_TIMESTAMPS => false, ··· 74 77 * Get the number of directory matches between this path specification and 75 78 * some real path. 76 79 */ 77 - public function getPathMatchStrength($path) { 78 - $this_path = $this->getPath(); 80 + public function getPathMatchStrength($path_fragments, $path_count) { 81 + $this_path = $this->path; 79 82 80 83 if ($this_path === '/') { 81 84 // The root path "/" just matches everything with strength 1. 82 85 return 1; 83 86 } 84 87 85 - $self_fragments = PhabricatorOwnersPackage::splitPath($this_path); 86 - $path_fragments = PhabricatorOwnersPackage::splitPath($path); 88 + if ($this->fragments === null) { 89 + $this->fragments = PhabricatorOwnersPackage::splitPath($this_path); 90 + $this->fragmentCount = count($this->fragments); 91 + } 87 92 88 - $self_count = count($self_fragments); 89 - $path_count = count($path_fragments); 93 + $self_fragments = $this->fragments; 94 + $self_count = $this->fragmentCount; 90 95 if ($self_count > $path_count) { 91 96 // If this path is longer (and therefore more specific) than the target 92 97 // path, we don't match it at all.