jenkins-bot has submitted this change and it was merged. Change subject: Better error handling for memc and some comments ......................................................................
Better error handling for memc and some comments Change-Id: Ibdd49677c7eac6b8d601ea1d317c0a4d61e42943 --- M includes/Data/MultiDimArray.php M includes/Data/ObjectManager.php M includes/Data/RevisionStorage.php M includes/Model/AbstractRevision.php M includes/Repository/MultiGetList.php M includes/Repository/TreeRepository.php 6 files changed, 128 insertions(+), 28 deletions(-) Approvals: Matthias Mullie: Looks good to me, approved jenkins-bot: Verified diff --git a/includes/Data/MultiDimArray.php b/includes/Data/MultiDimArray.php index 3a89928..9ed77db 100644 --- a/includes/Data/MultiDimArray.php +++ b/includes/Data/MultiDimArray.php @@ -2,6 +2,29 @@ namespace Flow\Data; +/** + * This object can be used to easily set keys in a multi-dimensional array. + * + * Usage: + * + * $arr = new Flow\Data\MultiDimArray; + * $arr[array(1,2,3)] = 4; + * $arr[array(2,3,4)] = 5; + * var_export( $arr->all() ); + * + * array ( + * 1 => array ( + * 2 => array ( + * 3 => 4, + * ), + * ), + * 2 => array ( + * 3 => array ( + * 4 => 5, + * ), + * ), + * ) + */ class MultiDimArray implements \ArrayAccess { protected $data = array(); diff --git a/includes/Data/ObjectManager.php b/includes/Data/ObjectManager.php index 8ac2e5b..dd19e56 100644 --- a/includes/Data/ObjectManager.php +++ b/includes/Data/ObjectManager.php @@ -76,36 +76,75 @@ function fromStorageRow( array $row, $object = null ); } -// An Index is just a store that receives updates via handler. -// backing store's can be passed via constructor +/** + * Indexes store one or more values bucketed by exact key/value combinations. + */ interface Index extends LifecycleHandler { - /// Indexes accept no query options + /** + * Find data models matching the provided equality condition. + * + * @param array $keys A map of k,v pairs to find via equality condition + * @return array|false Cached subset of data model rows matching the + * equality conditions provided in $keys. + */ function find( array $keys ); - /// Indexes accept no query options + /** + * Batch together multiple calls to self::find with minimal network round trips. + * + * @param array $queries An array of arrays in the form of $keys parameter of self::find + * @return array|false Array of arrays in same order as $queries representing batched result set. + */ function findMulti( array $queries ); - // Maximum number of items in a single index value + /** + * @return integer Maximum number of items in a single index value + */ function getLimit(); - // Can the index locate a result for this keys and options pair + /** + * Query options are not supported at the query level, the index always + * returns the same value for the same key/value combination. Depending on what + * the query stores it may contain the answers to various options, which will require + * post-processing by the caller. + * + * @return boolean Can the index locate a result for this keys and options pair + */ function canAnswer( array $keys, array $options ); } -// Compact rows before writing to memcache, expand when receiving back -// Still returns arrays, just removes unneccessary values +/** + * Compact rows before writing to memcache, expand when receiving back + * Still returns arrays, just removes unneccessary values + */ interface Compactor { - // Return only the values in $row that will be written to the cache + /** + * @param array $row A data model row to strip unnecessary data from + * @return array Only the values in $row that will be written to the cache + */ public function compactRow( array $row ); - // perform self::compactRow against an array of rows + + /** + * @param array $rows Multiple data model rows to strip unnecesssary data from + * @return array The provided rows now containing only the values the will be written to cache + */ public function compactRows( array $rows ); - // Repopulate BagOStuff::multiGet results with any values removed in self::compactRow + + /** + * Repopulate BagOStuff::multiGet results with any values removed in self::compactRow + * + * @param array $cached The multi-dimensional array results of BagOStuff::multiGet + * @param array $keyToQuery An array mapping memcache-key to the values used to generate that cache key + * @return array The cached content from memcache along with any data stripped in self::compactRow + */ public function expandCacheResult( array $cached, array $keyToQuery ); } -// A little glue code so you dont need to use the individual manager for each class -// Can be made more specific once the interfaces settle down +/** + * A little glue code to allow passing arround and manipulating multiple + * ObjectManagers more convenient. + */ class ManagerGroup { public function __construct( Container $container, array $classMap ) { $this->container = $container; @@ -653,7 +692,7 @@ foreach ( $res as $row ) { $result[] = (array) $row; } - wfDebugLog( __CLASS__, __METHOD__ . ': ' . print_r( $result, true ) ); + // wfDebugLog( __CLASS__, __METHOD__ . ': ' . print_r( $result, true ) ); return $result; } @@ -1292,7 +1331,12 @@ } if ( $keys ) { $flipped = array_flip( $keys ); - foreach ( parent::getMulti( $keys ) as $key => $value ) { + $res = parent::getMulti( $keys ); + if ( $res === false ) { + wfDebugLog( __CLASS__, __FUNCTION__ . ': Failure requesting data from memcache : ' . implode( ',', $keys ) ); + return $found; + } + foreach ( $res as $key => $value ) { $this->internal[$key] = $found[$key] = $value; unset( $keys[$flipped[$key]] ); } diff --git a/includes/Data/RevisionStorage.php b/includes/Data/RevisionStorage.php index 715cf31..f7a326a 100644 --- a/includes/Data/RevisionStorage.php +++ b/includes/Data/RevisionStorage.php @@ -488,6 +488,10 @@ $roots[] = UUID::create( $features['topic_root'] ); } $nodeList = $this->treeRepository->fetchSubtreeNodeList( $roots ); + if ( $nodeList === false ) { + // We can't return the existing $retval, that false data would be cached. + return false; + } $descendantQueries = array(); foreach ( $queries as $idx => $features ) { diff --git a/includes/Model/AbstractRevision.php b/includes/Model/AbstractRevision.php index d11cfdb..4130052 100644 --- a/includes/Model/AbstractRevision.php +++ b/includes/Model/AbstractRevision.php @@ -13,11 +13,18 @@ const MODERATED_CENSORED = 'censor'; + /** + * Possible moderation states of a revision. These must be ordered from + * least restrictive to most restrictive permission. + */ static protected $perms = array( self::MODERATED_NONE => array( + // The name of the permission checked with User::isAllowed 'perm' => null, + // This is the bit of text rendered instead of the post creator 'usertext' => null, - 'content' => null + // This is the bit of text rendered instead of the content + 'content' => null, ), self::MODERATED_HIDDEN => array( 'perm' => 'flow-hide', @@ -227,11 +234,12 @@ } public function getUserText( $user = null ) { - if ( $this->isAllowed( $user ) ) { - return $this->getUserTextRaw(); - } else { + // The text of *this* revision is only stripped when fully moderated + if ( $this->isCensored() ) { // Messages: flow-post-hidden, flow-post-deleted, flow-post-censored return wfMessage( self::$perms[$this->moderationState]['usertext'] ); + } else { + return $this->getUserTextRaw(); } } @@ -287,6 +295,10 @@ return $this->moderationState !== self::MODERATED_NONE; } + public function isCensored() { + return $this->moderationState === self::MODERATED_CENSORED; + } + public function getModerationTimestamp() { return $this->moderationTimestamp; } diff --git a/includes/Repository/MultiGetList.php b/includes/Repository/MultiGetList.php index 61b860c..1e33f63 100644 --- a/includes/Repository/MultiGetList.php +++ b/includes/Repository/MultiGetList.php @@ -32,14 +32,20 @@ return array(); } $result = array(); - foreach ( $this->cache->getMulti( array_keys( $cacheKeys ) ) as $key => $value ) { - if ( $cacheKeys[$key] instanceof UUID ) { - $idx = $cacheKeys[$key]->getBinary(); - } else { - $idx = $cacheKeys[$key]; + $multiRes = $this->cache->getMulti( array_keys( $cacheKeys ) ); + if ( $multiRes === false ) { + // Falls through to query only backend + wfDebugLog( __CLASS__, __FUNCTION__ . ': Failure querying memcache' ); + } else { + foreach ( $multiRes as $key => $value ) { + if ( $cacheKeys[$key] instanceof UUID ) { + $idx = $cacheKeys[$key]->getBinary(); + } else { + $idx = $cacheKeys[$key]; + } + $result[$idx] = $value; + unset( $cacheKeys[$key] ); } - $result[$idx] = $value; - unset( $cacheKeys[$key] ); } if ( count( $cacheKeys ) === 0 ) { return $result; @@ -57,7 +63,11 @@ $invCacheKeys[$id] = $cacheKey; } foreach ( $res as $id => $row ) { - $this->cache->set( $invCacheKeys[$id], $row ); + // If we failed contacting memcache a moment ago dont bother trying to + // push values either. + if ( $multiRes !== false ) { + $this->cache->set( $invCacheKeys[$id], $row ); + } $result[$id] = $row; } diff --git a/includes/Repository/TreeRepository.php b/includes/Repository/TreeRepository.php index 105233f..2d6e98a 100644 --- a/includes/Repository/TreeRepository.php +++ b/includes/Repository/TreeRepository.php @@ -215,7 +215,10 @@ $roots, array( $this, 'fetchSubtreeNodeListFromDb' ) ); - + if ( $res === false ) { + wfDebugLog( __CLASS__, __FUNCTION__ . ': Failure fetching node list from cache' ); + return false; + } // $idx is a binary UUID $retval = array(); foreach ( $res as $idx => $val ) { @@ -233,6 +236,10 @@ ), __METHOD__ ); + if ( $res === false ) { + wfDebugLog( __CLASS__, __FUNCTION__ . ': Failure fetching node list from database' ); + return false; + } if ( !$res ) { return array(); } -- To view, visit https://gerrit.wikimedia.org/r/83030 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ibdd49677c7eac6b8d601ea1d317c0a4d61e42943 Gerrit-PatchSet: 6 Gerrit-Project: mediawiki/extensions/Flow Gerrit-Branch: master Gerrit-Owner: EBernhardson (WMF) <ebernhard...@wikimedia.org> Gerrit-Reviewer: Bsitu <bs...@wikimedia.org> Gerrit-Reviewer: EBernhardson (WMF) <ebernhard...@wikimedia.org> Gerrit-Reviewer: Matthias Mullie <mmul...@wikimedia.org> Gerrit-Reviewer: Werdna <agarr...@wikimedia.org> Gerrit-Reviewer: jenkins-bot _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits