@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.

Improve settings caches on fast paths like Conduit

Summary:
Ref T11954. This reduces how much work we need to do to load settings, particularly for Conduit (which currently can not benefit directly from the user cache, because it loads the user indirectly via a token).

Specifically:

- Cache builtin defaults in the runtime cache. This means Phabricator may need to be restarted if you change a global setting default, but this is exceptionally rare.
- Cache global defaults in the mutable cache. This means we do less work to load them.
- Avoid loading settings classes if we don't have to.
- If we missed the user cache for settings, try to read it from the cache table before we actually go regenerate it (we miss on Conduit pathways).

Test Plan: Used `ab -n100 ...` to observe a ~6-10ms performance improvement for `user.whoami`.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T11954

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

+66 -36
+42 -30
src/applications/people/storage/PhabricatorUser.php
··· 490 490 $settings = $this->loadGlobalSettings(); 491 491 } 492 492 493 - // NOTE: To slightly improve performance, we're using all settings here, 494 - // not just settings that are enabled for the current viewer. It's fine to 495 - // get the value of a setting that we wouldn't let the user edit in the UI. 496 - $defaults = PhabricatorSetting::getAllSettings(); 497 - 498 493 if (array_key_exists($key, $settings)) { 499 494 $value = $settings[$key]; 495 + return $this->writeUserSettingCache($key, $value); 496 + } 500 497 501 - // Make sure the value is valid before we return it. This makes things 502 - // more robust when options are changed or removed. 503 - if (isset($defaults[$key])) { 504 - try { 505 - id(clone $defaults[$key]) 506 - ->setViewer($this) 507 - ->assertValidValue($value); 498 + $cache = PhabricatorCaches::getRuntimeCache(); 499 + $cache_key = "settings.defaults({$key})"; 500 + $cache_map = $cache->getKeys(array($cache_key)); 508 501 509 - return $this->writeUserSettingCache($key, $value); 510 - } catch (Exception $ex) { 511 - // Fall through below and return the default value. 512 - } 502 + if ($cache_map) { 503 + $value = $cache_map[$cache_key]; 504 + } else { 505 + $defaults = PhabricatorSetting::getAllSettings(); 506 + if (isset($defaults[$key])) { 507 + $value = id(clone $defaults[$key]) 508 + ->setViewer($this) 509 + ->getSettingDefaultValue(); 513 510 } else { 514 - // This is an ad-hoc setting with no controlling object. 515 - return $this->writeUserSettingCache($key, $value); 511 + $value = null; 516 512 } 517 - } 518 513 519 - if (isset($defaults[$key])) { 520 - $value = id(clone $defaults[$key]) 521 - ->setViewer($this) 522 - ->getSettingDefaultValue(); 523 - } else { 524 - $value = null; 514 + $cache->setKey($cache_key, $value); 525 515 } 526 516 527 517 return $this->writeUserSettingCache($key, $value); ··· 555 545 return $this->getUserSetting(PhabricatorTimezoneSetting::SETTINGKEY); 556 546 } 557 547 548 + public static function getGlobalSettingsCacheKey() { 549 + return 'user.settings.globals.v1'; 550 + } 551 + 558 552 private function loadGlobalSettings() { 559 - $cache_key = 'user.settings.global'; 560 - $cache = PhabricatorCaches::getRequestCache(); 561 - $settings = $cache->getKey($cache_key); 553 + $cache_key = self::getGlobalSettingsCacheKey(); 554 + $cache = PhabricatorCaches::getMutableStructureCache(); 562 555 563 - if ($settings === null) { 556 + $settings = $cache->getKey($cache_key); 557 + if (!$settings) { 564 558 $preferences = PhabricatorUserPreferences::loadGlobalPreferences($this); 565 559 $settings = $preferences->getPreferences(); 566 560 $cache->setKey($cache_key, $settings); ··· 1495 1489 throw new PhabricatorDataNotAttachedException($this); 1496 1490 } 1497 1491 1492 + $user_phid = $this->getPHID(); 1493 + 1494 + // Try to read the actual cache before we generate a new value. We can 1495 + // end up here via Conduit, which does not use normal sessions and can 1496 + // not pick up a free cache load during session identification. 1497 + if ($user_phid) { 1498 + $raw_data = PhabricatorUserCache::readCaches( 1499 + $type, 1500 + $key, 1501 + array($user_phid)); 1502 + if (array_key_exists($user_phid, $raw_data)) { 1503 + $raw_value = $raw_data[$user_phid]; 1504 + $usable_value = $type->getValueFromStorage($raw_value); 1505 + $this->rawCacheData[$key] = $raw_value; 1506 + $this->usableCacheData[$key] = $usable_value; 1507 + return $usable_value; 1508 + } 1509 + } 1510 + 1498 1511 $usable_value = $type->getDefaultValue(); 1499 1512 1500 - $user_phid = $this->getPHID(); 1501 1513 if ($user_phid) { 1502 1514 $map = $type->newValueForUsers($key, array($this)); 1503 1515 if (array_key_exists($user_phid, $map)) {
+20
src/applications/people/storage/PhabricatorUserCache.php
··· 96 96 unset($unguarded); 97 97 } 98 98 99 + public static function readCaches( 100 + PhabricatorUserCacheType $type, 101 + $key, 102 + array $user_phids) { 103 + 104 + $table = new self(); 105 + $conn = $table->establishConnection('r'); 106 + 107 + $rows = queryfx_all( 108 + $conn, 109 + 'SELECT userPHID, cacheData FROM %T WHERE userPHID IN (%Ls) 110 + AND cacheType = %s AND cacheIndex = %s', 111 + $table->getTableName(), 112 + $user_phids, 113 + $type->getUserCacheType(), 114 + PhabricatorHash::digestForIndex($key)); 115 + 116 + return ipull($rows, 'cacheData', 'userPHID'); 117 + } 118 + 99 119 public static function clearCache($key, $user_phid) { 100 120 return self::clearCaches($key, array($user_phid)); 101 121 }
+3
src/applications/settings/editor/PhabricatorUserPreferencesEditor.php
··· 158 158 PhabricatorUserPreferencesCacheType::KEY_PREFERENCES, 159 159 $user_phid); 160 160 } else { 161 + $cache = PhabricatorCaches::getMutableStructureCache(); 162 + $cache->deleteKey(PhabricatorUserPreferences::getGlobalCacheKey()); 163 + 161 164 PhabricatorUserCache::clearCacheForAllUsers( 162 165 PhabricatorUserPreferencesCacheType::KEY_PREFERENCES); 163 166 }
+1 -6
src/applications/settings/setting/PhabricatorPinnedApplicationsSetting.php
··· 10 10 } 11 11 12 12 public function getSettingDefaultValue() { 13 - $viewer = $this->getViewer(); 14 - 15 - // If we're editing a template, just show every available application. 16 - if (!$viewer) { 17 - $viewer = PhabricatorUser::getOmnipotentUser(); 18 - } 13 + $viewer = PhabricatorUser::getOmnipotentUser(); 19 14 20 15 $applications = id(new PhabricatorApplicationQuery()) 21 16 ->setViewer($viewer)