Allow the signature button wikitext to be overridden locally
[lhc/web/wiklou.git] / maintenance / updateCollation.php
index af666b0..922cc87 100644 (file)
@@ -33,8 +33,8 @@ require_once __DIR__ . '/Maintenance.php';
  * @ingroup Maintenance
  */
 class UpdateCollation extends Maintenance {
-       const BATCH_SIZE = 10000; // Number of rows to process in one batch
-       const SYNC_INTERVAL = 20; // Wait for slaves after this many batches
+       const BATCH_SIZE = 100; // Number of rows to process in one batch
+       const SYNC_INTERVAL = 5; // Wait for slaves after this many batches
 
        public $sizeHistogram = [];
 
@@ -51,7 +51,7 @@ TEXT
                );
 
                $this->addOption( 'force', 'Run on all rows, even if the collation is ' .
-                       'supposed to be up-to-date.' );
+                       'supposed to be up-to-date.', false, false, 'f' );
                $this->addOption( 'previous-collation', 'Set the previous value of ' .
                        '$wgCategoryCollation here to speed up this script, especially if your ' .
                        'categorylinks table is large. This will only update rows with that ' .
@@ -70,6 +70,7 @@ TEXT
                global $wgCategoryCollation;
 
                $dbw = $this->getDB( DB_MASTER );
+               $dbr = $this->getDB( DB_SLAVE );
                $force = $this->getOption( 'force' );
                $dryRun = $this->getOption( 'dry-run' );
                $verboseStats = $this->getOption( 'verbose-stats' );
@@ -85,10 +86,19 @@ TEXT
                // but this will raise an exception, breaking all category pages
                $collation->getFirstLetter( 'MediaWiki' );
 
+               // Locally at least, (my local is a rather old version of mysql)
+               // mysql seems to filesort if there is both an equality
+               // (but not for an inequality) condition on cl_collation in the
+               // WHERE and it is also the first item in the ORDER BY.
+               if ( $this->hasOption( 'previous-collation' ) ) {
+                       $orderBy = 'cl_to, cl_type, cl_from';
+               } else {
+                       $orderBy = 'cl_collation, cl_to, cl_type, cl_from';
+               }
                $options = [
                        'LIMIT' => self::BATCH_SIZE,
-                       'ORDER BY' => 'cl_from, cl_to',
-                       'STRAIGHT_JOIN',
+                       'ORDER BY' => $orderBy,
+                       'STRAIGHT_JOIN' // per T58041
                ];
 
                if ( $force || $dryRun ) {
@@ -102,7 +112,7 @@ TEXT
                                ];
                        }
 
-                       $count = $dbw->estimateRowCount(
+                       $count = $dbr->estimateRowCount(
                                'categorylinks',
                                '*',
                                $collationConds,
@@ -110,7 +120,7 @@ TEXT
                        );
                        // Improve estimate if feasible
                        if ( $count < 1000000 ) {
-                               $count = $dbw->selectField(
+                               $count = $dbr->selectField(
                                        'categorylinks',
                                        'COUNT(*)',
                                        $collationConds,
@@ -123,17 +133,26 @@ TEXT
                                return;
                        }
                        $this->output( "Fixing collation for $count rows.\n" );
+                       wfWaitForSlaves();
                }
-
                $count = 0;
                $batchCount = 0;
                $batchConds = [];
                do {
                        $this->output( "Selecting next " . self::BATCH_SIZE . " rows..." );
+
+                       // cl_type must be selected as a number for proper paging because
+                       // enums suck.
+                       if ( $dbw->getType() === 'mysql' ) {
+                               $clType = 'cl_type+0 AS "cl_type_numeric"';
+                       } else {
+                               $clType = 'cl_type';
+                       }
                        $res = $dbw->select(
                                [ 'categorylinks', 'page' ],
                                [ 'cl_from', 'cl_to', 'cl_sortkey_prefix', 'cl_collation',
-                                       'cl_sortkey', 'page_namespace', 'page_title'
+                                       'cl_sortkey', $clType,
+                                       'page_namespace', 'page_title'
                                ],
                                array_merge( $collationConds, $batchConds, [ 'cl_from = page_id' ] ),
                                __METHOD__,
@@ -217,18 +236,28 @@ TEXT
 
        /**
         * Return an SQL expression selecting rows which sort above the given row,
-        * assuming an ordering of cl_from, cl_to
+        * assuming an ordering of cl_collation, cl_to, cl_type, cl_from
         * @param stdClass $row
         * @param DatabaseBase $dbw
         * @return string
         */
        function getBatchCondition( $row, $dbw ) {
-               $fields = [ 'cl_from', 'cl_to' ];
+               if ( $this->hasOption( 'previous-collation' ) ) {
+                       $fields = [ 'cl_to', 'cl_type', 'cl_from' ];
+               } else {
+                       $fields = [ 'cl_collation', 'cl_to', 'cl_type', 'cl_from' ];
+               }
                $first = true;
                $cond = false;
                $prefix = false;
                foreach ( $fields as $field ) {
-                       $encValue = $dbw->addQuotes( $row->$field );
+                       if ( $dbw->getType() === 'mysql' && $field === 'cl_type' ) {
+                               // Range conditions with enums are weird in mysql
+                               // This must be a numeric literal, or it won't work.
+                               $encValue = intval( $row->cl_type_numeric );
+                       } else {
+                               $encValue = $dbw->addQuotes( $row->$field );
+                       }
                        $inequality = "$field > $encValue";
                        $equality = "$field = $encValue";
                        if ( $first ) {