==== Upgraded external libraries ====
* Updated es5-shim from v4.1.5 to v4.5.8
+* Updated composer/semver from v1.4.1 to v1.4.2
+* Updated wikimedia/php-session-serializer from v1.0.3 to v1.0.4
==== New external libraries ====
* Added wikimedia/scoped-callback v1.0.0
$wgAutoloadLocalClasses = [
'APCBagOStuff' => __DIR__ . '/includes/libs/objectcache/APCBagOStuff.php',
+ 'APCUBagOStuff' => __DIR__ . '/includes/libs/objectcache/APCUBagOStuff.php',
'AbstractContent' => __DIR__ . '/includes/content/AbstractContent.php',
'Action' => __DIR__ . '/includes/actions/Action.php',
'ActiveUsersPager' => __DIR__ . '/includes/specials/pagers/ActiveUsersPager.php',
"wiki": "https://www.mediawiki.org/"
},
"require": {
- "composer/semver": "1.4.1",
+ "composer/semver": "1.4.2",
"cssjanus/cssjanus": "1.1.2",
"ext-ctype": "*",
"ext-iconv": "*",
"wikimedia/composer-merge-plugin": "1.3.1",
"wikimedia/html-formatter": "1.0.1",
"wikimedia/ip-set": "1.1.0",
- "wikimedia/php-session-serializer": "1.0.3",
+ "wikimedia/php-session-serializer": "1.0.4",
"wikimedia/relpath": "1.0.3",
"wikimedia/running-stat": "1.1.0",
"wikimedia/scoped-callback": "1.0.0",
* - CACHE_NONE: Do not cache
* - CACHE_DB: Store cache objects in the DB
* - CACHE_MEMCACHED: MemCached, must specify servers in $wgMemCachedServers
- * - CACHE_ACCEL: APC, XCache or WinCache
+ * - CACHE_ACCEL: APC, APCU, XCache or WinCache
* - (other): A string may be used which identifies a cache
* configuration in $wgObjectCaches.
*
],
'apc' => [ 'class' => 'APCBagOStuff', 'reportDupes' => false ],
+ 'apcu' => [ 'class' => 'APCUBagOStuff', 'reportDupes' => false ],
'xcache' => [ 'class' => 'XCacheBagOStuff', 'reportDupes' => false ],
'wincache' => [ 'class' => 'WinCacheBagOStuff', 'reportDupes' => false ],
'memcached-php' => [ 'class' => 'MemcachedPhpBagOStuff', 'loggroup' => 'memcached' ],
* It will be either HTML or plain text based on isCommandLine().
*/
public function report() {
- MWExceptionRenderer::output( $this, MWExceptionRenderer::AS_PRETTY );
+ global $wgMimeType;
+
+ if ( defined( 'MW_API' ) ) {
+ // Unhandled API exception, we can't be sure that format printer is alive
+ self::header( 'MediaWiki-API-Error: internal_api_error_' . get_class( $this ) );
+ wfHttpError( 500, 'Internal Server Error', $this->getText() );
+ } elseif ( self::isCommandLine() ) {
+ $message = $this->getText();
+ // T17602: STDERR may not be available
+ if ( defined( 'STDERR' ) ) {
+ fwrite( STDERR, $message );
+ } else {
+ echo $message;
+ }
+ } else {
+ self::statusHeader( 500 );
+ self::header( "Content-Type: $wgMimeType; charset=utf-8" );
+
+ $this->reportHTML();
+ }
}
/**
// removed.
$e->report();
} else {
- MWExceptionRenderer::output(
- $e, MWExceptionRenderer::AS_PRETTY );
+ MWExceptionRenderer::output( $e, MWExceptionRenderer::AS_PRETTY );
}
} catch ( Exception $e2 ) {
// Exception occurred from within exception handler
// Show a simpler message for the original exception,
// don't try to invoke report()
- MWExceptionRenderer::output( $e, MWExceptionRenderer::AS_PRETTY, $e2 );
+ MWExceptionRenderer::output( $e, MWExceptionRenderer::AS_RAW, $e2 );
}
}
public static function output( $e, $mode, $eNew = null ) {
global $wgMimeType;
- if ( $e instanceof DBConnectionError ) {
- self::reportOutageHTML( $e );
- return;
- }
-
if ( defined( 'MW_API' ) ) {
// Unhandled API exception, we can't be sure that format printer is alive
self::header( 'MediaWiki-API-Error: internal_api_error_' . get_class( $e ) );
} elseif ( self::isCommandLine() ) {
self::printError( self::getText( $e ) );
} elseif ( $mode === self::AS_PRETTY ) {
- self::statusHeader( 500 );
- self::header( "Content-Type: $wgMimeType; charset=utf-8" );
- self::reportHTML( $e );
+ if ( $e instanceof DBConnectionError ) {
+ self::reportOutageHTML( $e );
+ } else {
+ self::statusHeader( 500 );
+ self::header( "Content-Type: $wgMimeType; charset=utf-8" );
+ self::reportHTML( $e );
+ }
} else {
if ( $eNew ) {
$message = "MediaWiki internal error.\n\n";
protected $objectCaches = [
'xcache' => 'xcache_get',
'apc' => 'apc_fetch',
+ 'apcu' => 'apcu_fetch',
'wincache' => 'wincache_ucache_get'
];
// 1.28
[ 'addIndex', 'recentchanges', 'rc_name_type_patrolled_timestamp',
'patch-add-rc_name_type_patrolled_timestamp_index.sql' ],
+ [ 'addField', 'change_tag', 'ct_id', 'patch-change_tag-ct_id.sql' ],
+ [ 'addField', 'tag_summary', 'ts_id', 'patch-tag_summary-ts_id.sql' ],
];
}
'patch-add-rc_name_type_patrolled_timestamp_index.sql' ],
[ 'doRevisionPageRevIndexNonUnique' ],
[ 'doNonUniquePlTlIl' ],
+ [ 'addField', 'change_tag', 'ct_id', 'patch-change_tag-ct_id.sql' ],
+ [ 'addField', 'tag_summary', 'ts_id', 'patch-tag_summary-ts_id.sql' ],
];
}
// 1.28
[ 'addIndex', 'recentchanges', 'rc_name_type_patrolled_timestamp',
'patch-add-rc_name_type_patrolled_timestamp_index.sql' ],
+ [ 'addField', 'change_tag', 'ct_id', 'patch-change_tag-ct_id.sql' ],
+ [ 'addField', 'tag_summary', 'ts_id', 'patch-tag_summary-ts_id.sql' ],
// KEEP THIS AT THE BOTTOM!!
[ 'doRebuildDuplicateFunction' ],
[ 'addSequence', 'archive', false, 'archive_ar_id_seq' ],
[ 'addSequence', 'externallinks', false, 'externallinks_el_id_seq' ],
[ 'addSequence', 'watchlist', false, 'watchlist_wl_id_seq' ],
+ [ 'addSequence', 'change_tag', false, 'change_tag_ct_id_seq' ],
+ [ 'addSequence', 'tag_summary', false, 'tag_summary_ts_id_seq' ],
# new tables
[ 'addTable', 'category', 'patch-category.sql' ],
// 1.28
[ 'addPgIndex', 'recentchanges', 'rc_name_type_patrolled_timestamp',
'( rc_namespace, rc_type, rc_patrolled, rc_timestamp )' ],
+ [ 'addPgField', 'change_tag', 'ct_id',
+ "INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('change_tag_ct_id_seq')" ],
+ [ 'addPgField', 'tag_summary', 'ts_id',
+ "INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('tag_summary_ts_id_seq')" ],
];
}
// 1.28
[ 'addIndex', 'recentchanges', 'rc_name_type_patrolled_timestamp',
'patch-add-rc_name_type_patrolled_timestamp_index.sql' ],
+ [ 'addField', 'change_tag', 'ct_id', 'patch-change_tag-ct_id.sql' ],
+ [ 'addField', 'tag_summary', 'ts_id', 'patch-tag_summary-ts_id.sql' ],
];
}
"config-memory-bad": "<strong>Warning:</strong> PHP's <code>memory_limit</code> is $1.\nThis is probably too low.\nThe installation may fail!",
"config-xcache": "[http://xcache.lighttpd.net/ XCache] is installed",
"config-apc": "[http://www.php.net/apc APC] is installed",
+ "config-apcu": "[http://www.php.net/apcu APCu] is installed",
"config-wincache": "[http://www.iis.net/download/WinCacheForPhp WinCache] is installed",
"config-no-cache-apcu": "<strong>Warning:</strong> Could not find [http://www.php.net/apcu APCu], [http://xcache.lighttpd.net/ XCache] or [http://www.iis.net/download/WinCacheForPhp WinCache].\nObject caching is not enabled.",
"config-mod-security": "<strong>Warning:</strong> Your web server has [http://modsecurity.org/ mod_security]/mod_security2 enabled. Many common configurations of this will cause problems for MediaWiki and other software that allows users to post arbitrary content.\nIf possible, this should be disabled. Otherwise, refer to [http://modsecurity.org/documentation/ mod_security documentation] or contact your host's support if you encounter random errors.",
"config-cache-options": "Settings for object caching:",
"config-cache-help": "Object caching is used to improve the speed of MediaWiki by caching frequently used data.\nMedium to large sites are highly encouraged to enable this, and small sites will see benefits as well.",
"config-cache-none": "No caching (no functionality is removed, but speed may be impacted on larger wiki sites)",
- "config-cache-accel": "PHP object caching (APC, XCache or WinCache)",
+ "config-cache-accel": "PHP object caching (APC, APCu, XCache or WinCache)",
"config-cache-memcached": "Use Memcached (requires additional setup and configuration)",
"config-memcached-servers": "Memcached servers:",
"config-memcached-help": "List of IP addresses to use for Memcached.\nShould specify one per line and specify the port to be used. For example:\n 127.0.0.1:11211\n 192.168.1.25:1234",
"config-memory-bad": "Parameters:\n* $1 is the configured <code>memory_limit</code>.",
"config-xcache": "Message indicates if this program is available",
"config-apc": "Message indicates if this program is available",
+ "config-apcu": "Message indicates if this program is available",
"config-wincache": "Message indicates if this program is available",
"config-no-cache-apcu": "Status message in the MediaWiki installer environment checks.",
"config-mod-security": "Status message in the MediaWiki installer environment checks.",
<?php
/**
- * APC-backed function memoization
+ * APC-backed and APCu-backed function memoization
*
* This class provides memoization for pure functions. A function is pure
* if its result value depends on nothing other than its input parameters
*
* The first invocation of the memoized callable with a particular set of
* arguments will be delegated to the underlying callable. Repeat invocations
- * with the same input parameters will be served from APC.
+ * with the same input parameters will be served from APC or APCu.
*
* @par Example:
* @code
}
/**
- * Fetch the result of a previous invocation from APC.
+ * Fetch the result of a previous invocation from APC or APCu.
*
* @param string $key
* @param bool &$success
$success = false;
if ( function_exists( 'apc_fetch' ) ) {
return apc_fetch( $key, $success );
+ } elseif ( function_exists( 'apcu_fetch' ) ) {
+ return apcu_fetch( $key, $success );
}
return false;
}
/**
- * Store the result of an invocation in APC.
+ * Store the result of an invocation in APC or APCu.
*
* @param string $key
* @param mixed $result
protected function storeResult( $key, $result ) {
if ( function_exists( 'apc_store' ) ) {
apc_store( $key, $result, $this->ttl );
+ } elseif ( function_exists( 'apcu_store' ) ) {
+ apcu_store( $key, $result, $this->ttl );
}
}
}
protected function doGet( $key, $flags = 0 ) {
- $val = apc_fetch( $key . self::KEY_SUFFIX );
+ return $this->getUnserialize(
+ apc_fetch( $key . self::KEY_SUFFIX )
+ );
+ }
- if ( is_string( $val ) && !$this->nativeSerialize ) {
- $val = $this->isInteger( $val )
- ? intval( $val )
- : unserialize( $val );
+ protected function getUnserialize( $value ) {
+ if ( is_string( $value ) && !$this->nativeSerialize ) {
+ $value = $this->isInteger( $value )
+ ? intval( $value )
+ : unserialize( $value );
}
-
- return $val;
+ return $value;
}
public function set( $key, $value, $exptime = 0, $flags = 0 ) {
+ apc_store(
+ $key . self::KEY_SUFFIX,
+ $this->setSerialize( $value ),
+ $exptime
+ );
+
+ return true;
+ }
+
+ protected function setSerialize( $value ) {
if ( !$this->nativeSerialize && !$this->isInteger( $value ) ) {
$value = serialize( $value );
}
-
- apc_store( $key . self::KEY_SUFFIX, $value, $exptime );
-
- return true;
+ return $value;
}
public function delete( $key ) {
--- /dev/null
+<?php
+/**
+ * Object caching using PHP's APCU accelerator.
+ *
+ * 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 Cache
+ */
+
+/**
+ * This is a wrapper for APCU's shared memory functions
+ *
+ * @ingroup Cache
+ */
+class APCUBagOStuff extends APCBagOStuff {
+ /**
+ * Constructor
+ *
+ * Available parameters are:
+ * - nativeSerialize: If true, pass objects to apcu_store(), and trust it
+ * to serialize them correctly. If false, serialize
+ * all values in PHP.
+ *
+ * @param array $params
+ */
+ public function __construct( array $params = [] ) {
+ parent::__construct( $params );
+ }
+
+ protected function doGet( $key, $flags = 0 ) {
+ return $this->getUnserialize(
+ apcu_fetch( $key . self::KEY_SUFFIX )
+ );
+ }
+
+ public function set( $key, $value, $exptime = 0, $flags = 0 ) {
+ apcu_store(
+ $key . self::KEY_SUFFIX,
+ $this->setSerialize( $value ),
+ $exptime
+ );
+
+ return true;
+ }
+
+ public function delete( $key ) {
+ apcu_delete( $key . self::KEY_SUFFIX );
+
+ return true;
+ }
+
+ public function incr( $key, $value = 1 ) {
+ /**
+ * @todo When we only support php 7 or higher remove this hack
+ *
+ * https://github.com/krakjoe/apcu/issues/166
+ */
+ if ( apcu_exists( $key . self::KEY_SUFFIX ) ) {
+ return apcu_inc( $key . self::KEY_SUFFIX, $value );
+ } else {
+ return apcu_set( $key . self::KEY_SUFFIX, $value );
+ }
+ }
+
+ public function decr( $key, $value = 1 ) {
+ /**
+ * @todo When we only support php 7 or higher remove this hack
+ *
+ * https://github.com/krakjoe/apcu/issues/166
+ */
+ if ( apcu_exists( $key . self::KEY_SUFFIX ) ) {
+ return apcu_dec( $key . self::KEY_SUFFIX, $value );
+ } else {
+ return apcu_set( $key . self::KEY_SUFFIX, -$value );
+ }
+ }
+}
*
* - ObjectCache::getLocalServerInstance( $fallbackType )
* Purpose: Memory cache for very hot keys.
- * Stored only on the individual web server (typically APC for web requests,
+ * Stored only on the individual web server (typically APC or APCu for web requests,
* and EmptyBagOStuff in CLI mode).
* Not replicated to the other servers.
*
/**
* Factory function for CACHE_ACCEL (referenced from DefaultSettings.php)
*
- * This will look for any APC style server-local cache.
+ * This will look for any APC or APCu style server-local cache.
* A fallback cache can be specified if none is found.
*
* // Direct calls
public static function getLocalServerInstance( $fallback = CACHE_NONE ) {
if ( function_exists( 'apc_fetch' ) ) {
$id = 'apc';
+ } elseif ( function_exists( 'apcu_fetch' ) ) {
+ $id = 'apcu';
} elseif ( function_exists( 'xcache_get' ) && wfIniGetBool( 'xcache.var_size' ) ) {
$id = 'xcache';
} elseif ( function_exists( 'wincache_ucache_get' ) ) {
* @deprecated since 1.21, getContent() should be used instead.
*/
public function getText( $audience = Revision::FOR_PUBLIC, User $user = null ) {
- ContentHandler::deprecated( __METHOD__, '1.21' );
+ wfDeprecated( __METHOD__, '1.21' );
$this->loadLastEdit();
if ( $this->mLastRevision ) {
'text' => $ilLangName,
'title' => $ilTitle,
'class' => $class,
+ 'link-class' => 'interlanguage-link-target',
'lang' => $ilInterwikiCodeBCP47,
'hreflang' => $ilInterwikiCodeBCP47,
];
if ( !$title->equals( $oldTitle ) ) {
$oldTitleText = $oldTitle->getPrefixedText();
- $oldTitleText = $this->msg( 'rc-old-title' )->params( $oldTitleText )->escaped();
+ $oldTitleText = Html::rawElement(
+ 'span',
+ [ 'class' => 'mw-newpages-oldtitle' ],
+ $this->msg( 'rc-old-title' )->params( $oldTitleText )->escaped()
+ );
}
return "<li{$css}>{$time} {$dm}{$plink} {$hist} {$dm}{$length} "
"searchprofile-advanced-tooltip": "Search in custom namespaces",
"search-result-size": "$1 ({{PLURAL:$2|1 word|$2 words}})",
"search-result-category-size": "{{PLURAL:$1|1 member|$1 members}} ({{PLURAL:$2|1 subcategory|$2 subcategories}}, {{PLURAL:$3|1 file|$3 files}})",
- "search-redirect": "(redirect $1)",
+ "search-redirect": "(redirect from $1)",
"search-section": "(section $1)",
"search-category": "(category $1)",
"search-file-match": "(matches file content)",
--- /dev/null
+-- Primary key in change_tag table
+
+ALTER TABLE /*$wgDBprefix*/change_tag
+ ADD COLUMN ct_id INT UNSIGNED NOT NULL AUTO_INCREMENT FIRST,
+ ADD PRIMARY KEY (ct_id);
--- /dev/null
+-- Primary key in tag_summary table
+
+ALTER TABLE /*$wgDBprefix*/tag_summary
+ ADD COLUMN ts_id INT UNSIGNED NOT NULL AUTO_INCREMENT FIRST,
+ ADD PRIMARY KEY (ts_id);
--- /dev/null
+-- Primary key in change_tag table
+
+ALTER TABLE /*_*/change_tag ADD ct_id INT IDENTITY;
+ALTER TABLE /*_*/change_tag ADD CONSTRAINT pk_change_tag PRIMARY KEY(ct_id)
--- /dev/null
+-- Primary key in tag_summary table
+
+ALTER TABLE /*_*/tag_summary ADD ts_id INT IDENTITY;
+ALTER TABLE /*_*/tag_summary ADD CONSTRAINT pk_tag_summary PRIMARY KEY(ts_id)
-- A table to track tags for revisions, logs and recent changes.
CREATE TABLE /*_*/change_tag (
+ ct_id int NOT NULL PRIMARY KEY IDENTITY,
-- RCID for the change
ct_rc_id int NULL REFERENCES /*_*/recentchanges(rc_id),
-- LOGID for the change
-- Rollup table to pull a LIST of tags simply without ugly GROUP_CONCAT
-- that only works on MySQL 4.1+
CREATE TABLE /*_*/tag_summary (
+ ts_id int NOT NULL PRIMARY KEY IDENTITY,
-- RCID for the change
ts_rc_id int NULL REFERENCES /*_*/recentchanges(rc_id),
-- LOGID for the change
--- /dev/null
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.change_tag ADD (
+ct_id NUMBER NOT NULL,
+);
+ALTER TABLE &mw_prefix.change_tag ADD CONSTRAINT &mw_prefix.change_tag_pk PRIMARY KEY (ct_id);
--- /dev/null
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.tag_summary ADD (
+ts_id NUMBER NOT NULL,
+);
+ALTER TABLE &mw_prefix.tag_summary ADD CONSTRAINT &mw_prefix.tag_summary_pk PRIMARY KEY (ts_id);
ALTER TABLE &mw_prefix.updatelog ADD CONSTRAINT &mw_prefix.updatelog_pk PRIMARY KEY (ul_key);
CREATE TABLE &mw_prefix.change_tag (
+ ct_id NUMBER NOT NULL,
ct_rc_id NUMBER NULL,
ct_log_id NUMBER NULL,
ct_rev_id NUMBER NULL,
ct_tag VARCHAR2(255) NOT NULL,
ct_params BLOB NULL
);
+ALTER TABLE &mw_prefix.change_tag ADD CONSTRAINT &mw_prefix.change_tag_pk PRIMARY KEY (ct_id);
CREATE UNIQUE INDEX &mw_prefix.change_tag_u01 ON &mw_prefix.change_tag (ct_rc_id,ct_tag);
CREATE UNIQUE INDEX &mw_prefix.change_tag_u02 ON &mw_prefix.change_tag (ct_log_id,ct_tag);
CREATE UNIQUE INDEX &mw_prefix.change_tag_u03 ON &mw_prefix.change_tag (ct_rev_id,ct_tag);
CREATE INDEX &mw_prefix.change_tag_i01 ON &mw_prefix.change_tag (ct_tag,ct_rc_id,ct_rev_id,ct_log_id);
CREATE TABLE &mw_prefix.tag_summary (
+ ts_id NUMBER NOT NULL,
ts_rc_id NUMBER NULL,
ts_log_id NUMBER NULL,
ts_rev_id NUMBER NULL,
ts_tags BLOB NOT NULL
);
+ALTER TABLE &mw_prefix.tag_summary ADD CONSTRAINT &mw_prefix.tag_summary_pk PRIMARY KEY (ts_id);
CREATE UNIQUE INDEX &mw_prefix.tag_summary_u01 ON &mw_prefix.tag_summary (ts_rc_id);
CREATE UNIQUE INDEX &mw_prefix.tag_summary_u02 ON &mw_prefix.tag_summary (ts_log_id);
CREATE UNIQUE INDEX &mw_prefix.tag_summary_u03 ON &mw_prefix.tag_summary (ts_rev_id);
DROP SEQUENCE IF EXISTS archive_ar_id_seq CASCADE;
DROP SEQUENCE IF EXISTS externallinks_el_id_seq CASCADE;
DROP SEQUENCE IF EXISTS sites_site_id_seq CASCADE;
+DROP SEQUENCE IF EXISTS change_tag_ct_id_seq CASCADE;
+DROP SEQUENCE IF EXISTS tag_summary_ts_id_seq CASCADE;
DROP FUNCTION IF EXISTS page_deleted() CASCADE;
DROP FUNCTION IF EXISTS ts2_page_title() CASCADE;
DROP FUNCTION IF EXISTS ts2_page_text() CASCADE;
CREATE UNIQUE INDEX category_title ON category(cat_title);
CREATE INDEX category_pages ON category(cat_pages);
+CREATE SEQUENCE change_tag_ct_id_seq;
CREATE TABLE change_tag (
+ ct_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('change_tag_ct_id_seq'),
ct_rc_id INTEGER NULL,
ct_log_id INTEGER NULL,
ct_rev_id INTEGER NULL,
CREATE UNIQUE INDEX change_tag_rev_tag ON change_tag(ct_rev_id,ct_tag);
CREATE INDEX change_tag_tag_id ON change_tag(ct_tag,ct_rc_id,ct_rev_id,ct_log_id);
+CREATE SEQUENCE tag_summary_ts_id_seq;
CREATE TABLE tag_summary (
- ts_rc_id INTEGER NULL,
- ts_log_id INTEGER NULL,
- ts_rev_id INTEGER NULL,
- ts_tags TEXT NOT NULL
+ ts_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('tag_summary_ts_id_seq'),
+ ts_rc_id INTEGER NULL,
+ ts_log_id INTEGER NULL,
+ ts_rev_id INTEGER NULL,
+ ts_tags TEXT NOT NULL
);
CREATE UNIQUE INDEX tag_summary_rc_id ON tag_summary(ts_rc_id);
CREATE UNIQUE INDEX tag_summary_log_id ON tag_summary(ts_log_id);
--- /dev/null
+DROP TABLE IF EXISTS /*_*/change_tag_tmp;
+
+CREATE TABLE /*$wgDBprefix*/change_tag_tmp (
+ ct_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ ct_rc_id int NULL,
+ ct_log_id int NULL,
+ ct_rev_id int NULL,
+ ct_tag varchar(255) NOT NULL,
+ ct_params blob NULL
+);
+
+INSERT OR IGNORE INTO /*_*/change_tag_tmp (
+ ct_rc_id, ct_log_id, ct_rev_id, ct_tag, ct_params )
+ SELECT
+ ct_rc_id, ct_log_id, ct_rev_id, ct_tag, ct_params
+ FROM /*_*/change_tag;
+
+DROP TABLE /*_*/change_tag;
+
+ALTER TABLE /*_*/change_tag_tmp RENAME TO /*_*/change_tag;
+
+CREATE UNIQUE INDEX /*i*/change_tag_rc_tag ON /*_*/change_tag (ct_rc_id,ct_tag);
+CREATE UNIQUE INDEX /*i*/change_tag_log_tag ON /*_*/change_tag (ct_log_id,ct_tag);
+CREATE UNIQUE INDEX /*i*/change_tag_rev_tag ON /*_*/change_tag (ct_rev_id,ct_tag);
+CREATE INDEX /*i*/change_tag_tag_id ON /*_*/change_tag (ct_tag,ct_rc_id,ct_rev_id,ct_log_id);
--- /dev/null
+DROP TABLE IF EXISTS /*_*/tag_summary_tmp;
+
+CREATE TABLE /*$wgDBprefix*/tag_summary_tmp (
+ ts_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ ts_rc_id int NULL,
+ ts_log_id int NULL,
+ ts_rev_id int NULL,
+ ts_tags blob NOT NULL
+);
+
+INSERT OR IGNORE INTO /*_*/tag_summary_tmp (
+ ts_rc_id, ts_log_id, ts_rev_id, ts_tags )
+ SELECT
+ ts_rc_id, ts_log_id, ts_rev_id, ts_tags
+ FROM /*_*/tag_summary;
+
+DROP TABLE /*_*/tag_summary;
+
+ALTER TABLE /*_*/tag_summary_tmp RENAME TO /*_*/tag_summary;
+
+CREATE UNIQUE INDEX /*i*/tag_summary_rc_id ON /*_*/tag_summary (ts_rc_id);
+CREATE UNIQUE INDEX /*i*/tag_summary_log_id ON /*_*/tag_summary (ts_log_id);
+CREATE UNIQUE INDEX /*i*/tag_summary_rev_id ON /*_*/tag_summary (ts_rev_id);
-- A table to track tags for revisions, logs and recent changes.
CREATE TABLE /*_*/change_tag (
+ ct_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
-- RCID for the change
ct_rc_id int NULL,
-- LOGID for the change
-- Rollup table to pull a LIST of tags simply without ugly GROUP_CONCAT
-- that only works on MySQL 4.1+
CREATE TABLE /*_*/tag_summary (
+ ts_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
-- RCID for the change
ts_rc_id int NULL,
-- LOGID for the change
<?php
/**
* A MemoizedCallable subclass that stores function return values
- * in an instance property rather than APC.
+ * in an instance property rather than APC or APCu.
*/
class ArrayBackedMemoizedCallable extends MemoizedCallable {
private $cache = [];
* Consecutive calls to the memoized callable with the same arguments
* should result in just one invocation of the underlying callable.
*
- * @requires function apc_store
+ * @requires function apc_store/apcu_store
*/
public function testCallableMemoized() {
$observer = $this->getMock( 'stdClass', [ 'computeSomething' ] );