X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FWatchedItemStore.php;h=89ca50c00b2efe5b2f083fb62717e2fccae08060;hb=ad631f135d460fb8a5c301f5959257041e6252d2;hp=eb652ce118b69c2265a57e83ff1a191ad19dbe3c;hpb=279dd4156c6195be16fe497980d73cd2e5c95884;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/WatchedItemStore.php b/includes/WatchedItemStore.php index eb652ce118..89ca50c00b 100644 --- a/includes/WatchedItemStore.php +++ b/includes/WatchedItemStore.php @@ -1,7 +1,6 @@ deferredUpdatesAddCallableUpdateCallback; $this->deferredUpdatesAddCallableUpdateCallback = $callback; return new ScopedCallback( function() use ( $previousValue ) { @@ -106,14 +103,12 @@ class WatchedItemStore implements StatsdAwareInterface { * @return ScopedCallback to reset the overridden value * @throws MWException */ - public function overrideRevisionGetTimestampFromIdCallback( $callback ) { + public function overrideRevisionGetTimestampFromIdCallback( callable $callback ) { if ( !defined( 'MW_PHPUNIT_TEST' ) ) { throw new MWException( 'Cannot override Revision::getTimestampFromId callback in operation.' ); } - Assert::parameterType( 'callable', $callback, '$callback' ); - $previousValue = $this->revisionGetTimestampFromIdCallback; $this->revisionGetTimestampFromIdCallback = $callback; return new ScopedCallback( function() use ( $previousValue ) { @@ -145,16 +140,28 @@ class WatchedItemStore implements StatsdAwareInterface { } private function uncacheLinkTarget( LinkTarget $target ) { + $this->stats->increment( 'WatchedItemStore.uncacheLinkTarget' ); if ( !isset( $this->cacheIndex[$target->getNamespace()][$target->getDBkey()] ) ) { return; } - $this->stats->increment( 'WatchedItemStore.uncacheLinkTarget' ); foreach ( $this->cacheIndex[$target->getNamespace()][$target->getDBkey()] as $key ) { $this->stats->increment( 'WatchedItemStore.uncacheLinkTarget.items' ); $this->cache->delete( $key ); } } + private function uncacheUser( User $user ) { + $this->stats->increment( 'WatchedItemStore.uncacheUser' ); + foreach ( $this->cacheIndex as $ns => $dbKeyArray ) { + foreach ( $dbKeyArray as $dbKey => $userArray ) { + if ( isset( $userArray[$user->getId()] ) ) { + $this->stats->increment( 'WatchedItemStore.uncacheUser.items' ); + $this->cache->delete( $userArray[$user->getId()] ); + } + } + } + } + /** * @param User $user * @param LinkTarget $target @@ -667,6 +674,41 @@ class WatchedItemStore implements StatsdAwareInterface { return $success; } + /** + * @param User $user The user to set the timestamp for + * @param string $timestamp Set the update timestamp to this value + * @param LinkTarget[] $targets List of targets to update. Default to all targets + * + * @return bool success + */ + public function setNotificationTimestampsForUser( User $user, $timestamp, array $targets = [] ) { + // Only loggedin user can have a watchlist + if ( $user->isAnon() ) { + return false; + } + + $dbw = $this->getConnection( DB_MASTER ); + + $conds = [ 'wl_user' => $user->getId() ]; + if ( $targets ) { + $batch = new LinkBatch( $targets ); + $conds[] = $batch->constructSet( 'wl', $dbw ); + } + + $success = $dbw->update( + 'watchlist', + [ 'wl_notificationtimestamp' => $dbw->timestamp( $timestamp ) ], + $conds, + __METHOD__ + ); + + $this->reuseConnection( $dbw ); + + $this->uncacheUser( $user ); + + return $success; + } + /** * @param User $editor The editor that triggered the update. Their notification * timestamp will not be updated(they have already seen it) @@ -677,42 +719,52 @@ class WatchedItemStore implements StatsdAwareInterface { */ public function updateNotificationTimestamp( User $editor, LinkTarget $target, $timestamp ) { $dbw = $this->getConnection( DB_MASTER ); - $res = $dbw->select( [ 'watchlist' ], - [ 'wl_user' ], + $uids = $dbw->selectFieldValues( + 'watchlist', + 'wl_user', [ 'wl_user != ' . intval( $editor->getId() ), 'wl_namespace' => $target->getNamespace(), 'wl_title' => $target->getDBkey(), 'wl_notificationtimestamp IS NULL', - ], __METHOD__ + ], + __METHOD__ ); + $this->reuseConnection( $dbw ); - $watchers = []; - foreach ( $res as $row ) { - $watchers[] = intval( $row->wl_user ); - } - + $watchers = array_map( 'intval', $uids ); if ( $watchers ) { // Update wl_notificationtimestamp for all watching users except the editor $fname = __METHOD__; - $dbw->onTransactionIdle( - function () use ( $dbw, $timestamp, $watchers, $target, $fname ) { - $dbw->update( 'watchlist', - [ /* SET */ - 'wl_notificationtimestamp' => $dbw->timestamp( $timestamp ) - ], [ /* WHERE */ - 'wl_user' => $watchers, - 'wl_namespace' => $target->getNamespace(), - 'wl_title' => $target->getDBkey(), - ], $fname - ); + DeferredUpdates::addCallableUpdate( + function () use ( $timestamp, $watchers, $target, $fname ) { + global $wgUpdateRowsPerQuery; + + $dbw = $this->getConnection( DB_MASTER ); + + $watchersChunks = array_chunk( $watchers, $wgUpdateRowsPerQuery ); + foreach ( $watchersChunks as $watchersChunk ) { + $dbw->update( 'watchlist', + [ /* SET */ + 'wl_notificationtimestamp' => $dbw->timestamp( $timestamp ) + ], [ /* WHERE - TODO Use wl_id T130067 */ + 'wl_user' => $watchersChunk, + 'wl_namespace' => $target->getNamespace(), + 'wl_title' => $target->getDBkey(), + ], $fname + ); + if ( count( $watchersChunks ) > 1 ) { + $dbw->commit( __METHOD__, 'flush' ); + wfGetLBFactory()->waitForReplication( [ 'wiki' => $dbw->getWikiID() ] ); + } + } $this->uncacheLinkTarget( $target ); + + $this->reuseConnection( $dbw ); } ); } - $this->reuseConnection( $dbw ); - return $watchers; }