Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/infrastructure/cluster/PhabricatorDatabaseRefParser.php
12241 views
1
<?php
2
3
final class PhabricatorDatabaseRefParser
4
extends Phobject {
5
6
private $defaultPort = 3306;
7
private $defaultUser;
8
private $defaultPass;
9
10
public function setDefaultPort($default_port) {
11
$this->defaultPort = $default_port;
12
return $this;
13
}
14
15
public function getDefaultPort() {
16
return $this->defaultPort;
17
}
18
19
public function setDefaultUser($default_user) {
20
$this->defaultUser = $default_user;
21
return $this;
22
}
23
24
public function getDefaultUser() {
25
return $this->defaultUser;
26
}
27
28
public function setDefaultPass($default_pass) {
29
$this->defaultPass = $default_pass;
30
return $this;
31
}
32
33
public function getDefaultPass() {
34
return $this->defaultPass;
35
}
36
37
public function newRefs(array $config) {
38
$default_port = $this->getDefaultPort();
39
$default_user = $this->getDefaultUser();
40
$default_pass = $this->getDefaultPass();
41
42
$refs = array();
43
44
$master_count = 0;
45
foreach ($config as $key => $server) {
46
$host = $server['host'];
47
$port = idx($server, 'port', $default_port);
48
$user = idx($server, 'user', $default_user);
49
$disabled = idx($server, 'disabled', false);
50
51
$pass = idx($server, 'pass');
52
if ($pass) {
53
$pass = new PhutilOpaqueEnvelope($pass);
54
} else {
55
$pass = clone $default_pass;
56
}
57
58
$role = $server['role'];
59
$is_master = ($role == 'master');
60
61
$use_persistent = (bool)idx($server, 'persistent', false);
62
63
$ref = id(new PhabricatorDatabaseRef())
64
->setHost($host)
65
->setPort($port)
66
->setUser($user)
67
->setPass($pass)
68
->setDisabled($disabled)
69
->setIsMaster($is_master)
70
->setUsePersistentConnections($use_persistent);
71
72
if ($is_master) {
73
$master_count++;
74
}
75
76
$refs[$key] = $ref;
77
}
78
79
$is_partitioned = ($master_count > 1);
80
if ($is_partitioned) {
81
$default_ref = null;
82
$partition_map = array();
83
foreach ($refs as $key => $ref) {
84
if (!$ref->getIsMaster()) {
85
continue;
86
}
87
88
$server = $config[$key];
89
$partition = idx($server, 'partition');
90
if (!is_array($partition)) {
91
throw new Exception(
92
pht(
93
'This server is configured with multiple master databases, '.
94
'but master "%s" is missing a "partition" configuration key to '.
95
'define application partitioning.',
96
$ref->getRefKey()));
97
}
98
99
$application_map = array();
100
foreach ($partition as $application) {
101
if ($application === 'default') {
102
if ($default_ref) {
103
throw new Exception(
104
pht(
105
'Multiple masters (databases "%s" and "%s") specify that '.
106
'they are the "default" partition. Only one master may be '.
107
'the default.',
108
$ref->getRefKey(),
109
$default_ref->getRefKey()));
110
} else {
111
$default_ref = $ref;
112
$ref->setIsDefaultPartition(true);
113
}
114
} else if (isset($partition_map[$application])) {
115
throw new Exception(
116
pht(
117
'Multiple masters (databases "%s" and "%s") specify that '.
118
'they are the partition for application "%s". Each '.
119
'application may be allocated to only one partition.',
120
$partition_map[$application]->getRefKey(),
121
$ref->getRefKey(),
122
$application));
123
} else {
124
// TODO: We should check that the application is valid, to
125
// prevent typos in application names. However, we do not
126
// currently have an efficient way to enumerate all of the valid
127
// application database names.
128
129
$partition_map[$application] = $ref;
130
$application_map[$application] = $application;
131
}
132
}
133
134
$ref->setApplicationMap($application_map);
135
}
136
} else {
137
// If we only have one master, make it the default.
138
foreach ($refs as $ref) {
139
if ($ref->getIsMaster()) {
140
$ref->setIsDefaultPartition(true);
141
}
142
}
143
}
144
145
$ref_map = array();
146
$master_keys = array();
147
foreach ($refs as $ref) {
148
$ref_key = $ref->getRefKey();
149
if (isset($ref_map[$ref_key])) {
150
throw new Exception(
151
pht(
152
'Multiple configured databases have the same internal '.
153
'key, "%s". You may have listed a database multiple times.',
154
$ref_key));
155
} else {
156
$ref_map[$ref_key] = $ref;
157
if ($ref->getIsMaster()) {
158
$master_keys[] = $ref_key;
159
}
160
}
161
}
162
163
foreach ($refs as $key => $ref) {
164
if ($ref->getIsMaster()) {
165
continue;
166
}
167
168
$server = $config[$key];
169
170
$partition = idx($server, 'partition');
171
if ($partition !== null) {
172
throw new Exception(
173
pht(
174
'Database "%s" is configured as a replica, but specifies a '.
175
'"partition". Only master databases may have a partition '.
176
'configuration. Replicas use the same configuration as the '.
177
'master they follow.',
178
$ref->getRefKey()));
179
}
180
181
$master_key = idx($server, 'master');
182
if ($master_key === null) {
183
if ($is_partitioned) {
184
throw new Exception(
185
pht(
186
'Database "%s" is configured as a replica, but does not '.
187
'specify which "master" it follows in configuration. Valid '.
188
'masters are: %s.',
189
$ref->getRefKey(),
190
implode(', ', $master_keys)));
191
} else if ($master_keys) {
192
$master_key = head($master_keys);
193
} else {
194
throw new Exception(
195
pht(
196
'Database "%s" is configured as a replica, but there is no '.
197
'master configured.',
198
$ref->getRefKey()));
199
}
200
}
201
202
if (!isset($ref_map[$master_key])) {
203
throw new Exception(
204
pht(
205
'Database "%s" is configured as a replica and specifies a '.
206
'master ("%s"), but that master is not a valid master. Valid '.
207
'masters are: %s.',
208
$ref->getRefKey(),
209
$master_key,
210
implode(', ', $master_keys)));
211
}
212
213
$master_ref = $ref_map[$master_key];
214
$ref->setMasterRef($ref_map[$master_key]);
215
$master_ref->addReplicaRef($ref);
216
}
217
218
return array_values($refs);
219
}
220
221
}
222
223