]> scripts.mit.edu Git - autoinstalls/mediawiki.git/blob - maintenance/archives/upgradeLogging.php
MediaWiki 1.17.0
[autoinstalls/mediawiki.git] / maintenance / archives / upgradeLogging.php
1 <?php
2 /**
3  * Replication-safe online upgrade script for log_id/log_deleted
4  *
5  * @file
6  * @ingroup MaintenanceArchive
7  */
8
9 require( dirname( __FILE__ ) . '/../commandLine.inc' );
10
11 class UpdateLogging {
12         var $dbw;
13         var $batchSize = 1000;
14         var $minTs = false;
15
16         function execute() {
17                 $this->dbw = wfGetDB( DB_MASTER );
18                 $logging = $this->dbw->tableName( 'logging' );
19                 $logging_1_10 = $this->dbw->tableName( 'logging_1_10' );
20                 $logging_pre_1_10 = $this->dbw->tableName( 'logging_pre_1_10' );
21
22                 if ( $this->dbw->tableExists( 'logging_pre_1_10' ) && !$this->dbw->tableExists( 'logging' ) ) {
23                         # Fix previous aborted run
24                         echo "Cleaning up from previous aborted run\n";
25                         $this->dbw->query( "RENAME TABLE $logging_pre_1_10 TO $logging", __METHOD__ );
26                 }
27
28                 if ( $this->dbw->tableExists( 'logging_pre_1_10' ) ) {
29                         echo "This script has already been run to completion\n";
30                         return;
31                 }
32
33                 # Create the target table
34                 if ( !$this->dbw->tableExists( 'logging_1_10' ) ) {
35                         global $wgDBTableOptions;
36
37                         $sql = <<<EOT
38 CREATE TABLE $logging_1_10 (
39   -- Log ID, for referring to this specific log entry, probably for deletion and such.
40   log_id int unsigned NOT NULL auto_increment,
41
42   -- Symbolic keys for the general log type and the action type
43   -- within the log. The output format will be controlled by the
44   -- action field, but only the type controls categorization.
45   log_type varbinary(10) NOT NULL default '',
46   log_action varbinary(10) NOT NULL default '',
47   
48   -- Timestamp. Duh.
49   log_timestamp binary(14) NOT NULL default '19700101000000',
50   
51   -- The user who performed this action; key to user_id
52   log_user int unsigned NOT NULL default 0,
53   
54   -- Key to the page affected. Where a user is the target,
55   -- this will point to the user page.
56   log_namespace int NOT NULL default 0,
57   log_title varchar(255) binary NOT NULL default '',
58   
59   -- Freeform text. Interpreted as edit history comments.
60   log_comment varchar(255) NOT NULL default '',
61   
62   -- LF separated list of miscellaneous parameters
63   log_params blob NOT NULL,
64
65   -- rev_deleted for logs
66   log_deleted tinyint unsigned NOT NULL default '0',
67
68   PRIMARY KEY log_id (log_id),
69   KEY type_time (log_type, log_timestamp),
70   KEY user_time (log_user, log_timestamp),
71   KEY page_time (log_namespace, log_title, log_timestamp),
72   KEY times (log_timestamp)
73
74 ) $wgDBTableOptions
75 EOT;
76                         echo "Creating table logging_1_10\n";
77                         $this->dbw->query( $sql, __METHOD__ );
78                 }
79
80                 # Synchronise the tables
81                 echo "Doing initial sync...\n";
82                 $this->sync( 'logging', 'logging_1_10' );
83                 echo "Sync done\n\n";
84
85                 # Rename the old table away
86                 echo "Renaming the old table to $logging_pre_1_10\n";
87                 $this->dbw->query( "RENAME TABLE $logging TO $logging_pre_1_10", __METHOD__ );
88
89                 # Copy remaining old rows
90                 # Done before the new table is active so that $copyPos is accurate
91                 echo "Doing final sync...\n";
92                 $this->sync( 'logging_pre_1_10', 'logging_1_10' );
93
94                 # Move the new table in
95                 echo "Moving the new table in...\n";
96                 $this->dbw->query( "RENAME TABLE $logging_1_10 TO $logging", __METHOD__ );
97                 echo "Finished.\n";
98         }
99
100         /**
101          * Copy all rows from $srcTable to $dstTable
102          */
103         function sync( $srcTable, $dstTable ) {
104                 $batchSize = 1000;
105                 $minTs = $this->dbw->selectField( $srcTable, 'MIN(log_timestamp)', false, __METHOD__ );
106                 $minTsUnix = wfTimestamp( TS_UNIX, $minTs );
107                 $numRowsCopied = 0;
108                 
109                 while ( true ) {
110                         $maxTs = $this->dbw->selectField( $srcTable, 'MAX(log_timestamp)', false, __METHOD__ );
111                         $copyPos = $this->dbw->selectField( $dstTable, 'MAX(log_timestamp)', false, __METHOD__ );
112                         $maxTsUnix = wfTimestamp( TS_UNIX, $maxTs );
113                         $copyPosUnix = wfTimestamp( TS_UNIX, $copyPos );
114
115                         if ( $copyPos === null ) {
116                                 $percent = 0;
117                         } else {
118                                 $percent = ( $copyPosUnix - $minTsUnix ) / ( $maxTsUnix - $minTsUnix ) * 100;
119                         }
120                         printf( "%s  %.2f%%\n", $copyPos, $percent );
121                         
122                         # Handle all entries with timestamp equal to $copyPos
123                         if ( $copyPos !== null ) {
124                                 $numRowsCopied += $this->copyExactMatch( $srcTable, $dstTable, $copyPos );
125                         }
126
127                         # Now copy a batch of rows
128                         if ( $copyPos === null ) {
129                                 $conds = false;
130                         } else {
131                                 $conds = array( 'log_timestamp > ' . $this->dbw->addQuotes( $copyPos ) );
132                         }
133                         $srcRes = $this->dbw->select( $srcTable, '*', $conds, __METHOD__,
134                                 array( 'LIMIT' => $batchSize, 'ORDER BY' => 'log_timestamp' ) );
135
136                         if ( ! $srcRes->numRows() ) {
137                                 # All done
138                                 break;
139                         }
140
141                         $batch = array();
142                         foreach ( $srcRes as $srcRow ) {
143                                 $batch[] = (array)$srcRow;
144                         }
145                         $this->dbw->insert( $dstTable, $batch, __METHOD__ );
146                         $numRowsCopied += count( $batch );
147
148                         wfWaitForSlaves( 5 );
149                 }
150                 echo "Copied $numRowsCopied rows\n";
151         }
152
153         function copyExactMatch( $srcTable, $dstTable, $copyPos ) {
154                 $numRowsCopied = 0;
155                 $srcRes = $this->dbw->select( $srcTable, '*', array( 'log_timestamp' => $copyPos ), __METHOD__ );
156                 $dstRes = $this->dbw->select( $dstTable, '*', array( 'log_timestamp' => $copyPos ), __METHOD__ );
157
158                 if ( $srcRes->numRows() ) {
159                         $srcRow = $srcRes->fetchObject();
160                         $srcFields = array_keys( (array)$srcRow );
161                         $srcRes->seek( 0 );
162                         $dstRowsSeen = array();
163
164                         # Make a hashtable of rows that already exist in the destination
165                         foreach ( $dstRes as $dstRow ) {
166                                 $reducedDstRow = array();
167                                 foreach ( $srcFields as $field ) {
168                                         $reducedDstRow[$field] = $dstRow->$field;
169                                 }
170                                 $hash = md5( serialize( $reducedDstRow ) );
171                                 $dstRowsSeen[$hash] = true;
172                         }
173
174                         # Copy all the source rows that aren't already in the destination
175                         foreach ( $srcRes as $srcRow ) {
176                                 $hash = md5( serialize( (array)$srcRow ) );
177                                 if ( !isset( $dstRowsSeen[$hash] ) ) {
178                                         $this->dbw->insert( $dstTable, (array)$srcRow, __METHOD__ );
179                                         $numRowsCopied++;
180                                 }
181                         }
182                 }
183                 return $numRowsCopied;
184         }
185 }
186
187 $ul = new UpdateLogging;
188 $ul->execute();
189