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

Rough cut of repository cluster status panel

Summary:
Ref T4292. This adds some very basic cluster/device data to the new management view. Nothing interesting yet.

Also deal with disabled bindings a little more cleanly.

Test Plan: {F1214619}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T4292

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

+230 -6
+1 -1
src/applications/config/controller/PhabricatorConfigClusterDatabasesController.php
··· 203 203 ->setIcon('fa-book') 204 204 ->setHref($doc_href) 205 205 ->setTag('a') 206 - ->setText(pht('Database Clustering Documentation'))); 206 + ->setText(pht('Documentation'))); 207 207 208 208 return id(new PHUIObjectBoxView()) 209 209 ->setHeader($header)
+110 -1
src/applications/diffusion/management/DiffusionRepositoryClusterManagementPanel.php
··· 14 14 } 15 15 16 16 public function buildManagementPanelContent() { 17 - return pht('TODO: Cluster configuration management.'); 17 + $repository = $this->getRepository(); 18 + $viewer = $this->getViewer(); 19 + 20 + $service_phid = $repository->getAlmanacServicePHID(); 21 + if ($service_phid) { 22 + $service = id(new AlmanacServiceQuery()) 23 + ->setViewer($viewer) 24 + ->withServiceTypes( 25 + array( 26 + AlmanacClusterRepositoryServiceType::SERVICETYPE, 27 + )) 28 + ->withPHIDs(array($service_phid)) 29 + ->needBindings(true) 30 + ->executeOne(); 31 + if (!$service) { 32 + // TODO: Viewer may not have permission to see the service, or it may 33 + // be invalid? Raise some more useful error here? 34 + throw new Exception(pht('Unable to load cluster service.')); 35 + } 36 + } else { 37 + $service = null; 38 + } 39 + 40 + Javelin::initBehavior('phabricator-tooltips'); 41 + 42 + $rows = array(); 43 + if ($service) { 44 + $bindings = $service->getBindings(); 45 + $bindings = mgroup($bindings, 'getDevicePHID'); 46 + 47 + foreach ($bindings as $binding_group) { 48 + $all_disabled = true; 49 + foreach ($binding_group as $binding) { 50 + if (!$binding->getIsDisabled()) { 51 + $all_disabled = false; 52 + break; 53 + } 54 + } 55 + 56 + $any_binding = head($binding_group); 57 + 58 + if ($all_disabled) { 59 + $binding_icon = 'fa-times grey'; 60 + $binding_tip = pht('Disabled'); 61 + } else { 62 + $binding_icon = 'fa-folder-open green'; 63 + $binding_tip = pht('Active'); 64 + } 65 + 66 + $binding_icon = id(new PHUIIconView()) 67 + ->setIcon($binding_icon) 68 + ->addSigil('has-tooltip') 69 + ->setMetadata( 70 + array( 71 + 'tip' => $binding_tip, 72 + )); 73 + 74 + $device = $any_binding->getDevice(); 75 + 76 + $rows[] = array( 77 + $binding_icon, 78 + phutil_tag( 79 + 'a', 80 + array( 81 + 'href' => $device->getURI(), 82 + ), 83 + $device->getName()), 84 + ); 85 + } 86 + } 87 + 88 + $table = id(new AphrontTableView($rows)) 89 + ->setNoDataString(pht('This is not a cluster repository.')) 90 + ->setHeaders( 91 + array( 92 + null, 93 + pht('Device'), 94 + )) 95 + ->setColumnClasses( 96 + array( 97 + null, 98 + 'wide', 99 + )); 100 + 101 + $doc_href = PhabricatorEnv::getDoclink('Cluster: Repositories'); 102 + 103 + $header = id(new PHUIHeaderView()) 104 + ->setHeader(pht('Cluster Status')) 105 + ->addActionLink( 106 + id(new PHUIButtonView()) 107 + ->setIcon('fa-book') 108 + ->setHref($doc_href) 109 + ->setTag('a') 110 + ->setText(pht('Documentation'))); 111 + 112 + if ($service) { 113 + $header->setSubheader( 114 + pht( 115 + 'This repository is hosted on %s.', 116 + phutil_tag( 117 + 'a', 118 + array( 119 + 'href' => $service->getURI(), 120 + ), 121 + $service->getName()))); 122 + } 123 + 124 + return id(new PHUIObjectBoxView()) 125 + ->setHeader($header) 126 + ->setTable($table); 18 127 } 19 128 20 129 }
+16 -4
src/applications/repository/daemon/PhabricatorRepositoryPullLocalDaemon.php
··· 398 398 $services = id(new AlmanacServiceQuery()) 399 399 ->setViewer($this->getViewer()) 400 400 ->withPHIDs($service_phids) 401 + ->withServiceTypes( 402 + array( 403 + AlmanacClusterRepositoryServiceType::SERVICETYPE, 404 + )) 401 405 ->needBindings(true) 402 406 ->execute(); 403 407 $services = mpull($services, null, 'getPHID'); ··· 422 426 } 423 427 424 428 $bindings = $service->getBindings(); 425 - $bindings = mpull($bindings, null, 'getDevicePHID'); 426 - $binding = idx($bindings, $device_phid); 427 - if (!$binding) { 429 + $bindings = mgroup($bindings, 'getDevicePHID'); 430 + $bindings = idx($bindings, $device_phid); 431 + if (!$bindings) { 428 432 $this->log( 429 433 pht( 430 434 'Repository "%s" is on cluster service "%s", but that service '. ··· 437 441 continue; 438 442 } 439 443 440 - if ($binding->getIsDisabled()) { 444 + $all_disabled = true; 445 + foreach ($bindings as $binding) { 446 + if (!$binding->getIsDisabled()) { 447 + $all_disabled = false; 448 + break; 449 + } 450 + } 451 + 452 + if ($all_disabled) { 441 453 $this->log( 442 454 pht( 443 455 'Repository "%s" is on cluster service "%s", but the binding '.
+17
src/docs/user/cluster/cluster.diviner
··· 26 26 The remainder of this document summarizes how to add redundancy to each 27 27 service and where your efforts are likely to have the greatest impact. 28 28 29 + 29 30 Cluster: Databases 30 31 ================= 31 32 ··· 38 39 the master, and to quickly promote the replica as a replacement. 39 40 40 41 For details, see @{article:Cluster: Databases}. 42 + 43 + 44 + Cluster: Repositories 45 + ===================== 46 + 47 + Configuring multiple repository hosts is complex. 48 + 49 + Repository replicas are important for availability if you host repositories 50 + on Phabricator, but less important if you host repositories elsewhere 51 + (instead, you should focus on making that service more available). 52 + 53 + The distributed nature of Git and Mercurial tend to mean that they are 54 + naturally somewhat resistant to data loss: every clone of a repository includes 55 + the entire history. 56 + 57 + For details, see @{article:Cluster: Repositories}.
+86
src/docs/user/cluster/cluster_repositories.diviner
··· 1 + @title Cluster: Repositories 2 + @group intro 3 + 4 + Configuring Phabricator to use multiple repository hosts. 5 + 6 + Overview 7 + ======== 8 + 9 + WARNING: This feature is a very early prototype; the features this document 10 + describes are mostly speculative fantasy. 11 + 12 + If you use Git or Mercurial, you can deploy Phabricator with multiple 13 + repository hosts, configured so that each host is readable and writable. The 14 + advantages of doing this are: 15 + 16 + - you can completely survive the loss of repository hosts; 17 + - reads and writes can scale across multiple machines; and 18 + - read and write performance across multiple geographic regions may improve. 19 + 20 + This configuration is complex, and many installs do not need to pursue it. 21 + 22 + This configuration is not currently supported with Subversion. 23 + 24 + 25 + Repository Hosts 26 + ================ 27 + 28 + Repository hosts must run a complete, fully configured copy of Phabricator, 29 + including a webserver. If you make repositories available over SSH, they must 30 + also run a properly configured `sshd`. 31 + 32 + Generally, these hosts will run the same set of services and configuration that 33 + web hosts run. If you prefer, you can overlay these services and put web and 34 + repository services on the same hosts. 35 + 36 + When a user requests information about a repository that can only be satisfied 37 + by examining a repository working copy, the webserver receiving the reqeust 38 + will make an HTTP service call to a repository server which hosts the 39 + repository to retrieve the data it needs. It will use the result of this query 40 + to respond to the user. 41 + 42 + 43 + How Reads and Writes Work 44 + ========================= 45 + 46 + Phabricator repository replicas are multi-master: every node is readable and 47 + writable, and a cluster of nodes can (almost always) survive the loss of any 48 + arbitrary subset of nodes so long as at least one node is still alive. 49 + 50 + Phabricator maintains an internal version for each repository, and increments 51 + it when the repository is mutated. 52 + 53 + Before responding to a read, replicas make sure their version of the repository 54 + is up to date (no node in the cluster has a newer version of the repository). 55 + If it isn't, they block the read until they can complete a fetch. 56 + 57 + Before responding to a write, replicas obtain a global lock, perform the same 58 + version check and fetch if necessary, then allow the write to continue. 59 + 60 + 61 + Backups 62 + ====== 63 + 64 + Even if you configure clustering, you should still consider retaining separate 65 + backup snapshots. Replicas protect you from data loss if you lose a host, but 66 + they do not let you rewind time to recover from data mutation mistakes. 67 + 68 + If something issues a `--force` push that destroys branch heads, the mutation 69 + will propagate to the replicas. 70 + 71 + You may be able to manually restore the branches by using tools like the 72 + Phabricator push log or the Git reflog so it is less important to retain 73 + repository snapshots than database snapshots, but it is still possible for 74 + data to be lost permanently, especially if you don't notice the problem for 75 + some time. 76 + 77 + Retaining separate backup snapshots will improve your ability to recover more 78 + data more easily in a wider range of disaster situations. 79 + 80 + 81 + Next Steps 82 + ========== 83 + 84 + Continue by: 85 + 86 + - returning to @{article:Clustering Introduction}.