diff options
Diffstat (limited to 'www/wiki/extensions/Translate/utils/MessageIndex.php')
-rw-r--r-- | www/wiki/extensions/Translate/utils/MessageIndex.php | 170 |
1 files changed, 115 insertions, 55 deletions
diff --git a/www/wiki/extensions/Translate/utils/MessageIndex.php b/www/wiki/extensions/Translate/utils/MessageIndex.php index d77707ad..0015d0aa 100644 --- a/www/wiki/extensions/Translate/utils/MessageIndex.php +++ b/www/wiki/extensions/Translate/utils/MessageIndex.php @@ -5,7 +5,7 @@ * @file * @author Niklas Laxstrom * @copyright Copyright © 2008-2013, Niklas Laxström - * @license GPL-2.0+ + * @license GPL-2.0-or-later */ /** @@ -23,6 +23,11 @@ abstract class MessageIndex { protected static $instance; /** + * @var MapCacheLRU|null + */ + private static $keysCache; + + /** * @return self */ public static function singleton() { @@ -58,19 +63,34 @@ abstract class MessageIndex { $title = $handle->getTitle(); if ( !$title->inNamespaces( $wgTranslateMessageNamespaces ) ) { - return array(); + return []; } $namespace = $title->getNamespace(); $key = $handle->getKey(); $normkey = TranslateUtils::normaliseKey( $namespace, $key ); - $value = self::singleton()->get( $normkey ); - if ( $value !== null ) { - return (array)$value; - } else { - return array(); + $cache = self::getCache(); + $value = $cache->get( $normkey ); + if ( $value === null ) { + $value = self::singleton()->get( $normkey ); + $value = $value !== null + ? (array)$value + : []; + $cache->set( $normkey, $value ); } + + return $value; + } + + /** + * @return MapCacheLRU + */ + private static function getCache() { + if ( self::$keysCache === null ) { + self::$keysCache = new MapCacheLRU( 30 ); + } + return self::$keysCache; } /** @@ -100,9 +120,20 @@ abstract class MessageIndex { } } - /// @return array + /** + * @param bool $forRebuild + * @return array + */ abstract public function retrieve( $forRebuild = false ); + /** + * @since 2018.01 + * @return string[] + */ + public function getKeys() { + return array_keys( $this->retrieve() ); + } + abstract protected function store( array $array, array $diff ); protected function lock() { @@ -121,7 +152,7 @@ abstract class MessageIndex { wfWarn( $msg ); $recursion--; - return array(); + return []; } $recursion++; @@ -131,15 +162,19 @@ abstract class MessageIndex { throw new Exception( __CLASS__ . ': unable to acquire lock' ); } - $new = $old = array(); + self::getCache()->clear(); + + $new = $old = []; $old = $this->retrieve( 'rebuild' ); - $postponed = array(); + $postponed = []; /** * @var MessageGroup $g */ foreach ( $groups as $g ) { if ( !$g->exists() ) { + $id = $g->getId(); + wfWarn( __METHOD__ . ": group '$id' is registered but does not exist" ); continue; } @@ -195,26 +230,26 @@ abstract class MessageIndex { * @return array */ public static function getArrayDiff( array $old, array $new ) { - $values = array(); + $values = []; $record = function ( $groups ) use ( &$values ) { foreach ( $groups as $group ) { $values[$group] = true; } }; - $keys = array( - 'add' => array(), - 'del' => array(), - 'mod' => array(), - ); + $keys = [ + 'add' => [], + 'del' => [], + 'mod' => [], + ]; foreach ( $new as $key => $groups ) { if ( !isset( $old[$key] ) ) { - $keys['add'][$key] = array( array(), (array)$groups ); + $keys['add'][$key] = [ [], (array)$groups ]; $record( (array)$groups ); // Using != here on purpose to ignore the order of items } elseif ( $groups != $old[$key] ) { - $keys['mod'][$key] = array( (array)$old[$key], (array)$groups ); + $keys['mod'][$key] = [ (array)$old[$key], (array)$groups ]; $record( array_diff( (array)$old[$key], (array)$groups ) ); $record( array_diff( (array)$groups, (array)$old[$key] ) ); } @@ -222,16 +257,16 @@ abstract class MessageIndex { foreach ( $old as $key => $groups ) { if ( !isset( $new[$key] ) ) { - $keys['del'][$key] = array( (array)$groups, array() ); - $record( (array)$groups, array() ); + $keys['del'][$key] = [ (array)$groups, [] ]; + $record( (array)$groups, [] ); } // We already checked for diffs above } - return array( + return [ 'keys' => $keys, 'values' => array_keys( $values ), - ); + ]; } /** @@ -247,15 +282,15 @@ abstract class MessageIndex { list( $ns, $pagename ) = explode( ':', $key, 2 ); $title = Title::makeTitle( $ns, $pagename ); $handle = new MessageHandle( $title ); - list ( $oldGroups, $newGroups ) = $data; + list( $oldGroups, $newGroups ) = $data; Hooks::run( 'TranslateEventMessageMembershipChange', - array( $handle, $oldGroups, $newGroups ) ); + [ $handle, $oldGroups, $newGroups ] ); } } } /** - * @param array $hugearray + * @param array &$hugearray * @param MessageGroup $g * @param bool $ignore */ @@ -296,7 +331,7 @@ abstract class MessageIndex { // references instead. References are hard! $value = & $hugearray[$key]; unset( $hugearray[$key] ); - $hugearray[$key] = array( &$value, &$id ); + $hugearray[$key] = [ &$value, &$id ]; } } else { $hugearray[$key] = & $id; @@ -305,9 +340,13 @@ abstract class MessageIndex { unset( $id ); // Disconnect the previous references to this $id } - /* These are probably slower than serialize and unserialize, + /** + * These are probably slower than serialize and unserialize, * but they are more space efficient because we only need - * strings and arrays. */ + * strings and arrays. + * @param mixed $data + * @return mixed + */ protected function serialize( $data ) { if ( is_array( $data ) ) { return implode( '|', $data ); @@ -408,11 +447,20 @@ class DatabaseMessageIndex extends MessageIndex { } protected function unlock() { + $fname = __METHOD__; $dbw = wfGetDB( DB_MASTER ); // Unlock once the rows are actually unlocked to avoid deadlocks - $dbw->onTransactionIdle( function () use ( $dbw ) { - $dbw->unlock( 'translate-messageindex', __METHOD__ ); - } ); + if ( !$dbw->trxLevel() ) { + $dbw->unlock( 'translate-messageindex', $fname ); + } elseif ( method_exists( $dbw, 'onTransactionResolution' ) ) { // 1.28 + $dbw->onTransactionResolution( function () use ( $dbw, $fname ) { + $dbw->unlock( 'translate-messageindex', $fname ); + } ); + } else { + $dbw->onTransactionIdle( function () use ( $dbw, $fname ) { + $dbw->unlock( 'translate-messageindex', $fname ); + } ); + } return true; } @@ -426,9 +474,9 @@ class DatabaseMessageIndex extends MessageIndex { return $this->index; } - $dbr = wfGetDB( $forRebuild ? DB_MASTER : DB_SLAVE ); - $res = $dbr->select( 'translate_messageindex', '*', array(), __METHOD__ ); - $this->index = array(); + $dbr = wfGetDB( $forRebuild ? DB_MASTER : DB_REPLICA ); + $res = $dbr->select( 'translate_messageindex', '*', [], __METHOD__ ); + $this->index = []; foreach ( $res as $row ) { $this->index[$row->tmi_key] = $this->unserialize( $row->tmi_value ); } @@ -437,11 +485,11 @@ class DatabaseMessageIndex extends MessageIndex { } protected function get( $key ) { - $dbr = wfGetDB( DB_SLAVE ); + $dbr = wfGetDB( DB_REPLICA ); $value = $dbr->selectField( 'translate_messageindex', 'tmi_value', - array( 'tmi_key' => $key ), + [ 'tmi_key' => $key ], __METHOD__ ); @@ -455,30 +503,30 @@ class DatabaseMessageIndex extends MessageIndex { } protected function store( array $array, array $diff ) { - $updates = array(); + $updates = []; - foreach ( array( $diff['add'], $diff['mod'] ) as $changes ) { + foreach ( [ $diff['add'], $diff['mod'] ] as $changes ) { foreach ( $changes as $key => $data ) { list( $old, $new ) = $data; - $updates[] = array( + $updates[] = [ 'tmi_key' => $key, 'tmi_value' => $this->serialize( $new ), - ); + ]; } } - $index = array( 'tmi_key' ); + $index = [ 'tmi_key' ]; $deletions = array_keys( $diff['del'] ); $dbw = wfGetDB( DB_MASTER ); $dbw->startAtomic( __METHOD__ ); - if ( $updates !== array() ) { - $dbw->replace( 'translate_messageindex', array( $index ), $updates, __METHOD__ ); + if ( $updates !== [] ) { + $dbw->replace( 'translate_messageindex', [ $index ], $updates, __METHOD__ ); } - if ( $deletions !== array() ) { - $dbw->delete( 'translate_messageindex', array( 'tmi_key' => $deletions ), __METHOD__ ); + if ( $deletions !== [] ) { + $dbw->delete( 'translate_messageindex', [ 'tmi_key' => $deletions ], __METHOD__ ); } $dbw->endAtomic( __METHOD__ ); @@ -556,7 +604,7 @@ class CDBMessageIndex extends MessageIndex { protected $index; /** - * @var CdbReader|null + * @var \Cdb\Reader|null */ protected $reader; @@ -576,15 +624,28 @@ class CDBMessageIndex extends MessageIndex { return $this->index; } - $keys = (array)$this->unserialize( $reader->get( '#keys' ) ); - $this->index = array(); - foreach ( $keys as $key ) { + $this->index = []; + foreach ( $this->getKeys() as $key ) { $this->index[$key] = $this->unserialize( $reader->get( $key ) ); } return $this->index; } + public function getKeys() { + $reader = $this->getReader(); + $keys = []; + while ( true ) { + $key = $keys === [] ? $reader->firstkey() : $reader->nextkey(); + if ( $key === false ) { + break; + } + $keys[] = $key; + } + + return $keys; + } + protected function get( $key ) { $reader = $this->getReader(); // We might have the full cache loaded @@ -611,8 +672,6 @@ class CDBMessageIndex extends MessageIndex { $file = TranslateUtils::cacheFile( $this->filename ); $cache = \Cdb\Writer::open( $file ); - $keys = array_keys( $array ); - $cache->set( '#keys', $this->serialize( $keys ) ); foreach ( $array as $key => $value ) { $value = $this->serialize( $value ); @@ -632,11 +691,12 @@ class CDBMessageIndex extends MessageIndex { $file = TranslateUtils::cacheFile( $this->filename ); if ( !file_exists( $file ) ) { // Create an empty index to allow rebuild - $this->store( array(), array() ); + $this->store( [], [] ); $this->index = $this->rebuild(); } - return $this->reader = \Cdb\Reader::open( $file ); + $this->reader = \Cdb\Reader::open( $file ); + return $this->reader; } } @@ -651,7 +711,7 @@ class HashMessageIndex extends MessageIndex { /** * @var array */ - protected $index = array(); + protected $index = []; /** * @param bool $forRebuild |