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

Reply via email to