Untested fixup script, committing for test on wikimedia cluster.
authorTim Starling <tstarling@users.mediawiki.org>
Mon, 10 Apr 2006 07:21:40 +0000 (07:21 +0000)
committerTim Starling <tstarling@users.mediawiki.org>
Mon, 10 Apr 2006 07:21:40 +0000 (07:21 +0000)
maintenance/fixTimestamps.php [new file with mode: 0644]

diff --git a/maintenance/fixTimestamps.php b/maintenance/fixTimestamps.php
new file mode 100644 (file)
index 0000000..ef1c018
--- /dev/null
@@ -0,0 +1,93 @@
+<?php\r
+\r
+/**\r
+ * This script fixes timestamp corruption caused by one or more webservers \r
+ * temporarily being set to the wrong time. The time offset must be known and\r
+ * consistent. Start and end times (in 14-character format) restrict the search, \r
+ * and must bracket the damage. There must be a majority of good timestamps in the \r
+ * search period.\r
+ */\r
+\r
+require_once( 'commandLine.inc' );\r
+\r
+if ( count( $args ) < 3 ) {\r
+       echo "Usage: php fixTimestamps.php <offset in hours> <start time> <end time>\n";\r
+       exit(1);\r
+}\r
+\r
+$offset = $args[0] * 3600;\r
+$start = $args[1];\r
+$end = $args[2];\r
+$fname = 'fixTimestamps.php';\r
+$grace = 60; // maximum normal clock offset\r
+\r
+# Find bounding revision IDs\r
+$dbw =& wfGetDB( DB_MASTER );\r
+$revisionTable = $dbw->tableName( 'revision' );\r
+$res = $dbw->query( "SELECT MIN(rev_id) as minrev, MAX(rev_id) as maxrev FROM $revisionTable " .\r
+       "WHERE rev_timestamp BETWEEN $start AND $end", $fname );\r
+$row = $dbw->fetchObject( $res );\r
+$minRev = $row->minrev;\r
+$maxRev = $row->maxrev;\r
+\r
+# Select all timestamps and IDs\r
+$sql = "SELECT rev_id, rev_timestamp FROM $revisionTable " .\r
+       "WHERE rev_id BETWEEN $minRev AND $maxRev";\r
+if ( $offset > 0 ) {\r
+       $sql .= " ORDER BY rev_id DESC";\r
+       $expectedSign = -1;\r
+} else {\r
+       $expectedSign = 1;\r
+}\r
+\r
+$res = $dbw->query( $sql, $fname );\r
+\r
+$lastNormal = 0;\r
+$badRevs = array();\r
+$numGoodRevs = 0;\r
+\r
+while ( $row = $dbw->fetchObject( $res ) ) {\r
+       $timestamp = wfTimestamp( TS_UNIX, $row->rev_timestamp );\r
+       $delta = $timestamp - $lastNormal;\r
+       $sign = $delta / abs( $delta );\r
+       if ( $sign == $expectedSign ) {\r
+               // Monotonic change\r
+               $lastNormal = $timestamp;\r
+               ++ $numGoodRevs;\r
+               continue;\r
+       } elseif ( abs( $delta ) <= $grace ) {\r
+               // Non-monotonic change within grace interval\r
+               ++ $numGoodRevs;\r
+               continue;\r
+       } else {\r
+               // Non-monotonic change larger than grace interval\r
+               $badRevs[] = $row->rev_id;\r
+       }\r
+}\r
+$dbw->freeResult( $res );\r
+\r
+if ( count( $badRevs ) > $numGoodRevs ) {\r
+       echo \r
+"The majority of revisions in the search interval are marked as bad.\r
+\r
+Are you sure the offset ($offset) has the right sign? Positive means the clock \r
+was incorrectly set forward, negative means the clock was incorrectly set back.\r
+\r
+If the offset is right, then increase the search interval until there are enough \r
+good revisions to provide a majority reference.\r
+";\r
+\r
+       exit(1);\r
+}\r
+\r
+printf( "Fixing %d revisions (%.2f%% of revisions in search interval)\n", \r
+       count( $badRevs ), count($badRevs) / $numGoodRevs * 100 );\r
+\r
+$sql = "UPDATE $revisionTable " .\r
+       "SET rev_timestamp=DATE_FORMAT(DATE_ADD(rev_timestamp, INTERVAL $fixup SECOND), '%Y%m%d%H%i%s') " .\r
+       "WHERE rev_id IN (" . $dbw->makeList( $badRevs ) . ')';\r
+echo $sql;\r
+//$dbw->query( $sql, $fname );\r
+//echo "Done\n";\r
+\r
+?>\r