r50567 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r50566‎ | r50567 | r50568 >
Date:22:03, 13 May 2009
Author:aaron
Status:ok (Comments)
Tags:
Comment:
[schema change] Use new log_search table to replace ugly code from r48839. Maintenance script added to populate the table with revisiondelete log items.
Modified paths:
  • /trunk/phase3/includes/LogEventsList.php (modified) (history)
  • /trunk/phase3/includes/LogPage.php (modified) (history)
  • /trunk/phase3/includes/specials/SpecialRevisiondelete.php (modified) (history)
  • /trunk/phase3/maintenance/populateLogSearch.php (added) (history)
  • /trunk/phase3/maintenance/tables.sql (modified) (history)
  • /trunk/phase3/maintenance/updaters.inc (modified) (history)

Diff [purge]

Index: trunk/phase3/maintenance/updaters.inc
@@ -156,6 +156,7 @@
157157 array( 'add_table', 'tag_summary', 'patch-change_tag.sql' ),
158158 array( 'add_table', 'valid_tag', 'patch-change_tag.sql' ),
159159 array( 'add_table', 'user_properties', 'patch-user_properties.sql' ),
 160+ array( 'add_table', 'log_search', 'patch-log_search.sql' ),
160161 ),
161162
162163 'sqlite' => array(
Index: trunk/phase3/maintenance/populateLogSearch.php
@@ -0,0 +1,67 @@
 2+<?php
 3+/**
 4+ * Makes the required database updates for Special:ProtectedPages
 5+ * to show all protected pages, even ones before the page restrictions
 6+ * schema change. All remaining page_restriction column values are moved
 7+ * to the new table.
 8+ *
 9+ * @file
 10+ * @ingroup Maintenance
 11+ */
 12+
 13+define( 'BATCH_SIZE', 100 );
 14+
 15+require_once 'commandLine.inc';
 16+
 17+$db =& wfGetDB( DB_MASTER );
 18+if ( !$db->tableExists( 'log_search' ) ) {
 19+ echo "log_search does not exist\n";
 20+ exit( 1 );
 21+}
 22+
 23+migrate_log_params( $db );
 24+
 25+function migrate_log_params( $db ) {
 26+ $start = $db->selectField( 'logging', 'MIN(log_id)', false, __FUNCTION__ );
 27+ if( !$start ) {
 28+ die("Nothing to do.\n");
 29+ }
 30+ $end = $db->selectField( 'logging', 'MAX(log_id)', false, __FUNCTION__ );
 31+
 32+ # Do remaining chunk
 33+ $end += BATCH_SIZE - 1;
 34+ $blockStart = $start;
 35+ $blockEnd = $start + BATCH_SIZE - 1;
 36+ while( $blockEnd <= $end ) {
 37+ echo "...doing log_id from $blockStart to $blockEnd\n";
 38+ $cond = "log_id BETWEEN $blockStart AND $blockEnd";
 39+ $res = $db->select( 'logging', '*', $cond, __FUNCTION__ );
 40+ $batch = array();
 41+ while( $row = $db->fetchObject( $res ) ) {
 42+ // RevisionDelete logs - revisions
 43+ if( LogEventsList::typeAction( $row, array('delete','suppress'), 'revision' ) ) {
 44+ $params = LogPage::extractParams( $row->log_params );
 45+ // Param format: <urlparam> <item CSV> [<ofield> <nfield>]
 46+ if( count($params) >= 2 ) {
 47+ $field = RevisionDeleter::getRelationType($params[0]);
 48+ $items = explode(',',$params[1]);
 49+ $log = new LogPage( $row->log_type );
 50+ $log->addRelations( $field, $items, $row->log_id );
 51+ }
 52+ // RevisionDelete logs - log events
 53+ } else if( LogEventsList::typeAction( $row, array('delete','suppress'), 'event' ) ) {
 54+ $params = LogPage::extractParams( $row->log_params );
 55+ // Param format: <item CSV> [<ofield> <nfield>]
 56+ if( count($params) >= 1 ) {
 57+ $items = explode(',',$params[0]);
 58+ $log = new LogPage( $row->log_type );
 59+ $log->addRelations( 'log_id', $items, $row->log_id );
 60+ }
 61+ }
 62+ }
 63+ $blockStart += BATCH_SIZE - 1;
 64+ $blockEnd += BATCH_SIZE - 1;
 65+ wfWaitForSlaves( 5 );
 66+ }
 67+ echo "...Done!\n";
 68+}
Property changes on: trunk/phase3/maintenance/populateLogSearch.php
___________________________________________________________________
Name: svn:eol-style
169 + native
Index: trunk/phase3/maintenance/tables.sql
@@ -1124,6 +1124,18 @@
11251125 CREATE INDEX /*i*/times ON /*_*/logging (log_timestamp);
11261126
11271127
 1128+CREATE TABLE /*_*/log_search (
 1129+ -- The type of ID (rev ID, log ID, rev timestamp, username)
 1130+ ls_field varbinary(32) NOT NULL,
 1131+ -- The value of the ID
 1132+ ls_value varchar(255) NOT NULL,
 1133+ -- Key to log_id
 1134+ ls_log_id int unsigned NOT NULL default 0,
 1135+ PRIMARY KEY (ls_field,ls_value,ls_log_id)
 1136+);
 1137+CREATE INDEX /*i*/ls_log_id ON /*_*/log_search (ls_log_id);
 1138+
 1139+
11281140 CREATE TABLE /*_*/trackbacks (
11291141 tb_id int PRIMARY KEY AUTO_INCREMENT,
11301142 tb_page int REFERENCES /*_*/page(page_id) ON DELETE CASCADE,
Index: trunk/phase3/includes/LogEventsList.php
@@ -651,22 +651,29 @@
652652 }
653653
654654 public function getQueryInfo() {
 655+ $tables = array( 'logging', 'user' );
655656 $this->mConds[] = 'user_id = log_user';
 657+ $index = array();
 658+ # Add log_search table if there are conditions on it
 659+ if( array_key_exists('ls_field',$this->mConds) ) {
 660+ $tables[] = 'log_search';
 661+ $index = array( 'log_search' => 'PRIMARY', 'logging' => 'PRIMARY' );
656662 # Don't use the wrong logging index
657 - if( $this->title || $this->pattern || $this->user ) {
658 - $index = array( 'USE INDEX' => array( 'logging' => array('page_time','user_time') ) );
 663+ } else if( $this->title || $this->pattern || $this->user ) {
 664+ $index = array( 'logging' => array('page_time','user_time') );
659665 } else if( $this->types ) {
660 - $index = array( 'USE INDEX' => array( 'logging' => 'type_time' ) );
 666+ $index = array( 'logging' => 'type_time' );
661667 } else {
662 - $index = array( 'USE INDEX' => array( 'logging' => 'times' ) );
 668+ $index = array( 'logging' => 'times' );
663669 }
664670 $info = array(
665 - 'tables' => array( 'logging', 'user' ),
 671+ 'tables' => $tables,
666672 'fields' => array( 'log_type', 'log_action', 'log_user', 'log_namespace', 'log_title', 'log_params',
667673 'log_comment', 'log_id', 'log_deleted', 'log_timestamp', 'user_name', 'user_editcount' ),
668674 'conds' => $this->mConds,
669 - 'options' => $index,
670 - 'join_conds' => array( 'user' => array( 'INNER JOIN', 'user_id=log_user' ) ),
 675+ 'options' => array( 'USE INDEX' => $index ),
 676+ 'join_conds' => array( 'user' => array( 'INNER JOIN', 'user_id=log_user' ),
 677+ 'log_search' => array( 'INNER JOIN', 'ls_log_id=log_id' ) ),
671678 );
672679
673680 ChangeTags::modifyDisplayQuery( $info['tables'], $info['fields'], $info['conds'],
Index: trunk/phase3/includes/specials/SpecialRevisiondelete.php
@@ -85,16 +85,15 @@
8686 $this->showImages();
8787 } else if( $this->deleteKey == 'logid' ) {
8888 $this->showLogItems();
89 - return; // no logs for now
9089 }
91 - list($qc,$lim) = $this->getLogQueryCond();
 90+ $qc = $this->getLogQueryCond();
9291 # Show relevant lines from the deletion log
9392 $wgOut->addHTML( "<h2>" . htmlspecialchars( LogPage::logName( 'delete' ) ) . "</h2>\n" );
94 - LogEventsList::showLogExtract( $wgOut, 'delete', $this->page->getPrefixedText(), '', $lim, $qc );
 93+ LogEventsList::showLogExtract( $wgOut, 'delete', $this->page->getPrefixedText(), '', 25, $qc );
9594 # Show relevant lines from the suppression log
9695 if( $wgUser->isAllowed( 'suppressionlog' ) ) {
9796 $wgOut->addHTML( "<h2>" . htmlspecialchars( LogPage::logName( 'suppress' ) ) . "</h2>\n" );
98 - LogEventsList::showLogExtract( $wgOut, 'suppress', $this->page->getPrefixedText(), '', $lim, $qc );
 97+ LogEventsList::showLogExtract( $wgOut, 'suppress', $this->page->getPrefixedText(), '', 25, $qc );
9998 }
10099 }
101100
@@ -121,9 +120,7 @@
122121 }
123122
124123 private function getLogQueryCond() {
125 - $ids = $safeIds = array();
126 - $limit = 25; // default
127 - $conds = array( 'log_action' => 'revision' ); // revision delete logs
 124+ $logAction = 'revision';
128125 switch( $this->deleteKey ) {
129126 case 'oldid':
130127 $ids = $this->oldids;
@@ -137,25 +134,19 @@
138135 case 'fileid':
139136 $ids = $this->fileids;
140137 break;
 138+ case 'logid':
 139+ $ids = $this->logids;
 140+ $logAction = 'event';
 141+ break;
141142 default: // bad type?
142 - return array($conds,$limit);
 143+ return array();
143144 }
144 - // Just get the whole log if there are a lot if items
145 - if( count($ids) > $limit )
146 - return array($conds,$limit);
147 - // Digit chars only
148 - foreach( $ids as $id ) {
149 - if( preg_match( '/^\d+$/', $id, $m ) ) {
150 - $safeIds[] = $m[0];
151 - }
152 - }
153 - // Format is <id1,id2,i3...>
154 - if( count($safeIds) ) {
155 - $conds[] = "log_params RLIKE '^{$this->deleteKey}.*(^|\n|,)(".implode('|',$safeIds).")(,|\n|$)'";
156 - } else {
157 - $conds = array('1=0');
158 - }
159 - return array($conds,$limit);
 145+ // Revision delete logs for these item
 146+ $conds = array( 'log_action' => $logAction );
 147+ $conds['ls_field'] = RevisionDeleter::getRelationType( $this->deleteKey );
 148+ $conds['ls_value'] = $ids;
 149+ $conds[] = 'log_id = ls_log_id';
 150+ return $conds;
160151 }
161152
162153 private function secureOperation() {
@@ -824,7 +815,7 @@
825816
826817 private function failure() {
827818 global $wgOut;
828 - $wgOut->setPagetitle( wfMsg( 'actioncomplete' ) );
 819+ $wgOut->setPagetitle( wfMsg( 'actionfailed' ) );
829820 $wrap = '<span class="error">$1</span>';
830821 if( $this->deleteKey == 'logid' ) {
831822 $this->showLogItems();
@@ -1540,18 +1531,41 @@
15411532 $param, $items = array() )
15421533 {
15431534 // Put things hidden from sysops in the oversight log
1544 - $logtype = ( ($nbitfield | $obitfield) & Revision::DELETED_RESTRICTED ) ?
 1535+ $logType = ( ($nbitfield | $obitfield) & Revision::DELETED_RESTRICTED ) ?
15451536 'suppress' : 'delete';
1546 - $log = new LogPage( $logtype );
 1537+ // Log deletions show with a difference action message
 1538+ $logAction = ( $param == 'logid' ) ? 'event' : 'revision';
 1539+ // Track what items changed here
15471540 $itemCSV = implode(',',$items);
1548 -
 1541+ // Add params for effected page and ids
15491542 if( $param == 'logid' ) {
15501543 $params = array( $itemCSV, "ofield={$obitfield}", "nfield={$nbitfield}" );
1551 - $log->addEntry( 'event', $title, $comment, $params );
15521544 } else {
1553 - // Add params for effected page and ids
15541545 $params = array( $param, $itemCSV, "ofield={$obitfield}", "nfield={$nbitfield}" );
1555 - $log->addEntry( 'revision', $title, $comment, $params );
15561546 }
 1547+ // Actually add the deletion log entry
 1548+ $log = new LogPage( $logType );
 1549+ $logid = $log->addEntry( $logAction, $title, $comment, $params );
 1550+ // Allow for easy searching of deletion log items for revision/log items
 1551+ $log->addRelations( self::getRelationType($param), $items, $logid );
15571552 }
1558 -}
 1553+
 1554+ // Get DB field name for URL param...
 1555+ // Future code for other things may also track
 1556+ // other types of revision-specific changes.
 1557+ public static function getRelationType( $param ) {
 1558+ switch( $param ) {
 1559+ case 'oldid':
 1560+ return 'rev_id';
 1561+ case 'artimestamp':
 1562+ return 'rev_timestamp';
 1563+ case 'oldimage':
 1564+ return 'oi_timestamp';
 1565+ case 'fileid':
 1566+ return 'file_id';
 1567+ case 'logid':
 1568+ return 'log_id';
 1569+ }
 1570+ throw new MWException( "Bad log URL param type!" );
 1571+ }
 1572+}
\ No newline at end of file
Index: trunk/phase3/includes/LogPage.php
@@ -91,7 +91,7 @@
9292 $this->type, $this->action, $this->target, $this->comment, $this->params, $newId );
9393 $rc->notifyRC2UDP();
9494 }
95 - return true;
 95+ return $newId;
