* ResourceLoader no longer creates the 'mw.legacy' placeholder object. It has
been unused since 1.16 and was deprecated in 1.22. To deprecate a property
in JavaScript, use mw.log.deprecate() instead.
+* The 'user.groups' module, deprecated in 1.28, was removed.
+ Use the 'user' module instead.
* …
=== Deprecations in 1.34 ===
RequestContext::getMain()->setTitle( $wgTitle );
try {
- /* Construct an ApiMain with the arguments passed via the URL. What we get back
- * is some form of an ApiMain, possibly even one that produces an error message,
- * but we don't care here, as that is handled by the constructor.
- */
+ // Construct an ApiMain with the arguments passed via the URL. What we get back
+ // is some form of an ApiMain, possibly even one that produces an error message,
+ // but we don't care here, as that is handled by the constructor.
$processor = new ApiMain( RequestContext::getMain(), true );
// Last chance hook before executing the API
'IP' => __DIR__ . '/includes/libs/IP.php',
'IPTC' => __DIR__ . '/includes/media/IPTC.php',
'IRCColourfulRCFeedFormatter' => __DIR__ . '/includes/rcfeed/IRCColourfulRCFeedFormatter.php',
+ 'IStoreKeyEncoder' => __DIR__ . '/includes/libs/objectcache/IStoreKeyEncoder.php',
'IcuCollation' => __DIR__ . '/includes/collation/IcuCollation.php',
'IdentityCollation' => __DIR__ . '/includes/collation/IdentityCollation.php',
'ImageBuilder' => __DIR__ . '/maintenance/rebuildImages.php',
<?php
/**
- * Handle page deletion
- *
- * Copyright © 2012 Timo Tijhof
- *
* 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
*
* @file
* @ingroup Actions
- * @author Timo Tijhof
*/
/**
<?php
/**
- * action=edit handler
- *
- * Copyright © 2012 Timo Tijhof
- *
* 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
*
* @file
* @ingroup Actions
- * @author Timo Tijhof
*/
/**
- * Page edition handler
+ * Page edition handler (action=edit)
*
* This is a wrapper that will call the EditPage class or a custom editor from an extension.
*
<?php
/**
- * action=protect handler
- *
- * Copyright © 2012 Timo Tijhof
- *
* 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
*
* @file
* @ingroup Actions
- * @author Timo Tijhof
*/
/**
- * Handle page protection
+ * Handle page protection (action=protect)
*
* This is a wrapper that will call Article::protect().
*
<?php
/**
- * Handle action=render
- *
- * Copyright © 2012 Timo Tijhof
- *
* 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
*
* @file
* @ingroup Actions
- * @author Timo Tijhof
*/
/**
<?php
/**
- * action=unprotect handler
- *
- * Copyright © 2012 Timo Tijhof
- *
* 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
*
* @file
* @ingroup Actions
- * @author Timo Tijhof
*/
/**
- * Handle page unprotection
+ * Handle page unprotection (action=unprotect)
*
* This is a wrapper that will call Article::unprotect().
*
<?php
/**
- * An action that views article content
- *
- * Copyright © 2012 Timo Tijhof
- *
* 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
*
* @file
* @ingroup Actions
- * @author Timo Tijhof
*/
/**
'tideways_disable',
'tideways_xhprof_disable'
] );
+ } else {
+ return null;
}
}
* Call the first available function from $functions.
* @param array $functions
* @param array $args
+ * @return mixed
* @throws Exception
*/
protected static function callAny( array $functions, array $args = [] ) {
} else {
Wikimedia\suppressWarnings();
$handle = fopen( $this->getLockPath( $path ), 'a+' );
- if ( !$handle ) { // lock dir missing?
- mkdir( $this->lockDir, 0777, true );
- $handle = fopen( $this->getLockPath( $path ), 'a+' ); // try again
+ if ( !$handle && !is_dir( $this->lockDir ) ) {
+ // Create the lock directory in case it is missing
+ if ( mkdir( $this->lockDir, 0777, true ) ) {
+ $handle = fopen( $this->getLockPath( $path ), 'a+' ); // try again
+ } else {
+ $this->logger->error( "Cannot create directory '{$this->lockDir}'." );
+ }
}
Wikimedia\restoreWarnings();
}
*
* @ingroup Cache
*/
-abstract class BagOStuff implements IExpiringStore, LoggerAwareInterface {
+abstract class BagOStuff implements IExpiringStore, IStoreKeyEncoder, LoggerAwareInterface {
/** @var array[] Lock tracking */
protected $locks = [];
/** @var int ERR_* class constant */
* @param string $date The reference date in MW format
* @param callable|bool $progressCallback Optional, a function which will be called
* regularly during long-running operations with the percentage progress
- * as the first parameter.
+ * as the first parameter. [optional]
+ * @param int $limit Maximum number of keys to delete [default: INF]
*
* @return bool Success, false if unimplemented
*/
- public function deleteObjectsExpiringBefore( $date, $progressCallback = false ) {
+ public function deleteObjectsExpiringBefore( $date, $progressCallback = false, $limit = INF ) {
// stub
return false;
}
$this->backend->setDebug( $bool );
}
- public function deleteObjectsExpiringBefore( $date, $progressCallback = false ) {
- parent::deleteObjectsExpiringBefore( $date, $progressCallback );
- return $this->backend->deleteObjectsExpiringBefore( $date, $progressCallback );
+ public function deleteObjectsExpiringBefore( $date, $progressCallback = false, $limit = INF ) {
+ parent::deleteObjectsExpiringBefore( $date, $progressCallback, $limit );
+ return $this->backend->deleteObjectsExpiringBefore( $date, $progressCallback, $limit );
}
public function makeKeyInternal( $keyspace, $args ) {
*
* @file
* @ingroup Cache
- * @author 2015 Timo Tijhof
*/
/**
--- /dev/null
+<?php
+
+/**
+ * Generic interface for object stores with key encoding methods.
+ *
+ * @ingroup Cache
+ * @since 1.34
+ */
+interface IStoreKeyEncoder {
+ /**
+ * Make a global cache key.
+ *
+ * @param string $class Key class
+ * @param string|null $component [optional] Key component (starting with a key collection name)
+ * @return string Colon-delimited list of $keyspace followed by escaped components of $args
+ */
+ public function makeGlobalKey( $class, $component = null );
+
+ /**
+ * Make a cache key, scoped to this instance's keyspace.
+ *
+ * @param string $class Key class
+ * @param string|null $component [optional] Key component (starting with a key collection name)
+ * @return string Colon-delimited list of $keyspace followed by escaped components of $args
+ */
+ public function makeKey( $class, $component = null );
+}
return $this->caches[0]->unlock( $key );
}
- /**
- * Delete objects expiring before a certain date.
- *
- * Succeed if any of the child caches succeed.
- * @param string $date
- * @param bool|callable $progressCallback
- * @return bool
- */
- public function deleteObjectsExpiringBefore( $date, $progressCallback = false ) {
+ public function deleteObjectsExpiringBefore( $date, $progressCallback = false, $limit = INF ) {
$ret = false;
foreach ( $this->caches as $cache ) {
- if ( $cache->deleteObjectsExpiringBefore( $date, $progressCallback ) ) {
+ if ( $cache->deleteObjectsExpiringBefore( $date, $progressCallback, $limit ) ) {
$ret = true;
}
}
return $this->writeStore->unlock( $key );
}
- public function deleteObjectsExpiringBefore( $date, $progressCallback = false ) {
+ public function deleteObjectsExpiringBefore( $date, $progressCallback = false, $limit = INF ) {
return $this->writeStore->deleteObjectsExpiringBefore( $date, $progressCallback );
}
* @ingroup Cache
* @since 1.26
*/
-class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
+class WANObjectCache implements IExpiringStore, IStoreKeyEncoder, LoggerAwareInterface {
/** @var BagOStuff The local datacenter cache */
protected $cache;
/** @var MapCacheLRU[] Map of group PHP instance caches */
/** @var int */
protected $lastExpireAll = 0;
/** @var int */
- protected $purgePeriod = 100;
+ protected $purgePeriod = 10;
+ /** @var int */
+ protected $purgeLimit = 100;
/** @var int */
protected $shards = 1;
/** @var string */
* when a cluster is replicated to another site (with different host names)
* but each server has a corresponding replica in the other cluster.
*
- * - purgePeriod: The average number of object cache requests in between
+ * - purgePeriod: The average number of object cache writes in between
* garbage collection operations, where expired entries
* are removed from the database. Or in other words, the
* reciprocal of the probability of purging on any given
- * request. If this is set to zero, purging will never be
- * done.
+ * write. If this is set to zero, purging will never be done.
+ *
+ * - purgeLimit: Maximum number of rows to purge at once.
*
* - tableName: The table name to use, default is "objectcache".
*
if ( isset( $params['purgePeriod'] ) ) {
$this->purgePeriod = intval( $params['purgePeriod'] );
}
+ if ( isset( $params['purgeLimit'] ) ) {
+ $this->purgeLimit = intval( $params['purgeLimit'] );
+ }
if ( isset( $params['tableName'] ) ) {
$this->tableName = $params['tableName'];
}
$keysByTable[$serverIndex][$tableName][] = $key;
}
- $this->garbageCollect(); // expire old entries if any
-
$dataRows = [];
foreach ( $keysByTable as $serverIndex => $serverKeys ) {
try {
// Disabled
return;
}
- // Only purge on one in every $this->purgePeriod requests.
+ // Only purge on one in every $this->purgePeriod writes
if ( $this->purgePeriod !== 1 && mt_rand( 0, $this->purgePeriod - 1 ) ) {
return;
}
// Avoid repeating the delete within a few seconds
if ( $now > ( $this->lastExpireAll + 1 ) ) {
$this->lastExpireAll = $now;
- $this->expireAll();
+ $this->deleteObjectsExpiringBefore(
+ wfTimestamp( TS_MW, $now ),
+ false,
+ $this->purgeLimit
+ );
}
}
$this->deleteObjectsExpiringBefore( wfTimestampNow() );
}
- /**
- * Delete objects from the database which expire before a certain date.
- * @param string $timestamp
- * @param bool|callable $progressCallback
- * @return bool
- */
- public function deleteObjectsExpiringBefore( $timestamp, $progressCallback = false ) {
+ public function deleteObjectsExpiringBefore(
+ $timestamp,
+ $progressCallback = false,
+ $limit = INF
+ ) {
/** @noinspection PhpUnusedLocalVariableInspection */
$silenceScope = $this->silenceTransactionProfiler();
+
+ $count = 0;
for ( $serverIndex = 0; $serverIndex < $this->numServers; $serverIndex++ ) {
$db = null;
try {
[ 'keyname', 'exptime' ],
$conds,
__METHOD__,
- [ 'LIMIT' => 100, 'ORDER BY' => 'exptime' ] );
+ [ 'LIMIT' => 100, 'ORDER BY' => 'exptime' ]
+ );
if ( $rows === false || !$rows->numRows() ) {
break;
}
'exptime < ' . $db->addQuotes( $dbTimestamp ),
'keyname' => $keys
],
- __METHOD__ );
+ __METHOD__
+ );
+ $count += $db->affectedRows();
+ if ( $count >= $limit ) {
+ return true;
+ }
- if ( $progressCallback ) {
+ if ( is_callable( $progressCallback ) ) {
if ( intval( $totalSeconds ) === 0 ) {
$percent = 0;
} else {
return false;
}
}
+
return true;
}
<?php
/**
- * Message blobs storage used by ResourceLoader.
- *
* 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
* @file
* @author Roan Kattouw
* @author Trevor Parscal
- * @author Timo Tijhof
*/
use MediaWiki\MediaWikiServices;
<?php
/**
- * ResourceLoader module for populating language specific data.
- *
* 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
*
* @file
* @author Santhosh Thottingal
- * @author Timo Tijhof
*/
/**
<?php
/**
- * ResourceLoader module for skin stylesheets.
- *
* 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
* http://www.gnu.org/copyleft/gpl.html
*
* @file
- * @author Timo Tijhof
*/
+/**
+ * ResourceLoader module for skin stylesheets.
+ */
class ResourceLoaderSkinModule extends ResourceLoaderFileModule {
/**
* All skins are assumed to be compatible with mobile
*
* @file
* @ingroup Benchmark
- * @author Timo Tijhof
*/
require_once __DIR__ . '/Benchmarker.php';
*
* @file
* @ingroup Benchmark
- * @author Timo Tijhof
*/
require_once __DIR__ . '/Benchmarker.php';
*
* @file
* @ingroup Benchmark
- * @author Timo Tijhof
*/
require_once __DIR__ . '/Benchmarker.php';
* symbols being documented but not declared or defined.
*
* Copyright (C) 2012 Tamas Imrei <tamas.imrei@gmail.com> https://virtualtee.blogspot.com/
- * Copyright (C) 2015 Timo Tijhof
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the "Software"),
<?php
/**
- * Remove all cache entries for ResourceLoader modules from the database.
- *
* 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
*
* @file
* @ingroup Maintenance
- * @author Timo Tijhof
*/
use Wikimedia\Rdbms\IDatabase;
require_once __DIR__ . '/Maintenance.php';
/**
- * Maintenance script to purge the module_deps database cache table.
+ * Maintenance script to purge the module_deps database cache table for ResourceLoader.
*
* @ingroup Maintenance
*/
'xmlns' => 'http://a9.com/-/spec/opensearch/1.1/',
'xmlns:moz' => 'http://www.mozilla.org/2006/browser/search/' ] );
-/* The spec says the ShortName must be no longer than 16 characters,
- * but 16 is *realllly* short. In practice, browsers don't appear to care
- * when we give them a longer string, so we're no longer attempting to trim.
- *
- * Note: ShortName and the <link title=""> need to match; they are used as
- * a key for identifying if the search engine has been added already, *and*
- * as the display name presented to the end-user.
- *
- * Behavior seems about the same between Firefox and IE 7/8 here.
- * 'Description' doesn't appear to be used by either.
- */
+// The spec says the ShortName must be no longer than 16 characters,
+// but 16 is *realllly* short. In practice, browsers don't appear to care
+// when we give them a longer string, so we're no longer attempting to trim.
+//
+// Note: ShortName and the <link title=""> need to match; they are used as
+// a key for identifying if the search engine has been added already, *and*
+// as the display name presented to the end-user.
+//
+// Behavior seems about the same between Firefox and IE 7/8 here.
+// 'Description' doesn't appear to be used by either.
$fullName = wfMessage( 'opensearch-desc' )->inContentLanguage()->text();
print Xml::element( 'ShortName', null, $fullName );
print Xml::element( 'Description', null, $fullName );
'class' => ResourceLoaderWikiModule::class,
'styles' => [ 'MediaWiki:Filepage.css' ],
],
- 'user.groups' => [
- // Merged into 'user' since MediaWiki 1.28 - kept for back-compat
- 'dependencies' => 'user',
- 'targets' => [ 'desktop', 'mobile' ],
- ],
// Scripts managed by the current user (stored in their user space)
'user' => [ 'class' => ResourceLoaderUserModule::class ],
'use strict';
var util,
- config = require( './config.json' ),
- origConfig = config;
+ config = require( './config.json' );
/**
* Encode the string like PHP's rawurlencode
*/
util = {
- /* Main body */
-
- setOptionsForTest: function ( opts ) {
- if ( !window.QUnit ) {
- throw new Error( 'Modifying options not allowed outside unit tests' );
- }
- config = $.extend( {}, config, opts );
- },
-
- resetOptionsForTest: function () {
- if ( !window.QUnit ) {
- throw new Error( 'Resetting options not allowed outside unit tests' );
- }
- config = origConfig;
- },
-
/**
* Encode the string like PHP's rawurlencode
*
}
};
+ // Not allowed outside unit tests
+ if ( window.QUnit ) {
+ util.setOptionsForTest = function ( opts ) {
+ var oldConfig = config;
+ config = $.extend( {}, config, opts );
+ return oldConfig;
+ };
+ }
+
/**
* Initialisation of mw.util.$content
*/
/*!
* Augment mw.loader to facilitate module-level profiling.
*
- * @author Timo Tijhof
* @since 1.32
*/
/* global mw */
QUnit.module( 'mediawiki.util', QUnit.newMwEnvironment( {
setup: function () {
$.fn.updateTooltipAccessKeys.setTestMode( true );
+ this.origConfig = mw.util.setOptionsForTest( {
+ FragmentMode: [ 'legacy', 'html5' ],
+ LoadScript: '/w/load.php'
+ } );
},
teardown: function () {
$.fn.updateTooltipAccessKeys.setTestMode( false );
- mw.util.resetOptionsForTest();
+ mw.util.setOptionsForTest( this.origConfig );
},
messages: {
// Used by accessKeyLabel in test for addPortletLink