'JobQueueGroup' => 'includes/jobqueue/JobQueueGroup.php',
'JobQueueFederated' => 'includes/jobqueue/JobQueueFederated.php',
'JobQueueRedis' => 'includes/jobqueue/JobQueueRedis.php',
+ 'JobRunner' => 'includes/jobqueue/JobRunner.php',
'JobSpecification' => 'includes/jobqueue/JobSpecification.php',
# includes/jobqueue/jobs
class BadTitleError extends ErrorPageError {
/**
* @param string|Message $msg A message key (default: 'badtitletext')
- * @param array $params parameter to wfMessage()
+ * @param array $params Parameter to wfMessage()
*/
public function __construct( $msg = 'badtitletext', $params = array() ) {
parent::__construct( 'badtitle', $msg, $params );
*
* @param string|Message $title Message key (string) for page title, or a Message object
* @param string|Message $msg Message key (string) for error text, or a Message object
- * @param array $params with parameters to wfMessage()
+ * @param array $params Array with parameters to wfMessage()
*/
public function __construct( $title, $msg, $params = array() ) {
$this->title = $title;
* itself. It also fails-over to the next possible clusters
* as provided in the first parameter.
*
- * @param array $tryStores refer to $wgDefaultExternalStore
+ * @param array $tryStores Refer to $wgDefaultExternalStore
* @param string $data
* @param array $params Associative array of ExternalStoreMedium parameters
* @return string|bool The URL of the stored data item, or false on error
/**
* Get an associative array containing information about a file in the local filesystem.
*
- * @param string $path absolute local filesystem path
+ * @param string $path Absolute local filesystem path
* @param mixed $ext The file extension, or true to extract it from the filename.
* Set it to false to ignore the extension.
* @return array
protected $params = array();
/**
- * @param string $dir file system directory
+ * @param string $dir File system directory
* @param array $params
*/
public function __construct( $dir, array $params ) {
/**
* Return an appropriate iterator object to wrap
*
- * @param string $dir file system directory
+ * @param string $dir File system directory
* @return Iterator
*/
protected function initIterator( $dir ) {
* @param string $storagePath
* @param string|null $content File data
* @param string|null $fsPath File system path
- * @return MIME type
+ * @return string MIME type
*/
protected function getContentType( $storagePath, $content, $fsPath ) {
return call_user_func_array( $this->mimeCallback, func_get_args() );
*
* @param string $container Resolved container name
* @param string $dir Resolved path relative to container
- * @param string $after null
+ * @param string $after
* @param int $limit
* @param array $params
* @return Traversable|array
/**
* Get the position ID of the latest journal entry at some point in time
*
- * @param int|string $time timestamp
+ * @param int|string $time Timestamp
* @return int|bool
*/
final public function getPositionAtTime( $time ) {
/**
* @see FileJournal::doGetPositionAtTime()
- * @param int|string $time timestamp
+ * @param int|string $time Timestamp
* @return int|bool
*/
protected function doGetPositionAtTime( $time ) {
protected $domain; // string; domain (usually wiki ID)
- /** @var array of (name => ('class' => ..., 'config' => ..., 'instance' => ...)) */
+ /** @var array Array of (name => ('class' => ..., 'config' => ..., 'instance' => ...)) */
protected $managers = array();
/**
/** @var array (server name => bool) */
protected $serversUp = array();
- /** @var string random UUID */
+ /** @var string Random UUID */
protected $session = '';
/**
/** @var array Map server names to hostname/IP and port numbers */
protected $lockServers = array();
- /** @var string random UUID */
+ /** @var string Random UUID */
protected $session = '';
/**
* Returns a FileRepoStatus object with the file Virtual URL in the value,
* file can later be disposed using FileRepo::freeTemp().
*
- * @param string $originalName the base name of the file as specified
+ * @param string $originalName The base name of the file as specified
* by the user. The file extension will be maintained.
* @param string $srcPath The current location of the file.
* @return FileRepoStatus Object with the URL in the value.
* Get an array or iterator of file objects for files that have a given
* SHA-1 content hash.
*
- * @param string $hash a sha1 hash to look for
+ * @param string $hash A sha1 hash to look for
* @return array
*/
function findBySha1( $hash ) {
/**
* Find all instances of files with this key
*
- * @param string $hash base 36 SHA-1 hash
+ * @param string $hash Base 36 SHA-1 hash
* @return array Array of File objects
*/
function findBySha1( $hash ) {
/**
* Find all instances of files with this keys
*
- * @param array $hashes base 36 SHA-1 hashes
+ * @param array $hashes Base 36 SHA-1 hashes
* @return array Array of array of File objects
*/
function findBySha1s( array $hashes ) {
* Split a virtual URL into repo, zone and rel parts
* @param string $url
* @throws MWException
- * @return array containing repo, zone and rel
+ * @return array Containing repo, zone and rel
*/
function splitVirtualUrl( $url ) {
if ( substr( $url, 0, 9 ) != 'mwrepo://' ) {
* @ingroup FileAbstraction
*/
class ArchivedFile {
- /** @var int filearchive row ID */
+ /** @var int Filearchive row ID */
private $id;
/** @var string File name */
/** @var int File size in bytes */
private $size;
- /** @var int size in bytes */
+ /** @var int Size in bytes */
private $bits;
/** @var int Width */
/** @var string Relative path including trailing slash */
protected $hashPath;
- /** @var string number of pages of a multipage document, or false for
+ /** @var string Number of pages of a multipage document, or false for
* documents which aren't multipage documents
*/
protected $pageCount;
*
* Currently used to add a warning to the image description page
*
- * @return bool false if the main image is both animated
+ * @return bool False if the main image is both animated
* and the thumbnail is not. In all other cases must return
* true. If image is not renderable whatsoever, should
* return true.
/**
* Returns the most appropriate source image for the thumbnail, given a target thumbnail size
* @param array $params
- * @return array source path and width/height of the source
+ * @return array Source path and width/height of the source
*/
public function getThumbnailSource( $params ) {
if ( $this->repo
*
* @param string $zone Name of requested zone
* @param bool|string $suffix If not false, the name of a file in zone
- * @return string path
+ * @return string Path
*/
function getZoneUrl( $zone, $suffix = false ) {
$this->assertRepoDefined();
* Get the URL of the thumbnail directory, or a particular file if $suffix is specified
*
* @param bool|string $suffix If not false, the name of a thumbnail file
- * @return string path
+ * @return string Path
*/
function getThumbUrl( $suffix = false ) {
return $this->getZoneUrl( 'thumb', $suffix );
* Get the URL of the transcoded directory, or a particular file if $suffix is specified
*
* @param bool|string $suffix If not false, the name of a media file
- * @return string path
+ * @return string Path
*/
function getTranscodedUrl( $suffix = false ) {
return $this->getZoneUrl( 'transcoded', $suffix );
* @param int $flags A bitwise combination of:
* File::DELETE_SOURCE Delete the source file, i.e. move rather than copy
* @param array $options Optional additional parameters
- * @return FileRepoStatus object. On success, the value member contains the
+ * @return FileRepoStatus On success, the value member contains the
* archive name, or an empty string if it was a new file.
*
* STUB
/** @var bool Does the file exist on disk? (loadFromXxx) */
protected $fileExists;
- /** @var int image width */
+ /** @var int Image width */
protected $width;
- /** @var int image height */
+ /** @var int Image height */
protected $height;
/** @var int Returned by getimagesize (loadFromXxx) */
* Create a LocalFile from a SHA-1 key
* Do not call this except from inside a repo class.
*
- * @param string $sha1 base-36 SHA-1
+ * @param string $sha1 Base-36 SHA-1
* @param LocalRepo $repo
* @param string|bool $timestamp MW_timestamp (optional)
* @return bool|LocalFile
/**
* @param DatabaseBase $dbr
* @param string $fname
- * @return array|false
+ * @return array|bool
*/
private function loadFieldsWithTimestamp( $dbr, $fname ) {
$fieldMap = false;
/**
* Get all thumbnail names previously generated for this file
* @param string|bool $archiveName Name of an archive file, default false
- * @return array first element is the base dir, then files in that base dir.
+ * @return array First element is the base dir, then files in that base dir.
*/
function getThumbnails( $archiveName = false ) {
if ( $archiveName ) {
* Start a transaction and lock the image for update
* Increments a reference counter if the lock is already held
* @throws MWException Throws an error if the lock was not acquired
- * @return bool success
+ * @return bool Success
*/
function lock() {
$dbw = $this->repo->getMasterDB();
* Create a OldLocalFile from a SHA-1 key
* Do not call this except from inside a repo class.
*
- * @param string $sha1 base-36 SHA-1
+ * @param string $sha1 Base-36 SHA-1
* @param LocalRepo $repo
* @param string|bool $timestamp MW_timestamp (optional)
*
* @param Title $title
* @param FileRepo $repo
* @param string $time Timestamp or null to load by archive name
- * @param string $archiveName archive name or null to load by timestamp
+ * @param string $archiveName Archive name or null to load by timestamp
* @throws MWException
*/
function __construct( $title, $repo, $time, $archiveName ) {
}
/**
- * @param MediaTransformOutput|bool $thumb the thumbnail, or false if no
+ * @param MediaTransformOutput|bool $thumb The thumbnail, or false if no
* thumb (which can happen)
* @return float
*/
* @param array $descriptor Input Descriptor, as described above
*
* @throws MWException
- * @return HTMLFormField subclass
+ * @return HTMLFormField Instance of a subclass of HTMLFormField
*/
public static function loadInputFromParameters( $fieldname, $descriptor ) {
$class = self::getClassFromDescriptor( $fieldname, $descriptor );
/**
* Add footer text, inside the form.
*
- * @param string $msg complete text of message to display
+ * @param string $msg Complete text of message to display
* @param string|null $section The section to add the footer text to
*
* @return HTMLForm $this for chaining calls (since 1.20)
* Only useful when the method is "post".
*
* @since 1.24
- * @param string|array Salt to use
- * @return HTMLForm $this for chaining calls
+ * @param string|array $salt Salt to use
+ * @return HTMLForm $this For chaining calls
*/
public function setTokenSalt( $salt ) {
$this->mTokenSalt = $salt;
*
* @param bool|string|array|Status $submitResult Output from HTMLForm::trySubmit()
*
- * @return Nothing, should be last call
+ * @return void Nothing, should be last call
*/
function displayForm( $submitResult ) {
$this->getOutput()->addHTML( $this->getHTML( $submitResult ) );
/**
* Format a stack of error messages into a single HTML string
*
- * @param array $errors of message keys/values
+ * @param array $errors Array of message keys/values
*
* @return string HTML, a "<ul>" list of errors
*/
/**
* Set the text for the submit button
*
- * @param string $t plaintext.
+ * @param string $t Plaintext
*
* @return HTMLForm $this for chaining calls (since 1.20)
*/
*
* @param array $data
*
- * @return
+ * @return array
*/
function filterDataForSubmit( $data ) {
return $data;
* the input object itself. It should not implement the surrounding
* table cells/rows, or labels/help messages.
*
- * @param string $value the value to set the input to; eg a default
+ * @param string $value The value to set the input to; eg a default
* text for a text input.
*
* @return string Valid HTML.
*
* @param array $alldata
* @param array $params
- * @return boolean
+ * @return bool
*/
protected function isHiddenRecurse( array $alldata, array $params ) {
$origParams = $params;
* @param string|array $value The value the field was submitted with
* @param array $alldata The data collected from the form
*
- * @return bool true to cancel the submission
+ * @return bool True to cancel the submission
*/
function cancelSubmit( $value, $alldata ) {
return false;
* @param string|array $value The value the field was submitted with
* @param array $alldata The data collected from the form
*
- * @return bool|string true on success, or String error to display, or
+ * @return bool|string True on success, or String error to display, or
* false to fail validation without displaying an error.
*/
function validate( $value, $alldata ) {
*
* Used only by environment checks.
*
- * @param string $path path to search
- * @param array $names of executable names
+ * @param string $path Path to search
+ * @param array $names Array of executable names
* @param array|bool $versionInfo False or array with two members:
* 0 => Command to run for version check, with $1 for the full executable name
* 1 => String to compare the output with
/**
* Main entry point.
*
- * @param array[] $session initial session array
+ * @param array[] $session Initial session array
*
* @return array[] New session array
*/
/**
* Get the starting tags of a fieldset.
*
- * @param string $legend message name
+ * @param string $legend Message name
*
* @return string
*/
*/
protected $mWikiID;
- /** @var bool whether the wiki is in this project */
+ /** @var bool Whether the wiki is in this project */
protected $mLocal;
/** @var bool Whether interwiki transclusions are allowed */
* @note More logic is explained in DefaultSettings.
*
* @param string $prefix Interwiki prefix
- * @return Interwiki object
+ * @return Interwiki
*/
protected static function getInterwikiCached( $prefix ) {
$value = self::getInterwikiCacheEntry( $prefix );
/**
* Insert a single job into the queue.
- * @return bool true on success
+ * @return bool True on success
* @deprecated since 1.21
*/
public function insert() {
--- /dev/null
+<?php
+/**
+ * Job queue runner utility methods
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup JobQueue
+ */
+
+/**
+ * Job queue runner utility methods
+ *
+ * @ingroup JobQueue
+ * @since 1.24
+ */
+class JobRunner {
+ /** @var callable|null Debug output handler */
+ protected $debug;
+
+ /**
+ * @param callable $debug Optional debug output handler
+ */
+ public function setDebugHandler( $debug ) {
+ $this->debug = $debug;
+ }
+
+ /**
+ * Run jobs of the specified number/type for the specified time
+ *
+ * The response map has a 'job' field that lists status of each job, including:
+ * - type : the job type
+ * - status : ok/failed
+ * - error : any error message string
+ * - time : the job run time in ms
+ * The response map also has:
+ * - backoffs : the (job type => seconds) map of backoff times
+ * - elapsed : the total time spent running tasks in ms
+ * - reached : the reason the script finished, one of (none-ready, job-limit, time-limit)
+ *
+ * @param array $options
+ * @return array Summary response that can easily be JSON serialized
+ */
+ public function run( array $options ) {
+ $response = array( 'jobs' => array(), 'reached' => 'none-ready' );
+
+ $type = isset( $options['type'] ) ? $options['type'] : false;
+ $maxJobs = isset( $options['maxJobs'] ) ? $options['maxJobs'] : false;
+ $maxTime = isset( $options['maxTime'] ) ? $options['maxTime'] : false;
+ $noThrottle = isset( $options['throttle'] ) && !$options['throttle'];
+
+ $group = JobQueueGroup::singleton();
+ // Handle any required periodic queue maintenance
+ $count = $group->executeReadyPeriodicTasks();
+ if ( $count > 0 ) {
+ $this->runJobsLog( "Executed $count periodic queue task(s)." );
+ }
+
+ // Flush any pending DB writes for sanity
+ wfGetLBFactory()->commitMasterChanges();
+
+ $backoffs = $this->loadBackoffs(); // map of (type => UNIX expiry)
+ $startingBackoffs = $backoffs; // avoid unnecessary writes
+ $backoffExpireFunc = function ( $t ) {
+ return $t > time();
+ };
+
+ $jobsRun = 0; // counter
+ $timeMsTotal = 0;
+ $flags = JobQueueGroup::USE_CACHE;
+ $startTime = microtime( true ); // time since jobs started running
+ $lastTime = microtime( true ); // time since last slave check
+ do {
+ $backoffs = array_filter( $backoffs, $backoffExpireFunc );
+ $blacklist = $noThrottle ? array() : array_keys( $backoffs );
+ if ( $type === false ) {
+ $job = $group->pop( JobQueueGroup::TYPE_DEFAULT, $flags, $blacklist );
+ } elseif ( in_array( $type, $blacklist ) ) {
+ $job = false; // requested queue in backoff state
+ } else {
+ $job = $group->pop( $type ); // job from a single queue
+ }
+ if ( $job ) { // found a job
+ $jType = $job->getType();
+
+ $this->runJobsLog( $job->toString() . " STARTING" );
+
+ // Run the job...
+ wfProfileIn( __METHOD__ . '-' . get_class( $job ) );
+ $t = microtime( true );
+ try {
+ ++$jobsRun;
+ $status = $job->run();
+ $error = $job->getLastError();
+ wfGetLBFactory()->commitMasterChanges();
+ } catch ( MWException $e ) {
+ MWExceptionHandler::rollbackMasterChangesAndLog( $e );
+ $status = false;
+ $error = get_class( $e ) . ': ' . $e->getMessage();
+ $e->report(); // write error to STDERR and the log
+ }
+ $timeMs = intval( ( microtime( true ) - $t ) * 1000 );
+ wfProfileOut( __METHOD__ . '-' . get_class( $job ) );
+ $timeMsTotal += $timeMs;
+
+ // Mark the job as done on success or when the job cannot be retried
+ if ( $status !== false || !$job->allowRetries() ) {
+ $group->ack( $job ); // done
+ }
+
+ if ( $status === false ) {
+ $this->runJobsLog( $job->toString() . " t=$timeMs error={$error}" );
+ } else {
+ $this->runJobsLog( $job->toString() . " t=$timeMs good" );
+ }
+
+ $response['jobs'][] = array(
+ 'type' => $jType,
+ 'status' => ( $status === false ) ? 'failed' : 'ok',
+ 'error' => $error,
+ 'time' => $timeMs
+ );
+
+ // Back off of certain jobs for a while (for throttling and for errors)
+ $ttw = $this->getBackoffTimeToWait( $job );
+ if ( $status === false && mt_rand( 0, 49 ) == 0 ) {
+ $ttw = max( $ttw, 30 );
+ }
+ if ( $ttw > 0 ) {
+ $backoffs[$jType] = isset( $backoffs[$jType] ) ? $backoffs[$jType] : 0;
+ $backoffs[$jType] = max( $backoffs[$jType], time() + $ttw );
+ }
+
+ // Break out if we hit the job count or wall time limits...
+ if ( $maxJobs && $jobsRun >= $maxJobs ) {
+ $response['reached'] = 'job-limit';
+ break;
+ } elseif ( $maxTime && ( microtime( true ) - $startTime ) > $maxTime ) {
+ $response['reached'] = 'time-limit';
+ break;
+ }
+
+ // Don't let any of the main DB slaves get backed up
+ $timePassed = microtime( true ) - $lastTime;
+ if ( $timePassed >= 5 || $timePassed < 0 ) {
+ wfWaitForSlaves( $lastTime );
+ $lastTime = microtime( true );
+ }
+ // Don't let any queue slaves/backups fall behind
+ if ( $jobsRun > 0 && ( $jobsRun % 100 ) == 0 ) {
+ $group->waitForBackups();
+ }
+
+ // Bail if near-OOM instead of in a job
+ $this->assertMemoryOK();
+ }
+ } while ( $job ); // stop when there are no jobs
+
+ // Sync the persistent backoffs for the next runJobs.php pass
+ $backoffs = array_filter( $backoffs, $backoffExpireFunc );
+ if ( $backoffs !== $startingBackoffs ) {
+ $this->syncBackoffs( $backoffs );
+ }
+
+ $response['backoffs'] = $backoffs;
+ $response['elapsed'] = $timeMsTotal;
+
+ return $response;
+ }
+
+ /**
+ * @param Job $job
+ * @return int Seconds for this runner to avoid doing more jobs of this type
+ * @see $wgJobBackoffThrottling
+ */
+ private function getBackoffTimeToWait( Job $job ) {
+ global $wgJobBackoffThrottling;
+
+ if ( !isset( $wgJobBackoffThrottling[$job->getType()] ) ||
+ $job instanceof DuplicateJob // no work was done
+ ) {
+ return 0; // not throttled
+ }
+
+ $itemsPerSecond = $wgJobBackoffThrottling[$job->getType()];
+ if ( $itemsPerSecond <= 0 ) {
+ return 0; // not throttled
+ }
+
+ $seconds = 0;
+ if ( $job->workItemCount() > 0 ) {
+ $exactSeconds = $job->workItemCount() / $itemsPerSecond;
+ // use randomized rounding
+ $seconds = floor( $exactSeconds );
+ $remainder = $exactSeconds - $seconds;
+ $seconds += ( mt_rand() / mt_getrandmax() < $remainder ) ? 1 : 0;
+ }
+
+ return (int)$seconds;
+ }
+
+ /**
+ * Get the previous backoff expiries from persistent storage
+ *
+ * @return array Map of (job type => backoff expiry timestamp)
+ */
+ private function loadBackoffs() {
+ $section = new ProfileSection( __METHOD__ );
+
+ $backoffs = array();
+ $file = wfTempDir() . '/mw-runJobs-backoffs.json';
+ if ( is_file( $file ) ) {
+ $handle = fopen( $file, 'rb' );
+ flock( $handle, LOCK_SH );
+ $content = stream_get_contents( $handle );
+ flock( $handle, LOCK_UN );
+ fclose( $handle );
+ $backoffs = json_decode( $content, true ) ? : array();
+ }
+
+ return $backoffs;
+ }
+
+ /**
+ * Merge the current backoff expiries from persistent storage
+ *
+ * @param array $backoffs Map of (job type => backoff expiry timestamp)
+ */
+ private function syncBackoffs( array $backoffs ) {
+ $section = new ProfileSection( __METHOD__ );
+
+ $file = wfTempDir() . '/mw-runJobs-backoffs.json';
+ $handle = fopen( $file, 'wb+' );
+ flock( $handle, LOCK_EX );
+ $content = stream_get_contents( $handle );
+ $cBackoffs = json_decode( $content, true ) ? : array();
+ foreach ( $backoffs as $type => $timestamp ) {
+ $cBackoffs[$type] = isset( $cBackoffs[$type] ) ? $cBackoffs[$type] : 0;
+ $cBackoffs[$type] = max( $cBackoffs[$type], $backoffs[$type] );
+ }
+ ftruncate( $handle, 0 );
+ fwrite( $handle, json_encode( $backoffs ) );
+ flock( $handle, LOCK_UN );
+ fclose( $handle );
+ }
+
+ /**
+ * Make sure that this script is not too close to the memory usage limit.
+ * It is better to die in between jobs than OOM right in the middle of one.
+ * @throws MWException
+ */
+ private function assertMemoryOK() {
+ static $maxBytes = null;
+ if ( $maxBytes === null ) {
+ $m = array();
+ if ( preg_match( '!^(\d+)(k|m|g|)$!i', ini_get( 'memory_limit' ), $m ) ) {
+ list( , $num, $unit ) = $m;
+ $conv = array( 'g' => 1073741824, 'm' => 1048576, 'k' => 1024, '' => 1 );
+ $maxBytes = $num * $conv[strtolower( $unit )];
+ } else {
+ $maxBytes = 0;
+ }
+ }
+ $usedBytes = memory_get_usage();
+ if ( $maxBytes && $usedBytes >= 0.95 * $maxBytes ) {
+ throw new MWException( "Detected excessive memory usage ($usedBytes/$maxBytes)." );
+ }
+ }
+
+ /**
+ * Log the job message
+ * @param string $msg The message to log
+ */
+ private function runJobsLog( $msg ) {
+ if ( $this->debug ) {
+ call_user_func_array( $this->debug, array( wfTimestamp( TS_DB ) . " $msg\n" ) );
+ }
+ wfDebugLog( 'runJobs', $msg );
+ }
+}
* Callers should use DuplicateJob::newFromJob() instead
*
* @param Title $title
- * @param array $params job parameters
+ * @param array $params Job parameters
*/
function __construct( $title, $params ) {
parent::__construct( 'duplicate', $title, $params );
class NullJob extends Job {
/**
* @param Title $title
- * @param array $params job parameters (lives, usleep)
+ * @param array $params Job parameters (lives, usleep)
*/
function __construct( $title, $params ) {
parent::__construct( 'null', $title, $params );
* Store a result in the session data. Note that the caller is responsible
* for appropriate session_start and session_write_close calls.
*
- * @param string $result the result (Success|Warning|Failure)
- * @param string $dataKey the key of the extra data
+ * @param string $result The result (Success|Warning|Failure)
+ * @param string $dataKey The key of the extra data
* @param mixed $dataValue The extra data itself
*/
protected function storeResultInSession( $result, $dataKey, $dataValue ) {
* Set the visibility restrictions for displaying content.
* If set to public, and an item is deleted, then it will be replaced
* with a placeholder even if the context user is allowed to view it.
- * @param int $audience self::FOR_THIS_USER or self::FOR_PUBLIC
+ * @param int $audience Const self::FOR_THIS_USER or self::FOR_PUBLIC
*/
public function setAudience( $audience ) {
$this->audience = ( $audience == self::FOR_THIS_USER )
* Even uglier hack to maintain backwards compatibilty with IRC bots
* (bug 34508).
* @see getActionText()
- * @return string text
+ * @return string Text
*/
public function getIRCActionComment() {
$actionComment = $this->getIRCActionText();
* Even uglier hack to maintain backwards compatibilty with IRC bots
* (bug 34508).
* @see getActionText()
- * @return string text
+ * @return string Text
*/
public function getIRCActionText() {
$this->plaintext = true;
* * number: Format value as number
* @param string $value The parameter value that should
* be formated
- * @return string|Message::numParam|Message::rawParam
- * Formated value
+ * @return string|array Formated value
* @since 1.21
*/
protected function formatParameterValue( $type, $value ) {
}
/**
- * @return array of titles that should be preloaded with LinkBatch.
+ * @return array Array of titles that should be preloaded with LinkBatch
*/
public function getPreloadTitles() {
return array();
}
/**
- * @return int log_id of the inserted log entry
+ * @return int The log_id of the inserted log entry
*/
protected function saveContent() {
global $wgLogRestrictions;
/**
* Get the list of valid log types
*
- * @return array of strings
+ * @return array Array of strings
*/
public static function validTypes() {
global $wgLogTypes;
* Get the log header for the given log type
*
* @todo handle missing log types
- * @param string $type logtype
+ * @param string $type Logtype
* @return string Header text of this logtype
* @deprecated since 1.19, warnings in 1.21. Use getDescription()
*/
* Generate text for a log entry.
* Only LogFormatter should call this function.
*
- * @param string $type log type
- * @param string $action log action
+ * @param string $type Log type
+ * @param string $action Log action
* @param Title|null $title Title object or null
* @param Skin|null $skin Skin object or null. If null, we want to use the wiki
* content language, since that will go to the IRC feed.
- * @param array $params parameters
+ * @param array $params Parameters
* @param bool $filterWikilinks Whether to filter wiki links
* @return string HTML
*/
/**
* Add a log entry
*
- * @param string $action one of '', 'block', 'protect', 'rights', 'delete',
+ * @param string $action One of '', 'block', 'protect', 'rights', 'delete',
* 'upload', 'move', 'move_redir'
* @param Title $target Title object
- * @param string $comment description associated
- * @param array $params parameters passed later to wfMessage function
+ * @param string $comment Description associated
+ * @param array $params Parameters passed later to wfMessage function
* @param null|int|User $doer The user doing the action. null for $wgUser
*
- * @return int log_id of the inserted log entry
+ * @return int The log_id of the inserted log entry
*/
public function addEntry( $action, $target, $comment, $params = array(), $doer = null ) {
global $wgContLang;
/** Add misc metadata. Warning: atm if the metadata category
* doesn't have a priority, it will be silently discarded.
*
- * @param array $metaArray array of metadata values
+ * @param array $meta Array of metadata values
* @param string $type Type. defaults to other. if two things have the same type they're merged
*/
function addMetadata( $metaArray, $type = 'other' ) {
/** Main entry point for jpeg's.
*
- * @param string $filename filename (with full path)
+ * @param string $filename Filename (with full path)
* @return array Metadata result array.
- * @throws MWException on invalid file.
+ * @throws MWException On invalid file.
*/
static function Jpeg( $filename ) {
$showXMP = function_exists( 'xml_parser_create_ns' );
* They don't really have native metadata, so just merges together
* XMP and image comment.
*
- * @param string $filename full path to file
+ * @param string $filename Full path to file
* @return array Metadata array
*/
public static function GIF( $filename ) {
// something that explicitly initializes local variables.
extract( unpack( 'a4magic/a4chunk/NchunkLength', $header ) );
/** @var string $chunk
- * @var string $chunkLength */
+ * @var string $chunkLength */
echo "$chunk $chunkLength\n";
$this->dumpForm( $file, $chunkLength, 1 );
fclose( $file );
// something that explicitly initializes local variables.
extract( unpack( 'a4chunk/NchunkLength', $chunkHeader ) );
/** @var string $chunk
- * @var string $chunkLength */
+ * @var string $chunkLength */
echo str_repeat( ' ', $indent * 4 ) . "$chunk $chunkLength\n";
if ( $chunk == 'FORM' ) {
extract( unpack( 'a4magic/a4form/NformLength/a4subtype', $header ) );
/** @var string $magic
- * @var string $subtype
- * @var string $formLength
- * @var string $formType */
+ * @var string $subtype
+ * @var string $formLength
+ * @var string $formType */
if ( $magic != 'AT&T' ) {
wfDebug( __METHOD__ . ": not a DjVu file\n" );
} elseif ( $subtype == 'DJVU' ) {
extract( unpack( 'a4chunk/Nlength', $header ) );
/** @var string $chunk
- * @var string $length */
+ * @var string $length */
return array( $chunk, $length );
}
}
# Newer files have rotation info in byte 10, but we don't use it yet.
/** @var string $width
- * @var string $height
- * @var string $major
- * @var string $minor
- * @var string $resolution
- * @var string $length
- * @var string $gamma */
+ * @var string $height
+ * @var string $major
+ * @var string $minor
+ * @var string $resolution
+ * @var string $length
+ * @var string $gamma */
return array(
'width' => $width,
'height' => $height,
* Do userComment tags and similar. See pg. 34 of exif standard.
* basically first 8 bytes is charset, rest is value.
* This has not been tested on any shift-JIS strings.
- * @param string $prop prop name.
+ * @param string $prop Prop name
*/
private function charCodeString( $prop ) {
if ( isset( $this->mFilteredExifData[$prop] ) ) {
/**
* Validates if a tag has a legal value according to the Exif spec
*
- * @param string $section section where tag is located.
- * @param string $tag the tag to check.
+ * @param string $section Section where tag is located.
+ * @param string $tag The tag to check.
* @param mixed $val The value of the tag.
* @param bool $recursive True if called recursively for array types.
* @return bool
/**
* Convenience function for debugging output
*
- * @param string $fname the name of the function calling this function
+ * @param string $fname The name of the function calling this function
* @param bool $io Specify whether we're beginning or ending
*/
private function debugFile( $fname, $io ) {
*
* This is the usual entry point for this class.
*
- * @param array $tags the Exif data to format ( as returned by
+ * @param array $tags The Exif data to format ( as returned by
* Exif::getFilteredData() or BitmapMetadataHandler )
* @param bool|IContextSource $context Context to use (optional)
* @return array
* value which most of the time are plain integers. This function
* formats Exif (and other metadata) values into human readable form.
*
- * @param array $tags the Exif data to format ( as returned by
+ * @param array $tags The Exif data to format ( as returned by
* Exif::getFilteredData() or BitmapMetadataHandler )
* @return array
* @since 1.23
/**
* Flatten an array, using the user language for any messages.
*
- * @param array $vals array of values
+ * @param array $vals Array of values
* @param string $type Type of array (either lang, ul, ol).
* lang = language assoc array with keys being the lang code
* ul = unordered list, ol = ordered list
*
* This is public on the basis it might be useful outside of this class.
*
- * @param array $vals array of values
+ * @param array $vals Array of values
* @param string $type Type of array (either lang, ul, ol).
* lang = language assoc array with keys being the lang code
* ul = unordered list, ol = ordered list
*
* @param File $file File to use
* @param array $extendedMetadata
- * @param int $maxCacheTime hook handlers might use this parameter to override cache time
+ * @param int $maxCacheTime Hook handlers might use this parameter to override cache time
*
* @return array [<property name> => ['value' => <value>]], or [] on error
* @since 1.23
* If the value is not a multilang array, it is returned unchanged.
* See mediawiki.org/wiki/Manual:File_metadata_handling#Multi-language_array_format
* @param mixed $value
- * @return mixed value in best language, null if there were no languages at all
+ * @return mixed Value in best language, null if there were no languages at all
* @since 1.23
*/
protected function resolveMultilangValue( $value ) {
*
* @see http://www.iptc.org/std/IIM/4.1/specification/IIMV4.1.pdf
*
- * @param string $rawData app13 block from jpeg containing iptc/iim data
+ * @param string $rawData The app13 block from jpeg containing iptc/iim data
* @return array IPTC metadata array
*/
static function parse( $rawData ) {
/**
* take the value of 1:90 tag and returns a charset
* @param string $tag 1:90 tag.
- * @return string charset name or "?"
+ * @return string Charset name or "?"
* Warning, this function does not (and is not intended to) detect
* all iso 2022 escape codes. In practise, the code for utf-8 is the
* only code that seems to have wide use. It does detect that code.
}
/** Validate and normalize quality value to be between 1 and 100 (inclusive).
- * @param int $value quality value, will be converted to integer or 0 if invalid
- * @return bool true if the value is valid
+ * @param int $value Quality value, will be converted to integer or 0 if invalid
+ * @return bool True if the value is valid
*/
private static function validateQuality( $value ) {
return $value === 'low';
* but gis doesn't support having multiple app1 segments
* and those can't extract xmp on files containing both exif and xmp data
*
- * @param string $filename name of jpeg file
- * @return array of interesting segments.
- * @throws MWException if given invalid file.
+ * @param string $filename Name of jpeg file
+ * @return array Array of interesting segments.
+ * @throws MWException If given invalid file.
*/
static function segmentSplitter( $filename ) {
$showXMP = function_exists( 'xml_parser_create_ns' );
*
* This should generally be called by BitmapMetadataHandler::doApp13()
*
- * @param string $app13 photoshop psir app13 block from jpg.
+ * @param string $app13 Photoshop psir app13 block from jpg.
* @throws MWException (It gets caught next level up though)
* @return string If the iptc hash is good or not. One of 'iptc-no-hash',
* 'iptc-good-hash', 'iptc-bad-hash'.
* first page.
*
* @param File $image The image object, or false if there isn't one
- * @param string $path the filename
+ * @param string $path The filename
* @return array Follow the format of PHP getimagesize() internal function.
* See http://www.php.net/getimagesize. MediaWiki will only ever use the
* first two array keys (the width and height), and the 'bits' associative
* @param string $ext Extension of original file
* @param string $mime MIME type of original file
* @param array $params Handler specific rendering parameters
- * @return array thumbnail extension and MIME type
+ * @return array Thumbnail extension and MIME type
*/
function getThumbType( $ext, $mime, $params = null ) {
$magic = MimeMagic::singleton();
* relevant errors.
*
* @param string $fileName The local path to the file.
- * @return Status object
+ * @return Status
*/
function verifyUpload( $fileName ) {
return Status::newGood();
/**
* Returns whether or not this handler supports the chained generation of thumbnails according
* to buckets
- * @return boolean
- * @since 1.24
+ * @return bool
+ * @since 1.24
*/
public function supportsBucketing() {
return false;
*/
public $responsiveUrls = array();
- /** @var File object */
+ /** @var File */
protected $file;
/** @var int Image width */
}
/**
- * @return File file
+ * @return File
*/
public function getFile() {
return $this->file;
/**
* We do not support making APNG thumbnails, so always false
* @param File $image
- * @return bool false
+ * @return bool False
*/
function canAnimateThumbnail( $image ) {
return false;
*
* @param resource $fh The file handle
* @param int $size Size in bytes.
- * @throws Exception if too big.
+ * @throws Exception If too big
* @return string The chunk.
*/
private static function read( $fh, $size ) {
}
/**
- * @param array $params name=>value pairs of parameters
+ * @param array $params Name=>value pairs of parameters
* @return string Filename to use
*/
function makeParamString( $params ) {
* @author Hashar
*
* @param string $filename Full path to a XCF file
- * @return bool|array metadata array just like PHP getimagesize()
+ * @return bool|array Metadata Array just like PHP getimagesize()
*/
static function getXCFMetaData( $filename ) {
# Decode master structure
*
* @param XMLParser $parser XMLParser reference to the xml parser
* @param string $data Character data
- * @throws MWException on invalid data
+ * @throws MWException On invalid data
*/
function char( $parser, $data ) {
* this should always be <rdf:Bag>
*
* @param string $elm Namespace . ' ' . tag
- * @throws MWException if we have an element that's not <rdf:Bag>
+ * @throws MWException If we have an element that's not <rdf:Bag>
*/
private function startElementModeBag( $elm ) {
if ( $elm === self::NS_RDF . ' Bag' ) {
* this should always be <rdf:Seq>
*
* @param string $elm Namespace . ' ' . tag
- * @throws MWException if we have an element that's not <rdf:Seq>
+ * @throws MWException If we have an element that's not <rdf:Seq>
*/
private function startElementModeSeq( $elm ) {
if ( $elm === self::NS_RDF . ' Seq' ) {
* we don't care about.
*
* @param string $elm Namespace . ' ' . tag
- * @throws MWException if we have an element that's not <rdf:Alt>
+ * @throws MWException If we have an element that's not <rdf:Alt>
*/
private function startElementModeLang( $elm ) {
if ( $elm === self::NS_RDF . ' Alt' ) {
*
* @param string $elm Namespace . ' ' . tagname
* @param array $attribs Attributes. (needed for BAGSTRUCTS)
- * @throws MWException if gets a tag other than <rdf:li>
+ * @throws MWException If gets a tag other than <rdf:li>
*/
private function startElementModeLi( $elm, $attribs ) {
if ( ( $elm ) !== self::NS_RDF . ' li' ) {
* Batch insertion
* @param array $data $key => $value assoc array
* @param int $exptime Either an interval in seconds or a unix timestamp for expiry
- * @return bool success
+ * @return bool Success
* @since 1.24
*/
public function setMulti( array $data, $exptime = 0 ) {
* This will create the key with value $init and TTL $ttl if not present
*
* @param string $key
- * @param integer $ttl
- * @param integer $value
- * @param integer $init
+ * @param int $ttl
+ * @param int $value
+ * @param int $init
* @return bool
* @since 1.24
*/
* Store a value in the WinCache object cache
*
* @param string $key Cache key
- * @param mixed $valueObject to store
+ * @param mixed $valueObject Value to store
* @param int $expire Expiration time
* @return bool
*/
$this->mParserOutput = $poolArticleView->getParserOutput();
$outputPage->addParserOutput( $this->mParserOutput );
if ( $content->getRedirectTarget() ) {
- $outputPage->addSubtitle( wfMessage( 'redirectpagesub' )->parse() );
+ $outputPage->addSubtitle(
+ "<span id=\"redirectsub\">" . wfMessage( 'redirectpagesub' )->parse() . "</span>"
+ );
}
# Don't cache a dirty ParserOutput object
* If the revision requested for view is deleted, check permissions.
* Send either an error message or a warning header to the output.
*
- * @return bool true if the view is allowed, false if not.
+ * @return bool True if the view is allowed, false if not.
*/
public function showDeletedRevisionHeader() {
if ( !$this->mRevision->isDeleted( Revision::DELETED_TEXT ) ) {
* output to the client that is necessary for this request.
* (that is, it has sent a cached version of the page)
*
- * @return bool true if cached version send, false otherwise
+ * @return bool True if cached version send, false otherwise
*/
protected function tryFileCache() {
static $called = false;
* Override the ParserOptions used to render the primary article wikitext.
*
* @param ParserOptions $options
- * @throws MWException if the parser options where already initialized.
+ * @throws MWException If the parser options where already initialized.
*/
public function setParserOptions( ParserOptions $options ) {
if ( $this->mParserOptions ) {
* of the dimensions are bigger than the max, or if the
* image is vectorized.
*
- * @param $maxWidth integer Max width to display at
- * @param $maxHeight integer Max height to display at
- * @param $width integer Actual width of the image
- * @param $height integer Actual height of the image
+ * @param int $maxWidth Max width to display at
+ * @param int $maxHeight Max height to display at
+ * @param int $width Actual width of the image
+ * @param int $height Actual height of the image
* @throws MWException
- * @return Array (width, height)
+ * @return array Array (width, height)
*/
protected function getDisplayWidthHeight( $maxWidth, $maxHeight, $width, $height ) {
if ( !$maxWidth || !$maxHeight ) {
* Get alternative thumbnail sizes.
*
* @note This will only list several alternatives if thumbnails are rendered on 404
- * @param $origWidth Actual width of image
- * @param $origHeight Actual height of image
- * @return Array An array of [width, height] pairs.
+ * @param int $origWidth Actual width of image
+ * @param int $origHeight Actual height of image
+ * @return array An array of [width, height] pairs.
*/
protected function getThumbSizes( $origWidth, $origHeight ) {
global $wgImageLimits;
/**
* Loads page_touched and returns a value indicating if it should be used
- * @return bool true if not a redirect
+ * @return bool True if not a redirect
*/
public function checkTouched() {
if ( !$this->mDataLoaded ) {
/**
* Get the page_latest field
- * @return int rev_id of current revision
+ * @return int The rev_id of current revision
*/
public function getLatest() {
if ( !$this->mDataLoaded ) {
/**
* Get the content of the current revision. No side-effects...
*
- * @param int $audience int One of:
+ * @param int $audience One of:
* Revision::FOR_PUBLIC to be displayed to all users
* Revision::FOR_THIS_USER to be displayed to $wgUser
* Revision::RAW get the text regardless of permissions
* Revision::RAW get the text regardless of permissions
* @param User $user User object to check for, only if FOR_THIS_USER is passed
* to the $audience parameter
- * @return int user ID for the user that made the last article revision
+ * @return int User ID for the user that made the last article revision
*/
public function getUser( $audience = Revision::FOR_PUBLIC, User $user = null ) {
$this->loadLastEdit();
* Revision::RAW get the text regardless of permissions
* @param User $user User object to check for, only if FOR_THIS_USER is passed
* to the $audience parameter
- * @return string username of the user that made the last article revision
+ * @return string Username of the user that made the last article revision
*/
public function getUserText( $audience = Revision::FOR_PUBLIC, User $user = null ) {
$this->loadLastEdit();
/**
* Get the Title object or URL this page redirects to
*
- * @return bool|Title|string false, Title of in-wiki target, or string with URL
+ * @return bool|Title|string False, Title of in-wiki target, or string with URL
*/
public function followRedirect() {
return $this->getRedirectURL( $this->getRedirectTarget() );
* objects for same-wiki, non-special redirects and URLs for everything
* else.
* @param Title $rt Redirect target
- * @return bool|Title|string false, Title object of local target, or string with URL
+ * @return bool|Title|string False, Title object of local target, or string with URL
*/
public function getRedirectURL( $rt ) {
if ( !$rt ) {
* Giving 0 indicates the new page flag should be set on.
* @param bool $lastRevIsRedirect If given, will optimize adding and
* removing rows in redirect table.
- * @return bool true on success, false on failure
+ * @return bool True on success, false on failure
*/
public function updateRevisionOn( $dbw, $revision, $lastRevision = null,
$lastRevIsRedirect = null
* or NULL if this is not a redirect
* @param null|bool $lastRevIsRedirect If given, will optimize adding and
* removing rows in redirect table.
- * @return bool true on success, false on failure
+ * @return bool True on success, false on failure
* @private
*/
public function updateRedirectOn( $dbw, $redirectTitle, $lastRevIsRedirect = null ) {
* must exist and must not be deleted
* @param Revision $undo
* @param Revision $undoafter Must be an earlier revision than $undo
- * @return mixed string on success, false on failure
+ * @return mixed String on success, false on failure
* @since 1.21
* Before we had the Content object, this was done in getUndoText
*/
* must exist and must not be deleted
* @param Revision $undo
* @param Revision $undoafter Must be an earlier revision than $undo
- * @return string|bool string on success, false on failure
+ * @return string|bool String on success, false on failure
* @deprecated since 1.21: use ContentHandler::getUndoContent() instead.
*/
public function getUndoText( Revision $undo, Revision $undoafter = null ) {
* or 'new' for a new section.
* @param Content $sectionContent New content of the section.
* @param string $sectionTitle New section's subject, only if $section is "new".
- * @param string $baseRevId integer|null
+ * @param int|null $baseRevId
*
* @throws MWException
* @return Content New complete article content, or null if error.
* @param User $user The user doing the edit
*
* @throws MWException
- * @return Status object. Possible errors:
+ * @return Status Possible errors:
* edit-hook-aborted: The ArticleSave hook aborted the edit but didn't
* set the fatal flag of $status
* edit-gone-missing: In update mode, but the article didn't exist.
* database.
*
* @throws MWException
- * @return Status object. Possible errors:
+ * @return Status Possible errors:
* edit-hook-aborted: The ArticleSave hook aborted the edit but didn't
* set the fatal flag of $status.
* edit-gone-missing: In update mode, but the article didn't exist.
*
* @param Content $content Content submitted
* @param User $user The relevant user
- * @param string $comment comment submitted
+ * @param string $comment Comment submitted
* @param string $serialisation_format Format for storing the content in the database
* @param bool $minor Whereas it's a minor modification
*/
* @param bool $commit Defaults to true, triggers transaction end
* @param array &$error Array of errors to append to
* @param User $user The deleting user
- * @return bool true if successful
+ * @return bool True if successful
*/
public function doDeleteArticle(
$reason, $suppress = false, $id = 0, $commit = true, &$error = '', User $user = null
/**
* Do some database updates after deletion
*
- * @param int $id page_id value of the page being deleted
+ * @param int $id The page_id value of the page being deleted
* @param Content $content Optional page content to be used when determining
* the required updates. This may be needed because $this->getContent()
* may already return null when the page proper was deleted.
* @param string $token Rollback token.
* @param bool $bot If true, mark all reverted edits as bot.
*
- * @param array $resultDetails contains result-specific array of additional values
+ * @param array $resultDetails Array contains result-specific array of additional values
* 'alreadyrolled' : 'current' (rev)
* success : 'summary' (str), 'current' (rev), 'target' (rev)
*
* @param int &$cascade Set to false if cascading protection isn't allowed.
* @param array $expiry Per restriction type expiration
* @param User $user The user updating the restrictions
- * @return bool true on success
+ * @return bool True on success
*/
public function updateRestrictions(
$limit = array(), $reason = '', &$cascade = 0, $expiry = array(), User $user = null
*
* @param Language|string|null $lang In which language to format the date
* Defaults to the site content language
- * @return DateFormatter object
+ * @return DateFormatter
*/
public static function &getInstance( $lang = null ) {
global $wgMemc, $wgContLang;
/**
* Replace <!--LINK--> link placeholders with actual links, in the buffer
*
- * @param $text
+ * @param string $text
* @return array Array of link CSS classes, indexed by PDBK.
*/
function replace( &$text ) {
var $mLangLinkLanguages;
/**
- * @var boolean Recursive call protection.
+ * @var bool Recursive call protection.
* This variable should be treated as if it were private.
*/
public $mInParse = false;
* Convert wikitext to HTML
* Do not call this function recursively.
*
- * @param string $text text we want to parse
+ * @param string $text Text we want to parse
* @param Title $title
* @param ParserOptions $options
* @param bool $linestart
/**
* Get the ParserOptions object
*
- * @return ParserOptions object
+ * @return ParserOptions
*/
function getOptions() {
return $this->mOptions;
*
* @param string $text
*
- * @return string the altered text
+ * @return string The altered text
*/
function doAllQuotes( $text ) {
wfProfileIn( __METHOD__ );
* @todo document
*/
class ParserCache {
- /** @var MWMemcached */
+ /** @var MWMemcached */
private $mMemc;
/**
* Get an instance of this object
*/
/**
- * \brief Set options of the Parser
+ * @brief Set options of the Parser
*
* All member variables are supposed to be private in theory, although in
* practise this is not the case.
/**
* @param Title $title Title object, must be an interwiki link
- * @throws MWException if given invalid input
+ * @throws MWException If given invalid input
*/
function addInterwikiLink( $title ) {
if ( !$title->isExternal() ) {
* -- this is assumed to have been validated
* (check equal normalisation, etc.)
*
- * @param string $text desired title text
+ * @param string $text Desired title text
*/
public function setDisplayTitle( $text ) {
$this->setTitleText( $text );
/**
* @param string $name The property name to look up.
*
- * @return mixed|false The value previously set using setProperty(). False if null or no value
+ * @return mixed|bool The value previously set using setProperty(). False if null or no value
* was set for the given property name.
*
* @note You need to use getProperties() to check for boolean and null properties.
/**
* @throws MWException
- * @param string|PPNode$root
+ * @param string|PPNode $root
* @param int $flags
* @return string
*/
* Lets another one grab the lock, and returns the workers
* waiting on acquireForAnyone()
*
- * @return Status value is one of Released/NotLocked/Error
+ * @return Status Value is one of Released/NotLocked/Error
*/
abstract public function release();
* the same key can acquire a lock.
*
* @param string $key PoolCounter instance key (any string)
- * @param int $slots the number of slots (max allowed value is 65536)
+ * @param int $slots The number of slots (max allowed value is 65536)
* @return int
*/
protected function hashKeyIntoSlots( $key, $slots ) {
/**
* Begin profiling of a function
- * @param string $functionname name of the function we will profile
+ * @param string $functionname Name of the function we will profile
*/
function wfProfileIn( $functionname ) {
if ( Profiler::$__instance === null ) { // use this directly to reduce overhead
/**
* Stop profiling of a function
- * @param string $functionname name of the function we have profiled
+ * @param string $functionname Name of the function we have profiled
*/
function wfProfileOut( $functionname = 'missing' ) {
if ( Profiler::$__instance === null ) { // use this directly to reduce overhead
/**
* Called by wfProfieOut()
*
- * @param string $functionname
+ * @param string $functionname
*/
abstract public function profileOut( $functionname );
/**
* Add an entry in the debug log file
*
- * @param string $s to output
+ * @param string $s String to output
*/
protected function debug( $s ) {
if ( function_exists( 'wfDebug' ) ) {
* Add an entry in the debug log group
*
* @param string $group Group to send the message to
- * @param string $s to output
+ * @param string $s String to output
*/
protected function debugGroup( $group, $s ) {
if ( function_exists( 'wfDebugLog' ) ) {
* @since 1.24
*/
class TransactionProfiler {
- /** @var float seconds */
+ /** @var float Seconds */
protected $mDBLockThreshold = 3.0;
/** @var array DB/server name => (active trx count, time, DBs involved) */
protected $mDBTrxHoldingLocks = array();
* Update an entry with timing data.
*
* @param string $name Section name
- * @param float $elapsedCpu elapsed CPU time
- * @param float $elapsedWall elapsed wall-clock time
+ * @param float $elapsedCpu Elapsed CPU time
+ * @param float $elapsedWall Elapsed wall-clock time
*/
public function updateRunningEntry( $name, $elapsedCpu, $elapsedWall ) {
// If this is the first measurement for this entry, store plain values.
/**
* Recursive function the format the current profiling array into a tree
*
- * @param array $stack profiling array
+ * @param array $stack Profiling array
* @return array
*/
protected function remapCallTree( array $stack ) {
* @see RecentChange::cleanupForIRC
* @param array $feed The feed, as configured in an associative array
* @param string $line The text to send
- * @return bool success
+ * @return bool Success
*/
public function send( array $feed, $line );
}
*/
protected $testModuleNames = array();
- /** @var array e.g. array( 'source-id' => array( 'loadScript' => 'http://.../load.php' ) ) */
+ /** @var array E.g. array( 'source-id' => array( 'loadScript' => 'http://.../load.php' ) ) */
protected $sources = array();
/** @var bool */
*
* @since 1.24
* @param string $source
- * @throws MWException on an invalid $source name
+ * @throws MWException On an invalid $source name
* @return string
*/
public function getLoadScript( $source ) {
* Build a load.php URL
*
* @since 1.24
- * @param string $source name of the ResourceLoader source
+ * @param string $source Name of the ResourceLoader source
* @param ResourceLoaderContext $context
* @param array $extraQuery
* @return string URL to load.php. May be protocol-relative (if $wgLoadScript is procol-relative)
/**
* Get loader script.
*
- * @return string|false JavaScript code to be added to startup module
+ * @return string|bool JavaScript code to be added to startup module
*/
public function getLoaderScript() {
if ( count( $this->loaderScripts ) === 0 ) {
* @param bool $flip
*
* @return string CSS data in script file
- * @throws MWException if the file doesn't exist
+ * @throws MWException If the file doesn't exist
*/
protected function readStyleFile( $path, $flip ) {
$localPath = $this->getLocalPath( $path );
/**
- * @param $context ResourceLoaderContext
+ * @param ResourceLoaderContext $context
* @return array
*/
protected function getData( ResourceLoaderContext $context ) {
}
/**
- * @param $context ResourceLoaderContext
+ * @param ResourceLoaderContext $context
* @return string JavaScript code
*/
public function getScript( ResourceLoaderContext $context ) {
* load the files directly. See also getScriptURLsForDebug()
*
* @param ResourceLoaderContext $context
- * @return array array( mediaType => array( URL1, URL2, ... ), ... )
+ * @return array Array( mediaType => array( URL1, URL2, ... ), ... )
*/
public function getStyleURLsForDebug( ResourceLoaderContext $context ) {
$resourceLoader = $context->getResourceLoader();
return false;
}
- /** @var JSParser lazy-initialized; use self::javaScriptParser() */
+ /** @var JSParser Lazy-initialized; use self::javaScriptParser() */
private static $jsParser;
private static $parseCacheVersion = 1;
* This way we can reasonably reduce the amout of module registration
* data send to the client.
*
- * @param Array &$registryData Modules keyed by name with properties:
+ * @param array &$registryData Modules keyed by name with properties:
* - string 'version'
* - array 'dependencies'
* - string|null 'group'
* Checks for a change in the bitfield for a certain option and updates the
* provided array accordingly.
*
- * @param string $desc description to add to the array if the option was
+ * @param string $desc Description to add to the array if the option was
* enabled / disabled.
* @param int $field The bitmask describing the single option.
* @param int $diff The xor of the old and new bitfields.
/**
* Split text into lines and add it to extracts array
*
- * @param array $extracts index -> $line
+ * @param array $extracts Index -> $line
* @param int $count
* @param string $text
*/
}
/**
- * @return string timestamp
+ * @return string Timestamp
*/
function getTimestamp() {
if ( $this->mRevision ) {
$group = new self();
/**
- * @var \Site $site
+ * @var Site $site
*/
foreach ( $this as $site ) {
if ( $site->getGroup() === $groupName ) {
* @param string $name Name of the special page, as seen in links and URLs
* @param string $restriction User right required, e.g. "block" or "delete"
* @param bool $listed Whether the page is listed in Special:Specialpages
- * @param callable|bool $function unused
- * @param string $file unused
+ * @param callable|bool $function Unused
+ * @param string $file Unused
* @param bool $includable Whether the page can be included in normal pages
*/
public function __construct(
// @todo FIXME: Decide which syntax to use for this, and stick to it
/**
* Whether this special page is listed in Special:SpecialPages
- * @since r3583 (v1.3)
+ * @since 1.3 (r3583)
* @return bool
*/
function isListed() {
* - `prefixSearchSubpages( "" )` should return `array( foo", "bar", "baz" )`
*
* @param string $search Prefix to search for
- * @param integer $limit Maximum number of results to return
+ * @param int $limit Maximum number of results to return
* @return string[] Matching subpages
*/
public function prefixSearchSubpages( $search, $limit = 10 ) {
/**
* Constructor
*
- * @param string $name name of the special page, as seen in links and URLs (default: 'Allpages')
+ * @param string $name Name of the special page, as seen in links and URLs (default: 'Allpages')
*/
function __construct( $name = 'Allpages' ) {
parent::__construct( $name );
/**
* Entry point : initialise variables and call subfunctions.
*
- * @param string $par becomes "FOO" when called like Special:Allpages/FOO (default null)
+ * @param string $par Becomes "FOO" when called like Special:Allpages/FOO (default null)
*/
function execute( $par ) {
$request = $this->getRequest();
* @ingroup SpecialPage
*/
class SpecialBlock extends FormSpecialPage {
- /** @var User user to be blocked, as passed either by parameter (url?wpTarget=Foo)
+ /** @var User User to be blocked, as passed either by parameter (url?wpTarget=Foo)
* or as subpage (Special:Block/Foo) */
protected $target;
/**
* Determine the target of the block, and the type of target
* @todo Should be in Block.php?
- * @param string $par subpage parameter passed to setup, or data value from
+ * @param string $par Subpage parameter passed to setup, or data value from
* the HTMLForm
* @param WebRequest $request Optionally try and get data from a request too
* @return array( User|string|null, Block::TYPE_ constant|null )
/**
* Set a message at the top of the Change Password form
* @since 1.23
- * @param Message $msg to parse and add to the form header
+ * @param Message $msg Message to parse and add to the form header
*/
public function setChangeMessage( Message $msg ) {
$this->mPreTextMessage = $msg;
}
/**
- * @throws PasswordError when cannot set the new password because requirements not met.
+ * @throws PasswordError When cannot set the new password because requirements not met.
*/
protected function attemptReset( $oldpass, $newpass, $retype ) {
global $wgPasswordAttemptThrottle;
* Return an array of subpages beginning with $search that this special page will accept.
*
* @param string $search Prefix to search for
- * @param integer $limit Maximum number of results to return
+ * @param int $limit Maximum number of results to return
* @return string[] Matching subpages
*/
public function prefixSearchSubpages( $search, $limit = 10 ) {
* form is open (bug 32126), but we know that invalid items will
* be harmless so we can override it here.
*
- * @param string $value the value the field was submitted with
- * @param array $alldata the data collected from the form
+ * @param string $value The value the field was submitted with
+ * @param array $alldata The data collected from the form
* @return bool|string Bool true on success, or String error to display.
*/
function validate( $value, $alldata ) {
/**
* Validate target User
*
- * @param string $target target user name
+ * @param string $target Target user name
* @return User User object on success or a string on error
*/
public static function getTarget( $target ) {
/** @var bool Whether or not to remove <nowiki> tags in the expanded wikitext */
protected $removeNowiki;
- /** @var maximum size in bytes to include. 50MB allows fixing those huge pages */
+ /** @var int Maximum size in bytes to include. 50MB allows fixing those huge pages */
const MAX_INCLUDE_SIZE = 50000000;
function __construct() {
/**
* Do the actual page exporting
*
- * @param string $page user input on what page(s) to export
+ * @param string $page User input on what page(s) to export
* @param int $history One of the WikiExporter history export constants
* @param bool $list_authors Whether to add distinct author list (when
* not returning full history)
* @param array $inputPages List of titles to look up
* @param array $pageSet Associative array indexed by titles for output
*
- * @return array associative array index by titles
+ * @return array Associative array index by titles
*/
private function getImages( $inputPages, $pageSet ) {
return $this->getLinks(
/**
* Fetch dupes from all connected file repositories.
*
- * @return array of File objects
+ * @return array Array of File objects
*/
function getDupes() {
return RepoGroup::singleton()->findBySha1( $this->hash );
/**
*
- * @param array $dupes of File objects
+ * @param array $dupes Array of File objects
*/
function showList( $dupes ) {
$html = array();
* Return an array of subpages beginning with $search that this special page will accept.
*
* @param string $search Prefix to search for
- * @param integer $limit Maximum number of results to return
+ * @param int $limit Maximum number of results to return
* @return string[] Matching subpages
*/
public function prefixSearchSubpages( $search, $limit = 10 ) {
/**
* Create a user-readable list of permissions from the given array.
*
- * @param array $permissions of permission => bool (from $wgGroupPermissions items)
- * @param array $revoke of permission => bool (from $wgRevokePermissions items)
- * @param array $add of groups this group is allowed to add or true
- * @param array $remove of groups this group is allowed to remove or true
- * @param array $addSelf of groups this group is allowed to add to self or true
- * @param array $removeSelf of group this group is allowed to remove from self or true
+ * @param array $permissions Array of permission => bool (from $wgGroupPermissions items)
+ * @param array $revoke Array of permission => bool (from $wgRevokePermissions items)
+ * @param array $add Array of groups this group is allowed to add or true
+ * @param array $remove Array of groups this group is allowed to remove or true
+ * @param array $addSelf Array of groups this group is allowed to add to self or true
+ * @param array $removeSelf Array of group this group is allowed to remove from self or true
* @return string List of all granted permissions, separated by comma separator
*/
private function formatPermissions( $permissions, $revoke, $add, $remove, $addSelf, $removeSelf ) {
* Return an array of subpages beginning with $search that this special page will accept.
*
* @param string $search Prefix to search for
- * @param integer $limit Maximum number of results to return
+ * @param int $limit Maximum number of results to return
* @return string[] Matching subpages
*/
public function prefixSearchSubpages( $search, $limit = 10 ) {
* Return an array of subpages beginning with $search that this special page will accept.
*
* @param string $search Prefix to search for
- * @param integer $limit Maximum number of results to return
+ * @param int $limit Maximum number of results to return
* @return string[] Matching subpages
*/
public function prefixSearchSubpages( $search, $limit = 10 ) {
* The user may have to "undo" the redirect manually to finish the "unmerge".
* Maybe this should delete redirects at the target page of merges?
*
- * @return boolean Success
+ * @return bool Success
*/
function merge() {
# Get the titles directly from the IDs, in case the target page params
/**
* Show the form
*
- * @param array $err error messages. Each item is an error message.
+ * @param array $err Error messages. Each item is an error message.
* It may either be a string message name or array message name and
* parameters, like the second argument to OutputPage::wrapWikiMsg().
*/
* it returns Page/fi if it exists, otherwise Page/de if it exists,
* otherwise Page.
*
- * @param $par
+ * @param string $par
* @return Title|null
*/
public function findTitle( $par ) {
*/
class SpecialPageLanguage extends FormSpecialPage {
/**
- * @var $goToUrl URL to go to if language change successful
+ * @var string URL to go to if language change successful
*/
private $goToUrl;
* Return an array of subpages beginning with $search that this special page will accept.
*
* @param string $search Prefix to search for
- * @param integer $limit Maximum number of results to return
+ * @param int $limit Maximum number of results to return
* @return string[] Matching subpages
*/
public function prefixSearchSubpages( $search, $limit = 10 ) {
*
* @param Title $category
* @return array The lowest and highest timestamp
- * @throws MWException if category has no entries.
+ * @throws MWException If category has no entries.
*/
protected function getMinAndMaxForCat( Title $category ) {
$dbr = wfGetDB( DB_SLAVE );
/**
* Handle Special:Redirect/user/xxxx (by redirecting to User:YYYY)
*
- * @return string|null url to redirect to, or null if $mValue is invalid.
+ * @return string|null Url to redirect to, or null if $mValue is invalid.
*/
function dispatchUser() {
if ( !ctype_digit( $this->mValue ) ) {
/**
* Handle Special:Redirect/file/xxxx
*
- * @return string|null url to redirect to, or null if $mValue is not found.
+ * @return string|null Url to redirect to, or null if $mValue is not found.
*/
function dispatchFile() {
$title = Title::makeTitleSafe( NS_FILE, $this->mValue );
* Handle Special:Redirect/revision/xxx
* (by redirecting to index.php?oldid=xxx)
*
- * @return string|null url to redirect to, or null if $mValue is invalid.
+ * @return string|null Url to redirect to, or null if $mValue is invalid.
*/
function dispatchRevision() {
$oldid = $this->mValue;
/**
* Handle Special:Redirect/page/xxx (by redirecting to index.php?curid=xxx)
*
- * @return string|null url to redirect to, or null if $mValue is invalid.
+ * @return string|null Url to redirect to, or null if $mValue is invalid.
*/
function dispatchPage() {
$curid = $this->mValue;
* or do nothing (if $mValue wasn't set) allowing the form to be
* displayed.
*
- * @return bool true if a redirect was successfully handled.
+ * @return bool True if a redirect was successfully handled.
*/
function dispatch() {
// the various namespaces supported by Special:Redirect
if ( !$this->typeName || count( $this->ids ) == 0 ) {
throw new ErrorPageError( 'revdelete-nooldid-title', 'revdelete-nooldid-text' );
}
+
+ # Allow the list type to adjust the passed target
+ $this->targetObj = RevisionDeleter::suggestTarget(
+ $this->typeName,
+ $this->targetObj,
+ $this->ids
+ );
+
$this->typeLabels = self::$UILabels[$this->typeName];
$list = $this->getList();
$list->reset();
$pageIsSuppressed = $bitfield & Revision::DELETED_RESTRICTED;
$this->mIsAllowed = $this->mIsAllowed && !( $canViewSuppressedOnly && $pageIsSuppressed );
- # Allow the list type to adjust the passed target
- $this->targetObj = RevisionDeleter::suggestTarget(
- $this->typeName,
- $this->targetObj,
- $this->ids
- );
-
$this->otherReason = $request->getVal( 'wpReason' );
# We need a target page!
if ( is_null( $this->targetObj ) ) {
return;
}
- $optional = array( 'maxjobs' => 0 );
+ $optional = array( 'maxjobs' => 0, 'maxtime' => 30, 'type' => false, 'async' => true );
$required = array_flip( array( 'title', 'tasks', 'signature', 'sigexpiry' ) );
$params = array_intersect_key( $this->getRequest()->getValues(), $required + $optional );
// Apply any default parameter values
$params += $optional;
- // Client will usually disconnect before checking the response,
- // but it needs to know when it is safe to disconnect. Until this
- // reaches ignore_user_abort(), it is not safe as the jobs won't run.
- ignore_user_abort( true ); // jobs may take a bit of time
- header( "HTTP/1.0 202 Accepted" );
- ob_flush();
- flush();
- // Once the client receives this response, it can disconnect
+ if ( $params['async'] ) {
+ // Client will usually disconnect before checking the response,
+ // but it needs to know when it is safe to disconnect. Until this
+ // reaches ignore_user_abort(), it is not safe as the jobs won't run.
+ ignore_user_abort( true ); // jobs may take a bit of time
+ header( "HTTP/1.0 202 Accepted" );
+ ob_flush();
+ flush();
+ // Once the client receives this response, it can disconnect
+ }
// Do all of the specified tasks...
if ( in_array( 'jobs', explode( '|', $params['tasks'] ) ) ) {
- self::executeJobs( (int)$params['maxjobs'] );
+ $runner = new JobRunner();
+ $response = $runner->run( array(
+ 'type' => $params['type'],
+ 'maxJobs' => $params['maxjobs'] ? $params['maxjobs'] : 1,
+ 'maxTime' => $params['maxtime'] ? $params['maxjobs'] : 30
+ ) );
+ if ( !$params['async'] ) {
+ print FormatJson::encode( $response, true );
+ }
}
}
ksort( $query ); // stable order
return hash_hmac( 'sha1', wfArrayToCgi( $query ), $wgSecretKey );
}
-
- /**
- * Run jobs from the job queue
- *
- * @note also called from Wiki.php
- *
- * @param int $maxJobs Maximum number of jobs to run
- * @return void
- */
- public static function executeJobs( $maxJobs ) {
- $n = $maxJobs; // number of jobs to run
- if ( $n < 1 ) {
- return;
- }
- try {
- $group = JobQueueGroup::singleton();
- $count = $group->executeReadyPeriodicTasks();
- if ( $count > 0 ) {
- wfDebugLog( 'jobqueue', "Executed $count periodic queue task(s)." );
- }
-
- do {
- $job = $group->pop( JobQueueGroup::TYPE_DEFAULT, JobQueueGroup::USE_CACHE );
- if ( $job ) {
- $output = $job->toString() . "\n";
- $t = -microtime( true );
- wfProfileIn( __METHOD__ . '-' . get_class( $job ) );
- $success = $job->run();
- wfProfileOut( __METHOD__ . '-' . get_class( $job ) );
- $group->ack( $job ); // done
- $t += microtime( true );
- $t = round( $t * 1000 );
- if ( $success === false ) {
- $output .= "Error: " . $job->getLastError() . ", Time: $t ms\n";
- } else {
- $output .= "Success, Time: $t ms\n";
- }
- wfDebugLog( 'jobqueue', $output );
- }
- } while ( --$n && $job );
- } catch ( MWException $e ) {
- MWExceptionHandler::rollbackMasterChangesAndLog( $e );
- // We don't want exceptions thrown during job execution to
- // be reported to the user since the output is already sent.
- // Instead we just log them.
- MWExceptionHandler::logException( $e );
- }
- }
}
* @param Title $title
* @param int $num The number of search results found
* @param null|SearchResultSet $titleMatches Results from title search
- * @param null|SearchResultSet $textMatches Results from text search
+ * @param null|SearchResultSet $textMatches Results from text search
*/
protected function showCreateLink( $title, $num, $titleMatches, $textMatches ) {
// show direct page/create link if applicable
* @param SearchResult $result
* @param string $lastInterwiki
* @param string $query
- * @param array $customCaptions iw prefix -> caption
+ * @param array $customCaptions Interwiki prefix -> caption
*
* @return string
*/
/**
* Empty function; submission is handled elsewhere.
*
- * @return bool false
+ * @return bool False
*/
function trySubmit() {
return false;
/**
* Execute page -- can output a file directly or show a listing of them.
*
- * @param string $subPage subpage, e.g. in
+ * @param string $subPage Subpage, e.g. in
* http://example.com/wiki/Special:UploadStash/foo.jpg, the "foo.jpg" part
* @return bool Success
*/
* If file available in stash, cats it out to the client as a simple HTTP response.
* n.b. Most sanity checking done in UploadStashLocalFile, so this is straightforward.
*
- * @param string $key the key of a particular requested file
+ * @param string $key The key of a particular requested file
* @throws HttpError
* @return bool
*/
* @param array $params Scaling parameters ( e.g. array( width => '50' ) );
* @param int $flags Scaling flags ( see File:: constants )
* @throws MWException
- * @return bool success
+ * @return bool Success
*/
private function outputRemoteScaledThumb( $file, $params, $flags ) {
// This global probably looks something like
/**
* Display a "successful action" page.
*
- * @param string $type condition of return to; see `executeReturnTo`
+ * @param string $type Condition of return to; see `executeReturnTo`
* @param string|Message $title Page's title
* @param string $msgname
* @param string $injected_html
/**
* Returns $this->getUser()->changeableGroups()
*
- * @return array array(
+ * @return array Array(
* 'add' => array( addablegroups ),
* 'remove' => array( removablegroups ),
* 'add-self' => array( addablegroups to self ),
}
/**
- * @return string wgVersion + a link to subversion revision of svn BASE
+ * @return string Global wgVersion + a link to subversion revision of svn BASE
*/
private static function getVersionLinkedSvn() {
global $IP;
/**
* @since 1.22 Returns the HEAD date in addition to the sha1 and link
- * @return bool|string wgVersion + HEAD sha1 stripped to the first 7 chars
+ * @return bool|string Global wgVersion + HEAD sha1 stripped to the first 7 chars
* with link and date, or false on failure
*/
private static function getVersionLinkedGit() {
* Return an array of subpages beginning with $search that this special page will accept.
*
* @param string $search Prefix to search for
- * @param integer $limit Maximum number of results to return
+ * @param int $limit Maximum number of results to return
* @return string[] Matching subpages
*/
public function prefixSearchSubpages( $search, $limit = 10 ) {
* HtmlPageLinkRenderer, we will be using them, so it seems prudent to
* already declare the dependency and inject them.
*
- * @param TitleFormatter $formatter formatter for generating the target title string
+ * @param TitleFormatter $formatter Formatter for generating the target title string
* @param string $baseUrl (currently unused, pending refactoring of Linker).
* Defaults to $wgArticlePath.
*/
* Returns the (partial) URL for the given page (including any section identifier).
*
* @param TitleValue $page The link's target
- * @param array $params any additional URL parameters.
+ * @param array $params Any additional URL parameters.
*
* @return string
*/
protected $localInterwikis;
/**
- * @param Language $language the language object to use for localizing namespace names.
- * @param GenderCache $genderCache the gender cache for generating gendered namespace names
+ * @param Language $language The language object to use for localizing namespace names.
+ * @param GenderCache $genderCache The gender cache for generating gendered namespace names
* @param string[]|string $localInterwikis
*/
public function __construct( Language $language, GenderCache $genderCache,
* @param int $namespace
* @param string $text
*
- * @throws InvalidArgumentException if the namespace is invalid
+ * @throws InvalidArgumentException If the namespace is invalid
* @return string
*/
public function getNamespaceName( $namespace, $text ) {
* Underscores will be replaced.
* @param string $fragment The fragment name (may be empty).
*
- * @throws InvalidArgumentException if the namespace is invalid
+ * @throws InvalidArgumentException If the namespace is invalid
* @return string
*/
public function formatTitle( $namespace, $text, $fragment = '' ) {
* @todo expand this to cover the functionality of Linker::linkUrl
*
* @param TitleValue $page The link's target
- * @param array $params any additional URL parameters.
+ * @param array $params Any additional URL parameters.
*
* @return string
*/
*
* @note Only minimal normalization is applied. Consider using TitleValue::getText() directly.
*
- * @param TitleValue $title the title to format
+ * @param TitleValue $title The title to format
*
* @return string
*/
/**
* Returns the title formatted for display, including the namespace name.
*
- * @param TitleValue $title the title to format
+ * @param TitleValue $title The title to format
*
* @return string
*/
/**
* Returns the title formatted for display, with namespace and fragment.
*
- * @param TitleValue $title the title to format
+ * @param TitleValue $title The title to format
*
* @return string
*/
*
* @note this only parses local page links, interwiki-prefixes etc. are not considered!
*
- * @param string $text the text to parse
- * @param int $defaultNamespace namespace to assume per default (usually NS_MAIN)
+ * @param string $text The text to parse
+ * @param int $defaultNamespace Namespace to assume per default (usually NS_MAIN)
*
* @throws MalformedTitleException If the text is not a valid representation of a page title.
* @return TitleValue
/**
* Verify whether the upload is sane.
- * @return mixed self::OK or else an array with error information
+ * @return mixed Const self::OK or else an array with error information
*/
public function verifyUpload() {
wfProfileIn( __METHOD__ );
* isAllowed() should be called as well for generic is-user-blocked or
* can-user-upload checking.
*
- * @param User $user object to verify the permissions against
+ * @param User $user User object to verify the permissions against
* @return mixed An array as returned by getUserPermissionsErrors or true
* in case the user has proper permissions.
*/
/**
* Callback to filter SVG Processing Instructions.
- * @param string $target processing instruction name
- * @param string $data processing instruction attribute and value
+ * @param string $target Processing instruction name
+ * @param string $data Processing instruction attribute and value
* @return bool (true if the filter identified something bad)
*/
public static function checkSvgPICallback( $target, $data ) {
* Calls the parent stashFile and updates the uploadsession table to handle "chunks"
*
* @param User|null $user
- * @return UploadStashFile stashed file
+ * @return UploadStashFile Stashed file
*/
public function stashFile( User $user = null ) {
// Stash file is the called on creating a new chunk session:
/**
* Add a chunk to the temporary directory
*
- * @param string $chunkPath path to temporary chunk file
- * @param int $chunkSize size of the current chunk
- * @param int $offset offset of current chunk ( mutch match database chunk offset )
+ * @param string $chunkPath Path to temporary chunk file
+ * @param int $chunkSize Size of the current chunk
+ * @param int $offset Offset of current chunk ( mutch match database chunk offset )
* @return Status
*/
public function addChunk( $chunkPath, $chunkSize, $offset ) {
/**
* Getter for file metadata.
*
- * @param string $key key under which file information is stored
+ * @param string $key Key under which file information is stored
* @return array
*/
public function getMetadata( $key ) {
/**
* Getter for fileProps
*
- * @param string $key key under which file information is stored
+ * @param string $key Key under which file information is stored
* @return array
*/
public function getFileProps( $key ) {
/**
* Helper function: Initialize the UploadStashFile for a given file.
*
- * @param string $key key under which to store the object
+ * @param string $key Key under which to store the object
* @throws UploadStashZeroLengthFileException
* @return bool
*/
* @since 1.23
*
* @param array $array1 The array to compare from
- * @param array $array2 An array to compare against
- * @param array ... More arrays to compare against
+ * @param array $array2,... More arrays to compare against
* @return array An array containing all the values from array1
* that are not present in any of the other arrays.
*/
"importlogpage": "Import log",
"importlogpagetext": "Administrative imports of pages with edit history from other wikis.",
"import-logentry-upload": "imported [[$1]] by file upload",
- "import-logentry-upload-detail": "$1 {{PLURAL:$1|revision|revisions}}",
+ "import-logentry-upload-detail": "$1 {{PLURAL:$1|revision|revisions}} imported",
"import-logentry-interwiki": "transwikied $1",
- "import-logentry-interwiki-detail": "$1 {{PLURAL:$1|revision|revisions}} from $2",
+ "import-logentry-interwiki-detail": "$1 {{PLURAL:$1|revision|revisions}} imported from $2",
"javascripttest": "JavaScript testing",
"javascripttest-backlink": "< $1",
"javascripttest-title": "Running $1 tests",
"importlogpage": "{{doc-logpage}}",
"importlogpagetext": "This text appears at the top of the [{{canonicalurl:Special:Log|type=import}} import log] special page.",
"import-logentry-upload": "This is the text of an entry in the Import log (and Recent Changes), after hour (and date, only in the Import log) and sysop name:\n* $1 is the name of the imported file",
- "import-logentry-upload-detail": "Used as success message. Parameters:\n* $1 - number of succeeded revisions\nSee also:\n* {{msg-mw|Import-logentry-interwiki-detail}}",
+ "import-logentry-upload-detail": "Used as success message and log entry. Parameters:\n* $1 - number of succeeded revisions\nSee also:\n* {{msg-mw|Import-logentry-interwiki-detail}}",
"import-logentry-interwiki": "Used as action listed in the log. Parameters:\n* $1 - page title",
- "import-logentry-interwiki-detail": "Used as success message. Parameters:\n* $1 - number of succeeded revisions\n* $2 - interwiki name\nSee also:\n* {{msg-mw|Import-logentry-upload-detail}}",
+ "import-logentry-interwiki-detail": "Used as success message and log entry. Parameters:\n* $1 - number of succeeded revisions\n* $2 - interwiki name\nSee also:\n* {{msg-mw|Import-logentry-upload-detail}}",
"javascripttest": "Title of the special page [[Special:JavaScriptTest]].\n\nSee also:\n* {{msg-mw|Javascripttest|title}}\n* {{msg-mw|Javascripttest-pagetext-noframework|summary}}\n* {{msg-mw|Javascripttest-pagetext-unknownframework|error message}}",
"javascripttest-backlink": "{{optional}}\nUsed as subtitle in [[Special:JavaScriptTest]]. Parameters:\n* $1 - page title",
"javascripttest-title": "Title of the special page when running a test suite. Parameters:\n* $1 is the name of the framework, for example QUnit.",
}
}
- $type = $this->getOption( 'type', false );
- $maxJobs = $this->getOption( 'maxjobs', false );
- $maxTime = $this->getOption( 'maxtime', false );
- $noThrottle = $this->hasOption( 'nothrottle' );
- $startTime = time();
-
- $group = JobQueueGroup::singleton();
- // Handle any required periodic queue maintenance
- $count = $group->executeReadyPeriodicTasks();
- if ( $count > 0 ) {
- $this->runJobsLog( "Executed $count periodic queue task(s)." );
- }
-
- $backoffs = $this->loadBackoffs(); // map of (type => UNIX expiry)
- $startingBackoffs = $backoffs; // avoid unnecessary writes
- $backoffExpireFunc = function ( $t ) {
- return $t > time();
- };
-
- $jobsRun = 0; // counter
- $flags = JobQueueGroup::USE_CACHE;
- $lastTime = microtime( true ); // time since last slave check
- do {
- $backoffs = array_filter( $backoffs, $backoffExpireFunc );
- $blacklist = $noThrottle ? array() : array_keys( $backoffs );
- if ( $type === false ) {
- $job = $group->pop( JobQueueGroup::TYPE_DEFAULT, $flags, $blacklist );
- } elseif ( in_array( $type, $blacklist ) ) {
- $job = false; // requested queue in backoff state
- } else {
- $job = $group->pop( $type ); // job from a single queue
- }
- if ( $job ) { // found a job
- ++$jobsRun;
- $this->runJobsLog( $job->toString() . " STARTING" );
-
- // Run the job...
- wfProfileIn( __METHOD__ . '-' . get_class( $job ) );
- $t = microtime( true );
- try {
- $status = $job->run();
- $error = $job->getLastError();
- } catch ( MWException $e ) {
- MWExceptionHandler::rollbackMasterChangesAndLog( $e );
- $status = false;
- $error = get_class( $e ) . ': ' . $e->getMessage();
- $e->report(); // write error to STDERR and the log
- }
- $timeMs = intval( ( microtime( true ) - $t ) * 1000 );
- wfProfileOut( __METHOD__ . '-' . get_class( $job ) );
-
- // Mark the job as done on success or when the job cannot be retried
- if ( $status !== false || !$job->allowRetries() ) {
- $group->ack( $job ); // done
- }
-
- if ( $status === false ) {
- $this->runJobsLog( $job->toString() . " t=$timeMs error={$error}" );
- } else {
- $this->runJobsLog( $job->toString() . " t=$timeMs good" );
- }
-
- // Back off of certain jobs for a while (for throttling and for errors)
- $ttw = $this->getBackoffTimeToWait( $job );
- if ( $status === false && mt_rand( 0, 49 ) == 0 ) {
- $ttw = max( $ttw, 30 );
- }
- if ( $ttw > 0 ) {
- $jType = $job->getType();
- $backoffs[$jType] = isset( $backoffs[$jType] ) ? $backoffs[$jType] : 0;
- $backoffs[$jType] = max( $backoffs[$jType], time() + $ttw );
- }
-
- // Break out if we hit the job count or wall time limits...
- if ( $maxJobs && $jobsRun >= $maxJobs ) {
- break;
- } elseif ( $maxTime && ( time() - $startTime ) > $maxTime ) {
- break;
- }
-
- // Don't let any of the main DB slaves get backed up
- $timePassed = microtime( true ) - $lastTime;
- if ( $timePassed >= 5 || $timePassed < 0 ) {
- wfWaitForSlaves( $lastTime );
- $lastTime = microtime( true );
- }
- // Don't let any queue slaves/backups fall behind
- if ( $jobsRun > 0 && ( $jobsRun % 100 ) == 0 ) {
- $group->waitForBackups();
- }
-
- // Bail if near-OOM instead of in a job
- $this->assertMemoryOK();
- }
- } while ( $job ); // stop when there are no jobs
- // Sync the persistent backoffs for the next runJobs.php pass
- $backoffs = array_filter( $backoffs, $backoffExpireFunc );
- if ( $backoffs !== $startingBackoffs ) {
- $this->syncBackoffs( $backoffs );
- }
- }
-
- /**
- * @param Job $job
- * @return int Seconds for this runner to avoid doing more jobs of this type
- * @see $wgJobBackoffThrottling
- */
- private function getBackoffTimeToWait( Job $job ) {
- global $wgJobBackoffThrottling;
-
- if ( !isset( $wgJobBackoffThrottling[$job->getType()] ) ||
- $job instanceof DuplicateJob // no work was done
- ) {
- return 0; // not throttled
- }
-
- $itemsPerSecond = $wgJobBackoffThrottling[$job->getType()];
- if ( $itemsPerSecond <= 0 ) {
- return 0; // not throttled
- }
-
- $seconds = 0;
- if ( $job->workItemCount() > 0 ) {
- $exactSeconds = $job->workItemCount() / $itemsPerSecond;
- // use randomized rounding
- $seconds = floor( $exactSeconds );
- $remainder = $exactSeconds - $seconds;
- $seconds += ( mt_rand() / mt_getrandmax() < $remainder ) ? 1 : 0;
- }
-
- return (int)$seconds;
- }
-
- /**
- * Get the previous backoff expiries from persistent storage
- *
- * @return array Map of (job type => backoff expiry timestamp)
- */
- private function loadBackoffs() {
- $section = new ProfileSection( __METHOD__ );
-
- $backoffs = array();
- $file = wfTempDir() . '/mw-runJobs-backoffs.json';
- if ( is_file( $file ) ) {
- $handle = fopen( $file, 'rb' );
- flock( $handle, LOCK_SH );
- $content = stream_get_contents( $handle );
- flock( $handle, LOCK_UN );
- fclose( $handle );
- $backoffs = json_decode( $content, true ) ? : array();
- }
-
- return $backoffs;
- }
-
- /**
- * Merge the current backoff expiries from persistent storage
- *
- * @param array $backoffs Map of (job type => backoff expiry timestamp)
- */
- private function syncBackoffs( array $backoffs ) {
- $section = new ProfileSection( __METHOD__ );
-
- $file = wfTempDir() . '/mw-runJobs-backoffs.json';
- $handle = fopen( $file, 'wb+' );
- flock( $handle, LOCK_EX );
- $content = stream_get_contents( $handle );
- $cBackoffs = json_decode( $content, true ) ? : array();
- foreach ( $backoffs as $type => $timestamp ) {
- $cBackoffs[$type] = isset( $cBackoffs[$type] ) ? $cBackoffs[$type] : 0;
- $cBackoffs[$type] = max( $cBackoffs[$type], $backoffs[$type] );
- }
- ftruncate( $handle, 0 );
- fwrite( $handle, json_encode( $backoffs ) );
- flock( $handle, LOCK_UN );
- fclose( $handle );
- }
-
- /**
- * Make sure that this script is not too close to the memory usage limit.
- * It is better to die in between jobs than OOM right in the middle of one.
- * @throws MWException
- */
- private function assertMemoryOK() {
- static $maxBytes = null;
- if ( $maxBytes === null ) {
- $m = array();
- if ( preg_match( '!^(\d+)(k|m|g|)$!i', ini_get( 'memory_limit' ), $m ) ) {
- list( , $num, $unit ) = $m;
- $conv = array( 'g' => 1073741824, 'm' => 1048576, 'k' => 1024, '' => 1 );
- $maxBytes = $num * $conv[strtolower( $unit )];
- } else {
- $maxBytes = 0;
- }
- }
- $usedBytes = memory_get_usage();
- if ( $maxBytes && $usedBytes >= 0.95 * $maxBytes ) {
- throw new MWException( "Detected excessive memory usage ($usedBytes/$maxBytes)." );
- }
+ $runner = new JobRunner();
+ $runner->setDebugHandler( array( $this, 'debugInternal' ) );
+ $runner->run( array(
+ 'type' => $this->getOption( 'type', false ),
+ 'maxJobs' => $this->getOption( 'maxjobs', false ),
+ 'maxTime' => $this->getOption( 'maxtime', false ),
+ 'throttle' => $this->hasOption( 'nothrottle' ) ? false : true,
+ ) );
}
/**
- * Log the job message
- * @param string $msg The message to log
+ * @param string $s
*/
- private function runJobsLog( $msg ) {
- $this->output( wfTimestamp( TS_DB ) . " $msg\n" );
- wfDebugLog( 'runJobs', $msg );
+ public function debugInternal( $s ) {
+ $this->output( $s );
}
}