public function unlockWiki() { global $wgCityId; if ($this->areUploadsDisabled) { WikiFactory::removeVarByName('wgEnableUploads', $wgCityId, self::REASON); WikiFactory::removeVarByName('wgUploadMaintenance', $wgCityId, self::REASON); $this->areUploadsDisabled = false; } }
public function execute() { global $wgCityId, $wgExternalSharedDB; // force migration of wikis with read-only mode if (wfReadOnly()) { global $wgReadOnly; $wgReadOnly = false; } $this->init(); $dbr = $this->getDB(DB_SLAVE); $isForced = $this->hasOption('force'); $isDryRun = $this->hasOption('dry-run'); // one migration is enough global $wgEnableSwiftFileBackend, $wgEnableUploads, $wgDBname; if (!empty($wgEnableSwiftFileBackend) && !$isForced) { $this->error("\$wgEnableSwiftFileBackend = true - new files storage already enabled on {$wgDBname} wiki!", 1); } if (empty($wgEnableUploads) && !$isForced) { $this->error("\$wgEnableUploads = false - migration is already running on {$wgDBname} wiki!", 1); } // get images count $tables = ['filearchive' => 'fa_size', 'image' => 'img_size', 'oldimage' => 'oi_size']; foreach ($tables as $table => $sizeField) { $row = $dbr->selectRow($table, ['count(*) AS cnt', "SUM({$sizeField}) AS size"], [], __METHOD__); $this->output(sprintf("* %s:\t%d images (%d MB)\n", $table, $row->cnt, round($row->size / 1024 / 1024))); $this->imagesCnt += $row->cnt; $this->imagesSize += $row->size; } $this->output(sprintf("\n%d image(s) (%d MB) will be migrated (should take ~ %s with %d kB/s / ~ %s with %d files/sec)...\n", $this->imagesCnt, round($this->imagesSize / 1024 / 1024), Wikia::timeDuration($this->imagesSize / 1024 / self::KB_PER_SEC), self::KB_PER_SEC, Wikia::timeDuration($this->imagesCnt / self::FILES_PER_SEC), self::FILES_PER_SEC)); if ($this->hasOption('stats-only')) { return; } // ok, so let's start... $this->time = time(); self::log(__CLASS__, 'migration started', self::LOG_MIGRATION_PROGRESS); // wait a bit to prevent deadlocks (from 0 to 2 sec) usleep(mt_rand(0, 2000) * 1000); // lock the wiki $dbw = $this->getDB(DB_MASTER, array(), $wgExternalSharedDB); if (!$isDryRun) { $dbw->replace('city_image_migrate', ['city_id'], ['city_id' => $wgCityId, 'locked' => 1], __CLASS__); } // block uploads via WikiFactory if (!$isDryRun) { WikiFactory::setVarByName('wgEnableUploads', $wgCityId, false, self::REASON); WikiFactory::setVarByName('wgUploadMaintenance', $wgCityId, true, self::REASON); $this->output("Uploads and image operations disabled\n\n"); } else { $this->output("Performing dry run...\n\n"); } // prepare the list of files to migrate to new storage // (a) current revisions of images // @see http://www.mediawiki.org/wiki/Image_table $this->output("\nA) Current revisions of images - /images\n"); $res = $dbr->select('image', ['img_name AS name', 'img_size AS size', 'img_sha1 AS hash', 'img_major_mime AS major_mime', 'img_minor_mime AS minor_mime']); while ($row = $res->fetchRow()) { $path = $this->getImagePath($row); $this->copyFile($path, $row); } // (b) old revisions of images // @see http://www.mediawiki.org/wiki/Oldimage_table $this->output("\nB) Old revisions of images - /archive\n"); $res = $dbr->select('oldimage', ['oi_name AS name', 'oi_archive_name AS archived_name', 'oi_size AS size', 'oi_sha1 AS hash', 'oi_major_mime AS major_mime', 'oi_minor_mime AS minor_mime']); while ($row = $res->fetchRow()) { $path = $this->getOldImagePath($row); $this->copyFile($path, $row); } // (c) deleted images // @see http://www.mediawiki.org/wiki/Filearchive_table $this->output("\nC) Deleted images - /deleted\n"); $res = $dbr->select('filearchive', ['fa_name AS name', 'fa_storage_key AS storage_key', 'fa_size AS size', 'fa_major_mime AS major_mime', 'fa_minor_mime AS minor_mime']); while ($row = $res->fetchRow()) { $path = $this->getRemovedImagePath($row); $this->copyFile($path, $row); } // stats per DC $statsPerDC = []; foreach ($this->timePerDC as $dc => $time) { $statsPerDC[] = sprintf("%s took %s", $dc, Wikia::timeDuration(round($time))); } // summary $totalTime = time() - $this->time; $report = sprintf('Migrated %d files (%d MB) with %d fails in %s (%.2f files/sec, %.2f kB/s) - DCs: %s', $this->migratedImagesCnt, round($this->migratedImagesSize / 1024 / 1024), $this->migratedImagesFailedCnt, Wikia::timeDuration($totalTime), floor($this->imagesCnt) / (time() - $this->time), $this->migratedImagesSize / 1024 / (time() - $this->time), join(', ', $statsPerDC)); $this->output("\n{$report}\n"); self::log(__CLASS__, 'migration completed - ' . $report, self::LOG_MIGRATION_PROGRESS); // if running in --dry-run, leave now if ($isDryRun) { $this->output("\nDry run completed!\n"); return; } // unlock the wiki $dbw->ping(); $dbw->replace('city_image_migrate', ['city_id'], ['city_id' => $wgCityId, 'locked' => 0], __CLASS__); // update wiki configuration // enable Swift storage via WikiFactory WikiFactory::setVarByName('wgEnableSwiftFileBackend', $wgCityId, true, sprintf('%s - migration took %s', self::REASON, Wikia::timeDuration($totalTime))); $this->output("\nNew storage enabled\n"); // too short bucket name fix if ($this->shortBucketNameFixed) { global $wgUploadPath, $wgUploadDirectory, $wgUploadDirectoryNFS; WikiFactory::setVarByName('wgUploadPath', $wgCityId, $wgUploadPath, self::REASON); WikiFactory::setVarByName('wgUploadDirectory', $wgCityId, $wgUploadDirectory, self::REASON); WikiFactory::setVarByName('wgUploadDirectoryNFS', $wgCityId, $wgUploadDirectoryNFS, self::REASON); $this->output("\nNew upload directory set up\n"); } // enable uploads via WikiFactory // wgEnableUploads = true / wgUploadMaintenance = false (remove values from WF to give them the default value) WikiFactory::removeVarByName('wgEnableUploads', $wgCityId, self::REASON); WikiFactory::removeVarByName('wgUploadMaintenance', $wgCityId, self::REASON); $this->output("\nUploads and image operations enabled\n"); $this->output("\nDone!\n"); }
function removeVisualEditorExt($id) { WikiFactory::removeVarByName('wgEnableVisualEditorExt', $id); WikiFactory::clearCache($id); }