9696 }
9797
9898 /**
@@ -373,6 +373,22 @@
374374
375375 return $this->saveContent();
376376 }
 377+
 378+ /**
 379+ * Add relations to log_search table
 380+ * @static
 381+ */
 382+ public function addRelations( $field, $values, $logid ) {
 383+ if( empty($values) )
 384+ return false; // nothing
 385+ $data = array();
 386+ foreach( $values as $value ) {
 387+ $data[] = array('ls_field' => $field,'ls_value' => $value,'ls_log_id' => $logid);
 388+ }
 389+ $dbw = wfGetDB( DB_MASTER );
 390+ $dbw->insert( 'log_search', $data, __METHOD__, 'IGNORE' );
 391+ return true;
 392+ }
377393
378394 /**
379395 * Create a blob from a parameter array

Follow-up revisions

RevisionCommit summaryAuthorDate
r50597Tweaks to r50567:...aaron19:49, 14 May 2009
r50608Cleanup for r50567:...brion22:43, 14 May 2009
r50625Follow-up r50567: also update PostgreSQL and SQLite schemaialex11:34, 15 May 2009
r55123Fix for CR comments on r51627: fix the log_search table if it was created bet...tstarling04:41, 16 August 2009

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r48839(bug 15814) Filter log chunk at Special:RevisionDelete to selected itemsaaron18:25, 25 March 2009

Comments

#Comment by Raymond (talk | contribs)   14:18, 14 May 2009

Schema change applied on translatewiki.net: successful

running populateLogSearch: failed

[...] ...doing log_id from 90982 to 91081 ...doing log_id from 91081 to 91180 Bad log URL param type! Backtrace:

  1. 0 /var/www/w/maintenance/populateLogSearch.php(46): RevisionDeleter::getRelationType('User:Siebrand/t...')
  2. 1 /var/www/w/maintenance/populateLogSearch.php(22): migrate_log_params(Object(DatabaseMysql))
  3. 2 {main}

Unclear at the moment who is the culprit.

#Comment by Aaron Schulz (talk | contribs)   19:49, 14 May 2009

Should be fixed in r50597

#Comment by Raymond (talk | contribs)   21:15, 14 May 2009

Confirmed for translatewiki. Thanks :)

#Comment by Brion VIBBER (talk | contribs)   23:08, 14 May 2009

I've followed up in r50609 to run the population in the updaters.

Status & tagging log