Umherirrender has uploaded a new change for review. https://gerrit.wikimedia.org/r/101233
Change subject: Expand CleanupPreferences script to handle unused preferences ...................................................................... Expand CleanupPreferences script to handle unused preferences Also added a check for preferences which are equal to the default value. Adds a --delete param to avoid write actions on first run. Script does a batched full table select to check each row against the criteria (unused or removed preferences; hidden [optional]; equal to default preference) and than deletes the found rows from the database This can help by cleaning up user_properties table as single or montly run, see bug 52777. This is not equals to calling User::saveSettings on a full loaded user object, but should be nearly the same. Using the user object sounds expensiver, because the whole user object is loaded for each user. Must add 3 preferences to $wgDefaultUserOptions, because otherwise there are not recognize as such and the rows where deleted. Change-Id: Ia5d8d1a344a6846777ffda980f884cfc5cdd55e7 --- M includes/DefaultSettings.php M maintenance/cleanupPreferences.php 2 files changed, 159 insertions(+), 9 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core refs/changes/33/101233/1 diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index 40f943f..54cb797 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -4012,6 +4012,7 @@ 'math' => 1, 'minordefault' => 0, 'newpageshidepatrolled' => 0, + 'nickname' => '', 'noconvertlink' => 0, 'norollbackdiff' => 0, 'numberheadings' => 0, @@ -4028,6 +4029,7 @@ 'showtoolbar' => 1, 'skin' => false, 'stubthreshold' => 0, + 'timecorrection' => '', 'thumbsize' => 2, 'underline' => 2, 'uselivepreview' => 0, @@ -4043,6 +4045,7 @@ 'watchlisthideminor' => 0, 'watchlisthideown' => 0, 'watchlisthidepatrolled' => 0, + 'watchlisttoken' => '', 'watchmoves' => 0, 'wllimit' => 250, 'useeditwarning' => 1, diff --git a/maintenance/cleanupPreferences.php b/maintenance/cleanupPreferences.php index 06ae17f..8345717 100644 --- a/maintenance/cleanupPreferences.php +++ b/maintenance/cleanupPreferences.php @@ -1,6 +1,6 @@ <?php /** - * Remove hidden preferences from the database. + * Remove hidden, unused or default preferences from the database. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,20 +31,167 @@ * @ingroup Maintenance */ class CleanupPreferences extends Maintenance { + public function __construct() { + parent::__construct(); + $this->mDescription = 'Delete hidden, unused or default preferences from database'; + $this->addOption( 'delete', 'Perform the deletion' ); + $this->addOption( 'start', + 'Key to start the script from in format "user" or "user,property"', false, true ); + $this->addOption( 'hidden', 'Remove also hidden prefs (from $wgHiddenPrefs)' ); + $this->setBatchSize( 150 ); + } + public function execute() { global $wgHiddenPrefs; $dbw = wfGetDB( DB_MASTER ); - $dbw->begin( __METHOD__ ); - foreach ( $wgHiddenPrefs as $item ) { - $dbw->delete( + $delete = $this->hasOption( 'delete' ); + $hidden = $this->hasOption( 'hidden' ); + + $defaultOptions = User::getDefaultOptions(); + + $cond = array(); + if ( $this->hasOption( 'start' ) ) { + $start = $this->getOption( 'start' ); + $startArray = explode( ',', $start, 2 ); + $cond = $this->buildSelectCond( $dbw, $startArray[0], + count( $startArray ) >= 2 ? $startArray[1] : null ); + $this->output( "Start by > " . $start . "\n" ); + } + + $countAll = 0; + $count = 0; + $deletedAll = 0; + $deleted = 0; + $statsDeletedProperty = array(); + do { + // select next batch + $res = $dbw->select( 'user_properties', - array( 'up_property' => $item ), - __METHOD__ + array( 'up_user', 'up_property', 'up_value' ), + $cond, + __METHOD__, + array( 'LIMIT' => $this->mBatchSize, 'ORDER BY' => array( 'up_user', 'up_property' ) ) ); - }; - $dbw->commit( __METHOD__ ); - $this->output( "Finished!\n" ); + $count = $res->numRows(); + $countAll += $count; + + $lastRow = null; + $deleteRows = array(); + foreach ( $res as $row ) { + $deleteTask = false; + $user = $row->up_user; + $property = $row->up_property; + $value = $row->up_value; + + //Check the row + if ( !isset( $defaultOptions[$property] ) ) { + // unused or old preference -> delete + $deleteTask = 'unused'; + } elseif ( $hidden && isset( $wgHiddenPrefs[$property] ) ) { + // marked as hidden + $deleteTask = 'hidden'; + } else { + // default property, check value + $defaultValue = $defaultOptions[$row->up_property]; + if ( $defaultValue === $row->up_value ) { + // row has same value as default -> delete + $deleteTask = 'default'; + } + } + + // a common wrong situation (from bug 52777) + if ( $property === 'skin' && $value === '' ) { + // Skin::newFromKey will return default skin + $deleteTask = 'default'; + } + + if ( $deleteTask !== false ) { + if ( !isset( $statsDeletedProperty[$deleteTask] ) ) { + $statsDeletedProperty[$deleteTask] = array(); + } + if ( !isset( $statsDeletedProperty[$deleteTask][$property] ) ) { + $statsDeletedProperty[$deleteTask][$property] = 0; + } + $statsDeletedProperty[$deleteTask][$property]++; + + $deleteRows[] = $row; + } + + $lastRow = $row; + } + + // Delete unused rows + $toDelete = count( $deleteRows ); + $deletedAll += $toDelete; + if ( $delete && $toDelete ) { + $dbw->begin( __METHOD__ ); + $dbw->delete( + 'user_properties', + $this->buildDeleteCond( $dbw, $deleteRows ), + __METHOD__ + ); + $dbw->commit( __METHOD__ ); + + $this->output( "Deleted " . $toDelete . " rows\n" ); + + wfWaitForSlaves(); + } + + // build condition to get the next batch + if ( $lastRow !== null && $count === $this->mBatchSize ) { + $cond = $this->buildSelectCond( $dbw, $lastRow->up_user, $lastRow->up_property ); + $this->output( "Last batch ends by " . $lastRow->up_user . "," . $lastRow->up_property . "\n" ); + } + } while ( $count === $this->mBatchSize ); + + $this->output( "\n" ); + + if ( $deletedAll > 0 ) { + if ( $delete ) { + $this->output( "Deleted the following properties:\n" ); + $this->printStats( $statsDeletedProperty ); + $this->output( 'Deleted ' . $deletedAll . ' rows out of ' . $countAll . ' rows' ); + } else { + $this->output( "Would delete the following properties:\n" ); + $this->printStats( $statsDeletedProperty ); + $this->output( 'Would delete ' . $deletedAll . ' rows out of ' . $countAll . ' rows' ); + } + } else { + $this->output( 'Nothing to do!' ); + } + } + + private function buildSelectCond( $db, $user, $property ) { + if ( $property === null ) { + return 'up_user > ' . $db->addQuotes( $user ); + } + + return 'up_user > ' . $db->addQuotes( $user ) . ' OR ' . + '(up_user = ' . $db->addQuotes( $user ) . ' AND ' . + 'up_property > ' . $db->addQuotes( $property ) . ')'; + } + + private function buildDeleteCond( $db, $rows ) { + $conds = array(); + foreach ( $rows as $row ) { + $conds[] = $db->makeList( + // the unique index of the table + array( 'up_user' => $row->up_user, 'up_property' => $row->up_property ), + LIST_AND + ); + } + + return $db->makeList( $conds, LIST_OR ); + } + + private function printStats( $statsDeletedProperty ) { + foreach ( $statsDeletedProperty as $type => $stats ) { + $this->output( $type . ":\n" ); + foreach ( $stats as $property => $count ) { + $this->output( ' "' . $property . '" (' . $count . ")\n" ); + } + } } } -- To view, visit https://gerrit.wikimedia.org/r/101233 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ia5d8d1a344a6846777ffda980f884cfc5cdd55e7 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/core Gerrit-Branch: master Gerrit-Owner: Umherirrender <umherirrender_de...@web.de> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits