Path: blob/master/src/infrastructure/cluster/PhabricatorDatabaseRefParser.php
12241 views
<?php12final class PhabricatorDatabaseRefParser3extends Phobject {45private $defaultPort = 3306;6private $defaultUser;7private $defaultPass;89public function setDefaultPort($default_port) {10$this->defaultPort = $default_port;11return $this;12}1314public function getDefaultPort() {15return $this->defaultPort;16}1718public function setDefaultUser($default_user) {19$this->defaultUser = $default_user;20return $this;21}2223public function getDefaultUser() {24return $this->defaultUser;25}2627public function setDefaultPass($default_pass) {28$this->defaultPass = $default_pass;29return $this;30}3132public function getDefaultPass() {33return $this->defaultPass;34}3536public function newRefs(array $config) {37$default_port = $this->getDefaultPort();38$default_user = $this->getDefaultUser();39$default_pass = $this->getDefaultPass();4041$refs = array();4243$master_count = 0;44foreach ($config as $key => $server) {45$host = $server['host'];46$port = idx($server, 'port', $default_port);47$user = idx($server, 'user', $default_user);48$disabled = idx($server, 'disabled', false);4950$pass = idx($server, 'pass');51if ($pass) {52$pass = new PhutilOpaqueEnvelope($pass);53} else {54$pass = clone $default_pass;55}5657$role = $server['role'];58$is_master = ($role == 'master');5960$use_persistent = (bool)idx($server, 'persistent', false);6162$ref = id(new PhabricatorDatabaseRef())63->setHost($host)64->setPort($port)65->setUser($user)66->setPass($pass)67->setDisabled($disabled)68->setIsMaster($is_master)69->setUsePersistentConnections($use_persistent);7071if ($is_master) {72$master_count++;73}7475$refs[$key] = $ref;76}7778$is_partitioned = ($master_count > 1);79if ($is_partitioned) {80$default_ref = null;81$partition_map = array();82foreach ($refs as $key => $ref) {83if (!$ref->getIsMaster()) {84continue;85}8687$server = $config[$key];88$partition = idx($server, 'partition');89if (!is_array($partition)) {90throw new Exception(91pht(92'This server is configured with multiple master databases, '.93'but master "%s" is missing a "partition" configuration key to '.94'define application partitioning.',95$ref->getRefKey()));96}9798$application_map = array();99foreach ($partition as $application) {100if ($application === 'default') {101if ($default_ref) {102throw new Exception(103pht(104'Multiple masters (databases "%s" and "%s") specify that '.105'they are the "default" partition. Only one master may be '.106'the default.',107$ref->getRefKey(),108$default_ref->getRefKey()));109} else {110$default_ref = $ref;111$ref->setIsDefaultPartition(true);112}113} else if (isset($partition_map[$application])) {114throw new Exception(115pht(116'Multiple masters (databases "%s" and "%s") specify that '.117'they are the partition for application "%s". Each '.118'application may be allocated to only one partition.',119$partition_map[$application]->getRefKey(),120$ref->getRefKey(),121$application));122} else {123// TODO: We should check that the application is valid, to124// prevent typos in application names. However, we do not125// currently have an efficient way to enumerate all of the valid126// application database names.127128$partition_map[$application] = $ref;129$application_map[$application] = $application;130}131}132133$ref->setApplicationMap($application_map);134}135} else {136// If we only have one master, make it the default.137foreach ($refs as $ref) {138if ($ref->getIsMaster()) {139$ref->setIsDefaultPartition(true);140}141}142}143144$ref_map = array();145$master_keys = array();146foreach ($refs as $ref) {147$ref_key = $ref->getRefKey();148if (isset($ref_map[$ref_key])) {149throw new Exception(150pht(151'Multiple configured databases have the same internal '.152'key, "%s". You may have listed a database multiple times.',153$ref_key));154} else {155$ref_map[$ref_key] = $ref;156if ($ref->getIsMaster()) {157$master_keys[] = $ref_key;158}159}160}161162foreach ($refs as $key => $ref) {163if ($ref->getIsMaster()) {164continue;165}166167$server = $config[$key];168169$partition = idx($server, 'partition');170if ($partition !== null) {171throw new Exception(172pht(173'Database "%s" is configured as a replica, but specifies a '.174'"partition". Only master databases may have a partition '.175'configuration. Replicas use the same configuration as the '.176'master they follow.',177$ref->getRefKey()));178}179180$master_key = idx($server, 'master');181if ($master_key === null) {182if ($is_partitioned) {183throw new Exception(184pht(185'Database "%s" is configured as a replica, but does not '.186'specify which "master" it follows in configuration. Valid '.187'masters are: %s.',188$ref->getRefKey(),189implode(', ', $master_keys)));190} else if ($master_keys) {191$master_key = head($master_keys);192} else {193throw new Exception(194pht(195'Database "%s" is configured as a replica, but there is no '.196'master configured.',197$ref->getRefKey()));198}199}200201if (!isset($ref_map[$master_key])) {202throw new Exception(203pht(204'Database "%s" is configured as a replica and specifies a '.205'master ("%s"), but that master is not a valid master. Valid '.206'masters are: %s.',207$ref->getRefKey(),208$master_key,209implode(', ', $master_keys)));210}211212$master_ref = $ref_map[$master_key];213$ref->setMasterRef($ref_map[$master_key]);214$master_ref->addReplicaRef($ref);215}216217return array_values($refs);218}219220}221222223