00001 <?php
00027 require_once( dirname(__FILE__) . '/Maintenance.php' );
00028
00029 class FixTimestamps extends Maintenance {
00030 public function __construct() {
00031 parent::__construct();
00032 $this->mDescription = "";
00033 $this->addArg( 'offset', '' );
00034 $this->addArg( 'start', 'Starting timestamp' );
00035 $this->addArg( 'end', 'Ending timestamp' );
00036 }
00037
00038 public function execute() {
00039 $offset = $this->getArg(0) * 3600;
00040 $start = $this->getArg(1);
00041 $end = $this->getArg(2);
00042 $grace = 60;
00043
00044 # Find bounding revision IDs
00045 $dbw = wfGetDB( DB_MASTER );
00046 $revisionTable = $dbw->tableName( 'revision' );
00047 $res = $dbw->query( "SELECT MIN(rev_id) as minrev, MAX(rev_id) as maxrev FROM $revisionTable " .
00048 "WHERE rev_timestamp BETWEEN '{$start}' AND '{$end}'", __METHOD__ );
00049 $row = $dbw->fetchObject( $res );
00050
00051 if ( is_null( $row->minrev ) ) {
00052 $this->error( "No revisions in search period.", true );
00053 }
00054
00055 $minRev = $row->minrev;
00056 $maxRev = $row->maxrev;
00057
00058 # Select all timestamps and IDs
00059 $sql = "SELECT rev_id, rev_timestamp FROM $revisionTable " .
00060 "WHERE rev_id BETWEEN $minRev AND $maxRev";
00061 if ( $offset > 0 ) {
00062 $sql .= " ORDER BY rev_id DESC";
00063 $expectedSign = -1;
00064 } else {
00065 $expectedSign = 1;
00066 }
00067
00068 $res = $dbw->query( $sql, __METHOD__ );
00069
00070 $lastNormal = 0;
00071 $badRevs = array();
00072 $numGoodRevs = 0;
00073
00074 foreach ( $res as $row ) {
00075 $timestamp = wfTimestamp( TS_UNIX, $row->rev_timestamp );
00076 $delta = $timestamp - $lastNormal;
00077 $sign = $delta == 0 ? 0 : $delta / abs( $delta );
00078 if ( $sign == 0 || $sign == $expectedSign ) {
00079
00080 $lastNormal = $timestamp;
00081 ++ $numGoodRevs;
00082 continue;
00083 } elseif ( abs( $delta ) <= $grace ) {
00084
00085 ++ $numGoodRevs;
00086 continue;
00087 } else {
00088
00089 $badRevs[] = $row->rev_id;
00090 }
00091 }
00092 $dbw->freeResult( $res );
00093
00094 $numBadRevs = count( $badRevs );
00095 if ( $numBadRevs > $numGoodRevs ) {
00096 $this->error(
00097 "The majority of revisions in the search interval are marked as bad.
00098
00099 Are you sure the offset ($offset) has the right sign? Positive means the clock
00100 was incorrectly set forward, negative means the clock was incorrectly set back.
00101
00102 If the offset is right, then increase the search interval until there are enough
00103 good revisions to provide a majority reference.", true );
00104 } elseif ( $numBadRevs == 0 ) {
00105 $this->output( "No bad revisions found.\n" );
00106 exit(0);
00107 }
00108
00109 $this->output( sprintf( "Fixing %d revisions (%.2f%% of revisions in search interval)\n",
00110 $numBadRevs, $numBadRevs / ($numGoodRevs + $numBadRevs) * 100 ) );
00111
00112 $fixup = -$offset;
00113 $sql = "UPDATE $revisionTable " .
00114 "SET rev_timestamp=DATE_FORMAT(DATE_ADD(rev_timestamp, INTERVAL $fixup SECOND), '%Y%m%d%H%i%s') " .
00115 "WHERE rev_id IN (" . $dbw->makeList( $badRevs ) . ')';
00116 $dbw->query( $sql, __METHOD__ );
00117 $this->output( "Done\n" );
00118 }
00119 }
00120
00121 $maintClass = "FixTimestamps";
00122 require_once( DO_MAINTENANCE );