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

Allow repository service lookups to return an ordered list of service refs

Summary:
Ref T13286. To support request retries, allow the service lookup method to return an ordered list of structured service references.

Existing callsites continue to immediately discard all but the first reference and pull a URI out of it.

Test Plan: Ran `git pull` in a clustered repository with an "up" node and a "down" node, saw 50% serivce failures and 50% clean pulls.

Maniphest Tasks: T13286

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

+112 -22
+2
src/__phutil_library_map__.php
··· 1021 1021 'DiffusionSSHWorkflow' => 'applications/diffusion/ssh/DiffusionSSHWorkflow.php', 1022 1022 'DiffusionSearchQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionSearchQueryConduitAPIMethod.php', 1023 1023 'DiffusionServeController' => 'applications/diffusion/controller/DiffusionServeController.php', 1024 + 'DiffusionServiceRef' => 'applications/diffusion/ref/DiffusionServiceRef.php', 1024 1025 'DiffusionSetPasswordSettingsPanel' => 'applications/diffusion/panel/DiffusionSetPasswordSettingsPanel.php', 1025 1026 'DiffusionSetupException' => 'applications/diffusion/exception/DiffusionSetupException.php', 1026 1027 'DiffusionSourceHyperlinkEngineExtension' => 'applications/diffusion/engineextension/DiffusionSourceHyperlinkEngineExtension.php', ··· 6967 6968 'DiffusionSSHWorkflow' => 'PhabricatorSSHWorkflow', 6968 6969 'DiffusionSearchQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 6969 6970 'DiffusionServeController' => 'DiffusionController', 6971 + 'DiffusionServiceRef' => 'Phobject', 6970 6972 'DiffusionSetPasswordSettingsPanel' => 'PhabricatorSettingsPanel', 6971 6973 'DiffusionSetupException' => 'Exception', 6972 6974 'DiffusionSourceHyperlinkEngineExtension' => 'PhabricatorRemarkupHyperlinkEngineExtension',
+48
src/applications/diffusion/ref/DiffusionServiceRef.php
··· 1 + <?php 2 + 3 + final class DiffusionServiceRef 4 + extends Phobject { 5 + 6 + private $uri; 7 + private $protocol; 8 + private $isWritable; 9 + private $devicePHID; 10 + private $deviceName; 11 + 12 + private function __construct() { 13 + return; 14 + } 15 + 16 + public static function newFromDictionary(array $map) { 17 + $ref = new self(); 18 + 19 + $ref->uri = $map['uri']; 20 + $ref->isWritable = $map['writable']; 21 + $ref->devicePHID = $map['devicePHID']; 22 + $ref->protocol = $map['protocol']; 23 + $ref->deviceName = $map['device']; 24 + 25 + return $ref; 26 + } 27 + 28 + public function isWritable() { 29 + return $this->isWritable; 30 + } 31 + 32 + public function getDevicePHID() { 33 + return $this->devicePHID; 34 + } 35 + 36 + public function getURI() { 37 + return $this->uri; 38 + } 39 + 40 + public function getProtocol() { 41 + return $this->protocol; 42 + } 43 + 44 + public function getDeviceName() { 45 + return $this->deviceName; 46 + } 47 + 48 + }
+18 -4
src/applications/diffusion/ssh/DiffusionSSHWorkflow.php
··· 73 73 return $this->shouldProxy; 74 74 } 75 75 76 - protected function getProxyCommand($for_write) { 76 + final protected function getAlmanacServiceRefs($for_write) { 77 77 $viewer = $this->getSSHUser(); 78 78 $repository = $this->getRepository(); 79 79 80 80 $is_cluster_request = $this->getIsClusterRequest(); 81 81 82 - $uri = $repository->getAlmanacServiceURI( 82 + $refs = $repository->getAlmanacServiceRefs( 83 83 $viewer, 84 84 array( 85 85 'neverProxy' => $is_cluster_request, ··· 89 89 'writable' => $for_write, 90 90 )); 91 91 92 - if (!$uri) { 92 + if (!$refs) { 93 93 throw new Exception( 94 94 pht( 95 95 'Failed to generate an intracluster proxy URI even though this '. 96 96 'request was routed as a proxy request.')); 97 97 } 98 98 99 - $uri = new PhutilURI($uri); 99 + return $refs; 100 + } 101 + 102 + final protected function getProxyCommand($for_write) { 103 + $refs = $this->getAlmanacServiceRefs($for_write); 104 + 105 + $ref = head($refs); 106 + 107 + return $this->getProxyCommandForServiceRef($ref); 108 + } 109 + 110 + final protected function getProxyCommandForServiceRef( 111 + DiffusionServiceRef $ref) { 112 + 113 + $uri = new PhutilURI($ref->getURI()); 100 114 101 115 $username = AlmanacKeys::getClusterSSHUser(); 102 116 if ($username === null) {
+44 -18
src/applications/repository/storage/PhabricatorRepository.php
··· 1842 1842 PhabricatorUser $viewer, 1843 1843 array $options) { 1844 1844 1845 + $refs = $this->getAlmanacServiceRefs($viewer, $options); 1846 + 1847 + if (!$refs) { 1848 + return null; 1849 + } 1850 + 1851 + $ref = head($refs); 1852 + return $ref->getURI(); 1853 + } 1854 + 1855 + public function getAlmanacServiceRefs( 1856 + PhabricatorUser $viewer, 1857 + array $options) { 1858 + 1845 1859 PhutilTypeSpec::checkMap( 1846 1860 $options, 1847 1861 array( ··· 1856 1870 1857 1871 $cache_key = $this->getAlmanacServiceCacheKey(); 1858 1872 if (!$cache_key) { 1859 - return null; 1873 + return array(); 1860 1874 } 1861 1875 1862 1876 $cache = PhabricatorCaches::getMutableStructureCache(); ··· 1869 1883 } 1870 1884 1871 1885 if ($uris === null) { 1872 - return null; 1886 + return array(); 1873 1887 } 1874 1888 1875 1889 $local_device = AlmanacKeys::getDeviceID(); ··· 1893 1907 1894 1908 if ($local_device && $never_proxy) { 1895 1909 if ($uri['device'] == $local_device) { 1896 - return null; 1910 + return array(); 1897 1911 } 1898 1912 } 1899 1913 ··· 1954 1968 } 1955 1969 } 1956 1970 1971 + $refs = array(); 1972 + foreach ($results as $result) { 1973 + $refs[] = DiffusionServiceRef::newFromDictionary($result); 1974 + } 1975 + 1957 1976 // If we require a writable device, remove URIs which aren't writable. 1958 1977 if ($writable) { 1959 - foreach ($results as $key => $uri) { 1960 - if (!$uri['writable']) { 1978 + foreach ($refs as $key => $ref) { 1979 + if (!$ref->isWritable()) { 1961 1980 unset($results[$key]); 1962 1981 } 1963 1982 } 1964 1983 1965 - if (!$results) { 1984 + if (!$refs) { 1966 1985 throw new Exception( 1967 1986 pht( 1968 1987 'This repository ("%s") is not writable with the given '. ··· 1974 1993 } 1975 1994 1976 1995 if ($writable) { 1977 - $results = $this->sortWritableAlmanacServiceURIs($results); 1996 + $refs = $this->sortWritableAlmanacServiceRefs($refs); 1978 1997 } else { 1979 - shuffle($results); 1998 + $refs = $this->sortReadableAlmanacServiceRefs($refs); 1980 1999 } 1981 2000 1982 - $result = head($results); 1983 - return $result['uri']; 2001 + return array_values($refs); 1984 2002 } 1985 2003 1986 - private function sortWritableAlmanacServiceURIs(array $results) { 2004 + private function sortReadableAlmanacServiceRefs(array $refs) { 2005 + assert_instances_of($refs, 'DiffusionServiceRef'); 2006 + shuffle($refs); 2007 + return $refs; 2008 + } 2009 + 2010 + private function sortWritableAlmanacServiceRefs(array $refs) { 2011 + assert_instances_of($refs, 'DiffusionServiceRef'); 2012 + 1987 2013 // See T13109 for discussion of how this method routes requests. 1988 2014 1989 2015 // In the absence of other rules, we'll send traffic to devices randomly. 1990 2016 // We also want to select randomly among nodes which are equally good 1991 2017 // candidates to receive the write, and accomplish that by shuffling the 1992 2018 // list up front. 1993 - shuffle($results); 2019 + shuffle($refs); 1994 2020 1995 2021 $order = array(); 1996 2022 ··· 2002 2028 $this->getPHID()); 2003 2029 if ($writer) { 2004 2030 $device_phid = $writer->getWriteProperty('devicePHID'); 2005 - foreach ($results as $key => $result) { 2006 - if ($result['devicePHID'] === $device_phid) { 2031 + foreach ($refs as $key => $ref) { 2032 + if ($ref->getDevicePHID() === $device_phid) { 2007 2033 $order[] = $key; 2008 2034 } 2009 2035 } ··· 2025 2051 } 2026 2052 $max_devices = array_fuse($max_devices); 2027 2053 2028 - foreach ($results as $key => $result) { 2029 - if (isset($max_devices[$result['devicePHID']])) { 2054 + foreach ($refs as $key => $ref) { 2055 + if (isset($max_devices[$ref->getDevicePHID()])) { 2030 2056 $order[] = $key; 2031 2057 } 2032 2058 } ··· 2034 2060 2035 2061 // Reorder the results, putting any we've selected as preferred targets for 2036 2062 // the write at the head of the list. 2037 - $results = array_select_keys($results, $order) + $results; 2063 + $refs = array_select_keys($refs, $order) + $refs; 2038 2064 2039 - return $results; 2065 + return $refs; 2040 2066 } 2041 2067 2042 2068 public function supportsSynchronization() {