X-Git-Url: http://git.cyclocoop.org/?a=blobdiff_plain;f=includes%2Fchangetags%2FChangeTags.php;h=5e83f9509aaa4836306adc1b7fdeeb5b302466de;hb=6e58bfb43a161235444d10d8cf42e8f0eaee4efe;hp=1d303c77b58ccd975f740236be3bce3c5874f35d;hpb=8f338c0e29da43b1f9b1b77c7520b766ab119a40;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/changetags/ChangeTags.php b/includes/changetags/ChangeTags.php index 1d303c77b5..5e83f9509a 100644 --- a/includes/changetags/ChangeTags.php +++ b/includes/changetags/ChangeTags.php @@ -262,8 +262,6 @@ class ChangeTags { &$rev_id = null, &$log_id = null, $params = null, RecentChange $rc = null, User $user = null ) { - global $wgChangeTagsSchemaMigrationStage; - $tagsToAdd = array_filter( (array)$tagsToAdd ); // Make sure we're submitting all tags... $tagsToRemove = array_filter( (array)$tagsToRemove ); @@ -347,33 +345,27 @@ class ChangeTags { $changeTagDefStore = MediaWikiServices::getInstance()->getChangeTagDefStore(); if ( count( $tagsToAdd ) ) { $changeTagMapping = []; - if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_OLD ) { - foreach ( $tagsToAdd as $tag ) { - $changeTagMapping[$tag] = $changeTagDefStore->acquireId( $tag ); - } - + foreach ( $tagsToAdd as $tag ) { + $changeTagMapping[$tag] = $changeTagDefStore->acquireId( $tag ); + } + // T207881: update the counts at the end of the transaction + $dbw->onTransactionPreCommitOrIdle( function () use ( $dbw, $tagsToAdd ) { $dbw->update( 'change_tag_def', [ 'ctd_count = ctd_count + 1' ], [ 'ctd_name' => $tagsToAdd ], __METHOD__ ); - } + } ); $tagsRows = []; foreach ( $tagsToAdd as $tag ) { - if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_WRITE_BOTH ) { - $tagName = null; - } else { - $tagName = $tag; - } // Filter so we don't insert NULLs as zero accidentally. // Keep in mind that $rc_id === null means "I don't care/know about the // rc_id, just delete $tag on this revision/log entry". It doesn't // mean "only delete tags on this revision/log WHERE rc_id IS NULL". $tagsRows[] = array_filter( [ - 'ct_tag' => $tagName, 'ct_rc_id' => $rc_id, 'ct_log_id' => $log_id, 'ct_rev_id' => $rev_id, @@ -390,36 +382,31 @@ class ChangeTags { // delete from change_tag if ( count( $tagsToRemove ) ) { foreach ( $tagsToRemove as $tag ) { - if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_WRITE_BOTH ) { - $tagName = null; - $tagId = $changeTagDefStore->getId( $tag ); - } else { - $tagName = $tag; - $tagId = null; - } $conds = array_filter( [ - 'ct_tag' => $tagName, 'ct_rc_id' => $rc_id, 'ct_log_id' => $log_id, 'ct_rev_id' => $rev_id, - 'ct_tag_id' => $tagId, + 'ct_tag_id' => $changeTagDefStore->getId( $tag ), ] ); $dbw->delete( 'change_tag', $conds, __METHOD__ ); - if ( $dbw->affectedRows() && $wgChangeTagsSchemaMigrationStage > MIGRATION_OLD ) { - $dbw->update( - 'change_tag_def', - [ 'ctd_count = ctd_count - 1' ], - [ 'ctd_name' => $tag ], - __METHOD__ - ); - - $dbw->delete( - 'change_tag_def', - [ 'ctd_name' => $tag, 'ctd_count' => 0, 'ctd_user_defined' => 0 ], - __METHOD__ - ); + if ( $dbw->affectedRows() ) { + // T207881: update the counts at the end of the transaction + $dbw->onTransactionPreCommitOrIdle( function () use ( $dbw, $tag ) { + $dbw->update( + 'change_tag_def', + [ 'ctd_count = ctd_count - 1' ], + [ 'ctd_name' => $tag ], + __METHOD__ + ); + + $dbw->delete( + 'change_tag_def', + [ 'ctd_name' => $tag, 'ctd_count' => 0, 'ctd_user_defined' => 0 ], + __METHOD__ + ); + } ); } } } @@ -783,7 +770,7 @@ class ChangeTags { public static function modifyDisplayQuery( &$tables, &$fields, &$conds, &$join_conds, &$options, $filter_tag = '' ) { - global $wgUseTagFilter, $wgChangeTagsSchemaMigrationStage; + global $wgUseTagFilter; // Normalize to arrays $tables = (array)$tables; @@ -791,6 +778,8 @@ class ChangeTags { $conds = (array)$conds; $options = (array)$options; + $fields['ts_tags'] = self::makeTagSummarySubquery( $tables ); + // Figure out which ID field to use if ( in_array( 'recentchanges', $tables ) ) { $join_cond = 'ct_rc_id=rc_id'; @@ -804,44 +793,26 @@ class ChangeTags { throw new MWException( 'Unable to determine appropriate JOIN condition for tagging.' ); } - $tagTables[] = 'change_tag'; - if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_WRITE_BOTH ) { - $tagTables[] = 'change_tag_def'; - $join_cond_ts_tags = [ 'change_tag_def' => [ 'INNER JOIN', 'ct_tag_id=ctd_id' ] ]; - $field = 'ctd_name'; - } else { - $field = 'ct_tag'; - $join_cond_ts_tags = []; - } - - $fields['ts_tags'] = wfGetDB( DB_REPLICA )->buildGroupConcatField( - ',', $tagTables, $field, $join_cond, $join_cond_ts_tags - ); - if ( $wgUseTagFilter && $filter_tag ) { // Somebody wants to filter on a tag. // Add an INNER JOIN on change_tag $tables[] = 'change_tag'; $join_conds['change_tag'] = [ 'INNER JOIN', $join_cond ]; - if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_WRITE_BOTH ) { - $filterTagIds = []; - $changeTagDefStore = MediaWikiServices::getInstance()->getChangeTagDefStore(); - foreach ( (array)$filter_tag as $filterTagName ) { - try { - $filterTagIds[] = $changeTagDefStore->getId( $filterTagName ); - } catch ( NameTableAccessException $exception ) { - // Return nothing. - $conds[] = '0'; - break; - }; - } + $filterTagIds = []; + $changeTagDefStore = MediaWikiServices::getInstance()->getChangeTagDefStore(); + foreach ( (array)$filter_tag as $filterTagName ) { + try { + $filterTagIds[] = $changeTagDefStore->getId( $filterTagName ); + } catch ( NameTableAccessException $exception ) { + // Return nothing. + $conds[] = '0'; + break; + }; + } - if ( $filterTagIds !== [] ) { - $conds['ct_tag_id'] = $filterTagIds; - } - } else { - $conds['ct_tag'] = $filter_tag; + if ( $filterTagIds !== [] ) { + $conds['ct_tag_id'] = $filterTagIds; } if ( @@ -853,6 +824,40 @@ class ChangeTags { } } + /** + * Make the tag summary subquery based on the given tables and return it. + * + * @param string|array $tables Table names, see Database::select + * + * @return string tag summary subqeury + * @throws MWException When unable to determine appropriate JOIN condition for tagging + */ + public static function makeTagSummarySubquery( $tables ) { + // Normalize to arrays + $tables = (array)$tables; + + // Figure out which ID field to use + if ( in_array( 'recentchanges', $tables ) ) { + $join_cond = 'ct_rc_id=rc_id'; + } elseif ( in_array( 'logging', $tables ) ) { + $join_cond = 'ct_log_id=log_id'; + } elseif ( in_array( 'revision', $tables ) ) { + $join_cond = 'ct_rev_id=rev_id'; + } elseif ( in_array( 'archive', $tables ) ) { + $join_cond = 'ct_rev_id=ar_rev_id'; + } else { + throw new MWException( 'Unable to determine appropriate JOIN condition for tagging.' ); + } + + $tagTables = [ 'change_tag', 'change_tag_def' ]; + $join_cond_ts_tags = [ 'change_tag_def' => [ 'INNER JOIN', 'ct_tag_id=ctd_id' ] ]; + $field = 'ctd_name'; + + return wfGetDB( DB_REPLICA )->buildGroupConcatField( + ',', $tagTables, $field, $join_cond, $join_cond_ts_tags + ); + } + /** * Build a text box to select a change tag * @@ -913,32 +918,20 @@ class ChangeTags { * @since 1.25 */ public static function defineTag( $tag ) { - global $wgChangeTagsSchemaMigrationStage; - $dbw = wfGetDB( DB_MASTER ); - if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_OLD ) { - $tagDef = [ - 'ctd_name' => $tag, - 'ctd_user_defined' => 1, - 'ctd_count' => 0 - ]; - $dbw->upsert( - 'change_tag_def', - $tagDef, - [ 'ctd_name' ], - [ 'ctd_user_defined' => 1 ], - __METHOD__ - ); - } + $tagDef = [ + 'ctd_name' => $tag, + 'ctd_user_defined' => 1, + 'ctd_count' => 0 + ]; + $dbw->upsert( + 'change_tag_def', + $tagDef, + [ 'ctd_name' ], + [ 'ctd_user_defined' => 1 ], + __METHOD__ + ); - if ( $wgChangeTagsSchemaMigrationStage < MIGRATION_NEW ) { - $dbw->replace( - 'valid_tag', - [ 'vt_tag' ], - [ 'vt_tag' => $tag ], - __METHOD__ - ); - } // clear the memcache of defined tags self::purgeTagCacheAll(); } @@ -952,28 +945,20 @@ class ChangeTags { * @since 1.25 */ public static function undefineTag( $tag ) { - global $wgChangeTagsSchemaMigrationStage; - $dbw = wfGetDB( DB_MASTER ); - if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_OLD ) { - $dbw->update( - 'change_tag_def', - [ 'ctd_user_defined' => 0 ], - [ 'ctd_name' => $tag ], - __METHOD__ - ); - - $dbw->delete( - 'change_tag_def', - [ 'ctd_name' => $tag, 'ctd_count' => 0 ], - __METHOD__ - ); - } + $dbw->update( + 'change_tag_def', + [ 'ctd_user_defined' => 0 ], + [ 'ctd_name' => $tag ], + __METHOD__ + ); - if ( $wgChangeTagsSchemaMigrationStage < MIGRATION_NEW ) { - $dbw->delete( 'valid_tag', [ 'vt_tag' => $tag ], __METHOD__ ); - } + $dbw->delete( + 'change_tag_def', + [ 'ctd_name' => $tag, 'ctd_count' => 0 ], + __METHOD__ + ); // clear the memcache of defined tags self::purgeTagCacheAll(); @@ -1275,19 +1260,14 @@ class ChangeTags { * @since 1.25 */ public static function deleteTagEverywhere( $tag ) { - global $wgChangeTagsSchemaMigrationStage; $dbw = wfGetDB( DB_MASTER ); $dbw->startAtomic( __METHOD__ ); // delete from valid_tag and/or set ctd_user_defined = 0 self::undefineTag( $tag ); - if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_WRITE_BOTH ) { - $tagId = MediaWikiServices::getInstance()->getChangeTagDefStore()->getId( $tag ); - $conditions = [ 'ct_tag_id' => $tagId ]; - } else { - $conditions = [ 'ct_tag' => $tag ]; - } + $tagId = MediaWikiServices::getInstance()->getChangeTagDefStore()->getId( $tag ); + $conditions = [ 'ct_tag_id' => $tagId ]; // find out which revisions use this tag, so we can delete from tag_summary $result = $dbw->select( 'change_tag', @@ -1303,17 +1283,9 @@ class ChangeTags { } // delete from change_tag - if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_WRITE_BOTH ) { - $tagId = MediaWikiServices::getInstance()->getChangeTagDefStore()->getId( $tag ); - $dbw->delete( 'change_tag', [ 'ct_tag_id' => $tagId ], __METHOD__ ); - } else { - $dbw->delete( 'change_tag', [ 'ct_tag' => $tag ], __METHOD__ ); - } - - if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_OLD ) { - $dbw->delete( 'change_tag_def', [ 'ctd_name' => $tag ], __METHOD__ ); - } - + $tagId = MediaWikiServices::getInstance()->getChangeTagDefStore()->getId( $tag ); + $dbw->delete( 'change_tag', [ 'ct_tag_id' => $tagId ], __METHOD__ ); + $dbw->delete( 'change_tag_def', [ 'ctd_name' => $tag ], __METHOD__ ); $dbw->endAtomic( __METHOD__ ); // give extensions a chance @@ -1479,16 +1451,16 @@ class ChangeTags { $cache->makeKey( 'valid-tags-db' ), WANObjectCache::TTL_MINUTE * 5, function ( $oldValue, &$ttl, array &$setOpts ) use ( $fname ) { - global $wgChangeTagsSchemaMigrationStage; $dbr = wfGetDB( DB_REPLICA ); $setOpts += Database::getCacheSetOptions( $dbr ); - if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_WRITE_BOTH ) { - $tags = self::listExplicitlyDefinedTagsNewBackend(); - } else { - $tags = $dbr->selectFieldValues( 'valid_tag', 'vt_tag', [], $fname ); - } + $tags = $dbr->selectFieldValues( + 'change_tag_def', + 'ctd_name', + [ 'ctd_user_defined' => 1 ], + __METHOD__ + ); return array_filter( array_unique( $tags ) ); }, @@ -1500,22 +1472,6 @@ class ChangeTags { ); } - /** - * Lists tags explicitly user defined tags. When ctd_user_defined is true. - * - * @return string[] Array of strings: tags - * @since 1.25 - */ - private static function listExplicitlyDefinedTagsNewBackend() { - $dbr = wfGetDB( DB_REPLICA ); - return $dbr->selectFieldValues( - 'change_tag_def', - 'ctd_name', - [ 'ctd_user_defined' => 1 ], - __METHOD__ - ); - } - /** * Lists tags defined by core or extensions using the ListDefinedTags hook. * Extensions need only define those tags they deem to be in active use. @@ -1578,59 +1534,9 @@ class ChangeTags { * Returns a map of any tags used on the wiki to number of edits * tagged with them, ordered descending by the hitcount. * This does not include tags defined somewhere that have never been applied. - * - * Keeps a short-term cache in memory, so calling this multiple times in the - * same request should be fine. - * * @return array Array of string => int */ public static function tagUsageStatistics() { - global $wgChangeTagsSchemaMigrationStage, $wgTagStatisticsNewTable; - if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_WRITE_BOTH || - ( $wgTagStatisticsNewTable && $wgChangeTagsSchemaMigrationStage > MIGRATION_OLD ) - ) { - return self::newTagUsageStatistics(); - } - - $fname = __METHOD__; - $cache = MediaWikiServices::getInstance()->getMainWANObjectCache(); - return $cache->getWithSetCallback( - $cache->makeKey( 'change-tag-statistics' ), - WANObjectCache::TTL_MINUTE * 5, - function ( $oldValue, &$ttl, array &$setOpts ) use ( $fname ) { - $dbr = wfGetDB( DB_REPLICA, 'vslow' ); - - $setOpts += Database::getCacheSetOptions( $dbr ); - - $res = $dbr->select( - 'change_tag', - [ 'ct_tag', 'hitcount' => 'count(*)' ], - [], - $fname, - [ 'GROUP BY' => 'ct_tag', 'ORDER BY' => 'hitcount DESC' ] - ); - - $out = []; - foreach ( $res as $row ) { - $out[$row->ct_tag] = $row->hitcount; - } - - return $out; - }, - [ - 'checkKeys' => [ $cache->makeKey( 'change-tag-statistics' ) ], - 'lockTSE' => WANObjectCache::TTL_MINUTE * 5, - 'pcTTL' => WANObjectCache::TTL_PROC_LONG - ] - ); - } - - /** - * Same self::tagUsageStatistics() but uses change_tag_def. - * - * @return array Array of string => int - */ - private static function newTagUsageStatistics() { $dbr = wfGetDB( DB_REPLICA ); $res = $dbr->select( 'change_tag_def',