MediaWiki  master
ClearUserWatchlistJob.php
Go to the documentation of this file.
1 <?php
2 
6 
15 class ClearUserWatchlistJob extends Job implements GenericParameterJob {
21  public function __construct( array $params ) {
22  parent::__construct( 'clearUserWatchlist', $params );
23 
24  $this->removeDuplicates = true;
25  }
26 
33  public static function newForUser( UserIdentity $user, $maxWatchlistId ) {
34  return new self( [ 'userId' => $user->getId(), 'maxWatchlistId' => $maxWatchlistId ] );
35  }
36 
37  public function run() {
38  $updateRowsPerQuery = MediaWikiServices::getInstance()->getMainConfig()->get(
39  MainConfigNames::UpdateRowsPerQuery );
40  $userId = $this->params['userId'];
41  $maxWatchlistId = $this->params['maxWatchlistId'];
42  $batchSize = $updateRowsPerQuery;
43 
44  $loadBalancer = MediaWikiServices::getInstance()->getDBLoadBalancer();
45  $dbw = $loadBalancer->getConnectionRef( DB_PRIMARY );
46  $dbr = $loadBalancer->getConnectionRef( DB_REPLICA, [ 'watchlist' ] );
47 
48  // Wait before lock to try to reduce time waiting in the lock.
49  if ( !$loadBalancer->waitForPrimaryPos( $dbr ) ) {
50  $this->setLastError( 'Timed out waiting for replica to catch up before lock' );
51  return false;
52  }
53 
54  // Use a named lock so that jobs for this user see each others' changes
55  $lockKey = "{{$dbw->getDomainID()}}:ClearUserWatchlist:$userId"; // per-wiki
56  $scopedLock = $dbw->getScopedLockAndFlush( $lockKey, __METHOD__, 10 );
57  if ( !$scopedLock ) {
58  $this->setLastError( "Could not acquire lock '$lockKey'" );
59  return false;
60  }
61 
62  if ( !$loadBalancer->waitForPrimaryPos( $dbr ) ) {
63  $this->setLastError( 'Timed out waiting for replica to catch up within lock' );
64  return false;
65  }
66 
67  // Clear any stale REPEATABLE-READ snapshot
68  $dbr->flushSnapshot( __METHOD__ );
69 
70  $watchlistIds = $dbr->selectFieldValues(
71  'watchlist',
72  'wl_id',
73  [
74  'wl_user' => $userId,
75  'wl_id <= ' . $maxWatchlistId
76  ],
77  __METHOD__,
78  [
79  'LIMIT' => $batchSize,
80  ]
81  );
82 
83  if ( count( $watchlistIds ) == 0 ) {
84  return true;
85  }
86 
87  $dbw->delete( 'watchlist', [ 'wl_id' => $watchlistIds ], __METHOD__ );
88  if ( MediaWikiServices::getInstance()->getMainConfig()->get(
89  MainConfigNames::WatchlistExpiry ) ) {
90  $dbw->delete( 'watchlist_expiry', [ 'we_item' => $watchlistIds ], __METHOD__ );
91  }
92 
93  // Commit changes and remove lock before inserting next job.
94  $lbf = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
95  $lbf->commitPrimaryChanges( __METHOD__ );
96  unset( $scopedLock );
97 
98  if ( count( $watchlistIds ) === (int)$batchSize ) {
99  // Until we get less results than the limit, recursively push
100  // the same job again.
101  MediaWikiServices::getInstance()->getJobQueueGroup()->push( new self( $this->getParams() ) );
102  }
103 
104  return true;
105  }
106 
107  public function getDeduplicationInfo() {
108  $info = parent::getDeduplicationInfo();
109  // This job never has a namespace or title so we can't use it for deduplication
110  unset( $info['namespace'] );
111  unset( $info['title'] );
112  return $info;
113  }
114 
115 }
Job to clear a users watchlist in batches.
static newForUser(UserIdentity $user, $maxWatchlistId)
getDeduplicationInfo()
Subclasses may need to override this to make duplication detection work.
Class to both describe a background job and handle jobs.
Definition: Job.php:39
getParams()
array Parameters that specify sources, targets, and options for execution
Definition: Job.php:193
setLastError( $error)
Definition: Job.php:469
array $params
Array of job parameters.
Definition: Job.php:44
A class containing constants representing the names of configuration variables.
Service locator for MediaWiki core services.
Interface for generic jobs only uses the parameters field and are JSON serializable.
Interface for objects representing user identity.
getId( $wikiId=self::LOCAL)
const DB_REPLICA
Definition: defines.php:26
const DB_PRIMARY
Definition: defines.php:28