mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-02 19:52:44 +01:00
8c89fc38fc
Summary: Ref T11044. Fixes T11672. In T11672, persistent connections seem to work fine, but they can require `max_connections` and other settings to be raised. Since most users don't need them, make them an advanced option. Test Plan: Configured persistent connections, loaded some pages, observed persistent connections get used. Reviewers: chad Reviewed By: chad Maniphest Tasks: T11044, T11672 Differential Revision: https://secure.phabricator.com/D16913
219 lines
6.4 KiB
PHP
219 lines
6.4 KiB
PHP
<?php
|
|
|
|
final class PhabricatorDatabaseRefParser
|
|
extends Phobject {
|
|
|
|
private $defaultPort = 3306;
|
|
private $defaultUser;
|
|
private $defaultPass;
|
|
|
|
public function setDefaultPort($default_port) {
|
|
$this->defaultPort = $default_port;
|
|
return $this;
|
|
}
|
|
|
|
public function getDefaultPort() {
|
|
return $this->defaultPort;
|
|
}
|
|
|
|
public function setDefaultUser($default_user) {
|
|
$this->defaultUser = $default_user;
|
|
return $this;
|
|
}
|
|
|
|
public function getDefaultUser() {
|
|
return $this->defaultUser;
|
|
}
|
|
|
|
public function setDefaultPass($default_pass) {
|
|
$this->defaultPass = $default_pass;
|
|
return $this;
|
|
}
|
|
|
|
public function getDefaultPass() {
|
|
return $this->defaultPass;
|
|
}
|
|
|
|
public function newRefs(array $config) {
|
|
$default_port = $this->getDefaultPort();
|
|
$default_user = $this->getDefaultUser();
|
|
$default_pass = $this->getDefaultPass();
|
|
|
|
$refs = array();
|
|
|
|
$master_count = 0;
|
|
foreach ($config as $key => $server) {
|
|
$host = $server['host'];
|
|
$port = idx($server, 'port', $default_port);
|
|
$user = idx($server, 'user', $default_user);
|
|
$disabled = idx($server, 'disabled', false);
|
|
|
|
$pass = idx($server, 'pass');
|
|
if ($pass) {
|
|
$pass = new PhutilOpaqueEnvelope($pass);
|
|
} else {
|
|
$pass = clone $default_pass;
|
|
}
|
|
|
|
$role = $server['role'];
|
|
$is_master = ($role == 'master');
|
|
|
|
$use_persistent = (bool)idx($server, 'persistent', false);
|
|
|
|
$ref = id(new PhabricatorDatabaseRef())
|
|
->setHost($host)
|
|
->setPort($port)
|
|
->setUser($user)
|
|
->setPass($pass)
|
|
->setDisabled($disabled)
|
|
->setIsMaster($is_master)
|
|
->setUsePersistentConnections($use_persistent);
|
|
|
|
if ($is_master) {
|
|
$master_count++;
|
|
}
|
|
|
|
$refs[$key] = $ref;
|
|
}
|
|
|
|
$is_partitioned = ($master_count > 1);
|
|
if ($is_partitioned) {
|
|
$default_ref = null;
|
|
$partition_map = array();
|
|
foreach ($refs as $key => $ref) {
|
|
if (!$ref->getIsMaster()) {
|
|
continue;
|
|
}
|
|
|
|
$server = $config[$key];
|
|
$partition = idx($server, 'partition');
|
|
if (!is_array($partition)) {
|
|
throw new Exception(
|
|
pht(
|
|
'Phabricator is configured with multiple master databases, '.
|
|
'but master "%s" is missing a "partition" configuration key to '.
|
|
'define application partitioning.',
|
|
$ref->getRefKey()));
|
|
}
|
|
|
|
$application_map = array();
|
|
foreach ($partition as $application) {
|
|
if ($application === 'default') {
|
|
if ($default_ref) {
|
|
throw new Exception(
|
|
pht(
|
|
'Multiple masters (databases "%s" and "%s") specify that '.
|
|
'they are the "default" partition. Only one master may be '.
|
|
'the default.',
|
|
$ref->getRefKey(),
|
|
$default_ref->getRefKey()));
|
|
} else {
|
|
$default_ref = $ref;
|
|
$ref->setIsDefaultPartition(true);
|
|
}
|
|
} else if (isset($partition_map[$application])) {
|
|
throw new Exception(
|
|
pht(
|
|
'Multiple masters (databases "%s" and "%s") specify that '.
|
|
'they are the partition for application "%s". Each '.
|
|
'application may be allocated to only one partition.',
|
|
$partition_map[$application]->getRefKey(),
|
|
$ref->getRefKey(),
|
|
$application));
|
|
} else {
|
|
// TODO: We should check that the application is valid, to
|
|
// prevent typos in application names. However, we do not
|
|
// currently have an efficient way to enumerate all of the valid
|
|
// application database names.
|
|
|
|
$partition_map[$application] = $ref;
|
|
$application_map[$application] = $application;
|
|
}
|
|
}
|
|
|
|
$ref->setApplicationMap($application_map);
|
|
}
|
|
} else {
|
|
// If we only have one master, make it the default.
|
|
foreach ($refs as $ref) {
|
|
if ($ref->getIsMaster()) {
|
|
$ref->setIsDefaultPartition(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
$ref_map = array();
|
|
$master_keys = array();
|
|
foreach ($refs as $ref) {
|
|
$ref_key = $ref->getRefKey();
|
|
if (isset($ref_map[$ref_key])) {
|
|
throw new Exception(
|
|
pht(
|
|
'Multiple configured databases have the same internal '.
|
|
'key, "%s". You may have listed a database multiple times.',
|
|
$ref_key));
|
|
} else {
|
|
$ref_map[$ref_key] = $ref;
|
|
if ($ref->getIsMaster()) {
|
|
$master_keys[] = $ref_key;
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach ($refs as $key => $ref) {
|
|
if ($ref->getIsMaster()) {
|
|
continue;
|
|
}
|
|
|
|
$server = $config[$key];
|
|
|
|
$partition = idx($server, 'partition');
|
|
if ($partition !== null) {
|
|
throw new Exception(
|
|
pht(
|
|
'Database "%s" is configured as a replica, but specifies a '.
|
|
'"partition". Only master databases may have a partition '.
|
|
'configuration. Replicas use the same configuration as the '.
|
|
'master they follow.',
|
|
$ref->getRefKey()));
|
|
}
|
|
|
|
$master_key = idx($server, 'master');
|
|
if ($master_key === null) {
|
|
if ($is_partitioned) {
|
|
throw new Exception(
|
|
pht(
|
|
'Database "%s" is configured as a replica, but does not '.
|
|
'specify which "master" it follows in configuration. Valid '.
|
|
'masters are: %s.',
|
|
$ref->getRefKey(),
|
|
implode(', ', $master_keys)));
|
|
} else if ($master_keys) {
|
|
$master_key = head($master_keys);
|
|
} else {
|
|
throw new Exception(
|
|
pht(
|
|
'Database "%s" is configured as a replica, but there is no '.
|
|
'master configured.',
|
|
$ref->getRefKey()));
|
|
}
|
|
}
|
|
|
|
if (!isset($ref_map[$master_key])) {
|
|
throw new Exception(
|
|
pht(
|
|
'Database "%s" is configured as a replica and specifies a '.
|
|
'master ("%s"), but that master is not a valid master. Valid '.
|
|
'masters are: %s.',
|
|
implode(', ', $master_keys)));
|
|
}
|
|
|
|
$master_ref = $ref_map[$master_key];
|
|
$ref->setMasterRef($ref_map[$master_key]);
|
|
$master_ref->addReplicaRef($ref);
|
|
}
|
|
|
|
return array_values($refs);
|
|
}
|
|
|
|
}
|