Go to the documentation of this file.
24 require_once __DIR__ .
'/Maintenance.php';
34 parent::__construct();
35 $this->mDescription =
"Sync one file backend with another using the journal";
36 $this->
addOption(
'src',
'Name of backend to sync from',
true,
true );
37 $this->
addOption(
'dst',
'Name of destination backend to sync',
false,
true );
38 $this->
addOption(
'start',
'Starting journal ID',
false,
true );
39 $this->
addOption(
'end',
'Ending journal ID',
false,
true );
40 $this->
addOption(
'posdir',
'Directory to read/record journal positions',
false,
true );
41 $this->
addOption(
'posdump',
'Just dump current journal position into the position dir.' );
42 $this->
addOption(
'postime',
'For position dumps, get the ID at this time',
false,
true );
43 $this->
addOption(
'backoff',
'Stop at entries younger than this age (sec).',
false,
true );
44 $this->
addOption(
'verbose',
'Verbose mode',
false,
false,
'v' );
52 $posFile = $posDir ? $posDir .
'/' .
wfWikiID() :
false;
57 $this->
error(
"Param posdir required!", 1 );
60 $id = (int)$src->getJournal()->getPositionAtTime( $this->
getOption(
'postime' ) );
61 $this->
output(
"Requested journal position is $id.\n" );
63 $id = (int)$src->getJournal()->getCurrentPosition();
64 $this->
output(
"Current journal position is $id.\n" );
66 if ( file_put_contents( $posFile, $id, LOCK_EX ) !==
false ) {
67 $this->
output(
"Saved journal position file.\n" );
69 $this->
output(
"Could not save journal position file.\n" );
78 $this->
error(
"Param dst required!", 1 );
83 if ( !$start && $posFile && is_dir( $posDir ) ) {
84 $start = is_file( $posFile )
85 ? (int)trim( file_get_contents( $posFile ) )
88 $startFromPosFile =
true;
90 $startFromPosFile =
false;
95 $end = (int)$src->getJournal()->getPositionAtTime(
$time );
100 $this->
output(
"Synchronizing backend '{$dst->getName()}' to '{$src->getName()}'...\n" );
101 $this->
output(
"Starting journal position is $start.\n" );
102 if ( is_finite( $end ) ) {
103 $this->
output(
"Ending journal position is $end.\n" );
107 $callback =
function( $pos ) use ( $startFromPosFile, $posFile, $start ) {
108 if ( $startFromPosFile && $pos >= $start ) {
109 file_put_contents( $posFile, $pos, LOCK_EX );
114 $lastOKPos = $this->
syncBackends( $src, $dst, $start, $end, $callback );
117 if ( $startFromPosFile && $lastOKPos >= $start ) {
118 if ( file_put_contents( $posFile, $lastOKPos, LOCK_EX ) !==
false ) {
119 $this->
output(
"Updated journal position file.\n" );
121 $this->
output(
"Could not update journal position file.\n" );
125 if ( $lastOKPos ===
false ) {
127 $this->
output(
"No journal entries found.\n" );
129 $this->
output(
"No new journal entries found.\n" );
132 $this->
output(
"Stopped synchronization at journal position $lastOKPos.\n" );
157 if ( $start > $end ) {
158 $this->
error(
"Error: given starting ID greater than ending ID.", 1 );
162 $limit = min( $this->mBatchSize, $end - $start + 1 );
163 $this->
output(
"Doing id $start to " . ( $start +
$limit - 1 ) .
"...\n" );
167 if ( $first && !count( $entries ) ) {
173 $pathsInBatch =
array();
174 foreach ( $entries
as $entry ) {
175 if ( $entry[
'op'] !==
'null' ) {
176 $pathsInBatch[$entry[
'path']] = 1;
178 $lastPosInBatch = $entry[
'id'];
181 $status = $this->
syncFileBatch( array_keys( $pathsInBatch ), $src, $dst );
182 if ( $status->isOK() ) {
183 $lastOKPos = max( $lastOKPos, $lastPosInBatch );
184 $callback( $lastOKPos );
186 $this->
error( print_r( $status->getErrorsArray(),
true ) );
191 $this->
output(
"End of journal entries.\n" );
193 }
while ( $start && $start <= $end );
208 if ( !count( $paths ) ) {
220 if ( !$status->isOK() ) {
229 foreach ( $sPaths
as $i => $sPath ) {
230 $dPath = $dPaths[$i];
231 $sExists = $src->
fileExists(
array(
'src' => $sPath,
'latest' => 1 ) );
232 if ( $sExists ===
true ) {
233 if ( $this->
filesAreSame( $src, $dst, $sPath, $dPath ) ) {
239 $this->
error(
"Unable to sync '$dPath': could not get local copy." );
240 $status->fatal(
'backend-fail-internal', $src->
getName() );
243 $fsFiles[] = $fsFile;
246 'dir' => dirname( $dPath ),
'bypassReadOnly' => 1 ) ) );
247 if ( !$status->isOK() ) {
250 $ops[] =
array(
'op' =>
'store',
251 'src' => $fsFile->getPath(),
'dst' => $dPath,
'overwrite' => 1 );
252 } elseif ( $sExists ===
false ) {
253 $ops[] =
array(
'op' =>
'delete',
'src' => $dPath,
'ignoreMissingSource' => 1 );
255 $this->
error(
"Unable to sync '$dPath': could not stat file." );
256 $status->fatal(
'backend-fail-internal', $src->
getName() );
261 $t_start = microtime(
true );
263 if ( !$status->isOK() ) {
267 $ellapsed_ms = floor( ( microtime(
true ) - $t_start ) * 1000 );
268 if ( $status->isOK() && $this->
getOption(
'verbose' ) ) {
269 $this->
output(
"Synchronized these file(s) [{$ellapsed_ms}ms]:\n" .
270 implode(
"\n", $dPaths ) .
"\n" );
284 '!^mwstore://([^/]+)!',
see documentation in includes Linker php for Linker::makeImageLink & $time
skin txt MediaWiki includes four core it has been set as the default in MediaWiki since the replacing Monobook it had been been the default skin since before being replaced by Vector largely rewritten in while keeping its appearance Several legacy skins were removed in the as the burden of supporting them became too heavy to bear Those in etc for skin dependent CSS etc for skin dependent JavaScript These can also be customised on a per user by etc This feature has led to a wide variety of user styles becoming that gallery is a good place to ending in php
preloadFileStat(array $params)
Preload file stat information (concurrently if possible) into in-process cache.
Base class for all file backend classes (including multi-write backends).
getName()
Get the unique backend name.
execute()
Do the actual work.
addOption( $name, $description, $required=false, $withArg=false, $shortName=false)
Add a parameter to the script.
static escapeRegexReplacement( $string)
Escape a string to make it suitable for inclusion in a preg_replace() replacement parameter.
static newGood( $value=null)
Factory function for good results.
require_once RUN_MAINTENANCE_IF_MAIN
Abstract maintenance class for quickly writing and churning out maintenance scripts with minimal effo...
Maintenance script that syncs one file backend to another based on the journal of later.
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return true
getScopedFileLocks(array $paths, $type, Status $status)
Lock the files at the given storage paths in the backend.
getFileSize(array $params)
Get the size (bytes) of a file at a storage path in the backend.
replaceNamePaths( $paths, FileBackend $backend)
Substitute the backend name of storage paths with that of a given one.
getFileSha1Base36(array $params)
Get a SHA-1 hash of the file at a storage path in the backend.
filesAreSame(FileBackend $src, FileBackend $dst, $sPath, $dPath)
the array() calling protocol came about after MediaWiki 1.4rc1.
List of Api Query prop modules.
syncFileBatch(array $paths, FileBackend $src, FileBackend $dst)
Sync particular files of backend $src to the corresponding $dst backend files.
wfWikiID()
Get an ASCII string identifying this wiki This is used as a prefix in memcached keys.
__construct()
Default constructor.
fileExists(array $params)
Check if a file exists at a storage path in the backend.
doQuickOperations(array $ops, array $opts=array())
Perform a set of independent file operations on some files.
prepare(array $params)
Prepare a storage directory for usage.
syncBackends(FileBackend $src, FileBackend $dst, $start, $end, Closure $callback)
Sync $dst backend to $src backend based on the $src logs given after $start.
getOption( $name, $default=null)
Get an option, or return the default.
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
error( $err, $die=0)
Throw an error to the user.
output( $out, $channel=null)
Throw some output to the user.
getJournal()
Get the file journal object for this backend.
getLocalReference(array $params)
Returns a file system file, identical to the file at a storage path.
hasOption( $name)
Checks to see if a particular param exists.
setBatchSize( $s=0)
Set the batch size.