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

Run all minor setup checks on all configured database hosts

Summary:
Fixes T10759. Fixes T11817. This runs all the general sanity/configuration checks on all the active servers.

None of these warnings are very important, and this doesn't change any logical stuff.

Depends on D16904.

Test Plan: Painstakingly triggered each warning, verified that they rendered correctly and that messages told me which host was affected.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T10759, T11817

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

+120 -68
+85 -60
src/applications/config/check/PhabricatorMySQLSetupCheck.php
··· 6 6 return self::GROUP_MYSQL; 7 7 } 8 8 9 - public static function loadRawConfigValue($key) { 10 - $conn_raw = id(new PhabricatorUser())->establishConnection('w'); 11 - 12 - try { 13 - $value = queryfx_one($conn_raw, 'SELECT @@%Q', $key); 14 - $value = $value['@@'.$key]; 15 - } catch (AphrontQueryException $ex) { 16 - $value = null; 9 + protected function executeChecks() { 10 + $refs = PhabricatorDatabaseRef::getActiveDatabaseRefs(); 11 + foreach ($refs as $ref) { 12 + $this->executeRefChecks($ref); 17 13 } 18 - 19 - return $value; 20 14 } 21 15 22 - protected function executeChecks() { 23 - // TODO: These checks should be executed against every reachable replica? 24 - // See T10759. 25 - if (PhabricatorEnv::isReadOnly()) { 26 - return; 27 - } 16 + private function executeRefChecks(PhabricatorDatabaseRef $ref) { 17 + $max_allowed_packet = $ref->loadRawMySQLConfigValue('max_allowed_packet'); 28 18 29 - $max_allowed_packet = self::loadRawConfigValue('max_allowed_packet'); 19 + $host_name = $ref->getRefKey(); 30 20 31 21 // This primarily supports setting the filesize limit for MySQL to 8MB, 32 22 // which may produce a >16MB packet after escaping. 33 23 $recommended_minimum = (32 * 1024 * 1024); 34 24 if ($max_allowed_packet < $recommended_minimum) { 35 25 $message = pht( 36 - "MySQL is configured with a small '%s' (%d), ". 37 - "which may cause some large writes to fail.", 26 + 'On host "%s", MySQL is configured with a small "%s" (%d), which '. 27 + 'may cause some large writes to fail. The recommended minimum value '. 28 + 'for this setting is "%d".', 29 + $host_name, 38 30 'max_allowed_packet', 39 - $max_allowed_packet); 31 + $max_allowed_packet, 32 + $recommended_minimum); 40 33 41 34 $this->newIssue('mysql.max_allowed_packet') 42 35 ->setName(pht('Small MySQL "%s"', 'max_allowed_packet')) 43 36 ->setMessage($message) 37 + ->setDatabaseRef($ref) 44 38 ->addMySQLConfig('max_allowed_packet'); 45 39 } 46 40 47 - $modes = self::loadRawConfigValue('sql_mode'); 41 + $modes = $ref->loadRawMySQLConfigValue('sql_mode'); 48 42 $modes = explode(',', $modes); 49 43 50 44 if (!in_array('STRICT_ALL_TABLES', $modes)) { 51 45 $summary = pht( 52 - 'MySQL is not in strict mode, but using strict mode is strongly '. 53 - 'encouraged.'); 46 + 'MySQL is not in strict mode (on host "%s"), but using strict mode '. 47 + 'is strongly encouraged.', 48 + $host_name); 54 49 55 50 $message = pht( 56 - "On your MySQL instance, the global %s is not set to %s. ". 51 + "On database host \"%s\", the global %s is not set to %s. ". 57 52 "It is strongly encouraged that you enable this mode when running ". 58 53 "Phabricator.\n\n". 59 54 "By default MySQL will silently ignore some types of errors, which ". ··· 67 62 "(Note that if you run other applications against the same database, ". 68 63 "they may not work in strict mode. Be careful about enabling it in ". 69 64 "these cases.)", 65 + $host_name, 70 66 phutil_tag('tt', array(), 'sql_mode'), 71 67 phutil_tag('tt', array(), 'STRICT_ALL_TABLES'), 72 68 phutil_tag('tt', array(), 'my.cnf'), ··· 78 74 ->setName(pht('MySQL %s Mode Not Set', 'STRICT_ALL_TABLES')) 79 75 ->setSummary($summary) 80 76 ->setMessage($message) 77 + ->setDatabaseRef($ref) 81 78 ->addMySQLConfig('sql_mode'); 82 79 } 80 + 83 81 if (in_array('ONLY_FULL_GROUP_BY', $modes)) { 84 82 $summary = pht( 85 - 'MySQL is in ONLY_FULL_GROUP_BY mode, but using this mode is strongly '. 86 - 'discouraged.'); 83 + 'MySQL is in ONLY_FULL_GROUP_BY mode (on host "%s"), but using this '. 84 + 'mode is strongly discouraged.', 85 + $host_name); 87 86 88 87 $message = pht( 89 - "On your MySQL instance, the global %s is set to %s. ". 88 + "On database host \"%s\", the global %s is set to %s. ". 90 89 "It is strongly encouraged that you disable this mode when running ". 91 90 "Phabricator.\n\n". 92 91 "With %s enabled, MySQL rejects queries for which the select list ". ··· 101 100 "they may not work with %s. Be careful about enabling ". 102 101 "it in these cases and consider migrating Phabricator to a different ". 103 102 "database.)", 103 + $host_name, 104 104 phutil_tag('tt', array(), 'sql_mode'), 105 105 phutil_tag('tt', array(), 'ONLY_FULL_GROUP_BY'), 106 106 phutil_tag('tt', array(), 'ONLY_FULL_GROUP_BY'), ··· 117 117 ->setName(pht('MySQL %s Mode Set', 'ONLY_FULL_GROUP_BY')) 118 118 ->setSummary($summary) 119 119 ->setMessage($message) 120 + ->setDatabaseRef($ref) 120 121 ->addMySQLConfig('sql_mode'); 121 122 } 122 123 123 - $stopword_file = self::loadRawConfigValue('ft_stopword_file'); 124 - 124 + $stopword_file = $ref->loadRawMySQLConfigValue('ft_stopword_file'); 125 125 if ($this->shouldUseMySQLSearchEngine()) { 126 126 if ($stopword_file === null) { 127 127 $summary = pht( 128 - 'Your version of MySQL does not support configuration of a '. 129 - 'stopword file. You will not be able to find search results for '. 130 - 'common words.'); 128 + 'Your version of MySQL (on database host "%s") does not support '. 129 + 'configuration of a stopword file. You will not be able to find '. 130 + 'search results for common words.', 131 + $host_name); 131 132 132 133 $message = pht( 133 - "Your MySQL instance does not support the %s option. You will not ". 134 + "Database host \"%s\" does not support the %s option. You will not ". 134 135 "be able to find search results for common words. You can gain ". 135 136 "access to this option by upgrading MySQL to a more recent ". 136 137 "version.\n\n". 137 138 "You can ignore this warning if you plan to configure ElasticSearch ". 138 139 "later, or aren't concerned about searching for common words.", 140 + $host_name, 139 141 phutil_tag('tt', array(), 'ft_stopword_file')); 140 142 141 143 $this->newIssue('mysql.ft_stopword_file') 142 144 ->setName(pht('MySQL %s Not Supported', 'ft_stopword_file')) 143 145 ->setSummary($summary) 144 146 ->setMessage($message) 147 + ->setDatabaseRef($ref) 145 148 ->addMySQLConfig('ft_stopword_file'); 146 149 147 150 } else if ($stopword_file == '(built-in)') { ··· 152 155 $namespace = PhabricatorEnv::getEnvConfig('storage.default-namespace'); 153 156 154 157 $summary = pht( 155 - 'MySQL is using a default stopword file, which will prevent '. 156 - 'searching for many common words.'); 158 + 'MySQL (on host "%s") is using a default stopword file, which '. 159 + 'will prevent searching for many common words.', 160 + $host_name); 157 161 158 162 $message = pht( 159 - "Your MySQL instance is using the builtin stopword file for ". 163 + "Database host \"%s\" is using the builtin stopword file for ". 160 164 "building search indexes. This can make Phabricator's search ". 161 165 "feature less useful.\n\n". 162 166 "Stopwords are common words which are not indexed and thus can not ". ··· 177 181 "Finally, run this command to rebuild indexes using the new ". 178 182 "rules:\n\n". 179 183 "%s", 184 + $host_name, 180 185 phutil_tag('tt', array(), 'my.cnf'), 181 186 phutil_tag('tt', array(), '[mysqld]'), 182 187 phutil_tag('tt', array(), 'mysqld'), ··· 190 195 ->setName(pht('MySQL is Using Default Stopword File')) 191 196 ->setSummary($summary) 192 197 ->setMessage($message) 198 + ->setDatabaseRef($ref) 193 199 ->addMySQLConfig('ft_stopword_file'); 194 200 } 195 201 } 196 202 197 - $min_len = self::loadRawConfigValue('ft_min_word_len'); 203 + $min_len = $ref->loadRawMySQLConfigValue('ft_min_word_len'); 198 204 if ($min_len >= 4) { 199 205 if ($this->shouldUseMySQLSearchEngine()) { 200 206 $namespace = PhabricatorEnv::getEnvConfig('storage.default-namespace'); 201 207 202 208 $summary = pht( 203 - 'MySQL is configured to only index words with at least %d '. 204 - 'characters.', 209 + 'MySQL is configured (on host "%s") to only index words with at '. 210 + 'least %d characters.', 211 + $host_name, 205 212 $min_len); 206 213 207 214 $message = pht( 208 - "Your MySQL instance is configured to use the default minimum word ". 215 + "Database host \"%s\" is configured to use the default minimum word ". 209 216 "length when building search indexes, which is 4. This means words ". 210 217 "which are only 3 characters long will not be indexed and can not ". 211 218 "be searched for.\n\n". ··· 222 229 "Finally, run this command to rebuild indexes using the new ". 223 230 "rules:\n\n". 224 231 "%s", 232 + $host_name, 225 233 phutil_tag('tt', array(), 'my.cnf'), 226 234 phutil_tag('tt', array(), '[mysqld]'), 227 235 phutil_tag('tt', array(), 'mysqld'), ··· 235 243 ->setName(pht('MySQL is Using Default Minimum Word Length')) 236 244 ->setSummary($summary) 237 245 ->setMessage($message) 246 + ->setDatabaseRef($ref) 238 247 ->addMySQLConfig('ft_min_word_len'); 239 248 } 240 249 } 241 250 242 - $bool_syntax = self::loadRawConfigValue('ft_boolean_syntax'); 251 + $bool_syntax = $ref->loadRawMySQLConfigValue('ft_boolean_syntax'); 243 252 if ($bool_syntax != ' |-><()~*:""&^') { 244 253 if ($this->shouldUseMySQLSearchEngine()) { 245 254 $summary = pht( 246 - 'MySQL is configured to search on fulltext indexes using "OR" by '. 247 - 'default. Using "AND" is usually the desired behaviour.'); 255 + 'MySQL (on host "%s") is configured to search on fulltext indexes '. 256 + 'using "OR" by default. Using "AND" is usually the desired '. 257 + 'behaviour.', 258 + $host_name); 248 259 249 260 $message = pht( 250 - "Your MySQL instance is configured to use the default Boolean ". 261 + "Database host \"%s\" is configured to use the default Boolean ". 251 262 "search syntax when using fulltext indexes. This means searching ". 252 263 "for 'search words' will yield the query 'search OR words' ". 253 264 "instead of the desired 'search AND words'.\n\n". ··· 260 271 "To change this setting, add this to your %s file ". 261 272 "(in the %s section) and then restart %s:\n\n". 262 273 "%s\n", 274 + $host_name, 263 275 phutil_tag('tt', array(), 'my.cnf'), 264 276 phutil_tag('tt', array(), '[mysqld]'), 265 277 phutil_tag('tt', array(), 'mysqld'), ··· 269 281 ->setName(pht('MySQL is Using the Default Boolean Syntax')) 270 282 ->setSummary($summary) 271 283 ->setMessage($message) 284 + ->setDatabaseRef($ref) 272 285 ->addMySQLConfig('ft_boolean_syntax'); 273 286 } 274 287 } 275 288 276 - $innodb_pool = self::loadRawConfigValue('innodb_buffer_pool_size'); 289 + $innodb_pool = $ref->loadRawMySQLConfigValue('innodb_buffer_pool_size'); 277 290 $innodb_bytes = phutil_parse_bytes($innodb_pool); 278 291 $innodb_readable = phutil_format_bytes($innodb_bytes); 279 292 ··· 286 299 $minimum_bytes = phutil_parse_bytes($minimum_readable); 287 300 if ($innodb_bytes < $minimum_bytes) { 288 301 $summary = pht( 289 - 'MySQL is configured with a very small innodb_buffer_pool_size, '. 290 - 'which may impact performance.'); 302 + 'MySQL (on host "%s") is configured with a very small '. 303 + 'innodb_buffer_pool_size, which may impact performance.', 304 + $host_name); 291 305 292 306 $message = pht( 293 - "Your MySQL instance is configured with a very small %s (%s). ". 307 + "Database host \"%s\" is configured with a very small %s (%s). ". 294 308 "This may cause poor database performance and lock exhaustion.\n\n". 295 309 "There are no hard-and-fast rules to setting an appropriate value, ". 296 310 "but a reasonable starting point for a standard install is something ". ··· 307 321 "%s\n". 308 322 "If you're satisfied with the current setting, you can safely ". 309 323 "ignore this setup warning.", 324 + $host_name, 310 325 phutil_tag('tt', array(), 'innodb_buffer_pool_size'), 311 326 phutil_tag('tt', array(), $innodb_readable), 312 327 phutil_tag('tt', array(), '1600M'), ··· 320 335 ->setName(pht('MySQL May Run Slowly')) 321 336 ->setSummary($summary) 322 337 ->setMessage($message) 338 + ->setDatabaseRef($ref) 323 339 ->addMySQLConfig('innodb_buffer_pool_size'); 324 340 } 325 341 326 - $conn_w = id(new PhabricatorUser())->establishConnection('w'); 342 + $conn = $ref->newManagementConnection(); 327 343 328 344 $ok = PhabricatorStorageManagementAPI::isCharacterSetAvailableOnConnection( 329 345 'utf8mb4', 330 - $conn_w); 346 + $conn); 331 347 if (!$ok) { 332 348 $summary = pht( 333 - 'You are using an old version of MySQL, and should upgrade.'); 349 + 'You are using an old version of MySQL (on host "%s"), and should '. 350 + 'upgrade.', 351 + $host_name); 334 352 335 353 $message = pht( 336 - 'You are using an old version of MySQL which has poor unicode '. 337 - 'support (it does not support the "utf8mb4" collation set). You will '. 338 - 'encounter limitations when working with some unicode data.'. 354 + 'You are using an old version of MySQL (on host "%s") which has poor '. 355 + 'unicode support (it does not support the "utf8mb4" collation set). '. 356 + 'You will encounter limitations when working with some unicode data.'. 339 357 "\n\n". 340 - 'We strongly recommend you upgrade to MySQL 5.5 or newer.'); 358 + 'We strongly recommend you upgrade to MySQL 5.5 or newer.', 359 + $host_name); 341 360 342 361 $this->newIssue('mysql.utf8mb4') 343 362 ->setName(pht('Old MySQL Version')) 344 363 ->setSummary($summary) 364 + ->setDatabaseRef($ref) 345 365 ->setMessage($message); 346 366 } 347 367 348 368 $info = queryfx_one( 349 - $conn_w, 369 + $conn, 350 370 'SELECT UNIX_TIMESTAMP() epoch'); 351 371 352 372 $epoch = (int)$info['epoch']; ··· 357 377 ->setName(pht('Major Web/Database Clock Skew')) 358 378 ->setSummary( 359 379 pht( 360 - 'This host is set to a very different time than the database.')) 380 + 'This web host ("%s") is set to a very different time than a '. 381 + 'database host "%s".', 382 + php_uname('n'), 383 + $host_name)) 361 384 ->setMessage( 362 385 pht( 363 - 'The database host and this host ("%s") disagree on the current '. 364 - 'time by more than 60 seconds (absolute skew is %s seconds). '. 365 - 'Check that the current time is set correctly everywhere.', 386 + 'A database host ("%s") and this web host ("%s") disagree on the '. 387 + 'current time by more than 60 seconds (absolute skew is %s '. 388 + 'seconds). Check that the current time is set correctly '. 389 + 'everywhere.', 390 + $host_name, 366 391 php_uname('n'), 367 392 new PhutilNumber($delta))); 368 393 }
+10
src/applications/config/issue/PhabricatorSetupIssue.php
··· 9 9 private $summary; 10 10 private $shortName; 11 11 private $group; 12 + private $databaseRef; 12 13 13 14 private $isIgnored = false; 14 15 private $phpExtensions = array(); ··· 66 67 return $this->getName(); 67 68 } 68 69 return $this->shortName; 70 + } 71 + 72 + public function setDatabaseRef(PhabricatorDatabaseRef $database_ref) { 73 + $this->databaseRef = $database_ref; 74 + return $this; 75 + } 76 + 77 + public function getDatabaseRef() { 78 + return $this->databaseRef; 69 79 } 70 80 71 81 public function setGroup($group) {
+12 -8
src/applications/config/view/PhabricatorSetupIssueView.php
··· 470 470 471 471 private function renderMySQLConfig(array $config) { 472 472 $values = array(); 473 - foreach ($config as $key) { 474 - $value = PhabricatorMySQLSetupCheck::loadRawConfigValue($key); 475 - if ($value === null) { 476 - $value = phutil_tag( 477 - 'em', 478 - array(), 479 - pht('(Not Supported)')); 473 + $issue = $this->getIssue(); 474 + $ref = $issue->getDatabaseRef(); 475 + if ($ref) { 476 + foreach ($config as $key) { 477 + $value = $ref->loadRawMySQLConfigValue($key); 478 + if ($value === null) { 479 + $value = phutil_tag( 480 + 'em', 481 + array(), 482 + pht('(Not Supported)')); 483 + } 484 + $values[$key] = $value; 480 485 } 481 - $values[$key] = $value; 482 486 } 483 487 484 488 $table = $this->renderValueTable($values);
+13
src/infrastructure/cluster/PhabricatorDatabaseRef.php
··· 518 518 return isset($this->applicationMap[$database]); 519 519 } 520 520 521 + public function loadRawMySQLConfigValue($key) { 522 + $conn = $this->newManagementConnection(); 523 + 524 + try { 525 + $value = queryfx_one($conn, 'SELECT @@%Q', $key); 526 + $value = $value['@@'.$key]; 527 + } catch (AphrontQueryException $ex) { 528 + $value = null; 529 + } 530 + 531 + return $value; 532 + } 533 + 521 534 public static function getMasterDatabaseRefForApplication($application) { 522 535 $masters = self::getMasterDatabaseRefs(); 523 536